/* chgrp -- change group ownership of files This is the chgrp utility
Copyright (C) 1989-2018 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/>. */ The GNUv3 license
/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
#include <config.h> Provides system specific information
#include <stdio.h> Provides standard I/O capability
#include <sys/types.h> Provides system data types
#include <grp.h> ...!includes auto-comment...
#include <getopt.h> ...!includes auto-comment...
#include "system.h" ...!includes auto-comment...
#include "chown-core.h" ...!includes auto-comment...
#include "die.h" ...!includes auto-comment...
#include "error.h" ...!includes auto-comment...
#include "fts_.h" ...!includes auto-comment...
#include "quote.h" ...!includes auto-comment...
#include "root-dev-ino.h" ...!includes auto-comment......!includes auto-comment...
#include "xstrtol.h" ...!includes auto-comment...
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "chgrp" Line 35
#define AUTHORS \ Line 37
proper_name ("David MacKenzie"), \ Line 38
proper_name ("Jim Meyering") Line 39
#if ! HAVE_ENDGRENT Line 41
# define endgrent() ((void) 0) Line 42
#endif Line 43
/* The argument to the --reference option. Use the group ID of this file.
This file must exist. */
static char *reference_file; Line 47
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum Line 51
{
DEREFERENCE_OPTION = CHAR_MAX + 1, Line 53
NO_PRESERVE_ROOT, Line 54
PRESERVE_ROOT, Line 55
REFERENCE_FILE_OPTION Line 56
}; Block 1
static struct option const long_options[] = Line 59
{
{"recursive", no_argument, NULL, 'R'}, Line 61
{"changes", no_argument, NULL, 'c'}, Line 62
{"dereference", no_argument, NULL, DEREFERENCE_OPTION}, Line 63
{"no-dereference", no_argument, NULL, 'h'}, Line 64
{"no-preserve-root", no_argument, NULL, NO_PRESERVE_ROOT}, Line 65
{"preserve-root", no_argument, NULL, PRESERVE_ROOT}, Line 66
{"quiet", no_argument, NULL, 'f'}, Line 67
{"silent", no_argument, NULL, 'f'}, Line 68
{"reference", required_argument, NULL, REFERENCE_FILE_OPTION}, Line 69
{"verbose", no_argument, NULL, 'v'}, Line 70
{GETOPT_HELP_OPTION_DECL}, Line 71
{GETOPT_VERSION_OPTION_DECL}, Line 72
{NULL, 0, NULL, 0} Line 73
}; Block 2
/* Return the group ID of NAME, or -1 if no name was specified. */
static gid_t Line 78
parse_group (const char *name) Line 79
{
gid_t gid = -1; Line 81
if (*name) Line 83
{
struct group *grp = getgrnam (name); Line 85
if (grp) Line 86
gid = grp->gr_gid; Line 87
else Line 88
{
unsigned long int tmp; Line 90
if (! (xstrtoul (name, NULL, 10, &tmp, "") == LONGINT_OK Line 91
&& tmp <= GID_T_MAX)) Line 92
die (EXIT_FAILURE, 0, _("invalid group: %s"), Line 93
quote (name)); Line 94
gid = tmp; Line 95
}
endgrent (); /* Save a file descriptor. */ Line 97
}
return gid; Line 100
} Block 3
void Line 103
usage (int status) Line 104
{
if (status != EXIT_SUCCESS) Line 106
emit_try_help (); ...!common auto-comment...
else Line 108
{
printf (_("\ Line 110
Usage: %s [OPTION]... GROUP FILE...\n\ Line 111
or: %s [OPTION]... --reference=RFILE FILE...\n\ Line 112
"), Line 113
program_name, program_name); Line 114
fputs (_("\ Line 115
Change the group of each FILE to GROUP.\n\ Line 116
With --reference, change the group of each FILE to that of RFILE.\n\ Line 117
\n\
"), stdout); Line 119
fputs (_("\ Line 120
-c, --changes like verbose but report only when a change is made\n\ Line 121
-f, --silent, --quiet suppress most error messages\n\ Line 122
-v, --verbose output a diagnostic for every file processed\n\ Line 123
"), stdout); Line 124
fputs (_("\ Line 125
--dereference affect the referent of each symbolic link (this is\n\ Line 126...!syscalls auto-comment...
the default), rather than the symbolic link itself\n\ Line 127
-h, --no-dereference affect symbolic links instead of any referenced file\n\Line 128
"), stdout); Line 129
fputs (_("\ Line 130
(useful only on systems that can change the\n\ Line 131
ownership of a symlink)\n\ Line 132
"), stdout); Line 133
fputs (_("\ Line 134
--no-preserve-root do not treat '/' specially (the default)\n\ Line 135
--preserve-root fail to operate recursively on '/'\n\ Line 136
"), stdout); Line 137
fputs (_("\ Line 138
--reference=RFILE use RFILE's group rather than specifying a\n\ Line 139
GROUP value\n\ Line 140
"), stdout); Line 141
fputs (_("\ Line 142
-R, --recursive operate on files and directories recursively\n\ Line 143
"), stdout); Line 144
fputs (_("\ Line 145
\n\
The following options modify how a hierarchy is traversed when the -R\n\ Line 147
option is also specified. If more than one is specified, only the final\n\ Line 148
one takes effect.\n\ Line 149
\n\
-H if a command line argument is a symbolic link\n\ Line 151
to a directory, traverse it\n\ Line 152
-L traverse every symbolic link to a directory\n\ Line 153
encountered\n\ Line 154
-P do not traverse any symbolic links (default)\n\ Line 155
\n\
"), stdout); Line 157
fputs (HELP_OPTION_DESCRIPTION, stdout); Line 158
fputs (VERSION_OPTION_DESCRIPTION, stdout); Line 159
printf (_("\ Line 160
\n\
Examples:\n\ Line 162
%s staff /u Change the group of /u to \"staff\".\n\ Line 163
%s -hR staff /u Change the group of /u and subfiles to \"staff\".\n\ Line 164
"), Line 165
program_name, program_name); Line 166
emit_ancillary_info (PROGRAM_NAME); Line 167
}
exit (status); Line 169
} Block 4
int
main (int argc, char **argv) Line 173
{
bool preserve_root = false; Line 175
gid_t gid; Line 176
/* Bit flags that control how fts works. */
int bit_flags = FTS_PHYSICAL; Line 179
/* 1 if --dereference, 0 if --no-dereference, -1 if neither has been
specified. */
int dereference = -1; Line 183
struct Chown_option chopt; Line 185
bool ok; Line 186
int optc; Line 187
initialize_main (&argc, &argv); VMS-specific entry point handling wildcard expansion
set_program_name (argv[0]); Retains program name and discards path
setlocale (LC_ALL, ""); Sets up internationalization (i18n)
bindtextdomain (PACKAGE, LOCALEDIR); Assigns i18n directorySets text domain for _() [gettext()] function
textdomain (PACKAGE); Sets text domain for _() [gettext()] function
atexit (close_stdout); Close stdout on exit (see gnulib)
chopt_init (&chopt); Line 197
while ((optc = getopt_long (argc, argv, "HLPRcfhv", long_options, NULL)) Line 199
!= -1) Line 200
{
switch (optc) Line 202
{
case 'H': /* Traverse command-line symlinks-to-directories. */ Line 204
bit_flags = FTS_COMFOLLOW | FTS_PHYSICAL; Line 205
break; Line 206
case 'L': /* Traverse all symlinks-to-directories. */ Line 208
bit_flags = FTS_LOGICAL; Line 209
break; Line 210
case 'P': /* Traverse no symlinks-to-directories. */ Line 212
bit_flags = FTS_PHYSICAL; Line 213
break; Line 214
case 'h': /* --no-dereference: affect symlinks */ Line 216
dereference = 0; Line 217
break; Line 218
case DEREFERENCE_OPTION: /* --dereference: affect the referent Line 220
of each symlink */
dereference = 1; Line 222
break; Line 223
case NO_PRESERVE_ROOT: Line 225
preserve_root = false; Line 226
break; Line 227
case PRESERVE_ROOT: Line 229
preserve_root = true; Line 230
break; Line 231
case REFERENCE_FILE_OPTION: Line 233
reference_file = optarg; Line 234
break; Line 235
case 'R': Line 237
chopt.recurse = true; Line 238
break; Line 239
case 'c': Line 241
chopt.verbosity = V_changes_only; Line 242
break; Line 243
case 'f': Line 245
chopt.force_silent = true; Line 246
break; Line 247
case 'v': Line 249
chopt.verbosity = V_high; Line 250
break; Line 251
case_GETOPT_HELP_CHAR; Line 253
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); Line 254
default: Line 255
usage (EXIT_FAILURE); Line 256
}
}
if (chopt.recurse) Line 260
{
if (bit_flags == FTS_PHYSICAL) Line 262
{
if (dereference == 1) Line 264
die (EXIT_FAILURE, 0, Line 265
_("-R --dereference requires either -H or -L")); Line 266
dereference = 0; Line 267
}
}
else Line 270
{
bit_flags = FTS_PHYSICAL; Line 272
}
chopt.affect_symlink_referent = (dereference != 0); Line 274
if (argc - optind < (reference_file ? 1 : 2)) Line 276
{
if (argc <= optind) Line 278
error (0, 0, _("missing operand")); Line 279
else Line 280
error (0, 0, _("missing operand after %s"), quote (argv[argc - 1])); Line 281
usage (EXIT_FAILURE); Line 282
}
if (reference_file) Line 285
{
struct stat ref_stats; Line 287
if (stat (reference_file, &ref_stats)) Line 288...!syscalls auto-comment...
die (EXIT_FAILURE, errno, _("failed to get attributes of %s"), Line 289
quoteaf (reference_file)); Line 290
gid = ref_stats.st_gid; Line 292
chopt.group_name = gid_to_name (ref_stats.st_gid); Line 293
}
else Line 295
{
char *group_name = argv[optind++]; Line 297
chopt.group_name = (*group_name ? xstrdup (group_name) : NULL); Line 298
gid = parse_group (group_name); Line 299
}
if (chopt.recurse && preserve_root) Line 302
{
static struct dev_ino dev_ino_buf; Line 304
chopt.root_dev_ino = get_root_dev_ino (&dev_ino_buf); Line 305
if (chopt.root_dev_ino == NULL) Line 306
die (EXIT_FAILURE, errno, _("failed to get attributes of %s"), Line 307
quoteaf ("/")); Line 308
}
bit_flags |= FTS_DEFER_STAT; Line 311
ok = chown_files (argv + optind, bit_flags, Line 312
(uid_t) -1, gid, Line 313
(uid_t) -1, (gid_t) -1, &chopt); Line 314
IF_LINT (chopt_free (&chopt)); Line 316
return ok ? EXIT_SUCCESS : EXIT_FAILURE; Line 318
} Block 5