1 /* install - copy files and set attributes
2 Copyright (C) 89, 90, 91, 1995-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Written by David MacKenzie <djm@gnu.ai.mit.edu> */
23 #include <sys/types.h>
29 #include "backupfile.h"
35 #include "modechange.h"
36 #include "path-concat.h"
41 /* The official name of this program (e.g., no `g' prefix). */
42 #define PROGRAM_NAME "install"
44 #define AUTHORS "David MacKenzie"
47 # include <sys/wait.h>
50 struct passwd *getpwnam ();
51 struct group *getgrnam ();
53 #ifndef _POSIX_VERSION
59 # define endgrent() ((void) 0)
63 # define endpwent() ((void) 0)
66 /* Initial number of entries in each hash table entry's table of inodes. */
67 #define INITIAL_HASH_MODULE 100
69 /* Initial number of entries in the inode hash table. */
70 #define INITIAL_ENTRY_TAB_SIZE 70
72 /* Number of bytes of a file to copy at a time. */
73 #define READ_SIZE (32 * 1024)
77 static bool change_timestamps (const char *from, const char *to);
78 static bool change_attributes (const char *path);
79 static bool copy_file (const char *from, const char *to,
80 const struct cp_options *x);
81 static bool install_file_to_path (const char *from, const char *to,
82 const 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 (const char *path);
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 /* The permissions to which the files will be set. The umask has
110 static mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
112 /* If true, strip executable files after copying them. */
113 static bool strip_files;
115 /* If true, install a directory instead of a regular file. */
118 static struct option const long_options[] =
120 {"backup", optional_argument, NULL, 'b'},
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 {"strip", no_argument, NULL, 's'},
128 {"suffix", required_argument, NULL, 'S'},
129 {"target-directory", required_argument, NULL, 't'},
130 {"version-control", required_argument, NULL, 'V'}, /* Deprecated. FIXME. */
131 {"verbose", no_argument, NULL, 'v'},
132 {GETOPT_HELP_OPTION_DECL},
133 {GETOPT_VERSION_OPTION_DECL},
138 cp_option_init (struct cp_options *x)
140 x->copy_as_regular = true;
141 x->dereference = DEREF_ALWAYS;
142 x->unlink_dest_before_opening = true;
143 x->unlink_dest_after_failed_open = false;
144 x->hard_link = false;
145 x->interactive = I_UNSPECIFIED;
146 x->move_mode = false;
147 x->myeuid = geteuid ();
148 x->one_file_system = false;
149 x->preserve_ownership = false;
150 x->preserve_links = false;
151 x->preserve_mode = false;
152 x->preserve_timestamps = false;
153 x->require_preserve = false;
154 x->recursive = false;
155 x->sparse_mode = SPARSE_AUTO;
156 x->symbolic_link = false;
157 x->backup_type = no_backups;
159 /* Create destination files initially writable so we can run strip on them.
160 Although GNU strip works fine on read-only files, some others
163 x->mode = S_IRUSR | S_IWUSR;
164 x->stdin_tty = false;
173 /* FILE is the last operand of this command. Return true if FILE is a
174 directory. But report an error there is a problem accessing FILE,
175 or if FILE does not exist but would have to refer to an existing
176 directory if it referred to anything at all. */
179 target_directory_operand (char const *file)
181 char const *b = base_name (file);
182 size_t blen = strlen (b);
183 bool looks_like_a_dir = (blen == 0 || ISSLASH (b[blen - 1]));
185 int err = (stat (file, &st) == 0 ? 0 : errno);
186 bool is_a_dir = !err && S_ISDIR (st.st_mode);
187 if (err && err != ENOENT)
188 error (EXIT_FAILURE, err, _("accessing %s"), quote (file));
189 if (is_a_dir < looks_like_a_dir)
190 error (EXIT_FAILURE, err, _("target %s is not a directory"), quote (file));
195 main (int argc, char **argv)
199 const char *specified_mode = NULL;
200 bool make_backups = false;
201 char *backup_suffix_string;
202 char *version_control_string = NULL;
203 bool mkdir_and_install = false;
205 char const *target_directory = NULL;
206 bool no_target_directory = false;
210 initialize_main (&argc, &argv);
211 program_name = argv[0];
212 setlocale (LC_ALL, "");
213 bindtextdomain (PACKAGE, LOCALEDIR);
214 textdomain (PACKAGE);
216 atexit (close_stdout);
226 /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
227 we'll actually use backup_suffix_string. */
228 backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
230 while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pt:TvV:S:", long_options,
238 case 'V': /* FIXME: this is deprecated. Remove it in 2001. */
240 _("warning: --version-control (-V) is obsolete; support for\
241 it\nwill be removed in some future release. Use --backup=%s instead."
248 version_control_string = optarg;
255 /* System V fork+wait does not work if SIGCHLD is ignored. */
256 signal (SIGCHLD, SIG_DFL);
263 mkdir_and_install = true;
272 specified_mode = optarg;
278 x.preserve_timestamps = true;
282 backup_suffix_string = optarg;
285 if (target_directory)
286 error (EXIT_FAILURE, 0,
287 _("multiple target directories specified"));
291 if (stat (optarg, &st) != 0)
292 error (EXIT_FAILURE, errno, _("accessing %s"), quote (optarg));
293 if (! S_ISDIR (st.st_mode))
294 error (EXIT_FAILURE, 0, _("target %s is not a directory"),
297 target_directory = optarg;
300 no_target_directory = true;
302 case_GETOPT_HELP_CHAR;
303 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
305 usage (EXIT_FAILURE);
309 /* Check for invalid combinations of arguments. */
310 if (dir_arg & strip_files)
311 error (EXIT_FAILURE, 0,
312 _("the strip option may not be used when installing a directory"));
313 if (dir_arg && target_directory)
314 error (EXIT_FAILURE, 0,
315 _("target directory not allowed when installing a directory"));
317 if (backup_suffix_string)
318 simple_backup_suffix = xstrdup (backup_suffix_string);
320 x.backup_type = (make_backups
321 ? xget_version (_("backup type"),
322 version_control_string)
325 n_files = argc - optind;
326 file = argv + optind;
328 if (n_files <= ! (dir_arg || target_directory))
331 error (0, 0, _("missing file operand"));
333 error (0, 0, _("missing destination file operand after %s"),
335 usage (EXIT_FAILURE);
338 if (no_target_directory)
340 if (target_directory)
341 error (EXIT_FAILURE, 0,
342 _("Cannot combine --target-directory (-t) "
343 "and --no-target-directory (-T)"));
346 error (0, 0, _("extra operand %s"), quote (file[2]));
347 usage (EXIT_FAILURE);
350 else if (! (dir_arg || target_directory))
352 if (2 <= n_files && target_directory_operand (file[n_files - 1]))
353 target_directory = file[--n_files];
354 else if (2 < n_files)
355 error (EXIT_FAILURE, 0, _("target %s is not a directory"),
356 quote (file[n_files - 1]));
361 struct mode_change *change = mode_compile (specified_mode, 0);
362 if (change == MODE_INVALID)
363 error (EXIT_FAILURE, 0, _("invalid mode %s"), quote (specified_mode));
364 else if (change == MODE_MEMORY_EXHAUSTED)
366 mode = mode_adjust (0, change);
374 for (i = 0; i < n_files; i++)
377 make_path (file[i], mode, mode, owner_id, group_id, false,
378 (x.verbose ? _("creating directory %s") : NULL));
383 /* FIXME: it's a little gross that this initialization is
384 required by copy.c::copy. */
387 if (!target_directory)
389 if (mkdir_and_install)
390 ok = install_file_to_path (file[0], file[1], &x);
392 ok = install_file_in_file (file[0], file[1], &x);
398 for (i = 0; i < n_files; i++)
400 ok &= install_file_in_dir (file[i], target_directory, &x);
405 exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
408 /* Copy file FROM onto file TO, creating any missing parent directories of TO.
409 Return true if successful. */
412 install_file_to_path (const char *from, const char *to,
413 const struct cp_options *x)
415 char *dest_dir = dir_name (to);
418 /* Make sure that the parent of the destination is a directory. */
419 if (! STREQ (dest_dir, "."))
421 /* Someone will probably ask for a new option or three to specify
422 owner, group, and permissions for parent directories. Remember
423 that this option is intended mainly to help installers when the
424 distribution doesn't provide proper install rules. */
425 #define DIR_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
426 ok = make_path (dest_dir, DIR_MODE, DIR_MODE, owner_id, group_id, true,
427 (x->verbose ? _("creating directory %s") : NULL));
433 ok = install_file_in_file (from, to, x);
438 /* Copy file FROM onto file TO and give TO the appropriate
440 Return true if successful. */
443 install_file_in_file (const char *from, const char *to,
444 const struct cp_options *x)
446 if (! copy_file (from, to, x))
450 if (! change_attributes (to))
452 if (x->preserve_timestamps)
453 return change_timestamps (from, to);
457 /* Copy file FROM into directory TO_DIR, keeping its same name,
458 and give the copy the appropriate attributes.
459 Return true if successful. */
462 install_file_in_dir (const char *from, const char *to_dir,
463 const struct cp_options *x)
465 const char *from_base = base_name (from);
466 char *to = path_concat (to_dir, from_base, NULL);
467 bool ret = install_file_in_file (from, to, x);
472 /* Copy file FROM onto file TO, creating TO if necessary.
473 Return true if successful. */
476 copy_file (const char *from, const char *to, const struct cp_options *x)
480 /* Allow installing from non-regular files like /dev/null.
481 Charles Karney reported that some Sun version of install allows that
482 and that sendmail's installation process relies on the behavior.
483 However, since !x->recursive, the call to "copy" will fail if FROM
486 return copy (from, to, false, x, ©_into_self, NULL);
489 /* Set the attributes of file or directory PATH.
490 Return true if successful. */
493 change_attributes (const char *path)
497 /* chown must precede chmod because on some systems,
498 chown clears the set[ug]id bits for non-superusers,
499 resulting in incorrect permissions.
500 On System V, users can give away files with chown and then not
501 be able to chmod them. So don't give files away.
503 We don't normally ignore errors from chown because the idea of
504 the install command is that the file is supposed to end up with
505 precisely the attributes that the user specified (or defaulted).
506 If the file doesn't end up with the group they asked for, they'll
507 want to know. But AFS returns EPERM when you try to change a
508 file's group; thus the kludge. */
510 if (chown (path, owner_id, group_id)
516 error (0, errno, _("cannot change ownership of %s"), quote (path));
520 if (ok && chmod (path, mode))
522 error (0, errno, _("cannot change permissions of %s"), quote (path));
529 /* Set the timestamps of file TO to match those of file FROM.
530 Return true if successful. */
533 change_timestamps (const char *from, const char *to)
536 struct timespec timespec[2];
538 if (stat (from, &stb))
540 error (0, errno, _("cannot obtain time stamps for %s"), quote (from));
544 timespec[0].tv_sec = stb.st_atime;
545 timespec[0].tv_nsec = TIMESPEC_NS (stb.st_atim);
546 timespec[1].tv_sec = stb.st_mtime;
547 timespec[1].tv_nsec = TIMESPEC_NS (stb.st_mtim);
548 if (utimens (to, timespec))
550 error (0, errno, _("cannot set time stamps for %s"), quote (to));
556 /* Strip the symbol table from the file PATH.
557 We could dig the magic number out of the file first to
558 determine whether to strip it, but the header files and
559 magic numbers vary so much from system to system that making
560 it portable would be very difficult. Not worth the effort. */
563 strip (const char *path)
571 error (EXIT_FAILURE, errno, _("fork system call failed"));
574 execlp ("strip", "strip", path, NULL);
575 error (EXIT_FAILURE, errno, _("cannot run strip"));
577 default: /* Parent. */
578 /* Parent process. */
579 while (pid != wait (&status)) /* Wait for kid to finish. */
582 error (EXIT_FAILURE, 0, _("strip failed"));
587 /* Initialize the user and group ownership of the files to install. */
597 pw = getpwnam (owner_name);
600 unsigned long int tmp;
601 if (xstrtoul (owner_name, NULL, 0, &tmp, NULL) != LONGINT_OK
603 error (EXIT_FAILURE, 0, _("invalid user %s"), quote (owner_name));
607 owner_id = pw->pw_uid;
611 owner_id = (uid_t) -1;
615 gr = getgrnam (group_name);
618 unsigned long int tmp;
619 if (xstrtoul (group_name, NULL, 0, &tmp, NULL) != LONGINT_OK
621 error (EXIT_FAILURE, 0, _("invalid group %s"), quote (group_name));
625 group_id = gr->gr_gid;
629 group_id = (gid_t) -1;
635 if (status != EXIT_SUCCESS)
636 fprintf (stderr, _("Try `%s --help' for more information.\n"),
641 Usage: %s [OPTION]... [-T] SOURCE DEST (1st form)\n\
642 or: %s [OPTION]... SOURCE... DIRECTORY (2nd form)\n\
643 or: %s [OPTION]... -t DIRECTORY SOURCE... (3rd form)\n\
644 or: %s [OPTION]... -d DIRECTORY... (4th form)\n\
646 program_name, program_name, program_name, program_name);
648 In the first three forms, copy SOURCE to DEST or multiple SOURCE(s) to\n\
649 the existing DIRECTORY, while setting permission modes and owner/group.\n\
650 In the 4th form, create all components of the given DIRECTORY(ies).\n\
654 Mandatory arguments to long options are mandatory for short options too.\n\
657 --backup[=CONTROL] make a backup of each existing destination file\n\
658 -b like --backup but does not accept an argument\n\
660 -d, --directory treat all arguments as directory names; create all\n\
661 components of the specified directories\n\
664 -D create all leading components of DEST except the last,\n\
665 then copy SOURCE to DEST; useful in the 1st format\n\
666 -g, --group=GROUP set group ownership, instead of process' current group\n\
667 -m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\
668 -o, --owner=OWNER set ownership (super-user only)\n\
671 -p, --preserve-timestamps apply access/modification times of SOURCE files\n\
672 to corresponding destination files\n\
673 -s, --strip strip symbol tables, only for 1st and 2nd formats\n\
674 -S, --suffix=SUFFIX override the usual backup suffix\n\
675 -t, --target-directory=DIRECTORY copy all SOURCE arguments into DIRECTORY\n\
676 -T, --no-target-directory treat DEST as a normal file\n\
677 -v, --verbose print the name of each directory as it is created\n\
679 fputs (HELP_OPTION_DESCRIPTION, stdout);
680 fputs (VERSION_OPTION_DESCRIPTION, stdout);
683 The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
684 The version control method may be selected via the --backup option or through\n\
685 the VERSION_CONTROL environment variable. Here are the values:\n\
689 none, off never make backups (even if --backup is given)\n\
690 numbered, t make numbered backups\n\
691 existing, nil numbered if numbered backups exist, simple otherwise\n\
692 simple, never always make simple backups\n\
694 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);