install.sh 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. #!/usr/bin/env bash
  2. #-
  3. # Copyright © 2010, 2011
  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. # Prepare a USB stick or CF/SD/MMC card or hard disc for installation
  27. # of OpenADK:
  28. # • install a Master Boot Record containing a MirBSD PBR loading GRUB
  29. # • write GRUB2 core.img just past the MBR
  30. # • create a root partition with ext2fs and extract the OpenADK image
  31. # just built there
  32. # • create a cfgfs partition
  33. TOPDIR=$(pwd)
  34. me=$0
  35. case :$PATH: in
  36. (*:$TOPDIR/bin/tools:*) ;;
  37. (*) export PATH=$PATH:$TOPDIR/bin/tools ;;
  38. esac
  39. test -n "$KSH_VERSION" || if ! which mksh >/dev/null 2>&1; then
  40. make package=mksh fetch || exit 1
  41. df=$(cd package/mksh; TOPDIR="$TOPDIR" gmake show=DISTFILES)
  42. mkdir -p build_mksh
  43. gzip -dc dl/"$df" | (cd build_mksh; cpio -mid)
  44. cd build_mksh/mksh
  45. bash Build.sh -r || exit 1
  46. cp mksh "$TOPDIR"/bin/tools/
  47. cd "$TOPDIR"
  48. rm -rf build_mksh
  49. fi
  50. test -n "$KSH_VERSION" || exec mksh "$me" "$@"
  51. if test -z "$KSH_VERSION"; then
  52. echo >&2 Fatal error: could not run myself with mksh!
  53. exit 255
  54. fi
  55. ### run with mksh from here onwards ###
  56. me=${me##*/}
  57. if (( USER_ID )); then
  58. print -u2 Installation is only possible as root!
  59. exit 1
  60. fi
  61. TOPDIR=$(realpath .)
  62. ostype=$(uname -s)
  63. cfgfs=1
  64. noformat=0
  65. quiet=0
  66. serial=0
  67. speed=115200
  68. panicreboot=10
  69. function usage {
  70. cat >&2 <<EOF
  71. Syntax: $me [-c cfgfssize] [-p panictime] [±q] [-s serialspeed]
  72. [±t] -n /dev/sdb image
  73. Defaults: -c 1 -p 10 -s 115200; -t = enable serial console
  74. EOF
  75. exit $1
  76. }
  77. while getopts "c:hp:qs:nt" ch; do
  78. case $ch {
  79. (c) if (( (cfgfs = OPTARG) < 0 || cfgfs > 5 )); then
  80. print -u2 "$me: -c $OPTARG out of bounds"
  81. exit 1
  82. fi ;;
  83. (h) usage 0 ;;
  84. (p) if (( (panicreboot = OPTARG) < 0 || panicreboot > 300 )); then
  85. print -u2 "$me: -p $OPTARG out of bounds"
  86. exit 1
  87. fi ;;
  88. (q) quiet=1 ;;
  89. (+q) quiet=0 ;;
  90. (s) if [[ $OPTARG != @(96|192|384|576|1152)00 ]]; then
  91. print -u2 "$me: serial speed $OPTARG invalid"
  92. exit 1
  93. fi
  94. speed=$OPTARG ;;
  95. (n) noformat=1 ;;
  96. (t) serial=1 ;;
  97. (+t) serial=0 ;;
  98. (*) usage 1 ;;
  99. }
  100. done
  101. shift $((OPTIND - 1))
  102. (( $# == 2 )) || usage 1
  103. f=0
  104. tools='mke2fs tune2fs'
  105. case $ostype {
  106. (DragonFly|*BSD*)
  107. ;;
  108. (Darwin)
  109. tools="$tools fuse-ext2"
  110. ;;
  111. (Linux)
  112. ;;
  113. (*)
  114. print -u2 Sorry, not ported to the OS "'$ostype'" yet.
  115. exit 1
  116. ;;
  117. }
  118. for tool in $tools; do
  119. print -n Checking if $tool is installed...
  120. if whence -p $tool >/dev/null; then
  121. print " okay"
  122. else
  123. print " failed"
  124. f=1
  125. fi
  126. done
  127. (( f )) && exit 1
  128. tgt=$1
  129. src=$2
  130. if [[ ! -b $tgt ]]; then
  131. print -u2 "'$tgt' is not a block device, exiting"
  132. exit 1
  133. fi
  134. if [[ ! -f $src ]]; then
  135. print -u2 "'$src' is not a file, exiting"
  136. exit 1
  137. fi
  138. (( quiet )) || print "Installing $src on $tgt."
  139. case $ostype {
  140. (DragonFly|*BSD*)
  141. basedev=${tgt%c}
  142. tgt=${basedev}c
  143. part=${basedev}i
  144. match=\'${basedev}\''[a-p]'
  145. function mount_ext2fs {
  146. mount -t ext2fs "$1" "$2"
  147. }
  148. ;;
  149. (Darwin)
  150. basedev=$tgt
  151. part=${basedev}s1
  152. match=\'${basedev}\''?(s+([0-9]))'
  153. function mount_ext2fs {
  154. fuse-ext2 "$1" "$2" -o rw+
  155. sleep 3
  156. }
  157. ;;
  158. (Linux)
  159. basedev=$tgt
  160. part=${basedev}1
  161. match=\'${basedev}\''+([0-9])'
  162. function mount_ext2fs {
  163. mount -t ext2 "$1" "$2"
  164. }
  165. ;;
  166. }
  167. mount |&
  168. while read -p dev rest; do
  169. eval [[ \$dev = $match ]] || continue
  170. print -u2 "Block device $tgt is in use, please umount first."
  171. exit 1
  172. done
  173. if (( !quiet )); then
  174. print "WARNING: This will overwrite $basedev - type Yes to continue!"
  175. read x
  176. [[ $x = Yes ]] || exit 0
  177. fi
  178. dksz=$(dkgetsz "$tgt")
  179. heads=64
  180. secs=32
  181. (( cyls = dksz / heads / secs ))
  182. if (( cyls < (cfgfs + 2) )); then
  183. print -u2 "Size of $tgt is $dksz, this looks fishy?"
  184. exit 1
  185. fi
  186. if stat -qs .>/dev/null 2>&1; then
  187. statcmd='stat -f %z' # BSD stat (or so we assume)
  188. else
  189. statcmd='stat -c %s' # GNU stat
  190. fi
  191. if ! T=$(mktemp -d /tmp/openadk.XXXXXXXXXX); then
  192. print -u2 Error creating temporary directory.
  193. exit 1
  194. fi
  195. tar -xOzf "$src" usr/share/grub-bin/core.img >"$T/core.img"
  196. integer coreimgsz=$($statcmd "$T/core.img")
  197. if (( coreimgsz < 1024 )); then
  198. print -u2 core.img is probably too small: $coreimgsz
  199. rm -rf "$T"
  200. exit 1
  201. fi
  202. if (( coreimgsz > 65024 )); then
  203. print -u2 core.img is larger than 64K-512: $coreimgsz
  204. rm -rf "$T"
  205. exit 1
  206. fi
  207. (( coreendsec = (coreimgsz + 511) / 512 ))
  208. if [[ $basedev = /dev/svnd+([0-9]) ]]; then
  209. # BSD svnd0 mode: protect sector #1
  210. corestartsec=2
  211. (( ++coreendsec ))
  212. corepatchofs=$((0x614))
  213. else
  214. corestartsec=1
  215. corepatchofs=$((0x414))
  216. fi
  217. # partition offset: at least coreendsec+1 but aligned on a multiple of secs
  218. (( partofs = ((coreendsec / secs) + 1) * secs ))
  219. (( quiet )) || print Preparing MBR and GRUB2...
  220. dd if=/dev/zero of="$T/firsttrack" count=$partofs 2>/dev/null
  221. echo $corestartsec $coreendsec | mksh "$TOPDIR/scripts/bootgrub.mksh" \
  222. -A -g $((cyls-cfgfs)):$heads:$secs -M 1:0x83 -O $partofs | \
  223. dd of="$T/firsttrack" conv=notrunc 2>/dev/null
  224. dd if="$T/core.img" of="$T/firsttrack" conv=notrunc seek=$corestartsec \
  225. 2>/dev/null
  226. # set partition where it can find /boot/grub
  227. print -n '\0\0\0\0' | \
  228. dd of="$T/firsttrack" conv=notrunc bs=1 seek=$corepatchofs 2>/dev/null
  229. # create cfgfs partition (mostly taken from bootgrub.mksh)
  230. set -A thecode
  231. typeset -Uui8 thecode
  232. mbrpno=0
  233. set -A g_code $cyls $heads $secs
  234. (( psz = g_code[0] * g_code[1] * g_code[2] ))
  235. (( pofs = (cyls - cfgfs) * g_code[1] * g_code[2] ))
  236. set -A o_code # g_code equivalent for partition offset
  237. (( o_code[2] = pofs % g_code[2] + 1 ))
  238. (( o_code[1] = pofs / g_code[2] ))
  239. (( o_code[0] = o_code[1] / g_code[1] + 1 ))
  240. (( o_code[1] = o_code[1] % g_code[1] + 1 ))
  241. # boot flag; C/H/S offset
  242. thecode[mbrpno++]=0x00
  243. (( thecode[mbrpno++] = o_code[1] - 1 ))
  244. (( cylno = o_code[0] > 1024 ? 1023 : o_code[0] - 1 ))
  245. (( thecode[mbrpno++] = o_code[2] | ((cylno & 0x0300) >> 2) ))
  246. (( thecode[mbrpno++] = cylno & 0x00FF ))
  247. # partition type; C/H/S end
  248. (( thecode[mbrpno++] = 0x88 ))
  249. (( thecode[mbrpno++] = g_code[1] - 1 ))
  250. (( cylno = g_code[0] > 1024 ? 1023 : g_code[0] - 1 ))
  251. (( thecode[mbrpno++] = g_code[2] | ((cylno & 0x0300) >> 2) ))
  252. (( thecode[mbrpno++] = cylno & 0x00FF ))
  253. # partition offset, size (LBA)
  254. (( thecode[mbrpno++] = pofs & 0xFF ))
  255. (( thecode[mbrpno++] = (pofs >> 8) & 0xFF ))
  256. (( thecode[mbrpno++] = (pofs >> 16) & 0xFF ))
  257. (( thecode[mbrpno++] = (pofs >> 24) & 0xFF ))
  258. (( pssz = psz - pofs ))
  259. (( thecode[mbrpno++] = pssz & 0xFF ))
  260. (( thecode[mbrpno++] = (pssz >> 8) & 0xFF ))
  261. (( thecode[mbrpno++] = (pssz >> 16) & 0xFF ))
  262. (( thecode[mbrpno++] = (pssz >> 24) & 0xFF ))
  263. # write partition table entry
  264. ostr=
  265. curptr=0
  266. while (( curptr < 16 )); do
  267. ostr=$ostr\\0${thecode[curptr++]#8#}
  268. done
  269. print -n "$ostr" | \
  270. dd of="$T/firsttrack" conv=notrunc bs=1 seek=$((0x1CE)) 2>/dev/null
  271. (( quiet )) || print Writing MBR and GRUB2 to target device...
  272. dd if="$T/firsttrack" of="$tgt"
  273. if [[ $basedev = /dev/svnd+([0-9]) ]]; then
  274. (( quiet )) || print "Creating BSD disklabel on target device..."
  275. # c: whole device (must be so)
  276. # i: ext2fs (matching first partition)
  277. # j: cfgfs (matching second partition)
  278. # p: MBR and GRUB2 area (by tradition)
  279. cat >"$T/bsdlabel" <<-EOF
  280. type: vnd
  281. disk: vnd device
  282. label: OpenADK
  283. flags:
  284. bytes/sector: 512
  285. sectors/track: $secs
  286. tracks/cylinder: $heads
  287. sectors/cylinder: $((heads * secs))
  288. cylinders: $cyls
  289. total sectors: $((cyls * heads * secs))
  290. rpm: 3600
  291. interleave: 1
  292. trackskew: 0
  293. cylinderskew: 0
  294. headswitch: 0
  295. track-to-track seek: 0
  296. drivedata: 0
  297. 16 partitions:
  298. c: $((cyls * heads * secs)) 0 unused
  299. i: $(((cyls - cfgfs) * heads * secs - partofs)) $partofs ext2fs
  300. j: $((cfgfs * heads * secs)) $(((cyls - cfgfs) * heads * secs)) unknown
  301. p: $partofs 0 unknown
  302. EOF
  303. disklabel -R ${basedev#/dev/} "$T/bsdlabel"
  304. fi
  305. (( quiet )) || print "Creating ext2fs on ${part}..."
  306. q=
  307. (( quiet )) && q=-q
  308. (( noformat )) || mke2fs $q "$part"
  309. partuuid=$(tune2fs -l "$part" | sed -n '/^Filesystem UUID:[ ]*/s///p')
  310. (( noformat )) || tune2fs -c 0 -i 0 "$part"
  311. (( quiet )) || print Extracting installation archive...
  312. mount_ext2fs "$part" "$T"
  313. gzip -dc "$src" | (cd "$T"; tar -xvpf -)
  314. cd "$T"
  315. rnddev=/dev/urandom
  316. [[ -c /dev/arandom ]] && rnddev=/dev/arandom
  317. dd if=$rnddev bs=16 count=1 >>etc/.rnd 2>/dev/null
  318. (( quiet )) || print Fixing up permissions...
  319. chown 0:0 tmp
  320. chmod 1777 tmp
  321. chmod 4755 bin/busybox
  322. [[ -f usr/bin/Xorg ]] && chmod 4755 usr/bin/Xorg
  323. [[ -f usr/bin/sudo ]] && chmod 4755 usr/bin/sudo
  324. (( quiet )) || print Configuring GRUB2 bootloader...
  325. mkdir -p boot/grub
  326. (
  327. print set default=0
  328. print set timeout=1
  329. if (( serial )); then
  330. print serial --unit=0 --speed=$speed
  331. print terminal_output serial
  332. print terminal_input serial
  333. consargs="console=ttyS0,$speed console=tty0"
  334. else
  335. print terminal_output console
  336. print terminal_input console
  337. consargs="console=tty0"
  338. fi
  339. print
  340. print 'menuentry "GNU/Linux (OpenADK)" {'
  341. linuxargs="root=UUID=$partuuid $consargs"
  342. (( panicreboot )) && linuxargs="$linuxargs panic=$panicreboot"
  343. print "\tlinux /boot/kernel $linuxargs"
  344. print '}'
  345. ) >boot/grub/grub.cfg
  346. set -A grubfiles
  347. ngrubfiles=0
  348. for a in usr/lib/grub/*-pc/{*.mod,efiemu??.o,command.lst,moddep.lst,fs.lst,handler.lst,parttool.lst}; do
  349. [[ -e $a ]] && grubfiles[ngrubfiles++]=$a
  350. done
  351. cp "${grubfiles[@]}" boot/grub/
  352. (( quiet )) || print Finishing up...
  353. cd "$TOPDIR"
  354. umount "$T"
  355. (( quiet )) || print "\nNote: the rootfs UUID is: $partuuid"
  356. rm -rf "$T"
  357. exit 0