Don't include version.h.
[coreutils.git] / src / rm.c
blob3244c4927616020c2e323852478559bba51cc8f2
1 /* `rm' file deletion utility for GNU.
2 Copyright (C) 1988, 1990, 1991, 1994, 1995 Free Software Foundation, Inc.
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.
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.
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
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 /* Written by Paul Rubin, David MacKenzie, and Richard Stallman. */
20 #include <config.h>
21 #include <stdio.h>
22 #include <getopt.h>
23 #include <sys/types.h>
25 #include "system.h"
26 #include "error.h"
28 #ifdef D_INO_IN_DIRENT
29 # define D_INO(dp) ((dp)->d_ino)
30 #else
31 /* Some systems don't have inodes, so fake them to avoid lots of ifdefs. */
32 # define D_INO(dp) 1
33 #endif
35 /* An element in a stack of pointers into `pathname'.
36 `pathp' points to where in `pathname' the terminating '\0' goes
37 for this level's directory name. */
38 struct pathstack
40 struct pathstack *next;
41 char *pathp;
42 ino_t inum;
45 char *basename ();
46 char *stpcpy ();
47 char *xmalloc ();
48 char *xrealloc ();
49 int euidaccess ();
50 int yesno ();
51 void strip_trailing_slashes ();
53 static int clear_directory __P ((struct stat *statp));
54 static int duplicate_entry __P ((struct pathstack *stack, ino_t inum));
55 static int remove_dir __P ((struct stat *statp));
56 static int remove_file __P ((struct stat *statp));
57 static int rm __P ((void));
58 static void usage __P ((int status));
60 /* Name this program was run with. */
61 char *program_name;
63 /* Linked list of pathnames of directories in progress in recursive rm.
64 The entries actually contain pointers into `pathname'.
65 `pathstack' is the current deepest level. */
66 static struct pathstack *pathstack = NULL;
68 /* Path of file now being processed; extended as necessary. */
69 static char *pathname;
71 /* Number of bytes currently allocated for `pathname';
72 made larger when necessary, but never smaller. */
73 static int pnsize;
75 /* If nonzero, display the name of each file removed. */
76 static int verbose;
78 /* If nonzero, ignore nonexistant files. */
79 static int ignore_missing_files;
81 /* If nonzero, recursively remove directories. */
82 static int recursive;
84 /* If nonzero, query the user about whether to remove each file. */
85 static int interactive;
87 /* If nonzero, remove directories with unlink instead of rmdir, and don't
88 require a directory to be empty before trying to unlink it.
89 Only works for the super-user. */
90 static int unlink_dirs;
92 /* If nonzero, stdin is a tty. */
93 static int stdin_tty;
95 /* If nonzero, display usage information and exit. */
96 static int show_help;
98 /* If nonzero, print the version on standard output and exit. */
99 static int show_version;
101 static struct option const long_opts[] =
103 {"directory", no_argument, &unlink_dirs, 1},
104 {"force", no_argument, NULL, 'f'},
105 {"interactive", no_argument, NULL, 'i'},
106 {"recursive", no_argument, &recursive, 1},
107 {"verbose", no_argument, &verbose, 1},
108 {"help", no_argument, &show_help, 1},
109 {"version", no_argument, &show_version, 1},
110 {NULL, 0, NULL, 0}
113 void
114 main (int argc, char **argv)
116 int err = 0;
117 int c;
119 program_name = argv[0];
120 setlocale (LC_ALL, "");
121 bindtextdomain (PACKAGE, LOCALEDIR);
122 textdomain (PACKAGE);
124 verbose = ignore_missing_files = recursive = interactive
125 = unlink_dirs = 0;
126 pnsize = 256;
127 pathname = xmalloc (pnsize);
129 while ((c = getopt_long (argc, argv, "dfirvR", long_opts, (int *) 0)) != EOF)
131 switch (c)
133 case 0: /* Long option. */
134 break;
135 case 'd':
136 unlink_dirs = 1;
137 break;
138 case 'f':
139 interactive = 0;
140 ignore_missing_files = 1;
141 break;
142 case 'i':
143 interactive = 1;
144 ignore_missing_files = 0;
145 break;
146 case 'r':
147 case 'R':
148 recursive = 1;
149 break;
150 case 'v':
151 verbose = 1;
152 break;
153 default:
154 usage (1);
158 if (show_version)
160 printf ("rm - %s\n", PACKAGE_VERSION);
161 exit (0);
164 if (show_help)
165 usage (0);
167 if (optind == argc)
169 if (ignore_missing_files)
170 exit (0);
171 else
173 error (0, 0, _("too few arguments"));
174 usage (1);
178 stdin_tty = isatty (STDIN_FILENO);
180 for (; optind < argc; optind++)
182 int len;
184 /* Stripping slashes is harmless for rmdir;
185 if the arg is not a directory, it will fail with ENOTDIR. */
186 strip_trailing_slashes (argv[optind]);
187 len = strlen (argv[optind]);
188 if (len + 1 > pnsize)
190 free (pathname);
191 pnsize = 2 * (len + 1);
192 pathname = xmalloc (pnsize);
194 strcpy (pathname, argv[optind]);
195 err += rm ();
198 exit (err > 0);
201 /* Remove file or directory `pathname' after checking appropriate things.
202 Return 0 if `pathname' is removed, 1 if not. */
204 static int
205 rm (void)
207 struct stat path_stats;
208 char *base = basename (pathname);
210 if (base[0] == '.' && (base[1] == '\0'
211 || (base[1] == '.' && base[2] == '\0')))
213 error (0, 0, _("cannot remove `.' or `..'"));
214 return 1;
217 if (lstat (pathname, &path_stats)
218 /* The following or-clause is solely for systems like SunOS 4.1.3
219 with (broken) lstat that interpret a zero-length file name
220 argument as something meaningful. For such systems, manually
221 set errno to ENOENT. */
222 || (pathname[0] == '\0' && (errno = ENOENT)))
224 if (errno == ENOENT && ignore_missing_files)
225 return 0;
226 error (0, errno, "%s", pathname);
227 return 1;
230 if (S_ISDIR (path_stats.st_mode) && !unlink_dirs)
231 return remove_dir (&path_stats);
232 else
233 return remove_file (&path_stats);
236 /* Query the user if appropriate, and if ok try to remove the
237 non-directory `pathname', which STATP contains info about.
238 Return 0 if `pathname' is removed, 1 if not. */
240 static int
241 remove_file (struct stat *statp)
243 if (!ignore_missing_files && (interactive || stdin_tty)
244 && euidaccess (pathname, W_OK)
245 #ifdef S_ISLNK
246 && !S_ISLNK (statp->st_mode)
247 #endif
250 fprintf (stderr, _("%s: remove %s`%s', overriding mode %04o? "),
251 program_name,
252 S_ISDIR (statp->st_mode) ? _("directory ") : "",
253 pathname,
254 (unsigned int) (statp->st_mode & 07777));
255 if (!yesno ())
256 return 1;
258 else if (interactive)
260 fprintf (stderr, _("%s: remove %s`%s'? "), program_name,
261 S_ISDIR (statp->st_mode) ? _("directory ") : "",
262 pathname);
263 if (!yesno ())
264 return 1;
267 if (verbose)
268 printf ("%s\n", pathname);
270 if (unlink (pathname) && (errno != ENOENT || !ignore_missing_files))
272 error (0, errno, "%s", pathname);
273 return 1;
275 return 0;
278 /* If not in recursive mode, print an error message and return 1.
279 Otherwise, query the user if appropriate, then try to recursively
280 remove directory `pathname', which STATP contains info about.
281 Return 0 if `pathname' is removed, 1 if not. */
283 static int
284 remove_dir (struct stat *statp)
286 int err;
288 if (!recursive)
290 error (0, 0, _("%s: is a directory"), pathname);
291 return 1;
294 if (!ignore_missing_files && (interactive || stdin_tty)
295 && euidaccess (pathname, W_OK))
297 fprintf (stderr,
298 _("%s: descend directory `%s', overriding mode %04o? "),
299 program_name, pathname,
300 (unsigned int) (statp->st_mode & 07777));
301 if (!yesno ())
302 return 1;
304 else if (interactive)
306 fprintf (stderr, _("%s: descend directory `%s'? "),
307 program_name, pathname);
308 if (!yesno ())
309 return 1;
312 if (verbose)
313 printf ("%s\n", pathname);
315 err = clear_directory (statp);
317 if (interactive)
319 if (err)
320 fprintf (stderr, _("%s: remove directory `%s' (might be nonempty)? "),
321 program_name, pathname);
322 else
323 fprintf (stderr, _("%s: remove directory `%s'? "),
324 program_name, pathname);
325 if (!yesno ())
326 return 1;
329 if (rmdir (pathname) && (errno != ENOENT || !ignore_missing_files))
331 error (0, errno, "%s", pathname);
332 return 1;
334 return 0;
337 /* Read directory `pathname' and remove all of its entries,
338 avoiding use of chdir.
339 On entry, STATP points to the results of stat on `pathname'.
340 Return 0 for success, error count for failure.
341 Upon return, `pathname' will have the same contents as before,
342 but its address might be different; in that case, `pnsize' will
343 be larger, as well. */
345 static int
346 clear_directory (struct stat *statp)
348 DIR *dirp;
349 struct dirent *dp;
350 char *name_space; /* Copy of directory's filenames. */
351 char *namep; /* Current entry in `name_space'. */
352 unsigned name_size; /* Bytes allocated for `name_space'. */
353 int name_length; /* Length of filename in `namep' plus '\0'. */
354 int pathname_length; /* Length of `pathname'. */
355 ino_t *inode_space; /* Copy of directory's inodes. */
356 ino_t *inodep; /* Current entry in `inode_space'. */
357 unsigned n_inodes_allocated; /* There is space for this many inodes
358 in `inode_space'. */
359 int err = 0; /* Return status. */
360 struct pathstack pathframe; /* New top of stack. */
361 struct pathstack *pp; /* Temporary. */
363 name_size = statp->st_size;
364 name_space = (char *) xmalloc (name_size);
366 n_inodes_allocated = (statp->st_size + sizeof (ino_t) - 1) / sizeof (ino_t);
367 inode_space = (ino_t *) xmalloc (n_inodes_allocated * sizeof (ino_t));
371 namep = name_space;
372 inodep = inode_space;
374 errno = 0;
375 dirp = opendir (pathname);
376 if (dirp == NULL)
378 if (errno != ENOENT || !ignore_missing_files)
380 error (0, errno, "%s", pathname);
381 err = 1;
383 free (name_space);
384 free (inode_space);
385 return err;
388 while ((dp = readdir (dirp)) != NULL)
390 /* Skip "." and "..". */
391 if (dp->d_name[0] != '.'
392 || (dp->d_name[1] != '\0'
393 && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
395 unsigned size_needed = (namep - name_space) + NLENGTH (dp) + 2;
397 if (size_needed > name_size)
399 char *new_name_space;
401 while (size_needed > name_size)
402 name_size += 1024;
404 new_name_space = xrealloc (name_space, name_size);
405 namep += new_name_space - name_space;
406 name_space = new_name_space;
408 namep = stpcpy (namep, dp->d_name) + 1;
410 if (inodep == inode_space + n_inodes_allocated)
412 ino_t *new_inode_space;
414 n_inodes_allocated += 1024;
415 new_inode_space = (ino_t *) xrealloc (inode_space,
416 n_inodes_allocated * sizeof (ino_t));
417 inodep += new_inode_space - inode_space;
418 inode_space = new_inode_space;
420 *inodep++ = D_INO (dp);
423 *namep = '\0';
424 if (CLOSEDIR (dirp))
426 error (0, errno, "%s", pathname);
427 err = 1;
430 pathname_length = strlen (pathname);
432 for (namep = name_space, inodep = inode_space; *namep != '\0';
433 namep += name_length, inodep++)
435 name_length = strlen (namep) + 1;
437 /* Handle arbitrarily long filenames. */
438 if (pathname_length + 1 + name_length > pnsize)
440 char *new_pathname;
442 pnsize = (pathname_length + 1 + name_length) * 2;
443 new_pathname = xrealloc (pathname, pnsize);
444 /* Update all pointers in the stack to use the new area. */
445 for (pp = pathstack; pp != NULL; pp = pp->next)
446 pp->pathp += new_pathname - pathname;
447 pathname = new_pathname;
450 /* Add a new frame to the top of the path stack. */
451 pathframe.pathp = pathname + pathname_length;
452 pathframe.inum = *inodep;
453 pathframe.next = pathstack;
454 pathstack = &pathframe;
456 /* Append '/' and the filename to current pathname, take care of
457 the file (which could result in recursive calls), and take
458 the filename back off. */
460 *pathstack->pathp = '/';
461 strcpy (pathstack->pathp + 1, namep);
463 /* If the i-number has already appeared, there's an error. */
464 if (duplicate_entry (pathstack->next, pathstack->inum))
465 err++;
466 else if (rm ())
467 err++;
469 *pathstack->pathp = '\0';
470 pathstack = pathstack->next; /* Pop the stack. */
473 /* Keep trying while there are still files to remove. */
474 while (namep > name_space && err == 0);
476 free (name_space);
477 free (inode_space);
478 return err;
481 /* If STACK does not already have an entry with the same i-number as INUM,
482 return 0. Otherwise, ask the user whether to continue;
483 if yes, return 1, and if no, exit.
484 This assumes that no one tries to remove filesystem mount points;
485 doing so could cause duplication of i-numbers that would not indicate
486 a corrupted file system. */
488 static int
489 duplicate_entry (struct pathstack *stack, ino_t inum)
491 #ifdef D_INO_IN_DIRENT
492 struct pathstack *p;
494 for (p = stack; p != NULL; p = p->next)
496 if (p->inum == inum)
498 fprintf (stderr, _("\
499 %s: WARNING: Circular directory structure.\n\
500 This almost certainly means that you have a corrupted file system.\n\
501 NOTIFY YOUR SYSTEM MANAGER.\n\
502 Cycle detected:\n\
503 %s\n\
504 is the same file as\n"), program_name, pathname);
505 *p->pathp = '\0'; /* Truncate pathname. */
506 fprintf (stderr, "%s\n", pathname);
507 *p->pathp = '/'; /* Put it back. */
508 if (interactive)
510 fprintf (stderr, _("%s: continue? "), program_name);
511 if (!yesno ())
512 exit (1);
513 return 1;
515 else
516 exit (1);
519 #endif /* D_INO_IN_DIRENT */
520 return 0;
523 static void
524 usage (int status)
526 if (status != 0)
527 fprintf (stderr, _("Try `%s --help' for more information.\n"),
528 program_name);
529 else
531 printf (_("Usage: %s [OPTION]... FILE...\n"), program_name);
532 printf (_("\
533 Remove (unlink) the FILE(s).\n\
535 -d, --directory unlink directory, even if non-empty (super-user only)\n\
536 -f, --force ignore nonexistent files, never prompt\n\
537 -i, --interactive prompt before any removal\n\
538 -v, --verbose explain what is being done\n\
539 -r, -R, --recursive remove the contents of directories recursively\n\
540 --help display this help and exit\n\
541 --version output version information and exit\n"));
543 exit (status);