about summary refs log tree commit diff
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);