aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jakob@odersky.com>2018-10-25 13:39:22 -0700
committerJakob Odersky <jakob@odersky.com>2018-10-25 13:39:22 -0700
commit802e1268022d8398c565601fd324994e5eab5ca8 (patch)
tree8613df8340e9f7b5a6e27c654797f18853948114
parentcfeb980e870a799676f07bb393c4957cfdd9e3a0 (diff)
downloadinfra-802e1268022d8398c565601fd324994e5eab5ca8.tar.gz
infra-802e1268022d8398c565601fd324994e5eab5ca8.tar.bz2
infra-802e1268022d8398c565601fd324994e5eab5ca8.zip
Add base image scripts for single-board computers
-rw-r--r--images/.gitignore2
-rw-r--r--images/cubieboard-2/Makefile29
-rw-r--r--images/cubieboard-2/README.md23
-rw-r--r--images/cubieboard-2/bootloader/Makefile37
-rw-r--r--images/cubieboard-2/rootfs/Makefile61
-rw-r--r--images/cubieboard-2/rootfs/firstboot42
-rwxr-xr-ximages/cubieboard-2/scripts/mkrootimg96
-rw-r--r--images/raspberry-pi-2/Makefile99
-rw-r--r--images/raspberry-pi-2/README.md17
-rw-r--r--images/raspberry-pi-2/firstboot82
-rwxr-xr-ximages/raspberry-pi-2/scripts/mkrootimg107
11 files changed, 595 insertions, 0 deletions
diff --git a/images/.gitignore b/images/.gitignore
new file mode 100644
index 0000000..6459df1
--- /dev/null
+++ b/images/.gitignore
@@ -0,0 +1,2 @@
+*.raw
+*.bmap
diff --git a/images/cubieboard-2/Makefile b/images/cubieboard-2/Makefile
new file mode 100644
index 0000000..e25b0c2
--- /dev/null
+++ b/images/cubieboard-2/Makefile
@@ -0,0 +1,29 @@
+BOOTLOADER=bootloader/u-boot-sunxi-with-spl.bin
+ROOTFS=rootfs/rootfs
+IMAGE=image
+
+all: $(IMAGE).bmap
+
+$(BOOTLOADER):
+ $(MAKE) -C bootloader u-boot-sunxi-with-spl.bin
+
+$(ROOTFS):
+ $(MAKE) -C rootfs rootfs.customized
+
+$(IMAGE).raw: $(BOOTLOADER) $(ROOTFS)
+ scripts/mkrootimg $(ROOTFS) $(IMAGE).raw
+ dd conv=notrunc if=$(BOOTLOADER) of=$(IMAGE).raw bs=1024 seek=8
+ touch $(IMAGE).raw
+
+$(IMAGE).bmap: $(IMAGE).raw
+ bmaptool create -o $(IMAGE).bmap $(IMAGE).raw
+
+clean:
+ $(MAKE) -C bootloader clean
+ $(MAKE) -C rootfs clean
+
+mrproper: clean
+ rm -f $(IMAGE).raw
+ rm -f $(IMAGE).bmap
+
+.PHONY: all clean mrproper
diff --git a/images/cubieboard-2/README.md b/images/cubieboard-2/README.md
new file mode 100644
index 0000000..9662bdf
--- /dev/null
+++ b/images/cubieboard-2/README.md
@@ -0,0 +1,23 @@
+# Minimal Debian Image for the Cubieboard 2
+
+Makefile for building a bootable image that may be directly flashed to a memory card and used with a Cubieboard 2.
+
+The image contains a very basic Debian installation with an OpenSSH server. It is also self-expanding: on first boot, the partitions contained in the image will be expanded to fill the availale size of the memory card.
+
+## Requirements
+
+Import (and trust) u-boot release key:
+
+ gpg --recv-keys E872DB409C1A687EFBE8633687F9F635D31D7652
+
+## Build
+
+*Note: creating the image requires super user privileges because `chroot` is invoked as part of the build process. The bootloader (in bootloader/) may be built without root.*
+
+Run the following to build a flashable image:
+
+ sudo make SSH_KEY_FILE=<path>
+
+where `SSH_KEY_FILE` is the absolute path of an SSH public key that will be used to login. SSH password login will be disabled, although the root account will nevertheless have its password set to "guest".
+
+This results in two image files `image.raw` and `image.bmap`. The former may be directly flashed to a memory card with a utility such as `dd`, whereas the latter is to be used with `bmaptool` (which promises perfomance increases of the flashing process).
diff --git a/images/cubieboard-2/bootloader/Makefile b/images/cubieboard-2/bootloader/Makefile
new file mode 100644
index 0000000..448c68b
--- /dev/null
+++ b/images/cubieboard-2/bootloader/Makefile
@@ -0,0 +1,37 @@
+BOOTLOADER_VERSION=2017.09
+
+ARCHIVE=u-boot.tar.bz2
+DIRECTORY=u-boot-$(BOOTLOADER_VERSION)
+BINARY=u-boot-sunxi-with-spl.bin
+
+all: $(BINARY)
+
+clean:
+ rm -f $(ARCHIVE)
+ rm -f $(ARCHIVE).sig
+ rm -f .u-boot.trusted
+ rm -rf $(DIRECTORY)
+ rm -f $(BINARY)
+
+$(ARCHIVE):
+ wget -O $(ARCHIVE) \
+ ftp://ftp.denx.de/pub/u-boot/u-boot-$(BOOTLOADER_VERSION).tar.bz2
+
+$(ARCHIVE).sig:
+ wget -O $(ARCHIVE).sig \
+ ftp://ftp.denx.de/pub/u-boot/u-boot-$(BOOTLOADER_VERSION).tar.bz2.sig
+
+.u-boot.trusted: $(ARCHIVE) $(ARCHIVE).sig
+ gpg --verify $(ARCHIVE).sig && touch .u-boot.trusted
+
+$(DIRECTORY): $(ARCHIVE) .u-boot.trusted
+ tar -xjf $(ARCHIVE)
+ touch $(DIRECTORY)
+
+$(BINARY): $(DIRECTORY)
+ $(MAKE) CROSS_COMPILE=arm-linux-gnueabihf- -C $(DIRECTORY) Cubieboard2_defconfig
+ $(MAKE) CROSS_COMPILE=arm-linux-gnueabihf- -C $(DIRECTORY)
+ cp $(DIRECTORY)/u-boot-sunxi-with-spl.bin $(BINARY)
+
+
+.PHONY: all clean
diff --git a/images/cubieboard-2/rootfs/Makefile b/images/cubieboard-2/rootfs/Makefile
new file mode 100644
index 0000000..7a0da65
--- /dev/null
+++ b/images/cubieboard-2/rootfs/Makefile
@@ -0,0 +1,61 @@
+SSH_KEY_FILE?=$(HOME)/.ssh/id_rsa.pub
+DISTRIBUTION=stretch
+ROOTFS=rootfs
+
+all: $(ROOTFS).customized
+
+$(ROOTFS).debootstrapped:
+# apt-cacher-ng listens on port 3142
+ http_proxy="http://localhost:3142" \
+ qemu-debootstrap \
+ --include=linux-image-armmp-lpae,flash-kernel,u-boot-tools,parted,dbus,apt,openssh-server \
+ --arch=armhf \
+ $(DISTRIBUTION) \
+ $(ROOTFS) \
+ http://httpredir.debian.org/debian
+ touch $(ROOTFS).debootstrapped
+
+$(ROOTFS).customized: $(ROOTFS).debootstrapped
+ echo "cube" > $(ROOTFS)/etc/hostname
+
+ echo "127.0.0.1 localhost" > $(ROOTFS)/etc/hosts
+ echo "::1 localhost" >> $(ROOTFS)/etc/hosts
+
+ echo "deb http://httpredir.debian.org/debian $(DISTRIBUTION) main contrib non-free" > $(ROOTFS)/etc/apt/sources.list
+ echo "deb http://httpredir.debian.org/debian $(DISTRIBUTION)-updates main contrib non-free" >> $(ROOTFS)/etc/apt/sources.list
+ echo "deb http://security.debian.org $(DISTRIBUTION)/updates main contrib non-free" >> $(ROOTFS)/etc/apt/sources.list
+
+ echo "auto lo" > "$(ROOTFS)/etc/network/interfaces.d/lo"
+ echo "iface lo inet loopback" >> "$(ROOTFS)/etc/network/interfaces.d/lo"
+
+ echo "allow-hotplug eth0" > "$(ROOTFS)/etc/network/interfaces.d/eth0"
+ echo "iface eth0 inet dhcp" >> "$(ROOTFS)/etc/network/interfaces.d/eth0"
+
+ echo "/dev/mmcblk0p1 / ext4 defaults 0 1" > $(ROOTFS)/etc/fstab
+ echo "tmpfs /tmp tmpfs defaults 0 0" >> $(ROOTFS)/etc/fstab
+
+ echo "Cubietech Cubieboard2" > $(ROOTFS)/etc/flash-kernel/machine
+ echo 'LINUX_KERNEL_CMDLINE="console=ttyS0,115200 root=/dev/mmcblk0p1 rootwait panic=10 ${extra}"' > $(ROOTFS)/etc/default/flash-kernel
+ echo "setenv ethaddr 02:00:00:00:00:01" > $(ROOTFS)/etc/flash-kernel/ubootenv.d/50-ethaddr
+ chroot $(ROOTFS) flash-kernel
+
+ mkdir -p -m 0600 $(ROOTFS)/root/.ssh
+ cat $(SSH_KEY_FILE) > $(ROOTFS)/root/.ssh/authorized_keys
+ sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' "$(ROOTFS)/etc/ssh/sshd_config"
+ chroot $(ROOTFS) sh -c "echo root:guest | chpasswd"
+
+ cp firstboot $(ROOTFS)/etc/firstboot
+ chmod +x $(ROOTFS)/etc/firstboot
+ echo "#!/bin/sh -e" > $(ROOTFS)/etc/rc.local
+ echo "/etc/firstboot" >> $(ROOTFS)/etc/rc.local
+ echo "exit 0" >> $(ROOTFS)/etc/rc.local
+ chmod +x $(ROOTFS)/etc/rc.local
+
+ touch $(ROOTFS).customized
+
+clean:
+ rm -rf $(ROOTFS)
+ rm -f $(ROOTFS).debootstrapped
+ rm -f $(ROOTFS).customized
+
+.PHONY: all clean
diff --git a/images/cubieboard-2/rootfs/firstboot b/images/cubieboard-2/rootfs/firstboot
new file mode 100644
index 0000000..fab67cd
--- /dev/null
+++ b/images/cubieboard-2/rootfs/firstboot
@@ -0,0 +1,42 @@
+#!/bin/bash
+set -e
+echo "first boot: starting"
+
+echo "first boot: generating ssh host keys"
+systemctl stop sshd
+rm -f /etc/ssh/ssh_host_*
+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
+
+echo "first boot: generating dbus machine-id"
+rm -f /var/lib/dbus/machine-id
+dbus-uuidgen --ensure
+
+echo "first boot: expanding root file system"
+fdisk /dev/mmcblk0 <<EOF || true
+p
+d
+1
+n
+p
+1
+
+
+n
+w
+EOF
+partprobe
+resize2fs /dev/mmcblk0p1
+
+echo "first boot: generating initramfs"
+update-initramfs -u
+
+echo "first boot: deleting script"
+rm -f /etc/firstboot
+sed -i '/.*firstboot/d' /etc/rc.local
+
+echo "first boot: finished"
+reboot
diff --git a/images/cubieboard-2/scripts/mkrootimg b/images/cubieboard-2/scripts/mkrootimg
new file mode 100755
index 0000000..4c915ce
--- /dev/null
+++ b/images/cubieboard-2/scripts/mkrootimg
@@ -0,0 +1,96 @@
+#!/bin/bash
+set -e
+
+print_usage() {
+ cat 1>&2 <<EOF
+Usage: $0 <rootfs_directory> <image_file>
+Package the contents of a debian root filesystem into a binary image file, ready to be burned onto an sd card.
+
+This script will create an image with a single root partition.
+EOF
+}
+
+fail() {
+ echo "$1" >&2
+ exit 1
+}
+
+log() {
+ echo "mkrootimg: $1" >&2
+}
+
+# Directory to package
+rootfs="$1"
+
+# Binary image file
+image="$2"
+
+# Contains temporary build files
+builddir=$(mktemp -d)
+
+([ -n "$rootfs" ] && [ -n "$image" ]) || fail "$(print_usage)"
+[ -d "$rootfs" ] || fail "$rootfs does not exist or is not a directory"
+
+[ "$EUID" -eq 0 ] || fail "$0 must be run as root"
+
+cleanup() {
+ set +e
+ umount --lazy "$builddir/mount" 2> /dev/null
+ sync
+ losetup --detach "$rootfs_loop" 2> /dev/null
+ rm -rf "$builddir"
+ trap - 0 1 2 3 6
+}
+trap cleanup 0 1 2 3 6
+
+# Partition layout
+#
+# Content Size
+# ---------------------------------------------
+# reserved 1024k (1M, for e.g. a bootloader)
+# rootfs as required
+
+# size in bytes
+reserved_size=$((1024*1024))
+rootfs_raw_size=$(du --block-size=1 -s "$rootfs" | awk '{ print $1 }')
+# as overhead for journaling and reserved blocks, 25% is added
+rootfs_size=$(( rootfs_raw_size + rootfs_raw_size * 25 / 100 ))
+image_size=$(( reserved_size + rootfs_size + 1))
+
+# create empty image file
+log "creating empty image"
+rm -rf "$image"
+truncate -s "$image_size" "$image"
+# round up 4096-byte sector size to avoid rounding errors
+truncate -s %4096 "$image"
+
+# write partition table to image
+parted "$image" --script mklabel msdos
+parted "$image" --script mkpart primary ext4 "$reserved_size"B $(( reserved_size + rootfs_size ))B
+
+# set up temporary loop devices
+log "setting up image loop devices"
+rootfs_loop=$(losetup \
+ --offset "$reserved_size" \
+ --sizelimit "$rootfs_size" \
+ --find \
+ --show \
+ "$image")
+
+# format partitions
+log "formatting partitions"
+mkfs.ext4 -O^64bit "$rootfs_loop" &> /dev/null
+
+# mount partitions
+log "mounting partitions"
+mkdir -p "$builddir/mount"
+mount "$rootfs_loop" "$builddir/mount"
+
+# copy root filesystem to image
+log "copying root filesystem"
+rsync -a "$rootfs/" "$builddir/mount/"
+
+log "cleaning up"
+cleanup
+
+log "done"
diff --git a/images/raspberry-pi-2/Makefile b/images/raspberry-pi-2/Makefile
new file mode 100644
index 0000000..1c38efd
--- /dev/null
+++ b/images/raspberry-pi-2/Makefile
@@ -0,0 +1,99 @@
+SSH_KEY_FILE?=$(HOME)/.ssh/id_rsa.pub
+DISTRIBUTION=stretch
+ROOTFS=rootfs
+IMAGE=image
+
+all: $(IMAGE).bmap
+
+$(ROOTFS).debootstrapped:
+# apt-cacher-ng listens on port 3142
+ http_proxy="http://localhost:3142" \
+ qemu-debootstrap \
+ --include=linux-image-armmp-lpae,flash-kernel,u-boot-tools,u-boot-rpi,parted,dbus,apt,openssh-server \
+ --arch=armhf \
+ $(DISTRIBUTION) \
+ $(ROOTFS) \
+ http://httpredir.debian.org/debian
+ touch $(ROOTFS).debootstrapped
+
+# configure fstab
+$(ROOTFS).customized: $(ROOTFS).debootstrapped
+ echo "/dev/mmcblk0p1 /boot/firmware vfat noatime 0 2" > $(ROOTFS)/etc/fstab
+ echo "/dev/mmcblk0p2 / ext4 defaults 0 1" >> $(ROOTFS)/etc/fstab
+ echo "tmpfs /tmp tmpfs defaults 0 0" >> $(ROOTFS)/etc/fstab
+
+# install proprietary 2nd-stage bootloader firmware
+ mkdir -p "$(ROOTFS)/boot/firmware"
+ wget -O "$(ROOTFS)/boot/firmware/bootcode.bin" \
+ https://github.com/raspberrypi/firmware/raw/master/boot/bootcode.bin
+ wget -O "$(ROOTFS)/boot/firmware/start.elf" \
+ https://github.com/raspberrypi/firmware/raw/master/boot/start.elf
+ wget -O "$(ROOTFS)/boot/firmware/fixup.dat" \
+ https://github.com/raspberrypi/firmware/raw/master/boot/fixup.dat
+
+# configure u-boot 3rd-stage bootloader
+# https://blog.night-shade.org.uk/2015/05/booting-a-raspberry-pi2-with-u-boot-and-hyp-enabled/
+ cp "$(ROOTFS)/usr/lib/u-boot/rpi_2/u-boot.bin" "$(ROOTFS)/boot/firmware/u-boot.bin"
+ echo "gpu_mem=64" > "$(ROOTFS)/boot/firmware/config.txt"
+ echo "kernel=u-boot.bin" >> "$(ROOTFS)/boot/firmware/config.txt"
+
+# configure kernel flashing utility
+# http://sjoerd.luon.net/posts/2015/02/debian-jessie-on-rpi2/
+ echo "Raspberry Pi 2 Model B" > "$(ROOTFS)/etc/flash-kernel/machine"
+ echo "setenv distro_bootpart 2" > "$(ROOTFS)/etc/flash-kernel/ubootenv.d/10-partition"
+ echo "setenv prefix /boot/" >> "$(ROOTFS)/etc/flash-kernel/ubootenv.d/10-partition"
+ 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"
+
+# configure kernel boot args
+ echo 'LINUX_KERNEL_CMDLINE="quiet"' > "$(ROOTFS)/etc/default/flash-kernel"
+ echo 'LINUX_KERNEL_CMDLINE_DEFAULTS="console=ttyAMA0 root=/dev/mmcblk0p2"' >> "$(ROOTFS)/etc/default/flash-kernel"
+ chroot $(ROOTFS) flash-kernel
+
+# configure other system settings
+ echo "pi" > $(ROOTFS)/etc/hostname
+
+ echo "127.0.0.1 localhost" > $(ROOTFS)/etc/hosts
+ echo "::1 localhost" >> $(ROOTFS)/etc/hosts
+
+ echo "deb http://httpredir.debian.org/debian $(DISTRIBUTION) main contrib non-free" > $(ROOTFS)/etc/apt/sources.list
+ echo "deb http://httpredir.debian.org/debian $(DISTRIBUTION)-updates main contrib non-free" >> $(ROOTFS)/etc/apt/sources.list
+ echo "deb http://security.debian.org $(DISTRIBUTION)/updates main contrib non-free" >> $(ROOTFS)/etc/apt/sources.list
+
+ echo "auto lo" > "$(ROOTFS)/etc/network/interfaces.d/lo"
+ echo "iface lo inet loopback" >> "$(ROOTFS)/etc/network/interfaces.d/lo"
+
+ echo "allow-hotplug eth0" > "$(ROOTFS)/etc/network/interfaces.d/eth0"
+ echo "iface eth0 inet dhcp" >> "$(ROOTFS)/etc/network/interfaces.d/eth0"
+
+ mkdir -p -m 0600 $(ROOTFS)/root/.ssh
+ cat $(SSH_KEY_FILE) > $(ROOTFS)/root/.ssh/authorized_keys
+ sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' "$(ROOTFS)/etc/ssh/sshd_config"
+ chroot $(ROOTFS) sh -c "echo root:guest | chpasswd"
+
+ cp firstboot $(ROOTFS)/etc/firstboot
+ chmod +x $(ROOTFS)/etc/firstboot
+ echo "#!/bin/sh -e" > $(ROOTFS)/etc/rc.local
+ echo "/etc/firstboot" >> $(ROOTFS)/etc/rc.local
+ echo "exit 0" >> $(ROOTFS)/etc/rc.local
+ chmod +x $(ROOTFS)/etc/rc.local
+
+ touch $(ROOTFS).customized
+
+$(IMAGE).raw: $(ROOTFS).customized
+ scripts/mkrootimg $(ROOTFS) $(IMAGE).raw
+ touch $(IMAGE).raw
+
+$(IMAGE).bmap: $(IMAGE).raw
+ bmaptool create -o $(IMAGE).bmap $(IMAGE).raw
+
+clean:
+ rm -rf $(ROOTFS)
+ rm -f $(ROOTFS).debootstrapped
+ rm -f $(ROOTFS).customized
+
+mrproper: clean
+ rm -f $(IMAGE).raw
+ rm -f $(IMAGE).bmap
+
+.PHONY: all clean mrproper
diff --git a/images/raspberry-pi-2/README.md b/images/raspberry-pi-2/README.md
new file mode 100644
index 0000000..9d4ed0f
--- /dev/null
+++ b/images/raspberry-pi-2/README.md
@@ -0,0 +1,17 @@
+# Minimal Debian Image for the Raspberry Pi 2
+
+Makefile for building a bootable image that may be directly flashed to a memory card and used with a Raspberry Pi 2 Model B.
+
+The image contains a very basic Debian installation with an OpenSSH server. It is also self-expanding: on first boot, the partitions contained in the image will be expanded to fill the availale size of the memory card.
+
+## Build
+
+*Note: creating the image requires super user privileges because `chroot` is invoked as part of the build process.*
+
+Run the following to build a flashable image:
+
+ sudo make SSH_KEY_FILE=<path>
+
+where `SSH_KEY_FILE` is the absolute path of an SSH public key that will be used to login. SSH password login will be disabled, although the root account will nevertheless have its password set to "guest".
+
+This results in two image files `image.raw` and `image.bmap`. The former may be directly flashed to a memory card with a utility such as `dd`, whereas the latter is to be used with `bmaptool` (which promises perfomance increases of the flashing process).
diff --git a/images/raspberry-pi-2/firstboot b/images/raspberry-pi-2/firstboot
new file mode 100644
index 0000000..c384d50
--- /dev/null
+++ b/images/raspberry-pi-2/firstboot
@@ -0,0 +1,82 @@
+#!/bin/bash
+set -e
+echo "first boot: starting"
+
+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"
+}
+
+echo "first boot: starting led trigger"
+led_blink ACT 0.1 20 &
+led_blink PWR 0.1 20
+led_trigger PWR heartbeat
+led_trigger ACT mmc0
+
+echo "first boot: generating ssh host keys"
+systemctl stop sshd
+rm -f /etc/ssh/ssh_host_*
+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
+
+echo "first boot: generating dbus machine-id"
+rm -f /var/lib/dbus/machine-id
+dbus-uuidgen --ensure
+
+echo "first boot: expanding root file system"
+fdisk /dev/mmcblk0 <<EOF || true
+p
+d
+2
+n
+p
+2
+
+
+n
+w
+EOF
+partprobe
+resize2fs /dev/mmcblk0p2
+
+echo "first boot: generating initramfs"
+update-initramfs -u
+
+echo "first boot: deleting script"
+rm -f /etc/firstboot
+sed -i '/.*firstboot/d' /etc/rc.local
+
+echo "first boot: stopping led trigger"
+led_trigger ACT heartbeat
+led_trigger PWR none
+
+echo "first boot: finished"
+reboot
diff --git a/images/raspberry-pi-2/scripts/mkrootimg b/images/raspberry-pi-2/scripts/mkrootimg
new file mode 100755
index 0000000..ff4f07c
--- /dev/null
+++ b/images/raspberry-pi-2/scripts/mkrootimg
@@ -0,0 +1,107 @@
+#!/bin/bash
+set -e
+
+print_usage() {
+ cat 1>&2 <<EOF
+Usage: $0 <rootfs_directory> <image_file>
+Package the contents of a debian root filesystem into a binary image file, ready to be burned onto an sd card.
+
+This script will create an image with two partitions, the first one for /boot/firmware and the second one for /.
+EOF
+}
+
+fail() {
+ echo "$1" >&2
+ exit 1
+}
+
+log() {
+ echo "mkrootimg: $1" >&2
+}
+
+# Directory to package
+rootfs="$1"
+
+# Binary image file
+image="$2"
+
+# Contains temporary build files
+builddir=$(mktemp -d)
+
+([ -n "$rootfs" ] && [ -n "$image" ]) || fail "$(print_usage)"
+[ -d "$rootfs" ] || fail "$rootfs does not exist or is not a directory"
+
+[ "$EUID" -eq 0 ] || fail "$0 must be run as root"
+
+cleanup() {
+ 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
+
+# Partition layout
+#
+# Content Size
+# ---------------------------------------------
+# reserved 1024k (1M, for e.g. a bootloader)
+# bootfs 100*1024k (100M)
+# rootfs as required
+
+# calculate minimum required space for root partition
+# (with 25% overhead for reserved blocks and journaling)
+rootfs_raw_size_min=$(du --block-size=1M -s "$rootfs" | awk '{ print $1 }')
+rootfs_size_min=$(( rootfs_raw_size_min + rootfs_raw_size_min * 25 / 100 ))
+
+# create and partition image file
+truncate --size $(( 1 + 100 + rootfs_size_min ))M "$image"
+parted "$image" --script mklabel msdos
+parted "$image" --script mkpart primary fat32 1M 100M
+parted "$image" --script mkpart primary ext4 100M 100%
+
+# get actual byte offsets of the partitions within the image
+bootfs_start=$(parted --machine --script "$image" unit B print | grep '^1:' | cut -d ':' -f 2 | sed 's/B//g')
+bootfs_size=$(parted --machine --script "$image" unit B print | grep '^1:' | cut -d ':' -f 4 | sed 's/B//g')
+rootfs_start=$(parted --machine --script "$image" unit B print | grep '^2:' | cut -d ':' -f 2 | sed 's/B//g')
+rootfs_size=$(parted --machine --script "$image" unit B print | grep '^2:' | cut -d ':' -f 4 | sed 's/B//g')
+
+# set up temporary loop devices
+log "setting up image loop devices"
+bootfs_loop=$(losetup \
+ --offset "$bootfs_start" \
+ --sizelimit "$bootfs_size" \
+ --find \
+ --show \
+ "$image")
+rootfs_loop=$(losetup \
+ --offset "$rootfs_start" \
+ --sizelimit "$rootfs_size" \
+ --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"