Since when do the POSIX and GNU rm not delete /

gnuhistoryposixrm

For several years now, the GNU rm utility won't delete / unless it is called with the --no-preserve-root option. However, the command rm -rf / has been lodged in the collective subconscious as dangerous for a very long time and people still often cite it as a "scary" command.

I was wondering when this rule that rm cannot delete / first appeared. I checked the POSIX specs, and I can see that while POSIX:2008 includes this safety feature, POSIX:2001 does not. Since the online versions of the POSIX specs are updated from time to time, with each new sub-release, I also checked the wayback machine and found the relevant page of POSIX:2008 from 2010 and was able to confirm that the rule that rm cannot remove / was already listed then.

So, my questions are:

  • When was the rule that rm cannot remove / added to the POSIX specs? Was it in the original 2008 edition of the Single UNIX Specification version 4 or was it added in a revision?
  • When was this limitation added to GNU rm? I'm pretty sure it was before it was added to POSIX, but when did it happen?

Best Answer

You can find the HTML version of all the editions of POSIX 2008 online:

That was added in the 2008 edition.

Technical corrigenda generally don't add new features.

You can see the previous version (http://pubs.opengroup.org/onlinepubs/009695399/utilities/rm.html) (POSIX 2004) didn't have that text.

The new text was accepted in the 2003-05-09 austin group conference for inclusion in a later revision of the standard.

It was requested by John Beck of Sun Microsystems in March that same year (link requires opengroup registration, see also Enhancement Request Number 5 here).

John Beck wrote, on Tue 11 Mar 2003:

@ page 820 line 31681-31683 section rm comment {JTB-1}

Problem:

Defect code :  3. Clarification required

An occasional user mistake, with devastating consequences, is to
write a shell script with a line such as:
      rm -rf $VARIABLE1/$VARIABLE2
or
      rm -rf /$VARIABLE1
without verifying that either variable is set, which can lead to
      rm -rf /
being the resulting command.  Since there is no plausible
circumstance under which this is the desired behavior, it seems
reasonable to disallow this.  Such a safeguard would, however,
violate the current specification.

Action:

Either extend the exceptions for . and .. on the noted lines
to list / as well, or specify that the behavior of rm if an
operand resolves to / is undefined.

GNU rm added --preserve-root and --no-preserve-root options in this 2003-11-09 commit, but --preserve-root only became the default in this 2006-09-03 commit, so in coreutils 6.2

FreeBSD has been preserving slash since that 2004-10-04 commit (with a "Find out how flame-proof my underwear really is" commit log), but initially not when under POSIXLY_CORRECT, until they remembered to check a decade later that POSIX was now mandating it at which point it was done also in POSIX mode.

The FreeBSD initial commit mentions Solaris was already doing it at that time.

@JdePB (in comment below) found that link to a Sun insider story corroborating and giving more details on the Solaris origin and suggesting Solaris already had the safeguard in place before they made the request to the Austin group.

It explains the rationale for adding that exclusion. While one can only blame oneself if they do rm -rf /, there's a case where a script could do it if doing rm -rf -- "$1/$2" without checking that $1/$2 were provided which is the thing that hit some Sun customers bad when misapplying a Solaris patch (according to that link).

The forbidding of deletion of . and .. was added long before that and again to safeguard against potential mishaps. rm still is a dangerous command. It does what it's meant to do: remove what you tell it to.

rm -rf /*
cd /tmp &&  rm -rf .*/   # on some systems where rm -rf ../ still removes
                         # the content of ../ and shells that still
                         # may include . and .. in glob expansions.
rm -rf -- "$diretcory"/* # note the misspelled variable name
dir='foo '; rm -rf $dir/*

Would also remove everything. Shell filename completion has been known to cause such problems when you do

rm -rf someth<Tab>/*

Expanded to:

rm -rf something /*

Because something so happened not to be a directory.

Shells like tcsh or zsh will add an extra prompt when trying to call rm with a * wildcard (tcsh not by default).