functions 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. # -*- shell-script -*-
  2. _log_msg()
  3. {
  4. if [ "$quiet" = "y" ]; then return; fi
  5. printf "$@"
  6. }
  7. log_success_msg()
  8. {
  9. _log_msg "Success: $@\n"
  10. }
  11. log_failure_msg()
  12. {
  13. _log_msg "Failure: $@\n"
  14. }
  15. log_warning_msg()
  16. {
  17. _log_msg "Warning: $@\n"
  18. }
  19. log_begin_msg()
  20. {
  21. _log_msg "Begin: $@ ... "
  22. }
  23. log_end_msg()
  24. {
  25. _log_msg "done.\n"
  26. }
  27. # Add failure hook
  28. add_mountroot_fail_hook()
  29. {
  30. mkdir -p /tmp/mountroot-fail-hooks.d
  31. ln -s "$0" /tmp/mountroot-fail-hooks.d/"$1"
  32. }
  33. # Run failure hooks.
  34. # When a failure hook exits "1", it has not done anything to correct the
  35. # system. Exiting "0" means that something has been attempted to resolve
  36. # the lack of a root filesystem.
  37. # Hooks are run in lexigraphical order, and are responsible for removing
  38. # themselves if they should not re-run in a later cycle. When one exits
  39. # "0", the stack is stopped, so the caller can return to the main rootfs
  40. # wait loop.
  41. try_failure_hooks()
  42. {
  43. local hook
  44. # Disable usplash so text from hooks can be seen
  45. if [ -x /sbin/usplash_write ]; then
  46. /sbin/usplash_write "QUIT"
  47. fi
  48. chvt 1
  49. if [ -x /bin/plymouth ] && plymouth --ping; then
  50. /bin/plymouth hide-splash > /dev/null 2>&1
  51. fi
  52. for hook in /tmp/mountroot-fail-hooks.d/*; do
  53. if [ -x ${hook} ] && ${hook} mountfail; then
  54. return 0
  55. fi
  56. done
  57. return 1
  58. }
  59. panic()
  60. {
  61. if command -v chvt >/dev/null 2>&1; then
  62. chvt 1
  63. fi
  64. echo "$@"
  65. # Disallow console access
  66. if [ -n "${panic}" ]; then
  67. echo "Rebooting automatically due to panic= boot argument"
  68. sleep ${panic}
  69. reboot
  70. exit # in case reboot fails, force kernel panic
  71. fi
  72. modprobe -v i8042 || true
  73. modprobe -v atkbd || true
  74. modprobe -v ehci-pci || true
  75. modprobe -v ehci-orion || true
  76. modprobe -v ehci-hcd || true
  77. modprobe -v uhci-hcd || true
  78. modprobe -v ohci-hcd || true
  79. modprobe -v usbhid || true
  80. run_scripts /scripts/panic
  81. REASON="$@" PS1='(initramfs) ' /bin/sh -i </dev/console >/dev/console 2>&1
  82. }
  83. maybe_break()
  84. {
  85. case ",$break," in
  86. *,$1,*)
  87. panic "Spawning shell within the initramfs"
  88. ;;
  89. esac
  90. }
  91. render()
  92. {
  93. eval "echo -n \${$@}"
  94. }
  95. # For boot time only; this is overridden at build time in hook-functions
  96. run_scripts()
  97. {
  98. initdir=${1}
  99. [ ! -d ${initdir} ] && return
  100. shift
  101. . ${initdir}/ORDER
  102. }
  103. # Load custom modules first
  104. load_modules()
  105. {
  106. if [ -e /conf/modules ]; then
  107. cat /conf/modules | while read m; do
  108. # Skip empty lines
  109. if [ -z "$m" ]; then
  110. continue
  111. fi
  112. # Skip comments - d?ash removes whitespace prefix
  113. com=$(printf "%.1s" "${m}")
  114. if [ "$com" = "#" ]; then
  115. continue
  116. fi
  117. modprobe $m
  118. done
  119. fi
  120. }
  121. # lilo compatibility
  122. parse_numeric() {
  123. case $1 in
  124. *:*)
  125. # Does it match /[0-9]*:[0-9]*/?
  126. minor=${1#*:}
  127. major=${1%:*}
  128. case $major$minor in
  129. *[!0-9]*)
  130. # No.
  131. return
  132. ;;
  133. esac
  134. ;;
  135. "" | *[!A-Fa-f0-9]*)
  136. # "", "/*", etc.
  137. return
  138. ;;
  139. *)
  140. # [A-Fa-f0-9]*
  141. value=$(( 0x${1} ))
  142. minor=$(( (${value} & 0xff) | (${value} >> 12) & 0xfff00 ))
  143. major=$(( (${value} >> 8) & 0xfff ))
  144. ;;
  145. esac
  146. ROOT="$(readlink -f /dev/block/${major}:${minor})"
  147. }
  148. # Parameter: device node to check
  149. # Echos fstype to stdout
  150. # Return value: indicates if an fs could be recognized
  151. get_fstype ()
  152. {
  153. local FS FSTYPE FSSIZE RET
  154. FS="${1}"
  155. # blkid has a more complete list of file systems,
  156. # but fstype is more robust
  157. FSTYPE="unknown"
  158. eval $(fstype "${FS}" 2> /dev/null)
  159. if [ "$FSTYPE" = "unknown" ] && command -v blkid >/dev/null 2>&1 ; then
  160. FSTYPE=$(blkid -o value -s TYPE "${FS}")
  161. elif [ "$FSTYPE" = "unknown" ] && [ -x /lib/udev/vol_id ]; then
  162. FSTYPE=$(/lib/udev/vol_id -t "${FS}" 2> /dev/null)
  163. fi
  164. RET=$?
  165. if [ -z "${FSTYPE}" ]; then
  166. FSTYPE="unknown"
  167. fi
  168. echo "${FSTYPE}"
  169. return ${RET}
  170. }
  171. configure_networking()
  172. {
  173. if [ -n "${BOOTIF}" ]; then
  174. # pxelinux sets BOOTIF to a value based on the mac address of the
  175. # network card used to PXE boot, so use this value for DEVICE rather
  176. # than a hard-coded device name from initramfs.conf. this facilitates
  177. # network booting when machines may have multiple network cards.
  178. # pxelinux sets BOOTIF to 01-$mac_address
  179. # strip off the leading "01-", which isn't part of the mac
  180. # address
  181. temp_mac=${BOOTIF#*-}
  182. # convert to typical mac address format by replacing "-" with ":"
  183. bootif_mac=""
  184. IFS='-'
  185. for x in $temp_mac ; do
  186. if [ -z "$bootif_mac" ]; then
  187. bootif_mac="$x"
  188. else
  189. bootif_mac="$bootif_mac:$x"
  190. fi
  191. done
  192. unset IFS
  193. # look for devices with matching mac address, and set DEVICE to
  194. # appropriate value if match is found.
  195. for device in /sys/class/net/* ; do
  196. if [ -f "$device/address" ]; then
  197. current_mac=$(cat "$device/address")
  198. if [ "$bootif_mac" = "$current_mac" ]; then
  199. DEVICE=${device##*/}
  200. break
  201. fi
  202. fi
  203. done
  204. fi
  205. # networking already configured thus bail out
  206. [ -n "${DEVICE}" ] && [ -e /run/net-"${DEVICE}".conf ] && return 0
  207. wait_for_udev 10
  208. # support ip options see linux sources
  209. # Documentation/filesystems/nfs/nfsroot.txt
  210. # Documentation/frv/booting.txt
  211. for ROUNDTTT in 2 3 4 6 9 16 25 36 64 100; do
  212. # The NIC is to be configured if this file does not exist.
  213. # Ip-Config tries to create this file and when it succeds
  214. # creating the file, ipconfig is not run again.
  215. for x in /run/net-"${DEVICE}".conf /run/net-*.conf ; do
  216. [ -e "$x" ] && break 2
  217. done
  218. case ${IP} in
  219. none|off)
  220. # Do nothing
  221. ;;
  222. ""|on|any)
  223. # Bring up device
  224. ipconfig -t ${ROUNDTTT} "${DEVICE}"
  225. ;;
  226. dhcp|bootp|rarp|both)
  227. ipconfig -t ${ROUNDTTT} -c ${IP} -d "${DEVICE}"
  228. ;;
  229. *)
  230. ipconfig -t ${ROUNDTTT} -d $IP
  231. # grab device entry from ip option
  232. NEW_DEVICE=${IP#*:*:*:*:*:*}
  233. if [ "${NEW_DEVICE}" != "${IP}" ]; then
  234. NEW_DEVICE=${NEW_DEVICE%%:*}
  235. else
  236. # wrong parse, possibly only a partial string
  237. NEW_DEVICE=
  238. fi
  239. if [ -n "${NEW_DEVICE}" ]; then
  240. DEVICE="${NEW_DEVICE}"
  241. fi
  242. ;;
  243. esac
  244. done
  245. # source ipconfig output
  246. if [ -n "${DEVICE}" ]; then
  247. # source specific bootdevice
  248. . /run/net-${DEVICE}.conf
  249. else
  250. # source any interface...
  251. # ipconfig should have quit after first response
  252. . /run/net-*.conf
  253. fi
  254. }
  255. # Wait for queued kernel/udev events
  256. wait_for_udev()
  257. {
  258. command -v udevadm >/dev/null 2>&1 || return 0
  259. udevadm settle ${1:+--timeout=$1}
  260. }
  261. # Find a specific fstab entry
  262. # $1=mountpoint
  263. # $2=fstype (optional)
  264. # returns 0 on success, 1 on failure (not found or no fstab)
  265. read_fstab_entry() {
  266. # Not found by default.
  267. found=1
  268. for file in ${rootmnt}/etc/fstab; do
  269. if [ -f "$file" ]; then
  270. while read MNT_FSNAME MNT_DIR MNT_TYPE MNT_OPTS MNT_FREQ MNT_PASS MNT_JUNK; do
  271. case "$MNT_FSNAME" in
  272. ""|\#*)
  273. continue;
  274. ;;
  275. esac
  276. if [ "$MNT_DIR" = "$1" ]; then
  277. if [ -n "$2" ]; then
  278. [ "$MNT_TYPE" = "$2" ] || continue;
  279. fi
  280. found=0
  281. break 2
  282. fi
  283. done < "$file"
  284. fi
  285. done
  286. return $found
  287. }
  288. # Resolve device node from a name. This expands any LABEL or UUID.
  289. # $1=name
  290. # Resolved name is echoed.
  291. resolve_device() {
  292. DEV="$1"
  293. local orig="$DEV"
  294. case "$DEV" in
  295. LABEL=* | UUID=* | PARTLABEL=* | PARTUUID=*)
  296. if command -v blkid >/dev/null 2>&1; then
  297. DEV="$(blkid -l -t "$DEV" -o device)"
  298. if [ "$?" != 0 ]; then
  299. DEV="$orig"
  300. # Support uppercase and lowercase UUIDs -- see RFC#4122:
  301. # "Each field is treated as an integer and has its value printed as
  302. # a zero-filled hexadecimal digit string with the most significant
  303. # digit first. The hexadecimal values "a" through "f" are output as
  304. # lower case characters and are case insensitive on input."
  305. #
  306. # Note: that blkid which we will use to map these assums the input is lower
  307. # case.
  308. # Only apply this behaviour to UUIDs.
  309. case "$DEV" in
  310. UUID=* | PARTUUID=*) ;;
  311. *) return 1 ;;
  312. esac
  313. # Pull DEV appart and map it.
  314. local type=$(echo ${DEV} | cut -f 1 -d =)
  315. local value=$(echo ${DEV} | cut -f 2 -d = | tr '[A-F]' '[a-f]')
  316. # ... in RFC#4122 format;
  317. # look for five hexadecimal fragments separated by minus signs.
  318. local fmt=$( echo "$value" | sed -e 's/[0-9a-fA-F]*//g' )
  319. if [ "$fmt" != '----' ]; then
  320. return 1
  321. fi
  322. DEV="${type}=${value}"
  323. # Retry with the lower cased UUID.
  324. DEV="$(blkid -l -t "$DEV" -o device)" || return 1
  325. fi
  326. else
  327. log_warning_msg "blkid not present, so cannot resolve $DEV"
  328. return 1
  329. fi
  330. ;;
  331. esac
  332. [ -e "$DEV" ] && echo "$DEV"
  333. }
  334. # Check a file system.
  335. # $1=device
  336. # $2=mountpoint (for diagnostics only)
  337. _checkfs_once()
  338. {
  339. DEV="$1"
  340. NAME="$2"
  341. if [ "$NAME" = "/" ] ; then
  342. NAME="root"
  343. fi
  344. FSCK_LOGFILE=/run/initramfs/fsck.log
  345. FSCK_STAMPFILE=/run/initramfs/fsck-${NAME#/}
  346. TYPE=$(get_fstype "$1")
  347. FSCKCODE=0
  348. if ! command -v fsck >/dev/null 2>&1; then
  349. log_warning_msg "fsck not present, so skipping $NAME file system"
  350. return
  351. fi
  352. if [ "$fastboot" = "y" ] ; then
  353. log_warning_msg "Fast boot enabled, so skipping $NAME file system check."
  354. return
  355. fi
  356. if [ "$forcefsck" = "y" ]
  357. then
  358. force="-f"
  359. else
  360. force=""
  361. fi
  362. if [ "$fsckfix" = "y" ]
  363. then
  364. fix="-y"
  365. elif [ "$fsckfix" = "n" ]
  366. then
  367. fix="-n"
  368. else
  369. fix="-a"
  370. fi
  371. spinner=""
  372. if [ -z "${debug}" ]; then
  373. spinner="-C"
  374. fi
  375. if [ "${quiet}" = n ]
  376. then
  377. log_begin_msg "Will now check $NAME file system"
  378. logsave -a -s $FSCK_LOGFILE fsck $spinner $force $fix -V -t $TYPE $DEV
  379. FSCKCODE=$?
  380. log_end_msg
  381. else
  382. log_begin_msg "Checking $NAME file system"
  383. logsave -a -s $FSCK_LOGFILE fsck $spinner $force $fix -T -t $TYPE $DEV
  384. FSCKCODE=$?
  385. log_end_msg
  386. fi
  387. # NOTE: "failure" is defined as exiting with a return code of
  388. # 4, possibly or-ed with other flags. A return code of 1
  389. # indicates that file system errors were corrected but that
  390. # the boot may proceed.
  391. #
  392. if [ "$FSCKCODE" -eq 32 ]
  393. then
  394. log_warning_msg "File system check was interrupted by user"
  395. elif [ $((FSCKCODE & 4)) -eq 4 ]
  396. then
  397. log_failure_msg "File system check of the $NAME filesystem failed"
  398. return 1
  399. elif [ "$FSCKCODE" -gt 1 ]
  400. then
  401. log_warning_msg "File system check failed but did not detect errors"
  402. sleep 5
  403. else
  404. > $FSCK_STAMPFILE
  405. fi
  406. return 0
  407. }
  408. checkfs()
  409. {
  410. while ! _checkfs_once "$@"; do
  411. panic "The $2 filesystem on $1 requires a manual fsck"
  412. done
  413. }
  414. # Mount a file system. We parse the information from the fstab. This
  415. # should be overridden by any boot script which can mount arbitrary
  416. # filesystems such as /usr. This default implementation delegates to
  417. # local or nfs based upon the filesystem type.
  418. # $1=mountpoint mount location
  419. mountfs()
  420. {
  421. type=local
  422. read_fstab_entry "$1"
  423. if [ "${MNT_TYPE}" = "nfs" ] || [ "${MNT_TYPE}" = "nfs4" ]; then
  424. type=nfs
  425. fi
  426. ${type}_mount_fs "$1"
  427. }
  428. # Mount the root file system. It should be overridden by all
  429. # boot scripts.
  430. mountroot()
  431. {
  432. :
  433. }
  434. # Run /scripts/${boot}-top. This should be overridden by all boot
  435. # scripts.
  436. mount_top()
  437. {
  438. :
  439. }
  440. # Run /scripts/${boot}-premount. This should be overridden by all boot
  441. # scripts.
  442. mount_premount()
  443. {
  444. :
  445. }
  446. # Run /scripts/${boot}-bottom. This should be overridden by all boot
  447. # scripts.
  448. mount_bottom()
  449. {
  450. :
  451. }