Created
March 25, 2018 12:06
-
-
Save kmdouglass/38e1383c7e62745f3cf522702c21cb49 to your computer and use it in GitHub Desktop.
Creates a chroot environment for creating custom Raspbian images and cross-compiling programs for the Raspberry Pi.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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}" |
Hi @kmdouglass,
I see, well I did manage to figure it out.
I ran into this: https://forums.raspberrypi.com/viewtopic.php?t=190154
With some trial and error I managed to use fstab
to get the limit sizes and that part works now!
I am running into this now :(
install: cannot stat 'setup.sh': No such file or directory
./.github/workflows/scripts/create_image.sh: Error on line 153: install -Dm755 "${script}" "${mount}/tmp/${script}"
Could this just simply be a pathing issue?
Nice, got that to work by splitting the actual script path and the file I wanted to mount.
Anyway, I know you haven't touched this for a long time but I have one remaining question.
I now have a script that mounts(chroots?) the iso, copies a folder and runs an install script.
How do I now turn that into a new ISO?
Is that just implicitly done by unmounting because of the chroot?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @Marvin-Brouwer ,
Thanks for the tweaks! I haven't worked on this for a few years and, to be honest, I don't remember the details of this script.
Looking at the error message, my guess is that the
mount
command is failing because either theboot_start_sector
orroot_start_sector
values are wrong, which would mean that you're trying to mount part of the same image twice. This is just a guess, however.