install.sh 9.8 KB

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