diff options
author | Gregor Kleen <gkleen@yggdrasil.li> | 2021-08-03 17:49:13 +0200 |
---|---|---|
committer | Gregor Kleen <gkleen@yggdrasil.li> | 2021-08-03 17:49:13 +0200 |
commit | 59914a02ccdeb88b6370d9a202f40435d5d04feb (patch) | |
tree | 66895f12d3bbe7baa9c1e0311d3f9224904976e9 /modules/stage-1/stage-1-init.sh | |
parent | 4afc0f33fd14959612af14db59231d95035a2556 (diff) | |
download | nixos-59914a02ccdeb88b6370d9a202f40435d5d04feb.tar nixos-59914a02ccdeb88b6370d9a202f40435d5d04feb.tar.gz nixos-59914a02ccdeb88b6370d9a202f40435d5d04feb.tar.bz2 nixos-59914a02ccdeb88b6370d9a202f40435d5d04feb.tar.xz nixos-59914a02ccdeb88b6370d9a202f40435d5d04feb.zip |
stage-1: dereference secrets
Diffstat (limited to 'modules/stage-1/stage-1-init.sh')
-rw-r--r-- | modules/stage-1/stage-1-init.sh | 638 |
1 files changed, 638 insertions, 0 deletions
diff --git a/modules/stage-1/stage-1-init.sh b/modules/stage-1/stage-1-init.sh new file mode 100644 index 00000000..ddaf9858 --- /dev/null +++ b/modules/stage-1/stage-1-init.sh | |||
@@ -0,0 +1,638 @@ | |||
1 | #! @shell@ | ||
2 | |||
3 | targetRoot=/mnt-root | ||
4 | console=tty1 | ||
5 | verbose="@verbose@" | ||
6 | |||
7 | info() { | ||
8 | if [[ -n "$verbose" ]]; then | ||
9 | echo "$@" | ||
10 | fi | ||
11 | } | ||
12 | |||
13 | extraUtils="@extraUtils@" | ||
14 | export LD_LIBRARY_PATH=@extraUtils@/lib | ||
15 | export PATH=@extraUtils@/bin | ||
16 | ln -s @extraUtils@/bin /bin | ||
17 | |||
18 | # Copy the secrets to their needed location | ||
19 | if [ -d "@extraUtils@/secrets" ]; then | ||
20 | for secret in $(cd "@extraUtils@/secrets"; find . -type f); do | ||
21 | mkdir -p $(dirname "/$secret") | ||
22 | ln -s "@extraUtils@/secrets/$secret" "$secret" | ||
23 | done | ||
24 | fi | ||
25 | |||
26 | # Stop LVM complaining about fd3 | ||
27 | export LVM_SUPPRESS_FD_WARNINGS=true | ||
28 | |||
29 | fail() { | ||
30 | if [ -n "$panicOnFail" ]; then exit 1; fi | ||
31 | |||
32 | @preFailCommands@ | ||
33 | |||
34 | # If starting stage 2 failed, allow the user to repair the problem | ||
35 | # in an interactive shell. | ||
36 | cat <<EOF | ||
37 | |||
38 | An error occurred in stage 1 of the boot process, which must mount the | ||
39 | root filesystem on \`$targetRoot' and then start stage 2. Press one | ||
40 | of the following keys: | ||
41 | |||
42 | EOF | ||
43 | if [ -n "$allowShell" ]; then cat <<EOF | ||
44 | i) to launch an interactive shell | ||
45 | f) to start an interactive shell having pid 1 (needed if you want to | ||
46 | start stage 2's init manually) | ||
47 | EOF | ||
48 | fi | ||
49 | cat <<EOF | ||
50 | r) to reboot immediately | ||
51 | *) to ignore the error and continue | ||
52 | EOF | ||
53 | |||
54 | read -n 1 reply | ||
55 | |||
56 | if [ -n "$allowShell" -a "$reply" = f ]; then | ||
57 | exec setsid @shell@ -c "exec @shell@ < /dev/$console >/dev/$console 2>/dev/$console" | ||
58 | elif [ -n "$allowShell" -a "$reply" = i ]; then | ||
59 | echo "Starting interactive shell..." | ||
60 | setsid @shell@ -c "exec @shell@ < /dev/$console >/dev/$console 2>/dev/$console" || fail | ||
61 | elif [ "$reply" = r ]; then | ||
62 | echo "Rebooting..." | ||
63 | reboot -f | ||
64 | else | ||
65 | info "Continuing..." | ||
66 | fi | ||
67 | } | ||
68 | |||
69 | trap 'fail' 0 | ||
70 | |||
71 | |||
72 | # Print a greeting. | ||
73 | info | ||
74 | info "[1;32m<<< NixOS Stage 1 >>>[0m" | ||
75 | info | ||
76 | |||
77 | # Make several required directories. | ||
78 | mkdir -p /etc/udev | ||
79 | touch /etc/fstab # to shut up mount | ||
80 | ln -s /proc/mounts /etc/mtab # to shut up mke2fs | ||
81 | touch /etc/udev/hwdb.bin # to shut up udev | ||
82 | touch /etc/initrd-release | ||
83 | |||
84 | # Function for waiting a device to appear. | ||
85 | waitDevice() { | ||
86 | local device="$1" | ||
87 | |||
88 | # USB storage devices tend to appear with some delay. It would be | ||
89 | # great if we had a way to synchronously wait for them, but | ||
90 | # alas... So just wait for a few seconds for the device to | ||
91 | # appear. | ||
92 | if test ! -e $device; then | ||
93 | echo -n "waiting for device $device to appear..." | ||
94 | try=20 | ||
95 | while [ $try -gt 0 ]; do | ||
96 | sleep 1 | ||
97 | # also re-try lvm activation now that new block devices might have appeared | ||
98 | lvm vgchange -ay | ||
99 | # and tell udev to create nodes for the new LVs | ||
100 | udevadm trigger --action=add | ||
101 | if test -e $device; then break; fi | ||
102 | echo -n "." | ||
103 | try=$((try - 1)) | ||
104 | done | ||
105 | echo | ||
106 | [ $try -ne 0 ] | ||
107 | fi | ||
108 | } | ||
109 | |||
110 | # Mount special file systems. | ||
111 | specialMount() { | ||
112 | local device="$1" | ||
113 | local mountPoint="$2" | ||
114 | local options="$3" | ||
115 | local fsType="$4" | ||
116 | |||
117 | mkdir -m 0755 -p "$mountPoint" | ||
118 | mount -n -t "$fsType" -o "$options" "$device" "$mountPoint" | ||
119 | } | ||
120 | source @earlyMountScript@ | ||
121 | |||
122 | # Log the script output to /dev/kmsg or /run/log/stage-1-init.log. | ||
123 | mkdir -p /tmp | ||
124 | mkfifo /tmp/stage-1-init.log.fifo | ||
125 | logOutFd=8 && logErrFd=9 | ||
126 | eval "exec $logOutFd>&1 $logErrFd>&2" | ||
127 | if test -w /dev/kmsg; then | ||
128 | tee -i < /tmp/stage-1-init.log.fifo /proc/self/fd/"$logOutFd" | while read -r line; do | ||
129 | if test -n "$line"; then | ||
130 | echo "<7>stage-1-init: [$(date)] $line" > /dev/kmsg | ||
131 | fi | ||
132 | done & | ||
133 | else | ||
134 | mkdir -p /run/log | ||
135 | tee -i < /tmp/stage-1-init.log.fifo /run/log/stage-1-init.log & | ||
136 | fi | ||
137 | exec > /tmp/stage-1-init.log.fifo 2>&1 | ||
138 | |||
139 | |||
140 | # Process the kernel command line. | ||
141 | export stage2Init=/init | ||
142 | for o in $(cat /proc/cmdline); do | ||
143 | case $o in | ||
144 | console=*) | ||
145 | set -- $(IFS==; echo $o) | ||
146 | params=$2 | ||
147 | set -- $(IFS=,; echo $params) | ||
148 | console=$1 | ||
149 | ;; | ||
150 | init=*) | ||
151 | set -- $(IFS==; echo $o) | ||
152 | stage2Init=$2 | ||
153 | ;; | ||
154 | boot.persistence=*) | ||
155 | set -- $(IFS==; echo $o) | ||
156 | persistence=$2 | ||
157 | ;; | ||
158 | boot.persistence.opt=*) | ||
159 | set -- $(IFS==; echo $o) | ||
160 | persistence_opt=$2 | ||
161 | ;; | ||
162 | boot.trace|debugtrace) | ||
163 | # Show each command. | ||
164 | set -x | ||
165 | ;; | ||
166 | boot.shell_on_fail) | ||
167 | allowShell=1 | ||
168 | ;; | ||
169 | boot.debug1|debug1) # stop right away | ||
170 | allowShell=1 | ||
171 | fail | ||
172 | ;; | ||
173 | boot.debug1devices) # stop after loading modules and creating device nodes | ||
174 | allowShell=1 | ||
175 | debug1devices=1 | ||
176 | ;; | ||
177 | boot.debug1mounts) # stop after mounting file systems | ||
178 | allowShell=1 | ||
179 | debug1mounts=1 | ||
180 | ;; | ||
181 | boot.panic_on_fail|stage1panic=1) | ||
182 | panicOnFail=1 | ||
183 | ;; | ||
184 | root=*) | ||
185 | # If a root device is specified on the kernel command | ||
186 | # line, make it available through the symlink /dev/root. | ||
187 | # Recognise LABEL= and UUID= to support UNetbootin. | ||
188 | set -- $(IFS==; echo $o) | ||
189 | if [ $2 = "LABEL" ]; then | ||
190 | root="/dev/disk/by-label/$3" | ||
191 | elif [ $2 = "UUID" ]; then | ||
192 | root="/dev/disk/by-uuid/$3" | ||
193 | else | ||
194 | root=$2 | ||
195 | fi | ||
196 | ln -s "$root" /dev/root | ||
197 | ;; | ||
198 | copytoram) | ||
199 | copytoram=1 | ||
200 | ;; | ||
201 | findiso=*) | ||
202 | # if an iso name is supplied, try to find the device where | ||
203 | # the iso resides on | ||
204 | set -- $(IFS==; echo $o) | ||
205 | isoPath=$2 | ||
206 | ;; | ||
207 | esac | ||
208 | done | ||
209 | |||
210 | # Set hostid before modules are loaded. | ||
211 | # This is needed by the spl/zfs modules. | ||
212 | @setHostId@ | ||
213 | |||
214 | # Load the required kernel modules. | ||
215 | mkdir -p /lib | ||
216 | ln -s @modulesClosure@/lib/modules /lib/modules | ||
217 | ln -s @modulesClosure@/lib/firmware /lib/firmware | ||
218 | echo @extraUtils@/bin/modprobe > /proc/sys/kernel/modprobe | ||
219 | for i in @kernelModules@; do | ||
220 | info "loading module $(basename $i)..." | ||
221 | modprobe $i | ||
222 | done | ||
223 | |||
224 | |||
225 | # Create device nodes in /dev. | ||
226 | @preDeviceCommands@ | ||
227 | info "running udev..." | ||
228 | ln -sfn /proc/self/fd /dev/fd | ||
229 | ln -sfn /proc/self/fd/0 /dev/stdin | ||
230 | ln -sfn /proc/self/fd/1 /dev/stdout | ||
231 | ln -sfn /proc/self/fd/2 /dev/stderr | ||
232 | mkdir -p /etc/systemd | ||
233 | ln -sfn @linkUnits@ /etc/systemd/network | ||
234 | mkdir -p /etc/udev | ||
235 | ln -sfn @udevRules@ /etc/udev/rules.d | ||
236 | mkdir -p /dev/.mdadm | ||
237 | systemd-udevd --daemon | ||
238 | udevadm trigger --action=add | ||
239 | udevadm settle | ||
240 | |||
241 | |||
242 | # XXX: Use case usb->lvm will still fail, usb->luks->lvm is covered | ||
243 | @preLVMCommands@ | ||
244 | |||
245 | info "starting device mapper and LVM..." | ||
246 | lvm vgchange -ay | ||
247 | |||
248 | if test -n "$debug1devices"; then fail; fi | ||
249 | |||
250 | |||
251 | @postDeviceCommands@ | ||
252 | |||
253 | |||
254 | # Return true if the machine is on AC power, or if we can't determine | ||
255 | # whether it's on AC power. | ||
256 | onACPower() { | ||
257 | ! test -d "/proc/acpi/battery" || | ||
258 | ! ls /proc/acpi/battery/BAT[0-9]* > /dev/null 2>&1 || | ||
259 | ! cat /proc/acpi/battery/BAT*/state | grep "^charging state" | grep -q "discharg" | ||
260 | } | ||
261 | |||
262 | |||
263 | # Check the specified file system, if appropriate. | ||
264 | checkFS() { | ||
265 | local device="$1" | ||
266 | local fsType="$2" | ||
267 | |||
268 | # Only check block devices. | ||
269 | if [ ! -b "$device" ]; then return 0; fi | ||
270 | |||
271 | # Don't check ROM filesystems. | ||
272 | if [ "$fsType" = iso9660 -o "$fsType" = udf ]; then return 0; fi | ||
273 | |||
274 | # Don't check resilient COWs as they validate the fs structures at mount time | ||
275 | if [ "$fsType" = btrfs -o "$fsType" = zfs -o "$fsType" = bcachefs ]; then return 0; fi | ||
276 | |||
277 | # Skip fsck for nilfs2 - not needed by design and no fsck tool for this filesystem. | ||
278 | if [ "$fsType" = nilfs2 ]; then return 0; fi | ||
279 | |||
280 | # Skip fsck for inherently readonly filesystems. | ||
281 | if [ "$fsType" = squashfs ]; then return 0; fi | ||
282 | |||
283 | # If we couldn't figure out the FS type, then skip fsck. | ||
284 | if [ "$fsType" = auto ]; then | ||
285 | echo 'cannot check filesystem with type "auto"!' | ||
286 | return 0 | ||
287 | fi | ||
288 | |||
289 | # Device might be already mounted manually | ||
290 | # e.g. NBD-device or the host filesystem of the file which contains encrypted root fs | ||
291 | if mount | grep -q "^$device on "; then | ||
292 | echo "skip checking already mounted $device" | ||
293 | return 0 | ||
294 | fi | ||
295 | |||
296 | # Optionally, skip fsck on journaling filesystems. This option is | ||
297 | # a hack - it's mostly because e2fsck on ext3 takes much longer to | ||
298 | # recover the journal than the ext3 implementation in the kernel | ||
299 | # does (minutes versus seconds). | ||
300 | if test -z "@checkJournalingFS@" -a \ | ||
301 | \( "$fsType" = ext3 -o "$fsType" = ext4 -o "$fsType" = reiserfs \ | ||
302 | -o "$fsType" = xfs -o "$fsType" = jfs -o "$fsType" = f2fs \) | ||
303 | then | ||
304 | return 0 | ||
305 | fi | ||
306 | |||
307 | # Don't run `fsck' if the machine is on battery power. !!! Is | ||
308 | # this a good idea? | ||
309 | if ! onACPower; then | ||
310 | echo "on battery power, so no \`fsck' will be performed on \`$device'" | ||
311 | return 0 | ||
312 | fi | ||
313 | |||
314 | echo "checking $device..." | ||
315 | |||
316 | fsckFlags= | ||
317 | if test "$fsType" != "btrfs"; then | ||
318 | fsckFlags="-V -a" | ||
319 | fi | ||
320 | fsck $fsckFlags "$device" | ||
321 | fsckResult=$? | ||
322 | |||
323 | if test $(($fsckResult | 2)) = $fsckResult; then | ||
324 | echo "fsck finished, rebooting..." | ||
325 | sleep 3 | ||
326 | reboot -f | ||
327 | fi | ||
328 | |||
329 | if test $(($fsckResult | 4)) = $fsckResult; then | ||
330 | echo "$device has unrepaired errors, please fix them manually." | ||
331 | fail | ||
332 | fi | ||
333 | |||
334 | if test $fsckResult -ge 8; then | ||
335 | echo "fsck on $device failed." | ||
336 | fail | ||
337 | fi | ||
338 | |||
339 | return 0 | ||
340 | } | ||
341 | |||
342 | |||
343 | # Function for mounting a file system. | ||
344 | mountFS() { | ||
345 | local device="$1" | ||
346 | local mountPoint="$2" | ||
347 | local options="$3" | ||
348 | local fsType="$4" | ||
349 | |||
350 | if [ "$fsType" = auto ]; then | ||
351 | fsType=$(blkid -o value -s TYPE "$device") | ||
352 | if [ -z "$fsType" ]; then fsType=auto; fi | ||
353 | fi | ||
354 | |||
355 | # Filter out x- options, which busybox doesn't do yet. | ||
356 | local optionsFiltered="$(IFS=,; for i in $options; do if [ "${i:0:2}" != "x-" ]; then echo -n $i,; fi; done)" | ||
357 | # Prefix (lower|upper|work)dir with /mnt-root (overlayfs) | ||
358 | local optionsPrefixed="$( echo "$optionsFiltered" | sed -E 's#\<(lowerdir|upperdir|workdir)=#\1=/mnt-root#g' )" | ||
359 | |||
360 | echo "$device /mnt-root$mountPoint $fsType $optionsPrefixed" >> /etc/fstab | ||
361 | |||
362 | checkFS "$device" "$fsType" | ||
363 | |||
364 | # Optionally resize the filesystem. | ||
365 | case $options in | ||
366 | *x-nixos.autoresize*) | ||
367 | if [ "$fsType" = ext2 -o "$fsType" = ext3 -o "$fsType" = ext4 ]; then | ||
368 | modprobe "$fsType" | ||
369 | echo "resizing $device..." | ||
370 | e2fsck -fp "$device" | ||
371 | resize2fs "$device" | ||
372 | elif [ "$fsType" = f2fs ]; then | ||
373 | echo "resizing $device..." | ||
374 | fsck.f2fs -fp "$device" | ||
375 | resize.f2fs "$device" | ||
376 | fi | ||
377 | ;; | ||
378 | esac | ||
379 | |||
380 | # Create backing directories for overlayfs | ||
381 | if [ "$fsType" = overlay ]; then | ||
382 | for i in upper work; do | ||
383 | dir="$( echo "$optionsPrefixed" | grep -o "${i}dir=[^,]*" )" | ||
384 | mkdir -m 0700 -p "${dir##*=}" | ||
385 | done | ||
386 | fi | ||
387 | |||
388 | info "mounting $device on $mountPoint..." | ||
389 | |||
390 | mkdir -p "/mnt-root$mountPoint" | ||
391 | |||
392 | # For ZFS and CIFS mounts, retry a few times before giving up. | ||
393 | # We do this for ZFS as a workaround for issue NixOS/nixpkgs#25383. | ||
394 | local n=0 | ||
395 | while true; do | ||
396 | mount "/mnt-root$mountPoint" && break | ||
397 | if [ \( "$fsType" != cifs -a "$fsType" != zfs \) -o "$n" -ge 10 ]; then fail; break; fi | ||
398 | echo "retrying..." | ||
399 | sleep 1 | ||
400 | n=$((n + 1)) | ||
401 | done | ||
402 | |||
403 | [ "$mountPoint" == "/" ] && | ||
404 | [ -f "/mnt-root/etc/NIXOS_LUSTRATE" ] && | ||
405 | lustrateRoot "/mnt-root" | ||
406 | |||
407 | true | ||
408 | } | ||
409 | |||
410 | lustrateRoot () { | ||
411 | local root="$1" | ||
412 | |||
413 | echo | ||
414 | echo -e "\e[1;33m<<< NixOS is now lustrating the root filesystem (cruft goes to /old-root) >>>\e[0m" | ||
415 | echo | ||
416 | |||
417 | mkdir -m 0755 -p "$root/old-root.tmp" | ||
418 | |||
419 | echo | ||
420 | echo "Moving impurities out of the way:" | ||
421 | for d in "$root"/* | ||
422 | do | ||
423 | [ "$d" == "$root/nix" ] && continue | ||
424 | [ "$d" == "$root/boot" ] && continue # Don't render the system unbootable | ||
425 | [ "$d" == "$root/old-root.tmp" ] && continue | ||
426 | |||
427 | mv -v "$d" "$root/old-root.tmp" | ||
428 | done | ||
429 | |||
430 | # Use .tmp to make sure subsequent invokations don't clash | ||
431 | mv -v "$root/old-root.tmp" "$root/old-root" | ||
432 | |||
433 | mkdir -m 0755 -p "$root/etc" | ||
434 | touch "$root/etc/NIXOS" | ||
435 | |||
436 | exec 4< "$root/old-root/etc/NIXOS_LUSTRATE" | ||
437 | |||
438 | echo | ||
439 | echo "Restoring selected impurities:" | ||
440 | while read -u 4 keeper; do | ||
441 | dirname="$(dirname "$keeper")" | ||
442 | mkdir -m 0755 -p "$root/$dirname" | ||
443 | cp -av "$root/old-root/$keeper" "$root/$keeper" | ||
444 | done | ||
445 | |||
446 | exec 4>&- | ||
447 | } | ||
448 | |||
449 | |||
450 | |||
451 | if test -e /sys/power/resume -a -e /sys/power/disk; then | ||
452 | if test -n "@resumeDevice@" && waitDevice "@resumeDevice@"; then | ||
453 | resumeDev="@resumeDevice@" | ||
454 | resumeInfo="$(udevadm info -q property "$resumeDev" )" | ||
455 | else | ||
456 | for sd in @resumeDevices@; do | ||
457 | # Try to detect resume device. According to Ubuntu bug: | ||
458 | # https://bugs.launchpad.net/ubuntu/+source/pm-utils/+bug/923326/comments/1 | ||
459 | # when there are multiple swap devices, we can't know where the hibernate | ||
460 | # image will reside. We can check all of them for swsuspend blkid. | ||
461 | if waitDevice "$sd"; then | ||
462 | resumeInfo="$(udevadm info -q property "$sd")" | ||
463 | if [ "$(echo "$resumeInfo" | sed -n 's/^ID_FS_TYPE=//p')" = "swsuspend" ]; then | ||
464 | resumeDev="$sd" | ||
465 | break | ||
466 | fi | ||
467 | fi | ||
468 | done | ||
469 | fi | ||
470 | if test -n "$resumeDev"; then | ||
471 | resumeMajor="$(echo "$resumeInfo" | sed -n 's/^MAJOR=//p')" | ||
472 | resumeMinor="$(echo "$resumeInfo" | sed -n 's/^MINOR=//p')" | ||
473 | echo "$resumeMajor:$resumeMinor" > /sys/power/resume 2> /dev/null || echo "failed to resume..." | ||
474 | fi | ||
475 | fi | ||
476 | |||
477 | # If we have a path to an iso file, find the iso and link it to /dev/root | ||
478 | if [ -n "$isoPath" ]; then | ||
479 | mkdir -p /findiso | ||
480 | |||
481 | for delay in 5 10; do | ||
482 | blkid | while read -r line; do | ||
483 | device=$(echo "$line" | sed 's/:.*//') | ||
484 | type=$(echo "$line" | sed 's/.*TYPE="\([^"]*\)".*/\1/') | ||
485 | |||
486 | mount -t "$type" "$device" /findiso | ||
487 | if [ -e "/findiso$isoPath" ]; then | ||
488 | ln -sf "/findiso$isoPath" /dev/root | ||
489 | break 2 | ||
490 | else | ||
491 | umount /findiso | ||
492 | fi | ||
493 | done | ||
494 | |||
495 | sleep "$delay" | ||
496 | done | ||
497 | fi | ||
498 | |||
499 | # Try to find and mount the root device. | ||
500 | mkdir -p $targetRoot | ||
501 | |||
502 | exec 3< @fsInfo@ | ||
503 | |||
504 | while read -u 3 mountPoint; do | ||
505 | read -u 3 device | ||
506 | read -u 3 fsType | ||
507 | read -u 3 options | ||
508 | |||
509 | # !!! Really quick hack to support bind mounts, i.e., where the | ||
510 | # "device" should be taken relative to /mnt-root, not /. Assume | ||
511 | # that every device that starts with / but doesn't start with /dev | ||
512 | # is a bind mount. | ||
513 | pseudoDevice= | ||
514 | case $device in | ||
515 | /dev/*) | ||
516 | ;; | ||
517 | //*) | ||
518 | # Don't touch SMB/CIFS paths. | ||
519 | pseudoDevice=1 | ||
520 | ;; | ||
521 | /*) | ||
522 | device=/mnt-root$device | ||
523 | ;; | ||
524 | *) | ||
525 | # Not an absolute path; assume that it's a pseudo-device | ||
526 | # like an NFS path (e.g. "server:/path"). | ||
527 | pseudoDevice=1 | ||
528 | ;; | ||
529 | esac | ||
530 | |||
531 | if test -z "$pseudoDevice" && ! waitDevice "$device"; then | ||
532 | # If it doesn't appear, try to mount it anyway (and | ||
533 | # probably fail). This is a fallback for non-device "devices" | ||
534 | # that we don't properly recognise. | ||
535 | echo "Timed out waiting for device $device, trying to mount anyway." | ||
536 | fi | ||
537 | |||
538 | # Wait once more for the udev queue to empty, just in case it's | ||
539 | # doing something with $device right now. | ||
540 | udevadm settle | ||
541 | |||
542 | # If copytoram is enabled: skip mounting the ISO and copy its content to a tmpfs. | ||
543 | if [ -n "$copytoram" ] && [ "$device" = /dev/root ] && [ "$mountPoint" = /iso ]; then | ||
544 | fsType=$(blkid -o value -s TYPE "$device") | ||
545 | fsSize=$(blockdev --getsize64 "$device") | ||
546 | |||
547 | mkdir -p /tmp-iso | ||
548 | mount -t "$fsType" /dev/root /tmp-iso | ||
549 | mountFS tmpfs /iso size="$fsSize" tmpfs | ||
550 | |||
551 | cp -r /tmp-iso/* /mnt-root/iso/ | ||
552 | |||
553 | umount /tmp-iso | ||
554 | rmdir /tmp-iso | ||
555 | continue | ||
556 | fi | ||
557 | |||
558 | if [ "$mountPoint" = / ] && [ "$device" = tmpfs ] && [ ! -z "$persistence" ]; then | ||
559 | echo persistence... | ||
560 | waitDevice "$persistence" | ||
561 | echo enabling persistence... | ||
562 | mountFS "$persistence" "$mountPoint" "$persistence_opt" "auto" | ||
563 | continue | ||
564 | fi | ||
565 | |||
566 | mountFS "$device" "$mountPoint" "$options" "$fsType" | ||
567 | done | ||
568 | |||
569 | exec 3>&- | ||
570 | |||
571 | |||
572 | @postMountCommands@ | ||
573 | |||
574 | |||
575 | # Emit a udev rule for /dev/root to prevent systemd from complaining. | ||
576 | if [ -e /mnt-root/iso ]; then | ||
577 | eval $(udevadm info --export --export-prefix=ROOT_ --device-id-of-file=/mnt-root/iso) | ||
578 | else | ||
579 | eval $(udevadm info --export --export-prefix=ROOT_ --device-id-of-file=$targetRoot) | ||
580 | fi | ||
581 | if [ "$ROOT_MAJOR" -a "$ROOT_MINOR" -a "$ROOT_MAJOR" != 0 ]; then | ||
582 | mkdir -p /run/udev/rules.d | ||
583 | echo 'ACTION=="add|change", SUBSYSTEM=="block", ENV{MAJOR}=="'$ROOT_MAJOR'", ENV{MINOR}=="'$ROOT_MINOR'", SYMLINK+="root"' > /run/udev/rules.d/61-dev-root-link.rules | ||
584 | fi | ||
585 | |||
586 | |||
587 | # Stop udevd. | ||
588 | udevadm control --exit | ||
589 | |||
590 | # Reset the logging file descriptors. | ||
591 | # Do this just before pkill, which will kill the tee process. | ||
592 | exec 1>&$logOutFd 2>&$logErrFd | ||
593 | eval "exec $logOutFd>&- $logErrFd>&-" | ||
594 | |||
595 | # Kill any remaining processes, just to be sure we're not taking any | ||
596 | # with us into stage 2. But keep storage daemons like unionfs-fuse. | ||
597 | # | ||
598 | # Storage daemons are distinguished by an @ in front of their command line: | ||
599 | # https://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons/ | ||
600 | for pid in $(pgrep -v -f '^@'); do | ||
601 | # Make sure we don't kill kernel processes, see #15226 and: | ||
602 | # http://stackoverflow.com/questions/12213445/identifying-kernel-threads | ||
603 | readlink "/proc/$pid/exe" &> /dev/null || continue | ||
604 | # Try to avoid killing ourselves. | ||
605 | [ $pid -eq $$ ] && continue | ||
606 | kill -9 "$pid" | ||
607 | done | ||
608 | |||
609 | if test -n "$debug1mounts"; then fail; fi | ||
610 | |||
611 | |||
612 | # Restore /proc/sys/kernel/modprobe to its original value. | ||
613 | echo /sbin/modprobe > /proc/sys/kernel/modprobe | ||
614 | |||
615 | |||
616 | # Start stage 2. `switch_root' deletes all files in the ramfs on the | ||
617 | # current root. The path has to be valid in the chroot not outside. | ||
618 | if [ ! -e "$targetRoot/$stage2Init" ]; then | ||
619 | stage2Check=${stage2Init} | ||
620 | while [ "$stage2Check" != "${stage2Check%/*}" ] && [ ! -L "$targetRoot/$stage2Check" ]; do | ||
621 | stage2Check=${stage2Check%/*} | ||
622 | done | ||
623 | if [ ! -L "$targetRoot/$stage2Check" ]; then | ||
624 | echo "stage 2 init script ($targetRoot/$stage2Init) not found" | ||
625 | fail | ||
626 | fi | ||
627 | fi | ||
628 | |||
629 | mkdir -m 0755 -p $targetRoot/proc $targetRoot/sys $targetRoot/dev $targetRoot/run | ||
630 | |||
631 | mount --move /proc $targetRoot/proc | ||
632 | mount --move /sys $targetRoot/sys | ||
633 | mount --move /dev $targetRoot/dev | ||
634 | mount --move /run $targetRoot/run | ||
635 | |||
636 | exec env -i $(type -P switch_root) "$targetRoot" "$stage2Init" | ||
637 | |||
638 | fail # should never be reached | ||