@@ -1,4 +1,4 @@ | |||||
ARG BASE_IMAGE=debian:buster | |||||
ARG BASE_IMAGE=debian:bullseye | |||||
FROM ${BASE_IMAGE} | FROM ${BASE_IMAGE} | ||||
ENV DEBIAN_FRONTEND noninteractive | ENV DEBIAN_FRONTEND noninteractive | ||||
@@ -8,7 +8,7 @@ RUN apt-get -y update && \ | |||||
git vim parted \ | git vim parted \ | ||||
quilt coreutils qemu-user-static debootstrap zerofree zip dosfstools \ | quilt coreutils qemu-user-static debootstrap zerofree zip dosfstools \ | ||||
libarchive-tools libcap2-bin rsync grep udev xz-utils curl xxd file kmod bc\ | libarchive-tools libcap2-bin rsync grep udev xz-utils curl xxd file kmod bc\ | ||||
binfmt-support ca-certificates qemu-utils kpartx util-linux fdisk \ | |||||
binfmt-support ca-certificates qemu-utils kpartx fdisk gpg pigz\ | |||||
&& rm -rf /var/lib/apt/lists/* | && rm -rf /var/lib/apt/lists/* | ||||
COPY . /pi-gen/ | COPY . /pi-gen/ | ||||
@@ -4,10 +4,15 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" | |||||
BUILD_OPTS="$*" | BUILD_OPTS="$*" | ||||
DOCKER="docker" | |||||
if ! ${DOCKER} ps >/dev/null 2>&1; then | |||||
DOCKER="sudo docker" | |||||
# Allow user to override docker command | |||||
DOCKER=${DOCKER:-docker} | |||||
# Ensure that default docker command is not set up in rootless mode | |||||
if \ | |||||
! ${DOCKER} ps >/dev/null 2>&1 || \ | |||||
${DOCKER} info 2>/dev/null | grep -q rootless \ | |||||
; then | |||||
DOCKER="sudo ${DOCKER}" | |||||
fi | fi | ||||
if ! ${DOCKER} ps >/dev/null; then | if ! ${DOCKER} ps >/dev/null; then | ||||
echo "error connecting to docker:" | echo "error connecting to docker:" | ||||
@@ -48,7 +53,7 @@ fi | |||||
CONTAINER_NAME=${CONTAINER_NAME:-pigen_work} | CONTAINER_NAME=${CONTAINER_NAME:-pigen_work} | ||||
CONTINUE=${CONTINUE:-0} | CONTINUE=${CONTINUE:-0} | ||||
PRESERVE_CONTAINER=${PRESERVE_CONTAINER:-0} | PRESERVE_CONTAINER=${PRESERVE_CONTAINER:-0} | ||||
PIGEN_DOCKER_OPTS=${PIGEN_DOCKER_OPTS:-""} | |||||
PIGEN_DOCKER_OPTS=${PIGEN_DOCKER_OPTS:-""} | |||||
if [ -z "${IMG_NAME}" ]; then | if [ -z "${IMG_NAME}" ]; then | ||||
echo "IMG_NAME not set in 'config'" 1>&2 | echo "IMG_NAME not set in 'config'" 1>&2 | ||||
@@ -75,42 +80,87 @@ fi | |||||
# Modify original build-options to allow config file to be mounted in the docker container | # 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@')" | BUILD_OPTS="$(echo "${BUILD_OPTS:-}" | sed -E 's@\-c\s?([^ ]+)@-c /config@')" | ||||
BASE_IMAGE=debian:buster | |||||
${DOCKER} build --build-arg BASE_IMAGE=${BASE_IMAGE} -t pi-gen "${DIR}" | |||||
${DOCKER} build --build-arg BASE_IMAGE=debian:bullseye -t pi-gen "${DIR}" | |||||
if [ "${CONTAINER_EXISTS}" != "" ]; then | 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 \ | |||||
--cap-add=ALL \ | |||||
-v /dev:/dev \ | |||||
-v /lib/modules:/lib/modules \ | |||||
${PIGEN_DOCKER_OPTS} \ | |||||
--volume "${CONFIG_FILE}":/config:ro \ | |||||
-e "GIT_HASH=${GIT_HASH}" \ | |||||
--volumes-from="${CONTAINER_NAME}" --name "${CONTAINER_NAME}_cont" \ | |||||
pi-gen \ | |||||
bash -e -o pipefail -c "dpkg-reconfigure qemu-user-static && | |||||
cd /pi-gen; ./build.sh ${BUILD_OPTS} && | |||||
rsync -av work/*/build.log deploy/" & | |||||
wait "$!" | |||||
DOCKER_CMDLINE_NAME="${CONTAINER_NAME}_cont" | |||||
DOCKER_CMDLINE_PRE=( \ | |||||
--rm \ | |||||
) | |||||
DOCKER_CMDLINE_POST=( \ | |||||
--volumes-from="${CONTAINER_NAME}" \ | |||||
) | |||||
else | else | ||||
trap 'echo "got CTRL+C... please wait 5s" && ${DOCKER} stop -t 5 ${CONTAINER_NAME}' SIGINT SIGTERM | |||||
time ${DOCKER} run --name "${CONTAINER_NAME}" --privileged \ | |||||
--cap-add=ALL \ | |||||
-v /dev:/dev \ | |||||
-v /lib/modules:/lib/modules \ | |||||
${PIGEN_DOCKER_OPTS} \ | |||||
--volume "${CONFIG_FILE}":/config:ro \ | |||||
-e "GIT_HASH=${GIT_HASH}" \ | |||||
pi-gen \ | |||||
bash -e -o pipefail -c "dpkg-reconfigure qemu-user-static && | |||||
cd /pi-gen; ./build.sh ${BUILD_OPTS} && | |||||
rsync -av work/*/build.log deploy/" & | |||||
wait "$!" | |||||
DOCKER_CMDLINE_NAME="${CONTAINER_NAME}" | |||||
DOCKER_CMDLINE_PRE=( \ | |||||
) | |||||
DOCKER_CMDLINE_POST=( \ | |||||
) | |||||
fi | |||||
# Check if binfmt_misc is required | |||||
binfmt_misc_required=1 | |||||
case $(uname -m) in | |||||
aarch64) | |||||
binfmt_misc_required=0 | |||||
;; | |||||
arm*) | |||||
binfmt_misc_required=0 | |||||
;; | |||||
esac | |||||
# Check if qemu-aarch64-static and /proc/sys/fs/binfmt_misc are present | |||||
if [[ "${binfmt_misc_required}" == "1" ]]; then | |||||
if ! qemu_arm=$(which qemu-aarch64-static) ; then | |||||
echo "qemu-aarch64-static not found (please install qemu-user-static)" | |||||
exit 1 | |||||
fi | |||||
if [ ! -f /proc/sys/fs/binfmt_misc/register ]; then | |||||
echo "binfmt_misc required but not mounted, trying to mount it..." | |||||
if ! mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc ; then | |||||
echo "mounting binfmt_misc failed" | |||||
exit 1 | |||||
fi | |||||
echo "binfmt_misc mounted" | |||||
fi | |||||
if ! grep -q "^interpreter ${qemu_arm}" /proc/sys/fs/binfmt_misc/qemu-aarch64* ; then | |||||
# Register qemu-aarch64 for binfmt_misc | |||||
reg="echo ':qemu-aarch64-rpi:M::"\ | |||||
"\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:"\ | |||||
"\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:"\ | |||||
"${qemu_arm}:F' > /proc/sys/fs/binfmt_misc/register" | |||||
echo "Registering qemu-aarch64 for binfmt_misc..." | |||||
sudo bash -c "${reg}" 2>/dev/null || true | |||||
fi | |||||
fi | fi | ||||
trap 'echo "got CTRL+C... please wait 5s" && ${DOCKER} stop -t 5 ${DOCKER_CMDLINE_NAME}' SIGINT SIGTERM | |||||
time ${DOCKER} run \ | |||||
--name "${DOCKER_CMDLINE_NAME}" \ | |||||
--privileged \ | |||||
--cap-add=ALL \ | |||||
-v /dev:/dev \ | |||||
-v /lib/modules:/lib/modules \ | |||||
${PIGEN_DOCKER_OPTS} \ | |||||
--volume "${CONFIG_FILE}":/config:ro \ | |||||
-e "GIT_HASH=${GIT_HASH}" \ | |||||
pi-gen \ | |||||
bash -e -o pipefail -c " | |||||
dpkg-reconfigure qemu-user-static && | |||||
# binfmt_misc is sometimes not mounted with debian bullseye image | |||||
(mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc || true) && | |||||
cd /pi-gen; ./build.sh ${BUILD_OPTS} && | |||||
rsync -av work/*/build.log deploy/ | |||||
" & | |||||
wait "$!" | |||||
# Ensure that deploy/ is always owned by calling user | |||||
echo "copying results from deploy/" | echo "copying results from deploy/" | ||||
${DOCKER} cp "${CONTAINER_NAME}":/pi-gen/deploy . | |||||
${DOCKER} cp "${CONTAINER_NAME}":/pi-gen/deploy - | tar -xf - | |||||
echo "copying log from container ${CONTAINER_NAME} to depoy/" | |||||
${DOCKER} logs --timestamps "${CONTAINER_NAME}" &>deploy/build-docker.log | |||||
ls -lah deploy | ls -lah deploy | ||||
# cleanup | # cleanup | ||||
@@ -14,20 +14,14 @@ $(cat "${i}-debconf") | |||||
SELEOF | SELEOF | ||||
EOF | EOF | ||||
log "End ${SUB_STAGE_DIR}/${i}-debconf" | |||||
log "End ${SUB_STAGE_DIR}/${i}-debconf" | |||||
fi | fi | ||||
if [ -f "${i}-packages-nr" ]; then | if [ -f "${i}-packages-nr" ]; then | ||||
log "Begin ${SUB_STAGE_DIR}/${i}-packages-nr" | log "Begin ${SUB_STAGE_DIR}/${i}-packages-nr" | ||||
PACKAGES="$(sed -f "${SCRIPT_DIR}/remove-comments.sed" < "${i}-packages-nr")" | PACKAGES="$(sed -f "${SCRIPT_DIR}/remove-comments.sed" < "${i}-packages-nr")" | ||||
if [ -n "$PACKAGES" ]; then | if [ -n "$PACKAGES" ]; then | ||||
on_chroot << EOF | on_chroot << EOF | ||||
n=0 | |||||
until [ "$n" -ge 5 ] | |||||
do | |||||
apt-get --ignore-missing --fix-missing install --no-install-recommends -y $PACKAGES && break | |||||
n=$((n+1)) | |||||
sleep 15 | |||||
done | |||||
apt-get -o Acquire::Retries=3 install --no-install-recommends -y $PACKAGES | |||||
EOF | EOF | ||||
if [ "${USE_QCOW2}" = "1" ]; then | if [ "${USE_QCOW2}" = "1" ]; then | ||||
on_chroot << EOF | on_chroot << EOF | ||||
@@ -42,13 +36,7 @@ EOF | |||||
PACKAGES="$(sed -f "${SCRIPT_DIR}/remove-comments.sed" < "${i}-packages")" | PACKAGES="$(sed -f "${SCRIPT_DIR}/remove-comments.sed" < "${i}-packages")" | ||||
if [ -n "$PACKAGES" ]; then | if [ -n "$PACKAGES" ]; then | ||||
on_chroot << EOF | on_chroot << EOF | ||||
n=0 | |||||
until [ "$n" -ge 5 ] | |||||
do | |||||
apt-get --ignore-missing --fix-missing install -y $PACKAGES && break | |||||
n=$((n+1)) | |||||
sleep 15 | |||||
done | |||||
apt-get -o Acquire::Retries=3 install -y $PACKAGES | |||||
EOF | EOF | ||||
if [ "${USE_QCOW2}" = "1" ]; then | if [ "${USE_QCOW2}" = "1" ]; then | ||||
on_chroot << EOF | on_chroot << EOF | ||||
@@ -145,7 +133,7 @@ run_stage(){ | |||||
done | done | ||||
fi | fi | ||||
if [ "${USE_QCOW2}" = "1" ]; then | |||||
if [ "${USE_QCOW2}" = "1" ]; then | |||||
unload_qimage | unload_qimage | ||||
else | else | ||||
# make sure we are not umounting during export-image stage | # make sure we are not umounting during export-image stage | ||||
@@ -167,6 +155,14 @@ if [ "$(id -u)" != "0" ]; then | |||||
fi | fi | ||||
BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||||
if [[ $BASE_DIR = *" "* ]]; then | |||||
echo "There is a space in the base path of pi-gen" | |||||
echo "This is not a valid setup supported by debootstrap." | |||||
echo "Please remove the spaces, or move pi-gen directory to a base path without spaces" 1>&2 | |||||
exit 1 | |||||
fi | |||||
export BASE_DIR | export BASE_DIR | ||||
if [ -f config ]; then | if [ -f config ]; then | ||||
@@ -207,19 +203,30 @@ fi | |||||
export USE_QEMU="${USE_QEMU:-0}" | export USE_QEMU="${USE_QEMU:-0}" | ||||
export IMG_DATE="${IMG_DATE:-"$(date +%Y-%m-%d)"}" | export IMG_DATE="${IMG_DATE:-"$(date +%Y-%m-%d)"}" | ||||
export IMG_FILENAME="${IMG_FILENAME:-"${IMG_DATE}-${IMG_NAME}"}" | export IMG_FILENAME="${IMG_FILENAME:-"${IMG_DATE}-${IMG_NAME}"}" | ||||
export ZIP_FILENAME="${ZIP_FILENAME:-"${IMG_DATE}-${IMG_NAME}"}" | |||||
export ARCHIVE_FILENAME="${ARCHIVE_FILENAME:-"image_${IMG_DATE}-${IMG_NAME}"}" | |||||
export SCRIPT_DIR="${BASE_DIR}/scripts" | export SCRIPT_DIR="${BASE_DIR}/scripts" | ||||
export WORK_DIR="${WORK_DIR:-"${BASE_DIR}/work/${IMG_DATE}-${IMG_NAME}"}" | |||||
export WORK_DIR="${WORK_DIR:-"${BASE_DIR}/work/${IMG_NAME}"}" | |||||
export DEPLOY_DIR=${DEPLOY_DIR:-"${BASE_DIR}/deploy"} | export DEPLOY_DIR=${DEPLOY_DIR:-"${BASE_DIR}/deploy"} | ||||
export DEPLOY_ZIP="${DEPLOY_ZIP:-1}" | |||||
# DEPLOY_ZIP was deprecated in favor of DEPLOY_COMPRESSION | |||||
# This preserve the old behavior with DEPLOY_ZIP=0 where no archive was created | |||||
if [ -z "${DEPLOY_COMPRESSION}" ] && [ "${DEPLOY_ZIP:-1}" = "0" ]; then | |||||
echo "DEPLOY_ZIP has been deprecated in favor of DEPLOY_COMPRESSION" | |||||
echo "Similar behavior to DEPLOY_ZIP=0 can be obtained with DEPLOY_COMPRESSION=none" | |||||
echo "Please update your config file" | |||||
DEPLOY_COMPRESSION=none | |||||
fi | |||||
export DEPLOY_COMPRESSION=${DEPLOY_COMPRESSION:-zip} | |||||
export COMPRESSION_LEVEL=${COMPRESSION_LEVEL:-6} | |||||
export LOG_FILE="${WORK_DIR}/build.log" | export LOG_FILE="${WORK_DIR}/build.log" | ||||
export TARGET_HOSTNAME=${TARGET_HOSTNAME:-raspberrypi} | export TARGET_HOSTNAME=${TARGET_HOSTNAME:-raspberrypi} | ||||
export FIRST_USER_NAME=${FIRST_USER_NAME:-pi} | export FIRST_USER_NAME=${FIRST_USER_NAME:-pi} | ||||
export FIRST_USER_PASS=${FIRST_USER_PASS:-raspberry} | |||||
export RELEASE=${RELEASE:-bullseye} | |||||
export FIRST_USER_PASS | |||||
export DISABLE_FIRST_BOOT_USER_RENAME=${DISABLE_FIRST_BOOT_USER_RENAME:-0} | |||||
export RELEASE=${RELEASE:-bullseye} # Don't forget to update stage0/prerun.sh | |||||
export WPA_ESSID | export WPA_ESSID | ||||
export WPA_PASSWORD | export WPA_PASSWORD | ||||
export WPA_COUNTRY | export WPA_COUNTRY | ||||
@@ -276,6 +283,10 @@ fi | |||||
export NO_PRERUN_QCOW2="${NO_PRERUN_QCOW2:-1}" | export NO_PRERUN_QCOW2="${NO_PRERUN_QCOW2:-1}" | ||||
if [ "$SETFCAP" != "1" ]; then | |||||
export CAPSH_ARG="--drop=cap_setfcap" | |||||
fi | |||||
dependencies_check "${BASE_DIR}/depends" | dependencies_check "${BASE_DIR}/depends" | ||||
#check username is valid | #check username is valid | ||||
@@ -284,6 +295,17 @@ if [[ ! "$FIRST_USER_NAME" =~ ^[a-z][-a-z0-9_]*$ ]]; then | |||||
exit 1 | exit 1 | ||||
fi | fi | ||||
if [[ "$DISABLE_FIRST_BOOT_USER_RENAME" == "1" ]] && [ -z "${FIRST_USER_PASS}" ]; then | |||||
echo "To disable user rename on first boot, FIRST_USER_PASS needs to be set" | |||||
echo "Not setting FIRST_USER_PASS makes your system vulnerable and open to cyberattacks" | |||||
exit 1 | |||||
fi | |||||
if [[ "$DISABLE_FIRST_BOOT_USER_RENAME" == "1" ]]; then | |||||
echo "User rename on the first boot is disabled" | |||||
echo "Be advised of the security risks linked to shipping a device with default username/password set." | |||||
fi | |||||
if [[ -n "${APT_PROXY}" ]] && ! curl --silent "${APT_PROXY}" >/dev/null ; then | if [[ -n "${APT_PROXY}" ]] && ! curl --silent "${APT_PROXY}" >/dev/null ; then | ||||
echo "Could not reach APT_PROXY server: ${APT_PROXY}" | echo "Could not reach APT_PROXY server: ${APT_PROXY}" | ||||
exit 1 | exit 1 | ||||
@@ -381,7 +403,7 @@ for EXPORT_DIR in ${EXPORT_DIRS}; do | |||||
else | else | ||||
run_stage | run_stage | ||||
fi | |||||
fi | |||||
if [ "${USE_QEMU}" != "1" ]; then | if [ "${USE_QEMU}" != "1" ]; then | ||||
if [ -e "${EXPORT_DIR}/EXPORT_NOOBS" ]; then | if [ -e "${EXPORT_DIR}/EXPORT_NOOBS" ]; then | ||||
# shellcheck source=/dev/null | # shellcheck source=/dev/null | ||||
@@ -2,3 +2,5 @@ IMG_NAME='PiSDR' | |||||
ENABLE_SSH=1 | ENABLE_SSH=1 | ||||
TARGET_HOSTNAME='pisdr' | TARGET_HOSTNAME='pisdr' | ||||
FIRST_USER_PASS='raspberry' | FIRST_USER_PASS='raspberry' | ||||
DEPLOY_COMPRESSION='xz' | |||||
COMPRESSION_LEVEL=9 |
@@ -19,3 +19,5 @@ lsmod:kmod | |||||
bc | bc | ||||
qemu-nbd:qemu-utils | qemu-nbd:qemu-utils | ||||
kpartx | kpartx | ||||
gpg | |||||
pigz |
@@ -0,0 +1 @@ | |||||
userconf-pi |
@@ -0,0 +1,9 @@ | |||||
#!/bin/bash -e | |||||
if [[ "${DISABLE_FIRST_BOOT_USER_RENAME}" == "0" ]]; then | |||||
on_chroot <<- EOF | |||||
SUDO_USER="${FIRST_USER_NAME}" rename-user -f -s | |||||
EOF | |||||
else | |||||
rm -f "${ROOTFS_DIR}/etc/xdg/autostart/piwiz.desktop" | |||||
fi |
@@ -18,6 +18,12 @@ fi | |||||
rm -f "${ROOTFS_DIR}/usr/bin/qemu-arm-static" | rm -f "${ROOTFS_DIR}/usr/bin/qemu-arm-static" | ||||
if [ "${USE_QEMU}" != "1" ]; then | |||||
if [ -e "${ROOTFS_DIR}/etc/ld.so.preload.disabled" ]; then | |||||
mv "${ROOTFS_DIR}/etc/ld.so.preload.disabled" "${ROOTFS_DIR}/etc/ld.so.preload" | |||||
fi | |||||
fi | |||||
rm -f "${ROOTFS_DIR}/etc/network/interfaces.dpkg-old" | rm -f "${ROOTFS_DIR}/etc/network/interfaces.dpkg-old" | ||||
rm -f "${ROOTFS_DIR}/etc/apt/sources.list~" | rm -f "${ROOTFS_DIR}/etc/apt/sources.list~" | ||||
@@ -72,9 +78,8 @@ cp "$ROOTFS_DIR/etc/rpi-issue" "$INFO_FILE" | |||||
mkdir -p "${DEPLOY_DIR}" | mkdir -p "${DEPLOY_DIR}" | ||||
rm -f "${DEPLOY_DIR}/${ZIP_FILENAME}${IMG_SUFFIX}.zip" | |||||
rm -f "${DEPLOY_DIR}/${ARCHIVE_FILENAME}${IMG_SUFFIX}.*" | |||||
rm -f "${DEPLOY_DIR}/${IMG_FILENAME}${IMG_SUFFIX}.img" | rm -f "${DEPLOY_DIR}/${IMG_FILENAME}${IMG_SUFFIX}.img" | ||||
rm -f "${DEPLOY_DIR}/${ZIP_FILENAME}${IMG_SUFFIX}.img.xz" | |||||
mv "$INFO_FILE" "$DEPLOY_DIR/" | mv "$INFO_FILE" "$DEPLOY_DIR/" | ||||
@@ -90,11 +95,22 @@ else | |||||
make_bootable_image "${STAGE_WORK_DIR}/${IMG_FILENAME}${IMG_SUFFIX}.qcow2" "$IMG_FILE" | make_bootable_image "${STAGE_WORK_DIR}/${IMG_FILENAME}${IMG_SUFFIX}.qcow2" "$IMG_FILE" | ||||
fi | fi | ||||
if [ "${DEPLOY_ZIP}" == "1" ]; then | |||||
case "${DEPLOY_COMPRESSION}" in | |||||
zip) | |||||
pushd "${STAGE_WORK_DIR}" > /dev/null | pushd "${STAGE_WORK_DIR}" > /dev/null | ||||
xz -T16 -c "$(basename "${IMG_FILE}")" > "${DEPLOY_DIR}/${ZIP_FILENAME}${IMG_SUFFIX}.img.xz" | |||||
zip -"${COMPRESSION_LEVEL}" \ | |||||
"${DEPLOY_DIR}/${ARCHIVE_FILENAME}${IMG_SUFFIX}.zip" "$(basename "${IMG_FILE}")" | |||||
popd > /dev/null | popd > /dev/null | ||||
rm -f "${DEPLOY_DIR}/${IMG_FILENAME}${IMG_SUFFIX}.img" | |||||
else | |||||
mv "$IMG_FILE" "$DEPLOY_DIR/" | |||||
fi | |||||
;; | |||||
gz) | |||||
pigz --force -"${COMPRESSION_LEVEL}" "$IMG_FILE" --stdout > \ | |||||
"${DEPLOY_DIR}/${ARCHIVE_FILENAME}${IMG_SUFFIX}.img.gz" | |||||
;; | |||||
xz) | |||||
xz --compress --force --threads 0 --memlimit-compress=50% -"${COMPRESSION_LEVEL}" \ | |||||
--stdout "$IMG_FILE" > "${DEPLOY_DIR}/${ARCHIVE_FILENAME}${IMG_SUFFIX}.img.xz" | |||||
;; | |||||
none | *) | |||||
cp "$IMG_FILE" "$DEPLOY_DIR/" | |||||
;; | |||||
esac |
@@ -33,49 +33,29 @@ if [ "${NO_PRERUN_QCOW2}" = "0" ]; then | |||||
parted --script "${IMG_FILE}" unit B mkpart primary fat32 "${BOOT_PART_START}" "$((BOOT_PART_START + BOOT_PART_SIZE - 1))" | parted --script "${IMG_FILE}" unit B mkpart primary fat32 "${BOOT_PART_START}" "$((BOOT_PART_START + BOOT_PART_SIZE - 1))" | ||||
parted --script "${IMG_FILE}" unit B mkpart primary ext4 "${ROOT_PART_START}" "$((ROOT_PART_START + ROOT_PART_SIZE - 1))" | parted --script "${IMG_FILE}" unit B mkpart primary ext4 "${ROOT_PART_START}" "$((ROOT_PART_START + ROOT_PART_SIZE - 1))" | ||||
PARTED_OUT=$(parted -sm "${IMG_FILE}" unit b print) | |||||
BOOT_OFFSET=$(echo "$PARTED_OUT" | grep -e '^1:' | cut -d':' -f 2 | tr -d B) | |||||
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) | |||||
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..." | |||||
echo "Creating loop device..." | |||||
cnt=0 | cnt=0 | ||||
until ROOT_DEV=$(losetup --show -f -o "${ROOT_OFFSET}" --sizelimit "${ROOT_LENGTH}" "${IMG_FILE}"); do | |||||
until ensure_next_loopdev && LOOP_DEV="$(losetup --show --find --partscan "$IMG_FILE")"; do | |||||
if [ $cnt -lt 5 ]; then | if [ $cnt -lt 5 ]; then | ||||
cnt=$((cnt + 1)) | cnt=$((cnt + 1)) | ||||
echo "Error in losetup for ROOT_DEV. Retrying..." | |||||
echo "Error in losetup. Retrying..." | |||||
sleep 5 | sleep 5 | ||||
else | else | ||||
echo "ERROR: losetup for ROOT_DEV failed; exiting" | |||||
echo "ERROR: losetup failed; exiting" | |||||
exit 1 | exit 1 | ||||
fi | fi | ||||
done | done | ||||
echo "/boot: offset $BOOT_OFFSET, length $BOOT_LENGTH" | |||||
echo "/: offset $ROOT_OFFSET, length $ROOT_LENGTH" | |||||
BOOT_DEV="${LOOP_DEV}p1" | |||||
ROOT_DEV="${LOOP_DEV}p2" | |||||
ROOT_FEATURES="^huge_file" | ROOT_FEATURES="^huge_file" | ||||
for FEATURE in metadata_csum 64bit; do | |||||
for FEATURE in 64bit; do | |||||
if grep -q "$FEATURE" /etc/mke2fs.conf; then | if grep -q "$FEATURE" /etc/mke2fs.conf; then | ||||
ROOT_FEATURES="^$FEATURE,$ROOT_FEATURES" | ROOT_FEATURES="^$FEATURE,$ROOT_FEATURES" | ||||
fi | fi | ||||
done | done | ||||
mkdosfs -n boot -F 32 -v "$BOOT_DEV" > /dev/null | |||||
mkdosfs -n bootfs -F 32 -s 4 -v "$BOOT_DEV" > /dev/null | |||||
mkfs.ext4 -L rootfs -O "$ROOT_FEATURES" "$ROOT_DEV" > /dev/null | mkfs.ext4 -L rootfs -O "$ROOT_FEATURES" "$ROOT_DEV" > /dev/null | ||||
mount -v "$ROOT_DEV" "${ROOTFS_DIR}" -t ext4 | mount -v "$ROOT_DEV" "${ROOTFS_DIR}" -t ext4 | ||||
@@ -7,21 +7,18 @@ bootstrap(){ | |||||
local BOOTSTRAP_CMD=debootstrap | local BOOTSTRAP_CMD=debootstrap | ||||
local BOOTSTRAP_ARGS=() | local BOOTSTRAP_ARGS=() | ||||
#export http_proxy=${APT_PROXY} | |||||
if [ "$(dpkg --print-architecture)" != "armhf" ] && [ "$(dpkg --print-architecture)" != "aarch64" ]; then | |||||
BOOTSTRAP_CMD=qemu-debootstrap | |||||
fi | |||||
export http_proxy=${APT_PROXY} | |||||
BOOTSTRAP_ARGS+=(--arch arm64) | BOOTSTRAP_ARGS+=(--arch arm64) | ||||
BOOTSTRAP_ARGS+=(--include gnupg) | BOOTSTRAP_ARGS+=(--include gnupg) | ||||
BOOTSTRAP_ARGS+=(--components "main,contrib,non-free") | BOOTSTRAP_ARGS+=(--components "main,contrib,non-free") | ||||
#BOOTSTRAP_ARGS+=(--keyring "${STAGE_DIR}/files/raspberrypi.gpg") | #BOOTSTRAP_ARGS+=(--keyring "${STAGE_DIR}/files/raspberrypi.gpg") | ||||
BOOTSTRAP_ARGS+=(--exclude=info) | BOOTSTRAP_ARGS+=(--exclude=info) | ||||
BOOTSTRAP_ARGS+=(--include=ca-certificates) | |||||
BOOTSTRAP_ARGS+=("$@") | BOOTSTRAP_ARGS+=("$@") | ||||
printf -v BOOTSTRAP_STR '%q ' "${BOOTSTRAP_ARGS[@]}" | printf -v BOOTSTRAP_STR '%q ' "${BOOTSTRAP_ARGS[@]}" | ||||
capsh --drop=cap_setfcap -- -c "'${BOOTSTRAP_CMD}' $BOOTSTRAP_STR" || true | |||||
capsh $CAPSH_ARG -- -c "'${BOOTSTRAP_CMD}' $BOOTSTRAP_STR" || true | |||||
if [ -d "$2/debootstrap" ] && ! rmdir "$2/debootstrap"; then | if [ -d "$2/debootstrap" ] && ! rmdir "$2/debootstrap"; then | ||||
cp "$2/debootstrap/debootstrap.log" "${STAGE_WORK_DIR}" | cp "$2/debootstrap/debootstrap.log" "${STAGE_WORK_DIR}" | ||||
@@ -61,19 +58,15 @@ export -f unmount | |||||
unmount_image(){ | unmount_image(){ | ||||
sync | sync | ||||
sleep 1 | sleep 1 | ||||
local LOOP_DEVICES | |||||
LOOP_DEVICES=$(losetup --list | grep "$(basename "${1}")" | cut -f1 -d' ') | |||||
for LOOP_DEV in ${LOOP_DEVICES}; do | |||||
if [ -n "${LOOP_DEV}" ]; then | |||||
local MOUNTED_DIR | |||||
MOUNTED_DIR=$(mount | grep "$(basename "${LOOP_DEV}")" | head -n 1 | cut -f 3 -d ' ') | |||||
if [ -n "${MOUNTED_DIR}" ] && [ "${MOUNTED_DIR}" != "/" ]; then | |||||
unmount "$(dirname "${MOUNTED_DIR}")" | |||||
LOOP_DEVICE=$(losetup --list | grep "$1" | cut -f1 -d' ') | |||||
if [ -n "$LOOP_DEVICE" ]; then | |||||
for part in "$LOOP_DEVICE"p*; do | |||||
if DIR=$(findmnt -n -o target -S "$part"); then | |||||
unmount "$DIR" | |||||
fi | fi | ||||
sleep 1 | |||||
losetup -d "${LOOP_DEV}" | |||||
fi | |||||
done | |||||
done | |||||
losetup -d "$LOOP_DEVICE" | |||||
fi | |||||
} | } | ||||
export -f unmount_image | export -f unmount_image | ||||
@@ -94,7 +87,15 @@ on_chroot() { | |||||
mount --bind /sys "${ROOTFS_DIR}/sys" | mount --bind /sys "${ROOTFS_DIR}/sys" | ||||
fi | fi | ||||
capsh --drop=cap_setfcap "--chroot=${ROOTFS_DIR}/" -- -e "$@" | |||||
if ! mount | grep -q "$(realpath "${ROOTFS_DIR}"/run)"; then | |||||
mount -t tmpfs tmpfs "${ROOTFS_DIR}/run" | |||||
fi | |||||
if ! mount | grep -q "$(realpath "${ROOTFS_DIR}"/tmp)"; then | |||||
mount -t tmpfs tmpfs "${ROOTFS_DIR}/tmp" | |||||
fi | |||||
capsh $CAPSH_ARG "--chroot=${ROOTFS_DIR}/" -- -e "$@" | |||||
} | } | ||||
export -f on_chroot | export -f on_chroot | ||||
@@ -102,3 +103,11 @@ update_issue() { | |||||
echo -e "Raspberry Pi reference ${IMG_DATE}\nGenerated using ${PI_GEN}, ${PI_GEN_REPO}, ${GIT_HASH}, ${1}" > "${ROOTFS_DIR}/etc/rpi-issue" | echo -e "Raspberry Pi reference ${IMG_DATE}\nGenerated using ${PI_GEN}, ${PI_GEN_REPO}, ${GIT_HASH}, ${1}" > "${ROOTFS_DIR}/etc/rpi-issue" | ||||
} | } | ||||
export -f update_issue | export -f update_issue | ||||
ensure_next_loopdev() { | |||||
local loopdev | |||||
loopdev="$(losetup -f)" | |||||
loopmaj="$(echo "$loopdev" | sed -E 's/.*[^0-9]*?([0-9]+)$/\1/')" | |||||
[[ -b "$loopdev" ]] || mknod "$loopdev" b 7 "$loopmaj" | |||||
} | |||||
export -f ensure_next_loopdev |
@@ -109,8 +109,8 @@ load_qimage() { | |||||
EOF | EOF | ||||
sync | sync | ||||
kpartx -as $NBD_DEV | kpartx -as $NBD_DEV | ||||
mkdosfs -n boot -F 32 -v $MAP_BOOT_DEV | |||||
mkfs.ext4 -L rootfs -O "^huge_file,^metadata_csum,^64bit" $MAP_ROOT_DEV | |||||
mkdosfs -n boot -F 32 -s 4 -v $MAP_BOOT_DEV | |||||
mkfs.ext4 -L rootfs -O "^huge_file,^64bit" $MAP_ROOT_DEV | |||||
sync | sync | ||||
else | else | ||||
if [ ! -f "${WORK_DIR}/image-${PREV_STAGE}.qcow2" ]; then | if [ ! -f "${WORK_DIR}/image-${PREV_STAGE}.qcow2" ]; then | ||||
@@ -12,7 +12,8 @@ else | |||||
rm -f "${ROOTFS_DIR}/etc/apt/apt.conf.d/51cache" | rm -f "${ROOTFS_DIR}/etc/apt/apt.conf.d/51cache" | ||||
fi | fi | ||||
on_chroot apt-key add - < files/raspberrypi.gpg.key | |||||
cat files/raspberrypi.gpg.key | gpg --dearmor > "${STAGE_WORK_DIR}/raspberrypi-archive-stable.gpg" | |||||
install -m 644 "${STAGE_WORK_DIR}/raspberrypi-archive-stable.gpg" "${ROOTFS_DIR}/etc/apt/trusted.gpg.d/" | |||||
on_chroot << EOF | on_chroot << EOF | ||||
dpkg --add-architecture armhf | dpkg --add-architecture armhf | ||||
apt-get update | apt-get update | ||||
@@ -0,0 +1 @@ | |||||
raspberrypi-archive-keyring |
@@ -1,3 +1,2 @@ | |||||
raspberrypi-bootloader | raspberrypi-bootloader | ||||
raspberrypi-kernel | raspberrypi-kernel | ||||
raspi-config |
@@ -1,5 +1,10 @@ | |||||
#!/bin/bash -e | #!/bin/bash -e | ||||
if [ "$RELEASE" != "bullseye" ]; then | |||||
echo "WARNING: RELEASE does not match the intended option for this branch." | |||||
echo " Please check the relevant README.md section." | |||||
fi | |||||
if [ ! -d "${ROOTFS_DIR}" ] || [ "${USE_QCOW2}" = "1" ]; then | if [ ! -d "${ROOTFS_DIR}" ] || [ "${USE_QCOW2}" = "1" ]; then | ||||
bootstrap ${RELEASE} "${ROOTFS_DIR}" http://deb.debian.org/debian/ | bootstrap ${RELEASE} "${ROOTFS_DIR}" http://deb.debian.org/debian/ | ||||
fi | fi |
@@ -0,0 +1 @@ | |||||
raspi-config |
@@ -8,7 +8,10 @@ on_chroot << EOF | |||||
if ! id -u ${FIRST_USER_NAME} >/dev/null 2>&1; then | if ! id -u ${FIRST_USER_NAME} >/dev/null 2>&1; then | ||||
adduser --disabled-password --gecos "" ${FIRST_USER_NAME} | adduser --disabled-password --gecos "" ${FIRST_USER_NAME} | ||||
fi | fi | ||||
echo "${FIRST_USER_NAME}:${FIRST_USER_PASS}" | chpasswd | |||||
if [ -n "${FIRST_USER_PASS}" ]; then | |||||
echo "${FIRST_USER_NAME}:${FIRST_USER_PASS}" | chpasswd | |||||
fi | |||||
echo "root:root" | chpasswd | echo "root:root" | chpasswd | ||||
EOF | EOF | ||||
@@ -1 +1,2 @@ | |||||
libraspberrypi-bin libraspberrypi0 | libraspberrypi-bin libraspberrypi0 | ||||
systemd-timesyncd |
@@ -1 +0,0 @@ | |||||
raspi-copies-and-fills |
@@ -1,6 +0,0 @@ | |||||
#!/bin/bash -e | |||||
if [ -f "${ROOTFS_DIR}/etc/ld.so.preload" ]; then | |||||
mv "${ROOTFS_DIR}/etc/ld.so.preload" "${ROOTFS_DIR}/etc/ld.so.preload.disabled" | |||||
fi | |||||
@@ -1,5 +1,5 @@ | |||||
ssh less fbset sudo psmisc strace ed ncdu crda | ssh less fbset sudo psmisc strace ed ncdu crda | ||||
console-setup keyboard-configuration debconf-utils parted unzip | |||||
console-setup keyboard-configuration debconf-utils parted | |||||
build-essential manpages-dev bash-completion gdb pkg-config | build-essential manpages-dev bash-completion gdb pkg-config | ||||
python-is-python3 | python-is-python3 | ||||
python3-rpi.gpio v4l-utils | python3-rpi.gpio v4l-utils | ||||
@@ -30,3 +30,7 @@ ntfs-3g | |||||
pciutils | pciutils | ||||
rpi-eeprom | rpi-eeprom | ||||
raspinfo | raspinfo | ||||
udisks2 | |||||
unzip zip p7zip-full | |||||
file | |||||
kms++-utils |
@@ -2,4 +2,4 @@ | |||||
+++ stage2/rootfs/boot/cmdline.txt | +++ stage2/rootfs/boot/cmdline.txt | ||||
@@ -1 +1 @@ | @@ -1 +1 @@ | ||||
-console=serial0,115200 console=tty1 root=ROOTDEV rootfstype=ext4 fsck.repair=yes rootwait | -console=serial0,115200 console=tty1 root=ROOTDEV rootfstype=ext4 fsck.repair=yes rootwait | ||||
+console=serial0,115200 console=tty1 root=ROOTDEV rootfstype=ext4 fsck.repair=yes rootwait quiet init=/usr/lib/raspi-config/init_resize.sh | |||||
+console=serial0,115200 console=tty1 root=ROOTDEV rootfstype=ext4 fsck.repair=yes rootwait quiet init=/usr/lib/raspberrypi-sys-mods/firstboot |
@@ -24,8 +24,6 @@ s/^#?[[:blank:]]*PasswordAuthentication[[:blank:]]*yes[[:blank:]]*$/PasswordAuth | |||||
fi | fi | ||||
on_chroot << EOF | on_chroot << EOF | ||||
gcc -march=native -Q --help=target | |||||
echo "++++++++++++++++++++++++++++++++++++" | |||||
systemctl disable hwclock.sh | systemctl disable hwclock.sh | ||||
systemctl disable nfs-common | systemctl disable nfs-common | ||||
systemctl disable rpcbind | systemctl disable rpcbind | ||||
@@ -54,11 +52,15 @@ on_chroot <<EOF | |||||
for GRP in input spi i2c gpio; do | for GRP in input spi i2c gpio; do | ||||
groupadd -f -r "\$GRP" | groupadd -f -r "\$GRP" | ||||
done | done | ||||
for GRP in adm dialout cdrom audio users sudo video games plugdev input gpio spi i2c netdev; do | |||||
for GRP in adm dialout cdrom audio users sudo video games plugdev input gpio spi i2c netdev render; do | |||||
adduser $FIRST_USER_NAME \$GRP | adduser $FIRST_USER_NAME \$GRP | ||||
done | done | ||||
EOF | EOF | ||||
if [ -f "${ROOTFS_DIR}/etc/sudoers.d/010_pi-nopasswd" ]; then | |||||
sed -i "s/^pi /$FIRST_USER_NAME /" "${ROOTFS_DIR}/etc/sudoers.d/010_pi-nopasswd" | |||||
fi | |||||
on_chroot << EOF | on_chroot << EOF | ||||
setupcon --force --save-only -v | setupcon --force --save-only -v | ||||
EOF | EOF | ||||
@@ -1,4 +1,5 @@ | |||||
wpasupplicant wireless-tools firmware-atheros firmware-brcm80211 firmware-libertas firmware-misc-nonfree firmware-realtek | wpasupplicant wireless-tools firmware-atheros firmware-brcm80211 firmware-libertas firmware-misc-nonfree firmware-realtek | ||||
raspberrypi-net-mods | raspberrypi-net-mods | ||||
dhcpcd5 | dhcpcd5 | ||||
network-manager | |||||
net-tools | net-tools |
@@ -5,10 +5,13 @@ install -v -m 600 files/wpa_supplicant.conf "${ROOTFS_DIR}/etc/wpa_supplicant/" | |||||
on_chroot << EOF | on_chroot << EOF | ||||
SUDO_USER="${FIRST_USER_NAME}" raspi-config nonint do_boot_wait 0 | SUDO_USER="${FIRST_USER_NAME}" raspi-config nonint do_boot_wait 0 | ||||
SUDO_USER="${FIRST_USER_NAME}" raspi-config nonint do_netconf 1 | |||||
EOF | EOF | ||||
if [ -v WPA_COUNTRY ]; then | if [ -v WPA_COUNTRY ]; then | ||||
echo "country=${WPA_COUNTRY}" >> "${ROOTFS_DIR}/etc/wpa_supplicant/wpa_supplicant.conf" | |||||
on_chroot <<- EOF | |||||
SUDO_USER="${FIRST_USER_NAME}" raspi-config nonint do_wifi_country "${WPA_COUNTRY}" | |||||
EOF | |||||
fi | fi | ||||
if [ -v WPA_ESSID ] && [ -v WPA_PASSWORD ]; then | if [ -v WPA_ESSID ] && [ -v WPA_PASSWORD ]; then | ||||
@@ -12,4 +12,4 @@ fonts-liberation2 | |||||
obconf | obconf | ||||
arandr | arandr | ||||
libcamera-tools | libcamera-tools | ||||
libcamera-apps | |||||
libcamera-apps |
@@ -4,3 +4,4 @@ lxde lxtask menu-xdg | |||||
zenity xdg-utils | zenity xdg-utils | ||||
gvfs-backends gvfs-fuse | gvfs-backends gvfs-fuse | ||||
lightdm gnome-themes-standard gnome-icon-theme | lightdm gnome-themes-standard gnome-icon-theme | ||||
gnome-keyring |
@@ -23,3 +23,5 @@ piwiz | |||||
rp-prefapps | rp-prefapps | ||||
ffmpeg | ffmpeg | ||||
vlc | vlc | ||||
rpi-imager | |||||
rpi-wayland |