summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Lane <john@lane.uk.net>2012-08-22 23:35:31 +0100
committerJohn Lane <john@lane.uk.net>2012-08-22 23:35:31 +0100
commit02352f3e032b049a5d8d3636e10ef111c3f3c4e9 (patch)
treebd182921663311941f693d553b7b238e6984857e
downloadrpi-utils-02352f3e032b049a5d8d3636e10ef111c3f3c4e9.zip
rpi-utils-02352f3e032b049a5d8d3636e10ef111c3f3c4e9.tar.gz
rpi-utils-02352f3e032b049a5d8d3636e10ef111c3f3c4e9.tar.bz2
Initial Commit
-rw-r--r--.gitignore12
-rw-r--r--LICENSE24
-rw-r--r--README.md38
-rw-r--r--archbuild/README.md25
-rw-r--r--archbuild/archbuild44
-rw-r--r--archbuild/commands39
-rwxr-xr-xarchbuild/source_files/cmdline.txt1
-rw-r--r--archbuild/source_files/inittab49
-rw-r--r--archbuild/source_files/locale.gen4
-rw-r--r--archbuild/source_files/mirrorlist30
-rw-r--r--archbuild/source_files/securetty16
-rw-r--r--archbuild/unmount8
-rw-r--r--disk/README.md22
-rwxr-xr-xdisk/rpi_mkimage659
-rwxr-xr-xdisk/rpi_mount82
-rwxr-xr-xdisk/rpi_umount51
-rw-r--r--emulator/README.md44
-rwxr-xr-xemulator/boot22
-rwxr-xr-xemulator/setup31
-rw-r--r--scrapbook/CONTENTS.md24
-rw-r--r--scrapbook/HowTo_Install_GRUB_into_a_disk_image.pdfbin0 -> 58715 bytes
-rw-r--r--scrapbook/HowTo_Mount_Image.md49
-rw-r--r--scrapbook/HowTo_Pacman_Keyring_Entropy.md15
-rw-r--r--scrapbook/Notes_Formatting_SD.md16
-rwxr-xr-xscrapbook/build53
-rwxr-xr-xscrapbook/mkpartitions7
26 files changed, 1365 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..93e4932
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+# Generic files to ignore
+*.un~
+*.swp
+
+# Specifially ignore emulator images
+emulator/*img
+emulator/*raw
+emulator/kernel-qemu
+
+# Specifically ignore disk images
+disk/*img
+disk/myimage
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..cfea716
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2012 John Lane
+
+MIT License
+
+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.
+
+http://www.opensource.org/licenses/mit-license.php
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ce1407d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,38 @@
+# Raspberry-Pi Utilities
+
+This is a collection of things to do with the Raspberry Pi that are made available
+to the community in the hope they are useful to others.
+
+## ArchBuild
+
+ArchBuild will build a new root filesystem for the Raspberry Pi. Use it instead of
+the official image if you want to tweak the installation.
+
+## Kernel
+
+Building a custom kernel.
+
+## Disk
+
+Some tools that can help with managing disks (or other storage devices, e.g: sd card)
+and disk images.
+
+## ScrapBook
+
+A collection of notes, scripts and other things that may be of interest. Basically,
+anything I have found useful will end up in here if they don't fit in anywhere
+else. See the ScrapBook CONTENTS file details of what's there.
+
+## Colophon
+
+### Copyright
+
+Copyright (c) 2012 John Lane.
+
+### License
+
+This collection of Raspberry-Pi Utilities is provided under the MIT License. See LICENSE file.
+
+### Latest Version
+
+Obtain the latest version from [GitHub](https://github.com/johnlane/rpi-utils)
diff --git a/archbuild/README.md b/archbuild/README.md
new file mode 100644
index 0000000..5f87b28
--- /dev/null
+++ b/archbuild/README.md
@@ -0,0 +1,25 @@
+# Raspberry-Pi Utilities : ArchBuild
+
+ArchBuild will build a new root filesystem for the Raspberry Pi. Use it instead of
+the official image if you want to tweak the installation.
+
+## Source Files
+
+The directory 'source_files' contains the files needed to complete the build
+of a new root filesystem. This directory can be re-created using the collect
+script described below.
+
+## Collect
+
+This is a simple script to collect the required files from a running raspberry-Pi
+Arch Linux system.
+
+## ArchBuild
+
+This is a script to build a new baseline Arch Linux root filesystem image. It
+requires that the source files directory (described above) exists.
+
+### Unmount
+
+This is a quick and dirty script to unmount the archroot created by build if,
+for some reason, the build script fails uncleanly.
diff --git a/archbuild/archbuild b/archbuild/archbuild
new file mode 100644
index 0000000..6aaed48
--- /dev/null
+++ b/archbuild/archbuild
@@ -0,0 +1,44 @@
+#!/bin/bash
+#
+# archbuild : build an Arch Linux system (run this on the Raspberry Pi)
+#
+
+PACMAN_MIRRORLIST=`mktemp`
+PACMAN_CONF=`mktemp`
+curl https://projects.archlinux.org/svntogit/packages.git/plain/trunk/pacman.conf?h=packages/pacman > "$PACMAN_CONF"
+VPS_ARCH=arm
+sed -i -e "s@/etc/pacman.d/mirrorlist@$PACMAN_MIRRORLIST@g" -e "s/\Architecture = auto/Architecture = "$VPS_ARCH"/g" "$PACMAN_CONF"
+sed -i -e 's/^SigLevel/#SigLevel/' -e '/^#SigLevel = Optional TrustedOnly/a\SigLevel = Never' "$PACMAN_CONF"
+sed -i -e 's/^CheckSpace/#CheckSpace/' "$PACMAN_CONF"
+echo -e "[alarm]\nInclude = $PACMAN_MIRRORLIST" >> "$PACMAN_CONF"
+country='GB'
+cp /etc/pacman.d/mirrorlist $PACMAN_MIRRORLIST
+VPS_PACKAGES="bash bzip2 coreutils cronie cryptsetup device-mapper dhcpcd diffutils e2fsprogs file filesystem findutils gawk gcc-libs gettext glibc grep gzip heirloom-mailx inetutils initscripts iputils jfsutils less licenses logrotate lvm2 man-db man-pages mdadm nano pacman pacman-mirrorlist pciutils perl ppp procps-ng psmisc reiserfsprogs sed shadow sysfsutils syslog-ng sysvinit tar texinfo usbutils util-linux vi wget which wpa_supplicant xfsprogs linux-raspberrypi linux-headers-raspberrypi raspberrypi-firmware"
+mkarchroot -C "$PACMAN_CONF" archroot $VPS_PACKAGES
+cp $PACMAN_MIRRORLIST archroot/etc/pacman.d/mirrorlist
+sed -i -e "s:$PACMAN_MIRRORLIST:/etc/pacman.d/mirrorlist:" archroot/etc/pacman.conf
+echo -e "root\nroot\n" | chroot archroot /usr/bin/passwd root
+cp /etc/securetty archroot/etc/securetty
+cp /etc/inittab archroot/etc/inittab
+cp /etc/locale.gen archroot/etc/locale.gen
+chroot archroot /usr/sbin/locale-gen
+chroot archroot mknod -m 600 /dev/console c 5 1
+chroot archroot mknod -m 666 /dev/null c 1 3
+chroot archroot mknod -m 666 /dev/zero c 1 5
+chroot archroot yes | /usr/bin/pacman -Scc
+
+#
+# Boot files
+#
+#cp /boot/bootcode.bin archroot/boot
+#cp /boot/loader.bin archroot/boot
+#cp /boot/arm???_start.elf archroot/boot
+#cp archroot/boot/{arm224_,}start.elf
+cp /boot/cmdline.txt archroot/boot
+
+DATE=$(date +%d-%m-%Y)
+cd archroot
+tar cJf ../archlinuxarm-$DATE.tar.xz ./*
+cd ..
+sha1sum archlinuxarm-jl-$DATE.tar.gz > archlinuxarm-$DATE.tar.gz.sha1
+rm -rf archroot*
diff --git a/archbuild/commands b/archbuild/commands
new file mode 100644
index 0000000..6712d05
--- /dev/null
+++ b/archbuild/commands
@@ -0,0 +1,39 @@
+PACMAN_MIRRORLIST=`mktemp`
+PACMAN_CONF=`mktemp`
+curl https://projects.archlinux.org/svntogit/packages.git/plain/trunk/pacman.conf?h=packages/pacman > "$PACMAN_CONF"
+VPS_ARCH=arm
+sed -i -e "s@/etc/pacman.d/mirrorlist@$PACMAN_MIRRORLIST@g" -e "s/\Architecture = auto/Architecture = "$VPS_ARCH"/g" "$PACMAN_CONF"
+sed -i -e 's/^SigLevel/#SigLevel/' -e '/^#SigLevel = Optional TrustedOnly/a\SigLevel = Never' "$PACMAN_CONF"
+sed -i -e 's/^CheckSpace/#CheckSpace/' "$PACMAN_CONF"
+echo -e "[alarm]\nInclude = $PACMAN_MIRRORLIST" >> "$PACMAN_CONF"
+country='GB'
+cp /etc/pacman.d/mirrorlist $PACMAN_MIRRORLIST
+VPS_PACKAGES="bash bzip2 coreutils cronie cryptsetup device-mapper dhcpcd diffutils e2fsprogs file filesystem findutils gawk gcc-libs gettext glibc grep gzip heirloom-mailx inetutils initscripts iputils jfsutils less licenses logrotate lvm2 man-db man-pages mdadm nano pacman pacman-mirrorlist pciutils perl ppp procps-ng psmisc reiserfsprogs sed shadow sysfsutils syslog-ng sysvinit tar texinfo usbutils util-linux vi wget which wpa_supplicant xfsprogs linux-raspberrypi linux-headers-raspberrypi raspberrypi-firmware"
+mkarchroot -C "$PACMAN_CONF" archroot $VPS_PACKAGES
+cp $PACMAN_MIRRORLIST archroot/etc/pacman.d/mirrorlist
+sed -i -e "s:$PACMAN_MIRRORLIST:/etc/pacman.d/mirrorlist:" archroot/etc/pacman.conf
+echo -e "root\nroot\n" | chroot archroot /usr/bin/passwd root
+cp /etc/securetty archroot/etc/securetty
+cp /etc/inittab archroot/etc/inittab
+cp /etc/locale.gen archroot/etc/locale.gen
+chroot archroot /usr/sbin/locale-gen
+chroot archroot mknod -m 600 /dev/console c 5 1
+chroot archroot mknod -m 666 /dev/null c 1 3
+chroot archroot mknod -m 666 /dev/zero c 1 5
+chroot archroot yes | /usr/bin/pacman -Scc
+
+#
+# Boot files
+#
+#cp /boot/bootcode.bin archroot/boot
+#cp /boot/loader.bin archroot/boot
+#cp /boot/arm???_start.elf archroot/boot
+#cp archroot/boot/{arm224_,}start.elf
+cp /boot/cmdline.txt archroot/boot
+
+DATE=$(date +%d-%m-%Y)
+cd archroot
+#tar cJf ../archlinuxarm-jl-$DATE.tar.xz ./*
+cd ..
+#sha1sum archlinuxarm-jl-$DATE.tar.gz > archlinuxarm-jl-$DATE.tar.gz.sha1
+#rm -rf archroot*
diff --git a/archbuild/source_files/cmdline.txt b/archbuild/source_files/cmdline.txt
new file mode 100755
index 0000000..34817c5
--- /dev/null
+++ b/archbuild/source_files/cmdline.txt
@@ -0,0 +1 @@
+smsc95xx.turbo_mode=N dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 loglevel=2 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait
diff --git a/archbuild/source_files/inittab b/archbuild/source_files/inittab
new file mode 100644
index 0000000..51d9af0
--- /dev/null
+++ b/archbuild/source_files/inittab
@@ -0,0 +1,49 @@
+#
+# /etc/inittab
+#
+
+# Runlevels:
+# 0 Halt
+# 1(S) Single-user
+# 2 Not used
+# 3 Multi-user
+# 4 Not used
+# 5 X11
+# 6 Reboot
+
+## Only one of the following two lines can be uncommented!
+# Boot to console
+id:3:initdefault:
+# Boot to X11
+#id:5:initdefault:
+
+rc::sysinit:/etc/rc.sysinit
+rs:S1:wait:/etc/rc.single
+rm:2345:wait:/etc/rc.multi
+rh:06:wait:/etc/rc.shutdown
+su:S:wait:/sbin/sulogin -p
+
+# -8 options fixes umlauts problem on login
+#s0:12345:respawn:/sbin/agetty -8 -s 115200 ttyS0 linux
+c1:2345:respawn:/sbin/agetty -8 -s 115200 tty1
+c2:2345:respawn:/sbin/agetty -8 -s 115200 ttyAMA0
+c3:2345:respawn:/sbin/agetty -8 -s 115200 tty3
+c4:2345:respawn:/sbin/agetty -8 -s 115200 tty4
+#c5:2345:respawn:/sbin/agetty -8 -s 38400 tty5 linux
+#c6:2345:respawn:/sbin/agetty -8 -s 38400 tty6 linux
+
+# Serial Virtual Console for KVM and others VMs
+#s0:2345:respawn:/sbin/agetty -8 -s 9600 ttyS0 linux
+
+# Hypervisor Virtual Console for Xen and KVM
+#h0:2345:respawn:/sbin/agetty -8 -s 38400 hvc0 linux
+
+ca::ctrlaltdel:/sbin/shutdown -t3 -r now
+
+# Example lines for starting a login manager
+x:5:respawn:/usr/bin/xdm -nodaemon
+#x:5:respawn:/usr/sbin/gdm -nodaemon
+#x:5:respawn:/usr/bin/kdm -nodaemon
+#x:5:respawn:/usr/bin/slim >/dev/null 2>&1
+
+# End of file
diff --git a/archbuild/source_files/locale.gen b/archbuild/source_files/locale.gen
new file mode 100644
index 0000000..5192d4b
--- /dev/null
+++ b/archbuild/source_files/locale.gen
@@ -0,0 +1,4 @@
+en_US.UTF-8 UTF-8
+en_US ISO-8859-1
+de_DE ISO-8859-1
+de_DE@euro ISO-8859-15
diff --git a/archbuild/source_files/mirrorlist b/archbuild/source_files/mirrorlist
new file mode 100644
index 0000000..1b88df8
--- /dev/null
+++ b/archbuild/source_files/mirrorlist
@@ -0,0 +1,30 @@
+#
+# Arch Linux ARM repository mirrorlist
+# Generated on 2012-06-08
+#
+
+## Geo-IP based mirror selection and load balancing
+Server = http://mirror.archlinuxarm.org/arm/$repo
+
+### Mirrors by country
+
+### China
+# Server = http://cn.mirror.archlinuxarm.org/arm/$repo
+
+### Finland
+# Server = http://fi.mirror.archlinuxarm.org/arm/$repo
+
+### Germany
+# Server = http://eu.mirror.archlinuxarm.org/arm/$repo
+# Server = http://6.eu.mirror.archlinuxarm.org/arm/$repo
+
+### Netherlands
+# Server = http://nl.mirror.archlinuxarm.org/arm/$repo
+
+### United States
+## CA
+# Server = http://ca.us.mirror.archlinuxarm.org/arm/$repo
+## IL
+# Server = http://us.mirror.archlinuxarm.org/arm/$repo
+## VA
+# Server = http://va.us.mirror.archlinuxarm.org/arm/$repo
diff --git a/archbuild/source_files/securetty b/archbuild/source_files/securetty
new file mode 100644
index 0000000..4b43ead
--- /dev/null
+++ b/archbuild/source_files/securetty
@@ -0,0 +1,16 @@
+#
+# /etc/securetty
+#
+
+console
+tty1
+#tty2
+ttyAMA0
+tty3
+tty4
+#tty5
+#tty6
+#ttyS0
+#hvc0
+
+# End of file
diff --git a/archbuild/unmount b/archbuild/unmount
new file mode 100644
index 0000000..8d43074
--- /dev/null
+++ b/archbuild/unmount
@@ -0,0 +1,8 @@
+umount archroot/sys
+umount archroot/proc/sys
+umount archroot/proc
+umount archroot/dev/shm
+umount archroot/dev/pts
+umount archroot/dev
+umount archroot/var/cache/pacman/pkg
+umount archroot/run
diff --git a/disk/README.md b/disk/README.md
new file mode 100644
index 0000000..fa12a8d
--- /dev/null
+++ b/disk/README.md
@@ -0,0 +1,22 @@
+# Raspberry-Pi Utilities : Disk
+
+Disk utilitles for working with SD cards and images.
+
+Root privileges are required.
+
+## rpi_mkimage
+
+Use rpi_mkimage to prepare a fileystem image or device. see rpi_mkimage --help
+for further information.
+
+## rpi_mount
+
+Use rpi_mount to mount an image or device. It first mounts the root partition and
+then mounts the boot partition on top. If mounting an image, it first creates
+a loop device.
+
+## rpi_unmount
+
+Use rpi_umount to unmount an image or device mounted by the mount command described
+above. It also removes any loop device used to mount an image.
+
diff --git a/disk/rpi_mkimage b/disk/rpi_mkimage
new file mode 100755
index 0000000..8f7d545
--- /dev/null
+++ b/disk/rpi_mkimage
@@ -0,0 +1,659 @@
+#!/usr/bin/env python2
+#
+LICENSE="""
+Copyright (c) 2012 John Lane
+
+MIT License
+
+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.
+
+http://www.opensource.org/licenses/mit-license.php
+"""
+
+DESCRIPTION="""
+rpi_mkimg : Make a Raspberry Pi SD Card Image
+
+Describes and, optionally, makes a disk image with partitions
+and filesystems prepared in accordance with the write and erase
+geometries of the target device. Optionally copies files into
+the new image from another image, directory or archive (tar file).
+
+Quick Start
+-----------
+
+Those that don't want to read the detail can try this:
+
+ $ sudo rpi_mkimg --device=sdcard --copy=image --create
+
+where 'sdcard' is the name of the sdcard device (e.g. mmcblk0)
+ and 'image' is the name of an image to copy (e.g.
+ archlinuxarm-13-06-2012.img)
+
+Detail
+------
+
+A device and/or an image name can be given as command-line
+arguments.
+
+If a device is given (such as an SD card that will be used
+to boot a Raspberry Pi), it will be used to set the attributes
+that are used to determine the block-level layout of the image.
+
+If no device is given then default values are used:
+
+ volume size = 2GiB
+ preferred erase size = 4MiB
+
+These attributes are used to define a partitioning scheme
+that ensures block alignment of the partitions and the file-
+systems on those partitions. Two partitions are created:
+
+ boot : a FAT32 partition (at least 40Mb)
+ root : an ext4 partition
+
+The partitioning scheme is displayed on standard output.
+
+A command-line argument can be given which causes a disk image
+to be created using the partitioning scheme. If this argument is
+not given then this will not happen. This is to protect against
+accidental writes.
+
+The image can be written directly onto the device or it can
+be written to a file that can be subsequently transferred onto
+a suitable device using 'dd'.
+
+If an image is specified then a new file will be created (replacing
+any existing file of the same name) and the partitioning scheme
+applied to it.
+
+If an image is not specified but a device is specified then
+the partitioning scheme will be applied to the device.
+
+NOTE: All contents of the device or any existing image file
+ will be overwritten!
+
+If neither image nor device are specified, the create argument
+is ignored and nothing will be created.
+
+Write permission to the image or device is required. Normally
+the latter will require root permissions.
+
+A command-line argument can be given which will copy files into
+the created image. This mounts the new image's root filesystem
+and then mounts its boot filesystem on top at /boot. The copy is
+then performed into the mount point.
+
+The files to be copied can be in another image file, directory
+or archive (tar) file.
+
+Block Alignment
+---------------
+
+The attribute used to define the device's block alignment is
+called preferred erase size. The actual value can be overriden
+using a command line argument.
+
+Block alignment is performed on the partitions as well as on the
+filesystems within them.
+
+Partitions and Filesystems
+--------------------------
+
+Two partitions are created in accordance with the requirements
+of the Raspberry Pi: A FAT32 partition containing a FAT16 boot
+filesystem and a linux partition containing an ext4 root file-
+system. Both partitions and filesystems are created in such a
+way that their data blocks are aligned with those of the device.
+
+By default:
+
+ - the boot partition size will be 40Mb but it may be larger than
+ this if the device's block sizes result in larger partitions;
+
+ - the root partition size will consume all of the
+ remaining space in the image;
+
+ - the total image size will be the size of any specified device
+ or 2GiB.
+
+Default sizes may be overridden using command-line arguments:
+
+ - specifying a minimum size for a partition will ensure that the
+ partition is at least that size. If this this cannot be achieved
+ then the programme will exit with an appropriate message.
+
+ - specifying a maximum size for a partition will make the
+ partition no bigger than that maximum (subject to block alignment,
+ see below) and any remaining space in the image will be unused.
+
+Partitions may be sized larger than a specified maximum if this is
+necessary to achieve block alignment.
+
+Operational requirements
+------------------------
+
+Arch Linux package requirements:
+ parted : to make partitions
+ dosfstools : to make vfat partition
+ python-pexpect : Python Expect used to run commands
+
+The loop device is used to mount image files. Ensure the "loop" kernel
+module is loaded: "modprobe loop" should achieve this.
+
+Commands requiring privileged entitlements are executed with sudo.
+
+
+ (c) John Lane 2012-08-03.
+ Licensed under the MIT License.
+
+ Part of the rpi-utilities:
+ https://github.com/johnlane/rpi-utils
+
+"""
+
+
+# References:
+#
+import sys
+import os
+import pexpect
+import argparse
+import atexit
+import tempfile
+import pwd
+
+def align(sector,grain):
+ if args.align == True:
+ excess = sector%grain
+ sector = sector if excess == 0 else sector + grain - excess
+ return sector
+
+def print_partition_info(name,start_sector,end_sector):
+
+ size_mib = (end_sector - start_sector + 1) * 512 / (1<<20)
+
+ print "------------------------------------------------------------"
+ print " Partition '%s':" % name
+ print " Start sector : %d" % start_sector
+ print " End sector : %d" % end_sector
+ print " 512 byte sectors : %d" % (end_sector - start_sector + 1)
+ print " 1KiB Blocks : %d" % ((end_sector - start_sector + 1) / 2)
+ print " Size : %d MiB" % ((end_sector - start_sector + 1) * 512 / (1<<20))
+ print "------------------------------------------------------------"
+
+def gib(n):
+ return (float(n)/(1<<30))
+
+def mib(n):
+ return (float(n)/(1<<20))
+
+def kib(n):
+ return (float(n)/(1<<10))
+
+def print_bytes(label,value):
+ llen=len(label)
+ print "%s : %d bytes" % (label,value)
+ if value>=(1<<10) and value<(1<<20): print "%s : %g Kib" % (''.rjust(llen),kib(value))
+ if value>=(1<<20): print "%s : %g Mib" % (''.rjust(llen),mib(value))
+ if value>=(1<<30): print "%s : %g Gib" % (''.rjust(llen),gib(value))
+
+def run_command(command):
+ output, exit_status = pexpect.run(command, withexitstatus=1)
+ output = output.strip()
+ return output, exit_status
+
+def do_or_die(command,error_message="Command Failed"):
+ output, exit_status = run_command(command)
+ if exit_status != 0:
+ abort("%s : %s" % (error_message, output))
+ return output
+
+def writable_or_die(d):
+ if os.access(d,os.W_OK) != True:
+ abort("No write access to %s" % d)
+
+def create_loop_device(d):
+ loop_device = do_or_die("losetup -f","Unable to get a loop device")
+ debug("Setting up loop device %s for %s" % (loop_device,d))
+ do_or_die("losetup -P %s %s" % (loop_device,d), "Unable to create loop device")
+ return loop_device
+
+def destroy_loop_device(d):
+ do_or_die("losetup -d %s" % d,"Unable to destroy loop device")
+
+
+def abort(error_message):
+ sys.exit("%s. Cannot continue" % error_message)
+
+##############################################################################################
+# A very primitive message logger
+LOG_DEBUG = 'debug'
+LOG_VERBOSE = 'verbose'
+def verbose(message): log(LOG_VERBOSE,message)
+def debug(message): log(LOG_DEBUG,message)
+def log(level,message):
+ if args.loglevels != None and level in args.loglevels: print "(%s) %s" % (level,message)
+def debug_enabled(): return args.loglevels != None and LOG_DEBUG in args.loglevels
+def verbose_enabled(): return args.loglevels != None and LOG_VERBOSE in args.loglevels
+##############################################################################################
+
+def allocate_sectors(first_sector,available_sectors,sector_alignment_grain,minimum_kb,maximum_kb,align_start=True):
+ min_sectors = minimum_kb / 512
+ max_sectors = maximum_kb / 512
+
+ if minimum_kb < ( min_sectors * 512 ): min_sectors += 1
+ if maximum_kb < ( max_sectors * 512 ): max_sectors += 1
+
+ if max_sectors == 0: max_sectors = available_sectors
+
+ debug("requested minimum %s and maximum %s sectors" % (min_sectors,max_sectors))
+
+ # align the first sector except unless requested not to
+ start_sector = align(first_sector,sector_alignment_grain) if align_start else first_sector
+
+ debug("allocating sectors, %d available starting at sector %d" % (available_sectors,start_sector))
+ debug("starting sector %d aligned to %d" % (first_sector,start_sector))
+ available_sectors -= (start_sector - first_sector)
+ debug("%d available sectors after front alignment" % available_sectors)
+
+ if available_sectors < min_sectors:
+ abort("Unable to allocate %d sectors (%d available)" % (min_sectors,available_sectors))
+
+ num_sectors = max_sectors if available_sectors >= max_sectors else available_sectors
+ debug( "allocated %d sectors" % num_sectors)
+
+ next_sector = start_sector + num_sectors
+ debug("the next free sector is %d" % next_sector)
+
+ # Unless we've used up all sectors, align the next free sector and extend allocation
+ if next_sector == start_sector + available_sectors:
+
+ # There are no more free sectors; the end sector is one less than the total number of sectors
+ # fdisk numbers LBA sectors from 0 but sector 0 is 'hidden' and contains the MBR. Sector
+ # numbers for partitions start at 1. Because there is a sector 0 the number of the last
+ # sector is one less than the total number of sectors. The value 'next sector' will be one
+ # greater than the total number of sectors, so we subtract 2 to get the last sector.
+ #
+ end_sector = next_sector - 1
+ next_sector = 0
+ available_sectors = 0
+
+ elif next_sector > start_sector + available_sectors:
+
+ # This case should never arise
+ abort("Unexpected sector number %d, which is greater than the total number of sectors, %d" % (next_sector,start_sector + available_sectors))
+
+ else:
+
+ # Align the next free sector; the end sector is the one before that
+ next_sector = align(next_sector,sector_alignment_grain)
+ end_sector = next_sector - 1
+
+ debug("start %d" % start_sector)
+ debug("end %d" % end_sector)
+ debug("num %d" % num_sectors)
+ debug("next %d" % next_sector)
+
+ return start_sector, end_sector, next_sector, available_sectors - (end_sector +1 - start_sector)
+
+def main(name, argv):
+
+ def cleanup():
+ try:
+ if loop_device: destroy_loop_device(loop_device)
+ if copy_loop_device: destroy_loop_device(copy_loop_device)
+ except NameError as e:
+ pass # move along, nothing to do
+
+ atexit.register(cleanup)
+
+ # Default sizes
+ pes = 4<<20 # 4MiB
+ #wbs = 8<<10 # 8KiB (not used)
+ vs = 2<<30 # 2GiB
+
+
+ # Parition sizing minima/maxima
+ bp_size_minimum = 40<<20 # 40MiB
+ bp_size_maximum = 40<<20 # 40MiB
+ rp_size_minimum = 1<<30 # 1GiB
+ rp_size_maximum = 0 # No limit
+
+ # Arguments
+ global args
+ parser = argparse.ArgumentParser(description=DESCRIPTION, formatter_class=argparse.RawDescriptionHelpFormatter)
+ parser.add_argument('--license', action='store_true', default=False, dest='license',
+ help='show the MIT License')
+ parser.add_argument('-d', '--device', action='store', dest='device',
+ help='Specify a device name (e.g. mmcblk0)')
+ parser.add_argument('-i', '--image', action='store', dest='image',
+ help='Specify an image file name(e.g. myimage.img)')
+ parser.add_argument('--copy', action='store', dest='copy',
+ help='Copy into the image from another image, directory or archive (tar) file ')
+ parser.add_argument('-c', '--create', action='store_true', default=False, dest='create',
+ help='Create (overwrites existing data)')
+ parser.add_argument('-v', '--verbose', action='append_const', const=LOG_VERBOSE, dest='loglevels',
+ help='Enable verbose message output')
+ parser.add_argument('--debug', action='append_const', const=LOG_DEBUG, dest='loglevels',
+ help='Enable debug message output')
+
+ parser.add_argument('--boot-minimum', action='store', dest='bp_size_minimum',
+ help='Override the boot partition minimum size default (%d)'%bp_size_minimum)
+ parser.add_argument('--boot-maximum', action='store', dest='bp_size_maximum',
+ help='Override the boot partition maximum size default (%d)'%bp_size_maximum)
+ parser.add_argument('--root-minimum', action='store', dest='rp_size_minimum',
+ help='Override the root partition minimum size default (%d)'%rp_size_minimum)
+ parser.add_argument('--root-maximum', action='store', dest='rp_size_maximum',
+ help='Override the root partition maximum size default (%d)'%rp_size_maximum)
+
+ parser.add_argument('--first-sector', action='store', dest='first_sector',
+ help='Specify a first sector to use (default is sector 1)')
+ parser.add_argument('--size', action='store', dest='volume_size',
+ help='Specify the size of the whole disk in bytes (default is %d bytes)'%vs)
+ parser.add_argument('--erase-block-size', action='store', dest='erase_block_size',
+ help='Specify the erase block size bytes (default is %d bytes or that of the device specified with -d)'%vs)
+ #parser.add_argument('--write-block-size', action='store', dest='write_block_size',
+ # help='Specify the write block size bytes (default is %d bytes or that of the device specified with -d)'%vs)
+
+ parser.add_argument('--no-align', action='store_false', default=True, dest='align',
+ help='Disable write block alignment')
+ parser.add_argument('--no-align-first', action='store_false', default=True, dest='align_first_partition',
+ help='Do not align the first partition (it will start at first-sector)')
+
+ args = parser.parse_args()
+
+ if args.license == True:
+ print LICENSE
+ return 0
+
+ if args.bp_size_minimum != None: bp_size_minimum = int(args.bp_size_minimum)
+ if args.bp_size_maximum != None: bp_size_maximum = int(args.bp_size_maximum)
+ if args.rp_size_minimum != None: rp_size_minimum = int(args.rp_size_minimum)
+ if args.rp_size_maximum != None: rp_size_maximum = int(args.rp_size_maximum)
+
+ # Preferred Erase Size
+ if args.erase_block_size != None:
+ pes = int(args.erase_block_size)
+ elif (args.device != None):
+ try:
+ device = args.device
+ device_sys_path = "/sys/class/block/%s" % (device, )
+ pes = int(file(device_sys_path+"/device/preferred_erase_size").read())
+ print "Using device %s" % device
+ vss = int(file(device_sys_path+"/size").read())
+ vs = vss * 512
+ except IOError as e:
+ print "Device %s not found: Using default values." % device
+ else:
+ print "No Device specified: Using default values."
+
+ # Write Block Size
+ #if args.write_block_size != None: wbs = int(args.write_block_size)
+
+ # Volume size in sectors
+ if args.volume_size != None: vs = int(args.volume_size)
+ vss = vs / 512 # vs in sectors
+
+ # First available sector (sector 0 is reserved for the MBR which contains the partition table)
+ first_sector = 1 if args.first_sector == None else int(args.first_sector)
+
+ print "------------------------------------------------------------"
+
+ print "Volume Size : %d sectors" % vss
+ print_bytes("Volume Size",vs)
+
+ if bp_size_minimum>0: print_bytes("Boot Partition Minimum Size",bp_size_minimum)
+ if bp_size_maximum>0: print_bytes("Boot Partition Maximum Size",bp_size_maximum)
+ if rp_size_minimum>0: print_bytes("Root Partition Minimum Size",rp_size_minimum)
+ if rp_size_maximum>0: print_bytes("Root Partition Maximum Size",rp_size_maximum)
+
+ #print_bytes("Write Block Size",wbs)
+ print_bytes("Preferred Erase Size",pes)
+
+ # sector alignment grain in sectors (512 bytes per sector)
+ sector_alignment_grain = pes/512
+ print "Sector Alignment Grain : %d / 512 = %d sectors" % (pes,sector_alignment_grain)
+
+ # Total number of available sectors includes the first sector (which is sector 0)
+ # the unused sectors are 0 thru (first_sector -1). Sector 0 is reserved for the MBR.
+ available_sectors = vss - first_sector
+
+ print "Starting at sector %d of %d total sectors" % (first_sector,vss)
+ print "The %d available sectors are %d thru %d" % (available_sectors,first_sector,vss-1)
+ print "%d sectors will be skipped (sectors 0 thru %d)" % (first_sector,first_sector-1)
+
+
+ print
+ print " Partition description"
+
+ # Boot partition
+ bp_start_sector, bp_end_sector, next_sector, available_sectors = allocate_sectors(first_sector,available_sectors,sector_alignment_grain,bp_size_minimum,bp_size_maximum,args.align_first_partition)
+ print_partition_info("boot",bp_start_sector, bp_end_sector)
+
+ # Root partition
+ rp_start_sector, rp_end_sector, next_sector, available_sectors = allocate_sectors(next_sector,available_sectors,sector_alignment_grain,rp_size_minimum,rp_size_maximum)
+ print_partition_info("root",rp_start_sector,rp_end_sector)
+
+ # Report any unused sectors
+ if available_sectors > 0:
+ print "Partitioning scheme leaves %s sectors unused" % available_sectors
+
+ # Only proceed if create option given
+ if args.create == False:
+ return 0
+
+ # must be root to go beyond here
+ if os.geteuid() != 0:
+ abort('Partitioning requires root privileges (and you are not root)')
+
+ # Where to write data
+ if args.image != None:
+ dest = args.image
+ elif args.device != None:
+ dest = args.device
+ dest_device = "/dev/%s" % dest
+ else:
+ print "Nothing to Create: neither device nor image specified."
+ return 0
+
+ # If dest is an image, create the image file and set up a loop device for it
+ if dest == args.image:
+ try:
+ if os.path.exists(dest): os.remove(dest) # remove any old image first
+ if pexpect.run('/bin/bash -c "df -T . | tail -1 | awk \'{print $2}\'"').rstrip() == "ext4":
+ debug("Using fallocate to create %s (%d bytes)" % (dest,vs))
+ pexpect.run("fallocate -l %d %s" % (vs,dest))
+ else:
+ debug("Using truncate to create %s (%d bytes)" % (dest,vs))
+ pexpect.run("truncate -s %d %s" % (vs,dest))
+
+ # make file owned by actual user (e.g. not root if invoked with sudo)
+ user = pexpect.run('logname').strip()
+ if user != os.environ['USER']:
+ uid = pwd.getpwnam(user).pw_uid
+ gid = pwd.getpwnam(user).pw_gid
+ os.chown(dest,uid,gid)
+ debug("Changed %s ownweship to user %s (%d:%d)" % (dest,user,uid,gid))
+
+ loop_device = create_loop_device(dest)
+ dest_device = loop_device
+
+ dest_size = os.path.getsize("myimage")
+ if dest_size != vs:
+ os.remove(dest)
+ abort("Created %s has incorrect size %d (expected %d)"%(dest,dest_size,vs))
+
+ except IOError as e:
+ abort("Unable to create %s" % dest)
+
+ # Make sure we can write to the destination
+ writable_or_die(dest_device)
+
+ debug("Will write to %s as %s" % (dest,dest_device))
+
+ # Get user confirmation
+ print "About to write new partition table to %s. Any existing data will be lost!!!!" % dest
+ if (raw_input("Enter 'yes' to continue (anything else quits!)...") != 'yes'):
+ return 0
+
+ # Do partitioning with parted
+ do_or_die("parted -s %s mktable msdos" % dest_device)
+ do_or_die("parted -s %s unit s mkpart primary fat32 %d %d" % (dest_device,bp_start_sector,bp_end_sector))
+ do_or_die("parted -s %s unit s mkpart primary ext2 %d %d" % (dest_device,rp_start_sector,rp_end_sector))
+
+ # Print the partition table
+ if verbose_enabled(): do_or_die("parted %s unit s print" % dest_device)
+
+ # Recreate any loop device so partition devices are available
+ try:
+ if loop_device:
+ destroy_loop_device(loop_device)
+ loop_device = create_loop_device(dest)
+ except NameError as e:
+ pass # move along, nothing to do
+
+ # Partition filesystem devices
+ dest_p1 = dest_device+"p1"
+ dest_p2 = dest_device+"p2"
+
+ # boot filesystem to be FAT16, aligned
+ #
+ # vfat args:
+ # -I Don't complain about using whole device
+ # -F 16 FAT size is 16 bit
+ # -n boot volume label is 'boot'
+ # -s 16 sectors per cluster (16 * 512 = 8KiB)
+ # -v Verbose output
+ # -R number of sectors to reserve
+
+ print "Creating boot filesystem"
+
+ # Make sure we can write to the partition
+ writable_or_die(dest_p1)
+
+ # Make unaligned FAT filesystem to establish FAT size
+ mkfs = pexpect.spawn("mkfs.vfat -I -F 16 -n boot -s 16 -v %s" % dest_p1)
+ if debug_enabled(): mkfs.logfile = sys.stdout
+ mkfs.expect('FAT size is ([0-9]+) sectors')
+ fat_sectors = int(mkfs.match.groups()[0])
+ mkfs.expect('Volume ID is (.*), volume label (.*)')
+ vol_id, vol_name = mkfs.match.groups()
+ mkfs.expect(pexpect.EOF)
+
+ # make aligned FAT filesystem
+ if args.align == True and args.align_first_partition == True:
+
+ debug("There are %d sectors in the FAT" % fat_sectors)
+
+ # There are two FATS, work out total size in bytes
+ fat_bytes = fat_sectors * 512 *2
+ debug("FAT sectors total %d bytes" % fat_bytes)
+
+ # Work out how many sectors to reserve to achieve alignment
+ reserved_sectors = (pes - fat_bytes) / 512
+ debug("Reserve %d sectors to achieve alignment" % reserved_sectors)
+
+ # Make aligned FAT filesystem
+ mkfs = pexpect.spawn("mkfs.vfat -I -F 16 -n boot -s 16 -R %d -v %s" % (reserved_sectors, dest_p1))
+ if debug_enabled(): mkfs.logfile = sys.stdout
+ mkfs.expect('Volume ID is (.*), volume label (.*)')
+ vol_id, vol_name = mkfs.match.groups()
+ mkfs.expect(pexpect.EOF)
+
+ print "Created volume %s id %s" % (vol_id, vol_name.strip())
+ uuid = pexpect.run("blkid -o value -s UUID %s" % dest_p1).strip()
+ print "Volume UUID: %s" % uuid
+
+ # root partition to be ext4, aligned
+ #
+ # ext4 args:
+ # -O ^has_journal disable journalling
+ # -E stride=2 treat 2 blocks as 1
+ # stripe-width=512
+ # -b
+ # -L root
+
+ print "Creating root filesystem"
+
+ # Make sure we can write to the partition
+ writable_or_die(dest_p2)
+
+ ext4_block_size = 4096
+ ext4_stride = 2
+ ext4_stride_size = ext4_block_size * ext4_stride
+ ext4_stripe_width = pes / ext4_stride_size
+
+ mkfs = pexpect.spawn("mkfs.ext4 -O ^has_journal -E stride=%d,stripe-width=%d -b %d -L root %s" % (ext4_stride, ext4_stripe_width, ext4_block_size, dest_p2))
+ if debug_enabled(): mkfs.logfile = sys.stdout
+ mkfs.expect(pexpect.EOF)
+
+ uuid = pexpect.run("blkid -o value -s UUID %s" % dest_p2).strip()
+ print "Volume UUID: %s" % uuid
+
+ if args.copy != None:
+ copy = args.copy
+
+ # Mount the image
+ dest_mount_point = tempfile.mkdtemp()
+ debug("Mounting %s on %s" % (dest_p2,dest_mount_point))
+ pexpect.run("mount %s %s" % (dest_p2,dest_mount_point))
+ os.mkdir(dest_mount_point+"/boot")
+ debug("Mounting %s on %s" % (dest_p1,dest_mount_point+"/boot"))
+ pexpect.run("mount %s %s" % (dest_p1,dest_mount_point+"/boot"))
+
+ copy_type = pexpect.run("file %s" % copy).strip()
+ if "x86 boot sector" in copy_type:
+ print "Copying from image %s ..." % copy
+ copy_loop_device = create_loop_device(copy)
+ copy_boot_device = copy_loop_device+"p1"
+ copy_root_device = copy_loop_device+"p2"
+ copy_mount_point = tempfile.mkdtemp()
+ debug("Mounting %s on %s" % (copy_root_device,copy_mount_point))
+ debug("Mounting %s on %s" % (copy_boot_device,copy_mount_point+"/boot"))
+ pexpect.run("mount %s %s" % (copy_root_device,copy_mount_point))
+ pexpect.run("mount %s %s" % (copy_boot_device,copy_mount_point+"/boot"))
+ debug("Copying from %s to %s" % (copy_mount_point,dest_mount_point))
+ os.system("cd %s ; cp -a * %s" % (copy_mount_point,dest_mount_point))
+ debug("Unmounting %s" % copy_boot_device)
+ os.system("umount %s" % copy_boot_device)
+ debug("Unmounting %s" % copy_root_device)
+ os.system("umount %s" % copy_root_device)
+ debug("Removing directory %s" % copy_mount_point)
+ os.rmdir(copy_mount_point)
+
+ elif "directory" in copy_type:
+ print "Copyng from directory" % copy
+ os.system("cd %s ; cp -a * %s" % (copy,dest_mount_point))
+ elif "tar archive" in copy_type or "compressed data" in copy_type:
+ if "compressed data" in copy_type: print "File is compressed (assuming compressed tar file)"
+ print "Copying from tar file" % copy
+ os.system("cd %s ; tar xf %s" % (dest_mount_point, copy))
+ else:
+ print "Don't know how to copy %s" % copy
+
+ # Unmount the image
+ debug("Unmounting %s" % dest_p1)
+ pexpect.run("umount %s" % dest_p1) # /boot
+ debug("Unmounting %s" % dest_p2)
+ pexpect.run("umount %s" % dest_p2) # /
+
+ print "done"
+
+sys.exit(main(sys.argv[0], sys.argv[1:]))
diff --git a/disk/rpi_mount b/disk/rpi_mount
new file mode 100755
index 0000000..a130a73
--- /dev/null
+++ b/disk/rpi_mount
@@ -0,0 +1,82 @@
+#!/bin/bash
+#
+# Mounts an RPI image or device (sdcard)
+#
+# usage: rpi_mount image mount_point
+#
+
+# Copyright (c) 2012 John Lane
+#
+# MIT License
+#
+# 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.
+#
+# http://www.opensource.org/licenses/mit-license.php
+
+
+if [[ $(id -u ) != 0 ]]; then
+
+ echo "Must be root"
+
+elif [[ ! -d $2 ]]; then
+
+ echo "Mount point $2 does not exist"
+
+else
+
+ if [[ -b $1 ]]; then
+
+ # mount a device
+
+ [[ ${1:5:6} == mmcblk ]] && partition_prefix="p"
+
+ boot_partition=${1}${partition_prefix}1
+ root_partition=${1}${partition_prefix}2
+
+ elif [[ -f $1 ]]; then
+
+ if [[ "$(file -b myimage | awk -F ';' '{print $1}')" == "x86 boot sector" ]]; then
+
+ # loop mount an image
+
+ loop_device=$(losetup -f)
+
+ losetup -P $loop_device $1
+
+ boot_partition=${loop_device}p1
+ root_partition=${loop_device}p2
+
+ fi
+
+ fi
+
+ if [[ ! -z "${boot_partition}" ]]; then
+
+ mount $root_partition $2
+ mkdir -p $2/boot
+ mount $boot_partition $2/boot
+
+ else
+ echo "Don't know how to mount $1. Sorry"
+ fi
+
+fi
+
+
diff --git a/disk/rpi_umount b/disk/rpi_umount
new file mode 100755
index 0000000..02b5d56
--- /dev/null
+++ b/disk/rpi_umount
@@ -0,0 +1,51 @@
+#!/bin/bash
+#
+# Unmounts an RPI image or device (sdcard)
+#
+# usage: rpi_umount mount_point
+#
+# Copyright (c) 2012 John Lane
+#
+# MIT License
+#
+# 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.
+#
+# http://www.opensource.org/licenses/mit-license.php
+
+if [[ $(id -u ) != 0 ]]; then
+
+ echo "Must be root"
+
+else
+
+ for device_path in $(mount | grep $1 | sort | awk '{print $1}')
+ do
+
+ umount $device_path
+
+ device=$(basename $device_path)
+
+ [[ ${device:0:4} == loop ]] && loop_device=${device_path:0:-2}
+
+ done
+
+ [[ -z "${loop_device}" ]] || losetup -d ${loop_device}
+
+fi
diff --git a/emulator/README.md b/emulator/README.md
new file mode 100644
index 0000000..cc6895b
--- /dev/null
+++ b/emulator/README.md
@@ -0,0 +1,44 @@
+# Raspberry Pi Emulator
+
+This describes a way to run a Raspberry Pi emulator using QEMU. It is written for Arch Linux but
+the techniques can be applied to other distributions.
+
+## Setup
+
+The setup script will install QEMU if it is not already installed. It will download a filesystem image,
+a kernel image and set up a data disk.
+Run as-is or modify it for your needs.
+
+Once the setup script completes, you will have
+
+1. QEMU installed
+2. A system image
+3. A ketnel image
+4. A data disk image
+
+## Booting
+
+The boot script will start QEMU using the images prepared by the setup script.
+Run as-is or modify it for your needs.
+
+## Networking
+
+The default network stack works. Note that using 'ping' to test the network connection will give the
+impression that it isn''t working. This is because ICMP traffic does does not work and is a limitation
+of the basic network stack, called SLIRP, provided by QEMU.
+
+## Data Disk
+
+The data disk image is presented as /dev/sdb. This needs to be formatted and mounted before use.
+Boot the emulator and then do:
+
+ $ mkfs.ext4 /dev/sdb
+ $ mount /dev/sdb /mnt
+
+## Acknowledgements
+
+Getting Raspberry Pi up and running in QEMU was quick and painless thanks to [this tutorial](http://xecdesign.com/qemu-emulating-raspberry-pi-the-easy-way). This worked first time for me with the default qemu package on Arch Linux and the archlinuxarm-13-06-2012.img.
+
+
+
+
diff --git a/emulator/boot b/emulator/boot
new file mode 100755
index 0000000..22fb473
--- /dev/null
+++ b/emulator/boot
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Boot the Raspberry Pi in QEMU
+#
+# Usage: boot [image]
+#
+# where [image] is a filesystem image to boot from. This is optional: if it is not
+# given then it defaults to "archlinux-13-0-6-2012.img" which must be present in
+# the current working directory.
+#
+# JL 2012-08-03
+#
+
+qemu-system-arm -machine versatilepb \
+ -cpu arm1176 \
+ -m 256 \
+ -no-reboot \
+ -serial stdio \
+ -kernel kernel-qemu \
+ -append "root=/dev/sda2 panic=1" \
+ -hda ${1:-archlinuxarm-13-06-2012.img} \
+ -hdb data_disk.raw
diff --git a/emulator/setup b/emulator/setup
new file mode 100755
index 0000000..d9b287d
--- /dev/null
+++ b/emulator/setup
@@ -0,0 +1,31 @@
+#!/bin/bash
+#
+# Setup images for QEMU Emulator
+#
+#
+# JL 2012-08-03
+
+image="13-06-2012"
+
+# Install QEMU
+
+pacman -Q qemu > /dev/null 2>&1 || sudo pacman -S qemu
+
+# Get kernel image
+
+[[ -f kernel-qemu ]] || wget http://xecdesign.com/downloads/linux-qemu/kernel-qemu
+
+# Get system image
+
+[[ -f archlinuxarm-$image.img ]] || {
+ wget http://achtbaan.nikhef.nl/events/rpi/images/archlinuxarm/archlinuxarm-$image/archlinuxarm-$image.zip
+ unzip archlinuxarm-$image.zip
+ mv archlinuxarm-$image/archlinuxarm-$image.img .
+ rm -rf archlinuxarm-$image archlinuxarm-$image.zip
+}
+
+# Make a data disk
+
+[[ -f data_disk.raw ]] || qemu-img create -f raw data_disk.raw 5G
+
+
diff --git a/scrapbook/CONTENTS.md b/scrapbook/CONTENTS.md
new file mode 100644
index 0000000..df84fdf
--- /dev/null
+++ b/scrapbook/CONTENTS.md
@@ -0,0 +1,24 @@
+# Raspberry Pi Scrapbook Contents
+
+## HowTos
+
+1. How to mount Raspberry Pi images
+ (HowTo_Mount_Image.md)
+
+2. How to provide entropy for pacman-key
+ (HowTo_Pacman_Keyring_Entropy)
+
+3. How to install Grub into a disk image
+ (source: http://www.sidebranch.com/papers/How%20To%20Install%20GRUB%20into%20a%20disk%20image.pdf)
+
+## Notes
+
+1. Notes on Formatting SD cards. A collection of links to some online information.
+ (Notes_Formatting_SD.md)
+
+## Scripts
+
+1. build script for making images. From [here](http://www.raspberrypi.org/phpBB3/viewtopic.php?p=129097#p129097).
+ (build)
+
+2. mkpartitions script contains basic commands to partition the sd card (nothing clever - just the basics).
diff --git a/scrapbook/HowTo_Install_GRUB_into_a_disk_image.pdf b/scrapbook/HowTo_Install_GRUB_into_a_disk_image.pdf
new file mode 100644
index 0000000..b064d3b
--- /dev/null
+++ b/scrapbook/HowTo_Install_GRUB_into_a_disk_image.pdf
Binary files differ
diff --git a/scrapbook/HowTo_Mount_Image.md b/scrapbook/HowTo_Mount_Image.md
new file mode 100644
index 0000000..291af78
--- /dev/null
+++ b/scrapbook/HowTo_Mount_Image.md
@@ -0,0 +1,49 @@
+# Mounting Raspberry Pi Images
+
+The official image files are at [here] [1]. To mount these on a
+filesystem you can use these tricks.
+
+(first, extract the .img from the downloaded .zip)
+
+## Gather required information
+
+The image is a disk image (i.e. it contains a partition table and partitions).
+We need to know the partition offsets within the image so that we can mount the filesystems.
+
+ $ parted archlinuxarm-01-03-2012.img
+ WARNING: You are not superuser. Watch out for permissions.
+ GNU Parted 3.1
+ Using .../archlinuxarm-01-03-2012.img
+ Welcome to GNU Parted! Type 'help' to view a list of commands.
+ (parted) unit
+ Unit? [compact]? B
+ (parted) print
+ Model: (file)
+ Disk .../archlinuxarm-01-03-2012.img: 1977614336B
+ Sector size (logical/physical): 512B/512B
+ Partition Table: msdos
+ Disk Flags:
+
+ Number Start End Size Type File system Flags
+ 1 512B 100000255B 99999744B primary fat16 lba
+ 2 100000256B 1977614335B 1877614080B primary ext3
+
+ (parted) q
+
+## Mount the first partition
+
+ sudo mount -o loop,offset=512 archlinuxarm-01-03-2012.img /mnt
+
+## Mount the second partition
+
+ sudo mount -o loop,offset=100000256 archlinuxarm-01-03-2012.img /mnt
+
+## Acknowledgement
+
+This is derived from a note written by [Andre Miller] [2] that has some further
+information and discussion.
+
+ [1]: http://www.raspberrypi.org/downloads
+
+ [2]: http://www.andremiller.net/content/mounting-hard-disk-image-including-partitions-using-linux
+
diff --git a/scrapbook/HowTo_Pacman_Keyring_Entropy.md b/scrapbook/HowTo_Pacman_Keyring_Entropy.md
new file mode 100644
index 0000000..f9b3af5
--- /dev/null
+++ b/scrapbook/HowTo_Pacman_Keyring_Entropy.md
@@ -0,0 +1,15 @@
+# Pacman Keyring Entropy
+
+Setting up the Pacman keyring requires "entropy" (randomness) in order to compute its keys.
+
+This is one way to quickly provide this entropy on a new system that has not been running
+long enough to do this on its own. (Such a system could otherwise take hours to complete
+"pacman-key --init")
+
+ $ pacman -S haveged
+ $ haveged -w 1024
+ $ pacman-key --init
+ $ pkill haveged
+ $ pacman -Rs haveged
+
+
diff --git a/scrapbook/Notes_Formatting_SD.md b/scrapbook/Notes_Formatting_SD.md
new file mode 100644
index 0000000..322c1d9
--- /dev/null
+++ b/scrapbook/Notes_Formatting_SD.md
@@ -0,0 +1,16 @@
+# Notes : Formatting SD Card
+
+# Found on the internet
+
+http://pastebin.com/u9Qpm5n0
+http://elinux.org/RPi_Tasks
+http://en.wikipedia.org/wiki/Master_boot_record
+http://libguestfs.org/virt-make-fs.1.html
+
+http://www.raspberrypi.org/phpBB3/viewtopic.php?p=118519
+
+(mkcard.sh:)
+http://www.raspberrypi.org/phpBB3/viewtopic.php?f=24&t=1079&p=8433&hilit=mbr#p8433
+
+
+
diff --git a/scrapbook/build b/scrapbook/build
new file mode 100755
index 0000000..c7dac7e
--- /dev/null
+++ b/scrapbook/build
@@ -0,0 +1,53 @@
+#!/bin/bash
+#
+# Arch Linux ARM Image Builder
+#
+# Licensed under the GPLv2.
+#
+# This script builds an Arch Linux ARM distribution/image.
+# First, it downloads and installs packages to the workingdir,
+# then configures some basics, sets the root password to "root",
+# and then creates a rootts.tar.gz and/or a UBI image, ready to flash.
+#
+# Usage: ./distro-builder workingdir
+#
+# NOTE: This script is interactive.
+# Agree to installing packages and answer "y" to cleaning the Pacman database.
+#
+# ==== Variables to set ====
+INSTALLEDPKGS="base kernel26 kernel26-headers file ntfs-3g openssh openssl"
+RELEASEVER=2011.06
+MAKETARGZ=1
+# ==== The Process ====
+mkdir -p $1
+echo -e "\033[1mInstalling packages...\033[0m"
+mkdir -p $1/var/lib/pacman
+pacman -Syyf --noconfirm --noprogressbar -r $1 $INSTALLEDPKGS
+
+echo -e "\033[1mSetting the password to 'root' and cleaning up:\033[0m"
+echo -e "root\nroot\n" | chroot $1/ /usr/bin/passwd root
+rm $1/dev/{console,null,zero}
+chroot $1/ mknod -m 600 /dev/console c 5 1
+chroot $1/ mknod -m 666 /dev/null c 1 3
+chroot $1/ mknod -m 666 /dev/zero c 1 5
+rm $1/etc/locale.gen
+echo "en_US.UTF-8 UTF-8" >> $1/etc/locale.gen
+echo "en_US ISO-8859-1" >> $1/etc/locale.gen
+echo "de_DE ISO-8859-1" >> $1/etc/locale.gen
+echo "de_DE@euro ISO-8859-15" >> $1/etc/locale.gen
+chroot $1/ /usr/sbin/locale-gen
+chroot $1/ yes | /usr/bin/pacman -Scc
+echo $RELEASEVER > $1/etc/alarm-version
+
+# Here is the rootfs.tar.gz part if you set MAKETARGZ to 1
+if [ $MAKETARGZ = 1 ]; then
+ echo -e "\033[1mCreating a rootfs.tar.gz...\033[0m"
+ cd $1
+ tar czf ../PlugApps-Linux-$RELEASEVER-rootfs.tar.gz ./*
+ cd ../
+else
+ echo -e "\033[1mNot creating a rootfs.tar.gz...\033[0m"
+fi
+
+echo -e "\033[1mCleaning up...\033[0m"
+rm -rf $1
diff --git a/scrapbook/mkpartitions b/scrapbook/mkpartitions
new file mode 100755
index 0000000..cd7df9d
--- /dev/null
+++ b/scrapbook/mkpartitions
@@ -0,0 +1,7 @@
+#!/bin/bash
+parted -s /dev/mmcblk0 mklabel msdos
+parted -s /dev/mmcblk0 unit cyl mkpart primary fat32 -- 0 16
+parted -s /dev/mmcblk0 set 1 boot on
+parted -s /dev/mmcblk0 unit cyl mkpart primary ext2 -- 16 -2
+mkfs.vfat /dev/mmcblk0p1
+mkfs.ext4 /dev/mmcblk0p2