(INTERACTIVE_OPTION): New enum value.
[platform/upstream/coreutils.git] / src / rm.c
1 /* `rm' file deletion utility for GNU.
2    Copyright (C) 88, 90, 91, 1994-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17
18 /* Written by Paul Rubin, David MacKenzie, and Richard Stallman.
19    Reworked to use chdir and avoid recursion by Jim Meyering.  */
20
21 /* Implementation overview:
22
23    In the `usual' case, RM saves no state for directories it is processing.
24    When a removal fails (either due to an error or to an interactive `no'
25    reply), the failure is noted (see description of `ht' in remove.c's
26    remove_cwd_entries function) so that when/if the containing directory
27    is reopened, RM doesn't try to remove the entry again.
28
29    RM may delete arbitrarily deep hierarchies -- even ones in which file
30    names (from root to leaf) are longer than the system-imposed maximum.
31    It does this by using chdir to change to each directory in turn before
32    removing the entries in that directory.
33
34    RM detects directory cycles lazily.  See lib/cycle-check.c.
35
36    RM is careful to avoid forming full file names whenever possible.
37    A full file name is formed only when it is about to be used -- e.g.
38    in a diagnostic or in an interactive-mode prompt.
39
40    RM minimizes the number of lstat system calls it makes.  On systems
41    that have valid d_type data in directory entries, RM makes only one
42    lstat call per command line argument -- regardless of the depth of
43    the hierarchy.  */
44
45 #include <config.h>
46 #include <stdio.h>
47 #include <getopt.h>
48 #include <sys/types.h>
49 #include <assert.h>
50
51 #include "system.h"
52 #include "argmatch.h"
53 #include "dirname.h"
54 #include "error.h"
55 #include "lstat.h"
56 #include "quote.h"
57 #include "quotearg.h"
58 #include "remove.h"
59 #include "root-dev-ino.h"
60 #include "yesno.h"
61
62 /* The official name of this program (e.g., no `g' prefix).  */
63 #define PROGRAM_NAME "rm"
64
65 #define AUTHORS \
66   "Paul Rubin", "David MacKenzie, Richard Stallman", "Jim Meyering"
67
68 /* Name this program was run with.  */
69 char *program_name;
70
71 /* For long options that have no equivalent short option, use a
72    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
73 enum
74 {
75   INTERACTIVE_OPTION = CHAR_MAX + 1,
76   NO_PRESERVE_ROOT,
77   PRESERVE_ROOT,
78   PRESUME_INPUT_TTY_OPTION
79 };
80
81 enum interactive_type
82   {
83     interactive_never,          /* 0: no option or --interactive=never */
84     interactive_once,           /* 1: -I or --interactive=once */
85     interactive_always          /* 2: default, -i or --interactive=always */
86   };
87
88 static struct option const long_opts[] =
89 {
90   {"directory", no_argument, NULL, 'd'},
91   {"force", no_argument, NULL, 'f'},
92   {"interactive", optional_argument, NULL, INTERACTIVE_OPTION},
93
94   {"no-preserve-root", no_argument, NULL, NO_PRESERVE_ROOT},
95   {"preserve-root", no_argument, NULL, PRESERVE_ROOT},
96
97   /* This is solely for testing.  Do not document.  */
98   /* It is relatively difficult to ensure that there is a tty on stdin.
99      Since rm acts differently depending on that, without this option,
100      it'd be harder to test the parts of rm that depend on that setting.  */
101   {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
102
103   {"recursive", no_argument, NULL, 'r'},
104   {"verbose", no_argument, NULL, 'v'},
105   {GETOPT_HELP_OPTION_DECL},
106   {GETOPT_VERSION_OPTION_DECL},
107   {NULL, 0, NULL, 0}
108 };
109
110 static char const *const interactive_args[] =
111 {
112   "never", "no", "none",
113   "once",
114   "always", "yes", NULL
115 };
116 static enum interactive_type const interactive_types[] =
117 {
118   interactive_never, interactive_never, interactive_never,
119   interactive_once,
120   interactive_always, interactive_always
121 };
122 ARGMATCH_VERIFY (interactive_args, interactive_types);
123
124 /* Advise the user about invalid usages like "rm -foo" if the file
125    "-foo" exists, assuming ARGC and ARGV are as with `main'.  */
126
127 static void
128 diagnose_leading_hyphen (int argc, char **argv)
129 {
130   /* OPTIND is unreliable, so iterate through the arguments looking
131      for a file name that looks like an option.  */
132   int i;
133
134   for (i = 1; i < argc; i++)
135     {
136       char const *arg = argv[i];
137       struct stat st;
138
139       if (arg[0] == '-' && arg[1] && lstat (arg, &st) == 0)
140         {
141           fprintf (stderr,
142                    _("Try `%s ./%s' to remove the file %s.\n"),
143                    argv[0],
144                    quotearg_n_style (1, shell_quoting_style, arg),
145                    quote (arg));
146           break;
147         }
148     }
149 }
150
151 void
152 usage (int status)
153 {
154   if (status != EXIT_SUCCESS)
155     fprintf (stderr, _("Try `%s --help' for more information.\n"),
156              program_name);
157   else
158     {
159       printf (_("Usage: %s [OPTION]... FILE...\n"), program_name);
160       fputs (_("\
161 Remove (unlink) the FILE(s).\n\
162 \n\
163   -f, --force           ignore nonexistent files, never prompt\n\
164   -i                    prompt before every removal\n\
165 "), stdout);
166       fputs (_("\
167   -I                    prompt once before removing more than three files, or\n\
168                           when removing recursively.  Less intrusive than -i,\n\
169                           while still giving protection against most mistakes\n\
170       --interactive[=WHEN]  prompt according to WHEN: never, once (-I), or\n\
171                           always (-i).  Without WHEN, prompt always\n\
172 "), stdout);
173       fputs (_("\
174       --no-preserve-root  do not treat `/' specially (the default)\n\
175       --preserve-root   fail to operate recursively on `/'\n\
176   -r, -R, --recursive   remove directories and their contents recursively\n\
177   -v, --verbose         explain what is being done\n\
178 "), stdout);
179       fputs (HELP_OPTION_DESCRIPTION, stdout);
180       fputs (VERSION_OPTION_DESCRIPTION, stdout);
181       fputs (_("\
182 \n\
183 By default, rm does not remove directories.  Use the --recursive (-r or -R)\n\
184 option to remove each listed directory, too, along with all of its contents.\n\
185 "), stdout);
186       printf (_("\
187 \n\
188 To remove a file whose name starts with a `-', for example `-foo',\n\
189 use one of these commands:\n\
190   %s -- -foo\n\
191 \n\
192   %s ./-foo\n\
193 "),
194               program_name, program_name);
195       fputs (_("\
196 \n\
197 Note that if you use rm to remove a file, it is usually possible to recover\n\
198 the contents of that file.  If you want more assurance that the contents are\n\
199 truly unrecoverable, consider using shred.\n\
200 "), stdout);
201       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
202     }
203   exit (status);
204 }
205
206 static void
207 rm_option_init (struct rm_options *x)
208 {
209   x->ignore_missing_files = false;
210   x->interactive = false;
211   x->recursive = false;
212   x->root_dev_ino = NULL;
213   x->stdin_tty = isatty (STDIN_FILENO);
214   x->verbose = false;
215
216   /* Since this program exits immediately after calling `rm', rm need not
217      expend unnecessary effort to preserve the initial working directory.  */
218   x->require_restore_cwd = false;
219 }
220
221 int
222 main (int argc, char **argv)
223 {
224   bool preserve_root = false;
225   struct rm_options x;
226   bool prompt_once = false;
227   int c;
228
229   initialize_main (&argc, &argv);
230   program_name = argv[0];
231   setlocale (LC_ALL, "");
232   bindtextdomain (PACKAGE, LOCALEDIR);
233   textdomain (PACKAGE);
234
235   atexit (close_stdout);
236
237   rm_option_init (&x);
238
239   while ((c = getopt_long (argc, argv, "dfirvIR", long_opts, NULL)) != -1)
240     {
241       switch (c)
242         {
243         case 'd':
244           /* Ignore this option, for backward compatibility with
245              coreutils 5.92.  Some time after 2005, we'll change this
246              to report an error (or perhaps behave like FreeBSD does)
247              instead of ignoring the option.  */
248           break;
249
250         case 'f':
251           x.interactive = false;
252           x.ignore_missing_files = true;
253           prompt_once = false;
254           break;
255
256         case 'i':
257           x.interactive = true;
258           x.ignore_missing_files = false;
259           prompt_once = false;
260           break;
261
262         case 'I':
263           x.interactive = false;
264           x.ignore_missing_files = false;
265           prompt_once = true;
266           break;
267
268         case 'r':
269         case 'R':
270           x.recursive = true;
271           break;
272
273         case INTERACTIVE_OPTION:
274           {
275             int i;
276             if (optarg)
277               i = XARGMATCH ("--interactive", optarg, interactive_args,
278                              interactive_types);
279             else
280               i = interactive_always;
281             switch (i)
282               {
283               case interactive_never:
284                 x.interactive = false;
285                 prompt_once = false;
286                 break;
287
288               case interactive_once:
289                 x.interactive = false;
290                 x.ignore_missing_files = false;
291                 prompt_once = true;
292                 break;
293
294               case interactive_always:
295                 x.interactive = true;
296                 x.ignore_missing_files = false;
297                 prompt_once = false;
298                 break;
299               }
300             break;
301           }
302
303         case NO_PRESERVE_ROOT:
304           preserve_root = false;
305           break;
306
307         case PRESERVE_ROOT:
308           preserve_root = true;
309           break;
310
311         case PRESUME_INPUT_TTY_OPTION:
312           x.stdin_tty = true;
313           break;
314
315         case 'v':
316           x.verbose = true;
317           break;
318
319         case_GETOPT_HELP_CHAR;
320         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
321         default:
322           diagnose_leading_hyphen (argc, argv);
323           usage (EXIT_FAILURE);
324         }
325     }
326
327   if (argc <= optind)
328     {
329       if (x.ignore_missing_files)
330         exit (EXIT_SUCCESS);
331       else
332         {
333           error (0, 0, _("missing operand"));
334           usage (EXIT_FAILURE);
335         }
336     }
337
338   if (x.recursive & preserve_root)
339     {
340       static struct dev_ino dev_ino_buf;
341       x.root_dev_ino = get_root_dev_ino (&dev_ino_buf);
342       if (x.root_dev_ino == NULL)
343         error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
344                quote ("/"));
345     }
346
347   {
348     size_t n_files = argc - optind;
349     char const *const *file = (char const *const *) argv + optind;
350
351     if (prompt_once && (x.recursive || 3 < n_files))
352       {
353         fprintf (stderr,
354                  (x.recursive
355                   ? _("%s: remove all arguments recursively? ")
356                   : _("%s: remove all arguments? ")),
357                  program_name);
358         if (!yesno ())
359           exit (EXIT_SUCCESS);
360       }
361     enum RM_status status = rm (n_files, file, &x);
362     assert (VALID_STATUS (status));
363     exit (status == RM_ERROR ? EXIT_FAILURE : EXIT_SUCCESS);
364   }
365 }