Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Creates a chroot environment for creating custom Raspbian images and cross-compiling programs for the Raspberry Pi.
#!/bin/bash
# Creates a custom Raspbian image and cross-compilation environment.
#
# USAGE: ./create_image.sh
#
# This script must be run as either root or sudo.
#
# After creating the chroot environment, the script specified in the
# *script* variable will be executed from within the chroot. Your
# custom system setup commands should be located here. For example,
# this file may contain commands for creating new users, configuring
# the firewall, or compiling custom code.
#
# Prior to running this script, you will need the qemu,
# qemu-user-static, and binfmt-support Debian/Ubuntu packages (or
# their equivalent on other distributions). To install them on a
# Debian/Ubuntu system, use the command:
#
# sudo apt-get install qemu qemu-user-static binfmt-support
#
# This script has been tested in Ubuntu 16.04.4 LTS.
#
# Credit for much of this script goes to Michael Daffin:
# https://disconnected.systems/blog/custom-rpi-image-with-github-travis/
#
# Kyle M. Douglass, 2018
# https://kmdouglass.github.io
#
# Setup script error handling. See
# https://disconnected.systems/blog/another-bash-strict-mode for
# details.
set -uo pipefail
trap 's=$?; echo "$0: Error on line "$LINENO": $BASH_COMMAND"; exit $s' ERR
IFS=$'\n\t'
# Ensure root.
if [[ $EUID -ne 0 ]]; then
echo "Error: This script must be run as root or sudo."
exit 1
fi
# User-defined variables. Adjust these to your needs.
mount="/mnt/alphapi"
host_home="/home/kmdouglass"
script="setup"
rpi_zip="raspbian_lite_latest.zip"
rpi_url="https://downloads.raspberrypi.org/raspbian_lite_latest"
img_size="4G"
tmp_img="tmp.img"
loop_dev="/dev/loop2"
# Create the mount directory if it does not exist.
mkdir -p "${mount}"
# Download Raspbian only if we have not already done so.
[ ! -f "${rpi_zip}" ] && wget "${rpi_url}" -O "${rpi_zip}"
export orig_img_name=$(unzip -l raspbian_lite_latest.zip | grep .img | awk -F" " '{print $4}')
# Tasks to run when the shell exits for any reason, unmount the image
# and general cleanup.
cleanup() {
[[ -f "${tmp_img}" ]] && rm "${tmp_img}"
if [[ -d "${mount}" ]]; then
umount "${mount}/dev/pts" || true
umount "${mount}/dev" || true
umount "${mount}/proc" || true
umount "${mount}/sys" || true
umount "${mount}/boot" || true
umount "${mount}${host_home}" || true
umount "${mount}" || true
rm -r "${mount}" || true
fi
}
trap cleanup EXIT
# Extract the image.
unzip raspbian_lite_latest.zip
export root_start_sector=$(fdisk -l $orig_img_name | grep .img2 | awk -F" " '{print $2}')
export boot_start_sector=$(fdisk -l $orig_img_name | grep .img1 | awk -F" " '{print $2}')
export sector_size=$(fdisk -l $orig_img_name | grep "Sector size" | awk -F" " '{print $4}')
echo -e "Start sector: ${root_start_sector}\nSector size: ${sector_size}"
# Increase the size of the image by first appending zeros and then
# expanding the partition.
echo "Expanding the size of the image file..."
orig_size=$(du -h ${orig_img_name} | awk -F" " '{print $1}')
diff_size=$[$(numfmt --from=iec ${img_size}) - \
$(numfmt --from=iec ${orig_size})]
dd if=/dev/zero bs=1 count=1 seek=${diff_size} of=${tmp_img}
cat ${tmp_img} >> ${orig_img_name}
parted ${orig_img_name} resizepart 2 100%
# Mount the root image, check it, expand it, then unmount it.
losetup --offset=$[root_start_sector * sector_size] ${loop_dev} ${orig_img_name}
e2fsck -f ${loop_dev}
resize2fs -f ${loop_dev}
losetup -d ${loop_dev}
# Mount the images. Mount parts of the original image by using the
# offset option and the previously-determined sectors.
[ ! -d "${mount}" ] && mkdir "${mount}"
mount -o loop,offset=$[root_start_sector * sector_size] ${orig_img_name} ${mount}
[ ! -d "${mount}/boot" ] && mkdir "${mount}/boot"
mount -o loop,offset=$[boot_start_sector * sector_size] ${orig_img_name} ${mount}/boot
# Copy the image setup script.
install -Dm755 "${script}" "${mount}/tmp/${script}"
# Prep the chroot.
mount -t proc none ${mount}/proc
mount -t sysfs none ${mount}/sys
mount -o bind /dev ${mount}/dev
mount -o bind /dev/pts ${mount}/dev/pts
# Provide network access to the chroot.
rm ${mount}/etc/resolv.conf
cp /etc/resolv.conf ${mount}/etc/resolv.conf
cp /usr/bin/qemu-arm-static ${mount}/usr/bin/
# Mount my current home directory which contains the software to build.
echo "Mounting host home directory..."
echo "Mount point: ${mount}${host_home}"
mkdir -p "${mount}${host_home}"
mount -o bind ${host_home} ${mount}${host_home}
chroot ${mount} "/tmp/${script}"
@hadim

This comment has been minimized.

Copy link

commented Mar 29, 2018

That looks very useful @kmdouglass !

A Docker image running it would make it even more accessible :-D

@kmdouglass

This comment has been minimized.

Copy link
Owner Author

commented Mar 30, 2018

That's the next step ;p I just got a new Pi Model 3B+ and when I get time I'll test to verify that the Micro-Manager build is working correctly. If it is, I'll put all the scripts inside the Docker image.

I also need to tinker a bit with properly setting up the firewall and user security settings before I post the setup script...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.