From 197dd1b911fa3003f6282a57eec84222b539cb02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1draig=20Brady?= Date: Wed, 27 Dec 2023 13:28:02 +0000 Subject: [PATCH] maint: merge chgrp and chown sources 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). (usage): Adjust depending on utility being called. * src/coreutils-chgrp.c: Likewise. * src/local.mk: Reference new wrappers. --- build-aux/gen-single-binary.sh | 1 + cfg.mk | 3 +- po/POTFILES.in | 1 - src/chgrp.c | 335 --------------------------------- src/chown-chgrp.c | 2 + src/chown-chown.c | 2 + src/chown.c | 63 +++++-- src/coreutils-chgrp.c | 33 ++++ src/local.mk | 9 +- 9 files changed, 94 insertions(+), 355 deletions(-) delete mode 100644 src/chgrp.c create mode 100644 src/chown-chgrp.c create mode 100644 src/chown-chown.c create mode 100644 src/coreutils-chgrp.c diff --git a/build-aux/gen-single-binary.sh b/build-aux/gen-single-binary.sh index 1e8f495b4..7d15b9bfc 100755 --- a/build-aux/gen-single-binary.sh +++ b/build-aux/gen-single-binary.sh @@ -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 378d97687..185d5005e 100644 --- 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)$$ diff --git a/po/POTFILES.in b/po/POTFILES.in index 751af7cc6..6a7d16d43 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -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 index 51fc10782..000000000 --- a/src/chgrp.c +++ /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 . */ - -/* Written by David MacKenzie . */ - -#include -#include -#include -#include -#include - -#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 index 000000000..aa0b18007 --- /dev/null +++ b/src/chown-chgrp.c @@ -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 index 000000000..9531fa260 --- /dev/null +++ b/src/chown-chown.c @@ -0,0 +1,2 @@ +#include "chown.h" +int chown_mode = CHOWN_CHOWN; diff --git a/src/chown.c b/src/chown.c index b2cb973b0..cfc34920b 100644 --- a/src/chown.c +++ b/src/chown.c @@ -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 #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/coreutils-chgrp.c b/src/coreutils-chgrp.c new file mode 100644 index 000000000..1b281f670 --- /dev/null +++ b/src/coreutils-chgrp.c @@ -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 . */ + +/* Written by Alex Deymo . */ + +#include +#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); +} diff --git a/src/local.mk b/src/local.mk index ed5d46ddb..692d9ba6d 100644 --- a/src/local.mk +++ b/src/local.mk @@ -105,9 +105,9 @@ 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_chown = $(LDADD) src_chroot_LDADD = $(LDADD) src_cksum_LDADD = $(LDADD) src_comm_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 -- 2.43.0