Init scripts
The boot process
After the basic boot process which is in the hands of BIOS and Linux kernel the remaining work is given to the program init. This program is responsible for starting processes, daemons, scripts and at the end the tty console (partially the X server, too) to prepare the user's login.
The configuration of init is quite simple but since many distributions with different concepts have existed it became very confusing.
The differences among the distributions are more basit than just different file and directory names but different ideas in the realisation of the boot process. Later more about this topic.
Basic structure of SysV
Linux knows different (so called) runlevels. With modern distributions the Linux
user gets in contact with his name indirectly.
In general the installation of the system would ask if the user wanted to login
on a console or already with X (using xdm, gdm or kdm). In the latest releases even
this question vanished and the X-server is started automatically.
Interpreted internally both variants belong to different runlevels. A login with console
or X is aquivalent to the runlevels 2 (Multi-User with network) and runlevel 3 (Multi-User
with network and graphical login), respectively.
In these two points nearly all distributions agree.
However you are not restricted to these runlevels. You can create and configure unlimited
runlevels on your system. At least 6 runlevels exist by default with most of the
distributions although a few could be empty.
A more detailed description which function corresponds to which runlevel, can be found
in /etc/inittab.
In the following listing taken from the inittab of a SuSE distribution:
| /etc/inittab (SuSE) |
# runlevel 0 is halt # runlevel S is single-user # runlevel 1 is multi-user without network # runlevel 2 is multi-user with network # runlevel 3 is multi-user with network and xdm # runlevel 6 is reboot |
Changing from one runlevel to another is possible in a running system. Therefore the command
>> init Xexists, where X stands for the desired runlevel. This way you can restart all daemons without rebooting or you could test a changed X configuration (first you change into the single user mode with init S followed by a e.g. init 3).
In addition it could help if you wanted to disconnect a Linux PC from the network (e.g. you had the suspicion that an unauthorised access via the network exists) without taking out the network cable. A simple
>> init Scuts all network connections and then the superuser can search for a Trojan horse.
In addition you see that a reboot or halt of the system is nothing else than a change to the runlevel 6 or 0, respectively. The commands reboot -n and halt are aquivalent to init 6 and init 0 respectively.
Also the default runlevel which is used during booting is set in the /etc/inittab. The entry
id:3:initdefault:defines it. Using SuSE with Yast and changing from the graphical login to the console login, in this line 3 is replaced by a 2. Nothing else!.
Configuration
Linux would not be Linux/Unix if you were not able to configure until eternity.
It can be very important which hardware is initialised in which runlevel.
For example a Laptop that is used mobile in one (or more) company(ies) only needs support for the PCMCIA network card if it is placed in the company. Using it mobile the printer drivers and all netowrk software (drivers, apache, NFS/mounting, NIS ...) are not needed and resources can be saved. This can be very simply realised with different runlevels.
One runlevel for a single computer, another with a network configuration.
It is even possible to configure different runlevels for different networks. If
you changed from one network to another for a running system you need not reboot but
simply start the corresponding runlevel and the network configuration fits to the network.
However this is just one of many ways to use runlevels.
The configuration of runlevels depends on the distribution which is used. Using SuSE you find the configuration files/scripts in /sbin/init.dwhile e.g. RedHat based installations place them at /etc/rc.d/.
Often a symbolic link exists from one directory to the other hoping that the compatibility among the distributions is kept (not more than a sad try).
Unfortunately a consensus is not near and every distributor points out the advantages of his concept.
In the corresponding subdirectory you find all scripts which start several tasks, daemons etc. which are necessary during booting and halting:
| ls /sbin/init.d/ (SuSE) |
i4l network random single alsasound i4l_hardware nfs reboot skeleton apache cron idedma nfsserver route smbfs apmd dhclient inetd scd routed sshd at dummy init.d pcmcia rstatd syslog autofs firewall irda pcnfsd rusersd usb boot gpm kbd portmap rwhod wvdial.dod halt kerneld powerfail sendmail xdm lpd pppoed serial ypclient |
These scripts are for e.g. starting the cron-daemon (cron) which takes care of commands that are executed regularly, starting the web server (apache) up to the initialisation of the USB hardware (usb).
Most scripts have a common structure:
| Structur of an Init-script |
#! /bin/sh
case "$1" in
start)
echo -n "Start service XYZ"
/path/to/XYZ
;;
stop)
echo -n "Stop service XYZ"
killall XYZ
# oder /path/to/XYZ -quit if supported by the program
;;
restart)
$0 stop && $0 start
;;
status)
echo -n "Status printout of the process:"
# A command which prints out information of the running program.
;;
*)
echo "Usage: $0 {start|stop|status|restart}"
exit 1
;;
esac
|
To set which script is executed in which runlevel you set a symbolic link to the script into the subdirectory rcX.d (where X stand for the runlevel) But a few details have to be mentioned:
The symbolic link has to follow a defined name structure. If the script had to be executed during booting the correspoinding link should start with a capital "S", folowed by a two digit number that sets the order in which the scripts are executed and then the name of the script. Starting with S01xxx the scripts are executed with rising numbers up to S99xxxx. The option "start" is added to the script automatically.
The execution of the scipts in a fixed order is necessary because many programs need others before they can be initalised. For example the network could only be used if the PCMCIA network card was initialised.
Similarly the processes are stopped when leaving a runlevel. The corresponding scripts are linked with the pattern K01xxxxx to K99xxxxx.
Thus the directory /sbin/init.d/rc2.d/ of the runlevel 2 could look like:
| ls /sbin/init.d/rc2.d/ (SuSE) |
K19cron K24ypclient S03pcmcia S19idedma K19nscd K30idedma S04dummy S20apache K19smbfs K30random S04firewall_init S20apmd K20apache K35routed S04irda S20at K20apmd K35syslog S05dhclient S20gpm K20at K36nfs S05i4l S20inetd K20gpm K37portmap S05network S20lpd K20inetd K38route S07firewall_setup S20rstatd K20lpd K40dhclient S07route S20rusersd K20rstatd K40i4l S08portmap S20rwhod K20rusersd K40network S09nfs S20sendmail K20rwhod K42pcmcia S09syslog S20sshd K20sendmail K44i4l_hardware S10kbd S21alsasound K20sshd K45dummy S10routed S21cron K21alsasound K45irda S13random S21nscd K22wvdial.dod K51firewall S16ypclient S21smbfs K23nfsserver K99kerneld S17autofs S22wvdial.dod K23pcnfsd S01kerneld S17nfsserver S99firewall_final K24autofs S03i4l_hardware S17pcnfsd |
Already here you see a difference between SuSE distributions and the presented scheme: You find many links in the subdirectories than you wanted to start in general.
What remains ...
As mentioned before, every distribution has its own idea of what a "good boot process"
should look like.
At present while aiming more and more to the desktop market, there is a "need" to hide any complexity of the
system from the users. This step covers a lot of problems because a user who does
not know this system cannot fix problems which might occur or fit to his needs.
This "userfriendly" start-up has gone so far that any messages from the
programs are suppressed at all and only a green done or a
error reports if the task was executed successfully.
If the start failed the user does not get any additional help and has the problem where and
how to fix the error.
Program which optimised to hide are e.g. LPP (Homepage: http://lpp.freelords.org/) which completely hide the boot process using colorful boot logos and status repots. It will only be a matter of time before common desktop oriented distributions will surprise as with these cruelities.
Taking SuSE the Init concept looks like:
All installed and system important tools are automatically built to the corresponding
rcX.d subdirectories. The existence fo the init does not mean that it is
started automatically but the script does only include a test of the global configuration file
/etc/rc.config. In this file the correspoinding variable START_XXX
(e.g. START_HTTPD for apache web-server) has to be set to yes before the script
is executed.
What you win is only the transport of all processes which have to be started during booting to Yast. For a beginner this looks simpler than creating the lniks in the /sbin/init.d subdirectories. However instead of putting the control into another file Yast could directly create or remove the symbolic link. The result would be the same and more standard, too.
On the other hand YAST has a weakness which should not be underestimated. The
variables START_XXX are not independent of the runlevels any longer but have an
influence to all runlevels.
The only way to handle this is to create links only in the runlevles where needed (e.g.
the link to xdm is only in runlevel 3).
If you wanted to create you own runlevel or if you wanted to start processes, which are administrated by YAST only in selected runlevels, you would have to do it yourself. This means you have to remove or create a link, eventually you have to replace existing scripts by you own written scripts.
boot.local
If all this was too complicated for you, you could avoid the scripts and instead use the boot.local. This is a simple script which you find in the /sbin/init.d/ directory and where simple commands can be placed by the system administrator which will be executed during booting the PC.
This file offers a place for processes which have to be started independently of the runlevel.
A short entry of the command which is necessary often saves the creation of a whole init script with all its options (start, stop, status ...).
Unfortunately different ways of realisation exist. The SuSE distribution up to version 6.x has executed the script boot.local at the end after all init-scripts were called. A link to the boot.local which is called S99local(??) exists in all runlevels.
From version 7.0 on the boot.local is called at the beginning, before
all other init scripts.
This can be important because usually you use the boot.local to execute small tools and programs,
where a complete init script would be too much.
If the execution of the boot.local is placed at the beginning many programs would not work
because the hardware they need (e.g. the network card) might not be initialised.
A solution could be your own batch-file in which you place all your small commands and which you link from all runlevels with a link called S99xxxx.
The different distributions
- SuSE:
The processes which are called in the init scripts are administrated by the programs startproc and killproc. startproc created for every process which was started a file with the name process+suffix".pid" in which the process ID (PID) is stored. This file is placed at /var/run/. The program killproc can kill all processes by sending a kill signal to the process-ID which is stored. In addition killproc removes the corresponding PID files.If the start of the process was successful the script would send a $rc_done to inetd which would print the success.
If an error occured ti would send a $rc_failed.
The text which is put to $rc_done and $rc_failed can be set using YAST (or in /etc/rc.config).A typical init script (for version 7.0) has the following structure:
Init-Skript #! /bin/sh # . /etc/rc.status . /etc/rc.config base=${0##*/} link=${base#*[SK][0-9][0-9]} rc_reset case "$1" in start) echo -n "Starting XYZ daemon" startproc /usr/sbin/XYZ rc_status -v ;; stop) echo -n "Shutting down XYZ daemon" killproc -TERM /usr/sbin/XYZ rc_status -v ;; restart) $0 stop && $0 start rc_status ;; reload) # Comman to re-read the configuration file ;; status) echo -n "Checking for XYZ daemon" checkproc /usr/sbin/XYZ && echo "XYZ is up" || echo "No XYZ daemon" ;; probe) # Command to test XYZ ;; *) echo "Usage: $0 {start|stop|status|restart|reload|probe}" exit 1 esac rc_exitA speciality of SuSE 7.0 which was already mentioned above is the start of the script boot.local. In 7.0 it is placed at the beginning before all init-scripts are started while older distributions start this file after executing all init-files.
This could lead into trouble with hardware related programs if the hardware was not initialised before.
A solution could be your own script e.g. /sbin/init.d/boot.last which is called after all scripts were started (symbolic link S99zzzboot.last -> .../boot.last. - RedHat:
If the structure of scripts made by RedHat increased the overview should be decided by yourself. Placing the different calls (start, stop ...) in separate functions does not really improve things.
In addition a lock-file in the /var/lock/subsys/ directory is createdInit script #! /bin/sh # # skeletond Start/Stop the skeleton daemon. # # chkconfig: 2345 90 60 # # processname: skeleton # config: /etc/skeleton # pidfile: /var/run/skeleton.pid # Source function library. . /etc/init.d/functions RETVAL=0 # See how we were called. start() { echo -n "Starting skeleton daemon: " daemon skeleton RETVAL=$? echo [ $RETVAL -eq 0 ] && touch /var/lock/subsys/skeleton return $RETVAL } stop() { echo -n "Stopping skeleton daemon: " killproc skeleton RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/skeleton return $RETVAL } rhstatus() { status skeleton } restart() { stop start } reload() { echo -n "Reloading skeleton daemon configuration: " killproc skeleton -HUP retval=$? echo return $RETVAL } case "$1" in start) start ;; stop) stop ;; restart) restart ;; reload) reload ;; status) rhstatus ;; condrestart) [ -f /var/lock/subsys/skeleton ] && restart || : ;; *) echo "Usage: crond {start|stop|status|restart|condrestart}" exit 1 esac exit $? - Mandrake:
Another skeleton as an example (the distribution itself does not have a skeleton file. The following file was taken from the start script of the cron daemon and was changed slightly.)The init script of the Mandrake distribution has the simplest structure of the three presented scripts and shows nealy no properties which depend on the distribution.
Init-Script #! /bin/sh # # skeleton Start/Stop a daemon. # # chkconfig: 2345 40 60 # # processname: skeleton # config: /etc/skeleton # pidfile: /var/run/skeleton.pid # Source function library. . /etc/rc.d/init.d/functions # See how we were called. case "$1" in start) echo -n "Starting daemon skeleton: " daemon skeletond echo touch /var/lock/subsys/skeletond ;; stop) echo -n "Stopping skeleton daemon: " killproc skeletond echo rm -f /var/lock/subsys/skeletond ;; status) status skeletond ;; restart) killall -HUP skeletond ;; *) echo "Usage: skeleton {start|stop|status|restart}" exit 1 esac exit 0 - Overview:
A short list of skeleton files for different distrubutions:
Hint: Special case laptops
The use of runlevels can be a very good tool, in particular for laptops which are
used in different networks. For example a laptop which is used at work but also in your
local LAN at home.
Usually you would have to reconfigure the network card, the gateway and the DNS
server if you changed the network. In addition a few services which are necessary
at work, are not needed at home (lpd, NIS, NFS ...).
If you created two runlevels, each for one network, the correct configuration
can be chosen and started. Therefore you copy an existing runlevel to e.g.
rc7.d and change it to your desires in the corresponding network.
You should not forget to announce the new runlevel in the file
/etc/inittab, in particular the row
7:123:respawn:/sbin/mingetty tty7has to be added, because otherwise no console is started where you can log in.
In addition you should change the configuration file by a special script which you have to create, i.e. this script copies the existing network configuration to a backup directory and replaces all necessary files by the configuration of the network you need. If the changes are quite exausting you could alternatively replace the total /etc-directory. In any case you have to make sure that the computer is not halted without any /etc-directory, because it cannot start next time.
Finally an entry in the LILO configuration files is necessary which tells the system during booting which configuration has to be started. Therefore you copy the entry for the distribution you used so far and extend it by one append-entry:
| /etc/lilo.conf |
[...]
# entry used so far
image = /boot/kernel_redhat7_z
root = /dev/hda2
label = redhat
#---new entry
image = /boot/kernel_redhat7_z
root = /dev/hda2
append = "init=/sbin/init 7"
label = firma
|
After calling the command lilo you can chose the option "office" during
the next boot process. LILO submits the line which you specified behind append to
the kernel and it will use the runlevel 7.
This script creates the /etc-directory which is needed in your office and
the system is set-up properly.
You see you can start the system with different configurations without creating a
separate partition for each.
Conclusions
The boot process clearly shows the differences between the distributions. Every "huge" distribution has its own imaginiation how the runnlevels should be structured and organized.
The disadvantage is clearly on the side of the users, as usual, who loose the overview when changing the distribution.
A simple and well-thought structure was messed up. Partially the runlevel directories are filled with an enourmous number of links which are not started in the end.
We can only hope that, with upcoming open standards, we get agreement how the sturcture of what the boot process has to look like.
I thank sh0 and zyz for supporting me with the skeleton files.
Homepage: www.libertynet.de
Talkback Area
Enter Own Comment