summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/Modules/files.c382
-rw-r--r--Src/Modules/parameter.c22
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);