A friend at work noticed that chown had a --from and needed that functionality in chgrp. --- src/chgrp.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/src/chgrp.c b/src/chgrp.c index 6ec3b4d99..f780a6fc2 100644 --- a/src/chgrp.c +++ b/src/chgrp.c @@ -28,6 +28,7 @@ #include "quote.h" #include "root-dev-ino.h" #include "xstrtol.h" +#include "userspec.h" /* The official name of this program (e.g., no 'g' prefix). */ #define PROGRAM_NAME "chgrp" @@ -49,6 +50,7 @@ static char *reference_file; enum { DEREFERENCE_OPTION = CHAR_MAX + 1, + FROM_OPTION, NO_PRESERVE_ROOT, PRESERVE_ROOT, REFERENCE_FILE_OPTION @@ -59,6 +61,7 @@ static struct option const long_options[] = {"recursive", no_argument, nullptr, 'R'}, {"changes", no_argument, nullptr, 'c'}, {"dereference", no_argument, nullptr, DEREFERENCE_OPTION}, + {"from", required_argument, nullptr, FROM_OPTION}, {"no-dereference", no_argument, nullptr, 'h'}, {"no-preserve-root", no_argument, nullptr, NO_PRESERVE_ROOT}, {"preserve-root", no_argument, nullptr, PRESERVE_ROOT}, @@ -121,6 +124,11 @@ With --reference, change the group of each FILE to that of RFILE.\n\ -v, --verbose output a diagnostic for every file processed\n\ "), stdout); fputs (_("\ + --from=CURRENT_OWNER:CURRENT_GROUP\n\ + change the group of each file only if its current\n\ + owner and/or group match those specified here.\n\ + Either may be omitted, in which case a match is \n\ + not required for the omitted attribute\n\ --dereference affect the referent of each symbolic link (this is\n\ the default), rather than the symbolic link itself\n\ -h, --no-dereference affect symbolic links instead of any referenced file\n\ @@ -184,6 +192,11 @@ main (int argc, char **argv) bool ok; int optc; + /* Change the group of a file only if it has this uid/gid. + * -1 means there's no restriction. */ + uid_t required_uid = -1; + gid_t required_gid = -1; + initialize_main (&argc, &argv); set_program_name (argv[0]); setlocale (LC_ALL, ""); @@ -232,6 +245,17 @@ main (int argc, char **argv) reference_file = optarg; break; + case FROM_OPTION: + { + bool warn; + char const *e = parse_user_spec_warn (optarg, + &required_uid, &required_gid, + nullptr, nullptr, &warn); + if (e) + error (warn ? 0 : EXIT_FAILURE, 0, "%s: %s", e, quote (optarg)); + break; + } + case 'R': chopt.recurse = true; break; @@ -309,7 +333,7 @@ main (int argc, char **argv) bit_flags |= FTS_DEFER_STAT; ok = chown_files (argv + optind, bit_flags, (uid_t) -1, gid, - (uid_t) -1, (gid_t) -1, &chopt); + (uid_t) required_uid, required_gid, &chopt); main_exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); } -- 2.39.2