From 67a069d62c11abc3ed709a1fd3c39a1aa43570e3 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 3 Jun 2012 00:32:12 -0500 Subject: Update chmod to work with new dirtree, and fix bugs in string_to_mode(). --- lib/lib.c | 28 ++++++++++++----- lib/lib.h | 1 + toys/chmod.c | 100 ++++++++++++++++++++++------------------------------------- 3 files changed, 58 insertions(+), 71 deletions(-) diff --git a/lib/lib.c b/lib/lib.c index 612c29e1..7af2af11 100644 --- a/lib/lib.c +++ b/lib/lib.c @@ -726,6 +726,17 @@ void xsendfile(int in, int out) } } +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 @@ char *num_to_sig(int sig) 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 @@ mode_t string_to_mode(char *modestr, mode_t mode) 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 @@ mode_t string_to_mode(char *modestr, mode_t mode) 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++; } diff --git a/lib/lib.h b/lib/lib.h index b45ea753..add0c14e 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -136,6 +136,7 @@ void loopfiles(char **argv, void (*function)(int fd, char *name)); 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); diff --git a/toys/chmod.c b/toys/chmod.c index a4803c65..b11c3cd9 100644 --- a/toys/chmod.c +++ b/toys/chmod.c @@ -2,91 +2,65 @@ * * chmod.c - Change file mode bits * - * Copyright 2012 Georgi Chorbadzhiyski + * Copyright 2012 Rob Landley * * 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. - - -R recurse into subdirectories. - -f suppress most error messages. - -v verbose output. + bool "chmod" + default y + help + usage: chmod [-R] MODE FILE... + + 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); - - 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); - } - } + TT.mode = *toys.optargs; + char **file; + + for (file = toys.optargs+1; *file; file++) dirtree_read(*file, do_chmod); } -- cgit v1.2.3