zoukankan      html  css  js  c++  java
  • 向busybox中添加自己的applet

    关键词: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[1] && is_prefixed_with(bb_basename(argv[0]), "busybox"))
            argv++;
    # endif
        applet_name = argv[0];
        if (applet_name[0] == '-')
            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 > 0
        /* find_applet_by_name() search is more expensive, so goes second */
        {
            int applet = find_applet_by_name(name);------------------根据applet的name找到其在applet_main[]中的序号。
            if (applet >= 0)
                run_applet_no_and_exit(applet, name, argv);
        }
    #  endif
    ...
    }
    
    static int busybox_main(char **argv)
    {
        if (!argv[1]) {-----------------------------------------------只有busybox情况下,显示帮助信息。
            /* Called without arguments */
    ...
        }
    
        if (is_prefixed_with(argv[1], "--list")) {---------------------busybox --list显示busybox所有applet。
    ...
        }
    ...
        if (strcmp(argv[1], "--help") == 0) {--------------------------busybox --help显示busybox帮助信息。
            /* "busybox --help [<applet>]" */
            if (!argv[2])
                goto help;
            /* convert to "<applet> --help" */
            argv[0] = argv[2];
            argv[2] = 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[0]);
        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 (1
    #  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 == 2 && strcmp(argv[1], "--help") == 0) {-------如果是applet对应的--help。
                /* Make "foo --help" exit with 0: */
                xfunc_error_retval = 0;
                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 < 0) /* 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 "
    
    "
    //usage:       "Monitor system or app exception.
    "
    //usage:     "
        -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 = {
    172,
    401,
    612,
    836,
    1048,
    1299,
    1514,
    };
    
    const char applet_names[] ALIGN1 = ""--------------------------------------在find_applet_by_name()等函数中根据applet名称找到applet对应序号。
    "[" ""
    "[[" ""
    "addgroup" ""
    "adduser" ""
    ...
    "zcat" ""
    ;
    
    #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 "
    
    " 
           "Monitor system or app exception.
    " 
         "
        -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添加自己的命令》。

  • 相关阅读:
    MySQLFront导入SQL文件报#1113错误解决
    LNMP1.3一键安装Linux环境,配置Nginx运行ThinkPHP3.2
    币胜网虚拟货币交易平台安装说明
    windows服务器详细安全设置
    WINDOWS SERVER 2008远程桌面端口修改方法
    mac终端ssh连接服务器 空闲的时候 连接断开
    FTP软件发送"AUTH TLS"提示 无法连接到服务器
    LNMP状态管理命令
    lnmp1.4环境FTP服务器的安装和使用
    springCloud
  • 原文地址:https://www.cnblogs.com/arnoldlu/p/10905698.html
Copyright © 2011-2022 走看看