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


Reply via email to