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> */
22 #include <sys/types.h>
26 #include <selinux/label.h>
30 #include "backupfile.h"
35 #include "filenamecat.h"
36 #include "full-read.h"
37 #include "mkancesdirs.h"
39 #include "modechange.h"
40 #include "prog-fprintf.h"
44 #include "stat-time.h"
45 #include "targetdir.h"
49 /* The official name of this program (e.g., no 'g' prefix). */
50 #define PROGRAM_NAME "install"
52 #define AUTHORS proper_name ("David MacKenzie")
54 static int selinux_enabled
= 0;
55 static bool use_default_selinux_context
= true;
58 # define endgrent() ((void) 0)
62 # define endpwent() ((void) 0)
65 /* The user name that will own the files, or NULL to make the owner
66 the current user ID. */
67 static char *owner_name
;
69 /* The user ID corresponding to 'owner_name'. */
70 static uid_t owner_id
;
72 /* The group name that will own the files, or NULL to make the group
73 the current group ID. */
74 static char *group_name
;
76 /* The group ID corresponding to 'group_name'. */
77 static gid_t group_id
;
79 #define DEFAULT_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
81 /* The file mode bits to which non-directory files will be set. The umask has
83 static mode_t mode
= DEFAULT_MODE
;
85 /* Similar, but for directories. */
86 static mode_t dir_mode
= DEFAULT_MODE
;
88 /* The file mode bits that the user cares about. This should be a
89 superset of DIR_MODE and a subset of CHMOD_MODE_BITS. This matters
90 for directories, since otherwise directories may keep their S_ISUID
92 static mode_t dir_mode_bits
= CHMOD_MODE_BITS
;
94 /* Compare files before installing (-C) */
95 static bool copy_only_if_needed
;
97 /* If true, strip executable files after copying them. */
98 static bool strip_files
;
100 /* If true, install a directory instead of a regular file. */
103 /* Program used to strip binaries, "strip" is default */
104 static char const *strip_program
= "strip";
106 /* For long options that have no equivalent short option, use a
107 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
110 PRESERVE_CONTEXT_OPTION
= CHAR_MAX
+ 1,
114 static struct option
const long_options
[] =
116 {"backup", optional_argument
, NULL
, 'b'},
117 {"compare", no_argument
, NULL
, 'C'},
118 {GETOPT_SELINUX_CONTEXT_OPTION_DECL
},
119 {"directory", no_argument
, NULL
, 'd'},
120 {"group", required_argument
, NULL
, 'g'},
121 {"mode", required_argument
, NULL
, 'm'},
122 {"no-target-directory", no_argument
, NULL
, 'T'},
123 {"owner", required_argument
, NULL
, 'o'},
124 {"preserve-timestamps", no_argument
, NULL
, 'p'},
125 {"preserve-context", no_argument
, NULL
, PRESERVE_CONTEXT_OPTION
},
126 {"strip", no_argument
, NULL
, 's'},
127 {"strip-program", required_argument
, NULL
, STRIP_PROGRAM_OPTION
},
128 {"suffix", required_argument
, NULL
, 'S'},
129 {"target-directory", required_argument
, NULL
, 't'},
130 {"verbose", no_argument
, NULL
, 'v'},
131 {GETOPT_HELP_OPTION_DECL
},
132 {GETOPT_VERSION_OPTION_DECL
},
136 /* Compare content of opened files using file descriptors A_FD and B_FD. Return
137 true if files are equal. */
139 have_same_content (int a_fd
, int b_fd
)
141 enum { CMP_BLOCK_SIZE
= 4096 };
142 static char a_buff
[CMP_BLOCK_SIZE
];
143 static char b_buff
[CMP_BLOCK_SIZE
];
146 while (0 < (size
= full_read (a_fd
, a_buff
, sizeof a_buff
))) {
147 if (size
!= full_read (b_fd
, b_buff
, sizeof b_buff
))
150 if (memcmp (a_buff
, b_buff
, size
) != 0)
157 /* Return true for mode with non-permission bits. */
159 extra_mode (mode_t input
)
161 mode_t mask
= S_IRWXUGO
| S_IFMT
;
162 return !! (input
& ~ mask
);
165 /* Return true if copy of file SRC_NAME to file DEST_NAME aka
166 DEST_DIRFD+DEST_RELNAME is necessary. */
168 need_copy (char const *src_name
, char const *dest_name
,
169 int dest_dirfd
, char const *dest_relname
,
170 const struct cp_options
*x
)
172 struct stat src_sb
, dest_sb
;
176 if (extra_mode (mode
))
179 /* compare files using stat */
180 if (lstat (src_name
, &src_sb
) != 0)
183 if (fstatat (dest_dirfd
, dest_relname
, &dest_sb
, AT_SYMLINK_NOFOLLOW
) != 0)
186 if (!S_ISREG (src_sb
.st_mode
) || !S_ISREG (dest_sb
.st_mode
)
187 || extra_mode (src_sb
.st_mode
) || extra_mode (dest_sb
.st_mode
))
190 if (src_sb
.st_size
!= dest_sb
.st_size
191 || (dest_sb
.st_mode
& CHMOD_MODE_BITS
) != mode
)
194 if (owner_id
== (uid_t
) -1)
197 uid_t ruid
= getuid ();
198 if ((ruid
== (uid_t
) -1 && errno
) || dest_sb
.st_uid
!= ruid
)
201 else if (dest_sb
.st_uid
!= owner_id
)
204 if (group_id
== (uid_t
) -1)
207 gid_t rgid
= getgid ();
208 if ((rgid
== (uid_t
) -1 && errno
) || dest_sb
.st_gid
!= rgid
)
211 else if (dest_sb
.st_gid
!= group_id
)
214 /* compare SELinux context if preserving */
215 if (selinux_enabled
&& x
->preserve_security_context
)
217 char *file_scontext
= NULL
;
218 char *to_scontext
= NULL
;
221 if (getfilecon (src_name
, &file_scontext
) == -1)
224 if (getfilecon (dest_name
, &to_scontext
) == -1)
226 freecon (file_scontext
);
230 scontext_match
= STREQ (file_scontext
, to_scontext
);
232 freecon (file_scontext
);
233 freecon (to_scontext
);
238 /* compare files content */
239 src_fd
= open (src_name
, O_RDONLY
| O_BINARY
);
243 dest_fd
= openat (dest_dirfd
, dest_relname
, O_RDONLY
| O_BINARY
);
250 content_match
= have_same_content (src_fd
, dest_fd
);
254 return !content_match
;
258 cp_option_init (struct cp_options
*x
)
260 cp_options_default (x
);
261 x
->copy_as_regular
= true;
262 x
->reflink_mode
= REFLINK_AUTO
;
263 x
->dereference
= DEREF_ALWAYS
;
264 x
->unlink_dest_before_opening
= true;
265 x
->unlink_dest_after_failed_open
= false;
266 x
->hard_link
= false;
267 x
->interactive
= I_UNSPECIFIED
;
268 x
->move_mode
= false;
269 x
->install_mode
= true;
270 x
->one_file_system
= false;
271 x
->preserve_ownership
= false;
272 x
->preserve_links
= false;
273 x
->preserve_mode
= false;
274 x
->preserve_timestamps
= false;
275 x
->explicit_no_preserve_mode
= false;
276 x
->reduce_diagnostics
=false;
277 x
->data_copy_required
= true;
278 x
->require_preserve
= false;
279 x
->require_preserve_xattr
= false;
280 x
->recursive
= false;
281 x
->sparse_mode
= SPARSE_AUTO
;
282 x
->symbolic_link
= false;
283 x
->backup_type
= no_backups
;
285 /* Create destination files initially writable so we can run strip on them.
286 Although GNU strip works fine on read-only files, some others
289 x
->mode
= S_IRUSR
| S_IWUSR
;
290 x
->stdin_tty
= false;
292 x
->open_dangling_dest_symlink
= false;
294 x
->require_preserve_context
= false; /* Not used by install currently. */
295 x
->preserve_security_context
= false; /* Whether to copy context from src. */
296 x
->set_security_context
= NULL
; /* Whether to set sys default context. */
297 x
->preserve_xattr
= false;
303 static struct selabel_handle
*
304 get_labeling_handle (void)
306 static bool initialized
;
307 static struct selabel_handle
*hnd
;
311 hnd
= selabel_open (SELABEL_CTX_FILE
, NULL
, 0);
313 error (0, errno
, _("warning: security labeling handle failed"));
318 /* Modify file context to match the specified policy.
319 If an error occurs the file will remain with the default directory
320 context. Note this sets the context to that returned by selabel_lookup
321 and thus discards MLS levels and user identity of the FILE. */
323 setdefaultfilecon (char const *file
)
326 char *scontext
= NULL
;
328 if (selinux_enabled
!= 1)
330 /* Indicate no context found. */
333 if (lstat (file
, &st
) != 0)
336 struct selabel_handle
*hnd
= get_labeling_handle ();
339 if (selabel_lookup (hnd
, &scontext
, file
, st
.st_mode
) != 0)
341 if (errno
!= ENOENT
&& ! ignorable_ctx_err (errno
))
342 error (0, errno
, _("warning: %s: context lookup failed"),
347 if (lsetfilecon (file
, scontext
) < 0 && errno
!= ENOTSUP
)
349 _("warning: %s: failed to change context to %s"),
350 quotef_n (0, file
), quote_n (1, scontext
));
355 /* Report that directory DIR was made, if OPTIONS requests this. */
357 announce_mkdir (char const *dir
, void *options
)
359 struct cp_options
const *x
= options
;
361 prog_fprintf (stdout
, _("creating directory %s"), quoteaf (dir
));
364 /* Make ancestor directory DIR, whose last file name component is
365 COMPONENT, with options OPTIONS. Assume the working directory is
366 COMPONENT's parent. */
368 make_ancestor (char const *dir
, char const *component
, void *options
)
370 struct cp_options
const *x
= options
;
371 if (x
->set_security_context
372 && defaultcon (x
->set_security_context
, component
, S_IFDIR
) < 0
373 && ! ignorable_ctx_err (errno
))
374 error (0, errno
, _("failed to set default creation context for %s"),
377 int r
= mkdir (component
, DEFAULT_MODE
);
379 announce_mkdir (dir
, options
);
383 /* Process a command-line file name, for the -d option. */
385 process_dir (char *dir
, struct savewd
*wd
, void *options
)
387 struct cp_options
const *x
= options
;
389 int ret
= (make_dir_parents (dir
, wd
, make_ancestor
, options
,
390 dir_mode
, announce_mkdir
,
391 dir_mode_bits
, owner_id
, group_id
, false)
395 /* FIXME: Due to the current structure of make_dir_parents()
396 we don't have the facility to call defaultcon() before the
397 final component of DIR is created. So for now, create the
398 final component with the context from previous component
399 and here we set the context for the final component. */
400 if (ret
== EXIT_SUCCESS
&& x
->set_security_context
)
402 if (! restorecon (x
->set_security_context
, last_component (dir
), false)
403 && ! ignorable_ctx_err (errno
))
404 error (0, errno
, _("failed to restore context for %s"),
411 /* Copy file FROM onto file TO aka TO_DIRFD+TO_RELNAME, creating TO if
412 necessary. Return true if successful. */
415 copy_file (char const *from
, char const *to
,
416 int to_dirfd
, char const *to_relname
, const struct cp_options
*x
)
420 if (copy_only_if_needed
&& !need_copy (from
, to
, to_dirfd
, to_relname
, x
))
423 /* Allow installing from non-regular files like /dev/null.
424 Charles Karney reported that some Sun version of install allows that
425 and that sendmail's installation process relies on the behavior.
426 However, since !x->recursive, the call to "copy" will fail if FROM
429 return copy (from
, to
, to_dirfd
, to_relname
, 0, x
, ©_into_self
, NULL
);
432 /* Set the attributes of file or directory NAME aka DIRFD+RELNAME.
433 Return true if successful. */
436 change_attributes (char const *name
, int dirfd
, char const *relname
)
439 /* chown must precede chmod because on some systems,
440 chown clears the set[ug]id bits for non-superusers,
441 resulting in incorrect permissions.
442 On System V, users can give away files with chown and then not
443 be able to chmod them. So don't give files away.
445 We don't normally ignore errors from chown because the idea of
446 the install command is that the file is supposed to end up with
447 precisely the attributes that the user specified (or defaulted).
448 If the file doesn't end up with the group they asked for, they'll
451 if (! (owner_id
== (uid_t
) -1 && group_id
== (gid_t
) -1)
452 && lchownat (dirfd
, relname
, owner_id
, group_id
) != 0)
453 error (0, errno
, _("cannot change ownership of %s"), quoteaf (name
));
454 else if (chmodat (dirfd
, relname
, mode
) != 0)
455 error (0, errno
, _("cannot change permissions of %s"), quoteaf (name
));
459 if (use_default_selinux_context
)
460 setdefaultfilecon (name
);
465 /* Set the timestamps of file DEST aka DIRFD+RELNAME to match those of SRC_SB.
466 Return true if successful. */
469 change_timestamps (struct stat
const *src_sb
, char const *dest
,
470 int dirfd
, char const *relname
)
472 struct timespec timespec
[2];
473 timespec
[0] = get_stat_atime (src_sb
);
474 timespec
[1] = get_stat_mtime (src_sb
);
476 if (utimensat (dirfd
, relname
, timespec
, 0))
478 error (0, errno
, _("cannot set timestamps for %s"), quoteaf (dest
));
484 /* Strip the symbol table from the file NAME.
485 We could dig the magic number out of the file first to
486 determine whether to strip it, but the header files and
487 magic numbers vary so much from system to system that making
488 it portable would be very difficult. Not worth the effort. */
491 strip (char const *name
)
500 error (0, errno
, _("fork system call failed"));
503 execlp (strip_program
, strip_program
, name
, NULL
);
504 die (EXIT_FAILURE
, errno
, _("cannot run %s"), quoteaf (strip_program
));
505 default: /* Parent. */
506 if (waitpid (pid
, &status
, 0) < 0)
507 error (0, errno
, _("waiting for strip"));
508 else if (! WIFEXITED (status
) || WEXITSTATUS (status
))
509 error (0, 0, _("strip process terminated abnormally"));
511 ok
= true; /* strip succeeded */
517 /* Initialize the user and group ownership of the files to install. */
527 pw
= getpwnam (owner_name
);
531 if (xstrtoumax (owner_name
, NULL
, 0, &tmp
, "") != LONGINT_OK
533 die (EXIT_FAILURE
, 0, _("invalid user %s"),
538 owner_id
= pw
->pw_uid
;
542 owner_id
= (uid_t
) -1;
546 gr
= getgrnam (group_name
);
550 if (xstrtoumax (group_name
, NULL
, 0, &tmp
, "") != LONGINT_OK
552 die (EXIT_FAILURE
, 0, _("invalid group %s"),
557 group_id
= gr
->gr_gid
;
561 group_id
= (gid_t
) -1;
567 if (status
!= EXIT_SUCCESS
)
572 Usage: %s [OPTION]... [-T] SOURCE DEST\n\
573 or: %s [OPTION]... SOURCE... DIRECTORY\n\
574 or: %s [OPTION]... -t DIRECTORY SOURCE...\n\
575 or: %s [OPTION]... -d DIRECTORY...\n\
577 program_name
, program_name
, program_name
, program_name
);
580 This install program copies files (often just compiled) into destination\n\
581 locations you choose. If you want to download and install a ready-to-use\n\
582 package on a GNU/Linux system, you should instead be using a package manager\n\
583 like yum(1) or apt-get(1).\n\
585 In the first three forms, copy SOURCE to DEST or multiple SOURCE(s) to\n\
586 the existing DIRECTORY, while setting permission modes and owner/group.\n\
587 In the 4th form, create all components of the given DIRECTORY(ies).\n\
590 emit_mandatory_arg_note ();
593 --backup[=CONTROL] make a backup of each existing destination file\n\
594 -b like --backup but does not accept an argument\n\
596 -C, --compare compare content of source and destination files, and\n\
597 if no change to content, ownership, and permissions,\n\
598 do not modify the destination at all\n\
599 -d, --directory treat all arguments as directory names; create all\n\
600 components of the specified directories\n\
603 -D create all leading components of DEST except the last,\n\
604 or all components of --target-directory,\n\
605 then copy SOURCE to DEST\n\
606 -g, --group=GROUP set group ownership, instead of process' current group\n\
607 -m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\
608 -o, --owner=OWNER set ownership (super-user only)\n\
611 -p, --preserve-timestamps apply access/modification times of SOURCE files\n\
612 to corresponding destination files\n\
613 -s, --strip strip symbol tables\n\
614 --strip-program=PROGRAM program used to strip binaries\n\
615 -S, --suffix=SUFFIX override the usual backup suffix\n\
616 -t, --target-directory=DIRECTORY copy all SOURCE arguments into DIRECTORY\n\
617 -T, --no-target-directory treat DEST as a normal file\n\
618 -v, --verbose print the name of each directory as it is created\n\
621 --preserve-context preserve SELinux security context\n\
622 -Z set SELinux security context of destination\n\
623 file and each created directory to default type\n\
624 --context[=CTX] like -Z, or if CTX is specified then set the\n\
625 SELinux or SMACK security context to CTX\n\
628 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
629 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
630 emit_backup_suffix_note ();
631 emit_ancillary_info (PROGRAM_NAME
);
636 /* Copy file FROM onto file TO aka TO_DIRFD+TO_RELNAME and give TO the
637 appropriate attributes. X gives the command options.
638 Return true if successful. */
641 install_file_in_file (char const *from
, char const *to
,
642 int to_dirfd
, char const *to_relname
,
643 const struct cp_options
*x
)
646 if (x
->preserve_timestamps
&& stat (from
, &from_sb
) != 0)
648 error (0, errno
, _("cannot stat %s"), quoteaf (from
));
651 if (! copy_file (from
, to
, to_dirfd
, to_relname
, x
))
656 if (unlinkat (to_dirfd
, to_relname
, 0) != 0) /* Cleanup. */
657 die (EXIT_FAILURE
, errno
, _("cannot unlink %s"), quoteaf (to
));
660 if (x
->preserve_timestamps
&& (strip_files
|| ! S_ISREG (from_sb
.st_mode
))
661 && ! change_timestamps (&from_sb
, to
, to_dirfd
, to_relname
))
663 return change_attributes (to
, to_dirfd
, to_relname
);
666 /* Create any missing parent directories of TO,
667 while maintaining the current Working Directory.
668 Return true if successful. */
671 mkancesdirs_safe_wd (char const *from
, char *to
, struct cp_options
*x
,
674 bool save_working_directory
=
676 || ! (IS_ABSOLUTE_FILE_NAME (from
) && IS_ABSOLUTE_FILE_NAME (to
));
677 int status
= EXIT_SUCCESS
;
681 if (! save_working_directory
)
684 if (mkancesdirs (to
, &wd
, make_ancestor
, x
) == -1)
686 error (0, errno
, _("cannot create directory %s"), quoteaf (to
));
687 status
= EXIT_FAILURE
;
690 if (save_working_directory
)
692 int restore_result
= savewd_restore (&wd
, status
);
693 int restore_errno
= errno
;
695 if (EXIT_SUCCESS
< restore_result
)
697 if (restore_result
< 0 && status
== EXIT_SUCCESS
)
699 error (0, restore_errno
, _("cannot create directory %s"),
704 return status
== EXIT_SUCCESS
;
707 /* Copy file FROM onto file TO, creating any missing parent directories of TO.
708 Return true if successful. */
711 install_file_in_file_parents (char const *from
, char *to
,
712 const struct cp_options
*x
)
714 return (mkancesdirs_safe_wd (from
, to
, (struct cp_options
*)x
, false)
715 && install_file_in_file (from
, to
, AT_FDCWD
, to
, x
));
718 /* Copy file FROM into directory TO_DIR, keeping its same name,
719 and give the copy the appropriate attributes.
720 Return true if successful. */
723 install_file_in_dir (char const *from
, char const *to_dir
,
724 const struct cp_options
*x
, bool mkdir_and_install
,
727 char const *from_base
= last_component (from
);
729 char *to
= file_name_concat (to_dir
, from_base
, &to_relname
);
732 if (!target_dirfd_valid (*target_dirfd
)
733 && (ret
= mkdir_and_install
)
734 && (ret
= mkancesdirs_safe_wd (from
, to
, (struct cp_options
*) x
, true)))
736 int fd
= open (to_dir
, O_PATHSEARCH
| O_DIRECTORY
);
739 error (0, errno
, _("cannot open %s"), quoteaf (to
));
748 int to_dirfd
= *target_dirfd
;
749 if (!target_dirfd_valid (to_dirfd
))
754 ret
= install_file_in_file (from
, to
, to_dirfd
, to_relname
, x
);
762 main (int argc
, char **argv
)
765 int exit_status
= EXIT_SUCCESS
;
766 char const *specified_mode
= NULL
;
767 bool make_backups
= false;
768 char const *backup_suffix
= NULL
;
769 char *version_control_string
= NULL
;
770 bool mkdir_and_install
= false;
772 char const *target_directory
= NULL
;
773 bool no_target_directory
= false;
776 bool strip_program_specified
= false;
777 char const *scontext
= NULL
;
778 /* set iff kernel has extra selinux system calls */
779 selinux_enabled
= (0 < is_selinux_enabled ());
781 initialize_main (&argc
, &argv
);
782 set_program_name (argv
[0]);
783 setlocale (LC_ALL
, "");
784 bindtextdomain (PACKAGE
, LOCALEDIR
);
785 textdomain (PACKAGE
);
787 atexit (close_stdin
);
797 while ((optc
= getopt_long (argc
, argv
, "bcCsDdg:m:o:pt:TvS:Z", long_options
,
805 version_control_string
= optarg
;
810 copy_only_if_needed
= true;
815 /* System V fork+wait does not work if SIGCHLD is ignored. */
816 signal (SIGCHLD
, SIG_DFL
);
819 case STRIP_PROGRAM_OPTION
:
820 strip_program
= xstrdup (optarg
);
821 strip_program_specified
= true;
827 mkdir_and_install
= true;
836 specified_mode
= optarg
;
842 x
.preserve_timestamps
= true;
846 backup_suffix
= optarg
;
849 if (target_directory
)
850 die (EXIT_FAILURE
, 0,
851 _("multiple target directories specified"));
852 target_directory
= optarg
;
855 no_target_directory
= true;
858 case PRESERVE_CONTEXT_OPTION
:
859 if (! selinux_enabled
)
861 error (0, 0, _("WARNING: ignoring --preserve-context; "
862 "this kernel is not SELinux-enabled"));
865 x
.preserve_security_context
= true;
866 use_default_selinux_context
= false;
871 /* Disable use of the install(1) specific setdefaultfilecon().
872 Note setdefaultfilecon() is different from the newer and more
873 generic restorecon() in that the former sets the context of
874 the dest files to that returned by selabel_lookup directly,
875 thus discarding MLS level and user identity of the file.
876 TODO: consider removing setdefaultfilecon() in future. */
877 use_default_selinux_context
= false;
882 x
.set_security_context
= get_labeling_handle ();
887 _("warning: ignoring --context; "
888 "it requires an SELinux-enabled kernel"));
891 case_GETOPT_HELP_CHAR
;
892 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
894 usage (EXIT_FAILURE
);
898 /* Check for invalid combinations of arguments. */
899 if (dir_arg
&& strip_files
)
900 die (EXIT_FAILURE
, 0,
901 _("the strip option may not be used when installing a directory"));
902 if (dir_arg
&& target_directory
)
903 die (EXIT_FAILURE
, 0,
904 _("target directory not allowed when installing a directory"));
906 x
.backup_type
= (make_backups
907 ? xget_version (_("backup type"),
908 version_control_string
)
910 set_simple_backup_suffix (backup_suffix
);
912 if (x
.preserve_security_context
&& (x
.set_security_context
|| scontext
))
913 die (EXIT_FAILURE
, 0,
914 _("cannot set target context and preserve it"));
916 if (scontext
&& setfscreatecon (scontext
) < 0)
917 die (EXIT_FAILURE
, errno
,
918 _("failed to set default file creation context to %s"),
921 n_files
= argc
- optind
;
922 file
= argv
+ optind
;
924 if (n_files
<= ! (dir_arg
|| target_directory
))
927 error (0, 0, _("missing file operand"));
929 error (0, 0, _("missing destination file operand after %s"),
931 usage (EXIT_FAILURE
);
935 int target_dirfd
= AT_FDCWD
;
936 if (no_target_directory
)
938 if (target_directory
)
939 die (EXIT_FAILURE
, 0,
940 _("cannot combine --target-directory (-t) "
941 "and --no-target-directory (-T)"));
944 error (0, 0, _("extra operand %s"), quoteaf (file
[2]));
945 usage (EXIT_FAILURE
);
948 else if (target_directory
)
950 target_dirfd
= target_directory_operand (target_directory
, &sb
);
951 if (! (target_dirfd_valid (target_dirfd
)
952 || (mkdir_and_install
&& errno
== ENOENT
)))
953 die (EXIT_FAILURE
, errno
, _("failed to access %s"),
954 quoteaf (target_directory
));
958 char const *lastfile
= file
[n_files
- 1];
959 int fd
= target_directory_operand (lastfile
, &sb
);
960 if (target_dirfd_valid (fd
))
963 target_directory
= lastfile
;
966 else if (2 < n_files
)
967 die (EXIT_FAILURE
, errno
, _("target %s"), quoteaf (lastfile
));
972 struct mode_change
*change
= mode_compile (specified_mode
);
974 die (EXIT_FAILURE
, 0, _("invalid mode %s"), quote (specified_mode
));
975 mode
= mode_adjust (0, false, 0, change
, NULL
);
976 dir_mode
= mode_adjust (0, true, 0, change
, &dir_mode_bits
);
980 if (strip_program_specified
&& !strip_files
)
981 error (0, 0, _("WARNING: ignoring --strip-program option as -s option was "
984 if (copy_only_if_needed
&& x
.preserve_timestamps
)
986 error (0, 0, _("options --compare (-C) and --preserve-timestamps are "
987 "mutually exclusive"));
988 usage (EXIT_FAILURE
);
991 if (copy_only_if_needed
&& strip_files
)
993 error (0, 0, _("options --compare (-C) and --strip are mutually "
995 usage (EXIT_FAILURE
);
998 if (copy_only_if_needed
&& extra_mode (mode
))
999 error (0, 0, _("the --compare (-C) option is ignored when you"
1000 " specify a mode with non-permission bits"));
1005 exit_status
= savewd_process_files (n_files
, file
, process_dir
, &x
);
1008 /* FIXME: it's a little gross that this initialization is
1009 required by copy.c::copy. */
1012 if (!target_directory
)
1014 if (! (mkdir_and_install
1015 ? install_file_in_file_parents (file
[0], file
[1], &x
)
1016 : install_file_in_file (file
[0], file
[1], AT_FDCWD
,
1018 exit_status
= EXIT_FAILURE
;
1023 dest_info_init (&x
);
1024 for (i
= 0; i
< n_files
; i
++)
1025 if (! install_file_in_dir (file
[i
], target_directory
, &x
,
1026 i
== 0 && mkdir_and_install
,
1028 exit_status
= EXIT_FAILURE
;
1032 main_exit (exit_status
);