blob: d142e97d443c8296f1092b3a0a9ebee27255e5c3 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
#!/bin/sh
# Copyright (c) Victor Lowther <victor.lowther@gmail.com>
# Licensed under the terms of the GNU GPL v2 or later.
# 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"
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"
|