summaryrefslogtreecommitdiffstats
path: root/Src/Modules
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-04-15 18:05:35 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-04-15 18:05:35 +0000
commit32c2ebbaa5d7927f33ee0ecf98472a71cf902cf3 (patch)
tree212c29fe244d0222bab8efe3032e7fa965842945 /Src/Modules
parentInitial revision (diff)
downloadzsh-3.1.5.tar
zsh-3.1.5.tar.gz
zsh-3.1.5.tar.bz2
zsh-3.1.5.tar.lz
zsh-3.1.5.tar.xz
zsh-3.1.5.tar.zst
zsh-3.1.5.zip
zsh-3.1.5zsh-3.1.5
Diffstat (limited to 'Src/Modules')
-rw-r--r--Src/Modules/.cvsignore10
-rw-r--r--Src/Modules/.distfiles8
-rw-r--r--Src/Modules/.exrc2
-rw-r--r--Src/Modules/cap.c141
-rw-r--r--Src/Modules/cap.mdd3
-rw-r--r--Src/Modules/clone.c115
-rw-r--r--Src/Modules/clone.mdd3
-rw-r--r--Src/Modules/example.c76
-rw-r--r--Src/Modules/example.mdd3
-rw-r--r--Src/Modules/files.c528
-rw-r--r--Src/Modules/files.mdd3
-rw-r--r--Src/Modules/stat.c535
-rw-r--r--Src/Modules/stat.mdd3
13 files changed, 1430 insertions, 0 deletions
diff --git a/Src/Modules/.cvsignore b/Src/Modules/.cvsignore
new file mode 100644
index 000000000..169be5ef9
--- /dev/null
+++ b/Src/Modules/.cvsignore
@@ -0,0 +1,10 @@
+Makefile
+Makefile.in
+*.pro
+*.o
+*.o.c
+*.so
+*.mdh
+*.mdhi
+*.mdhs
+*.mdh.tmp
diff --git a/Src/Modules/.distfiles b/Src/Modules/.distfiles
new file mode 100644
index 000000000..4c98f97ea
--- /dev/null
+++ b/Src/Modules/.distfiles
@@ -0,0 +1,8 @@
+DISTFILES_SRC='
+ .cvsignore .distfiles .exrc
+ cap.mdd cap.c
+ clone.mdd clone.c
+ example.mdd example.c
+ files.mdd files.c
+ stat.mdd stat.c
+'
diff --git a/Src/Modules/.exrc b/Src/Modules/.exrc
new file mode 100644
index 000000000..91d0b39ef
--- /dev/null
+++ b/Src/Modules/.exrc
@@ -0,0 +1,2 @@
+set ai
+set sw=4
diff --git a/Src/Modules/cap.c b/Src/Modules/cap.c
new file mode 100644
index 000000000..008b6932d
--- /dev/null
+++ b/Src/Modules/cap.c
@@ -0,0 +1,141 @@
+/*
+ * cap.c - POSIX.1e (POSIX.6) capability set manipulation
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 1997 Andrew Main
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Andrew Main or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Andrew Main and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Andrew Main and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose. The software
+ * provided hereunder is on an "as is" basis, and Andrew Main and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+#include "cap.mdh"
+#include "cap.pro"
+
+#ifdef HAVE_CAP_GET_PROC
+
+static int
+bin_cap(char *nam, char **argv, char *ops, int func)
+{
+ int ret = 0;
+ cap_t caps;
+ if(*argv) {
+ caps = cap_from_text(*argv);
+ if(!caps) {
+ zwarnnam(nam, "invalid capability string", NULL, 0);
+ return 1;
+ }
+ if(cap_set_proc(caps)) {
+ zwarnnam(nam, "can't change capabilites: %e", NULL, errno);
+ ret = 1;
+ }
+ } else {
+ char *result;
+ ssize_t length;
+ caps = cap_get_proc();
+ if(caps)
+ result = cap_to_text(caps, &length);
+ if(!caps || !result) {
+ zwarnnam(nam, "can't get capabilites: %e", NULL, errno);
+ ret = 1;
+ } else
+ puts(result);
+ }
+ cap_free(&caps);
+ return ret;
+}
+
+static int
+bin_getcap(char *nam, char **argv, char *ops, int func)
+{
+ int ret = 0;
+
+ do {
+ char *result;
+ ssize_t length;
+ cap_t caps = cap_get_file(*argv);
+ if(caps)
+ result = cap_to_text(caps, &length);
+ if (!caps || !result) {
+ zwarnnam(nam, "%s: %e", *argv, errno);
+ ret = 1;
+ } else
+ printf("%s %s\n", *argv, result);
+ cap_free(&caps);
+ } while(*++argv);
+ return ret;
+}
+
+static int
+bin_setcap(char *nam, char **argv, char *ops, int func)
+{
+ cap_t caps;
+ int ret = 0;
+
+ caps = cap_from_text(*argv++);
+ if(!caps) {
+ zwarnnam(nam, "invalid capability string", NULL, 0);
+ return 1;
+ }
+
+ do {
+ if(cap_set_file(*argv, caps)) {
+ zwarnnam(nam, "%s: %e", *argv, errno);
+ ret = 1;
+ }
+ } while(*++argv);
+ cap_free(&caps);
+ return ret;
+}
+
+#else /* !HAVE_CAP_GET_PROC */
+
+# define bin_cap bin_notavail
+# define bin_getcap bin_notavail
+# define bin_setcap bin_notavail
+
+#endif /* !HAVE_CAP_GET_PROC */
+
+/* module paraphernalia */
+
+static struct builtin bintab[] = {
+ BUILTIN("cap", 0, bin_cap, 0, 1, 0, NULL, NULL),
+ BUILTIN("getcap", 0, bin_getcap, 1, -1, 0, NULL, NULL),
+ BUILTIN("setcap", 0, bin_setcap, 2, -1, 0, NULL, NULL),
+};
+
+/**/
+int
+boot_cap(Module m)
+{
+ return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+}
+
+#ifdef MODULE
+
+/**/
+int
+cleanup_cap(Module m)
+{
+ deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+ return 0;
+}
+#endif
diff --git a/Src/Modules/cap.mdd b/Src/Modules/cap.mdd
new file mode 100644
index 000000000..97f377e9d
--- /dev/null
+++ b/Src/Modules/cap.mdd
@@ -0,0 +1,3 @@
+autobins="cap getcap setcap"
+
+objects="cap.o"
diff --git a/Src/Modules/clone.c b/Src/Modules/clone.c
new file mode 100644
index 000000000..11387fc90
--- /dev/null
+++ b/Src/Modules/clone.c
@@ -0,0 +1,115 @@
+/*
+ * clone.c - start a forked instance of the current shell on a new terminal
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 1997 Zoltán Hidvégi
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Zoltán Hidvégi or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Zoltán Hidvégi and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Zoltán Hidvégi and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose. The software
+ * provided hereunder is on an "as is" basis, and Zoltán Hidvégi and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+/*
+ * The clone builtin can be used to start a forked instance of the current
+ * shell on a new terminal. The only argument to the builtin is the name
+ * of the new terminal. In the new shell the PID, PPID and TTY parameters
+ * are changed appropriately. $! is set to zero in the new instance of the
+ * shell and to the pid of the new instance in the original shell.
+ *
+ */
+
+#include "clone.mdh"
+#include "clone.pro"
+
+/**/
+static int
+bin_clone(char *nam, char **args, char *ops, int func)
+{
+ int ttyfd, pid;
+
+ unmetafy(*args, NULL);
+ ttyfd = open(*args, O_RDWR|O_NOCTTY);
+ if (ttyfd < 0) {
+ zwarnnam(nam, "%s: %e", *args, errno);
+ return 1;
+ }
+ pid = fork();
+ if (!pid) {
+ clearjobtab();
+ ppid = getppid();
+ mypid = getpid();
+#ifdef HAVE_SETSID
+ if (setsid() != mypid) {
+ zwarnnam(nam, "failed to create new session: %e", NULL, errno);
+#endif
+#ifdef TIOCNOTTY
+ if (ioctl(SHTTY, TIOCNOTTY))
+ zwarnnam(nam, "%e", NULL, errno);
+ setpgrp(0L, mypid);
+#endif
+#ifdef HAVE_SETSID
+ }
+#endif
+ if (ttyfd) {
+ close(0);
+ dup(ttyfd);
+ } else
+ ttyfd = -1;
+ close(1);
+ close(2);
+ dup(0);
+ dup(0);
+ closem(0);
+ close(coprocin);
+ close(coprocout);
+ init_io();
+ setsparam("TTY", ztrdup(ttystrname));
+ }
+ close(ttyfd);
+ if (pid < 0) {
+ zerrnam(nam, "fork failed: %e", NULL, errno);
+ return 1;
+ }
+ lastpid = pid;
+ return 0;
+}
+
+static struct builtin bintab[] = {
+ BUILTIN("clone", 0, bin_clone, 1, 1, 0, NULL, NULL),
+};
+
+/**/
+int
+boot_clone(Module m)
+{
+ return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+}
+
+#ifdef MODULE
+
+/**/
+int
+cleanup_clone(Module m)
+{
+ deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+ return 0;
+}
+#endif
diff --git a/Src/Modules/clone.mdd b/Src/Modules/clone.mdd
new file mode 100644
index 000000000..5277d3151
--- /dev/null
+++ b/Src/Modules/clone.mdd
@@ -0,0 +1,3 @@
+autobins="clone"
+
+objects="clone.o"
diff --git a/Src/Modules/example.c b/Src/Modules/example.c
new file mode 100644
index 000000000..45ef3c28f
--- /dev/null
+++ b/Src/Modules/example.c
@@ -0,0 +1,76 @@
+/*
+ * example.c - an example module for zsh
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 1996-1997 Zoltán Hidvégi
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Zoltán Hidvégi or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Zoltán Hidvégi and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Zoltán Hidvégi and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose. The software
+ * provided hereunder is on an "as is" basis, and Zoltán Hidvégi and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+#include "example.mdh"
+#include "example.pro"
+
+/**/
+static int
+bin_example(char *nam, char **args, char *ops, int func)
+{
+ unsigned char c;
+
+ printf("Options: ");
+ for (c = 32; ++c < 128;)
+ if (ops[c])
+ putchar(c);
+ printf("\nArguments:");
+ for (; *args; args++) {
+ putchar(' ');
+ fputs(*args, stdout);
+ }
+ printf("\nName: %s\n", nam);
+ return 0;
+}
+
+/*
+ * boot_example is executed when the module is loaded.
+ */
+
+static struct builtin bintab[] = {
+ BUILTIN("example", 0, bin_example, 0, -1, 0, "flags", NULL),
+};
+
+/**/
+int
+boot_example(Module m)
+{
+ return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+}
+
+#ifdef MODULE
+
+/**/
+int
+cleanup_example(Module m)
+{
+ deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+ return 0;
+}
+#endif
diff --git a/Src/Modules/example.mdd b/Src/Modules/example.mdd
new file mode 100644
index 000000000..89f12097c
--- /dev/null
+++ b/Src/Modules/example.mdd
@@ -0,0 +1,3 @@
+autobins="example"
+
+objects="example.o"
diff --git a/Src/Modules/files.c b/Src/Modules/files.c
new file mode 100644
index 000000000..6127c5524
--- /dev/null
+++ b/Src/Modules/files.c
@@ -0,0 +1,528 @@
+/*
+ * files.c - file operation builtins
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 1996-1997 Andrew Main
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Andrew Main or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Andrew Main and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Andrew Main and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose. The software
+ * provided hereunder is on an "as is" basis, and Andrew Main and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+#include "files.mdh"
+
+typedef int (*MoveFunc) _((char const *, char const *));
+
+#ifndef STDC_HEADERS
+extern int link _((const char *, const char *));
+extern int symlink _((const char *, const char *));
+extern int rename _((const char *, const char *));
+#endif
+
+#include "files.pro"
+
+/**/
+static int
+ask(void)
+{
+ int a = getchar(), c;
+ for(c = a; c != EOF && c != '\n'; )
+ c = getchar();
+ return a == 'y' || a == 'Y';
+}
+
+/* sync builtin */
+
+/**/
+static int
+bin_sync(char *nam, char **args, char *ops, int func)
+{
+ sync();
+ return 0;
+}
+
+/* mkdir builtin */
+
+/**/
+static int
+bin_mkdir(char *nam, char **args, char *ops, int func)
+{
+ mode_t oumask = umask(0);
+ mode_t mode = 0777 & ~oumask;
+ int err = 0;
+
+ umask(oumask);
+ if(ops['m']) {
+ char *str = *args++, *ptr;
+
+ if(!*args) {
+ zwarnnam(nam, "not enough arguments", NULL, 0);
+ return 1;
+ }
+ mode = zstrtol(str, &ptr, 8);
+ if(!*str || *ptr) {
+ zwarnnam(nam, "invalid mode `%s'", str, 0);
+ return 1;
+ }
+ }
+ for(; *args; args++) {
+ char *ptr = strchr(*args, 0);
+
+ while(ptr > *args + (**args == '/') && *--ptr == '/')
+ *ptr = 0;
+ if(ztrlen(*args) > PATH_MAX - 1) {
+ zwarnnam(nam, "%s: %e", *args, ENAMETOOLONG);
+ err = 1;
+ continue;
+ }
+ if(ops['p']) {
+ char *ptr = *args;
+
+ for(;;) {
+ while(*ptr == '/')
+ ptr++;
+ while(*ptr && *ptr != '/')
+ ptr++;
+ if(!*ptr) {
+ err |= domkdir(nam, *args, mode, 1);
+ break;
+ } else {
+ int e;
+
+ *ptr = 0;
+ e = domkdir(nam, *args, mode | 0300, 1);
+ if(e) {
+ err = 1;
+ break;
+ }
+ *ptr = '/';
+ }
+ }
+ } else
+ err |= domkdir(nam, *args, mode, 0);
+ }
+ return err;
+}
+
+/**/
+static int
+domkdir(char *nam, char *path, mode_t mode, int p)
+{
+ int err;
+ mode_t oumask;
+ char const *rpath = unmeta(path);
+
+ if(p) {
+ struct stat st;
+
+ if(!lstat(rpath, &st) && S_ISDIR(st.st_mode))
+ return 0;
+ }
+ oumask = umask(0);
+ err = mkdir(path, mode) ? errno : 0;
+ umask(oumask);
+ if(!err)
+ return 0;
+ zwarnnam(nam, "cannot make directory `%s': %e", path, err);
+ return 1;
+}
+
+/* rmdir builtin */
+
+/**/
+static int
+bin_rmdir(char *nam, char **args, char *ops, int func)
+{
+ int err = 0;
+
+ for(; *args; args++) {
+ char *rpath = unmeta(*args);
+
+ if(!rpath) {
+ zwarnnam(nam, "%s: %e", *args, ENAMETOOLONG);
+ err = 1;
+ } else if(rmdir(rpath)) {
+ zwarnnam(nam, "cannot remove directory `%s': %e", *args, errno);
+ err = 1;
+ }
+ }
+ return err;
+}
+
+/* ln and mv builtins */
+
+#define BIN_LN 0
+#define BIN_MV 1
+
+#define MV_NODIRS (1<<0)
+#define MV_FORCE (1<<1)
+#define MV_INTER (1<<2)
+#define MV_ASKNW (1<<3)
+#define MV_ATOMIC (1<<4)
+
+/* bin_ln actually does three related jobs: hard linking, symbolic *
+ * linking, and renaming. If called as mv it renames, otherwise *
+ * it looks at the -s option. If hard linking, it will refuse to *
+ * attempt linking to a directory unless the -d option is given. */
+
+/**/
+static int
+bin_ln(char *nam, char **args, char *ops, int func)
+{
+ MoveFunc move;
+ int flags, space, err = 0;
+ char **a, *ptr, *rp;
+ struct stat st;
+ char buf[PATH_MAX * 2 + 1];
+
+
+ if(func == BIN_MV) {
+ move = rename;
+ flags = ops['f'] ? 0 : MV_ASKNW;
+ flags |= MV_ATOMIC;
+ } else {
+ flags = ops['f'] ? MV_FORCE : 0;
+#ifdef HAVE_LSTAT
+ if(ops['s'])
+ move = symlink;
+ else
+#endif
+ {
+ move = link;
+ if(!ops['d'])
+ flags |= MV_NODIRS;
+ }
+ }
+ if(ops['i'] && !ops['f'])
+ flags |= MV_INTER;
+ for(a = args; a[1]; a++) ;
+ if(a != args) {
+ rp = unmeta(*a);
+ if(rp && !stat(rp, &st) && S_ISDIR(st.st_mode))
+ goto havedir;
+ }
+ if(a > args+1) {
+ zwarnnam(nam, "last of many arguments must be a directory", NULL, 0);
+ return 1;
+ }
+ if(!args[1]) {
+ ptr = strrchr(args[0], '/');
+ if(ptr)
+ args[1] = ptr+1;
+ else
+ args[1] = args[0];
+ }
+ return domove(nam, move, args[0], args[1], flags);
+ havedir:
+ strcpy(buf, *a);
+ *a = NULL;
+ space = PATH_MAX - 1 - ztrlen(buf);
+ rp = strchr(buf, 0);
+ *rp++ = '/';
+ for(; *args; args++) {
+ if(ztrlen(*args) > PATH_MAX) {
+ zwarnnam(nam, "%s: %e", *args, ENAMETOOLONG);
+ err = 1;
+ continue;
+ }
+ ptr = strrchr(*args, '/');
+ if(ptr)
+ ptr++;
+ else
+ ptr = *args;
+ if(ztrlen(ptr) > space) {
+ zwarnnam(nam, "%s: %e", ptr, ENAMETOOLONG);
+ err = 1;
+ continue;
+ }
+ strcpy(rp, ptr);
+ err |= domove(nam, move, *args, buf, flags);
+ }
+ return err;
+}
+
+/**/
+static int
+domove(char *nam, MoveFunc move, char *p, char *q, int flags)
+{
+ struct stat st;
+ char *qbuf;
+ char pbuf[PATH_MAX + 1];
+ strcpy(pbuf, unmeta(p));
+ qbuf = unmeta(q);
+ if(flags & MV_NODIRS) {
+ errno = EISDIR;
+ if(lstat(pbuf, &st) || S_ISDIR(st.st_mode)) {
+ zwarnnam(nam, "%s: %e", p, errno);
+ return 1;
+ }
+ }
+ if(!lstat(qbuf, &st)) {
+ int doit = flags & MV_FORCE;
+ if(S_ISDIR(st.st_mode)) {
+ zwarnnam(nam, "%s: cannot overwrite directory", q, 0);
+ return 1;
+ } else if(flags & MV_INTER) {
+ nicezputs(nam, stderr);
+ fputs(": replace `", stderr);
+ nicezputs(q, stderr);
+ fputs("'? ", stderr);
+ fflush(stderr);
+ if(!ask())
+ return 0;
+ doit = 1;
+ } else if((flags & MV_ASKNW) &&
+ !S_ISLNK(st.st_mode) &&
+ access(qbuf, W_OK)) {
+ nicezputs(nam, stderr);
+ fputs(": replace `", stderr);
+ nicezputs(q, stderr);
+ fprintf(stderr, "', overriding mode %04o? ",
+ mode_to_octal(st.st_mode));
+ fflush(stderr);
+ if(!ask())
+ return 0;
+ doit = 1;
+ }
+ if(doit && !(flags & MV_ATOMIC))
+ unlink(qbuf);
+ }
+ if(move(pbuf, qbuf)) {
+ zwarnnam(nam, "%s: %e", p, errno);
+ return 1;
+ }
+ return 0;
+}
+
+/* rm builtin */
+
+/**/
+static int
+bin_rm(char *nam, char **args, char *ops, int func)
+{
+ int err = 0, len;
+ char *rp, *s;
+ struct dirsav ds;
+
+ ds.ino = ds.dev = 0;
+ ds.dirname = NULL;
+ ds.dirfd = ds.level = -1;
+ if (ops['r'] || ops['s']) {
+ if ((ds.dirfd = open(".", O_RDONLY|O_NOCTTY)) < 0 &&
+ zgetdir(&ds) && *ds.dirname != '/')
+ ds.dirfd = open("..", O_RDONLY|O_NOCTTY);
+ }
+ for(; !errflag && !(err & 2) && *args; args++) {
+ rp = ztrdup(*args);
+ unmetafy(rp, &len);
+ if (ops['s']) {
+ s = strrchr(rp, '/');
+ if (s && !s[1]) {
+ while (*s == '/' && s > rp)
+ *s-- = '\0';
+ while (*s != '/' && s > rp)
+ s--;
+ }
+ if (s && s[1]) {
+ int e;
+
+ *s = '\0';
+ e = lchdir(s > rp ? rp : "/", &ds, 1);
+ err |= -e;
+ if (!e) {
+ struct dirsav d;
+
+ d.ino = d.dev = 0;
+ d.dirname = NULL;
+ d.dirfd = d.level = -1;
+ err |= dorm(nam, *args, s + 1, ops, &d, 0);
+ zsfree(d.dirname);
+ if (restoredir(&ds))
+ err |= 2;
+ } else
+ zwarnnam(nam, "%s: %e", *args, errno);
+ } else
+ err |= dorm(nam, *args, rp, ops, &ds, 0);
+ } else
+ err |= dorm(nam, *args, rp, ops, &ds, 1);
+ zfree(rp, len + 1);
+ }
+ if ((err & 2) && ds.dirfd >= 0 && restoredir(&ds) && zchdir(pwd)) {
+ zsfree(pwd);
+ pwd = ztrdup("/");
+ chdir(pwd);
+ }
+ if (ds.dirfd >= 0)
+ close(ds.dirfd);
+ zsfree(ds.dirname);
+ return ops['f'] ? 0 : !!err;
+}
+
+/**/
+static int
+dorm(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first)
+{
+ struct stat st;
+
+ if((!ops['d'] || !ops['f']) && !lstat(rp, &st)) {
+ if(!ops['d'] && S_ISDIR(st.st_mode)) {
+ if(ops['r'])
+ return dormr(nam, arg, rp, ops, ds, first);
+ if(!ops['f'])
+ zwarnnam(nam, "%s: %e", arg, EISDIR);
+ return 1;
+ }
+ if(!ops['f'] && ops['i']) {
+ nicezputs(nam, stderr);
+ fputs(": remove `", stderr);
+ nicezputs(arg, stderr);
+ fputs("'? ", stderr);
+ fflush(stderr);
+ if(!ask())
+ return 0;
+ } else if(!ops['f'] &&
+ !S_ISLNK(st.st_mode) &&
+ access(rp, W_OK)) {
+ nicezputs(nam, stderr);
+ fputs(": remove `", stderr);
+ nicezputs(arg, stderr);
+ fprintf(stderr, "', overriding mode %04o? ",
+ mode_to_octal(st.st_mode));
+ fflush(stderr);
+ if(!ask())
+ return 0;
+ }
+ }
+ if(!unlink(rp))
+ return 0;
+ if(!ops['f'])
+ zwarnnam(nam, "%s: %e", arg, errno);
+ return 1;
+}
+
+/**/
+static int
+dormr(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first)
+{
+ char *fn;
+ DIR *d;
+ int err;
+ struct dirsav dsav;
+ char *files = NULL;
+ int fileslen = 0;
+
+ err = -lchdir(rp, ds, !first);
+ if (err) {
+ if (!ops['f'])
+ zwarnnam(nam, "%s: %e", arg, errno);
+ return err;
+ }
+
+ dsav.ino = dsav.dev = 0;
+ dsav.dirname = NULL;
+ dsav.dirfd = dsav.level = -1;
+ d = opendir(".");
+ if(!d) {
+ if(!ops['f'])
+ zwarnnam(nam, "%s: %e", arg, errno);
+ err = 1;
+ } else {
+ int arglen = strlen(arg) + 1;
+
+ while (!errflag && (fn = zreaddir(d, 1))) {
+ int l = strlen(fn) + 1;
+ files = hrealloc(files, fileslen, fileslen + l);
+ strcpy(files + fileslen, fn);
+ fileslen += l;
+ }
+ closedir(d);
+ for (fn = files; !errflag && !(err & 2) && fn < files + fileslen;) {
+ int l = strlen(fn) + 1;
+ VARARR(char, narg, arglen + l);
+
+ strcpy(narg,arg);
+ narg[arglen-1] = '/';
+ strcpy(narg + arglen, fn);
+ unmetafy(fn, NULL);
+ err |= dorm(nam, narg, fn, ops, &dsav, 0);
+ fn += l;
+ }
+ hrealloc(files, fileslen, 0);
+ }
+ zsfree(dsav.dirname);
+ if (err & 2)
+ return 2;
+ if (restoredir(ds)) {
+ if(!ops['f'])
+ zwarnnam(nam, "failed to return to previous directory: %e",
+ NULL, errno);
+ return 2;
+ }
+ if(!ops['f'] && ops['i']) {
+ nicezputs(nam, stderr);
+ fputs(": remove `", stderr);
+ nicezputs(arg, stderr);
+ fputs("'? ", stderr);
+ fflush(stderr);
+ if(!ask())
+ return err;
+ }
+ if(!rmdir(rp))
+ return err;
+ if(!ops['f'])
+ zwarnnam(nam, "%s: %e", arg, errno);
+ return 1;
+}
+
+/* module paraphernalia */
+
+#ifdef HAVE_LSTAT
+# define LN_OPTS "dfis"
+#else
+# define LN_OPTS "dfi"
+#endif
+
+static struct builtin bintab[] = {
+ BUILTIN("ln", 0, bin_ln, 1, -1, BIN_LN, LN_OPTS, NULL),
+ BUILTIN("mkdir", 0, bin_mkdir, 1, -1, 0, "pm", NULL),
+ BUILTIN("mv", 0, bin_ln, 2, -1, BIN_MV, "fi", NULL),
+ BUILTIN("rm", 0, bin_rm, 1, -1, 0, "dfirs", NULL),
+ BUILTIN("rmdir", 0, bin_rmdir, 1, -1, 0, NULL, NULL),
+ BUILTIN("sync", 0, bin_sync, 0, 0, 0, NULL, NULL),
+};
+
+/**/
+int
+boot_files(Module m)
+{
+ return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+}
+
+#ifdef MODULE
+
+/**/
+int
+cleanup_files(Module m)
+{
+ deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+ return 0;
+}
+#endif
diff --git a/Src/Modules/files.mdd b/Src/Modules/files.mdd
new file mode 100644
index 000000000..236ca2d5a
--- /dev/null
+++ b/Src/Modules/files.mdd
@@ -0,0 +1,3 @@
+autobins="ln mkdir mv rm rmdir sync"
+
+objects="files.o"
diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c
new file mode 100644
index 000000000..09245b52f
--- /dev/null
+++ b/Src/Modules/stat.c
@@ -0,0 +1,535 @@
+/*
+ * stat.c - stat builtin interface to system call
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 1996-1997 Peter Stephenson
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Peter Stephenson or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Peter Stephenson and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Peter Stephenson and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose. The software
+ * provided hereunder is on an "as is" basis, and Peter Stephenson and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+#include "stat.mdh"
+#include "stat.pro"
+
+enum statnum { ST_DEV, ST_INO, ST_MODE, ST_NLINK, ST_UID, ST_GID,
+ ST_RDEV, ST_SIZE, ST_ATIM, ST_MTIM, ST_CTIM,
+ ST_BLKSIZE, ST_BLOCKS, ST_READLINK, ST_COUNT };
+enum statflags { STF_NAME = 1, STF_FILE = 2, STF_STRING = 4, STF_RAW = 8,
+ STF_PICK = 16, STF_ARRAY = 32, STF_GMT = 64 };
+static char *statelts[] = { "device", "inode", "mode", "nlink",
+ "uid", "gid", "rdev", "size", "atime",
+ "mtime", "ctime", "blksize", "blocks",
+ "link", NULL };
+
+/**/
+static void
+statmodeprint(mode_t mode, char *outbuf, int flags)
+{
+ if (flags & STF_RAW) {
+ sprintf(outbuf, "%lu", (unsigned long)mode);
+ if (flags & STF_STRING)
+ strcat(outbuf, " (");
+ }
+ if (flags & STF_STRING) {
+ static const char *modes = "?rwxrwxrwx";
+ static const mode_t mflags[] = { S_IRUSR, S_IWUSR, S_IXUSR,
+ S_IRGRP, S_IWGRP, S_IXGRP,
+ S_IROTH, S_IWOTH, S_IXOTH };
+ const mode_t *mfp = mflags;
+ char pm[11];
+ int i;
+
+ if (S_ISBLK(mode))
+ *pm = 'b';
+ else if (S_ISCHR(mode))
+ *pm = 'c';
+ else if (S_ISDIR(mode))
+ *pm = 'd';
+ else if (S_ISFIFO(mode))
+ *pm = 'p';
+ else if (S_ISLNK(mode))
+ *pm = 'l';
+ else if (S_ISMPC(mode))
+ *pm = 'm';
+ else if (S_ISNWK(mode))
+ *pm = 'n';
+ else if (S_ISOFD(mode))
+ *pm = 'M';
+ else if (S_ISOFL(mode))
+ *pm = 'M';
+ else if (S_ISREG(mode))
+ *pm = '-';
+ else if (S_ISSOCK(mode))
+ *pm = 's';
+ else
+ *pm = '?';
+
+ for (i = 1; i <= 9; i++)
+ pm[i] = (mode & *mfp++) ? modes[i] : '-';
+
+ if (mode & S_ISUID)
+ pm[3] = (mode & S_IXUSR) ? 's' : 'S';
+ if (mode & S_ISGID)
+ pm[6] = (mode & S_IXGRP) ? 's' : 'S';
+ if (mode & S_ISVTX)
+ pm[9] = (mode & S_IXOTH) ? 't' : 'T';
+
+ pm[10] = 0;
+ strcat(outbuf, pm);
+ if (flags & STF_RAW)
+ strcat(outbuf, ")");
+ }
+}
+
+
+/**/
+static void
+statuidprint(uid_t uid, char *outbuf, int flags)
+{
+ if (flags & STF_RAW) {
+ sprintf(outbuf, "%lu", (unsigned long)uid);
+ if (flags & STF_STRING)
+ strcat(outbuf, " (");
+ }
+ if (flags & STF_STRING) {
+#ifdef HAVE_GETPWUID
+ struct passwd *pwd;
+ pwd = getpwuid(uid);
+ strcat(outbuf, pwd ? pwd->pw_name : "???");
+#else /* !HAVE_GETPWUID */
+ strcat(outbuf, "???");
+#endif /* !HAVE_GETPWUID */
+ if (flags & STF_RAW)
+ strcat(outbuf, ")");
+ }
+}
+
+
+/**/
+static void
+statgidprint(gid_t gid, char *outbuf, int flags)
+{
+ if (flags & STF_RAW) {
+ sprintf(outbuf, "%lu", (unsigned long)gid);
+ if (flags & STF_STRING)
+ strcat(outbuf, " (");
+ }
+ if (flags & STF_STRING) {
+#ifdef HAVE_GETGRGID
+ struct group *gr;
+ gr = getgrgid(gid);
+ strcat(outbuf, gr ? gr->gr_name : "???");
+#else /* !HAVE_GETGRGID */
+ strcat(outbuf, "???");
+#endif /* !HAVE_GETGRGID */
+ if (flags & STF_RAW)
+ strcat(outbuf, ")");
+ }
+}
+
+static char *timefmt;
+
+/**/
+static void
+stattimeprint(time_t tim, char *outbuf, int flags)
+{
+ if (flags & STF_RAW) {
+ sprintf(outbuf, "%ld", (unsigned long)tim);
+ if (flags & STF_STRING)
+ strcat(outbuf, " (");
+ }
+ if (flags & STF_STRING) {
+ char *oend = outbuf + strlen(outbuf);
+ ztrftime(oend, 40, timefmt, (flags & STF_GMT) ? gmtime(&tim) :
+ localtime(&tim));
+ if (flags & STF_RAW)
+ strcat(outbuf, ")");
+ }
+}
+
+
+/**/
+static void
+statulprint(unsigned long num, char *outbuf)
+{
+ sprintf(outbuf, "%lu", num);
+}
+
+
+/**/
+static void
+statlinkprint(struct stat *sbuf, char *outbuf, char *fname)
+{
+ int num;
+
+ /* fname is NULL if we are looking at an fd */
+ if (fname && S_ISLNK(sbuf->st_mode) &&
+ (num = readlink(fname, outbuf, PATH_MAX)) > 0) {
+ /* readlink doesn't terminate the buffer itself */
+ outbuf[num] = '\0';
+ }
+}
+
+
+/**/
+static void
+statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags)
+{
+ char *optr = outbuf;
+
+ if (flags & STF_NAME) {
+ sprintf(outbuf, (flags & (STF_PICK|STF_ARRAY)) ?
+ "%s " : "%-8s", statelts[iwhich]);
+ optr += strlen(outbuf);
+ }
+ *optr = '\0';
+
+ /* cast values to unsigned long as safest bet */
+ switch (iwhich) {
+ case ST_DEV:
+ statulprint((unsigned long)sbuf->st_dev, optr);
+ break;
+
+ case ST_INO:
+ statulprint((unsigned long)sbuf->st_ino, optr);
+ break;
+
+ case ST_MODE:
+ statmodeprint(sbuf->st_mode, optr, flags);
+ break;
+
+ case ST_NLINK:
+ statulprint((unsigned long)sbuf->st_nlink, optr);
+ break;
+
+ case ST_UID:
+ statuidprint(sbuf->st_uid, optr, flags);
+ break;
+
+ case ST_GID:
+ statgidprint(sbuf->st_gid, optr, flags);
+ break;
+
+ case ST_RDEV:
+ statulprint((unsigned long)sbuf->st_rdev, optr);
+ break;
+
+ case ST_SIZE:
+ statulprint((unsigned long)sbuf->st_size, optr);
+ break;
+
+ case ST_ATIM:
+ stattimeprint(sbuf->st_atime, optr, flags);
+ break;
+
+ case ST_MTIM:
+ stattimeprint(sbuf->st_mtime, optr, flags);
+ break;
+
+ case ST_CTIM:
+ stattimeprint(sbuf->st_ctime, optr, flags);
+ break;
+
+ case ST_BLKSIZE:
+ statulprint((unsigned long)sbuf->st_blksize, optr);
+ break;
+
+ case ST_BLOCKS:
+ statulprint((unsigned long)sbuf->st_blocks, optr);
+ break;
+
+ case ST_READLINK:
+ statlinkprint(sbuf, optr, fname);
+ break;
+
+ case ST_COUNT: /* keep some compilers happy */
+ break;
+ }
+}
+
+
+/*
+ *
+ * Options:
+ * -f fd: stat fd instead of file
+ * -g: use GMT rather than local time for time strings (forces -s on).
+ * -n: always print file name of file being statted
+ * -N: never print file name
+ * -l: list stat types
+ * -L: do lstat (else links are implicitly dereferenced by stat)
+ * -t: always print name of stat type
+ * -T: never print name of stat type
+ * -r: print raw alongside string data
+ * -s: string, print mode, times, uid, gid as appropriate strings:
+ * harmless but unnecessary when combined with -r.
+ * -A array: assign results to given array, one stat result per element.
+ * File names and type names are only added if explicitly requested:
+ * file names are returned as a separate array element, type names as
+ * prefix to element. Note the formatting deliberately contains
+ * fewer frills when -A is used.
+ * -F fmt: specify a $TIME-like format for printing times; the default
+ * is the (CTIME-like) "%a %b %e %k:%M:%S". This option implies
+ * -s as it is not useful for numerical times.
+ *
+ * +type selects just element type of stat buffer (-l gives list):
+ * type can be shortened to unambiguous string. only one type is
+ * allowed. The extra type, +link, reads the target of a symbolic
+ * link; it is empty if the stat was not an lstat or if
+ * a file descriptor was stat'd, if the stat'd file is
+ * not a symbolic link, or if symbolic links are not
+ * supported. If +link is explicitly requested, the -L (lstat)
+ * option is set automatically.
+ */
+/**/
+static int
+bin_stat(char *name, char **args, char *ops, int func)
+{
+ char **aptr, *arrnam = NULL, **array = NULL, **arrptr = NULL;
+ int len, iwhich = -1, ret = 0, flags = 0, arrsize = 0, fd = 0;
+ struct stat statbuf;
+ int found = 0, nargs;
+
+ timefmt = "%a %b %e %k:%M:%S";
+
+ for (; *args && (**args == '+' || **args == '-'); args++) {
+ char *arg = *args+1;
+ if (!*arg || *arg == '-' || *arg == '+') {
+ args++;
+ break;
+ }
+
+ if (**args == '+') {
+ if (found)
+ break;
+ len = strlen(arg);
+ for (aptr = statelts; *aptr; aptr++)
+ if (!strncmp(*aptr, arg, len)) {
+ found++;
+ iwhich = aptr - statelts;
+ }
+ if (found > 1) {
+ zerrnam(name, "%s: ambiguous stat element", arg, 0);
+ return 1;
+ } else if (found == 0) {
+ zerrnam(name, "%s: no such stat element", arg, 0);
+ return 1;
+ }
+ /* if name of link requested, turn on lstat */
+ if (iwhich == ST_READLINK)
+ ops['L'] = 1;
+ flags |= STF_PICK;
+ } else {
+ for (; *arg; arg++) {
+ if (strchr("glLnNrstT", *arg))
+ ops[*arg] = 1;
+ else if (*arg == 'A') {
+ if (arg[1]) {
+ arrnam = arg+1;
+ } else if (!(arrnam = *++args)) {
+ zerrnam(name, "missing parameter name\n",
+ NULL, 0);
+ return 1;
+ }
+ flags |= STF_ARRAY;
+ break;
+ } else if (*arg == 'f') {
+ char *sfd;
+ ops['f'] = 1;
+ if (arg[1]) {
+ sfd = arg+1;
+ } else if (!(sfd = *++args)) {
+ zerrnam(name, "missing file descriptor\n", NULL, 0);
+ return 1;
+ }
+ fd = zstrtol(sfd, &sfd, 10);
+ if (*sfd) {
+ zerrnam(name, "bad file descriptor\n", NULL, 0);
+ return 1;
+ }
+ break;
+ } else if (*arg == 'F') {
+ if (arg[1]) {
+ timefmt = arg+1;
+ } else if (!(timefmt = *++args)) {
+ zerrnam(name, "missing time format\n", NULL, 0);
+ return 1;
+ }
+ /* force string format in order to use time format */
+ ops['s'] = 1;
+ break;
+ } else {
+ zerrnam(name, "bad option: -%c", NULL, *arg);
+ return 1;
+ }
+ }
+ }
+ }
+
+ if (ops['l']) {
+ /* list types and return: can also list to array */
+ if (arrnam) {
+ arrptr = array = (char **)zalloc((ST_COUNT+1)*sizeof(char *));
+ array[ST_COUNT] = NULL;
+ }
+ for (aptr = statelts; *aptr; aptr++) {
+ if (arrnam) {
+ *arrptr++ = ztrdup(*aptr);
+ } else {
+ printf("%s", *aptr);
+ if (aptr[1])
+ putchar(' ');
+ }
+ }
+ if (arrnam) {
+ setaparam(arrnam, array);
+ if (errflag)
+ return 1;
+ } else
+ putchar('\n');
+ return 0;
+ }
+
+ if (!*args && !ops['f']) {
+ zwarnnam(name, "no files given", NULL, 0);
+ return 1;
+ } else if (*args && ops['f']) {
+ zwarnnam(name, "no files allowed with -f", NULL, 0);
+ return 1;
+ }
+
+ nargs = 0;
+ if (ops['f'])
+ nargs = 1;
+ else
+ for (aptr = args; *aptr; aptr++)
+ nargs++;
+
+ if (ops['s'] || ops['r'])
+ flags |= STF_STRING;
+ if (ops['r'] || !ops['s'])
+ flags |= STF_RAW;
+ if (ops['n'])
+ flags |= STF_FILE;
+ if (ops['t'])
+ flags |= STF_NAME;
+ if (ops['g'])
+ flags |= STF_GMT;
+
+ if (!arrnam) {
+ if (nargs > 1)
+ flags |= STF_FILE;
+ if (!(flags & STF_PICK))
+ flags |= STF_NAME;
+ }
+
+ if (ops['N'] || ops['f'])
+ flags &= ~STF_FILE;
+ if (ops['T'])
+ flags &= ~STF_NAME;
+
+ if (arrnam) {
+ arrsize = (flags & STF_PICK) ? 1 : ST_COUNT;
+ if (flags & STF_FILE)
+ arrsize++;
+ arrsize *= nargs;
+ arrptr = array = (char **)zcalloc((arrsize+1)*sizeof(char *));
+ }
+
+ for (; ops['f'] || *args; args++) {
+ char outbuf[PATH_MAX + 9]; /* "link " + link name + NULL */
+ int rval = ops['f'] ? fstat(fd, &statbuf) :
+ ops['L'] ? lstat(*args, &statbuf) : stat(*args, &statbuf);
+ if (rval) {
+ if (ops['f'])
+ sprintf(outbuf, "%d", fd);
+ zwarnnam(name, "%s: %e", ops['f'] ? outbuf : *args, errno);
+ ret = 1;
+ if (ops['f'] || arrnam)
+ break;
+ else
+ continue;
+ }
+
+ if (flags & STF_FILE)
+ if (arrnam)
+ *arrptr++ = ztrdup(*args);
+ else
+ printf("%s%s", *args, (flags & STF_PICK) ? " " : ":\n");
+ if (iwhich > -1) {
+ statprint(&statbuf, outbuf, *args, iwhich, flags);
+ if (arrnam)
+ *arrptr++ = ztrdup(outbuf);
+ else
+ printf("%s\n", outbuf);
+ } else {
+ int i;
+ for (i = 0; i < ST_COUNT; i++) {
+ statprint(&statbuf, outbuf, *args, i, flags);
+ if (arrnam)
+ *arrptr++= ztrdup(outbuf);
+ else
+ printf("%s\n", outbuf);
+ }
+ }
+ if (ops['f'])
+ break;
+
+ if (!arrnam && args[1] && !(flags & STF_PICK))
+ putchar('\n');
+ }
+
+ if (arrnam)
+ if (ret) {
+ for (aptr = array; *aptr; aptr++)
+ zsfree(*aptr);
+ zfree(array, arrsize+1);
+ } else {
+ setaparam(arrnam, array);
+ if (errflag)
+ return 1;
+ }
+
+ return ret;
+}
+
+static struct builtin bintab[] = {
+ BUILTIN("stat", 0, bin_stat, 0, -1, 0, NULL, NULL),
+};
+
+/**/
+int
+boot_stat(Module m)
+{
+ return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+}
+
+#ifdef MODULE
+
+/**/
+int
+cleanup_stat(Module m)
+{
+ deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+ return 0;
+}
+
+#endif
diff --git a/Src/Modules/stat.mdd b/Src/Modules/stat.mdd
new file mode 100644
index 000000000..b775fda09
--- /dev/null
+++ b/Src/Modules/stat.mdd
@@ -0,0 +1,3 @@
+autobins="stat"
+
+objects="stat.o"