switch_root and /etc/inittab

Denys Vlasenko vda.linux at googlemail.com
Fri Oct 8 12:29:40 UTC 2021


I'm terribly late for this...

On Tue, Jun 15, 2021 at 4:55 PM Porter, Jeremy
<porter.188 at buckeyemail.osu.edu> wrote:
> Thank you for the example--that was helpful to see how this works.
>
> I have initramfs in Linux enabled and I've been using that for a long time. I should be able to use switch_root.
>
> I followed the prior suggestion to skip the inittab and use a script. I put a script in /etc/init.d/rcS:
>
> #!/bin/busybox sh
>
> /bin/busybox echo "Running boot script..."
> /bin/busybox echo "Mounting filesystems..."
> /bin/busybox mount -t devpts devpts /dev/pts
> /bin/busybox mount -t tmpfs tmpfs /dev/shm
> /bin/busybox mount -t proc proc /proc
> /bin/busybox mount -t sysfs sysfs /sys
> /bin/busybox mount -t tmpfs tmpfs /tmp
> /bin/busybox echo "Installing links for busybox..."
> /bin/busybox --install -s
> /bin/busybox echo /sbin/mdev > /proc/sys/kernel/hotplug
> /bin/busybox mdev -s
> /bin/busybox echo "mounting rootfs..."
> /bin/busybox mount -t xfs /dev/vda /mnt
> /bin/busybox echo "Swtiching root"
> exec /sbin/switch_root -c /dev/console /mnt /sbin/init
>
> This runs and gets to switch_root.
>
> It does not switch_root though. It doesn't run the new roots inittab which is present.

If switch_root can't/won't chroot to the new root, it prints an error message.
See for yourself:

        // Change to new root directory and verify it's a different fs
        xchdir(newroot);
        xstat("/", &st);
        rootdev = st.st_dev;
        xstat(".", &st);
        if (st.st_dev == rootdev) {
                // Show usage, it says new root must be a mountpoint
                bb_show_usage();
        }
        if (!dry_run && getpid() != 1) {
                // Show usage, it says we must be PID 1
                bb_show_usage();
        }

        // Additional sanity checks: we're about to rm -rf /, so be REALLY SURE
        // we mean it. I could make this a CONFIG option, but I would get email
        // from all the people who WILL destroy their filesystems.
        if (stat("/init", &st) != 0 || !S_ISREG(st.st_mode)) {
                bb_error_msg_and_die("'%s' is not a regular file", "/init");
        }
        statfs("/", &stfs); // this never fails
        if ((unsigned)stfs.f_type != RAMFS_MAGIC
         && (unsigned)stfs.f_type != TMPFS_MAGIC
        ) {
                bb_simple_error_msg_and_die("root filesystem is not
ramfs/tmpfs");
        }

        if (!dry_run) {
                // Zap everything out of rootdev
                delete_contents("/", rootdev);

                // Overmount / with newdir and chroot into it
                if (mount(".", "/", NULL, MS_MOVE, NULL)) {
                        // For example, fails when newroot is not a mountpoint
                        bb_simple_perror_msg_and_die("error moving root");
                }
        }
        xchroot(".");

All error paths have messages. (x-functions (xstat et al) also always
print error messages if they die internally due to errors).

Thus, you should be reaching xchroot().
Then, you should be reaching execv, since it also has error printouts
everywhere else:
        if (dry_run) {
                // Does NEW_INIT look like it can be executed?
                //xstat(argv[0], &st);
                //if (!S_ISREG(st.st_mode))
                //      bb_perror_msg_and_die("'%s' is not a regular
file", argv[0]);
                if (access(argv[0], X_OK) == 0)
                        return 0;
        } else {
                // Exec NEW_INIT
                execv(argv[0], argv);
        }
        bb_perror_msg_and_die("can't execute '%s'", argv[0]);


> I get something like this:
>
> [    1.262512] XFS (vda): Ending recovery (logdev: internal)
> Swtiching root
>
> Please press Enter to activate this console.
>
> BusyBox v1.33.1 (2021-06-10 08:53:34 EDT) built-in shell (ash)
>
> / # ls

Looks like you are seeing the new init running default
    ::askfirst:-/bin/sh
action.

Look around the currently mounted root filesystem and
diagnose why /etc/inittab is not there.


> Is there any good way to debug this switch_root?

You can strace it, I guess...
You can also use

exec /sbin/switch_root -c /dev/console /mnt /bin/sh

which would drop you into a shell, and then see around
what files are in the filesystem, try "exec /sbin/init" etc.



> The new root has /etc/inittab like this:
>
> ::sysinit:-/bin/ash
> ::sysinit:/bin/busybox echo "hello from /etc/inittab"

Do you *see* it in the filesystem when you are in the askfirst shell?
E.g. "cat /etc/inittab" shows the file?


More information about the busybox mailing list