create-image-with-grub.sh 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. #!/usr/bin/env bash
  2. #-
  3. # Copyright © 2010, 2011, 2012
  4. # Waldemar Brodkorb <wbx@openadk.org>
  5. # Thorsten Glaser <tg@mirbsd.org>
  6. #
  7. # Provided that these terms and disclaimer and all copyright notices
  8. # are retained or reproduced in an accompanying document, permission
  9. # is granted to deal in this work without restriction, including un-
  10. # limited rights to use, publicly perform, distribute, sell, modify,
  11. # merge, give away, or sublicence.
  12. #
  13. # This work is provided 'AS IS' and WITHOUT WARRANTY of any kind, to
  14. # the utmost extent permitted by applicable law, neither express nor
  15. # implied; without malicious intent or gross negligence. In no event
  16. # may a licensor, author or contributor be held liable for indirect,
  17. # direct, other damage, loss, or other issues arising in any way out
  18. # of dealing in the work, even if advised of the possibility of such
  19. # damage or existence of a defect, except proven that it results out
  20. # of said person's immediate fault when using the work as intended.
  21. #
  22. # Alternatively, this work may be distributed under the terms of the
  23. # General Public License, any version, as published by the Free Soft-
  24. # ware Foundation.
  25. #-
  26. TOPDIR=$(pwd)
  27. me=$0
  28. case :$PATH: in
  29. (*:$TOPDIR/bin/tools:*) ;;
  30. (*) export PATH=$PATH:$TOPDIR/bin/tools ;;
  31. esac
  32. test -n "$KSH_VERSION" || if ! which mksh >/dev/null 2>&1; then
  33. make package=mksh fetch || exit 1
  34. df=$(cd package/mksh; TOPDIR="$TOPDIR" make show=DISTFILES)
  35. mkdir -p build_mksh
  36. gzip -dc dl/"$df" | (cd build_mksh; cpio -mid)
  37. cd build_mksh/mksh
  38. bash Build.sh -r -c lto || exit 1
  39. cp mksh "$TOPDIR"/bin/tools/
  40. cd "$TOPDIR"
  41. rm -rf build_mksh
  42. fi
  43. test -n "$KSH_VERSION" || exec mksh "$me" "$@"
  44. if test -z "$KSH_VERSION"; then
  45. echo >&2 Fatal error: could not run myself with mksh!
  46. exit 255
  47. fi
  48. ### run with mksh from here onwards ###
  49. me=${me##*/}
  50. TOPDIR=$(realpath .)
  51. ostype=$(uname -s)
  52. cfgfs=1
  53. noformat=0
  54. quiet=0
  55. serial=0
  56. speed=115200
  57. panicreboot=10
  58. type=qemu
  59. function usage {
  60. cat >&2 <<EOF
  61. Syntax: $me [± ][-c cfgfssize] [-p panictime] [±q] [-s serialspeed]
  62. [±t][ -f diskformat ] -n disk.img archive
  63. Defaults: -c 1 -p 10 -s 115200 -f qemu; -t = enable serial console
  64. EOF
  65. exit $1
  66. }
  67. while getopts "c:hp:qs:ntf:" ch; do
  68. case $ch {
  69. (c) if (( (cfgfs = OPTARG) < 0 || cfgfs > 5 )); then
  70. print -u2 "$me: -c $OPTARG out of bounds"
  71. exit 1
  72. fi ;;
  73. (h) usage 0 ;;
  74. (p) if (( (panicreboot = OPTARG) < 0 || panicreboot > 300 )); then
  75. print -u2 "$me: -p $OPTARG out of bounds"
  76. exit 1
  77. fi ;;
  78. (q) quiet=1 ;;
  79. (+q) quiet=0 ;;
  80. (s) if [[ $OPTARG != @(96|192|384|576|1152)00 ]]; then
  81. print -u2 "$me: serial speed $OPTARG invalid"
  82. exit 1
  83. fi
  84. speed=$OPTARG ;;
  85. (n) noformat=1 ;;
  86. (t) serial=1 ;;
  87. (+t) serial=0 ;;
  88. (f) type=$OPTARG ;;
  89. (*) usage 1 ;;
  90. }
  91. done
  92. shift $((OPTIND - 1))
  93. (( $# == 2 )) || usage 1
  94. f=0
  95. tools='genext2fs qemu-img'
  96. case $ostype {
  97. (DragonFly|*BSD*)
  98. ;;
  99. (Darwin)
  100. ;;
  101. (Linux)
  102. ;;
  103. (*)
  104. print -u2 Sorry, not ported to the OS "'$ostype'" yet.
  105. exit 1
  106. ;;
  107. }
  108. for tool in $tools; do
  109. print -n Checking if $tool is installed...
  110. if whence -p $tool >/dev/null; then
  111. print " okay"
  112. else
  113. print " failed"
  114. f=1
  115. fi
  116. done
  117. (( f )) && exit 1
  118. tgt=$1
  119. src=$2
  120. if [[ ! -f $src ]]; then
  121. print -u2 "'$src' is not a file, exiting"
  122. exit 1
  123. fi
  124. (( quiet )) || print "Installing $src on $tgt."
  125. case $ostype {
  126. (DragonFly|*BSD*)
  127. basedev=${tgt%c}
  128. tgt=${basedev}c
  129. part=${basedev}i
  130. match=\'${basedev}\''[a-p]'
  131. function mount_ext2fs {
  132. mount -t ext2fs "$1" "$2"
  133. }
  134. ;;
  135. (Darwin)
  136. basedev=$tgt
  137. part=${basedev}s1
  138. match=\'${basedev}\''?(s+([0-9]))'
  139. function mount_ext2fs {
  140. fuse-ext2 "$1" "$2" -o rw+
  141. sleep 3
  142. }
  143. ;;
  144. (Linux)
  145. basedev=$tgt
  146. part=${basedev}1
  147. match=\'${basedev}\''+([0-9])'
  148. function mount_ext2fs {
  149. mount -t ext2 "$1" "$2"
  150. }
  151. ;;
  152. }
  153. qemu-img create -f raw $tgt 524288k
  154. if stat -qs .>/dev/null 2>&1; then
  155. statcmd='stat -f %z' # BSD stat (or so we assume)
  156. else
  157. statcmd='stat -c %s' # GNU stat
  158. fi
  159. dksz=$(($($statcmd "$tgt")*2))
  160. heads=64
  161. secs=32
  162. (( cyls = dksz / heads / secs ))
  163. if (( cyls < (cfgfs + 2) )); then
  164. print -u2 "Size of $tgt is $dksz, this looks fishy?"
  165. exit 1
  166. fi
  167. if ! T=$(mktemp -d /tmp/openadk.XXXXXXXXXX); then
  168. print -u2 Error creating temporary directory.
  169. exit 1
  170. fi
  171. tar -xOzf "$src" usr/share/grub-bin/core.img >"$T/core.img"
  172. integer coreimgsz=$($statcmd "$T/core.img")
  173. if (( coreimgsz < 1024 )); then
  174. print -u2 core.img is probably too small: $coreimgsz
  175. rm -rf "$T"
  176. exit 1
  177. fi
  178. if (( coreimgsz > 65024 )); then
  179. print -u2 core.img is larger than 64K-512: $coreimgsz
  180. rm -rf "$T"
  181. exit 1
  182. fi
  183. (( coreendsec = (coreimgsz + 511) / 512 ))
  184. if [[ $basedev = /dev/svnd+([0-9]) ]]; then
  185. # BSD svnd0 mode: protect sector #1
  186. corestartsec=2
  187. (( ++coreendsec ))
  188. corepatchofs=$((0x614))
  189. else
  190. corestartsec=1
  191. corepatchofs=$((0x414))
  192. fi
  193. # partition offset: at least coreendsec+1 but aligned on a multiple of secs
  194. (( partofs = ((coreendsec / secs) + 1) * secs ))
  195. (( quiet )) || print Preparing MBR and GRUB2...
  196. dd if=/dev/zero of="$T/firsttrack" count=$partofs 2>/dev/null
  197. echo $corestartsec $coreendsec | mksh "$TOPDIR/scripts/bootgrub.mksh" \
  198. -A -g $((cyls-cfgfs)):$heads:$secs -M 1:0x83 -O $partofs | \
  199. dd of="$T/firsttrack" conv=notrunc 2>/dev/null
  200. dd if="$T/core.img" of="$T/firsttrack" conv=notrunc seek=$corestartsec \
  201. 2>/dev/null
  202. # set partition where it can find /boot/grub
  203. print -n '\0\0\0\0' | \
  204. dd of="$T/firsttrack" conv=notrunc bs=1 seek=$corepatchofs 2>/dev/null
  205. # create cfgfs partition (mostly taken from bootgrub.mksh)
  206. set -A thecode
  207. typeset -Uui8 thecode
  208. mbrpno=0
  209. set -A g_code $cyls $heads $secs
  210. (( psz = g_code[0] * g_code[1] * g_code[2] ))
  211. (( pofs = (cyls - cfgfs) * g_code[1] * g_code[2] ))
  212. set -A o_code # g_code equivalent for partition offset
  213. (( o_code[2] = pofs % g_code[2] + 1 ))
  214. (( o_code[1] = pofs / g_code[2] ))
  215. (( o_code[0] = o_code[1] / g_code[1] + 1 ))
  216. (( o_code[1] = o_code[1] % g_code[1] + 1 ))
  217. # boot flag; C/H/S offset
  218. thecode[mbrpno++]=0x00
  219. (( thecode[mbrpno++] = o_code[1] - 1 ))
  220. (( cylno = o_code[0] > 1024 ? 1023 : o_code[0] - 1 ))
  221. (( thecode[mbrpno++] = o_code[2] | ((cylno & 0x0300) >> 2) ))
  222. (( thecode[mbrpno++] = cylno & 0x00FF ))
  223. # partition type; C/H/S end
  224. (( thecode[mbrpno++] = 0x88 ))
  225. (( thecode[mbrpno++] = g_code[1] - 1 ))
  226. (( cylno = g_code[0] > 1024 ? 1023 : g_code[0] - 1 ))
  227. (( thecode[mbrpno++] = g_code[2] | ((cylno & 0x0300) >> 2) ))
  228. (( thecode[mbrpno++] = cylno & 0x00FF ))
  229. # partition offset, size (LBA)
  230. (( thecode[mbrpno++] = pofs & 0xFF ))
  231. (( thecode[mbrpno++] = (pofs >> 8) & 0xFF ))
  232. (( thecode[mbrpno++] = (pofs >> 16) & 0xFF ))
  233. (( thecode[mbrpno++] = (pofs >> 24) & 0xFF ))
  234. (( pssz = psz - pofs ))
  235. (( thecode[mbrpno++] = pssz & 0xFF ))
  236. (( thecode[mbrpno++] = (pssz >> 8) & 0xFF ))
  237. (( thecode[mbrpno++] = (pssz >> 16) & 0xFF ))
  238. (( thecode[mbrpno++] = (pssz >> 24) & 0xFF ))
  239. # write partition table entry
  240. ostr=
  241. curptr=0
  242. while (( curptr < 16 )); do
  243. ostr=$ostr\\0${thecode[curptr++]#8#}
  244. done
  245. print -n "$ostr" | \
  246. dd of="$T/firsttrack" conv=notrunc bs=1 seek=$((0x1CE)) 2>/dev/null
  247. (( quiet )) || print Writing MBR and GRUB2 to target device...
  248. dd if="$T/firsttrack" of="$tgt"
  249. (( quiet )) || print Extracting installation archive...
  250. gzip -dc "$src" | (cd "$T"; tar -xpf -)
  251. cd "$T"
  252. rnddev=/dev/urandom
  253. [[ -c /dev/arandom ]] && rnddev=/dev/arandom
  254. dd if=$rnddev bs=16 count=1 >>etc/.rnd 2>/dev/null
  255. (( quiet )) || print Fixing up permissions...
  256. chmod 1777 tmp
  257. chmod 4755 bin/busybox
  258. [[ -f usr/bin/Xorg ]] && chmod 4755 usr/bin/Xorg
  259. [[ -f usr/bin/sudo ]] && chmod 4755 usr/bin/sudo
  260. (( quiet )) || print Configuring GRUB2 bootloader...
  261. mkdir -p boot/grub
  262. (
  263. print set default=0
  264. print set timeout=1
  265. if (( serial )); then
  266. print serial --unit=0 --speed=$speed
  267. print terminal_output serial
  268. print terminal_input serial
  269. consargs="console=ttyS0,$speed console=tty0"
  270. else
  271. print terminal_output console
  272. print terminal_input console
  273. consargs="console=tty0"
  274. fi
  275. print
  276. print 'menuentry "GNU/Linux (OpenADK)" {'
  277. linuxargs="root=/dev/sda1 $consargs"
  278. (( panicreboot )) && linuxargs="$linuxargs panic=$panicreboot"
  279. print "\tlinux /boot/kernel $linuxargs"
  280. print '}'
  281. ) >boot/grub/grub.cfg
  282. set -A grubfiles
  283. ngrubfiles=0
  284. for a in usr/lib/grub/*-pc/{*.mod,efiemu??.o,command.lst,moddep.lst,fs.lst,handler.lst,parttool.lst}; do
  285. [[ -e $a ]] && grubfiles[ngrubfiles++]=$a
  286. done
  287. cp "${grubfiles[@]}" boot/grub/
  288. cd "$TOPDIR"
  289. dd if=qemu.img of=mbr bs=64k count=1
  290. bs=$((524288-64-1))
  291. (( quiet )) || print Generating ext2 image with size $bs...
  292. dd if=/dev/zero of=cfgfs bs=1024k count=$cfgfs
  293. genext2fs -q -b $bs -d $T ${tgt}.new
  294. (( quiet )) || print Finishing up...
  295. cat mbr ${tgt}.new cfgfs > $tgt
  296. rm -rf "$T" mbr ${tgt}.new cfgfs
  297. exit 0