From da091b3ab33a31f1354b8ab42915faf15c3c4745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1draig=20Brady?=
Date: Wed, 27 Sep 2023 20:32:06 +0100
Subject: [PATCH] chgrp: add --from parameter similar to chown
* doc/coreutils.texi (chown invocation): Convert --from option
description to a macro and call from ...
(chgrp description): ... here.
* src/chown-core.h (emit_from_option_description): A new function
refactored from ...
* src/chown.c (usage): ... here, and called from ...
* src/chgrp.c (usage): ... here.
(main): Accept the --from option as chown(1) does.
* po/POTFILES.in: Add chown-core.h as now translated.
* tests/chown/basic.sh: Decouple the root user from id 0.
* tests/chgrp/from.sh: A new test largely based on chown/basic.sh.
* tests/local.mk: Reference the new test.
* NEWS: Mention the new feature.
Suggested by Ed Neville.
---
NEWS | 3 +++
doc/coreutils.texi | 15 ++++++++----
po/POTFILES.in | 1 +
src/chgrp.c | 22 +++++++++++++++++-
src/chown-core.h | 12 ++++++++++
src/chown.c | 8 +------
tests/chgrp/from.sh | 54 ++++++++++++++++++++++++++++++++++++++++++++
tests/chown/basic.sh | 2 +-
tests/local.mk | 1 +
9 files changed, 104 insertions(+), 14 deletions(-)
create mode 100755 tests/chgrp/from.sh
diff --git a/NEWS b/NEWS
index 0823f0d9f..a4fd77073 100644
--- a/NEWS
+++ b/NEWS
@@ -45,6 +45,9 @@ GNU coreutils NEWS -*- outline -*-
** New features
+ chgrp now accepts the --from=OWNER:GROUP option to restrict changes to files
+ with matching current OWNER and/or GROUP, as already supported by chown(1).
+
tail now supports following multiple processes, with repeated --pid options.
** Improvements
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index d445ea228..1f8b356d1 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -11601,6 +11601,7 @@ actually changes.
Do not print error messages about files whose ownership cannot be
changed.
+@macro chownFromOption{cmd}
@item --from=@var{old-owner}
@opindex --from
@cindex symbolic links, changing owner
@@ -11613,17 +11614,17 @@ For example, to reflect a user ID numbering change for one user's files
without an option like this, @code{root} might run
@example
-find / -owner OLDUSER -print0 | xargs -0 chown -h NEWUSER
+find / -owner OLDUSER -print0 | xargs -0 \cmd\ -h NEWUSER
@end example
But that is dangerous because the interval between when the @command{find}
-tests the existing file's owner and when the @command{chown} is actually run
+tests the existing file's owner and when the @command{\cmd\} is actually run
may be quite large.
-One way to narrow the gap would be to invoke chown for each file
+One way to narrow the gap would be to invoke \cmd\ for each file
as it is found:
@example
-find / -owner OLDUSER -exec chown -h NEWUSER @{@} \;
+find / -owner OLDUSER -exec \cmd\ -h NEWUSER @{@} \\;
@end example
But that is very slow if there are many affected files.
@@ -11631,8 +11632,10 @@ With this option, it is safer (the gap is narrower still)
though still not perfect:
@example
-chown -h -R --from=OLDUSER NEWUSER /
+\cmd\ -h -R --from=OLDUSER NEWUSER /
@end example
+@end macro
+@chownFromOption{chown}
@item --dereference
@opindex --dereference
@@ -11766,6 +11769,8 @@ changes.
Do not print error messages about files whose group cannot be
changed.
+@chownFromOption{chgrp}
+
@item --dereference
@opindex --dereference
@cindex symbolic links, changing owner
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3029d1e3b..751af7cc6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -41,6 +41,7 @@ src/chcon.c
src/chgrp.c
src/chmod.c
src/chown-core.c
+src/chown-core.h
src/chown.c
src/chroot.c
src/cksum.c
diff --git a/src/chgrp.c b/src/chgrp.c
index 6ec3b4d99..51fc10782 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},
@@ -129,6 +132,7 @@ With --reference, change the group of each FILE to that of RFILE.\n\
(useful only on systems that can change the\n\
ownership of a symlink)\n\
"), stdout);
+ emit_from_option_description (false);
fputs (_("\
--no-preserve-root do not treat '/' specially (the default)\n\
--preserve-root fail to operate recursively on '/'\n\
@@ -184,6 +188,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 +241,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 +329,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);
+ required_uid, required_gid, &chopt);
main_exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
}
diff --git a/src/chown-core.h b/src/chown-core.h
index 8afdc0b1e..23cb89435 100644
--- a/src/chown-core.h
+++ b/src/chown-core.h
@@ -89,4 +89,16 @@ chown_files (char **files, int bit_flags,
struct Chown_option const *chopt)
_GL_ATTRIBUTE_NONNULL ();
+static inline void
+emit_from_option_description (bool user)
+{
+ printf (_("\
+ --from=CURRENT_OWNER:CURRENT_GROUP\n\
+ change the %sgroup of each file only if\n\
+ its current owner and/or group match those specified\n\
+ here. Either may be omitted, in which case a match\n\
+ is not required for the omitted attribute\n\
+"), user ? "owner and/or " : "");
+}
+
#endif /* CHOWN_CORE_H */
diff --git a/src/chown.c b/src/chown.c
index 4e0e1c3fc..b2cb973b0 100644
--- a/src/chown.c
+++ b/src/chown.c
@@ -99,13 +99,7 @@ With --reference, change the owner and group of each FILE to those of RFILE.\n\
(useful only on systems that can change the\n\
ownership of a symlink)\n\
"), stdout);
- fputs (_("\
- --from=CURRENT_OWNER:CURRENT_GROUP\n\
- change the owner and/or group of each file only if\n\
- its current owner and/or group match those specified\n\
- here. Either may be omitted, in which case a match\n\
- is not required for the omitted attribute\n\
-"), stdout);
+ emit_from_option_description (true);
fputs (_("\
--no-preserve-root do not treat '/' specially (the default)\n\
--preserve-root fail to operate recursively on '/'\n\
diff --git a/tests/chgrp/from.sh b/tests/chgrp/from.sh
new file mode 100755
index 000000000..2ddb85889
--- /dev/null
+++ b/tests/chgrp/from.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+# make sure chgrp --from=... works
+
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see