Here's a disgusting AI assisted attempt to automate the process
#!/bin/sh
# ----------------------------------------------------------------------
# NetBSD Kernel Build Automation Script
#
# Automates fetching, extracting, and building a custom NetBSD kernel.
#
# Features:
# - Auto-detects system architecture (override with --arch)
# - Fetch NetBSD source tarballs if not already present
# - Extract and set up /usr/src and /usr/xsrc
# - Build toolchain and kernel with custom config
# - Install new kernel (with backup)
# - Cleanup mode to start fresh
# - Dependency check with optional auto-install via pkgin
# - Colored output for clarity
#
# Usage: run with -h or --help for options.
# ----------------------------------------------------------------------
set -eu
set -o pipefail
# === Colors ===
RED=$'\033[0;31m'
GREEN=$'\033[0;32m'
YELLOW=$'\033[1;33m'
NC=$'\033[0m' # No Color
usage() {
printf "${YELLOW}"
cat <<EOF
Usage: $0 [options]
Automates fetching, extracting, and building a custom NetBSD kernel.
Options:
-h, --help Show this help message and exit
-n <name> Set custom kernel config name (default: MYKERNEL)
-j <jobs> Set number of build jobs (default: 4)
-v <version> NetBSD version (default: 10.1), e.g. 11.0, 11.1_RC2
-a <arch> Build architecture (auto-detects, e.g. amd64, i386)
--dry-run Show what would happen without doing it
--no-fetch Skip downloading source tarballs
--no-clean Skip cleanup prompt at end
--cleanup Cleanup downloaded sets, build dirs, and /usr/src /usr/xsrc
EOF
printf "${NC}"
}
# === Defaults & Globals ===
KERNEL_NAME="MYKERNEL"
CORES=4
NETBSD_VERSION="10.1"
DRY_RUN=0
SKIP_FETCH=0
SKIP_CLEAN=0
CLEANUP_ONLY=0
BUILD_ARCH=$(uname -m)
USERNAME=${DOAS_USER:-${USER:-$(id -un)}}
USER_GROUP=$(id -gn "$USERNAME")
SOURCE_DIR="$HOME/netbsd-sources"
BUILD_DIR="$HOME/netbsd-build"
FTP_BASE_URL="ftp://ftp.NetBSD.org/pub/NetBSD/NetBSD-${NETBSD_VERSION}/source/sets"
run() {
if [ "$DRY_RUN" -eq 1 ]; then
printf "${YELLOW}[dry-run] %s${NC}\n" "$*"
else
eval "$@"
fi
}
parse_args() {
while [ $# -gt 0 ]; do
case "$1" in
-h|--help) usage; exit 0 ;;
-n) shift; KERNEL_NAME=$1 ;;
-j) shift; CORES=$1 ;;
-v) shift; NETBSD_VERSION=$1
FTP_BASE_URL="ftp://ftp.NetBSD.org/pub/NetBSD/NetBSD-${NETBSD_VERSION}/source/sets" ;;
-a) shift; BUILD_ARCH=$1 ;;
--dry-run) DRY_RUN=1 ;;
--no-fetch) SKIP_FETCH=1 ;;
--no-clean) SKIP_CLEAN=1 ;;
--cleanup) CLEANUP_ONLY=1 ;;
*) printf "${RED}Unknown option: %s${NC}\n" "$1" >&2; usage; exit 1 ;;
esac
shift
done
}
check_dependencies() {
printf "${GREEN}==> Checking dependencies...${NC}\n"
REQUIRED_CMDS="ftp tar pv vim doas"
for cmd in $REQUIRED_CMDS; do
if ! command -v "$cmd" >/dev/null 2>&1; then
printf "${YELLOW} -> Missing: %s${NC}\n" "$cmd"
printf " Install with pkgin? (y/n) "
read -r ans
case "$ans" in
y|Y) run "doas pkgin -y install \"$cmd\"" ;;
*) printf "${RED} !! %s is required; script may fail.${NC}\n" "$cmd" ;;
esac
else
printf " -> %s found\n" "$cmd"
fi
done
}
cleanup() {
printf "${RED}==> Cleanup mode: removing sets, build dirs, and /usr/src /usr/xsrc${NC}\n"
printf "Are you sure? (y/n) "
read -r ans
case "$ans" in
y|Y)
run "rm -rf \"$SOURCE_DIR\""
run "rm -rf \"$BUILD_DIR\""
run "doas rm -rf /usr/src /usr/xsrc"
printf "${GREEN}==> Cleanup complete.${NC}\n"
;;
*) printf "${YELLOW}==> Cleanup cancelled.${NC}\n" ;;
esac
exit 0
}
fetch_sources() {
printf "${GREEN}==> Fetching sources to %s${NC}\n" "$SOURCE_DIR"
run "mkdir -p \"$SOURCE_DIR\""
cd "$SOURCE_DIR"
for file in src.tgz syssrc.tgz sharesrc.tgz gnusrc.tgz xsrc.tgz; do
if [ ! -f "$file" ]; then
printf " -> Downloading %s\n" "$file"
run "ftp -i \"${FTP_BASE_URL}/${file}\""
else
printf " -> %s already exists, skipping\n" "$file"
fi
done
}
ensure_src_dirs() {
printf "${GREEN}==> Ensuring /usr/src and /usr/xsrc exist & owned by %s${NC}\n" "$USERNAME"
for dir in /usr/src /usr/xsrc; do
if [ ! -d "$dir" ]; then
run "doas mkdir -p \"$dir\""
fi
owner=$(stat -f '%Su' "$dir")
if [ "$owner" != "$USERNAME" ]; then
run "doas chown -R \"$USERNAME:$USER_GROUP\" \"$dir\""
fi
done
}
extract_sources() {
printf "${GREEN}==> Extracting source sets...${NC}\n"
for file in "$SOURCE_DIR"/*.tgz; do
printf " -> %s\n" "$(basename "$file")"
run "pv \"$file\" | doas tar -xzf - -C /"
done
}
create_build_dirs() {
printf "${GREEN}==> Creating build dirs in %s${NC}\n" "$BUILD_DIR"
for sub in obj tools; do
[ -d "$BUILD_DIR/$sub" ] || run "mkdir -p \"$BUILD_DIR/$sub\""
done
}
build_toolchain() {
printf "${GREEN}==> Building toolchain...${NC}\n"
cd /usr/src
run "./build.sh -U -O \"$BUILD_DIR/obj\" -T \"$BUILD_DIR/tools\" -j$CORES tools"
}
edit_kernel_config() {
CONF_DIR="/usr/src/sys/arch/${BUILD_ARCH}/conf"
cd "$CONF_DIR"
if [ ! -f "$KERNEL_NAME" ]; then
run "cp GENERIC \"$KERNEL_NAME\""
[ "$DRY_RUN" -eq 0 ] && vim "$KERNEL_NAME"
else
printf "==> Kernel config %s already exists\n" "$KERNEL_NAME"
fi
}
build_kernel() {
printf "${GREEN}==> Building kernel: %s${NC}\n" "$KERNEL_NAME"
cd /usr/src
run "./build.sh -U -O \"$BUILD_DIR/obj\" -T \"$BUILD_DIR/tools\" -j$CORES kernel=\"$KERNEL_NAME\""
}
install_kernel() {
KERNEL_OUTPUT="$BUILD_DIR/obj/sys/arch/${BUILD_ARCH}/compile/$KERNEL_NAME/netbsd"
if [ "$DRY_RUN" -eq 0 ] && [ ! -f "$KERNEL_OUTPUT" ]; then
printf "${RED}!! Kernel not found: %s${NC}\n" "$KERNEL_OUTPUT"
exit 1
fi
printf "${GREEN}==> Kernel built! Output: %s${NC}\n" "$KERNEL_OUTPUT"
printf "Install kernel now? (y/n) "
read -r ans
case "$ans" in
y|Y)
run "doas cp /netbsd /netbsd.old"
run "doas cp \"$KERNEL_OUTPUT\" /netbsd"
printf "${GREEN}==> Installed. Reboot to use new kernel.${NC}\n"
;;
*) printf "${YELLOW}==> Skipping install; copy manually if needed.${NC}\n" ;;
esac
}
optional_cleanup() {
if [ "$DRY_RUN" -eq 0 ] && [ "$SKIP_CLEAN" -eq 0 ]; then
printf "Remove build dirs in %s? (y/n) " "$BUILD_DIR"
read -r ans
[ "$ans" = "y" ] && run "rm -rf \"$BUILD_DIR\""
else
printf "${YELLOW}==> Cleanup skipped (--no-clean or dry-run).${NC}\n"
fi
}
main() {
parse_args "$@"
[ "$CLEANUP_ONLY" -eq 1 ] && cleanup
check_dependencies
printf "${GREEN}==> NetBSD kernel rebuild${NC}\n"
printf "User: %s | Arch: %s | Version: %s | Kernel: %s | Jobs: %s\n" \
"$USERNAME" "$BUILD_ARCH" "$NETBSD_VERSION" "$KERNEL_NAME" "$CORES"
[ "$SKIP_FETCH" -eq 0 ] && fetch_sources || printf "${YELLOW}==> Skipping fetch (--no-fetch)${NC}\n"
ensure_src_dirs
extract_sources
create_build_dirs
build_toolchain
edit_kernel_config
build_kernel
install_kernel
optional_cleanup
}
main "$@"
It works... so, cool, i guess.... 😎