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
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
737
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
1 /* rm.c - remove files
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
2 *
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
3 * Copyright 2012 Rob Landley <rob@landley.net>
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
4 *
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
5 * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/rm.html
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
6
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
7 USE_RM(NEWTOY(rm, "<1fiRr[-fi]", TOYFLAG_BIN))
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
8
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
9 config RM
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
10 bool "rm"
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
11 default y
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
12 help
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
13 usage: rm [-fiRr] FILE...
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
14
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
15 Remove each argument from the filesystem.
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
16
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
17 -f force: remove without confirmation, no error if it doesn't exist
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
18 -i interactive: prompt for confirmation
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
19 -rR recursive: remove directory contents
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
20 */
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
21
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
22 #define FOR_rm
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
23 #include "toys.h"
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
24
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
25 static int do_rm(struct dirtree *try)
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
26 {
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
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
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
29
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
30 // Skip . and .. (yes, even explicitly on the command line: posix says to)
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
31 if (!dirtree_notdotdot(try)) return 0;
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
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
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
61 }
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
62 }
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
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
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
65 if (unlinkat(fd, try->name, using)) {
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
66 perror_msg("%s", try->name);
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
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
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
70 }
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
71
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
72 return 0;
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
73 }
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
74
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
75 void rm_main(void)
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
76 {
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
77 char **s;
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
78
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
79 for (s = toys.optargs; *s; s++) {
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
80 if (!strcmp(*s, "/")) {
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
81 error_msg("rm /. if you mean it");
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
82 toys.exitval = 1;
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
83 continue;
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
84 }
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
85
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
86 // There's a race here where a file removed between this access and
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
87 // dirtree's stat would report the nonexistence as an error, but that's
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
88 // not a normal "it didn't exist" so I'm ok with it.
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
89 if ((toys.optflags & FLAG_f) && (access(*s, F_OK) && errno == ENOENT))
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
90 continue;
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
91 dirtree_read(*s, do_rm);
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
92 }
dc4a38a13270 New rm command.
Rob Landley <rob@landley.net>
parents:
diff changeset
93 }