The Linux Saga: boot loader, initrd & Sys V
[ Tuesday, 22 July 2008, Keyto ]
Linux was filling up the memory. The boot loader was fetching more and more kilobytes of code. Thoughtlessly, without emotion. But what kind of emotions can we expect from a boot loader, honestly? Bit after bit, byte after byte, incoming chunks of code produced within many years of common effort, by many wise folks. They are the soul of the System. Yet loading, chunk after chunk, until the last bit. The boot loader took a look at its child. - Your time will come, yet again. - he said, and started loading the initrd image. Just like before, it worked very hard. When all required data was delivered at last, he delegated to the kernel, stepping out to the shadow, himself. The kernel came into life. Without hesitating, without complaining. It started suddenly and looked as if it had worked for hours already. And then… the darkness came. The Mad programmer pressed the reset key with a crazy smile. - Everything works exactly as I planned. But… what next…? - he thought. The programmer was Mad, but apart from that, he was a genius. He did not precede his work with the design phase. He just sat and coded. So now, he had at least three options to choose from. At least.
This article is a continuation of The Linux Saga: Preface.
Chapter 1: The beginning – the boot loader
How does the system startup look like? This question usually does not come into mind of a normal computer user. Oh, he presses the power button, goes to the kitchen to make a coffee and when he comes back, the password can be entered on the screen in the prepared field. Sometimes however, in the minds of a bit more keen computer enthusiasts, the question is born “how does it actually work?” It’s no black magic. This is what we all agree to. So, how? Well, that’s easy – the computer executes a series of commands ordered in some logical way, a pattern. But… how does it “know” what to run and when? All in all the System is not just one huge executable. There are tens of them, if not hundreds. So, how does it manage it all?
Well, first of all - some activities need to be performed regardless of the type of programs we want to run in the System and how we want to run them. We have already agreed that the power is on, the coffee is getting cold, the hardware looks alright. The first app, which has a pleasure of executing the prepared commands, is the boot loader (also known as boot manager). At this stage we can’t talk about the operating system, yet. We have only a booting program which once executed, is responsible for picking up the system kernel from a given location — stated in the configuration file — and loading it to the memory. Pretty straightforward, isn’t it. But the boot loader has one more task to perform. It needs to load an initrd image. Now what kind of animal is that?
Chapter 2: initrd
The name initrd is an abbreviation for “Initial RAM disk”. It’s a file, which includes the image of a file system. The idea is this: RAM disk (that is, a carefully selected chunk of memory which is visible for everyone else as just another data device - it could be described as a virtual hard drive) is kept in the computer memory. Its content is kept in the initrd file. Now the obvious question comes: why do all that? Why can’t we simply use the hard drive directly? Well we could, but the virtual drive has its indisputable benefits. First of all it gives us the certainty that we are going to have a usable file system regardless, if we manage to attach any non-virtual disk. Furthermore, let’s assume we have a new super-modern Ultra-SAS-SATA X device (they will be in common use in 55 years from now, but we have already got a preview version for testing, don’t ask us how we got it). At this moment the Linux kernel has no clue how to mount such a disk, and remember that monolithic kernels like Linux, are exclusively responsible for handling the hardware. So if the kernel “by itself” cannot handle it, then the wise guess would be that it has a module to do the work for it. Where is this module? On a hard drive, of course. And there we have a vicious circle, because it was the disk we wanted to access in the first place. Sad and tragic? Not at all. We can load the module thanks to the initrd “patent”! The file system embedded into the initrd image has the module for this particular hard drive, so everything should just work. Great. Now you are probably going to ask a question like: “How come the kernel could not access this freaking module, but the boot manager could do it without issues?”. The boot manager and a working operating system are two different universes. When the boot manager is in use, there is no operating system, and vice-versa. So they are not to be compared. Apart from that, where have I written that the boot manager has to grab the kernel image from the same disk, where the destination file system is? A few years ago I used a computer equipped with a SATA disk and Red Hat 8.0. Te root (”/”) directory was located on the SATA disk, which the kernel “couldn’t see”.”. To eliminate this “little inconvenience” the kernel itself together with the boot manager and a specially prepared initrd image was located on a “regular” old IDE disk. There is of course a number of other examples. The war veterans may remember how they used to install Slackware in the old days. They had to generate two floppy images: the first one with the boot loader and the image, the second with the initrd image (called the rootdisk). The crucial resident of the latter was a setup program used to install good old Slackware. But let’s stop these theoretic discussions and make some experiment instead:
Experiment 1: The easiest way is to use some of the LiveCD distros. Let’s take SLAX 6.0 then and here is what we do next:
- Run the system from the CD.
- Create an /initr d directory
- Find the /mnt/live/mnt/hdc/boot/initrd.gz file and unpack its content to the newly created
/initrddirectory. We can use Ark for this purpose which is available in the context menu for the file in KDE or choose the old fashioned way in the command line. - Create a new directory:
/initrd/mount - Execute:
root@slax:/mount -o loop /initrd/initrd /initrd/mount - In
/initrd/mountwe can now view the “mysterious” initrd image. I’d like to bring your attention to the scripts, which I described in detail in the recent article SLAX… how does it work? - End of experiment.
Cutting the discussion about initrd, with or without it, we do have a fully functional operating system. Here I stick to the definition, according to which the OS is the kernel and everything else is the applications. We also do have a file system prepared. By saying “prepared” I mean ready to use, not necessarily mounted! Our kernel only requires that there is a virtual file system ready to use. It can perfectly be just an empty root directory. Mounting disks is a complete new story. Now the time has come to run the system. Preferably, the procedure should be fully automatic. We would like to get a working system ready to work with all the traditional components like the graphical environment, sound, mouse, networking, web server, file sharing programs in the local network, etc. So now the real troubles begin, because the theory and practice look very different in many cases. Very different…
Chapter 3: System runlevels
Linux is a multi-task system. Let’s take it as a point of reference. Its multi-task capability is for a statistical user such obvious that he hardly even thinks about it. From the machine’s perspective, the case is simple - it is only supposed to run many tasks at once. It is important to realize (for real) that the machine does not care too much whether it renders images, serves web pages or calculates the number or words in a document. Either of them are logical-arithmetic operations that end up as binary ones when they reach the processor. Logical distinction between office suites, network applications and games makes only sense for us, humans (and perhaps also aliens, but we’ll get back to them later). From this perspective, multi-tasking is not such an obvious matter. What does it actually mean?
- That users can run multiple applications?
- That many users can log into one computer?
- That many users can run many programs?
If we think of multi-tasking in such terms, we are actually talking about applications that, when run at the same moment, describe the functionality of the system. I’ll state it explicitly. Linux alone is no Transformer. Once started, it runs just as it has been compiled. The rest is done by the applications launched on its top. If we run on our machine a hypothetical set of apps, a minimal set, we will indeed have the option of running many programs but only in text mode and only if we are physically sitting next to the machine. Additional apps may add the ability to handle multiple users, other enable the network, and yet another allow users to log in through this network. A little app called ’sshd’ makes it possible to remotely administer our machines using the SSH protocol. Even more apps “organize” the graphical interface, the sound, and so on and so on… Putting it differently - certain functionalities are provided by certain apps. These sets of apps providing certain functionalities are grouped into so called runlevels. It has been agreed that we have eight of them, marked with digits: 0 to 6 and an „S” (or „s”) level. Also, the following interpretation has been proposed:
| S | …during the system boot-up process. In theory the result of running them should be a basic system in one user mode… |
| 0 | …during the shutdown. |
| 1 | …single user mode. Used to administer the system with root privileges. A minimal set of apps is launched. No network, no graphical interface. |
| 2 | …multi-user environment, text mode, either with no network or with network but of crippled functionality. |
| 3 | …full multi-user mode, still in text mode but this time with the network, sound and all the goodies… |
| 4 | …personal configuration, usually same as in mode 3. |
| 5 | …same as mode 3 but with graphical environment. A so called “full functionality”. |
| 6 | …during system reboot. |
Slackware, runlevel 3
As I’ve written before - “it’s used to be like that” and that is how it looks like e.g. in Red Hat or Fedora, but it’s not difficult to figure out that there’s a whole bunch of exceptions for this “rule”. For example:
Debian - the default mode is 2, the multi-user mode, where the net, the graphical environment, the sound and many more technical goodies can work. Levels 3-5 don’t mean anything, or - as one may say - they mean the same as level 2.
Ubuntu - as above, is of course based on Debian.
Slackware - modes 2 and 4 are not used, but configured as level 3. Even more “funny” is the fact, which level is the default in a particular distro. And so is:
- Debian / Ubuntu - level 2,
- Slackware - level 3, (which gives, notabene, a lower functionality than the Debian level 2),
- Gentoo - level 3,
- Red Hat / Fedora - level 3 or 5,
- SUSE / openSUSE - level 5,
Slackware, runlevel S
And now, to throw away the monotony and boredom… But actually I would like it rather to be as much boring, as monotone… The actual system runlevel can be checked by running in the console:
# runlevel
as root, and as a regular mortal:
$ who -r
And coming back to the system booting…
Chapter 4: Init:
The first executable program in a work-ready environment is usually the init program. This program is placed in the /sbin directory, and its configuration file is /etc/inittab. In Linux init is the key program. Why? It’s “the ancestor to all other processes” (copied down from a handbook). More about this process - in the second part of “saga”. Now it’s enough to write that in its configuration file, a line quite important for our boot. An example (from Debian):
si::sysinit:/etc/init.d/rcSThe shown file will be executed during the boot. This file has to set applications, which work during the boot - which means on the “S” runlevel. It’s pretty significant, because later the runlevels can change. Let’s say, the root runs the init 1 command (in the command line) to ensure himself the exclusiveness to administer. He “administers” and then executes init 5 and we – simple users again have something to say. During this switching of runlevels certain scripts are executed, which set the environment in the proper way. But there are programs, which should be executed just once, e.g. swap partition should be rather activated on the computer startup, so it would work later, no matter which level we decide to set, isn’t it so? And it wouldn’t be surely too handy to turn the partition on and off, each time we switch the level. It wouldn’t just make any sense. Coming back to the init program. /etc/inittab also contains another interesting line:
id:2:initdefault: it’s the default system level. If our Slackware (just for example) has the level 3 set, we can set, by editing this line, a „graphic” run by default. But of course you need to know that in Slackware the multi-user level with graphics is the level 4, and not 5 as (e.g.) in Red Hat. The line in the example was taken from Debian, and in Debian the 2 is the “full functionality”. Actually /etc/inittab contains only interesting lines: what does the system have to do after pressing ctrl+alt+del, after power failure, how many virtual consoles should be available…
Chapter 5: an extraordinary short chapter about running programs
Programs, which ensure the functionality of the system aren’t usually run “just like that”, but thanks to corresponding scripts. The scripts are placed mostly in the /etc/init.d directory. There are for example:
- alsa - runs software, which allows to hear music,
- apache2 - runs the www server,
- gdm - turns on the graphic login manager,
- samba - enables the ability to make the local area network content available,
- urandom - a script, which (if run during system startup, restart and shutdown) “remembers” data.
Let’s spare the boring stuff - the switch to a certain system runlevel is simply running the scripts in a proper order. Most often from the /etc/init. d directory, but it’s not a must.
The programmer thought and thought… He knew the common used ways of running and closing (yes - don’t forget about closing - cause sometimes we have to reset the computer, or even to turn it off) applications during the switch of system runlevels. None of them was satisfying for him. The BSD style? It’s difficult to take care of. Maybe the SysV style? Maybe one of the less popular? He thought one more moment and exactly that moment made him realize . - Yes! That’s it! Now it’ll work faster and better! - he called and immediately began to work. If programmers, who worked on systems like Solaris, Debian or Slackware saw the code typed on the screen by the Mad, they would open their eyes wide of amazement and turn green of jealousy. If they even understood something of this at all.
Chapter 6: The BSD style
What is the easiest way to run scripts of applications needed during work in a certain system runlevel? It’s easy - you need to write a corresponding script. Such a solution is used in systems from the BSD family and in some Linux distros, like e.g. Slackware or CRUX. In the /etc/rc. d directory there are rc.S, rc.0, rc.4, rc.6 scripts, and so on… In those scripts there are elegant script runs, which execute corresponding programs, or even scripts of standalone programs. What does elegant mean? For example:
if [ -x /usr/bin/gdm ]; then
exec /usr/bin/gdm -nodeamon
fi
Which means something like this: „If there is a GNU graphic login manager - run it. Elegant means control, or the information, if what we expect from the system is even possible. So the rule is actually simple. We create a script, which leads the machine to the boot-up runlevel (”S”), and then to the target runlevel - e.g. 4, which means in Slackware “full functionality”. Likewise – we create a script for running applications, which provide functionality for the root level, a script for the system restart, and so on. Can it be done in a different way?
Chapter 7: The SysV style
Exactly as before, when we had used the example of Slackware, now we’re going to torture its not much younger brother – the Debian distro. It’s actually the canonical (it’s just the adjective, not the company) example for this style of setting a system runlevel, which is by the way the dominant in Linux. It’s more interesting in this case, at first glance – even magic. But let’s begin.
Experiment 2: Let’s prepare a directory on our computer. . Our experiment will work even in Slackware - we’re going to use standard commands. Let’s name the directory as “scripts”.
keyto@server:~/$ mkdir ~/scripts keyto@server:~/$ cd ~/scripts
Good. Now let’s prepare in this directory three files as following:
keyto@server:~/scripts$ echo '#!/bin/bash' > 01_script keyto@server:~/scripts$ echo 'echo Executes script 01' >> 01_script
We’re going to create the next two files in a similar way, but all ‘01′ sequences have to be replaced with ‘02′, ‘03′ sequences. Of course, you can generate even 100 of them, if you want. I suggest to use the “up” key to recall the last command and modify it. The next step will be giving our pseudo scripts the attribute of execution:
keyto@server:~/scripts$ chmod 700 *script
And now the most interesting part. As we know, we can run any script, e.g.:
keyto@server:~/scripts$ ./01_script Executes script 01
You can execute several of them, for example:
keyto@server:~/scripts$ ./01_script; ./02_script Executes script 01 Executes script 02
No discovery so far. But what if we want to run all scripts and there are not 5, but 105 of them? Well. Or what if another user of our PC is Bob the Builder, who added two more scripts? (Which doesn’t mean, he’s a bad builder, isn’t’ he? So what now? Write down all file names and strenuously “punch them in” in the command line? Of course not. The system contains a certain command, which we’re going to use right now:
keyto@server:~/scripts$ run-parts .Executes script 01 Executes script 02 Executes script 03
Interesting? Do not ignore the dot after the command name. I’d like to remind that the dot doesn’t mean an end of the sentence. It’s just the name of the current directory. In a similar way Debian follows through with running boot scripts. Please check the following directories. First the /etc/rcS.d These scripts are being executed at the start. An example of my computer (a fragment):
keyto@server:~/scripts$ ls -1 /etc/rcS.d S02mountvirtfs S04udev S05bootlogd S10checkroot
And so on, and so on… The names begin, as you can see, with the sequence ‘S’ plus a number. The thing is that the ‘run-parts’ program runs the scripts in an alphabetical order. If you want a specific script to be run earlier or later, you just need to change this number. For example ‘S04udev’ to ‘S76udev’. (But don’t do that! It’s just a possibility – it doesn’t mean that it will be good for the system!) A similar situation can be seen in the directories: from /etc/rc0.d to /etc/rc6.d. It is also important that the whole content of the directories analyzed here are the symbolic links created with the command ‘ln-s’. There is no sense, nor need in copying the specific files. The “originals” are sitting peacefully in the /etc/init.d directory, and their names aren’t preceded with any numbers. In other words the /etc/init. d directory contains the whole ensemble of boot scripts. If we want e.g. to run the ‘gdm’ script (running the login manager similar to GNOME in a graphical environment) automatic during system start, we execute the command:
root@server:/ # ln -s /etc/init.d /etc/rc2.d/S99gdm
And about the graphical login manager. Thanks to the numbers in script names you can achieve the MS-Windows-(R)-like effect, when the system actually still loads the desired applications, but the user can already see the login screen. You just need to move the gdm-program-run a little earlier. But does it actually make any sense? I’m leaving it to the Reader. Running a script can also be achieved thanks to the following command
for i in /etc/rcS.d/S??* do (...) done
Which means: for each file placed in the /etc/rcS.d/ directory with the name fitting to the pattern „S” plus two chars plus anything, execute… Debian uses this method as well, as the run-parts program. Is the way of running applications for the need of system runlevels used in Debian “better” than the way used in Slackware? It’s not a simple question. As I have mentioned before – in Slackware you need to type in strenuously the hundred-second, hundred-third, hundred-fourth script, which you want to use, and in Debian it’s like easier, but the other way… When you edit files, you’re theoretically more aware about what will happen to your system. And in the Slackware-script you can write your own comments. But for Debian and its “family” there are special programs prepared: the console-based update-rc.d, or KsysV (it’s a part of the KDE environment), which make the managing of symbolic links to scripts for a certain runlevel easier.
KSysV in Debian
Of course you can do it in a different way.
Chapter 8: GoboLinux
GoboLinux is different. Let’s agree that it’s a fact, and we don’t discuss facts. If it’s different, then the way of starting or closing it can not be standard. Generally it resembles the one known from BSD, but with a difference. In Gobo they used scripts, which contain a complex boot procedure and equally complex system shutdown procedure. In Slackware you’ve really had to go through several scripts (for example two of them), like rc.S and rc.4 for boot in “full” mode (with a graphic environment). And in Gobo the BootUp script (it’s placed in the /System/Settings/BootScripts directory) contains all system boot steps. From the start to the end. There is also a similar script named Shutdown. You can figure out by yourself, what it is for. (Such – a “riddle”.)
About midnight the phone rang. The Guru, a little bit lazy, turned the volume down and picked up the phone. - Michuk here. We have a problem - he heard. After a short moment in a matter-of-fact way he said: - Hy? - Keyto has acquired the source code of Mad programmer’s system. He’s stolen it or something like that… He tried to work it out for the purpose of the article, but he broke down under the enormous complexity and couldn’t stand the pressure… - What are you talking about!? - he didn’t make it, Guru. - He’s lost his mind. - Good God! Have you seen the code? - Of course not. - So what now? We’ve got to do something - Guru saddened. I’m not sure yet if it’s because of Keyto’s mental state or just an effect of serious problems with understanding the Mad’s code. - OK, good. I made the arrangements. The psychiatrist and both Linus Torvalds and RMS are on their way…
Post scriptum:
- First: The „Ultra-SAS-SATA X” disk - it was just a joke, obviously. They’ll be available in 57 years from now.
- Second: This article describes, of course, the booting process of a UNIX system. The booting of the Windows system will be published on the polishwindows.org site, when it’s online at last.
- Third: To be continued; In the next article in the series you’ll bread something about the /proc directory, and a lot more, so don’t miss it…
Proof-read by: too many to name them all
Subscribe to RSS feed for this article!
8 Comments
- A hyperlink: <a href="polishlinux.org">GNU/Linux for everyone!</a>,
- Strong text: <strong>Strong text</strong>,
- Italic text: <em>italic text</em>,
- Strike: <strike>
strike</strike>, - Code: <code>
printf("hello world");</code>, - Block quote: <blockquote>Block quote</blockquote>

















Hi. Thanks for your explanation. Perhaps you can line out how the bootloader gains access to the initrd (which still resides on the filesystem you cannot access without an additional kernel module)
Best Regards
Marcus
Very well written…
Enjoyed reading it
Phantastic! Informative with an intelligent humour…
Best article Ive ever read in computer magazines.
If you continue this series, Ill be able to write my own driver for my Ultra-SAS-SATA X without any help, when its finally available.
drz
You say runlevel 4 is not used in Slackware; correctly, it is not used by default. However, both 2 and 4 are available, and the “initdefault” runlevel can be changed to either of these.
Additionally, in run level 4 display manager is started automatically (Slackware’s init scripts look for kdm, gdm and xdm, respectively), so it’s not the same as runlevels 3 or 4. Don’t forget that Slack also supports SystemV style init scripts, where different run levels do matter.
What about the new init system (upstart?) that is used in ubuntu 8.04. Will you explain this also someday ?
paul
You can also just skip the initrd and have your (critical) drivers in the kernel.
I’ve some more details of the Grub bootloader process.