# HG changeset patch # User Rob Landley # Date 1354883181 21600 # Node ID dc4a38a1327084fc6041b3462e8dd3bdc4363d4e # Parent e7694c640f36b6f7378e1b8da0b55b15400aa01f New rm command. diff -r e7694c640f36 -r dc4a38a13270 toys/posix/rm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toys/posix/rm.c Fri Dec 07 06:26:21 2012 -0600 @@ -0,0 +1,77 @@ +/* rm.c - remove files + * + * Copyright 2012 Rob Landley + * + * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/rm.html + +USE_RM(NEWTOY(rm, "<1fiRr[-fi]", TOYFLAG_BIN)) + +config RM + bool "rm" + default y + help + usage: rm [-fiRr] FILE... + + Remove each argument from the filesystem. + + -f force: remove without confirmation, no error if it doesn't exist + -i interactive: prompt for confirmation + -rR recursive: remove directory contents +*/ + +#define FOR_rm +#include "toys.h" + +static int do_rm(struct dirtree *try) +{ + int fd = dirtree_parentfd(try), flags = toys.optflags; + int or = 0, using = 0; + + // Skip . and .. (yes, even explicitly on the command line: posix says to) + if (!dirtree_notdotdot(try)) return 0; + + if (S_ISDIR(try->st.st_mode)) { + if (flags & (FLAG_r|FLAG_R)) { + if (try->data != -1) return DIRTREE_COMEAGAIN; + using = AT_REMOVEDIR; + } + } + + // Prompt if necessary + if (!(flags & FLAG_f) && faccessat(fd, try->name, W_OK, AT_SYMLINK_NOFOLLOW)) + or++; + + if ((or && isatty(0)) || (flags & FLAG_i)) { + fprintf(stderr, "rm %s", or ? "ro " : ""); + if (!yesno(try->name, 2)) return 0; + } + + // Intentionally fail non-recursive attempts to remove even an empty dir + // because POSIX says to. + if (unlinkat(fd, try->name, using)) { + perror_msg("%s", try->name); + toys.exitval = 1; + } + + return 0; +} + +void rm_main(void) +{ + char **s; + + for (s = toys.optargs; *s; s++) { + if (!strcmp(*s, "/")) { + error_msg("rm /. if you mean it"); + toys.exitval = 1; + continue; + } + + // There's a race here where a file removed between this access and + // dirtree's stat would report the nonexistence as an error, but that's + // not a normal "it didn't exist" so I'm ok with it. + if ((toys.optflags & FLAG_f) && (access(*s, F_OK) && errno == ENOENT)) + continue; + dirtree_read(*s, do_rm); + } +}