diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Modules/files.c | 382 | ||||
-rw-r--r-- | Src/Modules/parameter.c | 22 |
2 files changed, 326 insertions, 78 deletions
diff --git a/Src/Modules/files.c b/Src/Modules/files.c index 6127c5524..388e35a55 100644 --- a/Src/Modules/files.c +++ b/Src/Modules/files.c @@ -30,6 +30,7 @@ #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,6 +38,8 @@ extern int symlink _((const char *, const char *)); extern int rename _((const char *, const char *)); #endif +struct recursivecmd; + #include "files.pro" /**/ @@ -68,6 +71,9 @@ bin_mkdir(char *nam, char **args, char *ops, int func) mode_t oumask = umask(0); mode_t mode = 0777 & ~oumask; int err = 0; +#ifdef HAVE_PATHCONF + int pathmax = 0; +#endif umask(oumask); if(ops['m']) { @@ -88,11 +94,20 @@ bin_mkdir(char *nam, char **args, char *ops, int func) while(ptr > *args + (**args == '/') && *--ptr == '/') *ptr = 0; - if(ztrlen(*args) > PATH_MAX - 1) { +#ifdef HAVE_PATHCONF + if((pathmax = pathconf(*args,_PC_PATH_MAX)) == -1) { + zwarnnam(nam, "%s: %e", *args, errno); + err = 1; + continue; + } + else if(ztrlen(*args) > pathmax - 1) { +#else + if(ztrlen(*args) > PATH_MAX - 1) { +#endif zwarnnam(nam, "%s: %e", *args, ENAMETOOLONG); err = 1; continue; - } + } if(ops['p']) { char *ptr = *args; @@ -195,18 +210,18 @@ bin_ln(char *nam, char **args, char *ops, int func) if(func == BIN_MV) { - move = rename; + move = (MoveFunc) 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; + move = (MoveFunc) symlink; else #endif { - move = link; + move = (MoveFunc) link; if(!ops['d']) flags |= MV_NODIRS; } @@ -312,20 +327,42 @@ domove(char *nam, MoveFunc move, char *p, char *q, int flags) return 0; } -/* rm builtin */ +/* 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 -bin_rm(char *nam, char **args, char *ops, int func) +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 (ops['r'] || ops['s']) { + 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,7 +370,7 @@ bin_rm(char *nam, char **args, char *ops, int func) for(; !errflag && !(err & 2) && *args; args++) { rp = ztrdup(*args); unmetafy(rp, &len); - if (ops['s']) { + if (opt_safe) { s = strrchr(rp, '/'); if (s && !s[1]) { while (*s == '/' && s > rp) @@ -353,16 +390,16 @@ bin_rm(char *nam, char **args, char *ops, int func) d.ino = d.dev = 0; d.dirname = NULL; d.dirfd = d.level = -1; - err |= dorm(nam, *args, s + 1, ops, &d, 0); + err |= recursivecmd_doone(&reccmd, *args, s + 1, &d, 0); zsfree(d.dirname); if (restoredir(&ds)) err |= 2; - } else + } else if(!opt_noerr) zwarnnam(nam, "%s: %e", *args, errno); } else - err |= dorm(nam, *args, rp, ops, &ds, 0); + err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 0); } else - err |= dorm(nam, *args, rp, ops, &ds, 1); + err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 1); zfree(rp, len + 1); } if ((err & 2) && ds.dirfd >= 0 && restoredir(&ds) && zchdir(pwd)) { @@ -373,76 +410,55 @@ bin_rm(char *nam, char **args, char *ops, int func) if (ds.dirfd >= 0) close(ds.dirfd); zsfree(ds.dirname); - return ops['f'] ? 0 : !!err; + return !!err; } /**/ static int -dorm(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first) +recursivecmd_doone(struct recursivecmd const *reccmd, + char *arg, char *rp, struct dirsav *ds, int first) { - struct stat st; + struct stat st, *sp = NULL; - 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(reccmd->opt_recurse && !lstat(rp, &st)) { + if(S_ISDIR(st.st_mode)) + return recursivecmd_dorec(reccmd, arg, rp, &st, ds, first); + sp = &st; } - if(!unlink(rp)) - return 0; - if(!ops['f']) - zwarnnam(nam, "%s: %e", arg, errno); - return 1; + return reccmd->leaf_func(arg, rp, sp, reccmd->magic); } /**/ static int -dormr(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first) +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; + 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 (!ops['f']) - zwarnnam(nam, "%s: %e", arg, errno); + 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(!ops['f']) - zwarnnam(nam, "%s: %e", arg, errno); + if(!reccmd->opt_noerr) + zwarnnam(reccmd->nam, "%s: %e", arg, errno); err = 1; } else { int arglen = strlen(arg) + 1; @@ -462,7 +478,7 @@ dormr(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first) narg[arglen-1] = '/'; strcpy(narg + arglen, fn); unmetafy(fn, NULL); - err |= dorm(nam, narg, fn, ops, &dsav, 0); + err |= recursivecmd_doone(reccmd, narg, fn, &dsav, 0); fn += l; } hrealloc(files, fileslen, 0); @@ -471,25 +487,222 @@ dormr(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first) if (err & 2) return 2; if (restoredir(ds)) { - if(!ops['f']) - zwarnnam(nam, "failed to return to previous directory: %e", + if(!reccmd->opt_noerr) + zwarnnam(reccmd->nam, "failed to return to previous directory: %e", NULL, errno); return 2; } - if(!ops['f'] && ops['i']) { - nicezputs(nam, stderr); + 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 err; + return 0; } - if(!rmdir(rp)) - return err; - if(!ops['f']) - zwarnnam(nam, "%s: %e", arg, errno); - return 1; + 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; + char *end; + + chm.nam = nam; + if(func == BIN_CHGRP) { + chm.uid = -1; + goto dogroup; + } + end = strchr(uspec, ':'); + if(!end) + end = strchr(uspec, '.'); + if(end == uspec) { + chm.uid = -1; + p++; + goto dogroup; + } else { + struct passwd *pwd; + 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 if(p[0] == ':' && !p[1]) { + chm.gid = -1; + } 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,28 +714,41 @@ dormr(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first) #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), + 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), }; /**/ int -boot_files(Module m) +setup_(Module m) { - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + return 0; } -#ifdef MODULE +/**/ +int +boot_(Module m) +{ + return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); +} /**/ int -cleanup_files(Module m) +cleanup_(Module m) { deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); return 0; } -#endif + +/**/ +int +finish_(Module m) +{ + return 0; +} diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index b8bae47ce..b19202625 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -1397,7 +1397,17 @@ scanpmjobdirs(HashTable ht, ScanFunc func, int flags) static void setpmnameddir(Param pm, char *value) { +#ifdef HAVE_PATHCONF + int pathmax = 0; + + pathmax = pathconf(value, _PC_PATH_MAX); + if (pathmax == -1) { + zwarn("%s: %e", value, errno); + } + else if (!value || *value != '/' || strlen(value) >= pathmax) +#else if (!value || *value != '/' || strlen(value) >= PATH_MAX) +#endif zwarn("invalid value: %s", value, 0); else adduserdir(pm->nam, value, 0, 1); @@ -1420,6 +1430,9 @@ setpmnameddirs(Param pm, HashTable ht) { int i; HashNode hn, next, hd; +#ifdef HAVE_PATHCONF + int pathmax = 0; +#endif if (!ht) return; @@ -1442,8 +1455,17 @@ setpmnameddirs(Param pm, HashTable ht) v.arr = NULL; v.pm = (Param) hn; +#ifdef HAVE_PATHCONF + if((pathmax = pathconf(val, _PC_PATH_MAX)) == -1) + zwarn("%s: %e", val, errno); + else +#endif if (!(val = getstrvalue(&v)) || *val != '/' || +#ifdef HAVE_PATHCONF strlen(val) >= PATH_MAX) +#else + strlen(val) >= pathmax) +#endif zwarn("invalid value: %s", val, 0); else adduserdir(hn->nam, val, 0, 1); |