Hi Superingo,
Superingo wrote on Fri, Oct 17, 2014 at 09:19:45PM +0200:
> I just fatfingered a ';' into a ',':
>
> $ rm a.out, cc mind.c
>
> rm: a.out,: No such file or directory
> rm: cc: No such file or directory
>
> In full POSIX-conformance I lost my mind.
> Coincidentally I had an idea.
> What do you think?
Here is what a standard Ingo would think:
Don't casually type multiple commands on the same line,
in particular, don't add needless stuff after potentially
dangerous commands like rm(1). Hitting "Enter" after each
interactive command often helps to mitigate the damage done
by catastrophic typos.
If you want to disregard that advice, use "cmd && cmd" rather
than "cmd; cmd" - it's safer with respect to failures and
chances are typos will more readily meet the eye.
Consider using
alias rm='rm -i'
Admittedly, that's a matter of taste, and it can be tedious
now and then, but it does help me to prevent such havoc.
Your proposal is not going to solve your problem.
You are not trying to tell me that you plan to type 'rm -x'
for each and every removal in the future, right?
And even if you do plan on doing that, it's easy to forget.
Finally, your proposal is a terrible idea.
We don't gratuitiously add knobs to POSIX tools.
* In NetBSD, FreeBSD, and Dragonfly, -x means "do not cross mount
points" (since last year).
* In illumos and in the GNU coreutils, there is no -x option.
So, this would be completely non-standard, conflicting, and
not very useful.
No thanks!
Ingo
> Index: bin/rm/rm.1
> ===================================================================
> RCS file: /cvs/src/bin/rm/rm.1,v
> retrieving revision 1.37
> diff -u -p -r1.37 rm.1
> --- bin/rm/rm.1 25 May 2014 19:07:36 -0000 1.37
> +++ bin/rm/rm.1 17 Oct 2014 18:37:18 -0000
> @@ -41,7 +41,7 @@
> .Nd remove directory entries
> .Sh SYNOPSIS
> .Nm rm
> -.Op Fl dfiPRr
> +.Op Fl dfxiPRr
> .Ar
> .Sh DESCRIPTION
> The
> @@ -65,6 +65,17 @@ The
> .Fl f
> option overrides any previous
> .Fl i
> +or
> +.Fl x
> +options.
> +.It Fl x
> +Exit immediately on error, instead of processing any remaining arguments.
> +The
> +.Fl x
> +option overrides any previous
> +.Fl f
> +or
> +.Fl i
> options.
> .It Fl i
> Request confirmation before attempting to remove each file, regardless of
> @@ -74,6 +85,8 @@ The
> .Fl i
> option overrides any previous
> .Fl f
> +or
> +.Fl x
> options.
> .It Fl P
> Overwrite regular files before deleting them.
> @@ -148,7 +161,7 @@ utility is compliant with the
> specification.
> .Pp
> The flags
> -.Op Fl dP
> +.Op Fl dxP
> are extensions to that specification.
> .Sh HISTORY
> An
> Index: bin/rm/rm.c
> ===================================================================
> RCS file: /cvs/src/bin/rm/rm.c,v
> retrieving revision 1.29
> diff -u -p -r1.29 rm.c
> --- bin/rm/rm.c 21 May 2014 06:23:02 -0000 1.29
> +++ bin/rm/rm.c 17 Oct 2014 18:37:18 -0000
> @@ -40,6 +40,7 @@
> #include <errno.h>
> #include <fcntl.h>
> #include <fts.h>
> +#include <stdarg.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> @@ -49,7 +50,7 @@
>
> extern char *__progname;
>
> -int dflag, eval, fflag, iflag, Pflag, stdin_ok;
> +int dflag, eval, fflag, xflag, iflag, Pflag, stdin_ok;
>
> int check(char *, char *, struct stat *);
> void checkdot(char **);
> @@ -58,6 +59,8 @@ int rm_overwrite(char *, struct stat *);
> int pass(int, off_t, char *, size_t);
> void rm_tree(char **);
> void usage(void);
> +void warnerr(const char * fmt, ...);
> +void warnerrx(const char * fmt, ...);
>
> /*
> * rm --
> @@ -74,7 +77,7 @@ main(int argc, char *argv[])
> setlocale(LC_ALL, "");
>
> Pflag = rflag = 0;
> - while ((ch = getopt(argc, argv, "dfiPRr")) != -1)
> + while ((ch = getopt(argc, argv, "dfxiPRr")) != -1)
> switch(ch) {
> case 'd':
> dflag = 1;
> @@ -82,10 +85,17 @@ main(int argc, char *argv[])
> case 'f':
> fflag = 1;
> iflag = 0;
> + xflag = 0;
> + break;
> + case 'x':
> + fflag = 0;
> + iflag = 0;
> + xflag = 1;
> break;
> case 'i':
> fflag = 0;
> iflag = 1;
> + xflag = 0;
> break;
> case 'P':
> Pflag = 1;
> @@ -146,7 +156,7 @@ rm_tree(char **argv)
> switch (p->fts_info) {
> case FTS_DNR:
> if (!fflag || p->fts_errno != ENOENT) {
> - warnx("%s: %s",
> + warnerrx("%s: %s",
> p->fts_path, strerror(p->fts_errno));
> eval = 1;
> }
> @@ -161,7 +171,7 @@ rm_tree(char **argv)
> if (!needstat)
> break;
> if (!fflag || p->fts_errno != ENOENT) {
> - warnx("%s: %s",
> + warnerrx("%s: %s",
> p->fts_path, strerror(p->fts_errno));
> eval = 1;
> }
> @@ -209,7 +219,7 @@ rm_tree(char **argv)
> (fflag && errno == ENOENT))
> continue;
> }
> - warn("%s", p->fts_path);
> + warnerr("%s", p->fts_path);
> eval = 1;
> }
> if (errno)
> @@ -232,14 +242,14 @@ rm_file(char **argv)
> /* Assume if can't stat the file, can't unlink it. */
> if (lstat(f, &sb)) {
> if (!fflag || errno != ENOENT) {
> - warn("%s", f);
> + warnerr("%s", f);
> eval = 1;
> }
> continue;
> }
>
> if (S_ISDIR(sb.st_mode) && !dflag) {
> - warnx("%s: is a directory", f);
> + warnerrx("%s: is a directory", f);
> eval = 1;
> continue;
> }
> @@ -253,7 +263,7 @@ rm_file(char **argv)
> rval = unlink(f);
> }
> if (rval && (!fflag || errno != ENOENT)) {
> - warn("%s", f);
> + warnerr("%s", f);
> eval = 1;
> }
> }
> @@ -289,7 +299,8 @@ rm_overwrite(char *file, struct stat *sb
> if (!S_ISREG(sbp->st_mode))
> return (1);
> if (sbp->st_nlink > 1) {
> - warnx("%s (inode %llu): not overwritten due to multiple links",
> + warnerrx(
> + "%s (inode %llu): not overwritten due to multiple links",
> file, (unsigned long long)sbp->st_ino);
> return (0);
> }
> @@ -317,7 +328,7 @@ rm_overwrite(char *file, struct stat *sb
> return (1);
>
> err:
> - warn("%s", file);
> + warnerr("%s", file);
> close(fd);
> eval = 1;
> free(buf);
> @@ -401,7 +412,7 @@ checkdot(char **argv)
>
> if (ISDOT(p)) {
> if (!complained++)
> - warnx("\".\" and \"..\" may not be removed");
> + warnerrx("\".\" and \"..\" may not be removed");
> eval = 1;
> for (save = t; (t[0] = t[1]) != NULL; ++t)
> continue;
> @@ -414,6 +425,32 @@ checkdot(char **argv)
> void
> usage(void)
> {
> - (void)fprintf(stderr, "usage: %s [-dfiPRr] file ...\n", __progname);
> + (void)fprintf(stderr, "usage: %s [-dfxiPRr] file ...\n", __progname);
> exit(1);
> +}
> +
> +void
> +warnerr(const char * fmt, ...)
> +{
> + va_list ap;
> +
> + va_start(ap, fmt);
> + if (xflag)
> + verr(EXIT_FAILURE, fmt, ap);
> + else
> + vwarn(fmt, ap);
> + va_end(ap);
> +}
> +
> +void
> +warnerrx(const char * fmt, ...)
> +{
> + va_list ap;
> +
> + va_start(ap, fmt);
> + if (xflag)
> + verrx(EXIT_FAILURE, fmt, ap);
> + else
> + vwarnx(fmt, ap);
> + va_end(ap);
> }