builder
#!/bin/bash# Download Raspbian Image, remove first-boot stuff, add repos and install packages. # Raspbianarchitecture="$2"case "$architecture" in "armhf" | "") RASPBIAN_TORRENT_URL=https://downloads.raspberrypi.org/raspios_armhf/images/raspios_armhf-2021-05-28/2021-05-07-raspios-buster-armhf.zip.torrent RASPBIAN_SHA256=b6c04b34d231f522278fc822d913fed3828d0849e1e7d786db72f52c28036c62 ;; "arm64") RASPBIAN_TORRENT_URL=downloads.raspberrypi.org/raspios_arm64/images/raspios_arm64-2021-05-28/2021-05-07-raspios-buster-arm64.zip.torrent RASPBIAN_SHA256=f882c4c7202074277938b04fa770411c4b8a12f49e9ad2c2d70966e168b7bcb4 ;;esac RASPBIAN_IMAGE_FILE=$(basename $RASPBIAN_TORRENT_URL | sed -e "s/.zip.torrent/.img/g") EXTRA_IMAGE_SIZE=1850MB MINIMAL_SPACE_LEFT appears unused. Verify it or export it.MINIMAL_SPACE_LEFT=111111 source lib.sh missing_deps=()for prog in kpartx wget gpg parted qemu-arm-static aria2c jq curl; do if ! type $prog &>/dev/null ; then missing_deps+=( "$prog" ) fidoneif (( ${#missing_deps[@]} > 0 )) ; then die "Missing required programs: ${missing_deps[*]} On Debian/Ubuntu try 'sudo apt install kpartx qemu-user-static parted wget curl jq aria2'" fi function _umount { for dir in "$@" ; do if grep -q "$dir" /proc/self/mounts ; then if ! umount -f "$dir" ; then # shellcheck disable=SC2046,SC2086 die "Could not umount $dir, check running procs:$NL$(lsof 2>/dev/null | grep $(readlink -f $dir))" fi fi done} function _get_image { echo "Fetching $RASPBIAN_TORRENT_URL" mkdir -p images if [ ! -f "$RASPBIAN_TORRENT" ]; then wget "$RASPBIAN_TORRENT_URL" -O "$RASPBIAN_TORRENT" || die "Download of $RASPBIAN_TORRENT failed" fi aria2c --enable-dht=true --bt-enable-lpd=true --continue "$RASPBIAN_TORRENT" -d images --seed-time 0 echo -n "Checksum of " sha256sum --strict --check - <<<"$RASPBIAN_SHA256 *$IMAGE_ZIP" || die "Download checksum validation failed, please check http://www.raspberrypi.org/downloads"} function _decompress_image { unzip -o "$IMAGE_ZIP" -d images || die "Could not unzip $IMAGE_ZIP"} function _disable_daemons { # Prevent services from being started inside the chroot. POLICY_RC_D=mnt/img_root/usr/sbin/policy-rc.d echo "#!/bin/sh" >> $POLICY_RC_D echo "exit 101" >> $POLICY_RC_D chmod +x $POLICY_RC_D} function _enable_daemons { POLICY_RC_D=mnt/img_root/usr/sbin/policy-rc.d rm -f $POLICY_RC_D} function _disable_ld_preload { cfg=mnt/img_root/etc/ld.so.preload if grep -q '^[^#]' $cfg; then sed -i -e 's/^/#/' $cfg || die "Could not disable ld.so.preload" fi} function _enable_ld_preload { cfg=mnt/img_root/etc/ld.so.preload if grep -q '^#' $cfg; then sed -i -e 's/^#//' $cfg || die "Could not enable ld.so.preload" fi} function _resize_image { RESIZE_IMAGE_PATH=images/$RASPBIAN_IMAGE_FILE if [[ -L "images" ]]; then rsync -Pav "images/$RASPBIAN_IMAGE_FILE" . RESIZE_IMAGE_PATH=$RASPBIAN_IMAGE_FILE fi start_sector=$(fdisk -l "$RESIZE_IMAGE_PATH" | awk -F" " '{ print $2 }' | sed '/^$/d' | sed -e '$!d') LOOP_BASE=$(losetup -a | grep -c 'loop') #formerly loop0, loop1, loop2 echo "LOOP BASE: $LOOP_BASE" LOOP_ONE=$(( LOOP_BASE + 1 )) echo "LOOP ONE: $LOOP_ONE" LOOP_TWO=$(( LOOP_BASE + 2 )) echo "LOOP TWO: $LOOP_TWO" truncate -s +$EXTRA_IMAGE_SIZE "$RESIZE_IMAGE_PATH" losetup "/dev/loop$LOOP_ONE" "$RESIZE_IMAGE_PATH" fdisk "/dev/loop$LOOP_ONE" <<EOFpd2np2$start_sector pwEOF losetup -d "/dev/loop$LOOP_ONE" losetup -o $((start_sector*512)) "/dev/loop$LOOP_TWO" "$RESIZE_IMAGE_PATH" e2fsck -f "/dev/loop$LOOP_TWO" resize2fs -f "/dev/loop$LOOP_TWO" losetup -d "/dev/loop$LOOP_TWO" if [[ -L "images" ]]; then rsync -Pav "$RASPBIAN_IMAGE_FILE" images/ rm "$RASPBIAN_IMAGE_FILE" fi} function _open_image { echo "Stupid Snaps" losetup -a | grep 'loop' echo "Loop-back mounting" "images/$RASPBIAN_IMAGE_FILE" # shellcheck disable=SC2086 kpartx="$(kpartx -sav images/$RASPBIAN_IMAGE_FILE)" || die "Could not setup loop-back access to $RASPBIAN_IMAGE_FILE:$NL$kpartx" # shellcheck disable=SC2162 read -d '' img_boot_dev img_root_dev <<<"$(grep -o 'loop.p.' <<<"$kpartx")" test "$img_boot_dev" -a "$img_root_dev" || die "Could not extract boot and root loop device from kpartx output:$NL$kpartx" img_boot_dev=/dev/mapper/$img_boot_dev img_root_dev=/dev/mapper/$img_root_dev mkdir -p mnt/img_root mount -t ext4 "$img_root_dev" mnt/img_root || die "Could not mount $img_root_dev mnt/img_root" mkdir -p mnt/img_root/boot || die "Could not mkdir mnt/img_root/boot" mount -t vfat "$img_boot_dev" mnt/img_root/boot || die "Could not mount $img_boot_dev mnt/img_root/boot" echo "Raspbian Image Details:" df -h mnt/img_root/boot mnt/img_root | sed -e "s#$(pwd)/##"} function _close_image { _umount mnt/img_root/var/cache/apt/archives \ mnt/img_root/{proc,sys,run,dev/pts} \ mnt/sd_root/bo?t mnt/img_root/boot \ mnt/sd_ro?t mnt/img_root kpartx -d "images/$RASPBIAN_IMAGE_FILE" >/dev/null} function _prepare_chroot { _disable_ld_preload cp -a "$(type -p qemu-arm-static)" mnt/img_root/usr/bin/ || die "Could not copy qemu-arm-static" _chroot date &>/dev/null || die "Could not chroot date" mount -t devpts devpts -o noexec,nosuid,gid=5,mode=620 mnt/img_root/dev/pts || die "Could not mount /dev/pts" mount -t proc proc mnt/img_root/proc || die "Could not mount /proc" mount -t sysfs sys mnt/img_root/sys || die "Could not mount /sys" mount -t tmpfs -o mode=1777 none mnt/img_root/run || "Could not mount /run" mkdir -p apt_cache mount --bind apt_cache mnt/img_root/var/cache/apt/archives} function _cleanup_chroot { _umount mnt/img_root/var/cache/apt/archives \ mnt/img_root/{proc,sys,run,dev/pts} _enable_daemons _enable_ld_preload} function _check_space_left { space_left=$(df | grep "dev/mapper/loop$LOOP_BASE\p2" | awk '{printf $4}') echo "Space left: ${space_left}K"} function _count_authorized_keys_lines { authorized_keys_lines=$(wc -l < mnt/img_root/root/.ssh/authorized_keys) echo "There are ${authorized_keys_lines} line(s) in /root/.ssh/authorized_keys"} function _modify_image { echo "Modifying Image" _prepare_chroot _disable_daemons run-parts --arg="$architecture" --exit-on-error -v --regex '[a-zA-Z.-_]*' scripts.d ||\ die "Image modification scripts failed" _enable_daemons _check_space_left _count_authorized_keys_lines _cleanup_chroot} function _usage { echo "Usage: $0 <--chroot|--noninteractive> Download Raspbian Image, remove first-boot stuff, add repos and install packages. Open interactive Shell in chroot or write result to SD Card License: GNU General Public License, see http://www.gnu.org/copyleft/gpl.html for full text"} function _shell { _prepare_chroot chroot mnt/img_root bash -i _cleanup_chroot} export LANG="C" LANGUAGE="C" LC_ALL="C.UTF-8"shopt -s nullglob if [[ $# -eq 0 || "$*" == *-h* ]] ; then _usage exit 1fi if [[ "$USER" != root && $(id -u) != "0" ]] ; then # restart as root echo "Switching over to run as root" exec sudo "$(readlink -f "$0")" "$@" echo "Need sudo permission to run as root!" exit 1fi if grep -wq "$(readlink -f mnt)" /proc/self/mounts; then die "mnt/ is already mounted!"fi rm -Rf --one-file-system mnt tempfunction exittrap { set +u +e _close_image echo "Script execution time: $SECONDS seconds"}trap exittrap 0trap exittrap ERR function _print_tag { tag=$(git tag --sort=-creatordate | sed -n '1p') echo echo "latest tag is '$tag'" echo} _print_tag RASPBIAN_TORRENT=images/$(basename $RASPBIAN_TORRENT_URL)echo "$RASPBIAN_TORRENT"IMAGE_ZIP=${RASPBIAN_TORRENT%.torrent}echo "$IMAGE_ZIP"IMAGE=${IMAGE_ZIP%.zip}.imgecho "$IMAGE" if [ ! -e "$IMAGE_ZIP" ]; then _get_imagefi _decompress_image_resize_image_open_image if [[ "$1" == "--chroot" ]] ; then _modify_image echo "Starting interactive Shell in image chroot" _shellelif [[ "$1" == "--noninteractive" ]] ; then _modify_imageelif [[ "$1" == "--shell" ]]; then _shellelse die "Usage error. Try $0 --help"fi #if [[ $space_left -lt $MINIMAL_SPACE_LEFT ]]; then# echo "Not enough space left."# exit 1#fi if [[ $authorized_keys_lines -le 20 ]]; then echo "/root/.ssh/authorized_keys has 20 line or less." exit 1fi # vim:autoindent:tabstop=2:shiftwidth=2:expandtab:softtabstop=2: