# initramfs init failed at switch_root

## mathfeel

I am learning to make my own initramfs and init script. The ./init script looks like this:

```
#!/bin/sh

NEWROOT=/newroot/

rescue_shell() {

  echo "Something went wrong. Dropping you to a shell."

  busybox --install -s

  exec /bin/sh

}

uuidlabel_root() {

  for cmd in ${CMDLINE} ; do

    case $cmd in

      root=*)

        type=$(echo $cmd | cut -d= -f2)

        if [ $type == "LABEL" ] || [ $type == "UUID" ]; then

          uuid=$(echo $cmd | cut -d= -f3)

          blkdev=$(findfs "$type"="$uuid")

        else

          blkdev=$type

        fi

        echo "mount -o ro ${blkdev} ${NEWROOT}" 

        mount -o ro ${blkdev} ${NEWROOT}

        ;;

    esac

  done

}

echo "Mounting /proc, /sys and /dev..."

mount -t proc proc /proc

mount -t sysfs sysfs /sys

mount -t devtmpfs none /dev

CMDLINE=$(cat /proc/cmdline)

#wait a little to avoid trailing kernel output

sleep 3

#root filesystem

uuidlabel_root || rescue_shell

#root switch

echo "exec /bin/busybox switch_root ${NEWROOT} /sbin/init ${CMDLINE}"

exec /bin/busybox switch_root ${NEWROOT} /sbin/init ${CMDLINE}

```

When I boot with this initramfs, the echo "exec /bin/busybox..." line prints out, but then everything stopped. mount /newroot is successful.  Any idea what's going on?

As a side question, I induced the "rescue_shell" part by hand earlier only to find that I don't have keyboard. What module do I need to load to get the keyboard?

----------

## Otamay

Try to change the exec to the second position:

```
/bin/busybox exec switch_root ${NEWROOT} /sbin/init ${CMDLINE} 
```

I have a similar initramfs script, but instead of

```
#!/bin/sh
```

I use 

```
#!/bin/busybox ash
```

And in the end,

```
exec switch_root ${NEWROOT} /sbin/init ${CMDLINE}
```

--EDIT--

Ah! the keyboard, mmm, I think is the atkbd module. I suggest you to include directly in the kernel.

----------

## mathfeel

 *Otamay wrote:*   

> Try to change the exec to the second position:
> 
> ```
> /bin/busybox exec switch_root ${NEWROOT} /sbin/init ${CMDLINE} 
> ```
> ...

 

exec is part of sh. I also tried the convoluted

```
/bin/busybox sh exec ...
```

Same result

 *Quote:*   

> 
> 
> ```
> #!/bin/busybox ash
> ```
> ...

 

Same result

 *Quote:*   

> 
> 
> Ah! the keyboard, mmm, I think is the atkbd module. I suggest you to include directly in the kernel.

 

I needed the USB HID compiled in. So now at least I get an sh prompt to play around! I can run the above exec at the prompt making sure everything that should be mounted in mounted.

exec hangs...

EDIT:

Turning off quiet kernel option it appears that switch root was successful and now I see boot stopped after printing a few "used greatest stack depth" message the last one being:

```
[#####.##] init-early.sh used greatest stack depth: 6052 bytes left
```

.

This is weird because if I can boot without the initramfs.

----------

## Aquous

If I'm understanding the initramfs correctly, you need switch_root to become PID 1.

When your initramfs initscript starts, it is PID 1. In order to make switch_root become PID 1 you need to load it in the address space of the current PID 1. That is what the exec function does: it overwrites the running process with the process-to-be-execed.

By running /bin/busybox exec ... you're creating a new process, which in turn runs exec. So switch_root will take over that process's address space.

There are two solutions:

1) use busybox as your initramfs script interpreter by changing the shebang to use busybox and removing the /bin/busybox before exec

2) change the exec line to: exec /bin/busybox exec switch_root ...

Disclaimer: I don't use an initramfs, therefore I didn't carefully study how it works, therefore this post may just be a load of bull.

----------

## frostschutz

Aquous is completely correct, if your init script is a busybox shell script you have to use exec directly, not /bin/busybox exec ... etc.

Also I'm not sure if CMDLINE belongs there.

Other than that, I suggest you make it drop you on the rescue shell before the switch_root so you can check out, whether the new root was actually mounted correctly, if it has an /sbin/init, if it has all the files required to run init. For example it won't work if you put /etc on a separate partition or something.

----------

## Hu

 *mathfeel wrote:*   

> 
> 
> ```
> 
> rescue_shell() {
> ...

 I suggest removing the exec here.  By removing it, you have the potential to repair the problem, exit the sh, and allow the boot to continue on.  With the exec, you will have to do everything by hand even after you repair the problem.

 *mathfeel wrote:*   

> 
> 
> ```
> mount -o ro ${blkdev} ${NEWROOT}
> ```
> ...

 Add || rescue_shell.  This is not needed with your current layout, but would become important if you added any other cleanup code between the call to mount and the end of the function.

 *mathfeel wrote:*   

> 
> 
> ```
> mount -t proc proc /proc
> 
> ...

 These could be unmounted once you have executed uuidlabel_root.

 *mathfeel wrote:*   

> 
> 
> ```
> 
> echo "exec /bin/busybox switch_root ${NEWROOT} /sbin/init ${CMDLINE}"
> ...

 Use set -x to make the shell print what it will do.  This reduces typing and saves on future maintenance.

----------

## mathfeel

Per my EDIT in last post。 I don't believe switch_root is the issue any more. Dropping the "quiet" option for kernel and I can see that switch_root handed over to the real /sbin/init just fine, but the boot is frozen right before openrc starts. (The last message being "init-early.sh used greatest stack depth: 6052 bytes left" (see above)).

This is strange because I can boot without the initramfs. I tried the following:

commenting out/restoring umount /sys /proc /dev in my init

clearing up switch_root to be just

```
exec switch_root /newroot /sbin/init
```

Dropping to rescue shell. Saw nothing abnormal, then runs exec switch_root from there.

None helped.

----------

## Aquous

I just thought of something. I've had the same issue as you (though without initramfs) until I enabled devtmpfs in my kernel .config. Maybe your initramfs needs to do something similar to what devtmpfs does.

Having said that, my previous comment still stands: whether you believe it's the issue or not, your switch_root is wrong.

----------

## mathfeel

 *Aquous wrote:*   

> I just thought of something. I've had the same issue as you (though without initramfs) until I enabled devtmpfs in my kernel .config. Maybe your initramfs needs to do something similar to what devtmpfs does.
> 
> Having said that, my previous comment still stands: whether you believe it's the issue or not, your switch_root is wrong.

 

I have the devtmpfs and automounting options enabled in kernel.  According to kernel doc, what devtmpfs does won't affect initramfs anyway. In fact, I am mounting and umounting my own /dev using devtmpfs in the init (see above).

I understands now that switch_root has to be run from pid 1. So I know Otamay's suggestion to change the switch_root line will not work. I also changed the switch_root line as you suggested. Same result.

----------

## alveraan

Hi all. I have the same problem here. I'm using the init script from DM-Crypt with LUKS (the first one) At first I thought it had to do with the hardened kernel, but then I switched to gentoo-sources and the problem persists. In hardened, the last message is from mounting /dev/shm. In gentoo-sources, the last message is

```
init-early.sh used greatest stack depth: 5804 bytes left
```

----------

## alveraan

Oh well, the solution can be found here: https://forums.gentoo.org/viewtopic-t-880149.html?sid=7de597df34c53ddac05ecde28596c507

Thanks Neddy.

----------

