* Allow multiple file systems to be mounted in stage 1 (i.e., from the

initrd).  This is useful if /nix (which is necessary for stage 2) is
  on a different file system than /.

svn path=/nixos/trunk/; revision=7862
This commit is contained in:
Eelco Dolstra 2007-02-06 16:53:36 +00:00
parent 923348b490
commit 8cf1eceb0a
3 changed files with 99 additions and 37 deletions

View File

@ -3,6 +3,7 @@
fail() { fail() {
# If starting stage 2 failed, start an interactive shell. # If starting stage 2 failed, start an interactive shell.
echo "Stage 2 failed, starting emergency shell..." echo "Stage 2 failed, starting emergency shell..."
echo "(Stage 1 init script is $stage2Init)"
exec @staticShell@ exec @staticShell@
} }
@ -67,12 +68,55 @@ udevtrigger
udevsettle udevsettle
# Function for mounting a file system.
mountFS() {
local device="$1"
local mountPoint="$2"
local options="$3"
# Check the root device, if .
mustCheck=
if test -b "$device"; then
mustCheck=1
else
case $device in
LABEL=*)
mustCheck=1
;;
esac
fi
if test -n "$mustCheck"; then
fsck -C -a "$device"
fsckResult=$?
if test $(($fsckResult | 2)) = $fsckResult; then
echo "fsck finished, rebooting..."
sleep 3
# reboot -f -d !!! don't have reboot yet
fail
fi
if test $(($fsckResult | 4)) = $fsckResult; then
echo "$device has unrepaired errors, please fix them manually."
fail
fi
if test $fsckResult -ge 8; then
echo "fsck on $device failed."
fail
fi
fi
# Mount read-writable.
mount -n -o "$options" "$device" /mnt/root$mountPoint || fail
}
# Try to find and mount the root device. # Try to find and mount the root device.
mkdir /mnt mkdir /mnt
mkdir /mnt/root mkdir /mnt/root
echo "mounting the root device..."
if test -n "@autoDetectRootDevice@"; then if test -n "@autoDetectRootDevice@"; then
# Look for the root device by label. # Look for the root device by label.
@ -109,32 +153,36 @@ if test -n "@autoDetectRootDevice@"; then
else else
# Hard-coded root device. # Hard-coded root device(s).
rootDevice="@rootDevice@" mountPoints=(@mountPoints@)
devices=(@devices@)
fsTypes=(@fsTypes@)
optionss=(@optionss@)
# Check the root device. for ((n = 0; n < ${#mountPoints[*]}; n++)); do
fsck -C -a "$rootDevice" mountPoint=${mountPoints[$n]}
fsckResult=$? device=${devices[$n]}
fsType=${fsTypes[$n]}
options=${optionss[$n]}
if test $(($fsckResult | 2)) = $fsckResult; then # !!! Really quick hack to support bind mounts, i.e., where
echo "fsck finished, rebooting..." # the "device" should be taken relative to /mnt/root, not /.
sleep 3 # Assume that every device that doesn't start with /dev or
# reboot -f -d !!! don't have reboot yet # LABEL= is a bind mount.
fail case $device in
fi /dev/*)
;;
LABEL=*)
;;
*)
device=/mnt/root$device
;;
esac
if test $(($fsckResult | 4)) = $fsckResult; then echo "mounting $device on $mountPoint..."
echo "$rootDevice has unrepaired errors, please fix them manually."
fail
fi
if test $fsckResult -ge 8; then mountFS "$device" "$mountPoint" "$options"
echo "fsck on $rootDevice failed." done
fail
fi
# Mount read-writable.
mount -n -o rw "$rootDevice" /mnt/root || fail
fi fi
@ -148,8 +196,6 @@ mount --move . /
umount /proc # cleanup umount /proc # cleanup
umount /sys umount /sys
echo "INIT = $stage2Init"
if test -z "$stage2Init"; then fail; fi if test -z "$stage2Init"; then fail; fi
exec chroot . $stage2Init exec chroot . $stage2Init

View File

@ -10,8 +10,15 @@
, # Whether to find root device automatically using its label. , # Whether to find root device automatically using its label.
autoDetectRootDevice autoDetectRootDevice
, # If not scanning, the root must be specified explicitly. , # If not scanning, the root must be specified explicitly. Actually,
rootDevice # stage 1 can mount multiple file systems. This is necessary if,
# for instance, /nix (necessary for stage 2) is on a different file
# system than /.
#
# This is a list of {mountPoint, device|label} attribute sets, i.e.,
# the format used by the fileSystems configuration option. There
# must at least be a file system for the / mount point in this list.
fileSystems ? []
# If scanning, we need a disk label. # If scanning, we need a disk label.
, rootLabel , rootLabel
@ -21,12 +28,23 @@
stage2Init ? "/init" stage2Init ? "/init"
}: }:
let
# !!! use XML; copy&pasted from upstart-jobs/filesystems.nix.
mountPoints = map (fs: fs.mountPoint) fileSystems;
devices = map (fs: if fs ? device then fs.device else "LABEL=" + fs.label) fileSystems;
fsTypes = map (fs: if fs ? fsType then fs.fsType else "auto") fileSystems;
optionss = map (fs: if fs ? options then fs.options else "defaults") fileSystems;
in
assert autoDetectRootDevice -> mountPoints != [];
substituteAll { substituteAll {
src = ./boot-stage-1-init.sh; src = ./boot-stage-1-init.sh;
isExecutable = true; isExecutable = true;
inherit staticShell modules modulesDir; inherit staticShell modules modulesDir;
inherit autoDetectRootDevice; inherit autoDetectRootDevice mountPoints devices fsTypes optionss;
rootDevice = if !autoDetectRootDevice then rootDevice else "";
rootLabel = if autoDetectRootDevice then rootLabel else ""; rootLabel = if autoDetectRootDevice then rootLabel else "";
path = [ path = [
staticTools staticTools

View File

@ -68,12 +68,10 @@ rec {
inherit (pkgsDiet) module_init_tools; inherit (pkgsDiet) module_init_tools;
inherit extraUtils; inherit extraUtils;
autoDetectRootDevice = config.get ["boot" "autoDetectRootDevice"]; autoDetectRootDevice = config.get ["boot" "autoDetectRootDevice"];
rootDevice = fileSystems =
let rootFS = pkgs.lib.filter
(pkgs.library.findSingle (fs: fs.mountPoint == "/") (fs: fs.mountPoint == "/" || (fs ? neededForBoot && fs.neededForBoot))
(abort "No root mount point declared.") (config.get ["fileSystems"]);
(config.get ["fileSystems"]));
in if rootFS ? device then rootFS.device else "LABEL=" + rootFS.label;
rootLabel = config.get ["boot" "rootLabel"]; rootLabel = config.get ["boot" "rootLabel"];
inherit stage2Init; inherit stage2Init;
modulesDir = modulesClosure; modulesDir = modulesClosure;