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 --- mkrootfs | 372 ++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 274 insertions(+), 98 deletions(-) (limited to 'mkrootfs') 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" -- cgit v1.2.3