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