From: "Roberto E. Vargas Caballero" <k...@shike2.com> POSIX mandates that if the input of rm is a tty and it does not have write rights over a file/dir then it should ask for confirmation, in the same way that is done with the -i flag. To accomodate both things the code has been rearrenged a bit to have only one case instead of having two. Also, this rework adds the error message when a directory is removed without a -r flag. --- README | 2 +- fs.h | 2 ++ libutil/rm.c | 41 +++++++++++++++++++++++++++++------------ mv.c | 2 +- rm.c | 9 ++++++--- 5 files changed, 39 insertions(+), 17 deletions(-)
diff --git a/README b/README index fd66095..ee2aae7 100644 --- a/README +++ b/README @@ -102,7 +102,7 @@ The following tools are implemented: 0=*|x readlink . 0=*|o renice . 0#* x rev . -0=*|o rm (-i) +0=*|o rm . 0=*|o rmdir . # sed . 0=*|x seq . diff --git a/fs.h b/fs.h index 085fb8c..fd647bb 100644 --- a/fs.h +++ b/fs.h @@ -24,6 +24,8 @@ enum { SAMEDEV = 1 << 0, DIRFIRST = 1 << 1, SILENT = 1 << 2, + CONFIRM = 1 << 3, + IGNORE = 1 << 4, }; extern int cp_aflag; diff --git a/libutil/rm.c b/libutil/rm.c index 8d4be08..fb99840 100644 --- a/libutil/rm.c +++ b/libutil/rm.c @@ -14,19 +14,36 @@ int rm_status = 0; void rm(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r) { - if (!r->maxdepth && S_ISDIR(st->st_mode)) { + int quiet, ask, write, flags, ignore; + + ignore = r->flags & IGNORE; + quiet = r->flags & SILENT; + ask = r->flags & CONFIRM; + write = faccessat(dirfd, name, W_OK, 0) == 0; + flags = 0; + + if (S_ISDIR(st->st_mode) && r->maxdepth) { + errno = EISDIR; + goto err; + } + + if (!quiet && (!write && isatty(0) || ask)) { + if (!confirm("remove file '%s'", r->path)); + return; + } + + if (S_ISDIR(st->st_mode)) { + flags = AT_REMOVEDIR; recurse(dirfd, name, NULL, r); + } + + if (unlinkat(dirfd, name, flags) < 0) + goto err; + return; - if (unlinkat(dirfd, name, AT_REMOVEDIR) < 0) { - if (!(r->flags & SILENT)) - weprintf("rmdir %s:", r->path); - if (!((r->flags & SILENT) && errno == ENOENT)) - rm_status = 1; - } - } else if (unlinkat(dirfd, name, 0) < 0) { - if (!(r->flags & SILENT)) - weprintf("unlink %s:", r->path); - if (!((r->flags & SILENT) && errno == ENOENT)) - rm_status = 1; +err: + if (!ignore) { + weprintf("cannot remove '%s':", r->path); + rm_status = 1; } } diff --git a/mv.c b/mv.c index 8441f9c..d24c77f 100644 --- a/mv.c +++ b/mv.c @@ -13,7 +13,7 @@ static int mv_status = 0; static int mv(const char *s1, const char *s2, int depth) { - struct recursor r = { .fn = rm, .follow = 'P' }; + struct recursor r = { .fn = rm, .follow = 'P', .flags = SILENT }; if (!rename(s1, s2)) return 0; diff --git a/rm.c b/rm.c index 8bebfcb..2391d68 100644 --- a/rm.c +++ b/rm.c @@ -7,7 +7,7 @@ static void usage(void) { - eprintf("usage: %s [-f] [-Rr] file ...\n", argv0); + eprintf("usage: %s [-f] [-iRr] file ...\n", argv0); } int @@ -17,7 +17,10 @@ main(int argc, char *argv[]) ARGBEGIN { case 'f': - r.flags |= SILENT; + r.flags |= SILENT | IGNORE; + break; + case 'i': + r.flags |= CONFIRM; break; case 'R': case 'r': @@ -28,7 +31,7 @@ main(int argc, char *argv[]) } ARGEND if (!argc) { - if (!(r.flags & SILENT)) + if (!(r.flags & IGNORE)) usage(); else return 0; -- 2.46.1