BusyBox 是很多标准 Linux® 工具的一个单个可执行实现。BusyBox 包含了一些简单的工具,例如 cat 和 echo,还包含了一些更大、更复杂的工具,例如 grep、find、mount 以及 telnet(不过它的选项比传统的版本要少);有些人将 BusyBox 称为 Linux 工具里的瑞士军刀。本文将探索 BusyBox 的目标,它是如何工作的,以及为什么它对于内存有限的环境来说是如此重要。

BusyBox 的诞生

BusyBox 最初是由 Bruce Perens 在 1996 年为 Debian GNU/Linux 安装盘编写的。其目标是在一张软盘上创建一个可引导的 GNU/Linux 系统,这可以用作安装盘和急救盘。一张软盘可以保存大约 1.4-1.7MB 的内容,因此这里没有多少空间留给 Linux 内核以及相关的用户应用程序使用。

BusyBox 揭露了这样一个事实:很多标准 Linux 工具都可以共享很多共同的元素。例如,很多基于文件的工具(比如grep和find)都需要在目录中搜索文件的代码。当这些工具被合并到一个可执行程序中时,它们就可以共享这些相同的元素,这样可以产生更小的可执行程序。实际上, BusyBox 可以将大约 3.5MB 的工具包装成大约 200KB 大小。这就为可引导的磁盘和使用 Linux 的嵌入式设备提供了更多功能。我们可以对 2.4 和 2.6 版本的 Linux 内核使用 BusyBox。

BusyBox 是如何工作的?

为了让一个可执行程序看起来就像是很多可执行程序一样,BusyBox 为传递给 C 的 main 函数的参数开发了一个很少使用的特性。回想一下 C 语言的 main 函数的定义如下:

清单 1. C 的 main 函数

int main( int argc, char *argv[] )

在这个定义中,argc是传递进来的参数的个数(参数数量),而argv是一个字符串数组,代表从命令行传递进来的参数(参数向量)。argv的索引 0 是从命令行调用的程序名。

清单 2 给出的这个简单 C 程序展示了 BusyBox 的调用。它只简单地打印argv向量的内容。

清单 2. BusyBox 使用 argv[0] 来确定调用哪个应用程序

// test.c

#include

int main( int argc, char *argv[] )

{

int i;

for (i = 0 ; i < argc ; i++)

{

printf("argv[%d] = %s\n", i, argv[i]);

}

return 0;

}

调用这个程序会显示所调用的第一个参数是该程序的名字。我们可以对这个可执行程序重新进行命名,此时再调用就会得到该程序的新名字。另外,我们可以创建一个到可执行程序的符号链接,在执行这个符号链接时,就可以看到这个符号链接的名字。

清单 3. 在使用新命令更新 BusyBox 之后的命令测试

$ gcc -Wall -o test test.c

$ ./test arg1 arg2

argv[0] = ./test

argv[1] = arg1

argv[2] = arg2

$ mv test newtest

$ ./newtest arg1

argv[0] = ./newtest

argv[1] = arg1

$ ln -s newtest linktest

$ ./linktest arg

argv[0] = ./linktest

argv[1] = arg

BusyBox 使用了符号链接以便使一个可执行程序看起来像很多程序一样。对于 BusyBox 中包含的每个工具来说,都会这样创建一个符号链接,这样就可以使用这些符号链接来调用 BusyBox 了。BusyBox 然后可以通过argv[0]来调用内部工具。

配置并编译 BusyBox

我们可以从 BusyBox 的 Web 站点上下载最新版本的 BusyBox(请参看参考资料一节的内容)。与大部分开放源码程序一样,它是以一个压缩的 tarball 形式发布的,我们可以使用清单 4 给出的命令将其转换成源代码树。(如果我们下载的版本不是 1.1.1,那就请在这个命令中使用适当的版本号以及特定于这个版本号的命令。)

清单 4. 展开 BusyBox

$ tar xvfz busybox-1.1.1.tar.gz

$

结果会生成一个目录,名为 busybox-1.1.1,其中包含了 BusyBox 的源代码。要编译默认的配置(其中包含了几乎所有的内容,并禁用了调试功能),请使用defconfigmake 目标:

清单 5. 编译默认的 BusyBox 配置

$ cd busybox-1.1.1$ make defconfig$ make

$

结果是一个相当大的 BusyBox 映像,不过这只是开始使用它的最简单的方法。我们可以直接调用这个新映像,这会产生一个简单的 Help 页面,里面包括当前配置的命令。要对这个映像进行测试,我们也可以对一个命令调用 BusyBox 来执行,如清单 6 所示。

清单 6. 展示 BusyBox 命令的执行和 BusyBox 中的 ash shell

$ ./busybox pwd

/usr/local/src/busybox-1.1.1

$ ./busybox ash

/usr/local/src/busybox-1.1.1

$ pwd

/usr/local/src/busybox-1.1.1

/usr/local/src/busybox-1.1.1

$ exit

$

在这个例子中,我们调用了pwd(打印工作目录)命令,使用 BusyBox 进入了ashshell,并在ash中调用了pwd。

手工配置

如果您正在构建一个具有特殊需求的嵌入式设备,那就可以手工使用menuconfigmake 目标来配置 BusyBox 的内容。如果您熟悉 Linux 内核的编译过程,就会注意到menuconfig与配置 Linux 内核的内容所使用的目标相同。实际上,它们都采用了相同的基于 ncurses 的应用程序。

使用手工配置,我们可以指定在最终的 BusyBox 映像中包含的命令。我们也可以对 BusyBox 环境进行配置,例如包括对 NSA(美国国家安全代理)的安全增强 Linux(SELinux),指定要使用的编译器(用来在嵌入式环境中进行交叉编译)以及 BusyBox 应该静态编译还是动态编译。图 1 给出了menuconfig的主界面。在这里我们应该可以看到可以为 BusyBox 配置的不同类型的应用程序(applet)。

图 1. 使用 menuconfig 配置 BusyBox

要手工配置 BusyBox,请使用下面的命令:

清单 7. 手工配置 BusyBox

$ make menuconfig

$ make

$

这为我们提供了可以调用的 BusyBox 的二进制文件。下一个步骤是围绕 BusyBox 构建一个环境,包括将标准 Linux 命令重定向到 BusyBox 二进制文件的符号链接。我们可以使用下面的命令简单地完成这个过程:

清单 8. 构建 BusyBox 环境

$ make install

$

默认情况下,这会创建一个新的本地子目录 _install,其中包含了基本的 Linux 环境。在这个根目录中,您会找到一个链接到 BusyBox 的linuxrc程序。这个linuxrc程序在构建安装盘或急救盘(允许提前进行模块化的引导)时非常有用。同样是在这个根目录中,还有一个包含操作系统二进制文件的 /sbin 子目录。还有一个包含用户二进制文件的 /bin 目录。在构建软盘发行版或嵌入式初始 RAM 磁盘时,我们可以将这个 _install 目录迁移到目标环境中。我们还可以使用 make 程序的PREFIX选项将安装目录重定向到其他位置。例如,下面的代码就使用 /tmp/newtarget 根目录来安装这些符号链接,而不是使用 ./_install 目录:

清单 9. 将符号链接安装到另外一个目录中

$ make PREFIX=/tmp/newtarget install

$

使用installmake 目标创建的符号链接都来自于 busybox.links 文件。这个文件是在编译 BusyBox 时创建的,它包含了已经配置的命令清单。在执行install时,就会检查 busybox.links 文件确定要创建的符号链接。

到 BusyBox 的命令行链接也可以使用 BusyBox 在运行时动态创建。CONFIG_FEATURE_INSTALLER选项就可以启用这个特性,在运行时可以这样执行:

清单 10. 在运行时创建命令链接

$ ./busybox --install -s

$

-s选项强制创建这些符号链接(否则就创建硬链接)。这个选项要求系统中存在 /proc 文件系统。

BusyBox 编译选项

BusyBox 包括了几个编译选项,可以帮助为我们编译和调试正确的 BusyBox。

表 1. 为 BusyBox 提供的几个 make 选项

make 目标说明

help

显示 make 选项的完整列表

defconfig

启用默认的(通用)配置

allnoconfig

禁用所有的应用程序(空配置)

allyesconfig

启用所有的应用程序(完整配置)

allbareconfig

启用所有的应用程序,但是不包括子特性

config

基于文本的配置工具

menuconfig

N-curses(基于菜单的)配置工具

all

编译 BusyBox 二进制文件和文档(./docs)

busybox

编译 BusyBox 二进制文件

clean

清除源代码树

distclean

彻底清除源代码树

sizes

显示所启用的应用程序的文本/数据大小

在定义配置时,我们只需要输入make就可以真正编译 BusyBox 二进制文件。例如,要为所有的应用程序编译 BusyBox,我们可以执行下面的命令:

清单 11. 编译 BusyBox 二进制程序

$ make allyesconfig

$ make

$

压缩 BusyBox

如果您非常关心对 BusyBox 映像的压缩,就需要记住两件事情:

永远不要编译为静态二进制文件(这会将所有需要的库都包含到映像文件中)。相反,如果我们是编译为一个共享映像,那么它会使用其他应用程序使用的库(例如/lib/libc.so.X)。

使用 uClibc 进行编译,这是一个对大小进行过优化的 C 库,它是为嵌入式系统开发的;而不要使用标准的 glibc (GNU C 库)来编译。

BusyBox 命令中支持的选项

BusyBox 中的命令并不支持所有可用选项,不过这些命令都包含了常用的选项。如果我们需要知道一个命令可以支持哪些选项,可以使用--help选项来调用这个命令,如清单 12 所示。

清单 12. 使用 --help 选项调用命令

$ ./busybox wc --help

BusyBox v1.1.1 (2006.04.09-15:27+0000) multi-call binaryUsage: wc [OPTION]... [FILE]...Print line, word, and byte counts for each FILE, and a total line ifmore than one FILE is specified. With no FILE, read standard input.Options:-cprint the byte counts-lprint the newline counts-Lprint the length of the longest line-wprint the word counts$

这些特定的数据只有在启用了CONFIG_FEATURE_VERBOSE_USAGE选项时才可以使用。如果没有这个选项,我们就无法获得这些详细数据,但是这样可以节省大约 13 KB 的空间。

向 BusyBox 中添加新命令

向 BusyBox 添加一个新命令非常简单,这是因为它具有良好定义的体系结构。第一个步骤是为新命令的源代码选择一个位置。我们要根据命令的类型(网络,shell 等)来选择位置,并与其他命令保持一致。这一点非常重要,因为这个新命令最终会在 menuconfig 的配置菜单中出现(在下面的例子中,是 Miscellaneous Utilities 菜单)。

对于这个例子来说,我将这个新命令称为newcmd,并将它放到了 ./miscutils 目录中。这个新命令的源代码如清单 13 所示。

清单 13. 集成到 BusyBox 中的新命令的源代码

#include "busybox.h"

int newcmd_main( int argc, char *argv[] )

{

int i;

printf("newcmd called:\n");

for (i = 0 ; i < argc ; i++)

{

printf("arg[%d] = %s\n", i, argv[i]);

}

return 0;

}

接下来,我们要将这个新命令的源代码添加到所选子目录中的Makefile.in中。在本例中,我更新了./miscutils/Makefile.in文件。请按照字母顺序来添加新命令,以便维持与现有命令的一致性:

清单 14. 将命令添加到 Makefile.in 中

MISCUTILS-$(CONFIG_MT) += mt.o

MISCUTILS-$(CONFIG_NEWCMD) += newcmd.o

MISCUTILS-$(CONFIG_RUNLEVEL) += runlevel.o

接下来再次更新 ./miscutils 目录中的配置文件,以便让新命令在配置过程中是可见的。这个文件名为 Config.in,新命令是按照字母顺序添加的:

清单 15. 将命令添加到 Config.in 中

config CONFIG_NEWCMD

bool "newcmd"default n

help

newcmd is a new test command.

这个结构定义了一个新配置项(通过config关键字)以及一个配置选项(CONFIG_NEWCMD)。新命令可以启用,也可以禁用,因此我们对配置的菜单属性使用了bool(Boolean)值。这个命令默认是禁用的(n表示 No),我们可以最后放上一个简短的 Help 描述。在源代码树的 ./scripts/config/Kconfig-language.txt 文件中,我们可以看到配置语法的完整文法。

接下来需要更新 ./include/applets.h 文件,使其包含这个新命令。将下面这行内容添加到这个文件中,记住要按照字母顺序。维护这个次序非常重要,否则我们的命令就会找不到。

清单 16. 将命令添加到 applets.h 中

USE_NEWCMD(APPLET(newcmd, newcmd_main, _BB_DIR_USER_BIN, _BB_SUID_NEVER))

这定义了命令名(newcmd),它在 Busybox 源代码中的函数名(newcmd_main),应该在哪里会为这个新命令创建链接(在这种情况中,它在 /usr/bin 目录中),最后这个命令是否有权设置用户 id(在本例中是 no)。

倒数第二个步骤是向 ./include/usage.h 文件中添加详细的帮助信息。正如您可以从这个文件的例子中看到的一样,使用信息可能非常详细。在本例中,我只添加了一点信息,这样就可以编译这个新命令了:

清单 17. 向 usage.h 添加帮助信息

#define newcmd_trivial_usage"None"#define newcmd_full_usage"None"

最后一个步骤是启用新命令(通过make menuconfig,然后在 Miscellaneous Utilities 菜单中启用这个选项)然后使用make来编译 BusyBox。

使用新的 BusyBox,我们可以对这个新命令进行测试,如清单 18 所示。

清单 18. 测试新命令

$ ./busybox

newcmd arg1newcmd called:

arg[0] = newcmd

arg[1] = arg1$ ./busybox newcmd --help

BusyBox v1.1.1 (2006.04.12-13:47+0000) multi-call binary

Usage: newcmd None

None

就是这样!BusyBox 开发人员开发了一个优秀但非常容易扩展的工具。

结束语

BusyBox 是为构建内存有限的嵌入式系统和基于软盘系统的一个优秀工具。BusyBox 通过将很多必需的工具放入一个可执行程序,并让它们可以共享代码中相同的部分,从而对它们的大小进行了很大程度的缩减,BusyBox 对于嵌入式系统来说是一个非常有用的工具,因此值得我们花一些时间进行探索。

面具busybox模块_【Linux技术】BusyBox详解相关推荐

  1. 交换机最多可以接几个_【技术】详解一个交换机能带动多少个网络监控摄像头?...

    原标题:[技术]详解一个交换机能带动多少个网络监控摄像头? 一个交换机能带动多少个网络监控摄像头?千兆交换机一般接200万网络摄像机能接几个?24个网络头,用一台24口百兆交换机行不行?下面就这类问题 ...

  2. GSM模块_常用AT指令详解

    基础查询命令: AT    //返回OK,表示模块串口工作正常 ATI    //查询版本,厂家,型号信息 ATE0    //返回OK,关闭回显 AT+CSQ    //查看信号强度(在20以上为稳 ...

  3. nmos导通流向_技术参数详解,MOS管知识最全收录!

    原标题:技术参数详解,MOS管知识最全收录! MOS管,即金属(Metal)-氧化物(Oxide)-半导体(Semiconductor)场效应晶体管,是一种应用场效应原理工作的半导体器件:和普通双极型 ...

  4. python远程linux服务器执行命令_基于使用paramiko执行远程linux主机命令(详解)

    paramiko是python的SSH库,可用来连接远程linux主机,然后执行linux命令或者通过SFTP传输文件. 关于使用paramiko执行远程主机命令可以找到很多参考资料了,本文在此基础上 ...

  5. centos7中ps显示的内容_值得收藏,史上最全Linux ps命令详解

    原标题:值得收藏,史上最全Linux ps命令详解 一.程序员的疑惑 大概在十多年前,我当时还是一个产品经理.由于一些工作的原因,需要向运维工程师学习一些linux常用命令. 当使用linux ps这 ...

  6. python six模块详解_对python中的six.moves模块的下载函数urlretrieve详解

    实验环境:windows 7,anaconda 3(python 3.5),tensorflow(gpu/cpu) 函数介绍:所用函数为six.moves下的urllib中的函数,调用如下urllib ...

  7. linux的ping命令含义,Linux ping命令详解

    Linux系统的ping命令是常用的网络命令,它通常用来测试与目标主机的连通性 基于IMCP协议 常见命令参数 -q 不显示任何传送封包的信息,只显示最后的结果 -n 只输出数值 -R 记录路由过程 ...

  8. 非常好的Linux编译内核详解 - -

    转载: http://blog.chinaunix.net/uid-263488-id-2138150.html 非常好的Linux编译内核详解 - - 一.内核简介  内核,是一个操作系统的核心.它 ...

  9. Android网络开发技术实战详解

    <Android网络开发技术实战详解> 基本信息 作者: 朱桂英 丛书名: Android移动开发技术丛书 出版社:电子工业出版社 ISBN:9787121173493 上架时间:2012 ...

  10. 【网络编程】Linux tcpdump命令详解---编辑中

    目录 即看即用 详细说明 简介 输出信息含义 链路层头 TCP 数据包 UDP 数据包 SMB/CIFS 解码 AFS 请求和回应 KIP AppleTalk协议 IP 数据包破碎 时间戳 反向过滤 ...

最新文章

  1. ATS和闰秒那些事儿
  2. mysql变量使用总结
  3. 排序算法(还需补充)
  4. python心得1000字-经典教材《统计学习导论》现在有了Python版
  5. win32应用程序创建流程
  6. Tornado報錯AttributeError: Unrecognized option 'port'
  7. you must reset your password using alter table
  8. Netweaver和SAP云平台的quota管理
  9. MFC关于JPG图片显示处理的几个方式
  10. js 实现 复制 功能 (zeroclipboard)
  11. ROS学习笔记四:用C++编写ROS发布与订阅
  12. finereport与finebi差别_Finereport和Finebi的区别
  13. Rect 的相关操作
  14. npm 更新依赖 / 更新库 / 更新包 的命令 | npm outdated | npm updated
  15. 20个Android游戏源码,…
  16. 关于linux中文输入法
  17. kubectl管理多个集群配置
  18. golang构建htpp服务
  19. 3. 乱石穿空,惊涛拍岸,卷起千堆雪。 2. 故垒西边,人道是,三国周郎赤壁。 4. 江山.... hai太乱了,我们来写程序排序输出到磁盘文件中
  20. pci总线定时协议_PCI总线标准及协议

热门文章

  1. 阅文年营收76.3亿:提质增效 Non-IFRS归母净利增9.6%
  2. 内部服务器错误500是什么?该如何解决?
  3. pom中parent标签使用
  4. # 单方面PING的通,我能PING通对方机子,对方机子PING不通我
  5. linux windows 设置 网卡1000m模式
  6. 从欧拉函数、欧拉定理到RSA加解密
  7. 小米抢购页面源码分析2014年03月18号
  8. pytorch实现 残差网络 ResNet18 CIFAR-10 分类 计算top1-ACC,top3-ACC
  9. Oracle-PDB资源限制
  10. 蓝牙耳机哪款性价比高?2023蓝牙耳机性价比排行