Here's a script which works for me. i like the simplicity that i don't need to touch the initramfs/initrd. So far my usage case has been very simple, i'm only working with clones of ubuntu bionic, and i must confess i'm not yet sure whether udev and kernel modules are working from the right hierarchy. it would be super if someone more knowledgeable could clarify that.
#!/bin/bash -f #set a subdirectory as root directory (with no change to initrd)(multiple installs don't need partitions) #simply specify on the kernel commandline: # init=pat pathname from partition root to this script (chmod 744) # subroot=foo pathname to become root directory # partroot=par mountpoint within subroot where partition root will be left mounted #menuentry "subroot foo" { #copy /etc/grub.d/40_custom to /etc/grub.d/07_custom and add menuentries like this example # echo "subroot foo" # set sub=foo # search --no-floppy --fs-uuid --set=root 22e7c84a-a416-43e9-ae9d-ee0119fc3894 #use your partition's uuid # linux /$sub/vmlinuz ro root=UUID=22e7c84a-a416-43e9-ae9d-ee0119fc3894 init=pat subroot=foo partroot=par # echo "initrd /$sub/initrd.img" # initrd /$sub/initrd.img #works in recent releases where this link is relative #} subroot(){ for a in $(<proc/cmdline) do [[ $a = subroot=* ]]&& subroot=${a#*=} [[ $a = partroot=* ]]&&partroot=${a#*=} done [[ $subroot ]]||{ echo no subroot on kernel cmdline;return 1;} [[ $partroot ]]||{ echo no partroot on kernel cmdline;return 1;} (set -x;mount --bind $subroot mnt)||return for m in $(while read -r r;do r=($r) [[ ${r[1]} = /?(mnt) ]]||echo ${r[1]} #excluding / and /mnt done<proc/mounts) do (set -x;mount --bind $m mnt$m)||return #--bind whatever's already mounted done set -x cd mnt||return pivot_root . $partroot } subroot&&exec chroot . init "$@"||exec bash