1#!/bin/bash 2# 3# Copyright (C) 2018 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18set -e 19set -u 20 21SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P) 22 23usage() { 24 echo -n "usage: $0 [-h] [-s bullseye|bullseye-cuttlefish|bullseye-rockpi|bullseye-server] " 25 echo -n "[-a i386|amd64|armhf|arm64] -k /path/to/kernel " 26 echo -n "-i /path/to/initramfs.gz [-d /path/to/dtb:subdir] " 27 echo "[-m http://mirror/debian] [-n rootfs|disk] [-r initrd] [-e] [-g]" 28 exit 1 29} 30 31mirror=http://ftp.debian.org/debian 32embed_kernel_initrd_dtb=0 33install_grub=0 34suite=bullseye 35arch=amd64 36 37dtb_subdir= 38initramfs= 39kernel= 40ramdisk= 41disk= 42dtb= 43 44while getopts ":hs:a:m:n:r:k:i:d:eg" opt; do 45 case "${opt}" in 46 h) 47 usage 48 ;; 49 s) 50 if [[ "${OPTARG%-*}" != "bullseye" ]]; then 51 echo "Invalid suite: ${OPTARG}" >&2 52 usage 53 fi 54 suite="${OPTARG}" 55 ;; 56 a) 57 arch="${OPTARG}" 58 ;; 59 m) 60 mirror="${OPTARG}" 61 ;; 62 n) 63 disk="${OPTARG}" 64 ;; 65 r) 66 ramdisk="${OPTARG}" 67 ;; 68 k) 69 kernel="${OPTARG}" 70 ;; 71 i) 72 initramfs="${OPTARG}" 73 ;; 74 d) 75 dtb="${OPTARG%:*}" 76 if [ "${OPTARG#*:}" != "${dtb}" ]; then 77 dtb_subdir="${OPTARG#*:}/" 78 fi 79 ;; 80 e) 81 embed_kernel_initrd_dtb=1 82 ;; 83 g) 84 install_grub=1 85 ;; 86 \?) 87 echo "Invalid option: ${OPTARG}" >&2 88 usage 89 ;; 90 :) 91 echo "Invalid option: ${OPTARG} requires an argument" >&2 92 usage 93 ;; 94 esac 95done 96 97# Disable Debian's "persistent" network device renaming 98cmdline="net.ifnames=0 rw 8250.nr_uarts=2 PATH=/usr/sbin:/bin:/usr/bin" 99cmdline="${cmdline} embed_kernel_initrd_dtb=${embed_kernel_initrd_dtb}" 100cmdline="${cmdline} install_grub=${install_grub}" 101 102case "${arch}" in 103 i386) 104 cmdline="${cmdline} console=ttyS0 exitcode=/dev/ttyS1" 105 machine="pc-i440fx-2.8,accel=kvm" 106 qemu="qemu-system-i386" 107 partguid="8303" 108 cpu="max" 109 ;; 110 amd64) 111 cmdline="${cmdline} console=ttyS0 exitcode=/dev/ttyS1" 112 machine="pc-i440fx-2.8,accel=kvm" 113 qemu="qemu-system-x86_64" 114 partguid="8304" 115 cpu="max" 116 ;; 117 armhf) 118 cmdline="${cmdline} console=ttyAMA0 exitcode=/dev/ttyS0" 119 machine="virt,gic-version=2" 120 qemu="qemu-system-arm" 121 partguid="8307" 122 cpu="cortex-a15" 123 ;; 124 arm64) 125 cmdline="${cmdline} console=ttyAMA0 exitcode=/dev/ttyS0" 126 machine="virt,gic-version=2" 127 qemu="qemu-system-aarch64" 128 partguid="8305" 129 cpu="cortex-a53" # "max" is too slow 130 ;; 131 *) 132 echo "Invalid arch: ${OPTARG}" >&2 133 usage 134 ;; 135esac 136 137if [[ -z "${disk}" ]]; then 138 if [[ "${install_grub}" = "1" ]]; then 139 base_image_name=disk 140 else 141 base_image_name=rootfs 142 fi 143 disk="${base_image_name}.${arch}.${suite}.$(date +%Y%m%d)" 144fi 145disk=$(realpath "${disk}") 146 147if [[ -z "${ramdisk}" ]]; then 148 ramdisk="initrd.${arch}.${suite}.$(date +%Y%m%d)" 149fi 150ramdisk=$(realpath "${ramdisk}") 151 152if [[ -z "${kernel}" ]]; then 153 echo "$0: Path to kernel image must be specified (with '-k')" 154 usage 155elif [[ ! -e "${kernel}" ]]; then 156 echo "$0: Kernel image not found at '${kernel}'" 157 exit 2 158fi 159 160if [[ -z "${initramfs}" ]]; then 161 echo "Path to initial ramdisk image must be specified (with '-i')" 162 usage 163elif [[ ! -e "${initramfs}" ]]; then 164 echo "Initial ramdisk image not found at '${initramfs}'" 165 exit 3 166fi 167 168# Sometimes it isn't obvious when the script fails 169failure() { 170 echo "Filesystem generation process failed." >&2 171 rm -f "${disk}" "${ramdisk}" 172} 173trap failure ERR 174 175# Import the package list for this release 176packages=$(cpp "${SCRIPT_DIR}/rootfs/${suite}.list" | grep -v "^#" | xargs | tr -s ' ' ',') 177 178# For the debootstrap intermediates 179tmpdir=$(mktemp -d) 180tmpdir_remove() { 181 echo "Removing temporary files.." >&2 182 sudo rm -rf "${tmpdir}" 183} 184trap tmpdir_remove EXIT 185 186workdir="${tmpdir}/_" 187mkdir "${workdir}" 188chmod 0755 "${workdir}" 189sudo chown root:root "${workdir}" 190 191# Run the debootstrap first 192cd "${workdir}" 193 194retries=5 195while ! sudo debootstrap --arch="${arch}" --variant=minbase --include="${packages}" \ 196 --foreign "${suite%-*}" . "${mirror}"; do 197 retries=$((${retries} - 1)) 198 if [ ${retries} -le 0 ]; then 199 failure 200 exit 1 201 fi 202 echo "debootstrap failed - trying again - ${retries} retries left" 203done 204 205# Copy some bootstrapping scripts into the rootfs 206sudo cp -a "${SCRIPT_DIR}"/rootfs/*.sh root/ 207sudo cp -a "${SCRIPT_DIR}"/rootfs/net_test.sh sbin/net_test.sh 208sudo chown root:root sbin/net_test.sh 209 210# Extract the ramdisk to bootstrap with to / 211lz4 -lcd "${initramfs}" | sudo cpio -idum lib/modules/* 212 213# Create /host, for the pivot_root and 9p mount use cases 214sudo mkdir host 215 216# debootstrap workaround: Run debootstrap in docker sometimes causes the 217# /proc being a symlink in first stage. We need to fix the symlink to an empty 218# directory. 219if [ -L "${workdir}/proc" ]; then 220 echo "/proc in debootstrap 1st stage is a symlink. Fixed!" 221 sudo rm -f "${workdir}/proc" 222 sudo mkdir "${workdir}/proc" 223fi 224 225# Leave the workdir, to build the filesystem 226cd - 227 228# For the initial ramdisk, and later for the final rootfs 229mount=$(mktemp -d) 230mount_remove() { 231 rmdir "${mount}" 232 tmpdir_remove 233} 234trap mount_remove EXIT 235 236# The initial ramdisk filesystem must be <=512M, or QEMU's -initrd 237# option won't touch it 238initrd=$(mktemp) 239initrd_remove() { 240 rm -f "${initrd}" 241 mount_remove 242} 243trap initrd_remove EXIT 244truncate -s 512M "${initrd}" 245/sbin/mke2fs -F -t ext4 -L ROOT "${initrd}" 246 247# Mount the new filesystem locally 248sudo mount -o loop -t ext4 "${initrd}" "${mount}" 249image_unmount() { 250 sudo umount "${mount}" 251 initrd_remove 252} 253trap image_unmount EXIT 254 255# Copy the patched debootstrap results into the new filesystem 256sudo cp -a "${workdir}"/* "${mount}" 257sudo rm -rf "${workdir}" 258 259# Unmount the initial ramdisk 260sudo umount "${mount}" 261trap initrd_remove EXIT 262 263if [[ "${install_grub}" = 1 ]]; then 264 part_num=0 265 # $1 partition size 266 # $2 gpt partition type 267 # $3 partition name 268 # $4 bypass alignment checks (use on <1MB partitions only) 269 # $5 partition attribute bit to set 270 sgdisk() { 271 part_num=$((part_num+1)) 272 [[ -n "${4:-}" ]] && prefix="-a1" || prefix= 273 [[ -n "${5:-}" ]] && suffix="-A:${part_num}:set:$5" || suffix= 274 /sbin/sgdisk ${prefix} \ 275 "-n:${part_num}:$1" "-t:${part_num}:$2" "-c:${part_num}:$3" \ 276 ${suffix} "${disk}" >/dev/null 2>&1 277 } 278 # If there's a bootloader, we need to make space for the GPT header, GPT 279 # footer and EFI system partition (legacy boot is not supported) 280 # Keep this simple - modern gdisk reserves 1MB for the GPT header and 281 # assumes all partitions are 1MB aligned 282 truncate -s "$((1 + 128 + 10 * 1024 + 1))M" "${disk}" 283 /sbin/sgdisk --zap-all "${disk}" >/dev/null 2>&1 284 # On RockPi devices, steal a bit of space at the start of the disk for 285 # some special bootloader partitions. Some of these have to start/end 286 # at specific offsets as well 287 if [[ "${suite#*-}" = "rockpi" ]]; then 288 # See https://opensource.rock-chips.com/wiki_Boot_option 289 # Keep in sync with rootfs/*-rockpi.sh 290 sgdisk "64:8127" "8301" "idbloader" "true" 291 sgdisk "8128:+64" "8301" "uboot_env" "true" 292 sgdisk "8M:+4M" "8301" "uboot" 293 sgdisk "12M:+4M" "8301" "trust" 294 sgdisk "16M:+1M" "8301" "misc" 295 sgdisk "17M:+128M" "ef00" "esp" "" "0" 296 sgdisk "145M:0" "8305" "rootfs" "" "2" 297 system_partition="6" 298 rootfs_partition="7" 299 else 300 sgdisk "0:+128M" "ef00" "esp" "" "0" 301 sgdisk "0:0" "${partguid}" "rootfs" "" "2" 302 system_partition="1" 303 rootfs_partition="2" 304 fi 305 306 # Create an empty EFI system partition; it will be initialized later 307 system_partition_start=$(partx -g -o START -s -n "${system_partition}" "${disk}" | xargs) 308 system_partition_end=$(partx -g -o END -s -n "${system_partition}" "${disk}" | xargs) 309 system_partition_num_sectors=$((${system_partition_end} - ${system_partition_start} + 1)) 310 system_partition_num_vfat_blocks=$((${system_partition_num_sectors} / 2)) 311 /sbin/mkfs.vfat -n SYSTEM -F 16 --offset=${system_partition_start} "${disk}" ${system_partition_num_vfat_blocks} >/dev/null 312 # Copy the rootfs to just after the EFI system partition 313 rootfs_partition_start=$(partx -g -o START -s -n "${rootfs_partition}" "${disk}" | xargs) 314 rootfs_partition_end=$(partx -g -o END -s -n "${rootfs_partition}" "${disk}" | xargs) 315 rootfs_partition_num_sectors=$((${rootfs_partition_end} - ${rootfs_partition_start} + 1)) 316 rootfs_partition_offset=$((${rootfs_partition_start} * 512)) 317 rootfs_partition_size=$((${rootfs_partition_num_sectors} * 512)) 318 dd if="${initrd}" of="${disk}" bs=512 seek="${rootfs_partition_start}" conv=fsync,notrunc 2>/dev/null 319 /sbin/e2fsck -p -f "${disk}"?offset=${rootfs_partition_offset} || true 320 disksize=$(stat -c %s "${disk}") 321 /sbin/resize2fs "${disk}"?offset=${rootfs_partition_offset} ${rootfs_partition_num_sectors}s 322 truncate -s "${disksize}" "${disk}" 323 /sbin/sgdisk -e "${disk}" 324 /sbin/e2fsck -p -f "${disk}"?offset=${rootfs_partition_offset} || true 325 /sbin/e2fsck -fy "${disk}"?offset=${rootfs_partition_offset} || true 326else 327 # If there's no bootloader, the initrd is the disk image 328 cp -a "${initrd}" "${disk}" 329 truncate -s 10G "${disk}" 330 /sbin/e2fsck -p -f "${disk}" || true 331 /sbin/resize2fs "${disk}" 332 system_partition= 333 rootfs_partition="raw" 334fi 335 336# Create another fake block device for initrd.img writeout 337raw_initrd=$(mktemp) 338raw_initrd_remove() { 339 rm -f "${raw_initrd}" 340 initrd_remove 341} 342trap raw_initrd_remove EXIT 343truncate -s 64M "${raw_initrd}" 344 345# Get number of cores for qemu. Restrict the maximum value to 8. 346qemucpucores=$(nproc) 347if [[ ${qemucpucores} -gt 8 ]]; then 348 qemucpucores=8 349fi 350 351# Complete the bootstrap process using QEMU and the specified kernel 352${qemu} -machine "${machine}" -cpu "${cpu}" -m 2048 >&2 \ 353 -kernel "${kernel}" -initrd "${initrd}" -no-user-config -nodefaults \ 354 -no-reboot -display none -nographic -serial stdio -parallel none \ 355 -smp "${qemucpucores}",sockets="${qemucpucores}",cores=1,threads=1 \ 356 -object rng-random,id=objrng0,filename=/dev/urandom \ 357 -device virtio-rng-pci-non-transitional,rng=objrng0,id=rng0,max-bytes=1024,period=2000 \ 358 -drive file="${disk}",format=raw,if=none,aio=threads,id=drive-virtio-disk0 \ 359 -device virtio-blk-pci-non-transitional,scsi=off,drive=drive-virtio-disk0 \ 360 -drive file="${raw_initrd}",format=raw,if=none,aio=threads,id=drive-virtio-disk1 \ 361 -device virtio-blk-pci-non-transitional,scsi=off,drive=drive-virtio-disk1 \ 362 -chardev file,id=exitcode,path=exitcode \ 363 -device pci-serial,chardev=exitcode \ 364 -append "root=/dev/ram0 ramdisk_size=524288 init=/root/stage1.sh ${cmdline}" 365[[ -s exitcode ]] && exitcode=$(cat exitcode | tr -d '\r') || exitcode=2 366rm -f exitcode 367if [ "${exitcode}" != "0" ]; then 368 echo "Second stage debootstrap failed (err=${exitcode})" 369 exit "${exitcode}" 370fi 371 372# Fix up any issues from the unclean shutdown 373if [[ ${rootfs_partition} = "raw" ]]; then 374 sudo e2fsck -p -f "${disk}" || true 375else 376 rootfs_partition_start=$(partx -g -o START -s -n "${rootfs_partition}" "${disk}" | xargs) 377 rootfs_partition_end=$(partx -g -o END -s -n "${rootfs_partition}" "${disk}" | xargs) 378 rootfs_partition_num_sectors=$((${rootfs_partition_end} - ${rootfs_partition_start} + 1)) 379 rootfs_partition_offset=$((${rootfs_partition_start} * 512)) 380 rootfs_partition_tempfile2=$(mktemp) 381 dd if="${disk}" of="${rootfs_partition_tempfile2}" bs=512 skip=${rootfs_partition_start} count=${rootfs_partition_num_sectors} 382 e2fsck -p -f "${rootfs_partition_tempfile2}" || true 383 dd if="${rootfs_partition_tempfile2}" of="${disk}" bs=512 seek=${rootfs_partition_start} count=${rootfs_partition_num_sectors} conv=fsync,notrunc 384 rm -f "${rootfs_partition_tempfile2}" 385 e2fsck -fy "${disk}"?offset=${rootfs_partition_offset} || true 386fi 387if [[ -n "${system_partition}" ]]; then 388 system_partition_start=$(partx -g -o START -s -n "${system_partition}" "${disk}" | xargs) 389 system_partition_end=$(partx -g -o END -s -n "${system_partition}" "${disk}" | xargs) 390 system_partition_num_sectors=$((${system_partition_end} - ${system_partition_start} + 1)) 391 system_partition_offset=$((${system_partition_start} * 512)) 392 system_partition_size=$((${system_partition_num_sectors} * 512)) 393 system_partition_tempfile=$(mktemp) 394 dd if="${disk}" of="${system_partition_tempfile}" bs=512 skip=${system_partition_start} count=${system_partition_num_sectors} 395 /sbin/fsck.vfat -a "${system_partition_tempfile}" || true 396 dd if="${system_partition_tempfile}" of="${disk}" bs=512 seek=${system_partition_start} count=${system_partition_num_sectors} conv=fsync,notrunc 397 rm -f "${system_partition_tempfile}" 398fi 399 400# New workdir for the initrd extraction 401workdir="${tmpdir}/initrd" 402mkdir "${workdir}" 403chmod 0755 "${workdir}" 404sudo chown root:root "${workdir}" 405 406# Change into workdir to repack initramfs 407cd "${workdir}" 408 409# Process the initrd to remove kernel-specific metadata 410kernel_version=$(basename $(lz4 -lcd "${raw_initrd}" | sudo cpio -idumv 2>&1 | grep usr/lib/modules/ - | head -n1)) 411lz4 -lcd "${raw_initrd}" | sudo cpio -idumv 412sudo rm -rf usr/lib/modules 413sudo mkdir -p usr/lib/modules 414 415# Debian symlinks /usr/lib to /lib, but we'd prefer the other way around 416# so that it more closely matches what happens in Android initramfs images. 417# This enables 'cat ramdiskA.img ramdiskB.img >ramdiskC.img' to "just work". 418sudo rm -f lib 419sudo mv usr/lib lib 420sudo ln -s /lib usr/lib 421 422# Repack the ramdisk to the final output 423find * | sudo cpio -H newc -o --quiet | lz4 -lc9 >"${ramdisk}" 424 425# Pack another ramdisk with the combined artifacts, for boot testing 426cat "${ramdisk}" "${initramfs}" >"${initrd}" 427 428# Leave workdir to boot-test combined initrd 429cd - 430 431rootfs_partition_tempfile=$(mktemp) 432# Mount the new filesystem locally 433if [[ ${rootfs_partition} = "raw" ]]; then 434 sudo mount -o loop -t ext4 "${disk}" "${mount}" 435else 436 rootfs_partition_start=$(partx -g -o START -s -n "${rootfs_partition}" "${disk}" | xargs) 437 rootfs_partition_offset=$((${rootfs_partition_start} * 512)) 438 rootfs_partition_end=$(partx -g -o END -s -n "${rootfs_partition}" "${disk}" | xargs) 439 rootfs_partition_num_sectors=$((${rootfs_partition_end} - ${rootfs_partition_start} + 1)) 440 dd if="${disk}" of="${rootfs_partition_tempfile}" bs=512 skip=${rootfs_partition_start} count=${rootfs_partition_num_sectors} 441fi 442image_unmount2() { 443 sudo umount "${mount}" 444 raw_initrd_remove 445} 446if [[ ${rootfs_partition} = "raw" ]]; then 447 trap image_unmount2 EXIT 448fi 449 450# Embed the kernel and dtb images now, if requested 451if [[ ${rootfs_partition} = "raw" ]]; then 452 if [[ "${embed_kernel_initrd_dtb}" = "1" ]]; then 453 if [ -n "${dtb}" ]; then 454 sudo mkdir -p "${mount}/boot/dtb/${dtb_subdir}" 455 sudo cp -a "${dtb}" "${mount}/boot/dtb/${dtb_subdir}" 456 sudo chown -R root:root "${mount}/boot/dtb/${dtb_subdir}" 457 fi 458 sudo cp -a "${kernel}" "${mount}/boot/vmlinuz-${kernel_version}" 459 sudo chown root:root "${mount}/boot/vmlinuz-${kernel_version}" 460 fi 461else 462 if [[ "${embed_kernel_initrd_dtb}" = "1" ]]; then 463 if [ -n "${dtb}" ]; then 464 e2mkdir -G 0 -O 0 "${rootfs_partition_tempfile}":"/boot/dtb/${dtb_subdir}" 465 e2cp -G 0 -O 0 "${dtb}" "${rootfs_partition_tempfile}":"/boot/dtb/${dtb_subdir}" 466 fi 467 e2cp -G 0 -O 0 "${kernel}" "${rootfs_partition_tempfile}":"/boot/vmlinuz-${kernel_version}" 468 fi 469fi 470 471# Unmount the initial ramdisk 472if [[ ${rootfs_partition} = "raw" ]]; then 473 sudo umount "${mount}" 474else 475 rootfs_partition_start=$(partx -g -o START -s -n "${rootfs_partition}" "${disk}" | xargs) 476 rootfs_partition_end=$(partx -g -o END -s -n "${rootfs_partition}" "${disk}" | xargs) 477 rootfs_partition_num_sectors=$((${rootfs_partition_end} - ${rootfs_partition_start} + 1)) 478 dd if="${rootfs_partition_tempfile}" of="${disk}" bs=512 seek=${rootfs_partition_start} count=${rootfs_partition_num_sectors} conv=fsync,notrunc 479fi 480rm -f "${rootfs_partition_tempfile}" 481trap raw_initrd_remove EXIT 482 483# Boot test the new system and run stage 3 484${qemu} -machine "${machine}" -cpu "${cpu}" -m 2048 >&2 \ 485 -kernel "${kernel}" -initrd "${initrd}" -no-user-config -nodefaults \ 486 -no-reboot -display none -nographic -serial stdio -parallel none \ 487 -smp "${qemucpucores}",sockets="${qemucpucores}",cores=1,threads=1 \ 488 -object rng-random,id=objrng0,filename=/dev/urandom \ 489 -device virtio-rng-pci-non-transitional,rng=objrng0,id=rng0,max-bytes=1024,period=2000 \ 490 -drive file="${disk}",format=raw,if=none,aio=threads,id=drive-virtio-disk0 \ 491 -device virtio-blk-pci-non-transitional,scsi=off,drive=drive-virtio-disk0 \ 492 -chardev file,id=exitcode,path=exitcode \ 493 -device pci-serial,chardev=exitcode \ 494 -netdev user,id=usernet0,ipv6=off \ 495 -device virtio-net-pci-non-transitional,netdev=usernet0,id=net0 \ 496 -append "root=LABEL=ROOT init=/root/${suite}.sh ${cmdline}" 497[[ -s exitcode ]] && exitcode=$(cat exitcode | tr -d '\r') || exitcode=2 498rm -f exitcode 499if [ "${exitcode}" != "0" ]; then 500 echo "Root filesystem finalization failed (err=${exitcode})" 501 exit "${exitcode}" 502fi 503 504# Fix up any issues from the unclean shutdown 505if [[ ${rootfs_partition} = "raw" ]]; then 506 sudo e2fsck -p -f "${disk}" || true 507else 508 rootfs_partition_start=$(partx -g -o START -s -n "${rootfs_partition}" "${disk}" | xargs) 509 rootfs_partition_end=$(partx -g -o END -s -n "${rootfs_partition}" "${disk}" | xargs) 510 rootfs_partition_num_sectors=$((${rootfs_partition_end} - ${rootfs_partition_start} + 1)) 511 rootfs_partition_offset=$((${rootfs_partition_start} * 512)) 512 rootfs_partition_tempfile2=$(mktemp) 513 dd if="${disk}" of="${rootfs_partition_tempfile2}" bs=512 skip=${rootfs_partition_start} count=${rootfs_partition_num_sectors} 514 e2fsck -p -f "${rootfs_partition_tempfile2}" || true 515 dd if="${rootfs_partition_tempfile2}" of="${disk}" bs=512 seek=${rootfs_partition_start} count=${rootfs_partition_num_sectors} conv=fsync,notrunc 516 rm -f "${rootfs_partition_tempfile2}" 517 e2fsck -fy "${disk}"?offset=${rootfs_partition_offset} || true 518fi 519if [[ -n "${system_partition}" ]]; then 520 system_partition_start=$(partx -g -o START -s -n "${system_partition}" "${disk}" | xargs) 521 system_partition_end=$(partx -g -o END -s -n "${system_partition}" "${disk}" | xargs) 522 system_partition_num_sectors=$((${system_partition_end} - ${system_partition_start} + 1)) 523 system_partition_offset=$((${system_partition_start} * 512)) 524 system_partition_size=$((${system_partition_num_sectors} * 512)) 525 system_partition_tempfile=$(mktemp) 526 dd if="${disk}" of="${system_partition_tempfile}" bs=512 skip=${system_partition_start} count=${system_partition_num_sectors} 527 /sbin/fsck.vfat -a "${system_partition_tempfile}" || true 528 dd if="${system_partition_tempfile}" of="${disk}" bs=512 seek=${system_partition_start} count=${system_partition_num_sectors} conv=fsync,notrunc 529 rm -f "${system_partition_tempfile}" 530fi 531 532# Mount the final disk image locally 533if [[ ${rootfs_partition} = "raw" ]]; then 534 sudo mount -o loop -t ext4 "${disk}" "${mount}" 535else 536 rootfs_partition_start=$(partx -g -o START -s -n "${rootfs_partition}" "${disk}" | xargs) 537 rootfs_partition_offset=$((${rootfs_partition_start} * 512)) 538 sudo mount -o loop,offset=${rootfs_partition_offset} -t ext4 "${disk}" "${mount}" 539fi 540image_unmount3() { 541 sudo umount "${mount}" 542 raw_initrd_remove 543} 544trap image_unmount3 EXIT 545 546# Fill the rest of the space with zeroes, to optimize compression 547sudo dd if=/dev/zero of="${mount}/sparse" bs=1M 2>/dev/null || true 548sudo rm -f "${mount}/sparse" 549 550echo "Debian ${suite} for ${arch} filesystem generated at '${disk}'." 551echo "Initial ramdisk generated at '${ramdisk}'." 552