/* 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