master xplshn/aruu / cmd / posix / rm.c
 1/* See LICENSE file for copyright and license details. */
 2
 3#include <fcntl.h>
 4#include <string.h>
 5
 6#include "fs.h"
 7#include "util.h"
 8
 9static void
10usage(void)
11{
12  eprintf("usage: %s [-f] [-iRr] file ...\n", argv0);
13}
14
15static int
16forbidden(char *path, struct stat *root)
17{
18  char       *s, *t;
19  size_t      n;
20  struct stat st;
21  static int  w1, w2;
22
23  n = strlen(path);
24  for (t = path + n; t > path && t[-1] == '/'; --t)
25    ;
26  for (s = t; s > path && s[-1] != '/'; --s)
27    ;
28  n = t - s;
29  if ((n == 1 && *s == '.') || (n == 2 && s[0] == '.' && s[1] == '.')) {
30    if (!w1)
31      weprintf("\".\" and \"..\" may not be removed\n");
32    w1 = 1;
33    return 1;
34  }
35
36  if (stat(path, &st) < 0)
37    return 0;
38  if (st.st_dev == root->st_dev && st.st_ino == root->st_ino) {
39    if (!w2)
40      weprintf("\"/\" may not be removed\n");
41    w2 = 1;
42    return 1;
43  }
44
45  return 0;
46}
47
48// ?man rm: remove files
49// ?man arguments: file ...
50// ?man remove files and directory hierarchies
51int
52main(int argc, char *argv[])
53{
54  struct stat     st;
55  struct recursor r = {.fn = rm, .maxdepth = 1, .follow = 'P'};
56
57  ARGBEGIN
58  {
59    // ?man -f: ignore nonexistent files and never prompt
60    case 'f':
61      r.flags |= SILENT | IGNORE;
62      break;
63    // ?man -i: prompt before every removal
64    case 'i':
65      r.flags |= CONFIRM;
66      break;
67    // ?man -R: remove directories and their contents recursively
68    case 'R':
69    // ?man -r: remove directories and their contents recursively
70    case 'r':
71      r.maxdepth = 0;
72      break;
73    default:
74      usage();
75  }
76  ARGEND
77
78  if (!argc) {
79    if (!(r.flags & IGNORE))
80      usage();
81    else
82      return 0;
83  }
84
85  if (stat("/", &st) < 0)
86    eprintf("stat root:");
87  for (; *argv; argc--, argv++) {
88    if (forbidden(*argv, &st)) {
89      rm_status = 1;
90      continue;
91    }
92    recurse(AT_FDCWD, *argv, NULL, &r);
93  }
94
95  return rm_status || recurse_status;
96}