What is BusyBox?
- title
- What is BusyBox?
- type
- summary
- summary
- Walk-through of BusyBox's multicall dispatch โ one binary, 130+ symlinks in Alpine, argv[0]-based applet lookup, ~304 applets compiled in
- tags
- linux, unix, busybox, alpine
- sources
- specular-what-is-busybox
- created
- 2026-05-13
- updated
- 2026-05-13
specular.fi post sparked by noticing that Alpine's /usr/bin/wget is actually BusyBox Wget, then realising the same is true for ~130 other Alpine binaries โ all symlinks to /bin/busybox. The post is short and reads like the author worked the source code out in real time:
$ ls -lah /usr/bin/wget
lrwxrwxrwx 1 root root 12 Apr 15 04:51 /usr/bin/wget -> /bin/busybox
How it dispatches
The BusyBox entry point reads argv[0] and looks up the matching applet:
applet_name = argv[0];
if (applet_name[0] == '-') // login shells: argv[0] starts with -
applet_name++;
applet_name = bb_basename(applet_name);
int applet = find_applet_by_name(name);
run_applet_no_and_exit(applet, name, argv);
// xfunc_error_retval = applet_main[applet_no](argc, argv);
Calling the binary directly works too:
$ busybox ls -1
bin
dev
etc
home
$ busybox meheh
meheh: applet not found
Each applet has its own C file (wget lives in wget.c) with Kconfig-style metadata in //config: comments and a typical entry point int wget_main(int argc, char **argv). The build pulls those into a single Kconfig surface so a downstream distro picks which applets to compile in.
busybox --install -s creates the symlinks (-s for symlinks; hard links are the default). busybox --list | wc -l reports the applet count โ 304 in Alpine.
The post's payoff observation:
Alpine is more like an interface to BusyBox-based binaries. Each binary seems to be a bit stripped-down version of the actual full-blown one.
This is exactly the design tradeoff multicall-binary makes โ one shared runtime, many command names, applets that cover the 80% case at a fraction of the disk and memory cost of GNU coreutils. Whether the applets are reimplementations or shrunk-down originals (the post wonders) is mostly the former โ BusyBox applets are written from scratch with a smaller option surface, not stripped GNU code.
Why this matters
- Alpine images are ~5 MB partly because of this design. Replace BusyBox with full GNU coreutils + util-linux + bash + ... and the image grows by an order of magnitude.
- Container-native shells, scripts, and
RUNlines that depend on GNU-specific flags break silently in Alpine โfind -printf,grep -P,sed -i '', etc. The fix is usuallyapk add coreutils findutils sed gnu-grep(which un-does the multicall optimisation for those tools) or rewrite the script to BusyBox-portable forms. - The same multicall pattern appears in Pi-style "one umbrella binary, many subcommands" CLIs, except those use argv[1] not argv[0] โ different mechanism, similar user model. See multicall-binary for the dividing line.
Where it fits
The post slots in next to other "small thing, big consequences" Unix write-ups in the wiki โ zsh-glob-qualifiers, t-context-go-testing, macos-tcp-time-bomb โ and gives multicall-binary its anchoring example. Closer cluster: minimal-userland design (microvm-2026, qemu-microvm) โ the same pressure to ship the smallest viable substrate that runs the actual workload. BusyBox is the userspace half of what microVMs are for the kernel-and-VMM half.