Goodbye, nash. We won't miss you.
This supercedes my previous switch_root patches, and applies on top of davej's repo at git.kernel.org. Nash is gone. In its place we have a reasonable switch_root implementation. Of course, this switch_root is written in some rather hideous shell script, and relies on some rather dodgy hacks. Rewriting in C would help things out. However, it should be distro-independent, and it gets the job done.master
parent
c968efbb13
commit
6b0daf2e25
9
TODO
9
TODO
|
@ -4,12 +4,9 @@ are/should be marked with "FIXME" in the code
|
|||
|
||||
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
|
||||
|
|
|
@ -19,9 +19,7 @@ Requires: findutils
|
|||
Requires: grep
|
||||
Requires: mktemp
|
||||
Requires: mount
|
||||
Requires: nash
|
||||
Requires: bash
|
||||
Requires: /usr/bin/eu-readelf
|
||||
Obsoletes: mkinitrd < 7.0
|
||||
Provides: mkinitrd = 7.0
|
||||
BuildArch: noarch
|
||||
|
|
43
init
43
init
|
@ -10,13 +10,12 @@ emergency_shell()
|
|||
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
|
||||
|
@ -31,16 +30,15 @@ source_all() {
|
|||
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
|
||||
|
@ -59,7 +57,7 @@ udevd --daemon
|
|||
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
|
||||
|
@ -85,22 +83,21 @@ echo "Trying to mount rootfs $root"
|
|||
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."
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#!/bin/bash
|
||||
dracut_install mount mknod mkdir modprobe pidof sleep chroot echo sed sh ls
|
||||
|
||||
# install our scripts and hooks
|
||||
inst "$initfile" "/init"
|
||||
inst "$switchroot" "/sbin/switch_root"
|
||||
|
|
113
switch_root
113
switch_root
|
@ -1,3 +1,112 @@
|
|||
#!/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"
|
||||
|
|
Loading…
Reference in New Issue