Chaitu Tech Bits

STARTING LINUX DAEMONS WITH init SCRIPTS

Tuesday, November 23, 2010

In the world of Linux based systems, and also other Unix-like systems, a daemon is a background process that starts during the system boot and runs forever. A daemon provides some kind of service. Some of the examples of daemons are the secure shell daemon sshd, and the print spooler, cupsd, formally known as the common unix printing system daemon.
In this tutorial, we first take a overview of the Linux boot sequence. We look at the traditional System V init process, the different init levels and the system of init scripts. Then, we look at upstart, which takes a different approach to the same job. Finally, we also look at the structure of a typical init script.


THE LINUX BOOT SEQUENCE

Once the processor has been powered-on, the instruction pointer points to the reset vector which is the first instruction to be executed. For the personal computer (PC), the instruction at the reset vector is actually a jump instruction to the BIOS, programmed in flash memory on the motherboard. The BIOS carries out Power On Self Test (POST), and once the POST is successful, tries to load an operating system. BIOS looks for an operating system in devices in the order as configured by the user.
The BIOS loads the first 512-byte sector, called the Master Boot Record (MBR), of the bootable device, which is often a partition on the hard disk, into the RAM and passes control to it. This is the first stage boot loader. The first stage boot loader is quite small and it lacks the capability to read the kernel image from the file system. So the first stage boot loader loads the 1.5 stage boot loader which has the capability to read the kernel image from the file system. The 1.5 stage bootloader loads the stage 2 bootloader, which can display a list of available kernels on a user-selectable splash screen image. Once the user selects, or the timeout completes, the booting of the user-selected or the default kernel starts.

THE init PROCESS

After the kernel image has been decompressed and kernel has been initialized, the first user space process init is created by the kernel. init has the process-id 1. It is the job of init to start further processes for running the system. So init is the parent of all these processes. Also, init adopts all processes whose natural parents have died.

RUN LEVELS

A Linux system works at a certain run levels, based on the configuration of processes running in the system and the functionality provided. The levels are 0-6 and S, or s. Three levels are reserved and are,
  • 0, for system halt
  • 1, for bringing the system to single user mode and,
  • 6, for rebooting the system.
Of the remaining levels, S, or s also bring the system to the single user model. The interpretation of remaining levels varies between implementations. For example, an implementation might provide level 2 for multi-user mode but without some networking protocols like NFS, level 3 for all network services and level 5 for availability of graphical user interface. Levels 2-5 are said to be user-defined and one implementation of level 2 might well be equivalent to level 3 of another and level 5 of yet another implementation. However, in all cases, there is a default run level, where all services are available and the system is fully usable.
There is a Linux command runlevel, which prints the previous and current run levels on the basis of records in the file, /var/run/utmp.

System V init PROCESS

In Unix System V, there is the /etc/inittab file, which provides the script for the init process. /etc/inittab serves two purposes. First, it identifies a default runlevel for the init process, that is, the runlevel to which it should bring up the system to, unless it has been executed with a specific runlevel parameter. When the system is booted, init brings the system to the default runlevel. Second, /etc/inittab gave init a list of programs to be executed for a given runlevel.
Looking at a part of a typical /etc/inittab file,




# The default runlevel
id:2:initdefault:


# Boot-time system configuration/initialization script.
si::sysinit:/etc/rc.sysinit


# What to do in single-user mode.
~:S:wait:/sbin/sulogin


# /etc/init.d executes the S and K scripts upon change
# of runlevel.
#
# Runlevel 0 is halt.
# Runlevel 1 is single-user.
# Runlevels 2-5 are multi-user.
# Runlevel 6 is reboot.


l0:0:wait:/etc/rc 0
l1:1:wait:/etc/rc 1
l2:2:wait:/etc/rc 2
l3:3:wait:/etc/rc 3
l4:4:wait:/etc/rc 4
l5:5:wait:/etc/rc 5
l6:6:wait:/etc/rc 6


# What to do at the CTRL-ALT-DEL
ca::ctrlaltdel:/sbin/shutdown -t3 -r now


# Runlevel 2,3: getty on virtual consoles
1:23:respawn:/sbin/mingetty tty1
2:23:respawn:/sbin/mingetty tty2
3:23:respawn:/sbin/mingetty tty3
4:23:respawn:/sbin/mingetty tty4


 
The entries are of the form id:runlevels:action:process, where id is the identifier of the relevant inittab entry, runlevels are the runlevels at which the entry is to be processed and process refers to the command to be executed. The third field, action tells how init should execute the command in the process field. action can have values like, wait, respawn, initdefault, etc. wait means that init should start this process when it enters this runlevel and wait for its completion. If the system was already at this runlevel and the init command for this runlevel was given, init would not execute this command. respawn means that the process would be restarted whenever it terminates.
Looking at the lines like l2:2:wait:/etc/rc 2 in the inittab file, it means that after entering the given runlevel (2, here), init executes /etc/rc with the runlevel (2, here) parameter. rc uses the runlevel parameter to decide which set of scripts are to be run. For example, in this case, rc, using the runlevel parameter 2, would run the scripts in /etc/rc2.d directory. If we look at /etc/rc2.d directory, we find the following files,


4 -rw-r--r-- 1 root root 677 2010-03-30 12:47 README
0 lrwxrwxrwx 1 root root 20 2010-05-15 22:03 S20fancontrol -> ../init.d/fancontrol
0 lrwxrwxrwx 1 root root 20 2010-05-15 22:03 S20kerneloops -> ../init.d/kerneloops
0 lrwxrwxrwx 1 root root 27 2010-05-15 22:03 S20speech-dispatcher -> ../init.d/speech-dispatcher
0 lrwxrwxrwx 1 root root 19 2010-05-15 22:03 S25bluetooth -> ../init.d/bluetooth
0 lrwxrwxrwx 1 root root 14 2010-05-15 22:03 S50cups -> ../init.d/cups
0 lrwxrwxrwx 1 root root 20 2010-05-15 22:03 S50pulseaudio -> ../init.d/pulseaudio
0 lrwxrwxrwx 1 root root 15 2010-05-15 22:03 S50rsync -> ../init.d/rsync
0 lrwxrwxrwx 1 root root 15 2010-05-15 22:03 S50saned -> ../init.d/saned
0 lrwxrwxrwx 1 root root 19 2010-05-15 22:03 S70dns-clean -> ../init.d/dns-clean
0 lrwxrwxrwx 1 root root 18 2010-05-15 22:03 S70pppd-dns -> ../init.d/pppd-dns
0 lrwxrwxrwx 1 root root 24 2010-05-15 22:03 S90binfmt-support -> ../init.d/binfmt-support
0 lrwxrwxrwx 1 root root 22 2010-05-15 22:03 S99acpi-support -> ../init.d/acpi-support
0 lrwxrwxrwx 1 root root 21 2010-05-15 22:03 S99grub-common -> ../init.d/grub-common
0 lrwxrwxrwx 1 root root 18 2010-05-15 22:03 S99ondemand -> ../init.d/ondemand
0 lrwxrwxrwx 1 root root 18 2010-05-15 22:03 S99rc.local -> ../init.d/rc.local 


Similarly /etc/rc1.d directory has the following files,


0 lrwxrwxrwx 1 root root 20 2010-05-15 22:03 K15pulseaudio -> ../init.d/pulseaudio
0 lrwxrwxrwx 1 root root 22 2010-05-15 22:03 K20acpi-support -> ../init.d/acpi-support
0 lrwxrwxrwx 1 root root 20 2010-05-15 22:03 K20kerneloops -> ../init.d/kerneloops
0 lrwxrwxrwx 1 root root 15 2010-05-15 22:03 K20rsync -> ../init.d/rsync
0 lrwxrwxrwx 1 root root 15 2010-05-15 22:03 K20saned -> ../init.d/saned
0 lrwxrwxrwx 1 root root 27 2010-05-15 22:03 K20speech-dispatcher -> ../init.d/speech-dispatcher
0 lrwxrwxrwx 1 root root 19 2010-05-15 22:03 K74bluetooth -> ../init.d/bluetooth
0 lrwxrwxrwx 1 root root 14 2010-05-15 22:03 K80cups -> ../init.d/cups
4 -rw-r--r-- 1 root root 369 2009-09-08 00:28 README
0 lrwxrwxrwx 1 root root 19 2010-05-15 22:03 S30killprocs -> ../init.d/killprocs
0 lrwxrwxrwx 1 root root 19 2010-05-15 22:03 S70dns-clean -> ../init.d/dns-clean
0 lrwxrwxrwx 1 root root 18 2010-05-15 22:03 S70pppd-dns -> ../init.d/pppd-dns
0 lrwxrwxrwx 1 root root 16 2010-05-15 22:03 S90single -> ../init.d/singl
Obviously, the scripts are in the /etc/init.d directory. A runlevel scripts directory, like /etc/rc1.d or /etc/rc2.d has symbolic links to these scripts. the links start with a K or an S character, followed by a number between 01 and 99. The /etc/rc script executes first the K scripts and then the S scripts, both in the ascending order of the two digit number, following the K or S character in the script link name.

Writing System V init script

A System V init script for starting and stopping a daemon process is written in the directory /etc/init.d. The script should support command line parameters, like start, stop, restart, reload and status. The script is then linked in the different /etc/rcx.d directories, where x is the runlevel. The symbolic links in a /etc/rcx.d directory start with the character S for starting the daemon and a K for stopping or killing a daemon. After an S or K is a two digit sequence number, which determines the order in which the relevant script is run. As per the /etc/inittab entry, the script /etc/rc is run with the runlevel parameter. The runlevel parameter determines the directory /etc/rcx.d in which scripts need to be run. The /etc/rc script, first executes the K scripts and then, the S scripts, both in the ascending order of the two digit sequence number.
Normally, it is not necessary to do the linking of script in various /etc/rcx.d directories manually. One writes the script in the /etc/init.d directory. Then execute the command,


update-rc.d myserver defaults 




init and Upstart

init has been in operation for a long time, but there are difficulties. Most of the problems stem from the fact that init is essentially a synchronous kind of process system. It executes certain scripts when it enters a runlevel sequentially, one after another. It is not able to discover and mount devices, when there is no change in runlevel. The most common example of this is a USB flash drive inserted in one of the USB ports of a system. Similarly, when a network interface become suddenly available, init does not know about it and is not able to do the necessary initialization steps and make the interface usable.
The solution has come from the Ubuntu team in the form of Upstart init process management daemon, which is the replacement for the System V init daemon. Upstart process management daemon was introduced in Ubuntu version 6.04, Edgy Eft, released in October 2006. Upstart is backward compatible with System V init, and is able to run System V init scripts unmodified.
The Upstart init daemon is event-based. It executes jobs in /etc/init directory based on events generated. Events are generated by the init daemon at certain points like startup and shutdown and are also received from other parts of the system like udev. Any part of the system can generate event using the initctl command.

Upstart Events

The startup event is signalled by Upstart init daemon signalling that it has completed its own initialization and that the rest of the system may be started. Other useful events are starting, started, stopping and stopped, emitted as jobs progress from start to completion.

Upstart Jobs

Upstart jobs definitions are kept in text files in the directory /etc/init. The file name of job files must end in .conf. The name of the job is the name of the file sans .conf. The job files must not have the executable permission for anyone. A job may be a task, in which case init's job is just to start it and forget about it. Else, a job may be a service, in which case it is expected to run for ever. If, for any reason, a service terminates, init restarts it. By default, all jobs are deemed to be services, unless there is a task stanza in the job file specifying it to be a task.
Let's look at a sample job file shown below. It is for starting a hypothetical server named myserver. The file is named myserver.conf.


# myserver - starting myserver after system startup
#


description "myserver - example"
author "Yours truly <yt@example.com>"


start on net-device-up IFACE=eth0
stop on runlevel [01S6]


console output


chdir /home/abc/prog/bin


exec /home/abc/prog/bin/myserver 


In the job file above, the lines starting with # are comments. A job file has multiple configuration stanzas. As the names suggest, the description stanza gives a description of the job and the author stanza has a string giving details about the author of the job configuration file. Now, we have the most important start on stanza. myserver depends upon availability of the network interface eth0 for communication with clients. network-interface job emits net-device-up event when the network interface eth0 comes up. The stop on stanza here indicates that the job should stop at runlevels, 0,1, S and 6. By default, the outputs go to /dev/null, so the console stanza says that the outputs should come to console instead of /dev/null. We want myserver to execute in directory /home/abc/prog/bin and chdir stanza ensures that.
Each job file must have a exec or script stanza. exec specifies the binary executable file to be executed for the job whereas script gives the shell script to be executed by the /bin/sh -e command.


RELATED COMMANDS

init(8), update-rc.d(8), initctl(8), inotify(7), runlevel(7), starting(7), started(7), stopping(7) and stopped(7).

REFERENCES

  1. man update-rc.d
  2. Upstart - Getting Started
  3. man 5 init



Share/Bookmark

Related Posts Plugin for WordPress, Blogger...