You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

stage-1-init.sh 17KB

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