/etc/init.d/umountfs is run during shutdown to unmount most filesystems. It contains this:

PROTECTED_MOUNTS="$(sed -n ':a;/^[^ ]* \(\/\|\/usr\) /!{H;n;ba};{H;s/.*//;x;s/\n//;p}' /proc/mounts)"

This command apparently selects a subset of the lines in /proc/mounts, which then become exempt from being unmounted later in the script.

It matches lines with / or /usr in the second field (the mount point) and then what it does next involves too many exotic sed features for me to figure out what the intent is.

It would make sense if this was just selecting the / and /usr lines, since those get unmounted in a different script. But it doesn't do that. When I run it on my actual /proc/mounts, $PROTECTED_MOUNTS ends up containing almost all the lines, including the /home line. It's not good if /home doesn't get unmounted, so that can't be right.

What could the writer of that sed command possibly have meant to do, with all that branching and hold space stuff?

  • 1
    Whatever they meant to do, it's quite ugly if you ask me... I mean, leaving the picket fence aside and the fact that it doesn't use ERE though the syntax assumes gnu sed, why doing n;ba ? Isn't that the same as simply using b or even better, d? And H when either... or... ? Why not using it only once, at the top of the script, so that it applies to all lines ? [[:shrugs:]] – don_crissti Aug 22 '17 at 9:39
  • The first sentence of the question is wrong. /etc/init.d/umountfs is not run at all, at startup or shutdown, by default in Debian, from Debian 8 onwards. It is masked by a symbolic link at /lib/systemd/system/umountfs.service. – JdeBP Aug 23 '17 at 5:14
  • And as I already pointed out in this Q&A, don_crissti, Debian bug #655582 has the explanation of what this was meant to do. – JdeBP Aug 23 '17 at 5:19
  • @JdeBP I'm not sure that applies to those of us still successfully resisting systemd. Or to the first shutdown after an upgrade. And the sed command in bug #655582 doesn't include the /usr part which is new in Debian 9. – user41515 Aug 23 '17 at 13:26

I'll give it a shot...

This will return every line up to and including the last occurrence of / or /usr. AKA this strips everything after the last occurrence of either of those.

:a;/^[^ ]* \(\/\|\/usr\) /!{H;n;ba};

This says, for lines that don't contain exactly / or /usr in the second (whitespace delimited) column, append to Hold space, fetch next line, loop back to label a.


We'll only get here if we encounter a line with / or /usr. Then we append to Hold space (which has everything from the first section), clear pattern space, exchange hold space with pattern space, remove first newline from pattern space and print it.

After we've seen the last / or /usr line (and we've printed everything up to that point), we loop through the first part and suck all the remaining non-matching lines up...but they never get printed since we don't enter the second part.

I did a bit of testing and that has been consistent with my claim.

Clearly this depends on some kind of ordering being maintained in /proc/mounts. But the list is simply built according to the order that the mount points are created. So wherever that is done must be maintained or this stuff will break, I guess. It all seems awfully brittle to me.

| improve this answer | |
  • Psst! Debian bug #655582 has the explanation. – JdeBP Aug 22 '17 at 4:28
  • So the assumptions are: 1. /proc/mounts is in some predictable order (which I always thought was not true); 2. in whatever order that is, all the "real" filesystems other than the root are below the last /usr – user41515 Aug 23 '17 at 2:00
  • @WumpusQ.Wumbley I got curious about the ordering. I added a link to a Q&A about that. – B Layer Aug 23 '17 at 4:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy