chmod.c (1553B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <fcntl.h> 3 #include <sys/stat.h> 4 5 #include "fs.h" 6 #include "util.h" 7 8 static char *modestr = ""; 9 static mode_t mask = 0; 10 static int ret = 0; 11 12 static void 13 chmodr(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r) 14 { 15 mode_t m; 16 17 m = parsemode(modestr, st->st_mode, mask); 18 if (!S_ISLNK(st->st_mode) && fchmodat(dirfd, name, m, 0) < 0) { 19 weprintf("chmod %s:", r->path); 20 ret = 1; 21 } else if (S_ISDIR(st->st_mode)) { 22 recurse(dirfd, name, NULL, r); 23 } 24 } 25 26 static void 27 usage(void) 28 { 29 eprintf("usage: %s [-R] mode file ...\n", argv0); 30 } 31 32 int 33 main(int argc, char *argv[]) 34 { 35 struct recursor r = { .fn = chmodr, .maxdepth = 1, .follow = 'H', .flags = DIRFIRST }; 36 size_t i; 37 38 argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0; 39 40 for (; *argv && (*argv)[0] == '-'; argc--, argv++) { 41 if (!(*argv)[1]) 42 usage(); 43 for (i = 1; (*argv)[i]; i++) { 44 switch ((*argv)[i]) { 45 case 'R': 46 r.maxdepth = 0; 47 break; 48 case 'r': case 'w': case 'x': case 'X': case 's': case 't': 49 /* -[rwxXst] are valid modes, so we're done */ 50 if (i == 1) 51 goto done; 52 /* fallthrough */ 53 case '-': 54 /* -- terminator */ 55 if (i == 1 && !(*argv)[i + 1]) { 56 argv++; 57 argc--; 58 goto done; 59 } 60 /* fallthrough */ 61 default: 62 usage(); 63 } 64 } 65 } 66 done: 67 mask = getumask(); 68 modestr = *argv; 69 70 if (argc < 2) 71 usage(); 72 73 for (--argc, ++argv; *argv; argc--, argv++) 74 recurse(AT_FDCWD, *argv, NULL, &r); 75 76 return ret || recurse_status; 77 }