1 /* install - copy files and set attributes
2    Copyright (C) 1989-2018 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 <https://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 #include <sys/wait.h>
28 
29 #include "system.h"
30 #include "backupfile.h"
31 #include "error.h"
32 #include "cp-hash.h"
33 #include "copy.h"
34 #include "die.h"
35 #include "filenamecat.h"
36 #include "full-read.h"
37 #include "mkancesdirs.h"
38 #include "mkdir-p.h"
39 #include "modechange.h"
40 #include "prog-fprintf.h"
41 #include "quote.h"
42 #include "savewd.h"
43 #include "selinux.h"
44 #include "stat-time.h"
45 #include "utimens.h"
46 #include "xstrtol.h"
47 
48 /* The official name of this program (e.g., no 'g' prefix).  */
49 #define PROGRAM_NAME "install"
50 
51 #define AUTHORS proper_name ("David MacKenzie")
52 
53 static int selinux_enabled = 0;
54 static bool use_default_selinux_context = true;
55 
56 #if ! HAVE_ENDGRENT
57 # define endgrent() ((void) 0)
58 #endif
59 
60 #if ! HAVE_ENDPWENT
61 # define endpwent() ((void) 0)
62 #endif
63 
64 #if ! HAVE_LCHOWN
65 # define lchown(name, uid, gid) chown (name, uid, gid)
66 #endif
67 
68 #if ! HAVE_MATCHPATHCON_INIT_PREFIX
69 # define matchpathcon_init_prefix(a, p) /* empty */
70 #endif
71 
72 /* The user name that will own the files, or NULL to make the owner
73    the current user ID. */
74 static char *owner_name;
75 
76 /* The user ID corresponding to 'owner_name'. */
77 static uid_t owner_id;
78 
79 /* The group name that will own the files, or NULL to make the group
80    the current group ID. */
81 static char *group_name;
82 
83 /* The group ID corresponding to 'group_name'. */
84 static gid_t group_id;
85 
86 #define DEFAULT_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
87 
88 /* The file mode bits to which non-directory files will be set.  The umask has
89    no effect. */
90 static mode_t mode = DEFAULT_MODE;
91 
92 /* Similar, but for directories.  */
93 static mode_t dir_mode = DEFAULT_MODE;
94 
95 /* The file mode bits that the user cares about.  This should be a
96    superset of DIR_MODE and a subset of CHMOD_MODE_BITS.  This matters
97    for directories, since otherwise directories may keep their S_ISUID
98    or S_ISGID bits.  */
99 static mode_t dir_mode_bits = CHMOD_MODE_BITS;
100 
101 /* Compare files before installing (-C) */
102 static bool copy_only_if_needed;
103 
104 /* If true, strip executable files after copying them. */
105 static bool strip_files;
106 
107 /* If true, install a directory instead of a regular file. */
108 static bool dir_arg;
109 
110 /* Program used to strip binaries, "strip" is default */
111 static char const *strip_program = "strip";
112 
113 /* For long options that have no equivalent short option, use a
114    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
115 enum
116 {
117   PRESERVE_CONTEXT_OPTION = CHAR_MAX + 1,
118   STRIP_PROGRAM_OPTION
119 };
120 
121 static struct option const long_options[] =
122 {
123   {"backup", optional_argument, NULL, 'b'},
124   {"compare", no_argument, NULL, 'C'},
125   {GETOPT_SELINUX_CONTEXT_OPTION_DECL},
126   {"directory", no_argument, NULL, 'd'},
127   {"group", required_argument, NULL, 'g'},
128   {"mode", required_argument, NULL, 'm'},
129   {"no-target-directory", no_argument, NULL, 'T'},
130   {"owner", required_argument, NULL, 'o'},
131   {"preserve-timestamps", no_argument, NULL, 'p'},
132   {"preserve-context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
133   {"strip", no_argument, NULL, 's'},
134   {"strip-program", required_argument, NULL, STRIP_PROGRAM_OPTION},
135   {"suffix", required_argument, NULL, 'S'},
136   {"target-directory", required_argument, NULL, 't'},
137   {"verbose", no_argument, NULL, 'v'},
138   {GETOPT_HELP_OPTION_DECL},
139   {GETOPT_VERSION_OPTION_DECL},
140   {NULL, 0, NULL, 0}
141 };
142 
143 /* Compare content of opened files using file descriptors A_FD and B_FD. Return
144    true if files are equal. */
145 static bool
have_same_content(int a_fd,int b_fd)146 have_same_content (int a_fd, int b_fd)
147 {
148   enum { CMP_BLOCK_SIZE = 4096 };
149   static char a_buff[CMP_BLOCK_SIZE];
150   static char b_buff[CMP_BLOCK_SIZE];
151 
152   size_t size;
153   while (0 < (size = full_read (a_fd, a_buff, sizeof a_buff))) {
154     if (size != full_read (b_fd, b_buff, sizeof b_buff))
155       return false;
156 
157     if (memcmp (a_buff, b_buff, size) != 0)
158       return false;
159   }
160 
161   return size == 0;
162 }
163 
164 /* Return true for mode with non-permission bits. */
165 static bool
extra_mode(mode_t input)166 extra_mode (mode_t input)
167 {
168   mode_t mask = S_IRWXUGO | S_IFMT;
169   return !! (input & ~ mask);
170 }
171 
172 /* Return true if copy of file SRC_NAME to file DEST_NAME is necessary. */
173 static bool
need_copy(const char * src_name,const char * dest_name,const struct cp_options * x)174 need_copy (const char *src_name, const char *dest_name,
175            const struct cp_options *x)
176 {
177   struct stat src_sb, dest_sb;
178   int src_fd, dest_fd;
179   bool content_match;
180 
181   if (extra_mode (mode))
182     return true;
183 
184   /* compare files using stat */
185   if (lstat (src_name, &src_sb) != 0)
186     return true;
187 
188   if (lstat (dest_name, &dest_sb) != 0)
189     return true;
190 
191   if (!S_ISREG (src_sb.st_mode) || !S_ISREG (dest_sb.st_mode)
192       || extra_mode (src_sb.st_mode) || extra_mode (dest_sb.st_mode))
193     return true;
194 
195   if (src_sb.st_size != dest_sb.st_size
196       || (dest_sb.st_mode & CHMOD_MODE_BITS) != mode)
197     return true;
198 
199   if (owner_id == (uid_t) -1)
200     {
201       errno = 0;
202       uid_t ruid = getuid ();
203       if ((ruid == (uid_t) -1 && errno) || dest_sb.st_uid != ruid)
204         return true;
205     }
206   else if (dest_sb.st_uid != owner_id)
207     return true;
208 
209   if (group_id == (uid_t) -1)
210     {
211       errno = 0;
212       gid_t rgid = getgid ();
213       if ((rgid == (uid_t) -1 && errno) || dest_sb.st_gid != rgid)
214         return true;
215     }
216   else if (dest_sb.st_gid != group_id)
217     return true;
218 
219   /* compare SELinux context if preserving */
220   if (selinux_enabled && x->preserve_security_context)
221     {
222       char *file_scontext = NULL;
223       char *to_scontext = NULL;
224       bool scontext_match;
225 
226       if (getfilecon (src_name, &file_scontext) == -1)
227         return true;
228 
229       if (getfilecon (dest_name, &to_scontext) == -1)
230         {
231           freecon (file_scontext);
232           return true;
233         }
234 
235       scontext_match = STREQ (file_scontext, to_scontext);
236 
237       freecon (file_scontext);
238       freecon (to_scontext);
239       if (!scontext_match)
240         return true;
241     }
242 
243   /* compare files content */
244   src_fd = open (src_name, O_RDONLY | O_BINARY);
245   if (src_fd < 0)
246     return true;
247 
248   dest_fd = open (dest_name, O_RDONLY | O_BINARY);
249   if (dest_fd < 0)
250     {
251       close (src_fd);
252       return true;
253     }
254 
255   content_match = have_same_content (src_fd, dest_fd);
256 
257   close (src_fd);
258   close (dest_fd);
259   return !content_match;
260 }
261 
262 static void
cp_option_init(struct cp_options * x)263 cp_option_init (struct cp_options *x)
264 {
265   cp_options_default (x);
266   x->copy_as_regular = true;
267   x->reflink_mode = REFLINK_NEVER;
268   x->dereference = DEREF_ALWAYS;
269   x->unlink_dest_before_opening = true;
270   x->unlink_dest_after_failed_open = false;
271   x->hard_link = false;
272   x->interactive = I_UNSPECIFIED;
273   x->move_mode = false;
274   x->install_mode = true;
275   x->one_file_system = false;
276   x->preserve_ownership = false;
277   x->preserve_links = false;
278   x->preserve_mode = false;
279   x->preserve_timestamps = false;
280   x->explicit_no_preserve_mode = false;
281   x->reduce_diagnostics=false;
282   x->data_copy_required = true;
283   x->require_preserve = false;
284   x->require_preserve_xattr = false;
285   x->recursive = false;
286   x->sparse_mode = SPARSE_AUTO;
287   x->symbolic_link = false;
288   x->backup_type = no_backups;
289 
290   /* Create destination files initially writable so we can run strip on them.
291      Although GNU strip works fine on read-only files, some others
292      would fail.  */
293   x->set_mode = true;
294   x->mode = S_IRUSR | S_IWUSR;
295   x->stdin_tty = false;
296 
297   x->open_dangling_dest_symlink = false;
298   x->update = false;
299   x->require_preserve_context = false;  /* Not used by install currently.  */
300   x->preserve_security_context = false; /* Whether to copy context from src.  */
301   x->set_security_context = false;    /* Whether to set sys default context.  */
302   x->preserve_xattr = false;
303   x->verbose = false;
304   x->dest_info = NULL;
305   x->src_info = NULL;
306 }
307 
308 #ifdef ENABLE_MATCHPATHCON
309 /* Modify file context to match the specified policy.
310    If an error occurs the file will remain with the default directory
311    context.  Note this sets the context to that returned by matchpathcon,
312    and thus discards MLS levels and user identity of the FILE.  */
313 static void
setdefaultfilecon(char const * file)314 setdefaultfilecon (char const *file)
315 {
316   struct stat st;
317   char *scontext = NULL;
318   static bool first_call = true;
319 
320   if (selinux_enabled != 1)
321     {
322       /* Indicate no context found. */
323       return;
324     }
325   if (lstat (file, &st) != 0)
326     return;
327 
328   if (first_call && IS_ABSOLUTE_FILE_NAME (file))
329     {
330       /* Calling matchpathcon_init_prefix (NULL, "/first_component/")
331          is an optimization to minimize the expense of the following
332          matchpathcon call.  Do it only once, just before the first
333          matchpathcon call.  We *could* call matchpathcon_fini after
334          the final matchpathcon call, but that's not necessary, since
335          by then we're about to exit, and besides, the buffers it
336          would free are still reachable.  */
337       char const *p0;
338       char const *p = file + 1;
339       while (ISSLASH (*p))
340         ++p;
341 
342       /* Record final leading slash, for when FILE starts with two or more.  */
343       p0 = p - 1;
344 
345       if (*p)
346         {
347           char *prefix;
348           do
349             {
350               ++p;
351             }
352           while (*p && !ISSLASH (*p));
353 
354           prefix = malloc (p - p0 + 2);
355           if (prefix)
356             {
357               stpcpy (stpncpy (prefix, p0, p - p0), "/");
358               matchpathcon_init_prefix (NULL, prefix);
359               free (prefix);
360             }
361         }
362     }
363   first_call = false;
364 
365   /* If there's an error determining the context, or it has none,
366      return to allow default context.  Note the "<<none>>" check
367      is only needed for libselinux < 1.20 (2005-01-04).  */
368   if ((matchpathcon (file, st.st_mode, &scontext) != 0)
369       || STREQ (scontext, "<<none>>"))
370     {
371       if (scontext != NULL)
372         freecon (scontext);
373       return;
374     }
375 
376   if (lsetfilecon (file, scontext) < 0 && errno != ENOTSUP)
377     error (0, errno,
378            _("warning: %s: failed to change context to %s"),
379            quotef_n (0, file), quote_n (1, scontext));
380 
381   freecon (scontext);
382   return;
383 }
384 #else
385 static void
setdefaultfilecon(char const * file)386 setdefaultfilecon (char const *file)
387 {
388   (void) file;
389 }
390 #endif
391 
392 /* FILE is the last operand of this command.  Return true if FILE is a
393    directory.  But report an error there is a problem accessing FILE,
394    or if FILE does not exist but would have to refer to an existing
395    directory if it referred to anything at all.  */
396 
397 static bool
target_directory_operand(char const * file)398 target_directory_operand (char const *file)
399 {
400   char const *b = last_component (file);
401   size_t blen = strlen (b);
402   bool looks_like_a_dir = (blen == 0 || ISSLASH (b[blen - 1]));
403   struct stat st;
404   int err = (stat (file, &st) == 0 ? 0 : errno);
405   bool is_a_dir = !err && S_ISDIR (st.st_mode);
406   if (err && err != ENOENT)
407     die (EXIT_FAILURE, err, _("failed to access %s"), quoteaf (file));
408   if (is_a_dir < looks_like_a_dir)
409     die (EXIT_FAILURE, err, _("target %s is not a directory"),
410          quoteaf (file));
411   return is_a_dir;
412 }
413 
414 /* Report that directory DIR was made, if OPTIONS requests this.  */
415 static void
announce_mkdir(char const * dir,void * options)416 announce_mkdir (char const *dir, void *options)
417 {
418   struct cp_options const *x = options;
419   if (x->verbose)
420     prog_fprintf (stdout, _("creating directory %s"), quoteaf (dir));
421 }
422 
423 /* Make ancestor directory DIR, whose last file name component is
424    COMPONENT, with options OPTIONS.  Assume the working directory is
425    COMPONENT's parent.  */
426 static int
make_ancestor(char const * dir,char const * component,void * options)427 make_ancestor (char const *dir, char const *component, void *options)
428 {
429   struct cp_options const *x = options;
430   if (x->set_security_context && defaultcon (component, S_IFDIR) < 0
431       && ! ignorable_ctx_err (errno))
432     error (0, errno, _("failed to set default creation context for %s"),
433            quoteaf (dir));
434 
435   int r = mkdir (component, DEFAULT_MODE);
436   if (r == 0)
437     announce_mkdir (dir, options);
438   return r;
439 }
440 
441 /* Process a command-line file name, for the -d option.  */
442 static int
process_dir(char * dir,struct savewd * wd,void * options)443 process_dir (char *dir, struct savewd *wd, void *options)
444 {
445   struct cp_options const *x = options;
446 
447   int ret = (make_dir_parents (dir, wd, make_ancestor, options,
448                                dir_mode, announce_mkdir,
449                                dir_mode_bits, owner_id, group_id, false)
450           ? EXIT_SUCCESS
451           : EXIT_FAILURE);
452 
453   /* FIXME: Due to the current structure of make_dir_parents()
454      we don't have the facility to call defaultcon() before the
455      final component of DIR is created.  So for now, create the
456      final component with the context from previous component
457      and here we set the context for the final component. */
458   if (ret == EXIT_SUCCESS && x->set_security_context)
459     {
460       if (! restorecon (last_component (dir), false, false)
461           && ! ignorable_ctx_err (errno))
462         error (0, errno, _("failed to restore context for %s"),
463                quoteaf (dir));
464     }
465 
466   return ret;
467 }
468 
469 /* Copy file FROM onto file TO, creating TO if necessary.
470    Return true if successful.  */
471 
472 static bool
copy_file(const char * from,const char * to,const struct cp_options * x)473 copy_file (const char *from, const char *to, const struct cp_options *x)
474 {
475   bool copy_into_self;
476 
477   if (copy_only_if_needed && !need_copy (from, to, x))
478     return true;
479 
480   /* Allow installing from non-regular files like /dev/null.
481      Charles Karney reported that some Sun version of install allows that
482      and that sendmail's installation process relies on the behavior.
483      However, since !x->recursive, the call to "copy" will fail if FROM
484      is a directory.  */
485 
486   return copy (from, to, false, x, &copy_into_self, NULL);
487 }
488 
489 /* Set the attributes of file or directory NAME.
490    Return true if successful.  */
491 
492 static bool
change_attributes(char const * name)493 change_attributes (char const *name)
494 {
495   bool ok = false;
496   /* chown must precede chmod because on some systems,
497      chown clears the set[ug]id bits for non-superusers,
498      resulting in incorrect permissions.
499      On System V, users can give away files with chown and then not
500      be able to chmod them.  So don't give files away.
501 
502      We don't normally ignore errors from chown because the idea of
503      the install command is that the file is supposed to end up with
504      precisely the attributes that the user specified (or defaulted).
505      If the file doesn't end up with the group they asked for, they'll
506      want to know.  */
507 
508   if (! (owner_id == (uid_t) -1 && group_id == (gid_t) -1)
509       && lchown (name, owner_id, group_id) != 0)
510     error (0, errno, _("cannot change ownership of %s"), quoteaf (name));
511   else if (chmod (name, mode) != 0)
512     error (0, errno, _("cannot change permissions of %s"), quoteaf (name));
513   else
514     ok = true;
515 
516   if (use_default_selinux_context)
517     setdefaultfilecon (name);
518 
519   return ok;
520 }
521 
522 /* Set the timestamps of file DEST to match those of SRC_SB.
523    Return true if successful.  */
524 
525 static bool
change_timestamps(struct stat const * src_sb,char const * dest)526 change_timestamps (struct stat const *src_sb, char const *dest)
527 {
528   struct timespec timespec[2];
529   timespec[0] = get_stat_atime (src_sb);
530   timespec[1] = get_stat_mtime (src_sb);
531 
532   if (utimens (dest, timespec))
533     {
534       error (0, errno, _("cannot set timestamps for %s"), quoteaf (dest));
535       return false;
536     }
537   return true;
538 }
539 
540 /* Strip the symbol table from the file NAME.
541    We could dig the magic number out of the file first to
542    determine whether to strip it, but the header files and
543    magic numbers vary so much from system to system that making
544    it portable would be very difficult.  Not worth the effort. */
545 
546 static bool
strip(char const * name)547 strip (char const *name)
548 {
549   int status;
550   bool ok = false;
551   pid_t pid = fork ();
552 
553   switch (pid)
554     {
555     case -1:
556       error (0, errno, _("fork system call failed"));
557       break;
558     case 0:			/* Child. */
559       execlp (strip_program, strip_program, name, NULL);
560       die (EXIT_FAILURE, errno, _("cannot run %s"), quoteaf (strip_program));
561     default:			/* Parent. */
562       if (waitpid (pid, &status, 0) < 0)
563         error (0, errno, _("waiting for strip"));
564       else if (! WIFEXITED (status) || WEXITSTATUS (status))
565         error (0, 0, _("strip process terminated abnormally"));
566       else
567         ok = true;      /* strip succeeded */
568       break;
569     }
570   return ok;
571 }
572 
573 /* Initialize the user and group ownership of the files to install. */
574 
575 static void
get_ids(void)576 get_ids (void)
577 {
578   struct passwd *pw;
579   struct group *gr;
580 
581   if (owner_name)
582     {
583       pw = getpwnam (owner_name);
584       if (pw == NULL)
585         {
586           unsigned long int tmp;
587           if (xstrtoul (owner_name, NULL, 0, &tmp, NULL) != LONGINT_OK
588               || UID_T_MAX < tmp)
589             die (EXIT_FAILURE, 0, _("invalid user %s"),
590                  quote (owner_name));
591           owner_id = tmp;
592         }
593       else
594         owner_id = pw->pw_uid;
595       endpwent ();
596     }
597   else
598     owner_id = (uid_t) -1;
599 
600   if (group_name)
601     {
602       gr = getgrnam (group_name);
603       if (gr == NULL)
604         {
605           unsigned long int tmp;
606           if (xstrtoul (group_name, NULL, 0, &tmp, NULL) != LONGINT_OK
607               || GID_T_MAX < tmp)
608             die (EXIT_FAILURE, 0, _("invalid group %s"),
609                  quote (group_name));
610           group_id = tmp;
611         }
612       else
613         group_id = gr->gr_gid;
614       endgrent ();
615     }
616   else
617     group_id = (gid_t) -1;
618 }
619 
620 void
usage(int status)621 usage (int status)
622 {
623   if (status != EXIT_SUCCESS)
624     emit_try_help ();
625   else
626     {
627       printf (_("\
628 Usage: %s [OPTION]... [-T] SOURCE DEST\n\
629   or:  %s [OPTION]... SOURCE... DIRECTORY\n\
630   or:  %s [OPTION]... -t DIRECTORY SOURCE...\n\
631   or:  %s [OPTION]... -d DIRECTORY...\n\
632 "),
633               program_name, program_name, program_name, program_name);
634       fputs (_("\
635 \n\
636 This install program copies files (often just compiled) into destination\n\
637 locations you choose.  If you want to download and install a ready-to-use\n\
638 package on a GNU/Linux system, you should instead be using a package manager\n\
639 like yum(1) or apt-get(1).\n\
640 \n\
641 In the first three forms, copy SOURCE to DEST or multiple SOURCE(s) to\n\
642 the existing DIRECTORY, while setting permission modes and owner/group.\n\
643 In the 4th form, create all components of the given DIRECTORY(ies).\n\
644 "), stdout);
645 
646       emit_mandatory_arg_note ();
647 
648       fputs (_("\
649       --backup[=CONTROL]  make a backup of each existing destination file\n\
650   -b                  like --backup but does not accept an argument\n\
651   -c                  (ignored)\n\
652   -C, --compare       compare each pair of source and destination files, and\n\
653                         in some cases, do not modify the destination at all\n\
654   -d, --directory     treat all arguments as directory names; create all\n\
655                         components of the specified directories\n\
656 "), stdout);
657       fputs (_("\
658   -D                  create all leading components of DEST except the last,\n\
659                         or all components of --target-directory,\n\
660                         then copy SOURCE to DEST\n\
661   -g, --group=GROUP   set group ownership, instead of process' current group\n\
662   -m, --mode=MODE     set permission mode (as in chmod), instead of rwxr-xr-x\n\
663   -o, --owner=OWNER   set ownership (super-user only)\n\
664 "), stdout);
665       fputs (_("\
666   -p, --preserve-timestamps   apply access/modification times of SOURCE files\n\
667                         to corresponding destination files\n\
668   -s, --strip         strip symbol tables\n\
669       --strip-program=PROGRAM  program used to strip binaries\n\
670   -S, --suffix=SUFFIX  override the usual backup suffix\n\
671   -t, --target-directory=DIRECTORY  copy all SOURCE arguments into DIRECTORY\n\
672   -T, --no-target-directory  treat DEST as a normal file\n\
673   -v, --verbose       print the name of each directory as it is created\n\
674 "), stdout);
675       fputs (_("\
676       --preserve-context  preserve SELinux security context\n\
677   -Z                      set SELinux security context of destination\n\
678                             file and each created directory to default type\n\
679       --context[=CTX]     like -Z, or if CTX is specified then set the\n\
680                             SELinux or SMACK security context to CTX\n\
681 "), stdout);
682 
683       fputs (HELP_OPTION_DESCRIPTION, stdout);
684       fputs (VERSION_OPTION_DESCRIPTION, stdout);
685       emit_backup_suffix_note ();
686       emit_ancillary_info (PROGRAM_NAME);
687     }
688   exit (status);
689 }
690 
691 /* Copy file FROM onto file TO and give TO the appropriate
692    attributes.
693    Return true if successful.  */
694 
695 static bool
install_file_in_file(const char * from,const char * to,const struct cp_options * x)696 install_file_in_file (const char *from, const char *to,
697                       const struct cp_options *x)
698 {
699   struct stat from_sb;
700   if (x->preserve_timestamps && stat (from, &from_sb) != 0)
701     {
702       error (0, errno, _("cannot stat %s"), quoteaf (from));
703       return false;
704     }
705   if (! copy_file (from, to, x))
706     return false;
707   if (strip_files)
708     if (! strip (to))
709       {
710         if (unlink (to) != 0)  /* Cleanup.  */
711           die (EXIT_FAILURE, errno, _("cannot unlink %s"), quoteaf (to));
712         return false;
713       }
714   if (x->preserve_timestamps && (strip_files || ! S_ISREG (from_sb.st_mode))
715       && ! change_timestamps (&from_sb, to))
716     return false;
717   return change_attributes (to);
718 }
719 
720 /* Create any missing parent directories of TO,
721    while maintaining the current Working Directory.
722    Return true if successful.  */
723 
724 static bool
mkancesdirs_safe_wd(char const * from,char * to,struct cp_options * x,bool save_always)725 mkancesdirs_safe_wd (char const *from, char *to, struct cp_options *x,
726                      bool save_always)
727 {
728   bool save_working_directory =
729     save_always
730     || ! (IS_ABSOLUTE_FILE_NAME (from) && IS_ABSOLUTE_FILE_NAME (to));
731   int status = EXIT_SUCCESS;
732 
733   struct savewd wd;
734   savewd_init (&wd);
735   if (! save_working_directory)
736     savewd_finish (&wd);
737 
738   if (mkancesdirs (to, &wd, make_ancestor, x) == -1)
739     {
740       error (0, errno, _("cannot create directory %s"), quoteaf (to));
741       status = EXIT_FAILURE;
742     }
743 
744   if (save_working_directory)
745     {
746       int restore_result = savewd_restore (&wd, status);
747       int restore_errno = errno;
748       savewd_finish (&wd);
749       if (EXIT_SUCCESS < restore_result)
750         return false;
751       if (restore_result < 0 && status == EXIT_SUCCESS)
752         {
753           error (0, restore_errno, _("cannot create directory %s"),
754                  quoteaf (to));
755           return false;
756         }
757     }
758   return status == EXIT_SUCCESS;
759 }
760 
761 /* Copy file FROM onto file TO, creating any missing parent directories of TO.
762    Return true if successful.  */
763 
764 static bool
install_file_in_file_parents(char const * from,char * to,const struct cp_options * x)765 install_file_in_file_parents (char const *from, char *to,
766                               const struct cp_options *x)
767 {
768   return (mkancesdirs_safe_wd (from, to, (struct cp_options *)x, false)
769           && install_file_in_file (from, to, x));
770 }
771 
772 /* Copy file FROM into directory TO_DIR, keeping its same name,
773    and give the copy the appropriate attributes.
774    Return true if successful.  */
775 
776 static bool
install_file_in_dir(const char * from,const char * to_dir,const struct cp_options * x,bool mkdir_and_install)777 install_file_in_dir (const char *from, const char *to_dir,
778                      const struct cp_options *x, bool mkdir_and_install)
779 {
780   const char *from_base = last_component (from);
781   char *to = file_name_concat (to_dir, from_base, NULL);
782   bool ret = true;
783 
784   if (mkdir_and_install)
785     ret = mkancesdirs_safe_wd (from, to, (struct cp_options *)x, true);
786 
787   ret = ret && install_file_in_file (from, to, x);
788   free (to);
789   return ret;
790 }
791 
792 int
main(int argc,char ** argv)793 main (int argc, char **argv)
794 {
795   int optc;
796   int exit_status = EXIT_SUCCESS;
797   const char *specified_mode = NULL;
798   bool make_backups = false;
799   char const *backup_suffix = NULL;
800   char *version_control_string = NULL;
801   bool mkdir_and_install = false;
802   struct cp_options x;
803   char const *target_directory = NULL;
804   bool no_target_directory = false;
805   int n_files;
806   char **file;
807   bool strip_program_specified = false;
808   char const *scontext = NULL;
809   /* set iff kernel has extra selinux system calls */
810   selinux_enabled = (0 < is_selinux_enabled ());
811 
812   initialize_main (&argc, &argv);
813   set_program_name (argv[0]);
814   setlocale (LC_ALL, "");
815   bindtextdomain (PACKAGE, LOCALEDIR);
816   textdomain (PACKAGE);
817 
818   atexit (close_stdin);
819 
820   cp_option_init (&x);
821 
822   owner_name = NULL;
823   group_name = NULL;
824   strip_files = false;
825   dir_arg = false;
826   umask (0);
827 
828   while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pt:TvS:Z", long_options,
829                               NULL)) != -1)
830     {
831       switch (optc)
832         {
833         case 'b':
834           make_backups = true;
835           if (optarg)
836             version_control_string = optarg;
837           break;
838         case 'c':
839           break;
840         case 'C':
841           copy_only_if_needed = true;
842           break;
843         case 's':
844           strip_files = true;
845 #ifdef SIGCHLD
846           /* System V fork+wait does not work if SIGCHLD is ignored.  */
847           signal (SIGCHLD, SIG_DFL);
848 #endif
849           break;
850         case STRIP_PROGRAM_OPTION:
851           strip_program = xstrdup (optarg);
852           strip_program_specified = true;
853           break;
854         case 'd':
855           dir_arg = true;
856           break;
857         case 'D':
858           mkdir_and_install = true;
859           break;
860         case 'v':
861           x.verbose = true;
862           break;
863         case 'g':
864           group_name = optarg;
865           break;
866         case 'm':
867           specified_mode = optarg;
868           break;
869         case 'o':
870           owner_name = optarg;
871           break;
872         case 'p':
873           x.preserve_timestamps = true;
874           break;
875         case 'S':
876           make_backups = true;
877           backup_suffix = optarg;
878           break;
879         case 't':
880           if (target_directory)
881             die (EXIT_FAILURE, 0,
882                  _("multiple target directories specified"));
883           target_directory = optarg;
884           break;
885         case 'T':
886           no_target_directory = true;
887           break;
888 
889         case PRESERVE_CONTEXT_OPTION:
890           if (! selinux_enabled)
891             {
892               error (0, 0, _("WARNING: ignoring --preserve-context; "
893                              "this kernel is not SELinux-enabled"));
894               break;
895             }
896           x.preserve_security_context = true;
897           use_default_selinux_context = false;
898           break;
899         case 'Z':
900           if (selinux_enabled)
901             {
902               /* Disable use of the install(1) specific setdefaultfilecon().
903                  Note setdefaultfilecon() is different from the newer and more
904                  generic restorecon() in that the former sets the context of
905                  the dest files to that returned by matchpathcon directly,
906                  thus discarding MLS level and user identity of the file.
907                  TODO: consider removing setdefaultfilecon() in future.  */
908               use_default_selinux_context = false;
909 
910               if (optarg)
911                 scontext = optarg;
912               else
913                 x.set_security_context = true;
914             }
915           else if (optarg)
916             {
917               error (0, 0,
918                      _("warning: ignoring --context; "
919                        "it requires an SELinux-enabled kernel"));
920             }
921           break;
922         case_GETOPT_HELP_CHAR;
923         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
924         default:
925           usage (EXIT_FAILURE);
926         }
927     }
928 
929   /* Check for invalid combinations of arguments. */
930   if (dir_arg && strip_files)
931     die (EXIT_FAILURE, 0,
932          _("the strip option may not be used when installing a directory"));
933   if (dir_arg && target_directory)
934     die (EXIT_FAILURE, 0,
935          _("target directory not allowed when installing a directory"));
936 
937   if (target_directory)
938     {
939       struct stat st;
940       bool stat_success = stat (target_directory, &st) == 0 ? true : false;
941       if (! mkdir_and_install && ! stat_success)
942         die (EXIT_FAILURE, errno, _("failed to access %s"),
943              quoteaf (target_directory));
944       if (stat_success && ! S_ISDIR (st.st_mode))
945         die (EXIT_FAILURE, 0, _("target %s is not a directory"),
946              quoteaf (target_directory));
947     }
948 
949   x.backup_type = (make_backups
950                    ? xget_version (_("backup type"),
951                                    version_control_string)
952                    : no_backups);
953   set_simple_backup_suffix (backup_suffix);
954 
955   if (x.preserve_security_context && (x.set_security_context || scontext))
956     die (EXIT_FAILURE, 0,
957          _("cannot set target context and preserve it"));
958 
959   if (scontext && setfscreatecon (se_const (scontext)) < 0)
960     die (EXIT_FAILURE, errno,
961          _("failed to set default file creation context to %s"),
962          quote (scontext));
963 
964   n_files = argc - optind;
965   file = argv + optind;
966 
967   if (n_files <= ! (dir_arg || target_directory))
968     {
969       if (n_files <= 0)
970         error (0, 0, _("missing file operand"));
971       else
972         error (0, 0, _("missing destination file operand after %s"),
973                quoteaf (file[0]));
974       usage (EXIT_FAILURE);
975     }
976 
977   if (no_target_directory)
978     {
979       if (target_directory)
980         die (EXIT_FAILURE, 0,
981              _("cannot combine --target-directory (-t) "
982                "and --no-target-directory (-T)"));
983       if (2 < n_files)
984         {
985           error (0, 0, _("extra operand %s"), quoteaf (file[2]));
986           usage (EXIT_FAILURE);
987         }
988     }
989   else if (! (dir_arg || target_directory))
990     {
991       if (2 <= n_files && target_directory_operand (file[n_files - 1]))
992         target_directory = file[--n_files];
993       else if (2 < n_files)
994         die (EXIT_FAILURE, 0, _("target %s is not a directory"),
995              quoteaf (file[n_files - 1]));
996     }
997 
998   if (specified_mode)
999     {
1000       struct mode_change *change = mode_compile (specified_mode);
1001       if (!change)
1002         die (EXIT_FAILURE, 0, _("invalid mode %s"), quote (specified_mode));
1003       mode = mode_adjust (0, false, 0, change, NULL);
1004       dir_mode = mode_adjust (0, true, 0, change, &dir_mode_bits);
1005       free (change);
1006     }
1007 
1008   if (strip_program_specified && !strip_files)
1009     error (0, 0, _("WARNING: ignoring --strip-program option as -s option was "
1010                    "not specified"));
1011 
1012   if (copy_only_if_needed && x.preserve_timestamps)
1013     {
1014       error (0, 0, _("options --compare (-C) and --preserve-timestamps are "
1015                      "mutually exclusive"));
1016       usage (EXIT_FAILURE);
1017     }
1018 
1019   if (copy_only_if_needed && strip_files)
1020     {
1021       error (0, 0, _("options --compare (-C) and --strip are mutually "
1022                      "exclusive"));
1023       usage (EXIT_FAILURE);
1024     }
1025 
1026   if (copy_only_if_needed && extra_mode (mode))
1027     error (0, 0, _("the --compare (-C) option is ignored when you"
1028                    " specify a mode with non-permission bits"));
1029 
1030   get_ids ();
1031 
1032   if (dir_arg)
1033     exit_status = savewd_process_files (n_files, file, process_dir, &x);
1034   else
1035     {
1036       /* FIXME: it's a little gross that this initialization is
1037          required by copy.c::copy. */
1038       hash_init ();
1039 
1040       if (!target_directory)
1041         {
1042           if (! (mkdir_and_install
1043                  ? install_file_in_file_parents (file[0], file[1], &x)
1044                  : install_file_in_file (file[0], file[1], &x)))
1045             exit_status = EXIT_FAILURE;
1046         }
1047       else
1048         {
1049           int i;
1050           dest_info_init (&x);
1051           for (i = 0; i < n_files; i++)
1052             if (! install_file_in_dir (file[i], target_directory, &x,
1053                                        i == 0 && mkdir_and_install))
1054               exit_status = EXIT_FAILURE;
1055         }
1056     }
1057 
1058   return exit_status;
1059 }
1060