update copyrights for 1997
[platform/upstream/coreutils.git] / src / install.c
1 /* install - copy files and set attributes
2    Copyright (C) 89, 90, 91, 95, 96, 1997 Free Software Foundation, Inc.
3
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.
8
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.
13
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.  */
17
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.
24
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.
30
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).
34
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.
39
40    -c   No effect.  For compatibility with old Unix versions of install.
41
42    -s, --strip
43         Strip the symbol tables from installed files.
44
45    -d, --directory
46         Create a directory and its leading directories, if they
47         do not already exist.  Set the owner, group and mode
48         as given on the command line.  Any leading directories
49         that are created are also given those attributes.
50         This is different from the SunOS 4.0 install, which gives
51         directories that it creates the default attributes.
52
53    David MacKenzie <djm@gnu.ai.mit.edu> */
54
55 #ifdef _AIX
56  #pragma alloca
57 #endif
58
59 #include <config.h>
60 #include <stdio.h>
61 #include <getopt.h>
62 #include <sys/types.h>
63 #include <pwd.h>
64 #include <grp.h>
65
66 #include "system.h"
67 #include "backupfile.h"
68 #include "modechange.h"
69 #include "makepath.h"
70 #include "error.h"
71 #include "xstrtol.h"
72
73 #if HAVE_SYS_WAIT_H
74 # include <sys/wait.h>
75 #endif
76
77 #if HAVE_VALUES_H
78 # include <values.h>
79 #endif
80
81 #ifndef BITSPERBYTE
82 # define BITSPERBYTE 8
83 #endif
84
85 struct passwd *getpwnam ();
86 struct group *getgrnam ();
87
88 #ifndef _POSIX_VERSION
89 uid_t getuid ();
90 gid_t getgid ();
91 #endif
92
93 #ifndef HAVE_ENDGRENT
94 # define endgrent() ((void) 0)
95 #endif
96
97 #ifndef HAVE_ENDPWENT
98 # define endpwent() ((void) 0)
99 #endif
100
101 /* True if C is an ASCII octal digit. */
102 #define isodigit(c) ((c) >= '0' && c <= '7')
103
104 /* Number of bytes of a file to copy at a time. */
105 #define READ_SIZE (32 * 1024)
106
107 #ifndef UID_T_MAX
108 # define UID_T_MAX ((uid_t)(~((unsigned long)1 << ((sizeof (uid_t) \
109                                                     * BITSPERBYTE - 1)))))
110 #endif
111
112 #ifndef GID_T_MAX
113 # define GID_T_MAX ((gid_t)(~((unsigned long)1 << ((sizeof (gid_t) \
114                                                     * BITSPERBYTE - 1)))))
115 #endif
116
117 char *basename ();
118 char *stpcpy ();
119 char *xmalloc ();
120 int safe_read ();
121 int full_write ();
122 int isdir ();
123 enum backup_type get_version ();
124
125 static int change_attributes __P ((char *path, int no_need_to_chown));
126 static int copy_file __P ((char *from, char *to, int *to_created));
127 static int install_file_in_dir __P ((char *from, char *to_dir));
128 static int install_file_in_file __P ((char *from, char *to));
129 static void get_ids __P ((void));
130 static void strip __P ((char *path));
131 static void usage __P ((int status));
132
133 /* The name this program was run with, for error messages. */
134 char *program_name;
135
136 /* The user name that will own the files, or NULL to make the owner
137    the current user ID. */
138 static char *owner_name;
139
140 /* The user ID corresponding to `owner_name'. */
141 static uid_t owner_id;
142
143 /* The group name that will own the files, or NULL to make the group
144    the current group ID. */
145 static char *group_name;
146
147 /* The group ID corresponding to `group_name'. */
148 static gid_t group_id;
149
150 /* The permissions to which the files will be set.  The umask has
151    no effect. */
152 static int mode;
153
154 /* If nonzero, strip executable files after copying them. */
155 static int strip_files;
156
157 /* If nonzero, install a directory instead of a regular file. */
158 static int dir_arg;
159
160 /* If nonzero, display usage information and exit.  */
161 static int show_help;
162
163 /* If nonzero, print the version on standard output and exit.  */
164 static int show_version;
165
166 static struct option const long_options[] =
167 {
168   {"strip", no_argument, NULL, 's'},
169   {"directory", no_argument, NULL, 'd'},
170   {"group", required_argument, NULL, 'g'},
171   {"mode", required_argument, NULL, 'm'},
172   {"owner", required_argument, NULL, 'o'},
173   {"backup", no_argument, NULL, 'b'},
174   {"version-control", required_argument, NULL, 'V'},
175   {"help", no_argument, &show_help, 1},
176   {"version", no_argument, &show_version, 1},
177   {NULL, 0, NULL, 0}
178 };
179
180 int
181 main (int argc, char **argv)
182 {
183   int optc;
184   int errors = 0;
185   char *symbolic_mode = NULL;
186   int make_backups = 0;
187   char *version;
188
189   program_name = argv[0];
190   setlocale (LC_ALL, "");
191   bindtextdomain (PACKAGE, LOCALEDIR);
192   textdomain (PACKAGE);
193
194   owner_name = NULL;
195   group_name = NULL;
196   mode = 0755;
197   strip_files = 0;
198   dir_arg = 0;
199   umask (0);
200
201    version = getenv ("SIMPLE_BACKUP_SUFFIX");
202    if (version)
203       simple_backup_suffix = version;
204    version = getenv ("VERSION_CONTROL");
205
206   while ((optc = getopt_long (argc, argv, "bcsdg:m:o:V:S:", long_options,
207                               NULL)) != -1)
208     {
209       switch (optc)
210         {
211         case 0:
212           break;
213         case 'b':
214           make_backups = 1;
215           break;
216         case 'c':
217           break;
218         case 's':
219           strip_files = 1;
220           break;
221         case 'd':
222           dir_arg = 1;
223           break;
224         case 'g':
225           group_name = optarg;
226           break;
227         case 'm':
228           symbolic_mode = optarg;
229           break;
230         case 'o':
231           owner_name = optarg;
232           break;
233         case 'S':
234           simple_backup_suffix = optarg;
235           break;
236         case 'V':
237           version = optarg;
238           break;
239         default:
240           usage (1);
241         }
242     }
243
244   if (show_version)
245     {
246       printf ("install (%s) %s\n", GNU_PACKAGE, VERSION);
247       exit (0);
248     }
249
250   if (show_help)
251     usage (0);
252
253   /* Check for invalid combinations of arguments. */
254   if (dir_arg && strip_files)
255     error (1, 0,
256            _("the strip option may not be used when installing a directory"));
257
258   if (make_backups)
259     backup_type = get_version (version);
260
261   if (optind == argc || (optind == argc - 1 && !dir_arg))
262     {
263       error (0, 0, _("too few arguments"));
264       usage (1);
265     }
266
267   if (symbolic_mode)
268     {
269       struct mode_change *change = mode_compile (symbolic_mode, 0);
270       if (change == MODE_INVALID)
271         error (1, 0, _("invalid mode `%s'"), symbolic_mode);
272       else if (change == MODE_MEMORY_EXHAUSTED)
273         error (1, 0, _("virtual memory exhausted"));
274       mode = mode_adjust (0, change);
275     }
276
277   get_ids ();
278
279   if (dir_arg)
280     {
281       for (; optind < argc; ++optind)
282         {
283           errors |=
284             make_path (argv[optind], mode, mode, owner_id, group_id, 0, NULL);
285         }
286     }
287   else
288     {
289       if (optind == argc - 2)
290         {
291           if (!isdir (argv[argc - 1]))
292             errors = install_file_in_file (argv[argc - 2], argv[argc - 1]);
293           else
294             errors = install_file_in_dir (argv[argc - 2], argv[argc - 1]);
295         }
296       else
297         {
298           if (!isdir (argv[argc - 1]))
299             usage (1);
300           for (; optind < argc - 1; ++optind)
301             {
302               errors |= install_file_in_dir (argv[optind], argv[argc - 1]);
303             }
304         }
305     }
306
307   exit (errors);
308 }
309
310 /* Copy file FROM onto file TO and give TO the appropriate
311    attributes.
312    Return 0 if successful, 1 if an error occurs. */
313
314 static int
315 install_file_in_file (char *from, char *to)
316 {
317   int to_created;
318   int no_need_to_chown;
319
320   if (copy_file (from, to, &to_created))
321     return 1;
322   if (strip_files)
323     strip (to);
324   no_need_to_chown = (to_created
325                       && owner_name == NULL
326                       && group_name == NULL);
327   return change_attributes (to, no_need_to_chown);
328 }
329
330 /* Copy file FROM into directory TO_DIR, keeping its same name,
331    and give the copy the appropriate attributes.
332    Return 0 if successful, 1 if not. */
333
334 static int
335 install_file_in_dir (char *from, char *to_dir)
336 {
337   char *from_base;
338   char *to;
339   int ret;
340
341   from_base = basename (from);
342   to = xmalloc ((unsigned) (strlen (to_dir) + strlen (from_base) + 2));
343   stpcpy (stpcpy (stpcpy (to, to_dir), "/"), from_base);
344   ret = install_file_in_file (from, to);
345   free (to);
346   return ret;
347 }
348
349 /* A chunk of a file being copied. */
350 static char buffer[READ_SIZE];
351
352 /* Copy file FROM onto file TO, creating TO if necessary.
353    Return 0 if the copy is successful, 1 if not.  If the copy is
354    successful, set *TO_CREATED to nonzero if TO was created (if it did
355    not exist or did, but was unlinked) and to zero otherwise.  If the
356    copy fails, don't modify *TO_CREATED.  */
357
358 static int
359 copy_file (char *from, char *to, int *to_created)
360 {
361   int fromfd, tofd;
362   int bytes;
363   int ret = 0;
364   struct stat from_stats, to_stats;
365   int target_created = 1;
366
367   if (stat (from, &from_stats))
368     {
369       error (0, errno, "%s", from);
370       return 1;
371     }
372
373   /* Allow installing from non-regular files like /dev/null.
374      Charles Karney reported that some Sun version of install allows that
375      and that sendmail's installation process relies on the behavior.  */
376   if (S_ISDIR (from_stats.st_mode))
377     {
378       error (0, 0, _("`%s' is a directory"), from);
379       return 1;
380     }
381   if (stat (to, &to_stats) == 0)
382     {
383       if (!S_ISREG (to_stats.st_mode))
384         {
385           error (0, 0, _("`%s' is not a regular file"), to);
386           return 1;
387         }
388       if (from_stats.st_dev == to_stats.st_dev
389           && from_stats.st_ino == to_stats.st_ino)
390         {
391           error (0, 0, _("`%s' and `%s' are the same file"), from, to);
392           return 1;
393         }
394
395       /* The destination file exists.  Try to back it up if required.  */
396       if (backup_type != none)
397         {
398           char *tmp_backup = find_backup_file_name (to);
399           char *dst_backup;
400
401           if (tmp_backup == NULL)
402             error (1, 0, "virtual memory exhausted");
403           dst_backup = (char *) alloca (strlen (tmp_backup) + 1);
404           strcpy (dst_backup, tmp_backup);
405           free (tmp_backup);
406           if (rename (to, dst_backup))
407             {
408               if (errno != ENOENT)
409                 {
410                   error (0, errno, "cannot backup `%s'", to);
411                   return 1;
412                 }
413             }
414         }
415
416       /* If unlink fails, try to proceed anyway.  */
417       if (unlink (to))
418         target_created = 0;
419     }
420
421   fromfd = open (from, O_RDONLY, 0);
422   if (fromfd == -1)
423     {
424       error (0, errno, "%s", from);
425       return 1;
426     }
427
428   /* Make sure to open the file in a mode that allows writing. */
429   tofd = open (to, O_WRONLY | O_CREAT | O_TRUNC, 0600);
430   if (tofd == -1)
431     {
432       error (0, errno, "%s", to);
433       close (fromfd);
434       return 1;
435     }
436
437   while ((bytes = safe_read (fromfd, buffer, READ_SIZE)) > 0)
438     if (full_write (tofd, buffer, bytes) < 0)
439       {
440         error (0, errno, "%s", to);
441         goto copy_error;
442       }
443
444   if (bytes == -1)
445     {
446       error (0, errno, "%s", from);
447       goto copy_error;
448     }
449
450   if (close (fromfd) < 0)
451     {
452       error (0, errno, "%s", from);
453       ret = 1;
454     }
455   if (close (tofd) < 0)
456     {
457       error (0, errno, "%s", to);
458       ret = 1;
459     }
460   if (ret == 0)
461     *to_created = target_created;
462   return ret;
463
464  copy_error:
465   close (fromfd);
466   close (tofd);
467   return 1;
468 }
469
470 /* Set the attributes of file or directory PATH.
471    If NO_NEED_TO_CHOWN is nonzero, don't call chown.
472    Return 0 if successful, 1 if not. */
473
474 static int
475 change_attributes (char *path, int no_need_to_chown)
476 {
477   int err = 0;
478
479   /* chown must precede chmod because on some systems,
480      chown clears the set[ug]id bits for non-superusers,
481      resulting in incorrect permissions.
482      On System V, users can give away files with chown and then not
483      be able to chmod them.  So don't give files away.
484
485      We don't pass -1 to chown to mean "don't change the value"
486      because SVR3 and earlier non-BSD systems don't support that.
487
488      We don't normally ignore errors from chown because the idea of
489      the install command is that the file is supposed to end up with
490      precisely the attributes that the user specified (or defaulted).
491      If the file doesn't end up with the group they asked for, they'll
492      want to know.  But AFS returns EPERM when you try to change a
493      file's group; thus the kludge.  */
494
495   if (!no_need_to_chown && chown (path, owner_id, group_id)
496 #ifdef AFS
497       && errno != EPERM
498 #endif
499       )
500     err = errno;
501   if (chmod (path, mode))
502     err = errno;
503   if (err)
504     {
505       error (0, err, "%s", path);
506       return 1;
507     }
508   return 0;
509 }
510
511 /* Strip the symbol table from the file PATH.
512    We could dig the magic number out of the file first to
513    determine whether to strip it, but the header files and
514    magic numbers vary so much from system to system that making
515    it portable would be very difficult.  Not worth the effort. */
516
517 static void
518 strip (char *path)
519 {
520   int pid, status;
521
522   pid = fork ();
523   switch (pid)
524     {
525     case -1:
526       error (1, errno, _("fork system call failed"));
527       break;
528     case 0:                     /* Child. */
529       execlp ("strip", "strip", path, (char *) NULL);
530       error (1, errno, _("cannot run strip"));
531       break;
532     default:                    /* Parent. */
533       /* Parent process. */
534       while (pid != wait (&status))     /* Wait for kid to finish. */
535         /* Do nothing. */ ;
536       break;
537     }
538 }
539
540 /* Initialize the user and group ownership of the files to install. */
541
542 static void
543 get_ids (void)
544 {
545   struct passwd *pw;
546   struct group *gr;
547
548   if (owner_name)
549     {
550       pw = getpwnam (owner_name);
551       if (pw == NULL)
552         {
553           long int tmp_long;
554           if (xstrtol (owner_name, NULL, 0, &tmp_long, NULL) != LONGINT_OK
555               || tmp_long < 0 || tmp_long > UID_T_MAX)
556             error (1, 0, _("invalid user `%s'"), owner_name);
557           owner_id = (uid_t) tmp_long;
558         }
559       else
560         owner_id = pw->pw_uid;
561       endpwent ();
562     }
563   else
564     owner_id = getuid ();
565
566   if (group_name)
567     {
568       gr = getgrnam (group_name);
569       if (gr == NULL)
570         {
571           long int tmp_long;
572           if (xstrtol (group_name, NULL, 0, &tmp_long, NULL) != LONGINT_OK
573               || tmp_long < 0 || tmp_long > (long) GID_T_MAX)
574             error (1, 0, _("invalid group `%s'"), group_name);
575           group_id = (gid_t) tmp_long;
576         }
577       else
578         group_id = gr->gr_gid;
579       endgrent ();
580     }
581   else
582     group_id = getgid ();
583 }
584
585 static void
586 usage (int status)
587 {
588   if (status != 0)
589     fprintf (stderr, _("Try `%s --help' for more information.\n"),
590              program_name);
591   else
592     {
593       printf (_("\
594 Usage: %s [OPTION]... SOURCE DEST           (1st format)\n\
595   or:  %s [OPTION]... SOURCE... DIRECTORY   (2nd format)\n\
596   or:  %s -d [OPTION]... DIRECTORY...       (3rd format)\n\
597 "),
598               program_name, program_name, program_name);
599       printf (_("\
600 In first two formats, copy SOURCE to DEST or multiple SOURCE(s) to\n\
601 DIRECTORY, while setting permission modes and owner/group.  In third\n\
602 format, make all components of the given DIRECTORY(ies).\n\
603 \n\
604   -b, --backup        make backup before removal\n\
605   -c                  (ignored)\n\
606   -d, --directory     create [leading] directories, mandatory for 3rd format\n\
607   -g, --group=GROUP   set group ownership, instead of process' current group\n\
608   -m, --mode=MODE     set permission mode (as in chmod), instead of rw-r--r--\n\
609   -o, --owner=OWNER   set ownership (super-user only)\n\
610   -s, --strip         strip symbol tables, only for 1st and 2nd formats\n\
611   -S, --suffix=SUFFIX override the usual backup suffix\n\
612   -V, --version-control=WORD   override the usual version control\n\
613       --help          display this help and exit\n\
614       --version       output version information and exit\n\
615 \n\
616 "));
617       printf (_("\
618 The backup suffix is ~, unless set with SIMPLE_BACKUP_SUFFIX.  The\n\
619 version control may be set with VERSION_CONTROL, values are:\n\
620 \n\
621   t, numbered     make numbered backups\n\
622   nil, existing   numbered if numbered backups exist, simple otherwise\n\
623   never, simple   always make simple backups\n\
624 "));
625       puts (_("\nReport bugs to <fileutils-bugs@gnu.ai.mit.edu>."));
626     }
627   exit (status);
628 }