master xplshn/aruu / cmd / posix / chgrp.c
 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}