Busybox 简单解析
Posted johnson37
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Busybox 简单解析相关的知识,希望对你有一定的参考价值。
BusyBox 简单解析
Busybox 作为一个简易的Linux 命令集,因为其小巧简便,在Linux嵌入式系统中应该颇为广泛,人送外号瑞士军刀。
Busybox也并非将所有命令的可执行程序进行了打包,对其实现也比较感兴趣,就翻了一下源码。
Busybox 工具的使用方式有两种,一种是将命令作为一个参数传入,例如: busybox ls, 而另外一种是将对应的命令直接软连接到busybox
BusyBox 实现的核心机制
Busybox的实现依赖于两个点:
- 通过读取执行程序时传入的参数表,来进行灵活处理。因为busybox有两种使用方法,故在解析之初会查看agrv[0]是否匹配busybox,以决定是哪种调用方式。
- Busybox当中自然包含了常见Linux命令的简单实现,但并不是应用的简单打包,而是通过一个颇为庞大的函数指针列表来实现具体的函数调用,譬如说ls_main。
BusyBox 两个Structure
Note: 代码的分析基于Busybox的2.16版本
File name: applet_tables.h
const char applet_names[] ALIGN1 = ""
"[" "\0"
"[[" "\0"
"addgroup" "\0"
"adduser" "\0"
"adjtimex" "\0"
"ar" "\0"
"arp" "\0"
"arping" "\0"
"ash" "\0"
...;
int (*const applet_main[])(int argc, char **argv) = {
test_main,
test_main,
addgroup_main,
adduser_main,
adjtimex_main,
ar_main,
arp_main,
arping_main,
ash_main,
awk_main,
basename_main,
beep_main,
blkid_main,
brctl_main,
...
第一个结构体的作用在于当获取到程序传入的参数表,检查要执行的Linux命令是否在我们的applet_name当中,即查看是否在我们支持的命令集当中,如果支持,则调用第二个数组当中对应的函数指针,去完成与之相对应的Linux命令。
Code
入口位于libbb/appletlib.c
main
{
...
applet_name = bb_basename(applet_name); // Here applet_name is argv[0], 做转换的原因是考虑到路径的存在
run_applet_and_exit(applet_name, argv);
...
}
void FAST_FUNC run_applet_and_exit(const char *name, char **argv)
{
int applet = find_applet_by_name(name); // Will check applet_name table.
if (applet >= 0)
run_applet_no_and_exit(applet, argv); // ls --> Hit here.
if (!strncmp(name, "busybox", 7))
exit(busybox_main(argv)); // Busybox ls , Hit here.
}
//One easy Loop for applet_names.
int FAST_FUNC find_applet_by_name(const char *name)
{
#if NUM_APPLETS > 8
/* Do a binary search to find the applet entry given the name. */
const char *p;
p = bsearch(name, applet_names, ARRAY_SIZE(applet_main), 1, applet_name_compare);
if (!p)
return -1;
return p - applet_names;
#else
/* A version which does not pull in bsearch */
int i = 0;
const char *p = applet_names;
while (i < NUM_APPLETS) {
if (strcmp(name, p) == 0)
return i;
p += strlen(p) + 1;
i++;
}
return -1;
#endif
}
void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
{
int argc = 1;
while (argv[argc])
argc++;
/* Reinit some shared global data */
xfunc_error_retval = EXIT_FAILURE;
applet_name = APPLET_NAME(applet_no);
if (argc == 2 && strcmp(argv[1], "--help") == 0) {
/* Special case. POSIX says "test --help"
* should be no different from e.g. "test --foo". */
//TODO: just compare applet_no with APPLET_NO_test
if (!ENABLE_TEST || strcmp(applet_name, "test") != 0)
bb_show_usage();
}
if (ENABLE_FEATURE_SUID)
check_suid(applet_no);
**exit(applet_main[applet_no](argc, argv));** // Hit here, such as ls_main, cat_main.
}
/* If we were called as "busybox..." */
static int busybox_main(char **argv)
{
... some paresr work...
applet_name = bb_get_last_path_component_nostrip(argv[0]);
run_applet_and_exit(applet_name, argv);
}
以上是关于Busybox 简单解析的主要内容,如果未能解决你的问题,请参考以下文章