*** empty log message ***
[coreutils.git] / src / install.c
blobcea817622882db0a99e79148f9179396158e6c16
1 /* install - copy files and set attributes
2 Copyright (C) 89, 90, 91, 1995-1999 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)
7 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, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Copy files and set their permission modes and, if possible,
19 their owner and group. Used similarly to `cp'; typically
20 used in Makefiles to copy programs into their destination
21 directories. It can also be used to create the destination
22 directories and any leading directories, and to set the final
23 directory's modes. It refuses to copy files onto themselves.
25 Options:
26 -g, --group=GROUP
27 Set the group ownership of the installed file or directory
28 to the group ID of GROUP (default is process's current
29 group). GROUP may also be a numeric group ID.
31 -m, --mode=MODE
32 Set the permission mode for the installed file or directory
33 to MODE, which is an octal number (default is u=rwx,g=rx,o=rx).
35 -o, --owner=OWNER
36 If run as root, set the ownership of the installed file to
37 the user ID of OWNER (default is root). OWNER may also be
38 a numeric user ID.
40 -c No effect. For compatibility with old Unix versions of install.
42 -s, --strip
43 Strip the symbol tables from installed files.
45 -p, --preserve-timestamps
46 Retain creation and modification timestamps when installing files.
48 -d, --directory
49 Create a directory and its leading directories, if they
50 do not already exist. Set the owner, group and mode
51 as given on the command line. Any leading directories
52 that are created are also given those attributes.
53 This is different from the SunOS 4.0 install, which gives
54 directories that it creates the default attributes.
57 Like the -d option, but a file is installed, along with the directory.
58 Useful when installing into a new directory, and the install
59 process doesn't properly comprehend making directories.
61 David MacKenzie <djm@gnu.ai.mit.edu> */
63 #ifdef _AIX
64 #pragma alloca
65 #endif
67 #include <config.h>
68 #include <stdio.h>
69 #include <getopt.h>
70 #include <sys/types.h>
71 #include <pwd.h>
72 #include <grp.h>
74 #include "system.h"
75 #include "backupfile.h"
76 #include "error.h"
77 #include "cp-hash.h"
78 #include "copy.h"
79 #include "dirname.h"
80 #include "makepath.h"
81 #include "modechange.h"
82 #include "path-concat.h"
83 #include "xstrtol.h"
85 /* The official name of this program (e.g., no `g' prefix). */
86 #define PROGRAM_NAME "install"
88 #define AUTHORS "David MacKenzie"
90 #if HAVE_SYS_WAIT_H
91 # include <sys/wait.h>
92 #endif
94 #if HAVE_VALUES_H
95 # include <values.h>
96 #endif
98 struct passwd *getpwnam ();
99 struct group *getgrnam ();
101 #ifndef _POSIX_VERSION
102 uid_t getuid ();
103 gid_t getgid ();
104 #endif
106 #if ! HAVE_ENDGRENT
107 # define endgrent() ((void) 0)
108 #endif
110 #if ! HAVE_ENDPWENT
111 # define endpwent() ((void) 0)
112 #endif
114 /* Initial number of entries in each hash table entry's table of inodes. */
115 #define INITIAL_HASH_MODULE 100
117 /* Initial number of entries in the inode hash table. */
118 #define INITIAL_ENTRY_TAB_SIZE 70
120 /* Number of bytes of a file to copy at a time. */
121 #define READ_SIZE (32 * 1024)
123 int full_write ();
124 int isdir ();
126 int stat ();
128 static int change_timestamps PARAMS ((const char *from, const char *to));
129 static int change_attributes PARAMS ((const char *path));
130 static int copy_file PARAMS ((const char *from, const char *to,
131 const struct cp_options *x));
132 static int install_file_to_path PARAMS ((const char *from, const char *to,
133 const struct cp_options *x));
134 static int install_file_in_dir PARAMS ((const char *from, const char *to_dir,
135 const struct cp_options *x));
136 static int install_file_in_file PARAMS ((const char *from, const char *to,
137 const struct cp_options *x));
138 static void get_ids PARAMS ((void));
139 static void strip PARAMS ((const char *path));
140 void usage PARAMS ((int status));
142 /* The name this program was run with, for error messages. */
143 char *program_name;
145 /* The user name that will own the files, or NULL to make the owner
146 the current user ID. */
147 static char *owner_name;
149 /* The user ID corresponding to `owner_name'. */
150 static uid_t owner_id;
152 /* The group name that will own the files, or NULL to make the group
153 the current group ID. */
154 static char *group_name;
156 /* The group ID corresponding to `group_name'. */
157 static gid_t group_id;
159 /* The permissions to which the files will be set. The umask has
160 no effect. */
161 static mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
163 /* If nonzero, strip executable files after copying them. */
164 static int strip_files;
166 /* If nonzero, install a directory instead of a regular file. */
167 static int dir_arg;
169 static struct option const long_options[] =
171 {"strip", no_argument, NULL, 's'},
172 {"directory", no_argument, NULL, 'd'},
173 {"group", required_argument, NULL, 'g'},
174 {"mode", required_argument, NULL, 'm'},
175 {"owner", required_argument, NULL, 'o'},
176 {"preserve-timestamps", no_argument, NULL, 'p'},
177 {"backup", no_argument, NULL, 'b'},
178 {"suffix", required_argument, NULL, 'S'},
179 {"version-control", required_argument, NULL, 'V'},
180 {"verbose", no_argument, NULL, 'v'},
181 {GETOPT_HELP_OPTION_DECL},
182 {GETOPT_VERSION_OPTION_DECL},
183 {NULL, 0, NULL, 0}
186 static void
187 cp_option_init (struct cp_options *x)
189 x->copy_as_regular = 1;
190 x->dereference = 1;
191 x->force = 1;
193 /* If unlink fails, try to proceed anyway. */
194 x->failed_unlink_is_fatal = 0;
196 x->hard_link = 0;
197 x->interactive = 0;
198 x->move_mode = 0;
199 x->myeuid = geteuid ();
200 x->one_file_system = 0;
201 x->preserve_owner_and_group = 0;
202 x->preserve_chmod_bits = 0;
203 x->preserve_timestamps = 0;
204 x->require_preserve = 0;
205 x->recursive = 0;
206 x->sparse_mode = SPARSE_AUTO;
207 x->symbolic_link = 0;
208 x->backup_type = none;
210 /* Create destination files initially writable so we can run strip on them.
211 Although GNU strip works fine on read-only files, some others
212 would fail. */
213 x->set_mode = 1;
214 x->mode = S_IRUSR | S_IWUSR;
216 x->umask_kill = 0;
217 x->update = 0;
218 x->verbose = 0;
219 x->xstat = stat;
223 main (int argc, char **argv)
225 int optc;
226 int errors = 0;
227 const char *symbolic_mode = NULL;
228 int make_backups = 0;
229 const char *version;
230 int mkdir_and_install = 0;
231 struct cp_options x;
232 int n_files;
233 char **file;
235 program_name = argv[0];
236 setlocale (LC_ALL, "");
237 bindtextdomain (PACKAGE, LOCALEDIR);
238 textdomain (PACKAGE);
240 cp_option_init (&x);
242 owner_name = NULL;
243 group_name = NULL;
244 strip_files = 0;
245 dir_arg = 0;
246 umask (0);
248 /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
249 we'll actually use simple_backup_suffix. */
250 version = getenv ("SIMPLE_BACKUP_SUFFIX");
251 if (version)
252 simple_backup_suffix = version;
253 version = NULL;
255 while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pvV:S:", long_options,
256 NULL)) != -1)
258 switch (optc)
260 case 0:
261 break;
262 case 'b':
263 make_backups = 1;
264 break;
265 case 'c':
266 break;
267 case 's':
268 strip_files = 1;
269 break;
270 case 'd':
271 dir_arg = 1;
272 break;
273 case 'D':
274 mkdir_and_install = 1;
275 break;
276 case 'v':
277 x.verbose = 1;
278 break;
279 case 'g':
280 group_name = optarg;
281 break;
282 case 'm':
283 symbolic_mode = optarg;
284 break;
285 case 'o':
286 owner_name = optarg;
287 break;
288 case 'p':
289 x.preserve_timestamps = 1;
290 break;
291 case 'S':
292 simple_backup_suffix = optarg;
293 break;
294 case 'V':
295 version = optarg;
296 break;
297 case_GETOPT_HELP_CHAR;
298 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
299 default:
300 usage (1);
304 /* Check for invalid combinations of arguments. */
305 if (dir_arg && strip_files)
306 error (1, 0,
307 _("the strip option may not be used when installing a directory"));
309 if (make_backups)
310 x.backup_type = xget_version ("--version-control", version);
312 n_files = argc - optind;
313 file = argv + optind;
315 if (n_files == 0 || (n_files == 1 && !dir_arg))
317 error (0, 0, _("too few arguments"));
318 usage (1);
321 if (symbolic_mode)
323 struct mode_change *change = mode_compile (symbolic_mode, 0);
324 if (change == MODE_INVALID)
325 error (1, 0, _("invalid mode `%s'"), symbolic_mode);
326 else if (change == MODE_MEMORY_EXHAUSTED)
327 error (1, 0, _("virtual memory exhausted"));
328 mode = mode_adjust (0, change);
331 get_ids ();
333 if (dir_arg)
335 int i;
336 for (i = 0; i < n_files; i++)
338 errors |=
339 make_path (file[i], mode, mode, owner_id, group_id, 0,
340 (x.verbose ? "creating directory `%s'" : NULL));
343 else
345 /* FIXME: it's a little gross that this initialization is
346 required by copy.c::copy. */
347 hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE);
349 if (n_files == 2)
351 if (mkdir_and_install)
352 errors = install_file_to_path (file[0], file[1], &x);
353 else if (!isdir (file[1]))
354 errors = install_file_in_file (file[0], file[1], &x);
355 else
356 errors = install_file_in_dir (file[0], file[1], &x);
358 else
360 int i;
361 const char *dest = file[n_files - 1];
362 if (!isdir (dest))
364 error (0, 0,
365 _("installing multiple files, but last argument (%s) \
366 is not a directory"),
367 dest);
368 usage (1);
370 for (i = 0; i < n_files - 1; i++)
372 errors |= install_file_in_dir (file[i], dest, &x);
377 if (x.verbose)
378 close_stdout ();
379 exit (errors);
382 /* Copy file FROM onto file TO, creating any missing parent directories of TO.
383 Return 0 if successful, 1 if an error occurs */
385 static int
386 install_file_to_path (const char *from, const char *to,
387 const struct cp_options *x)
389 char *dest_dir;
390 int fail;
392 dest_dir = dir_name (to);
394 /* check to make sure this is a path (not install a b ) */
395 if (!STREQ (dest_dir, ".")
396 && !isdir (dest_dir))
398 /* Someone will probably ask for a new option or three to specify
399 owner, group, and permissions for parent directories. Remember
400 that this option is intended mainly to help installers when the
401 distribution doesn't provide proper install rules. */
402 #define DIR_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
403 fail = make_path (dest_dir, DIR_MODE, DIR_MODE, owner_id, group_id, 0,
404 (x->verbose ? _("creating directory `%s'") : NULL));
406 if (fail == 0)
407 fail = install_file_in_dir (from, dest_dir, x);
409 else
411 fail = install_file_in_file (from, to, x);
414 free (dest_dir);
416 return fail;
419 /* Copy file FROM onto file TO and give TO the appropriate
420 attributes.
421 Return 0 if successful, 1 if an error occurs. */
423 static int
424 install_file_in_file (const char *from, const char *to,
425 const struct cp_options *x)
427 if (copy_file (from, to, x))
428 return 1;
429 if (strip_files)
430 strip (to);
431 if (change_attributes (to))
432 return 1;
433 if (x->preserve_timestamps)
434 return change_timestamps (from, to);
435 return 0;
438 /* Copy file FROM into directory TO_DIR, keeping its same name,
439 and give the copy the appropriate attributes.
440 Return 0 if successful, 1 if not. */
442 static int
443 install_file_in_dir (const char *from, const char *to_dir,
444 const struct cp_options *x)
446 const char *from_base;
447 char *to;
448 int ret;
450 from_base = base_name (from);
451 to = path_concat (to_dir, from_base, NULL);
452 ret = install_file_in_file (from, to, x);
453 free (to);
454 return ret;
457 /* Copy file FROM onto file TO, creating TO if necessary.
458 Return 0 if the copy is successful, 1 if not. */
460 static int
461 copy_file (const char *from, const char *to, const struct cp_options *x)
463 int fail;
464 int nonexistent_dst = 0;
465 int copy_into_self;
467 /* Allow installing from non-regular files like /dev/null.
468 Charles Karney reported that some Sun version of install allows that
469 and that sendmail's installation process relies on the behavior. */
470 if (isdir (from))
472 error (0, 0, _("`%s' is a directory"), from);
473 return 1;
476 fail = copy (from, to, nonexistent_dst, x, &copy_into_self, NULL);
478 return fail;
481 /* Set the attributes of file or directory PATH.
482 Return 0 if successful, 1 if not. */
484 static int
485 change_attributes (const char *path)
487 int err = 0;
489 /* chown must precede chmod because on some systems,
490 chown clears the set[ug]id bits for non-superusers,
491 resulting in incorrect permissions.
492 On System V, users can give away files with chown and then not
493 be able to chmod them. So don't give files away.
495 We don't normally ignore errors from chown because the idea of
496 the install command is that the file is supposed to end up with
497 precisely the attributes that the user specified (or defaulted).
498 If the file doesn't end up with the group they asked for, they'll
499 want to know. But AFS returns EPERM when you try to change a
500 file's group; thus the kludge. */
502 if (chown (path, owner_id, group_id)
503 #ifdef AFS
504 && errno != EPERM
505 #endif
507 err = errno;
508 if (chmod (path, mode))
509 err = errno;
510 if (err)
512 error (0, err, "%s", path);
513 return 1;
515 return 0;
518 /* Set the timestamps of file TO to match those of file FROM.
519 Return 0 if successful, 1 if not. */
521 static int
522 change_timestamps (const char *from, const char *to)
524 struct stat stb;
525 struct utimbuf utb;
527 if (stat (from, &stb))
529 error (0, errno, "%s", from);
530 return 1;
533 /* There's currently no interface to set file timestamps with
534 better than 1-second resolution, so discard any fractional
535 part of the source timestamp. */
537 utb.actime = stb.st_atime;
538 utb.modtime = stb.st_mtime;
539 if (utime (to, &utb))
541 error (0, errno, "%s", to);
542 return 1;
544 return 0;
547 /* Strip the symbol table from the file PATH.
548 We could dig the magic number out of the file first to
549 determine whether to strip it, but the header files and
550 magic numbers vary so much from system to system that making
551 it portable would be very difficult. Not worth the effort. */
553 static void
554 strip (const char *path)
556 int status;
557 pid_t pid = fork ();
559 switch (pid)
561 case -1:
562 error (1, errno, _("cannot fork"));
563 break;
564 case 0: /* Child. */
565 execlp ("strip", "strip", path, NULL);
566 error (1, errno, _("cannot run strip"));
567 break;
568 default: /* Parent. */
569 /* Parent process. */
570 while (pid != wait (&status)) /* Wait for kid to finish. */
571 /* Do nothing. */ ;
572 if (status)
573 error (1, 0, _("strip failed"));
574 break;
578 /* Initialize the user and group ownership of the files to install. */
580 static void
581 get_ids (void)
583 struct passwd *pw;
584 struct group *gr;
586 if (owner_name)
588 pw = getpwnam (owner_name);
589 if (pw == NULL)
591 long int tmp_long;
592 if (xstrtol (owner_name, NULL, 0, &tmp_long, NULL) != LONGINT_OK
593 || tmp_long < 0 || tmp_long > UID_T_MAX)
594 error (1, 0, _("invalid user `%s'"), owner_name);
595 owner_id = (uid_t) tmp_long;
597 else
598 owner_id = pw->pw_uid;
599 endpwent ();
601 else
602 owner_id = (uid_t) -1;
604 if (group_name)
606 gr = getgrnam (group_name);
607 if (gr == NULL)
609 long int tmp_long;
610 if (xstrtol (group_name, NULL, 0, &tmp_long, NULL) != LONGINT_OK
611 || tmp_long < 0 || tmp_long > GID_T_MAX)
612 error (1, 0, _("invalid group `%s'"), group_name);
613 group_id = (gid_t) tmp_long;
615 else
616 group_id = gr->gr_gid;
617 endgrent ();
619 else
620 group_id = (gid_t) -1;
623 void
624 usage (int status)
626 if (status != 0)
627 fprintf (stderr, _("Try `%s --help' for more information.\n"),
628 program_name);
629 else
631 printf (_("\
632 Usage: %s [OPTION]... SOURCE DEST (1st format)\n\
633 or: %s [OPTION]... SOURCE... DIRECTORY (2nd format)\n\
634 or: %s -d [OPTION]... DIRECTORY... (3rd format)\n\
636 program_name, program_name, program_name);
637 printf (_("\
638 In the first two formats, copy SOURCE to DEST or multiple SOURCE(s) to\n\
639 the existing DIRECTORY, while setting permission modes and owner/group.\n\
640 In the third format, create all components of the given DIRECTORY(ies).\n\
642 -b, --backup make backup before removal\n\
643 -c (ignored)\n\
644 -d, --directory treat all arguments as directory names; create all\n\
645 components of the specified directories\n\
646 -D create all leading components of DEST except the last,\n\
647 then copy SOURCE to DEST; useful in the 1st format\n\
648 -g, --group=GROUP set group ownership, instead of process' current group\n\
649 -m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\
650 -o, --owner=OWNER set ownership (super-user only)\n\
651 -p, --preserve-timestamps apply access/modification times of SOURCE files\n\
652 to corresponding destination files\n\
653 -s, --strip strip symbol tables, only for 1st and 2nd formats\n\
654 -S, --suffix=SUFFIX override the usual backup suffix\n\
655 --verbose print the name of each directory as it is created\n\
656 -V, --version-control=WORD override the usual version control\n\
657 --help display this help and exit\n\
658 --version output version information and exit\n\
660 "));
661 printf (_("\
662 The backup suffix is ~, unless set with SIMPLE_BACKUP_SUFFIX. The\n\
663 version control may be set with VERSION_CONTROL, values are:\n\
665 none, off never make backups (even if --backup is given)\n\
666 numbered, t make numbered backups\n\
667 existing, nil numbered if numbered backups exist, simple otherwise\n\
668 simple, never always make simple backups\n\
669 "));
670 puts (_("\nReport bugs to <bug-fileutils@gnu.org>."));
671 close_stdout ();
673 exit (status);