BusyBox 72 变
Posted Li-Yongjun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BusyBox 72 变相关的知识,希望对你有一定的参考价值。
BusyBox 简介
BusyBox 是一个遵循 GPL 协议、以自由软件形式发行的应用程序。Busybox 在单一的可执行文件中提供了精简的 Unix 工具集,可运行于多款 POSIX 环境的操作系统,例如 Linux(包括android)、Hurd、FreeBSD 等等。
BusyBox 之于嵌入式
由于 BusyBox 可执行文件比较小,使得它非常适用于嵌入式系统。作者将 BusyBox 称为“嵌入式 Linux 的瑞士军刀”。
BusyBox 最初是由布鲁斯·斐伦斯在 1996 年为 Debian GNU/Linux 的软盘安装编写的,其原始构想是希望在一张软盘上能放入一个引导系统,以作为急救盘和安装盘。后来它变成了嵌入式 Linux 设备和系统和 Linux 发行版安装程序的实质标准,因为每个 Linux 可执行文件需要数 KB 的空间,而集成两百多个程序的 BusyBox 可以节省大量空间。例如:Debian GNU/Linux 的安装光盘以 BusyBox 作为Shell 程序。
BusyBox 编译安装
我们可以从 BusyBox 官网下载源码,编译安装也很简单,就是 make && make install。
安装时默认会新建一个 _install 目录,然后安装进此目录。
liyongjun@Box:~/project/c/busybox-1.32.0$ ls _install/bin/ -l
总用量 1048
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 arch -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 ash -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 base64 -> busybox
-rwxr-xr-x 1 liyongjun liyongjun 1071816 10月 12 21:53 busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 cat -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 chattr -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 chgrp -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 chmod -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 chown -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 conspy -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 cp -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 cpio -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 cttyhack -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 date -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 dd -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 df -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 dmesg -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 dnsdomainname -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 dumpkmap -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 echo -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 ed -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 egrep -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 false -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 fatattr -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 fdflush -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 fgrep -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 fsync -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 getopt -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 grep -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 gunzip -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 gzip -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 hostname -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 hush -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 ionice -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 iostat -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 ipcalc -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 kbd_mode -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 kill -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 link -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 linux32 -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 linux64 -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 ln -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 login -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 ls -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 lsattr -> busybox
lrwxrwxrwx 1 liyongjun liyongjun 7 10月 12 21:53 lzop -> busybox
...
BusyBox 72 变
今天讲的重点是,为什么将 busybox 软链接成 ls,运行后就是 ls 的功能;软链接成 cat,运行后就是 cat 的功能?
我们先看看运行 busybox 有几种方式
(1)busybox <命令名>,如
busybox ls
busybox cat
(2)cp busybox <命令名>
cp busybox ls
ls
(3)ls -n busybox <命令名>
ln -n busybox ls
ls
而这三种方式最根本的差异是传递给 busybox 的 argc
argv
参数不同。
(1)busybox ls:argc = 2, argv[0] = “busybox”, argv[1] = “ls”
(2)ls:argc = 1,argv[0] = “ls”
(3)ls:argc = 1,argv[0] = “ls”
然后我们看下 busybox 是如何处理 argc
argv
的。
busybox 的入口是 appletlib.c 中的 main 函数,main 函数最终调用 run_applet_and_exit()
int main(int argc UNUSED_PARAM, char **argv)
{
...
run_applet_and_exit(applet_name, argv);
}
我们看下 run_applet_no_and_exit() 的实现
static NORETURN void run_applet_and_exit(const char *name, char **argv)
{
if (is_prefixed_with(name, "busybox")){
exit(busybox_main(/*unused:*/ 0, argv));
}
/* find_applet_by_name() search is more expensive, so goes second */
{
int applet = find_applet_by_name(name);
if (applet >= 0)
run_applet_no_and_exit(applet, name, argv);
}
exit(127);
}
其中 is_prefixed_with() 函数就是用来判断第一个参数是否为 busybox,如果是就执行 busybox_main(/*unused:*/ 0, argv)
,而在 busybox_main() 中会移除第一个参数 busybox,然后再次调用 run_applet_and_exit(),如此反复,直到第一个参数不为 busybox,然后通过 find_applet_by_name() 找到对应功能的 main 函数去执行。
举个实际的例子说明一下,例如我们运行 busybox busybox ls
,源码中函数调用关系如下:
1) main() // argv[0] = "busybox"; argv[1] = "busybox"; argv[2] = "ls";
2) run_applet_and_exit() // 判断到第一个参数为 busybox, 则调用 busybox_main()
3) busybox_main() // 去除第一层 busybox,传递给下面 busybox ls
4) run_applet_and_exit() // 判断到第一个参数为 busybox, 则调用 busybox_main()
5) busybox_main() // 去除第二层 busybox,传递给下面 ls
6) run_applet_and_exit() // 判断到第一个参数不为 busybox, 则执行 find_applet_by_name()
7) find_applet_by_name() // 找到 ls 对应的功能入口函数为 ls_main()
8) run_applet_no_and_exit() // 执行 ls_main() 然后直接退出
可以看出,前面有多少个 busybox, 就会执行多少次 3) 4) 步骤循环,直到去除前面所有的 busybox,露出真正的命令,然后去执行命令。这就是为什么我们以多种方式运行 busybox 命令,最终都能成功找到命令并运行的原因。
几种执行方式对比
- 先拷贝或软连接,然后执行
cp busybox ls
ls -n busybox ls
ls
main()
run_applet_and_exit()
run_applet_no_and_exit()
ls_main()
- busybox 加参数形式执行
busybox ls
main()
run_applet_and_exit()
busybox_main() // 剥掉一层 busybox
run_applet_and_exit()
run_applet_no_and_exit()
ls_main()
- busybox busybox ls
main()
run_applet_and_exit()
busybox_main() // 剥掉一层 busybox
run_applet_and_exit()
busybox_main() // 再剥掉一层 busybox
run_applet_and_exit()
run_applet_no_and_exit()
ls_main()
小结
以不同方式运行 busybox 会导致传递给 busybox 的 argv 参数不同,busybox ls
这种形式递给 busybox 的参数是 busybox
、ls
; 而将 busybox 拷贝成 ls,或软连接成 ls 后,再执行 ls,则传递给 busybox 的参数就只有 ls
。而 busybox 又有能力去除前面多余的 busybox
,所以使得我们使用多种形式执行命令时,busybox 能够自动地执行相应命令的功能。
以上是关于BusyBox 72 变的主要内容,如果未能解决你的问题,请参考以下文章