关键词:buysbox、applet等。

busybox常用于嵌入式环境,集成中断Linux命令和工具。这些工具简单高效。

下面从如下方面了解:

  • 这些命令是一个软链接到busybox,那么是如何从软连接到busybox再到执行相应的功能的?
  • 如何添加自己的applet命令,进而扩展busybox?
  • 以及一个applet是如何嵌入到busybox环境的。

1. 如何从软链接到busybox的applet调用?

在busybox环境中,调用命令比如ls,其实是指向/bin/ls -> busybox的。

那么buysbox又是如何将这个软链接对应的实际功能的呢?

int main(int argc UNUSED_PARAM, char **argv)
{
...
#if defined(SINGLE_APPLET_MAIN)
...
#else lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv));
# if !ENABLE_BUSYBOX
if (argv[] && is_prefixed_with(bb_basename(argv[]), "busybox"))
argv++;
# endif
applet_name = argv[];
if (applet_name[] == '-')
applet_name++;
applet_name = bb_basename(applet_name);
parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */run_applet_and_exit(applet_name, argv);
#endif
} static NORETURN void run_applet_and_exit(const char *name, char **argv)
{
# if ENABLE_BUSYBOX
if (is_prefixed_with(name, "busybox"))
exit(busybox_main(argv));--------------------------------显示busybox帮助信息、applet列表等。
# endif
# if NUM_APPLETS >
/* find_applet_by_name() search is more expensive, so goes second */
{
int applet = find_applet_by_name(name);------------------根据applet的name找到其在applet_main[]中的序号。
if (applet >= )
run_applet_no_and_exit(applet, name, argv);
}
# endif
...
} static int busybox_main(char **argv)
{
if (!argv[]) {-----------------------------------------------只有busybox情况下,显示帮助信息。
/* Called without arguments */
...
} if (is_prefixed_with(argv[], "--list")) {---------------------busybox --list显示busybox所有applet。
...
}
...
if (strcmp(argv[], "--help") == ) {--------------------------busybox --help显示busybox帮助信息。
/* "busybox --help [<applet>]" */
if (!argv[])
goto help;
/* convert to "<applet> --help" */
argv[] = argv[];
argv[] = NULL;
} else {
/* "busybox <applet> arg1 arg2 ..." */
argv++;
}
/* We support "busybox /a/path/to/applet args..." too. Allows for
* "#!/bin/busybox"-style wrappers */
applet_name = bb_get_last_path_component_nostrip(argv[]);
run_applet_and_exit(applet_name, argv);-----------------------类似于执行busybox ls,然后调用ls applet。
} void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **argv)
{
...
if (
# if defined APPLET_NO_test
&& applet_no != APPLET_NO_test
# endif
# if defined APPLET_NO_true
&& applet_no != APPLET_NO_true
# endif
# if defined APPLET_NO_false
&& applet_no != APPLET_NO_false
# endif
) {
if (argc == && strcmp(argv[], "--help") == ) {-------如果是applet对应的--help。
/* Make "foo --help" exit with 0: */
xfunc_error_retval = ;
bb_show_usage();
}
}
if (ENABLE_FEATURE_SUID)
check_suid(applet_no);
xfunc_error_retval =applet_main[applet_no](argc, argv);-----根据applet_no好找到对应的函数,比如ls对应ls_main()。
/* Note: applet_main() may also not return (die on a xfunc or such) */
xfunc_die();
} void FAST_FUNC bb_show_usage(void)
{
if (ENABLE_SHOW_USAGE) {
#ifdef SINGLE_APPLET_STR
...
#else
const char *p;
const char *usage_string = p = unpack_usage_messages();
int ap = find_applet_by_name(applet_name);---------------根据全局变量applet_name找到对应的序号,然后根据需要找到对应的usage字符串。 if (ap < ) /* never happens, paranoia */
xfunc_die();
while (ap) {
while (*p++) continue;
ap--;
}
...
}
xfunc_die();
}

2. 如何添加applet

若需要添加自己的applet,比如在miscutils下创建一个monitor.c文件,在include创建一个monitor.h文件。

//config:config MONITOR-----------------------------------------------------Config.src会读取下面内容写入到Config.in中,用于配置monitor功能。
//config: bool "monitor"
//config: default n
//config: select PLATFORM_LINUX
//config: help
//config: Monitor will collect system exception, daemon corruption, critical app exit. //applet:IF_MONITOR(APPLET(monitor, BB_DIR_SBIN, BB_SUID_DROP))--------------此句会写入include/applets.h中,等于是声明了monitor_main()函数。 //kbuild:lib-$(CONFIG_MONITOR) += monitor.o----------------------------------经由Kbuild.src生成写入到Kbuild中,是对是否编译monitor.c的控制。 //usage:#define monitor_trivial_usage----------------------------------------写入到include/usage.h中,是monitor的帮助信息。
//usage: "[-q] [-o OFF] [-f FREQ] [-p TCONST] [-t TICK]"
//usage:#define monitor_full_usage "\n\n"
//usage: "Monitor system or app exception.\n"
//usage: "\n -q Quiet" #include "libbb.h"
#include <syslog.h>
#include <sys/un.h>

上面的config/applet/kbuild/usage,分别生成到miscutils/Config.in、include/applets.h、miscutils/Kbuild、include/usage.h四个文件中。

所以在配置了CONFIG_MONITOR之后,根据miscutils/Kbuild会编译monitor.c,入口函数是monitor_main()。

3. applet是如何嵌入到busybox的?

通过applets/applet_tables.c生成可执行文件applet_tables。

applets/Kbuild中执行cmd_gen_applet_tables = applets/applet_tables include/applet_tables.h include/NUM_APPLETS.h,生成applet_tables.h文件,以及applet总数的NUM_APPLETS定义。

#define NUM_APPLETS 260
#define KNOWN_APPNAME_OFFSETS 8 const uint16_t applet_nameofs[] ALIGN2 = {
,
,
,
,
,
,
,
}; const char applet_names[] ALIGN1 = ""--------------------------------------在find_applet_by_name()等函数中根据applet名称找到applet对应序号。
"[" "\0"
"[[" "\0"
"addgroup" "\0"
"adduser" "\0"
...
"zcat" "\0"
; #define APPLET_NO_addgroup 2
#define APPLET_NO_adduser 3
...
#define APPLET_NO_zcat 259 #ifndef SKIP_applet_main
int (*const applet_main[])(int argc, char **argv) = {---------------------根据applet序号,找到对应的入口函数。
test_main,
test_main,
addgroup_main,
adduser_main,
...
gunzip_main,
};
#endif const uint8_t applet_suid[] ALIGN1 = {
0x00,
0x00,
...0x00,
}; const uint8_t applet_install_loc[] ALIGN1 = {
0x33,
0x44,
...0x13,
};

其他生成文件还包括:usage.h、applets.h等。

usage.h中包含了函数的帮助信息,是由usage.c编译的usage生成的。

#define monitor_trivial_usage \
"[-q] [-o OFF] [-f FREQ] [-p TCONST] [-t TICK]" \ #define monitor_full_usage "\n\n" \
"Monitor system or app exception.\n" \
"\n -q Quiet" \

4. 小结

一个是添加applet的路径,新增.c和.h文件,其中最重要的是.c文件中特殊注释:config:、applet:、kbuild:、usage:。

然后busybox编译系统,解析.c中的注释,并将其添加到include/applets.h、include/usage.h、include/applet_tables.h等文件中。

两一个是applet的执行路径,busybox的入口函数mian()根据传入的applet_name,然后通过find_applet_by_name()找到对应序号,然后执行applet_main[]函数。即完成对applet的调用。

参考文档:《扩充BusyBox,追加Applet的方法》、《如何向busybox添加自己的命令》。

向busybox中添加自己的applet的更多相关文章

  1. [转]busybox中telnet 功能添加

    使用busybox制作的一个基本根文件系统如何添加telnetd服务呢? 下面把本人的添加过程列出来供大家分享,如有不同意见请不吝赐教! 1. 添加telnet的支持(busybox中配置) Netw ...

  2. 在jekyll模板博客中添加网易云模块

    最近使用GitHub Pages + Jekyll 搭建了个人博客,作为一名重度音乐患者,博客里面可以不配图,但是不能不配音乐啊. 遂在博客里面引入了网易云模块,这里要感谢网易云的分享机制,对开发者非 ...

  3. 在Linux(Luna)下向Launch启动器中添加图标

    记录下在Luna下向Launch中添加图标的步骤,以供以后参考,这里我以加入eclipse图标为例: 首先,我们来创建一个desktop文件(Luna中到启动器Launch可以看作是Ubuntu中到桌 ...

  4. 用Retrofit发送请求中添加身份验证

    用Retrofit发送请求中添加身份验证====================在安卓应用开发中, retrofit可以极大的方便发送http网络请求,不管是GET, POST, 还是PUT, DEL ...

  5. 在html中添加script脚本的方法和注意事项

    在html中添加script脚本有两种方法,直接将javascript代码添加到html中与添加外部js文件,这两种方法都比较常用,大家可以根据自己需要自由选择 在html中添加<script& ...

  6. MVC学习随笔----如何在页面中添加JS和CSS文件

    http://blog.csdn.net/xxjoy_777/article/details/39050011 1.如何在页面中添加Js和CSS文件. 我们只需要在模板页中添加JS和CSS文件,然后子 ...

  7. 怎样在Windows资源管理器中添加右键菜单以及修改右键菜单顺序

    有时,我们需要在Windows资源管理器的右键菜单中添加一些项,以方便使用某些功能或程序. 比如我的电脑上有一个免安装版的Notepad++,我想在所有文件的右键菜单中添加一项用Notepad++打开 ...

  8. 在WebStorm环境中给nodejs项目中添加packages

    照前文 http://www.cnblogs.com/wtang/articles/4133820.html  给电脑设置了WebStorm的IDE的nodejs开发环境.新建了个express的网站 ...

  9. dotnet webapi 中添加Swagger文档

    首先添加"SwaggerGenerator": "1.1.0","SwaggerUi": "1.1.0" 需要注意的是这 ...

随机推荐

  1. Android进程管理机制研究

    一.Linux中的进程管理在Linux中,进程是指处理器上执行的一个实例,可使用任意资源以便完成它的任务,具体的进程管理,是通过“进程描述符”来完成的,对应Linux内核中的task_struct数据 ...

  2. 05-深入python的set和dict

    一.深入python的set和dict 1.1.dict的abc继承关系 from collections.abc import Mapping,MutableMapping #dict属于mappi ...

  3. Java之封装与访问权限控制(二)

    目录 Java之封装与访问权限控制(二) 包:库单元 import import static Java常用包 Java之封装与访问权限控制(二) 访问权限控制是具体实现的隐藏,是封装性的一部分体现. ...

  4. CSS(2)---css字体、文本样式属性

    css字体.文本样式属性 这篇主要讲CSS文本属性中的:字体样式属性 和 文本样式属性. 一.字体样式属性 CSS 字体属性主要包括:字体设置(font-family).字号大小(font-size) ...

  5. 剑指offer笔记面试题5----替换空格

    题目:请实现一个函数,把字符串中的每个空格替换成"20%".例如,输入"We are happy."则输出"We%20are%20happy.&quo ...

  6. 性能调优 -- TPS&QPS

    无论在工作中,还是看一些技术文章的时候,经常听到TPS.QPS这两个术语,那么两者分别是什么?又有哪些区别? QPS:query per second,是指单位时间内请求的数量. TPS:表示一个事务 ...

  7. linux中的交换分区(swap)及优化

    SWAP(交换内存) 1.什么是交换内存? 在硬盘上创建一块区域,当你的物理内存快要被用光的时候,内核临时的 物理内存上的文件数据交换到硬盘上的这段区域上面,当物理内存有闲置的时候 在把交换内存上的数 ...

  8. robotframework框架 - 利用RequestsLibrary关键字轻松实现接口自动化!

    robotframework(后续简称为robot)是一款自动化测试框架,可能做各种类型的自动化测试. 本文介绍通过robotframework来做接口测试. 第一步:安装第三方库,提供接口测试的关键 ...

  9. 由随机数rand5实现随机数rand7

    rand5表示生成随机数1,2,3,4,5 rand7表示生成随机数1,2,3,4,5,6,7 要通过rand5构造rand7现在可能没有什么思路,我们先试着用rand7生成rand5 rand7生成 ...

  10. JavaScript-----7.循环

    1.循环 在JS中主要有以下三种类型的循环 for循环 while循环 do...while循环 2. for循环 2.1 语法结构如下: for (初始化变量: 条件表达式: 操作表达式) { // ...