好吧,基本上,我正尝试以类似于 WUBI 的方式启动 Gentoo;我有一个 ext4 格式的环回文件安装,在 Windows Bootloader 下安装了 BURG,并且 kernel/initramfs 可用于启动。启动仍然有一些问题(我认为我可以解决这些问题,它们主要是因为程序本身的小问题),但我有基本的想法:
- 设置 busybox 并使用 mdev 获取设备
- 解析命令行选项,确定是否要求实数根或循环根
- 如果是真正的root,则将其挂载
/root
并切换为root,然后执行/sbin/init
。 - 如果循环根,则将主机分区挂载上
/host
。 - 安装环回 (
/host/${LOOP}
) 于/root
- 移动主机的挂载点(
mount -o move /host /root/host
用于 busybox) - 切换root到
/root
并执行/sbin/init
我在这里有init
脚本:
#!/bin/sh
# Rescue shell in case of error.
rescue_shell() {
echo "Something went wrong. Dropping you to a shell."
exec /bin/sh
}
parse_opt() {
case "$1" in
*\=*)
echo "$1" | cut -d= -f2-
;;
esac
}
# Set up BusyBox...
busybox --install -s
# Mount the /proc and /sys filesystems.
mount -t proc none /proc
mount -t sysfs none /sys
# Populate /dev
echo ":: Populating /dev..."
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
# Get command line options...
for x in ${CMDLINE}
do
case "${x}" in
root\=*)
ROOT=`parse_opt "${x}"`
;;
# Loadloop
loop\=*)
LOOP=`parse_opt "${x}"`
;;
ntfsroot)
NTFSROOT=1
;;
esac
done
if [ "${NTFSROOT}" != 1 ]
then
# Mount the root filesystem, plain and simple.
echo ":: Mounting real root..."
mount -o ro "${ROOT}" /mnt/root || rescue_shell
else
# Load up an NTFS-based root.
echo ":: NTFS Root mount requested. Mounting..."
ntfs-3g "${ROOT}" /host
if [ -f "/host/${LOOP}" ]
then
mount -o loop,ro "/host/${LOOP}" /root || rescue_shell
echo ":: Mounted. Moving host..."
mount -o move /host /root/host || rescue_shell
echo ":: Mounted."
else
"!! ERROR: Invalid/nonexistant loop given!"
rescue_shell
fi
fi
# Clean up.
umount /proc
umount /sys
# Boot the real thing.
echo ":: Switching to root and calling init..."
exec switch_root /root /sbin/init
其实没什么复杂的。NTFS-3G 显然不同意 busybox 的实现mount
和其他东西(它出于某种原因添加了参数 -i,然后ntfs-3g
就崩溃了),所以我正在考虑直接复制coreutils
实现或其他东西。此外,我需要检查安装环回分区所需的内容(当我尝试手动安装环回时,它会给我一个错误,如“文件未找到”)。不过,我认为这些很容易自己解决。
但是,我有点疑惑的是关机。一旦switch_root
完成,系统将留下一个/
回送挂载文件和/dev/sda2
(这是 Windows 7 安装)在/host
。现在,无法卸载/host
,因为它正在使用中。但是,/
当根目录的文件系统挂载在子目录中时,无法卸载。基于 WUBI 的 Ubuntu 安装必须面临同样的困境。如何克服这个问题?这是一个先有鸡还是先有蛋的问题,这真的让我很恼火。
我正在考虑编写一个引导脚本,该脚本保存用于基本根目录(类似于 initramfs,但反过来)的临时文件缓存。它会最后运行,将文件复制到 tmpfs,旋转根目录,也许将其恢复为 initramfs 的原始布局。我基本上会这样做:
- 安装 a
tmpfs
或者/tmp/shutdown/
某物。 - 复制关机文件(也许
/usr/share/shutdown/
或其他) pivot_root
将根目录移至 tmpfs/loop
并 chroot 到 tmpfs 中。mount --move
到/loop/host
/host
- 卸载
/loop
- 卸载
/host
- 彻底关闭,因为所有分区都已卸载。
但是,我从未对 Gentoo 进行过如此多的修改。使用 initscript 可以实现吗?我不希望它被对 baselayout 或任何 ebuild 的任何更新所覆盖,因为这会导致我的关机功能中断(我真的不想丢失主机分区)。还有一个问题是弄清楚 Gentoo 的 init 系统是否支持这样的功能。它似乎足够干净(如果有点黑客),但我对此不太确定。我想知道 Ubuntu 是否以不同的方式做到这一点,如果是,怎么做的?任何建议都会有所帮助。
编辑:
我启动成功了。只需使用 版本即可coreutils
,mount
就像我所想的那样。但是,我在关机时遇到了我预期的错误;无法卸载文件系统的错误和环回文件系统的日志错误。我仍然不知道如何修复这个问题。
编辑2:
好吧,我做了一些事情……有点奏效。我基本上编辑/etc/init.d/{halt.sh,reboot.sh,shutdown.sh}
并做了以下事情:
- 添加
/host
到RC_NO_UMOUNTS
变量中,可防止 EXT4 模块因日志错误而阻塞 - 添加
-o `pidof ntfs-3g`
到 opts 中killall5
(以确保它不会杀死 ntfs-3g) - 修改了 shutdown.sh 和 restart.sh,以在 /boot/shutdownfs 上挂载 tmpfs,并将一些 initramfs 文件复制到那里,旋转根,然后 chroot 进入其中,调用 /down 或 /restart。
- 这两个脚本本质上会进行一些快速而粗糙的 /proc 和 /sys 设置,将 /root/host 移动到 /host,然后进行延迟卸载。我无法让常规卸载工作(文件系统仍然很忙),但至少这似乎可以完全阻止文件系统呕吐。
该解决方案仍然不够完善,因此,如果能提供任何帮助,我们将不胜感激。
答案1
我不是这方面的专家,但在阅读umount
手册页后,我看到一个特定于循环安装设备的标志:
-d In case the unmounted device was a loop device, also free this loop device.
另外进一步阅读losetup
(仍然在手册页中),我建议您可以使用它来调试,因为它可用于查看循环安装设备的状态。
我指的是手册页的链接在这儿. 此选项:
-a Show status of all loop devices.
可能会给你一个线索,并且一些其他标志可能会帮助卸载循环设备。
由于我无法复制您的情况,我只能建议您自己寻找答案的方法,很抱歉我无法提供更多帮助。
答案2
-l
延迟卸载。立即将文件系统从文件系统层次结构中分离出来,并在文件系统不再繁忙时立即清除对文件系统的所有引用。(需要内核 2.4.11 或更高版本。)