diff options
Diffstat (limited to 'Src/Modules')
-rw-r--r-- | Src/Modules/.cvsignore | 10 | ||||
-rw-r--r-- | Src/Modules/.distfiles | 8 | ||||
-rw-r--r-- | Src/Modules/.exrc | 2 | ||||
-rw-r--r-- | Src/Modules/cap.c | 141 | ||||
-rw-r--r-- | Src/Modules/cap.mdd | 3 | ||||
-rw-r--r-- | Src/Modules/clone.c | 115 | ||||
-rw-r--r-- | Src/Modules/clone.mdd | 3 | ||||
-rw-r--r-- | Src/Modules/example.c | 76 | ||||
-rw-r--r-- | Src/Modules/example.mdd | 3 | ||||
-rw-r--r-- | Src/Modules/files.c | 528 | ||||
-rw-r--r-- | Src/Modules/files.mdd | 3 | ||||
-rw-r--r-- | Src/Modules/stat.c | 535 | ||||
-rw-r--r-- | Src/Modules/stat.mdd | 3 |
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" |