Include "mmap-stack.h".
[platform/upstream/coreutils.git] / src / cp.c
1 /* cp.c  -- file copying (main routines)
2    Copyright (C) 89, 90, 91, 1995-2003 Free Software Foundation.
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    Written by Torbjorn Granlund, David MacKenzie, and Jim Meyering. */
19
20 #ifdef _AIX
21  #pragma alloca
22 #endif
23
24 #include <config.h>
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <assert.h>
28 #include <getopt.h>
29
30 #include "system.h"
31 #include "argmatch.h"
32 #include "backupfile.h"
33 #include "copy.h"
34 #include "cp-hash.h"
35 #include "dirname.h"
36 #include "error.h"
37 #include "mmap-stack.h"
38 #include "path-concat.h"
39 #include "quote.h"
40
41 #define ASSIGN_BASENAME_STRDUPA(Dest, File_name)        \
42   do                                                    \
43     {                                                   \
44       char *tmp_abns_;                                  \
45       ASSIGN_STRDUPA (tmp_abns_, (File_name));          \
46       strip_trailing_slashes (tmp_abns_);               \
47       Dest = base_name (tmp_abns_);                     \
48     }                                                   \
49   while (0)
50
51 /* The official name of this program (e.g., no `g' prefix).  */
52 #define PROGRAM_NAME "cp"
53
54 #define AUTHORS N_ ("Torbjorn Granlund, David MacKenzie, and Jim Meyering")
55
56 #ifndef _POSIX_VERSION
57 uid_t geteuid ();
58 #endif
59
60 /* Used by do_copy, make_path_private, and re_protect
61    to keep a list of leading directories whose protections
62    need to be fixed after copying. */
63 struct dir_attr
64 {
65   int is_new_dir;
66   int slash_offset;
67   struct dir_attr *next;
68 };
69
70 /* For long options that have no equivalent short option, use a
71    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
72 enum
73 {
74   COPY_CONTENTS_OPTION = CHAR_MAX + 1,
75   NO_PRESERVE_ATTRIBUTES_OPTION,
76   PARENTS_OPTION,
77   PRESERVE_ATTRIBUTES_OPTION,
78   REPLY_OPTION,
79   SPARSE_OPTION,
80   STRIP_TRAILING_SLASHES_OPTION,
81   TARGET_DIRECTORY_OPTION,
82   UNLINK_DEST_BEFORE_OPENING
83 };
84
85 /* Initial number of entries in each hash table entry's table of inodes.  */
86 #define INITIAL_HASH_MODULE 100
87
88 /* Initial number of entries in the inode hash table.  */
89 #define INITIAL_ENTRY_TAB_SIZE 70
90
91 /* The invocation name of this program.  */
92 char *program_name;
93
94 /* If nonzero, the command "cp x/e_file e_dir" uses "e_dir/x/e_file"
95    as its destination instead of the usual "e_dir/e_file." */
96 static int flag_path = 0;
97
98 /* Remove any trailing slashes from each SOURCE argument.  */
99 static int remove_trailing_slashes;
100
101 static char const *const sparse_type_string[] =
102 {
103   "never", "auto", "always", 0
104 };
105
106 static enum Sparse_type const sparse_type[] =
107 {
108   SPARSE_NEVER, SPARSE_AUTO, SPARSE_ALWAYS
109 };
110
111 /* Valid arguments to the `--reply' option. */
112 static char const* const reply_args[] =
113 {
114   "yes", "no", "query", 0
115 };
116
117 /* The values that correspond to the above strings. */
118 static int const reply_vals[] =
119 {
120   I_ALWAYS_YES, I_ALWAYS_NO, I_ASK_USER
121 };
122
123 static struct option const long_opts[] =
124 {
125   {"archive", no_argument, NULL, 'a'},
126   {"backup", optional_argument, NULL, 'b'},
127   {"copy-contents", no_argument, NULL, COPY_CONTENTS_OPTION},
128   {"dereference", no_argument, NULL, 'L'},
129   {"force", no_argument, NULL, 'f'},
130   {"interactive", no_argument, NULL, 'i'},
131   {"link", no_argument, NULL, 'l'},
132   {"no-dereference", no_argument, NULL, 'P'},
133   {"no-preserve", required_argument, NULL, NO_PRESERVE_ATTRIBUTES_OPTION},
134   {"one-file-system", no_argument, NULL, 'x'},
135   {"parents", no_argument, NULL, PARENTS_OPTION},
136   {"path", no_argument, NULL, PARENTS_OPTION},   /* Deprecated.  */
137   {"preserve", optional_argument, NULL, PRESERVE_ATTRIBUTES_OPTION},
138   {"recursive", no_argument, NULL, 'R'},
139   {"remove-destination", no_argument, NULL, UNLINK_DEST_BEFORE_OPENING},
140   {"reply", required_argument, NULL, REPLY_OPTION},
141   {"sparse", required_argument, NULL, SPARSE_OPTION},
142   {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION},
143   {"suffix", required_argument, NULL, 'S'},
144   {"symbolic-link", no_argument, NULL, 's'},
145   {"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION},
146   {"update", no_argument, NULL, 'u'},
147   {"verbose", no_argument, NULL, 'v'},
148   {"version-control", required_argument, NULL, 'V'}, /* Deprecated. FIXME. */
149   {GETOPT_HELP_OPTION_DECL},
150   {GETOPT_VERSION_OPTION_DECL},
151   {NULL, 0, NULL, 0}
152 };
153
154 void
155 usage (int status)
156 {
157   if (status != 0)
158     fprintf (stderr, _("Try `%s --help' for more information.\n"),
159              program_name);
160   else
161     {
162       printf (_("\
163 Usage: %s [OPTION]... SOURCE DEST\n\
164   or:  %s [OPTION]... SOURCE... DIRECTORY\n\
165   or:  %s [OPTION]... --target-directory=DIRECTORY SOURCE...\n\
166 "),
167               program_name, program_name, program_name);
168       fputs (_("\
169 Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n\
170 \n\
171 "), stdout);
172       fputs (_("\
173 Mandatory arguments to long options are mandatory for short options too.\n\
174 "), stdout);
175       fputs (_("\
176   -a, --archive                same as -dpR\n\
177       --backup[=CONTROL]       make a backup of each existing destination file\n\
178   -b                           like --backup but does not accept an argument\n\
179       --copy-contents          copy contents of special files when recursive\n\
180   -d                           same as --no-dereference --preserve=link\n\
181 "), stdout);
182       fputs (_("\
183       --no-dereference         never follow symbolic links\n\
184   -f, --force                  if an existing destination file cannot be\n\
185                                  opened, remove it and try again\n\
186   -i, --interactive            prompt before overwrite\n\
187   -H                           follow command-line symbolic links\n\
188 "), stdout);
189       fputs (_("\
190   -l, --link                   link files instead of copying\n\
191   -L, --dereference            always follow symbolic links\n\
192   -p                           same as --preserve=mode,ownership,timestamps\n\
193       --preserve[=ATTR_LIST]   preserve the specified attributes (default:\n\
194                                  mode,ownership,timestamps), if possible\n\
195                                  additional attributes: links, all\n\
196 "), stdout);
197       fputs (_("\
198       --no-preserve=ATTR_LIST  don't preserve the specified attributes\n\
199       --parents                append source path to DIRECTORY\n\
200   -P                           same as `--no-dereference'\n\
201 "), stdout);
202       fputs (_("\
203   -R, -r, --recursive          copy directories recursively\n\
204       --remove-destination     remove each existing destination file before\n\
205                                  attempting to open it (contrast with --force)\n\
206 "), stdout);
207       fputs (_("\
208       --reply={yes,no,query}   specify how to handle the prompt about an\n\
209                                  existing destination file\n\
210       --sparse=WHEN            control creation of sparse files\n\
211       --strip-trailing-slashes remove any trailing slashes from each SOURCE\n\
212                                  argument\n\
213 "), stdout);
214       fputs (_("\
215   -s, --symbolic-link          make symbolic links instead of copying\n\
216   -S, --suffix=SUFFIX          override the usual backup suffix\n\
217       --target-directory=DIRECTORY  move all SOURCE arguments into DIRECTORY\n\
218 "), stdout);
219       fputs (_("\
220   -u, --update                 copy only when the SOURCE file is newer\n\
221                                  than the destination file or when the\n\
222                                  destination file is missing\n\
223   -v, --verbose                explain what is being done\n\
224   -x, --one-file-system        stay on this file system\n\
225 "), stdout);
226       fputs (HELP_OPTION_DESCRIPTION, stdout);
227       fputs (VERSION_OPTION_DESCRIPTION, stdout);
228       fputs (_("\
229 \n\
230 By default, sparse SOURCE files are detected by a crude heuristic and the\n\
231 corresponding DEST file is made sparse as well.  That is the behavior\n\
232 selected by --sparse=auto.  Specify --sparse=always to create a sparse DEST\n\
233 file whenever the SOURCE file contains a long enough sequence of zero bytes.\n\
234 Use --sparse=never to inhibit creation of sparse files.\n\
235 \n\
236 "), stdout);
237       fputs (_("\
238 The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
239 The version control method may be selected via the --backup option or through\n\
240 the VERSION_CONTROL environment variable.  Here are the values:\n\
241 \n\
242 "), stdout);
243       fputs (_("\
244   none, off       never make backups (even if --backup is given)\n\
245   numbered, t     make numbered backups\n\
246   existing, nil   numbered if numbered backups exist, simple otherwise\n\
247   simple, never   always make simple backups\n\
248 "), stdout);
249       fputs (_("\
250 \n\
251 As a special case, cp makes a backup of SOURCE when the force and backup\n\
252 options are given and SOURCE and DEST are the same name for an existing,\n\
253 regular file.\n\
254 "), stdout);
255       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
256     }
257   exit (status);
258 }
259
260 /* Ensure that the parent directories of CONST_DST_PATH have the
261    correct protections, for the --parents option.  This is done
262    after all copying has been completed, to allow permissions
263    that don't include user write/execute.
264
265    SRC_OFFSET is the index in CONST_DST_PATH of the beginning of the
266    source directory name.
267
268    ATTR_LIST is a null-terminated linked list of structures that
269    indicates the end of the filename of each intermediate directory
270    in CONST_DST_PATH that may need to have its attributes changed.
271    The command `cp --parents --preserve a/b/c d/e_dir' changes the
272    attributes of the directories d/e_dir/a and d/e_dir/a/b to match
273    the corresponding source directories regardless of whether they
274    existed before the `cp' command was given.
275
276    Return 0 if the parent of CONST_DST_PATH and any intermediate
277    directories specified by ATTR_LIST have the proper permissions
278    when done, otherwise 1. */
279
280 static int
281 re_protect (const char *const_dst_path, int src_offset,
282             struct dir_attr *attr_list, const struct cp_options *x)
283 {
284   struct dir_attr *p;
285   char *dst_path;               /* A copy of CONST_DST_PATH we can change. */
286   char *src_path;               /* The source name in `dst_path'. */
287   uid_t myeuid = geteuid ();
288
289   dst_path = (char *) alloca (strlen (const_dst_path) + 1);
290   strcpy (dst_path, const_dst_path);
291   src_path = dst_path + src_offset;
292
293   for (p = attr_list; p; p = p->next)
294     {
295       struct stat src_sb;
296
297       dst_path[p->slash_offset] = '\0';
298
299       if ((*(x->xstat)) (src_path, &src_sb))
300         {
301           error (0, errno, _("failed to get attributes of %s"),
302                  quote (src_path));
303           return 1;
304         }
305
306       /* Adjust the times (and if possible, ownership) for the copy.
307          chown turns off set[ug]id bits for non-root,
308          so do the chmod last.  */
309
310       if (x->preserve_timestamps)
311         {
312           struct utimbuf utb;
313
314           /* There's currently no interface to set file timestamps with
315              better than 1-second resolution, so discard any fractional
316              part of the source timestamp.  */
317
318           utb.actime = src_sb.st_atime;
319           utb.modtime = src_sb.st_mtime;
320
321           if (utime (dst_path, &utb))
322             {
323               error (0, errno, _("failed to preserve times for %s"),
324                      quote (dst_path));
325               return 1;
326             }
327         }
328
329       if (x->preserve_ownership)
330         {
331           /* If non-root uses -p, it's ok if we can't preserve ownership.
332              But root probably wants to know, e.g. if NFS disallows it,
333              or if the target system doesn't support file ownership.  */
334           if (chown (dst_path, src_sb.st_uid, src_sb.st_gid)
335               && ((errno != EPERM && errno != EINVAL) || myeuid == 0))
336             {
337               error (0, errno, _("failed to preserve ownership for %s"),
338                      quote (dst_path));
339               return 1;
340             }
341         }
342
343       if (x->preserve_mode || p->is_new_dir)
344         {
345           if (chmod (dst_path, src_sb.st_mode & x->umask_kill))
346             {
347               error (0, errno, _("failed to preserve permissions for %s"),
348                      quote (dst_path));
349               return 1;
350             }
351         }
352
353       dst_path[p->slash_offset] = '/';
354     }
355   return 0;
356 }
357
358 /* Ensure that the parent directory of CONST_DIRPATH exists, for
359    the --parents option.
360
361    SRC_OFFSET is the index in CONST_DIRPATH (which is a destination
362    path) of the beginning of the source directory name.
363    Create any leading directories that don't already exist,
364    giving them permissions MODE.
365    If VERBOSE_FMT_STRING is nonzero, use it as a printf format
366    string for printing a message after successfully making a directory.
367    The format should take two string arguments: the names of the
368    source and destination directories.
369    Creates a linked list of attributes of intermediate directories,
370    *ATTR_LIST, for re_protect to use after calling copy.
371    Sets *NEW_DST to 1 if this function creates parent of CONST_DIRPATH.
372
373    Return 0 if parent of CONST_DIRPATH exists as a directory with the proper
374    permissions when done, otherwise 1. */
375
376 /* FIXME: find a way to synch this function with the one in lib/makepath.c. */
377
378 static int
379 make_path_private (const char *const_dirpath, int src_offset, int mode,
380                    const char *verbose_fmt_string, struct dir_attr **attr_list,
381                    int *new_dst, int (*xstat)())
382 {
383   struct stat stats;
384   char *dirpath;                /* A copy of CONST_DIRPATH we can change. */
385   char *src;                    /* Source name in `dirpath'. */
386   char *dst_dirname;            /* Leading path of `dirpath'. */
387   size_t dirlen;                /* Length of leading path of `dirpath'. */
388
389   dirpath = (char *) alloca (strlen (const_dirpath) + 1);
390   strcpy (dirpath, const_dirpath);
391
392   src = dirpath + src_offset;
393
394   dirlen = dir_len (dirpath);
395   dst_dirname = (char *) alloca (dirlen + 1);
396   memcpy (dst_dirname, dirpath, dirlen);
397   dst_dirname[dirlen] = '\0';
398
399   *attr_list = NULL;
400
401   if ((*xstat) (dst_dirname, &stats))
402     {
403       /* Parent of CONST_DIRNAME does not exist.
404          Make all missing intermediate directories. */
405       char *slash;
406
407       slash = src;
408       while (*slash == '/')
409         slash++;
410       while ((slash = strchr (slash, '/')))
411         {
412           /* Add this directory to the list of directories whose modes need
413              fixing later. */
414           struct dir_attr *new =
415             (struct dir_attr *) xmalloc (sizeof (struct dir_attr));
416           new->slash_offset = slash - dirpath;
417           new->next = *attr_list;
418           *attr_list = new;
419
420           *slash = '\0';
421           if ((*xstat) (dirpath, &stats))
422             {
423               /* This element of the path does not exist.  We must set
424                  *new_dst and new->is_new_dir inside this loop because,
425                  for example, in the command `cp --parents ../a/../b/c e_dir',
426                  make_path_private creates only e_dir/../a if ./b already
427                  exists. */
428               *new_dst = 1;
429               new->is_new_dir = 1;
430               if (mkdir (dirpath, mode))
431                 {
432                   error (0, errno, _("cannot make directory %s"),
433                          quote (dirpath));
434                   return 1;
435                 }
436               else
437                 {
438                   if (verbose_fmt_string != NULL)
439                     printf (verbose_fmt_string, src, dirpath);
440                 }
441             }
442           else if (!S_ISDIR (stats.st_mode))
443             {
444               error (0, 0, _("%s exists but is not a directory"),
445                      quote (dirpath));
446               return 1;
447             }
448           else
449             {
450               new->is_new_dir = 0;
451               *new_dst = 0;
452             }
453           *slash++ = '/';
454
455           /* Avoid unnecessary calls to `stat' when given
456              pathnames containing multiple adjacent slashes.  */
457           while (*slash == '/')
458             slash++;
459         }
460     }
461
462   /* We get here if the parent of `dirpath' already exists. */
463
464   else if (!S_ISDIR (stats.st_mode))
465     {
466       error (0, 0, _("%s exists but is not a directory"), quote (dst_dirname));
467       return 1;
468     }
469   else
470     {
471       *new_dst = 0;
472     }
473   return 0;
474 }
475
476 /* Scan the arguments, and copy each by calling copy.
477    Return 0 if successful, 1 if any errors occur. */
478
479 static int
480 do_copy (int n_files, char **file, const char *target_directory,
481          struct cp_options *x)
482 {
483   const char *dest;
484   struct stat sb;
485   int new_dst = 0;
486   int ret = 0;
487   int dest_is_dir = 0;
488
489   if (n_files <= 0)
490     {
491       error (0, 0, _("missing file argument"));
492       usage (EXIT_FAILURE);
493     }
494   if (n_files == 1 && !target_directory)
495     {
496       error (0, 0, _("missing destination file"));
497       usage (EXIT_FAILURE);
498     }
499
500   if (target_directory)
501     dest = target_directory;
502   else
503     {
504       dest = file[n_files - 1];
505       --n_files;
506     }
507
508   /* Initialize these hash tables only if we'll need them.
509      The problems they're used to detect can arise only if
510      there are two or more files to copy.  */
511   if (n_files >= 2)
512     {
513       dest_info_init (x);
514       src_info_init (x);
515     }
516
517   if (lstat (dest, &sb))
518     {
519       if (errno != ENOENT)
520         {
521           error (0, errno, _("accessing %s"), quote (dest));
522           return 1;
523         }
524
525       new_dst = 1;
526     }
527   else
528     {
529       struct stat sbx;
530
531       /* If `dest' is not a symlink to a nonexistent file, use
532          the results of stat instead of lstat, so we can copy files
533          into symlinks to directories. */
534       if (stat (dest, &sbx) == 0)
535         sb = sbx;
536
537       dest_is_dir = S_ISDIR (sb.st_mode);
538     }
539
540   if (!dest_is_dir)
541     {
542       if (target_directory)
543         {
544           error (0, 0, _("%s: specified target is not a directory"),
545                  quote (dest));
546           usage (EXIT_FAILURE);
547         }
548
549       if (n_files > 1)
550         {
551           error (0, 0,
552          _("copying multiple files, but last argument %s is not a directory"),
553              quote (dest));
554           usage (EXIT_FAILURE);
555         }
556     }
557
558   if (dest_is_dir)
559     {
560       /* cp file1...filen edir
561          Copy the files `file1' through `filen'
562          to the existing directory `edir'. */
563       int i;
564
565       for (i = 0; i < n_files; i++)
566         {
567           char *dst_path;
568           int parent_exists = 1; /* True if dir_name (dst_path) exists. */
569           struct dir_attr *attr_list;
570           char *arg_in_concat = NULL;
571           char *arg = file[i];
572
573           /* Trailing slashes are meaningful (i.e., maybe worth preserving)
574              only in the source file names.  */
575           if (remove_trailing_slashes)
576             strip_trailing_slashes (arg);
577
578           if (flag_path)
579             {
580               char *arg_no_trailing_slash;
581
582               /* Use `arg' without trailing slashes in constructing destination
583                  file names.  Otherwise, we can end up trying to create a
584                  directory via `mkdir ("dst/foo/"...', which is not portable.
585                  It fails, due to the trailing slash, on at least
586                  NetBSD 1.[34] systems.  */
587               ASSIGN_STRDUPA (arg_no_trailing_slash, arg);
588               strip_trailing_slashes (arg_no_trailing_slash);
589
590               /* Append all of `arg' (minus any trailing slash) to `dest'.  */
591               dst_path = path_concat (dest, arg_no_trailing_slash,
592                                       &arg_in_concat);
593               if (dst_path == NULL)
594                 xalloc_die ();
595
596               /* For --parents, we have to make sure that the directory
597                  dir_name (dst_path) exists.  We may have to create a few
598                  leading directories. */
599               parent_exists = !make_path_private (dst_path,
600                                                   arg_in_concat - dst_path,
601                                                   S_IRWXU,
602                                                   (x->verbose
603                                                    ? "%s -> %s\n" : NULL),
604                                                   &attr_list, &new_dst,
605                                                   x->xstat);
606             }
607           else
608             {
609               char *arg_base;
610               /* Append the last component of `arg' to `dest'.  */
611
612               ASSIGN_BASENAME_STRDUPA (arg_base, arg);
613               /* For `cp -R source/.. dest', don't copy into `dest/..'. */
614               dst_path = (STREQ (arg_base, "..")
615                           ? xstrdup (dest)
616                           : path_concat (dest, arg_base, NULL));
617             }
618
619           if (!parent_exists)
620             {
621               /* make_path_private failed, so don't even attempt the copy. */
622               ret = 1;
623             }
624           else
625             {
626               int copy_into_self;
627               ret |= copy (arg, dst_path, new_dst, x, &copy_into_self, NULL);
628
629               if (flag_path)
630                 {
631                   ret |= re_protect (dst_path, arg_in_concat - dst_path,
632                                      attr_list, x);
633                 }
634             }
635
636           free (dst_path);
637         }
638       return ret;
639     }
640   else /* if (n_files == 1) */
641     {
642       char *new_dest;
643       char *source;
644       int unused;
645       struct stat source_stats;
646
647       if (flag_path)
648         {
649           error (0, 0,
650                _("when preserving paths, the destination must be a directory"));
651           usage (EXIT_FAILURE);
652         }
653
654       source = file[0];
655
656       /* When the force and backup options have been specified and
657          the source and destination are the same name for an existing
658          regular file, convert the user's command, e.g.,
659          `cp --force --backup foo foo' to `cp --force foo fooSUFFIX'
660          where SUFFIX is determined by any version control options used.  */
661
662       if (x->unlink_dest_after_failed_open
663           && x->backup_type != none
664           && STREQ (source, dest)
665           && !new_dst && S_ISREG (sb.st_mode))
666         {
667           static struct cp_options x_tmp;
668
669           new_dest = find_backup_file_name (dest, x->backup_type);
670           /* Set x->backup_type to `none' so that the normal backup
671              mechanism is not used when performing the actual copy.
672              backup_type must be set to `none' only *after* the above
673              call to find_backup_file_name -- that function uses
674              backup_type to determine the suffix it applies.  */
675           x_tmp = *x;
676           x_tmp.backup_type = none;
677           x = &x_tmp;
678
679           if (new_dest == NULL)
680             xalloc_die ();
681         }
682
683       /* When the destination is specified with a trailing slash and the
684          source exists but is not a directory, convert the user's command
685          `cp source dest/' to `cp source dest/basename(source)'.  Doing
686          this ensures that the command `cp non-directory file/' will now
687          fail rather than performing the copy.  COPY diagnoses the case of
688          `cp directory non-directory'.  */
689
690       else if (dest[strlen (dest) - 1] == '/'
691           && lstat (source, &source_stats) == 0
692           && !S_ISDIR (source_stats.st_mode))
693         {
694           char *source_base;
695
696           ASSIGN_BASENAME_STRDUPA (source_base, source);
697           new_dest = (char *) alloca (strlen (dest)
698                                       + strlen (source_base) + 1);
699           stpcpy (stpcpy (new_dest, dest), source_base);
700         }
701       else
702         {
703           new_dest = (char *) dest;
704         }
705
706       return copy (source, new_dest, new_dst, x, &unused, NULL);
707     }
708
709   /* unreachable */
710 }
711
712 static void
713 cp_option_init (struct cp_options *x)
714 {
715   x->copy_as_regular = 1;
716   x->dereference = DEREF_UNDEFINED;
717   x->unlink_dest_before_opening = 0;
718   x->unlink_dest_after_failed_open = 0;
719   x->hard_link = 0;
720   x->interactive = I_UNSPECIFIED;
721   x->myeuid = geteuid ();
722   x->move_mode = 0;
723   x->one_file_system = 0;
724
725   x->preserve_ownership = 0;
726   x->preserve_links = 0;
727   x->preserve_mode = 0;
728   x->preserve_timestamps = 0;
729
730   x->require_preserve = 0;
731   x->recursive = 0;
732   x->sparse_mode = SPARSE_AUTO;
733   x->symbolic_link = 0;
734   x->set_mode = 0;
735   x->mode = 0;
736
737   /* Not used.  */
738   x->stdin_tty = 0;
739
740   /* Find out the current file creation mask, to knock the right bits
741      when using chmod.  The creation mask is set to be liberal, so
742      that created directories can be written, even if it would not
743      have been allowed with the mask this process was started with.  */
744   x->umask_kill = ~ umask (0);
745
746   x->update = 0;
747   x->verbose = 0;
748   x->dest_info = NULL;
749   x->src_info = NULL;
750 }
751
752 /* Given a string, ARG, containing a comma-separated list of arguments
753    to the --preserve option, set the appropriate fields of X to ON_OFF.  */
754 static void
755 decode_preserve_arg (char const *arg, struct cp_options *x, int on_off)
756 {
757   enum File_attribute
758     {
759       PRESERVE_MODE,
760       PRESERVE_TIMESTAMPS,
761       PRESERVE_OWNERSHIP,
762       PRESERVE_LINK,
763       PRESERVE_ALL
764     };
765   static enum File_attribute const preserve_vals[] =
766     {
767       PRESERVE_MODE, PRESERVE_TIMESTAMPS,
768       PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_ALL
769     };
770
771   /* Valid arguments to the `--reply' option. */
772   static char const* const preserve_args[] =
773     {
774       "mode", "timestamps",
775       "ownership", "links", "all", 0
776     };
777
778   char *arg_writable = xstrdup (arg);
779   char *s = arg_writable;
780   do
781     {
782       /* find next comma */
783       char *comma = strchr (s, ',');
784       enum File_attribute val;
785
786       /* If we found a comma, put a NUL in its place and advance.  */
787       if (comma)
788         *comma++ = 0;
789
790       /* process S.  */
791       val = XARGMATCH ("--preserve", s, preserve_args, preserve_vals);
792       switch (val)
793         {
794         case PRESERVE_MODE:
795           x->preserve_mode = on_off;
796           break;
797
798         case PRESERVE_TIMESTAMPS:
799           x->preserve_timestamps = on_off;
800           break;
801
802         case PRESERVE_OWNERSHIP:
803           x->preserve_ownership = on_off;
804           break;
805
806         case PRESERVE_LINK:
807           x->preserve_links = on_off;
808           break;
809
810         case PRESERVE_ALL:
811           x->preserve_mode = on_off;
812           x->preserve_timestamps = on_off;
813           x->preserve_ownership = on_off;
814           x->preserve_links = on_off;
815           break;
816
817         default:
818           abort ();
819         }
820       s = comma;
821     }
822   while (s);
823
824   free (arg_writable);
825 }
826
827 static void run (size_t, char **, char const *, struct cp_options *)
828      ATTRIBUTE_NORETURN;
829 /* Encapsulate the `copy-and-exit' functionality.  */
830 static void
831 run (size_t n_files, char **files, char const *target_directory,
832      struct cp_options *x)
833 {
834   int fail;
835
836   /* Allocate space for remembering copied and created files.  */
837   hash_init ();
838
839   fail = do_copy (n_files, files, target_directory, x);
840
841   forget_all ();
842
843   exit (fail ? EXIT_FAILURE : EXIT_SUCCESS);
844 }
845
846 int
847 main (int argc, char **argv)
848 {
849   int c;
850   int make_backups = 0;
851   char *backup_suffix_string;
852   char *version_control_string = NULL;
853   struct cp_options x;
854   int copy_contents = 0;
855   char *target_directory = NULL;
856
857   program_name = argv[0];
858   setlocale (LC_ALL, "");
859   bindtextdomain (PACKAGE, LOCALEDIR);
860   textdomain (PACKAGE);
861
862   atexit (close_stdout);
863
864   cp_option_init (&x);
865
866   /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
867      we'll actually use backup_suffix_string.  */
868   backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
869
870   while ((c = getopt_long (argc, argv, "abdfHilLprsuvxPRS:V:", long_opts, NULL))
871          != -1)
872     {
873       switch (c)
874         {
875         case 0:
876           break;
877
878         case SPARSE_OPTION:
879           x.sparse_mode = XARGMATCH ("--sparse", optarg,
880                                      sparse_type_string, sparse_type);
881           break;
882
883         case 'a':               /* Like -dpPR. */
884           x.dereference = DEREF_NEVER;
885           x.preserve_links = 1;
886           x.preserve_ownership = 1;
887           x.preserve_mode = 1;
888           x.preserve_timestamps = 1;
889           x.require_preserve = 1;
890           x.recursive = 1;
891           break;
892
893         case 'V':  /* FIXME: this is deprecated.  Remove it in 2001.  */
894           error (0, 0,
895                  _("warning: --version-control (-V) is obsolete;  support for\
896  it\nwill be removed in some future release.  Use --backup=%s instead."
897                    ), optarg);
898           /* Fall through.  */
899
900         case 'b':
901           make_backups = 1;
902           if (optarg)
903             version_control_string = optarg;
904           break;
905
906         case COPY_CONTENTS_OPTION:
907           copy_contents = 1;
908           break;
909
910         case 'd':
911           x.preserve_links = 1;
912           x.dereference = DEREF_NEVER;
913           break;
914
915         case 'f':
916           x.unlink_dest_after_failed_open = 1;
917           break;
918
919         case 'H':
920           x.dereference = DEREF_COMMAND_LINE_ARGUMENTS;
921           break;
922
923         case 'i':
924           x.interactive = I_ASK_USER;
925           break;
926
927         case 'l':
928           x.hard_link = 1;
929           break;
930
931         case 'L':
932           x.dereference = DEREF_ALWAYS;
933           break;
934
935         case 'P':
936           x.dereference = DEREF_NEVER;
937           break;
938
939         case NO_PRESERVE_ATTRIBUTES_OPTION:
940           decode_preserve_arg (optarg, &x, 0);
941           break;
942
943         case PRESERVE_ATTRIBUTES_OPTION:
944           if (optarg == NULL)
945             {
946               /* Fall through to the case for `p' below.  */
947             }
948           else
949             {
950               decode_preserve_arg (optarg, &x, 1);
951               x.require_preserve = 1;
952               break;
953             }
954
955         case 'p':
956           x.preserve_ownership = 1;
957           x.preserve_mode = 1;
958           x.preserve_timestamps = 1;
959           x.require_preserve = 1;
960           break;
961
962         case PARENTS_OPTION:
963           flag_path = 1;
964           break;
965
966         case 'r':
967         case 'R':
968           x.recursive = 1;
969           break;
970
971         case REPLY_OPTION:
972           x.interactive = XARGMATCH ("--reply", optarg,
973                                      reply_args, reply_vals);
974           break;
975
976         case UNLINK_DEST_BEFORE_OPENING:
977           x.unlink_dest_before_opening = 1;
978           break;
979
980         case STRIP_TRAILING_SLASHES_OPTION:
981           remove_trailing_slashes = 1;
982           break;
983
984         case 's':
985 #ifdef S_ISLNK
986           x.symbolic_link = 1;
987 #else
988           error (EXIT_FAILURE, 0,
989                  _("symbolic links are not supported on this system"));
990 #endif
991           break;
992
993         case TARGET_DIRECTORY_OPTION:
994           target_directory = optarg;
995           break;
996
997         case 'u':
998           x.update = 1;
999           break;
1000
1001         case 'v':
1002           x.verbose = 1;
1003           break;
1004
1005         case 'x':
1006           x.one_file_system = 1;
1007           break;
1008
1009         case 'S':
1010           make_backups = 1;
1011           backup_suffix_string = optarg;
1012           break;
1013
1014         case_GETOPT_HELP_CHAR;
1015
1016         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1017
1018         default:
1019           usage (EXIT_FAILURE);
1020         }
1021     }
1022
1023   if (x.hard_link && x.symbolic_link)
1024     {
1025       error (0, 0, _("cannot make both hard and symbolic links"));
1026       usage (EXIT_FAILURE);
1027     }
1028
1029   if (backup_suffix_string)
1030     simple_backup_suffix = xstrdup (backup_suffix_string);
1031
1032   x.backup_type = (make_backups
1033                    ? xget_version (_("backup type"),
1034                                    version_control_string)
1035                    : none);
1036
1037   if (x.preserve_mode == 1)
1038     x.umask_kill = ~ (mode_t) 0;
1039
1040   if (x.dereference == DEREF_UNDEFINED)
1041     {
1042       if (x.recursive)
1043         /* This is compatible with FreeBSD.  */
1044         x.dereference = DEREF_NEVER;
1045       else
1046         x.dereference = DEREF_ALWAYS;
1047     }
1048
1049   /* The key difference between -d (--no-dereference) and not is the version
1050      of `stat' to call.  */
1051
1052   if (x.dereference == DEREF_NEVER)
1053     x.xstat = lstat;
1054   else
1055     {
1056       /* For DEREF_COMMAND_LINE_ARGUMENTS, x.xstat must be stat for
1057          each command line argument, but must later be `lstat' for
1058          any symlinks that are found via recursive traversal.  */
1059       x.xstat = stat;
1060     }
1061
1062   if (x.recursive)
1063     x.copy_as_regular = copy_contents;
1064
1065   /* If --force (-f) was specified and we're in link-creation mode,
1066      first remove any existing destination file.  */
1067   if (x.unlink_dest_after_failed_open && (x.hard_link || x.symbolic_link))
1068     x.unlink_dest_before_opening = 1;
1069
1070   RUN_WITH_BIG_STACK_4 (run, argc - optind, argv + optind,
1071                         target_directory, &x);
1072 }