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