| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 | #!/usr/bin/env bash#-# Copyright © 2010, 2011, 2012#	Thorsten Glaser <tg@mirbsd.org># Copyright © 2010-2014#	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=$0case :$PATH: in(*:$ADK_TOPDIR/host_$HOST/usr/bin:*) ;;(*) export PATH=$PATH:$ADK_TOPDIR/host_$HOST/usr/bin ;;esactest -n "$KSH_VERSION" || exec mksh "$me" "$@"if test -z "$KSH_VERSION"; then	echo >&2 Fatal error: could not run myself with mksh!	exit 255fi### run with mksh from here onwards ###me=${me##*/}ADK_TOPDIR=$(realpath .)ostype=$(uname -s)function usage {	cat >&2 <<EOFSyntax: $me [-c cfgfssize] [+g] [-i imagesize] [-p panictime]    [-s serialspeed] [-t] [-T imagetype] [+U] target.ima source.tgzExplanation/Defaults:	-c: minimum 0, maximum 5, default 1 (MiB)	-g: enable installing GNU GRUB 2	-i: total image, default 512 (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=1usegrub=0tgtmib=512panicreboot=10speed=115200serial=0tgttype=rawwhile 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 ;;	}doneshift $((OPTIND - 1))(( $# == 2 )) || usage 1f=0tools='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	fidone(( f )) && exit 1if bc --help >/dev/null 2>&1; then	# GNU bc shows a “welcome message” which irritates scripts	bc='bc -q'else	bc=bcfitgt=$1[[ $tgt = /* ]] || tgt=$PWD/$tgtsrc=$2if [[ ! -f $src ]]; then	print -u2 "'$src' is not a file, exiting"	exit 1fiif ! T=$(mktemp -d /tmp/openadk.XXXXXXXXXX); then	print -u2 Error creating temporary directory.	exit 1fiprint "Installing $src on $tgt."cyls=$tgtmibheads=64secs=32if stat -qs .>/dev/null 2>&1; then	statcmd='stat -f %z'	# BSD stat (or so we assume)else	statcmd='stat -c %s'	# GNU statfiif (( usegrub )); then	tar -xOzf "$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	fielse	# fake it	integer coreimgsz=1fi(( coreendsec = (coreimgsz + 511) / 512 ))corestartsec=1corepatchofs=$((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...fidd if=/dev/zero of="$T/firsttrack" count=$partofs 2>/dev/nullecho $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/nullif (( 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/nullfi# create cfgfs partition (mostly taken from bootgrub.mksh)set -A thecodetypeset -Uui8 thecodembrpno=0set -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 offsetthecode[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 entryostr=curptr=0while (( curptr < 16 )); do	ostr=$ostr\\0${thecode[curptr++]#8#}doneprint -n "$ostr" | \    dd of="$T/firsttrack" conv=notrunc bs=1 seek=$((0x1CE)) 2>/dev/nullprint Extracting installation archive...mkdir "$T/src"xz -dc "$src" | (cd "$T/src"; tar -xpf -)cd "$T/src"rnddev=/dev/urandom[[ -c /dev/arandom ]] && rnddev=/dev/arandomdd if=$rnddev bs=16 count=1 >>etc/.rnd 2>/dev/nullprint Fixing up permissions...chmod 1777 tmp[[ -f usr/bin/sudo ]] && chmod 4755 usr/bin/sudoif (( 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.cfgfiprint "Creating ext2fs filesystem image..."cd "$T"f=0genext2fs -U -N 32768 -b $((partfssz)) -d src fsimg || f=1if (( !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	fifiif (( f )); then	print -u2 "Error creating ext2fs filesystem image"	cd /	rm -rf "$T"	exit 1fi# delete source tree, to save disc spacerm -rf srcif [[ $tgttype = raw ]]; then	tgttmp=$tgtelse	tgttmp=$T/dst.imafiprint "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 arithmeticswantsz=$($bc <<<"$tgtmib*1048576")gotsz=$($statcmd "$tgttmp")if [[ $wantsz != "$gotsz" ]]; then	print -u2 "Error: want $wantsz bytes, got $gotsz bytes!"	cd /	rm -rf "$T"	exit 1ficase $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
 |