changeset 590:7becb497c3c4

Update chmod to work with new dirtree, and fix bugs in string_to_mode().
author Rob Landley <rob@landley.net>
date Sun, 03 Jun 2012 00:32:12 -0500
parents 7013fd450ff4
children 7c4ca3f0536b
files lib/lib.c lib/lib.h toys/chmod.c
diffstat 3 files changed, 56 insertions(+), 69 deletions(-) [+]
line wrap: on
line diff
--- a/lib/lib.c	Fri Jun 01 20:27:51 2012 -0500
+++ b/lib/lib.c	Sun Jun 03 00:32:12 2012 -0500
@@ -726,6 +726,17 @@
 	}
 }
 
+int wfchmodat(int fd, char *name, mode_t mode)
+{
+	int rc = fchmodat(fd, name, mode, 0);
+
+	if (rc) {
+		perror_msg("chmod '%s' to %04o", name, mode);
+		toys.exitval=1;
+	}
+	return rc;
+}
+
 // Open a temporary file to copy an existing file into.
 int copy_tempfile(int fdin, char *name, char **tempname)
 {
@@ -926,7 +937,7 @@
 
 mode_t string_to_mode(char *modestr, mode_t mode)
 {
-	char *whos = "ugoa", *hows = "=+-", *whats = "xwrstX", *whys = "ogu";
+	char *whos = "ogua", *hows = "=+-", *whats = "xwrstX", *whys = "ogu";
 	char *s, *str = modestr;
 
 	// Handle octal mode
@@ -944,16 +955,17 @@
 		dowho = dohow = dowhat = 0;
 
 		// Find the who, how, and what stanzas, in that order
-		while ((s = strchr(whos, *str))) {
-			dowho |= 1<<(whos-s);
+		while (*str && (s = strchr(whos, *str))) {
+			dowho |= 1<<(s-whos);
 			str++;
 		}
 		if (!dowho) dowho = 8;
-		if (!(s = strchr(hows, *str))) goto barf;
+		if (!*str || !(s = strchr(hows, *str))) goto barf;
 		dohow = *(str++);
+
 		if (!dohow) goto barf;
-		while ((s = strchr(whats, *str))) {
-			dowhat |= 1<<(whats-s);
+		while (*str && (s = strchr(whats, *str))) {
+			dowhat |= 1<<(s-whats);
 			str++;
 		}
 
@@ -961,8 +973,8 @@
 		if ((dowhat&32) &&  (S_ISDIR(mode) || (mode&0111))) dowhat |= 1;
 
 		// Copy mode from another category?
-		if (!dowhat && (s = strchr(whys, *str))) {
-			dowhat = (mode>>(3*(s-str)))&7;
+		if (!dowhat && *str && (s = strchr(whys, *str))) {
+			dowhat = (mode>>(3*(s-whys)))&7;
 			str++;
 		}
 
--- a/lib/lib.h	Fri Jun 01 20:27:51 2012 -0500
+++ b/lib/lib.h	Sun Jun 03 00:32:12 2012 -0500
@@ -136,6 +136,7 @@
 char *get_rawline(int fd, long *plen, char end);
 char *get_line(int fd);
 void xsendfile(int in, int out);
+int wfchmodat(int rc, char *name, mode_t mode);
 int copy_tempfile(int fdin, char *name, char **tempname);
 void delete_tempfile(int fdin, int fdout, char **tempname);
 void replace_tempfile(int fdin, int fdout, char **tempname);
--- a/toys/chmod.c	Fri Jun 01 20:27:51 2012 -0500
+++ b/toys/chmod.c	Sun Jun 03 00:32:12 2012 -0500
@@ -2,91 +2,65 @@
  *
  * chmod.c - Change file mode bits
  *
- * Copyright 2012 Georgi Chorbadzhiyski <georgi@unixsol.org>
+ * Copyright 2012 Rob Landley <rob@landley.net>
  *
  * See http://pubs.opengroup.org/onlinepubs/009695399/utilities/chmod.html
  *
 
-USE_CHMOD(NEWTOY(chmod, "<2Rfv", TOYFLAG_BIN))
+USE_CHMOD(NEWTOY(chmod, "<2?R", TOYFLAG_BIN))
 
 config CHMOD
-	bool "chmod"
-	default n
-	help
-	  usage: chmod [-R] [-f] [-v] mode file...
-	  Change mode bits of one or more files.
+    bool "chmod"
+    default y
+    help
+        usage: chmod [-R] MODE FILE...
 
-	  -R	recurse into subdirectories.
-	  -f	suppress most error messages.
-	  -v	verbose output.
+        Change mode of listed file[s] (recursively with -R).
+
+        MODE can be (comma-separated) stanzas: [ugoa][+-=][rwxstXugo]
+
+        Stanzas are applied in order: For each category (u = user,
+        g = group, o = other, a = all three, if none specified default is a),
+        set (+), clear (-), or copy (=), r = read, w = write, x = execute.
+        s = u+s = suid, g+s = sgid, o+s = sticky. (+t is an alias for o+s).
+        suid/sgid: execute as the user/group who owns the file.
+        sticky: can't delete files you don't own out of this directory
+        X = x for directories or if any category already has x set.
+
+        Or MODE can be an octal value up to 7777	ug uuugggooo	top +
+        bit 1 = o+x, bit 1<<8 = u+w, 1<<11 = g+1	sstrwxrwxrwx	bottom
+
+        Examples:
+        chmod u+w file - allow owner of "file" to write to it.
+        chmod 744 file - user can read/write/execute, everyone else read only
 */
 
 #include "toys.h"
 
-#define FLAG_R 4
-#define FLAG_f 2
-#define FLAG_v 1
-
 DEFINE_GLOBALS(
-	long mode;
+    char *mode;
 )
 
 #define TT this.chmod
 
-static int do_chmod(const char *path) {
-	int ret = chmod(path, TT.mode);
-	if (toys.optflags & FLAG_v)
-		xprintf("chmod(%04o, %s)\n", TT.mode, path);
-	if (ret == -1 && !(toys.optflags & FLAG_f))
-		perror_msg("changing perms of '%s' to %04o", path, TT.mode);
-	toys.exitval |= ret;
-	return ret;
-}
+#define FLAG_R 1
 
-// Copied from toys/cp.c:cp_node()
-int chmod_node(char *path, struct dirtree *node)
+int do_chmod(struct dirtree *try)
 {
-	char *s = path + strlen(path);
-	struct dirtree *n = node;
+    mode_t mode;
 
-	for ( ; ; n = n->parent) {
-		while (s!=path) {
-			if (*(--s) == '/') break;
-		}
-		if (!n) break;
-	}
-	if (s != path) s++;
+    if (!dirtree_notdotdot(try)) return 0;
 
-	do_chmod(s);
+    mode = string_to_mode(TT.mode, try->st.st_mode);
+    wfchmodat(try->parent ? try->parent->data : AT_FDCWD, try->name, mode);
 
-	return 0;
+    return (toys.optflags & FLAG_R) ? DIRTREE_RECURSE : 0;
 }
 
 void chmod_main(void)
 {
-	char **s;
-	TT.mode = strtoul(*toys.optargs, NULL, 8);
+    TT.mode = *toys.optargs;
+    char **file;
 
-	if (toys.optflags & FLAG_R) {
-		// Recurse into subdirectories
-		for (s=toys.optargs + 1; *s; s++) {
-			struct stat sb;
-			if (stat(*s, &sb) == -1) {
-				if (!(toys.optflags & FLAG_f))
-					perror_msg("%s", *s);
-				continue;
-			}
-			do_chmod(*s);
-			if (S_ISDIR(sb.st_mode)) {
-				strncpy(toybuf, *s, sizeof(toybuf) - 1);
-				toybuf[sizeof(toybuf) - 1] = 0;
-				dirtree_read(toybuf, NULL, chmod_node);
-			}
-		}
-	} else {
-		// Do not recurse
-		for (s=toys.optargs + 1; *s; s++) {
-			do_chmod(*s);
-		}
-	}
+    for (file = toys.optargs+1; *file; file++) dirtree_read(*file, do_chmod);
 }