]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
maint: merge chgrp and chown sources
authorPádraig Brady <P@draigBrady.com>
Wed, 27 Dec 2023 13:28:02 +0000 (13:28 +0000)
committerPádraig Brady <P@draigBrady.com>
Wed, 27 Dec 2023 19:51:00 +0000 (19:51 +0000)
chown is a close superset of chgrp functionality,
so merge sources to avoid unwanted divergence in future.
This removes about 300 lines in chgrp.c

* build-aux/gen-single-binary.sh: Generate new rules for chgrp.
* cfg.mk: Exclude new wrappers.
* po/POTFILES.in: Remove chgrp.c
* src/chgrp.c: Remove.
* src/chown-chgrp.c: New wrapper.
* src/chown-chown.c: Likewise.
* src/chown.c (main): Prepend ':' for chgrp(1).
* src/chown.h: Define both operating modes.
(usage): Adjust depending on utility being called.
* src/coreutils-chgrp.c: Likewise.
* src/local.mk: Reference new wrappers.

build-aux/gen-single-binary.sh
cfg.mk
po/POTFILES.in
src/chgrp.c [deleted file]
src/chown-chgrp.c [new file with mode: 0644]
src/chown-chown.c [new file with mode: 0644]
src/chown.c
src/chown.h [new file with mode: 0644]
src/coreutils-chgrp.c [new file with mode: 0644]
src/local.mk

index 1e8f495b4ab642a7f5e53a13918378d273ed5591..7d15b9bfc2dc5e5bc9b5cff10e0206964347faa3 100755 (executable)
@@ -71,6 +71,7 @@ override_single() {
 override_single dir ls
 override_single vdir ls
 override_single arch uname
+override_single chgrp chown
 
 for cmd in $ALL_PROGRAMS; do
   echo "# Command $cmd"
diff --git a/cfg.mk b/cfg.mk
index 378d976878a162ae610bb5314a4e603c53f22845..185d5005ee0213a6ae8c580bd855159c2da6db08 100644 (file)
--- a/cfg.mk
+++ b/cfg.mk
@@ -841,7 +841,8 @@ exclude_file_name_regexp--sc_trailing_blank = \
 exclude_file_name_regexp--sc_system_h_headers = \
   ^src/((system|copy|chown-core|find-mount-point)\.h|make-prime-list\.c)$$
 
-_src = (false|lbracket|ls-(dir|ls|vdir)|tac-pipe|uname-(arch|uname))
+_src := (false|lbracket|chown-(chgrp|chown)
+_src := $(_src)|ls-(dir|ls|vdir)|tac-pipe|uname-(arch|uname))
 _gl_src = (xdecto.max|cl-strtold)
 exclude_file_name_regexp--sc_require_config_h_first = \
   (^lib/buffer-lcm\.c|gl/lib/$(_gl_src)\.c|src/$(_src)\.c)$$
index 751af7cc62b4ab1ace6bbee949fb0841a1475304..6a7d16d435721fe6b0347355649888a5f450c43d 100644 (file)
@@ -38,7 +38,6 @@ src/basename.c
 src/basenc.c
 src/cat.c
 src/chcon.c
-src/chgrp.c
 src/chmod.c
 src/chown-core.c
 src/chown-core.h
diff --git a/src/chgrp.c b/src/chgrp.c
deleted file mode 100644 (file)
index 51fc107..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/* chgrp -- change group ownership of files
-   Copyright (C) 1989-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 <https://www.gnu.org/licenses/>.  */
-
-/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
-
-#include <config.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <grp.h>
-#include <getopt.h>
-
-#include "system.h"
-#include "chown-core.h"
-#include "fts_.h"
-#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"
-
-#define AUTHORS \
-  proper_name ("David MacKenzie"), \
-  proper_name ("Jim Meyering")
-
-#if ! HAVE_ENDGRENT
-# define endgrent() ((void) 0)
-#endif
-
-/* The argument to the --reference option.  Use the group ID of this file.
-   This file must exist.  */
-static char *reference_file;
-
-/* For long options that have no equivalent short option, use a
-   non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
-enum
-{
-  DEREFERENCE_OPTION = CHAR_MAX + 1,
-  FROM_OPTION,
-  NO_PRESERVE_ROOT,
-  PRESERVE_ROOT,
-  REFERENCE_FILE_OPTION
-};
-
-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},
-  {"quiet", no_argument, nullptr, 'f'},
-  {"silent", no_argument, nullptr, 'f'},
-  {"reference", required_argument, nullptr, REFERENCE_FILE_OPTION},
-  {"verbose", no_argument, nullptr, 'v'},
-  {GETOPT_HELP_OPTION_DECL},
-  {GETOPT_VERSION_OPTION_DECL},
-  {nullptr, 0, nullptr, 0}
-};
-
-/* Return the group ID of NAME, or -1 if no name was specified.  */
-
-static gid_t
-parse_group (char const *name)
-{
-  gid_t gid = -1;
-
-  if (*name)
-    {
-      struct group *grp = getgrnam (name);
-      if (grp)
-        gid = grp->gr_gid;
-      else
-        {
-          uintmax_t tmp;
-          if (! (xstrtoumax (name, nullptr, 10, &tmp, "") == LONGINT_OK
-                 && tmp <= GID_T_MAX))
-            error (EXIT_FAILURE, 0, _("invalid group: %s"),
-                   quote (name));
-          gid = tmp;
-        }
-      endgrent ();             /* Save a file descriptor. */
-    }
-
-  return gid;
-}
-
-void
-usage (int status)
-{
-  if (status != EXIT_SUCCESS)
-    emit_try_help ();
-  else
-    {
-      printf (_("\
-Usage: %s [OPTION]... GROUP FILE...\n\
-  or:  %s [OPTION]... --reference=RFILE FILE...\n\
-"),
-              program_name, program_name);
-      fputs (_("\
-Change the group of each FILE to GROUP.\n\
-With --reference, change the group of each FILE to that of RFILE.\n\
-\n\
-"), stdout);
-      fputs (_("\
-  -c, --changes          like verbose but report only when a change is made\n\
-  -f, --silent, --quiet  suppress most error messages\n\
-  -v, --verbose          output a diagnostic for every file processed\n\
-"), stdout);
-      fputs (_("\
-      --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\
-"), stdout);
-      fputs (_("\
-                         (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\
-"), stdout);
-      fputs (_("\
-      --reference=RFILE  use RFILE's group rather than specifying a GROUP.\n\
-                         RFILE is always dereferenced if a symbolic link.\n\
-"), stdout);
-      fputs (_("\
-  -R, --recursive        operate on files and directories recursively\n\
-"), stdout);
-      fputs (_("\
-\n\
-The following options modify how a hierarchy is traversed when the -R\n\
-option is also specified.  If more than one is specified, only the final\n\
-one takes effect.\n\
-\n\
-  -H                     if a command line argument is a symbolic link\n\
-                         to a directory, traverse it\n\
-  -L                     traverse every symbolic link to a directory\n\
-                         encountered\n\
-  -P                     do not traverse any symbolic links (default)\n\
-\n\
-"), stdout);
-      fputs (HELP_OPTION_DESCRIPTION, stdout);
-      fputs (VERSION_OPTION_DESCRIPTION, stdout);
-      printf (_("\
-\n\
-Examples:\n\
-  %s staff /u      Change the group of /u to \"staff\".\n\
-  %s -hR staff /u  Change the group of /u and subfiles to \"staff\".\n\
-"),
-              program_name, program_name);
-      emit_ancillary_info (PROGRAM_NAME);
-    }
-  exit (status);
-}
-
-int
-main (int argc, char **argv)
-{
-  bool preserve_root = false;
-  gid_t gid;
-
-  /* Bit flags that control how fts works.  */
-  int bit_flags = FTS_PHYSICAL;
-
-  /* 1 if --dereference, 0 if --no-dereference, -1 if neither has been
-     specified.  */
-  int dereference = -1;
-
-  struct Chown_option chopt;
-  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, "");
-  bindtextdomain (PACKAGE, LOCALEDIR);
-  textdomain (PACKAGE);
-
-  atexit (close_stdout);
-
-  chopt_init (&chopt);
-
-  while ((optc = getopt_long (argc, argv, "HLPRcfhv", long_options, nullptr))
-         != -1)
-    {
-      switch (optc)
-        {
-        case 'H': /* Traverse command-line symlinks-to-directories.  */
-          bit_flags = FTS_COMFOLLOW | FTS_PHYSICAL;
-          break;
-
-        case 'L': /* Traverse all symlinks-to-directories.  */
-          bit_flags = FTS_LOGICAL;
-          break;
-
-        case 'P': /* Traverse no symlinks-to-directories.  */
-          bit_flags = FTS_PHYSICAL;
-          break;
-
-        case 'h': /* --no-dereference: affect symlinks */
-          dereference = 0;
-          break;
-
-        case DEREFERENCE_OPTION: /* --dereference: affect the referent
-                                    of each symlink */
-          dereference = 1;
-          break;
-
-        case NO_PRESERVE_ROOT:
-          preserve_root = false;
-          break;
-
-        case PRESERVE_ROOT:
-          preserve_root = true;
-          break;
-
-        case REFERENCE_FILE_OPTION:
-          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;
-
-        case 'c':
-          chopt.verbosity = V_changes_only;
-          break;
-
-        case 'f':
-          chopt.force_silent = true;
-          break;
-
-        case 'v':
-          chopt.verbosity = V_high;
-          break;
-
-        case_GETOPT_HELP_CHAR;
-        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
-        default:
-          usage (EXIT_FAILURE);
-        }
-    }
-
-  if (chopt.recurse)
-    {
-      if (bit_flags == FTS_PHYSICAL)
-        {
-          if (dereference == 1)
-            error (EXIT_FAILURE, 0,
-                   _("-R --dereference requires either -H or -L"));
-          dereference = 0;
-        }
-    }
-  else
-    {
-      bit_flags = FTS_PHYSICAL;
-    }
-  chopt.affect_symlink_referent = (dereference != 0);
-
-  if (argc - optind < (reference_file ? 1 : 2))
-    {
-      if (argc <= optind)
-        error (0, 0, _("missing operand"));
-      else
-        error (0, 0, _("missing operand after %s"), quote (argv[argc - 1]));
-      usage (EXIT_FAILURE);
-    }
-
-  if (reference_file)
-    {
-      struct stat ref_stats;
-      if (stat (reference_file, &ref_stats))
-        error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
-               quoteaf (reference_file));
-
-      gid = ref_stats.st_gid;
-      chopt.group_name = gid_to_name (ref_stats.st_gid);
-    }
-  else
-    {
-      char *group_name = argv[optind++];
-      chopt.group_name = (*group_name ? xstrdup (group_name) : nullptr);
-      gid = parse_group (group_name);
-    }
-
-  if (chopt.recurse && preserve_root)
-    {
-      static struct dev_ino dev_ino_buf;
-      chopt.root_dev_ino = get_root_dev_ino (&dev_ino_buf);
-      if (chopt.root_dev_ino == nullptr)
-        error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
-               quoteaf ("/"));
-    }
-
-  bit_flags |= FTS_DEFER_STAT;
-  ok = chown_files (argv + optind, bit_flags,
-                    (uid_t) -1, gid,
-                    required_uid, required_gid, &chopt);
-
-  main_exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
-}
diff --git a/src/chown-chgrp.c b/src/chown-chgrp.c
new file mode 100644 (file)
index 0000000..aa0b180
--- /dev/null
@@ -0,0 +1,2 @@
+#include "chown.h"
+int chown_mode = CHOWN_CHGRP;
diff --git a/src/chown-chown.c b/src/chown-chown.c
new file mode 100644 (file)
index 0000000..9531fa2
--- /dev/null
@@ -0,0 +1,2 @@
+#include "chown.h"
+int chown_mode = CHOWN_CHOWN;
index b2cb973b0d4490e70738bd536b8cc0e68cef3666..cfc34920b5db9d464551f849ebfaddb34b09f1ae 100644 (file)
@@ -1,4 +1,4 @@
-/* chown -- change user and group ownership of files
+/* chown, chgrp -- change user and group ownership of files
    Copyright (C) 1989-2023 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
@@ -22,6 +22,7 @@
 #include <getopt.h>
 
 #include "system.h"
+#include "chown.h"
 #include "chown-core.h"
 #include "fts_.h"
 #include "quote.h"
@@ -29,7 +30,7 @@
 #include "userspec.h"
 
 /* The official name of this program (e.g., no 'g' prefix).  */
-#define PROGRAM_NAME "chown"
+#define PROGRAM_NAME (chown_mode == CHOWN_CHOWN ? "chown" : "chgrp")
 
 #define AUTHORS \
   proper_name ("David MacKenzie"), \
@@ -76,14 +77,23 @@ usage (int status)
   else
     {
       printf (_("\
-Usage: %s [OPTION]... [OWNER][:[GROUP]] FILE...\n\
+Usage: %s [OPTION]... %s FILE...\n\
   or:  %s [OPTION]... --reference=RFILE FILE...\n\
 "),
-              program_name, program_name);
-      fputs (_("\
+              program_name,
+              chown_mode == CHOWN_CHOWN ? "[OWNER][:[GROUP]]" : "GROUP",
+              program_name);
+      if (chown_mode == CHOWN_CHOWN)
+        fputs (_("\
 Change the owner and/or group of each FILE to OWNER and/or GROUP.\n\
 With --reference, change the owner and group of each FILE to those of RFILE.\n\
 \n\
+"), stdout);
+      else
+        fputs (_("\
+Change the group of each FILE to GROUP.\n\
+With --reference, change the group of each FILE to that of RFILE.\n\
+\n\
 "), stdout);
       fputs (_("\
   -c, --changes          like verbose but report only when a change is made\n\
@@ -99,14 +109,14 @@ 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);
-      emit_from_option_description (true);
+      emit_from_option_description (chown_mode == CHOWN_CHOWN);
       fputs (_("\
       --no-preserve-root  do not treat '/' specially (the default)\n\
       --preserve-root    fail to operate recursively on '/'\n\
 "), stdout);
       fputs (_("\
-      --reference=RFILE  use RFILE's owner and group rather than specifying\n\
-                         OWNER:GROUP values.  RFILE is always dereferenced.\n\
+      --reference=RFILE  use RFILE's ownership rather than specifying values\n\
+                         RFILE is always dereferenced if a symbolic link.\n\
 "), stdout);
       fputs (_("\
   -R, --recursive        operate on files and directories recursively\n\
@@ -126,13 +136,16 @@ one takes effect.\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
-      fputs (_("\
+      if (chown_mode == CHOWN_CHOWN)
+        fputs (_("\
 \n\
 Owner is unchanged if missing.  Group is unchanged if missing, but changed\n\
 to login group if implied by a ':' following a symbolic OWNER.\n\
 OWNER and GROUP may be numeric as well as symbolic.\n\
 "), stdout);
-      printf (_("\
+
+      if (chown_mode == CHOWN_CHOWN)
+        printf (_("\
 \n\
 Examples:\n\
   %s root /u        Change the owner of /u to \"root\".\n\
@@ -140,6 +153,14 @@ Examples:\n\
   %s -hR root /u    Change the owner of /u and subfiles to \"root\".\n\
 "),
               program_name, program_name, program_name);
+      else
+        printf (_("\
+\n\
+Examples:\n\
+  %s staff /u      Change the group of /u to \"staff\".\n\
+  %s -hR staff /u  Change the group of /u and subfiles to \"staff\".\n\
+"),
+              program_name, program_name);
       emit_ancillary_info (PROGRAM_NAME);
     }
   exit (status);
@@ -283,24 +304,38 @@ main (int argc, char **argv)
         error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
                quoteaf (reference_file));
 
-      uid = ref_stats.st_uid;
+      if (chown_mode == CHOWN_CHOWN)
+        {
+          uid = ref_stats.st_uid;
+          chopt.user_name = uid_to_name (ref_stats.st_uid);
+        }
       gid = ref_stats.st_gid;
-      chopt.user_name = uid_to_name (ref_stats.st_uid);
       chopt.group_name = gid_to_name (ref_stats.st_gid);
     }
   else
     {
+      char *ug = argv[optind];
+      if (chown_mode == CHOWN_CHGRP)
+        {
+          ug = xmalloc (1 + strlen (argv[optind]) + 1);
+          stpcpy (stpcpy (ug, ":"), argv[optind]);
+        }
+
       bool warn;
-      char const *e = parse_user_spec_warn (argv[optind], &uid, &gid,
+      char const *e = parse_user_spec_warn (ug, &uid, &gid,
                                             &chopt.user_name,
                                             &chopt.group_name, &warn);
+
+      if (ug != argv[optind])
+        free (ug);
+
       if (e)
         error (warn ? 0 : EXIT_FAILURE, 0, "%s: %s", e, quote (argv[optind]));
 
       /* If a group is specified but no user, set the user name to the
          empty string so that diagnostics say "ownership :GROUP"
          rather than "group GROUP".  */
-      if (!chopt.user_name && chopt.group_name)
+      if (chown_mode == CHOWN_CHOWN && !chopt.user_name && chopt.group_name)
         chopt.user_name = xstrdup ("");
 
       optind++;
diff --git a/src/chown.h b/src/chown.h
new file mode 100644 (file)
index 0000000..21f01c4
--- /dev/null
@@ -0,0 +1,7 @@
+/* This is for the 'chown' program. */
+#define CHOWN_CHOWN 1
+
+/* This is for the 'chgrp' program.  */
+#define CHOWN_CHGRP 2
+
+extern int chown_mode;
diff --git a/src/coreutils-chgrp.c b/src/coreutils-chgrp.c
new file mode 100644 (file)
index 0000000..1b281f6
--- /dev/null
@@ -0,0 +1,33 @@
+/* chgrp -- wrapper to uname with the right chown_mode.
+   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 <https://www.gnu.org/licenses/>.  */
+
+/* Written by Alex Deymo <deymo@chromium.org>.  */
+
+#include <config.h>
+#include "system.h"
+
+#include "chown.h"
+/* Ensure that the main for chown is declared even if the tool is not being
+   built in this single-binary. */
+int single_binary_main_chown (int argc, char **argv);
+int single_binary_main_chgrp (int argc, char **argv);
+
+int
+single_binary_main_chgrp (int argc, char **argv)
+{
+  chown_mode = CHOWN_CHGRP;
+  return single_binary_main_chown (argc, argv);
+}
index ed5d46ddbb9e0801eb6d389193593667c31399bb..61e0227fe9f0264434c1b7fecbf4ad56cb6b2ed5 100644 (file)
@@ -105,7 +105,7 @@ src_basenc_LDADD = $(LDADD)
 src_basename_LDADD = $(LDADD)
 src_cat_LDADD = $(LDADD)
 src_chcon_LDADD = $(LDADD)
-src_chgrp_LDADD = $(LDADD)
+# See chgrp_LDADD below
 src_chmod_LDADD = $(LDADD)
 src_chown_LDADD = $(LDADD)
 src_chroot_LDADD = $(LDADD)
@@ -219,6 +219,7 @@ src_yes_LDADD = $(LDADD)
 src___LDADD = $(src_test_LDADD)
 src_dir_LDADD = $(src_ls_LDADD)
 src_vdir_LDADD = $(src_ls_LDADD)
+src_chgrp_LDADD = $(src_chown_LDADD)
 
 src_cp_LDADD += $(copy_ldadd)
 src_ginstall_LDADD += $(copy_ldadd)
@@ -379,8 +380,8 @@ src_ls_SOURCES = src/ls.c src/ls-ls.c
 src_ln_SOURCES = src/ln.c \
   src/force-link.c src/force-link.h \
   src/relpath.c src/relpath.h
-src_chown_SOURCES = src/chown.c src/chown-core.c
-src_chgrp_SOURCES = src/chgrp.c src/chown-core.c
+src_chown_SOURCES = src/chown.c src/chown-core.c src/chown-chown.c
+src_chgrp_SOURCES = src/chown.c src/chown-core.c src/chown-chgrp.c
 src_kill_SOURCES = src/kill.c src/operand2sig.c
 src_realpath_SOURCES = src/realpath.c src/relpath.c src/relpath.h
 src_timeout_SOURCES = src/timeout.c src/operand2sig.c