Introduction
Introduction Statistics Contact Development Disclaimer Help
rm: Add -i and cleanup rm() - sbase - suckless unix tools
git clone git://git.suckless.org/sbase
Log
Files
Refs
README
LICENSE
---
commit 0df8cdc12d7a5600ad0c2b9420a14be4e2af340b
parent 948e5161902920705f0c3a6458533fc017452173
Author: Roberto E. Vargas Caballero <[email protected]>
Date: Wed, 23 Apr 2025 22:12:52 +0200
rm: Add -i and cleanup rm()
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.
Diffstat:
M README | 2 +-
M fs.h | 2 ++
M libutil/rm.c | 41 ++++++++++++++++++++++-------…
M mv.c | 2 +-
M rm.c | 9 ++++++---
5 files changed, 39 insertions(+), 17 deletions(-)
---
diff --git 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
@@ -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
@@ -14,19 +14,36 @@ int rm_status = 0;
void
rm(int dirfd, const char *name, struct stat *st, void *data, struct recursor *…
{
- 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
@@ -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
@@ -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;
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.