Safely Hand Off an Initramfs with switch_root
You will finish with a checked command line for handing control from an initramfs to the init process on a mounted real root filesystem. This is for boot environments, recovery shells and initramfs scripts, not for changing the root of an ordinary running system. The installed command is from util-linux 2.39.3 on this machine.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about twenty minutes for a dry review, or longer if you are repairing a boot failure. You need a root shell in the initramfs or another deliberately isolated boot environment, a mounted target filesystem, and an init executable on that target. The final command is service-disrupting and destructive to the old root, so read the warning in step 1 before running it.
1. Understand the irreversible part
switch_root moves the already mounted /proc, /dev, /sys and /run trees to the new root, makes the target the root filesystem, and starts the requested init process. It also recursively removes files and directories from the current root filesystem. That removal is the reason this command belongs at the end of an initramfs hand-off, after the real root is ready.
Do not test it from your normal host shell with a path under your live root. You could remove the environment that is currently running your system. There is no general undo command after a successful hand-off: recovery means rebooting into a working recovery or initramfs environment and repairing the boot configuration there.
Checkpoint: if you are not already in the boot environment that owns the temporary root, stop here. Use a recovery shell or a virtual machine for practice.
2. Confirm the installed command
These checks are ordinary and read-only. They do not need elevated privileges unless your environment restricts access to the binary:
$ command -v switch_root
/home/linuxbrew/.linuxbrew/sbin/switch_root
$ switch_root --version
switch_root from util-linux 2.42.4
$ dpkg-query -W -f='${Package} ${Version}\n' util-linux
util-linux 2.39.3-9ubuntu6.6
The package metadata and the selected executable disagree here because the executable is supplied by Linuxbrew while the Debian package is also installed. The local switch_root(8) manual is for util-linux 2.39.3, while the selected binary reports 2.42.4. Do not assume that another binary has identical diagnostics or implementation details. Use command -v and --version in the environment where the hand-off will happen.
The supported shape is:
switch_root NEWROOT INIT [ARG ...]
There are only two informational options in this installed interface: --help and --version. The target path and init command are positional arguments, not options.
3. Choose and mount the target root
Replace /newroot below with the directory where your boot environment mounted the real root filesystem. The mount operation normally requires elevated privileges. The exact device and filesystem type are deployment-specific, so do not paste the placeholder device:
# mkdir -p /newroot
# mount /dev/ROOT_DEVICE /newroot
# ls -ld /newroot /newroot/sbin /newroot/usr
Many systems use a layout where the init executable is below /sbin, /usr/sbin or another path selected by the boot system. Check the target rather than guessing:
# test -x /newroot/sbin/init && echo '/newroot/sbin/init is executable'
/newroot/sbin/init is executable
# ls -l /newroot/sbin/init
If the test fails, do not proceed. The target may be the wrong filesystem, may not have its usual mounts yet, or may use a different init path. A missing executable is a preparation failure, not a reason to try more sudo.
4. Make sure NEWROOT is a mount point
The manual requires NEWROOT to be the root of a mount. A plain directory on the current root is not enough, even if it contains a complete installed system. In a suitable root shell, inspect the mounts and confirm that the target was mounted at the exact path you will pass:
# findmnt --target /newroot
TARGET SOURCE FSTYPE OPTIONS
/newroot /dev/sda2 ext4 rw,relatime
Your source, filesystem type and options will differ. The useful result is a mount entry whose target is /newroot. If findmnt is unavailable, inspect /proc/self/mountinfo with the tools available in your initramfs rather than treating an ordinary directory as ready.
If you intentionally need to switch into a directory that is not already a mount, the manual documents a bind-mounting trick. It changes mount state and therefore needs elevated privileges:
# mount --bind /newroot /newroot
# findmnt --target /newroot
Only use this when you understand which filesystem contains the directory. A bind mount makes the directory a mount point; it does not populate the directory or fix an incorrectly mounted root.
5. Check the hand-off arguments
Before the destructive command, check both positional arguments in the exact environment that will execute it:
# NEWROOT=/newroot
# INIT=/newroot/sbin/init
# test -d "$NEWROOT" && test -x "$INIT" && echo 'target and init are ready'
target and init are ready
# printf 'new root: %s\ninit: %s\n' "$NEWROOT" "${INIT#/newroot}"
new root: /newroot
init: /sbin/init
Pass the init path as it should be seen after the root change, not as a path that still includes NEWROOT. In the example, the command uses /sbin/init, not /newroot/sbin/init. The shell variables above are only for review; the final command below uses the post-switch path explicitly.
Do not add arguments unless the target init and your boot design require them. Any arguments after the init path are passed to that process. Quote variable expansions if you build the command in a script, and keep the target and init values under your control.
6. Perform the hand-off
Read the warning again before this step: success does not return to the shell, and the old root is recursively removed. This is the point where an incorrect target can destroy the temporary environment or leave the machine unable to boot. Run it only from the intended initramfs or isolated recovery environment:
# switch_root /newroot /sbin/init
A successful invocation does not print a completion message and does not return. The requested init process takes over. Do not put switch_root behind sh -c merely to capture a later success status; there is no later status on success.
If the command returns, the manual specifies exit status 1 for failure. Preserve the diagnostic and inspect the target mount, init path and mount layout without repeatedly rerunning the destructive command:
# printf 'switch_root failed with status %s\n' "$?"
switch_root failed with status 1
The exact error text varies by version and failure. A failed attempt is not proof that every earlier preparation action was undone, so re-check the mount state before making another attempt.
7. Recover without guessing
If the new system does not start, reboot into the same recovery or initramfs environment and inspect the target before changing anything. Verify that the intended root is mounted, that the init path exists and is executable, and that the command selected in that environment is the one you reviewed. If you used the bind-mount trick, unmount that bind mount in the recovery environment when it is no longer needed:
# umount /newroot
Do not run that unmount blindly if other filesystems or services depend on the mount. Check the mount listing first. The original filesystem data cannot be restored by an umount; it only removes the mount relationship. For a production boot repair, keep a tested recovery path and a backup of the boot configuration before changing the initramfs or root selection.
Done means
- You ran
switch_root --versionin the actual hand-off environment and recorded which binary it selected. - The real root filesystem is mounted at the exact
NEWROOTpath. - The target init is executable and is passed using its path after the root change.
- You understand that
switch_rootrecursively removes the current root and does not return on success. - You have a recovery environment available before making the hand-off.
- After a successful hand-off, the new init process is running and the temporary root is no longer needed.