Can the init process be a shell script in Linux?

I was going through a tutorial on setting up a custom initramfs where it states:

The only thing that is missing is /init, the executable in the root of
the initramfs that is executed by the kernel once it is loaded.
Because sys-apps/busybox includes a fully functional shell, this means
you can write your /init binary as a simple shell script (instead of
making it a complicated application written in Assembler or C that you
have to compile).

and gives an example of init as a shell script that starts with #!/bin/busybox sh

So far, I was under the impression that init is the main process that is launched and that all the other user space process are eventually children of init. However, in the given example, the first process is actually bin/busybox/ sh from which later init is spawned.

Is this a correct interpertation? If I were, for example, have a available interpreter available at that point, I could write init as a Python script etc.?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

init is not “spawned” (as a child process), but rather exec‘d like this:

# Boot the real thing.
exec switch_root /mnt/root /sbin/init

exec replaces the entire process in place. The final init is still the first process (pid 1), even though it was preceded with those in the Initramfs.

The Initramfs /init, which is a Busybox shell script with pid 1, execs to Busybox switch_root (so now switch_root is pid 1); this program changes your mount points so /mnt/root will be the new /.

switch_root then again execs to /sbin/init of your real root filesystem; thereby it makes your real init system the first process with pid 1, which in turn may spawn any number of child processes.

Certainly it could just as well be done with a Python script, if you somehow managed to bake Python into your Initramfs. Although if you don’t plan to include busybox anyway, you would have to painstakingly reimplement some of its functionality (like switch_root, and everything else you would usually do with a simple command).

However, it does not work on kernels that do not allow script binaries (CONFIG_BINFMT_SCRIPT=y), or rather in such a case you’d have to start the interpreter directly and make it load your script somehow.

Method 2

The exec syscall of the Linux kernel underestands shebangs natively

When the executed file starts with the magic bytes #!, they tell the kernel to use #!/bin/sh as:

  • do and exec system call
  • with executable /bin/sh
  • and with CLI argument: path to current script

This is exactly the same that happens when you run a regular userland shell script with:

./myscript.sh

If the file had started with the magic bytes .ELF instead of #!, the kernel would pick the ELF loader instead to run it.

More details at: Why do people write the #!/usr/bin/env python shebang on the first line of a Python script? | Stack Overflow

Once you have this in mind, it becomes easy to accept that /init can be anything that the kernel can execute, including a shell script, and also why /bin/sh will be the first executable in that case.

Here is a minimal runnable example for those that want to try it out: https://github.com/cirosantilli/linux-kernel-module-cheat/tree/cbea7cc02c868711109ae1a261d01fd0473eea0b#custom-init


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x