#!/usr/bin/env bash # build-linux-rpi.sh - build/install a newer linux-rpi from rpi-6.18.y set -euo pipefail if [[ ${EUID:-0} -ne 0 ]]; then echo "run as root (sudo) to install build deps and kernel packages" >&2 exit 1 fi BUILD_USER=${LESAVKA_KERNEL_BUILD_USER:-${SUDO_USER:-$(id -un)}} if [[ -z $BUILD_USER || $BUILD_USER == root ]]; then echo "missing non-root build user; set LESAVKA_KERNEL_BUILD_USER" >&2 exit 1 fi KERNEL_REPO=${LESAVKA_KERNEL_REPO:-https://github.com/raspberrypi/linux.git} KERNEL_BRANCH=${LESAVKA_KERNEL_BRANCH:-rpi-6.18.y} KERNEL_COMMIT=${LESAVKA_KERNEL_COMMIT:-} PKGBUILD_REPO=${LESAVKA_KERNEL_PKG_REPO:-https://github.com/archlinuxarm/PKGBUILDs.git} BUILD_ROOT=${LESAVKA_KERNEL_BUILD_ROOT:-/var/tmp/lesavka-linux-rpi} PKGREL=${LESAVKA_KERNEL_PKGREL:-2} JOBS=${LESAVKA_KERNEL_JOBS:-2} SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) PATCH_DIR=${LESAVKA_KERNEL_PATCH_DIR:-$SCRIPT_DIR} PATCH_DWC2_FIFO=${LESAVKA_KERNEL_PATCH_DWC2_FIFO:-} PATCH_UVC_BULK=${LESAVKA_KERNEL_PATCH_UVC_BULK:-} PATCH_UVC_DEBUG=${LESAVKA_KERNEL_PATCH_UVC_DEBUG:-} HEARTBEAT=/etc/lesavka/watchdog.touch if [[ -w $HEARTBEAT && -z ${LESAVKA_DISABLE_KEEPALIVE:-} ]]; then (while true; do touch "$HEARTBEAT"; sleep 600; done) & KEEPALIVE_PID=$! trap 'kill $KEEPALIVE_PID' EXIT fi if [[ -z $KERNEL_COMMIT ]]; then KERNEL_COMMIT=$(git ls-remote "$KERNEL_REPO" "refs/heads/$KERNEL_BRANCH" | awk '{print $1}') fi if [[ -z $KERNEL_COMMIT ]]; then echo "failed to resolve kernel commit for $KERNEL_BRANCH" >&2 exit 1 fi KERNEL_VERSION=$( curl -fsSL "https://raw.githubusercontent.com/raspberrypi/linux/$KERNEL_COMMIT/Makefile" | awk -F' = ' ' /^VERSION =/ {v=$2} /^PATCHLEVEL =/ {p=$2} /^SUBLEVEL =/ {s=$2} END { if (v && p && s) print v "." p "." s }' ) if [[ -z $KERNEL_VERSION ]]; then echo "failed to determine kernel version from $KERNEL_COMMIT" >&2 exit 1 fi TARGET_VERSION="${KERNEL_VERSION}-${PKGREL}" INSTALLED_VERSION=$(pacman -Qi linux-rpi 2>/dev/null | awk -F': ' '/Version/{print $2}') if [[ -n $INSTALLED_VERSION && $INSTALLED_VERSION == "$TARGET_VERSION"* ]]; then echo "linux-rpi already at $TARGET_VERSION" exit 0 fi echo "==> Building linux-rpi $KERNEL_VERSION ($KERNEL_COMMIT) pkgrel=$PKGREL" pacman -Sy --needed --noconfirm git bc kmod inetutils base-devel rm -rf "$BUILD_ROOT" mkdir -p "$BUILD_ROOT" chown "$BUILD_USER":"$BUILD_USER" "$BUILD_ROOT" sudo -u "$BUILD_USER" git clone --depth 1 "$PKGBUILD_REPO" "$BUILD_ROOT/PKGBUILDs" cp -a "$BUILD_ROOT/PKGBUILDs/core/linux-rpi" "$BUILD_ROOT/linux-rpi" chown -R "$BUILD_USER":"$BUILD_USER" "$BUILD_ROOT/linux-rpi" sudo -u "$BUILD_USER" bash -c " set -euo pipefail cd '$BUILD_ROOT/linux-rpi' sed -i 's/^pkgver=.*/pkgver=$KERNEL_VERSION/' PKGBUILD sed -i 's/^pkgrel=.*/pkgrel=$PKGREL/' PKGBUILD sed -i 's/^_commit=.*/_commit=$KERNEL_COMMIT/' PKGBUILD makepkg -g > /tmp/lesavka-kernel.sums " sudo -u "$BUILD_USER" BUILD_ROOT="$BUILD_ROOT" python - <<'PY' import re from pathlib import Path import os root = Path(os.environ["BUILD_ROOT"]) pkgbuild = root / "linux-rpi" / "PKGBUILD" sums = Path("/tmp/lesavka-kernel.sums").read_text().splitlines() text = pkgbuild.read_text() for line in sums: if not line.startswith("sha256sums"): continue key = line.split("=", 1)[0] text = re.sub(rf"^{re.escape(key)}=.*$", line, text, flags=re.M) pkgbuild.write_text(text) PY MAKEPKG_EXTRA="" KERNEL_SRC="$BUILD_ROOT/linux-rpi/src/linux-$KERNEL_COMMIT" PATCHES=() if [[ -n $PATCH_DWC2_FIFO ]]; then PATCHES+=("dwc2-fifo.patch") fi if [[ -n $PATCH_UVC_BULK ]]; then PATCHES+=("uvc-bulk.patch") fi if [[ -n $PATCH_UVC_DEBUG ]]; then PATCHES+=("uvc-debug.patch") fi if [[ ${#PATCHES[@]} -gt 0 ]]; then sudo -u "$BUILD_USER" bash -c " set -euo pipefail cd '$BUILD_ROOT/linux-rpi' MAKEFLAGS='-j$JOBS' makepkg -o --noconfirm " sudo -u "$BUILD_USER" bash -c " set -euo pipefail src='$KERNEL_SRC' if [[ ! -d \$src ]]; then echo \"missing kernel source \$src\" >&2 exit 1 fi cd \"\$src\" for patch in ${PATCHES[*]}; do patch_file='$PATCH_DIR/'\"\$patch\" if [[ ! -f \$patch_file ]]; then echo \"missing patch \$patch_file\" >&2 exit 1 fi case \"\$patch\" in dwc2-fifo.patch) if grep -q 'dwc2_check_param_fifo_total' \"drivers/usb/dwc2/params.c\"; then echo \"dwc2-fifo patch already applied\" continue fi ;; uvc-bulk.patch) if grep -q 'streaming_bulk' \"drivers/usb/gadget/function/uvc_configfs.c\"; then echo \"uvc-bulk patch already applied\" continue fi ;; uvc-debug.patch) if grep -q 'uvcg_video_enable: missing uvc/func/config' \ \"drivers/usb/gadget/function/uvc_video.c\"; then echo \"uvc-debug patch already applied\" continue fi ;; esac patch -p1 < \"\$patch_file\" done " MAKEPKG_EXTRA="-e" fi sudo -u "$BUILD_USER" bash -c " set -euo pipefail cd '$BUILD_ROOT/linux-rpi' MAKEFLAGS='-j$JOBS' makepkg -s --noconfirm $MAKEPKG_EXTRA " mapfile -t PKGS < <(ls "$BUILD_ROOT/linux-rpi"/*.pkg.tar.* 2>/dev/null) if [[ ${#PKGS[@]} -eq 0 ]]; then echo "no kernel packages built" >&2 exit 1 fi pacman -U --noconfirm "${PKGS[@]}" echo "✅ linux-rpi upgraded to $TARGET_VERSION (reboot required)"