123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- #!/usr/bin/env bash
- #-
- # Copyright © 2010, 2011, 2012
- # Thorsten Glaser <tg@mirbsd.org>
- # Copyright © 2010-2024
- # Waldemar Brodkorb <wbx@openadk.org>
- #
- # Provided that these terms and disclaimer and all copyright notices
- # are retained or reproduced in an accompanying document, permission
- # is granted to deal in this work without restriction, including un‐
- # limited rights to use, publicly perform, distribute, sell, modify,
- # merge, give away, or sublicence.
- #
- # This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
- # the utmost extent permitted by applicable law, neither express nor
- # implied; without malicious intent or gross negligence. In no event
- # may a licensor, author or contributor be held liable for indirect,
- # direct, other damage, loss, or other issues arising in any way out
- # of dealing in the work, even if advised of the possibility of such
- # damage or existence of a defect, except proven that it results out
- # of said person’s immediate fault when using the work as intended.
- #
- # Alternatively, this work may be distributed under the Terms of the
- # General Public License, any version as published by the Free Soft‐
- # ware Foundation.
- #-
- # Create a hard disc image, bootable using GNU GRUB2, with an ext2fs
- # root partition and an OpenADK cfgfs partition.
- ADK_TOPDIR=$(pwd)
- HOST=$(gcc -dumpmachine)
- me=$0
- case :$PATH: in
- (*:$ADK_TOPDIR/host_$HOST/usr/bin:*) ;;
- (*) export PATH=$PATH:$ADK_TOPDIR/host_$HOST/usr/bin ;;
- esac
- test -n "$KSH_VERSION" || exec mksh "$me" "$@"
- if test -z "$KSH_VERSION"; then
- echo >&2 Fatal error: could not run myself with mksh!
- exit 255
- fi
- ### run with mksh from here onwards ###
- me=${me##*/}
- ADK_TOPDIR=$(realpath .)
- ostype=$(uname -s)
- function usage {
- cat >&2 <<EOF
- Syntax: $me [-c cfgfssize] [+g] [-i imagesize] [-p panictime]
- [-s serialspeed] [-t] [-T imagetype] [+U] target.ima source.tgz
- Explanation/Defaults:
- -c: minimum 0, maximum 5, default 1 (MiB)
- -g: enable installing GNU GRUB 2
- -i: total image, default 2048 (MiB; max. approx. 2 TiB)
- -p: default 10 (seconds; 0 disables; max. 300)
- -s: default 115200 (bps, others: 9600 19200 38400 57600)
- -t: enable serial console (+t disables it, default)
- -T: image type (default raw, others: vdi)
- EOF
- exit ${1:-1}
- }
- cfgfs=1
- usegrub=0
- tgtmib=2048
- panicreboot=10
- speed=115200
- serial=0
- tgttype=raw
- while getopts "c:ghi:p:s:tT:" ch; do
- case $ch {
- (c) if (( (cfgfs = OPTARG) < 0 || cfgfs > 5 )); then
- print -u2 "$me: -c $OPTARG out of bounds"
- usage
- fi ;;
- (g) usegrub=1 ;;
- (h) usage 0 ;;
- (i) if (( (tgtmib = OPTARG) < 7 || tgtmib > 2097150 )); then
- print -u2 "$me: -i $OPTARG out of bounds"
- usage
- fi ;;
- (p) if (( (panicreboot = OPTARG) < 0 || panicreboot > 300 )); then
- print -u2 "$me: -p $OPTARG out of bounds"
- usage
- fi ;;
- (s) if [[ $OPTARG != @(96|192|384|576|1152)00 ]]; then
- print -u2 "$me: serial speed $OPTARG invalid"
- usage
- fi
- speed=$OPTARG ;;
- (t) serial=1 ;;
- (+t) serial=0 ;;
- (T) if [[ $OPTARG != @(raw|vdi) ]]; then
- print -u2 "$me: image type $OPTARG invalid"
- usage
- fi
- tgttype=$OPTARG ;;
- (*) usage 1 ;;
- }
- done
- shift $((OPTIND - 1))
- (( $# == 2 )) || usage 1
- f=0
- tools='bc genext2fs'
- [[ $tgttype = vdi ]] && tools="$tools VBoxManage"
- for tool in $tools; do
- print -n Checking if $tool is installed...
- if whence -p $tool >/dev/null; then
- print " okay"
- else
- print " failed"
- f=1
- fi
- done
- (( f )) && exit 1
- if bc --help >/dev/null 2>&1; then
- # GNU bc shows a “welcome message” which irritates scripts
- bc='bc -q'
- else
- bc=bc
- fi
- tgt=$1
- [[ $tgt = /* ]] || tgt=$PWD/$tgt
- src=$2
- if [[ ! -f $src ]]; then
- print -u2 "'$src' is not a file, exiting"
- exit 1
- fi
- if ! T=$(mktemp -d /tmp/openadk.XXXXXXXXXX); then
- print -u2 Error creating temporary directory.
- exit 1
- fi
- print "Installing $src on $tgt."
- cyls=$tgtmib
- heads=64
- secs=32
- if stat -qs .>/dev/null 2>&1; then
- statcmd='stat -f %z' # BSD stat (or so we assume)
- else
- statcmd='stat -c %s' # GNU stat
- fi
- if (( usegrub )); then
- tar -xOJf "$src" boot/grub/core.img >"$T/core.img"
- integer coreimgsz=$($statcmd "$T/core.img")
- if (( coreimgsz < 1024 )); then
- print -u2 core.img is probably too small: $coreimgsz
- rm -rf "$T"
- exit 1
- fi
- if (( coreimgsz > 65024 )); then
- print -u2 core.img is larger than 64K-512: $coreimgsz
- rm -rf "$T"
- exit 1
- fi
- else
- # fake it
- integer coreimgsz=1
- fi
- (( coreendsec = (coreimgsz + 511) / 512 ))
- corestartsec=1
- corepatchofs=$((0x414))
- # partition offset: at least coreendsec+1 but aligned on a multiple of secs
- (( partofs = ((coreendsec / secs) + 1) * secs ))
- # calculate size of ext2fs in KiB as image size minus cfgfs minus firsttrack
- ((# partfssz = ((cyls - cfgfs) * 64 * 32 - partofs) / 2 ))
- if (( usegrub )); then
- print Preparing MBR and GRUB2...
- else
- print Preparing partition table...
- fi
- dd if=/dev/zero of="$T/firsttrack" count=$partofs 2>/dev/null
- echo $corestartsec $coreendsec | mksh "$ADK_TOPDIR/scripts/bootgrub.mksh" \
- -A -g $((cyls - cfgfs)):$heads:$secs -M 1:0x83 -O $partofs | \
- dd of="$T/firsttrack" conv=notrunc 2>/dev/null
- if (( usegrub )); then
- dd if="$T/core.img" of="$T/firsttrack" conv=notrunc \
- seek=$corestartsec 2>/dev/null
- # set partition where it can find /boot/grub
- print -n '\0\0\0\0' | \
- dd of="$T/firsttrack" conv=notrunc bs=1 seek=$corepatchofs \
- 2>/dev/null
- fi
- # create cfgfs partition (mostly taken from bootgrub.mksh)
- set -A thecode
- typeset -Uui8 thecode
- mbrpno=0
- set -A g_code $cyls $heads $secs
- (( pssz = cfgfs * g_code[1] * g_code[2] ))
- (( pofs = (cyls - cfgfs) * g_code[1] * g_code[2] ))
- set -A o_code # g_code equivalent for partition offset
- (( o_code[2] = pofs % g_code[2] + 1 ))
- (( o_code[1] = pofs / g_code[2] ))
- (( o_code[0] = o_code[1] / g_code[1] + 1 ))
- (( o_code[1] = o_code[1] % g_code[1] + 1 ))
- # boot flag; C/H/S offset
- thecode[mbrpno++]=0x00
- (( thecode[mbrpno++] = o_code[1] - 1 ))
- (( cylno = o_code[0] > 1024 ? 1023 : o_code[0] - 1 ))
- (( thecode[mbrpno++] = o_code[2] | ((cylno & 0x0300) >> 2) ))
- (( thecode[mbrpno++] = cylno & 0x00FF ))
- # partition type; C/H/S end
- (( thecode[mbrpno++] = 0x88 ))
- (( thecode[mbrpno++] = g_code[1] - 1 ))
- (( cylno = g_code[0] > 1024 ? 1023 : g_code[0] - 1 ))
- (( thecode[mbrpno++] = g_code[2] | ((cylno & 0x0300) >> 2) ))
- (( thecode[mbrpno++] = cylno & 0x00FF ))
- # partition offset, size (LBA)
- (( thecode[mbrpno++] = pofs & 0xFF ))
- (( thecode[mbrpno++] = (pofs >> 8) & 0xFF ))
- (( thecode[mbrpno++] = (pofs >> 16) & 0xFF ))
- (( thecode[mbrpno++] = (pofs >> 24) & 0xFF ))
- (( thecode[mbrpno++] = pssz & 0xFF ))
- (( thecode[mbrpno++] = (pssz >> 8) & 0xFF ))
- (( thecode[mbrpno++] = (pssz >> 16) & 0xFF ))
- (( thecode[mbrpno++] = (pssz >> 24) & 0xFF ))
- # write partition table entry
- ostr=
- curptr=0
- while (( curptr < 16 )); do
- ostr=$ostr\\0${thecode[curptr++]#8#}
- done
- print -n "$ostr" | \
- dd of="$T/firsttrack" conv=notrunc bs=1 seek=$((0x1CE)) 2>/dev/null
- print Extracting installation archive...
- mkdir "$T/src"
- gunzip -dc "$src" | (cd "$T/src"; tar -xpf -)
- cd "$T/src"
- rnddev=/dev/urandom
- [[ -c /dev/arandom ]] && rnddev=/dev/arandom
- dd if=$rnddev bs=16 count=1 >>etc/.rnd 2>/dev/null
- print Fixing up permissions...
- chmod 1777 tmp
- [[ -f usr/bin/sudo ]] && chmod 4755 usr/bin/sudo
- if (( usegrub )); then
- print Configuring GRUB2 bootloader...
- mkdir -p boot/grub
- (
- print set default=0
- print set timeout=1
- if (( serial )); then
- print serial --unit=0 --speed=$speed
- print terminal_output serial
- print terminal_input serial
- consargs="console=ttyS0,$speed console=tty0"
- else
- print terminal_output console
- print terminal_input console
- consargs="console=tty0"
- fi
- print
- print 'menuentry "GNU/Linux (OpenADK)" {'
- linuxargs="root=/dev/sda1 $consargs"
- (( panicreboot )) && linuxargs="$linuxargs panic=$panicreboot"
- print "\tlinux /boot/kernel $linuxargs"
- print '}'
- ) >boot/grub/grub.cfg
- fi
- print "Creating ext2fs filesystem image..."
- cd "$T"
- f=0
- genext2fs -U -N 65536 -b $((partfssz)) -d src fsimg || f=1
- if (( !f )); then
- # use bc(1): this may be over the shell’s 32-bit arithmetics
- wantsz=$($bc <<<"$((partfssz))*1024")
- gotsz=$($statcmd fsimg)
- if [[ $wantsz != "$gotsz" ]]; then
- print -u2 "Error: want $wantsz bytes, got $gotsz bytes!"
- f=1
- fi
- fi
- if (( f )); then
- print -u2 "Error creating ext2fs filesystem image"
- cd /
- rm -rf "$T"
- exit 1
- fi
- # delete source tree, to save disc space
- rm -rf src
- if [[ $tgttype = raw ]]; then
- tgttmp=$tgt
- else
- tgttmp=$T/dst.ima
- fi
- print "Putting together raw output image $tgttmp..."
- dd if=/dev/zero bs=1048576 count=$cfgfs 2>/dev/null | \
- cat firsttrack fsimg - >"$tgttmp"
- # use bc(1): this may be over the shell’s 32-bit arithmetics
- wantsz=$($bc <<<"$tgtmib*1048576")
- gotsz=$($statcmd "$tgttmp")
- if [[ $wantsz != "$gotsz" ]]; then
- print -u2 "Error: want $wantsz bytes, got $gotsz bytes!"
- cd /
- rm -rf "$T"
- exit 1
- fi
- case $tgttype {
- (raw)
- ;;
- (vdi)
- print "Converting raw image to VDI..."
- VBoxManage convertdd dst.ima dst.vdi
- rm dst.ima
- print "Moving VDI image to $tgt.vdi..."
- mv -f dst.vdi "$tgt".vdi
- ;;
- }
- print Finishing up...
- cd "$ADK_TOPDIR"
- rm -rf "$T"
- exit 0
|