#!/usr/bin/env bash #- # Copyright © 2010, 2011, 2012 # Thorsten Glaser # Copyright © 2010-2014 # Waldemar Brodkorb # # 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. TOPDIR=$(pwd) HOST=$(gcc -dumpmachine) me=$0 case :$PATH: in (*:$TOPDIR/host_$HOST/usr/bin:*) ;; (*) export PATH=$PATH:$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##*/} TOPDIR=$(realpath .) ostype=$(uname -s) function usage { cat >&2 < 5 )); then print -u2 "$me: -c $OPTARG out of bounds" usage fi ;; (g) usegrub=1 ;; (+g) usegrub=0 ;; (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 -xOzf "$src" usr/share/grub-bin/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 "$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" gzip -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... #chown 0:0 tmp chmod 1777 tmp chmod 4755 bin/busybox [[ -f usr/bin/Xorg ]] && chmod 4755 usr/bin/Xorg [[ -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 set -A grubfiles ngrubfiles=0 for a in usr/lib/grub/*-pc/{*.mod,efiemu??.o,command.lst,moddep.lst,fs.lst,handler.lst,parttool.lst}; do [[ -e $a ]] && grubfiles[ngrubfiles++]=$a done cp "${grubfiles[@]}" boot/grub/ fi print "Creating ext2fs filesystem image..." cd "$T" f=0 genext2fs -U -N 32768 -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..." mv -f dst.vdi "$tgt".vdi ;; } print Finishing up... cd "$TOPDIR" rm -rf "$T" exit 0