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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM