# Template file for 'busybox'
pkgname=busybox
version=1.36.1
revision=8
short_desc="Swiss Army knife of embedded Linux utilities"
maintainer="finwo <finwo@pm.me>"
license="GPL-2.0-only"
homepage="https://busybox.net"
distfiles="https://busybox.net/downloads/busybox-1.36.1.tar.bz2"
checksum=b8cc24c9574d809e7279c3be349795c5d5ceb6fdf19ca709f80cde50e47de314
depends=

# Applet policy (locked in PLAN.md section 10, enforced by assertions in
# do_build - a missing symbol fails the build, never the boot):
#
# ON: init sequence + supervision + shell + connection handling, i.e. the
#   whole reason busybox is here, plus console login and mgmt DHCP.
#   (INIT/HALT/POWEROFF/REBOOT/GETTY/LOGIN/MOUNT/UMOUNT/SWITCH_ROOT are
#   defconfig defaults; listing them makes the requirement explicit.)
# OFF: IP applets (iproute2 is the only `ip`), TC (iproute2's `tc` is
#   full-featured; busybox's references kernel-removed CBQ UAPI and does not
#   build against modern headers), LDCONFIG (glibc's real ldconfig owns
#   /sbin/ldconfig; the applet would conflict on that path and its cache
#   output must never feed glibc's loader), the xz family (real xz owns
#   usr/bin/{xz,xzcat,unxz,lzma,unlzma,lzcat} - apk refuses the overwrite
#   otherwise; six symbols gate them in bbunzip.c, all six go; kernel
#   initramfs xz stays independent via CONFIG_RD_XZ),
#   udhcpd (dnsmasq covers the server side), httpd/inetd (tcpsvd is our
#   super-server), IFUP (linkd owns /etc/network/interfaces via linkctl, busybox
#   ifupdown would conflict and its `iface <name>` parser is for old
#   `iface <name> inet static` only -- cumulus `iface <name>` fails there),
#   MKFS_VFAT/MKDOSFS (dosfstools owns mkfs.vfat; two providers of one command
#   resolved by PATH order is a trap, and busybox's variant warns about
#   codepage conversion on every run because it wants iconv data our
#   C.UTF-8-only glibc does not ship. dosfstools also brings fsck.fat, which
#   busybox has no equivalent of at all -- and the ESP is the one partition
#   whose corruption stops the switch booting).
# Untouched (defconfig default) until their design lands: SYSLOGD/KLOGD.
# No checked-in .config on purpose: defconfig + CFG_* is the source of truth
# (this kconfig has no savedefconfig anyway); the assertions below enforce it.
CFG_ON="INIT HALT POWEROFF REBOOT GETTY LOGIN MOUNT UMOUNT SWITCH_ROOT ASH ASH_JOB_CONTROL RUNSV RUNSVDIR SV SVLOGD CHPST SETUIDGID TCPSVD UDHCPC"
CFG_OFF="IP FEATURE_IP_ADDRESS FEATURE_IP_LINK FEATURE_IP_ROUTE FEATURE_IP_RULE FEATURE_IP_TUNNEL TC LDCONFIG UNLZMA LZCAT LZMA UNXZ XZCAT XZ UDHCPD HTTPD INETD IFUP IFDOWN MKFS_VFAT MKDOSFS"

# applet names as `busybox --list` prints them
REQUIRE="init halt poweroff reboot getty login mount umount switch_root ash runsv runsvdir sv svlogd chpst setuidgid tcpsvd udhcpc"
FORBID="ip tc ldconfig unlzma lzcat lzma unxz xzcat xz udhcpd httpd inetd ifup ifdown mkfs.vfat mkdosfs"

set_config() {
  # $1 = symbol, $2 = y|n
  if grep -q "^CONFIG_$1=" .config 2>/dev/null || grep -q "^# CONFIG_$1 is not set$" .config 2>/dev/null; then
    sed -i -e "s/^# CONFIG_$1 is not set\$/CONFIG_$1=$2/" -e "s/^CONFIG_$1=.*\$/CONFIG_$1=$2/" .config
  else
    [ "$2" = y ] && echo "CONFIG_$1=y" >> .config || echo "# CONFIG_$1 is not set" >> .config
  fi
}

do_configure() {
  cd "${WRKSRC}"
  make defconfig >/dev/null
  for c in ${CFG_ON}; do set_config "${c}" y; done
  for c in ${CFG_OFF}; do set_config "${c}" n; done
  # this kconfig has no olddefconfig; resolve non-interactively instead
  yes "" | make oldconfig >/dev/null
  for c in ${CFG_ON}; do
    grep -q "^CONFIG_${c}=y$" .config || die "busybox: CONFIG_${c} did not stick"
  done
}

do_build() {
  cd "${WRKSRC}"
  make -j"$(nproc)"
  have=$(./busybox --list)
  for a in ${REQUIRE}; do
    printf '%s\n' "${have}" | grep -qx "${a}" || die "busybox: required applet missing: ${a}"
  done
  for a in ${FORBID}; do
    printf '%s\n' "${have}" | grep -qx "${a}" && die "busybox: forbidden applet present: ${a}" || true
  done
}

do_install() {
  cd "${WRKSRC}"
  make CONFIG_PREFIX="${DESTDIR}" install
  # initrd-era fossil: the kernel runs /linuxrc only on classic initrd, and
  # UNOS boots initramfs-style (/init + switch_root). Prune it so the rootfs
  # carries no dead symlinks.
  rm -f "${DESTDIR}/linuxrc"
}
