Don't include closeout.h or version-etc.h explicitly. Now, they're included via sys2.h.
[platform/upstream/coreutils.git] / src / rm.c
1 /* `rm' file deletion utility for GNU.
2    Copyright (C) 88, 90, 91, 1994-1999 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 Paul Rubin, David MacKenzie, and Richard Stallman.
19    Reworked to use chdir and hash tables 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_cwd_entries)
26    so that when/if the containing directory is reopened, RM doesn't try to
27    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 by maintaining a table of the currently
35    active directories.  See the description of active_dir_map below.
36
37    RM is careful to avoid forming full file names whenever possible.
38    A full file name is formed only when it is about to be used -- e.g.
39    in a diagnostic or in an interactive-mode prompt.
40
41    RM minimizes the number of lstat system calls it makes.  On systems
42    that have valid d_type data in directory entries, RM makes only one
43    lstat call per command line argument -- regardless of the depth of
44    the hierarchy.  */
45
46 #include <config.h>
47 #include <stdio.h>
48 #include <getopt.h>
49 #include <sys/types.h>
50 #include <assert.h>
51
52 #include "system.h"
53 #include "error.h"
54 #include "remove.h"
55 #include "save-cwd.h"
56
57 /* The official name of this program (e.g., no `g' prefix).  */
58 #define PROGRAM_NAME "rm"
59
60 #define AUTHORS \
61   "Paul Rubin, David MacKenzie, Richard Stallman, and Jim Meyering"
62
63 void strip_trailing_slashes ();
64
65 /* Name this program was run with.  */
66 char *program_name;
67
68 static struct option const long_opts[] =
69 {
70   {"directory", no_argument, NULL, 'd'},
71   {"force", no_argument, NULL, 'f'},
72   {"interactive", no_argument, NULL, 'i'},
73   {"recursive", no_argument, NULL, 'r'},
74   {"verbose", no_argument, NULL, 'v'},
75   {GETOPT_HELP_OPTION_DECL},
76   {GETOPT_VERSION_OPTION_DECL},
77   {NULL, 0, NULL, 0}
78 };
79
80 void
81 usage (int status)
82 {
83   if (status != 0)
84     fprintf (stderr, _("Try `%s --help' for more information.\n"),
85              program_name);
86   else
87     {
88       printf (_("Usage: %s [OPTION]... FILE...\n"), program_name);
89       printf (_("\
90 Remove (unlink) the FILE(s).\n\
91 \n\
92   -d, --directory       unlink directory, even if non-empty (super-user only)\n\
93   -f, --force           ignore nonexistent files, never prompt\n\
94   -i, --interactive     prompt before any removal\n\
95   -r, -R, --recursive   remove the contents of directories recursively\n\
96   -v, --verbose         explain what is being done\n\
97       --help            display this help and exit\n\
98       --version         output version information and exit\n\
99 "));
100       puts (_("\nReport bugs to <bug-fileutils@gnu.org>."));
101       close_stdout ();
102     }
103   exit (status);
104 }
105
106 static void
107 rm_option_init (struct rm_options *x)
108 {
109   x->unlink_dirs = 0;
110   x->ignore_missing_files = 0;
111   x->interactive = 0;
112   x->recursive = 0;
113   x->stdin_tty = isatty (STDIN_FILENO);
114   x->verbose = 0;
115 }
116
117 int
118 main (int argc, char **argv)
119 {
120   struct rm_options x;
121   int fail = 0;
122   int c;
123
124   program_name = argv[0];
125   setlocale (LC_ALL, "");
126   bindtextdomain (PACKAGE, LOCALEDIR);
127   textdomain (PACKAGE);
128
129   rm_option_init (&x);
130
131   while ((c = getopt_long (argc, argv, "dfirvR", long_opts, NULL)) != -1)
132     {
133       switch (c)
134         {
135         case 0:         /* Long option.  */
136           break;
137         case 'd':
138           x.unlink_dirs = 1;
139           break;
140         case 'f':
141           x.interactive = 0;
142           x.ignore_missing_files = 1;
143           break;
144         case 'i':
145           x.interactive = 1;
146           x.ignore_missing_files = 0;
147           break;
148         case 'r':
149         case 'R':
150           x.recursive = 1;
151           break;
152         case 'v':
153           x.verbose = 1;
154           break;
155         case_GETOPT_HELP_CHAR;
156         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
157         default:
158           usage (1);
159         }
160     }
161
162   if (optind == argc)
163     {
164       if (x.ignore_missing_files)
165         exit (0);
166       else
167         {
168           error (0, 0, _("too few arguments"));
169           usage (1);
170         }
171     }
172
173   remove_init ();
174
175   for (; optind < argc; optind++)
176     {
177       struct File_spec fs;
178       enum RM_status status;
179
180       /* Stripping slashes is harmless for rmdir;
181          if the arg is not a directory, it will fail with ENOTDIR.  */
182       strip_trailing_slashes (argv[optind]);
183       fspec_init_file (&fs, argv[optind]);
184       status = rm (&fs, 1, &x);
185       assert (VALID_STATUS (status));
186       if (status == RM_ERROR)
187         fail = 1;
188     }
189
190   remove_fini ();
191
192   if (x.verbose)
193     close_stdout ();
194   exit (fail);
195 }