Here are two ways which work in ubuntu focal&bionic (and likely elsewhere). i've not enough rep to comment, but, bionic:/usr/share/initramfs-tools/init looks in /etc/fstab for /usr right after calling mountroot and before calling the *-bottom scripts, so adding an init-bottom script (as suggested in another answer here) is "too late". instead i recommend these:
#!/bin/bash -f #copyleft 2018 greg mott #set a subdirectory as root (so multiple installs don't need partitions) #these work in ubuntu bionic, might need tweaking to work elsewhere #1st choice: tweak initramfs-tools/scripts/local # pro: $sub becomes root directly, nothing gets any chance to see the partition root # con: requires the subdirectory's initramfs/initrd to be tweaked and rebuilt #2nd choice: specify this scriptfile as init= on the kernel commandline # pro: no need to rebuild initramfs # con: bin/bash in partition root must be executable by $sub/vmlinux (partition root older than $sub likely will work) # con: if the partition root etc/fstab mounts /usr, the $sub initramfs will mount the partition root /usr # con: additional initramfs scripts might also look in the partition root rather than $sub #for either choice copy /etc/grub.d/40_custom to /etc/grub.d/07_custom and add one or more menuentries that specify subroot: #menuentry "subroot foo" { # echo "subroot foo" # sub=/foo # uuid=22e7c84a-a416-43e9-ae9d-ee0119fc3894 #use your partition's uuid # search --no-floppy --fs-uuid --set=root $uuid # linux $sub/vmlinuz ro root=UUID=$uuid subroot=$sub # echo "initrd $sub/initrd.img" # initrd $sub/initrd.img #works in recent releases where the /initrd.img softlink is relative #} #for the 2nd choice, in addition to subroot= on the kernel commandline also specify: # init=/path/to/script #pathname from partition root to this scriptfile (chmod 744) #for the 1st choice, the tweak for bionic:/usr/share/initramfs-tools/scripts/local is replace: # mount ${roflag} ${FSTYPE:+-t ${FSTYPE} }${ROOTFLAGS} ${ROOT} ${rootmnt} # mountroot_status="$?" #with: # set -x # karg=" $(cat<proc/cmdline) " m=${karg#* subroot=} # [ "$m" = "$karg" ]||subroot=${m%% *} #extract subroot from kernel commandline # [ $subroot ]&&part=part||part=$rootmnt #no subroot, just mount partition as root # mkdir part # mount ${roflag} ${FSTYPE:+-t ${FSTYPE} }${ROOTFLAGS} ${ROOT} $part&& #mount partition # if [ "$subroot" ] # then mount --bind part/$subroot $rootmnt&& #mount subroot # umount part #&&sleep 15 #unmount partition root (uncomment &&sleep for time to watch) # fi # mountroot_status="$?" # [ $mountroot_status = 0 ]||sleep 90 #if error pause to see it # set +x #once you've edited /usr/share/initramfs-tools/scripts/local, update-initramfs -u will rebuild for the current kernel, #and it will automatically build into every new initrd/initramfs installed thereafter subroot(){ karg=" $(cat<proc/cmdline) " m=${karg#* subroot=} [ "$m" = "$karg" ]||subroot=${m%% *} #extract subroot from kernel commandline [ $subroot ]||return 0 #no subroot, just proceed in partition root while read -r m r m do for m in $M x #build list of what's already mounted do [[ $r = $m* ]]&&break #exclude subtrees (eg dev/**) done||[[ $r = / ]]||M=$M\ $r #exclude / done<proc/mounts (set -x;mount --bind $subroot mnt)||{ set -x #mount subroot sleep 30 #if not found pause to see error return 0;} #then reincarnate as partition root init for m in $M do (set -x;mount -n --move $m mnt$m)||return #move listed mounts to subroot done set -x cd mnt&& pivot_root . mnt&& #subroot becomes root umount -l mnt&& #unmount partition root #sleep 15 && #so far so good? uncomment for time to look exec chroot . init "$@" #reincarnate as subroot init } subroot "$@"&&exec init "$@"||exec bash #land in a shell if moves or pivot fail