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)
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.
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.
32 Set the permission mode for the installed file or directory
33 to MODE, which is an octal number (default is 0755).
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
40 -c No effect. For compatibility with old Unix versions of install.
43 Strip the symbol tables from installed files.
45 -p, --preserve-timestamps
46 Retain creation and modification timestamps when installing files.
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> */
70 #include <sys/types.h>
75 #include "backupfile.h"
76 #include "modechange.h"
83 # include <sys/wait.h>
90 struct passwd
*getpwnam ();
91 struct group
*getgrnam ();
93 #ifndef _POSIX_VERSION
99 # define endgrent() ((void) 0)
102 #ifndef HAVE_ENDPWENT
103 # define endpwent() ((void) 0)
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)
113 # define UID_T_MAX TYPE_MAXIMUM (uid_t)
117 # define GID_T_MAX TYPE_MAXIMUM (gid_t)
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
,
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. */
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
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. */
168 /* If nonzero, show what we are doing. */
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},
194 main (int argc
, char **argv
)
198 char *symbolic_mode
= NULL
;
199 int make_backups
= 0;
201 int mkdir_and_install
= 0;
203 program_name
= argv
[0];
204 setlocale (LC_ALL
, "");
205 bindtextdomain (PACKAGE
, LOCALEDIR
);
206 textdomain (PACKAGE
);
212 preserve_timestamps
= 0;
217 version
= getenv ("SIMPLE_BACKUP_SUFFIX");
219 simple_backup_suffix
= version
;
220 version
= getenv ("VERSION_CONTROL");
222 while ((optc
= getopt_long (argc
, argv
, "bcsDdg:m:o:pvV:S:", long_options
,
241 mkdir_and_install
= 1;
250 symbolic_mode
= optarg
;
256 preserve_timestamps
= 1;
259 simple_backup_suffix
= optarg
;
271 printf ("install (%s) %s\n", GNU_PACKAGE
, VERSION
);
279 /* Check for invalid combinations of arguments. */
280 if (dir_arg
&& strip_files
)
282 _("the strip option may not be used when installing a directory"));
285 backup_type
= get_version (version
);
287 if (optind
== argc
|| (optind
== argc
- 1 && !dir_arg
))
289 error (0, 0, _("too few arguments"));
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
);
307 for (; optind
< argc
; ++optind
)
310 make_path (argv
[optind
], mode
, mode
, owner_id
, group_id
, 0,
311 (verbose
? "creating directory `%s'" : NULL
));
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]);
323 errors
= install_file_in_dir (argv
[argc
- 2], argv
[argc
- 1]);
327 if (!isdir (argv
[argc
- 1]))
329 for (; optind
< argc
- 1; ++optind
)
331 errors
|= install_file_in_dir (argv
[optind
], argv
[argc
- 1]);
341 /* Copy file FROM onto file TO, creating any missing parent directories of TO.
342 Return 0 if successful, 1 if an error occurs */
345 install_file_to_path (const char *from
, const char *to
)
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
));
368 fail
= install_file_in_file (from
, to
);
376 /* Copy file FROM onto file TO and give TO the appropriate
378 Return 0 if successful, 1 if an error occurs. */
381 install_file_in_file (const char *from
, const char *to
)
384 int no_need_to_chown
;
386 if (copy_file (from
, to
, &to_created
))
390 no_need_to_chown
= (to_created
391 && owner_name
== NULL
392 && group_name
== NULL
);
393 if (change_attributes (to
, no_need_to_chown
))
395 if (preserve_timestamps
)
396 return change_timestamps (from
, to
);
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. */
405 install_file_in_dir (const char *from
, const char *to_dir
)
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
);
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. */
429 copy_file (const char *from
, const char *to
, int *to_created
)
434 struct stat from_stats
, to_stats
;
435 int target_created
= 1;
437 if (stat (from
, &from_stats
))
439 error (0, errno
, "%s", from
);
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
);
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
);
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
);
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
);
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
);
476 if (rename (to
, dst_backup
))
480 error (0, errno
, "cannot backup `%s'", to
);
486 /* If unlink fails, try to proceed anyway. */
491 /* Now it's the time to give some feedback if requested. */
493 printf ("copying `%s' to `%s'\n", from
, to
);
495 fromfd
= open (from
, O_RDONLY
, 0);
498 error (0, errno
, "%s", from
);
502 /* Make sure to open the file in a mode that allows writing. */
503 tofd
= open (to
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
506 error (0, errno
, "%s", to
);
511 while ((bytes
= safe_read (fromfd
, buffer
, READ_SIZE
)) > 0)
512 if (full_write (tofd
, buffer
, bytes
) < 0)
514 error (0, errno
, "%s", to
);
520 error (0, errno
, "%s", from
);
524 if (close (fromfd
) < 0)
526 error (0, errno
, "%s", from
);
529 if (close (tofd
) < 0)
531 error (0, errno
, "%s", to
);
535 *to_created
= target_created
;
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. */
549 change_attributes (const char *path
, int no_need_to_chown
)
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
)
575 if (chmod (path
, mode
))
579 error (0, err
, "%s", path
);
585 /* Set the timestamps of file TO to match those of file FROM.
586 Return 0 if successful, 1 if not. */
589 change_timestamps (const char *from
, const char *to
)
594 if (stat (from
, &stb
))
596 error (0, errno
, "%s", from
);
599 utb
.actime
= stb
.st_atime
;
600 utb
.modtime
= stb
.st_mtime
;
601 if (utime (to
, &utb
))
603 error (0, errno
, "%s", to
);
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. */
616 strip (const char *path
)
624 error (1, errno
, _("fork system call failed"));
627 execlp ("strip", "strip", path
, NULL
);
628 error (1, errno
, _("cannot run strip"));
630 default: /* Parent. */
631 /* Parent process. */
632 while (pid
!= wait (&status
)) /* Wait for kid to finish. */
638 /* Initialize the user and group ownership of the files to install. */
648 pw
= getpwnam (owner_name
);
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
;
658 owner_id
= pw
->pw_uid
;
662 owner_id
= (uid_t
) -1;
666 gr
= getgrnam (group_name
);
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
;
676 group_id
= gr
->gr_gid
;
680 group_id
= (gid_t
) -1;
687 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
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
);
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\
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\
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\
729 puts (_("\nReport bugs to <fileutils-bugs@gnu.org>."));