Acabei usando uma combinação de fatores fudge e uma abordagem iterativa (como fail-safe). Isso não precisa ser tão complicado quanto eu imaginava. Acontece que, por enquanto, pouca falsificação era necessária para o FAT, mas uma enorme quantidade de falsificação negativa era necessária para ext; com um fator de fudge zero para ext4, eu tinha muito espaço livre (mais de 21M). Eu converti para ext2 (que precisa de um diário fedorento ?!), aumentei o tamanho do meu bloco e contei cuidadosamente os inodes que eu precisava, e obtive ainda mais megabytes de espaço livre. Eu suponho que eu poderia ter obtido o "tamanho real" de du e trabalhado a partir daí, mas imaginei que contar a sobrecarga, mesmo que fossem sistemas de arquivos diferentes, seria uma aproximação mais próxima.
# 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