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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
#!/bin/sh
# Enable strict shell mode
set -euo pipefail
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MOUNT="/bin/mount"
UMOUNT="/bin/umount"
INIT="/sbin/init"
ROOT_MOUNT="/mnt"
ROOT_RODEVICE=""
ROOT_RWDEVICE=""
ROOT_ROMOUNT="/media/rfs/ro"
ROOT_RWMOUNT="/media/rfs/rw"
ROOT_RWRESET="no"
# Copied from initramfs-framework. The core of this script probably should be
# turned into initramfs-framework modules to reduce duplication.
udev_daemon() {
OPTIONS="/sbin/udev/udevd /sbin/udevd /lib/udev/udevd /lib/systemd/systemd-udevd"
for o in $OPTIONS; do
if [ -x "$o" ]; then
echo $o
return 0
fi
done
return 1
}
_UDEV_DAEMON=`udev_daemon`
early_setup() {
mkdir -p /proc
mkdir -p /sys
$MOUNT -t proc proc /proc
$MOUNT -t sysfs sysfs /sys
$MOUNT -t devtmpfs none /dev
mkdir -p /run
mkdir -p /var/run
$_UDEV_DAEMON --daemon
udevadm trigger --action=add
}
read_args() {
[ -z "${CMDLINE+x}" ] && CMDLINE=`cat /proc/cmdline`
for arg in $CMDLINE; do
optarg=`expr "x$arg" : 'x[^=]*=\(.*\)'`
case $arg in
root=*)
ROOT_RODEVICE=$optarg ;;
rootfstype=*)
modprobe $optarg 2> /dev/null ;;
rootrw=*)
ROOT_RWDEVICE=$optarg ;;
rootrwfstype=*)
modprobe $optarg 2> /dev/null ;;
rootrwreset=*)
ROOT_RWRESET=$optarg ;;
video=*)
video_mode=$arg ;;
vga=*)
vga_mode=$arg ;;
init=*)
INIT=$optarg ;;
console=*)
if [ -z "${console_params+x}" ]; then
console_params=$arg
else
console_params="$console_params $arg"
fi ;;
esac
done
}
fatal() {
echo $1 >$CONSOLE
echo >$CONSOLE
exec sh
}
early_setup
[ -z "${CONSOLE+x}" ] && CONSOLE="/dev/console"
read_args
mount_and_boot() {
mkdir -p $ROOT_MOUNT $ROOT_ROMOUNT $ROOT_RWMOUNT
# Build mount options for read only root filesystem.
# If no read-only device was specified via kernel commandline, use current
# rootfs.
if [ -z "${ROOT_RODEVICE}" ]; then
ROOT_ROMOUNTOPTIONS="--bind,ro /"
else
ROOT_ROMOUNTOPTIONS="-o ro,noatime,nodiratime $ROOT_RODEVICE"
fi
# Mount rootfs as read-only to mount-point
if ! $MOUNT $ROOT_ROMOUNTOPTIONS $ROOT_ROMOUNT ; then
fatal "Could not mount read-only rootfs"
fi
# Build mount options for read write root filesystem.
# If no read-write device was specified via kernel commandline, use tmpfs.
if [ -z "${ROOT_RWDEVICE}" ]; then
ROOT_RWMOUNTOPTIONS="-t tmpfs -o rw,noatime,mode=755 tmpfs"
else
ROOT_RWMOUNTOPTIONS="-o rw,noatime,mode=755 $ROOT_RWDEVICE"
fi
# Mount read-write filesystem into initram rootfs
if ! $MOUNT $ROOT_RWMOUNTOPTIONS $ROOT_RWMOUNT ; then
fatal "Could not mount read-write rootfs"
fi
# Reset read-write filesystem if specified
if [ "yes" == "$ROOT_RWRESET" -a -n "${ROOT_RWMOUNT}" ]; then
rm -rf $ROOT_RWMOUNT/*
fi
# Determine which unification filesystem to use
union_fs_type=""
if grep -w "overlay" /proc/filesystems; then
union_fs_type="overlay"
elif grep -w "aufs" /proc/filesystems; then
union_fs_type="aufs"
else
union_fs_type=""
fi
# Create/Mount overlay root filesystem
case $union_fs_type in
"overlay")
mkdir -p $ROOT_RWMOUNT/upperdir $ROOT_RWMOUNT/work
$MOUNT -t overlay overlay -o "lowerdir=$ROOT_ROMOUNT,upperdir=$ROOT_RWMOUNT/upperdir,workdir=$ROOT_RWMOUNT/work" $ROOT_MOUNT
;;
"aufs")
$MOUNT -t aufs -o "dirs=$ROOT_RWMOUNT=rw:$ROOT_ROMOUNT=ro" aufs $ROOT_MOUNT
;;
"")
fatal "No overlay filesystem type available"
;;
esac
# Move read-only and read-write root filesystem into the overlay filesystem
mkdir -p $ROOT_MOUNT/$ROOT_ROMOUNT $ROOT_MOUNT/$ROOT_RWMOUNT
$MOUNT -n --move $ROOT_ROMOUNT ${ROOT_MOUNT}/$ROOT_ROMOUNT
$MOUNT -n --move $ROOT_RWMOUNT ${ROOT_MOUNT}/$ROOT_RWMOUNT
# Watches the udev event queue, and exits if all current events are handled
udevadm settle --timeout=3
# Kills the current udev running processes, which survived after
# device node creation events were handled, to avoid unexpected behavior
killall -9 "${_UDEV_DAEMON##*/}" 2>/dev/null
# Remove /run /var/run that are created in early_setup
rm -rf /run /var/run
# Move the mount points of some filesystems over to
# the corresponding directories under the real root filesystem.
for dir in `awk '/\/dev.* \/run\/media/{print $2}' /proc/mounts`; do
mkdir -p ${ROOT_MOUNT}/media/${dir##*/}
$MOUNT -n --move $dir ${ROOT_MOUNT}/media/${dir##*/}
done
$MOUNT -n --move /proc ${ROOT_MOUNT}/proc
$MOUNT -n --move /sys ${ROOT_MOUNT}/sys
$MOUNT -n --move /dev ${ROOT_MOUNT}/dev
cd $ROOT_MOUNT
# busybox switch_root supports -c option
exec chroot $ROOT_MOUNT $INIT ||
fatal "Couldn't chroot, dropping to shell"
}
mount_and_boot
|