1 /* chmod.c - Change file mode bits
2  *
3  * Copyright 2012 Rob Landley <rob@landley.net>
4  *
5  * See http://opengroup.org/onlinepubs/9699919799/utilities/chmod.html
6 
7 USE_CHMOD(NEWTOY(chmod, "<2?vfR[-vf]", TOYFLAG_BIN))
8 
9 config CHMOD
10   bool "chmod"
11   default y
12   help
13     usage: chmod [-R] MODE FILE...
14 
15     Change mode of listed file[s] (recursively with -R).
16 
17     MODE can be (comma-separated) stanzas: [ugoa][+-=][rwxstXugo]
18 
19     Stanzas are applied in order: For each category (u = user,
20     g = group, o = other, a = all three, if none specified default is a),
21     set (+), clear (-), or copy (=), r = read, w = write, x = execute.
22     s = u+s = suid, g+s = sgid, +t = sticky. (o+s ignored so a+s doesn't set +t)
23     suid/sgid: execute as the user/group who owns the file.
24     sticky: can't delete files you don't own out of this directory
25     X = x for directories or if any category already has x set.
26 
27     Or MODE can be an octal value up to 7777	ug uuugggooo	top +
28     bit 1 = o+x, bit 1<<8 = u+w, 1<<11 = g+1	sstrwxrwxrwx	bottom
29 
30     Examples:
31     chmod u+w file - allow owner of "file" to write to it.
32     chmod 744 file - user can read/write/execute, everyone else read only
33 */
34 
35 #define FOR_chmod
36 #include "toys.h"
37 
GLOBALS(char * mode;)38 GLOBALS(
39   char *mode;
40 )
41 
42 static int do_chmod(struct dirtree *try)
43 {
44   mode_t mode;
45 
46   if (!dirtree_notdotdot(try)) return 0;
47 
48   if (FLAG(R) && try->parent && S_ISLNK(try->st.st_mode)) {
49     // Ignore symlinks found during recursion. We'll only try to modify
50     // symlinks mentioned directly as arguments. We'll fail, of course,
51     // but that's what you asked for in that case.
52   } else {
53     mode = string_to_mode(TT.mode, try->st.st_mode) & ~S_IFMT;
54     if (FLAG(v)) {
55       char *s = dirtree_path(try, 0);
56 
57       printf("chmod '%s' to %s\n", s, TT.mode);
58       free(s);
59     }
60     wfchmodat(dirtree_parentfd(try), try->name, mode);
61   }
62 
63   return FLAG(R)*DIRTREE_RECURSE;
64 }
65 
chmod_main(void)66 void chmod_main(void)
67 {
68   TT.mode = *toys.optargs;
69   char **file;
70 
71   for (file = toys.optargs+1; *file; file++) dirtree_read(*file, do_chmod);
72 }
73