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