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