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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
|
#!/bin/sh
#
# Licensed under the GPLv2
#
# Copyright 2008-2009, Red Hat, Inc.
# Harald Hoyer <harald@redhat.com>
# Jeremy Katz <katzj@redhat.com>
wait_for_loginit()
{
if getarg rdinitdebug; then
set +x
exec 0<>/dev/console 1<>/dev/console 2<>/dev/console
# wait for loginit
i=0
while [ $i -lt 10 ]; do
j=$(jobs)
[ -z "$j" ] && break
[ -z "${j##*Running*}" ] || break
sleep 0.1
i=$(($i+1))
done
[ $i -eq 10 ] && kill %1 >/dev/null 2>&1
while pidof -x /sbin/loginit >/dev/null 2>&1; do
for pid in $(pidof -x /sbin/loginit); do
kill $HARD $pid >/dev/null 2>&1
done
HARD="-9"
done
set -x
fi
}
emergency_shell()
{
if [ "$1" = "-n" ]; then
_rdshell_name=$2
shift 2
else
_rdshell_name=dracut
fi
wait_for_loginit
echo ; echo
echo $@
source_all emergency
echo
if getarg rdshell || getarg rdbreak; then
echo "Dropping to debug shell."
echo
export PS1="$_rdshell_name:\${PWD}# "
[ -e /.profile ] || echo "exec 0<>/dev/console 1<>/dev/console 2<>/dev/console" > /.profile
sh -i -l
else
echo "Boot has failed, sleeping forever."
while :; do sleep 365d;done
fi
}
export PATH=/sbin:/bin:/usr/sbin:/usr/bin
export TERM=linux
NEWROOT="/sysroot"
trap "emergency_shell Signal caught!" 0
# set umask
OLD_UMASK=$(umask)
umask 0007
RDDEBUG=""
. /lib/dracut-lib.sh
mknod -m 0666 /dev/null c 1 3
# mount some important things
mount -t proc /proc /proc >/dev/null 2>&1
mount -t sysfs /sys /sys >/dev/null 2>&1
if [ ! -c /dev/ptmx ]; then
# try to mount devtmpfs
if ! mount -t devtmpfs -omode=0755 udev /dev >/dev/null 2>&1; then
# if it failed fall back to normal tmpfs
mount -t tmpfs -omode=0755 udev /dev >/dev/null 2>&1
# Make some basic devices first, let udev handle the rest
mknod -m 0666 /dev/null c 1 3
mknod -m 0666 /dev/ptmx c 5 2
mknod -m 0600 /dev/console c 5 1
mknod -m 0660 /dev/kmsg c 1 11
fi
fi
ln -s /proc/self/fd /dev/fd >/dev/null 2>&1
if getarg rdinitdebug; then
getarg quiet && DRACUT_QUIET="yes"
mkfifo /dev/initlog.pipe
/sbin/loginit $DRACUT_QUIET </dev/initlog.pipe >/dev/console 2>&1 &
exec >/dev/initlog.pipe 2>&1
else
exec 0<>/dev/console 1<>/dev/console 2<>/dev/console
fi
setdebug
mkdir /dev/shm
mkdir /dev/pts
mount -t devpts -o gid=5,mode=620 devpts /dev/pts >/dev/null 2>&1
mount -t tmpfs tmpfs /dev/shm >/dev/null 2>&1
UDEVVERSION=$(udevadm --version)
source_conf /etc/conf.d
# run scriptlets to parse the command line
getarg 'rdbreak=cmdline' && emergency_shell -n cmdline "Break before cmdline"
source_all cmdline
[ -z "$root" ] && die "No or empty root= argument"
[ -z "$rootok" ] && die "Don't know how to handle 'root=$root'"
# Network root scripts may need updated root= options,
# so deposit them where they can see them (udev purges the env)
{
echo "root='$root'"
echo "rflags='$rflags'"
echo "fstype='$fstype'"
echo "netroot='$netroot'"
echo "NEWROOT='$NEWROOT'"
} > /tmp/root.info
# pre-udev scripts run before udev starts, and are run only once.
getarg 'rdbreak=pre-udev' && emergency_shell -n pre-udev "Break before pre-udev"
source_all pre-udev
# start up udev and trigger cold plugs
udevd --daemon --resolve-names=never
UDEV_LOG_PRIO_ARG=--log-priority
UDEV_QUEUE_EMPTY="udevadm settle --timeout=0"
if [ $UDEVVERSION -lt 140 ]; then
UDEV_LOG_PRIO_ARG=--log_priority
UDEV_QUEUE_EMPTY="udevadm settle --timeout=1"
fi
getarg rdudevinfo && udevadm control $UDEV_LOG_PRIO_ARG=info
getarg rdudevdebug && udevadm control $UDEV_LOG_PRIO_ARG=debug
getarg 'rdbreak=pre-trigger' && emergency_shell -n pre-trigger "Break before pre-trigger"
source_all pre-trigger
# then the rest
udevadm trigger --action=add $udevtriggeropts >/dev/null 2>&1
getarg 'rdbreak=initqueue' && emergency_shell -n initqueue "Break before initqueue"
RDRETRY=$(getarg 'rd_retry=')
RDRETRY=${RDRETRY:-20}
RDRETRY=$(($RDRETRY*2))
i=0
while :; do
check_finished && break
udevsettle
check_finished && break
if [ -f /initqueue/work ]; then
rm /initqueue/work
fi
for job in /initqueue/*.sh; do
[ -e "$job" ] || break
job=$job . $job
check_finished && break 2
done
$UDEV_QUEUE_EMPTY >/dev/null 2>&1 || continue
modprobe scsi_wait_scan && rmmod scsi_wait_scan
$UDEV_QUEUE_EMPTY >/dev/null 2>&1 || continue
for job in /initqueue-settled/*.sh; do
[ -e "$job" ] || break
job=$job . $job
check_finished && break 2
done
$UDEV_QUEUE_EMPTY >/dev/null 2>&1 || continue
# no more udev jobs and queues empty.
sleep 0.5
# dirty hack for some cdrom drives,
# which report no medium for quiet
# some time.
for cdrom in /sys/block/sr*; do
[ -e "$cdrom" ] || continue
# skip, if cdrom medium was already found
strstr "$(udevadm info --query=env --path=${cdrom##/sys})" \
ID_CDROM_MEDIA && continue
echo change > "$cdrom/uevent"
done
i=$(($i+1))
[ $i -gt $RDRETRY ] \
&& { flock -s 9 ; emergency_shell "No root device found"; } 9>/.console_lock
done
unset job
unset queuetriggered
# pre-mount happens before we try to mount the root filesystem,
# and happens once.
getarg 'rdbreak=pre-mount' && emergency_shell -n pre-mount "Break pre-mount"
source_all pre-mount
getarg 'rdbreak=mount' && emergency_shell -n mount "Break mount"
# mount scripts actually try to mount the root filesystem, and may
# be sourced any number of times. As soon as one suceeds, no more are sourced.
i=0
while :; do
[ -d "$NEWROOT/proc" ] && break;
for f in /mount/*.sh; do
[ -f "$f" ] && . "$f"
[ -d "$NEWROOT/proc" ] && break;
done
i=$(($i+1))
[ $i -gt 20 ] \
&& { flock -s 9 ; emergency_shell "Can't mount root filesystem"; } 9>/.console_lock
done
{
echo -n "Mounted root filesystem "
while read dev mp rest; do [ "$mp" = "$NEWROOT" ] && echo $dev; done < /proc/mounts
} | vinfo
# pre pivot scripts are sourced just before we switch over to the new root.
getarg 'rdbreak=pre-pivot' && emergency_shell -n pre-pivot "Break pre-pivot"
source_all pre-pivot
# by the time we get here, the root filesystem should be mounted.
# Try to find init.
for i in "$(getarg init=)" /sbin/init /etc/init /init /bin/sh; do
[ -f "$NEWROOT$i" -a -x "$NEWROOT$i" ] && { INIT="$i"; break; }
done
[ "$INIT" ] || {
echo "Cannot find init!"
echo "Please check to make sure you passed a valid root filesystem!"
emergency_shell
}
getarg rdbreak && emergency_shell -n switch_root "Break before switch_root"
# stop udev queue before killing it
udevadm control --stop-exec-queue
HARD=""
while pidof udevd >/dev/null 2>&1; do
for pid in $(pidof udevd); do
kill $HARD $pid >/dev/null 2>&1
done
HARD="-9"
done
# Clean up the environment
for i in $(export -p); do
i=${i#declare -x}
i=${i#export}
i=${i%%=*}
[ "$i" = "root" -o "$i" = "PATH" -o "$i" = "HOME" -o "$i" = "TERM" ] || unset $i
done
initargs=""
read CLINE </proc/cmdline
if getarg init= >/dev/null ; then
ignoreargs="console BOOT_IMAGE"
# only pass arguments after init= to the init
CLINE=${CLINE#*init=}
set $CLINE
shift
for x in "$@"; do
for s in $ignoreargs; do
[ "${x%%=*}" = $s ] && continue 2
done
initargs="$initargs $x"
done
unset CLINE
else
set $CLINE
shift
for x in "$@"; do
case "$x" in
[0-9]|s|S|single|emergency|auto )
initargs="$initargs $x"
;;
esac
done
fi
# Debug: Copy state
if getarg rdcopystate; then
mkdir /dev/.initramfs/
cp /tmp/* /dev/.initramfs/ >/dev/null 2>&1
fi
info "Switching root"
wait_for_loginit
umask $OLD_UMASK
exec switch_root "$NEWROOT" "$INIT" $initargs || {
echo "Something went very badly wrong in the initramfs. Please "
echo "file a bug against dracut."
emergency_shell
}
# vim:ts=8:sw=4:sts=4:et
|