chmod.c - sbase - suckless unix tools
(HTM) git clone git://git.suckless.org/sbase
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
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 }