LCOV - code coverage report
Current view: top level - src - install.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 252 309 81.6 %
Date: 2018-01-30 Functions: 14 16 87.5 %

          Line data    Source code
       1             : /* install - copy files and set attributes
       2             :    Copyright (C) 89, 90, 91, 1995-2008 Free Software Foundation, Inc.
       3             : 
       4             :    This program is free software: you can redistribute it and/or modify
       5             :    it under the terms of the GNU General Public License as published by
       6             :    the Free Software Foundation, either version 3 of the License, or
       7             :    (at your option) any later version.
       8             : 
       9             :    This program is distributed in the hope that it will be useful,
      10             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :    GNU General Public License for more details.
      13             : 
      14             :    You should have received a copy of the GNU General Public License
      15             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      16             : 
      17             : /* Written by David MacKenzie <djm@gnu.ai.mit.edu> */
      18             : 
      19             : #include <config.h>
      20             : #include <stdio.h>
      21             : #include <getopt.h>
      22             : #include <sys/types.h>
      23             : #include <signal.h>
      24             : #include <pwd.h>
      25             : #include <grp.h>
      26             : #include <selinux/selinux.h>
      27             : 
      28             : #include "system.h"
      29             : #include "backupfile.h"
      30             : #include "error.h"
      31             : #include "cp-hash.h"
      32             : #include "copy.h"
      33             : #include "filenamecat.h"
      34             : #include "mkancesdirs.h"
      35             : #include "mkdir-p.h"
      36             : #include "modechange.h"
      37             : #include "prog-fprintf.h"
      38             : #include "quote.h"
      39             : #include "quotearg.h"
      40             : #include "savewd.h"
      41             : #include "stat-time.h"
      42             : #include "utimens.h"
      43             : #include "xstrtol.h"
      44             : 
      45             : /* The official name of this program (e.g., no `g' prefix).  */
      46             : #define PROGRAM_NAME "install"
      47             : 
      48             : #define AUTHORS "David MacKenzie"
      49             : 
      50             : #if HAVE_SYS_WAIT_H
      51             : # include <sys/wait.h>
      52             : #endif
      53             : 
      54             : static int selinux_enabled = 0;
      55             : static bool use_default_selinux_context = true;
      56             : 
      57             : #if ! HAVE_ENDGRENT
      58             : # define endgrent() ((void) 0)
      59             : #endif
      60             : 
      61             : #if ! HAVE_ENDPWENT
      62             : # define endpwent() ((void) 0)
      63             : #endif
      64             : 
      65             : #if ! HAVE_LCHOWN
      66             : # define lchown(name, uid, gid) chown (name, uid, gid)
      67             : #endif
      68             : 
      69             : /* Initial number of entries in each hash table entry's table of inodes.  */
      70             : #define INITIAL_HASH_MODULE 100
      71             : 
      72             : /* Initial number of entries in the inode hash table.  */
      73             : #define INITIAL_ENTRY_TAB_SIZE 70
      74             : 
      75             : /* Number of bytes of a file to copy at a time. */
      76             : #define READ_SIZE (32 * 1024)
      77             : 
      78             : static bool change_timestamps (struct stat const *from_sb, char const *to);
      79             : static bool change_attributes (char const *name);
      80             : static bool copy_file (const char *from, const char *to,
      81             :                        const struct cp_options *x);
      82             : static bool install_file_in_file_parents (char const *from, char *to,
      83             :                                           struct cp_options *x);
      84             : static bool install_file_in_dir (const char *from, const char *to_dir,
      85             :                                  const struct cp_options *x);
      86             : static bool install_file_in_file (const char *from, const char *to,
      87             :                                   const struct cp_options *x);
      88             : static void get_ids (void);
      89             : static void strip (char const *name);
      90             : static void announce_mkdir (char const *dir, void *options);
      91             : static int make_ancestor (char const *dir, char const *component,
      92             :                           void *options);
      93             : void usage (int status);
      94             : 
      95             : /* The name this program was run with, for error messages. */
      96             : char *program_name;
      97             : 
      98             : /* The user name that will own the files, or NULL to make the owner
      99             :    the current user ID. */
     100             : static char *owner_name;
     101             : 
     102             : /* The user ID corresponding to `owner_name'. */
     103             : static uid_t owner_id;
     104             : 
     105             : /* The group name that will own the files, or NULL to make the group
     106             :    the current group ID. */
     107             : static char *group_name;
     108             : 
     109             : /* The group ID corresponding to `group_name'. */
     110             : static gid_t group_id;
     111             : 
     112             : #define DEFAULT_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
     113             : 
     114             : /* The file mode bits to which non-directory files will be set.  The umask has
     115             :    no effect. */
     116             : static mode_t mode = DEFAULT_MODE;
     117             : 
     118             : /* Similar, but for directories.  */
     119             : static mode_t dir_mode = DEFAULT_MODE;
     120             : 
     121             : /* The file mode bits that the user cares about.  This should be a
     122             :    superset of DIR_MODE and a subset of CHMOD_MODE_BITS.  This matters
     123             :    for directories, since otherwise directories may keep their S_ISUID
     124             :    or S_ISGID bits.  */
     125             : static mode_t dir_mode_bits = CHMOD_MODE_BITS;
     126             : 
     127             : /* If true, strip executable files after copying them. */
     128             : static bool strip_files;
     129             : 
     130             : /* If true, install a directory instead of a regular file. */
     131             : static bool dir_arg;
     132             : 
     133             : /* For long options that have no equivalent short option, use a
     134             :    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
     135             : enum
     136             : {
     137             :   PRESERVE_CONTEXT_OPTION = CHAR_MAX + 1
     138             : };
     139             : 
     140             : static struct option const long_options[] =
     141             : {
     142             :   {"backup", optional_argument, NULL, 'b'},
     143             :   {GETOPT_SELINUX_CONTEXT_OPTION_DECL},
     144             :   {"directory", no_argument, NULL, 'd'},
     145             :   {"group", required_argument, NULL, 'g'},
     146             :   {"mode", required_argument, NULL, 'm'},
     147             :   {"no-target-directory", no_argument, NULL, 'T'},
     148             :   {"owner", required_argument, NULL, 'o'},
     149             :   {"preserve-timestamps", no_argument, NULL, 'p'},
     150             :   {"preserve-context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
     151             :   /* Continue silent support for --preserve_context until Jan 2008. FIXME-obs
     152             :      After that, FIXME-obs: warn in, say, late 2008, and disable altogether
     153             :      a year or two later.  */
     154             :   {"preserve_context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
     155             :   {"strip", no_argument, NULL, 's'},
     156             :   {"suffix", required_argument, NULL, 'S'},
     157             :   {"target-directory", required_argument, NULL, 't'},
     158             :   {"verbose", no_argument, NULL, 'v'},
     159             :   {GETOPT_HELP_OPTION_DECL},
     160             :   {GETOPT_VERSION_OPTION_DECL},
     161             :   {NULL, 0, NULL, 0}
     162             : };
     163             : 
     164             : static void
     165         167 : cp_option_init (struct cp_options *x)
     166             : {
     167         167 :   cp_options_default (x);
     168         167 :   x->copy_as_regular = true;
     169         167 :   x->dereference = DEREF_ALWAYS;
     170         167 :   x->unlink_dest_before_opening = true;
     171         167 :   x->unlink_dest_after_failed_open = false;
     172         167 :   x->hard_link = false;
     173         167 :   x->interactive = I_UNSPECIFIED;
     174         167 :   x->move_mode = false;
     175         167 :   x->one_file_system = false;
     176         167 :   x->preserve_ownership = false;
     177         167 :   x->preserve_links = false;
     178         167 :   x->preserve_mode = false;
     179         167 :   x->preserve_timestamps = false;
     180         167 :   x->require_preserve = false;
     181         167 :   x->require_preserve_context = false;
     182         167 :   x->recursive = false;
     183         167 :   x->sparse_mode = SPARSE_AUTO;
     184         167 :   x->symbolic_link = false;
     185         167 :   x->backup_type = no_backups;
     186             : 
     187             :   /* Create destination files initially writable so we can run strip on them.
     188             :      Although GNU strip works fine on read-only files, some others
     189             :      would fail.  */
     190         167 :   x->set_mode = true;
     191         167 :   x->mode = S_IRUSR | S_IWUSR;
     192         167 :   x->stdin_tty = false;
     193             : 
     194         167 :   x->open_dangling_dest_symlink = false;
     195         167 :   x->update = false;
     196         167 :   x->preserve_security_context = false;
     197         167 :   x->verbose = false;
     198         167 :   x->dest_info = NULL;
     199         167 :   x->src_info = NULL;
     200         167 : }
     201             : 
     202             : #ifdef ENABLE_WHEN_MATCHPATHCON_IS_MORE_EFFICIENT
     203             : /* Modify file context to match the specified policy.
     204             :    If an error occurs the file will remain with the default directory
     205             :    context.  */
     206             : static void
     207             : setdefaultfilecon (char const *file)
     208             : {
     209             :   struct stat st;
     210             :   security_context_t scontext = NULL;
     211             :   if (selinux_enabled != 1)
     212             :     {
     213             :       /* Indicate no context found. */
     214             :       return;
     215             :     }
     216             :   if (lstat (file, &st) != 0)
     217             :     return;
     218             : 
     219             :   if (IS_ABSOLUTE_FILE_NAME (file))
     220             :     {
     221             :       /* Calling matchpathcon_init_prefix (NULL, "/first_component/")
     222             :          is an optimization to minimize the expense of the following
     223             :          matchpathcon call.  */
     224             :       char const *p0;
     225             :       char const *p = file + 1;
     226             :       while (ISSLASH (*p))
     227             :         ++p;
     228             : 
     229             :       /* Record final leading slash, for when FILE starts with two or more.  */
     230             :       p0 = p - 1;
     231             : 
     232             :       if (*p)
     233             :         {
     234             :           char *prefix;
     235             :           do
     236             :             {
     237             :               ++p;
     238             :             }
     239             :           while (*p && !ISSLASH (*p));
     240             : 
     241             :           prefix = malloc (p - p0 + 2);
     242             :           if (prefix)
     243             :             {
     244             :               stpcpy (stpncpy (prefix, p0, p - p0), "/");
     245             :               matchpathcon_init_prefix (NULL, prefix);
     246             :               free (prefix);
     247             :             }
     248             :         }
     249             :     }
     250             : 
     251             :   /* If there's an error determining the context, or it has none,
     252             :      return to allow default context */
     253             :   if ((matchpathcon (file, st.st_mode, &scontext) != 0) ||
     254             :       STREQ (scontext, "<<none>>"))
     255             :     {
     256             :       if (scontext != NULL)
     257             :         freecon (scontext);
     258             :       return;
     259             :     }
     260             : 
     261             :   if (lsetfilecon (file, scontext) < 0 && errno != ENOTSUP)
     262             :     error (0, errno,
     263             :            _("warning: %s: failed to change context to %s"),
     264             :            quotearg_colon (file), scontext);
     265             : 
     266             :   freecon (scontext);
     267             :   return;
     268             : }
     269             : #else
     270             : static void
     271          15 : setdefaultfilecon (char const *file)
     272             : {
     273             :   (void) file;
     274          15 : }
     275             : #endif
     276             : 
     277             : /* FILE is the last operand of this command.  Return true if FILE is a
     278             :    directory.  But report an error there is a problem accessing FILE,
     279             :    or if FILE does not exist but would have to refer to an existing
     280             :    directory if it referred to anything at all.  */
     281             : 
     282             : static bool
     283          88 : target_directory_operand (char const *file)
     284             : {
     285          88 :   char const *b = last_component (file);
     286          88 :   size_t blen = strlen (b);
     287          88 :   bool looks_like_a_dir = (blen == 0 || ISSLASH (b[blen - 1]));
     288             :   struct stat st;
     289          88 :   int err = (stat (file, &st) == 0 ? 0 : errno);
     290          88 :   bool is_a_dir = !err && S_ISDIR (st.st_mode);
     291          88 :   if (err && err != ENOENT)
     292           0 :     error (EXIT_FAILURE, err, _("accessing %s"), quote (file));
     293          88 :   if (is_a_dir < looks_like_a_dir)
     294           3 :     error (EXIT_FAILURE, err, _("target %s is not a directory"), quote (file));
     295          85 :   return is_a_dir;
     296             : }
     297             : 
     298             : /* Process a command-line file name, for the -d option.  */
     299             : static int
     300          46 : process_dir (char *dir, struct savewd *wd, void *options)
     301             : {
     302          46 :   return (make_dir_parents (dir, wd,
     303             :                             make_ancestor, options,
     304             :                             dir_mode, announce_mkdir,
     305             :                             dir_mode_bits, owner_id, group_id, false)
     306             :           ? EXIT_SUCCESS
     307          46 :           : EXIT_FAILURE);
     308             : }
     309             : 
     310             : int
     311         167 : main (int argc, char **argv)
     312             : {
     313             :   int optc;
     314         167 :   int exit_status = EXIT_SUCCESS;
     315         167 :   const char *specified_mode = NULL;
     316         167 :   bool make_backups = false;
     317             :   char *backup_suffix_string;
     318         167 :   char *version_control_string = NULL;
     319         167 :   bool mkdir_and_install = false;
     320             :   struct cp_options x;
     321         167 :   char const *target_directory = NULL;
     322         167 :   bool no_target_directory = false;
     323             :   int n_files;
     324             :   char **file;
     325         167 :   security_context_t scontext = NULL;
     326             :   /* set iff kernel has extra selinux system calls */
     327         167 :   selinux_enabled = (0 < is_selinux_enabled ());
     328             : 
     329             :   initialize_main (&argc, &argv);
     330         167 :   program_name = argv[0];
     331         167 :   setlocale (LC_ALL, "");
     332             :   bindtextdomain (PACKAGE, LOCALEDIR);
     333             :   textdomain (PACKAGE);
     334             : 
     335         167 :   atexit (close_stdin);
     336             : 
     337         167 :   cp_option_init (&x);
     338             : 
     339         167 :   owner_name = NULL;
     340         167 :   group_name = NULL;
     341         167 :   strip_files = false;
     342         167 :   dir_arg = false;
     343         167 :   umask (0);
     344             : 
     345             :   /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
     346             :      we'll actually use backup_suffix_string.  */
     347         167 :   backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
     348             : 
     349         455 :   while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pt:TvS:Z:", long_options,
     350             :                               NULL)) != -1)
     351             :     {
     352         133 :       switch (optc)
     353             :         {
     354          23 :         case 'b':
     355          23 :           make_backups = true;
     356          23 :           if (optarg)
     357           6 :             version_control_string = optarg;
     358          23 :           break;
     359           4 :         case 'c':
     360           4 :           break;
     361           2 :         case 's':
     362           2 :           strip_files = true;
     363             : #ifdef SIGCHLD
     364             :           /* System V fork+wait does not work if SIGCHLD is ignored.  */
     365           2 :           signal (SIGCHLD, SIG_DFL);
     366             : #endif
     367           2 :           break;
     368          30 :         case 'd':
     369          30 :           dir_arg = true;
     370          30 :           break;
     371           4 :         case 'D':
     372           4 :           mkdir_and_install = true;
     373           4 :           break;
     374           3 :         case 'v':
     375           3 :           x.verbose = true;
     376           3 :           break;
     377           8 :         case 'g':
     378           8 :           group_name = optarg;
     379           8 :           break;
     380          30 :         case 'm':
     381          30 :           specified_mode = optarg;
     382          30 :           break;
     383           4 :         case 'o':
     384           4 :           owner_name = optarg;
     385           4 :           break;
     386           3 :         case 'p':
     387           3 :           x.preserve_timestamps = true;
     388           3 :           break;
     389           1 :         case 'S':
     390           1 :           make_backups = true;
     391           1 :           backup_suffix_string = optarg;
     392           1 :           break;
     393           4 :         case 't':
     394           4 :           if (target_directory)
     395           0 :             error (EXIT_FAILURE, 0,
     396             :                    _("multiple target directories specified"));
     397             :           else
     398             :             {
     399             :               struct stat st;
     400           4 :               if (stat (optarg, &st) != 0)
     401           1 :                 error (EXIT_FAILURE, errno, _("accessing %s"), quote (optarg));
     402           3 :               if (! S_ISDIR (st.st_mode))
     403           1 :                 error (EXIT_FAILURE, 0, _("target %s is not a directory"),
     404             :                        quote (optarg));
     405             :             }
     406           2 :           target_directory = optarg;
     407           2 :           break;
     408           6 :         case 'T':
     409           6 :           no_target_directory = true;
     410           6 :           break;
     411             : 
     412           0 :         case PRESERVE_CONTEXT_OPTION:
     413           0 :           if ( ! selinux_enabled)
     414             :             {
     415           0 :               error (0, 0, _("Warning: ignoring --preserve-context; "
     416             :                              "this kernel is not SELinux-enabled."));
     417           0 :               break;
     418             :             }
     419           0 :           x.preserve_security_context = true;
     420           0 :           use_default_selinux_context = false;
     421           0 :           break;
     422           1 :         case 'Z':
     423           1 :           if ( ! selinux_enabled)
     424             :             {
     425           1 :               error (0, 0, _("Warning: ignoring --context (-Z); "
     426             :                              "this kernel is not SELinux-enabled."));
     427           1 :               break;
     428             :             }
     429           0 :           scontext = optarg;
     430           0 :           use_default_selinux_context = false;
     431           0 :           break;
     432           1 :         case_GETOPT_HELP_CHAR;
     433           1 :         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
     434           8 :         default:
     435           8 :           usage (EXIT_FAILURE);
     436             :         }
     437             :     }
     438             : 
     439             :   /* Check for invalid combinations of arguments. */
     440         155 :   if (dir_arg & strip_files)
     441           1 :     error (EXIT_FAILURE, 0,
     442             :            _("the strip option may not be used when installing a directory"));
     443         154 :   if (dir_arg && target_directory)
     444           1 :     error (EXIT_FAILURE, 0,
     445             :            _("target directory not allowed when installing a directory"));
     446             : 
     447         153 :   if (x.preserve_security_context && scontext != NULL)
     448           0 :     error (EXIT_FAILURE, 0,
     449             :            _("cannot force target context to %s and preserve it"),
     450             :            quote (scontext));
     451             : 
     452         153 :   if (backup_suffix_string)
     453           1 :     simple_backup_suffix = xstrdup (backup_suffix_string);
     454             : 
     455         151 :   x.backup_type = (make_backups
     456             :                    ? xget_version (_("backup type"),
     457             :                                    version_control_string)
     458         153 :                    : no_backups);
     459             : 
     460         151 :   if (scontext && setfscreatecon (scontext) < 0)
     461           0 :     error (EXIT_FAILURE, errno,
     462             :            _("failed to set default file creation context to %s"),
     463             :            quote (scontext));
     464             : 
     465         151 :   n_files = argc - optind;
     466         151 :   file = argv + optind;
     467             : 
     468         151 :   if (n_files <= ! (dir_arg || target_directory))
     469             :     {
     470          31 :       if (n_files <= 0)
     471          14 :         error (0, 0, _("missing file operand"));
     472             :       else
     473          17 :         error (0, 0, _("missing destination file operand after %s"),
     474             :                quote (file[0]));
     475          31 :       usage (EXIT_FAILURE);
     476             :     }
     477             : 
     478         120 :   if (no_target_directory)
     479             :     {
     480           5 :       if (target_directory)
     481           0 :         error (EXIT_FAILURE, 0,
     482             :                _("Cannot combine --target-directory (-t) "
     483             :                  "and --no-target-directory (-T)"));
     484           5 :       if (2 < n_files)
     485             :         {
     486           0 :           error (0, 0, _("extra operand %s"), quote (file[2]));
     487           0 :           usage (EXIT_FAILURE);
     488             :         }
     489             :     }
     490         115 :   else if (! (dir_arg || target_directory))
     491             :     {
     492          88 :       if (2 <= n_files && target_directory_operand (file[n_files - 1]))
     493          28 :         target_directory = file[--n_files];
     494          57 :       else if (2 < n_files)
     495           2 :         error (EXIT_FAILURE, 0, _("target %s is not a directory"),
     496           2 :                quote (file[n_files - 1]));
     497             :     }
     498             : 
     499         115 :   if (specified_mode)
     500             :     {
     501          29 :       struct mode_change *change = mode_compile (specified_mode);
     502          29 :       if (!change)
     503           9 :         error (EXIT_FAILURE, 0, _("invalid mode %s"), quote (specified_mode));
     504          20 :       mode = mode_adjust (0, false, 0, change, NULL);
     505          20 :       dir_mode = mode_adjust (0, true, 0, change, &dir_mode_bits);
     506          20 :       free (change);
     507             :     }
     508             : 
     509         106 :   get_ids ();
     510             : 
     511         101 :   if (dir_arg)
     512          27 :     exit_status = savewd_process_files (n_files, file, process_dir, &x);
     513             :   else
     514             :     {
     515             :       /* FIXME: it's a little gross that this initialization is
     516             :          required by copy.c::copy. */
     517          74 :       hash_init ();
     518             : 
     519          74 :       if (!target_directory)
     520             :         {
     521          96 :           if (! (mkdir_and_install
     522           3 :                  ? install_file_in_file_parents (file[0], file[1], &x)
     523          45 :                  : install_file_in_file (file[0], file[1], &x)))
     524          33 :             exit_status = EXIT_FAILURE;
     525             :         }
     526             :       else
     527             :         {
     528             :           int i;
     529          26 :           dest_info_init (&x);
     530          53 :           for (i = 0; i < n_files; i++)
     531          27 :             if (! install_file_in_dir (file[i], target_directory, &x))
     532          27 :               exit_status = EXIT_FAILURE;
     533             :         }
     534             :     }
     535             : 
     536         101 :   exit (exit_status);
     537             : }
     538             : 
     539             : /* Copy file FROM onto file TO, creating any missing parent directories of TO.
     540             :    Return true if successful.  */
     541             : 
     542             : static bool
     543           3 : install_file_in_file_parents (char const *from, char *to,
     544             :                               struct cp_options *x)
     545             : {
     546           3 :   bool save_working_directory =
     547           3 :     ! (IS_ABSOLUTE_FILE_NAME (from) && IS_ABSOLUTE_FILE_NAME (to));
     548           3 :   int status = EXIT_SUCCESS;
     549             : 
     550             :   struct savewd wd;
     551           3 :   savewd_init (&wd);
     552           3 :   if (! save_working_directory)
     553           1 :     savewd_finish (&wd);
     554             : 
     555           3 :   if (mkancesdirs (to, &wd, make_ancestor, x) == -1)
     556             :     {
     557           0 :       error (0, errno, _("cannot create directory %s"), to);
     558           0 :       status = EXIT_FAILURE;
     559             :     }
     560             : 
     561           3 :   if (save_working_directory)
     562             :     {
     563           2 :       int restore_result = savewd_restore (&wd, status);
     564           2 :       int restore_errno = errno;
     565           2 :       savewd_finish (&wd);
     566           2 :       if (EXIT_SUCCESS < restore_result)
     567           0 :         return false;
     568           2 :       if (restore_result < 0 && status == EXIT_SUCCESS)
     569             :         {
     570           0 :           error (0, restore_errno, _("cannot create directory %s"), to);
     571           0 :           return false;
     572             :         }
     573             :     }
     574             : 
     575           3 :   return (status == EXIT_SUCCESS && install_file_in_file (from, to, x));
     576             : }
     577             : 
     578             : /* Copy file FROM onto file TO and give TO the appropriate
     579             :    attributes.
     580             :    Return true if successful.  */
     581             : 
     582             : static bool
     583          75 : install_file_in_file (const char *from, const char *to,
     584             :                       const struct cp_options *x)
     585             : {
     586             :   struct stat from_sb;
     587          75 :   if (x->preserve_timestamps && stat (from, &from_sb) != 0)
     588             :     {
     589           1 :       error (0, errno, _("cannot stat %s"), quote (from));
     590           1 :       return false;
     591             :     }
     592          74 :   if (! copy_file (from, to, x))
     593          59 :     return false;
     594          15 :   if (strip_files)
     595           0 :     strip (to);
     596          15 :   if (x->preserve_timestamps && (strip_files || ! S_ISREG (from_sb.st_mode))
     597           0 :       && ! change_timestamps (&from_sb, to))
     598           0 :     return false;
     599          15 :   return change_attributes (to);
     600             : }
     601             : 
     602             : /* Copy file FROM into directory TO_DIR, keeping its same name,
     603             :    and give the copy the appropriate attributes.
     604             :    Return true if successful.  */
     605             : 
     606             : static bool
     607          27 : install_file_in_dir (const char *from, const char *to_dir,
     608             :                      const struct cp_options *x)
     609             : {
     610          27 :   const char *from_base = last_component (from);
     611          27 :   char *to = file_name_concat (to_dir, from_base, NULL);
     612          27 :   bool ret = install_file_in_file (from, to, x);
     613          27 :   free (to);
     614          27 :   return ret;
     615             : }
     616             : 
     617             : /* Copy file FROM onto file TO, creating TO if necessary.
     618             :    Return true if successful.  */
     619             : 
     620             : static bool
     621          74 : copy_file (const char *from, const char *to, const struct cp_options *x)
     622             : {
     623             :   bool copy_into_self;
     624             : 
     625             :   /* Allow installing from non-regular files like /dev/null.
     626             :      Charles Karney reported that some Sun version of install allows that
     627             :      and that sendmail's installation process relies on the behavior.
     628             :      However, since !x->recursive, the call to "copy" will fail if FROM
     629             :      is a directory.  */
     630             : 
     631          74 :   return copy (from, to, false, x, &copy_into_self, NULL);
     632             : }
     633             : 
     634             : /* Set the attributes of file or directory NAME.
     635             :    Return true if successful.  */
     636             : 
     637             : static bool
     638          15 : change_attributes (char const *name)
     639             : {
     640          15 :   bool ok = false;
     641             :   /* chown must precede chmod because on some systems,
     642             :      chown clears the set[ug]id bits for non-superusers,
     643             :      resulting in incorrect permissions.
     644             :      On System V, users can give away files with chown and then not
     645             :      be able to chmod them.  So don't give files away.
     646             : 
     647             :      We don't normally ignore errors from chown because the idea of
     648             :      the install command is that the file is supposed to end up with
     649             :      precisely the attributes that the user specified (or defaulted).
     650             :      If the file doesn't end up with the group they asked for, they'll
     651             :      want to know.  */
     652             : 
     653          15 :   if (! (owner_id == (uid_t) -1 && group_id == (gid_t) -1)
     654           0 :       && lchown (name, owner_id, group_id) != 0)
     655           0 :     error (0, errno, _("cannot change ownership of %s"), quote (name));
     656          15 :   else if (chmod (name, mode) != 0)
     657           0 :     error (0, errno, _("cannot change permissions of %s"), quote (name));
     658             :   else
     659          15 :     ok = true;
     660             : 
     661          15 :   if (use_default_selinux_context)
     662          15 :     setdefaultfilecon (name);
     663             : 
     664          15 :   return ok;
     665             : }
     666             : 
     667             : /* Set the timestamps of file TO to match those of file FROM.
     668             :    Return true if successful.  */
     669             : 
     670             : static bool
     671           0 : change_timestamps (struct stat const *from_sb, char const *to)
     672             : {
     673             :   struct timespec timespec[2];
     674           0 :   timespec[0] = get_stat_atime (from_sb);
     675           0 :   timespec[1] = get_stat_mtime (from_sb);
     676             : 
     677           0 :   if (utimens (to, timespec))
     678             :     {
     679           0 :       error (0, errno, _("cannot set time stamps for %s"), quote (to));
     680           0 :       return false;
     681             :     }
     682           0 :   return true;
     683             : }
     684             : 
     685             : /* Strip the symbol table from the file NAME.
     686             :    We could dig the magic number out of the file first to
     687             :    determine whether to strip it, but the header files and
     688             :    magic numbers vary so much from system to system that making
     689             :    it portable would be very difficult.  Not worth the effort. */
     690             : 
     691             : static void
     692           0 : strip (char const *name)
     693             : {
     694             :   int status;
     695           0 :   pid_t pid = fork ();
     696             : 
     697           0 :   switch (pid)
     698             :     {
     699           0 :     case -1:
     700           0 :       error (EXIT_FAILURE, errno, _("fork system call failed"));
     701           0 :       break;
     702           0 :     case 0:                     /* Child. */
     703           0 :       execlp ("strip", "strip", name, NULL);
     704           0 :       error (EXIT_FAILURE, errno, _("cannot run strip"));
     705           0 :       break;
     706           0 :     default:                    /* Parent. */
     707           0 :       if (waitpid (pid, &status, 0) < 0)
     708           0 :         error (EXIT_FAILURE, errno, _("waiting for strip"));
     709           0 :       else if (! WIFEXITED (status) || WEXITSTATUS (status))
     710           0 :         error (EXIT_FAILURE, 0, _("strip process terminated abnormally"));
     711           0 :       break;
     712             :     }
     713           0 : }
     714             : 
     715             : /* Initialize the user and group ownership of the files to install. */
     716             : 
     717             : static void
     718         106 : get_ids (void)
     719             : {
     720             :   struct passwd *pw;
     721             :   struct group *gr;
     722             : 
     723         106 :   if (owner_name)
     724             :     {
     725           3 :       pw = getpwnam (owner_name);
     726           3 :       if (pw == NULL)
     727             :         {
     728             :           unsigned long int tmp;
     729           2 :           if (xstrtoul (owner_name, NULL, 0, &tmp, NULL) != LONGINT_OK
     730           0 :               || UID_T_MAX < tmp)
     731           2 :             error (EXIT_FAILURE, 0, _("invalid user %s"), quote (owner_name));
     732           0 :           owner_id = tmp;
     733             :         }
     734             :       else
     735           1 :         owner_id = pw->pw_uid;
     736           1 :       endpwent ();
     737             :     }
     738             :   else
     739         103 :     owner_id = (uid_t) -1;
     740             : 
     741         104 :   if (group_name)
     742             :     {
     743           5 :       gr = getgrnam (group_name);
     744           5 :       if (gr == NULL)
     745             :         {
     746             :           unsigned long int tmp;
     747           3 :           if (xstrtoul (group_name, NULL, 0, &tmp, NULL) != LONGINT_OK
     748           0 :               || GID_T_MAX < tmp)
     749           3 :             error (EXIT_FAILURE, 0, _("invalid group %s"), quote (group_name));
     750           0 :           group_id = tmp;
     751             :         }
     752             :       else
     753           2 :         group_id = gr->gr_gid;
     754           2 :       endgrent ();
     755             :     }
     756             :   else
     757          99 :     group_id = (gid_t) -1;
     758         101 : }
     759             : 
     760             : /* Report that directory DIR was made, if OPTIONS requests this.  */
     761             : static void
     762           3 : announce_mkdir (char const *dir, void *options)
     763             : {
     764           3 :   struct cp_options const *x = options;
     765           3 :   if (x->verbose)
     766           0 :     prog_fprintf (stdout, _("creating directory %s"), quote (dir));
     767           3 : }
     768             : 
     769             : /* Make ancestor directory DIR, whose last file name component is
     770             :    COMPONENT, with options OPTIONS.  Assume the working directory is
     771             :    COMPONENT's parent.  */
     772             : static int
     773           8 : make_ancestor (char const *dir, char const *component, void *options)
     774             : {
     775           8 :   int r = mkdir (component, DEFAULT_MODE);
     776           8 :   if (r == 0)
     777           1 :     announce_mkdir (dir, options);
     778           8 :   return r;
     779             : }
     780             : 
     781             : void
     782          42 : usage (int status)
     783             : {
     784          42 :   if (status != EXIT_SUCCESS)
     785          41 :     fprintf (stderr, _("Try `%s --help' for more information.\n"),
     786             :              program_name);
     787             :   else
     788             :     {
     789           1 :       printf (_("\
     790             : Usage: %s [OPTION]... [-T] SOURCE DEST\n\
     791             :   or:  %s [OPTION]... SOURCE... DIRECTORY\n\
     792             :   or:  %s [OPTION]... -t DIRECTORY SOURCE...\n\
     793             :   or:  %s [OPTION]... -d DIRECTORY...\n\
     794             : "),
     795             :               program_name, program_name, program_name, program_name);
     796           1 :       fputs (_("\
     797             : In the first three forms, copy SOURCE to DEST or multiple SOURCE(s) to\n\
     798             : the existing DIRECTORY, while setting permission modes and owner/group.\n\
     799             : In the 4th form, create all components of the given DIRECTORY(ies).\n\
     800             : \n\
     801             : "), stdout);
     802           1 :       fputs (_("\
     803             : Mandatory arguments to long options are mandatory for short options too.\n\
     804             : "), stdout);
     805           1 :       fputs (_("\
     806             :       --backup[=CONTROL]  make a backup of each existing destination file\n\
     807             :   -b                  like --backup but does not accept an argument\n\
     808             :   -c                  (ignored)\n\
     809             :   -d, --directory     treat all arguments as directory names; create all\n\
     810             :                         components of the specified directories\n\
     811             : "), stdout);
     812           1 :       fputs (_("\
     813             :   -D                  create all leading components of DEST except the last,\n\
     814             :                         then copy SOURCE to DEST\n\
     815             :   -g, --group=GROUP   set group ownership, instead of process' current group\n\
     816             :   -m, --mode=MODE     set permission mode (as in chmod), instead of rwxr-xr-x\n\
     817             :   -o, --owner=OWNER   set ownership (super-user only)\n\
     818             : "), stdout);
     819           1 :       fputs (_("\
     820             :   -p, --preserve-timestamps   apply access/modification times of SOURCE files\n\
     821             :                         to corresponding destination files\n\
     822             :   -s, --strip         strip symbol tables\n\
     823             :   -S, --suffix=SUFFIX  override the usual backup suffix\n\
     824             :   -t, --target-directory=DIRECTORY  copy all SOURCE arguments into DIRECTORY\n\
     825             :   -T, --no-target-directory  treat DEST as a normal file\n\
     826             :   -v, --verbose       print the name of each directory as it is created\n\
     827             : "), stdout);
     828           1 :       fputs (_("\
     829             :       --preserve-context  preserve SELinux security context\n\
     830             :   -Z, --context=CONTEXT  set SELinux security context of files and directories\n\
     831             : "), stdout);
     832             : 
     833           1 :       fputs (HELP_OPTION_DESCRIPTION, stdout);
     834           1 :       fputs (VERSION_OPTION_DESCRIPTION, stdout);
     835           1 :       fputs (_("\
     836             : \n\
     837             : The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
     838             : The version control method may be selected via the --backup option or through\n\
     839             : the VERSION_CONTROL environment variable.  Here are the values:\n\
     840             : \n\
     841             : "), stdout);
     842           1 :       fputs (_("\
     843             :   none, off       never make backups (even if --backup is given)\n\
     844             :   numbered, t     make numbered backups\n\
     845             :   existing, nil   numbered if numbered backups exist, simple otherwise\n\
     846             :   simple, never   always make simple backups\n\
     847             : "), stdout);
     848           1 :       emit_bug_reporting_address ();
     849             :     }
     850          42 :   exit (status);
     851             : }

Generated by: LCOV version 1.10