Home | History | Annotate | Download | only in posix
      1 /* chgrp.c - Change user and group ownership
      2  *
      3  * Copyright 2012 Georgi Chorbadzhiyski <georgi (at) 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 output.
     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 
     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,
     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 
     74 void 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 
    103 void chown_main()
    104 {
    105   chgrp_main();
    106 }
    107