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