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