diff --git a/Dockerfile b/Dockerfile index 2e53149..3d5874d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ -FROM debian:buster +ARG BASE_IMAGE=debian:buster +FROM ${BASE_IMAGE} ENV DEBIAN_FRONTEND noninteractive diff --git a/README.md b/README.md index c218fe0..1563bd8 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ # pi-gen -_Tool used to create the raspberrypi.org Raspbian images_ +Tool used to create Raspberry Pi OS images. (Previously known as Raspbian). ## Dependencies -pi-gen runs on Debian based operating systems. Currently it is only supported on +pi-gen runs on Debian-based operating systems. Currently it is only supported on either Debian Buster or Ubuntu Xenial and is known to have issues building on earlier releases of these systems. On other Linux distributions it may be possible to use the Docker build described below. -To install the required dependencies for pi-gen you should run: +To install the required dependencies for `pi-gen` you should run: ```bash apt-get install coreutils quilt parted qemu-user-static debootstrap zerofree zip \ @@ -68,7 +68,7 @@ The following environment variables are supported: system for each build stage, amounting to tens of gigabytes in the case of Raspbian. - **CAUTION**: If your working directory is on an NTFS partition you probably won't be able to build. Make sure this is a proper Linux filesystem. + **CAUTION**: If your working directory is on an NTFS partition you probably won't be able to build: make sure this is a proper Linux filesystem. * `DEPLOY_DIR` (Default: `"$BASE_DIR/deploy"`) @@ -116,12 +116,24 @@ The following environment variables are supported: * `WPA_ESSID`, `WPA_PASSWORD` and `WPA_COUNTRY` (Default: unset) - If these are set, they are use to configure `wpa_supplicant.conf`, so that the Raspberry Pi can automatically connect to a wifi network on first boot. If `WPA_ESSID` is set and `WPA_PASSWORD` is unset an unprotected wifi network will be configured. If set, `WPA_PASSWORD` must be between 8 and 63 characters. + If these are set, they are use to configure `wpa_supplicant.conf`, so that the Raspberry Pi can automatically connect to a wireless network on first boot. If `WPA_ESSID` is set and `WPA_PASSWORD` is unset an unprotected wireless network will be configured. If set, `WPA_PASSWORD` must be between 8 and 63 characters. * `ENABLE_SSH` (Default: `0`) Setting to `1` will enable ssh server for remote log in. Note that if you are using a common password such as the defaults there is a high risk of attackers taking over you Raspberry Pi. + * `PUBKEY_SSH_FIRST_USER` (Default: unset) + + Setting this to a value will make that value the contents of the FIRST_USER_NAME's ~/.ssh/authorized_keys. Obviously the value should + therefore be a valid authorized_keys file. Note that this does not + automatically enable SSH. + + * `PUBKEY_ONLY_SSH` (Default: `0`) + + * Setting to `1` will disable password authentication for SSH and enable + public key authentication. Note that if SSH is not enabled this will take + effect when SSH becomes enabled. + * `STAGE_LIST` (Default: `stage*`) If set, then instead of working through the numeric stages in order, this list will be followed. For example setting to `"stage0 stage1 mystage stage2"` will run the contents of `mystage` before stage2. Note that quotes are needed around the list. An absolute or relative path can be given for stages outside the pi-gen directory. @@ -256,7 +268,7 @@ maintenance and allows for more easy customization. - **Stage 2** - lite system. This stage produces the Raspbian-Lite image. It installs some optimized memory functions, sets timezone and charmap - defaults, installs fake-hwclock and ntp, wifi and bluetooth support, + defaults, installs fake-hwclock and ntp, wireless LAN and bluetooth support, dphys-swapfile, and other basics for managing the hardware. It also creates necessary groups and gives the pi user access to sudo and the standard console hardware permission groups. diff --git a/build-docker.sh b/build-docker.sh index b6a9ea3..350f722 100755 --- a/build-docker.sh +++ b/build-docker.sh @@ -73,7 +73,17 @@ fi # Modify original build-options to allow config file to be mounted in the docker container BUILD_OPTS="$(echo "${BUILD_OPTS:-}" | sed -E 's@\-c\s?([^ ]+)@-c /config@')" -${DOCKER} build -t pi-gen "${DIR}" +# Check the arch of the machine we're running on. If it's 64-bit, use a 32-bit base image instead +case "$(uname -m)" in + x86_64|aarch64) + BASE_IMAGE=i386/debian:buster + ;; + *) + BASE_IMAGE=debian:buster + ;; +esac +${DOCKER} build --build-arg BASE_IMAGE=${BASE_IMAGE} -t pi-gen "${DIR}" + if [ "${CONTAINER_EXISTS}" != "" ]; then trap 'echo "got CTRL+C... please wait 5s" && ${DOCKER} stop -t 5 ${CONTAINER_NAME}_cont' SIGINT SIGTERM time ${DOCKER} run --rm --privileged \ diff --git a/build.sh b/build.sh index 3652a12..725ab61 100755 --- a/build.sh +++ b/build.sh @@ -169,6 +169,7 @@ export WPA_ESSID export WPA_PASSWORD export WPA_COUNTRY export ENABLE_SSH="${ENABLE_SSH:-0}" +export PUBKEY_ONLY_SSH="${PUBKEY_ONLY_SSH:-0}" export LOCALE_DEFAULT="${LOCALE_DEFAULT:-en_GB.UTF-8}" @@ -179,6 +180,8 @@ export TIMEZONE_DEFAULT="${TIMEZONE_DEFAULT:-Europe/London}" export GIT_HASH=${GIT_HASH:-"$(git rev-parse HEAD)"} +export PUBKEY_SSH_FIRST_USER + export CLEAN export IMG_NAME export APT_PROXY @@ -218,6 +221,11 @@ if [[ -n "${WPA_PASSWORD}" && ${#WPA_PASSWORD} -lt 8 || ${#WPA_PASSWORD} -gt 63 exit 1 fi +if [[ "${PUBKEY_ONLY_SSH}" = "1" && -z "${PUBKEY_SSH_FIRST_USER}" ]]; then + echo "Must set 'PUBKEY_SSH_FIRST_USER' to a valid SSH public key if using PUBKEY_ONLY_SSH" + exit 1 +fi + mkdir -p "${WORK_DIR}" log "Begin ${BASE_DIR}" diff --git a/export-image/01-set-sources/01-run.sh b/export-image/01-set-sources/01-run.sh index 86dea2d..5f51209 100755 --- a/export-image/01-set-sources/01-run.sh +++ b/export-image/01-set-sources/01-run.sh @@ -1,5 +1,7 @@ #!/bin/bash -e +rm -f "${ROOTFS_DIR}/etc/apt/apt.conf.d/51cache" +find "${ROOTFS_DIR}/var/lib/apt/lists/" -type f -delete on_chroot << EOF apt-get update apt-get -y dist-upgrade diff --git a/export-image/04-finalise/01-run.sh b/export-image/04-finalise/01-run.sh index c3aa1eb..91264e5 100755 --- a/export-image/04-finalise/01-run.sh +++ b/export-image/04-finalise/01-run.sh @@ -12,7 +12,10 @@ if hash hardlink 2>/dev/null; then fi EOF -rm -f "${ROOTFS_DIR}/etc/apt/apt.conf.d/51cache" +if [ -d "${ROOTFS_DIR}/home/${FIRST_USER_NAME}/.config" ]; then + chmod 700 "${ROOTFS_DIR}/home/${FIRST_USER_NAME}/.config" +fi + rm -f "${ROOTFS_DIR}/usr/bin/qemu-arm-static" if [ "${USE_QEMU}" != "1" ]; then diff --git a/export-image/prerun.sh b/export-image/prerun.sh index 8bbc566..4b5cf8c 100755 --- a/export-image/prerun.sh +++ b/export-image/prerun.sh @@ -39,8 +39,32 @@ BOOT_LENGTH=$(echo "$PARTED_OUT" | grep -e '^1:' | cut -d':' -f 4 | tr -d B) ROOT_OFFSET=$(echo "$PARTED_OUT" | grep -e '^2:' | cut -d':' -f 2 | tr -d B) ROOT_LENGTH=$(echo "$PARTED_OUT" | grep -e '^2:' | cut -d':' -f 4 | tr -d B) -BOOT_DEV=$(losetup --show -f -o "${BOOT_OFFSET}" --sizelimit "${BOOT_LENGTH}" "${IMG_FILE}") -ROOT_DEV=$(losetup --show -f -o "${ROOT_OFFSET}" --sizelimit "${ROOT_LENGTH}" "${IMG_FILE}") +echo "Mounting BOOT_DEV..." +cnt=0 +until BOOT_DEV=$(losetup --show -f -o "${BOOT_OFFSET}" --sizelimit "${BOOT_LENGTH}" "${IMG_FILE}"); do + if [ $cnt -lt 5 ]; then + cnt=$((cnt + 1)) + echo "Error in losetup for BOOT_DEV. Retrying..." + sleep 5 + else + echo "ERROR: losetup for BOOT_DEV failed; exiting" + exit 1 + fi +done + +echo "Mounting ROOT_DEV..." +cnt=0 +until ROOT_DEV=$(losetup --show -f -o "${ROOT_OFFSET}" --sizelimit "${ROOT_LENGTH}" "${IMG_FILE}"); do + if [ $cnt -lt 5 ]; then + cnt=$((cnt + 1)) + echo "Error in losetup for ROOT_DEV. Retrying..." + sleep 5 + else + echo "ERROR: losetup for ROOT_DEV failed; exiting" + exit 1 + fi +done + echo "/boot: offset $BOOT_OFFSET, length $BOOT_LENGTH" echo "/: offset $ROOT_OFFSET, length $ROOT_LENGTH" diff --git a/export-noobs/00-release/files/OS.png b/export-noobs/00-release/files/OS.png index 02b67cf..3091bf9 100644 Binary files a/export-noobs/00-release/files/OS.png and b/export-noobs/00-release/files/OS.png differ diff --git a/export-noobs/00-release/files/release_notes.txt b/export-noobs/00-release/files/release_notes.txt index 8d7f014..be998d9 100644 --- a/export-noobs/00-release/files/release_notes.txt +++ b/export-noobs/00-release/files/release_notes.txt @@ -1,4 +1,76 @@ UNRELEASED: + * PulseAudio now included and running by default + * Bluealsa Bluetooth interface removed - Bluetooth audio is now handled by PulseAudio + * LXPanel volume control plugin replaced with PulseAudio version + * Version 84.0.4147.105 of Chromium web browser included + * Version 3.3.0 of Thonny included + * Version 32.0.0.453 of Flash player included - note that this will be the final release of Flash, as it is end-of-lifed at the end of 2020 + * CUPS printer system included, along with system-config-printer CUPS GUI and HP printer drivers + * raspi-config menu structure rearranged to match Raspberry Pi Configuration tabs + * Control for GPIO-connected fans added to raspi-config and Raspberry Pi Configuration + * Control for power / activity LED on Pi 400 and Pi Zero added to raspi-config and Raspberry Pi Configuration + * Improved screen reader voice prompts in several applications + * Added ctrl-alt-space shortcut to install Orca screen reader at any point + * Low voltage warnings added to battery monitor plugin + * Magnifier plugin zoom can now be changed with scroll wheel when pointer is over icon + * Change to notification popups - now will only close when clicked on directly, not by clicking anywhere + * Bookshelf now made compatible with translated versions of books and magazines, and will offer translated versions where available, based on system language setting + * Bug fix - crash in CPU temperature plugin when throttling detection fails + * Bug fix - if Orca is running, shutdown commands and shutdown dialog will force kill it to prevent it locking up the reboot or shutdown process + * Various additional language translations added + * Various minor bug fixes and UI tweaks + * Raspberry Pi firmware b324aea801f669b6ab18441f970e74a5a7346684 + * Linux kernel 5.4.79 +2020-08-20: + * raspi-config - added selection of boot device order + * raspi-config - added selection of boot EEPROM version + * SD Card Copier - copy is now immediately aborted if drives are connected or disconnected while copying + * Version 32.0.0.414 of Flash player included + * User feedback survey removed from first run of Chromium + * Recommended Software - now allows multiple install and reinstall operations without having to close between each one + * Bug fix - misleading file browser from panel menu icon selection dialog - icons must now be in icon theme rather than arbitrary files + * Bug fix - items in main menu not being translated + * Bug fix - raspi-config not detecting audio devices in non-English locales + * Bug fix - Bookshelf claiming no disk space in non-English locales + * Bug fix - failed installation of both 32 and 64 bit versions of packages by Recommended Software on 64-bit images + * Italian translations added (thanks to Emanuele Goldoni and the Italian translation team) + * Raspberry Pi firmware ef72c17bcaaeb89093d87bcf71f3228e1b5e1fff + * Linux kernel 5.4.51 +2020-05-27: + * Added Bookshelf application + * Added Raspberry Pi Diagnostics application + * Added magnifier plugin to taskbar - needs magnifier application installed from Recommended Software to enable + * Added Magnifier application to Recommended Software + * Added marketing questionnaire as initial Chromium tab + * Version 0.25 of Scratch 2 included - uses external application to access IMU on SenseHAT + * Version 1.0.5 of Scratch 3 included - uses external application to access IMU on SenseHAT + * Version 32.0.0.371 of Flash player included + * Version 1.0.6 of Node-RED included + * Version 6.7.1 of VNC Server included + * Version 6.20.113 of VNC Client included + * Internal audio outputs enabled as separate ALSA devices + * MagPi preinstall removed and replaced with Beginner’s Guide + * MagPi weblink removed from main menu + * Chromium made default application for PDF files + * Common icon loading code for lxpanel plugins used + * Italian translations added + * Initial move of mouse pointer to menu button disabled + * Padding at left of menu button removed + * Focus behaviour changed so that focus moves to desktop if no windows are opened - improves reliability of Orca screen reader + * Bug fix - focus bug in volume plugin + * Bug fix - keyboard repeat interval bug in Mouse & Keyboard Settings + * Bug fix - battery detection bug in battery plugin + * Bug fix - spurious active areas on taskbar when plugins are hidden + * Bug fix - occasional crash in file manager on file selection + * Disk ID is now regenerated on first boot + * Updated udev rules + - Remove unused argon rule + - Add vcsm-cma to video group + - Add pwm to gpio group + * i2cprobe: More flexible I2C/SPI alias mapping + * Raspberry Pi firmware 21e1fe3477ffb708a5736ed61a924fd650031136 + * Linux kernel 4.19.118 +2020-02-13: * Raspberry Pi Configuration - screen blanking setting disabled if Xscreensaver is installed * Bug fix - switch to turn off VNC server in Raspberry Pi Configuration has no effect * Bug fix - fix %20 characters in file names diff --git a/export-noobs/prerun.sh b/export-noobs/prerun.sh index 54e0c59..c161ee6 100755 --- a/export-noobs/prerun.sh +++ b/export-noobs/prerun.sh @@ -16,8 +16,32 @@ BOOT_LENGTH=$(echo "$PARTED_OUT" | grep -e '^1:' | cut -d':' -f 4 | tr -d B) ROOT_OFFSET=$(echo "$PARTED_OUT" | grep -e '^2:' | cut -d':' -f 2 | tr -d B) ROOT_LENGTH=$(echo "$PARTED_OUT" | grep -e '^2:' | cut -d':' -f 4 | tr -d B) -BOOT_DEV=$(losetup --show -f -o "${BOOT_OFFSET}" --sizelimit "${BOOT_LENGTH}" "${IMG_FILE}") -ROOT_DEV=$(losetup --show -f -o "${ROOT_OFFSET}" --sizelimit "${ROOT_LENGTH}" "${IMG_FILE}") +echo "Mounting BOOT_DEV..." +cnt=0 +until BOOT_DEV=$(losetup --show -f -o "${BOOT_OFFSET}" --sizelimit "${BOOT_LENGTH}" "${IMG_FILE}"); do + if [ $cnt -lt 5 ]; then + cnt=$((cnt + 1)) + echo "Error in losetup for BOOT_DEV. Retrying..." + sleep 5 + else + echo "ERROR: losetup for BOOT_DEV failed; exiting" + exit 1 + fi +done + +echo "Mounting ROOT_DEV..." +cnt=0 +until ROOT_DEV=$(losetup --show -f -o "${ROOT_OFFSET}" --sizelimit "${ROOT_LENGTH}" "${IMG_FILE}"); do + if [ $cnt -lt 5 ]; then + cnt=$((cnt + 1)) + echo "Error in losetup for ROOT_DEV. Retrying..." + sleep 5 + else + echo "ERROR: losetup for ROOT_DEV failed; exiting" + exit 1 + fi +done + echo "/boot: offset $BOOT_OFFSET, length $BOOT_LENGTH" echo "/: offset $ROOT_OFFSET, length $ROOT_LENGTH" diff --git a/stage2/01-sys-tweaks/00-packages b/stage2/01-sys-tweaks/00-packages index 16b9350..83ec74c 100644 --- a/stage2/01-sys-tweaks/00-packages +++ b/stage2/01-sys-tweaks/00-packages @@ -28,3 +28,4 @@ vl805fw ntfs-3g pciutils rpi-eeprom +raspinfo diff --git a/stage2/01-sys-tweaks/01-run.sh b/stage2/01-sys-tweaks/01-run.sh index 5d83c17..d296a06 100755 --- a/stage2/01-sys-tweaks/01-run.sh +++ b/stage2/01-sys-tweaks/01-run.sh @@ -11,6 +11,18 @@ install -m 644 files/console-setup "${ROOTFS_DIR}/etc/default/" install -m 755 files/rc.local "${ROOTFS_DIR}/etc/" +if [ -n "${PUBKEY_SSH_FIRST_USER}" ]; then + install -v -m 0700 -o 1000 -g 1000 -d "${ROOTFS_DIR}"/home/"${FIRST_USER_NAME}"/.ssh + echo "${PUBKEY_SSH_FIRST_USER}" >"${ROOTFS_DIR}"/home/"${FIRST_USER_NAME}"/.ssh/authorized_keys + chown 1000:1000 "${ROOTFS_DIR}"/home/"${FIRST_USER_NAME}"/.ssh/authorized_keys + chmod 0600 "${ROOTFS_DIR}"/home/"${FIRST_USER_NAME}"/.ssh/authorized_keys +fi + +if [ "${PUBKEY_ONLY_SSH}" = "1" ]; then + sed -i -Ee 's/^#?[[:blank:]]*PubkeyAuthentication[[:blank:]]*no[[:blank:]]*$/PubkeyAuthentication yes/ +s/^#?[[:blank:]]*PasswordAuthentication[[:blank:]]*yes[[:blank:]]*$/PasswordAuthentication no/' "${ROOTFS_DIR}"/etc/ssh/sshd_config +fi + on_chroot << EOF systemctl disable hwclock.sh systemctl disable nfs-common diff --git a/stage2/02-net-tweaks/01-run.sh b/stage2/02-net-tweaks/01-run.sh index 0929755..d82381b 100755 --- a/stage2/02-net-tweaks/01-run.sh +++ b/stage2/02-net-tweaks/01-run.sh @@ -25,7 +25,12 @@ network={ EOL fi -# Disable wifi on 5GHz models +# Disable wifi on 5GHz models if WPA_COUNTRY is not set mkdir -p "${ROOTFS_DIR}/var/lib/systemd/rfkill/" -echo 1 > "${ROOTFS_DIR}/var/lib/systemd/rfkill/platform-3f300000.mmcnr:wlan" -echo 1 > "${ROOTFS_DIR}/var/lib/systemd/rfkill/platform-fe300000.mmcnr:wlan" +if [ -n "$WPA_COUNTRY" ]; then + echo 0 > "${ROOTFS_DIR}/var/lib/systemd/rfkill/platform-3f300000.mmcnr:wlan" + echo 0 > "${ROOTFS_DIR}/var/lib/systemd/rfkill/platform-fe300000.mmcnr:wlan" +else + echo 1 > "${ROOTFS_DIR}/var/lib/systemd/rfkill/platform-3f300000.mmcnr:wlan" + echo 1 > "${ROOTFS_DIR}/var/lib/systemd/rfkill/platform-fe300000.mmcnr:wlan" +fi diff --git a/stage4/03-bookshelf/00-run.sh b/stage4/03-bookshelf/00-run.sh new file mode 100755 index 0000000..5bd9885 --- /dev/null +++ b/stage4/03-bookshelf/00-run.sh @@ -0,0 +1,15 @@ +#!/bin/sh -e + +BOOKSHELF_URL="https://magpi.raspberrypi.org/bookshelf.xml" +GUIDE_URL="$(curl -s "$BOOKSHELF_URL" | awk -F '[<>]' "/Raspberry Pi Beginner's Guide v3<\/TITLE>/ {f=1; next} f==1 && /PDF/ {print \$3; exit}")" +OUTPUT="$(basename "$GUIDE_URL" | cut -f1 -d'?')" + +if [ ! -f "files/$OUTPUT" ]; then + rm files/*.pdf -f + curl -s "$GUIDE_URL" -o "files/$OUTPUT" +fi + +file "files/$OUTPUT" | grep -q "PDF document" + +install -v -o 1000 -g 1000 -d "${ROOTFS_DIR}/home/${FIRST_USER_NAME}/Bookshelf" +install -v -o 1000 -g 1000 -m 644 "files/$OUTPUT" "${ROOTFS_DIR}/home/${FIRST_USER_NAME}/Bookshelf/" diff --git a/stage4/03-bookshelf/files/.gitignore b/stage4/03-bookshelf/files/.gitignore new file mode 100644 index 0000000..a136337 --- /dev/null +++ b/stage4/03-bookshelf/files/.gitignore @@ -0,0 +1 @@ +*.pdf diff --git a/stage4/05-print-support/00-packages b/stage4/05-print-support/00-packages new file mode 100644 index 0000000..e9c36bd --- /dev/null +++ b/stage4/05-print-support/00-packages @@ -0,0 +1,2 @@ +cups +system-config-printer diff --git a/stage4/05-print-support/01-run.sh b/stage4/05-print-support/01-run.sh new file mode 100755 index 0000000..dc9e2b2 --- /dev/null +++ b/stage4/05-print-support/01-run.sh @@ -0,0 +1,5 @@ +#!/bin/bash -e + +on_chroot <<EOF +adduser "$FIRST_USER_NAME" lpadmin +EOF