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
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.
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
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 }