Files
Sprinter-SDCC/toolchain/make_hdd.sh
T

164 lines
6.9 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# make_hdd.sh [--dest DIR] OUT.chd FILE_OR_TREE1 [FILE_OR_TREE2 ...]
#
# Собирает 32 МБ RAW-образ жёсткого диска (MBR + один раздел FAT16) с
# указанными файлами и конвертит его в CHD для MAME (монтируется как -hard2).
# По умолчанию файлы кладутся в корень. --dest DIR (или HDD_DEST_DIR)
# переносит всё дерево под DIR, например games/sprpop.
#
# Требует: mtools (mpartition/mformat/mcopy) + chdman (из MAME).
# CHDMAN_BIN может указывать на установленный chdman вне PATH.
# Sprinter DSS штатно монтирует стандартный MBR+FAT16 (подтверждено).
#
# Использование:
# toolchain/make_hdd.sh mame/v306/IMG/test_hdd.chd prog.exe data1 data2 ...
# toolchain/make_hdd.sh --dest games/sprpop out.chd prog.exe data1 ...
# toolchain/make_hdd.sh out.chd prog.exe KID:kid0.atl GUARD:g0.atl ...
# — аргумент вида КАТАЛОГ:файл кладёт файл в подкаталог относительно
# DIR; без префикса файл идёт непосредственно в DIR.
# toolchain/make_hdd.sh out.chd prog.exe /tmp/test-tree
# — каталог копируется рекурсивно вместе со своим именем. Это заметно
# ускоряет сборку нагрузочных образов с сотнями мелких файлов.
set -e
DEST_DIR=${HDD_DEST_DIR:-}
while [ $# -gt 0 ]; do
case "$1" in
--dest)
if [ $# -lt 2 ]; then
echo "make_hdd.sh: --dest требует путь" >&2
exit 1
fi
DEST_DIR="$2"
shift 2
;;
--dest=*)
DEST_DIR="${1#--dest=}"
shift
;;
--)
shift
break
;;
*) break ;;
esac
done
if [ $# -lt 2 ]; then
echo "usage: $0 [--dest DIR] OUT.chd FILE1 [FILE2 ...]" >&2
exit 1
fi
for command in mpartition mformat mcopy mmd mdir; do
if ! command -v "$command" >/dev/null 2>&1; then
echo "make_hdd.sh: не найден host-инструмент $command (mtools)" >&2
exit 1
fi
done
CHDMAN_BIN=${CHDMAN_BIN:-chdman}
if ! command -v "$CHDMAN_BIN" >/dev/null 2>&1; then
echo "make_hdd.sh: не найден chdman: $CHDMAN_BIN" >&2
exit 1
fi
OUT_CHD="$1"; shift
# DSS использует обратный слэш, но mtools — прямой. Ведущие/замыкающие
# разделители не несут смысла: DIR всегда задаётся относительно корня HDD.
DEST_DIR="${DEST_DIR//\\//}"
while [ "${DEST_DIR#/}" != "$DEST_DIR" ]; do DEST_DIR="${DEST_DIR#/}"; done
while [ "${DEST_DIR%/}" != "$DEST_DIR" ]; do DEST_DIR="${DEST_DIR%/}"; done
case "/$DEST_DIR/" in
*/./*|*/../*|*:* )
echo "make_hdd.sh: недопустимый каталог назначения: $DEST_DIR" >&2
exit 1
;;
esac
# Геометрия: 128*16*32*512 = 32 МБ. BPS=512.
CYLS=128; HEADS=16; SECS=32
SECTORS=$((CYLS * HEADS * SECS)) # 65536
# macOS mktemp требует X'ы в КОНЦЕ шаблона.
RAW=$(mktemp /tmp/sphdd.raw.XXXXXX)
MTC=$(mktemp /tmp/sphdd.mtc.XXXXXX)
trap 'rm -f "$RAW" "$MTC"' EXIT
dd if=/dev/zero of="$RAW" bs=512 count=$SECTORS status=none
# mtools-диск z: = раздел 1 нашего RAW-образа.
printf 'drive z: file="%s" partition=1\n' "$RAW" > "$MTC"
export MTOOLSRC="$MTC" MTOOLS_SKIP_CHECK=1
# mtools собран с enable-raw-term и, когда ему нужно что-то спросить,
# открывает УПРАВЛЯЮЩИЙ ТЕРМИНАЛ напрямую (/dev/tty) — в обход stdin.
# Поэтому ни `< /dev/null`, ни перенаправление stdio не спасают: из
# терминала сборка молча вставала навсегда на `mmd z:/BG` (подтверждено
# lsof: fd 0 = /dev/null, fd 4 = /dev/tty, процесс спит). Лечится только
# отсутствием управляющего терминала — запускаем mtools в новой сессии,
# тогда открыть /dev/tty нечего и mtools идёт неинтерактивным путём.
#
# setsid(1) в macOS нет, поэтому делаем то же самое питоном.
# Каналов, откуда mtools может ждать ответ, ДВА, и закрывать надо оба:
# /dev/tty — убирается новой сессией (os.setsid);
# stdin — убирается перенаправлением из /dev/null.
# Закрыть только один недостаточно: с одним лишь setsid mmd переключался на
# stdin и вис уже на нём (lsof: fd 0 = /dev/ttys002).
mt() {
python3 -c 'import os,sys; os.setsid(); os.execvp(sys.argv[1], sys.argv[1:])' \
"$@" < /dev/null
}
# mmd не создаёт родителей сам: строим путь по одному компоненту. Пустой
# путь означает корень и сохраняет прежнее поведение скрипта.
make_dir_tree() {
local path="$1" part current="" old_ifs="$IFS"
[ -z "$path" ] && return
IFS='/'
for part in $path; do
[ -z "$part" ] && continue
current="${current:+$current/}$part"
mt mmd "z:/$current" >/dev/null 2>&1 || true
done
IFS="$old_ifs"
}
# MBR + раздел 1 на весь диск (тип FAT16), затем формат FAT16.
echo "--- разметка и формат образа ---"
mt mpartition -I -c -t $CYLS -h $HEADS -s $SECS z:
mt mformat z:
echo "--- копирование файлов ---"
make_dir_tree "$DEST_DIR"
DEST_ROOT="z:${DEST_DIR:+/$DEST_DIR}"
# Аргумент может быть файлом, деревом каталогов либо парой КАТАЛОГ:файл.
# Дерево копируется рекурсивно вместе с именем своего корня. Имена на
# Sprinter/DSS — 8.3.
for f in "$@"; do
case "$f" in
*:*) dir="${f%%:*}"; src="${f#*:}"
target_dir="${DEST_DIR:+$DEST_DIR/}$dir"
# Каталог может уже быть — это не ошибка; stderr НЕ прячем, иначе
# непрошедший вопрос mtools снова окажется невидимым.
make_dir_tree "$target_dir"
mt mcopy -o "$src" "z:/$target_dir/" ;;
*) if [ -d "$f" ]; then
mt mcopy -s -o "$f" "$DEST_ROOT/"
else
mt mcopy -o "$f" "$DEST_ROOT/"
fi ;;
esac
done
echo "--- содержимое образа ---"
mt mdir -/ z:
# RAW -> CHD (без сжатия = быстро; та же геометрия).
echo "--- конвертация RAW -> CHD ---"
"$CHDMAN_BIN" createhd -i "$RAW" -o "$OUT_CHD" -c none \
-chs $CYLS,$HEADS,$SECS -ss 512 -f
echo "готово: $OUT_CHD"