In episode 103 of BSD Now, Bryan Cantrill talks about the fact that
on illumos "rm -rf /" is an error.  It turns out that this behavior
is mandated by POSIX 1003.1-2013:

"If either of the files dot or dot-dot are specified as the basename
portion of an operand (that is, the final pathname component) or if an
operand resolves to the root directory, rm shall write a diagnostic
message to standard error and do nothing more with such operands."
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/rm.html

On FreeBSD, a check for "/" only happens if POSIXLY_CORRECT is set,
while on NetBSD, there currently is no such check at all.

Index: bin/rm/rm.1
===================================================================
RCS file: /var/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 22 Aug 2015 21:49:02 -0000
@@ -102,6 +102,7 @@ The
 utility removes symbolic links, not the files referenced by the links.
 .Pp
 It is an error to attempt to remove the files
+.Dq / ,
 .Dq \&.
 or
 .Dq .. .
Index: bin/rm/rm.c
===================================================================
RCS file: /var/cvs/src/bin/rm/rm.c,v
retrieving revision 1.30
diff -u -p -r1.30 rm.c
--- bin/rm/rm.c 16 Jan 2015 06:39:32 -0000      1.30
+++ bin/rm/rm.c 22 Aug 2015 21:58:28 -0000
@@ -54,7 +54,7 @@ extern char *__progname;
 int dflag, eval, fflag, iflag, Pflag, stdin_ok;
 
 int    check(char *, char *, struct stat *);
-void   checkdot(char **);
+void   checkdotorslash(char **);
 void   rm_file(char **);
 int    rm_overwrite(char *, struct stat *);
 int    pass(int, off_t, char *, size_t);
@@ -105,7 +105,7 @@ main(int argc, char *argv[])
        if (argc < 1 && fflag == 0)
                usage();
 
-       checkdot(argv);
+       checkdotorslash(argv);
 
        if (*argv) {
                stdin_ok = isatty(STDIN_FILENO);
@@ -383,7 +383,7 @@ check(char *path, char *name, struct sta
  */
 #define ISDOT(a)       ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && 
!(a)[2])))
 void
-checkdot(char **argv)
+checkdotorslash(char **argv)
 {
        char *p, **save, **t;
        int complained;
@@ -401,9 +401,10 @@ checkdot(char **argv)
                else
                        p = *t;
 
-               if (ISDOT(p)) {
+               if (ISDOT(p) || *p == '\0') {
                        if (!complained++)
-                               warnx("\".\" and \"..\" may not be removed");
+                               warnx("\"/\", \".\" and \"..\" may not be "
+                                   "removed");
                        eval = 1;
                        for (save = t; (t[0] = t[1]) != NULL; ++t)
                                continue;

Reply via email to