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