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 简单解析的主要内容,如果未能解决你的问题,请参考以下文章

BusyBox 1.28.4 发布,Unix 常用工具包

busybox浅析

什么是Busybox,简单使用

Linux下BusyBox根文件系统制作

片段(Java) | 机试题+算法思路+考点+代码解析 2023

android设备不识别awk命令,缺少busybox