aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/lib.c28
-rw-r--r--lib/lib.h1
-rw-r--r--toys/chmod.c100
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 <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.
-
- -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);
}