nixpkgs/boot/boot-stage-1-init.sh

262 lines
5.9 KiB
Bash
Raw Normal View History

#! @staticShell@
fail() {
# If starting stage 2 failed, start an interactive shell.
echo "Stage 2 failed, starting emergency shell..."
echo "(Stage 1 init script is $stage2Init)"
exec @staticShell@
}
# Poor man's `basename'.
basename() {
local s="$1"
set -- $(IFS=/; echo $s)
local res
while test $# != 0; do res=$1; shift; done
echo $res
}
# Print a greeting.
echo
echo "<<< NixOS Stage 1 >>>"
echo
# Set the PATH.
export PATH=/empty
for i in @path@; do
PATH=$PATH:$i/bin
if test -e $i/sbin; then
PATH=$PATH:$i/sbin
fi
done
# Mount special file systems.
mkdir -p /etc # to shut up mount
echo -n > /etc/fstab # idem
mkdir -p /proc
mount -t proc none /proc
mkdir -p /sys
mount -t sysfs none /sys
# Process the kernel command line.
stage2Init=/init
for o in $(cat /proc/cmdline); do
case $o in
init=*)
set -- $(IFS==; echo $o)
stage2Init=$2
;;
debugtrace)
# Show each command.
set -x
;;
debug1) # stop right away
fail
;;
debug1devices) # stop after loading modules and creating device nodes
debug1devices=1
;;
debug1mounts) # stop after mounting file systems
debug1mounts=1
;;
esac
done
# Load some kernel modules.
for i in $(cat @modulesClosure@/insmod-list); do
echo "loading module $(basename $i)..."
insmod $i
done
# Create /dev/null.
mknod /dev/null c 1 3
# Try to resume - all modules are loaded now.
if test -e /sys/power/tuxonice/resume; then
if test -n "$(cat /sys/power/tuxonice/resume)"; then
echo 0 > /sys/power/tuxonice/user_interface/enabled
echo 1 > /sys/power/tuxonice/do_resume || echo "Failed to resume..."
fi
fi
echo "@resumeDevice@" > /sys/power/resume 2> /dev/null || echo "Failed to resume..."
echo shutdown > /sys/power/disk
# Create device nodes in /dev.
export UDEV_CONFIG_FILE=/udev.conf
echo 'udev_rules="/rules"' > $UDEV_CONFIG_FILE
mkdir /rules
udevd --daemon
udevadm trigger
udevadm settle
if type -p dmsetup > /dev/null; then
echo "dmsetup found, starting device mapper and lvm"
dmsetup mknodes
lvm vgscan --ignorelockingfailure
lvm vgchange -ay --ignorelockingfailure
fi
if test -n "$debug1devices"; then fail; fi
# Function for mounting a file system.
mountFS() {
local device="$1"
local mountPoint="$2"
local options="$3"
local fsType="$4"
# 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
FSTAB_FILE="/etc/mtab" fsck -V -v -C -a "$device"
fsckResult=$?
if test $(($fsckResult | 2)) = $fsckResult; then
echo "fsck finished, rebooting..."
sleep 3
reboot
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 -t "$fsType" -o "$options" "$device" /mnt-root$mountPoint || fail
}
# Try to find and mount the root device.
mkdir /mnt-root
echo "mounting the root device.... (fix: sleeping 5 seconds to wait for upcoming usb drivers)"
sleep 5
if test -n "@autoDetectRootDevice@"; then
# Look for the root device by label.
echo "probing for the NixOS installation CD..."
for i in /sys/block/*; do
if test "$(cat $i/removable)" = "1"; then
echo " in $i..."
set -- $(IFS=: ; echo $(cat $i/dev))
major="$1"
minor="$2"
# Create a device node for this device.
nuke /dev/tmpdev # don't have `rm' in klibc
mknod /dev/tmpdev b "$major" "$minor"
if mount -o ro -t iso9660 /dev/tmpdev /mnt-root; then
if test -e "/mnt-root/@rootLabel@"; then
found=1
break
fi
umount /mnt-root
fi
fi
done
if test -z "$found"; then
echo "CD not found!"
fail
fi
else
# Hard-coded root device(s).
mountPoints=(@mountPoints@)
devices=(@devices@)
fsTypes=(@fsTypes@)
optionss=(@optionss@)
for ((n = 0; n < ${#mountPoints[*]}; n++)); do
mountPoint=${mountPoints[$n]}
device=${devices[$n]}
fsType=${fsTypes[$n]}
options=${optionss[$n]}
# !!! Really quick hack to support bind mounts, i.e., where
# the "device" should be taken relative to /mnt-root, not /.
# Assume that every device that start with / but doesn't
# start with /dev or LABEL= is a bind mount.
case $device in
/dev/*)
;;
LABEL=*)
;;
/*)
device=/mnt-root$device
;;
esac
echo "mounting $device on $mountPoint..."
mountFS "$device" "$mountPoint" "$options" "$fsType"
done
fi
# If this is a live-CD/DVD, then union-mount a tmpfs on top of the
# original root.
targetRoot=/mnt-root
if test -n "@isLiveCD@"; then
mkdir /mnt-tmpfs
mount -t tmpfs -o "mode=755" none /mnt-tmpfs
mkdir /mnt-union
mount -t aufs -o dirs=/mnt-tmpfs=rw:$targetRoot=ro none /mnt-union
targetRoot=/mnt-union
fi
if test -n "$debug1mounts"; then fail; fi
# `run-init' needs a /dev/console on the target FS.
if ! test -e $targetRoot/dev/console; then
mkdir -p $targetRoot/dev
mknod $targetRoot/dev/console c 5 1
fi
# Start stage 2. `run-init' deletes all files in the ramfs on the
# current /.
if test -z "$stage2Init"; then fail; fi
umount /sys
umount /proc
exec run-init "$targetRoot" "$stage2Init"
fail