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