00 BusyBox nedir?
BusyBox, "The Swiss Army Knife of Embedded Linux" olarak tanımlanır. GNU coreutils, util-linux, procps ve birçok ağ aracının yerini tek bir küçük binary olarak alır. Gömülü sistemlerde depolama ve RAM kısıtlamalarını aşmak için vazgeçilmez bir araçtır.
Applet kavramı
BusyBox tek bir binary'dir (/bin/busybox). Bu binary'ye farklı isimlerle sembolik link oluşturulduğunda, çağrıldığı isme göre farklı bir araç gibi davranır. argv[0]'a bakarak hangi applet'in çalıştırılacağını belirler.
/bin/busybox
│
├── /bin/sh → symlink → busybox (ash shell)
├── /bin/ls → symlink → busybox (ls applet)
├── /bin/mount → symlink → busybox (mount applet)
├── /sbin/init → symlink → busybox (init applet)
├── /sbin/mdev → symlink → busybox (mdev applet)
└── /usr/sbin/httpd → symlink → busybox (httpd applet)
Çalışma: argv[0] = "ls" → ls applet çalışır
argv[0] = "busybox" → busybox ls / applet listesi
Boyut optimizasyonu
| Konfigürasyon | Binary boyutu | Applet sayısı | Not |
|---|---|---|---|
| Tam (tüm applet'ler) | ~1.2 MB (stripped) | 400+ | glibc dinamik |
| Tam, static musl | ~900 KB | 400+ | musl-libc, no shared libs |
| Minimal (seçili) | ~300-400 KB | 50-80 | sadece gerekli applet'ler |
| UPX sıkıştırmalı | ~200 KB | 50-80 | yavaş başlatma tradeoff |
| Buildroot defconfig | ~500 KB | ~200 | musl + LTO optimizasyon |
BusyBox, LGPL lisanslıdır. Ticari gömülü ürünlerde kaynak kodu veya yapı konfigürasyonu uyumluluğu için lisans koşullarını dikkatle inceleyin. Alternatif olarak BSD lisanslı ToyBox projesi benzer işlevsellik sunar.
01 Derleme: menuconfig ve cross-compile
BusyBox derlemesi Linux kernel'e benzer bir yapılandırma sistemi kullanır. make menuconfig ile hangi applet'lerin dahil edileceği seçilir, ardından cross-compile ile hedef mimari için derlenir.
Kaynak indirme ve defconfig
wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar xf busybox-1.36.1.tar.bz2
cd busybox-1.36.1
# ARM64 cross-compile için ortam değişkenleri
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
# Varsayılan tam konfigürasyon
make defconfig
# Minimal konfigürasyon başlangıç noktası
make allnoconfig # hiçbir şey seçili değil, sıfırdan başla
# Grafik konfigürasyon arayüzü
make menuconfig
Kritik menuconfig seçenekleri
ARM64 static musl derleme
# musl cross toolchain:
# https://musl.cc/ adresinden aarch64-linux-musl-cross indirilir
export PATH="$HOME/toolchains/aarch64-linux-musl-cross/bin:$PATH"
export CROSS_COMPILE=aarch64-linux-musl-
export ARCH=arm64
# .config'de static'i aktifleştir
cat >> .config << 'EOF'
CONFIG_STATIC=y
CONFIG_STATIC_LIBGCC=y
EOF
make oldconfig
make -j$(nproc)
make install # _install/ altına sembolik linklerle kurar
# Boyut kontrolü
ls -lh busybox
file busybox # ELF 64-bit, statically linked
# strip ile ek küçültme
aarch64-linux-musl-strip --strip-all busybox
UPX ile sıkıştırma
# UPX kurulum:
sudo apt install upx-ucl
# Sıkıştır (--best en yüksek sıkıştırma, yavaş başlatma):
upx --best busybox -o busybox.upx
# Boyut karşılaştırması:
ls -lh busybox busybox.upx
# busybox: 900K
# busybox.upx: 340K
# UPX'li binary şeffaf çalışır — symlink'ler normal çalışır
# Dikkat: Flash'ta depolanan sistemlerde runtime decompression için
# RAM gerektirir — küçük RAM'li sistemlerde dikkatli olun
02 Applet kategorileri
BusyBox applet'leri işlevsel gruplara ayrılmıştır. Minimum rootfs için hangi kategorilerin zorunlu olduğunu bilmek, boyut optimizasyonunda kritik öneme sahiptir.
| Kategori | Örnekler | Zorunluluk |
|---|---|---|
| coreutils | ls, cp, mv, rm, mkdir, chmod, chown, cat, echo, printf | Temel sistem işlemleri için zorunlu |
| util-linux | mount, umount, fdisk, blkid, swapon, lsblk, dmesg | Depolama yönetimi için gerekli |
| Shell | ash, hush, sh | ash önerilir — POSIX sh uyumlu, küçük |
| init | init, halt, reboot, poweroff | BusyBox init kullanılıyorsa zorunlu |
| procps | ps, top, free, kill, killall, pidof | Süreç yönetimi |
| Networking | ifconfig, ip, ping, wget, nc, nslookup | Ağ bağlantısı için |
| DHCP | udhcpc, udhcpd | IP alımı için udhcpc |
| Editors | vi, nano (minimal) | Bakım için önerilir |
| mdev | mdev | Statik /dev yerine dinamik device node yönetimi |
| klogd/syslogd | klogd, syslogd | Log yönetimi |
| gzip/tar | gzip, gunzip, tar, xz | Arşiv işlemleri |
| find/grep | find, grep, awk, sed | Script'ler için gerekli |
03 BusyBox init sistemi
BusyBox init, SysV init'e benzer ama çok daha basit bir init sistemidir. /etc/inittab dosyasından çalıştırılacak süreçleri okur. systemd veya OpenRC'nin aksine son derece küçüktür.
/etc/inittab sözdizimi
# /etc/inittab format:
# id:runlevel:action:process
# Önyükleme: bir kez çalıştır
::sysinit:/etc/init.d/rcS
# Konsol getty — bağlantı kesilince yeniden başlat
ttyS0::respawn:/sbin/getty -L ttyS0 115200 vt100
tty1::respawn:/sbin/getty 38400 tty1
tty2::respawn:/sbin/getty 38400 tty2
# Kullanıcıya Enter'a basmasını sor (geliştirme için):
ttyS0::askfirst:/bin/sh
# Kapatma sinyali gelince
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a
Action türleri
/etc/init.d/rcS — sysinit scripti
#!/bin/sh
# /etc/init.d/rcS — sistem başlangıç scripti
# Temel dosya sistemlerini mount et
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev 2>/dev/null || \
mdev -s # devtmpfs yoksa mdev ile doldur
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
# Geçici dosya sistemi
mount -t tmpfs tmpfs /tmp -o size=64m
mount -t tmpfs tmpfs /run -o size=32m
# Saat sınıfını yükle (RTC varsa)
hwclock -s 2>/dev/null
# Hostname ayarla
echo "embedded-device" > /proc/sys/kernel/hostname
# Syslog başlat
syslogd -n -O /var/log/messages &
klogd -n &
# Ağ başlat
ifconfig lo up
ip link set eth0 up
udhcpc -i eth0 -s /etc/udhcpc/default.script -b
echo "Sistem hazır."
04 mdev — udev alternatifi
mdev, BusyBox'ın minimal udev implementasyonudur. Hotplug olaylarına yanıt verir, device node'ları oluşturur ve firmware yükleme yapabilir. udev'in 10MB+ bağımlılığının aksine mdev BusyBox binary'sinin içindedir.
mdev kurulumu
# /etc/init.d/rcS içinde:
echo /sbin/mdev > /proc/sys/kernel/hotplug
# /dev dizinini doldur (başlangıçta statik device'lar için)
mdev -s
# devtmpfs kullanılıyorsa (önerilir):
mount -t devtmpfs devtmpfs /dev
# mdev sadece hotplug için yeterli
/etc/mdev.conf sözdizimi
# /etc/mdev.conf
# Format: regex owner:group permissions [command]
# Tüm cihazları root:root 660 yap (varsayılan)
.* root:root 660
# Block cihazlar
sd[a-z][0-9]? root:disk 660
mmcblk[0-9]p[0-9] root:disk 660
nvme[0-9]n[0-9]p[0-9] root:disk 660
# Seri port
ttyS[0-9]* root:dialout 660
ttyUSB[0-9]* root:dialout 660
# Video
video[0-9]* root:video 660
# Input cihazları
mice root:input 640
mouse[0-9] root:input 640
event[0-9]* root:input 640
# USB cihaz ekleme/çıkarma olayı:
# $MDEV = cihaz adı, $ACTION = add/remove
usb.* root:root 660 *:if [ "$ACTION" = "add" ]; then \
logger "USB eklendi: $MDEV"; fi
# Firmware yükleme — kernel firmware_class mekanizması
firmware/.* root:root 640 *:/sbin/load_firmware.sh $MDEV
Firmware yükleme scripti
#!/bin/sh
# /sbin/load_firmware.sh — mdev firmware helper
FIRMWARE_DIR="/lib/firmware"
FIRMWARE="$FIRMWARE_DIR/$FIRMWARE"
LOADING="/sys$DEVPATH/loading"
DATA="/sys$DEVPATH/data"
if [ -e "$FIRMWARE" ]; then
echo 1 > "$LOADING"
cat "$FIRMWARE" > "$DATA"
echo 0 > "$LOADING"
logger "Firmware yüklendi: $FIRMWARE"
else
echo -1 > "$LOADING"
logger "Firmware bulunamadı: $FIRMWARE"
fi
mdev, udev'e göre önemli eksikliklere sahiptir: udev rule parser kadar gelişmiş değildir, D-Bus ile entegrasyonu yoktur ve karmaşık device sıralama kurallarını desteklemez. Basit gömülü sistemler için mdev yeterlidir; Android gibi karmaşık sistemler kendi device manager'larını (ueventd) kullanır.
05 initramfs + BusyBox rootfs
initramfs (initial RAM filesystem), kernel başlangıcında belleğe yüklenen geçici kök dosya sistemidir. BusyBox initramfs, gerçek rootfs mount edilene kadar temel sistemi sağlar veya kendisi kalıcı rootfs olarak kullanılır.
initramfs ile gerçek rootfs arası fark
Minimal initramfs dizin yapısı
mkdir -p initramfs/{bin,sbin,usr/{bin,sbin},lib,lib64,etc,proc,sys,dev,tmp,mnt,run,var/log}
# BusyBox'ı kopyala ve sembolik linkleri oluştur
cp busybox initramfs/bin/busybox
chmod +x initramfs/bin/busybox
# Sembolik linkleri oluştur (_install dizininden kopyala)
cd busybox-1.36.1
make install INSTALL_PATH=$(pwd)/../initramfs
cd ..
# Gerekli konfigürasyon dosyaları
cat > initramfs/etc/passwd << 'EOF'
root:x:0:0:root:/root:/bin/sh
EOF
cat > initramfs/etc/group << 'EOF'
root:x:0:
EOF
cat > initramfs/etc/inittab << 'EOF'
::sysinit:/etc/init.d/rcS
::respawn:/sbin/getty -L ttyS0 115200 vt100
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
EOF
mkdir -p initramfs/etc/init.d
cat > initramfs/etc/init.d/rcS << 'EOF'
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev 2>/dev/null || mdev -s
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
mount -t tmpfs tmpfs /tmp -o size=32m
echo "BusyBox initramfs hazır"
EOF
chmod +x initramfs/etc/init.d/rcS
# cpio arşivi oluştur
cd initramfs
find . | cpio -o -H newc | gzip -9 > ../initramfs.cpio.gz
cd ..
ls -lh initramfs.cpio.gz
switch_root ile gerçek rootfs'e geçiş
#!/bin/sh
# /init — initramfs ana init scripti, gerçek rootfs'e geçiş yapar
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
# Kernel command line'dan root cihazını al
ROOT=$(cat /proc/cmdline | tr ' ' '\n' | grep '^root=' | cut -d= -f2)
# udev/mdev ile cihazın hazır olmasını bekle
mdev -s
# Root cihazını mount et
mkdir -p /mnt/root
mount "$ROOT" /mnt/root
# initramfs'i temizle ve gerçek rootfs'e geç
# switch_root: initramfs belleğini serbest bırakır
exec switch_root /mnt/root /sbin/init
06 Buildroot entegrasyonu
Buildroot, BusyBox'ı birinci sınıf paket olarak destekler. BusyBox konfigürasyonu Buildroot'un menuconfig'i üzerinden yönetilir ve özelleştirme dosyası overlay mekanizmasıyla uygulanır.
Buildroot BusyBox konfigürasyonu
# Buildroot menuconfig:
# System configuration → Init system → BusyBox
# System configuration → /dev management → Dynamic using devtmpfs + mdev
# BR2_PACKAGE_BUSYBOX: otomatik seçili
# BR2_PACKAGE_BUSYBOX_CONFIG: özel .config dosyası yolu
# BusyBox'a özgü konfigürasyon için:
make busybox-menuconfig
# Bu komut BusyBox'ın kendi menuconfig'ini açar
# Değişiklikler output/build/busybox-VERSION/.config'e yazılır
# Konfigürasyonu kaydet (proje içinde versiyonlanabilir):
make busybox-update-config
# board/myboard/busybox.config olarak kaydedilir
BR2_ROOTFS_OVERLAY ile özelleştirme
# buildroot/conf/local.conf veya make menuconfig:
# System configuration → Root filesystem overlay directories
# BR2_ROOTFS_OVERLAY = "board/myboard/rootfs_overlay"
# Dizin yapısı:
board/myboard/rootfs_overlay/
├── etc/
│ ├── inittab # BusyBox inittab
│ ├── passwd # Özel kullanıcılar
│ ├── network/
│ │ └── interfaces # Ağ konfigürasyonu
│ └── init.d/
│ ├── S10syslog # Syslog başlatma
│ ├── S20network # Ağ başlatma
│ └── S99myapp # Uygulama başlatma
├── usr/
│ └── bin/
│ └── myapp # Özel binary
└── lib/
└── firmware/ # Aygıt yazılımı dosyaları
Buildroot BusyBox build
cd buildroot
# ARM platformu için (örn. Cortex-A9):
make qemu_arm_vexpress_defconfig
make menuconfig
# Target → ARM Cortex-A9
# Toolchain → musl
# System → Init: BusyBox
make -j$(nproc) 2>&1 | tee build.log
# Çıktılar:
# output/images/rootfs.ext2 — ext2 rootfs imajı
# output/images/rootfs.cpio.gz — cpio initramfs
# output/images/zImage — kernel
# output/images/vexpress-v2p-ca9.dtb — DTB
07 BusyBox networking
BusyBox, tam teşekküllü ağ araçları ve daemon'ları barındırır. udhcpc DHCP istemcisinden httpd web sunucusuna kadar gömülü ağ uygulamaları için eksiksiz bir set sunar.
Temel ağ araçları
# Ağ arayüzü yapılandırma
ifconfig eth0 192.168.1.100 netmask 255.255.255.0
ifconfig eth0 up
ip addr add 192.168.1.100/24 dev eth0
ip route add default via 192.168.1.1
# DNS
echo "nameserver 8.8.8.8" > /etc/resolv.conf
# Bağlantı testi
ping -c 4 192.168.1.1
ping6 -c 4 fe80::1%eth0
# Port tarama / bağlantı testi (nc = netcat)
nc -vz 192.168.1.1 80 # TCP bağlantı testi
nc -l -p 8080 # Dinleyici başlat
echo "GET / HTTP/1.0" | nc example.com 80 # HTTP isteği
udhcpc DHCP istemcisi
# Basit kullanım:
udhcpc -i eth0
# Script ile (tam konfigürasyon):
udhcpc -i eth0 -s /etc/udhcpc/default.script -b -p /run/udhcpc.pid
#!/bin/sh
# /etc/udhcpc/default.script — udhcpc lease callback
case "$1" in
deconfig)
ip addr flush dev $interface
ip route flush dev $interface
;;
bound|renew)
ip addr add $ip/$mask dev $interface
ip route add default via $router dev $interface
# DNS ayarla
echo "" > /etc/resolv.conf
for dns in $dns; do
echo "nameserver $dns" >> /etc/resolv.conf
done
echo "DHCP lease alındı: $ip/$mask gw=$router"
;;
leasefail|nak)
echo "DHCP başarısız — statik IP dene"
ip addr add 169.254.1.1/16 dev $interface # link-local fallback
;;
esac
BusyBox httpd web sunucusu
# /www/index.html hazırla
mkdir -p /www
cat > /www/index.html << 'EOF'
<html><body>
<h1>Gömülü Cihaz</h1>
<p>Uptime: <b>$(uptime)</b></p>
</body></html>
EOF
# httpd başlat (port 80, /www dizininden sun):
httpd -p 80 -h /www
# CGI desteği:
mkdir -p /www/cgi-bin
cat > /www/cgi-bin/status.sh << 'EOF'
#!/bin/sh
echo "Content-Type: text/plain"
echo ""
echo "=== CPU ==="
cat /proc/cpuinfo | grep "model name" | head -1
echo "=== Bellek ==="
free -m
echo "=== Disk ==="
df -h
EOF
chmod +x /www/cgi-bin/status.sh
udhcpd DHCP sunucusu
# /etc/udhcpd.conf
start 192.168.2.100
end 192.168.2.200
interface eth0
max_leases 100
opt subnet 255.255.255.0
opt router 192.168.2.1
opt dns 8.8.8.8 8.8.4.4
opt lease 86400
# Başlatma:
udhcpd /etc/udhcpd.conf
08 Pratik: 2MB minimal rootfs
Bu bölümde BusyBox static binary + Linux kernel + initramfs kombinasyonuyla QEMU'da çalışan ~2MB'lık bir gömülü Linux sistemi oluşturacağız.
Boyut hedefleri
| Bileşen | Hedef boyut | Teknik |
|---|---|---|
| BusyBox (ARM64 musl static) | ~400 KB | strip + LTO, minimal applet seçimi |
| Konfigürasyon dosyaları (/etc) | ~10 KB | sadece zorunlular |
| Dizin yapısı | ~0 KB | sembolik linkler yer kaplamaz |
| initramfs.cpio.gz (sıkıştırılmış) | ~500 KB | gzip -9 |
| Linux kernel (ARM64, minimal) | ~1.5 MB | tinyconfig + gerekli sürücüler |
| Toplam | ~2 MB |
Adım adım minimal sistem
#!/bin/bash
# build_minimal.sh — 2MB gömülü Linux sistemi
set -e
WORK=$(pwd)/minimal_system
CROSS=aarch64-linux-musl-
mkdir -p $WORK && cd $WORK
# ─── 1. BusyBox ───────────────────────────────────────
wget -q https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar xf busybox-1.36.1.tar.bz2
cd busybox-1.36.1
make CROSS_COMPILE=$CROSS ARCH=arm64 defconfig
# Zorunlu optimizasyonlar:
scripts/config --enable CONFIG_STATIC
scripts/config --enable CONFIG_STATIC_LIBGCC
scripts/config --disable CONFIG_DEBUG_OPTIMIZATIONS
scripts/config --enable CONFIG_LTO
# Gereksiz applet'leri kapat:
scripts/config --disable CONFIG_FEATURE_VI_REGEX
scripts/config --disable CONFIG_BC
scripts/config --disable CONFIG_DC
scripts/config --disable CONFIG_HUSH
scripts/config --set-str CONFIG_DEFAULT_SHELL ash
make CROSS_COMPILE=$CROSS ARCH=arm64 olddefconfig
make CROSS_COMPILE=$CROSS ARCH=arm64 -j$(nproc)
${CROSS}strip --strip-all busybox
BUSYBOX_SIZE=$(stat -c%s busybox)
echo "BusyBox boyutu: $((BUSYBOX_SIZE / 1024)) KB"
make CROSS_COMPILE=$CROSS ARCH=arm64 install \
CONFIG_PREFIX=$WORK/rootfs
cd $WORK
# ─── 2. rootfs yapısı ─────────────────────────────────
for d in proc sys dev tmp run mnt var/log; do
mkdir -p rootfs/$d
done
# inittab
cat > rootfs/etc/inittab << 'EOF'
::sysinit:/etc/init.d/rcS
::respawn:/sbin/getty -L ttyAMA0 115200 vt100
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
EOF
mkdir -p rootfs/etc/init.d
cat > rootfs/etc/init.d/rcS << 'EOF'
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev 2>/dev/null || mdev -s
echo /sbin/mdev > /proc/sys/kernel/hotplug
mount -t tmpfs tmpfs /tmp -o size=16m
ifconfig lo up
echo "Minimal Linux hazir — BusyBox ile calisiyor"
EOF
chmod +x rootfs/etc/init.d/rcS
echo "root::0:0:root:/root:/bin/sh" > rootfs/etc/passwd
echo "root:x:0:" > rootfs/etc/group
# ─── 3. cpio initramfs ────────────────────────────────
cd rootfs
find . | cpio -o -H newc | gzip -9 > ../initramfs.cpio.gz
cd ..
echo "initramfs boyutu: $(du -sh initramfs.cpio.gz | cut -f1)"
# ─── 4. QEMU ile test ─────────────────────────────────
echo "QEMU başlatılıyor..."
qemu-system-aarch64 \
-machine virt \
-cpu cortex-a57 \
-m 128M \
-kernel /path/to/linux/arch/arm64/boot/Image \
-initrd initramfs.cpio.gz \
-append "console=ttyAMA0 rdinit=/sbin/init" \
-nographic \
-no-reboot
Minimal kernel konfigürasyonu
# ARM64 için tinyconfig + gömülü gereksinimler
cd linux
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- tinyconfig
# Zorunlu eklemeler:
scripts/config --enable CONFIG_TTY
scripts/config --enable CONFIG_SERIAL_AMBA_PL011
scripts/config --enable CONFIG_SERIAL_AMBA_PL011_CONSOLE
scripts/config --enable CONFIG_BINFMT_ELF
scripts/config --enable CONFIG_BINFMT_SCRIPT
scripts/config --enable CONFIG_PROC_FS
scripts/config --enable CONFIG_SYSFS
scripts/config --enable CONFIG_TMPFS
scripts/config --enable CONFIG_DEVTMPFS
scripts/config --enable CONFIG_INITRAMFS_SOURCE
scripts/config --set-str CONFIG_INITRAMFS_SOURCE "$(pwd)/../minimal_system/initramfs.cpio.gz"
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- olddefconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc)
ls -lh arch/arm64/boot/Image
Kernel binary'sinin içine initramfs gömülürse (CONFIG_INITRAMFS_SOURCE), tek bir Image dosyası yeterli olur — ayrıca initrd parametresi vermek gerekmez. Bu yaklaşım, çok kısıtlı ortamlarda (örn. basit TFTP boot) işi basitleştirir ancak her initramfs değişikliğinde kernel yeniden derlenmek zorundadır.