10f66f451Sopenharmony_ci/* Toybox infrastructure. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2006 Rob Landley <rob@landley.net> 40f66f451Sopenharmony_ci */ 50f66f451Sopenharmony_ci 60f66f451Sopenharmony_ci#include "toys.h" 70f66f451Sopenharmony_ci 80f66f451Sopenharmony_ci// Populate toy_list[]. 90f66f451Sopenharmony_ci 100f66f451Sopenharmony_ci#undef NEWTOY 110f66f451Sopenharmony_ci#undef OLDTOY 120f66f451Sopenharmony_ci#define NEWTOY(name, opts, flags) {#name, name##_main, OPTSTR_##name, flags}, 130f66f451Sopenharmony_ci#define OLDTOY(name, oldname, flags) \ 140f66f451Sopenharmony_ci {#name, oldname##_main, OPTSTR_##oldname, flags}, 150f66f451Sopenharmony_ci 160f66f451Sopenharmony_cistruct toy_list toy_list[] = { 170f66f451Sopenharmony_ci#include "generated/newtoys.h" 180f66f451Sopenharmony_ci}; 190f66f451Sopenharmony_ci 200f66f451Sopenharmony_ci// global context for this command. 210f66f451Sopenharmony_ci 220f66f451Sopenharmony_cistruct toy_context toys; 230f66f451Sopenharmony_ciunion global_union this; 240f66f451Sopenharmony_cichar toybuf[4096], libbuf[4096]; 250f66f451Sopenharmony_ci 260f66f451Sopenharmony_cistruct toy_list *toy_find(char *name) 270f66f451Sopenharmony_ci{ 280f66f451Sopenharmony_ci int top, bottom, middle; 290f66f451Sopenharmony_ci 300f66f451Sopenharmony_ci if (!CFG_TOYBOX || strchr(name, '/')) return 0; 310f66f451Sopenharmony_ci 320f66f451Sopenharmony_ci // If the name starts with "toybox" accept that as a match. Otherwise 330f66f451Sopenharmony_ci // skip the first entry, which is out of order. 340f66f451Sopenharmony_ci 350f66f451Sopenharmony_ci if (!strncmp(name, "toybox", 6)) return toy_list; 360f66f451Sopenharmony_ci bottom = 1; 370f66f451Sopenharmony_ci 380f66f451Sopenharmony_ci // Binary search to find this command. 390f66f451Sopenharmony_ci 400f66f451Sopenharmony_ci top = ARRAY_LEN(toy_list)-1; 410f66f451Sopenharmony_ci for (;;) { 420f66f451Sopenharmony_ci int result; 430f66f451Sopenharmony_ci 440f66f451Sopenharmony_ci middle = (top+bottom)/2; 450f66f451Sopenharmony_ci if (middle<bottom || middle>top) return 0; 460f66f451Sopenharmony_ci result = strcmp(name,toy_list[middle].name); 470f66f451Sopenharmony_ci if (!result) return toy_list+middle; 480f66f451Sopenharmony_ci if (result<0) top = --middle; 490f66f451Sopenharmony_ci else bottom = ++middle; 500f66f451Sopenharmony_ci } 510f66f451Sopenharmony_ci} 520f66f451Sopenharmony_ci 530f66f451Sopenharmony_ci// Figure out whether or not anything is using the option parsing logic, 540f66f451Sopenharmony_ci// because the compiler can't figure out whether or not to optimize it away 550f66f451Sopenharmony_ci// on its' own. NEED_OPTIONS becomes a constant allowing if() to optimize 560f66f451Sopenharmony_ci// stuff out via dead code elimination. 570f66f451Sopenharmony_ci 580f66f451Sopenharmony_ci#undef NEWTOY 590f66f451Sopenharmony_ci#undef OLDTOY 600f66f451Sopenharmony_ci#define NEWTOY(name, opts, flags) opts || 610f66f451Sopenharmony_ci#define OLDTOY(name, oldname, flags) OPTSTR_##oldname || 620f66f451Sopenharmony_cistatic const int NEED_OPTIONS = 630f66f451Sopenharmony_ci#include "generated/newtoys.h" 640f66f451Sopenharmony_ci0; // Ends the opts || opts || opts... 650f66f451Sopenharmony_ci 660f66f451Sopenharmony_cistatic void unknown(char *name) 670f66f451Sopenharmony_ci{ 680f66f451Sopenharmony_ci toys.exitval = 127; 690f66f451Sopenharmony_ci toys.which = toy_list; 700f66f451Sopenharmony_ci error_exit("Unknown command %s", name); 710f66f451Sopenharmony_ci} 720f66f451Sopenharmony_ci 730f66f451Sopenharmony_ci// Setup toybox global state for this command. 740f66f451Sopenharmony_cistatic void toy_singleinit(struct toy_list *which, char *argv[]) 750f66f451Sopenharmony_ci{ 760f66f451Sopenharmony_ci toys.which = which; 770f66f451Sopenharmony_ci toys.argv = argv; 780f66f451Sopenharmony_ci 790f66f451Sopenharmony_ci if (CFG_TOYBOX_I18N) setlocale(LC_CTYPE, "C.UTF-8"); 800f66f451Sopenharmony_ci setlinebuf(stdout); 810f66f451Sopenharmony_ci 820f66f451Sopenharmony_ci // Parse --help and --version for (almost) all commands 830f66f451Sopenharmony_ci if (CFG_TOYBOX_HELP_DASHDASH && !(which->flags & TOYFLAG_NOHELP) && argv[1]) { 840f66f451Sopenharmony_ci if (!strcmp(argv[1], "--help")) { 850f66f451Sopenharmony_ci if (CFG_TOYBOX && toys.which == toy_list && toys.argv[2]) 860f66f451Sopenharmony_ci if (!(toys.which = toy_find(toys.argv[2]))) unknown(toys.argv[2]); 870f66f451Sopenharmony_ci show_help(stdout); 880f66f451Sopenharmony_ci xexit(); 890f66f451Sopenharmony_ci } 900f66f451Sopenharmony_ci 910f66f451Sopenharmony_ci if (!strcmp(argv[1], "--version")) { 920f66f451Sopenharmony_ci xputs("toybox "TOYBOX_VERSION); 930f66f451Sopenharmony_ci xexit(); 940f66f451Sopenharmony_ci } 950f66f451Sopenharmony_ci } 960f66f451Sopenharmony_ci 970f66f451Sopenharmony_ci if (NEED_OPTIONS && which->options) get_optflags(); 980f66f451Sopenharmony_ci else { 990f66f451Sopenharmony_ci toys.optargs = argv+1; 1000f66f451Sopenharmony_ci for (toys.optc = 0; toys.optargs[toys.optc]; toys.optc++); 1010f66f451Sopenharmony_ci } 1020f66f451Sopenharmony_ci toys.old_umask = umask(0); 1030f66f451Sopenharmony_ci if (!(which->flags & TOYFLAG_UMASK)) umask(toys.old_umask); 1040f66f451Sopenharmony_ci toys.signalfd--; 1050f66f451Sopenharmony_ci toys.toycount = ARRAY_LEN(toy_list); 1060f66f451Sopenharmony_ci} 1070f66f451Sopenharmony_ci 1080f66f451Sopenharmony_ci// Full init needed by multiplexer or reentrant calls, calls singleinit at end 1090f66f451Sopenharmony_civoid toy_init(struct toy_list *which, char *argv[]) 1100f66f451Sopenharmony_ci{ 1110f66f451Sopenharmony_ci void *oldwhich = toys.which; 1120f66f451Sopenharmony_ci 1130f66f451Sopenharmony_ci // Drop permissions for non-suid commands. 1140f66f451Sopenharmony_ci 1150f66f451Sopenharmony_ci if (CFG_TOYBOX_SUID) { 1160f66f451Sopenharmony_ci if (!toys.which) toys.which = toy_list; 1170f66f451Sopenharmony_ci 1180f66f451Sopenharmony_ci uid_t uid = getuid(), euid = geteuid(); 1190f66f451Sopenharmony_ci 1200f66f451Sopenharmony_ci if (!(which->flags & TOYFLAG_STAYROOT)) { 1210f66f451Sopenharmony_ci if (uid != euid) { 1220f66f451Sopenharmony_ci if (setuid(uid)) perror_exit("setuid %d->%d", euid, uid); // drop root 1230f66f451Sopenharmony_ci euid = uid; 1240f66f451Sopenharmony_ci toys.wasroot++; 1250f66f451Sopenharmony_ci } 1260f66f451Sopenharmony_ci } else if (CFG_TOYBOX_DEBUG && uid && which != toy_list) 1270f66f451Sopenharmony_ci error_msg("Not installed suid root"); 1280f66f451Sopenharmony_ci 1290f66f451Sopenharmony_ci if ((which->flags & TOYFLAG_NEEDROOT) && euid) help_exit("Not root"); 1300f66f451Sopenharmony_ci } 1310f66f451Sopenharmony_ci 1320f66f451Sopenharmony_ci // Free old toys contents (to be reentrant), but leave rebound if any 1330f66f451Sopenharmony_ci // don't blank old optargs if our new argc lives in the old optargs. 1340f66f451Sopenharmony_ci if (argv<toys.optargs || argv>toys.optargs+toys.optc) free(toys.optargs); 1350f66f451Sopenharmony_ci memset(&toys, 0, offsetof(struct toy_context, rebound)); 1360f66f451Sopenharmony_ci if (oldwhich) memset(&this, 0, sizeof(this)); 1370f66f451Sopenharmony_ci 1380f66f451Sopenharmony_ci // Continue to portion of init needed by standalone commands 1390f66f451Sopenharmony_ci toy_singleinit(which, argv); 1400f66f451Sopenharmony_ci} 1410f66f451Sopenharmony_ci 1420f66f451Sopenharmony_ci// Run an internal toybox command. 1430f66f451Sopenharmony_ci// Only returns if it can't run command internally, otherwise xexit() when done. 1440f66f451Sopenharmony_civoid toy_exec_which(struct toy_list *which, char *argv[]) 1450f66f451Sopenharmony_ci{ 1460f66f451Sopenharmony_ci // Return if we can't find it (which includes no multiplexer case), 1470f66f451Sopenharmony_ci if (!which) return; 1480f66f451Sopenharmony_ci 1490f66f451Sopenharmony_ci // Return if stack depth getting noticeable (proxy for leaked heap, etc). 1500f66f451Sopenharmony_ci 1510f66f451Sopenharmony_ci // Compiler writers have decided subtracting char * is undefined behavior, 1520f66f451Sopenharmony_ci // so convert to integers. (LP64 says sizeof(long)==sizeof(pointer).) 1530f66f451Sopenharmony_ci // Signed typecast so stack growth direction is irrelevant: we're measuring 1540f66f451Sopenharmony_ci // the distance between two pointers on the same stack, hence the labs(). 1550f66f451Sopenharmony_ci if (!CFG_TOYBOX_NORECURSE && toys.stacktop) 1560f66f451Sopenharmony_ci if (labs((long)toys.stacktop-(long)&which)>6000) return; 1570f66f451Sopenharmony_ci 1580f66f451Sopenharmony_ci // Return if we need to re-exec to acquire root via suid bit. 1590f66f451Sopenharmony_ci if (toys.which && (which->flags&TOYFLAG_ROOTONLY) && toys.wasroot) return; 1600f66f451Sopenharmony_ci 1610f66f451Sopenharmony_ci // Run command 1620f66f451Sopenharmony_ci toy_init(which, argv); 1630f66f451Sopenharmony_ci if (toys.which) toys.which->toy_main(); 1640f66f451Sopenharmony_ci xexit(); 1650f66f451Sopenharmony_ci} 1660f66f451Sopenharmony_ci 1670f66f451Sopenharmony_ci// Lookup internal toybox command to run via argv[0] 1680f66f451Sopenharmony_civoid toy_exec(char *argv[]) 1690f66f451Sopenharmony_ci{ 1700f66f451Sopenharmony_ci toy_exec_which(toy_find(basename(*argv)), argv); 1710f66f451Sopenharmony_ci} 1720f66f451Sopenharmony_ci 1730f66f451Sopenharmony_ci// Multiplexer command, first argument is command to run, rest are args to that. 1740f66f451Sopenharmony_ci// If first argument starts with - output list of command install paths. 1750f66f451Sopenharmony_civoid toybox_main(void) 1760f66f451Sopenharmony_ci{ 1770f66f451Sopenharmony_ci static char *toy_paths[]={"usr/","bin/","sbin/",0}; 1780f66f451Sopenharmony_ci int i, len = 0; 1790f66f451Sopenharmony_ci 1800f66f451Sopenharmony_ci // fast path: try to exec immediately. 1810f66f451Sopenharmony_ci // (Leave toys.which null to disable suid return logic.) 1820f66f451Sopenharmony_ci // Try dereferencing one layer of symlink 1830f66f451Sopenharmony_ci if (toys.argv[1]) { 1840f66f451Sopenharmony_ci toy_exec(toys.argv+1); 1850f66f451Sopenharmony_ci if (0<readlink(toys.argv[1], libbuf, sizeof(libbuf))) { 1860f66f451Sopenharmony_ci struct toy_list *tl= toy_find(basename(libbuf)); 1870f66f451Sopenharmony_ci 1880f66f451Sopenharmony_ci if (tl == toy_list) unknown(basename(toys.argv[1])); 1890f66f451Sopenharmony_ci else toy_exec_which(tl, toys.argv+1); 1900f66f451Sopenharmony_ci } 1910f66f451Sopenharmony_ci } 1920f66f451Sopenharmony_ci 1930f66f451Sopenharmony_ci // For early error reporting 1940f66f451Sopenharmony_ci toys.which = toy_list; 1950f66f451Sopenharmony_ci 1960f66f451Sopenharmony_ci if (toys.argv[1] && toys.argv[1][0] != '-') unknown(toys.argv[1]); 1970f66f451Sopenharmony_ci 1980f66f451Sopenharmony_ci // Output list of command. 1990f66f451Sopenharmony_ci for (i=1; i<ARRAY_LEN(toy_list); i++) { 2000f66f451Sopenharmony_ci int fl = toy_list[i].flags; 2010f66f451Sopenharmony_ci if (fl & TOYMASK_LOCATION) { 2020f66f451Sopenharmony_ci if (toys.argv[1]) { 2030f66f451Sopenharmony_ci int j; 2040f66f451Sopenharmony_ci for (j=0; toy_paths[j]; j++) 2050f66f451Sopenharmony_ci if (fl & (1<<j)) len += printf("%s", toy_paths[j]); 2060f66f451Sopenharmony_ci } 2070f66f451Sopenharmony_ci len += printf("%s",toy_list[i].name); 2080f66f451Sopenharmony_ci if (++len > 65) len = 0; 2090f66f451Sopenharmony_ci xputc(len ? ' ' : '\n'); 2100f66f451Sopenharmony_ci } 2110f66f451Sopenharmony_ci } 2120f66f451Sopenharmony_ci xputc('\n'); 2130f66f451Sopenharmony_ci} 2140f66f451Sopenharmony_ci 2150f66f451Sopenharmony_ciint main(int argc, char *argv[]) 2160f66f451Sopenharmony_ci{ 2170f66f451Sopenharmony_ci if (!*argv) return 127; 2180f66f451Sopenharmony_ci 2190f66f451Sopenharmony_ci // Snapshot stack location so we can detect recursion depth later. 2200f66f451Sopenharmony_ci // This is its own block so probe doesn't permanently consume stack. 2210f66f451Sopenharmony_ci else { 2220f66f451Sopenharmony_ci int stack; 2230f66f451Sopenharmony_ci 2240f66f451Sopenharmony_ci toys.stacktop = &stack; 2250f66f451Sopenharmony_ci } 2260f66f451Sopenharmony_ci 2270f66f451Sopenharmony_ci // Up to and including Android M, bionic's dynamic linker added a handler to 2280f66f451Sopenharmony_ci // cause a crash dump on SIGPIPE. That was removed in Android N, but adbd 2290f66f451Sopenharmony_ci // was still setting the SIGPIPE disposition to SIG_IGN, and its children 2300f66f451Sopenharmony_ci // were inheriting that. In Android O, adbd is fixed, but manually asking 2310f66f451Sopenharmony_ci // for the default disposition is harmless, and it'll be a long time before 2320f66f451Sopenharmony_ci // no one's using anything older than O! 2330f66f451Sopenharmony_ci if (CFG_TOYBOX_ON_ANDROID) signal(SIGPIPE, SIG_DFL); 2340f66f451Sopenharmony_ci 2350f66f451Sopenharmony_ci // If nommu can't fork, special reentry path. 2360f66f451Sopenharmony_ci // Use !stacktop to signal "vfork happened", both before and after xexec() 2370f66f451Sopenharmony_ci if (!CFG_TOYBOX_FORK) { 2380f66f451Sopenharmony_ci if (0x80 & **argv) { 2390f66f451Sopenharmony_ci **argv &= 0x7f; 2400f66f451Sopenharmony_ci toys.stacktop = 0; 2410f66f451Sopenharmony_ci } 2420f66f451Sopenharmony_ci } 2430f66f451Sopenharmony_ci 2440f66f451Sopenharmony_ci if (CFG_TOYBOX) { 2450f66f451Sopenharmony_ci // Call the multiplexer, adjusting this argv[] to be its' argv[1]. 2460f66f451Sopenharmony_ci // (It will adjust it back before calling toy_exec().) 2470f66f451Sopenharmony_ci toys.argv = argv-1; 2480f66f451Sopenharmony_ci toybox_main(); 2490f66f451Sopenharmony_ci } else { 2500f66f451Sopenharmony_ci // a single toybox command built standalone with no multiplexer 2510f66f451Sopenharmony_ci toy_singleinit(toy_list, argv); 2520f66f451Sopenharmony_ci toy_list->toy_main(); 2530f66f451Sopenharmony_ci } 2540f66f451Sopenharmony_ci 2550f66f451Sopenharmony_ci xexit(); 2560f66f451Sopenharmony_ci} 257