1/* See LICENSE file for copyright and license details. */
2
3
4#include <sys/stat.h>
5
6#include <errno.h>
7#include <fcntl.h>
8#include <grp.h>
9#include <unistd.h>
10
11#include "fs.h"
12#include "util.h"
13
14static int hflag = 0;
15static gid_t gid = -1;
16static int ret = 0;
17
18static void
19chgrp(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
20{
21 int flags = 0;
22
23 (void)data;
24
25 if ((r->maxdepth == 0 && r->follow == 'P') || (r->follow == 'H' && r->depth) || (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 // ?man -h: affect symbolic links instead of referenced files
52 case 'h':
53 hflag = 1;
54 break;
55 // ?man -R: change group ownership recursively
56 case 'R':
57 r.maxdepth = 0;
58 break;
59 // ?man -H: specify option flag
60 case 'H':
61 // ?man -L: specify option flag
62 case 'L':
63 // ?man -P: specify option flag
64 case 'P':
65 r.follow = ARGC();
66 break;
67 default:
68 usage();
69 } ARGEND
70
71 if (argc < 2)
72 usage();
73
74 errno = 0;
75 if ((gr = getgrnam(argv[0]))) {
76 gid = gr->gr_gid;
77 } else {
78 if (errno)
79 eprintf("getgrnam %s:", argv[0]);
80 gid = estrtonum(argv[0], 0, UINT_MAX);
81 }
82
83 for (argc--, argv++; *argv; argc--, argv++)
84 recurse(AT_FDCWD, *argv, NULL, &r);
85
86 return ret || recurse_status;
87}