Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/applets/applets.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/applets/applets.c
r821 r1770 13 13 */ 14 14 15 #include <assert.h> 15 16 #include "busybox.h" 16 #include <unistd.h> 17 #include <string.h> 18 #include <assert.h> 17 18 /* Apparently uclibc defines __GLIBC__ (compat trick?). Oh well. */ 19 #if ENABLE_STATIC && defined(__GLIBC__) && !defined(__UCLIBC__) 20 #warning Static linking against glibc produces buggy executables 21 #warning (glibc does not cope well with ld --gc-sections). 22 #warning See sources.redhat.com/bugzilla/show_bug.cgi?id=3400 23 #warning Note that glibc is unsuitable for static linking anyway. 24 #warning If you still want to do it, remove -Wl,--gc-sections 25 #warning from top-level Makefile and remove this warning. 26 #error Aborting compilation. 27 #endif 28 29 30 /* Declare <applet>_main() */ 31 #define PROTOTYPES 32 #include "applets.h" 33 #undef PROTOTYPES 19 34 20 35 #if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE 21 static const char usage_messages[] = 36 /* Define usage_messages[] */ 37 static const char usage_messages[] ALIGN1 = "" 22 38 #define MAKE_USAGE 23 39 #include "usage.h" … … 27 43 #else 28 44 #define usage_messages 0 29 #endif /* ENABLE_SHOW_USAGE */ 30 31 #undef APPLET 32 #undef APPLET_NOUSAGE 33 #undef PROTOTYPES 45 #endif /* SHOW_USAGE */ 46 47 /* Define struct bb_applet applets[] */ 34 48 #include "applets.h" 35 36 static struct BB_applet *applet_using; 37 38 /* The -1 arises because of the {0,NULL,0,-1} entry above. */ 39 const size_t NUM_APPLETS = (sizeof (applets) / sizeof (struct BB_applet) - 1); 40 41 42 #ifdef CONFIG_FEATURE_SUID_CONFIG 43 44 #include <ctype.h> 45 #include "pwd_.h" 46 #include "grp_.h" 47 48 #define CONFIG_FILE "/etc/busybox.conf" 49 50 /* applets [] is const, so we have to define this "override" structure */ 51 static struct BB_suid_config 52 { 53 struct BB_applet *m_applet; 54 55 uid_t m_uid; 56 gid_t m_gid; 57 mode_t m_mode; 58 59 struct BB_suid_config *m_next; 49 /* The -1 arises because of the {0,NULL,0,-1} entry. */ 50 51 #if ENABLE_FEATURE_SH_STANDALONE 52 const unsigned short NUM_APPLETS = ARRAY_SIZE(applets); 53 #endif 54 const struct bb_applet *current_applet; 55 const char *applet_name ATTRIBUTE_EXTERNALLY_VISIBLE; 56 #if !BB_MMU 57 bool re_execed; 58 #endif 59 60 USE_FEATURE_SUID(static uid_t ruid;) /* real uid */ 61 62 #if ENABLE_FEATURE_SUID_CONFIG 63 64 /* applets[] is const, so we have to define this "override" structure */ 65 static struct BB_suid_config { 66 const struct bb_applet *m_applet; 67 uid_t m_uid; 68 gid_t m_gid; 69 mode_t m_mode; 70 struct BB_suid_config *m_next; 60 71 } *suid_config; 61 72 62 static intsuid_cfg_readable;73 static bool suid_cfg_readable; 63 74 64 75 /* check if u is member of group g */ 65 static int ingroup 66 { 67 struct group *grp = getgrgid(g);68 69 70 char **mem;71 72 for (mem = grp->gr_mem; *mem; mem++) {73 struct passwd *pwd = getpwnam(*mem);74 75 76 return 1;77 }78 79 76 static int ingroup(uid_t u, gid_t g) 77 { 78 struct group *grp = getgrgid(g); 79 80 if (grp) { 81 char **mem; 82 83 for (mem = grp->gr_mem; *mem; mem++) { 84 struct passwd *pwd = getpwnam(*mem); 85 86 if (pwd && (pwd->pw_uid == u)) 87 return 1; 88 } 89 } 90 return 0; 80 91 } 81 92 … … 93 104 } 94 105 } 95 e[1] = 0;106 e[1] = '\0'; 96 107 97 108 /* Next, advance past all leading space and return a ptr to the … … 100 111 } 101 112 102 103 #define parse_error(x) { err=x; goto pe_label; }104 105 113 /* Don't depend on the tools to combine strings. */ 106 static const char config_file[] = CONFIG_FILE; 107 108 /* There are 4 chars + 1 nul for each of user/group/other. */ 109 static const char mode_chars[] = "Ssx-\0Ssx-\0Ttx-"; 114 static const char config_file[] ALIGN1 = "/etc/busybox.conf"; 110 115 111 116 /* We don't supply a value for the nul, so an index adjustment is 112 117 * necessary below. Also, we use unsigned short here to save some 113 118 * space even though these are really mode_t values. */ 114 static const unsigned short mode_mask[] = {115 /* SST sst xxx--- */119 static const unsigned short mode_mask[] ALIGN2 = { 120 /* SST sst xxx --- */ 116 121 S_ISUID, S_ISUID|S_IXUSR, S_IXUSR, 0, /* user */ 117 122 S_ISGID, S_ISGID|S_IXGRP, S_IXGRP, 0, /* group */ … … 119 124 }; 120 125 126 #define parse_error(x) do { errmsg = x; goto pe_label; } while (0) 127 121 128 static void parse_config_file(void) 122 129 { 123 130 struct BB_suid_config *sct_head; 124 131 struct BB_suid_config *sct; 125 struct BB_applet *applet;132 const struct bb_applet *applet; 126 133 FILE *f; 127 c har *err;134 const char *errmsg; 128 135 char *s; 129 136 char *e; 130 int i, lc, section; 137 int i; 138 unsigned lc; 139 smallint section; 131 140 char buffer[256]; 132 141 struct stat st; 133 142 134 assert(!suid_config); /* Should be set to NULL by bss init. */ 135 136 if ((stat(config_file, &st) != 0) /* No config file? */ 137 || !S_ISREG(st.st_mode) /* Not a regular file? */ 138 || (st.st_uid != 0) /* Not owned by root? */ 139 || (st.st_mode & (S_IWGRP | S_IWOTH)) /* Writable by non-root? */ 140 || !(f = fopen(config_file, "r")) /* Can not open? */ 141 ) { 143 assert(!suid_config); /* Should be set to NULL by bss init. */ 144 145 ruid = getuid(); 146 if (ruid == 0) /* run by root - don't need to even read config file */ 147 return; 148 149 if ((stat(config_file, &st) != 0) /* No config file? */ 150 || !S_ISREG(st.st_mode) /* Not a regular file? */ 151 || (st.st_uid != 0) /* Not owned by root? */ 152 || (st.st_mode & (S_IWGRP | S_IWOTH)) /* Writable by non-root? */ 153 || !(f = fopen(config_file, "r")) /* Cannot open? */ 154 ) { 142 155 return; 143 156 } … … 147 160 section = lc = 0; 148 161 149 do{162 while (1) { 150 163 s = buffer; 151 164 … … 175 188 /* Trim leading and trailing whitespace, ignoring comments, and 176 189 * check if the resulting string is empty. */ 177 if (!*(s = get_trimmed_slice(s, strchrnul(s, '#')))) { 190 s = get_trimmed_slice(s, strchrnul(s, '#')); 191 if (!*s) { 178 192 continue; 179 193 } … … 185 199 * whitespace for the section name. We also require that 186 200 * there are no stray characters after the closing bracket. */ 187 if (!(e = strchr(s, ']')) /* Missing right bracket? */ 188 || e[1] /* Trailing characters? */ 189 || !*(s = get_trimmed_slice(s+1, e)) /* Missing name? */ 190 ) { 201 e = strchr(s, ']'); 202 if (!e /* Missing right bracket? */ 203 || e[1] /* Trailing characters? */ 204 || !*(s = get_trimmed_slice(s+1, e)) /* Missing name? */ 205 ) { 191 206 parse_error("section header"); 192 207 } … … 214 229 215 230 /* First get the key (an applet name in our case). */ 216 if (!!(e = strchr(s, '='))) { 231 e = strchr(s, '='); 232 if (e) { 217 233 s = get_trimmed_slice(s, e); 218 234 } … … 223 239 /* Ok, we have an applet name. Process the rhs if this 224 240 * applet is currently built in and ignore it otherwise. 225 * Note: This can hide config file bugs which only pop241 * Note: this can hide config file bugs which only pop 226 242 * up when the busybox configuration is changed. */ 227 if ((applet = find_applet_by_name(s))) { 243 applet = find_applet_by_name(s); 244 if (applet) { 228 245 /* Note: We currently don't check for duplicates! 229 246 * The last config line for each applet will be the … … 240 257 e = skip_whitespace(e+1); 241 258 242 for (i=0 ; i < 3 ; i++) { 259 for (i = 0; i < 3; i++) { 260 /* There are 4 chars + 1 nul for each of user/group/other. */ 261 static const char mode_chars[] ALIGN1 = "Ssx-\0" "Ssx-\0" "Ttx-"; 262 243 263 const char *q; 244 if (!*(q = strchrnul(mode_chars + 5*i, *e++))) { 264 q = strchrnul(mode_chars + 5*i, *e++); 265 if (!*q) { 245 266 parse_error("mode"); 246 267 } … … 253 274 s = skip_whitespace(e); 254 275 255 /* Note: We require whitespace between the mode and the276 /* Note: we require whitespace between the mode and the 256 277 * user/group info. */ 257 278 if ((s == e) || !(e = strchr(s, '.'))) { 258 279 parse_error("<uid>.<gid>"); 259 280 } 260 *e++ = 0;281 *e++ = '\0'; 261 282 262 283 /* We can't use get_ug_id here since it would exit() 263 284 * if a uid or gid was not found. Oh well... */ 264 { 265 char *e2; 266 267 sct->m_uid = strtoul(s, &e2, 10); 268 if (*e2 || (s == e2)) { 269 struct passwd *pwd; 270 if (!(pwd = getpwnam(s))) { 271 parse_error("user"); 272 } 273 sct->m_uid = pwd->pw_uid; 285 sct->m_uid = bb_strtoul(s, NULL, 10); 286 if (errno) { 287 struct passwd *pwd = getpwnam(s); 288 if (!pwd) { 289 parse_error("user"); 274 290 } 275 276 sct->m_gid = strtoul(e, &e2, 10); 277 if (*e2 || (e == e2)) { 278 struct group *grp; 279 if (!(grp = getgrnam(e))) { 280 parse_error("group"); 281 } 282 sct->m_gid = grp->gr_gid; 291 sct->m_uid = pwd->pw_uid; 292 } 293 294 sct->m_gid = bb_strtoul(e, NULL, 10); 295 if (errno) { 296 struct group *grp; 297 grp = getgrnam(e); 298 if (!grp) { 299 parse_error("group"); 283 300 } 301 sct->m_gid = grp->gr_gid; 284 302 } 285 303 } … … 298 316 } 299 317 300 } while (1);318 } /* while (1) */ 301 319 302 320 pe_label: 303 321 fprintf(stderr, "Parse error in %s, line %d: %s\n", 304 config_file, lc, err );322 config_file, lc, errmsg); 305 323 306 324 fclose(f); … … 311 329 sct_head = sct; 312 330 } 313 return; 314 } 315 331 } 316 332 #else 317 #define parse_config_file() 318 #endif /* CONFIG_FEATURE_SUID_CONFIG */ 319 320 #ifdef CONFIG_FEATURE_SUID 321 static void check_suid (struct BB_applet *applet) 322 { 323 uid_t ruid = getuid (); /* real [ug]id */ 324 uid_t rgid = getgid (); 325 326 #ifdef CONFIG_FEATURE_SUID_CONFIG 327 if (suid_cfg_readable) { 328 struct BB_suid_config *sct; 329 330 for (sct = suid_config; sct; sct = sct->m_next) { 331 if (sct->m_applet == applet) 332 break; 333 } 334 if (sct) { 335 mode_t m = sct->m_mode; 336 337 if (sct->m_uid == ruid) /* same uid */ 338 m >>= 6; 339 else if ((sct->m_gid == rgid) || ingroup (ruid, sct->m_gid)) /* same group / in group */ 340 m >>= 3; 341 342 if (!(m & S_IXOTH)) /* is x bit not set ? */ 343 bb_error_msg_and_die ("You have no permission to run this applet!"); 344 345 if ((sct->m_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { /* *both* have to be set for sgid */ 346 if (setegid (sct->m_gid)) 347 bb_error_msg_and_die 348 ("BusyBox binary has insufficient rights to set proper GID for applet!"); 349 } else 350 setgid (rgid); /* no sgid -> drop */ 351 352 if (sct->m_mode & S_ISUID) { 353 if (seteuid (sct->m_uid)) 354 bb_error_msg_and_die 355 ("BusyBox binary has insufficient rights to set proper UID for applet!"); 356 } else 357 setuid (ruid); /* no suid -> drop */ 358 } else { 333 static inline void parse_config_file(void) 334 { 335 USE_FEATURE_SUID(ruid = getuid();) 336 } 337 #endif /* FEATURE_SUID_CONFIG */ 338 339 340 #if ENABLE_FEATURE_SUID 341 static void check_suid(const struct bb_applet *applet) 342 { 343 gid_t rgid; /* real gid */ 344 345 if (ruid == 0) /* set by parse_config_file() */ 346 return; /* run by root - no need to check more */ 347 rgid = getgid(); 348 349 #if ENABLE_FEATURE_SUID_CONFIG 350 if (suid_cfg_readable) { 351 uid_t uid; 352 struct BB_suid_config *sct; 353 mode_t m; 354 355 for (sct = suid_config; sct; sct = sct->m_next) { 356 if (sct->m_applet == applet) 357 goto found; 358 } 359 359 /* default: drop all privileges */ 360 setgid (rgid); 361 setuid (ruid); 362 } 363 return; 364 } else { 365 #ifndef CONFIG_FEATURE_SUID_CONFIG_QUIET 366 static int onetime = 0; 367 368 if (!onetime) { 369 onetime = 1; 370 fprintf (stderr, "Using fallback suid method\n"); 371 } 372 #endif 373 } 374 #endif 375 376 if (applet->need_suid == _BB_SUID_ALWAYS) { 377 if (geteuid () != 0) 378 bb_error_msg_and_die ("This applet requires root privileges!"); 379 } else if (applet->need_suid == _BB_SUID_NEVER) { 380 setgid (rgid); /* drop all privileges */ 381 setuid (ruid); 382 } 360 xsetgid(rgid); 361 xsetuid(ruid); 362 return; 363 found: 364 m = sct->m_mode; 365 if (sct->m_uid == ruid) 366 /* same uid */ 367 m >>= 6; 368 else if ((sct->m_gid == rgid) || ingroup(ruid, sct->m_gid)) 369 /* same group / in group */ 370 m >>= 3; 371 372 if (!(m & S_IXOTH)) /* is x bit not set ? */ 373 bb_error_msg_and_die("you have no permission to run this applet!"); 374 375 /* _both_ sgid and group_exec have to be set for setegid */ 376 if ((sct->m_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) 377 rgid = sct->m_gid; 378 /* else (no setegid) we will set egid = rgid */ 379 380 /* We set effective AND saved ids. If saved-id is not set 381 * like we do below, seteiud(0) can still later succeed! */ 382 if (setresgid(-1, rgid, rgid)) 383 bb_perror_msg_and_die("setresgid"); 384 385 /* do we have to set effective uid? */ 386 uid = ruid; 387 if (sct->m_mode & S_ISUID) 388 uid = sct->m_uid; 389 /* else (no seteuid) we will set euid = ruid */ 390 391 if (setresuid(-1, uid, uid)) 392 bb_perror_msg_and_die("setresuid"); 393 return; 394 } 395 #if !ENABLE_FEATURE_SUID_CONFIG_QUIET 396 { 397 static bool onetime = 0; 398 399 if (!onetime) { 400 onetime = 1; 401 fprintf(stderr, "Using fallback suid method\n"); 402 } 403 } 404 #endif 405 #endif 406 407 if (applet->need_suid == _BB_SUID_ALWAYS) { 408 /* Real uid is not 0. If euid isn't 0 too, suid bit 409 * is most probably not set on our executable */ 410 if (geteuid()) 411 bb_error_msg_and_die("applet requires root privileges!"); 412 } else if (applet->need_suid == _BB_SUID_NEVER) { 413 xsetgid(rgid); /* drop all privileges */ 414 xsetuid(ruid); 415 } 383 416 } 384 417 #else 385 #define check_suid(x) 386 #endif /* CONFIG_FEATURE_SUID */ 387 418 #define check_suid(x) ((void)0) 419 #endif /* FEATURE_SUID */ 388 420 389 421 … … 395 427 static const char *unpack_usage_messages(void) 396 428 { 397 int input[2], output[2], pid; 398 char *buf; 399 400 if(pipe(input) < 0 || pipe(output) < 0) 401 exit(1); 402 403 pid = fork(); 404 switch (pid) { 405 case -1: /* error */ 406 exit(1); 407 case 0: /* child */ 408 close(input[1]); 409 close(output[0]); 410 uncompressStream(input[0], output[1]); 411 exit(0); 412 } 413 /* parent */ 414 415 close(input[0]); 416 close(output[1]); 417 pid = fork(); 418 switch (pid) { 419 case -1: /* error */ 420 exit(1); 421 case 0: /* child */ 422 bb_full_write(input[1], packed_usage, sizeof(packed_usage)); 423 exit(0); 424 } 425 /* parent */ 426 close(input[1]); 427 428 buf = xmalloc(SIZEOF_usage_messages); 429 bb_full_read(output[0], buf, SIZEOF_usage_messages); 430 return buf; 431 } 429 char *outbuf = NULL; 430 bunzip_data *bd; 431 int i; 432 433 i = start_bunzip(&bd, 434 /* src_fd: */ -1, 435 /* inbuf: */ packed_usage, 436 /* len: */ sizeof(packed_usage)); 437 /* read_bunzip can longjmp to start_bunzip, and ultimately 438 * end up here with i != 0 on read data errors! Not trivial */ 439 if (!i) { 440 /* Cannot use xmalloc: will leak bd in NOFORK case! */ 441 outbuf = malloc_or_warn(SIZEOF_usage_messages); 442 if (outbuf) 443 read_bunzip(bd, outbuf, SIZEOF_usage_messages); 444 } 445 dealloc_bunzip(bd); 446 return outbuf; 447 } 448 #define dealloc_usage_messages(s) free(s) 432 449 433 450 #else 451 434 452 #define unpack_usage_messages() usage_messages 435 #endif /* ENABLE_FEATURE_COMPRESS_USAGE */ 436 437 void bb_show_usage (void) 453 #define dealloc_usage_messages(s) ((void)(s)) 454 455 #endif /* FEATURE_COMPRESS_USAGE */ 456 457 458 void bb_show_usage(void) 438 459 { 439 460 if (ENABLE_SHOW_USAGE) { 440 461 const char *format_string; 441 const char *usage_string = unpack_usage_messages(); 462 const char *p; 463 const char *usage_string = p = unpack_usage_messages(); 442 464 int i; 443 465 444 for (i = applet_using - applets; i > 0;) 445 if (!*usage_string++) --i; 446 447 format_string = "%s\n\nUsage: %s %s\n\n"; 448 if (*usage_string == '\b') 449 format_string = "%s\n\nNo help available.\n\n"; 450 fprintf (stderr, format_string, bb_msg_full_version, 451 applet_using->name, usage_string); 452 } 453 454 exit (bb_default_error_retval); 455 } 456 457 static int applet_name_compare (const void *x, const void *y) 458 { 459 const char *name = x; 460 const struct BB_applet *applet = y; 461 462 return strcmp (name, applet->name); 463 } 464 465 extern const size_t NUM_APPLETS; 466 467 struct BB_applet *find_applet_by_name (const char *name) 468 { 469 return bsearch (name, applets, NUM_APPLETS, sizeof (struct BB_applet), 470 applet_name_compare); 471 } 472 473 void run_applet_by_name (const char *name, int argc, char **argv) 474 { 475 if(ENABLE_FEATURE_SUID_CONFIG) parse_config_file (); 476 477 if(!strncmp(name, "busybox", 7)) busybox_main(argc, argv); 466 i = current_applet - applets; 467 while (i) { 468 while (*p++) continue; 469 i--; 470 } 471 472 fprintf(stderr, "%s multi-call binary\n", bb_banner); 473 format_string = "\nUsage: %s %s\n\n"; 474 if (*p == '\b') 475 format_string = "\nNo help available.\n\n"; 476 fprintf(stderr, format_string, applet_name, p); 477 dealloc_usage_messages((char*)usage_string); 478 } 479 xfunc_die(); 480 } 481 482 483 static int applet_name_compare(const void *name, const void *vapplet) 484 { 485 const struct bb_applet *applet = vapplet; 486 487 return strcmp(name, applet->name); 488 } 489 490 const struct bb_applet *find_applet_by_name(const char *name) 491 { 478 492 /* Do a binary search to find the applet entry given the name. */ 479 applet_using = find_applet_by_name(name); 480 if(applet_using) { 481 bb_applet_name = applet_using->name; 482 if(argc==2 && !strcmp(argv[1], "--help")) bb_show_usage (); 483 if(ENABLE_FEATURE_SUID) check_suid (applet_using); 484 exit ((*(applet_using->main)) (argc, argv)); 485 } 486 } 493 return bsearch(name, applets, ARRAY_SIZE(applets)-1, sizeof(applets[0]), 494 applet_name_compare); 495 } 496 497 498 #if ENABLE_FEATURE_INSTALLER 499 /* create (sym)links for each applet */ 500 static void install_links(const char *busybox, int use_symbolic_links) 501 { 502 /* directory table 503 * this should be consistent w/ the enum, 504 * busybox.h::bb_install_loc_t, or else... */ 505 static const char usr_bin [] ALIGN1 = "/usr/bin"; 506 static const char usr_sbin[] ALIGN1 = "/usr/sbin"; 507 static const char *const install_dir[] = { 508 &usr_bin [8], /* "", equivalent to "/" for concat_path_file() */ 509 &usr_bin [4], /* "/bin" */ 510 &usr_sbin[4], /* "/sbin" */ 511 usr_bin, 512 usr_sbin 513 }; 514 515 int (*lf)(const char *, const char *) = link; 516 char *fpc; 517 int i; 518 int rc; 519 520 if (use_symbolic_links) 521 lf = symlink; 522 523 for (i = 0; applets[i].name != NULL; i++) { 524 fpc = concat_path_file( 525 install_dir[applets[i].install_loc], 526 applets[i].name); 527 rc = lf(busybox, fpc); 528 if (rc != 0 && errno != EEXIST) { 529 bb_perror_msg("%s", fpc); 530 } 531 free(fpc); 532 } 533 } 534 #else 535 #define install_links(x,y) ((void)0) 536 #endif /* FEATURE_INSTALLER */ 537 538 539 /* If we were called as "busybox..." */ 540 static int busybox_main(char **argv) 541 { 542 if (!argv[1]) { 543 /* Called without arguments */ 544 const struct bb_applet *a; 545 int col, output_width; 546 help: 547 output_width = 80; 548 if (ENABLE_FEATURE_AUTOWIDTH) { 549 /* Obtain the terminal width */ 550 get_terminal_width_height(0, &output_width, NULL); 551 } 552 /* leading tab and room to wrap */ 553 output_width -= sizeof("start-stop-daemon, ") + 8; 554 555 printf("%s multi-call binary\n", bb_banner); /* reuse const string... */ 556 printf("Copyright (C) 1998-2006 Erik Andersen, Rob Landley, and others.\n" 557 "Licensed under GPLv2. See source distribution for full notice.\n" 558 "\n" 559 "Usage: busybox [function] [arguments]...\n" 560 " or: [function] [arguments]...\n" 561 "\n" 562 "\tBusyBox is a multi-call binary that combines many common Unix\n" 563 "\tutilities into a single executable. Most people will create a\n" 564 "\tlink to busybox for each function they wish to use and BusyBox\n" 565 "\twill act like whatever it was invoked as!\n" 566 "\nCurrently defined functions:\n"); 567 col = 0; 568 a = applets; 569 while (a->name) { 570 if (col > output_width) { 571 puts(","); 572 col = 0; 573 } 574 col += printf("%s%s", (col ? ", " : "\t"), a->name); 575 a++; 576 } 577 puts("\n"); 578 return 0; 579 } 580 581 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) { 582 const char *busybox; 583 busybox = xmalloc_readlink(bb_busybox_exec_path); 584 if (!busybox) 585 busybox = bb_busybox_exec_path; 586 /* -s makes symlinks */ 587 install_links(busybox, argv[2] && strcmp(argv[2], "-s") == 0); 588 return 0; 589 } 590 591 if (strcmp(argv[1], "--help") == 0) { 592 /* "busybox --help [<applet>]" */ 593 if (!argv[2]) 594 goto help; 595 /* convert to "<applet> --help" */ 596 argv[0] = argv[2]; 597 argv[2] = NULL; 598 } else { 599 /* "busybox <applet> arg1 arg2 ..." */ 600 argv++; 601 } 602 /* we want "<argv[0]>: applet not found", not "busybox: ..." */ 603 applet_name = argv[0]; 604 run_applet_and_exit(argv[0], argv); 605 bb_error_msg_and_die("applet not found"); 606 } 607 608 void run_current_applet_and_exit(char **argv) 609 { 610 int argc = 1; 611 612 while (argv[argc]) 613 argc++; 614 615 /* Reinit some shared global data */ 616 optind = 1; 617 xfunc_error_retval = EXIT_FAILURE; 618 619 applet_name = current_applet->name; 620 if (argc == 2 && !strcmp(argv[1], "--help")) 621 bb_show_usage(); 622 if (ENABLE_FEATURE_SUID) 623 check_suid(current_applet); 624 exit(current_applet->main(argc, argv)); 625 } 626 627 void run_applet_and_exit(const char *name, char **argv) 628 { 629 current_applet = find_applet_by_name(name); 630 if (current_applet) 631 run_current_applet_and_exit(argv); 632 if (!strncmp(name, "busybox", 7)) 633 exit(busybox_main(argv)); 634 } 635 636 637 #ifdef __GLIBC__ 638 /* Make it reside in R/W memory: */ 639 int *const bb_errno __attribute__ ((section (".data"))); 640 #endif 641 642 int main(int argc, char **argv) 643 { 644 #ifdef __GLIBC__ 645 (*(int **)&bb_errno) = __errno_location(); 646 #endif 647 648 #if !BB_MMU 649 /* NOMMU re-exec trick sets high-order bit in first byte of name */ 650 if (argv[0][0] & 0x80) { 651 re_execed = 1; 652 argv[0][0] &= 0x7f; 653 } 654 #endif 655 applet_name = argv[0]; 656 if (applet_name[0] == '-') 657 applet_name++; 658 applet_name = bb_basename(applet_name); 659 660 parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */ 661 662 /* Set locale for everybody except 'init' */ 663 if (ENABLE_LOCALE_SUPPORT && getpid() != 1) 664 setlocale(LC_ALL, ""); 665 666 run_applet_and_exit(applet_name, argv); 667 bb_error_msg_and_die("applet not found"); 668 }
Note:
See TracChangeset
for help on using the changeset viewer.