aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/rosa
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-01-19 01:12:47 +0900
committerOphestra <cat@gensokyo.uk>2026-01-19 01:12:47 +0900
commit823f9c76a74b671fb7b76101346da562e5bcb655 (patch)
tree84fc67ae968c39f507c972df8f3309aa9c05a741 /internal/rosa
parent2df913999b3ab5e79248fc892bd2dd089cac7f26 (diff)
internal/rosa: busybox from source
This will be part of the standard toolchain. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/rosa')
-rw-r--r--internal/rosa/busybox.go259
1 files changed, 259 insertions, 0 deletions
diff --git a/internal/rosa/busybox.go b/internal/rosa/busybox.go
index 3fe221b9..25baee95 100644
--- a/internal/rosa/busybox.go
+++ b/internal/rosa/busybox.go
@@ -5,6 +5,8 @@ import (
"io"
"net/http"
"os"
+ "slices"
+ "strings"
"time"
"hakurei.app/container/fhs"
@@ -97,3 +99,260 @@ func newBusyboxBin() pkg.Artifact {
)}),
)
}
+
+// NewBusybox returns a [pkg.Artifact] containing a dynamically linked busybox
+// installation usable within the [Toolchain] it is compiled against.
+func (t Toolchain) NewBusybox() pkg.Artifact {
+ const (
+ version = "1.37.0"
+ checksum = "Ial94Tnt7esJ_YEeb0AxunVL6MGYFyOw7Rtu2o87CXCi1TLrc6rlznVsN1rZk7it"
+ )
+
+ extra := []pkg.Artifact{
+ t.NewMake(),
+ t.NewKernelHeaders(),
+ }
+ var env []string
+
+ if t == toolchainStage3 {
+ extra = nil
+ env = append(env, "EXTRA_LDFLAGS=-static")
+ }
+
+ return t.New("busybox-"+version, extra, nil, slices.Concat([]string{
+ "ROSA_BUSYBOX_ENABLE=" + strings.Join([]string{
+ "STATIC",
+ "PIE",
+ }, " "),
+ "ROSA_BUSYBOX_DISABLE=" + strings.Join([]string{
+ "FEATURE_IPV6",
+ "FEATURE_PREFER_IPV4_ADDRESS",
+ "FEATURE_HWIB",
+ "ARP",
+ "ARPING",
+ "BRCTL",
+ "FEATURE_BRCTL_FANCY",
+ "FEATURE_BRCTL_SHOW",
+ "DNSD",
+ "ETHER_WAKE",
+ "FTPD",
+ "FEATURE_FTPD_WRITE",
+ "FEATURE_FTPD_ACCEPT_BROKEN_LIST",
+ "FEATURE_FTPD_AUTHENTICATION",
+ "FTPGET",
+ "FTPPUT",
+ "FEATURE_FTPGETPUT_LONG_OPTIONS",
+ "HOSTNAME",
+ "DNSDOMAINNAME",
+ "HTTPD",
+ "FEATURE_HTTPD_PORT_DEFAULT",
+ "FEATURE_HTTPD_RANGES",
+ "FEATURE_HTTPD_SETUID",
+ "FEATURE_HTTPD_BASIC_AUTH",
+ "FEATURE_HTTPD_AUTH_MD5",
+ "FEATURE_HTTPD_CGI",
+ "FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR",
+ "FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV",
+ "FEATURE_HTTPD_ENCODE_URL_STR",
+ "FEATURE_HTTPD_ERROR_PAGES",
+ "FEATURE_HTTPD_PROXY",
+ "FEATURE_HTTPD_GZIP",
+ "FEATURE_HTTPD_ETAG",
+ "FEATURE_HTTPD_LAST_MODIFIED",
+ "FEATURE_HTTPD_DATE",
+ "FEATURE_HTTPD_ACL_IP",
+ "IFCONFIG",
+ "FEATURE_IFCONFIG_STATUS",
+ "FEATURE_IFCONFIG_SLIP",
+ "FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ",
+ "FEATURE_IFCONFIG_HW",
+ "FEATURE_IFCONFIG_BROADCAST_PLUS",
+ "IFENSLAVE",
+ "IFPLUGD",
+ "IFUP",
+ "IFDOWN",
+ "IFUPDOWN_IFSTATE_PATH",
+ "FEATURE_IFUPDOWN_IP",
+ "FEATURE_IFUPDOWN_IPV4",
+ "FEATURE_IFUPDOWN_IPV6",
+ "FEATURE_IFUPDOWN_MAPPING",
+ "INETD",
+ "FEATURE_INETD_SUPPORT_BUILTIN_ECHO",
+ "FEATURE_INETD_SUPPORT_BUILTIN_DISCARD",
+ "FEATURE_INETD_SUPPORT_BUILTIN_TIME",
+ "FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME",
+ "FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN",
+ "IP",
+ "IPADDR",
+ "IPLINK",
+ "IPROUTE",
+ "IPTUNNEL",
+ "IPRULE",
+ "IPNEIGH",
+ "FEATURE_IP_ADDRESS",
+ "FEATURE_IP_LINK",
+ "FEATURE_IP_LINK_CAN",
+ "FEATURE_IP_ROUTE",
+ "FEATURE_IP_ROUTE_DIR",
+ "FEATURE_IP_TUNNEL",
+ "FEATURE_IP_RULE",
+ "FEATURE_IP_NEIGH",
+ "IPCALC",
+ "FEATURE_IPCALC_LONG_OPTIONS",
+ "FEATURE_IPCALC_FANCY",
+ "FAKEIDENTD",
+ "NAMEIF",
+ "FEATURE_NAMEIF_EXTENDED",
+ "NBDCLIENT",
+ "NC",
+ "NC_SERVER",
+ "NC_EXTRA",
+ "NC_110_COMPAT",
+ "NETSTAT",
+ "FEATURE_NETSTAT_WIDE",
+ "FEATURE_NETSTAT_PRG",
+ "NSLOOKUP",
+ "FEATURE_NSLOOKUP_BIG",
+ "FEATURE_NSLOOKUP_LONG_OPTIONS",
+ "NTPD",
+ "FEATURE_NTPD_SERVER",
+ "FEATURE_NTPD_CONF",
+ "FEATURE_NTP_AUTH",
+ "PING",
+ "PING6",
+ "FEATURE_FANCY_PING",
+ "PSCAN",
+ "ROUTE",
+ "SLATTACH",
+ "SSL_CLIENT",
+ "TC",
+ "FEATURE_TC_INGRESS",
+ "TCPSVD",
+ "UDPSVD",
+ "TELNET",
+ "FEATURE_TELNET_TTYPE",
+ "FEATURE_TELNET_AUTOLOGIN",
+ "FEATURE_TELNET_WIDTH",
+ "TELNETD",
+ "FEATURE_TELNETD_STANDALONE",
+ "FEATURE_TELNETD_PORT_DEFAULT",
+ "FEATURE_TELNETD_INETD_WAIT",
+ "TFTP",
+ "FEATURE_TFTP_PROGRESS_BAR",
+ "FEATURE_TFTP_HPA_COMPAT",
+ "TFTPD",
+ "FEATURE_TFTP_GET",
+ "FEATURE_TFTP_PUT",
+ "FEATURE_TFTP_BLOCKSIZE",
+ "TLS",
+ "TRACEROUTE",
+ "TRACEROUTE6",
+ "FEATURE_TRACEROUTE_VERBOSE",
+ "FEATURE_TRACEROUTE_USE_ICMP",
+ "TUNCTL",
+ "FEATURE_TUNCTL_UG",
+ "VCONFIG",
+ "WGET",
+ "FEATURE_WGET_LONG_OPTIONS",
+ "FEATURE_WGET_STATUSBAR",
+ "FEATURE_WGET_FTP",
+ "FEATURE_WGET_AUTHENTICATION",
+ "FEATURE_WGET_TIMEOUT",
+ "FEATURE_WGET_HTTPS",
+ "FEATURE_WGET_OPENSSL",
+ "WHOIS",
+ "ZCIP",
+ "UDHCPD",
+ "FEATURE_UDHCPD_BOOTP",
+ "FEATURE_UDHCPD_WRITE_LEASES_EARLY",
+ "DHCPD_LEASES_FILE",
+ "DUMPLEASES",
+ "DHCPRELAY",
+ "UDHCPC",
+ "FEATURE_UDHCPC_ARPING",
+ "FEATURE_UDHCPC_SANITIZEOPT",
+ "UDHCPC_DEFAULT_SCRIPT",
+ "UDHCPC6_DEFAULT_SCRIPT",
+ "UDHCPC6",
+ "FEATURE_UDHCPC6_RFC3646",
+ "FEATURE_UDHCPC6_RFC4704",
+ "FEATURE_UDHCPC6_RFC4833",
+ "FEATURE_UDHCPC6_RFC5970",
+ }, " "),
+ }, env), `
+config_enable() {
+ for ent in "$@"; do
+ sed "s/^# CONFIG_${ent}.*/CONFIG_${ent}=y/" -i .config
+ shift
+ done
+}
+
+config_disable() {
+ for ent in "$@"; do
+ sed "s/^CONFIG_${ent}=y/# CONFIG_${ent} is not set/" -i .config
+ shift
+ done
+}
+
+cat > /bin/gcc << EOF
+exec clang \
+ -Wno-ignored-optimization-argument \
+ ${ROSA_CFLAGS} \
+ ${LDFLAGS} \
+ \$@
+EOF
+chmod +x /bin/gcc
+
+cd /usr/src/busybox
+chmod +w editors editors/awk.c
+patch -p 1 < /usr/src/patches/awk-fix-literal-backslash.patch
+
+cd "$(mktemp -d)"
+make \
+ KBUILD_SRC=/usr/src/busybox \
+ -f /usr/src/busybox/Makefile \
+ defconfig
+
+config_enable $ROSA_BUSYBOX_ENABLE
+config_disable $ROSA_BUSYBOX_DISABLE
+ln -s ../system/bin/pwd /bin/pwd || true
+make CFLAGS_busybox="${LDFLAGS} ${EXTRA_LDFLAGS}" "-j$(nproc)"
+
+mkdir -p /system/bin/ /work/bin/
+cp busybox /system/bin/
+
+mkdir -pv /work/system/bin/
+busybox --install -s /work/system/bin/
+cp -v busybox /work/system/bin/
+ln -vs ../system/bin/hush /work/bin/sh
+`, pkg.Path(AbsUsrSrc.Append("busybox"), true, pkg.NewHTTPGetTar(
+ &http.Client{Transport: &http.Transport{
+ // busybox website is really slow to respond
+ TLSHandshakeTimeout: 2 * time.Minute,
+ }},
+ "https://busybox.net/downloads/busybox-"+version+".tar.bz2",
+ mustDecode(checksum),
+ pkg.TarBzip2,
+ )), pkg.Path(
+ AbsUsrSrc.Append("patches", "awk-fix-literal-backslash.patch"), false,
+ pkg.NewFile("awk-fix-literal-backslash.patch", []byte(`diff --git a/editors/awk.c b/editors/awk.c
+index 64e752f4b..40f5ba7f7 100644
+--- a/editors/awk.c
++++ b/editors/awk.c
+@@ -2636,8 +2636,13 @@ static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest /*,in
+ resbuf = qrealloc(resbuf, residx + replen + n, &resbufsize);
+ memcpy(resbuf + residx, sp + pmatch[j].rm_so - start_ofs, n);
+ residx += n;
+- } else
++ } else {
++/* '\\' and '&' following a backslash keep its original meaning, any other
++ * occurrence of a '\\' should be treated as literal */
++ if (bslash && c != '\\' && c != '&')
++ resbuf[residx++] = '\\';
+ resbuf[residx++] = c;
++ }
+ bslash = 0;
+ }
+ }`)),
+ ))
+}