master xplshn/aruu / cmd / posix / chgrp.c
 1/* See LICENSE file for copyright and license details. */
 2
 3#include <sys/stat.h>
 4
 5#include <errno.h>
 6#include <fcntl.h>
 7#include <grp.h>
 8#include <unistd.h>
 9
10#include "fs.h"
11#include "util.h"
12
13static int   hflag = 0;
14static gid_t gid   = -1;
15static int   ret   = 0;
16
17static void
18chgrp(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
19{
20  int flags = 0;
21
22  (void)data;
23
24  if ((r->maxdepth == 0 && r->follow == 'P') || (r->follow == 'H' && r->depth)
25      || (hflag && !(r->depth)))
26    flags |= AT_SYMLINK_NOFOLLOW;
27  if (fchownat(dirfd, name, -1, gid, flags) < 0) {
28    weprintf("chown %s:", r->path);
29    ret = 1;
30  } else if (S_ISDIR(st->st_mode)) {
31    recurse(dirfd, name, NULL, r);
32  }
33}
34
35static void
36usage(void)
37{
38  eprintf("usage: %s [-h] [-R [-H | -L | -P]] group file ...\n", argv0);
39}
40
41// ?man chgrp: change group ownership
42// ?man arguments: group file ...
43// ?man change the group ownership of files and directories
44int
45main(int argc, char *argv[])
46{
47  struct group   *gr;
48  struct recursor r = {.fn = chgrp, .maxdepth = 1, .follow = 'P'};
49
50  ARGBEGIN
51  {
52    // ?man -h: affect symbolic links instead of referenced files
53    case 'h':
54      hflag = 1;
55      break;
56    // ?man -R: change group ownership recursively
57    case 'R':
58      r.maxdepth = 0;
59      break;
60    // ?man -H: specify option flag
61    case 'H':
62    // ?man -L: specify option flag
63    case 'L':
64    // ?man -P: specify option flag
65    case 'P':
66      r.follow = ARGC();
67      break;
68    default:
69      usage();
70  }
71  ARGEND
72
73  if (argc < 2)
74    usage();
75
76  errno = 0;
77  if ((gr = getgrnam(argv[0]))) {
78    gid = gr->gr_gid;
79  } else {
80    if (errno)
81      eprintf("getgrnam %s:", argv[0]);
82    gid = estrtonum(argv[0], 0, UINT_MAX);
83  }
84
85  for (argc--, argv++; *argv; argc--, argv++)
86    recurse(AT_FDCWD, *argv, NULL, &r);
87
88  return ret || recurse_status;
89}