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}