blob: ef911a43b36dd6893f4f3c422fa93fa19b382c61
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * Applet table generator. |
4 | * Runs on host and produces include/applet_tables.h |
5 | * |
6 | * Copyright (C) 2007 Denys Vlasenko <vda.linux@googlemail.com> |
7 | * |
8 | * Licensed under GPLv2, see file LICENSE in this source tree. |
9 | */ |
10 | #include <sys/types.h> |
11 | #include <sys/stat.h> |
12 | #include <fcntl.h> |
13 | #include <stdlib.h> |
14 | #include <string.h> |
15 | #include <stdio.h> |
16 | #include <unistd.h> |
17 | #include <ctype.h> |
18 | |
19 | #undef ARRAY_SIZE |
20 | #define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0]))) |
21 | |
22 | #include "../include/autoconf.h" |
23 | #include "../include/applet_metadata.h" |
24 | |
25 | struct bb_applet { |
26 | const char *name; |
27 | const char *main; |
28 | enum bb_install_loc_t install_loc; |
29 | enum bb_suid_t need_suid; |
30 | /* true if instead of fork(); exec("applet"); waitpid(); |
31 | * one can do fork(); exit(applet_main(argc,argv)); waitpid(); */ |
32 | unsigned char noexec; |
33 | /* Even nicer */ |
34 | /* true if instead of fork(); exec("applet"); waitpid(); |
35 | * one can simply call applet_main(argc,argv); */ |
36 | unsigned char nofork; |
37 | }; |
38 | |
39 | /* Define struct bb_applet applets[] */ |
40 | #include "../include/applets.h" |
41 | |
42 | enum { NUM_APPLETS = ARRAY_SIZE(applets) }; |
43 | |
44 | static int cmp_name(const void *a, const void *b) |
45 | { |
46 | const struct bb_applet *aa = a; |
47 | const struct bb_applet *bb = b; |
48 | return strcmp(aa->name, bb->name); |
49 | } |
50 | |
51 | static int str_isalnum_(const char *s) |
52 | { |
53 | while (*s) { |
54 | if (!isalnum(*s) && *s != '_') |
55 | return 0; |
56 | s++; |
57 | } |
58 | return 1; |
59 | } |
60 | |
61 | int main(int argc, char **argv) |
62 | { |
63 | int i, j; |
64 | |
65 | // In find_applet_by_name(), before linear search, narrow it down |
66 | // by looking at N "equidistant" names. With ~350 applets: |
67 | // KNOWN_APPNAME_OFFSETS cycles |
68 | // 0 9057 |
69 | // 2 4604 + ~100 bytes of code |
70 | // 4 2407 + 4 bytes |
71 | // 8 1342 + 8 bytes |
72 | // 16 908 + 16 bytes |
73 | // 32 884 + 32 bytes |
74 | // With 8, int16_t applet_nameofs[] table has 7 elements. |
75 | int KNOWN_APPNAME_OFFSETS = 8; |
76 | // With 128 applets we do two linear searches, with 1..7 strcmp's in the first one |
77 | // and 1..16 strcmp's in the second. With 256 apps, second search does 1..32 strcmp's. |
78 | if (NUM_APPLETS < 128) |
79 | KNOWN_APPNAME_OFFSETS = 4; |
80 | if (NUM_APPLETS < 32) |
81 | KNOWN_APPNAME_OFFSETS = 0; |
82 | |
83 | qsort(applets, NUM_APPLETS, sizeof(applets[0]), cmp_name); |
84 | |
85 | if (!argv[1]) |
86 | return 1; |
87 | i = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT, 0666); |
88 | if (i < 0) |
89 | return 1; |
90 | dup2(i, 1); |
91 | |
92 | /* Keep in sync with include/busybox.h! */ |
93 | |
94 | printf("/* This is a generated file, don't edit */\n\n"); |
95 | |
96 | printf("#define NUM_APPLETS %u\n", NUM_APPLETS); |
97 | if (NUM_APPLETS == 1) { |
98 | printf("#define SINGLE_APPLET_STR \"%s\"\n", applets[0].name); |
99 | printf("#define SINGLE_APPLET_MAIN %s_main\n", applets[0].main); |
100 | } |
101 | |
102 | printf("#define KNOWN_APPNAME_OFFSETS %u\n\n", KNOWN_APPNAME_OFFSETS); |
103 | if (KNOWN_APPNAME_OFFSETS > 0) { |
104 | int ofs, offset[KNOWN_APPNAME_OFFSETS], index[KNOWN_APPNAME_OFFSETS]; |
105 | for (i = 0; i < KNOWN_APPNAME_OFFSETS; i++) |
106 | index[i] = i * NUM_APPLETS / KNOWN_APPNAME_OFFSETS; |
107 | ofs = 0; |
108 | for (i = 0; i < NUM_APPLETS; i++) { |
109 | for (j = 0; j < KNOWN_APPNAME_OFFSETS; j++) |
110 | if (i == index[j]) |
111 | offset[j] = ofs; |
112 | ofs += strlen(applets[i].name) + 1; |
113 | } |
114 | /* If the list of names is too long refuse to proceed */ |
115 | if (ofs > 0xffff) |
116 | return 1; |
117 | printf("const uint16_t applet_nameofs[] ALIGN2 = {\n"); |
118 | for (i = 1; i < KNOWN_APPNAME_OFFSETS; i++) |
119 | printf("%d,\n", offset[i]); |
120 | printf("};\n\n"); |
121 | } |
122 | |
123 | //printf("#ifndef SKIP_definitions\n"); |
124 | printf("const char applet_names[] ALIGN1 = \"\"\n"); |
125 | for (i = 0; i < NUM_APPLETS; i++) { |
126 | printf("\"%s\" \"\\0\"\n", applets[i].name); |
127 | // if (MAX_APPLET_NAME_LEN < strlen(applets[i].name)) |
128 | // MAX_APPLET_NAME_LEN = strlen(applets[i].name); |
129 | } |
130 | printf(";\n\n"); |
131 | |
132 | for (i = 0; i < NUM_APPLETS; i++) { |
133 | if (str_isalnum_(applets[i].name)) |
134 | printf("#define APPLET_NO_%s %d\n", applets[i].name, i); |
135 | } |
136 | printf("\n"); |
137 | |
138 | printf("#ifndef SKIP_applet_main\n"); |
139 | printf("int (*const applet_main[])(int argc, char **argv) = {\n"); |
140 | for (i = 0; i < NUM_APPLETS; i++) { |
141 | printf("%s_main,\n", applets[i].main); |
142 | } |
143 | printf("};\n"); |
144 | printf("#endif\n\n"); |
145 | |
146 | #if ENABLE_FEATURE_PREFER_APPLETS \ |
147 | || ENABLE_FEATURE_SH_STANDALONE \ |
148 | || ENABLE_FEATURE_SH_NOFORK |
149 | printf("const uint8_t applet_flags[] ALIGN1 = {\n"); |
150 | i = 0; |
151 | while (i < NUM_APPLETS) { |
152 | int v = applets[i].nofork + (applets[i].noexec << 1); |
153 | if (++i < NUM_APPLETS) |
154 | v |= (applets[i].nofork + (applets[i].noexec << 1)) << 2; |
155 | if (++i < NUM_APPLETS) |
156 | v |= (applets[i].nofork + (applets[i].noexec << 1)) << 4; |
157 | if (++i < NUM_APPLETS) |
158 | v |= (applets[i].nofork + (applets[i].noexec << 1)) << 6; |
159 | printf("0x%02x,\n", v); |
160 | i++; |
161 | } |
162 | printf("};\n\n"); |
163 | #endif |
164 | |
165 | #if ENABLE_FEATURE_SUID |
166 | printf("const uint8_t applet_suid[] ALIGN1 = {\n"); |
167 | i = 0; |
168 | while (i < NUM_APPLETS) { |
169 | int v = applets[i].need_suid; /* 2 bits */ |
170 | if (++i < NUM_APPLETS) |
171 | v |= applets[i].need_suid << 2; |
172 | if (++i < NUM_APPLETS) |
173 | v |= applets[i].need_suid << 4; |
174 | if (++i < NUM_APPLETS) |
175 | v |= applets[i].need_suid << 6; |
176 | printf("0x%02x,\n", v); |
177 | i++; |
178 | } |
179 | printf("};\n\n"); |
180 | #endif |
181 | |
182 | #if ENABLE_FEATURE_INSTALLER |
183 | printf("const uint8_t applet_install_loc[] ALIGN1 = {\n"); |
184 | i = 0; |
185 | while (i < NUM_APPLETS) { |
186 | int v = applets[i].install_loc; /* 3 bits */ |
187 | if (++i < NUM_APPLETS) |
188 | v |= applets[i].install_loc << 4; /* 3 bits */ |
189 | printf("0x%02x,\n", v); |
190 | i++; |
191 | } |
192 | printf("};\n"); |
193 | #endif |
194 | //printf("#endif /* SKIP_definitions */\n"); |
195 | |
196 | // printf("\n"); |
197 | // printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN); |
198 | |
199 | if (argv[2]) { |
200 | FILE *fp; |
201 | char line_new[80]; |
202 | // char line_old[80]; |
203 | |
204 | sprintf(line_new, "#define NUM_APPLETS %u\n", NUM_APPLETS); |
205 | // line_old[0] = 0; |
206 | // fp = fopen(argv[2], "r"); |
207 | // if (fp) { |
208 | // fgets(line_old, sizeof(line_old), fp); |
209 | // fclose(fp); |
210 | // } |
211 | // if (strcmp(line_old, line_new) != 0) { |
212 | fp = fopen(argv[2], "w"); |
213 | if (!fp) |
214 | return 1; |
215 | fputs(line_new, fp); |
216 | // } |
217 | } |
218 | |
219 | return 0; |
220 | } |
221 |