Files
Sprinter-SDCC/toolchain/make_hdd.sh
T
snark13 8e389c03f8 Volkov: добавить Sprinter Commander
Реализовать двухпанельный Commander от платформенного PoC до этапов P6-P20: EMM-каталог, сортировку и выбор, операции с файлами и деревьями, транзакционное копирование, метаданные, политику конфликтов и предварительную проверку свободного места.

Добавить проектную документацию, HDD/MAME-сценарии и проверенные артефакты. Расширить libc операцией bank_write_page, исправлением режима O_RDONLY и связанными регрессионными проверками.
2026-09-10 10:45:30 +03:00

151 lines
6.5 KiB
Bash
Executable File
Raw Permalink 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).
# 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
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 createhd -i "$RAW" -o "$OUT_CHD" -c none \
-chs $CYLS,$HEADS,$SECS -ss 512 -f
echo "готово: $OUT_CHD"