Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
davidmonro committed Mar 25, 2014
0 parents commit 040241f
Show file tree
Hide file tree
Showing 10 changed files with 467 additions and 0 deletions.
151 changes: 151 additions & 0 deletions README
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
A framework for generating raspberryPi rootfs trees.

SOME ASSEMBLY REQUIRED. BATTERIES NOT INCLUDED.

I AM NOT RESPONSIBLE IF THESE SCRIPTS WIPE YOUR MACHINE, SET FIRE TO
YOUR HOUSE, EMAIL YOUR BANKING PASSWORD TO CRIMINAL GANGS OR PRECIPITATE
GLOBAL THERMONUCLEAR WAR.

Given that you will need to run some of these scripts under sudo, the
first is a distinctly non-zero possibility. If you are worried about
this, you could probably build yourself a basic ubuntu VM to run this in
so you don't hose stuff if things go wrong.

WHAT YOU WILL NEED:

* A machine running a debian derivative (eg debian itself, ubuntu, etc).

* A recent version of multistrap.
At time of writing, ubuntu ships 2.1.6ubuntu3 which is too old.
I installed 2.1.20 from debian; it is pretty much a standalone
package so this is reasonably safe.

* A qemu-static binary appropriate for your target architecture.
Which I'm assuming is a raspberry Pi, but could be anything.
Ideally, it would match exactly. In practice,
/usr/bin/qemu-arm-static on my ubuntu system is armv7, but
everything still seems to work OK. I suspect it is possible
that some packages which compile stuff at install time
might generate code that wouldn't actually run on the pi,
but I haven't hit that in my experiments. If someone could build
a qemu static binary which more closely matches the pi, that
would be cool.

* An SD card (assuming a Pi)

HOW TO USE IT

To get started, customize the list of packages in the [raspbian] section
of multistrap.conf, check all the points marked "FIXME" in
configscript.sh, and run something like:

sudo multistrap -a armhf -d pi-root-tree -f multistrap.conf

(where pi-root-tree is the name of the target directory, which ideally
should be non-existant or empty).

A few minutes later (about 5 on my machine), it will finish, hopefully
with no errors. You will now have a directory tree under the target
directory which looks like the filesystem of a raspberry pi.

Now you need to format your SD card appropriately and mount it
somewhere. My example configscript.sh assumes that your card has a vfat
partition 1, swap space on partition 2, and everything else in an ext4
partition 3. Partition your card with fdisk, create appropriate
filesystems on the first and third partitions, mkswap the second one.
Now mount the third partition somewhere (eg /mnt), create the boot
directory (eg mkdir /mnt/boot), and then mount the first partition on
that point. Now do something like:
sudo rsync -nav --delete --numeric-ids --exclude=lost+found --modify-window=1 pi-root-tree/ /mnt/

Unmount the card (you'll need to umount /mnt/boot before /mnt), remove
it from the host machine and plug it into the Pi - and hopefully it will
boot.

In theory you could avoid the rsync step by mounting up your SD card as
above before building the tree, and then running multistrap with the
root of the SD card as the target directory, but this will involve doing
a lot of IO to the SD card, so this will probably be extremely slow.

Of course, if you are building this for something other then a raspberry
Pi, you'll need to know how to convert this directory tree into a root
fs image for whatever you are targeting.

HOW IT WORKS:

Multistrap is the engine that drives most of this.

The multistrap.conf file contains enough to build a very basic install
for a pi.

The [General] section at the top has a couple of keywords worth looking
at.

debconfseed=preseed
This causes the file called 'preseed' to get copied into
/tmp/preseeds under the chroot, and used to answer config questions with
predefined values rather than interactive prompts. The included example
sets the timezone, the default locale, and says to use /bin/dash as
/bin/sh. If you include other packages which need configuration you may
need to add stuff to this file.

configscript=configscript.sh
This causes the file 'configscript.sh' to get copied into the
chroot. We execute this in chroot context from a hook later.

hookdir=zzz-hooks
This points to a directory containing hook scripts which get
executed at various points. We use one of these to execute the
configscript.sh later.

The [raspbian] and [pi] sections define sets of packages to be
installed. All packages defined as 'required' will be installed anyway.
You could in fact remove all the packages= lines under the
[raspbian] section and get an even more stripped out image, but that
would remove, for example, networking. However you should definitely
review these packages lines to add tools you like to always have
available or remove any you know you wouldn't use (eg wpasupplicant,
wireless tools and iw if you never expect to be using wifi for
networking).

The configscript.sh file is run in chroot context under qemu after the
packages are unpacked by multistrap (and after any other hook scripts
defined in other multistrap configuration files). Quite a few things
will probably need fixing in there for your environment; look for the
string "FIXME" to see where I think you'll need to look at it.
Near the bottom, it runs any other scripts found in /tmp/hook-scripts;
so other variants (see below) can simply put scripts here in the chroot
for them to be executed in chroot context later.
Finally there's a section which removes the temporary stuff, including
configscript.sh itself and the qemu binary.

zzz-hooks/completion-zzz-final-hook.sh is the script which actually does
the qemu work.

multistrap-mpd.conf is an example of a cascaded multistrap configuration
which extends the base system built by the multistrap.conf above. The
[General] section has an 'include=multistrap.conf' line which causes it
to pick up the base stuff. It defines its own hookdir with some
additional scripts, and an extra package section where it installs more
packages (note that the source, suite and omitdebsrc lines are the same
as the [raspbian] section in the main file).

mpd-hooks/completion-copy-wolfson-kernel.sh copies a tarball of the
custom kernel needed for the wolfson audio card into the chroot

mpd-hooks/completion-create-scripts.sh mostly just creates a script
under /tmp/hook-scripts in the chroot, which will get executed near the
bottom of configscript.sh.

mpd-hooks/completion-patch-base-files-postinst.sh corrects an issue in
the postinst of the base-files package which breaks things if packages
create new directories under /var/run (which mpd does).

If for some reason you want to get into the chroot and do something
after multistrap has finished running (eg install an extra package you
forgot), just copy qemu-arm-static into /usr/bin under the chroot, and
chroot into it. You'll probably need to create an /etc/resolv.conf if
you want to install anything, and if it is a daemon you would probably
want to do the trick with the fake scripts at the top of configscript.sh
so you don't end up with the daemon being started under qemu in the
chroot!
16 changes: 16 additions & 0 deletions base-files-6.5-postint.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--- base-files-6.5ubuntu3/debian/postinst.in 2011-07-13 17:20:35.000000000 -0300
+++ helio-base/debian/postinst.in 2012-01-23 15:07:18.150498042 -0200
@@ -25,6 +25,13 @@

migrate_directory() {
if [ ! -L $1 ]; then
+ if [ ! -z "`ls -A $1/`" ]; then
+ for x in $1/* $1/.[!.]* $1/..?*; do
+ if [ -e "$x" ]; then
+ mv -- "$x" $2/
+ fi
+ done
+ fi
rmdir $1
ln -s $2 $1
fi
145 changes: 145 additions & 0 deletions configscript.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#!/bin/bash

# This script will be run in chroot context probably under qemu.

# FIXME Variables you can mess with
HOSTNAME=pi-base
MYUSERNAME=myuser


export LC_ALL=C LANGUAGE=C LANG=C
export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true

# This stops things trying to start daemons inside the chroot.
mkdir /tmp/fake
for i in initctl invoke-rc.d restart start stop start-stop-daemon service
do
ln -s /bin/true /tmp/fake/$i
done
export PATH=/tmp/fake:$PATH
cat > /etc/resolv.conf <<EOF
# FIXME
# Contents of a valid resolv.conf file here
# This is only used during the build process
# and is removed in the cleanup phase at the end;
# it is assumed dhcp will configure this at runtime.
# For static IP, put the right bits here and fix the
# cleanup section at the end of the file
EOF

# FIXME replace with your syslog host
sed -i 's/^SYSLOG_OPTS=.*$/SYSLOG_OPTS="-R syslog.my.domain"/' /etc/default/busybox-syslogd

# Dash needs special handling
/var/lib/dpkg/info/dash.preinst install

# Preseed files can pre-configure packages.
if [ -d /tmp/preseeds/ ]; then
for file in `ls -1 /tmp/preseeds/*`; do
debconf-set-selections $file
done
fi

# Actually configure the unpackage packages
dpkg --configure -a

ln -s /proc/mounts /etc/mtab

# FIXME you may need to change the root location and fstab contents if you format your SD card differently
echo 'dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p3 rootfstype=ext4 rootwait' > /boot/cmdline.txt

cat > /etc/fstab << EOF
/dev/mmcblk0p3 / ext4 errors=remount-ro,noatime 0 1
/dev/mmcblk0p1 /boot vfat utf8 0 2
/dev/mmcblk0p2 none swap sw 0 0
tmpfs /tmp tmpfs mode=1777,size=25%,noatime 0 0
EOF

# FIXME this should be the hash of the desired root password
echo 'root:$6$XXXXXXXX$YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY' | chpasswd -e

# FIXME with an appropriate hashed password for your non-root account
# You may also want to tailor the set of groups
groupadd ${MYUSERNAME}
useradd -c "My Name" -d /home/${MYUSERNAME} -m -g ${MYUSERNAME} -G adm,dialout,cdrom,floppy,audio,dip,video,plugdev -s /bin/bash -p '$6$ZZZZZZZZ$WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW' ${MYUSERNAME}

# FIXME put your SSH public key here if you want
mkdir /home/${MYUSERNAME}/.ssh
cat > /home/${MYUSERNAME}/.ssh/authorized_keys << EOF
ssh-dss stuff........
EOF

# FIXME grant yourself sudo access
echo "${MYUSERNAME} ALL=(ALL) ALL" >> /etc/sudoers


# This adds the key 7FA3303E: public key "Raspberry Pi Archive Signing Key"
# Needed for archive.raspberrypi.org/debian repo which doesn't seem to have
# a keyring package
apt-key add - << EOF
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.12 (GNU/Linux)
mQENBE/d7o8BCACrwqQacGJfn3tnMzGui6mv2lLxYbsOuy/+U4rqMmGEuo3h9m92
30E2EtypsoWczkBretzLUCFv+VUOxaA6sV9+puTqYGhhQZFuKUWcG7orf7QbZRuu
TxsEUepW5lg7MExmAu1JJzqM0kMQX8fVyWVDkjchZ/is4q3BPOUCJbUJOsE+kK/6
8kW6nWdhwSAjfDh06bA5wvoXNjYoDdnSZyVdcYCPEJXEg5jfF/+nmiFKMZBraHwn
eQsepr7rBXxNcEvDlSOPal11fg90KXpy7Umre1UcAZYJdQeWcHu7X5uoJx/MG5J8
ic6CwYmDaShIFa92f8qmFcna05+lppk76fsnABEBAAG0IFJhc3BiZXJyeSBQaSBB
cmNoaXZlIFNpZ25pbmcgS2V5iQE4BBMBAgAiBQJP3e6PAhsDBgsJCAcDAgYVCAIJ
CgsEFgIDAQIeAQIXgAAKCRCCsSmSf6MwPk6vB/9pePB3IukU9WC9Bammh3mpQTvL
OifbkzHkmAYxzjfK6D2I8pT0xMxy949+ThzJ7uL60p6T/32ED9DR3LHIMXZvKtuc
mQnSiNDX03E2p7lIP/htoxW2hDP2n8cdlNdt0M9IjaWBppsbO7IrDppG2B1aRLni
uD7v8bHRL2mKTtIDLX42Enl8aLAkJYgNWpZyPkDyOqamjijarIWjGEPCkaURF7g4
d44HvYhpbLMOrz1m6N5Bzoa5+nq3lmifeiWKxioFXU+Hy5bhtAM6ljVb59hbD2ra
X4+3LXC9oox2flmQnyqwoyfZqVgSQa0B41qEQo8t1bz6Q1Ti7fbMLThmbRHiuQEN
BE/d7o8BCADNlVtBZU63fm79SjHh5AEKFs0C3kwa0mOhp9oas/haDggmhiXdzeD3
49JWz9ZTx+vlTq0s+I+nIR1a+q+GL+hxYt4HhxoA6vlDMegVfvZKzqTX9Nr2VqQa
S4Kz3W5ULv81tw3WowK6i0L7pqDmvDqgm73mMbbxfHD0SyTt8+fk7qX6Ag2pZ4a9
ZdJGxvASkh0McGpbYJhk1WYD+eh4fqH3IaeJi6xtNoRdc5YXuzILnp+KaJyPE5CR
qUY5JibOD3qR7zDjP0ueP93jLqmoKltCdN5+yYEExtSwz5lXniiYOJp8LWFCgv5h
m8aYXkcJS1xVV9Ltno23YvX5edw9QY4hABEBAAGJAR8EGAECAAkFAk/d7o8CGwwA
CgkQgrEpkn+jMD5Figf/dIC1qtDMTbu5IsI5uZPX63xydaExQNYf98cq5H2fWF6O
yVR7ERzA2w33hI0yZQrqO6pU9SRnHRxCFvGv6y+mXXXMRcmjZG7GiD6tQWeN/3wb
EbAn5cg6CJ/Lk/BI4iRRfBX07LbYULCohlGkwBOkRo10T+Ld4vCCnBftCh5x2OtZ
TOWRULxP36y2PLGVNF+q9pho98qx+RIxvpofQM/842ZycjPJvzgVQsW4LT91KYAE
4TVf6JjwUM6HZDoiNcX6d7zOhNfQihXTsniZZ6rky287htsWVDNkqOi5T3oTxWUo
m++/7s3K3L0zWopdhMVcgg6Nt9gcjzqN1c0gy55L/g==
=mNSj
-----END PGP PUBLIC KEY BLOCK-----
EOF

chown -R ${MYUSERNAME}: /home/${MYUSERNAME}/.ssh
chmod -R go= /home/${MYUSERNAME}/.ssh

# FIXME you'll want to change the wlan config
cat > /etc/network/interfaces << EOF
# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback
allow-hotplug eth0
iface eth0 inet dhcp
allow-hotplug wlan0
iface wlan0 inet dhcp
wpa-ssid MY-SSID
wpa-psk MY-PSK-PASSWORD
EOF
chmod 600 /etc/network/interfaces

echo $HOSTNAME > /etc/hostname

# This is a hack. I'm not sure why, but on the initial unpack/configure
# /boot ends up empty; this solves the issue.
apt-get -y update < /dev/null
apt-get -y install --reinstall raspberrypi-bootloader < /dev/null

# Run the other bits
run-parts -v /tmp/hook-scripts

# cleanup
apt-get clean
rm /etc/resolv.conf
rm -rf /tmp/*
exec rm /configscript.sh /usr/bin/qemu-arm-static
4 changes: 4 additions & 0 deletions mpd-hooks/completion-copy-wolfson-kernel.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

# This one simply copies tar balls of the wolfson kernel and scripts into place in the chroot
cp ~/pi-roots/wolfson-kernel.tar ~/pi-roots/wolfson-scripts.tar $1/tmp/
77 changes: 77 additions & 0 deletions mpd-hooks/completion-create-scripts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/bin/bash

# This runs in host context.
# I just create a script which will be run later in chroot context.
# This then does various things including unpacking the wolfson
# tarballs we placed in the chroot earlier

TDIR=$1
mkdir -p $TDIR/tmp/hook-scripts
cat > $TDIR/tmp/hook-scripts/mpd << EOF
#!/bin/bash
# FIXME where is your audio stash?
cat >> /etc/fstab << EO2F
server:/audio /var/lib/mpd/music nfs ro,nolock,bg 0 0
server:/playlists /var/lib/mpd/playlists nfs ro,nolock,bg 0 0
EO2F
# I used a hacked kernel to handle the wolfson audio card
rm -rf /lib/modules /lib/firmware /boot/kernel.img
tar xCvf / /tmp/wolfson-kernel.tar
tar xCvf / /tmp/wolfson-scripts.tar
# Modified mpd.conf. Note this puts the state file in /var/run
# which means it won't persist over reboots, this may not be what
# you want (default is /var/lib/mpd/state).
cat > /etc/mpd.conf << EO2F
music_directory "/var/lib/mpd/music"
playlist_directory "/var/lib/mpd/playlists"
db_file "/var/lib/mpd/tag_cache"
log_file "syslog"
pid_file "/var/run/mpd/pid"
state_file "/var/run/mpd/state"
sticker_file "/var/lib/mpd/sticker.sql"
zeroconf_name "Unnamed Music Player"
user "mpd"
input {
plugin "curl"
}
audio_output {
type "alsa"
name "My ALSA Device"
device "hw:0,0" # optional
mixer_device "default" # optional
mixer_control "HPOUT2 Digital" # optional
mixer_index "0" # optional
}
filesystem_charset "UTF-8"
id3v1_encoding "UTF-8"
EO2F
# This is some stuff I run on startup to clear any mpd state,
# configure the audio card, and set the volume to something sane.
# First we remove the "exit 0" at the end of the file
sed -i 's/^exit 0$//' /etc/rc.local
# Then add our stuff
cat >> /etc/rc.local << EO2F
mpc clear
mpc update
/usr/local/bin/Reset_paths.sh
/usr/local/bin/Playback_to_Lineout.sh
mpc volume 40
EO2F
# Customize the hostname appropriately
echo "test-mpd" > /etc/hostname
EOF

chmod 755 $TDIR/tmp/hook-scripts/mpd
Loading

0 comments on commit 040241f

Please sign in to comment.