Mercurial > hg > toybox
annotate toys/posix/rm.c @ 739:451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
author | Rob Landley <rob@landley.net> |
---|---|
date | Sat, 08 Dec 2012 02:26:56 -0600 |
parents | dc4a38a13270 |
children | 5caa4035c1c8 |
rev | line source |
---|---|
737 | 1 /* rm.c - remove files |
2 * | |
3 * Copyright 2012 Rob Landley <rob@landley.net> | |
4 * | |
5 * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/rm.html | |
6 | |
7 USE_RM(NEWTOY(rm, "<1fiRr[-fi]", TOYFLAG_BIN)) | |
8 | |
9 config RM | |
10 bool "rm" | |
11 default y | |
12 help | |
13 usage: rm [-fiRr] FILE... | |
14 | |
15 Remove each argument from the filesystem. | |
16 | |
17 -f force: remove without confirmation, no error if it doesn't exist | |
18 -i interactive: prompt for confirmation | |
19 -rR recursive: remove directory contents | |
20 */ | |
21 | |
22 #define FOR_rm | |
23 #include "toys.h" | |
24 | |
25 static int do_rm(struct dirtree *try) | |
26 { | |
27 int fd = dirtree_parentfd(try), flags = toys.optflags; | |
739
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
28 int dir = S_ISDIR(try->st.st_mode), or = 0, using = 0; |
737 | 29 |
30 // Skip . and .. (yes, even explicitly on the command line: posix says to) | |
31 if (!dirtree_notdotdot(try)) return 0; | |
32 | |
739
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
33 // Intentionally fail non-recursive attempts to remove even an empty dir |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
34 // (via wrong flags to unlinkat) because POSIX says to. |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
35 if (dir && !(flags & (FLAG_r|FLAG_R))) goto skip; |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
36 |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
37 // This is either the posix section 2(b) prompt or the section 3 prompt. |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
38 if (!(flags & FLAG_f) && faccessat(fd, try->name, W_OK, AT_SYMLINK_NOFOLLOW)) |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
39 or++; |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
40 if (!(dir && try->data == -1) && ((or && isatty(0)) || (flags & FLAG_i))) { |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
41 char *s = dirtree_path(try, 0); |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
42 fprintf(stderr, "rm %s%s", or ? "ro " : "", dir ? "dir " : ""); |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
43 or = yesno(s, 0); |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
44 free(s); |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
45 if (!or) goto nodelete; |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
46 } |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
47 |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
48 // handle directory recursion |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
49 if (dir) { |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
50 |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
51 if (try->data != -1) return DIRTREE_COMEAGAIN; |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
52 using = AT_REMOVEDIR; |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
53 if (try->symlink) goto nodelete; |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
54 if (flags & FLAG_i) { |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
55 char *s = dirtree_path(try, 0); |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
56 // This is the section 2(d) prompt. (Yes, posix says to prompt twice.) |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
57 fprintf(stderr, "rmdir "); |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
58 or = yesno(s, 0); |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
59 free(s); |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
60 if (!or) goto nodelete; |
737 | 61 } |
62 } | |
63 | |
739
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
64 skip: |
737 | 65 if (unlinkat(fd, try->name, using)) { |
66 perror_msg("%s", try->name); | |
67 toys.exitval = 1; | |
739
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
68 nodelete: |
451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
Rob Landley <rob@landley.net>
parents:
737
diff
changeset
|
69 if (try->parent) try->parent->symlink = (char *)1; |
737 | 70 } |
71 | |
72 return 0; | |
73 } | |
74 | |
75 void rm_main(void) | |
76 { | |
77 char **s; | |
78 | |
79 for (s = toys.optargs; *s; s++) { | |
80 if (!strcmp(*s, "/")) { | |
81 error_msg("rm /. if you mean it"); | |
82 toys.exitval = 1; | |
83 continue; | |
84 } | |
85 | |
86 // There's a race here where a file removed between this access and | |
87 // dirtree's stat would report the nonexistence as an error, but that's | |
88 // not a normal "it didn't exist" so I'm ok with it. | |
89 if ((toys.optflags & FLAG_f) && (access(*s, F_OK) && errno == ENOENT)) | |
90 continue; | |
91 dirtree_read(*s, do_rm); | |
92 } | |
93 } |