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} 36 prog=${0##*/} 37 etcdir=/etc 38 39 40 usage() 41 { 42 cat 1>&2 << _USAGE_ 43 Usage: ${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 59 plural() 60 { 61 [ "$1" -ne 1 ] && echo "s" 62 } 63 64 roundup() 65 { 66 echo $(( ( ( $1 ) + ( $2 ) - 1 ) / ( $2 ) )) 67 } 68 69 70 # parse and check arguments 71 # 72 73 while 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 91 done 92 93 shift $(( ${OPTIND} - 1 )) 94 [ $# -lt 3 ] && usage 95 floppybase=$1 96 floppysize=$2 97 shift 2 98 files=$* 99 100 # setup temp file, remove existing images 101 # 102 floppy=floppy.$$.tar 103 trap "rm -f ${floppy}" 0 1 2 3 # EXIT HUP INT QUIT 104 rm -f ${floppybase}?${suffix} # XXX breaks if maxdisks > 9 105 106 # create tar file 107 # 108 dd 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 # 119 if [ -n "$instboot" ]; then 120 instboot=$( echo $instboot | sed -e s/@IMAGE@/${floppy}/ ) 121 echo "Running instboot: ${instboot}" 122 eval ${instboot} || exit 1 123 fi 124 125 # check size against available number of disks 126 # 127 set -- $(ls -ln $floppy) 128 bytes=$5 129 blocks=$(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 133 numdisks=$(roundup ${blocks}-16 ${floppysize}-16) 134 if [ -z "${maxdisks}" ]; then 135 maxdisks=${numdisks} 136 fi 137 138 # Try to accurately summarise free space 139 # 140 msg= 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. 146 free_space=$(($maxdisks * ($floppysize - 16) * 512 - 512 * 2)) 147 for 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)) 156 done 157 echo "Free space in last tar block:$msg" 158 159 if [ ${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 166 fi 167 168 padto=$(( ${floppysize} * ${maxdisks} )) 169 if [ -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)" 175 else 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)" 180 fi 181 182 # write disks 183 # 184 curdisk=1 185 image= 186 seek=0 187 skip=0 188 floppysize8k=$(( ${floppysize} / 16 )) 189 while [ ${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 204 done 205 206 # pad last disk if necessary 207 # 208 if [ -n "${pad}" ]; then 209 dd if=$image of=$image conv=notrunc conv=sync bs=${floppysize}b count=1 210 fi 211 212 213 # final status 214 # 215 echo "Final result:" 216 ls -l ${floppybase}?${suffix} # XXX breaks if maxdisks > 9 217 218 exit 0 219