Annotation of hatari/tools/atari-hd-image.sh, revision 1.1.1.4

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=""

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.