1 /* install - copy files and set attributes
2 Copyright (C) 89, 90, 91, 1995-2007 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> */
22 #include <sys/types.h>
26 #include <selinux/selinux.h>
29 #include "backupfile.h"
33 #include "filenamecat.h"
34 #include "mkancesdirs.h"
36 #include "modechange.h"
40 #include "stat-time.h"
44 /* The official name of this program (e.g., no `g' prefix). */
45 #define PROGRAM_NAME "install"
47 #define AUTHORS "David MacKenzie"
50 # include <sys/wait.h>
53 static int selinux_enabled = 0;
54 static bool use_default_selinux_context = true;
57 # define endgrent() ((void) 0)
61 # define endpwent() ((void) 0)
65 # define lchown(name, uid, gid) chown (name, uid, gid)
68 /* Initial number of entries in each hash table entry's table of inodes. */
69 #define INITIAL_HASH_MODULE 100
71 /* Initial number of entries in the inode hash table. */
72 #define INITIAL_ENTRY_TAB_SIZE 70
74 /* Number of bytes of a file to copy at a time. */
75 #define READ_SIZE (32 * 1024)
77 static bool change_timestamps (struct stat const *from_sb, char const *to);
78 static bool change_attributes (char const *name);
79 static bool copy_file (const char *from, const char *to,
80 const struct cp_options *x);
81 static bool install_file_in_file_parents (char const *from, char *to,
82 struct cp_options *x);
83 static bool install_file_in_dir (const char *from, const char *to_dir,
84 const struct cp_options *x);
85 static bool install_file_in_file (const char *from, const char *to,
86 const struct cp_options *x);
87 static void get_ids (void);
88 static void strip (char const *name);
89 static void announce_mkdir (char const *dir, void *options);
90 static int make_ancestor (char const *dir, char const *component,
92 void usage (int status);
94 /* The name this program was run with, for error messages. */
97 /* The user name that will own the files, or NULL to make the owner
98 the current user ID. */
99 static char *owner_name;
101 /* The user ID corresponding to `owner_name'. */
102 static uid_t owner_id;
104 /* The group name that will own the files, or NULL to make the group
105 the current group ID. */
106 static char *group_name;
108 /* The group ID corresponding to `group_name'. */
109 static gid_t group_id;
111 #define DEFAULT_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
113 /* The file mode bits to which non-directory files will be set. The umask has
115 static mode_t mode = DEFAULT_MODE;
117 /* Similar, but for directories. */
118 static mode_t dir_mode = DEFAULT_MODE;
120 /* The file mode bits that the user cares about. This should be a
121 superset of DIR_MODE and a subset of CHMOD_MODE_BITS. This matters
122 for directories, since otherwise directories may keep their S_ISUID
124 static mode_t dir_mode_bits = CHMOD_MODE_BITS;
126 /* If true, strip executable files after copying them. */
127 static bool strip_files;
129 /* If true, install a directory instead of a regular file. */
132 /* For long options that have no equivalent short option, use a
133 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
136 PRESERVE_CONTEXT_OPTION = CHAR_MAX + 1
139 static struct option const long_options[] =
141 {"backup", optional_argument, NULL, 'b'},
142 {GETOPT_SELINUX_CONTEXT_OPTION_DECL},
143 {"directory", no_argument, NULL, 'd'},
144 {"group", required_argument, NULL, 'g'},
145 {"mode", required_argument, NULL, 'm'},
146 {"no-target-directory", no_argument, NULL, 'T'},
147 {"owner", required_argument, NULL, 'o'},
148 {"preserve-timestamps", no_argument, NULL, 'p'},
149 {"preserve-context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
150 /* Continue silent support for --preserve_context until Jan 2008. FIXME-obs
151 After that, FIXME-obs: warn in, say, late 2008, and disable altogether
152 a year or two later. */
153 {"preserve_context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
154 {"strip", no_argument, NULL, 's'},
155 {"suffix", required_argument, NULL, 'S'},
156 {"target-directory", required_argument, NULL, 't'},
157 {"verbose", no_argument, NULL, 'v'},
158 {GETOPT_HELP_OPTION_DECL},
159 {GETOPT_VERSION_OPTION_DECL},
164 cp_option_init (struct cp_options *x)
166 x->copy_as_regular = true;
167 x->dereference = DEREF_ALWAYS;
168 x->unlink_dest_before_opening = true;
169 x->unlink_dest_after_failed_open = false;
170 x->hard_link = false;
171 x->interactive = I_UNSPECIFIED;
172 x->move_mode = false;
173 x->chown_privileges = chown_privileges ();
174 x->one_file_system = false;
175 x->preserve_ownership = false;
176 x->preserve_links = false;
177 x->preserve_mode = false;
178 x->preserve_timestamps = false;
179 x->require_preserve = false;
180 x->require_preserve_context = false;
181 x->recursive = false;
182 x->sparse_mode = SPARSE_AUTO;
183 x->symbolic_link = false;
184 x->backup_type = no_backups;
186 /* Create destination files initially writable so we can run strip on them.
187 Although GNU strip works fine on read-only files, some others
190 x->mode = S_IRUSR | S_IWUSR;
191 x->stdin_tty = false;
194 x->preserve_security_context = false;
200 /* Modify file context to match the specified policy.
201 If an error occurs the file will remain with the default directory
204 setdefaultfilecon (char const *file)
207 security_context_t scontext = NULL;
208 if (selinux_enabled != 1)
210 /* Indicate no context found. */
213 if (lstat (file, &st) != 0)
216 /* If there's an error determining the context, or it has none,
217 return to allow default context */
218 if ((matchpathcon (file, st.st_mode, &scontext) != 0) ||
219 STREQ (scontext, "<<none>>"))
221 if (scontext != NULL)
226 if (lsetfilecon (file, scontext) < 0 && errno != ENOTSUP)
228 _("warning: %s: failed to change context to %s"),
229 quotearg_colon (file), scontext);
235 /* FILE is the last operand of this command. Return true if FILE is a
236 directory. But report an error there is a problem accessing FILE,
237 or if FILE does not exist but would have to refer to an existing
238 directory if it referred to anything at all. */
241 target_directory_operand (char const *file)
243 char const *b = last_component (file);
244 size_t blen = strlen (b);
245 bool looks_like_a_dir = (blen == 0 || ISSLASH (b[blen - 1]));
247 int err = (stat (file, &st) == 0 ? 0 : errno);
248 bool is_a_dir = !err && S_ISDIR (st.st_mode);
249 if (err && err != ENOENT)
250 error (EXIT_FAILURE, err, _("accessing %s"), quote (file));
251 if (is_a_dir < looks_like_a_dir)
252 error (EXIT_FAILURE, err, _("target %s is not a directory"), quote (file));
256 /* Process a command-line file name, for the -d option. */
258 process_dir (char *dir, struct savewd *wd, void *options)
260 return (make_dir_parents (dir, wd,
261 make_ancestor, options,
262 dir_mode, announce_mkdir,
263 dir_mode_bits, owner_id, group_id, false)
269 main (int argc, char **argv)
272 int exit_status = EXIT_SUCCESS;
273 const char *specified_mode = NULL;
274 bool make_backups = false;
275 char *backup_suffix_string;
276 char *version_control_string = NULL;
277 bool mkdir_and_install = false;
279 char const *target_directory = NULL;
280 bool no_target_directory = false;
283 security_context_t scontext = NULL;
284 /* set iff kernel has extra selinux system calls */
285 selinux_enabled = (0 < is_selinux_enabled ());
287 initialize_main (&argc, &argv);
288 program_name = argv[0];
289 setlocale (LC_ALL, "");
290 bindtextdomain (PACKAGE, LOCALEDIR);
291 textdomain (PACKAGE);
293 atexit (close_stdout);
303 /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
304 we'll actually use backup_suffix_string. */
305 backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
307 while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pt:TvS:Z:", long_options,
315 version_control_string = optarg;
322 /* System V fork+wait does not work if SIGCHLD is ignored. */
323 signal (SIGCHLD, SIG_DFL);
330 mkdir_and_install = true;
339 specified_mode = optarg;
345 x.preserve_timestamps = true;
349 backup_suffix_string = optarg;
352 if (target_directory)
353 error (EXIT_FAILURE, 0,
354 _("multiple target directories specified"));
358 if (stat (optarg, &st) != 0)
359 error (EXIT_FAILURE, errno, _("accessing %s"), quote (optarg));
360 if (! S_ISDIR (st.st_mode))
361 error (EXIT_FAILURE, 0, _("target %s is not a directory"),
364 target_directory = optarg;
367 no_target_directory = true;
370 case PRESERVE_CONTEXT_OPTION:
371 if ( ! selinux_enabled)
373 error (0, 0, _("Warning: ignoring --preserve-context; "
374 "this kernel is not SELinux-enabled."));
377 x.preserve_security_context = true;
378 use_default_selinux_context = false;
381 if ( ! selinux_enabled)
383 error (0, 0, _("Warning: ignoring --context (-Z); "
384 "this kernel is not SELinux-enabled."));
388 use_default_selinux_context = false;
390 case_GETOPT_HELP_CHAR;
391 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
393 usage (EXIT_FAILURE);
397 /* Check for invalid combinations of arguments. */
398 if (dir_arg & strip_files)
399 error (EXIT_FAILURE, 0,
400 _("the strip option may not be used when installing a directory"));
401 if (dir_arg && target_directory)
402 error (EXIT_FAILURE, 0,
403 _("target directory not allowed when installing a directory"));
405 if (x.preserve_security_context && scontext != NULL)
406 error (EXIT_FAILURE, 0,
407 _("cannot force target context to %s and preserve it"),
410 if (backup_suffix_string)
411 simple_backup_suffix = xstrdup (backup_suffix_string);
413 x.backup_type = (make_backups
414 ? xget_version (_("backup type"),
415 version_control_string)
418 if (scontext && setfscreatecon (scontext) < 0)
419 error (EXIT_FAILURE, errno,
420 _("failed to set default file creation context to %s"),
423 n_files = argc - optind;
424 file = argv + optind;
426 if (n_files <= ! (dir_arg || target_directory))
429 error (0, 0, _("missing file operand"));
431 error (0, 0, _("missing destination file operand after %s"),
433 usage (EXIT_FAILURE);
436 if (no_target_directory)
438 if (target_directory)
439 error (EXIT_FAILURE, 0,
440 _("Cannot combine --target-directory (-t) "
441 "and --no-target-directory (-T)"));
444 error (0, 0, _("extra operand %s"), quote (file[2]));
445 usage (EXIT_FAILURE);
448 else if (! (dir_arg || target_directory))
450 if (2 <= n_files && target_directory_operand (file[n_files - 1]))
451 target_directory = file[--n_files];
452 else if (2 < n_files)
453 error (EXIT_FAILURE, 0, _("target %s is not a directory"),
454 quote (file[n_files - 1]));
459 struct mode_change *change = mode_compile (specified_mode);
461 error (EXIT_FAILURE, 0, _("invalid mode %s"), quote (specified_mode));
462 mode = mode_adjust (0, false, 0, change, NULL);
463 dir_mode = mode_adjust (0, true, 0, change, &dir_mode_bits);
470 exit_status = savewd_process_files (n_files, file, process_dir, &x);
473 /* FIXME: it's a little gross that this initialization is
474 required by copy.c::copy. */
477 if (!target_directory)
479 if (! (mkdir_and_install
480 ? install_file_in_file_parents (file[0], file[1], &x)
481 : install_file_in_file (file[0], file[1], &x)))
482 exit_status = EXIT_FAILURE;
488 for (i = 0; i < n_files; i++)
489 if (! install_file_in_dir (file[i], target_directory, &x))
490 exit_status = EXIT_FAILURE;
497 /* Copy file FROM onto file TO, creating any missing parent directories of TO.
498 Return true if successful. */
501 install_file_in_file_parents (char const *from, char *to,
502 struct cp_options *x)
504 bool save_working_directory =
505 ! (IS_ABSOLUTE_FILE_NAME (from) && IS_ABSOLUTE_FILE_NAME (to));
506 int status = EXIT_SUCCESS;
510 if (! save_working_directory)
513 if (mkancesdirs (to, &wd, make_ancestor, x) == -1)
515 error (0, errno, _("cannot create directory %s"), to);
516 status = EXIT_FAILURE;
519 if (save_working_directory)
521 int restore_result = savewd_restore (&wd, status);
522 int restore_errno = errno;
524 if (EXIT_SUCCESS < restore_result)
526 if (restore_result < 0 && status == EXIT_SUCCESS)
528 error (0, restore_errno, _("cannot create directory %s"), to);
533 return (status == EXIT_SUCCESS && install_file_in_file (from, to, x));
536 /* Copy file FROM onto file TO and give TO the appropriate
538 Return true if successful. */
541 install_file_in_file (const char *from, const char *to,
542 const struct cp_options *x)
545 if (x->preserve_timestamps && stat (from, &from_sb) != 0)
547 error (0, errno, _("cannot stat %s"), quote (from));
550 if (! copy_file (from, to, x))
554 if (x->preserve_timestamps && (strip_files || ! S_ISREG (from_sb.st_mode))
555 && ! change_timestamps (&from_sb, to))
557 return change_attributes (to);
560 /* Copy file FROM into directory TO_DIR, keeping its same name,
561 and give the copy the appropriate attributes.
562 Return true if successful. */
565 install_file_in_dir (const char *from, const char *to_dir,
566 const struct cp_options *x)
568 const char *from_base = last_component (from);
569 char *to = file_name_concat (to_dir, from_base, NULL);
570 bool ret = install_file_in_file (from, to, x);
575 /* Copy file FROM onto file TO, creating TO if necessary.
576 Return true if successful. */
579 copy_file (const char *from, const char *to, const struct cp_options *x)
583 /* Allow installing from non-regular files like /dev/null.
584 Charles Karney reported that some Sun version of install allows that
585 and that sendmail's installation process relies on the behavior.
586 However, since !x->recursive, the call to "copy" will fail if FROM
589 return copy (from, to, false, x, ©_into_self, NULL);
592 /* Set the attributes of file or directory NAME.
593 Return true if successful. */
596 change_attributes (char const *name)
599 /* chown must precede chmod because on some systems,
600 chown clears the set[ug]id bits for non-superusers,
601 resulting in incorrect permissions.
602 On System V, users can give away files with chown and then not
603 be able to chmod them. So don't give files away.
605 We don't normally ignore errors from chown because the idea of
606 the install command is that the file is supposed to end up with
607 precisely the attributes that the user specified (or defaulted).
608 If the file doesn't end up with the group they asked for, they'll
611 if (! (owner_id == (uid_t) -1 && group_id == (gid_t) -1)
612 && lchown (name, owner_id, group_id) != 0)
613 error (0, errno, _("cannot change ownership of %s"), quote (name));
614 else if (chmod (name, mode) != 0)
615 error (0, errno, _("cannot change permissions of %s"), quote (name));
619 if (use_default_selinux_context)
620 setdefaultfilecon (name);
625 /* Set the timestamps of file TO to match those of file FROM.
626 Return true if successful. */
629 change_timestamps (struct stat const *from_sb, char const *to)
631 struct timespec timespec[2];
632 timespec[0] = get_stat_atime (from_sb);
633 timespec[1] = get_stat_mtime (from_sb);
635 if (utimens (to, timespec))
637 error (0, errno, _("cannot set time stamps for %s"), quote (to));
643 /* Strip the symbol table from the file NAME.
644 We could dig the magic number out of the file first to
645 determine whether to strip it, but the header files and
646 magic numbers vary so much from system to system that making
647 it portable would be very difficult. Not worth the effort. */
650 strip (char const *name)
658 error (EXIT_FAILURE, errno, _("fork system call failed"));
661 execlp ("strip", "strip", name, NULL);
662 error (EXIT_FAILURE, errno, _("cannot run strip"));
664 default: /* Parent. */
665 if (waitpid (pid, &status, 0) < 0)
666 error (EXIT_FAILURE, errno, _("waiting for strip"));
667 else if (! WIFEXITED (status) || WEXITSTATUS (status))
668 error (EXIT_FAILURE, 0, _("strip process terminated abnormally"));
673 /* Initialize the user and group ownership of the files to install. */
683 pw = getpwnam (owner_name);
686 unsigned long int tmp;
687 if (xstrtoul (owner_name, NULL, 0, &tmp, NULL) != LONGINT_OK
689 error (EXIT_FAILURE, 0, _("invalid user %s"), quote (owner_name));
693 owner_id = pw->pw_uid;
697 owner_id = (uid_t) -1;
701 gr = getgrnam (group_name);
704 unsigned long int tmp;
705 if (xstrtoul (group_name, NULL, 0, &tmp, NULL) != LONGINT_OK
707 error (EXIT_FAILURE, 0, _("invalid group %s"), quote (group_name));
711 group_id = gr->gr_gid;
715 group_id = (gid_t) -1;
718 /* Report that directory DIR was made, if OPTIONS requests this. */
720 announce_mkdir (char const *dir, void *options)
722 struct cp_options const *x = options;
724 error (0, 0, _("creating directory %s"), quote (dir));
727 /* Make ancestor directory DIR, whose last file name component is
728 COMPONENT, with options OPTIONS. Assume the working directory is
729 COMPONENT's parent. */
731 make_ancestor (char const *dir, char const *component, void *options)
733 int r = mkdir (component, DEFAULT_MODE);
735 announce_mkdir (dir, options);
742 if (status != EXIT_SUCCESS)
743 fprintf (stderr, _("Try `%s --help' for more information.\n"),
748 Usage: %s [OPTION]... [-T] SOURCE DEST\n\
749 or: %s [OPTION]... SOURCE... DIRECTORY\n\
750 or: %s [OPTION]... -t DIRECTORY SOURCE...\n\
751 or: %s [OPTION]... -d DIRECTORY...\n\
753 program_name, program_name, program_name, program_name);
755 In the first three forms, copy SOURCE to DEST or multiple SOURCE(s) to\n\
756 the existing DIRECTORY, while setting permission modes and owner/group.\n\
757 In the 4th form, create all components of the given DIRECTORY(ies).\n\
761 Mandatory arguments to long options are mandatory for short options too.\n\
764 --backup[=CONTROL] make a backup of each existing destination file\n\
765 -b like --backup but does not accept an argument\n\
767 -d, --directory treat all arguments as directory names; create all\n\
768 components of the specified directories\n\
771 -D create all leading components of DEST except the last,\n\
772 then copy SOURCE to DEST\n\
773 -g, --group=GROUP set group ownership, instead of process' current group\n\
774 -m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\
775 -o, --owner=OWNER set ownership (super-user only)\n\
778 -p, --preserve-timestamps apply access/modification times of SOURCE files\n\
779 to corresponding destination files\n\
780 -s, --strip strip symbol tables\n\
781 -S, --suffix=SUFFIX override the usual backup suffix\n\
782 -t, --target-directory=DIRECTORY copy all SOURCE arguments into DIRECTORY\n\
783 -T, --no-target-directory treat DEST as a normal file\n\
784 -v, --verbose print the name of each directory as it is created\n\
787 --preserve-context preserve SELinux security context\n\
788 -Z, --context=CONTEXT set SELinux security context of files and directories\n\
791 fputs (HELP_OPTION_DESCRIPTION, stdout);
792 fputs (VERSION_OPTION_DESCRIPTION, stdout);
795 The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
796 The version control method may be selected via the --backup option or through\n\
797 the VERSION_CONTROL environment variable. Here are the values:\n\
801 none, off never make backups (even if --backup is given)\n\
802 numbered, t make numbered backups\n\
803 existing, nil numbered if numbered backups exist, simple otherwise\n\
804 simple, never always make simple backups\n\
806 emit_bug_reporting_address ();