nixpkgs/modules/system/boot/stage-1-init.sh
Eelco Dolstra 6c9059e717 * Added an option `boot.initrd.availableKernelModules' that specifies
modules that should be added to the initrd, but should only be
  loaded on demand (e.g. by the kernel or by udev).  This is
  especially useful in the installation CD, where we now only load the
  modules needed by the hardware.
* Enable automatic modprobing by udev in the initrd.

svn path=/nixos/trunk/; revision=18975
2009-12-15 16:38:20 +00:00

307 lines
7.7 KiB
Bash
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#! @shell@
targetRoot=/mnt-root
export LD_LIBRARY_PATH=@extraUtils@/lib
export PATH=@extraUtils@/bin:@klibc@/bin
fail() {
# If starting stage 2 failed, allow the user to repair the problem
# in an interactive shell.
cat <<EOF
An error occured in stage 1 of the boot process, which must mount the
root filesystem on \`$targetRoot' and then start stage 2. Press one
of the following keys within $timeout seconds:
i) to launch an interactive shell;
f) to start an interactive shell having pid 1 (needed if you want to
start stage 2's init manually); or
*) to ignore the error and continue.
EOF
read reply
case $reply in
f)
exec @shell@;;
i)
echo "Starting interactive shell..."
@shell@ || fail
;;
*)
echo "Continuing...";;
esac
}
trap 'fail' ERR
# Print a greeting.
echo
echo "<<< NixOS Stage 1 >>>"
echo
# 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.
export 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 the required kernel modules.
echo @extraUtils@/bin/modprobe > /proc/sys/kernel/modprobe
for i in @kernelModules@; do
echo "loading module $(basename $i)..."
modprobe $i || true
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
if test -e /sys/power/resume -a -e /sys/power/disk; then
echo "@resumeDevice@" > /sys/power/resume 2> /dev/null || echo "failed to resume..."
echo shutdown > /sys/power/disk
fi
# Create device nodes in /dev.
echo "running udev..."
export UDEV_CONFIG_FILE=@udevConf@
mkdir -p /dev/.udev # !!! bug in udev?
udevd --daemon
udevadm trigger
udevadm settle
if type -p dmsetup > /dev/null; then
echo "starting device mapper and LVM..."
dmsetup mknodes
lvm vgscan --ignorelockingfailure
lvm vgchange -ay --ignorelockingfailure
fi
if test -n "$debug1devices"; then fail; fi
@postDeviceCommands@
# Return true if the machine is on AC power, or if we can't determine
# whether it's on AC power.
onACPower() {
! test -d "/proc/acpi/battery" ||
! ls /proc/acpi/battery/BAT[0-9]* > /dev/null 2>&1 ||
! cat /proc/acpi/battery/BAT*/state | grep "^charging state" | grep -q "discharg"
}
# Check the specified file system, if appropriate.
checkFS() {
# Only check block devices.
if ! test -b "$device"; then return 0; fi
eval $(fstype "$device")
# Don't check ROM filesystems.
if test "$FSTYPE" = iso9660 -o "$FSTYPE" = udf; then return 0; fi
# Optionally, skip fsck on journaling filesystems. This option is
# a hack - it's mostly because e2fsck on ext3 takes much longer to
# recover the journal than the ext3 implementation in the kernel
# does (minutes versus seconds).
if test -z "@checkJournalingFS@" -a \
\( "$FSTYPE" = ext3 -o "$FSTYPE" = ext4 -o "$FSTYPE" = reiserfs \
-o "$FSTYPE" = xfs -o "$FSTYPE" = jfs \)
then
return 0
fi
# Don't run `fsck' if the machine is on battery power. !!! Is
# this a good idea?
if ! onACPower; then
echo "on battery power, so no \`fsck' will be performed on \`$device'"
return 0
fi
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
return 0
}
# Function for mounting a file system.
mountFS() {
local device="$1"
local mountPoint="$2"
local options="$3"
local fsType="$4"
checkFS "$device"
mkdir -p "/mnt-root$mountPoint" || true
mount -t "$fsType" -o "$options" "$device" /mnt-root$mountPoint || fail
}
# Try to find and mount the root device.
mkdir /mnt-root
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 starts with / but doesn't start with /dev
# is a bind mount.
pseudoDevice=
case $device in
/dev/*)
;;
//*)
# Don't touch SMB/CIFS paths.
pseudoDevice=1
;;
/*)
device=/mnt-root$device
;;
*)
# Not an absolute path; assume that it's a pseudo-device
# like an NFS path (e.g. "server:/path").
pseudoDevice=1
;;
esac
# USB storage devices tend to appear with some delay. It would be
# great if we had a way to synchronously wait for them, but
# alas... So just wait for a few seconds for the device to
# appear. If it doesn't appear, try to mount it anyway (and
# probably fail). This is a fallback for non-device "devices"
# that we don't properly recognise.
if test -z "$pseudoDevice" -a ! -e $device; then
echo -n "waiting for device $device to appear..."
for ((try = 0; try < 10; try++)); do
sleep 1
if test -e $device; then break; fi
echo -n "."
done
echo
fi
echo "mounting $device on $mountPoint..."
mountFS "$device" "$mountPoint" "$options" "$fsType"
done
# If this is a live-CD/DVD, then union-mount a tmpfs on top of the
# original root.
if test -n "@isLiveCD@"; then
mkdir /mnt-root-tmpfs
mount -t tmpfs -o "mode=755" none /mnt-root-tmpfs
mkdir /mnt-root-union
mount -t aufs -o dirs=/mnt-root-tmpfs=rw:$targetRoot=ro none /mnt-root-union
targetRoot=/mnt-root-union
mkdir /mnt-store-tmpfs
mount -t tmpfs -o "mode=755" none /mnt-store-tmpfs
mkdir -p $targetRoot/nix/store
mount -t aufs -o dirs=/mnt-store-tmpfs=rw:/mnt-root/nix/store=ro none /mnt-root-union/nix/store
fi
@postMountCommands@
# Stop udevd.
kill $(minips -C udevd -o pid=) 2> /dev/null
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 /. Note that $stage2Init might be an absolute symlink, in
# which case "-e" won't work because we're not in the chroot yet.
if ! test -e "$targetRoot/$stage2Init" -o -L "$targetRoot/$stage2Init"; then
echo "stage 2 init script not found"
fail
fi
umount /sys
umount /proc
exec run-init "$targetRoot" "$stage2Init"
fail # should never be reached