Linux boot up process - Upstart

Booting a Linux installation involves multiple stages and software components, including firmware initialization, execution of a boot loader, loading and startup of a Linux kernel image, and execution of various startup scripts and daemons. In the previous post, sysvinit is discussed. Now we look into upstart.

Linux upstart

Upstart is an event-based replacement for the /sbin/init daemon which handles starting of tasks and services during boot, stopping them during shutdown and supervising them while the system is running.

It was originally developed for the Ubuntu distribution, but is intended to be suitable for deployment in all Linux distributions as a replacement for the venerable System-V init.

Make sure upstart version of /sbin/init is installed in the system

cgr@cgr-tst1:~$ /sbin/init --version
init (upstart 1.12.1)
Copyright (C) 2006-2014 Canonical Ltd., 2011 Scott James Remnant

This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.
cgr@cgr-tst1:~$

upstart based init File structure

One of key thing upstart is that it is backward compatible with sysvinit, i.e. all the file /etc/inittab, /etc/init.d, /etc/rc[0-6].d/ are still valid.

For upstart, there is a new directory /etc/init/, which holds Job configuration files, see below for a typical ubuntu 14.04 desktop system.

cgr@cgr-tst1:/etc/init$ ls
acpid.conf                   modemmanager.conf                 rcS.conf
alsa-restore.conf            mountall-bootclean.sh.conf        rc-sysinit.conf
alsa-state.conf              mountall.conf                     resolvconf.conf
alsa-store.conf              mountall-net.conf                 rfkill-restore.conf
anacron.conf                 mountall-reboot.conf              rfkill-store.conf
apport.conf                  mountall.sh.conf                  rsyslog.conf
avahi-cups-reload.conf       mountall-shell.conf               ser2net.conf
avahi-daemon.conf            mountdevsubfs.sh.conf             setvtrgb.conf
bluetooth.conf               mounted-debugfs.conf              shutdown.conf
bootmisc.sh.conf             mounted-dev.conf                  ssh.conf
checkfs.sh.conf              mounted-proc.conf                 startpar-bridge.conf
checkroot-bootclean.sh.conf  mounted-run.conf                  systemd-logind.conf
checkroot.sh.conf            mounted-tmp.conf                  tty1.conf
console.conf                 mounted-var.conf                  tty2.conf
console-font.conf            mountkernfs.sh.conf               tty3.conf
console-setup.conf           mountnfs-bootclean.sh.conf        tty4.conf
container-detect.conf        mountnfs.sh.conf                  tty5.conf
control-alt-delete.conf      mtab.sh.conf                      tty6.conf
cron.conf                    networking.conf                   udev.conf
cups-browsed.conf            network-interface.conf            udev-fallback-graphics.conf
cups.conf                    network-interface-container.conf  udev-finish.conf
dbus.conf                    network-interface-security.conf   udevmonitor.conf
dmesg.conf                   network-manager.conf              udevtrigger.conf
failsafe.conf                passwd.conf                       ufw.conf
failsafe-x.conf              plymouth.conf                     upstart-file-bridge.conf
flush-early-job-log.conf     plymouth-log.conf                 upstart-socket-bridge.conf
friendly-recovery.conf       plymouth-ready.conf               upstart-udev-bridge.conf
gpu-manager.conf             plymouth-shutdown.conf            ureadahead.conf
hostname.conf                plymouth-splash.conf              ureadahead-other.conf
hwclock.conf                 plymouth-stop.conf                usb-modeswitch-upstart.conf
hwclock-save.conf            plymouth-upstart-bridge.conf      wait-for-state.conf
irqbalance.conf              procps.conf                       whoopsie.conf
kmod.conf                    pulseaudio.conf
lightdm.conf                 rc.conf
cgr@cgr-tst1:/etc/init$

Writing Jobs

Jobs are defined in files placed in /etc/init, the name of the job is the filename under this directory without the .conf extension. They are plain text files and should not be executable.

The format treats one or more space or tabs as whitespace, which is skipped unless placed in single or double quotes. Line breaks are permitted within quotes, or if preceeded by a backslash. Comments begin with a ‘#’ and continue until the end of the line.

exec and script

All job files must have either an exec or script stanza. This specifies what will be run for the job.

exec /bin/foo --opt -xyz foo bar

script instead gives shell script code that will be executed using /bin/sh. The -e shell option is used, so any command that fails will terminate the script. The stanza is terminated by a line containing just “end script”.

script
    # do some stuff
    if [ ... ]; then
        ...
    fi
end script

Below is an example of ser2net Job, which is to start “ser2net” job when it is in runlevel 2,3,4,5. In pre-start, it makes sure it is executable.

cgr@cgr-tst1:/etc/init$ cat ser2net.conf
# /usr/local/sbin/ser2net -p 4000 -c /etc/ser2net.conf -P /var/run/ser2net.pid
# The ser2net server provide serail to tcp access to act as console server.

description     "ser2net server"

start on runlevel [2345]
stop on runlevel [!2345]

respawn
respawn limit 10 5
umask 022

pre-start script
    test -x /usr/local/sbin/ser2net || { stop; exit 0; }
end script

exec /usr/local/sbin/ser2net -p 4000 -c /etc/ser2net.conf -P /var/run/ser2net.pid
cgr@cgr-tst1:/etc/init$

start on and stop on

Your job is now able to be started and stopped manually by a system administrator, however you also probably want it to be started and stopped automatically when events are emitted.

The primary event emitted by upstart is startup which is when the machine is first started (without writable filesystems or networking).

If you’re using the example jobs, you will also have runlevel X events, where X is one of 0–6 or S. Jobs will be run alongside the init scripts for that runlevel.

Finally other jobs generate events as they are run; you can have yours run when another job stops by using stopped job. The other useful job event is started job.

You list the events you want to start your job with start on, and the events that stop your job with stop on.

start on startup

start on runlevel [23]

start on stopped rcS

start on started tty

Job Control

start, stop, status

Jobs may be started and stopped manually by using the start and stop commands, usually installed into /sbin. Each takes a job name, and outputs the final status (see below).

cgr@cgr-tst1:/etc/init$ which start
/sbin/start
cgr@cgr-tst1:/etc/init$ which stop
/sbin/stop
cgr@cgr-tst1:/etc/init$ which status
/sbin/status
cgr@cgr-tst1:/etc/init$ initctl list | grep tty
tty4 start/running, process 1173
tty5 start/running, process 1177
tty2 start/running, process 1183
tty3 start/running, process 1184
tty1 start/running, process 1381
tty6 start/running, process 1188
cgr@cgr-tst1:/etc/init$ sudo stop tty6
[sudo] password for cgr:
tty6 stop/waiting
cgr@cgr-tst1:/etc/init$ initctl list | grep tty
tty4 start/running, process 1173
tty5 start/running, process 1177
tty2 start/running, process 1183
tty3 start/running, process 1184
tty1 start/running, process 1381
tty6 stop/waiting
cgr@cgr-tst1:/etc/init$ sudo start tty6
tty6 start/running, process 8214
cgr@cgr-tst1:/etc/init$ initctl list | grep tty
tty4 start/running, process 1173
tty5 start/running, process 1177
tty2 start/running, process 1183
tty3 start/running, process 1184
tty1 start/running, process 1381
tty6 start/running, process 8214
cgr@cgr-tst1:/etc/init$
cgr@cgr-tst1:/etc/init$ status tty6
tty6 start/running, process 8214
cgr@cgr-tst1:/etc/init$

initctl list

A list of all jobs and their states can be obtained by using initctl list.

cgr@cgr-tst1:/etc/init$ sudo initctl list
avahi-daemon start/running, process 893
mountnfs-bootclean.sh start/running
rsyslog start/running, process 664
tty4 start/running, process 1173
udev start/running, process 290
upstart-udev-bridge start/running, process 281
whoopsie start/running, process 1391
avahi-cups-reload stop/waiting
mountall-net stop/waiting
passwd stop/waiting
rc stop/waiting
startpar-bridge stop/waiting
ureadahead-other stop/waiting
apport start/running
systemd-logind start/running, process 890
tty5 start/running, process 1177
console-setup stop/waiting
gpu-manager stop/waiting
.........................................
network-interface-security (networking) start/running
networking start/running
dmesg stop/waiting
procps stop/waiting
rfkill-restore stop/waiting
tty6 start/running, process 8214
console-font stop/waiting
network-interface-container stop/waiting
ureadahead stop/waiting
cgr@cgr-tst1:/etc/init$

service vs job

The above we discussed is called job, which is defined by a file under /etc/init/ with extention “.conf”. In ubuntu distribution, you will see “service”, which is essentially the task started by sysvinit way.

cgr@cgr-tst1:/etc/init$ sudo service --status-all
 [ + ]  acpid
 [ - ]  anacron
 [ + ]  apparmor
 [ ? ]  apport
 [ + ]  avahi-daemon
 [ + ]  bluetooth
 [ - ]  brltty
 [ ? ]  console-setup
 [ + ]  cron
 [ + ]  cups
 [ + ]  cups-browsed
 [ - ]  dbus
 [ ? ]  dns-clean
 [ + ]  friendly-recovery
 [ - ]  grub-common
 [ ? ]  irqbalance
 [ + ]  kerneloops
 [ ? ]  killprocs
 [ ? ]  kmod
 [ ? ]  lightdm
 [ ? ]  networking
 [ ? ]  ondemand
 [ ? ]  pppd-dns
 [ - ]  procps
 [ - ]  pulseaudio
 [ ? ]  rc.local
 [ + ]  resolvconf
 [ - ]  rsync
 [ + ]  rsyslog
 [ + ]  saned
 [ ? ]  screen-cleanup
 [ ? ]  sendsigs
 [ - ]  ser2net
 [ ? ]  speech-dispatcher
 [ - ]  ssh
 [ - ]  sudo
 [ + ]  udev
 [ ? ]  umountfs
 [ ? ]  umountnfs.sh
 [ ? ]  umountroot
 [ - ]  unattended-upgrades
 [ - ]  urandom
 [ - ]  x11-common
cgr@cgr-tst1:/etc/init$

initctl list will show the process managed using upstart native file. service will show those using a more traditional init script. systemctl will show the one using systemd native format.