1 /* chgrp.c - Change user and group ownership
2  *
3  * Copyright 2012 Georgi Chorbadzhiyski <georgi@unixsol.org>
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, "<2hPLHRfv[-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, flags = toys.optflags;
48 
49   // Depth first search
50   if (!dirtree_notdotdot(node)) return 0;
51   if ((flags & FLAG_R) && !node->again && S_ISDIR(node->st.st_mode))
52     return DIRTREE_COMEAGAIN|(DIRTREE_SYMFOLLOW*!!(flags&FLAG_L));
53 
54   fd = dirtree_parentfd(node);
55   ret = fchownat(fd, node->name, TT.owner, TT.group,
56     AT_SYMLINK_NOFOLLOW*(!(flags&(FLAG_L|FLAG_H)) && (flags&(FLAG_h|FLAG_R))));
57 
58   if (ret || (flags & FLAG_v)) {
59     char *path = dirtree_path(node, 0);
60     if (flags & 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 && !(toys.optflags & 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*!!(toys.optflags&(FLAG_H|FLAG_L)),
98       do_chgrp);
99 
100   if (CFG_TOYBOX_FREE && ischown) free(own);
101 }
102 
chown_main()103 void chown_main()
104 {
105   chgrp_main();
106 }
107