从分区的子目录启动Linux系统?


11

我想尝试设置一台计算机,以便它在同一文件系统中都安装了多个Linux。例如,filesytem将有3个文件夹:/Ubuntu_Precise/Ubuntu_Oneiric,和/Ubuntu_Natty

(我知道您可以使用BTRFS和子卷来执行此操作,但是我想使用EXT4来​​提高速度)。

我曾经使用BTRFS设置了多个不同发行版的多个安装,并且通过使它正常工作,我知道Grub可以很好地从“非标准”路径启动vmlinuz和initrd映像。但是当我做BTRFS时,有rootflags=subvol=@<subvolume_name>一个告诉内核将子卷挂载为/在文件系统中。是否有任何论点可以传递给内核,以使其绑定到/分区中的子文件夹,然后引导它?

我认为对于其他部分,我已经很接近了。我知道如何在中特定绑定绑定/etc/fstab。另外,从在BTRFS子卷中安装多个Linux的系统开始,我就习惯于在VM中安装发行版,然后使用rsync进行迁移,因此我不太担心需要做什么。得到正确的配置,我只是在尝试找出正确的配置。知道这一点后,我应该可以轻松地迁移到子文件夹并进行文件编辑了。

我已经了解虚拟化和分区,但这不是我想要的。目标计算机没有足够的能力进行虚拟化,并且分区不共享可用空间。我正在寻求建立一个双/三/四/等启动Linux发行版的系统,但是仅用一个文件系统即可完成,因此不会出现“我有可用空间,但它位于错误的分区!”的情况。

如果有人对如何编辑我的问题或其标题提出更清晰的建议,我无所不能。


1
AFAIK没有任何内容内置到系统中。您可能需要做的是添加另一个bootparameter并修改initramfs以将chroot放入子目录,然后再执行init
Ulrich Dangel 2012年

@UlrichDangel就是我要提出的内容。回答吧!
尼尔斯2012年

@Nils好吧,我刚刚提供了一个答案,TBH。我不想一开始就写一个,因为我不想提供补丁/脚本
Ulrich Dangel,2012年

Answers:


10

简短的答案-据我所知,还没有针对您的特定要求的开箱即用的解决方案。您将必须调整每个发行版的每个initramfs以满足您的特定需求。

长答案-是的,有可能。如今,大多数Linux发行版都使用initramfs,这些文件将由引导加载程序加载到内存中,然后由内核解压缩。它将在那里运行/sbin/init,它负责设置早期的用户空间(运行udev,加载模块,启动普利茅斯,要求加密密码短语,为网络安装设置网络,等等)。您可以运行自己的脚本并评估自定义启动参数。

Debian示例

如果您使用的是Debian(与Ubuntu相同),则应该能够在/etc/initramfs-tools/scripts/init-bottom/启动init之前放置一个将在其中执行的脚本。有关脚本的更多信息,请参见man initramfs-tools中的不同目录和布局。您将不得不调整rootmnt并添加目标目录。

示例(未经测试)脚本,应以/etc/initramfs-tools/scripts/local-bottom/00-myroot或安装/usr/share/initramfs-tools/scripts/init-top/00-myroot

#!/bin/sh -e

PREREQS=""

prereqs() { echo "$PREREQS"; }

case "$1" in
  prereqs)
  prereqs
  exit 0
;;
esac

for opt in $(cat /proc/cmdline); do
  case $opt in
    rootdir=*)
      new_mntdir="${opt#rootdir=}"
      ;;
    esac
done

if [ -n "$new_mntdir" ] ; then
  echo rootmnt="$rootmnt/$new_mntdir" >> /conf/param.conf
fi

这个想法是要调整rootmnt initramfs init脚本中用来启动/执行实际init的代码。由于根设备已经安装在init-bootom阶段中,因此您只需调整/更改目标目录即可。

要使用此脚本,只需添加一个新的引导参数,将脚本复制,使其可执行,重新生成initramfs并为Linux发行版添加引导参数,例如rootdir=/Ubuntu_Precise


您可能还想将实际根目录绑定安装到os根目录的子目录中,以便可以从引导的目录中看到其他OS文件。
psusi

@psusi您可以通过fstab或直接mount /dev/rootdevice /mountpoint在系统运行后执行
Ulrich Dangel 2012年

我不知道什么时候改变了?您过去无法再次安装相同的块设备。你会很忙。
psusi

1
@psusi不确定,但可能会引入绑定安装
Ulrich Dangel

@UlrichDangel感谢(非常)详细的答案!
阿岑代尔(Azendale)2012年

2

这是在ubuntu仿生中(以及可能在其他地方)工作的两种方法。我没有足够的代表发表评论,但是,仿生的:/ usr / share / initramfs-tools / init在调用mountroot之后,在调用* -bottom脚本之前,在/ etc / fstab中查找/ usr,因此添加了一个init-底部脚本(如此处另一个答案所示)为“为时已晚”。相反,我推荐这些:

#!/bin/bash -f
#copyleft 2018 greg mott

#set a subdirectory as root (so multiple installs don't need partitions)
#these work in ubuntu bionic, could be different elsewhere
#1st choice:  tweak initramfs-tools/scripts/local
#   pro:  subdirectory becomes root directly, nothing gets any chance to see the partition root
#   con:  only works if the subdirectory's initramfs/initrd is tweaked and rebuilt
#2nd choice:  specify this script as init= on the kernel commandline
#   pro:  no need to rebuild initramfs
#   con:  if the partition root etc/fstab mounts /usr the initramfs will have already mounted it
#   con:  it's conceivable some initramfs script might still look in the partition root rather than your subdirectory
#   con:  this script requires bin/bash et al in the partition root

#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
#}

#to use this script, in addition to subroot= on the kernel commandline also specify:
#   init=/path/to/script        #pathname from partition root to this script (chmod 744)

#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 look)
#             fi
#          mountroot_status="$?"
#          [ $mountroot_status = 0 ]||sleep 90                                          #if error pause to look
#          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 kernel installed

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 (ie 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

这对我来说是一种享受
paultop6 '18

1

出于不同目的,引导不同的linux而不弄乱分区表很有趣,共享文件系统的另一种解决方案是使用循环卷,这里需要进行一些更改,假设您在/ dev / sdb1文件系统中有一个/ debian循环文件/卷。 (我正在使用当前的GNU / Debian sid / unstable用于main和loop操作系统)。

/etc/grub.d/40_custom: # outside from loop volume
menuentry 'label' --class gnu-linux --class gnu --class os {
    ...
    loopback loop (hd2,msdos1)/debian
    linux   (loop)/boot/vmlinuz root=/dev/sdb1 loop=/debian ro
    initrd  (loop)/boot/initrd
}

通过initrd / init将在grub中定义为Linux命令行的参数设置为env,因此:

ROOT=/dev/sdb1
rootmnt=/root
loop=/debian 

循环允许通过“自身”挂载卷,默认脚本流程会执行一个操作,mount /dev/sdb1 /root我们只是有选择地将/ dev / sdb1重新挂载为rw(如果它是ro),然后总是附加一个mount -o loop /root/debian /root

/etc/initramfs-tools/scripts/local-bottom/loop: # inside the loop volume
#!/bin/sh

[ "$1" = "prereqs" ] && echo && exit 0

if [ -n "${loop}" ]; then
        if [ "${readonly}" = "y" ]; then
                roflag=-r
                mount -o remount,rw ${ROOT} ${rootmnt}
        else
                roflag=-w
        fi
        mount ${roflag} -o loop ${rootmnt}${loop} ${rootmnt}
fi

还需要预加载一些模块到initram中(然后不要忘记运行update-initramfs)

/etc/initramfs-tools/modules: # inside the loop volume
...
loop
ext4

不知道使用循环有多少会影响性能或浪费资源,我想知道将ext4挂载到ext4上是否会使文件系统故障的可能性增加一倍,但您猜想可以进行一些调整。也许有更好的方法来使用循环,减少黑客行为,如果有的话请让我知道,因为我还没有找到。


0

这不是一个答案,但是我想澄清一下关于乌尔里希的答案和评论的一些观点(我不能在上面发表评论)。

Ulrich提出的解决方案建议“可能”工作(尚未试用),但是您将获得一个不可重装的文件系统。作为一种解决方法(恕我直言,这很丑),您可以在chroot之前将fs挂载为rw(如此处建议),但要注意损坏的init脚本。我猜这种解决方法有更多的副作用(例如损坏的fs试图重新安装ro并失败)。

我正在使用ext4的内核3.2,并在chroot中安装一个已经安装的开发人员,正如psusi所说的,仍然很忙。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.