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