ls: fix possible incorrect exit status when recursing directories
[coreutils.git] / src / install.c
bloba5ed7a821406ecdc7477cf1fa123b37910ec2077
1 /* install - copy files and set attributes
2 Copyright (C) 1989-2013 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 <http://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/selinux.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 "filenamecat.h"
35 #include "full-read.h"
36 #include "mkancesdirs.h"
37 #include "mkdir-p.h"
38 #include "modechange.h"
39 #include "prog-fprintf.h"
40 #include "quote.h"
41 #include "quotearg.h"
42 #include "savewd.h"
43 #include "stat-time.h"
44 #include "utimens.h"
45 #include "xstrtol.h"
47 /* The official name of this program (e.g., no 'g' prefix). */
48 #define PROGRAM_NAME "install"
50 #define AUTHORS proper_name ("David MacKenzie")
52 static int selinux_enabled = 0;
53 static bool use_default_selinux_context = true;
55 #if ! HAVE_ENDGRENT
56 # define endgrent() ((void) 0)
57 #endif
59 #if ! HAVE_ENDPWENT
60 # define endpwent() ((void) 0)
61 #endif
63 #if ! HAVE_LCHOWN
64 # define lchown(name, uid, gid) chown (name, uid, gid)
65 #endif
67 #if ! HAVE_MATCHPATHCON_INIT_PREFIX
68 # define matchpathcon_init_prefix(a, p) /* empty */
69 #endif
71 /* The user name that will own the files, or NULL to make the owner
72 the current user ID. */
73 static char *owner_name;
75 /* The user ID corresponding to 'owner_name'. */
76 static uid_t owner_id;
78 /* The group name that will own the files, or NULL to make the group
79 the current group ID. */
80 static char *group_name;
82 /* The group ID corresponding to 'group_name'. */
83 static gid_t group_id;
85 #define DEFAULT_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
87 /* The file mode bits to which non-directory files will be set. The umask has
88 no effect. */
89 static mode_t mode = DEFAULT_MODE;
91 /* Similar, but for directories. */
92 static mode_t dir_mode = DEFAULT_MODE;
94 /* The file mode bits that the user cares about. This should be a
95 superset of DIR_MODE and a subset of CHMOD_MODE_BITS. This matters
96 for directories, since otherwise directories may keep their S_ISUID
97 or S_ISGID bits. */
98 static mode_t dir_mode_bits = CHMOD_MODE_BITS;
100 /* Compare files before installing (-C) */
101 static bool copy_only_if_needed;
103 /* If true, strip executable files after copying them. */
104 static bool strip_files;
106 /* If true, install a directory instead of a regular file. */
107 static bool dir_arg;
109 /* Program used to strip binaries, "strip" is default */
110 static char const *strip_program = "strip";
112 /* For long options that have no equivalent short option, use a
113 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
114 enum
116 PRESERVE_CONTEXT_OPTION = CHAR_MAX + 1,
117 STRIP_PROGRAM_OPTION
120 static struct option const long_options[] =
122 {"backup", optional_argument, NULL, 'b'},
123 {"compare", no_argument, NULL, 'C'},
124 {GETOPT_SELINUX_CONTEXT_OPTION_DECL},
125 {"directory", no_argument, NULL, 'd'},
126 {"group", required_argument, NULL, 'g'},
127 {"mode", required_argument, NULL, 'm'},
128 {"no-target-directory", no_argument, NULL, 'T'},
129 {"owner", required_argument, NULL, 'o'},
130 {"preserve-timestamps", no_argument, NULL, 'p'},
131 {"preserve-context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
132 {"strip", no_argument, NULL, 's'},
133 {"strip-program", required_argument, NULL, STRIP_PROGRAM_OPTION},
134 {"suffix", required_argument, NULL, 'S'},
135 {"target-directory", required_argument, NULL, 't'},
136 {"verbose", no_argument, NULL, 'v'},
137 {GETOPT_HELP_OPTION_DECL},
138 {GETOPT_VERSION_OPTION_DECL},
139 {NULL, 0, NULL, 0}
142 /* Compare content of opened files using file descriptors A_FD and B_FD. Return
143 true if files are equal. */
144 static bool
145 have_same_content (int a_fd, int b_fd)
147 enum { CMP_BLOCK_SIZE = 4096 };
148 static char a_buff[CMP_BLOCK_SIZE];
149 static char b_buff[CMP_BLOCK_SIZE];
151 size_t size;
152 while (0 < (size = full_read (a_fd, a_buff, sizeof a_buff))) {
153 if (size != full_read (b_fd, b_buff, sizeof b_buff))
154 return false;
156 if (memcmp (a_buff, b_buff, size) != 0)
157 return false;
160 return size == 0;
163 /* Return true for mode with non-permission bits. */
164 static bool
165 extra_mode (mode_t input)
167 mode_t mask = S_IRWXUGO | S_IFMT;
168 return !! (input & ~ mask);
171 /* Return true if copy of file SRC_NAME to file DEST_NAME is necessary. */
172 static bool
173 need_copy (const char *src_name, const char *dest_name,
174 const struct cp_options *x)
176 struct stat src_sb, dest_sb;
177 int src_fd, dest_fd;
178 bool content_match;
180 if (extra_mode (mode))
181 return true;
183 /* compare files using stat */
184 if (lstat (src_name, &src_sb) != 0)
185 return true;
187 if (lstat (dest_name, &dest_sb) != 0)
188 return true;
190 if (!S_ISREG (src_sb.st_mode) || !S_ISREG (dest_sb.st_mode)
191 || extra_mode (src_sb.st_mode) || extra_mode (dest_sb.st_mode))
192 return true;
194 if (src_sb.st_size != dest_sb.st_size
195 || (dest_sb.st_mode & CHMOD_MODE_BITS) != mode)
196 return true;
198 if (owner_id == (uid_t) -1)
200 errno = 0;
201 uid_t ruid = getuid ();
202 if ((ruid == (uid_t) -1 && errno) || dest_sb.st_uid != ruid)
203 return true;
205 else if (dest_sb.st_uid != owner_id)
206 return true;
208 if (group_id == (uid_t) -1)
210 errno = 0;
211 gid_t rgid = getgid ();
212 if ((rgid == (uid_t) -1 && errno) || dest_sb.st_gid != rgid)
213 return true;
215 else if (dest_sb.st_gid != group_id)
216 return true;
218 /* compare SELinux context if preserving */
219 if (selinux_enabled && x->preserve_security_context)
221 security_context_t file_scontext = NULL;
222 security_context_t to_scontext = NULL;
223 bool scontext_match;
225 if (getfilecon (src_name, &file_scontext) == -1)
226 return true;
228 if (getfilecon (dest_name, &to_scontext) == -1)
230 freecon (file_scontext);
231 return true;
234 scontext_match = STREQ (file_scontext, to_scontext);
236 freecon (file_scontext);
237 freecon (to_scontext);
238 if (!scontext_match)
239 return true;
242 /* compare files content */
243 src_fd = open (src_name, O_RDONLY | O_BINARY);
244 if (src_fd < 0)
245 return true;
247 dest_fd = open (dest_name, O_RDONLY | O_BINARY);
248 if (dest_fd < 0)
250 close (src_fd);
251 return true;
254 content_match = have_same_content (src_fd, dest_fd);
256 close (src_fd);
257 close (dest_fd);
258 return !content_match;
261 static void
262 cp_option_init (struct cp_options *x)
264 cp_options_default (x);
265 x->copy_as_regular = true;
266 x->reflink_mode = REFLINK_NEVER;
267 x->dereference = DEREF_ALWAYS;
268 x->unlink_dest_before_opening = true;
269 x->unlink_dest_after_failed_open = false;
270 x->hard_link = false;
271 x->interactive = I_UNSPECIFIED;
272 x->move_mode = false;
273 x->one_file_system = false;
274 x->preserve_ownership = false;
275 x->preserve_links = false;
276 x->preserve_mode = false;
277 x->preserve_timestamps = false;
278 x->explicit_no_preserve_mode = false;
279 x->reduce_diagnostics=false;
280 x->data_copy_required = true;
281 x->require_preserve = false;
282 x->require_preserve_context = false;
283 x->require_preserve_xattr = false;
284 x->recursive = false;
285 x->sparse_mode = SPARSE_AUTO;
286 x->symbolic_link = false;
287 x->backup_type = no_backups;
289 /* Create destination files initially writable so we can run strip on them.
290 Although GNU strip works fine on read-only files, some others
291 would fail. */
292 x->set_mode = true;
293 x->mode = S_IRUSR | S_IWUSR;
294 x->stdin_tty = false;
296 x->open_dangling_dest_symlink = false;
297 x->update = false;
298 x->preserve_security_context = false;
299 x->preserve_xattr = false;
300 x->verbose = false;
301 x->dest_info = NULL;
302 x->src_info = NULL;
305 #ifdef ENABLE_MATCHPATHCON
306 /* Modify file context to match the specified policy.
307 If an error occurs the file will remain with the default directory
308 context. */
309 static void
310 setdefaultfilecon (char const *file)
312 struct stat st;
313 security_context_t scontext = NULL;
314 static bool first_call = true;
316 if (selinux_enabled != 1)
318 /* Indicate no context found. */
319 return;
321 if (lstat (file, &st) != 0)
322 return;
324 if (first_call && IS_ABSOLUTE_FILE_NAME (file))
326 /* Calling matchpathcon_init_prefix (NULL, "/first_component/")
327 is an optimization to minimize the expense of the following
328 matchpathcon call. Do it only once, just before the first
329 matchpathcon call. We *could* call matchpathcon_fini after
330 the final matchpathcon call, but that's not necessary, since
331 by then we're about to exit, and besides, the buffers it
332 would free are still reachable. */
333 char const *p0;
334 char const *p = file + 1;
335 while (ISSLASH (*p))
336 ++p;
338 /* Record final leading slash, for when FILE starts with two or more. */
339 p0 = p - 1;
341 if (*p)
343 char *prefix;
346 ++p;
348 while (*p && !ISSLASH (*p));
350 prefix = malloc (p - p0 + 2);
351 if (prefix)
353 stpcpy (stpncpy (prefix, p0, p - p0), "/");
354 matchpathcon_init_prefix (NULL, prefix);
355 free (prefix);
359 first_call = false;
361 /* If there's an error determining the context, or it has none,
362 return to allow default context */
363 if ((matchpathcon (file, st.st_mode, &scontext) != 0)
364 || STREQ (scontext, "<<none>>"))
366 if (scontext != NULL)
367 freecon (scontext);
368 return;
371 if (lsetfilecon (file, scontext) < 0 && errno != ENOTSUP)
372 error (0, errno,
373 _("warning: %s: failed to change context to %s"),
374 quotearg_colon (file), scontext);
376 freecon (scontext);
377 return;
379 #else
380 static void
381 setdefaultfilecon (char const *file)
383 (void) file;
385 #endif
387 /* FILE is the last operand of this command. Return true if FILE is a
388 directory. But report an error there is a problem accessing FILE,
389 or if FILE does not exist but would have to refer to an existing
390 directory if it referred to anything at all. */
392 static bool
393 target_directory_operand (char const *file)
395 char const *b = last_component (file);
396 size_t blen = strlen (b);
397 bool looks_like_a_dir = (blen == 0 || ISSLASH (b[blen - 1]));
398 struct stat st;
399 int err = (stat (file, &st) == 0 ? 0 : errno);
400 bool is_a_dir = !err && S_ISDIR (st.st_mode);
401 if (err && err != ENOENT)
402 error (EXIT_FAILURE, err, _("failed to access %s"), quote (file));
403 if (is_a_dir < looks_like_a_dir)
404 error (EXIT_FAILURE, err, _("target %s is not a directory"), quote (file));
405 return is_a_dir;
408 /* Report that directory DIR was made, if OPTIONS requests this. */
409 static void
410 announce_mkdir (char const *dir, void *options)
412 struct cp_options const *x = options;
413 if (x->verbose)
414 prog_fprintf (stdout, _("creating directory %s"), quote (dir));
417 /* Make ancestor directory DIR, whose last file name component is
418 COMPONENT, with options OPTIONS. Assume the working directory is
419 COMPONENT's parent. */
420 static int
421 make_ancestor (char const *dir, char const *component, void *options)
423 int r = mkdir (component, DEFAULT_MODE);
424 if (r == 0)
425 announce_mkdir (dir, options);
426 return r;
429 /* Process a command-line file name, for the -d option. */
430 static int
431 process_dir (char *dir, struct savewd *wd, void *options)
433 return (make_dir_parents (dir, wd,
434 make_ancestor, options,
435 dir_mode, announce_mkdir,
436 dir_mode_bits, owner_id, group_id, false)
437 ? EXIT_SUCCESS
438 : EXIT_FAILURE);
441 /* Copy file FROM onto file TO, creating TO if necessary.
442 Return true if successful. */
444 static bool
445 copy_file (const char *from, const char *to, const struct cp_options *x)
447 bool copy_into_self;
449 if (copy_only_if_needed && !need_copy (from, to, x))
450 return true;
452 /* Allow installing from non-regular files like /dev/null.
453 Charles Karney reported that some Sun version of install allows that
454 and that sendmail's installation process relies on the behavior.
455 However, since !x->recursive, the call to "copy" will fail if FROM
456 is a directory. */
458 return copy (from, to, false, x, &copy_into_self, NULL);
461 /* Set the attributes of file or directory NAME.
462 Return true if successful. */
464 static bool
465 change_attributes (char const *name)
467 bool ok = false;
468 /* chown must precede chmod because on some systems,
469 chown clears the set[ug]id bits for non-superusers,
470 resulting in incorrect permissions.
471 On System V, users can give away files with chown and then not
472 be able to chmod them. So don't give files away.
474 We don't normally ignore errors from chown because the idea of
475 the install command is that the file is supposed to end up with
476 precisely the attributes that the user specified (or defaulted).
477 If the file doesn't end up with the group they asked for, they'll
478 want to know. */
480 if (! (owner_id == (uid_t) -1 && group_id == (gid_t) -1)
481 && lchown (name, owner_id, group_id) != 0)
482 error (0, errno, _("cannot change ownership of %s"), quote (name));
483 else if (chmod (name, mode) != 0)
484 error (0, errno, _("cannot change permissions of %s"), quote (name));
485 else
486 ok = true;
488 if (use_default_selinux_context)
489 setdefaultfilecon (name);
491 return ok;
494 /* Set the timestamps of file DEST to match those of SRC_SB.
495 Return true if successful. */
497 static bool
498 change_timestamps (struct stat const *src_sb, char const *dest)
500 struct timespec timespec[2];
501 timespec[0] = get_stat_atime (src_sb);
502 timespec[1] = get_stat_mtime (src_sb);
504 if (utimens (dest, timespec))
506 error (0, errno, _("cannot set time stamps for %s"), quote (dest));
507 return false;
509 return true;
512 /* Strip the symbol table from the file NAME.
513 We could dig the magic number out of the file first to
514 determine whether to strip it, but the header files and
515 magic numbers vary so much from system to system that making
516 it portable would be very difficult. Not worth the effort. */
518 static bool
519 strip (char const *name)
521 int status;
522 bool ok = false;
523 pid_t pid = fork ();
525 switch (pid)
527 case -1:
528 error (0, errno, _("fork system call failed"));
529 break;
530 case 0: /* Child. */
531 execlp (strip_program, strip_program, name, NULL);
532 error (EXIT_FAILURE, errno, _("cannot run %s"), strip_program);
533 break;
534 default: /* Parent. */
535 if (waitpid (pid, &status, 0) < 0)
536 error (0, errno, _("waiting for strip"));
537 else if (! WIFEXITED (status) || WEXITSTATUS (status))
538 error (0, 0, _("strip process terminated abnormally"));
539 else
540 ok = true; /* strip succeeded */
541 break;
543 return ok;
546 /* Initialize the user and group ownership of the files to install. */
548 static void
549 get_ids (void)
551 struct passwd *pw;
552 struct group *gr;
554 if (owner_name)
556 pw = getpwnam (owner_name);
557 if (pw == NULL)
559 unsigned long int tmp;
560 if (xstrtoul (owner_name, NULL, 0, &tmp, NULL) != LONGINT_OK
561 || UID_T_MAX < tmp)
562 error (EXIT_FAILURE, 0, _("invalid user %s"), quote (owner_name));
563 owner_id = tmp;
565 else
566 owner_id = pw->pw_uid;
567 endpwent ();
569 else
570 owner_id = (uid_t) -1;
572 if (group_name)
574 gr = getgrnam (group_name);
575 if (gr == NULL)
577 unsigned long int tmp;
578 if (xstrtoul (group_name, NULL, 0, &tmp, NULL) != LONGINT_OK
579 || GID_T_MAX < tmp)
580 error (EXIT_FAILURE, 0, _("invalid group %s"), quote (group_name));
581 group_id = tmp;
583 else
584 group_id = gr->gr_gid;
585 endgrent ();
587 else
588 group_id = (gid_t) -1;
591 void
592 usage (int status)
594 if (status != EXIT_SUCCESS)
595 emit_try_help ();
596 else
598 printf (_("\
599 Usage: %s [OPTION]... [-T] SOURCE DEST\n\
600 or: %s [OPTION]... SOURCE... DIRECTORY\n\
601 or: %s [OPTION]... -t DIRECTORY SOURCE...\n\
602 or: %s [OPTION]... -d DIRECTORY...\n\
604 program_name, program_name, program_name, program_name);
605 fputs (_("\
607 This install program copies files (often just compiled) into destination\n\
608 locations you choose. If you want to download and install a ready-to-use\n\
609 package on a GNU/Linux system, you should instead be using a package manager\n\
610 like yum(1) or apt-get(1).\n\
612 In the first three forms, copy SOURCE to DEST or multiple SOURCE(s) to\n\
613 the existing DIRECTORY, while setting permission modes and owner/group.\n\
614 In the 4th form, create all components of the given DIRECTORY(ies).\n\
615 "), stdout);
617 emit_mandatory_arg_note ();
619 fputs (_("\
620 --backup[=CONTROL] make a backup of each existing destination file\n\
621 -b like --backup but does not accept an argument\n\
622 -c (ignored)\n\
623 -C, --compare compare each pair of source and destination files, and\n\
624 in some cases, do not modify the destination at all\n\
625 -d, --directory treat all arguments as directory names; create all\n\
626 components of the specified directories\n\
627 "), stdout);
628 fputs (_("\
629 -D create all leading components of DEST except the last,\n\
630 then copy SOURCE to DEST\n\
631 -g, --group=GROUP set group ownership, instead of process' current group\n\
632 -m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\
633 -o, --owner=OWNER set ownership (super-user only)\n\
634 "), stdout);
635 fputs (_("\
636 -p, --preserve-timestamps apply access/modification times of SOURCE files\n\
637 to corresponding destination files\n\
638 -s, --strip strip symbol tables\n\
639 --strip-program=PROGRAM program used to strip binaries\n\
640 -S, --suffix=SUFFIX override the usual backup suffix\n\
641 -t, --target-directory=DIRECTORY copy all SOURCE arguments into DIRECTORY\n\
642 -T, --no-target-directory treat DEST as a normal file\n\
643 -v, --verbose print the name of each directory as it is created\n\
644 "), stdout);
645 fputs (_("\
646 --preserve-context preserve SELinux security context\n\
647 -Z, --context=CONTEXT set SELinux security context of files and directories\
649 "), stdout);
651 fputs (HELP_OPTION_DESCRIPTION, stdout);
652 fputs (VERSION_OPTION_DESCRIPTION, stdout);
653 fputs (_("\
655 The backup suffix is '~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
656 The version control method may be selected via the --backup option or through\n\
657 the VERSION_CONTROL environment variable. Here are the values:\n\
659 "), stdout);
660 fputs (_("\
661 none, off never make backups (even if --backup is given)\n\
662 numbered, t make numbered backups\n\
663 existing, nil numbered if numbered backups exist, simple otherwise\n\
664 simple, never always make simple backups\n\
665 "), stdout);
666 emit_ancillary_info ();
668 exit (status);
671 /* Copy file FROM onto file TO and give TO the appropriate
672 attributes.
673 Return true if successful. */
675 static bool
676 install_file_in_file (const char *from, const char *to,
677 const struct cp_options *x)
679 struct stat from_sb;
680 if (x->preserve_timestamps && stat (from, &from_sb) != 0)
682 error (0, errno, _("cannot stat %s"), quote (from));
683 return false;
685 if (! copy_file (from, to, x))
686 return false;
687 if (strip_files)
688 if (! strip (to))
690 if (unlink (to) != 0) /* Cleanup. */
691 error (EXIT_FAILURE, errno, _("cannot unlink %s"), to);
692 return false;
694 if (x->preserve_timestamps && (strip_files || ! S_ISREG (from_sb.st_mode))
695 && ! change_timestamps (&from_sb, to))
696 return false;
697 return change_attributes (to);
700 /* Copy file FROM onto file TO, creating any missing parent directories of TO.
701 Return true if successful. */
703 static bool
704 install_file_in_file_parents (char const *from, char *to,
705 struct cp_options *x)
707 bool save_working_directory =
708 ! (IS_ABSOLUTE_FILE_NAME (from) && IS_ABSOLUTE_FILE_NAME (to));
709 int status = EXIT_SUCCESS;
711 struct savewd wd;
712 savewd_init (&wd);
713 if (! save_working_directory)
714 savewd_finish (&wd);
716 if (mkancesdirs (to, &wd, make_ancestor, x) == -1)
718 error (0, errno, _("cannot create directory %s"), to);
719 status = EXIT_FAILURE;
722 if (save_working_directory)
724 int restore_result = savewd_restore (&wd, status);
725 int restore_errno = errno;
726 savewd_finish (&wd);
727 if (EXIT_SUCCESS < restore_result)
728 return false;
729 if (restore_result < 0 && status == EXIT_SUCCESS)
731 error (0, restore_errno, _("cannot create directory %s"), to);
732 return false;
736 return (status == EXIT_SUCCESS && install_file_in_file (from, to, x));
739 /* Copy file FROM into directory TO_DIR, keeping its same name,
740 and give the copy the appropriate attributes.
741 Return true if successful. */
743 static bool
744 install_file_in_dir (const char *from, const char *to_dir,
745 const struct cp_options *x)
747 const char *from_base = last_component (from);
748 char *to = file_name_concat (to_dir, from_base, NULL);
749 bool ret = install_file_in_file (from, to, x);
750 free (to);
751 return ret;
755 main (int argc, char **argv)
757 int optc;
758 int exit_status = EXIT_SUCCESS;
759 const char *specified_mode = NULL;
760 bool make_backups = false;
761 char *backup_suffix_string;
762 char *version_control_string = NULL;
763 bool mkdir_and_install = false;
764 struct cp_options x;
765 char const *target_directory = NULL;
766 bool no_target_directory = false;
767 int n_files;
768 char **file;
769 bool strip_program_specified = false;
770 security_context_t scontext = NULL;
771 /* set iff kernel has extra selinux system calls */
772 selinux_enabled = (0 < is_selinux_enabled ());
774 initialize_main (&argc, &argv);
775 set_program_name (argv[0]);
776 setlocale (LC_ALL, "");
777 bindtextdomain (PACKAGE, LOCALEDIR);
778 textdomain (PACKAGE);
780 atexit (close_stdin);
782 cp_option_init (&x);
784 owner_name = NULL;
785 group_name = NULL;
786 strip_files = false;
787 dir_arg = false;
788 umask (0);
790 /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
791 we'll actually use backup_suffix_string. */
792 backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
794 while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pt:TvS:Z:", long_options,
795 NULL)) != -1)
797 switch (optc)
799 case 'b':
800 make_backups = true;
801 if (optarg)
802 version_control_string = optarg;
803 break;
804 case 'c':
805 break;
806 case 'C':
807 copy_only_if_needed = true;
808 break;
809 case 's':
810 strip_files = true;
811 #ifdef SIGCHLD
812 /* System V fork+wait does not work if SIGCHLD is ignored. */
813 signal (SIGCHLD, SIG_DFL);
814 #endif
815 break;
816 case STRIP_PROGRAM_OPTION:
817 strip_program = xstrdup (optarg);
818 strip_program_specified = true;
819 break;
820 case 'd':
821 dir_arg = true;
822 break;
823 case 'D':
824 mkdir_and_install = true;
825 break;
826 case 'v':
827 x.verbose = true;
828 break;
829 case 'g':
830 group_name = optarg;
831 break;
832 case 'm':
833 specified_mode = optarg;
834 break;
835 case 'o':
836 owner_name = optarg;
837 break;
838 case 'p':
839 x.preserve_timestamps = true;
840 break;
841 case 'S':
842 make_backups = true;
843 backup_suffix_string = optarg;
844 break;
845 case 't':
846 if (target_directory)
847 error (EXIT_FAILURE, 0,
848 _("multiple target directories specified"));
849 else
851 struct stat st;
852 if (stat (optarg, &st) != 0)
853 error (EXIT_FAILURE, errno, _("failed to access %s"),
854 quote (optarg));
855 if (! S_ISDIR (st.st_mode))
856 error (EXIT_FAILURE, 0, _("target %s is not a directory"),
857 quote (optarg));
859 target_directory = optarg;
860 break;
861 case 'T':
862 no_target_directory = true;
863 break;
865 case PRESERVE_CONTEXT_OPTION:
866 if ( ! selinux_enabled)
868 error (0, 0, _("WARNING: ignoring --preserve-context; "
869 "this kernel is not SELinux-enabled"));
870 break;
872 x.preserve_security_context = true;
873 use_default_selinux_context = false;
874 break;
875 case 'Z':
876 if ( ! selinux_enabled)
878 error (0, 0, _("WARNING: ignoring --context (-Z); "
879 "this kernel is not SELinux-enabled"));
880 break;
882 scontext = optarg;
883 use_default_selinux_context = false;
884 break;
885 case_GETOPT_HELP_CHAR;
886 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
887 default:
888 usage (EXIT_FAILURE);
892 /* Check for invalid combinations of arguments. */
893 if (dir_arg && strip_files)
894 error (EXIT_FAILURE, 0,
895 _("the strip option may not be used when installing a directory"));
896 if (dir_arg && target_directory)
897 error (EXIT_FAILURE, 0,
898 _("target directory not allowed when installing a directory"));
900 if (x.preserve_security_context && scontext != NULL)
901 error (EXIT_FAILURE, 0,
902 _("cannot force target context to %s and preserve it"),
903 quote (scontext));
905 if (backup_suffix_string)
906 simple_backup_suffix = xstrdup (backup_suffix_string);
908 x.backup_type = (make_backups
909 ? xget_version (_("backup type"),
910 version_control_string)
911 : no_backups);
913 if (scontext && setfscreatecon (scontext) < 0)
914 error (EXIT_FAILURE, errno,
915 _("failed to set default file creation context to %s"),
916 quote (scontext));
918 n_files = argc - optind;
919 file = argv + optind;
921 if (n_files <= ! (dir_arg || target_directory))
923 if (n_files <= 0)
924 error (0, 0, _("missing file operand"));
925 else
926 error (0, 0, _("missing destination file operand after %s"),
927 quote (file[0]));
928 usage (EXIT_FAILURE);
931 if (no_target_directory)
933 if (target_directory)
934 error (EXIT_FAILURE, 0,
935 _("cannot combine --target-directory (-t) "
936 "and --no-target-directory (-T)"));
937 if (2 < n_files)
939 error (0, 0, _("extra operand %s"), quote (file[2]));
940 usage (EXIT_FAILURE);
943 else if (! (dir_arg || target_directory))
945 if (2 <= n_files && target_directory_operand (file[n_files - 1]))
946 target_directory = file[--n_files];
947 else if (2 < n_files)
948 error (EXIT_FAILURE, 0, _("target %s is not a directory"),
949 quote (file[n_files - 1]));
952 if (specified_mode)
954 struct mode_change *change = mode_compile (specified_mode);
955 if (!change)
956 error (EXIT_FAILURE, 0, _("invalid mode %s"), quote (specified_mode));
957 mode = mode_adjust (0, false, 0, change, NULL);
958 dir_mode = mode_adjust (0, true, 0, change, &dir_mode_bits);
959 free (change);
962 if (strip_program_specified && !strip_files)
963 error (0, 0, _("WARNING: ignoring --strip-program option as -s option was "
964 "not specified"));
966 if (copy_only_if_needed && x.preserve_timestamps)
968 error (0, 0, _("options --compare (-C) and --preserve-timestamps are "
969 "mutually exclusive"));
970 usage (EXIT_FAILURE);
973 if (copy_only_if_needed && strip_files)
975 error (0, 0, _("options --compare (-C) and --strip are mutually "
976 "exclusive"));
977 usage (EXIT_FAILURE);
980 if (copy_only_if_needed && extra_mode (mode))
981 error (0, 0, _("the --compare (-C) option is ignored when you"
982 " specify a mode with non-permission bits"));
984 get_ids ();
986 if (dir_arg)
987 exit_status = savewd_process_files (n_files, file, process_dir, &x);
988 else
990 /* FIXME: it's a little gross that this initialization is
991 required by copy.c::copy. */
992 hash_init ();
994 if (!target_directory)
996 if (! (mkdir_and_install
997 ? install_file_in_file_parents (file[0], file[1], &x)
998 : install_file_in_file (file[0], file[1], &x)))
999 exit_status = EXIT_FAILURE;
1001 else
1003 int i;
1004 dest_info_init (&x);
1005 for (i = 0; i < n_files; i++)
1006 if (! install_file_in_dir (file[i], target_directory, &x))
1007 exit_status = EXIT_FAILURE;
1011 exit (exit_status);