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