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 };

 

posted @ 2012-10-27 20:36  strorehouse  阅读(4972)  评论(0编辑  收藏  举报