disable debug
[openadk.git] / scripts / install.sh
blob6d27c48541a4f0eebdac8d810f53e496cf3c13ca
1 #!/usr/bin/env bash
2 #-
3 # Copyright © 2010-2015
4 # Waldemar Brodkorb <wbx@openadk.org>
5 # Thorsten Glaser <tg@mirbsd.org>
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.
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.
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.
26 # Prepare a USB stick or CF/SD/MMC card or hard disc for installation
27 # of OpenADK
29 ADK_TOPDIR=$(pwd)
30 HOST=$(gcc -dumpmachine)
31 me=$0
33 case :$PATH: in
34 (*:$ADK_TOPDIR/host_$HOST/usr/bin:*) ;;
35 (*) export PATH=$PATH:$ADK_TOPDIR/host_$HOST/usr/bin ;;
36 esac
38 test -n "$KSH_VERSION" || exec mksh "$me" "$@"
39 if test -z "$KSH_VERSION"; then
40 echo >&2 Fatal error: could not run myself with mksh!
41 exit 255
44 ### run with mksh from here onwards ###
46 me=${me##*/}
48 if (( USER_ID )); then
49 print -u2 Installation is only possible as root!
50 exit 1
53 ADK_TOPDIR=$(realpath .)
54 ostype=$(uname -s)
56 fs=ext4
57 cfgfs=1
58 datafssz=0
59 noformat=0
60 quiet=0
61 serial=0
62 speed=115200
63 panicreboot=10
64 keep=0
66 function usage {
67 cat >&2 <<EOF
68 Syntax: $me [-f filesystem] [-c cfgfssize] [-d datafssize] [-k] [-n]
69 [-p panictime] [±q] [-s serialspeed] [±t] <target> <device> <archive>
70 Partition sizes are in MiB. Filesystem type is currently ignored (ext4).
71 To keep filesystem on data partition use -k.
72 Use -n to not format boot/root partition.
73 Defaults: -c 1 -p 10 -s 115200; -t = enable serial console
74 EOF
75 exit $1
78 while getopts "c:d:f:hknp:qs:t" ch; do
79 case $ch {
80 (c) if (( (cfgfs = OPTARG) < 0 || cfgfs > 16 )); then
81 print -u2 "$me: -c $OPTARG out of bounds"
82 exit 1
83 fi ;;
84 (d) if (( (datafssz = OPTARG) < 0 )); then
85 print -u2 "$me: -d $OPTARG out of bounds"
86 exit 1
87 fi ;;
88 (f) if [[ $OPTARG != @(ext2|ext3|ext4|xfs) ]]; then
89 print -u2 "$me: filesystem $OPTARG invalid"
90 exit 1
92 fs=$OPTARG ;;
93 (h) usage 0 ;;
94 (k) keep=1 ;;
95 (p) if (( (panicreboot = OPTARG) < 0 || panicreboot > 300 )); then
96 print -u2 "$me: -p $OPTARG out of bounds"
97 exit 1
98 fi ;;
99 (q) quiet=1 ;;
100 (+q) quiet=0 ;;
101 (s) if [[ $OPTARG != @(96|192|384|576|1152)00 ]]; then
102 print -u2 "$me: serial speed $OPTARG invalid"
103 exit 1
105 speed=$OPTARG ;;
106 (n) noformat=1 ;;
107 (t) serial=1 ;;
108 (+t) serial=0 ;;
109 (*) usage 1 ;;
111 done
112 shift $((OPTIND - 1))
114 (( $# == 3 )) || usage 1
117 case $ostype {
118 (Linux)
119 tools="bc mkfs.$fs tune2fs partprobe"
121 (Darwin)
122 tools="bc diskutil"
125 print -u2 Sorry, not ported to the OS "'$ostype'" yet.
126 exit 1
129 for tool in $tools; do
130 print -n Checking if $tool is installed...
131 if whence -p $tool >/dev/null; then
132 print " okay"
133 else
134 print " failed"
137 done
138 (( f )) && exit 1
140 target=$1
141 tgt=$2
142 src=$3
144 case $target {
145 (banana-pro|raspberry-pi|raspberry-pi2|solidrun-imx6|default) ;;
147 print -u2 "Unknown target '$target', exiting"
148 exit 1 ;;
150 if [[ ! -b $tgt ]]; then
151 print -u2 "'$tgt' is not a block device, exiting"
152 exit 1
154 if [[ ! -f $src ]]; then
155 print -u2 "'$src' is not a file, exiting"
156 exit 1
158 (( quiet )) || print "Installing $src on $tgt."
160 case $ostype {
161 (Darwin)
162 R=/Volumes/ADKROOT; diskutil unmount $R
163 B=/Volumes/ADKBOOT; diskutil unmount $B
164 D=/Volumes/ADKDATA; diskutil unmount $D
165 basedev=$tgt
166 rootpart=${basedev}s1
167 datapart=${basedev}s2
168 if [[ $target = raspberry-pi || $target = raspberry-pi2 ]]; then
169 bootpart=${basedev}s1
170 rootpart=${basedev}s2
171 datapart=${basedev}s3
173 match=\'${basedev}\''?(s+([0-9]))'
174 function mount_fs {
176 function umount_fs {
177 diskutil unmount "$1"
179 function create_fs {
180 if [[ $3 = ext4 ]]; then
181 fstype=UFSD_EXTFS4
183 if [[ $3 = vfat ]]; then
184 fstype=fat32
186 diskutil eraseVolume $fstype "$2" "$1"
188 function tune_fs {
191 (Linux)
192 basedev=$tgt
193 rootpart=${basedev}1
194 datapart=${basedev}2
195 if [[ $target = raspberry-pi || $target = raspberry-pi2 ]]; then
196 bootpart=${basedev}1
197 rootpart=${basedev}2
198 datapart=${basedev}3
201 match=\'${basedev}\''+([0-9])'
202 function mount_fs {
203 mount -t "$3" "$1" "$2"
205 function umount_fs {
206 umount "$1"
208 function create_fs {
209 (( quiet )) || print "Creating filesystem on ${1}..."
210 partprobe $tgt
211 mkfs.$3 "$1"
213 function tune_fs {
214 tune2fs -c 0 -i 0 "$1"
219 mount |&
220 while read -p dev rest; do
221 eval [[ \$dev = $match ]] || continue
222 print -u2 "Block device $tgt is in use, please umount first."
223 exit 1
224 done
226 if (( !quiet )); then
227 print "WARNING: This will overwrite $basedev - type Yes to continue!"
228 read x
229 [[ $x = Yes ]] || exit 0
232 if ! T=$(mktemp -d /tmp/openadk.XXXXXXXXXX); then
233 print -u2 Error creating temporary directory.
234 exit 1
236 if [[ $ostype != Darwin ]]; then
237 R=$T/rootmnt
238 B=$T/bootmnt
239 D=$T/datamnt
240 mkdir -p "$R" "$B" "$D"
243 # get disk size
244 dksz=$(dkgetsz "$tgt")
246 # partition layouts:
247 # n̲a̲m̲e̲ p̲a̲r̲t̲#̲0̲ p̲̲a̲r̲t̲#̲1̲ p̲̲a̲r̲t̲#̲2̲ p̲̲a̲r̲t̲#̲3̲
248 # default: 0x83(system) 0x83(?data) -(unused) 0x88(cfgfs)
249 # raspberry: 0x0B(boot) 0x83(system) 0x83(?data) 0x88(cfgfs)
251 syspartno=0
253 # sizes:
254 # boot(raspberry) - fixed (100 MiB)
255 # cfgfs - fixed (parameter, max. 16 MiB)
256 # data - flexible (parameter)
257 # system - everything else
259 if [[ $target = raspberry-pi || $target = raspberry-pi2 ]]; then
260 syspartno=1
261 bootfssz=100
262 if (( grub )); then
263 print -u2 "Cannot combine GRUB with $target"
264 rm -rf "$T"
265 exit 1
267 else
268 bootfssz=0
271 heads=64
272 secs=32
273 (( cyls = dksz / heads / secs ))
274 if (( cyls < (bootfssz + cfgfs + datafssz + 2) )); then
275 print -u2 "Size of $tgt is $dksz, this looks fishy?"
276 rm -rf "$T"
277 exit 1
280 if stat -qs .>/dev/null 2>&1; then
281 statcmd='stat -f %z' # BSD stat (or so we assume)
282 else
283 statcmd='stat -c %s' # GNU stat
286 if (( grub )); then
287 tar -xOzf "$src" boot/grub/core.img >"$T/core.img"
288 integer coreimgsz=$($statcmd "$T/core.img")
289 else
290 coreimgsz=65024
292 if (( coreimgsz < 1024 )); then
293 print -u2 core.img is probably too small: $coreimgsz
294 rm -rf "$T"
295 exit 1
297 if (( coreimgsz > 65024 )); then
298 print -u2 core.img is larger than 64K-512: $coreimgsz
299 rm -rf "$T"
300 exit 1
302 (( coreendsec = (coreimgsz + 511) / 512 ))
303 if [[ $basedev = /dev/svnd+([0-9]) ]]; then
304 # BSD svnd0 mode: protect sector #1
305 corestartsec=2
306 (( ++coreendsec ))
307 corepatchofs=$((0x614))
308 else
309 corestartsec=1
310 corepatchofs=$((0x414))
312 # partition offset: at least coreendsec+1 but aligned on a multiple of secs
313 #(( partofs = ((coreendsec / secs) + 1) * secs ))
314 # we just use 2048 all the time, since some loaders are longer
315 partofs=2048
316 if [[ $target = raspberry-pi || $target = raspberry-pi2 ]]; then
317 (( spartofs = partofs + (100 * 2048) ))
318 else
319 spartofs=$partofs
322 (( quiet )) || if (( grub )); then
323 print Preparing MBR and GRUB2...
324 else
325 print Preparing MBR...
327 dd if=/dev/zero of="$T/firsttrack" count=$partofs 2>/dev/null
328 # add another MiB to clear the first partition
329 dd if=/dev/zero bs=1048576 count=1 >>"$T/firsttrack" 2>/dev/null
330 echo $corestartsec $coreendsec | mksh "$ADK_TOPDIR/scripts/bootgrub.mksh" \
331 -A -g $((cyls - bootfssz - cfgfs - datafssz)):$heads:$secs -M 1:0x83 \
332 -O $spartofs | dd of="$T/firsttrack" conv=notrunc 2>/dev/null
333 (( grub )) && dd if="$T/core.img" of="$T/firsttrack" conv=notrunc \
334 seek=$corestartsec 2>/dev/null
335 # set partition where it can find /boot/grub
336 (( grub )) && print -n '\0\0\0\0' | \
337 dd of="$T/firsttrack" conv=notrunc bs=1 seek=$corepatchofs 2>/dev/null
339 # create cfgfs partition (mostly taken from bootgrub.mksh)
340 set -A thecode
341 typeset -Uui8 thecode
342 mbrpno=0
343 set -A g_code $cyls $heads $secs
344 (( psz = g_code[0] * g_code[1] * g_code[2] ))
345 (( pofs = (cyls - cfgfs) * g_code[1] * g_code[2] ))
346 set -A o_code # g_code equivalent for partition offset
347 (( o_code[2] = pofs % g_code[2] + 1 ))
348 (( o_code[1] = pofs / g_code[2] ))
349 (( o_code[0] = o_code[1] / g_code[1] + 1 ))
350 (( o_code[1] = o_code[1] % g_code[1] + 1 ))
351 # boot flag; C/H/S offset
352 thecode[mbrpno++]=0x00
353 (( thecode[mbrpno++] = o_code[1] - 1 ))
354 (( cylno = o_code[0] > 1024 ? 1023 : o_code[0] - 1 ))
355 (( thecode[mbrpno++] = o_code[2] | ((cylno & 0x0300) >> 2) ))
356 (( thecode[mbrpno++] = cylno & 0x00FF ))
357 # partition type; C/H/S end
358 (( thecode[mbrpno++] = 0x88 ))
359 (( thecode[mbrpno++] = g_code[1] - 1 ))
360 (( cylno = g_code[0] > 1024 ? 1023 : g_code[0] - 1 ))
361 (( thecode[mbrpno++] = g_code[2] | ((cylno & 0x0300) >> 2) ))
362 (( thecode[mbrpno++] = cylno & 0x00FF ))
363 # partition offset, size (LBA)
364 (( thecode[mbrpno++] = pofs & 0xFF ))
365 (( thecode[mbrpno++] = (pofs >> 8) & 0xFF ))
366 (( thecode[mbrpno++] = (pofs >> 16) & 0xFF ))
367 (( thecode[mbrpno++] = (pofs >> 24) & 0xFF ))
368 (( pssz = psz - pofs ))
369 (( thecode[mbrpno++] = pssz & 0xFF ))
370 (( thecode[mbrpno++] = (pssz >> 8) & 0xFF ))
371 (( thecode[mbrpno++] = (pssz >> 16) & 0xFF ))
372 (( thecode[mbrpno++] = (pssz >> 24) & 0xFF ))
373 # write partition table entry
374 ostr=
375 curptr=0
376 while (( curptr < 16 )); do
377 ostr=$ostr\\0${thecode[curptr++]#8#}
378 done
379 print -n "$ostr" | \
380 dd of="$T/firsttrack" conv=notrunc bs=1 seek=$((0x1EE)) 2>/dev/null
382 if (( datafssz )); then
383 # create data partition (copy of the above :)
384 set -A thecode
385 typeset -Uui8 thecode
386 mbrpno=0
387 set -A g_code $cyls $heads $secs
388 (( psz = (cyls - cfgfs) * g_code[1] * g_code[2] ))
389 (( pofs = (cyls - cfgfs - datafssz) * g_code[1] * g_code[2] ))
390 set -A o_code # g_code equivalent for partition offset
391 (( o_code[2] = pofs % g_code[2] + 1 ))
392 (( o_code[1] = pofs / g_code[2] ))
393 (( o_code[0] = o_code[1] / g_code[1] + 1 ))
394 (( o_code[1] = o_code[1] % g_code[1] + 1 ))
395 # boot flag; C/H/S offset
396 thecode[mbrpno++]=0x00
397 (( thecode[mbrpno++] = o_code[1] - 1 ))
398 (( cylno = o_code[0] > 1024 ? 1023 : o_code[0] - 1 ))
399 (( thecode[mbrpno++] = o_code[2] | ((cylno & 0x0300) >> 2) ))
400 (( thecode[mbrpno++] = cylno & 0x00FF ))
401 # partition type; C/H/S end
402 (( thecode[mbrpno++] = 0x83 ))
403 (( thecode[mbrpno++] = g_code[1] - 1 ))
404 (( cylno = (g_code[0] - cfgfs) > 1024 ? 1023 : g_code[0] - cfgfs - 1 ))
405 (( thecode[mbrpno++] = g_code[2] | ((cylno & 0x0300) >> 2) ))
406 (( thecode[mbrpno++] = cylno & 0x00FF ))
407 # partition offset, size (LBA)
408 (( thecode[mbrpno++] = pofs & 0xFF ))
409 (( thecode[mbrpno++] = (pofs >> 8) & 0xFF ))
410 (( thecode[mbrpno++] = (pofs >> 16) & 0xFF ))
411 (( thecode[mbrpno++] = (pofs >> 24) & 0xFF ))
412 (( pssz = psz - pofs ))
413 (( thecode[mbrpno++] = pssz & 0xFF ))
414 (( thecode[mbrpno++] = (pssz >> 8) & 0xFF ))
415 (( thecode[mbrpno++] = (pssz >> 16) & 0xFF ))
416 (( thecode[mbrpno++] = (pssz >> 24) & 0xFF ))
417 # write partition table entry
418 ostr=
419 curptr=0
420 while (( curptr < 16 )); do
421 ostr=$ostr\\0${thecode[curptr++]#8#}
422 done
423 print -n "$ostr" | \
424 dd of="$T/firsttrack" conv=notrunc bs=1 seek=$((0x1CE)) 2>/dev/null
427 if [[ $target = raspberry-pi || $target = raspberry-pi2 ]]; then
428 # move system and data partition from #0/#1 to #1/#2
429 dd if="$T/firsttrack" bs=1 skip=$((0x1BE)) count=32 of="$T/x" 2>/dev/null
430 dd of="$T/firsttrack" conv=notrunc bs=1 seek=$((0x1CE)) if="$T/x" 2>/dev/null
431 # create boot partition (copy of the above :)
432 set -A thecode
433 typeset -Uui8 thecode
434 mbrpno=0
435 set -A g_code $cyls $heads $secs
436 psz=$spartofs
437 pofs=$partofs
438 set -A o_code # g_code equivalent for partition offset
439 (( o_code[2] = pofs % g_code[2] + 1 ))
440 (( o_code[1] = pofs / g_code[2] ))
441 (( o_code[0] = o_code[1] / g_code[1] + 1 ))
442 (( o_code[1] = o_code[1] % g_code[1] + 1 ))
443 # boot flag; C/H/S offset
444 thecode[mbrpno++]=0x00
445 (( thecode[mbrpno++] = o_code[1] - 1 ))
446 (( cylno = o_code[0] > 1024 ? 1023 : o_code[0] - 1 ))
447 (( thecode[mbrpno++] = o_code[2] | ((cylno & 0x0300) >> 2) ))
448 (( thecode[mbrpno++] = cylno & 0x00FF ))
449 # partition type; C/H/S end
450 (( thecode[mbrpno++] = 0x0B ))
451 (( thecode[mbrpno++] = g_code[1] - 1 ))
452 (( cylno = (spartofs / 2048) > 1024 ? 1023 : (spartofs / 2048) - 1 ))
453 (( thecode[mbrpno++] = g_code[2] | ((cylno & 0x0300) >> 2) ))
454 (( thecode[mbrpno++] = cylno & 0x00FF ))
455 # partition offset, size (LBA)
456 (( thecode[mbrpno++] = pofs & 0xFF ))
457 (( thecode[mbrpno++] = (pofs >> 8) & 0xFF ))
458 (( thecode[mbrpno++] = (pofs >> 16) & 0xFF ))
459 (( thecode[mbrpno++] = (pofs >> 24) & 0xFF ))
460 (( pssz = psz - pofs ))
461 (( thecode[mbrpno++] = pssz & 0xFF ))
462 (( thecode[mbrpno++] = (pssz >> 8) & 0xFF ))
463 (( thecode[mbrpno++] = (pssz >> 16) & 0xFF ))
464 (( thecode[mbrpno++] = (pssz >> 24) & 0xFF ))
465 # write partition table entry
466 ostr=
467 curptr=0
468 while (( curptr < 16 )); do
469 ostr=$ostr\\0${thecode[curptr++]#8#}
470 done
471 print -n "$ostr" | \
472 dd of="$T/firsttrack" conv=notrunc bs=1 seek=$((0x1BE)) 2>/dev/null
475 # disk signature
476 rnddev=/dev/urandom
477 [[ -c /dev/arandom ]] && rnddev=/dev/arandom
478 dd if=$rnddev bs=4 count=1 2>/dev/null | \
479 dd of="$T/firsttrack" conv=notrunc bs=1 seek=$((0x1B8)) 2>/dev/null
480 print -n '\0\0' | \
481 dd of="$T/firsttrack" conv=notrunc bs=1 seek=$((0x1BC)) 2>/dev/null
482 partuuid=$(dd if="$T/firsttrack" bs=1 count=4 skip=$((0x1B8)) 2>/dev/null | \
483 hexdump -e '1/4 "%08x"')-0$((syspartno+1))
485 ((keep)) || if (( datafssz )); then
486 (( quiet )) || print Cleaning out data partition...
487 dd if=/dev/zero of="$tgt" bs=1048576 count=1 seek=$((cyls - cfgfs - datafssz)) > /dev/null 2>&1
489 (( quiet )) || print Cleaning out root partition...
490 dd if=/dev/zero bs=1048576 of="$tgt" count=1 seek=$((spartofs / 2048)) > /dev/null 2>&1
492 (( quiet )) || if (( grub )); then
493 print Writing MBR and GRUB2 to target device... system PARTUUID=$partuuid
494 else
495 print Writing MBR to target device... system PARTUUID=$partuuid
497 dd if="$T/firsttrack" of="$tgt" > /dev/null 2>&1
499 fwdir=$(dirname "$src")
501 case $target {
502 (banana-pro)
503 dd if="$fwdir/u-boot-sunxi-with-spl.bin" of="$tgt" bs=1024 seek=8 > /dev/null 2>&1
505 (solidrun-imx6)
506 dd if="$fwdir/SPL" of="$tgt" bs=1024 seek=1 > /dev/null 2>&1
507 dd if="$fwdir/u-boot.img" of="$tgt" bs=1024 seek=42 > /dev/null 2>&1
509 (raspberry-pi|raspberry-pi2)
510 (( noformat )) || create_fs "$bootpart" ADKBOOT vfat
514 (( noformat )) || create_fs "$rootpart" ADKROOT ext4
515 (( noformat )) || tune_fs "$rootpart"
517 (( quiet )) || print Extracting installation archive...
518 mount_fs "$rootpart" "$R" ext4
519 xz -dc "$src" | (cd "$R"; tar -xpf -)
521 if (( datafssz )); then
522 mkdir -m0755 "$R"/data
523 ((keep)) || create_fs "$datapart" ADKDATA ext4
524 ((keep)) || tune_fs "$datapart"
525 case $target {
526 (raspberry-pi|raspberry-pi2)
527 echo "/dev/mmcblk0p3 /data ext4 rw 0 0" >> "$R"/etc/fstab
529 (banana-pro|solidrun-imx6)
530 echo "/dev/mmcblk0p2 /data ext4 rw 0 0" >> "$R"/etc/fstab
535 case $target {
536 (raspberry-pi|raspberry-pi2)
537 mount_fs "$bootpart" "$B" vfat
538 for x in "$R"/boot/*; do
539 [[ -e "$x" ]] && mv -f "$R"/boot/* "$B/"
540 break
541 done
542 for x in "$fwdir"/*.dtb; do
543 [[ -e "$x" ]] && cp "$fwdir"/*.dtb "$B/"
544 break
545 done
546 mkdir "$B/"overlays
547 for x in "$B/"*-overlay.dtb; do
548 [[ -e "$x" ]] && mv "$B/"*-overlay.dtb "$B/"overlays
549 break
550 done
551 umount_fs "$B"
553 (solidrun-imx6)
554 for x in "$fwdir"/*.dtb; do
555 [[ -e "$x" ]] && cp "$fwdir"/*.dtb "$R/boot/"
556 break
557 done
561 cd "$R"
562 dd if=$rnddev bs=16 count=1 >>etc/.rnd 2>/dev/null
563 (( quiet )) || print Fixing up permissions...
564 chown 0:0 tmp
565 chmod 1777 tmp
566 [[ -f usr/bin/sudo ]] && chmod 4755 usr/bin/sudo
568 if (( grub )); then
569 (( quiet )) || print Configuring GRUB2 bootloader...
570 mkdir -p boot/grub
572 print set default=0
573 print set timeout=1
574 if (( serial )); then
575 print serial --unit=0 --speed=$speed
576 print terminal_output serial
577 print terminal_input serial
578 consargs="console=ttyS0,$speed console=tty0"
579 else
580 print terminal_output console
581 print terminal_input console
582 consargs="console=tty0"
584 print
585 print 'menuentry "GNU/Linux (OpenADK)" {'
586 linuxargs="root=PARTUUID=$partuuid $consargs"
587 (( panicreboot )) && linuxargs="$linuxargs panic=$panicreboot"
588 print "\tlinux /boot/kernel $linuxargs"
589 print '}'
590 ) >boot/grub/grub.cfg
593 (( quiet )) || print Finishing up...
594 cd "$ADK_TOPDIR"
595 umount_fs "$R"
596 rm -rf "$T"
597 exit 0