dd: synchronize output after write errors
[coreutils.git] / src / install.c
blobb157f59d28282004cae8ceee86b34b4269467826
1 /* install - copy files and set attributes
2 Copyright (C) 1989-2022 Free Software Foundation, Inc.
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.
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.
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/>. */
17 /* Written by David MacKenzie <djm@gnu.ai.mit.edu> */
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/label.h>
27 #include <sys/wait.h>
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"
48 /* The official name of this program (e.g., no 'g' prefix). */
49 #define PROGRAM_NAME "install"
51 #define AUTHORS proper_name ("David MacKenzie")
53 static int selinux_enabled = 0;
54 static bool use_default_selinux_context = true;
56 #if ! HAVE_ENDGRENT
57 # define endgrent() ((void) 0)
58 #endif
60 #if ! HAVE_ENDPWENT
61 # define endpwent() ((void) 0)
62 #endif
64 #if ! HAVE_LCHOWN
65 # define lchown(name, uid, gid) chown (name, uid, gid)
66 #endif
68 /* The user name that will own the files, or NULL to make the owner
69 the current user ID. */
70 static char *owner_name;
72 /* The user ID corresponding to 'owner_name'. */
73 static uid_t owner_id;
75 /* The group name that will own the files, or NULL to make the group
76 the current group ID. */
77 static char *group_name;
79 /* The group ID corresponding to 'group_name'. */
80 static gid_t group_id;
82 #define DEFAULT_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
84 /* The file mode bits to which non-directory files will be set. The umask has
85 no effect. */
86 static mode_t mode = DEFAULT_MODE;
88 /* Similar, but for directories. */
89 static mode_t dir_mode = DEFAULT_MODE;
91 /* The file mode bits that the user cares about. This should be a
92 superset of DIR_MODE and a subset of CHMOD_MODE_BITS. This matters
93 for directories, since otherwise directories may keep their S_ISUID
94 or S_ISGID bits. */
95 static mode_t dir_mode_bits = CHMOD_MODE_BITS;
97 /* Compare files before installing (-C) */
98 static bool copy_only_if_needed;
100 /* If true, strip executable files after copying them. */
101 static bool strip_files;
103 /* If true, install a directory instead of a regular file. */
104 static bool dir_arg;
106 /* Program used to strip binaries, "strip" is default */
107 static char const *strip_program = "strip";
109 /* For long options that have no equivalent short option, use a
110 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
111 enum
113 PRESERVE_CONTEXT_OPTION = CHAR_MAX + 1,
114 STRIP_PROGRAM_OPTION
117 static struct option const long_options[] =
119 {"backup", optional_argument, NULL, 'b'},
120 {"compare", no_argument, NULL, 'C'},
121 {GETOPT_SELINUX_CONTEXT_OPTION_DECL},
122 {"directory", no_argument, NULL, 'd'},
123 {"group", required_argument, NULL, 'g'},
124 {"mode", required_argument, NULL, 'm'},
125 {"no-target-directory", no_argument, NULL, 'T'},
126 {"owner", required_argument, NULL, 'o'},
127 {"preserve-timestamps", no_argument, NULL, 'p'},
128 {"preserve-context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
129 {"strip", no_argument, NULL, 's'},
130 {"strip-program", required_argument, NULL, STRIP_PROGRAM_OPTION},
131 {"suffix", required_argument, NULL, 'S'},
132 {"target-directory", required_argument, NULL, 't'},
133 {"verbose", no_argument, NULL, 'v'},
134 {GETOPT_HELP_OPTION_DECL},
135 {GETOPT_VERSION_OPTION_DECL},
136 {NULL, 0, NULL, 0}
139 /* Compare content of opened files using file descriptors A_FD and B_FD. Return
140 true if files are equal. */
141 static bool
142 have_same_content (int a_fd, int b_fd)
144 enum { CMP_BLOCK_SIZE = 4096 };
145 static char a_buff[CMP_BLOCK_SIZE];
146 static char b_buff[CMP_BLOCK_SIZE];
148 size_t size;
149 while (0 < (size = full_read (a_fd, a_buff, sizeof a_buff))) {
150 if (size != full_read (b_fd, b_buff, sizeof b_buff))
151 return false;
153 if (memcmp (a_buff, b_buff, size) != 0)
154 return false;
157 return size == 0;
160 /* Return true for mode with non-permission bits. */
161 static bool
162 extra_mode (mode_t input)
164 mode_t mask = S_IRWXUGO | S_IFMT;
165 return !! (input & ~ mask);
168 /* Return true if copy of file SRC_NAME to file DEST_NAME is necessary. */
169 static bool
170 need_copy (char const *src_name, char const *dest_name,
171 const struct cp_options *x)
173 struct stat src_sb, dest_sb;
174 int src_fd, dest_fd;
175 bool content_match;
177 if (extra_mode (mode))
178 return true;
180 /* compare files using stat */
181 if (lstat (src_name, &src_sb) != 0)
182 return true;
184 if (lstat (dest_name, &dest_sb) != 0)
185 return true;
187 if (!S_ISREG (src_sb.st_mode) || !S_ISREG (dest_sb.st_mode)
188 || extra_mode (src_sb.st_mode) || extra_mode (dest_sb.st_mode))
189 return true;
191 if (src_sb.st_size != dest_sb.st_size
192 || (dest_sb.st_mode & CHMOD_MODE_BITS) != mode)
193 return true;
195 if (owner_id == (uid_t) -1)
197 errno = 0;
198 uid_t ruid = getuid ();
199 if ((ruid == (uid_t) -1 && errno) || dest_sb.st_uid != ruid)
200 return true;
202 else if (dest_sb.st_uid != owner_id)
203 return true;
205 if (group_id == (uid_t) -1)
207 errno = 0;
208 gid_t rgid = getgid ();
209 if ((rgid == (uid_t) -1 && errno) || dest_sb.st_gid != rgid)
210 return true;
212 else if (dest_sb.st_gid != group_id)
213 return true;
215 /* compare SELinux context if preserving */
216 if (selinux_enabled && x->preserve_security_context)
218 char *file_scontext = NULL;
219 char *to_scontext = NULL;
220 bool scontext_match;
222 if (getfilecon (src_name, &file_scontext) == -1)
223 return true;
225 if (getfilecon (dest_name, &to_scontext) == -1)
227 freecon (file_scontext);
228 return true;
231 scontext_match = STREQ (file_scontext, to_scontext);
233 freecon (file_scontext);
234 freecon (to_scontext);
235 if (!scontext_match)
236 return true;
239 /* compare files content */
240 src_fd = open (src_name, O_RDONLY | O_BINARY);
241 if (src_fd < 0)
242 return true;
244 dest_fd = open (dest_name, O_RDONLY | O_BINARY);
245 if (dest_fd < 0)
247 close (src_fd);
248 return true;
251 content_match = have_same_content (src_fd, dest_fd);
253 close (src_fd);
254 close (dest_fd);
255 return !content_match;
258 static void
259 cp_option_init (struct cp_options *x)
261 cp_options_default (x);
262 x->copy_as_regular = true;
263 x->reflink_mode = REFLINK_AUTO;
264 x->dereference = DEREF_ALWAYS;
265 x->unlink_dest_before_opening = true;
266 x->unlink_dest_after_failed_open = false;
267 x->hard_link = false;
268 x->interactive = I_UNSPECIFIED;
269 x->move_mode = false;
270 x->install_mode = true;
271 x->one_file_system = false;
272 x->preserve_ownership = false;
273 x->preserve_links = false;
274 x->preserve_mode = false;
275 x->preserve_timestamps = false;
276 x->explicit_no_preserve_mode = false;
277 x->reduce_diagnostics=false;
278 x->data_copy_required = true;
279 x->require_preserve = false;
280 x->require_preserve_xattr = false;
281 x->recursive = false;
282 x->sparse_mode = SPARSE_AUTO;
283 x->symbolic_link = false;
284 x->backup_type = no_backups;
286 /* Create destination files initially writable so we can run strip on them.
287 Although GNU strip works fine on read-only files, some others
288 would fail. */
289 x->set_mode = true;
290 x->mode = S_IRUSR | S_IWUSR;
291 x->stdin_tty = false;
293 x->open_dangling_dest_symlink = false;
294 x->update = false;
295 x->require_preserve_context = false; /* Not used by install currently. */
296 x->preserve_security_context = false; /* Whether to copy context from src. */
297 x->set_security_context = NULL; /* Whether to set sys default context. */
298 x->preserve_xattr = false;
299 x->verbose = false;
300 x->dest_info = NULL;
301 x->src_info = NULL;
304 static struct selabel_handle *
305 get_labeling_handle (void)
307 static bool initialized;
308 static struct selabel_handle *hnd;
309 if (!initialized)
311 initialized = true;
312 hnd = selabel_open (SELABEL_CTX_FILE, NULL, 0);
313 if (!hnd)
314 error (0, errno, _("warning: security labeling handle failed"));
316 return hnd;
319 /* Modify file context to match the specified policy.
320 If an error occurs the file will remain with the default directory
321 context. Note this sets the context to that returned by selabel_lookup
322 and thus discards MLS levels and user identity of the FILE. */
323 static void
324 setdefaultfilecon (char const *file)
326 struct stat st;
327 char *scontext = NULL;
329 if (selinux_enabled != 1)
331 /* Indicate no context found. */
332 return;
334 if (lstat (file, &st) != 0)
335 return;
337 struct selabel_handle *hnd = get_labeling_handle ();
338 if (!hnd)
339 return;
340 if (selabel_lookup (hnd, &scontext, file, st.st_mode) != 0)
342 if (errno != ENOENT && ! ignorable_ctx_err (errno))
343 error (0, errno, _("warning: %s: context lookup failed"),
344 quotef (file));
345 return;
348 if (lsetfilecon (file, scontext) < 0 && errno != ENOTSUP)
349 error (0, errno,
350 _("warning: %s: failed to change context to %s"),
351 quotef_n (0, file), quote_n (1, scontext));
353 freecon (scontext);
356 /* FILE is the last operand of this command. Return true if FILE is a
357 directory. But report an error there is a problem accessing FILE,
358 or if FILE does not exist but would have to refer to an existing
359 directory if it referred to anything at all. */
361 static bool
362 target_directory_operand (char const *file)
364 char const *b = last_component (file);
365 size_t blen = strlen (b);
366 bool looks_like_a_dir = (blen == 0 || ISSLASH (b[blen - 1]));
367 struct stat st;
368 int err = (stat (file, &st) == 0 ? 0 : errno);
369 bool is_a_dir = !err && S_ISDIR (st.st_mode);
370 if (err && err != ENOENT)
371 die (EXIT_FAILURE, err, _("failed to access %s"), quoteaf (file));
372 if (is_a_dir < looks_like_a_dir)
373 die (EXIT_FAILURE, err, _("target %s is not a directory"),
374 quoteaf (file));
375 return is_a_dir;
378 /* Report that directory DIR was made, if OPTIONS requests this. */
379 static void
380 announce_mkdir (char const *dir, void *options)
382 struct cp_options const *x = options;
383 if (x->verbose)
384 prog_fprintf (stdout, _("creating directory %s"), quoteaf (dir));
387 /* Make ancestor directory DIR, whose last file name component is
388 COMPONENT, with options OPTIONS. Assume the working directory is
389 COMPONENT's parent. */
390 static int
391 make_ancestor (char const *dir, char const *component, void *options)
393 struct cp_options const *x = options;
394 if (x->set_security_context
395 && defaultcon (x->set_security_context, component, S_IFDIR) < 0
396 && ! ignorable_ctx_err (errno))
397 error (0, errno, _("failed to set default creation context for %s"),
398 quoteaf (dir));
400 int r = mkdir (component, DEFAULT_MODE);
401 if (r == 0)
402 announce_mkdir (dir, options);
403 return r;
406 /* Process a command-line file name, for the -d option. */
407 static int
408 process_dir (char *dir, struct savewd *wd, void *options)
410 struct cp_options const *x = options;
412 int ret = (make_dir_parents (dir, wd, make_ancestor, options,
413 dir_mode, announce_mkdir,
414 dir_mode_bits, owner_id, group_id, false)
415 ? EXIT_SUCCESS
416 : EXIT_FAILURE);
418 /* FIXME: Due to the current structure of make_dir_parents()
419 we don't have the facility to call defaultcon() before the
420 final component of DIR is created. So for now, create the
421 final component with the context from previous component
422 and here we set the context for the final component. */
423 if (ret == EXIT_SUCCESS && x->set_security_context)
425 if (! restorecon (x->set_security_context, last_component (dir), false)
426 && ! ignorable_ctx_err (errno))
427 error (0, errno, _("failed to restore context for %s"),
428 quoteaf (dir));
431 return ret;
434 /* Copy file FROM onto file TO, creating TO if necessary.
435 Return true if successful. */
437 static bool
438 copy_file (char const *from, char const *to, const struct cp_options *x)
440 bool copy_into_self;
442 if (copy_only_if_needed && !need_copy (from, to, x))
443 return true;
445 /* Allow installing from non-regular files like /dev/null.
446 Charles Karney reported that some Sun version of install allows that
447 and that sendmail's installation process relies on the behavior.
448 However, since !x->recursive, the call to "copy" will fail if FROM
449 is a directory. */
451 return copy (from, to, AT_FDCWD, to, 0, x, &copy_into_self, NULL);
454 /* Set the attributes of file or directory NAME.
455 Return true if successful. */
457 static bool
458 change_attributes (char const *name)
460 bool ok = false;
461 /* chown must precede chmod because on some systems,
462 chown clears the set[ug]id bits for non-superusers,
463 resulting in incorrect permissions.
464 On System V, users can give away files with chown and then not
465 be able to chmod them. So don't give files away.
467 We don't normally ignore errors from chown because the idea of
468 the install command is that the file is supposed to end up with
469 precisely the attributes that the user specified (or defaulted).
470 If the file doesn't end up with the group they asked for, they'll
471 want to know. */
473 if (! (owner_id == (uid_t) -1 && group_id == (gid_t) -1)
474 && lchown (name, owner_id, group_id) != 0)
475 error (0, errno, _("cannot change ownership of %s"), quoteaf (name));
476 else if (chmod (name, mode) != 0)
477 error (0, errno, _("cannot change permissions of %s"), quoteaf (name));
478 else
479 ok = true;
481 if (use_default_selinux_context)
482 setdefaultfilecon (name);
484 return ok;
487 /* Set the timestamps of file DEST to match those of SRC_SB.
488 Return true if successful. */
490 static bool
491 change_timestamps (struct stat const *src_sb, char const *dest)
493 struct timespec timespec[2];
494 timespec[0] = get_stat_atime (src_sb);
495 timespec[1] = get_stat_mtime (src_sb);
497 if (utimens (dest, timespec))
499 error (0, errno, _("cannot set timestamps for %s"), quoteaf (dest));
500 return false;
502 return true;
505 /* Strip the symbol table from the file NAME.
506 We could dig the magic number out of the file first to
507 determine whether to strip it, but the header files and
508 magic numbers vary so much from system to system that making
509 it portable would be very difficult. Not worth the effort. */
511 static bool
512 strip (char const *name)
514 int status;
515 bool ok = false;
516 pid_t pid = fork ();
518 switch (pid)
520 case -1:
521 error (0, errno, _("fork system call failed"));
522 break;
523 case 0: /* Child. */
524 execlp (strip_program, strip_program, name, NULL);
525 die (EXIT_FAILURE, errno, _("cannot run %s"), quoteaf (strip_program));
526 default: /* Parent. */
527 if (waitpid (pid, &status, 0) < 0)
528 error (0, errno, _("waiting for strip"));
529 else if (! WIFEXITED (status) || WEXITSTATUS (status))
530 error (0, 0, _("strip process terminated abnormally"));
531 else
532 ok = true; /* strip succeeded */
533 break;
535 return ok;
538 /* Initialize the user and group ownership of the files to install. */
540 static void
541 get_ids (void)
543 struct passwd *pw;
544 struct group *gr;
546 if (owner_name)
548 pw = getpwnam (owner_name);
549 if (pw == NULL)
551 uintmax_t tmp;
552 if (xstrtoumax (owner_name, NULL, 0, &tmp, "") != LONGINT_OK
553 || UID_T_MAX < tmp)
554 die (EXIT_FAILURE, 0, _("invalid user %s"),
555 quote (owner_name));
556 owner_id = tmp;
558 else
559 owner_id = pw->pw_uid;
560 endpwent ();
562 else
563 owner_id = (uid_t) -1;
565 if (group_name)
567 gr = getgrnam (group_name);
568 if (gr == NULL)
570 uintmax_t tmp;
571 if (xstrtoumax (group_name, NULL, 0, &tmp, "") != LONGINT_OK
572 || GID_T_MAX < tmp)
573 die (EXIT_FAILURE, 0, _("invalid group %s"),
574 quote (group_name));
575 group_id = tmp;
577 else
578 group_id = gr->gr_gid;
579 endgrent ();
581 else
582 group_id = (gid_t) -1;
585 void
586 usage (int status)
588 if (status != EXIT_SUCCESS)
589 emit_try_help ();
590 else
592 printf (_("\
593 Usage: %s [OPTION]... [-T] SOURCE DEST\n\
594 or: %s [OPTION]... SOURCE... DIRECTORY\n\
595 or: %s [OPTION]... -t DIRECTORY SOURCE...\n\
596 or: %s [OPTION]... -d DIRECTORY...\n\
598 program_name, program_name, program_name, program_name);
599 fputs (_("\
601 This install program copies files (often just compiled) into destination\n\
602 locations you choose. If you want to download and install a ready-to-use\n\
603 package on a GNU/Linux system, you should instead be using a package manager\n\
604 like yum(1) or apt-get(1).\n\
606 In the first three forms, copy SOURCE to DEST or multiple SOURCE(s) to\n\
607 the existing DIRECTORY, while setting permission modes and owner/group.\n\
608 In the 4th form, create all components of the given DIRECTORY(ies).\n\
609 "), stdout);
611 emit_mandatory_arg_note ();
613 fputs (_("\
614 --backup[=CONTROL] make a backup of each existing destination file\n\
615 -b like --backup but does not accept an argument\n\
616 -c (ignored)\n\
617 -C, --compare compare each pair of source and destination files, and\n\
618 in some cases, do not modify the destination at all\n\
619 -d, --directory treat all arguments as directory names; create all\n\
620 components of the specified directories\n\
621 "), stdout);
622 fputs (_("\
623 -D create all leading components of DEST except the last,\n\
624 or all components of --target-directory,\n\
625 then copy SOURCE to DEST\n\
626 -g, --group=GROUP set group ownership, instead of process' current group\n\
627 -m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\
628 -o, --owner=OWNER set ownership (super-user only)\n\
629 "), stdout);
630 fputs (_("\
631 -p, --preserve-timestamps apply access/modification times of SOURCE files\n\
632 to corresponding destination files\n\
633 -s, --strip strip symbol tables\n\
634 --strip-program=PROGRAM program used to strip binaries\n\
635 -S, --suffix=SUFFIX override the usual backup suffix\n\
636 -t, --target-directory=DIRECTORY copy all SOURCE arguments into DIRECTORY\n\
637 -T, --no-target-directory treat DEST as a normal file\n\
638 -v, --verbose print the name of each directory as it is created\n\
639 "), stdout);
640 fputs (_("\
641 --preserve-context preserve SELinux security context\n\
642 -Z set SELinux security context of destination\n\
643 file and each created directory to default type\n\
644 --context[=CTX] like -Z, or if CTX is specified then set the\n\
645 SELinux or SMACK security context to CTX\n\
646 "), stdout);
648 fputs (HELP_OPTION_DESCRIPTION, stdout);
649 fputs (VERSION_OPTION_DESCRIPTION, stdout);
650 emit_backup_suffix_note ();
651 emit_ancillary_info (PROGRAM_NAME);
653 exit (status);
656 /* Copy file FROM onto file TO and give TO the appropriate
657 attributes.
658 Return true if successful. */
660 static bool
661 install_file_in_file (char const *from, char const *to,
662 const struct cp_options *x)
664 struct stat from_sb;
665 if (x->preserve_timestamps && stat (from, &from_sb) != 0)
667 error (0, errno, _("cannot stat %s"), quoteaf (from));
668 return false;
670 if (! copy_file (from, to, x))
671 return false;
672 if (strip_files)
673 if (! strip (to))
675 if (unlink (to) != 0) /* Cleanup. */
676 die (EXIT_FAILURE, errno, _("cannot unlink %s"), quoteaf (to));
677 return false;
679 if (x->preserve_timestamps && (strip_files || ! S_ISREG (from_sb.st_mode))
680 && ! change_timestamps (&from_sb, to))
681 return false;
682 return change_attributes (to);
685 /* Create any missing parent directories of TO,
686 while maintaining the current Working Directory.
687 Return true if successful. */
689 static bool
690 mkancesdirs_safe_wd (char const *from, char *to, struct cp_options *x,
691 bool save_always)
693 bool save_working_directory =
694 save_always
695 || ! (IS_ABSOLUTE_FILE_NAME (from) && IS_ABSOLUTE_FILE_NAME (to));
696 int status = EXIT_SUCCESS;
698 struct savewd wd;
699 savewd_init (&wd);
700 if (! save_working_directory)
701 savewd_finish (&wd);
703 if (mkancesdirs (to, &wd, make_ancestor, x) == -1)
705 error (0, errno, _("cannot create directory %s"), quoteaf (to));
706 status = EXIT_FAILURE;
709 if (save_working_directory)
711 int restore_result = savewd_restore (&wd, status);
712 int restore_errno = errno;
713 savewd_finish (&wd);
714 if (EXIT_SUCCESS < restore_result)
715 return false;
716 if (restore_result < 0 && status == EXIT_SUCCESS)
718 error (0, restore_errno, _("cannot create directory %s"),
719 quoteaf (to));
720 return false;
723 return status == EXIT_SUCCESS;
726 /* Copy file FROM onto file TO, creating any missing parent directories of TO.
727 Return true if successful. */
729 static bool
730 install_file_in_file_parents (char const *from, char *to,
731 const struct cp_options *x)
733 return (mkancesdirs_safe_wd (from, to, (struct cp_options *)x, false)
734 && install_file_in_file (from, to, x));
737 /* Copy file FROM into directory TO_DIR, keeping its same name,
738 and give the copy the appropriate attributes.
739 Return true if successful. */
741 static bool
742 install_file_in_dir (char const *from, char const *to_dir,
743 const struct cp_options *x, bool mkdir_and_install)
745 char const *from_base = last_component (from);
746 char *to = file_name_concat (to_dir, from_base, NULL);
747 bool ret = true;
749 if (mkdir_and_install)
750 ret = mkancesdirs_safe_wd (from, to, (struct cp_options *)x, true);
752 ret = ret && install_file_in_file (from, to, x);
753 free (to);
754 return ret;
758 main (int argc, char **argv)
760 int optc;
761 int exit_status = EXIT_SUCCESS;
762 char const *specified_mode = NULL;
763 bool make_backups = false;
764 char const *backup_suffix = NULL;
765 char *version_control_string = NULL;
766 bool mkdir_and_install = false;
767 struct cp_options x;
768 char const *target_directory = NULL;
769 bool no_target_directory = false;
770 int n_files;
771 char **file;
772 bool strip_program_specified = false;
773 char const *scontext = NULL;
774 /* set iff kernel has extra selinux system calls */
775 selinux_enabled = (0 < is_selinux_enabled ());
777 initialize_main (&argc, &argv);
778 set_program_name (argv[0]);
779 setlocale (LC_ALL, "");
780 bindtextdomain (PACKAGE, LOCALEDIR);
781 textdomain (PACKAGE);
783 atexit (close_stdin);
785 cp_option_init (&x);
787 owner_name = NULL;
788 group_name = NULL;
789 strip_files = false;
790 dir_arg = false;
791 umask (0);
793 while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pt:TvS:Z", long_options,
794 NULL)) != -1)
796 switch (optc)
798 case 'b':
799 make_backups = true;
800 if (optarg)
801 version_control_string = optarg;
802 break;
803 case 'c':
804 break;
805 case 'C':
806 copy_only_if_needed = true;
807 break;
808 case 's':
809 strip_files = true;
810 #ifdef SIGCHLD
811 /* System V fork+wait does not work if SIGCHLD is ignored. */
812 signal (SIGCHLD, SIG_DFL);
813 #endif
814 break;
815 case STRIP_PROGRAM_OPTION:
816 strip_program = xstrdup (optarg);
817 strip_program_specified = true;
818 break;
819 case 'd':
820 dir_arg = true;
821 break;
822 case 'D':
823 mkdir_and_install = true;
824 break;
825 case 'v':
826 x.verbose = true;
827 break;
828 case 'g':
829 group_name = optarg;
830 break;
831 case 'm':
832 specified_mode = optarg;
833 break;
834 case 'o':
835 owner_name = optarg;
836 break;
837 case 'p':
838 x.preserve_timestamps = true;
839 break;
840 case 'S':
841 make_backups = true;
842 backup_suffix = optarg;
843 break;
844 case 't':
845 if (target_directory)
846 die (EXIT_FAILURE, 0,
847 _("multiple target directories specified"));
848 target_directory = optarg;
849 break;
850 case 'T':
851 no_target_directory = true;
852 break;
854 case PRESERVE_CONTEXT_OPTION:
855 if (! selinux_enabled)
857 error (0, 0, _("WARNING: ignoring --preserve-context; "
858 "this kernel is not SELinux-enabled"));
859 break;
861 x.preserve_security_context = true;
862 use_default_selinux_context = false;
863 break;
864 case 'Z':
865 if (selinux_enabled)
867 /* Disable use of the install(1) specific setdefaultfilecon().
868 Note setdefaultfilecon() is different from the newer and more
869 generic restorecon() in that the former sets the context of
870 the dest files to that returned by selabel_lookup directly,
871 thus discarding MLS level and user identity of the file.
872 TODO: consider removing setdefaultfilecon() in future. */
873 use_default_selinux_context = false;
875 if (optarg)
876 scontext = optarg;
877 else
878 x.set_security_context = get_labeling_handle ();
880 else if (optarg)
882 error (0, 0,
883 _("warning: ignoring --context; "
884 "it requires an SELinux-enabled kernel"));
886 break;
887 case_GETOPT_HELP_CHAR;
888 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
889 default:
890 usage (EXIT_FAILURE);
894 /* Check for invalid combinations of arguments. */
895 if (dir_arg && strip_files)
896 die (EXIT_FAILURE, 0,
897 _("the strip option may not be used when installing a directory"));
898 if (dir_arg && target_directory)
899 die (EXIT_FAILURE, 0,
900 _("target directory not allowed when installing a directory"));
902 if (target_directory)
904 struct stat st;
905 bool stat_success = stat (target_directory, &st) == 0 ? true : false;
906 if (! mkdir_and_install && ! stat_success)
907 die (EXIT_FAILURE, errno, _("failed to access %s"),
908 quoteaf (target_directory));
909 if (stat_success && ! S_ISDIR (st.st_mode))
910 die (EXIT_FAILURE, 0, _("target %s is not a directory"),
911 quoteaf (target_directory));
914 x.backup_type = (make_backups
915 ? xget_version (_("backup type"),
916 version_control_string)
917 : no_backups);
918 set_simple_backup_suffix (backup_suffix);
920 if (x.preserve_security_context && (x.set_security_context || scontext))
921 die (EXIT_FAILURE, 0,
922 _("cannot set target context and preserve it"));
924 if (scontext && setfscreatecon (scontext) < 0)
925 die (EXIT_FAILURE, errno,
926 _("failed to set default file creation context to %s"),
927 quote (scontext));
929 n_files = argc - optind;
930 file = argv + optind;
932 if (n_files <= ! (dir_arg || target_directory))
934 if (n_files <= 0)
935 error (0, 0, _("missing file operand"));
936 else
937 error (0, 0, _("missing destination file operand after %s"),
938 quoteaf (file[0]));
939 usage (EXIT_FAILURE);
942 if (no_target_directory)
944 if (target_directory)
945 die (EXIT_FAILURE, 0,
946 _("cannot combine --target-directory (-t) "
947 "and --no-target-directory (-T)"));
948 if (2 < n_files)
950 error (0, 0, _("extra operand %s"), quoteaf (file[2]));
951 usage (EXIT_FAILURE);
954 else if (! (dir_arg || target_directory))
956 if (2 <= n_files && target_directory_operand (file[n_files - 1]))
957 target_directory = file[--n_files];
958 else if (2 < n_files)
959 die (EXIT_FAILURE, 0, _("target %s is not a directory"),
960 quoteaf (file[n_files - 1]));
963 if (specified_mode)
965 struct mode_change *change = mode_compile (specified_mode);
966 if (!change)
967 die (EXIT_FAILURE, 0, _("invalid mode %s"), quote (specified_mode));
968 mode = mode_adjust (0, false, 0, change, NULL);
969 dir_mode = mode_adjust (0, true, 0, change, &dir_mode_bits);
970 free (change);
973 if (strip_program_specified && !strip_files)
974 error (0, 0, _("WARNING: ignoring --strip-program option as -s option was "
975 "not specified"));
977 if (copy_only_if_needed && x.preserve_timestamps)
979 error (0, 0, _("options --compare (-C) and --preserve-timestamps are "
980 "mutually exclusive"));
981 usage (EXIT_FAILURE);
984 if (copy_only_if_needed && strip_files)
986 error (0, 0, _("options --compare (-C) and --strip are mutually "
987 "exclusive"));
988 usage (EXIT_FAILURE);
991 if (copy_only_if_needed && extra_mode (mode))
992 error (0, 0, _("the --compare (-C) option is ignored when you"
993 " specify a mode with non-permission bits"));
995 get_ids ();
997 if (dir_arg)
998 exit_status = savewd_process_files (n_files, file, process_dir, &x);
999 else
1001 /* FIXME: it's a little gross that this initialization is
1002 required by copy.c::copy. */
1003 hash_init ();
1005 if (!target_directory)
1007 if (! (mkdir_and_install
1008 ? install_file_in_file_parents (file[0], file[1], &x)
1009 : install_file_in_file (file[0], file[1], &x)))
1010 exit_status = EXIT_FAILURE;
1012 else
1014 int i;
1015 dest_info_init (&x);
1016 for (i = 0; i < n_files; i++)
1017 if (! install_file_in_dir (file[i], target_directory, &x,
1018 i == 0 && mkdir_and_install))
1019 exit_status = EXIT_FAILURE;
1020 #ifdef lint
1021 dest_info_free (&x);
1022 #endif
1026 return exit_status;