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 2, or (at your option)
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, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 /* Written by David MacKenzie <djm@gnu.ai.mit.edu> */
23 #include <sys/types.h>
27 #include <selinux/selinux.h>
30 #include "backupfile.h"
34 #include "filenamecat.h"
35 #include "mkancesdirs.h"
37 #include "modechange.h"
41 #include "stat-time.h"
45 /* The official name of this program (e.g., no `g' prefix). */
46 #define PROGRAM_NAME "install"
48 #define AUTHORS "David MacKenzie"
51 # include <sys/wait.h>
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 /* Initial number of entries in each hash table entry's table of inodes. */
66 #define INITIAL_HASH_MODULE 100
68 /* Initial number of entries in the inode hash table. */
69 #define INITIAL_ENTRY_TAB_SIZE 70
71 /* Number of bytes of a file to copy at a time. */
72 #define READ_SIZE (32 * 1024)
74 static bool change_timestamps (struct stat const *from_sb, char const *to);
75 static bool change_attributes (char const *name);
76 static bool copy_file (const char *from, const char *to,
77 const struct cp_options *x);
78 static bool install_file_in_file_parents (char const *from, char *to,
79 struct cp_options *x);
80 static bool install_file_in_dir (const char *from, const char *to_dir,
81 const struct cp_options *x);
82 static bool install_file_in_file (const char *from, const char *to,
83 const struct cp_options *x);
84 static void get_ids (void);
85 static void strip (char const *name);
86 static void announce_mkdir (char const *dir, void *options);
87 static int make_ancestor (char const *dir, char const *component,
89 void usage (int status);
91 /* The name this program was run with, for error messages. */
94 /* The user name that will own the files, or NULL to make the owner
95 the current user ID. */
96 static char *owner_name;
98 /* The user ID corresponding to `owner_name'. */
99 static uid_t owner_id;
101 /* The group name that will own the files, or NULL to make the group
102 the current group ID. */
103 static char *group_name;
105 /* The group ID corresponding to `group_name'. */
106 static gid_t group_id;
108 #define DEFAULT_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
110 /* The file mode bits to which non-directory files will be set. The umask has
112 static mode_t mode = DEFAULT_MODE;
114 /* Similar, but for directories. */
115 static mode_t dir_mode = DEFAULT_MODE;
117 /* The file mode bits that the user cares about. This should be a
118 superset of DIR_MODE and a subset of CHMOD_MODE_BITS. This matters
119 for directories, since otherwise directories may keep their S_ISUID
121 static mode_t dir_mode_bits = CHMOD_MODE_BITS;
123 /* If true, strip executable files after copying them. */
124 static bool strip_files;
126 /* If true, install a directory instead of a regular file. */
129 /* For long options that have no equivalent short option, use a
130 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
133 PRESERVE_CONTEXT_OPTION = CHAR_MAX + 1
136 static struct option const long_options[] =
138 {"backup", optional_argument, NULL, 'b'},
139 {GETOPT_SELINUX_CONTEXT_OPTION_DECL},
140 {"directory", no_argument, NULL, 'd'},
141 {"group", required_argument, NULL, 'g'},
142 {"mode", required_argument, NULL, 'm'},
143 {"no-target-directory", no_argument, NULL, 'T'},
144 {"owner", required_argument, NULL, 'o'},
145 {"preserve-timestamps", no_argument, NULL, 'p'},
146 {"preserve-context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
147 /* Continue silent support for --preserve_context until Jan 2008. FIXME-obs
148 After that, FIXME-obs: warn in, say, late 2008, and disable altogether
149 a year or two later. */
150 {"preserve_context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
151 {"strip", no_argument, NULL, 's'},
152 {"suffix", required_argument, NULL, 'S'},
153 {"target-directory", required_argument, NULL, 't'},
154 {"verbose", no_argument, NULL, 'v'},
155 {GETOPT_HELP_OPTION_DECL},
156 {GETOPT_VERSION_OPTION_DECL},
161 cp_option_init (struct cp_options *x)
163 x->copy_as_regular = true;
164 x->dereference = DEREF_ALWAYS;
165 x->unlink_dest_before_opening = true;
166 x->unlink_dest_after_failed_open = false;
167 x->hard_link = false;
168 x->interactive = I_UNSPECIFIED;
169 x->move_mode = false;
170 x->chown_privileges = chown_privileges ();
171 x->one_file_system = false;
172 x->preserve_ownership = false;
173 x->preserve_links = false;
174 x->preserve_mode = false;
175 x->preserve_timestamps = false;
176 x->require_preserve = false;
177 x->require_preserve_context = false;
178 x->recursive = false;
179 x->sparse_mode = SPARSE_AUTO;
180 x->symbolic_link = false;
181 x->backup_type = no_backups;
183 /* Create destination files initially writable so we can run strip on them.
184 Although GNU strip works fine on read-only files, some others
187 x->mode = S_IRUSR | S_IWUSR;
188 x->stdin_tty = false;
191 x->preserve_security_context = false;
197 /* Modify file context to match the specified policy.
198 If an error occurs the file will remain with the default directory
201 setdefaultfilecon (char const *file)
204 security_context_t scontext = NULL;
205 if (selinux_enabled != 1)
207 /* Indicate no context found. */
210 if (lstat (file, &st) != 0)
213 /* If there's an error determining the context, or it has none,
214 return to allow default context */
215 if ((matchpathcon (file, st.st_mode, &scontext) != 0) ||
216 (strcmp (scontext, "<<none>>") == 0))
218 if (scontext != NULL)
223 if (lsetfilecon (file, scontext) < 0 && errno != ENOTSUP)
225 _("warning: %s: failed to change context to %s"),
226 quotearg_colon (file), scontext);
232 /* FILE is the last operand of this command. Return true if FILE is a
233 directory. But report an error there is a problem accessing FILE,
234 or if FILE does not exist but would have to refer to an existing
235 directory if it referred to anything at all. */
238 target_directory_operand (char const *file)
240 char const *b = last_component (file);
241 size_t blen = strlen (b);
242 bool looks_like_a_dir = (blen == 0 || ISSLASH (b[blen - 1]));
244 int err = (stat (file, &st) == 0 ? 0 : errno);
245 bool is_a_dir = !err && S_ISDIR (st.st_mode);
246 if (err && err != ENOENT)
247 error (EXIT_FAILURE, err, _("accessing %s"), quote (file));
248 if (is_a_dir < looks_like_a_dir)
249 error (EXIT_FAILURE, err, _("target %s is not a directory"), quote (file));
253 /* Process a command-line file name, for the -d option. */
255 process_dir (char *dir, struct savewd *wd, void *options)
257 return (make_dir_parents (dir, wd,
258 make_ancestor, options,
259 dir_mode, announce_mkdir,
260 dir_mode_bits, owner_id, group_id, false)
266 main (int argc, char **argv)
269 int exit_status = EXIT_SUCCESS;
270 const char *specified_mode = NULL;
271 bool make_backups = false;
272 char *backup_suffix_string;
273 char *version_control_string = NULL;
274 bool mkdir_and_install = false;
276 char const *target_directory = NULL;
277 bool no_target_directory = false;
280 security_context_t scontext = NULL;
281 /* set iff kernel has extra selinux system calls */
282 selinux_enabled = (0 < is_selinux_enabled ());
284 initialize_main (&argc, &argv);
285 program_name = argv[0];
286 setlocale (LC_ALL, "");
287 bindtextdomain (PACKAGE, LOCALEDIR);
288 textdomain (PACKAGE);
290 atexit (close_stdout);
300 /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
301 we'll actually use backup_suffix_string. */
302 backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
304 while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pt:TvS:Z:", long_options,
312 version_control_string = optarg;
319 /* System V fork+wait does not work if SIGCHLD is ignored. */
320 signal (SIGCHLD, SIG_DFL);
327 mkdir_and_install = true;
336 specified_mode = optarg;
342 x.preserve_timestamps = true;
346 backup_suffix_string = optarg;
349 if (target_directory)
350 error (EXIT_FAILURE, 0,
351 _("multiple target directories specified"));
355 if (stat (optarg, &st) != 0)
356 error (EXIT_FAILURE, errno, _("accessing %s"), quote (optarg));
357 if (! S_ISDIR (st.st_mode))
358 error (EXIT_FAILURE, 0, _("target %s is not a directory"),
361 target_directory = optarg;
364 no_target_directory = true;
367 case PRESERVE_CONTEXT_OPTION:
368 if ( ! selinux_enabled)
370 error (0, 0, _("Warning: ignoring --preserve-context; "
371 "this kernel is not SELinux-enabled."));
374 x.preserve_security_context = true;
375 use_default_selinux_context = false;
378 if ( ! selinux_enabled)
380 error (0, 0, _("Warning: ignoring --context (-Z); "
381 "this kernel is not SELinux-enabled."));
385 use_default_selinux_context = false;
387 case_GETOPT_HELP_CHAR;
388 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
390 usage (EXIT_FAILURE);
394 /* Check for invalid combinations of arguments. */
395 if (dir_arg & strip_files)
396 error (EXIT_FAILURE, 0,
397 _("the strip option may not be used when installing a directory"));
398 if (dir_arg && target_directory)
399 error (EXIT_FAILURE, 0,
400 _("target directory not allowed when installing a directory"));
402 if (x.preserve_security_context && scontext != NULL)
403 error (EXIT_FAILURE, 0,
404 _("cannot force target context to %s and preserve it"),
407 if (backup_suffix_string)
408 simple_backup_suffix = xstrdup (backup_suffix_string);
410 x.backup_type = (make_backups
411 ? xget_version (_("backup type"),
412 version_control_string)
415 if (scontext && setfscreatecon (scontext) < 0)
416 error (EXIT_FAILURE, errno,
417 _("failed to set default file creation context to %s"),
420 n_files = argc - optind;
421 file = argv + optind;
423 if (n_files <= ! (dir_arg || target_directory))
426 error (0, 0, _("missing file operand"));
428 error (0, 0, _("missing destination file operand after %s"),
430 usage (EXIT_FAILURE);
433 if (no_target_directory)
435 if (target_directory)
436 error (EXIT_FAILURE, 0,
437 _("Cannot combine --target-directory (-t) "
438 "and --no-target-directory (-T)"));
441 error (0, 0, _("extra operand %s"), quote (file[2]));
442 usage (EXIT_FAILURE);
445 else if (! (dir_arg || target_directory))
447 if (2 <= n_files && target_directory_operand (file[n_files - 1]))
448 target_directory = file[--n_files];
449 else if (2 < n_files)
450 error (EXIT_FAILURE, 0, _("target %s is not a directory"),
451 quote (file[n_files - 1]));
456 struct mode_change *change = mode_compile (specified_mode);
458 error (EXIT_FAILURE, 0, _("invalid mode %s"), quote (specified_mode));
459 mode = mode_adjust (0, false, 0, change, NULL);
460 dir_mode = mode_adjust (0, true, 0, change, &dir_mode_bits);
467 exit_status = savewd_process_files (n_files, file, process_dir, &x);
470 /* FIXME: it's a little gross that this initialization is
471 required by copy.c::copy. */
474 if (!target_directory)
476 if (! (mkdir_and_install
477 ? install_file_in_file_parents (file[0], file[1], &x)
478 : install_file_in_file (file[0], file[1], &x)))
479 exit_status = EXIT_FAILURE;
485 for (i = 0; i < n_files; i++)
486 if (! install_file_in_dir (file[i], target_directory, &x))
487 exit_status = EXIT_FAILURE;
494 /* Copy file FROM onto file TO, creating any missing parent directories of TO.
495 Return true if successful. */
498 install_file_in_file_parents (char const *from, char *to,
499 struct cp_options *x)
501 bool save_working_directory =
502 ! (IS_ABSOLUTE_FILE_NAME (from) && IS_ABSOLUTE_FILE_NAME (to));
503 int status = EXIT_SUCCESS;
507 if (! save_working_directory)
510 if (mkancesdirs (to, &wd, make_ancestor, x) == -1)
512 error (0, errno, _("cannot create directory %s"), to);
513 status = EXIT_FAILURE;
516 if (save_working_directory)
518 int restore_result = savewd_restore (&wd, status);
519 int restore_errno = errno;
521 if (EXIT_SUCCESS < restore_result)
523 if (restore_result < 0 && status == EXIT_SUCCESS)
525 error (0, restore_errno, _("cannot create directory %s"), to);
530 return (status == EXIT_SUCCESS && install_file_in_file (from, to, x));
533 /* Copy file FROM onto file TO and give TO the appropriate
535 Return true if successful. */
538 install_file_in_file (const char *from, const char *to,
539 const struct cp_options *x)
542 if (x->preserve_timestamps && stat (from, &from_sb) != 0)
544 error (0, errno, _("cannot stat %s"), quote (from));
547 if (! copy_file (from, to, x))
551 if (x->preserve_timestamps && (strip_files || ! S_ISREG (from_sb.st_mode))
552 && ! change_timestamps (&from_sb, to))
554 return change_attributes (to);
557 /* Copy file FROM into directory TO_DIR, keeping its same name,
558 and give the copy the appropriate attributes.
559 Return true if successful. */
562 install_file_in_dir (const char *from, const char *to_dir,
563 const struct cp_options *x)
565 const char *from_base = last_component (from);
566 char *to = file_name_concat (to_dir, from_base, NULL);
567 bool ret = install_file_in_file (from, to, x);
572 /* Copy file FROM onto file TO, creating TO if necessary.
573 Return true if successful. */
576 copy_file (const char *from, const char *to, const struct cp_options *x)
580 /* Allow installing from non-regular files like /dev/null.
581 Charles Karney reported that some Sun version of install allows that
582 and that sendmail's installation process relies on the behavior.
583 However, since !x->recursive, the call to "copy" will fail if FROM
586 return copy (from, to, false, x, ©_into_self, NULL);
589 /* Set the attributes of file or directory NAME.
590 Return true if successful. */
593 change_attributes (char const *name)
596 /* chown must precede chmod because on some systems,
597 chown clears the set[ug]id bits for non-superusers,
598 resulting in incorrect permissions.
599 On System V, users can give away files with chown and then not
600 be able to chmod them. So don't give files away.
602 We don't normally ignore errors from chown because the idea of
603 the install command is that the file is supposed to end up with
604 precisely the attributes that the user specified (or defaulted).
605 If the file doesn't end up with the group they asked for, they'll
608 if (! (owner_id == (uid_t) -1 && group_id == (gid_t) -1)
609 && chown (name, owner_id, group_id) != 0)
610 error (0, errno, _("cannot change ownership of %s"), quote (name));
611 else if (chmod (name, mode) != 0)
612 error (0, errno, _("cannot change permissions of %s"), quote (name));
616 if (use_default_selinux_context)
617 setdefaultfilecon (name);
622 /* Set the timestamps of file TO to match those of file FROM.
623 Return true if successful. */
626 change_timestamps (struct stat const *from_sb, char const *to)
628 struct timespec timespec[2];
629 timespec[0] = get_stat_atime (from_sb);
630 timespec[1] = get_stat_mtime (from_sb);
632 if (utimens (to, timespec))
634 error (0, errno, _("cannot set time stamps for %s"), quote (to));
640 /* Strip the symbol table from the file NAME.
641 We could dig the magic number out of the file first to
642 determine whether to strip it, but the header files and
643 magic numbers vary so much from system to system that making
644 it portable would be very difficult. Not worth the effort. */
647 strip (char const *name)
655 error (EXIT_FAILURE, errno, _("fork system call failed"));
658 execlp ("strip", "strip", name, NULL);
659 error (EXIT_FAILURE, errno, _("cannot run strip"));
661 default: /* Parent. */
662 if (waitpid (pid, &status, 0) < 0)
663 error (EXIT_FAILURE, errno, _("waiting for strip"));
664 else if (! WIFEXITED (status) || WEXITSTATUS (status))
665 error (EXIT_FAILURE, 0, _("strip process terminated abnormally"));
670 /* Initialize the user and group ownership of the files to install. */
680 pw = getpwnam (owner_name);
683 unsigned long int tmp;
684 if (xstrtoul (owner_name, NULL, 0, &tmp, NULL) != LONGINT_OK
686 error (EXIT_FAILURE, 0, _("invalid user %s"), quote (owner_name));
690 owner_id = pw->pw_uid;
694 owner_id = (uid_t) -1;
698 gr = getgrnam (group_name);
701 unsigned long int tmp;
702 if (xstrtoul (group_name, NULL, 0, &tmp, NULL) != LONGINT_OK
704 error (EXIT_FAILURE, 0, _("invalid group %s"), quote (group_name));
708 group_id = gr->gr_gid;
712 group_id = (gid_t) -1;
715 /* Report that directory DIR was made, if OPTIONS requests this. */
717 announce_mkdir (char const *dir, void *options)
719 struct cp_options const *x = options;
721 error (0, 0, _("creating directory %s"), quote (dir));
724 /* Make ancestor directory DIR, whose last file name component is
725 COMPONENT, with options OPTIONS. Assume the working directory is
726 COMPONENT's parent. */
728 make_ancestor (char const *dir, char const *component, void *options)
730 int r = mkdir (component, DEFAULT_MODE);
732 announce_mkdir (dir, options);
739 if (status != EXIT_SUCCESS)
740 fprintf (stderr, _("Try `%s --help' for more information.\n"),
745 Usage: %s [OPTION]... [-T] SOURCE DEST\n\
746 or: %s [OPTION]... SOURCE... DIRECTORY\n\
747 or: %s [OPTION]... -t DIRECTORY SOURCE...\n\
748 or: %s [OPTION]... -d DIRECTORY...\n\
750 program_name, program_name, program_name, program_name);
752 In the first three forms, copy SOURCE to DEST or multiple SOURCE(s) to\n\
753 the existing DIRECTORY, while setting permission modes and owner/group.\n\
754 In the 4th form, create all components of the given DIRECTORY(ies).\n\
758 Mandatory arguments to long options are mandatory for short options too.\n\
761 --backup[=CONTROL] make a backup of each existing destination file\n\
762 -b like --backup but does not accept an argument\n\
764 -d, --directory treat all arguments as directory names; create all\n\
765 components of the specified directories\n\
768 -D create all leading components of DEST except the last,\n\
769 then copy SOURCE to DEST\n\
770 -g, --group=GROUP set group ownership, instead of process' current group\n\
771 -m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\
772 -o, --owner=OWNER set ownership (super-user only)\n\
775 -p, --preserve-timestamps apply access/modification times of SOURCE files\n\
776 to corresponding destination files\n\
777 -s, --strip strip symbol tables\n\
778 -S, --suffix=SUFFIX override the usual backup suffix\n\
779 -t, --target-directory=DIRECTORY copy all SOURCE arguments into DIRECTORY\n\
780 -T, --no-target-directory treat DEST as a normal file\n\
781 -v, --verbose print the name of each directory as it is created\n\
784 --preserve-context preserve SELinux security context\n\
785 -Z, --context=CONTEXT set SELinux security context of files and directories\n\
788 fputs (HELP_OPTION_DESCRIPTION, stdout);
789 fputs (VERSION_OPTION_DESCRIPTION, stdout);
792 The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
793 The version control method may be selected via the --backup option or through\n\
794 the VERSION_CONTROL environment variable. Here are the values:\n\
798 none, off never make backups (even if --backup is given)\n\
799 numbered, t make numbered backups\n\
800 existing, nil numbered if numbered backups exist, simple otherwise\n\
801 simple, never always make simple backups\n\
803 emit_bug_reporting_address ();