1 /* chgrp.c - Change user and group ownership
2 *
3 * Copyright 2012 Georgi Chorbadzhiyski <[email protected]>
4 *
5 * See http://opengroup.org/onlinepubs/9699919799/utilities/chown.html
6 * See http://opengroup.org/onlinepubs/9699919799/utilities/chgrp.html
7
8 USE_CHGRP(NEWTOY(chgrp, "<2h(no-dereference)PLHRfv[-HLP]", TOYFLAG_BIN))
9 USE_CHOWN(OLDTOY(chown, chgrp, TOYFLAG_BIN))
10
11 config CHGRP
12 bool "chgrp"
13 default y
14 help
15 usage: chgrp/chown [-RHLP] [-fvh] GROUP FILE...
16
17 Change group of one or more files.
18
19 -f Suppress most error messages
20 -h Change symlinks instead of what they point to
21 -R Recurse into subdirectories (implies -h)
22 -H With -R change target of symlink, follow command line symlinks
23 -L With -R change target of symlink, follow all symlinks
24 -P With -R change symlink, do not follow symlinks (default)
25 -v Verbose
26
27 config CHOWN
28 bool "chown"
29 default y
30 help
31 see: chgrp
32 */
33
34 #define FOR_chgrp
35 #define FORCE_FLAGS
36 #include "toys.h"
37
38 GLOBALS(
39 uid_t owner;
40 gid_t group;
41 char *owner_name, *group_name;
42 int symfollow;
43 )
44
do_chgrp(struct dirtree * node)45 static int do_chgrp(struct dirtree *node)
46 {
47 int fd, ret;
48
49 // Depth first search
50 if (!dirtree_notdotdot(node)) return 0;
51 if (FLAG(R) && !(node->again&DIRTREE_COMEAGAIN) && S_ISDIR(node->st.st_mode))
52 return DIRTREE_COMEAGAIN|DIRTREE_SYMFOLLOW*FLAG(L);
53
54 fd = dirtree_parentfd(node);
55 ret = fchownat(fd, node->name, TT.owner, TT.group,
56 AT_SYMLINK_NOFOLLOW*(!(FLAG(L)|FLAG(H)) && (FLAG(h)|FLAG(R))));
57
58 if (ret || FLAG(v)) {
59 char *path = dirtree_path(node, 0);
60 if (FLAG(v))
61 xprintf("%s %s%s%s %s\n", toys.which->name, TT.owner_name,
62 (toys.which->name[2]=='o' && *TT.group_name) ? ":" : "",
63 TT.group_name, path);
64 if (ret == -1 && !FLAG(f))
65 perror_msg("'%s' to '%s:%s'", path, TT.owner_name, TT.group_name);
66 free(path);
67 }
68 toys.exitval |= ret;
69
70 return 0;
71 }
72
chgrp_main(void)73 void chgrp_main(void)
74 {
75 int ischown = toys.which->name[2] == 'o';
76 char **s, *own;
77
78 TT.owner = TT.group = -1;
79 TT.owner_name = TT.group_name = "";
80
81 // Distinguish chown from chgrp
82 if (ischown) {
83 char *grp;
84
85 own = xstrdup(*toys.optargs);
86 if ((grp = strchr(own, ':')) || (grp = strchr(own, '.'))) {
87 *(grp++) = 0;
88 TT.group_name = grp;
89 }
90 if (*own) TT.owner = xgetuid(TT.owner_name = own);
91 } else TT.group_name = *toys.optargs;
92
93 if (TT.group_name && *TT.group_name)
94 TT.group = xgetgid(TT.group_name);
95
96 for (s=toys.optargs+1; *s; s++)
97 dirtree_flagread(*s, DIRTREE_SYMFOLLOW*(FLAG(H)|FLAG(L)), do_chgrp);
98
99 if (CFG_TOYBOX_FREE && ischown) free(own);
100 }
101