强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

BusyBox 搭建 mini rootfs 完全指南 / 第 3 章:基本用法

第 3 章:基本用法

3.1 BusyBox 命令调用机制

3.1.1 argv[0] 调度原理

BusyBox 最核心的设计在于:它通过程序名(argv[0])来决定执行哪个 Applet

调用流程:
┌──────────────────┐
│ 用户执行 /bin/ls  │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ busybox 主函数    │  → 检查 argv[0] = "ls"
│ (applets/busybox.c)│
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ 查找 Applet 表    │  → 匹配 "ls" → ls_main()
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ 执行 ls_main()    │  → 实现 ls 功能
└──────────────────┘

验证这个机制:

# 直接使用 busybox 命令
$ busybox ls -la /tmp
total 8
drwxrwxrwt 2 root root 4096 Jan  1 10:00 .
drwxr-xr-x 3 root root 4096 Jan  1 09:00 ..

# busybox 后跟 Applet 名 + 参数
$ busybox cat /etc/hostname
myhost

# 内部原理等同于
$ exec -a "ls" /bin/busybox -la /tmp

3.1.2 三种调用方式

# 方式一:通过 busybox 命令显式调用
$ busybox ls /tmp
$ busybox cat /etc/hosts
$ busybox wget -O /tmp/file http://example.com

# 方式二:通过符号链接调用(最常用)
$ ls /tmp           # /bin/ls -> /bin/busybox
$ cat /etc/hosts    # /bin/cat -> /bin/busybox

# 方式三:通过硬链接调用(不推荐,占用更多空间)
$ cp -l /bin/busybox /bin/ls

3.1.3 查看 Applet 列表

# 列出所有已编译的 Applet
$ busybox --list
[
[[
ash
awk
base64
basename
cat
chattr
...

# 带完整路径的列表
$ busybox --list-full
/usr/bin/[
/usr/bin/[[
/usr/bin/ash
/usr/bin/awk
...

# 统计 Applet 数量
$ busybox --list | wc -l
342

# 检查特定 Applet 是否存在
$ busybox --list | grep "^ls$"
ls

3.2 创建符号链接

3.2.1 手动创建

# 基本语法
$ ln -s /bin/busybox /bin/ls
$ ln -s /bin/busybox /bin/cat
$ ln -s /bin/busybox /bin/cp

# 批量创建所有 Applet 的符号链接
$ for cmd in $(busybox --list); do
    ln -s /bin/busybox /bin/$cmd
  done

# 验证
$ ls -la /bin/ | head -10
lrwxrwxrwx 1 root root    11 Jan  1 00:00 ash -> /bin/busybox
-rwxr-xr-x 1 root root 1.2M Jan  1 00:00 busybox
lrwxrwxrwx 1 root root    11 Jan  1 00:00 cat -> /bin/busybox
lrwxrwxrwx 1 root root    11 Jan  1 00:00 chmod -> /bin/busybox
lrwxrwxrwx 1 root root    11 Jan  1 00:00 cp -> /bin/busybox
...

3.2.2 使用 make install 自动创建

# 安装到指定目录(自动创建符号链接)
$ make CONFIG_PREFIX=./_install install

# 查看安装结果
$ find ./_install -type l | head -10
./_install/bin/ash
./_install/bin/awk
./_install/bin/base64
./_install/bin/basename
./_install/bin/cat
./_install/bin/chattr
./_install/bin/chgrp
./_install/bin/chmod
./_install/bin/chown
./_install/bin/cp

3.2.3 自定义安装脚本

#!/bin/bash
# install_busybox.sh - 安装 BusyBox 到目标 rootfs

BUSYBOX="./busybox"
TARGET="${1:-./rootfs}"

# 创建基本目录
mkdir -p "$TARGET"/{bin,sbin,usr/bin,usr/sbin}

# 安装 BusyBox 主二进制
install -m 755 "$BUSYBOX" "$TARGET/bin/busybox"

# 创建 bin 目录的符号链接
APPLETS_BIN="sh ash bash cat chmod chown cp date df echo grep ln ls mkdir
             mount mv ping ps pwd rm rmdir sed sh sleep tar touch umount
             vi wc wget which head tail sort uniq tr cut"

for cmd in $APPLETS_BIN; do
    ln -sf busybox "$TARGET/bin/$cmd"
done

# 创建 sbin 目录的符号链接
APPLETS_SBIN="adjtimex arp brctl depmod devmem fbsplash freeramdisk
              fsck.ext2 fsck.ext3 fsck.minix getty halt hwclock
              ifconfig ifdown ifup init insmod ip klogd loadfont
              loadkmap logread lsmod mdev modinfo modprobe
              poweroff raidautorun reboot rmmod route sysctl
              syslogd telnetd udhcpc udhcpd vconfig watchdog"

for cmd in $APPLETS_SBIN; do
    ln -sf ../bin/busybox "$TARGET/sbin/$cmd"
done

# 创建 linuxrc(initrd 场景)
ln -sf bin/busybox "$TARGET/linuxrc"

echo "Installed $(find $TARGET -type l | wc -l) symlinks"
echo "Binary size: $(ls -lh $TARGET/bin/busybox | awk '{print $5}')"

3.2.4 符号链接 vs busybox 命令

# 符号链接方式(推荐)
$ ln -s /bin/busybox /bin/ls
$ /bin/ls /tmp         # argv[0] = "/bin/ls",提取 "ls"

# busybox 命令方式(调试时有用)
$ /bin/busybox ls /tmp # argv[0] = "/bin/busybox",argv[1] = "ls"

# 区别:如果需要查看调用了哪个 Applet
$ /bin/busybox ls --help 2>&1 | head -1
BusyBox v1.36.1 (2024-01-01 10:00:00 CST) multi-call binary.

# 使用 busybox_applet_name 环境变量(调试)
$ exec -a "test" busybox ls  # argv[0]="test",找不到 Applet
busybox: applet not found

3.3 Applet 调用语法

3.3.1 标准调用格式

# 格式一:busybox <applet> [选项] [参数]
$ busybox ls -la /tmp
$ busybox wget -O /tmp/file http://example.com
$ busybox tar xzf /tmp/archive.tar.gz -C /opt

# 格式二:<applet> [选项] [参数](通过符号链接)
$ ls -la /tmp
$ wget -O /tmp/file http://example.com
$ tar xzf /tmp/archive.tar.gz -C /opt

3.3.2 多 Applet 模式

# busybox 可以一次性调用多个 Applet
$ busybox sh -c "ls -la /tmp && cat /etc/hostname"

# 使用管道组合多个 BusyBox 工具
$ busybox cat /var/log/messages | busybox grep "error" | busybox wc -l
5

# BusyBox ash 管道(与标准 Shell 一致)
$ ls /tmp | grep ".log" | wc -l

3.3.3 Applet 帮助信息

# 查看 BusyBox 总体帮助
$ busybox --help
BusyBox v1.36.1 (2024-01-01 10:00:00 CST) multi-call binary.
[...]

Currently defined functions:
        ash, awk, cat, chmod, ...

# 查看特定 Applet 的帮助
$ busybox ls --help
BusyBox v1.36.1 (2024-01-01 10:00:00 CST) multi-call binary.

Usage: ls [-1AaCxdLHRFplinsehrSXvctu] [-w WIDTH] [FILE]...

List directory contents

Options:
        -1      One column output
        -a      Include entries which start with .
        -A      Like -a, except . and ..
        -C      List by columns
        ...

# 注意:BusyBox 的 --help 输出格式统一
# 第一行:Usage: <applet> [选项] [参数]
# 第二行:简短描述
# 后续:选项说明

3.3.4 Applet 版本信息

# 查看 BusyBox 版本
$ busybox
BusyBox v1.36.1 (Ubuntu 1:1.36.1-1ubuntu1) multi-call binary.
BusyBox is copyrighted by many authors between 1998-2015.
Licensed under GPLv2. See source distribution for detailed
copyright notices.
...

# 大多数 Applet 没有独立的 --version
$ busybox cat --version 2>&1 | head -3
BusyBox v1.36.1 (2024-01-01 10:00:00 CST) multi-call binary.

Usage: cat [-nbvteA] [FILE]...

3.4 busybox.conf 配置文件

3.4.1 配置文件位置

BusyBox SUID 配置文件位于 /etc/busybox.conf

# 配置文件格式
$ cat /etc/busybox.conf
[SUID]
su = ssx root.root
mount = ssx root.root
ping = ssx root.root

3.4.2 配置项说明

# 配置文件格式
[<section>]
<applet> = <permissions> <uid>.<gid>

# 权限说明
# s = SUID bit
# x = 执行权限
# S = 允许非 root 用户执行(需 SUID)

# 示例
[SUID]
su = ssx root.root        # su 需要 SUID
mount = ssx root.root      # mount 需要 root 权限
ping = ssx root.root       # ping 需要 CAP_NET_RAW

# 普通 Applet(无 SUID)
[Regular]
ls = sx user.user
cat = sx user.user

3.4.3 启用 SUID 支持

在 menuconfig 中启用:

Settings --->
  --- Installation Options
  [*] Support for SUID/SGID handling
      /etc/busybox.conf (SUID/SGID configuration file path)

3.5 常用操作示例

3.5.1 文件操作

# 列出文件
$ ls -la /tmp
$ ls -lh /var/log/*.log

# 查看文件内容
$ cat /etc/hostname
$ head -20 /var/log/messages
$ tail -f /var/log/messages

# 文件复制/移动/删除
$ cp /etc/hosts /etc/hosts.bak
$ mv /tmp/file1 /tmp/file2
$ rm -rf /tmp/cache

# 创建目录
$ mkdir -p /tmp/test/{a,b,c}

# 创建符号链接
$ ln -sf /usr/bin/busybox /usr/local/bin/mytool

# 文件权限
$ chmod 755 /usr/local/bin/mytool
$ chown root:root /usr/local/bin/mytool

3.5.2 文本处理

# 搜索文本
$ grep -r "error" /var/log/
$ grep -i "warning" /var/log/messages

# 文本替换
$ sed -i 's/old/new/g' /etc/config.txt
$ sed -n '10,20p' /etc/passwd

# 字段提取
$ cut -d: -f1 /etc/passwd
$ awk '{print $1, $3}' /proc/cpuinfo

# 排序和去重
$ sort /tmp/list.txt | uniq
$ sort -n /tmp/numbers.txt

3.5.3 系统信息

# 系统信息
$ uname -a
Linux myhost 5.15.0 #1 SMP x86_64 GNU/Linux

$ uptime
 10:00:00 up 1 day, 2:30, load average: 0.10, 0.05, 0.01

$ free -m
              total        used        free      shared  buff/cache   available
Mem:           1024         256         512          32         256         700

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1       2.0G  1.1G  800M  58% /

# 进程信息
$ ps aux
PID   USER     COMMAND
    1 root     init
  100 root     syslogd
  101 root     klogd
  102 root     /bin/sh

# 查看内存使用
$ cat /proc/meminfo | head -5
MemTotal:        1048576 kB
MemFree:          524288 kB
MemAvailable:     720896 kB
Buffers:           32768 kB
Cached:           262144 kB

3.5.4 网络操作

# 查看网络接口
$ ifconfig
eth0      Link encap:Ethernet  HWaddr 00:11:22:33:44:55
          inet addr:192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500

# 测试网络连通性
$ ping -c 3 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=115 time=10.1 ms

# 下载文件
$ wget -O /tmp/index.html http://example.com
Connecting to example.com (93.184.216.34:80)
saving to '/tmp/index.html'
index.html           100% |*****************************|  1256  0:00:00 ETA

# DNS 查询
$ nslookup example.com
Server:    8.8.8.8
Address 1: 8.8.8.8

Name:      example.com
Address 1: 93.184.216.34

3.5.5 压缩归档

# tar 归档
$ tar czf /tmp/backup.tar.gz /etc/
$ tar xzf /tmp/backup.tar.gz -C /tmp/restore

# gzip 压缩
$ gzip /tmp/largefile.txt
$ gunzip /tmp/largefile.txt.gz

# bzip2 压缩
$ bzip2 /tmp/largefile.txt
$ bunzip2 /tmp/largefile.txt.bz2

# xz 压缩(压缩率最高)
$ xz /tmp/largefile.txt
$ unxz /tmp/largefile.txt.xz

3.6 BusyBox Shell 入门

3.6.1 ash Shell 基本用法

# 启动 ash
$ busybox sh
$ # 或
$ ash

# 基本命令执行
$ echo "Hello, BusyBox!"
Hello, BusyBox!

# 变量操作
$ NAME="World"
$ echo "Hello, $NAME!"
Hello, World!

# 环境变量
$ export PATH="/usr/local/bin:$PATH"
$ echo $PATH
/usr/local/bin:/usr/bin:/bin

3.6.2 ash 脚本执行

# 创建脚本
$ cat > /tmp/hello.sh << 'EOF'
#!/bin/sh
echo "Script started"
echo "Arguments: $@"
echo "PID: $$"
echo "Script finished"
EOF

$ chmod +x /tmp/hello.sh
$ /tmp/hello.sh arg1 arg2
Script started
Arguments: arg1 arg2
PID: 1234
Script finished

3.7 调试技巧

3.7.1 Applet 不存在时的错误

# 当 Applet 未编译时
$ busybox nonexistent
busybox: applet not found

# 检查 Applet 是否存在
$ busybox --list | grep -q "^mycommand$" && echo "exists" || echo "not found"
not found

3.7.2 查看 BusyBox 内部信息

# 查看编译配置
$ busybox --install -s    # 打印所有支持的 Applet

# 调试符号链接问题
$ ls -la $(which ls)
lrwxrwxrwx 1 root root 7 Jan  1 00:00 /bin/ls -> busybox

# 跟踪系统调用
$ strace busybox ls /tmp 2>&1 | head -20
execve("/bin/busybox", ["busybox", "ls", "/tmp"], 0x7ffc... ) = 0
brk(NULL)                               = 0x55...
...

3.7.3 性能对比测试

# 对比 BusyBox 和 GNU 工具的性能
$ time busybox find / -name "*.conf" 2>/dev/null | wc -l
156

real    0m0.125s
user    0m0.020s
sys     0m0.080s

$ time find / -name "*.conf" 2>/dev/null | wc -l
156

real    0m0.098s
user    0m0.015s
sys     0m0.065s

3.8 与 GNU 工具混用

3.8.1 PATH 优先级控制

# 场景:系统同时有 GNU 和 BusyBox 工具
# /usr/bin/ls → GNU ls
# /bin/ls → BusyBox ls (符号链接)

# 查看当前 PATH
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# 强制使用 BusyBox 版本
$ /bin/ls --help 2>&1 | head -1
BusyBox v1.36.1 (...) multi-call binary.

# 强制使用 GNU 版本
$ /usr/bin/ls --help 2>&1 | head -1
ls (GNU coreutils) 8.32

# 修改 PATH 让 BusyBox 优先
$ PATH="/bin:/usr/bin:$PATH"

# 创建 BusyBox 专用目录
$ mkdir -p /opt/busybox/bin
$ for cmd in $(busybox --list); do
    ln -s /opt/busybox/bin/busybox /opt/busybox/bin/$cmd
  done
$ PATH="/opt/busybox/bin:$PATH"

3.8.2 常见差异处理

# GNU grep 支持 -P(PCRE),BusyBox 不支持
$ grep -P '\d+' file.txt             # GNU
$ busybox grep -E '[0-9]+' file.txt  # BusyBox 替代方案

# GNU sed -i 需要空字符串参数,BusyBox 可以省略
$ sed -i'' 's/old/new/g' file        # 两者兼容的写法
$ sed -i 's/old/new/g' file          # BusyBox 也支持

# GNU ls 有 --time-style,BusyBox 没有
$ ls --time-style='+%Y-%m-%d'        # GNU 专用
$ ls -l                               # BusyBox 通用

3.9 本章小结

概念说明
argv[0] 调度BusyBox 通过程序名决定执行哪个 Applet
三种调用busybox <cmd>、符号链接、硬链接
帮助信息<cmd> --help 查看 Applet 帮助
符号链接ln -s /bin/busybox /bin/<cmd>
混用通过 PATH 控制 GNU/BusyBox 优先级

扩展阅读


上一章: 第 2 章 — 编译安装
下一章: 第 4 章 — rootfs 概念与构建