Magellan Linux

Contents of /tags/mkinitrd-6_1_11/busybox/libbb/appletlib.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 928 - (show annotations) (download)
Wed Oct 28 13:31:19 2009 UTC (14 years, 6 months ago) by niro
File MIME type: text/plain
File size: 21016 byte(s)
tagged 'mkinitrd-6_1_11'
1 /* vi: set sw=4 ts=4: */
2 /*
3 * Utility routines.
4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 *
9 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
10 * Permission has been granted to redistribute this code under the GPL.
11 *
12 * Licensed under GPLv2 or later, see file License in this tarball for details.
13 */
14
15 /* We are trying to not use printf, this benefits the case when selected
16 * applets are really simple. Example:
17 *
18 * $ ./busybox
19 * ...
20 * Currently defined functions:
21 * basename, false, true
22 *
23 * $ size busybox
24 * text data bss dec hex filename
25 * 4473 52 72 4597 11f5 busybox
26 *
27 * FEATURE_INSTALLER or FEATURE_SUID will still link printf routines in. :(
28 */
29
30 #include <assert.h>
31 #include "busybox.h"
32
33
34 /* Declare <applet>_main() */
35 #define PROTOTYPES
36 #include "applets.h"
37 #undef PROTOTYPES
38
39 #if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE
40 /* Define usage_messages[] */
41 static const char usage_messages[] ALIGN1 = ""
42 #define MAKE_USAGE
43 #include "usage.h"
44 #include "applets.h"
45 ;
46 #undef MAKE_USAGE
47 #else
48 #define usage_messages 0
49 #endif /* SHOW_USAGE */
50
51
52 /* Include generated applet names, pointers to <applet>_main, etc */
53 #include "applet_tables.h"
54 /* ...and if applet_tables generator says we have only one applet... */
55 #ifdef SINGLE_APPLET_MAIN
56 #undef ENABLE_FEATURE_INDIVIDUAL
57 #define ENABLE_FEATURE_INDIVIDUAL 1
58 #undef USE_FEATURE_INDIVIDUAL
59 #define USE_FEATURE_INDIVIDUAL(...) __VA_ARGS__
60 #endif
61
62
63 #if ENABLE_FEATURE_COMPRESS_USAGE
64
65 #include "usage_compressed.h"
66 #include "unarchive.h"
67
68 static const char *unpack_usage_messages(void)
69 {
70 char *outbuf = NULL;
71 bunzip_data *bd;
72 int i;
73
74 i = start_bunzip(&bd,
75 /* src_fd: */ -1,
76 //FIXME: can avoid storing these 2 bytes!
77 /* inbuf: */ (void *)packed_usage + 2,
78 /* len: */ sizeof(packed_usage));
79 /* read_bunzip can longjmp to start_bunzip, and ultimately
80 * end up here with i != 0 on read data errors! Not trivial */
81 if (!i) {
82 /* Cannot use xmalloc: will leak bd in NOFORK case! */
83 outbuf = malloc_or_warn(SIZEOF_usage_messages);
84 if (outbuf)
85 read_bunzip(bd, outbuf, SIZEOF_usage_messages);
86 }
87 dealloc_bunzip(bd);
88 return outbuf;
89 }
90 #define dealloc_usage_messages(s) free(s)
91
92 #else
93
94 #define unpack_usage_messages() usage_messages
95 #define dealloc_usage_messages(s) ((void)(s))
96
97 #endif /* FEATURE_COMPRESS_USAGE */
98
99
100 static void full_write2_str(const char *str)
101 {
102 full_write(STDERR_FILENO, str, strlen(str));
103 }
104
105 void FAST_FUNC bb_show_usage(void)
106 {
107 if (ENABLE_SHOW_USAGE) {
108 #ifdef SINGLE_APPLET_STR
109 /* Imagine that this applet is "true". Dont suck in printf! */
110 const char *p;
111 const char *usage_string = p = unpack_usage_messages();
112
113 if (*p == '\b') {
114 full_write2_str("\nNo help available.\n\n");
115 } else {
116 full_write2_str("\nUsage: "SINGLE_APPLET_STR" ");
117 full_write2_str(p);
118 full_write2_str("\n\n");
119 }
120 dealloc_usage_messages((char*)usage_string);
121 #else
122 const char *p;
123 const char *usage_string = p = unpack_usage_messages();
124 int ap = find_applet_by_name(applet_name);
125
126 if (ap < 0) /* never happens, paranoia */
127 xfunc_die();
128 while (ap) {
129 while (*p++) continue;
130 ap--;
131 }
132 full_write2_str(bb_banner);
133 full_write2_str(" multi-call binary\n");
134 if (*p == '\b')
135 full_write2_str("\nNo help available.\n\n");
136 else {
137 full_write2_str("\nUsage: ");
138 full_write2_str(applet_name);
139 full_write2_str(" ");
140 full_write2_str(p);
141 full_write2_str("\n\n");
142 }
143 dealloc_usage_messages((char*)usage_string);
144 #endif
145 }
146 xfunc_die();
147 }
148
149 #if NUM_APPLETS > 8
150 /* NB: any char pointer will work as well, not necessarily applet_names */
151 static int applet_name_compare(const void *name, const void *v)
152 {
153 int i = (const char *)v - applet_names;
154 return strcmp(name, APPLET_NAME(i));
155 }
156 #endif
157 int FAST_FUNC find_applet_by_name(const char *name)
158 {
159 #if NUM_APPLETS > 8
160 /* Do a binary search to find the applet entry given the name. */
161 const char *p;
162 p = bsearch(name, applet_names, ARRAY_SIZE(applet_main), 1, applet_name_compare);
163 if (!p)
164 return -1;
165 return p - applet_names;
166 #else
167 /* A version which does not pull in bsearch */
168 int i = 0;
169 const char *p = applet_names;
170 while (i < NUM_APPLETS) {
171 if (strcmp(name, p) == 0)
172 return i;
173 p += strlen(p) + 1;
174 i++;
175 }
176 return -1;
177 #endif
178 }
179
180
181 void lbb_prepare(const char *applet
182 USE_FEATURE_INDIVIDUAL(, char **argv))
183 MAIN_EXTERNALLY_VISIBLE;
184 void lbb_prepare(const char *applet
185 USE_FEATURE_INDIVIDUAL(, char **argv))
186 {
187 #ifdef __GLIBC__
188 (*(int **)&bb_errno) = __errno_location();
189 barrier();
190 #endif
191 applet_name = applet;
192
193 /* Set locale for everybody except 'init' */
194 if (ENABLE_LOCALE_SUPPORT && getpid() != 1)
195 setlocale(LC_ALL, "");
196
197 #if ENABLE_FEATURE_INDIVIDUAL
198 /* Redundant for busybox (run_applet_and_exit covers that case)
199 * but needed for "individual applet" mode */
200 if (argv[1] && !argv[2] && strcmp(argv[1], "--help") == 0) {
201 /* Special case. POSIX says "test --help"
202 * should be no different from e.g. "test --foo". */
203 if (!ENABLE_TEST || strcmp(applet_name, "test") != 0)
204 bb_show_usage();
205 }
206 #endif
207 }
208
209 /* The code below can well be in applets/applets.c, as it is used only
210 * for busybox binary, not "individual" binaries.
211 * However, keeping it here and linking it into libbusybox.so
212 * (together with remaining tiny applets/applets.o)
213 * makes it possible to avoid --whole-archive at link time.
214 * This makes (shared busybox) + libbusybox smaller.
215 * (--gc-sections would be even better....)
216 */
217
218 const char *applet_name;
219 #if !BB_MMU
220 bool re_execed;
221 #endif
222
223
224 /* If not built as a single-applet executable... */
225 #if !defined(SINGLE_APPLET_MAIN)
226
227 USE_FEATURE_SUID(static uid_t ruid;) /* real uid */
228
229 #if ENABLE_FEATURE_SUID_CONFIG
230
231 /* applets[] is const, so we have to define this "override" structure */
232 static struct BB_suid_config {
233 int m_applet;
234 uid_t m_uid;
235 gid_t m_gid;
236 mode_t m_mode;
237 struct BB_suid_config *m_next;
238 } *suid_config;
239
240 static bool suid_cfg_readable;
241
242 /* check if u is member of group g */
243 static int ingroup(uid_t u, gid_t g)
244 {
245 struct group *grp = getgrgid(g);
246
247 if (grp) {
248 char **mem;
249
250 for (mem = grp->gr_mem; *mem; mem++) {
251 struct passwd *pwd = getpwnam(*mem);
252
253 if (pwd && (pwd->pw_uid == u))
254 return 1;
255 }
256 }
257 return 0;
258 }
259
260 /* This should probably be a libbb routine. In that case,
261 * I'd probably rename it to something like bb_trimmed_slice.
262 */
263 static char *get_trimmed_slice(char *s, char *e)
264 {
265 /* First, consider the value at e to be nul and back up until we
266 * reach a non-space char. Set the char after that (possibly at
267 * the original e) to nul. */
268 while (e-- > s) {
269 if (!isspace(*e)) {
270 break;
271 }
272 }
273 e[1] = '\0';
274
275 /* Next, advance past all leading space and return a ptr to the
276 * first non-space char; possibly the terminating nul. */
277 return skip_whitespace(s);
278 }
279
280 /* Don't depend on the tools to combine strings. */
281 static const char config_file[] ALIGN1 = "/etc/busybox.conf";
282
283 /* We don't supply a value for the nul, so an index adjustment is
284 * necessary below. Also, we use unsigned short here to save some
285 * space even though these are really mode_t values. */
286 static const unsigned short mode_mask[] ALIGN2 = {
287 /* SST sst xxx --- */
288 S_ISUID, S_ISUID|S_IXUSR, S_IXUSR, 0, /* user */
289 S_ISGID, S_ISGID|S_IXGRP, S_IXGRP, 0, /* group */
290 0, S_IXOTH, S_IXOTH, 0 /* other */
291 };
292
293 #define parse_error(x) do { errmsg = x; goto pe_label; } while (0)
294
295 static void parse_config_file(void)
296 {
297 struct BB_suid_config *sct_head;
298 struct BB_suid_config *sct;
299 int applet_no;
300 FILE *f;
301 const char *errmsg;
302 char *s;
303 char *e;
304 int i;
305 unsigned lc;
306 smallint section;
307 char buffer[256];
308 struct stat st;
309
310 assert(!suid_config); /* Should be set to NULL by bss init. */
311
312 ruid = getuid();
313 if (ruid == 0) /* run by root - don't need to even read config file */
314 return;
315
316 if ((stat(config_file, &st) != 0) /* No config file? */
317 || !S_ISREG(st.st_mode) /* Not a regular file? */
318 || (st.st_uid != 0) /* Not owned by root? */
319 || (st.st_mode & (S_IWGRP | S_IWOTH)) /* Writable by non-root? */
320 || !(f = fopen_for_read(config_file)) /* Cannot open? */
321 ) {
322 return;
323 }
324
325 suid_cfg_readable = 1;
326 sct_head = NULL;
327 section = lc = 0;
328
329 while (1) {
330 s = buffer;
331
332 if (!fgets(s, sizeof(buffer), f)) { /* Are we done? */
333 // why?
334 if (ferror(f)) { /* Make sure it wasn't a read error. */
335 parse_error("reading");
336 }
337 fclose(f);
338 suid_config = sct_head; /* Success, so set the pointer. */
339 return;
340 }
341
342 lc++; /* Got a (partial) line. */
343
344 /* If a line is too long for our buffer, we consider it an error.
345 * The following test does mistreat one corner case though.
346 * If the final line of the file does not end with a newline and
347 * yet exactly fills the buffer, it will be treated as too long
348 * even though there isn't really a problem. But it isn't really
349 * worth adding code to deal with such an unlikely situation, and
350 * we do err on the side of caution. Besides, the line would be
351 * too long if it did end with a newline. */
352 if (!strchr(s, '\n') && !feof(f)) {
353 parse_error("line too long");
354 }
355
356 /* Trim leading and trailing whitespace, ignoring comments, and
357 * check if the resulting string is empty. */
358 s = get_trimmed_slice(s, strchrnul(s, '#'));
359 if (!*s) {
360 continue;
361 }
362
363 /* Check for a section header. */
364
365 if (*s == '[') {
366 /* Unlike the old code, we ignore leading and trailing
367 * whitespace for the section name. We also require that
368 * there are no stray characters after the closing bracket. */
369 e = strchr(s, ']');
370 if (!e /* Missing right bracket? */
371 || e[1] /* Trailing characters? */
372 || !*(s = get_trimmed_slice(s+1, e)) /* Missing name? */
373 ) {
374 parse_error("section header");
375 }
376 /* Right now we only have one section so just check it.
377 * If more sections are added in the future, please don't
378 * resort to cascading ifs with multiple strcasecmp calls.
379 * That kind of bloated code is all too common. A loop
380 * and a string table would be a better choice unless the
381 * number of sections is very small. */
382 if (strcasecmp(s, "SUID") == 0) {
383 section = 1;
384 continue;
385 }
386 section = -1; /* Unknown section so set to skip. */
387 continue;
388 }
389
390 /* Process sections. */
391
392 if (section == 1) { /* SUID */
393 /* Since we trimmed leading and trailing space above, we're
394 * now looking for strings of the form
395 * <key>[::space::]*=[::space::]*<value>
396 * where both key and value could contain inner whitespace. */
397
398 /* First get the key (an applet name in our case). */
399 e = strchr(s, '=');
400 if (e) {
401 s = get_trimmed_slice(s, e);
402 }
403 if (!e || !*s) { /* Missing '=' or empty key. */
404 parse_error("keyword");
405 }
406
407 /* Ok, we have an applet name. Process the rhs if this
408 * applet is currently built in and ignore it otherwise.
409 * Note: this can hide config file bugs which only pop
410 * up when the busybox configuration is changed. */
411 applet_no = find_applet_by_name(s);
412 if (applet_no >= 0) {
413 /* Note: We currently don't check for duplicates!
414 * The last config line for each applet will be the
415 * one used since we insert at the head of the list.
416 * I suppose this could be considered a feature. */
417 sct = xmalloc(sizeof(struct BB_suid_config));
418 sct->m_applet = applet_no;
419 sct->m_mode = 0;
420 sct->m_next = sct_head;
421 sct_head = sct;
422
423 /* Get the specified mode. */
424
425 e = skip_whitespace(e+1);
426
427 for (i = 0; i < 3; i++) {
428 /* There are 4 chars + 1 nul for each of user/group/other. */
429 static const char mode_chars[] ALIGN1 = "Ssx-\0" "Ssx-\0" "Ttx-";
430
431 const char *q;
432 q = strchrnul(mode_chars + 5*i, *e++);
433 if (!*q) {
434 parse_error("mode");
435 }
436 /* Adjust by -i to account for nul. */
437 sct->m_mode |= mode_mask[(q - mode_chars) - i];
438 }
439
440 /* Now get the the user/group info. */
441
442 s = skip_whitespace(e);
443
444 /* Note: we require whitespace between the mode and the
445 * user/group info. */
446 if ((s == e) || !(e = strchr(s, '.'))) {
447 parse_error("<uid>.<gid>");
448 }
449 *e++ = '\0';
450
451 /* We can't use get_ug_id here since it would exit()
452 * if a uid or gid was not found. Oh well... */
453 sct->m_uid = bb_strtoul(s, NULL, 10);
454 if (errno) {
455 struct passwd *pwd = getpwnam(s);
456 if (!pwd) {
457 parse_error("user");
458 }
459 sct->m_uid = pwd->pw_uid;
460 }
461
462 sct->m_gid = bb_strtoul(e, NULL, 10);
463 if (errno) {
464 struct group *grp;
465 grp = getgrnam(e);
466 if (!grp) {
467 parse_error("group");
468 }
469 sct->m_gid = grp->gr_gid;
470 }
471 }
472 continue;
473 }
474
475 /* Unknown sections are ignored. */
476
477 /* Encountering configuration lines prior to seeing a
478 * section header is treated as an error. This is how
479 * the old code worked, but it may not be desirable.
480 * We may want to simply ignore such lines in case they
481 * are used in some future version of busybox. */
482 if (!section) {
483 parse_error("keyword outside section");
484 }
485
486 } /* while (1) */
487
488 pe_label:
489 fprintf(stderr, "Parse error in %s, line %d: %s\n",
490 config_file, lc, errmsg);
491
492 fclose(f);
493 /* Release any allocated memory before returning. */
494 while (sct_head) {
495 sct = sct_head->m_next;
496 free(sct_head);
497 sct_head = sct;
498 }
499 }
500 #else
501 static inline void parse_config_file(void)
502 {
503 USE_FEATURE_SUID(ruid = getuid();)
504 }
505 #endif /* FEATURE_SUID_CONFIG */
506
507
508 #if ENABLE_FEATURE_SUID
509 static void check_suid(int applet_no)
510 {
511 gid_t rgid; /* real gid */
512
513 if (ruid == 0) /* set by parse_config_file() */
514 return; /* run by root - no need to check more */
515 rgid = getgid();
516
517 #if ENABLE_FEATURE_SUID_CONFIG
518 if (suid_cfg_readable) {
519 uid_t uid;
520 struct BB_suid_config *sct;
521 mode_t m;
522
523 for (sct = suid_config; sct; sct = sct->m_next) {
524 if (sct->m_applet == applet_no)
525 goto found;
526 }
527 goto check_need_suid;
528 found:
529 m = sct->m_mode;
530 if (sct->m_uid == ruid)
531 /* same uid */
532 m >>= 6;
533 else if ((sct->m_gid == rgid) || ingroup(ruid, sct->m_gid))
534 /* same group / in group */
535 m >>= 3;
536
537 if (!(m & S_IXOTH)) /* is x bit not set ? */
538 bb_error_msg_and_die("you have no permission to run this applet!");
539
540 /* _both_ sgid and group_exec have to be set for setegid */
541 if ((sct->m_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
542 rgid = sct->m_gid;
543 /* else (no setegid) we will set egid = rgid */
544
545 /* We set effective AND saved ids. If saved-id is not set
546 * like we do below, seteiud(0) can still later succeed! */
547 if (setresgid(-1, rgid, rgid))
548 bb_perror_msg_and_die("setresgid");
549
550 /* do we have to set effective uid? */
551 uid = ruid;
552 if (sct->m_mode & S_ISUID)
553 uid = sct->m_uid;
554 /* else (no seteuid) we will set euid = ruid */
555
556 if (setresuid(-1, uid, uid))
557 bb_perror_msg_and_die("setresuid");
558 return;
559 }
560 #if !ENABLE_FEATURE_SUID_CONFIG_QUIET
561 {
562 static bool onetime = 0;
563
564 if (!onetime) {
565 onetime = 1;
566 fprintf(stderr, "Using fallback suid method\n");
567 }
568 }
569 #endif
570 check_need_suid:
571 #endif
572 if (APPLET_SUID(applet_no) == _BB_SUID_ALWAYS) {
573 /* Real uid is not 0. If euid isn't 0 too, suid bit
574 * is most probably not set on our executable */
575 if (geteuid())
576 bb_error_msg_and_die("must be suid to work properly");
577 } else if (APPLET_SUID(applet_no) == _BB_SUID_NEVER) {
578 xsetgid(rgid); /* drop all privileges */
579 xsetuid(ruid);
580 }
581 }
582 #else
583 #define check_suid(x) ((void)0)
584 #endif /* FEATURE_SUID */
585
586
587 #if ENABLE_FEATURE_INSTALLER
588 /* create (sym)links for each applet */
589 static void install_links(const char *busybox, int use_symbolic_links)
590 {
591 /* directory table
592 * this should be consistent w/ the enum,
593 * busybox.h::bb_install_loc_t, or else... */
594 static const char usr_bin [] ALIGN1 = "/usr/bin";
595 static const char usr_sbin[] ALIGN1 = "/usr/sbin";
596 static const char *const install_dir[] = {
597 &usr_bin [8], /* "", equivalent to "/" for concat_path_file() */
598 &usr_bin [4], /* "/bin" */
599 &usr_sbin[4], /* "/sbin" */
600 usr_bin,
601 usr_sbin
602 };
603
604 int (*lf)(const char *, const char *);
605 char *fpc;
606 unsigned i;
607 int rc;
608
609 lf = link;
610 if (use_symbolic_links)
611 lf = symlink;
612
613 for (i = 0; i < ARRAY_SIZE(applet_main); i++) {
614 fpc = concat_path_file(
615 install_dir[APPLET_INSTALL_LOC(i)],
616 APPLET_NAME(i));
617 // debug: bb_error_msg("%slinking %s to busybox",
618 // use_symbolic_links ? "sym" : "", fpc);
619 rc = lf(busybox, fpc);
620 if (rc != 0 && errno != EEXIST) {
621 bb_simple_perror_msg(fpc);
622 }
623 free(fpc);
624 }
625 }
626 #else
627 #define install_links(x,y) ((void)0)
628 #endif /* FEATURE_INSTALLER */
629
630 /* If we were called as "busybox..." */
631 static int busybox_main(char **argv)
632 {
633 if (!argv[1]) {
634 /* Called without arguments */
635 const char *a;
636 unsigned col, output_width;
637 help:
638 output_width = 80;
639 if (ENABLE_FEATURE_AUTOWIDTH) {
640 /* Obtain the terminal width */
641 get_terminal_width_height(0, &output_width, NULL);
642 }
643 /* leading tab and room to wrap */
644 output_width -= MAX_APPLET_NAME_LEN + 8;
645
646 dup2(1, 2);
647 full_write2_str(bb_banner); /* reuse const string... */
648 full_write2_str(" multi-call binary\n"
649 "Copyright (C) 1998-2008 Erik Andersen, Rob Landley, Denys Vlasenko\n"
650 "and others. Licensed under GPLv2.\n"
651 "See source distribution for full notice.\n"
652 "\n"
653 "Usage: busybox [function] [arguments]...\n"
654 " or: function [arguments]...\n"
655 "\n"
656 "\tBusyBox is a multi-call binary that combines many common Unix\n"
657 "\tutilities into a single executable. Most people will create a\n"
658 "\tlink to busybox for each function they wish to use and BusyBox\n"
659 "\twill act like whatever it was invoked as!\n"
660 "\n"
661 "Currently defined functions:\n");
662 col = 0;
663 a = applet_names;
664 while (*a) {
665 int len;
666 if (col > output_width) {
667 full_write2_str(",\n");
668 col = 0;
669 }
670 full_write2_str(col ? ", " : "\t");
671 full_write2_str(a);
672 len = strlen(a);
673 col += len + 2;
674 a += len + 1;
675 }
676 full_write2_str("\n\n");
677 return 0;
678 }
679
680 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) {
681 const char *busybox;
682 busybox = xmalloc_readlink(bb_busybox_exec_path);
683 if (!busybox)
684 busybox = bb_busybox_exec_path;
685 /* -s makes symlinks */
686 install_links(busybox, argv[2] && strcmp(argv[2], "-s") == 0);
687 return 0;
688 }
689
690 if (strcmp(argv[1], "--help") == 0) {
691 /* "busybox --help [<applet>]" */
692 if (!argv[2])
693 goto help;
694 /* convert to "<applet> --help" */
695 argv[0] = argv[2];
696 argv[2] = NULL;
697 } else {
698 /* "busybox <applet> arg1 arg2 ..." */
699 argv++;
700 }
701 /* We support "busybox /a/path/to/applet args..." too. Allows for
702 * "#!/bin/busybox"-style wrappers */
703 applet_name = bb_get_last_path_component_nostrip(argv[0]);
704 run_applet_and_exit(applet_name, argv);
705
706 /*bb_error_msg_and_die("applet not found"); - sucks in printf */
707 full_write2_str(applet_name);
708 full_write2_str(": applet not found\n");
709 xfunc_die();
710 }
711
712 void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
713 {
714 int argc = 1;
715
716 while (argv[argc])
717 argc++;
718
719 /* Reinit some shared global data */
720 xfunc_error_retval = EXIT_FAILURE;
721
722 applet_name = APPLET_NAME(applet_no);
723 if (argc == 2 && strcmp(argv[1], "--help") == 0) {
724 /* Special case. POSIX says "test --help"
725 * should be no different from e.g. "test --foo". */
726 //TODO: just compare applet_no with APPLET_NO_test
727 if (!ENABLE_TEST || strcmp(applet_name, "test") != 0)
728 bb_show_usage();
729 }
730 if (ENABLE_FEATURE_SUID)
731 check_suid(applet_no);
732 exit(applet_main[applet_no](argc, argv));
733 }
734
735 void FAST_FUNC run_applet_and_exit(const char *name, char **argv)
736 {
737 int applet = find_applet_by_name(name);
738 if (applet >= 0)
739 run_applet_no_and_exit(applet, argv);
740 if (!strncmp(name, "busybox", 7))
741 exit(busybox_main(argv));
742 }
743
744 #endif /* !defined(SINGLE_APPLET_MAIN) */
745
746
747
748 #if ENABLE_BUILD_LIBBUSYBOX
749 int lbb_main(char **argv)
750 #else
751 int main(int argc UNUSED_PARAM, char **argv)
752 #endif
753 {
754 #if defined(SINGLE_APPLET_MAIN)
755 /* Only one applet is selected by the user! */
756 /* applet_names in this case is just "applet\0\0" */
757 lbb_prepare(applet_names USE_FEATURE_INDIVIDUAL(, argv));
758 return SINGLE_APPLET_MAIN(argc, argv);
759 #else
760 lbb_prepare("busybox" USE_FEATURE_INDIVIDUAL(, argv));
761
762 #if !BB_MMU
763 /* NOMMU re-exec trick sets high-order bit in first byte of name */
764 if (argv[0][0] & 0x80) {
765 re_execed = 1;
766 argv[0][0] &= 0x7f;
767 }
768 #endif
769 applet_name = argv[0];
770 if (applet_name[0] == '-')
771 applet_name++;
772 applet_name = bb_basename(applet_name);
773
774 parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */
775
776 run_applet_and_exit(applet_name, argv);
777
778 /*bb_error_msg_and_die("applet not found"); - sucks in printf */
779 full_write2_str(applet_name);
780 full_write2_str(": applet not found\n");
781 xfunc_die();
782 #endif
783 }