/* chown -- change user and group ownership of files This is the chown 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 <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 "userspec.h" ...!includes auto-comment...
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "chown" Line 34
#define AUTHORS \ Line 36
proper_name ("David MacKenzie"), \ Line 37
proper_name ("Jim Meyering") Line 38
/* The argument to the --reference option. Use the owner and group IDs
of this file. This file must exist. */
static char *reference_file; Line 42
/* 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 46
{
DEREFERENCE_OPTION = CHAR_MAX + 1, Line 48
FROM_OPTION, Line 49
NO_PRESERVE_ROOT, Line 50
PRESERVE_ROOT, Line 51
REFERENCE_FILE_OPTION Line 52
}; Block 1
static struct option const long_options[] = Line 55
{
{"recursive", no_argument, NULL, 'R'}, Line 57
{"changes", no_argument, NULL, 'c'}, Line 58
{"dereference", no_argument, NULL, DEREFERENCE_OPTION}, Line 59
{"from", required_argument, NULL, FROM_OPTION}, Line 60
{"no-dereference", no_argument, NULL, 'h'}, Line 61
{"no-preserve-root", no_argument, NULL, NO_PRESERVE_ROOT}, Line 62
{"preserve-root", no_argument, NULL, PRESERVE_ROOT}, Line 63
{"quiet", no_argument, NULL, 'f'}, Line 64
{"silent", no_argument, NULL, 'f'}, Line 65
{"reference", required_argument, NULL, REFERENCE_FILE_OPTION}, Line 66
{"verbose", no_argument, NULL, 'v'}, Line 67
{GETOPT_HELP_OPTION_DECL}, Line 68
{GETOPT_VERSION_OPTION_DECL}, Line 69
{NULL, 0, NULL, 0} Line 70
}; Block 2
void Line 73
usage (int status) Line 74
{
if (status != EXIT_SUCCESS) Line 76
emit_try_help (); ...!common auto-comment...
else Line 78
{
printf (_("\ Line 80
Usage: %s [OPTION]... [OWNER][:[GROUP]] FILE...\n\ Line 81
or: %s [OPTION]... --reference=RFILE FILE...\n\ Line 82
"), Line 83
program_name, program_name); Line 84
fputs (_("\ Line 85
Change the owner and/or group of each FILE to OWNER and/or GROUP.\n\ Line 86
With --reference, change the owner and group of each FILE to those of RFILE.\n\ Line 87
\n\
"), stdout); Line 89
fputs (_("\ Line 90
-c, --changes like verbose but report only when a change is made\n\ Line 91
-f, --silent, --quiet suppress most error messages\n\ Line 92
-v, --verbose output a diagnostic for every file processed\n\ Line 93
"), stdout); Line 94
fputs (_("\ Line 95
--dereference affect the referent of each symbolic link (this is\n\ Line 96...!syscalls auto-comment...
the default), rather than the symbolic link itself\n\ Line 97
-h, --no-dereference affect symbolic links instead of any referenced file\n\Line 98
"), stdout); Line 99
fputs (_("\ Line 100
(useful only on systems that can change the\n\ Line 101
ownership of a symlink)\n\ Line 102
"), stdout); Line 103
fputs (_("\ Line 104
--from=CURRENT_OWNER:CURRENT_GROUP\n\ Line 105
change the owner and/or group of each file only if\n\ Line 106
its current owner and/or group match those specified\n\Line 107
here. Either may be omitted, in which case a match\n\ Line 108
is not required for the omitted attribute\n\ Line 109
"), stdout); Line 110
fputs (_("\ Line 111
--no-preserve-root do not treat '/' specially (the default)\n\ Line 112
--preserve-root fail to operate recursively on '/'\n\ Line 113
"), stdout); Line 114
fputs (_("\ Line 115
--reference=RFILE use RFILE's owner and group rather than\n\ Line 116
specifying OWNER:GROUP values\n\ Line 117
"), stdout); Line 118
fputs (_("\ Line 119
-R, --recursive operate on files and directories recursively\n\ Line 120
"), stdout); Line 121
fputs (_("\ Line 122
\n\
The following options modify how a hierarchy is traversed when the -R\n\ Line 124
option is also specified. If more than one is specified, only the final\n\ Line 125
one takes effect.\n\ Line 126
\n\
-H if a command line argument is a symbolic link\n\ Line 128
to a directory, traverse it\n\ Line 129
-L traverse every symbolic link to a directory\n\ Line 130
encountered\n\ Line 131
-P do not traverse any symbolic links (default)\n\ Line 132
\n\
"), stdout); Line 134
fputs (HELP_OPTION_DESCRIPTION, stdout); Line 135
fputs (VERSION_OPTION_DESCRIPTION, stdout); Line 136
fputs (_("\ Line 137
\n\
Owner is unchanged if missing. Group is unchanged if missing, but changed\n\ Line 139
to login group if implied by a ':' following a symbolic OWNER.\n\ Line 140
OWNER and GROUP may be numeric as well as symbolic.\n\ Line 141
"), stdout); Line 142
printf (_("\ Line 143
\n\
Examples:\n\ Line 145
%s root /u Change the owner of /u to \"root\".\n\ Line 146
%s root:staff /u Likewise, but also change its group to \"staff\".\n\ Line 147
%s -hR root /u Change the owner of /u and subfiles to \"root\".\n\ Line 148
"), Line 149
program_name, program_name, program_name); Line 150
emit_ancillary_info (PROGRAM_NAME); Line 151
}
exit (status); Line 153
} Block 3
int
main (int argc, char **argv) Line 157
{
bool preserve_root = false; Line 159
uid_t uid = -1; /* Specified uid; -1 if not to be changed. */ Line 161
gid_t gid = -1; /* Specified gid; -1 if not to be changed. */ Line 162
/* Change the owner (group) of a file only if it has this uid (gid).
-1 means there's no restriction. */
uid_t required_uid = -1; Line 166
gid_t required_gid = -1; Line 167
/* Bit flags that control how fts works. */
int bit_flags = FTS_PHYSICAL; Line 170
/* 1 if --dereference, 0 if --no-dereference, -1 if neither has been
specified. */
int dereference = -1; Line 174
struct Chown_option chopt; Line 176
bool ok; Line 177
int optc; Line 178
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 188
while ((optc = getopt_long (argc, argv, "HLPRcfhv", long_options, NULL)) Line 190
!= -1) Line 191
{
switch (optc) Line 193
{
case 'H': /* Traverse command-line symlinks-to-directories. */ Line 195
bit_flags = FTS_COMFOLLOW | FTS_PHYSICAL; Line 196
break; Line 197
case 'L': /* Traverse all symlinks-to-directories. */ Line 199
bit_flags = FTS_LOGICAL; Line 200
break; Line 201
case 'P': /* Traverse no symlinks-to-directories. */ Line 203
bit_flags = FTS_PHYSICAL; Line 204
break; Line 205
case 'h': /* --no-dereference: affect symlinks */ Line 207
dereference = 0; Line 208
break; Line 209
case DEREFERENCE_OPTION: /* --dereference: affect the referent Line 211
of each symlink */
dereference = 1; Line 213
break; Line 214
case NO_PRESERVE_ROOT: Line 216
preserve_root = false; Line 217
break; Line 218
case PRESERVE_ROOT: Line 220
preserve_root = true; Line 221
break; Line 222
case REFERENCE_FILE_OPTION: Line 224
reference_file = optarg; Line 225
break; Line 226
case FROM_OPTION: Line 228
{
const char *e = parse_user_spec (optarg, Line 230
&required_uid, &required_gid, Line 231
NULL, NULL); Line 232
if (e) Line 233
die (EXIT_FAILURE, 0, "%s: %s", e, quote (optarg)); Line 234
break; Line 235
}
case 'R': Line 238
chopt.recurse = true; Line 239
break; Line 240
case 'c': Line 242
chopt.verbosity = V_changes_only; Line 243
break; Line 244
case 'f': Line 246
chopt.force_silent = true; Line 247
break; Line 248
case 'v': Line 250
chopt.verbosity = V_high; Line 251
break; Line 252
case_GETOPT_HELP_CHAR; Line 254
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); Line 255
default: Line 256
usage (EXIT_FAILURE); Line 257
}
}
if (chopt.recurse) Line 261
{
if (bit_flags == FTS_PHYSICAL) Line 263
{
if (dereference == 1) Line 265
die (EXIT_FAILURE, 0, Line 266
_("-R --dereference requires either -H or -L")); Line 267
dereference = 0; Line 268
}
}
else Line 271
{
bit_flags = FTS_PHYSICAL; Line 273
}
chopt.affect_symlink_referent = (dereference != 0); Line 275
if (argc - optind < (reference_file ? 1 : 2)) Line 277
{
if (argc <= optind) Line 279
error (0, 0, _("missing operand")); Line 280
else Line 281
error (0, 0, _("missing operand after %s"), quote (argv[argc - 1])); Line 282
usage (EXIT_FAILURE); Line 283
}
if (reference_file) Line 286
{
struct stat ref_stats; Line 288
if (stat (reference_file, &ref_stats)) Line 289...!syscalls auto-comment...
die (EXIT_FAILURE, errno, _("failed to get attributes of %s"), Line 290
quoteaf (reference_file)); Line 291
uid = ref_stats.st_uid; Line 293
gid = ref_stats.st_gid; Line 294
chopt.user_name = uid_to_name (ref_stats.st_uid); Line 295
chopt.group_name = gid_to_name (ref_stats.st_gid); Line 296
}
else Line 298
{
const char *e = parse_user_spec (argv[optind], &uid, &gid, Line 300
&chopt.user_name, &chopt.group_name); Line 301
if (e) Line 302
die (EXIT_FAILURE, 0, "%s: %s", e, quote (argv[optind])); Line 303
/* 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) Line 308
chopt.user_name = xstrdup (""); Line 309
optind++; Line 311
}
if (chopt.recurse && preserve_root) Line 314
{
static struct dev_ino dev_ino_buf; Line 316
chopt.root_dev_ino = get_root_dev_ino (&dev_ino_buf); Line 317
if (chopt.root_dev_ino == NULL) Line 318
die (EXIT_FAILURE, errno, _("failed to get attributes of %s"), Line 319
quoteaf ("/")); Line 320
}
bit_flags |= FTS_DEFER_STAT; Line 323
ok = chown_files (argv + optind, bit_flags, Line 324
uid, gid, Line 325
required_uid, required_gid, &chopt); Line 326
IF_LINT (chopt_free (&chopt)); Line 328
return ok ? EXIT_SUCCESS : EXIT_FAILURE; Line 330
} Block 4