.
[coreutils.git] / src / install.c
blob878d9cd60291d9ac2c7b863fe7d716b5d1e9921c
1 /* install - copy files and set attributes
2 Copyright (C) 89, 90, 91, 95, 96, 97, 1998 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 0755).
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 "modechange.h"
77 #include "makepath.h"
78 #include "closeout.h"
79 #include "error.h"
80 #include "xstrtol.h"
82 #if HAVE_SYS_WAIT_H
83 # include <sys/wait.h>
84 #endif
86 #if HAVE_VALUES_H
87 # include <values.h>
88 #endif
90 struct passwd *getpwnam ();
91 struct group *getgrnam ();
93 #ifndef _POSIX_VERSION
94 uid_t getuid ();
95 gid_t getgid ();
96 #endif
98 #ifndef HAVE_ENDGRENT
99 # define endgrent() ((void) 0)
100 #endif
102 #ifndef HAVE_ENDPWENT
103 # define endpwent() ((void) 0)
104 #endif
106 /* True if C is an ASCII octal digit. */
107 #define isodigit(c) ((c) >= '0' && c <= '7')
109 /* Number of bytes of a file to copy at a time. */
110 #define READ_SIZE (32 * 1024)
112 #ifndef UID_T_MAX
113 # define UID_T_MAX TYPE_MAXIMUM (uid_t)
114 #endif
116 #ifndef GID_T_MAX
117 # define GID_T_MAX TYPE_MAXIMUM (gid_t)
118 #endif
120 char *base_name ();
121 char *dirname ();
122 int safe_read ();
123 int full_write ();
124 int isdir ();
125 enum backup_type get_version ();
127 static int change_timestamps PARAMS ((const char *from, const char *to));
128 static int change_attributes PARAMS ((const char *path, int no_need_to_chown));
129 static int copy_file PARAMS ((const char *from, const char *to,
130 int *to_created));
131 static int install_file_to_path PARAMS ((const char *from, const char *to));
132 static int install_file_in_dir PARAMS ((const char *from, const char *to_dir));
133 static int install_file_in_file PARAMS ((const char *from, const char *to));
134 static void get_ids PARAMS ((void));
135 static void strip PARAMS ((const char *path));
136 static void usage PARAMS ((int status));
138 /* The name this program was run with, for error messages. */
139 char *program_name;
141 /* The user name that will own the files, or NULL to make the owner
142 the current user ID. */
143 static char *owner_name;
145 /* The user ID corresponding to `owner_name'. */
146 static uid_t owner_id;
148 /* The group name that will own the files, or NULL to make the group
149 the current group ID. */
150 static char *group_name;
152 /* The group ID corresponding to `group_name'. */
153 static gid_t group_id;
155 /* The permissions to which the files will be set. The umask has
156 no effect. */
157 static int mode;
159 /* If nonzero, strip executable files after copying them. */
160 static int strip_files;
162 /* If nonzero, preserve timestamps when installing files. */
163 static int preserve_timestamps;
165 /* If nonzero, install a directory instead of a regular file. */
166 static int dir_arg;
168 /* If nonzero, show what we are doing. */
169 static int verbose;
171 /* If nonzero, display usage information and exit. */
172 static int show_help;
174 /* If nonzero, print the version on standard output and exit. */
175 static int show_version;
177 static struct option const long_options[] =
179 {"strip", no_argument, NULL, 's'},
180 {"directory", no_argument, NULL, 'd'},
181 {"group", required_argument, NULL, 'g'},
182 {"mode", required_argument, NULL, 'm'},
183 {"owner", required_argument, NULL, 'o'},
184 {"preserve-timestamps", no_argument, NULL, 'p'},
185 {"backup", no_argument, NULL, 'b'},
186 {"version-control", required_argument, NULL, 'V'},
187 {"verbose", no_argument, NULL, 'v'},
188 {"help", no_argument, &show_help, 1},
189 {"version", no_argument, &show_version, 1},
190 {NULL, 0, NULL, 0}
194 main (int argc, char **argv)
196 int optc;
197 int errors = 0;
198 char *symbolic_mode = NULL;
199 int make_backups = 0;
200 char *version;
201 int mkdir_and_install = 0;
203 program_name = argv[0];
204 setlocale (LC_ALL, "");
205 bindtextdomain (PACKAGE, LOCALEDIR);
206 textdomain (PACKAGE);
208 owner_name = NULL;
209 group_name = NULL;
210 mode = 0755;
211 strip_files = 0;
212 preserve_timestamps = 0;
213 dir_arg = 0;
214 verbose = 0;
215 umask (0);
217 version = getenv ("SIMPLE_BACKUP_SUFFIX");
218 if (version)
219 simple_backup_suffix = version;
220 version = getenv ("VERSION_CONTROL");
222 while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pvV:S:", long_options,
223 NULL)) != -1)
225 switch (optc)
227 case 0:
228 break;
229 case 'b':
230 make_backups = 1;
231 break;
232 case 'c':
233 break;
234 case 's':
235 strip_files = 1;
236 break;
237 case 'd':
238 dir_arg = 1;
239 break;
240 case 'D':
241 mkdir_and_install = 1;
242 break;
243 case 'v':
244 verbose = 1;
245 break;
246 case 'g':
247 group_name = optarg;
248 break;
249 case 'm':
250 symbolic_mode = optarg;
251 break;
252 case 'o':
253 owner_name = optarg;
254 break;
255 case 'p':
256 preserve_timestamps = 1;
257 break;
258 case 'S':
259 simple_backup_suffix = optarg;
260 break;
261 case 'V':
262 version = optarg;
263 break;
264 default:
265 usage (1);
269 if (show_version)
271 printf ("install (%s) %s\n", GNU_PACKAGE, VERSION);
272 close_stdout ();
273 exit (0);
276 if (show_help)
277 usage (0);
279 /* Check for invalid combinations of arguments. */
280 if (dir_arg && strip_files)
281 error (1, 0,
282 _("the strip option may not be used when installing a directory"));
284 if (make_backups)
285 backup_type = get_version (version);
287 if (optind == argc || (optind == argc - 1 && !dir_arg))
289 error (0, 0, _("too few arguments"));
290 usage (1);
293 if (symbolic_mode)
295 struct mode_change *change = mode_compile (symbolic_mode, 0);
296 if (change == MODE_INVALID)
297 error (1, 0, _("invalid mode `%s'"), symbolic_mode);
298 else if (change == MODE_MEMORY_EXHAUSTED)
299 error (1, 0, _("virtual memory exhausted"));
300 mode = mode_adjust (0, change);
303 get_ids ();
305 if (dir_arg)
307 for (; optind < argc; ++optind)
309 errors |=
310 make_path (argv[optind], mode, mode, owner_id, group_id, 0,
311 (verbose ? "creating directory `%s'" : NULL));
314 else
316 if (optind == argc - 2)
318 if (mkdir_and_install)
319 errors = install_file_to_path (argv[argc - 2], argv[argc - 1]);
320 else if (!isdir (argv[argc - 1]))
321 errors = install_file_in_file (argv[argc - 2], argv[argc - 1]);
322 else
323 errors = install_file_in_dir (argv[argc - 2], argv[argc - 1]);
325 else
327 if (!isdir (argv[argc - 1]))
328 usage (1);
329 for (; optind < argc - 1; ++optind)
331 errors |= install_file_in_dir (argv[optind], argv[argc - 1]);
336 if (verbose)
337 close_stdout ();
338 exit (errors);
341 /* Copy file FROM onto file TO, creating any missing parent directories of TO.
342 Return 0 if successful, 1 if an error occurs */
344 static int
345 install_file_to_path (const char *from, const char *to)
347 char *dest_dir;
348 int fail;
350 dest_dir = dirname (to);
352 /* check to make sure this is a path (not install a b ) */
353 if (!STREQ (dest_dir, ".")
354 && !isdir (dest_dir))
356 /* FIXME: Note that it's a little kludgey (even dangerous) that we
357 derive the permissions for parent directories from the permissions
358 specfied for the file, but since this option is intended mainly to
359 help installers when the distribution doesn't provide proper install
360 rules, it's not so bad. Maybe use something like this instead:
361 int parent_dir_mode = (mode | (S_IRUGO | S_IXUGO)) & (~SPECIAL_BITS);
363 fail = make_path (dest_dir, mode, mode, owner_id, group_id, 0,
364 (verbose ? _("creating directory `%s'") : NULL));
366 else
368 fail = install_file_in_file (from, to);
371 free (dest_dir);
373 return fail;
376 /* Copy file FROM onto file TO and give TO the appropriate
377 attributes.
378 Return 0 if successful, 1 if an error occurs. */
380 static int
381 install_file_in_file (const char *from, const char *to)
383 int to_created;
384 int no_need_to_chown;
386 if (copy_file (from, to, &to_created))
387 return 1;
388 if (strip_files)
389 strip (to);
390 no_need_to_chown = (to_created
391 && owner_name == NULL
392 && group_name == NULL);
393 if (change_attributes (to, no_need_to_chown))
394 return 1;
395 if (preserve_timestamps)
396 return change_timestamps (from, to);
397 return 0;
400 /* Copy file FROM into directory TO_DIR, keeping its same name,
401 and give the copy the appropriate attributes.
402 Return 0 if successful, 1 if not. */
404 static int
405 install_file_in_dir (const char *from, const char *to_dir)
407 char *from_base;
408 char *to;
409 int ret;
411 from_base = base_name (from);
412 to = xmalloc ((unsigned) (strlen (to_dir) + strlen (from_base) + 2));
413 stpcpy (stpcpy (stpcpy (to, to_dir), "/"), from_base);
414 ret = install_file_in_file (from, to);
415 free (to);
416 return ret;
419 /* A chunk of a file being copied. */
420 static char buffer[READ_SIZE];
422 /* Copy file FROM onto file TO, creating TO if necessary.
423 Return 0 if the copy is successful, 1 if not. If the copy is
424 successful, set *TO_CREATED to nonzero if TO was created (if it did
425 not exist or did, but was unlinked) and to zero otherwise. If the
426 copy fails, don't modify *TO_CREATED. */
428 static int
429 copy_file (const char *from, const char *to, int *to_created)
431 int fromfd, tofd;
432 int bytes;
433 int ret = 0;
434 struct stat from_stats, to_stats;
435 int target_created = 1;
437 if (stat (from, &from_stats))
439 error (0, errno, "%s", from);
440 return 1;
443 /* Allow installing from non-regular files like /dev/null.
444 Charles Karney reported that some Sun version of install allows that
445 and that sendmail's installation process relies on the behavior. */
446 if (S_ISDIR (from_stats.st_mode))
448 error (0, 0, _("`%s' is a directory"), from);
449 return 1;
451 if (stat (to, &to_stats) == 0)
453 if (!S_ISREG (to_stats.st_mode))
455 error (0, 0, _("`%s' is not a regular file"), to);
456 return 1;
458 if (from_stats.st_dev == to_stats.st_dev
459 && from_stats.st_ino == to_stats.st_ino)
461 error (0, 0, _("`%s' and `%s' are the same file"), from, to);
462 return 1;
465 /* The destination file exists. Try to back it up if required. */
466 if (backup_type != none)
468 char *tmp_backup = find_backup_file_name (to);
469 char *dst_backup;
471 if (tmp_backup == NULL)
472 error (1, 0, "virtual memory exhausted");
473 dst_backup = (char *) alloca (strlen (tmp_backup) + 1);
474 strcpy (dst_backup, tmp_backup);
475 free (tmp_backup);
476 if (rename (to, dst_backup))
478 if (errno != ENOENT)
480 error (0, errno, "cannot backup `%s'", to);
481 return 1;
486 /* If unlink fails, try to proceed anyway. */
487 if (unlink (to))
488 target_created = 0;
491 /* Now it's the time to give some feedback if requested. */
492 if (verbose)
493 printf ("copying `%s' to `%s'\n", from, to);
495 fromfd = open (from, O_RDONLY, 0);
496 if (fromfd == -1)
498 error (0, errno, "%s", from);
499 return 1;
502 /* Make sure to open the file in a mode that allows writing. */
503 tofd = open (to, O_WRONLY | O_CREAT | O_TRUNC, 0600);
504 if (tofd == -1)
506 error (0, errno, "%s", to);
507 close (fromfd);
508 return 1;
511 while ((bytes = safe_read (fromfd, buffer, READ_SIZE)) > 0)
512 if (full_write (tofd, buffer, bytes) < 0)
514 error (0, errno, "%s", to);
515 goto copy_error;
518 if (bytes == -1)
520 error (0, errno, "%s", from);
521 goto copy_error;
524 if (close (fromfd) < 0)
526 error (0, errno, "%s", from);
527 ret = 1;
529 if (close (tofd) < 0)
531 error (0, errno, "%s", to);
532 ret = 1;
534 if (ret == 0)
535 *to_created = target_created;
536 return ret;
538 copy_error:
539 close (fromfd);
540 close (tofd);
541 return 1;
544 /* Set the attributes of file or directory PATH.
545 If NO_NEED_TO_CHOWN is nonzero, don't call chown.
546 Return 0 if successful, 1 if not. */
548 static int
549 change_attributes (const char *path, int no_need_to_chown)
551 int err = 0;
553 /* chown must precede chmod because on some systems,
554 chown clears the set[ug]id bits for non-superusers,
555 resulting in incorrect permissions.
556 On System V, users can give away files with chown and then not
557 be able to chmod them. So don't give files away.
559 We don't pass -1 to chown to mean "don't change the value"
560 because SVR3 and earlier non-BSD systems don't support that.
562 We don't normally ignore errors from chown because the idea of
563 the install command is that the file is supposed to end up with
564 precisely the attributes that the user specified (or defaulted).
565 If the file doesn't end up with the group they asked for, they'll
566 want to know. But AFS returns EPERM when you try to change a
567 file's group; thus the kludge. */
569 if (!no_need_to_chown && chown (path, owner_id, group_id)
570 #ifdef AFS
571 && errno != EPERM
572 #endif
574 err = errno;
575 if (chmod (path, mode))
576 err = errno;
577 if (err)
579 error (0, err, "%s", path);
580 return 1;
582 return 0;
585 /* Set the timestamps of file TO to match those of file FROM.
586 Return 0 if successful, 1 if not. */
588 static int
589 change_timestamps (const char *from, const char *to)
591 struct stat stb;
592 struct utimbuf utb;
594 if (stat (from, &stb))
596 error (0, errno, "%s", from);
597 return 1;
599 utb.actime = stb.st_atime;
600 utb.modtime = stb.st_mtime;
601 if (utime (to, &utb))
603 error (0, errno, "%s", to);
604 return 1;
606 return 0;
609 /* Strip the symbol table from the file PATH.
610 We could dig the magic number out of the file first to
611 determine whether to strip it, but the header files and
612 magic numbers vary so much from system to system that making
613 it portable would be very difficult. Not worth the effort. */
615 static void
616 strip (const char *path)
618 int pid, status;
620 pid = fork ();
621 switch (pid)
623 case -1:
624 error (1, errno, _("fork system call failed"));
625 break;
626 case 0: /* Child. */
627 execlp ("strip", "strip", path, NULL);
628 error (1, errno, _("cannot run strip"));
629 break;
630 default: /* Parent. */
631 /* Parent process. */
632 while (pid != wait (&status)) /* Wait for kid to finish. */
633 /* Do nothing. */ ;
634 break;
638 /* Initialize the user and group ownership of the files to install. */
640 static void
641 get_ids (void)
643 struct passwd *pw;
644 struct group *gr;
646 if (owner_name)
648 pw = getpwnam (owner_name);
649 if (pw == NULL)
651 long int tmp_long;
652 if (xstrtol (owner_name, NULL, 0, &tmp_long, NULL) != LONGINT_OK
653 || tmp_long < 0 || tmp_long > UID_T_MAX)
654 error (1, 0, _("invalid user `%s'"), owner_name);
655 owner_id = (uid_t) tmp_long;
657 else
658 owner_id = pw->pw_uid;
659 endpwent ();
661 else
662 owner_id = (uid_t) -1;
664 if (group_name)
666 gr = getgrnam (group_name);
667 if (gr == NULL)
669 long int tmp_long;
670 if (xstrtol (group_name, NULL, 0, &tmp_long, NULL) != LONGINT_OK
671 || tmp_long < 0 || tmp_long > GID_T_MAX)
672 error (1, 0, _("invalid group `%s'"), group_name);
673 group_id = (gid_t) tmp_long;
675 else
676 group_id = gr->gr_gid;
677 endgrent ();
679 else
680 group_id = (gid_t) -1;
683 static void
684 usage (int status)
686 if (status != 0)
687 fprintf (stderr, _("Try `%s --help' for more information.\n"),
688 program_name);
689 else
691 printf (_("\
692 Usage: %s [OPTION]... SOURCE DEST (1st format)\n\
693 or: %s [OPTION]... SOURCE... DIRECTORY (2nd format)\n\
694 or: %s -d [OPTION]... DIRECTORY... (3rd format)\n\
696 program_name, program_name, program_name);
697 printf (_("\
698 In the first two formats, copy SOURCE to DEST or multiple SOURCE(s) to\n\
699 the existing DIRECTORY, while setting permission modes and owner/group.\n\
700 In the third format, create all components of the given DIRECTORY(ies).\n\
702 -b, --backup make backup before removal\n\
703 -c (ignored)\n\
704 -d, --directory treat all arguments as directory names; create all\n\
705 components of the specified directories\n\
706 -D create all leading components of DEST except the last,\n\
707 then copy SOURCE to DEST; useful in the 1st format\n\
708 -g, --group=GROUP set group ownership, instead of process' current group\n\
709 -m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\
710 -o, --owner=OWNER set ownership (super-user only)\n\
711 -p, --preserve-timestamps apply access/modification times of SOURCE files\n\
712 to corresponding destination files\n\
713 -s, --strip strip symbol tables, only for 1st and 2nd formats\n\
714 -S, --suffix=SUFFIX override the usual backup suffix\n\
715 --verbose print the name of each directory as it is created\n\
716 -V, --version-control=WORD override the usual version control\n\
717 --help display this help and exit\n\
718 --version output version information and exit\n\
720 "));
721 printf (_("\
722 The backup suffix is ~, unless set with SIMPLE_BACKUP_SUFFIX. The\n\
723 version control may be set with VERSION_CONTROL, values are:\n\
725 t, numbered make numbered backups\n\
726 nil, existing numbered if numbered backups exist, simple otherwise\n\
727 never, simple always make simple backups\n\
728 "));
729 puts (_("\nReport bugs to <fileutils-bugs@gnu.org>."));
730 close_stdout ();
732 exit (status);