Understanding Run Levels
Emmett Dulaney
UNIX systems, as well as BSD flavors, have only two
run levels --
single user and multiple user. Under SV, run levels
have become to
a machine what permissions are to a user. Operating
at one run level
restricts a machine from performing certain tasks (such
as networking),
while running at another enables these functions. Which
functions
are enabled at each run level has changed over the years
(for example,
run level 1 used to be equivalent to multi-user state
on many older
machines), but under current definitions, there are
eight accepted
run levels:
0 -- Shutdown state requiring a manual reboot.
When you change to this level, files are synchronized
with the disk
and the system is left in a state where it is safe to
power it off.
This level is also known on some systems as "Q"
or "q".
Q or q -- On systems where these are
not equal to zero, they force the system to reread the
inittab
files and take into account any changes that have occurred
since last
boot.
1 -- Single user mode, also known as "S"
or "s" mode on many systems. This allows only
one user (traditionally
the root user) to access the system and prevents anyone
else from
getting in. Additionally, it allows only one terminal
to login. If
the change is to level 1, then the one terminal allowed
to login is
the one defined as the console (and this command can
be given only
at the console). If the change is to S/s, then the only
terminal allowed
to log in is the one that changed the run level. This
is the level
used when performing kernel rebuilds, installing software
that rebuilds
the kernel, performing troubleshooting, etc.
2 -- Multiple user mode, the traditional
state allowing more than one user to login at a time.
This is the
level where background processes (daemons) startup and
additional
file systems, if present, are mounted. (Note: the root
file system
is always mounted.)
3 -- Network mode. This is the same as level
2, but with networking or remote file sharing enabled.
4 -- User defined.
5 -- Hardware state.
6 -- Shutdown and automatic reboot. This
performs the same action as changing to run level 0
then rebooting
the machine. This can be called a "warm boot"
(in the language
of the DOS world), because power is never removed from
the components.
Run levels 0 and 5 represent a "cold boot,"
since power must
be turned off and then restored.
An easy way to summarize the run levels is that 2, 3,
and 4 are operational
states of the computer -- it is up and running and users
are allowed
to conduct business. All other run levels involve some
sort of maintenance
or shutdown operation that prevents users from processing.
Identifying and Changing Run Levels
The -r parameter of the who command gives you your
machine's current run level as well as the two most
recent previous
run levels. For example,
$ who -r
. run level 2 May 4 10:07 2 1 0
$
shows that the current run level is 2 and that that
has
been the run level since May 4th at 10:07. The three
numbers to the
right show the current run level, the previous run level,
and the
next previous run level on some systems. On other systems,
the three
numbers represent the process termination status, process
id, and
process exit status.
Changing levels requires root permission and can be
done with either
the init or shutdown command. Depending upon your
vendor and system, the init utility is located in either
/etc
or /sbin. The shutdown command, is traditionally in
/usr/sbin. The init utility is very simple: it allows
you to specify a number and the machine then changes
to that run level.
Thus
# init 3
would immediately change the machine to run level 3.
The shutdown command interacts with init and offers
substantially more parameters and options. A -g option
allows
you to specify a grace period of seconds to use before
beginning the
operation (the default is 60), -i signifies which run
level
you want to go to, and -y carries out the action without
asking
for additional confirmation. To change to run level
3 in 15 seconds,
the command would be:
# shutdown -g15 -i3 -y
Once the command is typed, a warning message is broadcast
telling users that the run level is changing (this is
true with init
as well). The system then waits the specified number
of seconds --
allowing users to save files and log off -- before making
the change.
By contrast, init, would tell users the run level is
changing
and would immediately begin changing it without giving
the users time
to protect their work.
Actions Defined in inittab
The inittab file, located in /etc or /sbin,
is an initialization table. It contains a list (or table)
of the actions
that take place when a machine changes to a different
run level. Listing 1
shows a section of an inittab file from an SCO system.
The
line numbers to the left have been added to aid this
discussion. Each
entry is a colon-delimited field consisting of four
entries:
id:rstate:action:process
id is the identification of the process, usually
only two or three letters in length -- one to four is
the allowable
range.
rstate is the required state, or run level,
necessary for the process to execute.
action is a keyword telling init what
to do with the process.
process is the actual command to be carried
out.
Line 3 of Listing 1 is extremely important: it is the
initdefault
line. In this example, each time the system is rebooted,
it will attempt
to change to an initial state of S -- single user. It
could
just as easily be 2 -- multi-user. The file is plain
text,
so to make the system boot to a different level, you
can use any editor
to change this line. The inittab file is not required
for
the operating system to boot -- it is only a convenience.
On most
systems, if the file is erased or damaged, the system
will boot to
single user, and any attempt to change to another state
can cause
it to hang. On other systems, if the entry or file is
missing,
a prompt will ask the console what the run level should
be.
Line 3 of Listing 1 is the only place where the action
field is defined
as initdefault. Other actions that can be specified
are:
boot -- The entry is processed only on bootup
and is not restarted if it dies. init does not wait
for it
to complete running before continuing on to the next
command, and
can run many of these simultaneously. This action is
rarely used.
bootwait -- The entry is processed only
on bootup; init waits for it to finish running and then
die
before continuing. It does not restart the process once
it finishes
or dies off. Line 2 of Listing 1 uses this option with
a utility to
mount and check file systems.
off -- If the process is currently running,
a warning signal is sent, and after 20 seconds the process
is killed
with a kill -9 command. Line 16 shows that when the
run level
is changed to 2 (multiple user) terminal 1 is killed.
This has the
effect of logging that user off; it adds a level of
security that
protects against the possibility of the root user changing
run levels
and walking away from the terminal, thus allowing access
to anyone
who happens to sit there.
once -- When the specified run level is
reached, the process is started. init does not wait
for the
process to terminate before continuing on, and does
not restart it
if it dies. Like boot, this option is not used very
often.
ondemand -- This option has the same meaning
as respawn but is used mostly with a, b, and c levels
(user
defined) (see respawn for more information).
powerfail -- The action is triggered only
when a power failure is at hand. A signal 19 is the
most common indication
of a power failure. A powerfail typically calls a sync
operation.
powerwait -- When a power failure occurs,
this process is run, and init waits until the processing
finishes
before processing anymore commands. Again, sync operations
are the
main purpose of the action.
respawn -- If the process dies after it
has been started, it gets restarted. init, does not
wait for
it to complete execution before continuing on to other
commands. As
lines 8-15 in Listing 1 show, respawn is associated
with terminals;
once a terminal is killed, you want it to respawn and
allow
another login.
syncinit -- This option is not available
on all systems. It tells init to reset the default sync
interval,
that is, the number of seconds until modified memory
disk buffers
are written to the physical disk. Default time is 300
seconds, but
the interval can be set to anything between 15 and 900.
sysinit -- Before init tries to
access the console, it must run this entry, which is
usually reserved
for devices that must be initialized before run levels
are determined.
Line 1 in Listing 1 shows that the Trusted Computing
Base, which is
used for user login and authentication, is initialized
even before
the console is made active, allowing any user to log
in.
wait -- This option starts the process
at the specified run level and causes init to wait until
the
process completes before moving on. This option is associated
with
scripts that perform the run level changes. Lines 4-7
in Listing 1
use this option for every run level change.
Line 2 of Listing 1 shows that the same processes will
be carried
out for run level changes to 2 or 3. Similarly, line
4 shows that
the same processes will be carried out for changes to
run levels 0,
5, or 6. The process carried out by line 4 is a shell
command script
in the /etc directory called rc0.
Listing 2 shows several key routines from the rc0 script
of
an SCO machine. I chose to use SCO because it illustrates
nicely the
steps that are carried out. I added line numbers to
the file for purposes
of this discussion, and then stipped away those lines
that were not
pertinent.
Lines 24 and 81 of Listing 2 work together, first saving
the terminal
settings and then restoring them after completing other
processes.
Line 26 echoes that the system is coming down. Line
42 is where things
get interesting: a test is performed to see if there
is a directory
called /etc/rc0.d. If there is, then any file within
that
directory that begins with a "K" is executed
(lines 44-50).
Next any file within that directory beginning with an
"S"
gets executed (lines 54-60). Line 74 effectively ignores
the standard
kill signal by mapping it to nothing -- theoretically,
up until this point, it is still possible to stop the
shutdown. A
killall is performed to kill all processes with a signal
of
9, then three sync operations are performed. Finally,
drives are unmounted
(line 80), two more syncs are done (line 82), and a
message is echoed
that the system is down. One last sync rounds out the
change to run
level 0.
Similar scripts exist under the names of rc1, rc2,
and rc3. Each performs similar operations. For example,
rc1
checks to see if there is an rc1.d subdirectory. If
there
is, it executes any scripts within that subdirectory
starting with
"K", that any scripts within that subdirectory
starting with
"S".
About K and S Scripts
On older systems, all executable scripts are kept in
a single directory,
with each script combining the S* and K* action (hard
links point to the relevant script). On newer systems,
script files
within each rcx.d subdirectory that begin with a "K"
kill a process that is already running; those that begin
with an "S"
start a process that is not yet running. The names of
these scripts
typically begin with the "K" or "S",
followed by a
two-digit number and a name for the operation. Listing
3 shows a listing
of the rc0.d and rc2.d subdirectories. The two digit
number has no special significance, and can fall anywhere
between
00 and 99. The numbers need not increment in any certain
order, and
a newly created script can take any number not already
in use within
that directory. The only thing to bear in mind is the
scripts are
called for execution with "K*" and "S*";
thus they
are executed in numerical order with 00 (providing it
exists) executed
first and 99 executed last.
It is relatively simple to understand what most of the
scripts do,
since to their names are descriptive. The files displayed
in Listing 3
have the following consequences:
K00ANNOUNCE -- simply echoes "System
services are now being stopped."
K70uucp -- cleans up miscellaneous uucp
locks (/usr/spool/uucp/LCK.*)
K75cron -- links to S75cron. Depending
upon which way it is called, it will either kill the
cron
pid, or start /etc/cron the same script is capable
of
doing both.
K80lp -- links to S80lp. It will
either summon /usr/lib/lpshut or start /usr/lib/lpsched.
If a printer lock exists (/usr/spool/lp/SCHEDLOCK),
it also
removes that.
K86mmdf -- links to S86mmdf.
Depending upon how it is called, it will either start
the mmdf
daemon or kill its associated pid. Like several of these
scripts,
K86mmdf uses the following syntax to find the pid:
pid=`/bin/su root -c "/bin/ps -e" | grep whatever | sed -e 's/^ *//' -e 's/.*//'
S00SYSINIT -- runs additional scripts in
/etc/rc.d/0 and /etc/rc.d/1. This is used only for
historical purposes and to maintain compatibility with
older UNIX\XENIX
versions.
S01MOUNTFSYS -- performs a mountall
to bring up the filesystems and initiate auditing.
S03RECOVERY -- provides crash recovery after
a boot.
S04CLEAN -- removes temporary and lock files.
This is where /tmp gets emptied out.
S05RMTMPFILES -- cleans up any other existing
temporary files.
S15HWDNLOAD -- performs a hardware download.
S16KERNINIT -- performs a kernel initialization.
S20sysetup -- prints system id information,
if it exists; creates the information by sending the
output of uname
-n to /etc/systemid.
S21perf -- fires up the administrative utility
sadc.
S87USRDAEMON -- starts up the user daemons.
S88USRDEFINE -- provides a location where
system specific routines can be placed.
S90RESERVED -- sets several variables, and
mails information about the boot to the root user's
mail file.
You can start and stop additional processes when you
change to one
of the already defined run levels simply by creating
a shell script,
preceding it with "K" or "S", and
placing it in the
appropriate rcx.d subdirectory.
Creating a Run Level
Using the information presented here, you can easily
create your own
run level. Run level 4 is, by default, not used by the
UNIX operating
system. As mentioned earlier, you can use it to customize
your system.
To do so follow these four steps:
1. Create an entry in /etc/inittab. It should resemble
the following:
r4:4:wait:/etc/rc4 1> /dev/console 2>&1 </dev/console
2. Create a script in /etc called rc4 by copying rc0
to rc4, then changing all references from rc0.d to
rc4.d. The only references should be as shown in Listing
1
on lines 42, 44, and 54. Comment out lines 26, 76-80,
82, and 85.
Then change the echo statement on line 84 to say "Change
to Run Level 4 completed."
3. Make an rc4.d subdirectory below /etc.
4. Within /etc/rc4.d create your command scripts. If,
for
example, you want to start a database process when you
change to this
run level, call the script S00DATABASE, and place the
command
to start it within that script. Then create a corresponding
"K"
script to close the database when you change from that
run level.
Significant Files
Several files maintain run level information. /etc/default/boot
is an SCO-specific file that maintains information on
the console
keyboard. /etc/wtmp and /etc/utmp work as opposite
log files to each other. /etc/wtmp keeps a record of
all processes
that are spawned, while /etc/utmp keeps a record of
all processes
that have died. These log files do tend to grow and
should be routinely
trimmed.
Summary
Changing run levels simply entails calling an additional
set of scripts.
Those scripts can either start processes that are not
running or kill
processes that are. Run levels 2 and 3 are operational
states allowing
users to interact with the operating system. Run levels
0, 1, 5, and
6 involve downing the computer or performing maintenance
operations.
Run level 4 is available for administrator definition
and can easily
be used to stop and start additional processes.
About the Author
Emmett Dulaney is a product developer for New Riders
Publishing and
co-author of Inside TCP/IP. He can be reached on CompuServe
at
74507,3713.
|