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 8USE_CHGRP(NEWTOY(chgrp, "<2hPLHRfv[-HLP]", TOYFLAG_BIN)) 9USE_CHOWN(OLDTOY(chown, chgrp, TOYFLAG_BIN)) 10 11config 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 output. 26 27config 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 38GLOBALS( 39 uid_t owner; 40 gid_t group; 41 char *owner_name, *group_name; 42 int symfollow; 43) 44 45static 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, 62 TT.owner_name ? TT.owner_name : "", 63 toys.which->name[2]=='o' && TT.group_name ? ":" : "", 64 TT.group_name ? TT.group_name : "", path); 65 if (ret == -1 && !(toys.optflags & FLAG_f)) 66 perror_msg("'%s' to '%s:%s'", path, TT.owner_name, TT.group_name); 67 free(path); 68 } 69 toys.exitval |= ret; 70 71 return 0; 72} 73 74void chgrp_main(void) 75{ 76 int ischown = toys.which->name[2] == 'o'; 77 char **s, *own; 78 79 TT.owner = TT.group = -1; 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 = xgetpwnamid(TT.owner_name = own)->pw_uid; 91 } else TT.group_name = *toys.optargs; 92 93 if (TT.group_name && *TT.group_name) 94 TT.group = xgetgrnamid(TT.group_name)->gr_gid; 95 96 for (s=toys.optargs+1; *s; s++) 97 dirtree_handle_callback(dirtree_start(*s, toys.optflags&(FLAG_H|FLAG_L)), 98 do_chgrp);; 99 100 if (CFG_TOYBOX_FREE && ischown) free(own); 101} 102 103void chown_main() 104{ 105 chgrp_main(); 106} 107