#!/bin/bash set -e hostname=pi ssh_key="$HOME/.ssh/id_rsa.pub" release=stretch rootfs= print_usage() { cat < 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 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 } 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) shift [[ -z "$1" ]] && fail "no hostname specified" hostname="$1" ;; --release) shift [[ -z "$1" ]] && fail "no release specified" release="$1" ;; --ssh-key) shift [[ -z "$1" ]] && fail "no ssh-key specified" ssh_key="$1" ;; --no-debootstrap) nodeboostrap=true ;; *) [[ -n "$rootfs" ]] && fail "rootfs already defined" rootfs="$1" ;; esac shift done [ -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 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() { LANG=C LC_ALL=C DEBIAN_FRONTEND=noninteractive chroot "$rootfs" "$@" } # Unmount and remove any temporary files cleanup() { log "cleaning" set +e 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 # 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 log "done"