* PATCH: chown and chgrp in files module @ 1999-12-09 16:02 zefram 1999-12-09 17:20 ` James Kirkpatrick 0 siblings, 1 reply; 7+ messages in thread From: zefram @ 1999-12-09 16:02 UTC (permalink / raw) To: zsh-workers I got a request for chown/chgrp as shell builtins, so here they are. It's pretty simple; most of the code change is actually just factoring out the recursion code from rm, so that it can be shared with chown. As a bonus, chown gets rm's -s option. I'm not 100% happy about the error handling in the recursion code. It seems to me that if the current directory is lost, the error message and return code should not be suppressed by rm's -f option. But I've left it as it is, because I don't immediately see how to separate out that case from the other errors handled by that code. -zefram diff -cr ../zsh-/Doc/Zsh/mod_files.yo ./Doc/Zsh/mod_files.yo *** ../zsh-/Doc/Zsh/mod_files.yo Sun Nov 28 17:42:27 1999 --- ./Doc/Zsh/mod_files.yo Thu Dec 9 12:33:23 1999 *************** *** 4,9 **** --- 4,46 ---- The tt(files) module makes some standard commands available as builtins: startitem() + findex(chgrp) + item(tt(chgrp) [ tt(-Rs) ] var(group) var(filename) ...)( + Changes group of files specified. This is equivalent to tt(chown) with + a var(user-spec) argument of `tt(:)var(group)'. + ) + findex(chown) + item(tt(chown) [ tt(-Rs) ] var(user-spec) var(filename) ...)( + Changes ownership and group of files specified. + + The var(user-spec) can be in four forms: + + startsitem() + sitem(var(user))(change owner to var(user); do not change group) + sitem(var(user)tt(:))(change owner to var(user); change group to var(user)'s primary group) + sitem(var(user)tt(:)var(group))(change owner to var(user); change group to var(group)) + sitem(tt(:)var(group))(do not change owner; change group to var(group)) + endsitem() + + In each case, the `tt(:)' may instead be a `tt(.)'. + Each of var(user) and var(group) may be either a username (or group name, as + appropriate) or a decimal user ID (group ID). Interpretation as a name + takes precedence, if there is an all-numeric username (or group name). + + The tt(-R) option causes tt(chown) to recursively descend into directories, + changing the ownership of all files in the directory after + changing the ownership of the directory itself. + + The tt(-s) option is a zsh extension to tt(chown) functionality. It enables + paranoid behaviour, intended to avoid security problems involving + a tt(chown) being tricked into affecting files other than the ones + intended. It will refuse to follow symbolic links, so that (for example) + ``tt(chown luser /tmp/foo/passwd)'' can't accidentally chown tt(/etc/passwd) + if tt(/tmp/foo) happens to be a link to tt(/etc). It will also check + where it is after leaving directories, so that a recursive chown of + a deep directory tree can't end up recursively chowning tt(/usr) as + a result of directories being moved up the tree. + ) findex(ln) xitem(tt(ln) [ tt(-dfis) ] var(filename) var(dest)) item(tt(ln) [ tt(-dfis) ] var(filename) ... var(dir))( diff -cr ../zsh-/Src/Modules/files.c ./Src/Modules/files.c *** ../zsh-/Src/Modules/files.c Sun Nov 28 17:42:28 1999 --- ./Src/Modules/files.c Thu Dec 9 15:43:52 1999 *************** *** 30,35 **** --- 30,36 ---- #include "files.mdh" typedef int (*MoveFunc) _((char const *, char const *)); + typedef int (*RecurseFunc) _((char *, char *, struct stat const *, void *)); #ifndef STDC_HEADERS extern int link _((const char *, const char *)); *************** *** 37,42 **** --- 38,45 ---- extern int rename _((const char *, const char *)); #endif + struct recursivecmd; + #include "files.pro" /**/ *************** *** 312,331 **** 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); --- 315,356 ---- return 0; } ! /* general recursion */ ! ! struct recursivecmd { ! char *nam; ! int opt_noerr; ! int opt_recurse; ! int opt_safe; ! RecurseFunc dirpre_func; ! RecurseFunc dirpost_func; ! RecurseFunc leaf_func; ! void *magic; ! }; /**/ static int ! recursivecmd(char *nam, int opt_noerr, int opt_recurse, int opt_safe, ! char **args, RecurseFunc dirpre_func, RecurseFunc dirpost_func, ! RecurseFunc leaf_func, void *magic) { int err = 0, len; char *rp, *s; struct dirsav ds; + struct recursivecmd reccmd; + reccmd.nam = nam; + reccmd.opt_noerr = opt_noerr; + reccmd.opt_recurse = opt_recurse; + reccmd.opt_safe = opt_safe; + reccmd.dirpre_func = dirpre_func; + reccmd.dirpost_func = dirpost_func; + reccmd.leaf_func = leaf_func; + reccmd.magic = magic; ds.ino = ds.dev = 0; ds.dirname = NULL; ds.dirfd = ds.level = -1; ! if (opt_recurse || opt_safe) { if ((ds.dirfd = open(".", O_RDONLY|O_NOCTTY)) < 0 && zgetdir(&ds) && *ds.dirname != '/') ds.dirfd = open("..", O_RDONLY|O_NOCTTY); *************** *** 333,339 **** 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) --- 358,364 ---- for(; !errflag && !(err & 2) && *args; args++) { rp = ztrdup(*args); unmetafy(rp, &len); ! if (opt_safe) { s = strrchr(rp, '/'); if (s && !s[1]) { while (*s == '/' && s > rp) *************** *** 353,368 **** 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)) { --- 378,393 ---- d.ino = d.dev = 0; d.dirname = NULL; d.dirfd = d.level = -1; ! err |= recursivecmd_doone(&reccmd, *args, s + 1, &d, 0); zsfree(d.dirname); if (restoredir(&ds)) err |= 2; ! } else if(!opt_noerr) zwarnnam(nam, "%s: %e", *args, errno); } else ! err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 0); } else ! err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 1); zfree(rp, len + 1); } if ((err & 2) && ds.dirfd >= 0 && restoredir(&ds) && zchdir(pwd)) { *************** *** 373,448 **** 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; --- 398,452 ---- if (ds.dirfd >= 0) close(ds.dirfd); zsfree(ds.dirname); ! return !!err; } /**/ static int ! recursivecmd_doone(struct recursivecmd const *reccmd, ! char *arg, char *rp, struct dirsav *ds, int first) { ! struct stat st, *sp = NULL; ! if(reccmd->opt_recurse && !lstat(rp, &st)) { ! if(S_ISDIR(st.st_mode)) ! return recursivecmd_dorec(reccmd, arg, rp, &st, ds, first); ! sp = &st; } ! return reccmd->leaf_func(arg, rp, sp, reccmd->magic); } /**/ static int ! recursivecmd_dorec(struct recursivecmd const *reccmd, ! char *arg, char *rp, struct stat const *sp, struct dirsav *ds, int first) { char *fn; DIR *d; ! int err, err1; struct dirsav dsav; char *files = NULL; int fileslen = 0; + err1 = reccmd->dirpre_func(arg, rp, sp, reccmd->magic); + if(err1 & 2) + return 2; + err = -lchdir(rp, ds, !first); if (err) { ! if(!reccmd->opt_noerr) ! zwarnnam(reccmd->nam, "%s: %e", arg, errno); return err; } + err = err1; dsav.ino = dsav.dev = 0; dsav.dirname = NULL; dsav.dirfd = dsav.level = -1; d = opendir("."); if(!d) { ! if(!reccmd->opt_noerr) ! zwarnnam(reccmd->nam, "%s: %e", arg, errno); err = 1; } else { int arglen = strlen(arg) + 1; *************** *** 462,468 **** narg[arglen-1] = '/'; strcpy(narg + arglen, fn); unmetafy(fn, NULL); ! err |= dorm(nam, narg, fn, ops, &dsav, 0); fn += l; } hrealloc(files, fileslen, 0); --- 466,472 ---- narg[arglen-1] = '/'; strcpy(narg + arglen, fn); unmetafy(fn, NULL); ! err |= recursivecmd_doone(reccmd, narg, fn, &dsav, 0); fn += l; } hrealloc(files, fileslen, 0); *************** *** 471,495 **** 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 */ --- 475,693 ---- if (err & 2) return 2; if (restoredir(ds)) { ! if(!reccmd->opt_noerr) ! zwarnnam(reccmd->nam, "failed to return to previous directory: %e", NULL, errno); return 2; } ! return err | reccmd->dirpost_func(arg, rp, sp, reccmd->magic); ! } ! ! /**/ ! static int ! recurse_donothing(char *arg, char *rp, struct stat const *sp, void *magic) ! { ! return 0; ! } ! ! /* rm builtin */ ! ! struct rmmagic { ! char *nam; ! int opt_force; ! int opt_interact; ! int opt_unlinkdir; ! }; ! ! /**/ ! static int ! rm_leaf(char *arg, char *rp, struct stat const *sp, void *magic) ! { ! struct rmmagic *rmm = magic; ! struct stat st; ! ! if(!rmm->opt_unlinkdir || !rmm->opt_force) { ! if(!sp) { ! if(!lstat(rp, &st)) ! sp = &st; ! } ! if(sp) { ! if(!rmm->opt_unlinkdir && S_ISDIR(sp->st_mode)) { ! if(rmm->opt_force) ! return 0; ! zwarnnam(rmm->nam, "%s: %e", arg, EISDIR); ! return 1; ! } ! if(rmm->opt_interact) { ! nicezputs(rmm->nam, stderr); ! fputs(": remove `", stderr); ! nicezputs(arg, stderr); ! fputs("'? ", stderr); ! fflush(stderr); ! if(!ask()) ! return 0; ! } else if(!rmm->opt_force && ! !S_ISLNK(sp->st_mode) && ! access(rp, W_OK)) { ! nicezputs(rmm->nam, stderr); ! fputs(": remove `", stderr); ! nicezputs(arg, stderr); ! fprintf(stderr, "', overriding mode %04o? ", ! mode_to_octal(sp->st_mode)); ! fflush(stderr); ! if(!ask()) ! return 0; ! } ! } ! } ! if(unlink(rp) && !rmm->opt_force) { ! zwarnnam(rmm->nam, "%s: %e", arg, errno); ! return 1; ! } ! return 0; ! } ! ! /**/ ! static int ! rm_dirpost(char *arg, char *rp, struct stat const *sp, void *magic) ! { ! struct rmmagic *rmm = magic; ! ! if(rmm->opt_interact) { ! nicezputs(rmm->nam, stderr); fputs(": remove `", stderr); nicezputs(arg, stderr); fputs("'? ", stderr); fflush(stderr); if(!ask()) ! return 0; } ! if(rmdir(rp) && !rmm->opt_force) { ! zwarnnam(rmm->nam, "%s: %e", arg, errno); ! return 1; ! } ! return 0; ! } ! ! /**/ ! static int ! bin_rm(char *nam, char **args, char *ops, int func) ! { ! struct rmmagic rmm; ! int err; ! ! rmm.nam = nam; ! rmm.opt_force = ops['f']; ! rmm.opt_interact = ops['i'] && !ops['f']; ! rmm.opt_unlinkdir = ops['d']; ! err = recursivecmd(nam, ops['f'], ops['r'] && !ops['d'], ops['s'], ! args, recurse_donothing, rm_dirpost, rm_leaf, &rmm); ! return ops['f'] ? 0 : err; ! } ! ! /* chown builtin */ ! ! struct chownmagic { ! char *nam; ! uid_t uid; ! gid_t gid; ! }; ! ! /**/ ! static int ! chown_dochown(char *arg, char *rp, struct stat const *sp, void *magic) ! { ! struct chownmagic *chm = magic; ! ! if(lchown(rp, chm->uid, chm->gid)) { ! zwarnnam(chm->nam, "%s: %e", arg, errno); ! return 1; ! } ! return 0; ! } ! ! /**/ ! static unsigned long getnumeric(char *p, int *errp) ! { ! unsigned long ret; ! ! if(*p < '0' || *p > '9') { ! *errp = 1; ! return 0; ! } ! ret = strtoul(p, &p, 10); ! *errp = !!*p; ! return ret; ! } ! ! enum { BIN_CHOWN, BIN_CHGRP }; ! ! /**/ ! static int ! bin_chown(char *nam, char **args, char *ops, int func) ! { ! struct chownmagic chm; ! char *uspec = ztrdup(*args), *p = uspec; ! ! chm.nam = nam; ! if(func == BIN_CHGRP) { ! chm.uid = -1; ! goto dogroup; ! } ! if(*p == ':' || *p == '.') { ! chm.uid = -1; ! p++; ! goto dogroup; ! } else { ! struct passwd *pwd; ! char *end = strchr(p, ':'); ! if(!end) ! end = strchr(p, '.'); ! if(end) ! *end = 0; ! pwd = getpwnam(p); ! if(pwd) ! chm.uid = pwd->pw_uid; ! else { ! int err; ! chm.uid = getnumeric(p, &err); ! if(err) { ! zwarnnam(nam, "%s: no such user", p, 0); ! free(uspec); ! return 1; ! } ! } ! if(end) { ! p = end+1; ! if(!*p) { ! if(!pwd && !(pwd = getpwuid(chm.uid))) { ! zwarnnam(nam, "%s: no such user", uspec, 0); ! free(uspec); ! return 1; ! } ! chm.gid = pwd->pw_gid; ! } else { ! struct group *grp; ! dogroup: ! grp = getgrnam(p); ! if(grp) ! chm.gid = grp->gr_gid; ! else { ! int err; ! chm.gid = getnumeric(p, &err); ! if(err) { ! zwarnnam(nam, "%s: no such group", p, 0); ! free(uspec); ! return 1; ! } ! } ! } ! } else ! chm.gid = -1; ! } ! free(uspec); ! return recursivecmd(nam, 0, ops['R'], ops['s'], ! args + 1, chown_dochown, recurse_donothing, chown_dochown, &chm); } /* module paraphernalia */ *************** *** 501,512 **** #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), }; /**/ --- 699,712 ---- #endif static struct builtin bintab[] = { ! BUILTIN("chgrp", 0, bin_chown, 2, -1, BIN_CHGRP, "Rs", NULL), ! BUILTIN("chown", 0, bin_chown, 2, -1, BIN_CHOWN, "Rs", NULL), ! 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), }; /**/ diff -cr ../zsh-/Src/Modules/files.mdd ./Src/Modules/files.mdd *** ../zsh-/Src/Modules/files.mdd Sun Nov 28 17:42:28 1999 --- ./Src/Modules/files.mdd Thu Dec 9 12:33:44 1999 *************** *** 1,3 **** ! autobins="ln mkdir mv rm rmdir sync" objects="files.o" --- 1,3 ---- ! autobins="chgrp chown ln mkdir mv rm rmdir sync" objects="files.o" diff -cr ../zsh-/Src/system.h ./Src/system.h *** ../zsh-/Src/system.h Sun Nov 28 17:42:28 1999 --- ./Src/system.h Thu Dec 9 15:19:03 1999 *************** *** 583,588 **** --- 583,592 ---- # define R_OK 4 #endif + #ifndef HAVE_LCHOWN + # define lchown chown + #endif + #ifndef HAVE_MEMCPY # define memcpy memmove #endif diff -cr ../zsh-/configure.in ./configure.in *** ../zsh-/configure.in Wed Dec 8 19:58:26 1999 --- ./configure.in Thu Dec 9 15:18:05 1999 *************** *** 784,790 **** dnl need to integrate this function dnl AC_FUNC_STRFTIME ! AC_CHECK_FUNCS(memcpy memmove \ strftime waitpid select poll tcsetpgrp tcgetattr strstr lstat \ getlogin setpgid gettimeofday gethostname mkfifo wait3 difftime \ sigblock sigsetmask sigrelse sighold killpg sigaction getrlimit \ --- 784,790 ---- dnl need to integrate this function dnl AC_FUNC_STRFTIME ! AC_CHECK_FUNCS(lchown memcpy memmove \ strftime waitpid select poll tcsetpgrp tcgetattr strstr lstat \ getlogin setpgid gettimeofday gethostname mkfifo wait3 difftime \ sigblock sigsetmask sigrelse sighold killpg sigaction getrlimit \ END ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: PATCH: chown and chgrp in files module 1999-12-09 16:02 PATCH: chown and chgrp in files module zefram @ 1999-12-09 17:20 ` James Kirkpatrick 1999-12-09 17:41 ` Zefram 0 siblings, 1 reply; 7+ messages in thread From: James Kirkpatrick @ 1999-12-09 17:20 UTC (permalink / raw) To: zefram; +Cc: zsh-workers I'm not sure I understand. chown and chgrp are now builtins? I need to object to this. We use, for example, the GNU shell utilities, and rely on certain of the options and syntaxes available. Will the zsh builtins attempt to emulate all options from everybody's chown and chgrp? Are they POSIX compliant? This does not seem to be the sort of thing that should be built in to a shell, any more than rm, ls, find, or a C compiler :-) Jim On Thu, 9 Dec 1999 zefram@fysh.org wrote: > I got a request for chown/chgrp as shell builtins, so here they are. > It's pretty simple; most of the code change is actually just factoring > out the recursion code from rm, so that it can be shared with chown. > As a bonus, chown gets rm's -s option. > > I'm not 100% happy about the error handling in the recursion code. > It seems to me that if the current directory is lost, the error message > and return code should not be suppressed by rm's -f option. But I've > left it as it is, because I don't immediately see how to separate out > that case from the other errors handled by that code. > > -zefram > > diff -cr ../zsh-/Doc/Zsh/mod_files.yo ./Doc/Zsh/mod_files.yo > *** ../zsh-/Doc/Zsh/mod_files.yo Sun Nov 28 17:42:27 1999 > --- ./Doc/Zsh/mod_files.yo Thu Dec 9 12:33:23 1999 > *************** > *** 4,9 **** > --- 4,46 ---- > The tt(files) module makes some standard commands available as builtins: > > startitem() > + findex(chgrp) > + item(tt(chgrp) [ tt(-Rs) ] var(group) var(filename) ...)( > + Changes group of files specified. This is equivalent to tt(chown) with > + a var(user-spec) argument of `tt(:)var(group)'. > + ) > + findex(chown) > + item(tt(chown) [ tt(-Rs) ] var(user-spec) var(filename) ...)( > + Changes ownership and group of files specified. > + > + The var(user-spec) can be in four forms: > + > + startsitem() > + sitem(var(user))(change owner to var(user); do not change group) > + sitem(var(user)tt(:))(change owner to var(user); change group to var(user)'s primary group) > + sitem(var(user)tt(:)var(group))(change owner to var(user); change group to var(group)) > + sitem(tt(:)var(group))(do not change owner; change group to var(group)) > + endsitem() > + > + In each case, the `tt(:)' may instead be a `tt(.)'. > + Each of var(user) and var(group) may be either a username (or group name, as > + appropriate) or a decimal user ID (group ID). Interpretation as a name > + takes precedence, if there is an all-numeric username (or group name). > + > + The tt(-R) option causes tt(chown) to recursively descend into directories, > + changing the ownership of all files in the directory after > + changing the ownership of the directory itself. > + > + The tt(-s) option is a zsh extension to tt(chown) functionality. It enables > + paranoid behaviour, intended to avoid security problems involving > + a tt(chown) being tricked into affecting files other than the ones > + intended. It will refuse to follow symbolic links, so that (for example) > + ``tt(chown luser /tmp/foo/passwd)'' can't accidentally chown tt(/etc/passwd) > + if tt(/tmp/foo) happens to be a link to tt(/etc). It will also check > + where it is after leaving directories, so that a recursive chown of > + a deep directory tree can't end up recursively chowning tt(/usr) as > + a result of directories being moved up the tree. > + ) > findex(ln) > xitem(tt(ln) [ tt(-dfis) ] var(filename) var(dest)) > item(tt(ln) [ tt(-dfis) ] var(filename) ... var(dir))( > diff -cr ../zsh-/Src/Modules/files.c ./Src/Modules/files.c > *** ../zsh-/Src/Modules/files.c Sun Nov 28 17:42:28 1999 > --- ./Src/Modules/files.c Thu Dec 9 15:43:52 1999 > *************** > *** 30,35 **** > --- 30,36 ---- > #include "files.mdh" > > typedef int (*MoveFunc) _((char const *, char const *)); > + typedef int (*RecurseFunc) _((char *, char *, struct stat const *, void *)); > > #ifndef STDC_HEADERS > extern int link _((const char *, const char *)); > *************** > *** 37,42 **** > --- 38,45 ---- > extern int rename _((const char *, const char *)); > #endif > > + struct recursivecmd; > + > #include "files.pro" > > /**/ > *************** > *** 312,331 **** > 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); > --- 315,356 ---- > return 0; > } > > ! /* general recursion */ > ! > ! struct recursivecmd { > ! char *nam; > ! int opt_noerr; > ! int opt_recurse; > ! int opt_safe; > ! RecurseFunc dirpre_func; > ! RecurseFunc dirpost_func; > ! RecurseFunc leaf_func; > ! void *magic; > ! }; > > /**/ > static int > ! recursivecmd(char *nam, int opt_noerr, int opt_recurse, int opt_safe, > ! char **args, RecurseFunc dirpre_func, RecurseFunc dirpost_func, > ! RecurseFunc leaf_func, void *magic) > { > int err = 0, len; > char *rp, *s; > struct dirsav ds; > + struct recursivecmd reccmd; > > + reccmd.nam = nam; > + reccmd.opt_noerr = opt_noerr; > + reccmd.opt_recurse = opt_recurse; > + reccmd.opt_safe = opt_safe; > + reccmd.dirpre_func = dirpre_func; > + reccmd.dirpost_func = dirpost_func; > + reccmd.leaf_func = leaf_func; > + reccmd.magic = magic; > ds.ino = ds.dev = 0; > ds.dirname = NULL; > ds.dirfd = ds.level = -1; > ! if (opt_recurse || opt_safe) { > if ((ds.dirfd = open(".", O_RDONLY|O_NOCTTY)) < 0 && > zgetdir(&ds) && *ds.dirname != '/') > ds.dirfd = open("..", O_RDONLY|O_NOCTTY); > *************** > *** 333,339 **** > 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) > --- 358,364 ---- > for(; !errflag && !(err & 2) && *args; args++) { > rp = ztrdup(*args); > unmetafy(rp, &len); > ! if (opt_safe) { > s = strrchr(rp, '/'); > if (s && !s[1]) { > while (*s == '/' && s > rp) > *************** > *** 353,368 **** > 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)) { > --- 378,393 ---- > d.ino = d.dev = 0; > d.dirname = NULL; > d.dirfd = d.level = -1; > ! err |= recursivecmd_doone(&reccmd, *args, s + 1, &d, 0); > zsfree(d.dirname); > if (restoredir(&ds)) > err |= 2; > ! } else if(!opt_noerr) > zwarnnam(nam, "%s: %e", *args, errno); > } else > ! err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 0); > } else > ! err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 1); > zfree(rp, len + 1); > } > if ((err & 2) && ds.dirfd >= 0 && restoredir(&ds) && zchdir(pwd)) { > *************** > *** 373,448 **** > 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; > --- 398,452 ---- > if (ds.dirfd >= 0) > close(ds.dirfd); > zsfree(ds.dirname); > ! return !!err; > } > > /**/ > static int > ! recursivecmd_doone(struct recursivecmd const *reccmd, > ! char *arg, char *rp, struct dirsav *ds, int first) > { > ! struct stat st, *sp = NULL; > > ! if(reccmd->opt_recurse && !lstat(rp, &st)) { > ! if(S_ISDIR(st.st_mode)) > ! return recursivecmd_dorec(reccmd, arg, rp, &st, ds, first); > ! sp = &st; > } > ! return reccmd->leaf_func(arg, rp, sp, reccmd->magic); > } > > /**/ > static int > ! recursivecmd_dorec(struct recursivecmd const *reccmd, > ! char *arg, char *rp, struct stat const *sp, struct dirsav *ds, int first) > { > char *fn; > DIR *d; > ! int err, err1; > struct dirsav dsav; > char *files = NULL; > int fileslen = 0; > > + err1 = reccmd->dirpre_func(arg, rp, sp, reccmd->magic); > + if(err1 & 2) > + return 2; > + > err = -lchdir(rp, ds, !first); > if (err) { > ! if(!reccmd->opt_noerr) > ! zwarnnam(reccmd->nam, "%s: %e", arg, errno); > return err; > } > + err = err1; > > dsav.ino = dsav.dev = 0; > dsav.dirname = NULL; > dsav.dirfd = dsav.level = -1; > d = opendir("."); > if(!d) { > ! if(!reccmd->opt_noerr) > ! zwarnnam(reccmd->nam, "%s: %e", arg, errno); > err = 1; > } else { > int arglen = strlen(arg) + 1; > *************** > *** 462,468 **** > narg[arglen-1] = '/'; > strcpy(narg + arglen, fn); > unmetafy(fn, NULL); > ! err |= dorm(nam, narg, fn, ops, &dsav, 0); > fn += l; > } > hrealloc(files, fileslen, 0); > --- 466,472 ---- > narg[arglen-1] = '/'; > strcpy(narg + arglen, fn); > unmetafy(fn, NULL); > ! err |= recursivecmd_doone(reccmd, narg, fn, &dsav, 0); > fn += l; > } > hrealloc(files, fileslen, 0); > *************** > *** 471,495 **** > 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 */ > --- 475,693 ---- > if (err & 2) > return 2; > if (restoredir(ds)) { > ! if(!reccmd->opt_noerr) > ! zwarnnam(reccmd->nam, "failed to return to previous directory: %e", > NULL, errno); > return 2; > } > ! return err | reccmd->dirpost_func(arg, rp, sp, reccmd->magic); > ! } > ! > ! /**/ > ! static int > ! recurse_donothing(char *arg, char *rp, struct stat const *sp, void *magic) > ! { > ! return 0; > ! } > ! > ! /* rm builtin */ > ! > ! struct rmmagic { > ! char *nam; > ! int opt_force; > ! int opt_interact; > ! int opt_unlinkdir; > ! }; > ! > ! /**/ > ! static int > ! rm_leaf(char *arg, char *rp, struct stat const *sp, void *magic) > ! { > ! struct rmmagic *rmm = magic; > ! struct stat st; > ! > ! if(!rmm->opt_unlinkdir || !rmm->opt_force) { > ! if(!sp) { > ! if(!lstat(rp, &st)) > ! sp = &st; > ! } > ! if(sp) { > ! if(!rmm->opt_unlinkdir && S_ISDIR(sp->st_mode)) { > ! if(rmm->opt_force) > ! return 0; > ! zwarnnam(rmm->nam, "%s: %e", arg, EISDIR); > ! return 1; > ! } > ! if(rmm->opt_interact) { > ! nicezputs(rmm->nam, stderr); > ! fputs(": remove `", stderr); > ! nicezputs(arg, stderr); > ! fputs("'? ", stderr); > ! fflush(stderr); > ! if(!ask()) > ! return 0; > ! } else if(!rmm->opt_force && > ! !S_ISLNK(sp->st_mode) && > ! access(rp, W_OK)) { > ! nicezputs(rmm->nam, stderr); > ! fputs(": remove `", stderr); > ! nicezputs(arg, stderr); > ! fprintf(stderr, "', overriding mode %04o? ", > ! mode_to_octal(sp->st_mode)); > ! fflush(stderr); > ! if(!ask()) > ! return 0; > ! } > ! } > ! } > ! if(unlink(rp) && !rmm->opt_force) { > ! zwarnnam(rmm->nam, "%s: %e", arg, errno); > ! return 1; > ! } > ! return 0; > ! } > ! > ! /**/ > ! static int > ! rm_dirpost(char *arg, char *rp, struct stat const *sp, void *magic) > ! { > ! struct rmmagic *rmm = magic; > ! > ! if(rmm->opt_interact) { > ! nicezputs(rmm->nam, stderr); > fputs(": remove `", stderr); > nicezputs(arg, stderr); > fputs("'? ", stderr); > fflush(stderr); > if(!ask()) > ! return 0; > } > ! if(rmdir(rp) && !rmm->opt_force) { > ! zwarnnam(rmm->nam, "%s: %e", arg, errno); > ! return 1; > ! } > ! return 0; > ! } > ! > ! /**/ > ! static int > ! bin_rm(char *nam, char **args, char *ops, int func) > ! { > ! struct rmmagic rmm; > ! int err; > ! > ! rmm.nam = nam; > ! rmm.opt_force = ops['f']; > ! rmm.opt_interact = ops['i'] && !ops['f']; > ! rmm.opt_unlinkdir = ops['d']; > ! err = recursivecmd(nam, ops['f'], ops['r'] && !ops['d'], ops['s'], > ! args, recurse_donothing, rm_dirpost, rm_leaf, &rmm); > ! return ops['f'] ? 0 : err; > ! } > ! > ! /* chown builtin */ > ! > ! struct chownmagic { > ! char *nam; > ! uid_t uid; > ! gid_t gid; > ! }; > ! > ! /**/ > ! static int > ! chown_dochown(char *arg, char *rp, struct stat const *sp, void *magic) > ! { > ! struct chownmagic *chm = magic; > ! > ! if(lchown(rp, chm->uid, chm->gid)) { > ! zwarnnam(chm->nam, "%s: %e", arg, errno); > ! return 1; > ! } > ! return 0; > ! } > ! > ! /**/ > ! static unsigned long getnumeric(char *p, int *errp) > ! { > ! unsigned long ret; > ! > ! if(*p < '0' || *p > '9') { > ! *errp = 1; > ! return 0; > ! } > ! ret = strtoul(p, &p, 10); > ! *errp = !!*p; > ! return ret; > ! } > ! > ! enum { BIN_CHOWN, BIN_CHGRP }; > ! > ! /**/ > ! static int > ! bin_chown(char *nam, char **args, char *ops, int func) > ! { > ! struct chownmagic chm; > ! char *uspec = ztrdup(*args), *p = uspec; > ! > ! chm.nam = nam; > ! if(func == BIN_CHGRP) { > ! chm.uid = -1; > ! goto dogroup; > ! } > ! if(*p == ':' || *p == '.') { > ! chm.uid = -1; > ! p++; > ! goto dogroup; > ! } else { > ! struct passwd *pwd; > ! char *end = strchr(p, ':'); > ! if(!end) > ! end = strchr(p, '.'); > ! if(end) > ! *end = 0; > ! pwd = getpwnam(p); > ! if(pwd) > ! chm.uid = pwd->pw_uid; > ! else { > ! int err; > ! chm.uid = getnumeric(p, &err); > ! if(err) { > ! zwarnnam(nam, "%s: no such user", p, 0); > ! free(uspec); > ! return 1; > ! } > ! } > ! if(end) { > ! p = end+1; > ! if(!*p) { > ! if(!pwd && !(pwd = getpwuid(chm.uid))) { > ! zwarnnam(nam, "%s: no such user", uspec, 0); > ! free(uspec); > ! return 1; > ! } > ! chm.gid = pwd->pw_gid; > ! } else { > ! struct group *grp; > ! dogroup: > ! grp = getgrnam(p); > ! if(grp) > ! chm.gid = grp->gr_gid; > ! else { > ! int err; > ! chm.gid = getnumeric(p, &err); > ! if(err) { > ! zwarnnam(nam, "%s: no such group", p, 0); > ! free(uspec); > ! return 1; > ! } > ! } > ! } > ! } else > ! chm.gid = -1; > ! } > ! free(uspec); > ! return recursivecmd(nam, 0, ops['R'], ops['s'], > ! args + 1, chown_dochown, recurse_donothing, chown_dochown, &chm); > } > > /* module paraphernalia */ > *************** > *** 501,512 **** > #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), > }; > > /**/ > --- 699,712 ---- > #endif > > static struct builtin bintab[] = { > ! BUILTIN("chgrp", 0, bin_chown, 2, -1, BIN_CHGRP, "Rs", NULL), > ! BUILTIN("chown", 0, bin_chown, 2, -1, BIN_CHOWN, "Rs", NULL), > ! 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), > }; > > /**/ > diff -cr ../zsh-/Src/Modules/files.mdd ./Src/Modules/files.mdd > *** ../zsh-/Src/Modules/files.mdd Sun Nov 28 17:42:28 1999 > --- ./Src/Modules/files.mdd Thu Dec 9 12:33:44 1999 > *************** > *** 1,3 **** > ! autobins="ln mkdir mv rm rmdir sync" > > objects="files.o" > --- 1,3 ---- > ! autobins="chgrp chown ln mkdir mv rm rmdir sync" > > objects="files.o" > diff -cr ../zsh-/Src/system.h ./Src/system.h > *** ../zsh-/Src/system.h Sun Nov 28 17:42:28 1999 > --- ./Src/system.h Thu Dec 9 15:19:03 1999 > *************** > *** 583,588 **** > --- 583,592 ---- > # define R_OK 4 > #endif > > + #ifndef HAVE_LCHOWN > + # define lchown chown > + #endif > + > #ifndef HAVE_MEMCPY > # define memcpy memmove > #endif > diff -cr ../zsh-/configure.in ./configure.in > *** ../zsh-/configure.in Wed Dec 8 19:58:26 1999 > --- ./configure.in Thu Dec 9 15:18:05 1999 > *************** > *** 784,790 **** > dnl need to integrate this function > dnl AC_FUNC_STRFTIME > > ! AC_CHECK_FUNCS(memcpy memmove \ > strftime waitpid select poll tcsetpgrp tcgetattr strstr lstat \ > getlogin setpgid gettimeofday gethostname mkfifo wait3 difftime \ > sigblock sigsetmask sigrelse sighold killpg sigaction getrlimit \ > --- 784,790 ---- > dnl need to integrate this function > dnl AC_FUNC_STRFTIME > > ! AC_CHECK_FUNCS(lchown memcpy memmove \ > strftime waitpid select poll tcsetpgrp tcgetattr strstr lstat \ > getlogin setpgid gettimeofday gethostname mkfifo wait3 difftime \ > sigblock sigsetmask sigrelse sighold killpg sigaction getrlimit \ > END > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: PATCH: chown and chgrp in files module 1999-12-09 17:20 ` James Kirkpatrick @ 1999-12-09 17:41 ` Zefram 1999-12-09 18:19 ` James Kirkpatrick ` (2 more replies) 0 siblings, 3 replies; 7+ messages in thread From: Zefram @ 1999-12-09 17:41 UTC (permalink / raw) To: James Kirkpatrick; +Cc: zefram, zsh-workers James Kirkpatrick wrote: >I'm not sure I understand. chown and chgrp are now builtins? If you load the files module. If you do nothing, you get the usual external programs. rm, mv, ln, mkdir, rmdir and sync are already available as builtins in exactly the same way. > Are they >POSIX compliant? Almost. chown accepts "." to separate username and group, in addition to the POSIX ":". This is the same level of POSIX conformance as GNU chown. >This does not seem to be the sort of thing that should be built in to a >shell, any more than rm, ls, find, or a C compiler :-) It's very useful to have these things built into a statically-linked system administration shell. (That's where the request for a builtin chown originated.) In addition to the utilities I listed above, we have a `stat' module that effectively makes possible a full implementation of ls as a shell function, and zsh globbing with glob qualifiers very nearly makes find redundant. -zefram ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: PATCH: chown and chgrp in files module 1999-12-09 17:41 ` Zefram @ 1999-12-09 18:19 ` James Kirkpatrick 1999-12-09 23:40 ` James Antill 1999-12-10 21:43 ` Clint Adams 2 siblings, 0 replies; 7+ messages in thread From: James Kirkpatrick @ 1999-12-09 18:19 UTC (permalink / raw) To: Zefram; +Cc: zsh-workers OK, I understand. "Conditionally builtin" :-) Jim On Thu, 9 Dec 1999, Zefram wrote: > James Kirkpatrick wrote: > >I'm not sure I understand. chown and chgrp are now builtins? > > If you load the files module. If you do nothing, you get the usual > external programs. rm, mv, ln, mkdir, rmdir and sync are already > available as builtins in exactly the same way. > > > Are they > >POSIX compliant? > > Almost. chown accepts "." to separate username and group, in addition to > the POSIX ":". This is the same level of POSIX conformance as GNU chown. > > >This does not seem to be the sort of thing that should be built in to a > >shell, any more than rm, ls, find, or a C compiler :-) > > It's very useful to have these things built into a statically-linked > system administration shell. (That's where the request for a builtin > chown originated.) In addition to the utilities I listed above, we have > a `stat' module that effectively makes possible a full implementation > of ls as a shell function, and zsh globbing with glob qualifiers very > nearly makes find redundant. > > -zefram ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: PATCH: chown and chgrp in files module 1999-12-09 17:41 ` Zefram 1999-12-09 18:19 ` James Kirkpatrick @ 1999-12-09 23:40 ` James Antill 1999-12-13 12:10 ` Zefram 1999-12-10 21:43 ` Clint Adams 2 siblings, 1 reply; 7+ messages in thread From: James Antill @ 1999-12-09 23:40 UTC (permalink / raw) To: Zefram; +Cc: James Kirkpatrick, zsh-workers Zefram <zefram@fysh.org> writes: > James Kirkpatrick wrote: > > >This does not seem to be the sort of thing that should be built in to a > >shell, any more than rm, ls, find, or a C compiler :-) > > It's very useful to have these things built into a statically-linked > system administration shell. (That's where the request for a builtin > chown originated.) In addition to the utilities I listed above, we have > a `stat' module that effectively makes possible a full implementation > of ls as a shell function, and zsh globbing with glob qualifiers very > nearly makes find redundant. Which begs the question, who's working on the C compiler ?:) ObZsh: Would it be possible to have a statically linked sys-admin shell built as part of the build process. Then you could literally just have it[1] on a floppy and boot Linux with init=/bin/zsh_admin. [1] Ignoreing the kernel and a _very_ small root fs (ok I guess you probably want vi and fsck too ... but not much more). -- James Antill -- james@and.org I am always an optimist, but frankly there is no hope. -Hosni Mubarek ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: PATCH: chown and chgrp in files module 1999-12-09 23:40 ` James Antill @ 1999-12-13 12:10 ` Zefram 0 siblings, 0 replies; 7+ messages in thread From: Zefram @ 1999-12-13 12:10 UTC (permalink / raw) To: james; +Cc: zefram, jimkirk, zsh-workers James Antill wrote: > Which begs the question, who's working on the C compiler ?:) Actually, the friend that asked for builtin chown started off asking for tar as a builtin (the aim being to restore the system from tape backup using only the running root shell). Once I pointed at zftp he conceded that zftp plus builtins for ln, chown and chmod (next thing for me to do) would be sufficient. Actually, I think we need mknod too. mount and umount wouldn't be a bad idea, although somewhat system-dependent. And halt and reboot would be nice... hmm, maybe we need an admintools module. Anyway, the thing about tar got me thinking, maybe GNU tar could be modified so that it can be compiled as a zsh module. Certain other tools may be worth modifying this way too. Not gcc, I think. I remember one of the other free shells -- I think it was ash -- had a way of doing its builtins so that they could also be compiled as standalone programs. With such a well-defined interface, we could probably produce some automated way to compile a group of ash builtins as a zsh module. >ObZsh: Would it be possible to have a statically linked sys-admin >shell built as part of the build process. Then you could literally >just have it[1] on a floppy and boot Linux with init=/bin/zsh_admin. You can do that manually already. Set LDFLAGS for static linking when you configure, and edit Src/xmods.conf to list all (and only) the modules that you want to link in. You shouldn't need to do --disable-dynamic; module loading won't work with static linking anyway, and configure will detect that. Another thing I'd like to do is to make that easier: a configure switch to change LDFLAGS to do static linking, and another switch to control which modules get linked in and which get autoloaded. Then one could build an admin zsh from a script just as readily as one can build the normal zsh. Come to think of it, a shorthand configure switch --enable-admin-config to do all of that would be a good idea. -zefram ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: PATCH: chown and chgrp in files module 1999-12-09 17:41 ` Zefram 1999-12-09 18:19 ` James Kirkpatrick 1999-12-09 23:40 ` James Antill @ 1999-12-10 21:43 ` Clint Adams 2 siblings, 0 replies; 7+ messages in thread From: Clint Adams @ 1999-12-10 21:43 UTC (permalink / raw) To: Zefram; +Cc: James Kirkpatrick, zsh-workers > Almost. chown accepts "." to separate username and group, in addition to > the POSIX ":". This is the same level of POSIX conformance as GNU chown. Which is unlike any other chown on the planet. GNU chown would be a lot more tolerable if it supported some sort of override to allow usernames containing periods; such as '--ignore-group' or '::' ideas which have been suggested elsewhere. ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~1999-12-13 12:10 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 1999-12-09 16:02 PATCH: chown and chgrp in files module zefram 1999-12-09 17:20 ` James Kirkpatrick 1999-12-09 17:41 ` Zefram 1999-12-09 18:19 ` James Kirkpatrick 1999-12-09 23:40 ` James Antill 1999-12-13 12:10 ` Zefram 1999-12-10 21:43 ` Clint Adams
Code repositories for project(s) associated with this public inbox https://git.vuxu.org/mirror/zsh/ This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).