diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2026-01-27 11:05:11 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2026-01-27 11:17:38 +0100 |
| commit | 97a78139719deeb2dae02fda6299f174809320fb (patch) | |
| tree | b1be5983f13c42e59314daaf581131fb230898fb | |
| parent | e4f4bf95ac446e72f2c04770552cb2bc8590cfdd (diff) | |
| download | busybox-w32-97a78139719deeb2dae02fda6299f174809320fb.tar.gz busybox-w32-97a78139719deeb2dae02fda6299f174809320fb.tar.bz2 busybox-w32-97a78139719deeb2dae02fda6299f174809320fb.zip | |
ash: move applet handling out of tryexec() - making it similar to dash
function old new delta
tryexec - 60 +60
shellexec 476 349 -127
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 0/1 up/down: 60/-127) Total: -67 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | shell/ash.c | 123 |
1 files changed, 61 insertions, 62 deletions
diff --git a/shell/ash.c b/shell/ash.c index 97ad95a28..7cfd1bc42 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
| @@ -8476,67 +8476,71 @@ static struct tblentry **cmdtable; | |||
| 8476 | static int builtinloc = -1; /* index in path of %builtin, or -1 */ | 8476 | static int builtinloc = -1; /* index in path of %builtin, or -1 */ |
| 8477 | 8477 | ||
| 8478 | 8478 | ||
| 8479 | static void | ||
| 8480 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp) | ||
| 8481 | { | ||
| 8482 | #if ENABLE_FEATURE_SH_STANDALONE | 8479 | #if ENABLE_FEATURE_SH_STANDALONE |
| 8483 | if (applet_no >= 0) { | 8480 | static void |
| 8484 | if (!vforked && APPLET_IS_NOEXEC(applet_no)) { | 8481 | tryexec_applet(int applet_no, const char *cmd, char **argv, char **envp) |
| 8485 | dbg_show_dirtymem("dirtymem in NOEXEC tryexec"); | 8482 | { |
| 8486 | clearenv(); | 8483 | if (!vforked && APPLET_IS_NOEXEC(applet_no)) { |
| 8487 | while (*envp) | 8484 | dbg_show_dirtymem("dirtymem in NOEXEC tryexec"); |
| 8488 | putenv(*envp++); | 8485 | clearenv(); |
| 8489 | popredir(/*drop:*/ 1); | 8486 | while (*envp) |
| 8487 | putenv(*envp++); | ||
| 8488 | popredir(/*drop:*/ 1); | ||
| 8490 | //FIXME: exec resets all non-DFL, non-IGN signal handlers to DFL, | 8489 | //FIXME: exec resets all non-DFL, non-IGN signal handlers to DFL, |
| 8491 | //but we _don't_ exec, such signals will reach ash's handler instead! | 8490 | //but we _don't_ exec, such signals will reach ash's handler instead! |
| 8492 | //Maybe add code there to set the handler to DFL, and signal itself? | 8491 | //Maybe add code there to set the handler to DFL, and signal itself? |
| 8493 | // This works for "CMD [| CMD]..." pipes: | 8492 | // This works for "CMD [| CMD]..." pipes: |
| 8494 | //vforkexec() | 8493 | //vforkexec(): |
| 8495 | // vfork(); | 8494 | // vfork(); |
| 8496 | // forkchild(jp, n, FORK_FG); // this resets TSTP,TTOU,INT,TERM,QUIT to DFL | 8495 | // forkchild(jp, n, FORK_FG); // this resets TSTP,TTOU,INT,TERM,QUIT to DFL |
| 8497 | // shellexec(argv[0], argv, path, idx) | 8496 | // shellexec(argv[0], argv, path, idx) |
| 8498 | // tryexec() | 8497 | // tryexec_applet() |
| 8499 | // we are here | 8498 | // we are here |
| 8500 | // And for "exec CMD": | 8499 | // And for "exec CMD": |
| 8501 | //execcmd() | 8500 | //execcmd(): |
| 8502 | // iflag = 0; | 8501 | // iflag = 0; |
| 8503 | // mflag = 0; | 8502 | // mflag = 0; |
| 8504 | // optschanged(); // this resets TSTP,TTOU,INT,TERM to DFL | 8503 | // optschanged(); // this resets TSTP,TTOU,INT,TERM to DFL |
| 8505 | // shlvl++; | 8504 | // shlvl++; |
| 8506 | // setsignal(SIGQUIT); // this resets QUIT to DFL | 8505 | // setsignal(SIGQUIT); // this resets QUIT to DFL |
| 8507 | // shellexec() | 8506 | // shellexec() -> |
| 8508 | // tryexec() | 8507 | // tryexec_applet() -> |
| 8509 | // we are here | 8508 | // we are here |
| 8510 | // But ash -c 'LAST_CMD_DOESNT_FORK' does not work! | 8509 | // But ash -c 'LAST_CMD_WONT_FORK' does not work! |
| 8511 | //evalcommand() | 8510 | //evalcommand(): |
| 8512 | // if (!(flags & EV_EXIT) || may_have_traps) | 8511 | // if (!(flags & EV_EXIT) || may_have_traps) |
| 8513 | // // we don't use this branch | 8512 | // // we don't use this branch |
| 8514 | // //else: | 8513 | // //else: |
| 8515 | // shellexec() | 8514 | // shellexec() -> |
| 8516 | // tryexec() | 8515 | // tryexec_applet() -> |
| 8517 | // we are here | 8516 | // we are here |
| 8518 | //SIGINT works 'by accident' (sets DFL+signals itself) | 8517 | //SIGINT works 'by accident' (sets DFL+signals itself) |
| 8519 | //SIGQUIT is IGNORED! | 8518 | //SIGQUIT is IGNORED! |
| 8520 | //Fixed by adding in the evalcommand() before the shown shellexec(): | 8519 | //Fixed by adding in the evalcommand() before that shellexec(): |
| 8521 | // shlvl++; | 8520 | // shlvl++; |
| 8522 | // setsignal(SIGQUIT); | 8521 | // setsignal(SIGQUIT); |
| 8523 | // //TODO: setsignal(TSTP,TTOU,INT,TERM) too? | 8522 | // //TODO: setsignal(TSTP,TTOU,INT,TERM) too? |
| 8524 | // | 8523 | // |
| 8525 | // With traps set, this: | 8524 | // With traps set, this: |
| 8526 | // ash -c 'trap "echo HERE!" INT; exec xargs' | 8525 | // ash -c 'trap "echo HERE!" INT; exec xargs' |
| 8527 | // didn't work: ^C sets a "run trap later" flag and _returns_, | 8526 | // didn't work: ^C sets a "run trap later" flag and _returns_, |
| 8528 | // which is not expected by the NOFORK'ed xargs! | 8527 | // which is not expected by the NOEXEC'ed xargs applet! (It gets EINTR on read). |
| 8529 | // clear_traps() helps with this: | 8528 | // clear_traps() helps with this: |
| 8530 | clear_traps(); | 8529 | clear_traps(); |
| 8531 | run_noexec_applet_and_exit(applet_no, cmd, argv); | 8530 | run_noexec_applet_and_exit(applet_no, cmd, argv); |
| 8532 | } | 8531 | /* does not return */ |
| 8533 | /* re-exec ourselves with the new arguments */ | ||
| 8534 | execve(bb_busybox_exec_path, argv, envp); | ||
| 8535 | /* If they called chroot or otherwise made the binary no longer | ||
| 8536 | * executable, fall through */ | ||
| 8537 | } | 8532 | } |
| 8533 | /* re-exec ourselves with the new arguments */ | ||
| 8534 | execve(bb_busybox_exec_path, argv, envp); | ||
| 8535 | /* If they called chroot or otherwise made the binary | ||
| 8536 | * no longer executable, return. | ||
| 8537 | */ | ||
| 8538 | } | ||
| 8538 | #endif | 8539 | #endif |
| 8539 | 8540 | ||
| 8541 | static void | ||
| 8542 | tryexec(const char *cmd, char **argv, char **envp) | ||
| 8543 | { | ||
| 8540 | repeat: | 8544 | repeat: |
| 8541 | #ifdef SYSV | 8545 | #ifdef SYSV |
| 8542 | do { | 8546 | do { |
| @@ -8545,7 +8549,6 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
| 8545 | #else | 8549 | #else |
| 8546 | execve(cmd, argv, envp); | 8550 | execve(cmd, argv, envp); |
| 8547 | #endif | 8551 | #endif |
| 8548 | |||
| 8549 | if (cmd != bb_busybox_exec_path && errno == ENOEXEC) { | 8552 | if (cmd != bb_busybox_exec_path && errno == ENOEXEC) { |
| 8550 | /* Run "cmd" as a shell script: | 8553 | /* Run "cmd" as a shell script: |
| 8551 | * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html | 8554 | * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html |
| @@ -8585,30 +8588,25 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) | |||
| 8585 | int e; | 8588 | int e; |
| 8586 | char **envp; | 8589 | char **envp; |
| 8587 | int exerrno; | 8590 | int exerrno; |
| 8588 | int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ | ||
| 8589 | 8591 | ||
| 8590 | envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); | 8592 | envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); |
| 8591 | if (strchr(prog, '/') != NULL | 8593 | if (strchr(prog, '/') != NULL) { |
| 8592 | #if ENABLE_FEATURE_SH_STANDALONE | 8594 | tryexec(prog, argv, envp); |
| 8593 | || (applet_no = find_applet_by_name(prog)) >= 0 | ||
| 8594 | #endif | ||
| 8595 | ) { | ||
| 8596 | tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); | ||
| 8597 | if (applet_no >= 0) { | ||
| 8598 | /* We tried execing ourself, but it didn't work. | ||
| 8599 | * Maybe /proc/self/exe doesn't exist? | ||
| 8600 | * Try $PATH search. | ||
| 8601 | */ | ||
| 8602 | goto try_PATH; | ||
| 8603 | } | ||
| 8604 | e = errno; | 8595 | e = errno; |
| 8605 | } else { | 8596 | } else { |
| 8606 | try_PATH: | 8597 | #if ENABLE_FEATURE_SH_STANDALONE |
| 8598 | int applet_no = find_applet_by_name(prog); | ||
| 8599 | if (applet_no >= 0) | ||
| 8600 | tryexec_applet(applet_no, prog, argv, envp); | ||
| 8601 | /* We tried execing ourself, but it didn't work. | ||
| 8602 | * Maybe /proc/self/exe doesn't exist? | ||
| 8603 | */ | ||
| 8604 | #endif | ||
| 8607 | e = ENOENT; | 8605 | e = ENOENT; |
| 8608 | while (padvance(&path, argv[0]) >= 0) { | 8606 | while (padvance(&path, argv[0]) >= 0) { |
| 8609 | cmdname = stackblock(); | 8607 | cmdname = stackblock(); |
| 8610 | if (--idx < 0 && pathopt == NULL) { | 8608 | if (--idx < 0 && pathopt == NULL) { |
| 8611 | tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp); | 8609 | tryexec(cmdname, argv, envp); |
| 8612 | if (errno != ENOENT && errno != ENOTDIR) | 8610 | if (errno != ENOENT && errno != ENOTDIR) |
| 8613 | e = errno; | 8611 | e = errno; |
| 8614 | } | 8612 | } |
| @@ -10869,6 +10867,7 @@ evalcommand(union node *cmd, int flags) | |||
| 10869 | /* Testcase: ash -c 'ONE_CMD' will use EV_EXIT for ONE_CMD */ | 10867 | /* Testcase: ash -c 'ONE_CMD' will use EV_EXIT for ONE_CMD */ |
| 10870 | shlvl++; /* dash does not need it because it doesn't ignore SIGQUIT */ | 10868 | shlvl++; /* dash does not need it because it doesn't ignore SIGQUIT */ |
| 10871 | setsignal(SIGQUIT); /* we do (bash compat) */ | 10869 | setsignal(SIGQUIT); /* we do (bash compat) */ |
| 10870 | //TODO: setsignal(TSTP,TTOU,INT,TERM) too? | ||
| 10872 | shellexec(argv[0], argv, path, cmdentry.u.index); | 10871 | shellexec(argv[0], argv, path, cmdentry.u.index); |
| 10873 | /* NOTREACHED */ | 10872 | /* NOTREACHED */ |
| 10874 | } /* default */ | 10873 | } /* default */ |
