1#!/bin/sh 2# 3# $NetBSD: buildfloppies.sh,v 1.20 2022/01/24 09:42:13 andvar Exp $ 4# 5# Copyright (c) 2002-2003 The NetBSD Foundation, Inc. 6# All rights reserved. 7# 8# This code is derived from software contributed to The NetBSD Foundation 9# by Luke Mewburn of Wasabi Systems. 10# 11# Redistribution and use in source and binary forms, with or without 12# modification, are permitted provided that the following conditions 13# are met: 14# 1. Redistributions of source code must retain the above copyright 15# notice, this list of conditions and the following disclaimer. 16# 2. Redistributions in binary form must reproduce the above copyright 17# notice, this list of conditions and the following disclaimer in the 18# documentation and/or other materials provided with the distribution. 19# 20# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30# POSSIBILITY OF SUCH DAMAGE. 31# 32 33# set defaults 34# 35: ${PAX=pax} 36prog=${0##*/} 37etcdir=/etc 38 39 40usage() 41{ 42 cat 1>&2 << _USAGE_ 43Usage: ${prog} [options] base size file [...] 44 -i instboot eval instboot as a shell command to install a 45 bootstrap. @IMAGE@ is replaced with the 46 file name of the floppy image. 47 -m max maximum number of floppies to build 48 -N etcdir directory in which to find passwd and group files. 49 -p pad last floppy to floppy size 50 -s suffix suffix for floppies 51 -t timestamp set timestamp for reproducible builds 52 base basename of generated floppies 53 size size of a floppy in 512 byte blocks 54 file [...] file(s) to store in the floppies 55_USAGE_ 56 exit 1 57} 58 59plural() 60{ 61 [ "$1" -ne 1 ] && echo "s" 62} 63 64roundup() 65{ 66 echo $(( ( ( $1 ) + ( $2 ) - 1 ) / ( $2 ) )) 67} 68 69 70# parse and check arguments 71# 72 73while getopts i:m:N:ps:t: opt; do 74 case ${opt} in 75 i) 76 instboot=${OPTARG} ;; 77 m) 78 maxdisks=${OPTARG} ;; 79 N) 80 etcdir=${OPTARG} ;; 81 p) 82 pad=1 ;; 83 s) 84 suffix=${OPTARG} ;; 85 t) 86 timestamp="--timestamp ${OPTARG}" ;; 87 \?|*) 88 usage 89 ;; 90 esac 91done 92 93shift $(( ${OPTIND} - 1 )) 94[ $# -lt 3 ] && usage 95floppybase=$1 96floppysize=$2 97shift 2 98files=$* 99 100# setup temp file, remove existing images 101# 102floppy=floppy.$$.tar 103trap "rm -f ${floppy}" 0 1 2 3 # EXIT HUP INT QUIT 104rm -f ${floppybase}?${suffix} # XXX breaks if maxdisks > 9 105 106# create tar file 107# 108dd if=/dev/zero of=${floppy} bs=8k count=1 2>/dev/null 109( 110 echo ". type=dir optional" 111 for f in ${files}; do 112 echo "./$f type=file uname=root gname=wheel mode=0444" 113 done 114) | \ 115${PAX} ${timestamp} -O -w -b8k -M -N "${etcdir}" -s,^./,, >> ${floppy} || exit 1 116 117# install bootstrap before the image is split into multiple disks 118# 119if [ -n "$instboot" ]; then 120 instboot=$( echo $instboot | sed -e s/@IMAGE@/${floppy}/ ) 121 echo "Running instboot: ${instboot}" 122 eval ${instboot} || exit 1 123fi 124 125# check size against available number of disks 126# 127set -- $(ls -ln $floppy) 128bytes=$5 129blocks=$(roundup ${bytes} 512) 130 # when calculating numdisks, take into account: 131 # a) the image already has an 8K tar header prepended 132 # b) each floppy needs an 8K tar volume header 133numdisks=$(roundup ${blocks}-16 ${floppysize}-16) 134if [ -z "${maxdisks}" ]; then 135 maxdisks=${numdisks} 136fi 137 138# Try to accurately summarise free space 139# 140msg= 141# First floppy has 8k boot code, the rest an 8k 'multivolume header'. 142# Each file has a 512 byte header and is rounded to a multiple of 512. 143# The archive ends with two 512 byte blocks of zeros. 144# The output file is then rounded up to a multiple of 8k. 145# floppysize is in units of 512-byte blocks; free_space is in bytes. 146free_space=$(($maxdisks * ($floppysize - 16) * 512 - 512 * 2)) 147for file in $files; do 148 set -- $(ls -ln $file) 149 file_bytes=$5 150 pad_bytes=$(($(roundup $file_bytes 512) * 512 - $file_bytes)) 151 if [ "$file_bytes" != 0 ] || [ "$file" = "${file#USTAR.volsize.}" ] 152 then 153 msg="$msg $file $pad_bytes," 154 fi 155 free_space=$(($free_space - 512 - $file_bytes - $pad_bytes)) 156done 157echo "Free space in last tar block:$msg" 158 159if [ ${numdisks} -gt ${maxdisks} ]; then 160 # Add in the size of the last item (we really want the kernel) ... 161 excess=$(( 0 - $free_space + $pad_bytes)) 162 echo 1>&2 \ 163 "$prog: Image is ${excess} bytes ($(( ${excess} / 1024 )) KB)"\ 164 "too big to fit on ${maxdisks} disk"$(plural ${maxdisks}) 165 exit 1 166fi 167 168padto=$(( ${floppysize} * ${maxdisks} )) 169if [ -n "${pad}" ]; then 170 echo \ 171 "Writing $(( ${padto} * 512 )) bytes ($(( ${padto} / 2 )) KB)" \ 172 "on ${numdisks} disk"$(plural ${numdisks})"," \ 173 "padded by ${free_space} bytes" \ 174 "($(( ${free_space} / 1024 )) KB)" 175else 176 echo "Writing ${bytes} bytes ($(( ${blocks} / 2 )) KB)"\ 177 "on ${numdisks} disk"$(plural ${numdisks})"," \ 178 "free space ${free_space} bytes" \ 179 "($(( ${free_space} / 1024 )) KB)" 180fi 181 182# write disks 183# 184curdisk=1 185image= 186seek=0 187skip=0 188floppysize8k=$(( ${floppysize} / 16 )) 189while [ ${curdisk} -le ${numdisks} ]; do 190 image="${floppybase}${curdisk}${suffix}" 191 echo "Creating disk ${curdisk} to ${image}" 192 if [ ${curdisk} -eq 1 ]; then 193 : > ${image} 194 else 195 echo USTARFS ${curdisk} > ${image} 196 fi 197 count=$(( ${floppysize8k} - ${seek} )) 198 dd bs=8k conv=sync seek=${seek} skip=${skip} count=${count} \ 199 if=${floppy} of=${image} 2>/dev/null 200 201 curdisk=$(( ${curdisk} + 1 )) 202 skip=$(( $skip + $count )) 203 seek=1 204done 205 206# pad last disk if necessary 207# 208if [ -n "${pad}" ]; then 209 dd if=$image of=$image conv=notrunc conv=sync bs=${floppysize}b count=1 210fi 211 212 213# final status 214# 215echo "Final result:" 216ls -l ${floppybase}?${suffix} # XXX breaks if maxdisks > 9 217 218exit 0 219