Peter's Notes: The init Process

/sbin/init is the father of all processes. It is invoked as the last step of the boot process; it's the very first process to run upon booting. If you do a ps ax, you'll see that init is the first process. Before going into init in depth, we need to know about the concept of a runlevel.


At boot, each process (like sendmail, crond or sysklogd) gets started by its own startup script. These startup scripts are garden variety Bourne shell scripts and are run by init. Exactly which startup scripts get run by init is determined by which runlevel the system is being put into. In other words, a runlevel is a way of specifying which set of processes init is to run when the system is booted. There are 7 normal processes (the most common are 1, 3, and 5):
1:single user mode
2: multi-user without NFS (same as 3 if there's no networking)
3: Full multi-user mode
4: unused
5:Full graphical mode
By default, Linux starts with runlevel 3. Why wouldn't you want to start with runlevel 5 to get a nice graphical X login prompt when you boot up? The reason is that you may not have a working X server. If your X server doesn't work and you try to start runlevel 5, you'll have big problems. Once you're sure X is up and stable, you can safely change the default runlevel.

How does init know which set of processes to run for each runlevel? It gets this information from a very important file, /etc/inittab. The Bourne scripts that init runs are all located in /etc/rc.d/init.d, but there are links to them in /etc/rc0.d, ..., rc6.d corresponding to the 7 normal runlevels. If inittab is missing or damaged, only single user mode is possible.

The /etc/inittab File

Each entry in inittab is a single line with 4 fields separated by colons (lines that begin with a # are comment lines):
Suppose we have the entry
in inittab. The field explanations are:
id: A unique 1 or 2 character identifier which init uses internally. You can use any id you want, as long as you make sure each line has a unique id. The id for our sample entry is fb.
runlevel:Which runlevel this entry applies to. If you want this entry to be run for multiple runlevels, simply list them all. Thus our sample entry will be run whenever we enter runlevels 2, 3 or 5.
action:Tells init what to do with the entry. Some actions are: initdefault: init interprets this as the default run level
wait: init starts the process and waits until that process exits
once: init starts this process once when the runlevel is entered.
respawn: The process will be restarted by init whenever it terminates
. There are many more actions, and you can see what each does by looking at man inittab.
process:The name of the process init has to start (not necessary if the action is initdefault).
The processes to run for each runlevel are specified in /etc/inittab. If you look at /etc/inittab, you'll see one of the first lines (all lines starting with # are comments):
which means that when you boot the computer up, you automatically go into runlevel 3. If you want to automatically go into the X GUI when you turn the compture on, change the 3 to a 5. Note that this IS the runlevel upon booting. If you change this value to 0 or 6, you will not be able to boot the computer without a rescue disk. Be careful when changing this line.

Next we have:

# System initialization.
The file /etc/rc.d/rc.sysinit is run for ALL runlevels upon booting. That's why it's located in /etc/rc.d and not one of the /etc/rc.d/rc*.d directories. sysinit initializes networking, activates the swap partition, runs fsck, mounts the /proc partition, sets up plug-n-pray[TM] devices, sound modules, the hostname, NFS/NIS (or not) and RAID devices, and many more small tasks. Basically, this script is responsible for setting up the root filesystem and services necessary to allow single-user operation. This is quite the important script! On other flavors of Unix, this file is sometimes called bccheckrc.

After running rc.sysinit, we have:

l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6
You can see that init runs a script called /etc/rc.d/rc no matter what runlevel we enter, however, it passes the argument "1" to rc when we enter runlevel 1, passes the argument "2" to rc when we enter runlevel 2, etc. The rc script is complex; to learn more about it, see my page on the rc script.

Next we have:

# Things to run in every runlevel. ud::once:/sbin/update # Trap CTRL-ALT-DELETE ca::ctrlaltdel:/sbin/shutdown -t3 -r now
/sbin/update is a binary that starts bdflush daemon. I haven't got a clue what bdflush does. Here are the next lines from my inittab:
# Run gettys in standard runlevels
1:12345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
# Run xdm in runlevel 5
x:5:respawn:/usr/bin/X11/xdm -nodaemon
The program mingetty is responsible for getting your login and password. Basically, it "watches" the tty specified by the argument. Note that for runlevels 2-5, we have 5 mingetty's. These correspond to your 5 virtual consoles that you can access using alt-F1, alt-F2, ... , alt-F5. In runlevel 1, we only have 1 mingetty--why is that? Because runlevel 1 is single user mode. Only one user is allowed on the system, so we only need one virtual console.

Lastly, in runlevel 5, we always run xdm which starts the X server (so you don't have to type startx to get the GUI up).

Changing runlevels

You can change the runlevel using init too. For example, to change to runlevel 5, simply type "init 5". When this happens, init sends the message "terminate" (SIGTERM) to all processes that aren't supposed to exist in runlevel 5. If they don't terminate within 20 seconds, init forces them to die by sending them the "kill signal" (SIGKILL). This is precisely what happens when you shutdown or halt the system. You could even change the 20 seconds to whatever you want. For example, if you specify init -t 100 5, you will change to runlevel 5 and init will wait 100 seconds between sending SIGTERM and SIGKILL signals.

Instead of changing the runlevel using init, you could also change it using /sbin/telinit which is simply a symbolic link to init. I have no idea why telinit exists.