|
|
1.1 root 1: #!/bin/sh
1.1.1.2 root 2: # script for creating a compatible DOS HD image for Hatari with
3: # a single FAT16 partition of given size, with given contents
1.1 root 4:
5: # defaults for disk attributes
6: diskfile=hd.img # HD image filename
7: partname=DOS # partition name
8:
1.1.1.2 root 9: # no args or first arg has non-digit characters?
10: if [ $# -lt 1 ] || [ \! -z "$(echo $1|tr -d 0-9)" ]; then
1.1 root 11: name=${0##*/}
12: echo
13: echo "usage: $name <size> [filename] [partition name] [directory]"
14: echo
15: echo "Create an ACSI/IDE harddisk image for Hatari with a single Atari"
16: echo "compatible DOS partition. Arguments are (defaults in parenthesis):"
1.1.1.3 root 17: echo "- size: harddisk image size in megabytes, 8-512"
1.1 root 18: echo "- filename: name for the harddisk image ($diskfile)"
19: echo "- partition name: name for that single partition ($partname)"
20: echo "- directory: directory for initial content copied to the image"
21: echo
22: echo "For example:"
23: echo "- 16MB '$diskfile' HD image:"
24: echo " $name 16"
25: echo "- 8MB image with 'TEST' partition having files from content/:"
26: echo " $name 8 8mb-disk.img TEST content/"
27: echo
28: exit 1
29: fi
30:
31: # sfdisk/mkdosfs reside in /sbin
32: PATH=/sbin:$PATH
33: export PATH
34:
35: # check tools
1.1.1.2 root 36: if [ -z $(which mkdosfs) ] || [ -z $(which python) ]; then
37: echo "ERROR: either mkdosfs or python tool missing!"
1.1 root 38: exit 1
39: fi
40:
41: # check disk size
1.1.1.4 ! root 42: disksize=$1
! 43: if [ $disksize -lt 5 ]; then
1.1 root 44: echo "ERROR: disk size needs to be at least 5 (MB) to work properly."
45: exit 1
46: fi
1.1.1.4 ! root 47: if [ $disksize -gt 512 ]; then
1.1.1.3 root 48: echo "ERROR: mkdosfs supports Atari compatible partitions only up to 512 MB."
1.1 root 49: exit 1
50: fi
1.1.1.2 root 51:
1.1 root 52: # check optional arguments
53: if [ \! -z $2 ]; then
54: diskfile=$2
55: fi
56: if [ \! -z $3 ]; then
57: partname=$3
58: fi
1.1.1.4 ! root 59:
! 60: # check that there's enough space:
! 61: # - partition + disk image (2.5x size just in case)
! 62: freespace=$(df $diskfile | awk '/\//{print $4/1024}')
! 63: if [ $freespace -lt $((5*$disksize/2)) ]; then
! 64: echo "ERROR: not enough space for partition creation!"
! 65: exit 1
! 66: fi
! 67:
! 68: # check content
! 69: convertdir=""
1.1 root 70: if [ \! -z $4 ]; then
1.1.1.4 ! root 71: contentdir=${4%/}
! 72: if [ \! -d $contentdir ]; then
! 73: echo "ERROR: given content directory doesn't exist!"
! 74: exit 1
! 75: fi
! 76: contentsize=$(du -ks $contentdir | awk '{printf("%d", $1/1024)}')
! 77: if [ $contentsize -ge $disksize ]; then
! 78: echo "ERROR: '$contentdir' directory contents ($contentsize MB) don't fit to given image size ($disksize MB)!"
! 79: exit 1
! 80: fi
! 81: # name conversion script should be in same dir as this script, or in PATH
! 82: convert=${0%/*}/atari-convert-dir.py
! 83: if [ \! -x $convert ]; then
! 84: if [ -z $(which atari-convert-dir) ]; then
! 85: echo "ERROR: $convert script for file name conversion missing!"
! 86: exit 1
! 87: fi
! 88: convert=atari-convert-dir
! 89: fi
! 90: convertdir=$contentdir.converted
1.1 root 91: if [ -z $(which mcopy) ]; then
92: echo "ERROR: mcopy (from Mtools) missing!"
93: exit 1
94: fi
95: fi
96:
97: # don't overwrite files by accident
98: if [ -f $diskfile ]; then
99: echo "ERROR: given harddisk image already exits. Give another name or remove it:"
100: echo " rm $diskfile"
101: exit 1
102: fi
103:
1.1.1.4 ! root 104: # disk geometry
! 105: skip=0 # alignment / "padding" sectors between MBR before partition
! 106: diskheads=16
! 107: tracksectors=32 # same as used by mkdosfs
! 108: sectorsize=512
! 109:
! 110: # partition size in sectors:
! 111: # 16*32*512 is 1/4MB -> multiply by 4 to get number of required sectors
! 112: partsectors=$((4*$disksize*$diskheads*$tracksectors))
! 113:
1.1 root 114: # temporary files
115: tmppart=$diskfile.part
116:
1.1.1.4 ! root 117: # ------------------------------------------------------------------
! 118:
1.1.1.2 root 119: error="premature script exit"
1.1 root 120: # script exit/error handling
121: exit_cleanup ()
122: {
123: echo
1.1.1.2 root 124: if [ -z "$error" ]; then
1.1 root 125: echo "$step) Cleaning up..."
126: else
1.1.1.2 root 127: echo "ERROR: $error"
1.1 root 128: echo
1.1.1.2 root 129: echo "cleaning up..."
1.1.1.4 ! root 130: if [ -f $diskfile ]; then
! 131: echo "rm -f $diskfile"
! 132: rm -f $diskfile
! 133: fi
! 134: fi
! 135: if [ -f $tmppart ]; then
! 136: echo "rm -f $tmppart"
! 137: rm -f $tmppart
! 138: fi
! 139: if [ \! -z $convertdir ] && [ -d $convertdir ]; then
! 140: echo "rm -f $convertdir"
! 141: rm -f $convertdir
1.1 root 142: fi
143: echo "Done."
144: }
145: trap exit_cleanup EXIT
146:
1.1.1.4 ! root 147: # ------------------------------------------------------------------
! 148:
1.1 root 149: echo
150: step=1
1.1.1.4 ! root 151: echo "$step) Create DOS Master Boot Record / partition table..."
1.1.1.2 root 152: # See:
153: # - http://en.wikipedia.org/wiki/Master_boot_record
154: # - http://en.wikipedia.org/wiki/Cylinder-head-sector
155: # - http://en.wikipedia.org/wiki/File_Allocation_Table#Boot_Sector
156: # For DOS MBR, the values are little endian.
157: # -----------
158: python << EOF
159: #!/usr/bin/env python
160: mbr = bytearray(512)
161:
162: def set_long(idx, value):
163: mbr[idx+0] = value & 0xff
164: mbr[idx+1] = value >> 8 & 0xff
165: mbr[idx+2] = value >> 16 & 0xff
166: mbr[idx+3] = value >> 24
167:
168: def set_word(idx, value):
169: mbr[idx] = value & 0xff
170: mbr[idx+1] = value >> 8 & 0xff
171:
172: def set_CHS(idx, values):
173: c, h, s = values
174: print "CHS: %3d,%3d,%3d @ $%x" % (c,h,s,idx)
175: mbr[idx] = h
176: mbr[idx+1] = (s & 0x3F) | ((c >> 2) & 0xC0)
177: mbr[idx+2] = c & 0xFF
178:
179: def LBA2CHS(lba):
180: c = lba / ($tracksectors * $diskheads)
181: h = (lba / $tracksectors) % $diskheads
182: s = (lba % $tracksectors) + 1
183: return (c,h,s)
184:
185: # disk size
186: sectors = 1 + $skip + $partsectors
187: if sectors < 65536:
188: set_word(0x13, sectors)
189: set_long(0x20, sectors)
190: parttype=0x4
191: else:
192: set_long(0x20, sectors)
193: parttype=0x6
194:
195: # reserved sectors = MBR
196: mbr[0x0E] = 1
197:
198: # CHS information
199: set_word(0x0B, $sectorsize)
200: mbr[0x0D] = 2 # sectors / cluster
201: set_word(0x18, $tracksectors)
202: set_word(0x1A, $diskheads)
203:
204: # non-removable disk
205: mbr[0x15] = 0xF8
206: mbr[0x24] = 0x80
207:
208: # partition size in sectors
209: partsectors = $partsectors - 1
210: # first partition takes all
211: offset = 0x1BE
212: mbr[offset] = 0x80 # bootable
213: mbr[offset+4] = parttype
214: # partition start & sector count in LBA
215: set_long(offset + 0x08, 1)
216: set_long(offset + 0x0C, partsectors)
217: # partition start & end in CHS
218: set_CHS(offset + 1, LBA2CHS(1))
219: set_CHS(offset + 5, LBA2CHS(partsectors))
220: # 3 last partitions are empty
221: for i in (1,2,3):
222: offset += 0x10
223: set_long(offset + 0x08, partsectors+1)
224: set_long(offset + 0x0C, 0)
225: set_CHS(offset + 1, LBA2CHS(partsectors+1))
226: set_CHS(offset + 5, LBA2CHS(partsectors))
227:
228: # MBR signature
229: mbr[0x1FE] = 0x55
230: mbr[0x1FF] = 0xAA
1.1 root 231:
1.1.1.2 root 232: open("$diskfile", "wb").write(bytes(mbr))
1.1 root 233: EOF
1.1.1.2 root 234: # -----------
235: od -t x1 $diskfile
1.1 root 236:
1.1.1.4 ! root 237: # ------------------------------------------------------------------
! 238:
1.1 root 239: echo
240: step=$(($step+1))
1.1.1.4 ! root 241: echo "$step) Create an Atari TOS compatible DOS partition..."
1.1 root 242: # mkdosfs keeps the sector count below 32765 when -A is used by increasing
243: # the logical sector size (this is for TOS compatibility, -A guarantees
244: # also 2 sectors / cluster and Atari serial number etc). Mtools barfs
245: # if partition size doesn't divide evenly with its track size. Determine
246: # suitable cluster count & corresponding track size and align (decrease)
247: # the file system sector count accordingly.
248: tracksize=32
1.1.1.2 root 249: clustertmp=$((partsectors/2))
250: echo "Sectors: $partsectors, sectors/track: $tracksize, clusters: $clustertmp"
1.1 root 251: while [ $clustertmp -gt 32765 ]; do
252: clustertmp=$((clustertmp/2))
253: tracksize=$(($tracksize*2))
254: echo "Doubling sector size as >32765 clusters -> $clustertmp clusters"
255: done
1.1.1.2 root 256: sectors=$(($partsectors/$tracksize))
1.1 root 257: sectors=$(($sectors*$tracksize))
258: kilobytes=$(($sectors/2))
1.1.1.2 root 259: if [ $sectors -ne $partsectors ]; then
260: echo "Align sector count with clusters/sectors/track: $partsectors -> $sectors ($kilobytes kB)"
1.1 root 261: fi
1.1.1.2 root 262: echo "mkdosfs -A -F 16 -n $partname -C $tmppart $kilobytes"
263: mkdosfs -A -F 16 -n $partname -C $tmppart $kilobytes
1.1 root 264:
1.1.1.4 ! root 265: # ------------------------------------------------------------------
! 266:
1.1 root 267: if [ \! -z $contentdir ]; then
268: echo
269: step=$(($step+1))
1.1.1.4 ! root 270: echo "$step) Clip/convert long file names to Atari compatible 8+3 format..."
! 271: echo "$convert $contentdir $convertdir"
! 272: $convert $contentdir $convertdir
! 273: if [ $? -ne 0 ]; then
! 274: error="conversion failed."
! 275: exit 2
! 276: fi
! 277:
! 278: echo
! 279: step=$(($step+1))
1.1 root 280: # copy contents of given directory to the new partition
1.1.1.4 ! root 281: echo "$step) Copy the initial content to the partition..."
! 282: echo "MTOOLS_NO_VFAT=1 mcopy -i $tmppart -spmv $convertdir/* ::"
! 283: MTOOLS_NO_VFAT=1 mcopy -i $tmppart -spmv $convertdir/* ::
1.1 root 284: if [ $? -ne 0 ]; then
1.1.1.2 root 285: error="mcopy failed."
1.1 root 286: exit 2
287: fi
1.1.1.4 ! root 288: echo "rm -rf $convertdir"
! 289: rm -rf $convertdir
1.1 root 290: fi
291:
1.1.1.4 ! root 292: # ------------------------------------------------------------------
! 293:
1.1 root 294: echo
295: step=$(($step+1))
296: # copy the partition into disk
1.1.1.4 ! root 297: echo "$step) Copy the partition to disk image..."
1.1.1.2 root 298: echo "dd if=$tmppart of=$diskfile bs=512 seek=$((1+$skip)) count=$sectors"
299: dd if=$tmppart of=$diskfile bs=512 seek=$((1+$skip)) count=$sectors
1.1 root 300:
301: step=$(($step+1))
302: # cleanup is done by exit_cleanup() trap
1.1.1.2 root 303: error=""
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.