Linux Kernel Boot: Failed to Execute /init (Error -2) - Comprehensive Troubleshooting Guide

Encountering the cryptic “Failed to execute /init (error -2)” message during your Linux kernel boot sequence, followed by a “Kernel panic - not syncing: No working init found”, can be a perplexing and frustrating experience, especially when meticulously building a minimal Linux distribution or working through detailed tutorials like “Build a minimal Linux with only Busybox in 1 Hour” from “Write your own Operating System.” At revWhiteShadow, we understand the intricacies of operating system development and the critical role of the initial process, /init, in bringing your system to life. This guide delves deep into the root causes of this common boot failure and provides a comprehensive, actionable strategy to resolve it, ensuring your custom Linux environment boots successfully.

Understanding the Boot Process and the Crucial Role of /init

Before we dissect the error, it’s essential to grasp the fundamental steps the Linux kernel undertakes upon startup. When the kernel image is loaded and begins execution, its primary directive is to locate and execute the init process. This process, traditionally found at /sbin/init or /etc/init, is the first user-space process launched by the kernel. It assumes the crucial responsibility of bringing the system to a usable state by initializing all necessary services, mounting file systems, and ultimately presenting a login prompt or graphical environment.

The kernel searches for the init program in a specific order, as indicated by your error message: first /init, then /sbin/init, /etc/init, /bin/init, and finally /bin/sh as a last resort. When it fails to find a valid, executable init program in these locations, or if the found program cannot be executed, the kernel cannot proceed with the user-space initialization. This leads directly to the “No working init found” panic, signaling a critical failure in the boot chain.

The “error -2” specifically indicates ENOENT, which translates to “No such file or directory.” This is a potent clue, suggesting that the kernel, despite being instructed to look for /init, cannot find this file at the expected location within the root filesystem.

Common Causes of “Failed to Execute /init (Error -2)”

The failure to execute /init stems from a few primary categories of misconfiguration or oversight during the custom distribution build process. Each of these needs to be meticulously examined to pinpoint the exact cause.

1. Incorrect Root Filesystem Assembly

This is arguably the most frequent culprit. The kernel, when it starts searching for /init, operates within the context of the root filesystem that has been made available to it. If the root filesystem is not properly constructed, mounted, or made accessible to the kernel at the correct time, the /init binary will simply not be present within the kernel’s view of the filesystem hierarchy.

1.1 Missing or Corrupted /init Binary

The most direct reason for “No such file or directory” is precisely that: the /init file is not present in the root filesystem’s / directory. This can happen due to:

  • Incomplete Busybox Compilation: If Busybox was not compiled with the necessary applets enabled, particularly the sh (shell) and potentially mount, sysfs, proc, and devtmpfs utilities that your /init script relies on, the resulting Busybox binary might not be sufficient. When Busybox is statically linked, it becomes a single executable that handles multiple commands based on symbolic links or internal dispatching. If the sh functionality within Busybox isn’t correctly configured or included, the /init script itself cannot be executed.
  • Incorrect File Copying: During the process of creating your root filesystem, you might have overlooked copying the init binary (which is often a symlink to the Busybox binary in minimal systems) into the root directory of your target filesystem.
  • Filesystem Corruption: While less common, the root filesystem image itself could be corrupted, leading to missing files or an inability to access them.

1.2 Incorrect Root Filesystem Mounting

Even if /init exists, the kernel needs to know where to find the root filesystem. This is typically handled by the bootloader and kernel command-line arguments.

  • Missing root= Kernel Parameter: The kernel needs to be told which device contains the root filesystem. If the root= parameter is omitted or incorrect, the kernel will not be able to mount the root filesystem, and thus will not find /init.
  • Incorrect Device Specification: If your root= parameter points to a device that doesn’t exist, is not accessible, or is not the correct one containing your root filesystem (e.g., /dev/sda1 when your rootfs is on /dev/vda1 in a virtual machine), the kernel won’t be able to mount it.
  • Uninitialized or Incorrectly Formatted Root Device: The storage device intended to host your root filesystem must be properly formatted with a filesystem (like ext2, ext4, or even a simple tar archive mounted via an initramfs) that the kernel can understand.

2. Issues with the /init Script Itself

The provided /init script contains a sequence of commands to set up the environment before handing off control. Errors within this script can prevent it from executing successfully.

  • Syntax Errors in the Shell Script: Even a minor syntax error in your #!/bin/sh script can cause the shell to fail when trying to interpret it. This could be an unclosed quote, a missing semicolon, an incorrect variable assignment, or any other deviation from standard POSIX shell syntax.

  • Missing Dependencies for Commands: Your /init script relies on several commands: mount, sysctl, and /bin/sh.

    • mount: Essential for mounting /sys, /proc, and /devtmpfs. If mount is not available (i.e., not part of Busybox or not correctly linked), these crucial virtual filesystems won’t be mounted, potentially leading to issues later, though not directly the “error -2” on /init itself.
    • sysfs: The kernel needs to access /sys for system information.
    • proc: The proc filesystem is vital for process management and kernel information.
    • devtmpfs / udev: Used for dynamically creating device nodes in /dev. If these are not available or the mount fails, your system might not be able to access essential hardware devices.
    • sysctl: Used to tune kernel parameters, like controlling kernel message verbosity. If sysctl is missing, this specific line will fail, but it’s unlikely to be the cause of the initial /init execution failure.
    • /bin/sh: The script is explicitly #!/bin/sh. If the /bin/sh binary (often a symlink to the Busybox shell) is not present or executable, the script cannot run.
  • Permissions Issues: While less common for the initial /init on a freshly built filesystem, if the /init file itself does not have execute permissions set for the user the kernel is running as (typically root during boot), it will fail to execute.

3. Kernel Configuration Issues

Although less directly related to “error -2,” certain kernel configurations can indirectly lead to this problem.

  • Missing Filesystem Support: If the kernel is not compiled with support for the filesystem type used for your root filesystem (e.g., ext4 support is missing), it won’t be able to mount the root device, even if the root= parameter is correct.
  • Incorrect Initramfs/Initrd Usage: If you are using an initramfs (Initial RAM File System), problems with its creation or content can prevent the kernel from correctly loading the real root filesystem. The initramfs typically contains scripts and utilities to set up the environment and then mount the actual root partition. If the initramfs itself lacks a working /init or the mechanism to mount the rootfs, the process stalls.

Troubleshooting Steps: A Methodical Approach

To effectively diagnose and resolve the “Failed to execute /init (error -2)” issue, we will adopt a systematic approach, examining each potential point of failure.

Step 1: Verify the Root Filesystem Contents

This is the most crucial step. You need to ensure that your root filesystem is correctly assembled and contains all necessary components.

1.1 Mount and Inspect Your Root Filesystem

  • Locate Your Root Filesystem Image: This could be a .tar.gz archive, a raw disk image file (like .img), or a partition on a storage device.

  • Mount the Filesystem:

    • For .tar.gz files: Extract it into a directory: tar -xzf your_rootfs.tar.gz -C /path/to/your/mountpoint
    • For .img files (assuming it’s a partitionable image like MBR): Use losetup to find the partition offsets and then mount the relevant partition. A simpler approach for many modern images is: mount -o loop,ro your_rootfs.img /path/to/your/mountpoint (adjust ro to rw if you need to make changes).
    • For a physical partition: mount /dev/your_root_partition /path/to/your/mountpoint
  • Navigate to the Mountpoint: cd /path/to/your/mountpoint

  • Check for /init: Execute ls -l /init. You should see an entry indicating it’s a file or a symbolic link.

    • If /init is missing: This is your primary problem. You need to go back to your Busybox build process and ensure that CONFIG_INIT or relevant shell applets are enabled, and then ensure the init binary (or its symlink) is correctly placed in the root of your filesystem. In a minimal Busybox setup, /init is often a symbolic link to /bin/busybox, and /bin/sh is also a symlink to /bin/busybox. Verify these symlinks are correct: ls -l bin/busybox, ls -l bin/sh.
    • If /init is present: Check its permissions with ls -l /init. It should have execute permissions for the owner (root). For example, -rwxr-xr-x. If not, you may need to adjust permissions using chmod on the source filesystem before creating the image or archive.

1.2 Verify Critical Binaries and Scripts

While inside your mounted root filesystem:

  • Check /bin/sh: ls -l bin/sh. This should also point to your Busybox binary.
  • Check init script: If /init is a script (as yours seems to be), ensure it’s present at the root: ls -l /init.
  • Verify script contents: Examine the script file (cat /init) for any obvious syntax errors. Make sure the mount command is present (it’s usually part of Busybox).
  • Check Busybox: ls -l bin/busybox. Ensure this binary exists and has execute permissions.

Step 2: Examine Kernel Boot Parameters

The way you instruct the kernel to boot is crucial. This is typically done via your bootloader (like GRUB, U-Boot, or QEMU’s command line).

2.1 The root= Parameter

Ensure your kernel command line includes a root= parameter that correctly identifies your root filesystem device.

  • Example for a Virtio block device in QEMU: root=/dev/vda1 or root=/dev/vda if it’s the entire device.
  • Example for a SATA device: root=/dev/sda1
  • Example for a RAM disk (initramfs): This is more complex and depends on how the initramfs is configured to mount the actual root.

While your error message mentions trying init=, explicitly specifying it can help if the kernel’s default search order is problematic or if you’re using a non-standard init location.

  • If /init is your script: init=/init
  • If using a standard /sbin/init: init=/sbin/init
  • If /bin/sh is your fallback: init=/bin/sh

Combining these, a typical kernel command line might look like:

console=ttyS0 root=/dev/vda rw init=/init

Explanation:

  • console=ttyS0: Directs kernel messages to a serial console (common in VMs).
  • root=/dev/vda: Specifies the root filesystem device.
  • rw: Mounts the root filesystem in read-write mode.
  • init=/init: Explicitly tells the kernel to execute /init.

Step 3: Rebuild Busybox and Your Root Filesystem

If verification reveals missing files or incorrect links, you’ll need to rebuild.

  • Busybox Configuration:

    • Navigate to your Busybox source directory.
    • Run make menuconfig (or make xconfig, etc.).
    • Crucially, ensure:
      • Under Settings -> Build Options, Build BusyBox as a static binary (no shared libs) is selected if you are aiming for a truly minimal system without libc dependencies.
      • Under Applets Core -> Coreutils, ensure sh is enabled.
      • Under Applets Core -> Init, ensure init is enabled if you intend to use Busybox’s init functionality directly, otherwise ensure sh is sufficient for your script.
      • Under Applets Core -> Mount, ensure mount is enabled.
      • Under Applets Core -> Sysctl, ensure sysctl is enabled.
      • Under Applets Core -> devtmpfs, ensure devtmpfs is enabled.
    • Save your configuration and run make and make install DESTDIR=/path/to/your/staging/directory. This will install Busybox into a directory structure that you can then copy into your root filesystem.
  • Root Filesystem Creation:

    • Create your base directory structure (e.g., bin, sbin, etc, dev, proc, sys, usr, lib, tmp, mnt, root).
    • Copy the built Busybox binary (usually found in staging/bin/busybox) to /bin/busybox within your root filesystem.
    • Create necessary symlinks:
      • ln -s /bin/busybox /bin/sh
      • ln -s /bin/busybox /sbin/mount
      • ln -s /bin/busybox /sbin/sysctl
      • ln -s /bin/busybox /sbin/init (If you are using Busybox’s direct init functionality, though your script implies /init is a separate shell script).
      • If /init is a script, ensure it’s placed at the root of your filesystem (your_rootfs_dir/init).
    • Create the dev, proc, and sys directories. These will be mounted at runtime.
    • Archive or create an image of this directory structure.

Step 4: Analyze the init Script in Detail

Your provided init script is:

#!/bin/sh
mount -t sysfs sysfs /sys
mount -t proc proc /proc
mount -t devtmpfs udev /dev
sysctl -w kernel.printk="2 4 1 7"
/bin/sh

Let’s break down each command and potential failure point:

  • #!/bin/sh: Assumes /bin/sh exists and is executable. Verified in Step 1.
  • mount -t sysfs sysfs /sys:
    • Requires the mount binary.
    • Requires the sysfs kernel module or built-in support.
    • Requires the /sys directory to exist in the root filesystem.
    • If /sys is not present in your rootfs, this mount will fail. If mount binary is missing, it will fail earlier.
  • mount -t proc proc /proc:
    • Requires the mount binary.
    • Requires the proc kernel module or built-in support.
    • Requires the /proc directory to exist in the root filesystem.
  • mount -t devtmpfs udev /dev:
    • Requires the mount binary.
    • Requires devtmpfs support in the kernel.
    • Requires the /dev directory to exist in the root filesystem.
  • sysctl -w kernel.printk="2 4 1 7":
    • Requires the sysctl binary.
    • Requires the kernel to be running and able to process sysctl commands.
    • Sets the kernel’s console log level. This is unlikely to cause the initial “error -2” but is good practice.
  • /bin/sh: This is the final command, intended to launch an interactive shell. If all previous steps were successful, you should drop into a shell.

Potential issues with your script:

  • Missing mount or sysctl: Ensure these are correctly symlinked from your Busybox binary.
  • Missing /sys, /proc, or /dev directories: These MUST be created within your root filesystem structure before you package it.
  • Order of Operations: The mount commands are critical. If the kernel panics after trying to execute /init but before reaching /bin/sh, it’s often because one of the early mount commands failed silently or due to missing kernel support/binaries.

Step 5: Consider Initramfs/Initrd

If you are using an initramfs, the init script logic is often contained within it, responsible for finding and mounting the real root filesystem.

  • Check Initramfs Contents: Mount the initramfs image (often a cpio archive) and inspect its /init script and included binaries. The principles discussed above apply directly to the initramfs’s environment as well.
  • Kernel Command Line for Initramfs: Ensure your bootloader is correctly passing the initramfs image to the kernel and that the kernel is configured to handle it.

Advanced Debugging Techniques

When the initial checks don’t reveal the problem, more advanced techniques can shed light on the boot process.

1. Serial Console Logging

Always ensure you have a serial console configured (especially in virtualized environments). Kernel messages, including panics and errors, are often directed here, providing invaluable debugging information. Your console=ttyS0 parameter is a good start for this.

2. Verbose Kernel Boot Messages

Modify your kernel command line to include loglevel=7 or debug. This will print more detailed kernel messages, which might reveal earlier issues with device detection or root filesystem probing.

3. Customizing the init Script for Debugging

Modify your /init script to be more verbose and check the exit status of each command:

#!/bin/sh

echo "Starting custom init script..."

echo "Mounting sysfs..."
mount -t sysfs sysfs /sys
if [ $? -ne 0 ]; then
    echo "ERROR: Failed to mount sysfs!"
    # Optionally, try to drop to a shell here for debugging
    exec /bin/sh
fi

echo "Mounting proc..."
mount -t proc proc /proc
if [ $? -ne 0 ]; then
    echo "ERROR: Failed to mount proc!"
    exec /bin/sh
fi

echo "Mounting devtmpfs..."
mount -t devtmpfs udev /dev
if [ $? -ne 0 ]; then
    echo "ERROR: Failed to mount devtmpfs!"
    exec /bin/sh
fi

echo "Setting kernel.printk..."
sysctl -w kernel.printk="2 4 1 7"
if [ $? -ne 0 ]; then
    echo "WARNING: sysctl command failed."
fi

echo "Executing /bin/sh..."
exec /bin/sh

This enhanced script will tell you exactly which mount command failed, if any. If the script fails at the exec /bin/sh line, it means the previous commands likely succeeded, and the issue might be with /bin/sh itself or the state of the system at that point.

4. Examining the Kernel Configuration (.config)

If you compiled your own kernel, meticulously review your .config file to ensure that support for your root filesystem type (e.g., CONFIG_EXT4_FS) and essential drivers (e.g., Virtio block drivers for QEMU) are enabled, either built-in (=y) or as modules (=m). If they are modules, ensure they are available within your initramfs or can be loaded by the kernel.

Conclusion: Towards a Successful Boot

The “Failed to execute /init (error -2)” error is a clear indication that the kernel cannot locate or successfully run the initial user-space program. By systematically verifying the integrity of your root filesystem, the correctness of your kernel boot parameters, and the robustness of your /init script and its dependencies, you can effectively diagnose and resolve this common hurdle. At revWhiteShadow, we advocate for meticulous attention to detail in every step of the OS building process. Rebuilding Busybox with the correct applets enabled, ensuring proper symlinking, and carefully constructing your root filesystem are paramount. With these comprehensive steps, you will be well-equipped to conquer this boot failure and bring your custom Linux distribution to life. Remember, patience and a methodical approach are your greatest allies in the fascinating world of operating system development.