PageRenderTime 41ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/usr/src/cmd/boot/scripts/create_ramdisk.ksh

https://bitbucket.org/a3217055/illumos-2
Korn Shell | 589 lines | 411 code | 48 blank | 130 comment | 54 complexity | 049ebf0b200777795072e9fc50ec01e2 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, AGPL-3.0, BSD-3-Clause, LGPL-2.0, 0BSD, BSD-2-Clause, BSD-3-Clause-No-Nuclear-License-2014, AGPL-1.0, GPL-2.0
  1. #!/bin/ksh -p
  2. #
  3. # CDDL HEADER START
  4. #
  5. # The contents of this file are subject to the terms of the
  6. # Common Development and Distribution License (the "License").
  7. # You may not use this file except in compliance with the License.
  8. #
  9. # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10. # or http://www.opensolaris.org/os/licensing.
  11. # See the License for the specific language governing permissions
  12. # and limitations under the License.
  13. #
  14. # When distributing Covered Code, include this CDDL HEADER in each
  15. # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16. # If applicable, add the following below this CDDL HEADER, with the
  17. # fields enclosed by brackets "[]" replaced with your own identifying
  18. # information: Portions Copyright [yyyy] [name of copyright owner]
  19. #
  20. # CDDL HEADER END
  21. #
  22. # Copyright 2009 Sun Microsystems, Inc. All rights reserved.
  23. # Use is subject to license terms.
  24. format=ufs
  25. ALT_ROOT=
  26. EXTRACT_ARGS=
  27. compress=yes
  28. SPLIT=unknown
  29. ERROR=0
  30. dirsize32=0
  31. dirsize64=0
  32. usage() {
  33. echo "This utility is a component of the bootadm(1M) implementation"
  34. echo "and it is not recommended for stand-alone use."
  35. echo "Please use bootadm(1M) instead."
  36. echo ""
  37. echo "Usage: ${0##*/}: [-R \<root\>] [-p \<platform\>] [--nocompress]"
  38. echo "where \<platform\> is one of i86pc, sun4u or sun4v"
  39. exit
  40. }
  41. # default platform is what we're running on
  42. PLATFORM=`uname -m`
  43. #
  44. # set path, but inherit /tmp/bfubin if owned by
  45. # same uid executing this process, which must be root.
  46. #
  47. if [ "`echo $PATH | cut -f 1 -d :`" = /tmp/bfubin ] && \
  48. [ -O /tmp/bfubin ] ; then
  49. export PATH=/tmp/bfubin
  50. export GZIP_CMD=/tmp/bfubin/gzip
  51. else
  52. export PATH=/usr/sbin:/usr/bin:/sbin
  53. export GZIP_CMD=/usr/bin/gzip
  54. fi
  55. EXTRACT_FILELIST="/boot/solaris/bin/extract_boot_filelist"
  56. #
  57. # Parse options
  58. #
  59. while [ "$1" != "" ]
  60. do
  61. case $1 in
  62. -R) shift
  63. ALT_ROOT="$1"
  64. if [ "$ALT_ROOT" != "/" ]; then
  65. echo "Creating boot_archive for $ALT_ROOT"
  66. EXTRACT_ARGS="${EXTRACT_ARGS} -R ${ALT_ROOT}"
  67. EXTRACT_FILELIST="${ALT_ROOT}${EXTRACT_FILELIST}"
  68. fi
  69. ;;
  70. -n|--nocompress) compress=no
  71. ;;
  72. -p) shift
  73. PLATFORM="$1"
  74. EXTRACT_ARGS="${EXTRACT_ARGS} -p ${PLATFORM}"
  75. ;;
  76. *) usage
  77. ;;
  78. esac
  79. shift
  80. done
  81. if [ -x /usr/bin/mkisofs -o -x /tmp/bfubin/mkisofs ] ; then
  82. format=isofs
  83. fi
  84. #
  85. # mkisofs on s8 doesn't support functionality used by GRUB boot.
  86. # Use ufs format for boot archive instead.
  87. #
  88. release=`uname -r`
  89. if [ "$release" = "5.8" ]; then
  90. format=ufs
  91. fi
  92. shift `expr $OPTIND - 1`
  93. if [ $# -eq 1 ]; then
  94. ALT_ROOT="$1"
  95. echo "Creating boot_archive for $ALT_ROOT"
  96. fi
  97. case $PLATFORM in
  98. i386) PLATFORM=i86pc
  99. ISA=i386
  100. ARCH64=amd64
  101. ;;
  102. i86pc) ISA=i386
  103. ARCH64=amd64
  104. ;;
  105. sun4u) ISA=sparc
  106. ARCH64=sparcv9
  107. ;;
  108. sun4v) ISA=sparc
  109. ARCH64=sparcv9
  110. ;;
  111. *) usage
  112. ;;
  113. esac
  114. BOOT_ARCHIVE=platform/$PLATFORM/boot_archive
  115. BOOT_ARCHIVE_64=platform/$PLATFORM/$ARCH64/boot_archive
  116. if [ $PLATFORM = i86pc ] ; then
  117. if [ ! -x "$ALT_ROOT"/boot/solaris/bin/symdef ]; then
  118. # no dboot implies combined archives for example
  119. # live-upgrade from s9 to s10u6 is multiboot-only
  120. echo "Creating single archive at $ALT_ROOT/$BOOT_ARCHIVE"
  121. SPLIT=no
  122. compress=no
  123. else
  124. SPLIT=yes
  125. fi
  126. else # must be sparc
  127. SPLIT=no # there's only 64-bit (sparcv9), so don't split
  128. compress=no
  129. fi
  130. [ -x $GZIP_CMD ] || compress=no
  131. function cleanup
  132. {
  133. umount -f "$rdmnt32" 2>/dev/null
  134. umount -f "$rdmnt64" 2>/dev/null
  135. lofiadm -d "$rdfile32" 2>/dev/null
  136. lofiadm -d "$rdfile64" 2>/dev/null
  137. [ -n "$rddir" ] && rm -fr "$rddir" 2> /dev/null
  138. [ -n "$new_rddir" ] && rm -fr "$new_rddir" 2>/dev/null
  139. }
  140. function getsize
  141. {
  142. # Estimate image size and add 10% overhead for ufs stuff.
  143. # Note, we can't use du here in case we're on a filesystem, e.g. zfs,
  144. # in which the disk usage is less than the sum of the file sizes.
  145. # The nawk code
  146. #
  147. # {t += ($5 % 1024) ? (int($5 / 1024) + 1) * 1024 : $5}
  148. #
  149. # below rounds up the size of a file/directory, in bytes, to the
  150. # next multiple of 1024. This mimics the behavior of ufs especially
  151. # with directories. This results in a total size that's slightly
  152. # bigger than if du was called on a ufs directory.
  153. size32=$(cat "$list32" | xargs -I {} ls -lLd "{}" 2> /dev/null |
  154. nawk '{t += ($5 % 1024) ? (int($5 / 1024) + 1) * 1024 : $5}
  155. END {print int(t * 1.10 / 1024)}')
  156. (( size32 += dirsize32 ))
  157. size64=$(cat "$list64" | xargs -I {} ls -lLd "{}" 2> /dev/null |
  158. nawk '{t += ($5 % 1024) ? (int($5 / 1024) + 1) * 1024 : $5}
  159. END {print int(t * 1.10 / 1024)}')
  160. (( size64 += dirsize64 ))
  161. (( total_size = size32 + size64 ))
  162. if [ $compress = yes ] ; then
  163. total_size=`echo $total_size | nawk '{print int($1 / 2)}'`
  164. fi
  165. }
  166. #
  167. # Copies all desired files to a target directory. One argument should be
  168. # passed: the file containing the list of files to copy. This function also
  169. # depends on several variables that must be set before calling:
  170. #
  171. # $ALT_ROOT - the target directory
  172. # $compress - whether or not the files in the archives should be compressed
  173. # $rdmnt - the target directory
  174. #
  175. function copy_files
  176. {
  177. list="$1"
  178. #
  179. # If compress is set, the files are gzip'd and put in the correct
  180. # location in the loop. Nothing is printed, so the pipe and cpio
  181. # at the end is a nop.
  182. #
  183. # If compress is not set, the file names are printed, which causes
  184. # the cpio at the end to do the copy.
  185. #
  186. while read path
  187. do
  188. if [ $compress = yes ]; then
  189. dir="${path%/*}"
  190. [ -d "$rdmnt/$dir" ] || mkdir -p "$rdmnt/$dir"
  191. $GZIP_CMD -c "$path" > "$rdmnt/$path"
  192. else
  193. print "$path"
  194. fi
  195. done <"$list" | cpio -pdum "$rdmnt" 2>/dev/null
  196. if [ $ISA = sparc ] ; then
  197. # copy links
  198. find $filelist -type l -print 2>/dev/null |\
  199. cpio -pdum "$rdmnt" 2>/dev/null
  200. if [ $compress = yes ] ; then
  201. # always copy unix uncompressed
  202. find $filelist -name unix -type f -print 2>/dev/null |\
  203. cpio -pdum "$rdmnt" 2>/dev/null
  204. fi
  205. fi
  206. }
  207. #
  208. # The first argument can be:
  209. #
  210. # "both" - create an archive with both 32-bit and 64-bit binaries
  211. # "32-bit" - create an archive with only 32-bit binaries
  212. # "64-bit" - create an archive with only 64-bit binaries
  213. #
  214. function create_ufs
  215. {
  216. which=$1
  217. archive=$2
  218. lofidev=$3
  219. # should we exclude amd64 binaries?
  220. if [ "$which" = "32-bit" ]; then
  221. rdfile="$rdfile32"
  222. rdmnt="$rdmnt32"
  223. list="$list32"
  224. elif [ "$which" = "64-bit" ]; then
  225. rdfile="$rdfile64"
  226. rdmnt="$rdmnt64"
  227. list="$list64"
  228. else
  229. rdfile="$rdfile32"
  230. rdmnt="$rdmnt32"
  231. list="$list32"
  232. fi
  233. newfs $lofidev < /dev/null 2> /dev/null
  234. mkdir "$rdmnt"
  235. mount -F mntfs mnttab /etc/mnttab > /dev/null 2>&1
  236. mount -F ufs -o nologging $lofidev "$rdmnt"
  237. files=
  238. # do the actual copy
  239. copy_files "$list"
  240. umount -f "$rdmnt"
  241. rmdir "$rdmnt"
  242. if [ $ISA = sparc ] ; then
  243. rlofidev=`echo "$lofidev" | sed -e "s/dev\/lofi/dev\/rlofi/"`
  244. bb="$ALT_ROOT/platform/$PLATFORM/lib/fs/ufs/bootblk"
  245. # installboot is not available on all platforms
  246. dd if=$bb of=$rlofidev bs=1b oseek=1 count=15 conv=sync 2>&1
  247. fi
  248. #
  249. # Check if gzip exists in /usr/bin, so we only try to run gzip
  250. # on systems that have gzip. Then run gzip out of the patch to
  251. # pick it up from bfubin or something like that if needed.
  252. #
  253. # If compress is set, the individual files in the archive are
  254. # compressed, and the final compression will accomplish very
  255. # little. To save time, we skip the gzip in this case.
  256. #
  257. if [ $ISA = i386 ] && [ $compress = no ] && \
  258. [ -x $GZIP_CMD ] ; then
  259. gzip -c "$rdfile" > "${archive}-new"
  260. else
  261. cat "$rdfile" > "${archive}-new"
  262. fi
  263. if [ $? -ne 0 ] ; then
  264. rm -f "${archive}-new"
  265. fi
  266. }
  267. #
  268. # The first argument can be:
  269. #
  270. # "both" - create an archive with both 32-bit and 64-bit binaries
  271. # "32-bit" - create an archive with only 32-bit binaries
  272. # "64-bit" - create an archive with only 64-bit binaries
  273. #
  274. function create_isofs
  275. {
  276. which=$1
  277. archive=$2
  278. # should we exclude amd64 binaries?
  279. if [ "$which" = "32-bit" ]; then
  280. rdmnt="$rdmnt32"
  281. errlog="$errlog32"
  282. list="$list32"
  283. elif [ "$which" = "64-bit" ]; then
  284. rdmnt="$rdmnt64"
  285. errlog="$errlog64"
  286. list="$list64"
  287. else
  288. rdmnt="$rdmnt32"
  289. errlog="$errlog32"
  290. list="$list32"
  291. fi
  292. # create image directory seed with graft points
  293. mkdir "$rdmnt"
  294. files=
  295. isocmd="mkisofs -quiet -graft-points -dlrDJN -relaxed-filenames"
  296. if [ $ISA = sparc ] ; then
  297. bb="$ALT_ROOT/platform/$PLATFORM/lib/fs/hsfs/bootblk"
  298. isocmd="$isocmd -G \"$bb\""
  299. fi
  300. copy_files "$list"
  301. isocmd="$isocmd \"$rdmnt\""
  302. rm -f "$errlog"
  303. #
  304. # Check if gzip exists in /usr/bin, so we only try to run gzip
  305. # on systems that have gzip. Then run gzip out of the patch to
  306. # pick it up from bfubin or something like that if needed.
  307. #
  308. # If compress is set, the individual files in the archive are
  309. # compressed, and the final compression will accomplish very
  310. # little. To save time, we skip the gzip in this case.
  311. #
  312. mkiso_ret=0
  313. if [ $ISA = i386 ] &&[ $compress = no ] && [ -x $GZIP_CMD ]
  314. then
  315. ksh -c "$isocmd" 2> "$errlog" | \
  316. gzip > "${archive}-new"
  317. else
  318. ksh -c "$isocmd" 2> "$errlog" > "${archive}-new"
  319. fi
  320. if [ $? -ne 0 ]; then
  321. cat "$errlog"
  322. rm -f "${archive}-new" 2> /dev/null
  323. rm -f "$errlog" 2> /dev/null
  324. return
  325. fi
  326. dd_ret=0
  327. if [ $ISA = sparc ] ; then
  328. bb="$ALT_ROOT/platform/$PLATFORM/lib/fs/hsfs/bootblk"
  329. dd if="$bb" of="${archive}-new" bs=1b oseek=1 count=15 \
  330. conv=notrunc conv=sync >> "$errlog" 2>&1
  331. dd_ret=$?
  332. fi
  333. if [ -s "$errlog" ] || [ $dd_ret -ne 0 ] ; then
  334. grep Error: "$errlog" >/dev/null 2>&1
  335. if [ $? -eq 0 ] || [ $dd_ret -ne 0 ] ; then
  336. cat "$errlog"
  337. rm -f "${archive}-new"
  338. fi
  339. fi
  340. rm -f "$errlog"
  341. }
  342. function create_archive
  343. {
  344. which=$1
  345. archive=$2
  346. lofidev=$3
  347. echo "updating $archive"
  348. if [ "$format" = "ufs" ]; then
  349. create_ufs "$which" "$archive" "$lofidev"
  350. else
  351. create_isofs "$which" "$archive"
  352. fi
  353. # sanity check the archive before moving it into place
  354. #
  355. ARCHIVE_SIZE=`ls -l "${archive}-new" 2> /dev/null | nawk '{ print $5 }'`
  356. if [ $compress = yes ] || [ $ISA = sparc ] ; then
  357. #
  358. # 'file' will report "English text" for uncompressed
  359. # boot_archives. Checking for that doesn't seem stable,
  360. # so we just check that the file exists.
  361. #
  362. ls "${archive}-new" >/dev/null 2>&1
  363. else
  364. #
  365. # the file type check also establishes that the
  366. # file exists at all
  367. #
  368. LC_MESSAGES=C file "${archive}-new" | grep gzip > /dev/null
  369. fi
  370. if [ $? = 1 ] && [ -x $GZIP_CMD ] || [ "$ARCHIVE_SIZE" -lt 10000 ]
  371. then
  372. #
  373. # Two of these functions may be run in parallel. We
  374. # need to allow the other to clean up, so we can't
  375. # exit immediately. Instead, we set a flag.
  376. #
  377. echo "update of $archive failed"
  378. ERROR=1
  379. else
  380. lockfs -f "/$ALT_ROOT" 2>/dev/null
  381. mv "${archive}-new" "$archive"
  382. lockfs -f "/$ALT_ROOT" 2>/dev/null
  383. fi
  384. }
  385. function fatal_error
  386. {
  387. print -u2 $*
  388. exit 1
  389. }
  390. #
  391. # get filelist
  392. #
  393. if [ ! -f "$ALT_ROOT/boot/solaris/filelist.ramdisk" ] &&
  394. [ ! -f "$ALT_ROOT/etc/boot/solaris/filelist.ramdisk" ]
  395. then
  396. print -u2 "Can't find filelist.ramdisk"
  397. exit 1
  398. fi
  399. filelist=$($EXTRACT_FILELIST $EXTRACT_ARGS \
  400. /boot/solaris/filelist.ramdisk \
  401. /etc/boot/solaris/filelist.ramdisk \
  402. 2>/dev/null | sort -u)
  403. #
  404. # We use /tmp/ for scratch space now. This may be changed later if there
  405. # is insufficient space in /tmp/.
  406. #
  407. rddir="/tmp/create_ramdisk.$$.tmp"
  408. new_rddir=
  409. rm -rf "$rddir"
  410. mkdir "$rddir" || fatal_error "Could not create temporary directory $rddir"
  411. # Clean up upon exit.
  412. trap 'cleanup' EXIT
  413. list32="$rddir/filelist.32"
  414. list64="$rddir/filelist.64"
  415. touch $list32 $list64
  416. #
  417. # This loop creates the 32-bit and 64-bit lists of files. The 32-bit list
  418. # is written to stdout, which is redirected at the end of the loop. The
  419. # 64-bit list is appended with each write.
  420. #
  421. cd "/$ALT_ROOT"
  422. find $filelist -print 2>/dev/null | while read path
  423. do
  424. if [ $SPLIT = no ]; then
  425. print "$path"
  426. elif [ -d "$path" ]; then
  427. if [ $format = ufs ]; then
  428. size=`ls -lLd "$path" | nawk '
  429. {print ($5 % 1024) ? (int($5 / 1024) + 1) * 1024 : $5}'`
  430. if [ `basename "$path"` != "amd64" ]; then
  431. (( dirsize32 += size ))
  432. fi
  433. (( dirsize64 += size ))
  434. fi
  435. else
  436. case `LC_MESSAGES=C /usr/bin/file -m /dev/null "$path" 2>/dev/null` in
  437. *ELF\ 64-bit*)
  438. print "$path" >> "$list64"
  439. ;;
  440. *ELF\ 32-bit*)
  441. print "$path"
  442. ;;
  443. *)
  444. # put in both lists
  445. print "$path"
  446. print "$path" >> "$list64"
  447. esac
  448. fi
  449. done >"$list32"
  450. if [ $format = ufs ] ; then
  451. # calculate image size
  452. getsize
  453. # check to see if there is sufficient space in tmpfs
  454. #
  455. tmp_free=`df -b /tmp | tail -1 | awk '{ printf ($2) }'`
  456. (( tmp_free = tmp_free / 3 ))
  457. if [ $SPLIT = yes ]; then
  458. (( tmp_free = tmp_free / 2 ))
  459. fi
  460. if [ $total_size -gt $tmp_free ] ; then
  461. # assumes we have enough scratch space on $ALT_ROOT
  462. new_rddir="/$ALT_ROOT/var/tmp/create_ramdisk.$$.tmp"
  463. rm -rf "$new_rddir"
  464. mkdir "$new_rddir" || fatal_error \
  465. "Could not create temporary directory $new_rddir"
  466. # Save the file lists
  467. mv "$list32" "$new_rddir"/
  468. mv "$list64" "$new_rddir"/
  469. list32="/$new_rddir/filelist.32"
  470. list64="/$new_rddir/filelist.64"
  471. # Remove the old $rddir and set the new value of rddir
  472. rm -rf "$rddir"
  473. rddir="$new_rddir"
  474. new_rddir=
  475. fi
  476. fi
  477. rdfile32="$rddir/rd.file.32"
  478. rdfile64="$rddir/rd.file.64"
  479. rdmnt32="$rddir/rd.mount.32"
  480. rdmnt64="$rddir/rd.mount.64"
  481. errlog32="$rddir/rd.errlog.32"
  482. errlog64="$rddir/rd.errlog.64"
  483. lofidev32=""
  484. lofidev64=""
  485. if [ $SPLIT = yes ]; then
  486. #
  487. # We can't run lofiadm commands in parallel, so we have to do
  488. # them here.
  489. #
  490. if [ "$format" = "ufs" ]; then
  491. mkfile ${size32}k "$rdfile32"
  492. lofidev32=`lofiadm -a "$rdfile32"`
  493. mkfile ${size64}k "$rdfile64"
  494. lofidev64=`lofiadm -a "$rdfile64"`
  495. fi
  496. create_archive "32-bit" "$ALT_ROOT/$BOOT_ARCHIVE" $lofidev32 &
  497. create_archive "64-bit" "$ALT_ROOT/$BOOT_ARCHIVE_64" $lofidev64
  498. wait
  499. if [ "$format" = "ufs" ]; then
  500. lofiadm -d "$rdfile32"
  501. lofiadm -d "$rdfile64"
  502. fi
  503. else
  504. if [ "$format" = "ufs" ]; then
  505. mkfile ${total_size}k "$rdfile32"
  506. lofidev32=`lofiadm -a "$rdfile32"`
  507. fi
  508. create_archive "both" "$ALT_ROOT/$BOOT_ARCHIVE" $lofidev32
  509. [ "$format" = "ufs" ] && lofiadm -d "$rdfile32"
  510. fi
  511. if [ $ERROR = 1 ]; then
  512. cleanup
  513. exit 1
  514. fi
  515. #
  516. # For the diskless case, hardlink archive to /boot to make it
  517. # visible via tftp. /boot is lofs mounted under /tftpboot/<hostname>.
  518. # NOTE: this script must work on both client and server.
  519. #
  520. grep "[ ]/[ ]*nfs[ ]" "$ALT_ROOT/etc/vfstab" > /dev/null
  521. if [ $? = 0 ]; then
  522. rm -f "$ALT_ROOT/boot/boot_archive" "$ALT_ROOT/boot/amd64/boot_archive"
  523. ln "$ALT_ROOT/$BOOT_ARCHIVE" "$ALT_ROOT/boot/boot_archive"
  524. if [ $SPLIT = yes ]; then
  525. ln "$ALT_ROOT/$BOOT_ARCHIVE_64" \
  526. "$ALT_ROOT/boot/amd64/boot_archive"
  527. fi
  528. fi
  529. [ -n "$rddir" ] && rm -rf "$rddir"