From ae43325d1ce55bbce43bd0a996cfab00657be838 Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Sun, 5 Feb 2017 00:30:32 -0800 Subject: Implement mkrootfs and mkrootimg for Raspberry Pi 2 --- README.md | 51 ++++--- chrootfs | 76 ---------- mkrootfs | 372 ++++++++++++++++++++++++++++++++++------------- mkrootfs.d/01-apt.sh | 5 - mkrootfs.d/02-kernel.sh | 12 -- mkrootfs.d/03-fstab.sh | 5 - mkrootfs.d/04-network.sh | 14 -- mkrootfs.d/05-locales.sh | 2 - mkrootfs.d/06-login.sh | 18 --- mkrootimg | 145 ++++++++++-------- 10 files changed, 388 insertions(+), 312 deletions(-) delete mode 100755 chrootfs delete mode 100644 mkrootfs.d/01-apt.sh delete mode 100644 mkrootfs.d/02-kernel.sh delete mode 100644 mkrootfs.d/03-fstab.sh delete mode 100644 mkrootfs.d/04-network.sh delete mode 100644 mkrootfs.d/05-locales.sh delete mode 100644 mkrootfs.d/06-login.sh diff --git a/README.md b/README.md index 044928f..f7120d7 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,46 @@ -A suite of utilities to build debian root filesystems and bootable images for the Cubieboard 5 (Cubietruck Plus). +A suite of utilities to build a debian root filesystem and bootable image for the Raspberry Pi 2, model B. ## Utilities -- `mkrootfs ` Build a debian root filesystem in the given directory -- `chrootfs ` Start a shell in the given root filesystem. -- `mkrootimg ` Bundle a root filesystem into a binary image that can be flashed to an sd card (bootloader still needs to be flashed manually). +- `mkrootfs` Build a debian root filesystem in the given directory +- `mkrootimg` Bundle a root filesystem into a bootable, binary image that can be flashed to an sd card. -Run any of the above utilities with the `-h` or `--help` options for additional information. +Run any of the above utilities without arguments for additional information. ## Usage Example -The typical use-case, creating a bootable image for the Cubieboard 5 involves the following steps: +The typical use-case, creating a bootable image involves the following steps: 1. Create a root filesystem in a temporary directory "tmprootfs". - mkrootfs --hostname=cb5 --release=stretch --ssh-key=/home/user/.ssh/id_rsa.pub tmprootfs - -2. (optional) Start a shell in the directory to install any additional packages. + mkrootfs --hostname=pi --release=stretch --ssh-key=/home/user/.ssh/id_rsa.pub tmprootfs - chrootfs tmprootfs - - root@inside_rootfs:~# apt install ... - root@inside_rootfs:~# ... - root@inside_rootfs:~# exit - -3. Pack the root filesystem into a binary image (note that the first 1MB of the image will be empty, reserved for a bootloader). +2. Pack the root filesystem into a binary image - mkrootimg tmprootfs cb5-stretch.img + mkrootimg tmprootfs pi2-stretch.img -4. Add bootloader to start of image (see http://linux-sunxi.org/Mainline_Debian_HowTo for instructions on how to build u-boot). +3. Copy the image to an sd card. + + dd if=pi2-stretch.img of=/dev/mmc0 + +4. Boot a Raspberry Pi from the card. + + Note that several initialization tasks are performed during the first boot: + + - the root filesystem is expanded to fill the whole sd card + - ssh keys and machine ids are regenerated + + Progress will be signaled through the ACT and PWR LEDs: - dd if=/u-boot-sunxi-with-spl.bin of=cb5-stretch.img bs=1024 seek=8 conv=notrunc - -5. Copy the image to an sd card. + - both leds will flash rapidly for a couple of seconds, indicating + that first-boot tasks are about to start + - PWR will blink in a "heartbeat" pattern and ACT will indicate sd card activity + - first-boot tasks are run + - after completion, the ACT led will blink in a heartbeat pattern an PWR will be turned off - dd if=cb5-stretch.img of=/dev/mmc0 +## Requirements -Note that you will need root privileges to run most of these commands. +- qemu-user-static +- qemu-debootstrap ## Copying This program is free software, released under the GNU General Public License version 2. diff --git a/chrootfs b/chrootfs deleted file mode 100755 index 0b42070..0000000 --- a/chrootfs +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash -set -e - -# Directory in which the root filesystem is contained -# -ROOTFS=$(pwd)/cb5-rootfs - -print_usage() { - cat 1>&2 <&2 - exit 1 - esac - shift -done - -# Process last argument, the root file system location -if [ -z "$1" ] || [ "$1" = -h ] || [ "$1" = --help ]; then - print_usage - exit 1 -fi -if [ "$EUID" -ne 0 ]; then - echo "This must be run as root." 1>&2 - exit 1 -fi -export ROOTFS="$1" - -# Unmount and remove any temporary files -# -cleanup() { - set +e - - # Identify and kill all processes still using files - echo "Killing processes using mount point" 1>&2 - fuser -k "${ROOTFS}" - sleep 3 - fuser -9 -k -v "${ROOTFS}" - - # Clean up all temporary mount points - echo "Removing temporary mount points" 1>&2 - umount -l "${ROOTFS}/proc" 2> /dev/null - umount -l "${ROOTFS}/sys" 2> /dev/null - umount -l "${ROOTFS}/dev/pts" 2> /dev/null - umount -l "${ROOTFS}/dev" 2> /dev/null - trap - 0 1 2 3 6 -} -trap cleanup 0 1 2 3 6 - -# Prepare filesystem to be chrooted -# -echo "Creating temporary system mount points in rootfs" 1>&2 -mount -t proc chproc "$ROOTFS/proc" -mount -t sysfs chsys "$ROOTFS/sys" -mount -t devtmpfs chdev "$ROOTFS/dev" -mount -t devpts chpts "$ROOTFS/dev/pts" - -echo "Starting shell in rootfs" 1>&2 -LANG=C LC_ALL=C DEBIAN_FRONTEND=noninteractive chroot ${ROOTFS} - -cleanup -echo "Cleaned up" diff --git a/mkrootfs b/mkrootfs index e8941b0..09047cb 100755 --- a/mkrootfs +++ b/mkrootfs @@ -1,136 +1,312 @@ #!/bin/bash set -e -# Directory in which the file system will be built -# -ROOTFS=$(pwd)/cb5-rootfs - -# Debian release -# -RELEASE=stretch - -# Host name to be used by machine -# -HOSTNAME=cb5 - -# SSH to log in as root -# -SSH_KEY="$HOME/.ssh/id_rsa.pub" +hostname=pi +ssh_key="$HOME/.ssh/id_rsa.pub" +release=stretch +rootfs= print_usage() { - cat 1>&2 < + +Create a bare debian root filesystem for the Raspberry Pi 2 B. The +password for the root account will be set to 'guest' by default. Options: - --hostname=<$HOSTNAME> Use a given hostname for the device. - --ssh-key=<$SSH_KEY> Add the given SSH key to root's authorized_keys file. When this option is provided, root's account will be locked. - --release=<$RELEASE> Create a root filesystem for the given debian release. + --hostname Use a given hostname for the device. Defaults to '$hostname'. + --ssh-key Add the given SSH key to root's authorized_keys file. Defaults to '$ssh_key'. + --release Create a root filesystem for the given debian release. Defaults to '$release'. + --no-debootstrap Don't create an initial file system with debootstrap. This may be useful for debugging purposes EOF } -# Process options -# -while [ $# -gt 1 ] -do +fail() { + echo "$1" >&2 + exit 1 +} + +log() { + echo "mkrootfs: $1" >&2 +} + +# Process arguments +while [ $# -gt 0 ]; do case "$1" in --help|-h) print_usage exit 0 ;; - --hostname=*) - HOSTNAME="${1#*=}" + --hostname) + shift + [[ -z "$1" ]] && fail "no hostname specified" + hostname="$1" + ;; + --release) + shift + [[ -z "$1" ]] && fail "no release specified" + release="$1" ;; - --release=*) - RELEASE="${1#*=}" + --ssh-key) + shift + [[ -z "$1" ]] && fail "no ssh-key specified" + ssh_key="$1" ;; - --ssh-key=*) - SSH_KEY="${1#*=}" + --no-debootstrap) + nodeboostrap=true ;; *) - echo "Unknown option '$1'" 1>&2 - exit 1 + [[ -n "$rootfs" ]] && fail "rootfs already defined" + rootfs="$1" + ;; esac shift done -# Process last argument, the root file system location -if [ -z "$1" ] || [ "$1" = -h ] || [ "$1" = --help ]; then - print_usage - exit 1 -fi -if [ "$EUID" -ne 0 ]; then - echo "This must be run as root." 1>&2 - exit 1 -fi -export ROOTFS="$1" +[ -n "$rootfs" ] || fail "$(print_usage)" +[ ! -e "$rootfs" ] || fail "$rootfs already exists" +[ "$EUID" -eq 0 ] || fail "$0 must be run as root" + +if [ -n "$nodebootstrap" ]; then + echo "skipping deboostrap" >&2 +else + log "debootstrapping" + if [ $(dpkg -l | grep -c apt-cacher-ng) -gt 0 ]; then + export http_proxy="http://localhost:3142" + else + echo "WARNING: running debootstrap will download a lot of data. It is recommended to use apt-cacher-ng." >&2 + fi -export RELEASE -export HOSTNAME -export SSH_KEY + qemu-debootstrap \ + --verbose \ + --include=wget,curl,openssl,ca-certificates \ + --arch=armhf \ + "$release" \ + "$rootfs" \ + http://httpredir.debian.org/debian + + log "debootstrap complete" + # http_proxy conflicts with direct calls to apt-get + #unset http_proxy +fi # Run a command in the root file system -# chroot_exec() { - # Exec command in chroot - LANG=C LC_ALL=C DEBIAN_FRONTEND=noninteractive chroot ${ROOTFS} /bin/sh -c "$*" + LANG=C LC_ALL=C DEBIAN_FRONTEND=noninteractive chroot "$rootfs" "$@" } -export -f chroot_exec # Unmount and remove any temporary files -# cleanup() { + log "cleaning" set +e - - # Identify and kill all processes still using files - echo "Killing processes using mount point" 1>&2 - fuser -k "${ROOTFS}" - sleep 3 - fuser -9 -k -v "${ROOTFS}" - - # Clean up all temporary mount points - echo "Removing temporary mount points" 1>&2 - umount -l "${ROOTFS}/proc" 2> /dev/null - umount -l "${ROOTFS}/sys" 2> /dev/null - umount -l "${ROOTFS}/dev/pts" 2> /dev/null - umount -l "${ROOTFS}/dev" 2> /dev/null + fuser --kill -SIGTERM "$rootfs" + sleep 2 + fuser --kill -SIGKILL --verbose "$rootfs" + umount -l "$rootfs/proc" 2> /dev/null + umount -l "$rootfs/sys" 2> /dev/null + umount -l "$rootfs/dev/pts" 2> /dev/null + umount -l "$rootfs/dev" 2> /dev/null trap - 0 1 2 3 6 } trap cleanup 0 1 2 3 6 -# Bootstrap initial file system -# -echo "Creating rootfs" 1>&2 -# proxy is set to use apt-cacher-ng -http_proxy="localhost:3142" qemu-debootstrap \ - --verbose \ - --include=linux-image-armmp-lpae,locales,flash-kernel,sunxi-tools,firmware-linux-free,u-boot-tools \ - --arch=armhf \ - "$RELEASE" \ - "$ROOTFS" \ - http://httpredir.debian.org/debian - -# Prepare filesystem to be chrooted -# -echo "Creating temporary system mount points in rootfs" 1>&2 -mount -t proc chproc "$ROOTFS/proc" -mount -t sysfs chsys "$ROOTFS/sys" -mount -t devtmpfs chdev "$ROOTFS/dev" -mount -t devpts chpts "$ROOTFS/dev/pts" -echo "Configuring rootfs" 1>&2 -chroot_exec dpkg --configure -a - -# Run setup scripts -# -echo "Running setup scripts" 1>&2 -dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) -for script in "$dir"/mkrootfs.d/*.sh; do - echo "Running $script" 1>&2 - bash "$script" -done -echo "Completed setup scripts" 1>&2 +# Prepare filesystem to be chrooted into +log "creating temporary system mount points" +mount -t proc chproc "$rootfs/proc" +mount -t sysfs chsys "$rootfs/sys" +mount -t devtmpfs chdev "$rootfs/dev" +mount -t devpts chpts "$rootfs/dev/pts" + +# Set up package archive +log "configuring apt archive" +cat > "$rootfs/etc/apt/sources.list" < "$rootfs/etc/fstab" < "$rootfs/boot/firmware/config.txt" +gpu_mem=64 +kernel=u-boot.bin +EOF + +# Install and configure kernel flashing utility +# http://sjoerd.luon.net/posts/2015/02/debian-jessie-on-rpi2/ +chroot_exec apt-get install -y flash-kernel u-boot-tools +echo "Raspberry Pi 2 Model B" > "$rootfs/etc/flash-kernel/machine" +cat < "$rootfs/etc/flash-kernel/ubootenv.d/10-partition" +setenv distro_bootpart 2 +setenv prefix /boot/ +EOF +echo "Machine: Raspberry Pi 2 Model B" >> "$rootfs/etc/flash-kernel/db" +echo "Boot-Script-Path: /boot/firmware/boot.scr" >> "$rootfs/etc/flash-kernel/db" + +# Install kernel +log "installing kernel" +chroot_exec apt-get install -y linux-image-armmp-lpae + +# Configure kernel boot args +log "setting kernel boot arguments" +cat < "$rootfs/etc/default/flash-kernel" +LINUX_KERNEL_CMDLINE="quiet" +LINUX_KERNEL_CMDLINE_DEFAULTS="console=ttyAMA0 root=/dev/mmcblk0p2" +EOF +chroot_exec flash-kernel + +# Set up hostname configuration +log "configuring network host names" +echo "$hostname" > "$rootfs/etc/hostname" +sed -i "/^127.0.0.1/ s/\$/ $hostname/" "$rootfs/etc/hosts" +sed -i "/^::1/ s/\$/ $hostname/" "$rootfs/etc/hosts" + +# Set up network interfaces +log "configuring network interfaces" +cat > "$rootfs/etc/network/interfaces.d/lo" < "$rootfs/etc/network/interfaces.d/eth0" < "$rootfs/root/.ssh/authorized_keys" + chmod 600 "$rootfs/root/.ssh/authorized_keys" + sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' "$rootfs/etc/ssh/sshd_config" + echo "SSH password login disabled. Use the key in $ssh_key to login." 1>&2 +else + sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/g' "$rootfs/etc/ssh/sshd_config" + echo "Warning: SSH password login is enabled! This can be a security risk." 1>&2 +fi + +# Prepare first boot +log "setting up first boot script" +chroot_exec apt-get -y install parted +cat <<'EOM' > "$rootfs/etc/rc.firstboot" +#!/bin/bash +set -e +logger -t "rc.firstboot" "Starting first boot" + +led_blink() { + local led=/sys/class/leds/"$1" + + local time_on="$2" + local time_off="$time_on" + local blinks="$3" + + local trigger=$(cat "$led/trigger" | sed 's/.*\[\(.*\)\].*/\1/g' -) + local brightness=$(cat "$led/brightness") + + echo "none" > "$led/trigger" + for i in $(seq 1 $blinks); do + echo 255 > "$led/brightness" + sleep "$time_on" + echo 0 > "$led/brightness" + sleep "$time_off" + done + echo "$brightness" > "$led/brightness" + echo "$trigger" > "$led/trigger" +} + +led_trigger() { + local led=/sys/class/leds/"$1" + + if [ "$2" == "heartbeat" ]; then + modprobe ledtrig_heartbeat || true + fi + echo "$2" > "$led/trigger" +} + +led_blink ACT 0.1 20 & +led_blink PWR 0.1 20 +led_trigger PWR heartbeat +led_trigger ACT mmc0 + +logger -t "rc.firstboot" "Generating ssh host keys" +rm -f /etc/ssh/ssh_host_* +systemctl stop sshd +ssh-keygen -q -t rsa -N "" -f /etc/ssh/ssh_host_rsa_key +ssh-keygen -q -t dsa -N "" -f /etc/ssh/ssh_host_dsa_key +ssh-keygen -q -t ecdsa -N "" -f /etc/ssh/ssh_host_ecdsa_key +ssh-keygen -q -t ed25519 -N "" -f /etc/ssh/ssh_host_ed25519_key +systemctl start sshd + +logger -t "rc.firstboot" "Expanding root file system" +fdisk /dev/mmcblk0 < "$rootfs/etc/rc.local" +#!/bin/sh -e +/etc/rc.firstboot +exit 0 +EOF +chmod +x "$rootfs/etc/rc.local" cleanup -echo "Successfully created rootfs" 1>&2 + +log "done" diff --git a/mkrootfs.d/01-apt.sh b/mkrootfs.d/01-apt.sh deleted file mode 100644 index 9bda665..0000000 --- a/mkrootfs.d/01-apt.sh +++ /dev/null @@ -1,5 +0,0 @@ -cat > "$ROOTFS/etc/apt/sources.list" < "$ROOTFS/etc/flash-kernel/machine" -echo 'LINUX_KERNEL_CMDLINE="console=ttyS0,115200 hdmi.audio=EDID:0 disp.screen0_output_mode=EDID:1280x1024p60 rootfstype=ext4 root=/dev/mmcblk0p1 rootwait panic=10 ${extra}"' >> "$ROOTFS/etc/default/flash-kernel" - -# Enable specific modules at startup -echo "rtc_sunxi" >> "$ROOTFS/etc/initramfs-tools/modules" -echo "mmc_core" >> "$ROOTFS/etc/initramfs-tools/modules" -echo "mmc_block" >> "$ROOTFS/etc/initramfs-tools/modules" -echo "sdhci" >> "$ROOTFS/etc/initramfs-tools/modules" -echo "sdhci-pci" >> "$ROOTFS/etc/initramfs-tools/modules" - -chroot_exec flash-kernel diff --git a/mkrootfs.d/03-fstab.sh b/mkrootfs.d/03-fstab.sh deleted file mode 100644 index 835afc6..0000000 --- a/mkrootfs.d/03-fstab.sh +++ /dev/null @@ -1,5 +0,0 @@ -# Configure fstab -cat > "$ROOTFS/etc/fstab" < "$ROOTFS/etc/hostname" -sed -i "/^127.0.0.1/ s/\$/ $HOSTNAME/" "$ROOTFS/etc/hosts" -sed -i "/^::1/ s/\$/ $HOSTNAME/" "$ROOTFS/etc/hosts" - -# Set up networking -cat > "$ROOTFS/etc/network/interfaces.d/lo" < "$ROOTFS/etc/network/interfaces.d/eth0" <> "$ROOTFS/etc/inittab" - -if [ -e "$SSH_KEY" ]; then - chroot_exec apt-get -y install openssh-server - mkdir -p "$ROOTFS/root/.ssh" - chmod 600 "$ROOTFS/root/.ssh" - cat "$SSH_KEY" > "$ROOTFS/root/.ssh/authorized_keys" - chmod 600 "$ROOTFS/root/.ssh/authorized_keys" - sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' "$ROOTFS/etc/ssh/sshd_config" - # Lock root account password - chroot_exec passwd -l root - echo "Success: root's account was locked and SSH password login disabled. Use the key in $SSH_KEY to login." 1>&2 -else - sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/g' "$ROOTFS"/etc/ssh/sshd_config - chroot_exec echo "root:guest" | chpasswd - echo "Warning: no SSH key found, root's password has been set to 'guest' and SSH password login has been enabled! This can be a security risk if the device is exposed to a public network." 1>&2 -fi diff --git a/mkrootimg b/mkrootimg index 01d509b..22a492f 100755 --- a/mkrootimg +++ b/mkrootimg @@ -3,36 +3,19 @@ set -e print_usage() { cat 1>&2 < +Package the contents of a debian root filesystem into a binary image file, ready to be burned onto an sd card. EOF } -# Process options -# -while [ $# -gt 2 ] -do - case "$1" in - --help|-h) - print_usage - exit 0 - ;; - *) - echo "Unknown option '$1'" 1>&2 - exit 1 - esac - shift -done - -# Process last argument, the root file system location -if [ -z "$1" ] || [ -z "$2" ] || [ "$1" = -h ] || [ "$1" = --help ]; then - print_usage - exit 1 -fi -if [ "$EUID" -ne 0 ]; then - echo "This must be run as root." 1>&2 +fail() { + echo "$1" >&2 exit 1 -fi +} + +log() { + echo "mkrootimg: $1" >&2 +} # Directory to package rootfs="$1" @@ -40,46 +23,90 @@ rootfs="$1" # Binary image file image="$2" -# Number of 512-byte sectors reserved at the beginning of the image -# (usually 1M for e.g. a bootloader) -table_sectors=$(expr 1 \* 1024 \* 1024 \/ 512) - -# Calculate size of the rootfs directory in KB -rootfs_size=$(expr `du -s "${rootfs}" | awk '{ print $1 }'`) - -# The root partition is EXT4 -# This means more space than the actual used space of the rootfs is used. -# As overhead for journaling and reserved blocks 25% are added. -rootfs_sectors=$(expr $(expr ${rootfs_size} + ${rootfs_size} \/ 100 \* 25) \* 1024 \/ 512) +# Contains temporary build files +builddir=$(mktemp -d) -# Calculate required image size in 512 Byte sectors -image_sectors=$(expr ${table_sectors} + ${rootfs_sectors}) +([ -n "$rootfs" ] && [ -n "$image" ]) || fail "$(print_usage)" +[ -d "$rootfs" ] || fail "$rootfs does not exist or is not a directory" +[ ! -e "$image" ] || fail "$image already exists" -# Initialize image file -dd if=/dev/zero of="$image" bs=512 count=${table_sectors} -dd if=/dev/zero of="$image" bs=512 count=0 seek=${image_sectors} - -# Write partition table -sfdisk "$image" < /dev/null + set +e + umount --lazy "$builddir/mount/boot/firmware" 2> /dev/null + umount --lazy "$builddir/mount" 2> /dev/null + sync + losetup --detach "$bootfs_loop" 2> /dev/null + losetup --detach "$rootfs_loop" 2> /dev/null + rm -rf "$builddir" trap - 0 1 2 3 6 } trap cleanup 0 1 2 3 6 -# Mount the temporary loop devices -mount_dir=$(mktemp -d) -mount "$image_loop" "$mount_dir" +# Partition layout +# +# Content Size +# --------------------------------------------- +# reserved 1024k (1M, for e.g. a bootloader) +# bootfs 100*1024k (100M) +# rootfs as required + +# size in bytes +reserved_size=1024*1024 +bootfs_size=$((100*1024*1024)) +rootfs_size=$(du --block-size=1 -s "$rootfs" | awk '{ print $1 }') + +# converted to 512-byte sectors +reserved_sectors=$(( $reserved_size / 512 )) +bootfs_sectors=$(( $bootfs_size / 512 )) +# as overhead for journaling and reserved blocks 25% are added. +rootfs_sectors=$(( ($rootfs_size + $rootfs_size * 25 / 100) / 512 )) +image_sectors=$(( $reserved_sectors + $bootfs_sectors + $rootfs_sectors )) + +# create empty image file +log "creating empty image" +dd if=/dev/zero of="$image" bs=512 count="$image_sectors" status=none + +# write partition table to image +log "partitioning image" +sfdisk --label dos -q -uS "$image" < /dev/null +$reserved_sectors,$bootfs_sectors,c,* +,$rootfs_sectors,L, +EOF -# Copy all files from the chroot to the loop device mount point directory -rsync -a "$rootfs/" "$mount_dir" -umount "$mount_dir" +# set up temporary loop devices +log "setting up image loop devices" +bootfs_loop=$(losetup \ + --offset $(( $reserved_sectors * 512 )) \ + --sizelimit $(( $bootfs_sectors * 512 )) \ + --find \ + --show \ + "$image") +rootfs_loop=$(losetup \ + --offset $(( ($reserved_sectors + $bootfs_sectors) * 512 )) \ + --sizelimit $(( $rootfs_sectors * 512 )) \ + --find \ + --show \ + "$image") + +# format partitions +log "formatting partitions" +mkfs.vfat -F 32 "$bootfs_loop" &> /dev/null +mkfs.ext4 -O^64bit "$rootfs_loop" &> /dev/null + +# mount partitions +log "mounting partitions" +mkdir -p "$builddir/mount" +mount "$rootfs_loop" "$builddir/mount" +mkdir -p "$builddir/mount/boot/firmware" +mount "$bootfs_loop" "$builddir/mount/boot/firmware" + +# copy root filesystem to image +log "copying root filesystem" +rsync -a "$rootfs/" "$builddir/mount/" + +log "cleaning up" cleanup + +log "done" -- cgit v1.2.3