split: port ‘split -n N /dev/null’ better to macOS
[coreutils.git] / src / install.c
blob3aa6ea92b6ef29e5ab995212107cded2b1b6ed91
1 /* install - copy files and set attributes
2 Copyright (C) 1989-2023 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 "targetdir.h"
46 #include "utimens.h"
47 #include "xstrtol.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;
57 #if ! HAVE_ENDGRENT
58 # define endgrent() ((void) 0)
59 #endif
61 #if ! HAVE_ENDPWENT
62 # define endpwent() ((void) 0)
63 #endif
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
82 no effect. */
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
91 or S_ISGID bits. */
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. */
101 static bool dir_arg;
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. */
108 enum
110 DEBUG_OPTION = CHAR_MAX + 1,
111 PRESERVE_CONTEXT_OPTION,
112 STRIP_PROGRAM_OPTION
115 static struct option const long_options[] =
117 {"backup", optional_argument, NULL, 'b'},
118 {"compare", no_argument, NULL, 'C'},
119 {GETOPT_SELINUX_CONTEXT_OPTION_DECL},
120 {"debug", no_argument, NULL, DEBUG_OPTION},
121 {"directory", no_argument, NULL, 'd'},
122 {"group", required_argument, NULL, 'g'},
123 {"mode", required_argument, NULL, 'm'},
124 {"no-target-directory", no_argument, NULL, 'T'},
125 {"owner", required_argument, NULL, 'o'},
126 {"preserve-timestamps", no_argument, NULL, 'p'},
127 {"preserve-context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
128 {"strip", no_argument, NULL, 's'},
129 {"strip-program", required_argument, NULL, STRIP_PROGRAM_OPTION},
130 {"suffix", required_argument, NULL, 'S'},
131 {"target-directory", required_argument, NULL, 't'},
132 {"verbose", no_argument, NULL, 'v'},
133 {GETOPT_HELP_OPTION_DECL},
134 {GETOPT_VERSION_OPTION_DECL},
135 {NULL, 0, NULL, 0}
138 /* Compare content of opened files using file descriptors A_FD and B_FD. Return
139 true if files are equal. */
140 static bool
141 have_same_content (int a_fd, int b_fd)
143 enum { CMP_BLOCK_SIZE = 4096 };
144 static char a_buff[CMP_BLOCK_SIZE];
145 static char b_buff[CMP_BLOCK_SIZE];
147 size_t size;
148 while (0 < (size = full_read (a_fd, a_buff, sizeof a_buff))) {
149 if (size != full_read (b_fd, b_buff, sizeof b_buff))
150 return false;
152 if (memcmp (a_buff, b_buff, size) != 0)
153 return false;
156 return size == 0;
159 /* Return true for mode with non-permission bits. */
160 static bool
161 extra_mode (mode_t input)
163 mode_t mask = S_IRWXUGO | S_IFMT;
164 return !! (input & ~ mask);
167 /* Return true if copy of file SRC_NAME to file DEST_NAME aka
168 DEST_DIRFD+DEST_RELNAME is necessary. */
169 static bool
170 need_copy (char const *src_name, char const *dest_name,
171 int dest_dirfd, char const *dest_relname,
172 const struct cp_options *x)
174 struct stat src_sb, dest_sb;
175 int src_fd, dest_fd;
176 bool content_match;
178 if (extra_mode (mode))
179 return true;
181 /* compare files using stat */
182 if (lstat (src_name, &src_sb) != 0)
183 return true;
185 if (fstatat (dest_dirfd, dest_relname, &dest_sb, AT_SYMLINK_NOFOLLOW) != 0)
186 return true;
188 if (!S_ISREG (src_sb.st_mode) || !S_ISREG (dest_sb.st_mode)
189 || extra_mode (src_sb.st_mode) || extra_mode (dest_sb.st_mode))
190 return true;
192 if (src_sb.st_size != dest_sb.st_size
193 || (dest_sb.st_mode & CHMOD_MODE_BITS) != mode)
194 return true;
196 if (owner_id == (uid_t) -1)
198 errno = 0;
199 uid_t ruid = getuid ();
200 if ((ruid == (uid_t) -1 && errno) || dest_sb.st_uid != ruid)
201 return true;
203 else if (dest_sb.st_uid != owner_id)
204 return true;
206 if (group_id == (uid_t) -1)
208 errno = 0;
209 gid_t rgid = getgid ();
210 if ((rgid == (uid_t) -1 && errno) || dest_sb.st_gid != rgid)
211 return true;
213 else if (dest_sb.st_gid != group_id)
214 return true;
216 /* compare SELinux context if preserving */
217 if (selinux_enabled && x->preserve_security_context)
219 char *file_scontext = NULL;
220 char *to_scontext = NULL;
221 bool scontext_match;
223 if (getfilecon (src_name, &file_scontext) == -1)
224 return true;
226 if (getfilecon (dest_name, &to_scontext) == -1)
228 freecon (file_scontext);
229 return true;
232 scontext_match = STREQ (file_scontext, to_scontext);
234 freecon (file_scontext);
235 freecon (to_scontext);
236 if (!scontext_match)
237 return true;
240 /* compare files content */
241 src_fd = open (src_name, O_RDONLY | O_BINARY);
242 if (src_fd < 0)
243 return true;
245 dest_fd = openat (dest_dirfd, dest_relname, O_RDONLY | O_BINARY);
246 if (dest_fd < 0)
248 close (src_fd);
249 return true;
252 content_match = have_same_content (src_fd, dest_fd);
254 close (src_fd);
255 close (dest_fd);
256 return !content_match;
259 static void
260 cp_option_init (struct cp_options *x)
262 cp_options_default (x);
263 x->copy_as_regular = true;
264 x->reflink_mode = REFLINK_AUTO;
265 x->dereference = DEREF_ALWAYS;
266 x->unlink_dest_before_opening = true;
267 x->unlink_dest_after_failed_open = false;
268 x->hard_link = false;
269 x->interactive = I_UNSPECIFIED;
270 x->move_mode = false;
271 x->install_mode = true;
272 x->one_file_system = false;
273 x->preserve_ownership = false;
274 x->preserve_links = false;
275 x->preserve_mode = false;
276 x->preserve_timestamps = false;
277 x->explicit_no_preserve_mode = false;
278 x->reduce_diagnostics=false;
279 x->data_copy_required = true;
280 x->require_preserve = false;
281 x->require_preserve_xattr = false;
282 x->recursive = false;
283 x->sparse_mode = SPARSE_AUTO;
284 x->symbolic_link = false;
285 x->backup_type = no_backups;
287 /* Create destination files initially writable so we can run strip on them.
288 Although GNU strip works fine on read-only files, some others
289 would fail. */
290 x->set_mode = true;
291 x->mode = S_IRUSR | S_IWUSR;
292 x->stdin_tty = false;
294 x->open_dangling_dest_symlink = false;
295 x->update = false;
296 x->require_preserve_context = false; /* Not used by install currently. */
297 x->preserve_security_context = false; /* Whether to copy context from src. */
298 x->set_security_context = NULL; /* Whether to set sys default context. */
299 x->preserve_xattr = false;
300 x->verbose = false;
301 x->dest_info = NULL;
302 x->src_info = NULL;
305 static struct selabel_handle *
306 get_labeling_handle (void)
308 static bool initialized;
309 static struct selabel_handle *hnd;
310 if (!initialized)
312 initialized = true;
313 hnd = selabel_open (SELABEL_CTX_FILE, NULL, 0);
314 if (!hnd)
315 error (0, errno, _("warning: security labeling handle failed"));
317 return hnd;
320 /* Modify file context to match the specified policy.
321 If an error occurs the file will remain with the default directory
322 context. Note this sets the context to that returned by selabel_lookup
323 and thus discards MLS levels and user identity of the FILE. */
324 static void
325 setdefaultfilecon (char const *file)
327 struct stat st;
328 char *scontext = NULL;
330 if (selinux_enabled != 1)
332 /* Indicate no context found. */
333 return;
335 if (lstat (file, &st) != 0)
336 return;
338 struct selabel_handle *hnd = get_labeling_handle ();
339 if (!hnd)
340 return;
341 if (selabel_lookup (hnd, &scontext, file, st.st_mode) != 0)
343 if (errno != ENOENT && ! ignorable_ctx_err (errno))
344 error (0, errno, _("warning: %s: context lookup failed"),
345 quotef (file));
346 return;
349 if (lsetfilecon (file, scontext) < 0 && errno != ENOTSUP)
350 error (0, errno,
351 _("warning: %s: failed to change context to %s"),
352 quotef_n (0, file), quote_n (1, scontext));
354 freecon (scontext);
357 /* Report that directory DIR was made, if OPTIONS requests this. */
358 static void
359 announce_mkdir (char const *dir, void *options)
361 struct cp_options const *x = options;
362 if (x->verbose)
363 prog_fprintf (stdout, _("creating directory %s"), quoteaf (dir));
366 /* Make ancestor directory DIR, whose last file name component is
367 COMPONENT, with options OPTIONS. Assume the working directory is
368 COMPONENT's parent. */
369 static int
370 make_ancestor (char const *dir, char const *component, void *options)
372 struct cp_options const *x = options;
373 if (x->set_security_context
374 && defaultcon (x->set_security_context, component, S_IFDIR) < 0
375 && ! ignorable_ctx_err (errno))
376 error (0, errno, _("failed to set default creation context for %s"),
377 quoteaf (dir));
379 int r = mkdir (component, DEFAULT_MODE);
380 if (r == 0)
381 announce_mkdir (dir, options);
382 return r;
385 /* Process a command-line file name, for the -d option. */
386 static int
387 process_dir (char *dir, struct savewd *wd, void *options)
389 struct cp_options const *x = options;
391 int ret = (make_dir_parents (dir, wd, make_ancestor, options,
392 dir_mode, announce_mkdir,
393 dir_mode_bits, owner_id, group_id, false)
394 ? EXIT_SUCCESS
395 : EXIT_FAILURE);
397 /* FIXME: Due to the current structure of make_dir_parents()
398 we don't have the facility to call defaultcon() before the
399 final component of DIR is created. So for now, create the
400 final component with the context from previous component
401 and here we set the context for the final component. */
402 if (ret == EXIT_SUCCESS && x->set_security_context)
404 if (! restorecon (x->set_security_context, last_component (dir), false)
405 && ! ignorable_ctx_err (errno))
406 error (0, errno, _("failed to restore context for %s"),
407 quoteaf (dir));
410 return ret;
413 /* Copy file FROM onto file TO aka TO_DIRFD+TO_RELNAME, creating TO if
414 necessary. Return true if successful. */
416 static bool
417 copy_file (char const *from, char const *to,
418 int to_dirfd, char const *to_relname, const struct cp_options *x)
420 bool copy_into_self;
422 if (copy_only_if_needed && !need_copy (from, to, to_dirfd, to_relname, x))
423 return true;
425 /* Allow installing from non-regular files like /dev/null.
426 Charles Karney reported that some Sun version of install allows that
427 and that sendmail's installation process relies on the behavior.
428 However, since !x->recursive, the call to "copy" will fail if FROM
429 is a directory. */
431 return copy (from, to, to_dirfd, to_relname, 0, x, &copy_into_self, NULL);
434 /* Set the attributes of file or directory NAME aka DIRFD+RELNAME.
435 Return true if successful. */
437 static bool
438 change_attributes (char const *name, int dirfd, char const *relname)
440 bool ok = false;
441 /* chown must precede chmod because on some systems,
442 chown clears the set[ug]id bits for non-superusers,
443 resulting in incorrect permissions.
444 On System V, users can give away files with chown and then not
445 be able to chmod them. So don't give files away.
447 We don't normally ignore errors from chown because the idea of
448 the install command is that the file is supposed to end up with
449 precisely the attributes that the user specified (or defaulted).
450 If the file doesn't end up with the group they asked for, they'll
451 want to know. */
453 if (! (owner_id == (uid_t) -1 && group_id == (gid_t) -1)
454 && lchownat (dirfd, relname, owner_id, group_id) != 0)
455 error (0, errno, _("cannot change ownership of %s"), quoteaf (name));
456 else if (chmodat (dirfd, relname, mode) != 0)
457 error (0, errno, _("cannot change permissions of %s"), quoteaf (name));
458 else
459 ok = true;
461 if (use_default_selinux_context)
462 setdefaultfilecon (name);
464 return ok;
467 /* Set the timestamps of file DEST aka DIRFD+RELNAME to match those of SRC_SB.
468 Return true if successful. */
470 static bool
471 change_timestamps (struct stat const *src_sb, char const *dest,
472 int dirfd, char const *relname)
474 struct timespec timespec[2];
475 timespec[0] = get_stat_atime (src_sb);
476 timespec[1] = get_stat_mtime (src_sb);
478 if (utimensat (dirfd, relname, timespec, 0))
480 error (0, errno, _("cannot set timestamps for %s"), quoteaf (dest));
481 return false;
483 return true;
486 /* Strip the symbol table from the file NAME.
487 We could dig the magic number out of the file first to
488 determine whether to strip it, but the header files and
489 magic numbers vary so much from system to system that making
490 it portable would be very difficult. Not worth the effort. */
492 static bool
493 strip (char const *name)
495 int status;
496 bool ok = false;
497 pid_t pid = fork ();
499 switch (pid)
501 case -1:
502 error (0, errno, _("fork system call failed"));
503 break;
504 case 0: /* Child. */
505 execlp (strip_program, strip_program, name, NULL);
506 die (EXIT_FAILURE, errno, _("cannot run %s"), quoteaf (strip_program));
507 default: /* Parent. */
508 if (waitpid (pid, &status, 0) < 0)
509 error (0, errno, _("waiting for strip"));
510 else if (! WIFEXITED (status) || WEXITSTATUS (status))
511 error (0, 0, _("strip process terminated abnormally"));
512 else
513 ok = true; /* strip succeeded */
514 break;
516 return ok;
519 /* Initialize the user and group ownership of the files to install. */
521 static void
522 get_ids (void)
524 struct passwd *pw;
525 struct group *gr;
527 if (owner_name)
529 pw = getpwnam (owner_name);
530 if (pw == NULL)
532 uintmax_t tmp;
533 if (xstrtoumax (owner_name, NULL, 0, &tmp, "") != LONGINT_OK
534 || UID_T_MAX < tmp)
535 die (EXIT_FAILURE, 0, _("invalid user %s"),
536 quote (owner_name));
537 owner_id = tmp;
539 else
540 owner_id = pw->pw_uid;
541 endpwent ();
543 else
544 owner_id = (uid_t) -1;
546 if (group_name)
548 gr = getgrnam (group_name);
549 if (gr == NULL)
551 uintmax_t tmp;
552 if (xstrtoumax (group_name, NULL, 0, &tmp, "") != LONGINT_OK
553 || GID_T_MAX < tmp)
554 die (EXIT_FAILURE, 0, _("invalid group %s"),
555 quote (group_name));
556 group_id = tmp;
558 else
559 group_id = gr->gr_gid;
560 endgrent ();
562 else
563 group_id = (gid_t) -1;
566 void
567 usage (int status)
569 if (status != EXIT_SUCCESS)
570 emit_try_help ();
571 else
573 printf (_("\
574 Usage: %s [OPTION]... [-T] SOURCE DEST\n\
575 or: %s [OPTION]... SOURCE... DIRECTORY\n\
576 or: %s [OPTION]... -t DIRECTORY SOURCE...\n\
577 or: %s [OPTION]... -d DIRECTORY...\n\
579 program_name, program_name, program_name, program_name);
580 fputs (_("\
582 This install program copies files (often just compiled) into destination\n\
583 locations you choose. If you want to download and install a ready-to-use\n\
584 package on a GNU/Linux system, you should instead be using a package manager\n\
585 like yum(1) or apt-get(1).\n\
587 In the first three forms, copy SOURCE to DEST or multiple SOURCE(s) to\n\
588 the existing DIRECTORY, while setting permission modes and owner/group.\n\
589 In the 4th form, create all components of the given DIRECTORY(ies).\n\
590 "), stdout);
592 emit_mandatory_arg_note ();
594 fputs (_("\
595 --backup[=CONTROL] make a backup of each existing destination file\n\
596 -b like --backup but does not accept an argument\n\
597 -c (ignored)\n\
598 -C, --compare compare content of source and destination files, and\n\
599 if no change to content, ownership, and permissions,\n\
600 do not modify the destination at all\n\
601 -d, --directory treat all arguments as directory names; create all\n\
602 components of the specified directories\n\
603 "), stdout);
604 fputs (_("\
605 -D create all leading components of DEST except the last,\n\
606 or all components of --target-directory,\n\
607 then copy SOURCE to DEST\n\
608 "), stdout);
609 fputs (_("\
610 --debug explain how a file is copied. Implies -v\n\
611 "), stdout);
612 fputs (_("\
613 -g, --group=GROUP set group ownership, instead of process' current group\n\
614 -m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\
615 -o, --owner=OWNER set ownership (super-user only)\n\
616 "), stdout);
617 fputs (_("\
618 -p, --preserve-timestamps apply access/modification times of SOURCE files\n\
619 to corresponding destination files\n\
620 -s, --strip strip symbol tables\n\
621 --strip-program=PROGRAM program used to strip binaries\n\
622 -S, --suffix=SUFFIX override the usual backup suffix\n\
623 -t, --target-directory=DIRECTORY copy all SOURCE arguments into DIRECTORY\n\
624 -T, --no-target-directory treat DEST as a normal file\n\
625 "), stdout);
626 fputs (_("\
627 -v, --verbose print the name of each created file or directory\n\
628 "), stdout);
629 fputs (_("\
630 --preserve-context preserve SELinux security context\n\
631 -Z set SELinux security context of destination\n\
632 file and each created directory to default type\n\
633 --context[=CTX] like -Z, or if CTX is specified then set the\n\
634 SELinux or SMACK security context to CTX\n\
635 "), stdout);
637 fputs (HELP_OPTION_DESCRIPTION, stdout);
638 fputs (VERSION_OPTION_DESCRIPTION, stdout);
639 emit_backup_suffix_note ();
640 emit_ancillary_info (PROGRAM_NAME);
642 exit (status);
645 /* Copy file FROM onto file TO aka TO_DIRFD+TO_RELNAME and give TO the
646 appropriate attributes. X gives the command options.
647 Return true if successful. */
649 static bool
650 install_file_in_file (char const *from, char const *to,
651 int to_dirfd, char const *to_relname,
652 const struct cp_options *x)
654 struct stat from_sb;
655 if (x->preserve_timestamps && stat (from, &from_sb) != 0)
657 error (0, errno, _("cannot stat %s"), quoteaf (from));
658 return false;
660 if (! copy_file (from, to, to_dirfd, to_relname, x))
661 return false;
662 if (strip_files)
663 if (! strip (to))
665 if (unlinkat (to_dirfd, to_relname, 0) != 0) /* Cleanup. */
666 die (EXIT_FAILURE, errno, _("cannot unlink %s"), quoteaf (to));
667 return false;
669 if (x->preserve_timestamps && (strip_files || ! S_ISREG (from_sb.st_mode))
670 && ! change_timestamps (&from_sb, to, to_dirfd, to_relname))
671 return false;
672 return change_attributes (to, to_dirfd, to_relname);
675 /* Create any missing parent directories of TO,
676 while maintaining the current Working Directory.
677 Return true if successful. */
679 static bool
680 mkancesdirs_safe_wd (char const *from, char *to, struct cp_options *x,
681 bool save_always)
683 bool save_working_directory =
684 save_always
685 || ! (IS_ABSOLUTE_FILE_NAME (from) && IS_ABSOLUTE_FILE_NAME (to));
686 int status = EXIT_SUCCESS;
688 struct savewd wd;
689 savewd_init (&wd);
690 if (! save_working_directory)
691 savewd_finish (&wd);
693 if (mkancesdirs (to, &wd, make_ancestor, x) == -1)
695 error (0, errno, _("cannot create directory %s"), quoteaf (to));
696 status = EXIT_FAILURE;
699 if (save_working_directory)
701 int restore_result = savewd_restore (&wd, status);
702 int restore_errno = errno;
703 savewd_finish (&wd);
704 if (EXIT_SUCCESS < restore_result)
705 return false;
706 if (restore_result < 0 && status == EXIT_SUCCESS)
708 error (0, restore_errno, _("cannot create directory %s"),
709 quoteaf (to));
710 return false;
713 return status == EXIT_SUCCESS;
716 /* Copy file FROM onto file TO, creating any missing parent directories of TO.
717 Return true if successful. */
719 static bool
720 install_file_in_file_parents (char const *from, char *to,
721 const struct cp_options *x)
723 return (mkancesdirs_safe_wd (from, to, (struct cp_options *)x, false)
724 && install_file_in_file (from, to, AT_FDCWD, to, x));
727 /* Copy file FROM into directory TO_DIR, keeping its same name,
728 and give the copy the appropriate attributes.
729 Return true if successful. */
731 static bool
732 install_file_in_dir (char const *from, char const *to_dir,
733 const struct cp_options *x, bool mkdir_and_install,
734 int *target_dirfd)
736 char const *from_base = last_component (from);
737 char *to_relname;
738 char *to = file_name_concat (to_dir, from_base, &to_relname);
739 bool ret = true;
741 if (!target_dirfd_valid (*target_dirfd)
742 && (ret = mkdir_and_install)
743 && (ret = mkancesdirs_safe_wd (from, to, (struct cp_options *) x, true)))
745 int fd = open (to_dir, O_PATHSEARCH | O_DIRECTORY);
746 if (fd < 0)
748 error (0, errno, _("cannot open %s"), quoteaf (to));
749 ret = false;
751 else
752 *target_dirfd = fd;
755 if (ret)
757 int to_dirfd = *target_dirfd;
758 if (!target_dirfd_valid (to_dirfd))
760 to_dirfd = AT_FDCWD;
761 to_relname = to;
763 ret = install_file_in_file (from, to, to_dirfd, to_relname, x);
766 free (to);
767 return ret;
771 main (int argc, char **argv)
773 int optc;
774 int exit_status = EXIT_SUCCESS;
775 char const *specified_mode = NULL;
776 bool make_backups = false;
777 char const *backup_suffix = NULL;
778 char *version_control_string = NULL;
779 bool mkdir_and_install = false;
780 struct cp_options x;
781 char const *target_directory = NULL;
782 bool no_target_directory = false;
783 int n_files;
784 char **file;
785 bool strip_program_specified = false;
786 char const *scontext = NULL;
787 /* set iff kernel has extra selinux system calls */
788 selinux_enabled = (0 < is_selinux_enabled ());
790 initialize_main (&argc, &argv);
791 set_program_name (argv[0]);
792 setlocale (LC_ALL, "");
793 bindtextdomain (PACKAGE, LOCALEDIR);
794 textdomain (PACKAGE);
796 atexit (close_stdin);
798 cp_option_init (&x);
800 owner_name = NULL;
801 group_name = NULL;
802 strip_files = false;
803 dir_arg = false;
804 umask (0);
806 while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pt:TvS:Z", long_options,
807 NULL)) != -1)
809 switch (optc)
811 case 'b':
812 make_backups = true;
813 if (optarg)
814 version_control_string = optarg;
815 break;
816 case 'c':
817 break;
818 case 'C':
819 copy_only_if_needed = true;
820 break;
821 case 's':
822 strip_files = true;
823 #ifdef SIGCHLD
824 /* System V fork+wait does not work if SIGCHLD is ignored. */
825 signal (SIGCHLD, SIG_DFL);
826 #endif
827 break;
828 case DEBUG_OPTION:
829 x.debug = x.verbose = true;
830 break;
831 case STRIP_PROGRAM_OPTION:
832 strip_program = xstrdup (optarg);
833 strip_program_specified = true;
834 break;
835 case 'd':
836 dir_arg = true;
837 break;
838 case 'D':
839 mkdir_and_install = true;
840 break;
841 case 'v':
842 x.verbose = true;
843 break;
844 case 'g':
845 group_name = optarg;
846 break;
847 case 'm':
848 specified_mode = optarg;
849 break;
850 case 'o':
851 owner_name = optarg;
852 break;
853 case 'p':
854 x.preserve_timestamps = true;
855 break;
856 case 'S':
857 make_backups = true;
858 backup_suffix = optarg;
859 break;
860 case 't':
861 if (target_directory)
862 die (EXIT_FAILURE, 0,
863 _("multiple target directories specified"));
864 target_directory = optarg;
865 break;
866 case 'T':
867 no_target_directory = true;
868 break;
870 case PRESERVE_CONTEXT_OPTION:
871 if (! selinux_enabled)
873 error (0, 0, _("WARNING: ignoring --preserve-context; "
874 "this kernel is not SELinux-enabled"));
875 break;
877 x.preserve_security_context = true;
878 use_default_selinux_context = false;
879 break;
880 case 'Z':
881 if (selinux_enabled)
883 /* Disable use of the install(1) specific setdefaultfilecon().
884 Note setdefaultfilecon() is different from the newer and more
885 generic restorecon() in that the former sets the context of
886 the dest files to that returned by selabel_lookup directly,
887 thus discarding MLS level and user identity of the file.
888 TODO: consider removing setdefaultfilecon() in future. */
889 use_default_selinux_context = false;
891 if (optarg)
892 scontext = optarg;
893 else
894 x.set_security_context = get_labeling_handle ();
896 else if (optarg)
898 error (0, 0,
899 _("warning: ignoring --context; "
900 "it requires an SELinux-enabled kernel"));
902 break;
903 case_GETOPT_HELP_CHAR;
904 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
905 default:
906 usage (EXIT_FAILURE);
910 /* Check for invalid combinations of arguments. */
911 if (dir_arg && strip_files)
912 die (EXIT_FAILURE, 0,
913 _("the strip option may not be used when installing a directory"));
914 if (dir_arg && target_directory)
915 die (EXIT_FAILURE, 0,
916 _("target directory not allowed when installing a directory"));
918 x.backup_type = (make_backups
919 ? xget_version (_("backup type"),
920 version_control_string)
921 : no_backups);
922 set_simple_backup_suffix (backup_suffix);
924 if (x.preserve_security_context && (x.set_security_context || scontext))
925 die (EXIT_FAILURE, 0,
926 _("cannot set target context and preserve it"));
928 if (scontext && setfscreatecon (scontext) < 0)
929 die (EXIT_FAILURE, errno,
930 _("failed to set default file creation context to %s"),
931 quote (scontext));
933 n_files = argc - optind;
934 file = argv + optind;
936 if (n_files <= ! (dir_arg || target_directory))
938 if (n_files <= 0)
939 error (0, 0, _("missing file operand"));
940 else
941 error (0, 0, _("missing destination file operand after %s"),
942 quoteaf (file[0]));
943 usage (EXIT_FAILURE);
946 struct stat sb;
947 int target_dirfd = AT_FDCWD;
948 if (no_target_directory)
950 if (target_directory)
951 die (EXIT_FAILURE, 0,
952 _("cannot combine --target-directory (-t) "
953 "and --no-target-directory (-T)"));
954 if (2 < n_files)
956 error (0, 0, _("extra operand %s"), quoteaf (file[2]));
957 usage (EXIT_FAILURE);
960 else if (target_directory)
962 target_dirfd = target_directory_operand (target_directory, &sb);
963 if (! (target_dirfd_valid (target_dirfd)
964 || (mkdir_and_install && errno == ENOENT)))
965 die (EXIT_FAILURE, errno, _("failed to access %s"),
966 quoteaf (target_directory));
968 else if (!dir_arg)
970 char const *lastfile = file[n_files - 1];
971 int fd = target_directory_operand (lastfile, &sb);
972 if (target_dirfd_valid (fd))
974 target_dirfd = fd;
975 target_directory = lastfile;
976 n_files--;
978 else if (2 < n_files)
979 die (EXIT_FAILURE, errno, _("target %s"), quoteaf (lastfile));
982 if (specified_mode)
984 struct mode_change *change = mode_compile (specified_mode);
985 if (!change)
986 die (EXIT_FAILURE, 0, _("invalid mode %s"), quote (specified_mode));
987 mode = mode_adjust (0, false, 0, change, NULL);
988 dir_mode = mode_adjust (0, true, 0, change, &dir_mode_bits);
989 free (change);
992 if (strip_program_specified && !strip_files)
993 error (0, 0, _("WARNING: ignoring --strip-program option as -s option was "
994 "not specified"));
996 if (copy_only_if_needed && x.preserve_timestamps)
998 error (0, 0, _("options --compare (-C) and --preserve-timestamps are "
999 "mutually exclusive"));
1000 usage (EXIT_FAILURE);
1003 if (copy_only_if_needed && strip_files)
1005 error (0, 0, _("options --compare (-C) and --strip are mutually "
1006 "exclusive"));
1007 usage (EXIT_FAILURE);
1010 if (copy_only_if_needed && extra_mode (mode))
1011 error (0, 0, _("the --compare (-C) option is ignored when you"
1012 " specify a mode with non-permission bits"));
1014 get_ids ();
1016 if (dir_arg)
1017 exit_status = savewd_process_files (n_files, file, process_dir, &x);
1018 else
1020 /* FIXME: it's a little gross that this initialization is
1021 required by copy.c::copy. */
1022 hash_init ();
1024 if (!target_directory)
1026 if (! (mkdir_and_install
1027 ? install_file_in_file_parents (file[0], file[1], &x)
1028 : install_file_in_file (file[0], file[1], AT_FDCWD,
1029 file[1], &x)))
1030 exit_status = EXIT_FAILURE;
1032 else
1034 int i;
1035 dest_info_init (&x);
1036 for (i = 0; i < n_files; i++)
1037 if (! install_file_in_dir (file[i], target_directory, &x,
1038 i == 0 && mkdir_and_install,
1039 &target_dirfd))
1040 exit_status = EXIT_FAILURE;
1044 main_exit (exit_status);