(euidaccess): Remove declaration. It was unused. From Michael Stone.
[platform/upstream/coreutils.git] / src / mv.c
1 /* mv -- move or rename files
2    Copyright (C) 86, 89, 90, 91, 1995-2002 Free Software Foundation, Inc.
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 Mike Parker, 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 <getopt.h>
27 #include <sys/types.h>
28 #include <assert.h>
29
30 #include "system.h"
31 #include "argmatch.h"
32 #include "backupfile.h"
33 #include "copy.h"
34 #include "cp-hash.h"
35 #include "dirname.h"
36 #include "error.h"
37 #include "path-concat.h"
38 #include "quote.h"
39 #include "remove.h"
40
41 /* The official name of this program (e.g., no `g' prefix).  */
42 #define PROGRAM_NAME "mv"
43
44 #define AUTHORS N_ ("Mike Parker, David MacKenzie, and Jim Meyering")
45
46 /* Initial number of entries in each hash table entry's table of inodes.  */
47 #define INITIAL_HASH_MODULE 100
48
49 /* Initial number of entries in the inode hash table.  */
50 #define INITIAL_ENTRY_TAB_SIZE 70
51
52 /* For long options that have no equivalent short option, use a
53    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
54 enum
55 {
56   TARGET_DIRECTORY_OPTION = CHAR_MAX + 1,
57   STRIP_TRAILING_SLASHES_OPTION,
58   REPLY_OPTION
59 };
60
61 int isdir ();
62 int lstat ();
63
64 /* The name this program was run with. */
65 char *program_name;
66
67 /* Remove any trailing slashes from each SOURCE argument.  */
68 static int remove_trailing_slashes;
69
70 /* Valid arguments to the `--reply' option. */
71 static char const* const reply_args[] =
72 {
73   "yes", "no", "query", 0
74 };
75
76 /* The values that correspond to the above strings. */
77 static int const reply_vals[] =
78 {
79   I_ALWAYS_YES, I_ALWAYS_NO, I_ASK_USER
80 };
81
82 static struct option const long_options[] =
83 {
84   {"backup", optional_argument, NULL, 'b'},
85   {"force", no_argument, NULL, 'f'},
86   {"interactive", no_argument, NULL, 'i'},
87   {"reply", required_argument, NULL, REPLY_OPTION},
88   {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION},
89   {"suffix", required_argument, NULL, 'S'},
90   {"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION},
91   {"update", no_argument, NULL, 'u'},
92   {"verbose", no_argument, NULL, 'v'},
93   {"version-control", required_argument, NULL, 'V'},
94   {GETOPT_HELP_OPTION_DECL},
95   {GETOPT_VERSION_OPTION_DECL},
96   {NULL, 0, NULL, 0}
97 };
98
99 static void
100 rm_option_init (struct rm_options *x)
101 {
102   x->unlink_dirs = 0;
103
104   x->ignore_missing_files = 0;
105
106   x->recursive = 1;
107
108   /* Should we prompt for removal, too?  No.  Prompting for the `move'
109      part is enough.  It implies removal.  */
110   x->interactive = 0;
111   x->stdin_tty = 0;
112
113   x->verbose = 0;
114 }
115
116 static void
117 cp_option_init (struct cp_options *x)
118 {
119   x->copy_as_regular = 0;  /* FIXME: maybe make this an option */
120   x->dereference = DEREF_NEVER;
121   x->unlink_dest_before_opening = 0;
122   x->unlink_dest_after_failed_open = 0;
123   x->hard_link = 0;
124   x->interactive = I_UNSPECIFIED;
125   x->move_mode = 1;
126   x->myeuid = geteuid ();
127   x->one_file_system = 0;
128   x->preserve_ownership = 1;
129   x->preserve_links = 1;
130   x->preserve_mode = 1;
131   x->preserve_timestamps = 1;
132   x->require_preserve = 0;  /* FIXME: maybe make this an option */
133   x->recursive = 1;
134   x->sparse_mode = SPARSE_AUTO;  /* FIXME: maybe make this an option */
135   x->symbolic_link = 0;
136   x->set_mode = 0;
137   x->mode = 0;
138   x->stdin_tty = isatty (STDIN_FILENO);
139
140   /* Find out the current file creation mask, to knock the right bits
141      when using chmod.  The creation mask is set to be liberal, so
142      that created directories can be written, even if it would not
143      have been allowed with the mask this process was started with.  */
144   x->umask_kill = ~ umask (0);
145
146   x->update = 0;
147   x->verbose = 0;
148   x->xstat = lstat;
149   x->dest_info = NULL;
150   x->src_info = NULL;
151 }
152
153 /* If PATH is an existing directory, return nonzero, else 0.  */
154
155 static int
156 is_real_dir (const char *path)
157 {
158   struct stat stats;
159
160   return lstat (path, &stats) == 0 && S_ISDIR (stats.st_mode);
161 }
162
163 /* Move SOURCE onto DEST.  Handles cross-filesystem moves.
164    If SOURCE is a directory, DEST must not exist.
165    Return 0 if successful, non-zero if an error occurred.  */
166
167 static int
168 do_move (const char *source, const char *dest, const struct cp_options *x)
169 {
170   static int first = 1;
171   int copy_into_self;
172   int rename_succeeded;
173   int fail;
174
175   if (first)
176     {
177       first = 0;
178
179       /* Allocate space for remembering copied and created files.  */
180       hash_init ();
181     }
182
183   fail = copy (source, dest, 0, x, &copy_into_self, &rename_succeeded);
184
185   if (!fail)
186     {
187       char const *dir_to_remove;
188       if (copy_into_self)
189         {
190           /* In general, when copy returns with copy_into_self set, SOURCE is
191              the same as, or a parent of DEST.  In this case we know it's a
192              parent.  It doesn't make sense to move a directory into itself, and
193              besides in some situations doing so would give highly nonintuitive
194              results.  Run this `mkdir b; touch a c; mv * b' in an empty
195              directory.  Here's the result of running echo `find b -print`:
196              b b/a b/b b/b/a b/c.  Notice that only file `a' was copied
197              into b/b.  Handle this by giving a diagnostic, removing the
198              copied-into-self directory, DEST (`b/b' in the example),
199              and failing.  */
200
201           dir_to_remove = NULL;
202           fail = 1;
203         }
204       else if (rename_succeeded)
205         {
206           /* No need to remove anything.  SOURCE was successfully
207              renamed to DEST.  Or the user declined to rename a file.  */
208           dir_to_remove = NULL;
209         }
210       else
211         {
212           /* This may mean SOURCE and DEST referred to different devices.
213              It may also conceivably mean that even though they referred
214              to the same device, rename wasn't implemented for that device.
215
216              E.g., (from Joel N. Weber),
217              [...] there might someday be cases where you can't rename
218              but you can copy where the device name is the same, especially
219              on Hurd.  Consider an ftpfs with a primitive ftp server that
220              supports uploading, downloading and deleting, but not renaming.
221
222              Also, note that comparing device numbers is not a reliable
223              check for `can-rename'.  Some systems can be set up so that
224              files from many different physical devices all have the same
225              st_dev field.  This is a feature of some NFS mounting
226              configurations.
227
228              We reach this point if SOURCE has been successfully copied
229              to DEST.  Now we have to remove SOURCE.
230
231              This function used to resort to copying only when rename
232              failed and set errno to EXDEV.  */
233
234           dir_to_remove = source;
235         }
236
237       if (dir_to_remove != NULL)
238         {
239           struct rm_options rm_options;
240           enum RM_status status;
241
242           rm_option_init (&rm_options);
243           rm_options.verbose = x->verbose;
244
245           status = rm (1, &dir_to_remove, &rm_options);
246           assert (VALID_STATUS (status));
247           if (status == RM_ERROR)
248             fail = 1;
249         }
250     }
251
252   return fail;
253 }
254
255 /* Move file SOURCE onto DEST.  Handles the case when DEST is a directory.
256    DEST_IS_DIR must be nonzero when DEST is a directory or a symlink to a
257    directory and zero otherwise.
258    Return 0 if successful, non-zero if an error occurred.  */
259
260 static int
261 movefile (char *source, char *dest, int dest_is_dir,
262           const struct cp_options *x)
263 {
264   int dest_had_trailing_slash = strip_trailing_slashes (dest);
265   int fail;
266
267   /* This code was introduced to handle the ambiguity in the semantics
268      of mv that is induced by the varying semantics of the rename function.
269      Some systems (e.g., Linux) have a rename function that honors a
270      trailing slash, while others (like Solaris 5,6,7) have a rename
271      function that ignores a trailing slash.  I believe the Linux
272      rename semantics are POSIX and susv2 compliant.  */
273
274   if (remove_trailing_slashes)
275     strip_trailing_slashes (source);
276
277   /* In addition to when DEST is a directory, if DEST has a trailing
278      slash and neither SOURCE nor DEST is a directory, presume the target
279      is DEST/`basename source`.  This converts `mv x y/' to `mv x y/x'.
280      This change means that the command `mv any file/' will now fail
281      rather than performing the move.  The case when SOURCE is a
282      directory and DEST is not is properly diagnosed by do_move.  */
283
284   if (dest_is_dir || (dest_had_trailing_slash && !is_real_dir (source)))
285     {
286       /* DEST is a directory; build full target filename. */
287       char *src_basename;
288       char *new_dest;
289
290       strip_trailing_slashes (source);
291       src_basename = base_name (source);
292       new_dest = path_concat (dest, src_basename, NULL);
293       if (new_dest == NULL)
294         xalloc_die ();
295       fail = do_move (source, new_dest, x);
296       free (new_dest);
297     }
298   else
299     {
300       fail = do_move (source, dest, x);
301     }
302
303   return fail;
304 }
305
306 void
307 usage (int status)
308 {
309   if (status != 0)
310     fprintf (stderr, _("Try `%s --help' for more information.\n"),
311              program_name);
312   else
313     {
314       printf (_("\
315 Usage: %s [OPTION]... SOURCE DEST\n\
316   or:  %s [OPTION]... SOURCE... DIRECTORY\n\
317   or:  %s [OPTION]... --target-directory=DIRECTORY SOURCE...\n\
318 "),
319               program_name, program_name, program_name);
320       fputs (_("\
321 Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n\
322 \n\
323 "), stdout);
324       fputs (_("\
325 Mandatory arguments to long options are mandatory for short options too.\n\
326 "), stdout);
327       fputs (_("\
328       --backup[=CONTROL]       make a backup of each existing destination file\n\
329   -b                           like --backup but does not accept an argument\n\
330   -f, --force                  do not prompt before overwriting\n\
331                                  equivalent to --reply=yes\n\
332   -i, --interactive            prompt before overwrite\n\
333                                  equivalent to --reply=query\n\
334 "), stdout);
335       fputs (_("\
336       --reply={yes,no,query}   specify how to handle the prompt about an\n\
337                                  existing destination file\n\
338       --strip-trailing-slashes remove any trailing slashes from each SOURCE\n\
339                                  argument\n\
340   -S, --suffix=SUFFIX          override the usual backup suffix\n\
341 "), stdout);
342       fputs (_("\
343       --target-directory=DIRECTORY  move all SOURCE arguments into DIRECTORY\n\
344   -u, --update                 move only when the SOURCE file is newer\n\
345                                  than the destination file or when the\n\
346                                  destination file is missing\n\
347   -v, --verbose                explain what is being done\n\
348 "), stdout);
349       fputs (HELP_OPTION_DESCRIPTION, stdout);
350       fputs (VERSION_OPTION_DESCRIPTION, stdout);
351       fputs (_("\
352 \n\
353 The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
354 The version control method may be selected via the --backup option or through\n\
355 the VERSION_CONTROL environment variable.  Here are the values:\n\
356 \n\
357 "), stdout);
358       fputs (_("\
359   none, off       never make backups (even if --backup is given)\n\
360   numbered, t     make numbered backups\n\
361   existing, nil   numbered if numbered backups exist, simple otherwise\n\
362   simple, never   always make simple backups\n\
363 "), stdout);
364       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
365     }
366   exit (status);
367 }
368
369 int
370 main (int argc, char **argv)
371 {
372   int c;
373   int errors;
374   int make_backups = 0;
375   int dest_is_dir;
376   char *backup_suffix_string;
377   char *version_control_string = NULL;
378   struct cp_options x;
379   char *target_directory = NULL;
380   int target_directory_specified;
381   unsigned int n_files;
382   char **file;
383
384   program_name = argv[0];
385   setlocale (LC_ALL, "");
386   bindtextdomain (PACKAGE, LOCALEDIR);
387   textdomain (PACKAGE);
388
389   atexit (close_stdout);
390
391   cp_option_init (&x);
392
393   /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
394      we'll actually use backup_suffix_string.  */
395   backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
396
397   errors = 0;
398
399   while ((c = getopt_long (argc, argv, "bfiuvS:V:", long_options, NULL)) != -1)
400     {
401       switch (c)
402         {
403         case 0:
404           break;
405
406         case 'V':  /* FIXME: this is deprecated.  Remove it in 2001.  */
407           error (0, 0,
408                  _("warning: --version-control (-V) is obsolete;  support for\
409  it\nwill be removed in some future release.  Use --backup=%s instead."
410                    ), optarg);
411           /* Fall through.  */
412
413         case 'b':
414           make_backups = 1;
415           if (optarg)
416             version_control_string = optarg;
417           break;
418         case 'f':
419           x.interactive = I_ALWAYS_YES;
420           break;
421         case 'i':
422           x.interactive = I_ASK_USER;
423           break;
424         case REPLY_OPTION:
425           x.interactive = XARGMATCH ("--reply", optarg,
426                                      reply_args, reply_vals);
427           break;
428         case STRIP_TRAILING_SLASHES_OPTION:
429           remove_trailing_slashes = 1;
430           break;
431         case TARGET_DIRECTORY_OPTION:
432           target_directory = optarg;
433           break;
434         case 'u':
435           x.update = 1;
436           break;
437         case 'v':
438           x.verbose = 1;
439           break;
440         case 'S':
441           make_backups = 1;
442           backup_suffix_string = optarg;
443           break;
444         case_GETOPT_HELP_CHAR;
445         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
446         default:
447           usage (1);
448         }
449     }
450
451   n_files = argc - optind;
452   file = argv + optind;
453
454   target_directory_specified = (target_directory != NULL);
455   if (target_directory == NULL && n_files != 0)
456     target_directory = file[n_files - 1];
457
458   dest_is_dir = (n_files > 0 && isdir (target_directory));
459
460   if (n_files == 0 || (n_files == 1 && !target_directory_specified))
461     {
462       error (0, 0, _("missing file argument"));
463       usage (1);
464     }
465
466   if (target_directory_specified)
467     {
468       if (!dest_is_dir)
469         {
470           error (0, 0, _("specified target, %s is not a directory"),
471                  quote (target_directory));
472           usage (1);
473         }
474     }
475   else if (n_files > 2 && !dest_is_dir)
476     {
477       error (0, 0,
478             _("when moving multiple files, last argument must be a directory"));
479       usage (1);
480     }
481
482   if (backup_suffix_string)
483     simple_backup_suffix = xstrdup (backup_suffix_string);
484
485   x.backup_type = (make_backups
486                    ? xget_version (_("backup type"),
487                                    version_control_string)
488                    : none);
489
490   /* Move each arg but the last into the target_directory.  */
491   {
492     unsigned int last_file_idx = (target_directory_specified
493                                   ? n_files - 1
494                                   : n_files - 2);
495     unsigned int i;
496
497     /* Initialize the hash table only if we'll need it.
498        The problem it is used to detect can arise only if there are
499        two or more files to move.  */
500     if (last_file_idx)
501       dest_info_init (&x);
502
503     for (i = 0; i <= last_file_idx; ++i)
504       errors |= movefile (file[i], target_directory, dest_is_dir, &x);
505   }
506
507   exit (errors);
508 }