42

I am creating a linux distro and now I need an init program. I can code in c really well and I know quite a bit about linux (not much but I've been using arch linux for development for 4 years), so I thought I should try writing my own basic init script in C. I was just wondering, what tasks does init do to set the system up for a simple shell? (When I ask "what does init do?", I do know what init is and what it's for. I just don't know what tasks it does.)

I don't need code and I possibly don't even need basic commands but I do need the order that they are run in.

migrated from serverfault.com Apr 20 '15 at 16:35

This question came from our site for system and network administrators.

  • 1
    You can use whatever interpreter you like for SysV-style init scripts, including Perl, awk, bash, (t)csh, native binaries, ... Bash is normally used because it's virtually guaranteed to be available on the system where such scripts are deployed at the relevant point in the boot process, not because there is some coupling between SysVinit and bash. SysVinit defines the contract and each script is free to implement that contract in any way its developer sees fit. – a CVn Apr 20 '15 at 18:49
51
+300

System 5 init will tell you only a small part of the story.

There's a sort of myopia that affects the Linux world. People think that they use a thing called "System 5 init", and that is both what is traditional and the best place to start. Neither is in fact the case.

Tradition isn't in fact what such people say it to be, for starters. System 5 init and System 5 rc date to AT&T UNIX System 5, which was almost as far after the first UNIX as we are now (say) after the first version of Linux-Mandrake.

1st Edition UNIX only had init. It did not have rc. The 1st Edition assembly language init (whose code has been restored and made available by Warren Toomey et al.) directly spawned and respawned 12 getty processes, mounted 3 hardwired filesystems from a built-in table, and directly ran a program from the home directory of a user named mel. The getty table was also directly in the program image.

It was another decade after UNIX System 5 that the so-called "traditional" Linux init system came along. In 1992, Miquel van Smoorenburg (re-)wrote a Linux init+rc, and their associated tools, which people now refer to as "System 5 init", even though it isn't actually the software from UNIX System 5 (and isn't just init).

System 5 init/rc isn't the best place to start, and even if one adds on knowledge of systemd that doesn't cover half of what there is to know. There's been a lot of work in the area of init system design (for Linux and the BSDs) that has happened in the past two decades alone. All sorts of engineering decisions have been discussed, made, designed, implemented, and practised. The commercial Unices did a lot, too.

Existing systems to study and and learn from

Here is an incomplete list of some of the major init systems other than those two, and one or two of their (several) salient points:

  • Joachim Nilsson's finit went the route of using a more human-readable configuration file.
  • Felix von Leitner's minit went for a filesystem-is-the-database configuration system, small memory footprints, and start/stop dependencies amongst things that init starts.
  • Gerrit Pape's runit went for what I have previously described as the just spawn four shell scripts approach.
  • InitNG aimed to have dependencies, named targets, multiple configuration files, and a more flexible configuration syntax with a whole load more settings for child processes.
  • upstart went for a complete redesign, modelling the system not as services and interdependencies at all, but as events and jobs triggered by them.
  • The design of nosh includes pushing all of the service management out (including even the getty spawning and zombie reaping) into a separate service manager, and just handling operating-system-specific "API" devices/symlinks/directories and system events.
  • sinit is a very simple init. It executes /bin/rc.init whose job it is to start programs, mount filesystem, etc. For this you can use something like minirc.

Moreover, about 10 years ago, there was discussion amongst daemontools users and others of using svscan as process #1, which led to projects like Paul Jarc's svscan as process 1 study, Gerrit Pape's ideas, and Laurent Bercot's svscan as process 1.

Which brings us to what process #1 programs do.

What process #1 programs do

Notions of what process #1 is "supposed" to do are by their natures subjective. A meaningful objective design criterion is what process #1 at minimum must do. The kernel imposes several requirements on it. And there are always some operating-system-specific things of various kinds that it has to do. When it comes to what process #1 has traditionally done, then we are not at that minimum and never really have been.

There are several things that various operating system kernels and other programs demand of process #1 that one simply cannot escape.

People will tell you that fork()ing things and acting as the parent of orphaned processes is the prime function of process #1. Ironically, this is untrue. Dealing with orphaned processes is (with recent Linux kernels, as explained at https://unix.stackexchange.com/a/177361/5132) a part the system that one can largely factor out of process #1 into other processes, such as a dedicated service manager. All of these are service managers, that run outwith process #1:

  • the IBM AIX srcmstr program, the System Resource Controller
  • Gerrit Pape's runsvdir from runit
  • Daniel J. Bernstein's svscan from daemontools, Adam Sampson's svscan from freedt, Bruce Guenter's svscan from daemontools-encore, and Laurent Bercot's s6-svscan from s6
  • Wayne Marshall's perpd from perp
  • the Service Management Facility in Solaris 10
  • the service-manager from nosh

Similarly, as explained at https://superuser.com/a/888936/38062, the whole /dev/initctl idea doesn't need to be anywhere near process #1. Ironically, it is the highly centralized systemd that demonstrates that it can be moved out of process #1.

Conversely, the mandatory things for init, that people usually forget in their off-the-top-of-the-head designs, are things such as handling SIGINT, SIGPWR, SIGWINCH, and so forth sent from the kernel and enacting the various system state change requests sent from programs that "know" that certain signals to process #1 mean certain things. (For example: As explained at https://unix.stackexchange.com/a/196471/5132, BSD toolsets "know" that SIGUSR1 has a specific meaning.)

There are also once-off initialization and finalization tasks that one cannot escape, or will suffer greatly from not doing, such as mounting "API" filesystems or flushing the filesystem cache.

The basics of dealing with "API" filesystems are little different to the operation of init rom 1st Edition UNIX: One has a list of information hardwired into the program, and one simply mount()s all of the entries in the list. You'll find this mechanism in systems as diverse as BSD (sic!) init, through the nosh system-manager, to systemd.

"set the system up for a simple shell"

As you have observed, init=/bin/sh doesn't get "API" fileystems mounted, crashes in an ungainly fashion with no cache flush when one types exit (https://unix.stackexchange.com/a/195978/5132), and in general leaves it to the (super)user to manually do the actions that make the system minimally usable.

To see what one actually has no choice but to do in process #1 programs, and thus set you on a good course for your stated design goal, your best option is to look at the overlaps in the operation of Gerrit Pape's runit, Felix von Leitner's minit, and the system-manager program from the nosh package. The former two show two attempts to be minimalist, yet still handle the stuff that it is impossible to avoid.

The latter is useful, I suggest, for its extensive manual entry for the system-manager program, which details exactly what "API" filesystems are mounted, what initialization tasks are run, and what signals are handled; in a system that by design has the system manager just spawn three other things (the service manager, an accompanying logger, and the program to run the state changes) and only do the unavoidable in process #1.

  • 2
    Awesome answer and very informative. But I'm asking myself where in this big picture is OSX launchd. Sometimes people forget entirely that OSX is a (great) a member of the large *nix family. – DavAlPi Apr 25 '15 at 17:33
4

System V init on Debian (there are other variants and variations) does the following:

  • When entering a runlevel, it calls scripts in /etc/rcX.d/S* in alphanumeric order, where X is the runlevel. These scripts should setup the runlevel. Typical setup is starting daemons and performs setup tasks for that run level. This is a one-time thing done when entering the runlevel.
  • While in a run level, it starts daemons that are listed in the /etc/inittab as needing to be active during that run level. If those daemons stop running, it restarts them. While you can have any daemon you want managed by init, at a minimum you want a few getty's so you can log in. getty exits once a log in is completed, then init restarts it, providing a fresh login prompt.
    • If the daemon restarts too many times in too short of a time, it stops trying to restart it for a while.
    • Just because something was started by the kickoff scripts when entering the run level does not make init automatically try to keep it running. You need to specify that separately in the /etc/inittab.
  • When exiting a runlevel, it calls scripts in /etc/rcX.d/K* in alphanumeric order, where X is the runlevel. A way to implement shutdown or reboot is to define a runlevel for those events and make the last task executed the halt or reboot command.
  • It will call executables in response to certain events, such as power events or Ctrl-Alt-Del.
  • It listens on a socket, if it receives certain messages it will change runlevel.

So you can use init as rudimentary service manager if you want, but it's main task these days is to keep getty's available so a user can login, and kick off runlevel transitions.

I was just wondering, what tasks does init do to set the system up for a simple shell?

Whatever you want. On Debian, in each /etc/rcX.d directory is a symlink to a script in /etc/init.d and you can fully customize or remove those scripts. The order is established by preceding each script with a 00, 01, etc.

You can also specify a -b option to init (i.e. via kernel command line) if you just want init to spawn a shell. When you exit the shell, init dies and when init dies, the kernel will panic.

2

The absolute bare minimum that init must do is run at least one other program and not ever exit. If init exits the system crashes. I suppose that even running the one other program is not strictly necessary, but If you don't do that init would have to be responsible for doing every thing that the system is expected to do, or it would not be very useful.

  • 1
    I've had buggy Linux systems where PID 1 crashed but the system basically kept running. How bad PID 1 crashing is may depend on the kernel version. – Gilles Apr 22 '15 at 22:39
0

If you are committed to the modular "do one thing and do it well" principle, then an init programme should start processes.

Start Processes

It should be executed once the kernel has been successfully decompressed, taking care of all the rudimentary tasks involved in initialising all the initial processes that a system requires to operate (such as mounting drives found in /etc/fstab, bringing up network interfaces, and so on).

Since the process of booting up and shutting down are essentially inverse of one another, it is common for an init programme to also ensure that processes are stopped upon a shutdown command.

Stop Processes

This means it must stop processes according to that process's man page (in other words, not just a blatant kill -9, it should bring the process down in the way that it wants to be ended), unmount drives, and ultimately issue the final power down command.

References

A good reference for how this is done by others is to look at Slackware's /etc/rc.d scripts, and also at a simple init system that already exists, like ninit (a successor to minit). It has process supervision (meaning that if a process dies, it is relaunched), which is arguably not init's job, but it's still quite basic and simple to understand, especially through the author's sample scripts.

0

init can do whatever you want

init is an arbitrary executable called by the Linux kernel at the end of the boot process (and the only one such executable).

It is normally implemented as an ELF executable, but it can even be a shell script with chmod +x: Init as a shell script

Typical implementations like sysemd will read configuration files, ofen /etc/initrc, and then fork a bunch of userland processes based on those configurations, to implement various aspects of the system.

However, this is completely implementation specific, and therefore you question cannot be answered without specifying a specific implementation. For example, I've been playing with a init process that simply does a reboot syscall for education purposes.

The Linux kernel simply looks for the executable at the path /init by default, but this can be overridden by the init= Linux kernel command line parameter.

One great way to play around with init is to use QEMU, since you can pass the kernel command line parameters to QEMU from the QEMU command line with the -append option, and without the fear of bricking your desktop.

Here is my minimal fully automated Buildroot + QEMU setup that makes it very easy to play around with your own inits to demystify the matter.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.