Booting the Kernel

The bootloader as Grub loads the kernel. The kernel is the extracting itself and starts itself.

If something goes wrong the kernel stops with a panic messages. Sometimes the kernel hangs. I this case it is worth to wait, maybe it is just a blocker and the kernel continuous after a while (e.g. after 1 min). If the system comes up, dmesg will show the trouble and its first column is the time, so the hanger can easily be found.

When the kernel comes up in a traditionally SysVinit system it starts /sbin/init. Grub can be configured to let the kernel start any other program than init. Some newer Linux systems have replaced init by the newer systemd. On those system /usr/lib/systemd/systemd will be called instead.

To get a nice boot sequence seeing one tux per processor, you need to enable framebuffer support in the kernel, select therefore VESA VGA graphics and Framebuffer Console support.

SysVinit

SysVinit makes uses init and init reads /etc/inittab and executes the scripts in /etc/init.d accordingly. Since this configuration is very flexible and can be easy adapted many versions of the scripts exist. This is one of the main differences between the different Linux distributions. The following is based on the scripts OpenRC https://wiki.gentoo.org/wiki/Project:OpenRC uses. OpenRC is what uses init on a Gentoo Linux system.

OpenRC

Openrc makes use of c programs and allows that script can run in parallel. See: https://wiki.gentoo.org/wiki/OpenRC .

The configuration is in /etc/rc.conf. It can create a log file (optionally verbose) in /var/log/rc.log, however during booting no writable file-system might be available and therefore the logger might create an error. A way out might be specify an other path than /var/log as setting up an initial ram disk.

A option exist and set by default to interrupt the boot process by pressing the I key.

/etc/conf.d/modules holds the kernel modules to be loaded.

Inittab

As default the Linux kernel starts the program init as first process.

init is a regular program see man init. init reads the file /etc/inittab that has a list of instructions for init.

There are usually 7 runlevels (0 to 6). A runlevel is a mode of operation defined in /etc/inittab.

The program init can also be called when Linux is running to change the runlevel.

The command init 0 changes to runlevel halt and turns off the computer.

The command init 6 causes a reboot.

The program init creates the binary log files /var/run/utmp and /var/log/wtmp.

The file /etc/inittab contains individual lines having the following structure:

idcode: runlevel: action: command

  1. The idcode has to be an unique 2 character string.

  2. The runlevel is a number 0 to 6 or a list of runlevel numbers indicating on what runlevels the line has to be interpreted.

  3. The action field defines the purpose of the line (initdefault, ctrlaltdelete, once, respawn, sysinit, wait)

  4. Finally the command is the command executed in the way the line defines it (runlevel and action). As any command the command can also have command line arguments.

The contents of /etc/inittab is Linux distribution depending. In Gentoo /etc/inittab is configured that the script /sbin/rc is called with various script parameters (shutdown, boot, sysinit).

Traditional distributions made use of simple bash scripts for the purpose of rc. This is more open, but has some limitations. Gentoo uses the bash script rc script, however it does not use bash directly it uses /sbin/runscript. runscript is a program written in c that calls runscript.sh (also in /sbin) both are part of Gentoo's baselayout, both form a initscript handler that calls bash. As root type runscript help. The source of the c program runscript is delivered inside baselayout-<version>.tar.bz2 that can be found in /usr/portage/distfiles when not present download it from http://sources.gentoo.org/cgi-bin/viewvc.cgi/baselayout/. There are many copies of runscript on the pc:

whereis runscript

runscript: /usr/bin/runscript /sbin/runscript /usr/share/man/man1/runscript.1.bz2 /usr/share/man/man8/runscript.8.bz2

The /usr/sbin/runscript will be taken at boot as seen by the PATH environmental variable:

echo $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin:

or found by which:

which runscript

/usr/sbin/runscript

To see from where all the other runscripts are coming from:

qfile /usr/bin/runscript

net-dialup/minicom (/usr/bin/runscript)

Or all in one command

qfile $(whereis runscript)

sys-apps/openrc (/usr/share/man/man8/runscript.8.bz2)

sys-apps/openrc (/sbin/runscript)

net-dialup/minicom (/usr/share/man/man1/runscript.1.bz2)

net-dialup/minicom (/usr/bin/runscript)

The script interpreter for minicom is also called runscript, but is a completely different program. If the path and which would point to this binary, then the system would no more to be able to boot!

To see what init is doing, runscript.c can be hacked. Copy baselayout somewhere and go into the /src directory. There modify the main by putting some print statements:

int main(int argc, char *argv[])
{
"
"
int debugcounter;
printf("\033[33mDebug support in runscript, %i command line parameters\n",argc);
for(debugcounter=0;debugcounter<argc;debugcounter++){
  printf("%i:%s\n",debugcounter,argv[debugcounter]);
}
printf("\033[m\n");

Save the file and run make in this directory, now backup the runscript in /sbin and copy over the new runscript. Now when you boot or do a shutdown, you can observe how init is calling rc and how the /etc/init.d routines are called. This is a temporary hack and will be wiped off when you do a re-emerge baselayout, or just copy over the saved runscript.

The hack could be expanded to debug further the rc scripts! It would be nice to have something as this not as hack, but as official baselayout feature!

Improving the boot time

The /sbin/init boots one service after an other. This is quite robust and reliable but not very fast. The PC waits e.g. for a IP address from the DHCP server and continues just after having it receive. Instead of waiting it could initialize other hardware and do other things.

You could work with static IP addresses to avoid waiting for DHCP.

To get some other slight optimization there is also an option in the /etc/conf.d/rc

RC_PARALLEL_STARTUP="yes"

However the bootup messages are drastically reduced and you will not easily see if the system has a problem.

There is also the kernel parameter fastboot that can be added to the grub

title=Gentoo Linux fastboot 2.6.36-gentoo-r5-2010-12-27
root (hd0,0)
kernel /kernel-2.6.36-gentoo-r5-2010-12-27 root=/dev/sda2 vga=0x31B fastboot

Mounting the file systems

init is also responsible to read /etc/fstab and mount the file system. In fact this is one of the first action it does. However it does this not automatically, it reads this out of /etc/inittab

si::sysinit:/sbin/rc sysinit

Boot script and default runlevel

After having mounted the file systems, init reads from /etc/inittab to start the bootscripts:

rc::bootwait:/sbin/rc boot

after this the default runlevel 3 is read from /etc/inittab

id:3:initdefault:

Then all scripts and login shells from this runlevel are started.

Initscripts

/etc/init.d holds all the scripts that init starts. Which boot scripts start depends on the users needs and runlevels. The rc-update program finally configures what scripts in /etc/init.d have to run and when. Type rc-update -s to get the view of the situation. The configuration is stored in /etc/runlevels where every runlevel has a directory and those directories have links to the scripts in /etc/init.d.

The scripts can also be started, stopped or restarted

/etc/init.d/ntpd stop

/etc/init.d/ntpd start

/etc/init.d/ntpd restart

Instead of typing (or press the tab key) the path and service the command rc-service <service>can be typed in. This sounds like less work however the service has to be typed in completely and correctly. The first approach pressing the tab key is therefore faster and more reliable.

What init handles can be see by

rc-update -s or full command rc-update show

The /etc/init.d scripts can be linked to init by

rc-update add lircd default

rc-update del lircd

To see what is going on with the run levels:

rc-status boot

rc-status default

rc-status -a or rc-status --all

The command runlevel shows preceding and actual runlevel.

Additional runlevels can be added and even be selected on boot time telling grub to pass a parameter via kernel to init. The runlevel offline can be used with the keyword softlevel (or bootlevel) on a laptop to give an alternative to not start the network.

title Gentoo Linux Offline Usage
root (hd0,0)
kernel (hd0,0)/kernel-2.4.25 root=/dev/hda3 softlevel=offline

The scripts make use of their configuration data found under /etc/conf.d The file /etc/conf.d/local.start is a bit special since commands can be put there that will be started on boot. A cleaner way is writing boot scripts for /etc/init.d

Writing OpenRC scripts

Once OpenRC was a project on its own, but it became an orphaned so Gentoo took it over. Unfortunately the documentation is now a bit vague, The fact that many Linux distributions move away from SysVinit to systemd gives not much hope that the documentation improves. Reverse engineering from scripts under /etc/init.d as ntpd and ntp-client is a way to go however a good documentation can also be found at http://big-elephants.com/2013-01/writing-your-own-init-scripts/

Just on script is required to start and stop the daemons, it should look as follows

#!/sbin/runscript
depend(){
}
start(){
}
stop(){
}

The depend function can have keywords as need,use, before and after and allows to set a startup sequence.

depend(){
  need apache2
}

The start function starts the daemon using the start-stop-daemon function (see man start-stop-daemon) with all options as desired

start(){
  ebegin "starting my daemon"
  start-stop-daemon --background --start --exec <daemon> \ 
  --make-pidfile --pid-file /var/run/<pid file>.pid
  eend $?
}

Creating a pid file is optional but helps OpenRC to find the process number and to stop the script when desired.

The stop function then could look as

stop(){
  ebegin "stop my daemon"
  start-stop-daemon --stop --exec daemon \ 
  --pid-file /var/run/pid file.pid
  eend $?
}

Login at startup

Additionally /etc/inittab is responsible for the login. Historically there was one UNIX computer that had many terminals connected via RS232 to it. Now this is emulated with different console windows (getty). The agetty lines define such a virtual terminal with the virtual baudrate of 28400.

c1:12345:respawn:/sbin/agetty 38400 tty1 linux

Or if you really want to log in via RS232

#s0:12345:respawn:/sbin/agetty 9600 ttyS0 vt100

There is also mingetty that allows automatic login of users without password. Just emerge mingetty and put a line as

1:3:respawn:/sbin/mingetty --autologin <USER> tty1

to replace agetty and it parameters.

systemd

systemd is a replacement for sysvinit. Unfortunately there is a lot of controversy about it but finally it has made it in most of the Linux distributions as default start up method.

Some links: http://www.h-online.com/open/features/Control-Centre-The-systemd-Linux-init-system-1565543.html or the original German version https://wiki.debian.org/systemd https://wiki.archlinux.org/index.php/systemd https://wiki.archlinux.org/index.php/Network_Configuration, https://www.digitalocean.com/community/tutorials/systemd-essentials-working-with-services-units-and-the-journal

Using systemd makes the different Linux distributions very similar. What stays different is the package handling and management.

/etc/mtab is handled differently since systemd does mounting. For backward compatibility do or check ln -sf /proc/self/mounts /etc/mtab

systemd does not require a udev package since it includes it (this has put the pressure to distributions using OpenRC to fork udev in a separate package).

systemd replaces ConsoleKit

Dealing with /etc/fstab additional .mount and .swap units can be automatically created

comment=systemd.automount

can be added to the drives in /etc/fstab to convert them to automount drives and not have the system waiting until such typically network drives are ready.

Since systemd is running all the time also a gui tool systemadm is available.

systemd-analyze tells how long the boot process was taking

There is support to make a svg graphics as bootchart systemd-analyze plot > plot.svg or systemd-analyze dot | dot -Tsvg > systemd.svg to convert it first to dot format and then having dot making the dependengy graph. Or simply see the ranking of what took long to start systemd-analyze blame

Keyboard layout can be listed as localectl list-keymaps and loaded as root with loadkeys <keymap as sg> or persistent by localectl set-keymap --no-convert <keymap> this modifies /etc/vconsole.conf obviously /etc/vconsole.conf could also be edited using an editor.

systemctl poweroff turns off the computer and systemctl reboot reboots it. More precise systemctrl calls the unit poweroff.target that is in /usr/lib/systemd/system

Modules not loaded automatically can be listed (one per line) and added to files like /etc/modules-load.d/<some name>.conf

The network must probably be started. In case of dhcp start the client daemon dhcpcd eth0 or start it via its unit systemctl start dhcpcd@eth0.service

Boot with systemd

The kernel must know to start systemd and not init after it has booted. For grub legacy put

kernel /vmlinuz root=/dev/sda2 init=/usr/lib/systemd/systemd

in /boot/grub/grub.conf and for grub 2 put

GRUB_CMDLINE_LINUX="init=/usr/lib/systemd/systemd"

in /etc/default/grub

Systemd units

The units are text files and have different file extensions as

  • .service to start a service (e.g a daemon)

  • .mount to mount a filesystem (there is also .automount)

  • .socket prepare a socket for a listener and when accessed trigger an action

  • .path to monitor accesses to a file or directory and trigger an action

systemd handle services as known from sysvinit systems:

systemctl start <name>.service starts a service

systemctl stop <name>.service stops a service

systemctl restart <name>.service stops and then starts a service

systemctl reload <name>.service similar to restart is reload however normal functionality of the service keeps maintained.

sysemctl status <name>.service shows the status

systemctl --failed to show what failed

systemctl cat <name>.service to read the file without dealing with its path

systemctl list-dependencies <name>.service or systemctl list-dependencies --all <name>.service to see its dependencies

systemctl show <name>.service to see the low level details

systemctl edit <name>.service or systemctl edit --full <name>.service to edit it without dealing with its path followed by systemctl daemon-reload to have effect

Available units can be seen by

ls /usr/lib/systemd/system

systemctl --all --full

systemctl list-units or simply systemctl

systemctl list-units --all

systemctl list-unit-files

systemctl | grep running

systemctl list-unit-files | grep enabled

Customization can be made by copying and modifying those files to /etc/systemd/system

systemd calls more or less it units in parallel. If a unit calls an other that is not ready, then systemd buffers the request using sockets.

Systemd can create automatically additional units as when devices are plugged in. Therefore it uses in udev rules

TAG+="systemd"

Systemd targets

systemd targets are units as well but are used to group units and have them started together and form therefore something similar as runlevels in a sysvinit system.

systemctl list-unit-files --type=target lists the unit files that are targets

Adding a services to the list of being started at boot (the boot.target) is more uniform:

systemctl enable <name>.service enable automatic start at boot

systemctl disable <name>.service disable automatic start at boot

systemctl get-default shows the targets that are run at boot

Other targets exist as rescue.target, multi-user.target

systemctl set-default multi-user.target sets it

Finally everything are links so the same could be achieved by ln -sf /lib/systemd/system/multi-user.target /etc/systemd/system/default.target makes the multiuser-target the default target.

systemctl list-dependencies multi-user.target show what depends on it.

systemctl isolate multi-user.target will stop all targets except the multi-user.target

Journal the systemd logger

systemd does not need a logger since it includes the logger journal. It can be configured via /etc/systemd/journald.conf

To have the log stored on the disk /var/log/journal

Storage=persistent

or mkdir -p /var/log/journal

To set maximum size on disk

SystemMaxUse=50M

Limits to 50MByte if this is missing it will be limited to 10% of the partition size.

The log is binary and not ASCII and can be read via journalctl, for just the current boot journalctl -b or for the kernel messages journalctl -k.

journalctl -u <name>.service will show what has been logged for a service.

The journal can feed a classic logger by systemctl enable syslog-ng so the log becomes ASCII again.


Linurs startpage