From 8c4d00155e324c774af19f137d805ca920219a6d Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Tue, 15 Sep 2015 14:42:37 +0200 Subject: initial commit --- README.md | 49 ++++++++++++ pistrap-debian | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 285 insertions(+) create mode 100644 README.md create mode 100755 pistrap-debian diff --git a/README.md b/README.md new file mode 100644 index 0000000..ac8df11 --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +# pistrap-debian + +Create a bootable Debian SD card for the RaspberryPi 2. + +Pistrap-debian is a shell script that partitions and mounts an SD card and subsequently creates a bootable root file system for the RaspberryPi 2. + +The root filesystem is that of a minimal Debian Jessie distribution with the kernel pulled in from the Raspbian archive. Furthermore, hostnames, timezones, passwords, networking and SSH are setup as to remove the need of any additional screen-and-keyboard configuration. + +## Requirements +Debian-based host system with the following packages: + +- qemu-user-static +- parted + +The resulting image is only compatible with ARMv7 processors (armhf Debian distribution), hence the requirement of a RaspberryPi 2. + +## Usage +``` +Usage: pistrap-debian [OPTION]... DEVICE + +Create a bootable image for a RaspberryPi 2 on DEVICE. + +Options: + --force Don't ask for any confirmations. + --mirror=<$MIRROR> Use a debian mirror, such as "fr" or "ch" + --hostname=<$HOSTNAME> Use a given hostname for the device. + --timezone=<$TIMEZONE> Set timezone data as listed in /usr/share/zoneinfo + --wpa-essid=<$WPA_ESSID> Use a given wireless ESSID. Sets up wireless networking. + --wpa-psk=<$WPA_PSK> Use a given WPA pre-shared key. + --password=<$ROOT_PASWORD> Set the given root password. + --ssh-key=<$SSH_KEY> Add the given SSH key to root's authorized_keys file. If invalid, password login will be enabled. + --root-fs=<$ROOTFS> Use given directory as mount point during installation. +``` + +## Caveats +- The script is very fragile. Should anything unexpected happen during the installation process, the script will abort and manual unmounting will be required. +Also, the script must be run on an unmounted SD card and, in case of interruption, cannot resume. + +## Origin +The commands run by the script are adapted from two documents on creating bootable file systems: + +- USB Armory, https://github.com/inversepath/usbarmory/wiki/Preparing-a-bootable-microSD-image, by Andrea Barisani and others + +- Stock Debian Jessie on the Raspberry Pi 2, https://0xstubs.org/stock-debian-jessie-on-the-raspberry-pi-2/, by Michael Laß + +## Copying +Copyright (c) 2015 Jakob Odersky + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. diff --git a/pistrap-debian b/pistrap-debian new file mode 100755 index 0000000..eefaa9a --- /dev/null +++ b/pistrap-debian @@ -0,0 +1,236 @@ +#!/bin/bash +set -e + +# Variables set through command-line arguments +# the assigned values are used as defaults if no matching argument is provided +FORCE=0 +MIRROR="" +HOSTNAME="pi" +TIMEZONE="UTC" +WPA_ESSID="" +WPA_PSK="" +ROOT_PASSWORD="toor" +SSH_KEY="$HOME/.ssh/id_rsa.pub" + +# Paths for installation +DEVICE=/dev/nonexisting +PARTITION1="$DEVICE"p1 +PARTITION2="$DEVICE"p2 +ROOTFS=/mnt/pi + +print_usage() { + cat 1>&2 < Use a debian mirror, such as "fr" or "ch" + --hostname=<$HOSTNAME> Use a given hostname for the device. + --timezone=<$TIMEZONE> Set timezone data as listed in /usr/share/zoneinfo + --wpa-essid=<$WPA_ESSID> Use a given wireless ESSID. Sets up wireless networking. + --wpa-psk=<$WPA_PSK> Use a given WPA pre-shared key. + --password=<$ROOT_PASWORD> Set the given root password. + --ssh-key=<$SSH_KEY> Add the given SSH key to root's authorized_keys file. If invalid, password login will be enabled. + --root-fs=<$ROOTFS> Use given directory as mount point during installation. +EOF + +} + + +# Process options +while [ $# -gt 1 ] +do + case "$1" in + -f|--force) + FORCE=1 + ;; + --mirror=*) + MIRROR=."${1#*=}" + ;; + --hostname=*) + HOSTNAME="${1#*=}" + ;; + --timezone=*) + TIMEZONE="${1#*=}" + ;; + --wpa-essid=*) + WPA_ESSID="${1#*=}" + ;; + --wpa-psk=*) + WPA_PSK="${1#*=}" + ;; + --password=*) + ROOT_PASSWORD="${1#*=}" + ;; + --ssh-key=*) + SSH_KEY="${1#*=}" + ;; + --root-fs=*) + ROOTFS="${1#*=}" + ;; + *) + echo "Unknown argument: $1" 1>&2 + exit 1 + esac + shift +done + +# Process last argument, the device to use +if [ -z "$1" ] || [ "$1" = -h ] || [ "$1" = --help ]; then + print_usage + exit 1 +fi +if [ ! -e "$1" ]; then + echo "Device not found: $1" 1>&2 + exit 1 +fi +if [ ! -b "$1" ]; then + echo "Specified device is not a block device: $1" 1>&2 + exit 1 +fi +DEVICE="$1" +PARTITION1="$DEVICE"p1 +PARTITION2="$DEVICE"p2 + +# Check environment +if [ "$EUID" != 0 ]; then + echo "This script must be run as root." 1>&2 + exit 1 +fi + +# Argument processing and enivronment check are done at this point +# Start with actual script + +# Setup partitions on SD card +partition() { + parted "$DEVICE" --script mklabel msdos && + parted "$DEVICE" --script mkpart primary fat32 1M 200M && + parted "$DEVICE" --script mkpart primary ext4 200M 100% && + mkfs.vfat -F 32 "$PARTITION1" && + mkfs.ext4 "$PARTITION2" +} + +mountrootfs() { + mkdir "$ROOTFS" && + mount "$PARTITION2" "$ROOTFS" && + + mkdir "$ROOTFS"/boot && + mount "$PARTITION1" "$ROOTFS"/boot +} + +mkrootfs() { + # Create initial debian filesystem + qemu-debootstrap --arch=armhf \ + --include=ssh,sudo,ntpdate,fake-hwclock,openssl,ca-certificates,vim,nano,cryptsetup,lvm2,locales,less,cpufrequtils,wireless-tools,wpasupplicant \ + jessie \ + "$ROOTFS" \ + "http://ftp${MIRROR}.debian.org/debian/" + + # Set package configuration to use raspberrypi.org archive for kernel package + cat > "$ROOTFS"/etc/apt/sources.list < "$ROOTFS"/etc/apt/preferences.d/raspberrypi < "$ROOTFS"/boot/config.txt < "$ROOTFS"/etc/network/interfaces.d/wlan0 < "$ROOTFS"/etc/network/interfaces.d/eth0 < "$ROOTFS"/etc/fstab < "$ROOTFS"/etc/timezone + ln -sf /usr/share/zoneinfo/"$TIMEZONE" "$ROOTFS"/etc/localtime + + # Set host configuration + echo "$HOSTNAME" > "$ROOTFS"/etc/hostname + sed -i "/^127.0.0.1/ s/\$/ $HOSTNAME/" "$ROOTFS"/etc/hosts + sed -i "/^::1/ s/\$/ $HOSTNAME/" > "$ROOTFS"/etc/hosts + + # Login options + chroot "$ROOTFS" /bin/sh -c "echo root:$ROOT_PASSWORD | chpasswd" + + if [ -e "$SSH_KEY" ]; then + mkdir "$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 + echo "Success: SSH password login was 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 + echo "Warning: no SSH key found, SSH password login has been enabled for root! Please enable key-login only as soon as possible." 1>&2 + fi +} + +umountrootfs() { + rm -f "$ROOTFS"/usr/bin/qemu-arm-static + umount "$ROOTFS"/boot + umount "$ROOTFS" + rm -r "$ROOTFS" +} + + +if [ "$FORCE" != 1 ]; then + echo "WARNING: The following operations may have destructive consequences." 1>&2 + echo "Partition device $DEVICE and create bootable root file system on $ROOTFS" 1>&2 + read -p "Continue? [Y,n] " yn + if [ "$yn" != "Y" ] && [ "$yn" != "y" ]; then + echo "Aborting." 1>&2 + exit 1 + fi +fi + +partition && mountrootfs && mkrootfs && umountrootfs -- cgit v1.2.3