/* install - copy files and set attributes This is the install 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 <getopt.h> ...!includes auto-comment...
#include <sys/types.h> Provides system data types
#include <signal.h> ...!includes auto-comment...
#include <pwd.h> ...!includes auto-comment...
#include <grp.h> ...!includes auto-comment...
#include <selinux/selinux.h> ...!includes auto-comment......!includes auto-comment...
#include <sys/wait.h> ...!includes auto-comment...
#include "system.h" ...!includes auto-comment...
#include "backupfile.h" ...!includes auto-comment...
#include "error.h" ...!includes auto-comment...
#include "cp-hash.h" ...!includes auto-comment......!includes auto-comment...
#include "copy.h" ...!includes auto-comment...
#include "die.h" ...!includes auto-comment...
#include "filenamecat.h" ...!includes auto-comment...
#include "full-read.h" ...!includes auto-comment...
#include "mkancesdirs.h" ...!includes auto-comment...
#include "mkdir-p.h" ...!includes auto-comment...
#include "modechange.h" ...!includes auto-comment...
#include "prog-fprintf.h" ...!includes auto-comment...
#include "quote.h" ...!includes auto-comment...
#include "savewd.h" ...!includes auto-comment...
#include "selinux.h" ...!includes auto-comment...
#include "stat-time.h" ...!includes auto-comment...
#include "utimens.h" ...!includes auto-comment...
#include "xstrtol.h" ...!includes auto-comment...
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "install" Line 49
#define AUTHORS proper_name ("David MacKenzie") Line 51
static int selinux_enabled = 0; Line 53
static bool use_default_selinux_context = true; Line 54
#if ! HAVE_ENDGRENT Line 56
# define endgrent() ((void) 0) Line 57
#endif Line 58
#if ! HAVE_ENDPWENT Line 60
# define endpwent() ((void) 0) Line 61
#endif Line 62
#if ! HAVE_LCHOWN Line 64
# define lchown(name, uid, gid) chown (name, uid, gid) Line 65
#endif Line 66
#if ! HAVE_MATCHPATHCON_INIT_PREFIX Line 68
# define matchpathcon_init_prefix(a, p) /* empty */ Line 69
#endif Line 70
/* The user name that will own the files, or NULL to make the owner
the current user ID. */
static char *owner_name; Line 74
/* The user ID corresponding to 'owner_name'. */
static uid_t owner_id; Line 77
/* The group name that will own the files, or NULL to make the group
the current group ID. */
static char *group_name; Line 81
/* The group ID corresponding to 'group_name'. */
static gid_t group_id; Line 84
#define DEFAULT_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) Line 86
/* The file mode bits to which non-directory files will be set. The umask has
no effect. */
static mode_t mode = DEFAULT_MODE; Line 90
/* Similar, but for directories. */
static mode_t dir_mode = DEFAULT_MODE; Line 93
/* The file mode bits that the user cares about. This should be a
superset of DIR_MODE and a subset of CHMOD_MODE_BITS. This matters
for directories, since otherwise directories may keep their S_ISUID
or S_ISGID bits. */
static mode_t dir_mode_bits = CHMOD_MODE_BITS; Line 99
/* Compare files before installing (-C) */
static bool copy_only_if_needed; Line 102
/* If true, strip executable files after copying them. */
static bool strip_files; Line 105
/* If true, install a directory instead of a regular file. */
static bool dir_arg; Line 108
/* Program used to strip binaries, "strip" is default */
static char const *strip_program = "strip"; Line 111
/* 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 115
{
PRESERVE_CONTEXT_OPTION = CHAR_MAX + 1, Line 117
STRIP_PROGRAM_OPTION Line 118
}; Block 1
static struct option const long_options[] = Line 121
{
{"backup", optional_argument, NULL, 'b'}, Line 123
{"compare", no_argument, NULL, 'C'}, Line 124
{GETOPT_SELINUX_CONTEXT_OPTION_DECL}, Line 125
{"directory", no_argument, NULL, 'd'}, Line 126
{"group", required_argument, NULL, 'g'}, Line 127
{"mode", required_argument, NULL, 'm'}, Line 128
{"no-target-directory", no_argument, NULL, 'T'}, Line 129
{"owner", required_argument, NULL, 'o'}, Line 130
{"preserve-timestamps", no_argument, NULL, 'p'}, Line 131
{"preserve-context", no_argument, NULL, PRESERVE_CONTEXT_OPTION}, Line 132
{"strip", no_argument, NULL, 's'}, Line 133
{"strip-program", required_argument, NULL, STRIP_PROGRAM_OPTION}, Line 134
{"suffix", required_argument, NULL, 'S'}, Line 135
{"target-directory", required_argument, NULL, 't'}, Line 136
{"verbose", no_argument, NULL, 'v'}, Line 137
{GETOPT_HELP_OPTION_DECL}, Line 138
{GETOPT_VERSION_OPTION_DECL}, Line 139
{NULL, 0, NULL, 0} Line 140
}; Block 2
/* Compare content of opened files using file descriptors A_FD and B_FD. Return
true if files are equal. */
static bool Line 145
have_same_content (int a_fd, int b_fd) Line 146
{
enum { CMP_BLOCK_SIZE = 4096 }; Line 148
static char a_buff[CMP_BLOCK_SIZE]; Line 149
static char b_buff[CMP_BLOCK_SIZE]; Line 150
size_t size; Line 152
while (0 < (size = full_read (a_fd, a_buff, sizeof a_buff))) { Line 153...!syscalls auto-comment...
if (size != full_read (b_fd, b_buff, sizeof b_buff)) Line 154...!syscalls auto-comment...
return false; Line 155
if (memcmp (a_buff, b_buff, size) != 0) Line 157
return false; Line 158
}
return size == 0; Line 161
} Block 3
/* Return true for mode with non-permission bits. */
static bool Line 165
extra_mode (mode_t input) Line 166
{
mode_t mask = S_IRWXUGO | S_IFMT; Line 168
return !! (input & ~ mask); Line 169
} Block 4
/* Return true if copy of file SRC_NAME to file DEST_NAME is necessary. */
static bool Line 173
need_copy (const char *src_name, const char *dest_name, Line 174
const struct cp_options *x) Line 175
{
struct stat src_sb, dest_sb; Line 177
int src_fd, dest_fd; Line 178
bool content_match; Line 179
if (extra_mode (mode)) Line 181
return true; Line 182
/* compare files using stat */
if (lstat (src_name, &src_sb) != 0) Line 185...!syscalls auto-comment...
return true; Line 186
if (lstat (dest_name, &dest_sb) != 0) Line 188...!syscalls auto-comment...
return true; Line 189
if (!S_ISREG (src_sb.st_mode) || !S_ISREG (dest_sb.st_mode) Line 191
|| extra_mode (src_sb.st_mode) || extra_mode (dest_sb.st_mode)) Line 192
return true; Line 193
if (src_sb.st_size != dest_sb.st_size Line 195
|| (dest_sb.st_mode & CHMOD_MODE_BITS) != mode) Line 196
return true; Line 197
if (owner_id == (uid_t) -1) Line 199
{
errno = 0; Line 201
uid_t ruid = getuid (); Line 202...!syscalls auto-comment...
if ((ruid == (uid_t) -1 && errno) || dest_sb.st_uid != ruid) Line 203
return true; Line 204
}
else if (dest_sb.st_uid != owner_id) Line 206
return true; Line 207
if (group_id == (uid_t) -1) Line 209
{
errno = 0; Line 211
gid_t rgid = getgid (); Line 212...!syscalls auto-comment...
if ((rgid == (uid_t) -1 && errno) || dest_sb.st_gid != rgid) Line 213
return true; Line 214
}
else if (dest_sb.st_gid != group_id) Line 216
return true; Line 217
/* compare SELinux context if preserving */
if (selinux_enabled && x->preserve_security_context) Line 220
{
char *file_scontext = NULL; Line 222
char *to_scontext = NULL; Line 223
bool scontext_match; Line 224
if (getfilecon (src_name, &file_scontext) == -1) Line 226
return true; Line 227
if (getfilecon (dest_name, &to_scontext) == -1) Line 229
{
freecon (file_scontext); Line 231
return true; Line 232
}
scontext_match = STREQ (file_scontext, to_scontext); Line 235
freecon (file_scontext); Line 237
freecon (to_scontext); Line 238
if (!scontext_match) Line 239
return true; Line 240
}
/* compare files content */
src_fd = open (src_name, O_RDONLY | O_BINARY); Line 244...!syscalls auto-comment...
if (src_fd < 0) Line 245
return true; Line 246
dest_fd = open (dest_name, O_RDONLY | O_BINARY); Line 248...!syscalls auto-comment...
if (dest_fd < 0) Line 249
{
close (src_fd); Line 251...!syscalls auto-comment...
return true; Line 252
}
content_match = have_same_content (src_fd, dest_fd); Line 255
close (src_fd); Line 257...!syscalls auto-comment...
close (dest_fd); Line 258...!syscalls auto-comment...
return !content_match; Line 259
} Block 5
static void Line 262
cp_option_init (struct cp_options *x) Line 263
{
cp_options_default (x); Line 265
x->copy_as_regular = true; Line 266
x->reflink_mode = REFLINK_NEVER; Line 267
x->dereference = DEREF_ALWAYS; Line 268
x->unlink_dest_before_opening = true; Line 269
x->unlink_dest_after_failed_open = false; Line 270
x->hard_link = false; Line 271
x->interactive = I_UNSPECIFIED; Line 272
x->move_mode = false; Line 273
x->install_mode = true; Line 274
x->one_file_system = false; Line 275
x->preserve_ownership = false; Line 276
x->preserve_links = false; Line 277
x->preserve_mode = false; Line 278
x->preserve_timestamps = false; Line 279
x->explicit_no_preserve_mode = false; Line 280
x->reduce_diagnostics=false; Line 281
x->data_copy_required = true; Line 282
x->require_preserve = false; Line 283
x->require_preserve_xattr = false; Line 284
x->recursive = false; Line 285
x->sparse_mode = SPARSE_AUTO; Line 286
x->symbolic_link = false; Line 287
x->backup_type = no_backups; Line 288
/* Create destination files initially writable so we can run strip on them.
Although GNU strip works fine on read-only files, some others
would fail. */
x->set_mode = true; Line 293
x->mode = S_IRUSR | S_IWUSR; Line 294
x->stdin_tty = false; Line 295
x->open_dangling_dest_symlink = false; Line 297
x->update = false; Line 298
x->require_preserve_context = false; /* Not used by install currently. */ Line 299
x->preserve_security_context = false; /* Whether to copy context from src. */Line 300
x->set_security_context = false; /* Whether to set sys default context. */Line 301
x->preserve_xattr = false; Line 302
x->verbose = false; Line 303
x->dest_info = NULL; Line 304
x->src_info = NULL; Line 305
} Block 6
#ifdef ENABLE_MATCHPATHCON Line 308
/* Modify file context to match the specified policy.
If an error occurs the file will remain with the default directory
context. Note this sets the context to that returned by matchpathcon,
and thus discards MLS levels and user identity of the FILE. */
static void Line 313
setdefaultfilecon (char const *file) Line 314
{
struct stat st; Line 316
char *scontext = NULL; Line 317
static bool first_call = true; Line 318
if (selinux_enabled != 1) Line 320
{
/* Indicate no context found. */
return; Line 323
}
if (lstat (file, &st) != 0) Line 325...!syscalls auto-comment...
return; Line 326
if (first_call && IS_ABSOLUTE_FILE_NAME (file)) Line 328
{
/* Calling matchpathcon_init_prefix (NULL, "/first_component/")
is an optimization to minimize the expense of the following
matchpathcon call. Do it only once, just before the first
matchpathcon call. We *could* call matchpathcon_fini after
the final matchpathcon call, but that's not necessary, since
by then we're about to exit, and besides, the buffers it
would free are still reachable. */
char const *p0; Line 337
char const *p = file + 1; Line 338
while (ISSLASH (*p)) Line 339
++p; Line 340
/* Record final leading slash, for when FILE starts with two or more. */
p0 = p - 1; Line 343
if (*p) Line 345
{
char *prefix; Line 347
do
{
++p; Line 350
}
while (*p && !ISSLASH (*p)); Line 352
prefix = malloc (p - p0 + 2); Line 354
if (prefix) Line 355
{
stpcpy (stpncpy (prefix, p0, p - p0), "/"); Line 357
matchpathcon_init_prefix (NULL, prefix); Line 358
free (prefix); Line 359
}
}
}
first_call = false; Line 363
/* If there's an error determining the context, or it has none,
return to allow default context. Note the "<<none>>" check
is only needed for libselinux < 1.20 (2005-01-04). */
if ((matchpathcon (file, st.st_mode, &scontext) != 0) Line 368
|| STREQ (scontext, "<<none>>")) Line 369
{
if (scontext != NULL) Line 371
freecon (scontext); Line 372
return; Line 373
}
if (lsetfilecon (file, scontext) < 0 && errno != ENOTSUP) Line 376
error (0, errno, Line 377
_("warning: %s: failed to change context to %s"), Line 378
quotef_n (0, file), quote_n (1, scontext)); Line 379
freecon (scontext); Line 381
return; Line 382
} Block 7
#else Line 384
static void Line 385
setdefaultfilecon (char const *file) Line 386
{
(void) file; Line 388
} Block 8
#endif Line 390
/* FILE is the last operand of this command. Return true if FILE is a
directory. But report an error there is a problem accessing FILE,
or if FILE does not exist but would have to refer to an existing
directory if it referred to anything at all. */
static bool Line 397
target_directory_operand (char const *file) Line 398
{
char const *b = last_component (file); Line 400
size_t blen = strlen (b); Line 401
bool looks_like_a_dir = (blen == 0 || ISSLASH (b[blen - 1])); Line 402
struct stat st; Line 403
int err = (stat (file, &st) == 0 ? 0 : errno); Line 404...!syscalls auto-comment...
bool is_a_dir = !err && S_ISDIR (st.st_mode); Line 405
if (err && err != ENOENT) Line 406
die (EXIT_FAILURE, err, _("failed to access %s"), quoteaf (file)); Line 407
if (is_a_dir < looks_like_a_dir) Line 408
die (EXIT_FAILURE, err, _("target %s is not a directory"), Line 409
quoteaf (file)); Line 410
return is_a_dir; Line 411
} Block 9
/* Report that directory DIR was made, if OPTIONS requests this. */
static void Line 415
announce_mkdir (char const *dir, void *options) Line 416...!syscalls auto-comment...
{
struct cp_options const *x = options; Line 418
if (x->verbose) Line 419
prog_fprintf (stdout, _("creating directory %s"), quoteaf (dir)); Line 420
} Block 10
/* Make ancestor directory DIR, whose last file name component is
COMPONENT, with options OPTIONS. Assume the working directory is
COMPONENT's parent. */
static int Line 426
make_ancestor (char const *dir, char const *component, void *options) Line 427
{
struct cp_options const *x = options; Line 429
if (x->set_security_context && defaultcon (component, S_IFDIR) < 0 Line 430
&& ! ignorable_ctx_err (errno)) Line 431
error (0, errno, _("failed to set default creation context for %s"), Line 432
quoteaf (dir)); Line 433
int r = mkdir (component, DEFAULT_MODE); Line 435...!syscalls auto-comment...
if (r == 0) Line 436
announce_mkdir (dir, options); Line 437...!syscalls auto-comment...
return r; Line 438
} Block 11
/* Process a command-line file name, for the -d option. */
static int Line 442
process_dir (char *dir, struct savewd *wd, void *options) Line 443
{
struct cp_options const *x = options; Line 445
int ret = (make_dir_parents (dir, wd, make_ancestor, options, Line 447
dir_mode, announce_mkdir, Line 448
dir_mode_bits, owner_id, group_id, false) Line 449
? EXIT_SUCCESS Line 450
: EXIT_FAILURE); Line 451
/* FIXME: Due to the current structure of make_dir_parents()
we don't have the facility to call defaultcon() before the
final component of DIR is created. So for now, create the
final component with the context from previous component
and here we set the context for the final component. */
if (ret == EXIT_SUCCESS && x->set_security_context) Line 458
{
if (! restorecon (last_component (dir), false, false) Line 460
&& ! ignorable_ctx_err (errno)) Line 461
error (0, errno, _("failed to restore context for %s"), Line 462
quoteaf (dir)); Line 463
}
return ret; Line 466
} Block 12
/* Copy file FROM onto file TO, creating TO if necessary.
Return true if successful. */
static bool Line 472
copy_file (const char *from, const char *to, const struct cp_options *x) Line 473
{
bool copy_into_self; Line 475
if (copy_only_if_needed && !need_copy (from, to, x)) Line 477
return true; Line 478
/* Allow installing from non-regular files like /dev/null.
Charles Karney reported that some Sun version of install allows that
and that sendmail's installation process relies on the behavior.
However, since !x->recursive, the call to "copy" will fail if FROM
is a directory. */
return copy (from, to, false, x, ©_into_self, NULL); Line 486
} Block 13
/* Set the attributes of file or directory NAME.
Return true if successful. */
static bool Line 492
change_attributes (char const *name) Line 493
{
bool ok = false; Line 495
/* chown must precede chmod because on some systems,
chown clears the set[ug]id bits for non-superusers,
resulting in incorrect permissions.
On System V, users can give away files with chown and then not
be able to chmod them. So don't give files away.
We don't normally ignore errors from chown because the idea of
the install command is that the file is supposed to end up with
precisely the attributes that the user specified (or defaulted).
If the file doesn't end up with the group they asked for, they'll
want to know. */
if (! (owner_id == (uid_t) -1 && group_id == (gid_t) -1) Line 508
&& lchown (name, owner_id, group_id) != 0) Line 509
error (0, errno, _("cannot change ownership of %s"), quoteaf (name)); Line 510
else if (chmod (name, mode) != 0) Line 511
error (0, errno, _("cannot change permissions of %s"), quoteaf (name)); Line 512
else Line 513
ok = true; Line 514
if (use_default_selinux_context) Line 516
setdefaultfilecon (name); Line 517
return ok; Line 519
} Block 14
/* Set the timestamps of file DEST to match those of SRC_SB.
Return true if successful. */
static bool Line 525
change_timestamps (struct stat const *src_sb, char const *dest) Line 526
{
struct timespec timespec[2]; Line 528
timespec[0] = get_stat_atime (src_sb); Line 529
timespec[1] = get_stat_mtime (src_sb); Line 530
if (utimens (dest, timespec)) Line 532
{
error (0, errno, _("cannot set timestamps for %s"), quoteaf (dest)); Line 534
return false; Line 535
}
return true; Line 537
} Block 15
/* Strip the symbol table from the file NAME.
We could dig the magic number out of the file first to
determine whether to strip it, but the header files and
magic numbers vary so much from system to system that making
it portable would be very difficult. Not worth the effort. */
static bool Line 546
strip (char const *name) Line 547
{
int status; Line 549
bool ok = false; Line 550
pid_t pid = fork (); Line 551...!syscalls auto-comment...
switch (pid) Line 553
{
case -1: Line 555
error (0, errno, _("fork system call failed")); Line 556
break; Line 557
case 0: /* Child. */ Line 558
execlp (strip_program, strip_program, name, NULL); Line 559
die (EXIT_FAILURE, errno, _("cannot run %s"), quoteaf (strip_program)); Line 560
default: /* Parent. */ Line 561
if (waitpid (pid, &status, 0) < 0) Line 562
error (0, errno, _("waiting for strip")); Line 563
else if (! WIFEXITED (status) || WEXITSTATUS (status)) Line 564
error (0, 0, _("strip process terminated abnormally")); Line 565
else Line 566
ok = true; /* strip succeeded */ Line 567
break; Line 568
}
return ok; Line 570
} Block 16
/* Initialize the user and group ownership of the files to install. */
static void Line 575
get_ids (void) Line 576
{
struct passwd *pw; Line 578
struct group *gr; Line 579
if (owner_name) Line 581
{
pw = getpwnam (owner_name); Line 583
if (pw == NULL) Line 584
{
unsigned long int tmp; Line 586
if (xstrtoul (owner_name, NULL, 0, &tmp, NULL) != LONGINT_OK Line 587
|| UID_T_MAX < tmp) Line 588
die (EXIT_FAILURE, 0, _("invalid user %s"), Line 589
quote (owner_name)); Line 590
owner_id = tmp; Line 591
}
else Line 593
owner_id = pw->pw_uid; Line 594
endpwent (); Line 595
}
else Line 597
owner_id = (uid_t) -1; Line 598
if (group_name) Line 600
{
gr = getgrnam (group_name); Line 602
if (gr == NULL) Line 603
{
unsigned long int tmp; Line 605
if (xstrtoul (group_name, NULL, 0, &tmp, NULL) != LONGINT_OK Line 606
|| GID_T_MAX < tmp) Line 607
die (EXIT_FAILURE, 0, _("invalid group %s"), Line 608
quote (group_name)); Line 609
group_id = tmp; Line 610
}
else Line 612
group_id = gr->gr_gid; Line 613
endgrent (); Line 614
}
else Line 616
group_id = (gid_t) -1; Line 617
} Block 17
void Line 620
usage (int status) Line 621
{
if (status != EXIT_SUCCESS) Line 623
emit_try_help (); ...!common auto-comment...
else Line 625
{
printf (_("\ Line 627
Usage: %s [OPTION]... [-T] SOURCE DEST\n\ Line 628
or: %s [OPTION]... SOURCE... DIRECTORY\n\ Line 629
or: %s [OPTION]... -t DIRECTORY SOURCE...\n\ Line 630
or: %s [OPTION]... -d DIRECTORY...\n\ Line 631
"), Line 632
program_name, program_name, program_name, program_name); Line 633
fputs (_("\ Line 634
\n\
This install program copies files (often just compiled) into destination\n\ Line 636
locations you choose. If you want to download and install a ready-to-use\n\ Line 637
package on a GNU/Linux system, you should instead be using a package manager\n\ Line 638
like yum(1) or apt-get(1).\n\ Line 639
\n\
In the first three forms, copy SOURCE to DEST or multiple SOURCE(s) to\n\ Line 641
the existing DIRECTORY, while setting permission modes and owner/group.\n\ Line 642
In the 4th form, create all components of the given DIRECTORY(ies).\n\ Line 643
"), stdout); Line 644
emit_mandatory_arg_note (); ...!common auto-comment...
fputs (_("\ Line 648
--backup[=CONTROL] make a backup of each existing destination file\n\ Line 649
-b like --backup but does not accept an argument\n\ Line 650
-c (ignored)\n\ Line 651
-C, --compare compare each pair of source and destination files, and\n\ Line 652
in some cases, do not modify the destination at all\n\ Line 653
-d, --directory treat all arguments as directory names; create all\n\ Line 654
components of the specified directories\n\ Line 655
"), stdout); Line 656
fputs (_("\ Line 657
-D create all leading components of DEST except the last,\n\ Line 658
or all components of --target-directory,\n\ Line 659
then copy SOURCE to DEST\n\ Line 660
-g, --group=GROUP set group ownership, instead of process' current group\n\ Line 661
-m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\Line 662
-o, --owner=OWNER set ownership (super-user only)\n\ Line 663
"), stdout); Line 664
fputs (_("\ Line 665
-p, --preserve-timestamps apply access/modification times of SOURCE files\n\Line 666
to corresponding destination files\n\ Line 667
-s, --strip strip symbol tables\n\ Line 668
--strip-program=PROGRAM program used to strip binaries\n\ Line 669
-S, --suffix=SUFFIX override the usual backup suffix\n\ Line 670
-t, --target-directory=DIRECTORY copy all SOURCE arguments into DIRECTORY\n\ Line 671
-T, --no-target-directory treat DEST as a normal file\n\ Line 672
-v, --verbose print the name of each directory as it is created\n\ Line 673
"), stdout); Line 674
fputs (_("\ Line 675
--preserve-context preserve SELinux security context\n\ Line 676
-Z set SELinux security context of destination\n\ Line 677
file and each created directory to default type\n\ Line 678
--context[=CTX] like -Z, or if CTX is specified then set the\n\ Line 679
SELinux or SMACK security context to CTX\n\ Line 680
"), stdout); Line 681
fputs (HELP_OPTION_DESCRIPTION, stdout); Line 683
fputs (VERSION_OPTION_DESCRIPTION, stdout); Line 684
emit_backup_suffix_note (); Line 685
emit_ancillary_info (PROGRAM_NAME); Line 686
}
exit (status); Line 688
} Block 18
/* Copy file FROM onto file TO and give TO the appropriate
attributes.
Return true if successful. */
static bool Line 695
install_file_in_file (const char *from, const char *to, Line 696
const struct cp_options *x) Line 697
{
struct stat from_sb; Line 699
if (x->preserve_timestamps && stat (from, &from_sb) != 0) Line 700...!syscalls auto-comment...
{
error (0, errno, _("cannot stat %s"), quoteaf (from)); Line 702
return false; Line 703
}
if (! copy_file (from, to, x)) Line 705
return false; Line 706
if (strip_files) Line 707
if (! strip (to)) Line 708
{
if (unlink (to) != 0) /* Cleanup. */ Line 710...!syscalls auto-comment......!syscalls auto-comment...
die (EXIT_FAILURE, errno, _("cannot unlink %s"), quoteaf (to)); Line 711
return false; Line 712
}
if (x->preserve_timestamps && (strip_files || ! S_ISREG (from_sb.st_mode)) Line 714
&& ! change_timestamps (&from_sb, to)) Line 715
return false; Line 716
return change_attributes (to); Line 717
} Block 19
/* Create any missing parent directories of TO,
while maintaining the current Working Directory.
Return true if successful. */
static bool Line 724
mkancesdirs_safe_wd (char const *from, char *to, struct cp_options *x, Line 725
bool save_always) Line 726
{
bool save_working_directory = Line 728
save_always Line 729
|| ! (IS_ABSOLUTE_FILE_NAME (from) && IS_ABSOLUTE_FILE_NAME (to)); Line 730
int status = EXIT_SUCCESS; Line 731
struct savewd wd; Line 733
savewd_init (&wd); Line 734
if (! save_working_directory) Line 735
savewd_finish (&wd); Line 736
if (mkancesdirs (to, &wd, make_ancestor, x) == -1) Line 738
{
error (0, errno, _("cannot create directory %s"), quoteaf (to)); Line 740
status = EXIT_FAILURE; Line 741
}
if (save_working_directory) Line 744
{
int restore_result = savewd_restore (&wd, status); Line 746
int restore_errno = errno; Line 747
savewd_finish (&wd); Line 748
if (EXIT_SUCCESS < restore_result) Line 749
return false; Line 750
if (restore_result < 0 && status == EXIT_SUCCESS) Line 751
{
error (0, restore_errno, _("cannot create directory %s"), Line 753
quoteaf (to)); Line 754
return false; Line 755
}
}
return status == EXIT_SUCCESS; Line 758
} Block 20
/* Copy file FROM onto file TO, creating any missing parent directories of TO.
Return true if successful. */
static bool Line 764
install_file_in_file_parents (char const *from, char *to, Line 765
const struct cp_options *x) Line 766
{
return (mkancesdirs_safe_wd (from, to, (struct cp_options *)x, false) Line 768
&& install_file_in_file (from, to, x)); Line 769
} Block 21
/* Copy file FROM into directory TO_DIR, keeping its same name,
and give the copy the appropriate attributes.
Return true if successful. */
static bool Line 776
install_file_in_dir (const char *from, const char *to_dir, Line 777
const struct cp_options *x, bool mkdir_and_install) Line 778
{
const char *from_base = last_component (from); Line 780
char *to = file_name_concat (to_dir, from_base, NULL); Line 781
bool ret = true; Line 782
if (mkdir_and_install) Line 784
ret = mkancesdirs_safe_wd (from, to, (struct cp_options *)x, true); Line 785
ret = ret && install_file_in_file (from, to, x); Line 787
free (to); Line 788
return ret; Line 789
} Block 22
int
main (int argc, char **argv) Line 793
{
int optc; Line 795
int exit_status = EXIT_SUCCESS; Line 796
const char *specified_mode = NULL; Line 797
bool make_backups = false; Line 798
char const *backup_suffix = NULL; Line 799
char *version_control_string = NULL; Line 800
bool mkdir_and_install = false; Line 801
struct cp_options x; Line 802
char const *target_directory = NULL; Line 803
bool no_target_directory = false; Line 804
int n_files; Line 805
char **file; Line 806
bool strip_program_specified = false; Line 807
char const *scontext = NULL; Line 808
/* set iff kernel has extra selinux system calls */
selinux_enabled = (0 < is_selinux_enabled ()); ...!common auto-comment...
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_stdin); Close stdout on exit (see gnulib)
cp_option_init (&x); Line 820
owner_name = NULL; Line 822
group_name = NULL; Line 823
strip_files = false; Line 824
dir_arg = false; Line 825
umask (0); Line 826
while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pt:TvS:Z", long_options, Line 828
NULL)) != -1) Line 829
{
switch (optc) Line 831
{
case 'b': Line 833
make_backups = true; Line 834
if (optarg) Line 835
version_control_string = optarg; Line 836
break; Line 837
case 'c': Line 838
break; Line 839
case 'C': Line 840
copy_only_if_needed = true; Line 841
break; Line 842
case 's': Line 843
strip_files = true; Line 844
#ifdef SIGCHLD Line 845
/* System V fork+wait does not work if SIGCHLD is ignored. */
signal (SIGCHLD, SIG_DFL); Line 847
#endif Line 848
break; Line 849
case STRIP_PROGRAM_OPTION: Line 850
strip_program = xstrdup (optarg); Line 851
strip_program_specified = true; Line 852
break; Line 853
case 'd': Line 854
dir_arg = true; Line 855
break; Line 856
case 'D': Line 857
mkdir_and_install = true; Line 858
break; Line 859
case 'v': Line 860
x.verbose = true; Line 861
break; Line 862
case 'g': Line 863
group_name = optarg; Line 864
break; Line 865
case 'm': Line 866
specified_mode = optarg; Line 867
break; Line 868
case 'o': Line 869
owner_name = optarg; Line 870
break; Line 871
case 'p': Line 872
x.preserve_timestamps = true; Line 873
break; Line 874
case 'S': Line 875
make_backups = true; Line 876
backup_suffix = optarg; Line 877
break; Line 878
case 't': Line 879
if (target_directory) Line 880
die (EXIT_FAILURE, 0, Line 881
_("multiple target directories specified")); Line 882
target_directory = optarg; Line 883
break; Line 884
case 'T': Line 885
no_target_directory = true; Line 886
break; Line 887
case PRESERVE_CONTEXT_OPTION: Line 889
if (! selinux_enabled) Line 890
{
error (0, 0, _("WARNING: ignoring --preserve-context; " Line 892
"this kernel is not SELinux-enabled")); Line 893
break; Line 894
}
x.preserve_security_context = true; Line 896
use_default_selinux_context = false; Line 897
break; Line 898
case 'Z': Line 899
if (selinux_enabled) Line 900
{
/* Disable use of the install(1) specific setdefaultfilecon().
Note setdefaultfilecon() is different from the newer and more
generic restorecon() in that the former sets the context of
the dest files to that returned by matchpathcon directly,
thus discarding MLS level and user identity of the file.
TODO: consider removing setdefaultfilecon() in future. */
use_default_selinux_context = false; Line 908
if (optarg) Line 910
scontext = optarg; Line 911
else Line 912
x.set_security_context = true; Line 913
}
else if (optarg) Line 915
{
error (0, 0, Line 917
_("warning: ignoring --context; " Line 918
"it requires an SELinux-enabled kernel")); Line 919
}
break; Line 921
case_GETOPT_HELP_CHAR; Line 922
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); Line 923
default: Line 924
usage (EXIT_FAILURE); Line 925
}
}
/* Check for invalid combinations of arguments. */
if (dir_arg && strip_files) Line 930
die (EXIT_FAILURE, 0, Line 931
_("the strip option may not be used when installing a directory")); Line 932
if (dir_arg && target_directory) Line 933
die (EXIT_FAILURE, 0, Line 934
_("target directory not allowed when installing a directory")); Line 935
if (target_directory) Line 937
{
struct stat st; Line 939
bool stat_success = stat (target_directory, &st) == 0 ? true : false; Line 940...!syscalls auto-comment...
if (! mkdir_and_install && ! stat_success) Line 941
die (EXIT_FAILURE, errno, _("failed to access %s"), Line 942
quoteaf (target_directory)); Line 943
if (stat_success && ! S_ISDIR (st.st_mode)) Line 944
die (EXIT_FAILURE, 0, _("target %s is not a directory"), Line 945
quoteaf (target_directory)); Line 946
}
x.backup_type = (make_backups Line 949
? xget_version (_("backup type"), Line 950
version_control_string) Line 951
: no_backups); Line 952
set_simple_backup_suffix (backup_suffix); Line 953
if (x.preserve_security_context && (x.set_security_context || scontext)) Line 955
die (EXIT_FAILURE, 0, Line 956
_("cannot set target context and preserve it")); Line 957
if (scontext && setfscreatecon (se_const (scontext)) < 0) Line 959
die (EXIT_FAILURE, errno, Line 960
_("failed to set default file creation context to %s"), Line 961
quote (scontext)); Line 962
n_files = argc - optind; Line 964
file = argv + optind; Line 965
if (n_files <= ! (dir_arg || target_directory)) Line 967
{
if (n_files <= 0) Line 969
error (0, 0, _("missing file operand")); Line 970
else Line 971
error (0, 0, _("missing destination file operand after %s"), Line 972
quoteaf (file[0])); Line 973
usage (EXIT_FAILURE); Line 974
}
if (no_target_directory) Line 977
{
if (target_directory) Line 979
die (EXIT_FAILURE, 0, Line 980
_("cannot combine --target-directory (-t) " Line 981
"and --no-target-directory (-T)")); Line 982
if (2 < n_files) Line 983
{
error (0, 0, _("extra operand %s"), quoteaf (file[2])); Line 985
usage (EXIT_FAILURE); Line 986
}
}
else if (! (dir_arg || target_directory)) Line 989
{
if (2 <= n_files && target_directory_operand (file[n_files - 1])) Line 991
target_directory = file[--n_files]; Line 992
else if (2 < n_files) Line 993
die (EXIT_FAILURE, 0, _("target %s is not a directory"), Line 994
quoteaf (file[n_files - 1])); Line 995
}
if (specified_mode) Line 998
{
struct mode_change *change = mode_compile (specified_mode); Line 1000
if (!change) Line 1001
die (EXIT_FAILURE, 0, _("invalid mode %s"), quote (specified_mode)); Line 1002
mode = mode_adjust (0, false, 0, change, NULL); Line 1003
dir_mode = mode_adjust (0, true, 0, change, &dir_mode_bits); Line 1004
free (change); Line 1005
}
if (strip_program_specified && !strip_files) Line 1008
error (0, 0, _("WARNING: ignoring --strip-program option as -s option was " Line 1009
"not specified")); Line 1010
if (copy_only_if_needed && x.preserve_timestamps) Line 1012
{
error (0, 0, _("options --compare (-C) and --preserve-timestamps are " Line 1014
"mutually exclusive")); Line 1015
usage (EXIT_FAILURE); Line 1016
}
if (copy_only_if_needed && strip_files) Line 1019
{
error (0, 0, _("options --compare (-C) and --strip are mutually " Line 1021
"exclusive")); Line 1022
usage (EXIT_FAILURE); Line 1023
}
if (copy_only_if_needed && extra_mode (mode)) Line 1026
error (0, 0, _("the --compare (-C) option is ignored when you" Line 1027
" specify a mode with non-permission bits")); Line 1028
get_ids (); Line 1030
if (dir_arg) Line 1032
exit_status = savewd_process_files (n_files, file, process_dir, &x); Line 1033
else Line 1034
{
/* FIXME: it's a little gross that this initialization is
required by copy.c::copy. */
hash_init (); Line 1038
if (!target_directory) Line 1040
{
if (! (mkdir_and_install Line 1042
? install_file_in_file_parents (file[0], file[1], &x) Line 1043
: install_file_in_file (file[0], file[1], &x))) Line 1044
exit_status = EXIT_FAILURE; Line 1045
}
else Line 1047
{
int i; Line 1049
dest_info_init (&x); Line 1050
for (i = 0; i < n_files; i++) Line 1051
if (! install_file_in_dir (file[i], target_directory, &x, Line 1052
i == 0 && mkdir_and_install)) Line 1053
exit_status = EXIT_FAILURE; Line 1054
}
}
return exit_status; Line 1058
} Block 23