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