
Ich muss in für Scripting/Make/Automation geeignetem Code ein Disk-Image (zwei Partitionen, ein FAT-Dateisystem und ein ext4-Dateisystem, für UEFI/Syslinux USB Linux-Booten [OS-Installer], der sich in der Produktion nie ändern wird) mit einer Größe erstellen, die genau (oder sehr nahe an) einen Satz von Dateien beliebiger Größe fasst. Mit anderen Worten, bei einem gegebenen Satz von erstellten Dateien muss ich wissen, wie man FAT- und ext4-Dateisystem-Images und das Disk-Image, das partitioniert ist, um sie aufzunehmen, generiert, deren Größen so berechnet sind, dass der freie Speicherplatz so nahe wie möglich an null liegt. Es ist in Ordnung, ein bisschen mehr Platz einzuplanen, aber es ist nicht in Ordnung, zu scheitern, wenn jemand in zwei Jahren N+1 Bytes zur Datei hinzufügt. Dies muss für ein Makefile geeignet sein, d. h. Versuch und Irrtum reichen nicht aus (obwohl ich annehme, dass im schlimmsten Fall eine iterative Lösung mit einem Schwellenwert funktionieren könnte). Dies ist so etwas wie ein ISO-9660-Image (was es bei einem früheren Projekt war, aber Syslinux unterstützt keine ISO-9660-Images auf UEFI).
Ich erstelle die Dateien mit dd
(um das Disk-Image zuzuweisen), parted
( dd
um das FAT-Dateisystem zuzuweisen), mkfs.vfat
( dd
für ext4), (um die Partitionen zuzuordnen), mkfs.ext4
( um die FAT-Partition zu schreiben), (um die ext4-Partition zu schreiben) und schließlich um das Disk-Image auf einen USB-Stick zu schreiben, um auf der tatsächlichen Hardware zu booten.kpartx
dd
dd
dd
Meine aktuelle Idee ist, du
zu bestimmen, wie viel Speicherplatz die Dateien auf der Build-Diskette einnehmen, und dann einen gewissen Spielraum für zusätzlichen Dateisystem- und Partitions-Overhead sowie einen Fehlerspielraum hinzuzufügen. Daher muss ich die Blockanzahl für jedes der dd
Ergebnisse kennen du
.
Eine andere Möglichkeit besteht darin, ein großes Image mit fester Größe zu erstellen, die Dateien zu schreiben und dann die FAT-, ext4- und Partitionsgröße auf die Mindestgröße zu ändern. ext4-Dateisysteme können verkleinert werden, und ich sehe, dass FAT-Dateisysteme verkleinert werden können. Aber dann bleibt immer noch das Problem, zu berechnen, um wie viel es verkleinert werden muss. Ich frage mich, ob das schon einmal jemand gemacht hat und konkrete Ideen (oder Beispielcode) hat.
Antwort1
Am Ende habe ich eine Kombination aus Schummelfaktoren und einem iterativen Ansatz (als Ausfallsicherung) verwendet. Das muss nicht so kompliziert sein, wie ich es mir ursprünglich vorgestellt hatte. Es stellte sich heraus, dass für FAT vorerst nur wenig Schummeln erforderlich war, für ext jedoch eine große Menge an negativem Schummeln; mit einem Schummelfaktor von null für ext4 hatte ich jede Menge freien Speicherplatz (über 21 MB). Ich konvertierte zu ext2 (wer braucht schon ein verdammtes Journal?!), erhöhte meine Blockgröße, zählte sorgfältig die Inodes, die ich brauchte, und holte sogar noch mehr Megabyte freien Speicherplatz heraus. Ich nehme an, ich hätte die „tatsächliche Größe“ von du bekommen und von dort aus weiterarbeiten können, aber ich dachte, dass das Zählen des Overheads, selbst wenn es sich um unterschiedliche Dateisysteme handelt, eine bessere Annäherung wäre.
# Estimated filesystem overhead, in 512-byte blocks
FS_ESP_FUDGE=256
FS_ISO_FUDGE=-80000 # Wow!
FS_FUDGE_INCR=1024
...
read ESP_RSIZE d < <(du --summarize --block-size=512 $ESP)
read ISO_RSIZE d < <(du --summarize --block-size=512 $ISO)
success=false
until $success; do
let ESP_SIZE=ESP_RSIZE+FS_ESP_FUDGE
let ISO_SIZE=ISO_RSIZE+FS_ISO_FUDGE
let ESP_START=2048
let IMG_SIZE=ESP_SIZE+ISO_SIZE+ESP_START
let ESP_END=ESP_START+ESP_SIZE-1
let ISO_START=ESP_END+1
success=true
...
sudo /sbin/mkfs.vfat /dev/mapper/$p1 -F 16 \
|| error_exit "mkfs.vfat failed" 5
# -N: Count the inodes (all files, plus . and .. for each directory,
# which I can't get "find" to include).
sudo /sbin/mke2fs -b 4096 -N $(( $(find $ISO | wc -l ) + 2 * $(find $ISO -type d | wc -l))) -m 0 -q /dev/mapper/$p2 \
|| error_exit "mke2fs failed" 6
...
if ! tar -C $ESP -c --exclude-vcs --exclude-backups . | \
sudo tar -C mnt/esp -x; then
{
read
read fs onek used avail use rest
} < <(df mnt/esp)
# Are we out of disk space? If not, bail, else increase margin, retry
[[ $onek -ne $used || $avail -ne 0 || $use != "100%" ]] && \
error_exit "esp tar failed" 9
let FS_ESP_FUDGE=FS_ESP_FUDGE+FS_FUDGE_INCR
success=false
fi
if ! tar -C $ISO -c --exclude-vcs --exclude-backups . | \
sudo tar -C mnt/iso --owner=root --group=root -x ; then
{
read
read fs onek used avail use rest
} < <(df mnt/iso)
# Are we out of disk space? If not, bail, else increase margin, retry
[[ $onek -ne $used || $avail -ne 0 || $use != "100%" ]] && \
error_exit "iso tar failed" 10
let FS_ISO_FUDGE=FS_ISO_FUDGE+FS_FUDGE_INCR
success=false
fi
$success || echo "Whoops, I guessed too small; please adjust fudge factor. Retrying ..."
...
done