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, ©_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