Run Levels And Start Scripts

When a machine boots, it looks in the /etc/rc?.d directories and if it finds a script that starts with an upper-case S, it calls that script with a start argument. As a machine shuts down, it looks in the /etc/rc?.d directories and if it finds a script that starts with an upper-case K, it calls that script with a stop argument. But it is not as simple as that...

Testing

To determine what scripts were run under certain situations, I created a simple script

#!/sbin/sh
#
echo $0 $1 >> /var/tmp/init.log
I then created links to it in all of the /etc/rc?.d directories as both a start script and as a stop script, with the last character of the filename the same number as the level it would run from. The /etc/rc?.d directories are:
/etc/rc0.d
/etc/rc1.d
/etc/rc2.d
/etc/rc3.d
/etc/rcS.d

How did the machine get shut down

halt

I have always known that the various methods of rebooting a machine produced different effects, which is an indication that which scripts are run depends on how you reboot the machine. As expected, the halt command does not run any kill scripts. Since it does not reboot the machine, I manually ran through the various run levels, and noted which scripts ran as we entered the various levels. I was surprised to see that the kill scripts get run when entering rc3, but not when entering any other level...

 halt 
 init s 
/etc/rcS.d/S99inittestS start
 init 1 
/etc/rc1.d/S99inittest1 start
 init 2 
/etc/rc2.d/S99inittest2 start
 init 3 
/etc/rc3.d/K99inittest3 stop
/etc/rc3.d/S99inittest3 start

reboot

I was surprised to see that the reboot command does not run any kill scripts either.

/etc/rcS.d/S99inittestS start
/etc/rc2.d/S99inittest2 start
/etc/rc3.d/K99inittest3 stop
/etc/rc3.d/S99inittest3 start

shutdown

I have always known that shutdown was a "cleaner" way to shut down a machine than reboot or halt, but I was surprised to see that it skips over rc1.d:

shutdown -y -g0 -i6

/etc/rc0.d/K99inittest0 stop
/etc/rc0.d/S99inittest0 start
/etc/rcS.d/S99inittestS start
/etc/rc2.d/S99inittest2 start
/etc/rc3.d/K99inittest3 stop
/etc/rc3.d/S99inittest3 start

But using shutdown to get to single user mode is NOT the best way. (since a normal reboot with shutdown -y -g0 -i6 runs kill scripts in rc0.d, people are likely to put their kill scripts in rc0.d and not in rcS.d, so they are not executed with this command):

from run level 3: shutdown -y -g0 -is

/etc/rcS.d/K99inittestS stop

The normal reboot with shutdown -y -g0 -i6 seems to run the same scripts, regardless of which level it is started from:

from run level S: shutdown -y -g0 -i6

/etc/rc0.d/K99inittest0 stop
/etc/rc0.d/S99inittest0 start
/etc/rcS.d/S99inittestS start
/etc/rc2.d/S99inittest2 start
/etc/rc3.d/K99inittest3 stop
/etc/rc3.d/S99inittest3 start

So the rules for decreasing the run level look like they are simple:

  1. Run the stop scripts in whatever level you are going to

And the rules for increasing the run level look like they are not so simple:

  1. Run the start scripts in whatever level is between the level you are at, and the level you are going to
  2. but skip rc1.d
  3. and run the kill scripts in rc3.d before running the start scripts

from run level 3: init 2

/etc/rc2.d/K99inittest2 stop
from run level 2: init 1
/etc/rc1.d/K99inittest1 stop
/etc/rc1.d/S99inittest1 start
from run level 1: init 2
/etc/rc2.d/S99inittest2 start
from run level 2: init 3
/etc/rc3.d/K99inittest3 stop
/etc/rc3.d/S99inittest3 start

It looks like an init 6 is the same as running a shutdown -i6, but remember that shutdown does a few more tings than just call init 6: from run level 3: init 6

/etc/rc0.d/K99inittest0 stop
/etc/rc0.d/S99inittest0 start
/etc/rcS.d/S99inittestS start
/etc/rc2.d/S99inittest2 start
/etc/rc3.d/K99inittest3 stop
/etc/rc3.d/S99inittest3 start

Naming Your RC Scripts

The order in which the scripts are run is obvious if you only use two digit numbers, but what happens if you start using three-digit numbers in your script names? I have worked at a number of places where they have made three-digit names, and I do not think they are getting what they expect.

To test this issue, I created additional links in rc3.d, one with a three digit number: /etc/rc3.d/S100inittest3 start and two other that would be run near it: /etc/rc3.d/S10inittest3 start and /etc/rc3.d/S99inittest3 start

from run level 3: init 6

/etc/rc0.d/K99inittest0 stop
/etc/rc0.d/S99inittest0 start
/etc/rcS.d/S99inittestS start
/etc/rc2.d/S99inittest2 start
/etc/rc3.d/K100inittest3 stop
/etc/rc3.d/K10inittest3 stop
/etc/rc3.d/K99inittest3 stop
/etc/rc3.d/S100inittest3 start
/etc/rc3.d/S10inittest3 start
/etc/rc3.d/S99inittest3 start