(long_opts): Change the name of each undocumented, for-
[platform/upstream/coreutils.git] / src / rm.c
1 /* `rm' file deletion utility for GNU.
2    Copyright (C) 88, 90, 91, 1994-2005 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 "dirname.h"
53 #include "error.h"
54 #include "lstat.h"
55 #include "quote.h"
56 #include "quotearg.h"
57 #include "remove.h"
58 #include "root-dev-ino.h"
59
60 /* The official name of this program (e.g., no `g' prefix).  */
61 #define PROGRAM_NAME "rm"
62
63 #define AUTHORS \
64   "Paul Rubin", "David MacKenzie, Richard Stallman", "Jim Meyering"
65
66 /* Name this program was run with.  */
67 char *program_name;
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_PRESERVE_ROOT = CHAR_MAX + 1,
74   PRESERVE_ROOT,
75   PRESUME_INPUT_TTY_OPTION
76 };
77
78 static struct option const long_opts[] =
79 {
80   {"directory", no_argument, NULL, 'd'},
81   {"force", no_argument, NULL, 'f'},
82   {"interactive", no_argument, NULL, 'i'},
83
84   {"no-preserve-root", no_argument, NULL, NO_PRESERVE_ROOT},
85   {"preserve-root", no_argument, NULL, PRESERVE_ROOT},
86
87   /* This is solely for testing.  Do not document.  */
88   /* It is relatively difficult to ensure that there is a tty on stdin.
89      Since rm acts differently depending on that, without this option,
90      it'd be harder to test the parts of rm that depend on that setting.  */
91   {"-presume-input-tty", no_argument, NULL, PRESUME_INPUT_TTY_OPTION},
92
93   {"recursive", no_argument, NULL, 'r'},
94   {"verbose", no_argument, NULL, 'v'},
95   {GETOPT_HELP_OPTION_DECL},
96   {GETOPT_VERSION_OPTION_DECL},
97   {NULL, 0, NULL, 0}
98 };
99
100 /* Advise the user about invalid usages like "rm -foo" if the file
101    "-foo" exists, assuming ARGC and ARGV are as with `main'.  */
102
103 static void
104 diagnose_leading_hyphen (int argc, char **argv)
105 {
106   /* OPTIND is unreliable, so iterate through the arguments looking
107      for a file name that looks like an option.  */
108   int i;
109
110   for (i = 1; i < argc; i++)
111     {
112       char const *arg = argv[i];
113       struct stat st;
114
115       if (arg[0] == '-' && arg[1] && lstat (arg, &st) == 0)
116         {
117           fprintf (stderr,
118                    _("Try `%s ./%s' to remove the file %s.\n"),
119                    argv[0],
120                    quotearg_n_style (1, shell_quoting_style, arg),
121                    quote (arg));
122           break;
123         }
124     }
125 }
126
127 void
128 usage (int status)
129 {
130   if (status != EXIT_SUCCESS)
131     fprintf (stderr, _("Try `%s --help' for more information.\n"),
132              program_name);
133   else
134     {
135       char *base = base_name (program_name);
136       printf (_("Usage: %s [OPTION]... FILE...\n"), program_name);
137       fputs (_("\
138 Remove (unlink) the FILE(s).\n\
139 \n\
140   -f, --force           ignore nonexistent files, never prompt\n\
141   -i, --interactive     prompt before any removal\n\
142 "), stdout);
143       fputs (_("\
144       --no-preserve-root do not treat `/' specially (the default)\n\
145       --preserve-root   fail to operate recursively on `/'\n\
146   -r, -R, --recursive   remove directories and their contents recursively\n\
147   -v, --verbose         explain what is being done\n\
148 "), stdout);
149       fputs (HELP_OPTION_DESCRIPTION, stdout);
150       fputs (VERSION_OPTION_DESCRIPTION, stdout);
151       fputs (_("\
152 \n\
153 By default, rm does not remove directories.  Use the --recursive (-r or -R)\n\
154 option to remove each listed directory, too, along with all of its contents.\n\
155 "), stdout);
156       printf (_("\
157 \n\
158 To remove a file whose name starts with a `-', for example `-foo',\n\
159 use one of these commands:\n\
160   %s -- -foo\n\
161 \n\
162   %s ./-foo\n\
163 "),
164               base, base);
165       fputs (_("\
166 \n\
167 Note that if you use rm to remove a file, it is usually possible to recover\n\
168 the contents of that file.  If you want more assurance that the contents are\n\
169 truly unrecoverable, consider using shred.\n\
170 "), stdout);
171       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
172     }
173   exit (status);
174 }
175
176 static void
177 rm_option_init (struct rm_options *x)
178 {
179   x->ignore_missing_files = false;
180   x->interactive = false;
181   x->recursive = false;
182   x->root_dev_ino = NULL;
183   x->stdin_tty = isatty (STDIN_FILENO);
184   x->verbose = false;
185
186   /* Since this program exits immediately after calling `rm', rm need not
187      expend unnecessary effort to preserve the initial working directory.  */
188   x->require_restore_cwd = false;
189 }
190
191 int
192 main (int argc, char **argv)
193 {
194   bool preserve_root = false;
195   struct rm_options x;
196   int c;
197
198   initialize_main (&argc, &argv);
199   program_name = argv[0];
200   setlocale (LC_ALL, "");
201   bindtextdomain (PACKAGE, LOCALEDIR);
202   textdomain (PACKAGE);
203
204   atexit (close_stdout);
205
206   rm_option_init (&x);
207
208   while ((c = getopt_long (argc, argv, "dfirvR", long_opts, NULL)) != -1)
209     {
210       switch (c)
211         {
212         case 'd':
213           /* Ignore this option, for backward compatibility with
214              coreutils 5.92.  Some time after 2005, we'll change this
215              to report an error (or perhaps behave like FreeBSD does)
216              instead of ignoring the option.  */
217           break;
218
219         case 'f':
220           x.interactive = false;
221           x.ignore_missing_files = true;
222           break;
223
224         case 'i':
225           x.interactive = true;
226           x.ignore_missing_files = false;
227           break;
228
229         case 'r':
230         case 'R':
231           x.recursive = true;
232           break;
233
234         case NO_PRESERVE_ROOT:
235           preserve_root = false;
236           break;
237
238         case PRESERVE_ROOT:
239           preserve_root = true;
240           break;
241
242         case PRESUME_INPUT_TTY_OPTION:
243           x.stdin_tty = true;
244           break;
245
246         case 'v':
247           x.verbose = true;
248           break;
249
250         case_GETOPT_HELP_CHAR;
251         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
252         default:
253           diagnose_leading_hyphen (argc, argv);
254           usage (EXIT_FAILURE);
255         }
256     }
257
258   if (argc <= optind)
259     {
260       if (x.ignore_missing_files)
261         exit (EXIT_SUCCESS);
262       else
263         {
264           error (0, 0, _("missing operand"));
265           usage (EXIT_FAILURE);
266         }
267     }
268
269   if (x.recursive & preserve_root)
270     {
271       static struct dev_ino dev_ino_buf;
272       x.root_dev_ino = get_root_dev_ino (&dev_ino_buf);
273       if (x.root_dev_ino == NULL)
274         error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
275                quote ("/"));
276     }
277
278   {
279     size_t n_files = argc - optind;
280     char const *const *file = (char const *const *) argv + optind;
281
282     enum RM_status status = rm (n_files, file, &x);
283     assert (VALID_STATUS (status));
284     exit (status == RM_ERROR ? EXIT_FAILURE : EXIT_SUCCESS);
285   }
286 }