#!/bin/sh # Copyright (C) 2012 Michael Gorven # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. set -ev NAME="${1?Please specify output image name.}" IMAGE_SIZE=1000 BOOT_SIZE=64 ALIGN_SECTORS=8192 ALIGN_FSBLOCKS="$(($ALIGN_SECTORS*512/4096))" MIRROR="http://mirrordirector.raspbian.org/raspbian" BASE_PACKAGES="openssh-server sudo ntp fake-hwclock raspi-copies-and-fills raspi-config" XBMC_PACKAGES="nfs-client xbmc udisks avahi-daemon" XBMC_USER="xbmc" XBMC_HOSTNAME="xbmc" export LANG=en_US.UTF-8 export LC_ALL=en_US.UTF-8 check_host() { if [ $(id -u) != 0 ]; then echo "This script must be run as root." exit 2 fi for BINARY in wget gpg qemu-debootstrap rsync kpartx sfdisk mkfs.ext4 mkfs.vfat tune2fs tar sha256sum; do if ! which $BINARY > /dev/null; then echo "Unable to find $BINARY binary, please install it" exit 1 fi done } bootstrap() { if [ ! "$BUILDROOT" ]; then echo "BUILDROOT is empty, aborting." exit 1 fi KEYRING="${TMPDIR:-/tmp}/raspbian.gpg" if [ ! -s "$KEYRING" ]; then wget -O- http://archive.raspbian.org/raspbian.public.key | gpg --no-default-keyring --keyring "$KEYRING" --import fi qemu-debootstrap --arch=armhf --keyring="$KEYRING" wheezy "$BUILDROOT" "$MIRROR" } configure_base() { if [ ! "$BUILDROOT" ]; then echo "BUILDROOT is empty, aborting." exit 1 fi cat > "$BUILDROOT/usr/sbin/policy-rc.d" <<-EOF #!/bin/sh exit 101 EOF chmod +x "$BUILDROOT/usr/sbin/policy-rc.d" cat > "$BUILDROOT/etc/apt/sources.list" <<-EOF deb $MIRROR wheezy main contrib non-free rpi EOF cat > "$BUILDROOT/etc/apt/sources.list.d/mene.list" <<-EOF deb http://archive.mene.za.net/raspbian wheezy contrib EOF cat > "$BUILDROOT/etc/apt/sources.list.d/raspi.list" <<-EOF deb http://archive.raspberrypi.org/debian/ wheezy main EOF if [ "$http_proxy" ]; then cat > "$BUILDROOT/etc/apt/apt.conf.d/30proxy" <<-EOF Acquire::http::proxy "$http_proxy"; EOF fi wget -O- http://archive.raspberrypi.org/debian/raspberrypi.gpg.key | chroot "$BUILDROOT" apt-key add - wget -O- http://archive.mene.za.net/key.asc | chroot "$BUILDROOT" apt-key add - export DEBIAN_FRONTEND=noninteractive chroot "$BUILDROOT" apt-get --yes dist-upgrade chroot "$BUILDROOT" apt-get --yes update chroot "$BUILDROOT" apt-get --yes install raspberrypi-bootloader libraspberrypi-bin $BASE_PACKAGES cat > "$BUILDROOT/boot/config.txt" <<-EOF disable_overscan=1 EOF cat > "$BUILDROOT/boot/cmdline.txt" <<-EOF dwc_otg.lpm_enable=0 dwc_otg.fiq_fix_enable=1 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=noop rootwait EOF chroot "$BUILDROOT" adduser --disabled-password --gecos 'Raspberry Pi User,,,,' pi echo 'pi:raspberry' | chroot "$BUILDROOT" chpasswd chroot "$BUILDROOT" adduser pi sudo cat >> "$BUILDROOT/etc/network/interfaces" <<-EOF auto eth0 iface eth0 inet dhcp EOF echo "$XBMC_HOSTNAME" > "$BUILDROOT/etc/hostname" cat >> "$BUILDROOT/etc/hosts" <<-EOF 127.0.0.2 $XBMC_HOSTNAME EOF cat > "$BUILDROOT/etc/fstab" <<-EOF LABEL=boot /boot vfat defaults 0 2 LABEL=root / ext4 errors=remount-ro,noatime,nodiratime 0 1 EOF cat >> "$BUILDROOT/etc/modules" <<-EOF vchiq snd_bcm2835 EOF cat > "$BUILDROOT/etc/sysctl.d/raspi.conf" <<-EOF vm.min_free_kbytes = 8192 EOF cat > "$BUILDROOT/etc/init.d/regenerate_ssh_host_keys" <<-"EOF" #!/bin/sh ### BEGIN INIT INFO # Provides: regenerate_ssh_host_keys # Required-Start: # Required-Stop: # Default-Start: 2 # Default-Stop: # Short-Description: Regenerate ssh host keys # Description: ### END INIT INFO . /lib/lsb/init-functions set -e case "$1" in start) log_daemon_msg "Regenerating ssh host keys (in background)" nohup sh -c "yes | ssh-keygen -q -N '' -t dsa -f /etc/ssh/ssh_host_dsa_key && \ yes | ssh-keygen -q -N '' -t rsa -f /etc/ssh/ssh_host_rsa_key && \ yes | ssh-keygen -q -N '' -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key && \ update-rc.d ssh enable && sync && \ rm /etc/init.d/regenerate_ssh_host_keys && \ update-rc.d regenerate_ssh_host_keys remove && \ printf '\nfinished\n' && invoke-rc.d ssh start" > /var/log/regen_ssh_keys.log 2>&1 & log_end_msg $? ;; *) echo "Usage: $0 start" >&2 exit 3 ;; esac EOF chmod +x "$BUILDROOT/etc/init.d/regenerate_ssh_host_keys" chroot "$BUILDROOT" update-rc.d ssh disable chroot "$BUILDROOT" update-rc.d regenerate_ssh_host_keys defaults } configure_xbmc() { cp "$BUILDROOT/boot/arm128_start.elf" "$BUILDROOT/boot/start.elf" chroot "$BUILDROOT" apt-get --yes install $XBMC_PACKAGES chroot "$BUILDROOT" addgroup --system input chroot "$BUILDROOT" adduser --disabled-login --shell /bin/false --gecos 'XBMC Media Centre,,,' "$XBMC_USER" chroot "$BUILDROOT" adduser "$XBMC_USER" video chroot "$BUILDROOT" adduser "$XBMC_USER" audio chroot "$BUILDROOT" adduser "$XBMC_USER" plugdev chroot "$BUILDROOT" adduser "$XBMC_USER" input cat > "$BUILDROOT/etc/default/xbmc" <<-EOF ENABLED=1 USER="$XBMC_USER" NICE=-5 EOF cat > "$BUILDROOT/etc/udev/rules.d/99-input.rules" <<-EOF SUBSYSTEM=="input", GROUP="input", MODE="0660" EOF cat > "$BUILDROOT/var/lib/polkit-1/localauthority/50-local.d/50-xbmc.pkla" <<-EOF [Actions for $XBMC_USER user] Identity=unix-user:$XBMC_USER Action=Action=org.freedesktop.upower.*;org.freedesktop.consolekit.system.*;org.freedesktop.udisks.* ResultActive=yes ResultAny=yes ResultInactive=no EOF chown -R 1001:1001 "$BUILDROOT/home/$XBMC_USER" } cleanup() { chroot "$BUILDROOT" apt-get --yes clean find "$BUILDROOT/var/lib/apt/lists/" -type f -delete rm -f "$BUILDROOT/etc/apt/apt.conf.d/30proxy" "$BUILDROOT/usr/sbin/policy-rc.d" } mkimage() { IMAGE="$NAME.img" TAR="$NAME.tar.xz" dd if=/dev/zero of="$IMAGE" bs=1MB count=0 seek="$IMAGE_SIZE" BOOT_SECTORS="$(($BOOT_SIZE*2048/$ALIGN_SECTORS*$ALIGN_SECTORS))" cat | sfdisk --quiet --unit S --force "$IMAGE" <<-EOF $ALIGN_SECTORS,$(($BOOT_SECTORS)),c,* $(($ALIGN_SECTORS+$BOOT_SECTORS)),,L EOF LOOP="$(basename $(losetup -f))" kpartx -a "$IMAGE" BOOT="/dev/mapper/${LOOP}p1" ROOT="/dev/mapper/${LOOP}p2" mkfs.vfat -F 32 -n boot "$BOOT" mkfs.ext4 -b 4096 -E stride=$ALIGN_FSBLOCKS,stripe-width=$ALIGN_FSBLOCKS -m 1 -L root "$ROOT" tune2fs -i 0 -c 0 "$ROOT" MNT="$(mktemp -d --tmpdir raspbian.XXXXXX)" mount "$ROOT" "$MNT" mkdir "$MNT/boot" mount "$BOOT" "$MNT/boot" rsync --archive --devices --specials --hard-links --acls --xattrs --sparse --verbose "$BUILDROOT" "$MNT" umount "$MNT/boot" umount "$MNT" kpartx -d "$IMAGE" tar -cSJvf "$TAR" "$IMAGE" sha256sum "$TAR" > "$TAR.sha256" } BUILDROOT="$(mktemp -d $PWD/raspbian.XXXXXX)/root/" check_host bootstrap configure_base configure_xbmc cleanup mkimage