zoukankan      html  css  js  c++  java
  • Busybox 框架代码分析

    对Busybox 1.1.2版的大体框架进行了抽取,以便于看清。

      1 /*
      2 Author: 
      3 Framework of busybox
      4 
      5 A simple demo to show how busybox works
      6 
      7 complie:
      8 gcc ***.c -o busybox
      9 
     10 run:
     11 ./busybox bbtest
     12 
     13 */
     14 
     15 #include <stdlib.h>
     16 #include <stdarg.h>
     17 #include <errno.h>
     18 #include <string.h>
     19 #include <stdio.h>
     20 
     21 /*
     22 包含名字和入口地址函数的结构体
     23 */
     24 struct BB_applet
     25 {
     26    const char* name;
     27    int (*main) (int argc, char** argv);
     28 };
     29 
     30 int bbtest_main(int argc, char* argv[]);
     31 void bb_error_msg_and_die(const char *s, ...);
     32 void run_applet_by_name(const char* name,int argc,char* argv[]);
     33 static struct BB_applet* applet_using;
     34 char* bb_applet_name = NULL;
     35 /*
     36 结构体数组
     37 */
     38 const struct BB_applet applets[] =
     39 {
     40 #define APPLET(a,b) {#a,b}
     41    APPLET(bbtest, bbtest_main)
     42 };
     43 
     44 const size_t NUM_APPLETS = (sizeof (applets) / sizeof (struct BB_applet));
     45 
     46 int main(int argc, char** argv)
     47 {
     48    const char* s;
     49 
     50    bb_applet_name = argv[0];
     51    /*
     52    if (*bb_applet_name == '-') bb_applet_name++;
     53    */
     54 /*
     55 对类似于 “./busybox vi”
     56 的命令进行解析
     57 */
     58    for (s = bb_applet_name; *s ;)
     59        if (*(s++) == '/') bb_applet_name = s;
     60 
     61    /* Set locale for everybody except `init' */
     62    /*
     63    if(ENABLE_LOCALE_SUPPORT && getpid() != 1)
     64        setlocale(LC_ALL, "");
     65        */
     66 
     67    printf("%s\n",bb_applet_name);
     68 /*
     69 按名字找到对应的组件程序,并执行
     70 */
     71    run_applet_by_name(bb_applet_name, argc, argv);
     72    /*
     73    bb_error_msg_and_die("applet not found");
     74    */
     75 }
     76 
     77 
     78 int busybox_main(int argc, char** argv)
     79 {
     80    /*
     81     * This style of argument parsing doesn't scale well
     82     * in the event that busybox starts wanting more --options.
     83     * If someone has a cleaner approach, by all means implement it.
     84     */
     85    /*
     86    if (ENABLE_FEATURE_INSTALLER && argc > 1 && !strcmp(argv[1], "--install")) {
     87        int use_symbolic_links = 0;
     88        int rc = 0;
     89        char *busybox;
     90        */
     91 
     92    /* to use symlinks, or not to use symlinks... */
     93    /*
     94        if (argc > 2) {
     95            if ((strcmp(argv[2], "-s") == 0)) {
     96                use_symbolic_links = 1;
     97            }
     98        }
     99        */
    100 
    101    /* link */
    102    /*
    103        busybox = xreadlink("/proc/self/exe");
    104        if (busybox) {
    105            install_links(busybox, use_symbolic_links);
    106            free(busybox);
    107        } else {
    108            rc = 1;
    109        }
    110        return rc;
    111    }
    112    */
    113 
    114    /* Deal with --help.  (Also print help when called with no arguments) */
    115 
    116    if (argc == 1 || !strcmp(argv[1], "--help") )
    117    {
    118        if (argc > 2)
    119        {
    120            run_applet_by_name(bb_applet_name = argv[2], 2, argv);
    121        }
    122        else
    123        {
    124            const struct BB_applet* a;
    125            int col, output_width;
    126 
    127            /*
    128            if (ENABLE_FEATURE_AUTOWIDTH)
    129            {
    130            */
    131                /* Obtain the terminal width.  */
    132            /*
    133                get_terminal_width_height(0, &output_width, NULL);
    134                */
    135                /* leading tab and room to wrap */
    136            /*
    137                output_width -= 20;
    138            }
    139            else output_width = 60;
    140            */
    141 
    142 
    143            printf(/*"%s\n\n"*/
    144                   "Usage: busybox [function] [arguments]...\n"
    145                   "   or: [function] [arguments]...\n\n"
    146                   "\tBusyBox is a multi-call binary that combines many common Unix\n"
    147                   "\tutilities into a single executable.  Most people will create a\n"
    148                   "\tlink to busybox for each function they wish to use and BusyBox\n"
    149                   "\twill act like whatever it was invoked as!\n"
    150                   "\nCurrently defined functions:\n"/*, bb_msg_full_version*/);
    151            col = 0;
    152            for (a = applets; a->name;)
    153            {
    154                col += printf("%s%s", (col ? ", " : "\t"), (a++)->name);
    155                if (col > output_width && a->name)
    156                {
    157                    printf(",\n");
    158                    col = 0;
    159                }
    160            }
    161 
    162            printf("\n\n");
    163            exit(0);
    164        }
    165    }
    166    else run_applet_by_name(bb_applet_name = argv[1], argc - 1, argv + 1);
    167 
    168    bb_error_msg_and_die("applet not found");
    169 }
    170 
    171 struct BB_applet* find_applet_by_name (const char* name);
    172 void run_applet_by_name (const char* name, int argc, char** argv)
    173 {
    174    /*
    175    if(ENABLE_FEATURE_SUID_CONFIG) parse_config_file ();
    176    */
    177 /*
    178 如果命令是“./busybox vi”形式的
    179 */
    180    if (!strncmp(name, "busybox", 7)) busybox_main(argc, argv);
    181    /* Do a binary search to find the applet entry given the name. */
    182    applet_using = find_applet_by_name(name);
    183    if (applet_using)
    184    {
    185        bb_applet_name = applet_using->name;
    186        /*if (argc == 2 && !strcmp(argv[1], "--help")) bb_show_usage ();*/
    187        /*        if(ENABLE_FEATURE_SUID) check_suid (applet_using);*/
    188 /*
    189 跳转到对应的组件程序执行
    190 */
    191        exit ((*(applet_using->main)) (argc, argv));
    192    }
    193 }
    194 
    195 /*
    196 比较组件程序名字的回调函数
    197 */
    198 static int applet_name_compare (const void* x, const void* y)
    199 {
    200    const char* name = x;
    201    const struct BB_applet* applet = y;
    202 
    203    return strcmp (name, applet->name);
    204 }
    205 
    206 /*
    207 按名字进行二分查找
    208 这也是applet.h 的head中一直强调要按字符顺序来添加组件入口的原因
    209 后续版本的busybox中已经做了修改,会对组件结构体进行qsort排序
    210 */
    211 struct BB_applet* find_applet_by_name (const char* name)
    212 {
    213    return bsearch (name, applets, NUM_APPLETS, sizeof (struct BB_applet),
    214                    applet_name_compare);
    215 }
    216 
    217 /*
    218 作为测试组件的main函数
    219 */
    220 int bbtest_main(int argc, char* argv[])
    221 {
    222    printf("/***********************************************************/\n"
    223           "                  Now in bbtest!\n");
    224    return 0;
    225 }
    226 
    227 
    228 void bb_verror_msg(const char *s, va_list p)
    229 {
    230    fflush(stdout);
    231    fprintf(stderr, "%s: ", bb_applet_name);
    232    vfprintf(stderr, s, p);
    233 }
    234 
    235 int bb_default_error_retval=EXIT_FAILURE;
    236 void bb_error_msg_and_die(const char *s, ...)
    237 {
    238    va_list p;
    239 
    240    va_start(p, s);
    241    bb_verror_msg(s, p);
    242    va_end(p);
    243    putc('\n', stderr);
    244    exit(bb_default_error_retval);
    245 }

    阅读的时候遇到下面这段代码里的类似USE_TEST,USE_ADDGROUP之类的宏定义一直不理解。

    这些宏定义只有在applets.h里面出现过一次,在所有的源文件中找不到其定义,按常理是不会通过编译的。

    后来问了寝室里的大师兄才了解到,编译的时候会自动生成bb_config.h这个头文件。里面定义了这些宏定义,其实就是直接脱掉了外层的宏展开。

    (编译时提示“procps.c:15:22: error: asm/page.h: No such find.”的解决方法

    这种在编译的最开始时才生成头文件的技术是第一次遇到,果然见识还是太短了。

     1   const struct BB_applet applets[] = {
     2 # define APPLET(a,b,c,d) {#a,b,c,d},
     3 # define APPLET_NOUSAGE(a,b,c,d) {#a,b,c,d},
     4 # define APPLET_ODDNAME(a,b,c,d,e) {#a,b,c,d},
     5 #endif
     6 
     7 #ifdef CONFIG_INSTALL_NO_USR
     8 # define _BB_DIR_USR_BIN _BB_DIR_BIN
     9 # define _BB_DIR_USR_SBIN _BB_DIR_SBIN
    10 #endif
    11 
    12 
    13 USE_TEST(APPLET_NOUSAGE([, test_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
    14 USE_TEST(APPLET_NOUSAGE([[, test_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
    15 USE_ADDGROUP(APPLET(addgroup, addgroup_main, _BB_DIR_BIN, _BB_SUID_NEVER))
    16 /*
    17 .............
    18 */
    19 };
  • 相关阅读:
    如何在帮助页面添加测试工具
    如何给你的ASP.NET页面添加HelpPage
    各种序列化库的性能数据
    Quartz.NET配置
    T-SQL中只截取日期的日期部分和日期的时间部分
    sql 根据指定条件获取一个字段批量获取数据插入另外一张表字段中+MD5加密
    读取图片数据流转换成图片
    T-SQL Transact-SQL 编程
    Python 链接Mysql数据库
    c 生成随机不重复的整数序列
  • 原文地址:https://www.cnblogs.com/invisible/p/2742763.html
Copyright © 2011-2022 走看看