/* vi: set sw=4 ts=4: * * chown.c - Change ownership * * Copyright 2012 Georgi Chorbadzhiyski * * See http://pubs.opengroup.org/onlinepubs/009695399/utilities/chown.html * See http://pubs.opengroup.org/onlinepubs/009695399/utilities/chgrp.html * * TODO: group only one of [HLP] USE_CHGRP(NEWTOY(chgrp, "<2hPLHRfv", TOYFLAG_BIN)) USE_CHGRP(OLDTOY(chown, chgrp, "<2hPLHRfv", TOYFLAG_BIN)) config CHGRP bool "chgrp/chown" default y help usage: chown [-RHLP] [-fvh] [owner][:group] file... usage: chgrp [-RHLP] [-fvh] group file... Change ownership of one or more files. -f suppress most error messages. -h change symlinks instead of what they point to -R recurse into subdirectories (implies -h). -H with -R change target of symlink, follow command line symlinks -L with -R change target of symlink, follow all symlinks -P with -R change symlink, do not follow symlinks (default) -v verbose output. */ #include "toys.h" #define FLAG_v 1 #define FLAG_f 2 #define FLAG_R 4 #define FLAG_H 8 #define FLAG_L 16 #define FLAG_P 32 #define FLAG_h 64 DEFINE_GLOBALS( uid_t owner; gid_t group; char *owner_name, *group_name; int symfollow; ) #define TT this.chgrp static int do_chgrp(struct dirtree *node) { int fd, ret, flags = toys.optflags; // Depth first search if (!dirtree_notdotdot(node)) return 0; if ((flags & FLAG_R) && node->data != -1 && S_ISDIR(node->st.st_mode)) return DIRTREE_COMEAGAIN|((flags&FLAG_L) ? DIRTREE_SYMFOLLOW : 0); fd = dirtree_parentfd(node); ret = fchownat(fd, node->name, TT.owner, TT.group, (flags&(FLAG_L|FLAG_H)) || !(flags&(FLAG_h|FLAG_R)) ? 0 : AT_SYMLINK_NOFOLLOW); if (ret || (flags & FLAG_v)) { char *path = dirtree_path(node, 0); if (flags & FLAG_v) xprintf("%s %s%s%s %s\n", toys.which->name, TT.owner_name ? TT.owner_name : "", toys.which->name[2]=='o' && TT.group_name ? ":" : "", TT.group_name ? TT.group_name : "", path); if (ret == -1 && !(toys.optflags & FLAG_f)) perror_msg("changing owner:group of '%s' to '%s:%s'", path, TT.owner_name, TT.group_name); free(path); } toys.exitval |= ret; return 0; } void chgrp_main(void) { int ischown = toys.which->name[2] == 'o'; char **s, *own; // Distinguish chown from chgrp if (ischown) { char *grp; struct passwd *p; own = xstrdup(*toys.optargs); if ((grp = strchr(own, ':')) || (grp = strchr(own, '.'))) { *(grp++) = 0; TT.group_name = grp; } if (*own) { TT.owner_name = own; p = getpwnam(own); // TODO: trailing garbage? if (!p && isdigit(*own)) p=getpwuid(atoi(own)); if (!p) error_exit("no user '%s'", own); TT.owner = p->pw_uid; } } else TT.group_name = *toys.optargs; if (TT.group_name) { struct group *g; g = getgrnam(TT.group_name); if (!g) g=getgrgid(atoi(TT.group_name)); if (!g) error_exit("no group '%s'", TT.group_name); TT.group = g->gr_gid; } for (s=toys.optargs+1; *s; s++) { struct dirtree *new = dirtree_add_node(AT_FDCWD, *s, toys.optflags&(FLAG_H|FLAG_L)); if (new) handle_callback(new, do_chgrp); else toys.exitval = 1; } if (CFG_TOYBOX_FREE) free(own); }