Mercurial > hg > toybox
annotate toys/posix/rm.c @ 746:5caa4035c1c8
essat's flag not to follow symlinks isn't in the system call, and if libc is supposed to implement this as a wrapper uClibc gets it wrong. So use the stat info about symlinks instead. (Doesn't check the parent directory, but if that's read only we can't delete the file anyway so prompting is moot.)
author | Rob Landley <rob@landley.net> |
---|---|
date | Mon, 10 Dec 2012 01:48:02 -0600 |
parents | 451d7e91232e |
children | 8947c0d35e58 |
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. |
746
5caa4035c1c8
essat's flag not to follow symlinks isn't in the system call, and if libc is supposed to implement this as a wrapper uClibc gets it wrong. So use the stat info about symlinks instead. (Doesn't check the parent directory, but if that's read only we can't delete the file anyway so prompting is moot.)
Rob Landley <rob@landley.net>
parents:
739
diff
changeset
|
38 if (!(flags & FLAG_f) |
5caa4035c1c8
essat's flag not to follow symlinks isn't in the system call, and if libc is supposed to implement this as a wrapper uClibc gets it wrong. So use the stat info about symlinks instead. (Doesn't check the parent directory, but if that's read only we can't delete the file anyway so prompting is moot.)
Rob Landley <rob@landley.net>
parents:
739
diff
changeset
|
39 && (!S_ISLNK(try->st.st_mode) && faccessat(fd, try->name, W_OK, 0))) or++; |
739
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 } |