INITRAMFS TODO
--------------
-* Currently, our switch_root command uses nash's switchroot. Getting
-a reasonable switchroot implementation into util-linux-ng is a
-pre-condition for support on other distros. pjones has a basic
-implementation at
-http://pjones.fedorapeople.org/mkstart/usr/lib/mkstart/switchroot.c
-and I've asked kzak about util-linux inclusion
+* We have a horribly ugly switchroot implementation whose only
+ good point is that it gets rid of our dependency on nash.
+ It needs to be replaced by something nicer.
* The hard-coded list of udev rules that we care about is kind of
lame. See about getting /lib/udev/initrules.d or similar for storing
the rules that we care about in the initramfs. These could be
echo ; echo
echo "Bug in initramfs /init detected. Dropping to a shell. Good luck!"
echo
- sh -i 2>/dev/console
+ sh -i
}
getarg() {
local o line
- read -r line </proc/cmdline
- for o in $line; do
+ for o in $CMDLINE; do
[ "${o%%=*}" = "$1" ] && { echo $o; break; }
done
return 1
echo "Starting initrd..."
export PATH=/sbin:/bin:/usr/sbin:/usr/bin
export TERM=linux
-
+CONSOLE=/dev/console
+[ -c $CONSOLE ] && exec >$CONSOLE 2>&1 <$CONSOLE
trap "emergency_shell" 0
-# /dev/console comes from the built-in initramfs crud in the kernel
-# someday, we may need to mkdir /dev first here
-# exec > /dev/console 2>&1 < /dev/console
-
# mount some important things
mount -t proc /proc /proc
mount -t sysfs /sys /sys
mount -t tmpfs -omode=0755 udev /dev
+read CMDLINE </proc/cmdline;
+
# FIXME: what device nodes does plymouth really _need_ ?
mknod /dev/ptmx c 5 2
udevadm trigger >/dev/null 2>&1
# mount the rootfs
-NEWROOT="/sysroot"
+export NEWROOT="/sysroot"
# FIXME: there's got to be a better way ...
# it'd be nice if we had a udev rule that just did all of the bits for
ln -s "$root" /dev/root
mount -o ro /dev/root $NEWROOT || emergency_shell
-# now we need to prepare to switchroot
-mount --bind /dev $NEWROOT/dev
-
-# FIXME: now for a bunch of boiler-plate mounts. really, we should have
-# some like /etc/fstab.sys that's provided by filesystem/initscripts
-# and then do mount -f /etc/fstab.sys -a
-mount -t proc /proc $NEWROOT/proc
-mount -t sysfs /sys $NEWROOT/sys
-
+INIT=$(getarg init)
+[ "$INIT" ] || {
+ for i in /sbin/init /etc/init /init /bin/sh; do
+ [ -x "$NEWROOT$i" ] && { INIT="$i"; break; }
+ done
+ [ "$INIT" ] || {
+ echo "Cannot find init! Please check to make sure you passed"
+ echo "a valid root filesystem! Dropping to a shell."
+ emergency_shell
+ }
+}
+
source_all pre-pivot
-# kill off udev
-kill $(pidof udevd)
-
-# FIXME: nash die die die
-exec switch_root
+exec switch_root "$NEWROOT" "$INIT" $CMDLINE
# davej doesn't like initrd bugs
echo "Something went very badly wrong in the initrd. Please "
echo "file a bug against mkinitrd."
-#!/sbin/nash
+#!/bin/sh
+# Copyright (c) Victor Lowther <victor.lowther@gmail.com>
+# Licensed under the terms of the GNU GPL v2 or later.
-nash-switchroot
+# some utility functions first
+# this is so we can scroll back.
+
+die() { echo "${1}, dying horribly."; while :;do read line; done }
+
+# jsut enough to get the job done
+simple_find() {
+ # $1 = file to look for
+ # $rest = places to look for it
+ local file=$1
+ shift
+ for loc in "$@"; do
+ [ -f "$NEWROOT$loc/$file" ] && { echo "$loc/$file"; return 0; }
+ done
+ return 1
+}
+
+# We really should not be doing this from here, but...
+find_interp() {
+ local ldso=$("$NEWROOT$CHROOT" "$NEWROOT" "$LDD" "$1" |
+ while read interp rest; do
+ [ -f "${NEWROOT}$interp" ] || continue
+ echo "$interp"
+ break
+ done);
+ [ "$ldso" ] && echo $ldso
+}
+
+# this makes it easier to run a command entirely from newroot
+# $1 = elf interpreter (must pass empty string if none)
+# $2 = command or "exec"
+# $3 = command if exec was passed
+run_from_newroot() {
+ local ldso="$1" cmd="$2"; shift; shift
+ if [ "$cmd" = "exec" ]; then
+ cmd="$1"; shift
+ if [ "$ldso" ]; then
+ exec "$NEWROOT$ldso" --library-path "$LIBPATH" "$NEWROOT$cmd" "$@"
+ else
+ exec "$NEWROOT$cmd" "$@"
+ fi
+ else
+ if [ "$ldso" ]; then
+ "$NEWROOT$ldso" --library-path "$LIBPATH" "$NEWROOT$cmd" "$@"
+ else
+ "$NEWROOT$cmd" "$@"
+ fi
+ fi
+}
+# update the path to find our dynamic libraries on newroot
+update_newroot_libpath() {
+ local x
+ LIBPATH=":"
+ LIBDIRS="$(echo $NEWROOT/lib* $NEWROOT/usr/lib*)"
+ for x in $LIBDIRS; do
+ [ -d "$x" ] && LIBPATH="${LIBPATH}${x}:"
+ done
+ LIBPATH="${LIBPATH%:}"; LIBPATH="${LIBPATH#:}"
+ [ "$LIBPATH" ] || die "Cannot find shared library diectories on $NEWROOT"
+}
+NEWROOT="$1"
+INIT="$2"
+[ -d "$NEWROOT" ] || die "$NEWROOT is not a directory"
+[ -x "$NEWROOT$INIT" ] || die "$NEWROOT/$INIT is not executable."
+shift; shift
+
+update_newroot_libpath
+
+# start looking for required binaries and bits of infrastructure
+BINDIRS="/bin /sbin /usr/bin /usr/sbin"
+INITDIRS="/sbin /etc /"
+RM=$(simple_find rm $BINDIRS) || die "Cannnot find rm on $NEWROOT"
+CHROOT=$(simple_find chroot $BINDIRS) || die "Cannot find chroot on $NEWROOT"
+LDD=$(simple_find ldd $BINDIRS) || die "Cannot find ldd on $NEWROOT"
+MOUNT=$(simple_find mount $BINDIRS) || die "Cannot find mount on $NEWROOT"
+
+# now, start the real process of switching the root
+cd /
+
+# kill udevd, move all our mounts over to the new root
+kill $(pidof udevd)
+mount --move /proc $NEWROOT/proc
+mount --move /sys $NEWROOT/sys
+mount --move /dev $NEWROOT/dev
+
+# Find the binary interpreter for our three required binaries.
+# We do it here so that ldd does not complain about a missing /dev/null.
+CHROOT_LDSO=$(find_interp "$CHROOT")
+RM_LDSO=$(find_interp "$RM")
+MOUNT_LDSO=$(find_interp "$MOUNT")
+
+# redirect to new console. Our old initramfs will not be freed otherwise
+CONSOLE=$NEWROOT/dev/console
+[ -c $CONSOLE ] && exec >$CONSOLE 2>&1 <$CONSOLE
+for x in *; do
+ [ "/$x" = "$NEWROOT" ] || run_from_newroot "$RM_LDSO" "$RM" -rf -- "$x"
+done
+# switch to our new root dir
+cd "$NEWROOT"
+# this moves rootfs to the actual root...
+run_from_newroot "$MOUNT_LDSO" "$MOUNT" -n --move . /
+# but does not update where / is in directory lookups.
+# Therefore, newroot is now ".". Update things accordingly, then chroot and
+# exec init.
+NEWROOT="."
+update_newroot_libpath
+run_from_newroot "$CHROOT_LDSO" exec "$CHROOT" "$NEWROOT" "$INIT" "$@"
+die "The chroot did not take for some reason"