aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2023-04-03 08:33:14 +0100
committerRon Yorston <rmy@pobox.com>2023-04-03 08:33:14 +0100
commit64c8f5f3d0bbfcaf3b88aa97a23d90c14326b79e (patch)
tree878917ac4dfd0d271494a1b5436db918b0a0ed88
parent1b2ee3667543b2588446dba6655720eb929bfe03 (diff)
downloadbusybox-w32-64c8f5f3d0bbfcaf3b88aa97a23d90c14326b79e.tar.gz
busybox-w32-64c8f5f3d0bbfcaf3b88aa97a23d90c14326b79e.tar.bz2
busybox-w32-64c8f5f3d0bbfcaf3b88aa97a23d90c14326b79e.zip
ash: add support for INT trap
The trap builtin now handles INT. As before, other signals (from a limited list) are accepted but their traps don't have any effect. There's some variability in how shells handle traps. This patch upholds that proud tradition. Various changes are needed to make this work: - Line editing has a new flag to ignore Ctrl-C. - If INT is being trapped or ignored don't call raise_interrupt(). - A minimal implementation of dotrap() is provided. - Call dotrap() when the read builtin or line input detect Ctrl-C. - Adjust Ctrl-C detection when the INT trap is changed. - Set may_have_traps when an INT trap is set. Costs 368-448 bytes. (GitHub issue #303)
-rw-r--r--include/libbb.h3
-rw-r--r--libbb/lineedit.c4
-rw-r--r--shell/ash.c91
3 files changed, 88 insertions, 10 deletions
diff --git a/include/libbb.h b/include/libbb.h
index 4276bae61..2841d7fbf 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -2040,6 +2040,9 @@ enum {
2040 VI_MODE = 8 * ENABLE_FEATURE_EDITING_VI, 2040 VI_MODE = 8 * ENABLE_FEATURE_EDITING_VI,
2041 WITH_PATH_LOOKUP = 0x10, 2041 WITH_PATH_LOOKUP = 0x10,
2042 LI_INTERRUPTIBLE = 0x20, 2042 LI_INTERRUPTIBLE = 0x20,
2043#if ENABLE_PLATFORM_MINGW32
2044 IGNORE_CTRL_C = 0x40,
2045#endif
2043 FOR_SHELL = DO_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION | LI_INTERRUPTIBLE, 2046 FOR_SHELL = DO_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION | LI_INTERRUPTIBLE,
2044}; 2047};
2045line_input_t *new_line_input_t(int flags) FAST_FUNC; 2048line_input_t *new_line_input_t(int flags) FAST_FUNC;
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 9220ddeb3..45d4c33f5 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -3030,6 +3030,10 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
3030 && ic_raw == initial_settings.c_cc[VINTR] 3030 && ic_raw == initial_settings.c_cc[VINTR]
3031 ) { 3031 ) {
3032 /* Ctrl-C (usually) - stop gathering input */ 3032 /* Ctrl-C (usually) - stop gathering input */
3033#if ENABLE_PLATFORM_MINGW32
3034 if (state->flags & IGNORE_CTRL_C)
3035 break;
3036#endif
3033 command_len = 0; 3037 command_len = 0;
3034 break_out = -1; /* "do not append '\n'" */ 3038 break_out = -1; /* "do not append '\n'" */
3035 break; 3039 break;
diff --git a/shell/ash.c b/shell/ash.c
index d15a6f685..a748b003f 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -627,8 +627,8 @@ struct globals_misc {
627 627
628 /* indicates specified signal received */ 628 /* indicates specified signal received */
629 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ 629 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
630 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
631#endif 630#endif
631 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
632 char *trap[NSIG + 1]; 632 char *trap[NSIG + 1];
633/* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */ 633/* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */
634#define NTRAP_ERR NSIG 634#define NTRAP_ERR NSIG
@@ -687,10 +687,8 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
687#if ENABLE_PLATFORM_MINGW32 687#if ENABLE_PLATFORM_MINGW32
688#undef got_sigchld 688#undef got_sigchld
689#undef pending_sig 689#undef pending_sig
690#undef may_have_traps
691#undef trap_ptr 690#undef trap_ptr
692#define pending_sig (0) 691#define pending_sig (0)
693#define may_have_traps (0)
694#define trap_ptr trap 692#define trap_ptr trap
695#endif 693#endif
696 694
@@ -869,10 +867,17 @@ raise_exception(int e)
869 * are held using the INT_OFF macro. (The test for iflag is just 867 * are held using the INT_OFF macro. (The test for iflag is just
870 * defensive programming.) 868 * defensive programming.)
871 */ 869 */
872static void raise_interrupt(void) NORETURN; 870static void raise_interrupt(void) IF_NOT_PLATFORM_MINGW32(NORETURN);
873static void 871static void
874raise_interrupt(void) 872raise_interrupt(void)
875{ 873{
874#if ENABLE_PLATFORM_MINGW32
875 /* Contrary to the comment above on Windows raise_interrupt() is
876 * called when SIGINT is trapped or ignored. We detect this here
877 * and return without doing anything. */
878 if (trap[SIGINT])
879 return;
880#endif
876 pending_int = 0; 881 pending_int = 0;
877#if !ENABLE_PLATFORM_MINGW32 882#if !ENABLE_PLATFORM_MINGW32
878 /* Signal is not automatically unmasked after it is raised, 883 /* Signal is not automatically unmasked after it is raised,
@@ -4820,8 +4825,11 @@ sprint_status48(char *os, int status, int sigonly)
4820static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) 4825static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
4821{ 4826{
4822 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { 4827 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
4823 if (!suppress_int && !(rootshell && iflag)) 4828# if ENABLE_FEATURE_EDITING
4824 raise_interrupt(); /* does not return */ 4829 bb_got_signal = SIGINT; /* for read_line_input: "we got a signal" */
4830# endif
4831 if (!suppress_int)
4832 raise_interrupt();
4825 pending_int = 1; 4833 pending_int = 1;
4826 return TRUE; 4834 return TRUE;
4827 } 4835 }
@@ -10184,7 +10192,43 @@ dotrap(void)
10184 TRACE(("dotrap returns\n")); 10192 TRACE(("dotrap returns\n"));
10185} 10193}
10186#else 10194#else
10187# define dotrap() 10195static void
10196dotrap(void)
10197{
10198 int status, last_status;
10199 char *p;
10200
10201 if (!pending_int)
10202 return;
10203
10204 status = savestatus;
10205 last_status = status;
10206 if (status < 0) {
10207 status = exitstatus;
10208 savestatus = status;
10209 }
10210 pending_int = 0;
10211 barrier();
10212
10213 TRACE(("dotrap entered\n"));
10214 if (evalskip) {
10215 pending_int = 1;
10216 return;
10217 }
10218
10219 p = trap[SIGINT];
10220 if (p) {
10221 TRACE(("sig %d is active, will run handler '%s'\n", SIGINT, p));
10222 trap_depth++;
10223 evalstring(p, 0);
10224 trap_depth--;
10225 if (evalskip != SKIPFUNC)
10226 exitstatus = status;
10227 }
10228
10229 savestatus = last_status;
10230 TRACE(("dotrap returns\n"));
10231}
10188#endif 10232#endif
10189 10233
10190/* forward declarations - evaluation is fairly recursive business... */ 10234/* forward declarations - evaluation is fairly recursive business... */
@@ -11853,8 +11897,13 @@ preadfd(void)
11853 */ 11897 */
11854# else 11898# else
11855 raise_interrupt(); 11899 raise_interrupt();
11900 write(STDOUT_FILENO, "^C\n", 3);
11856# endif 11901# endif
11857 if (trap[SIGINT]) { 11902 if (trap[SIGINT]) {
11903# if ENABLE_PLATFORM_MINGW32
11904 pending_int = 1;
11905 dotrap();
11906# endif
11858 empty_line_input: 11907 empty_line_input:
11859 buf[0] = '\n'; 11908 buf[0] = '\n';
11860 buf[1] = '\0'; 11909 buf[1] = '\0';
@@ -15088,12 +15137,30 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
15088 } 15137 }
15089 free(trap[signo]); 15138 free(trap[signo]);
15090 trap[signo] = action; 15139 trap[signo] = action;
15140#if ENABLE_PLATFORM_MINGW32
15141 if (signo == SIGINT) {
15142 // trap '' INT disables Ctrl-C, anything else enables it
15143 if (action && action[0] == '\0') {
15144 SetConsoleCtrlHandler(NULL, TRUE);
15145 if (line_input_state) {
15146 line_input_state->flags |= IGNORE_CTRL_C;
15147 }
15148 } else {
15149 SetConsoleCtrlHandler(NULL, FALSE);
15150 if (line_input_state) {
15151 line_input_state->flags &= ~IGNORE_CTRL_C;
15152 }
15153 }
15154 }
15155#else
15091 if (signo != 0 && signo < NSIG) 15156 if (signo != 0 && signo < NSIG)
15092 setsignal(signo); 15157 setsignal(signo);
15158#endif
15093 INT_ON; 15159 INT_ON;
15094 next: 15160 next:
15095 ap++; 15161 ap++;
15096 } 15162 }
15163 may_have_traps = trap[SIGINT] && trap[SIGINT][0] != '\0';
15097 return exitcode; 15164 return exitcode;
15098} 15165}
15099 15166
@@ -15391,10 +15458,14 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
15391#if ENABLE_PLATFORM_MINGW32 15458#if ENABLE_PLATFORM_MINGW32
15392 if ((uintptr_t)r == 2) { 15459 if ((uintptr_t)r == 2) {
15393 /* ^C pressed, propagate event */ 15460 /* ^C pressed, propagate event */
15394 if (iflag) { 15461 if (trap[SIGINT]) {
15462 write(STDOUT_FILENO, "^C", 2);
15463 pending_int = 1;
15464 dotrap();
15465 goto again;
15466 } else if (iflag) {
15395 raise_interrupt(); 15467 raise_interrupt();
15396 } 15468 } else {
15397 else {
15398 GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); 15469 GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
15399 exitshell(); 15470 exitshell();
15400 } 15471 }