aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2016-11-27 22:25:07 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2016-11-27 22:25:07 +0100
commitbff71d3b9d4244abc5182c38d0a98f4913188391 (patch)
treecd881f8a0563b32ad537f0bcae455dab2aa1decb
parent710b6ce9b0dba1b13028e7205bade70eefc2543f (diff)
downloadbusybox-w32-bff71d3b9d4244abc5182c38d0a98f4913188391.tar.gz
busybox-w32-bff71d3b9d4244abc5182c38d0a98f4913188391.tar.bz2
busybox-w32-bff71d3b9d4244abc5182c38d0a98f4913188391.zip
lineedit: fix two bugs in SIGWINCH signal handling
(1) restore entire sigaction, not only signal handler function (2) do not use stdio when not sure WINCH did not interrupt a printf() or such. function old new delta cmdedit_setwidth - 81 +81 read_line_input 3682 3722 +40 lineedit_read_key 138 155 +17 put_prompt 55 51 -4 win_changed 93 47 -46 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/2 up/down: 138/-50) Total: 88 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--libbb/lineedit.c70
1 files changed, 41 insertions, 29 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 4d7828cfa..7a1b5433d 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -129,8 +129,7 @@ static const char null_str[] ALIGN1 = "";
129struct lineedit_statics { 129struct lineedit_statics {
130 line_input_t *state; 130 line_input_t *state;
131 131
132 volatile unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */ 132 unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */
133 sighandler_t previous_SIGWINCH_handler;
134 133
135 unsigned cmdedit_x; /* real x (col) terminal position */ 134 unsigned cmdedit_x; /* real x (col) terminal position */
136 unsigned cmdedit_y; /* pseudoreal y (row) terminal position */ 135 unsigned cmdedit_y; /* pseudoreal y (row) terminal position */
@@ -155,15 +154,22 @@ struct lineedit_statics {
155 unsigned num_matches; 154 unsigned num_matches;
156#endif 155#endif
157 156
157 unsigned SIGWINCH_saved;
158 volatile unsigned SIGWINCH_count;
159 volatile smallint ok_to_redraw;
160
158#if ENABLE_FEATURE_EDITING_VI 161#if ENABLE_FEATURE_EDITING_VI
159# define DELBUFSIZ 128 162# define DELBUFSIZ 128
160 CHAR_T *delptr;
161 smallint newdelflag; /* whether delbuf should be reused yet */ 163 smallint newdelflag; /* whether delbuf should be reused yet */
164 CHAR_T *delptr;
162 CHAR_T delbuf[DELBUFSIZ]; /* a place to store deleted characters */ 165 CHAR_T delbuf[DELBUFSIZ]; /* a place to store deleted characters */
163#endif 166#endif
164#if ENABLE_FEATURE_EDITING_ASK_TERMINAL 167#if ENABLE_FEATURE_EDITING_ASK_TERMINAL
165 smallint sent_ESC_br6n; 168 smallint sent_ESC_br6n;
166#endif 169#endif
170
171 /* Largish struct, keeping it last results in smaller code */
172 struct sigaction SIGWINCH_handler;
167}; 173};
168 174
169/* See lineedit_ptr_hack.c */ 175/* See lineedit_ptr_hack.c */
@@ -172,7 +178,6 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics;
172#define S (*lineedit_ptr_to_statics) 178#define S (*lineedit_ptr_to_statics)
173#define state (S.state ) 179#define state (S.state )
174#define cmdedit_termw (S.cmdedit_termw ) 180#define cmdedit_termw (S.cmdedit_termw )
175#define previous_SIGWINCH_handler (S.previous_SIGWINCH_handler)
176#define cmdedit_x (S.cmdedit_x ) 181#define cmdedit_x (S.cmdedit_x )
177#define cmdedit_y (S.cmdedit_y ) 182#define cmdedit_y (S.cmdedit_y )
178#define cmdedit_prmt_len (S.cmdedit_prmt_len) 183#define cmdedit_prmt_len (S.cmdedit_prmt_len)
@@ -434,14 +439,11 @@ static void beep(void)
434 439
435static void put_prompt(void) 440static void put_prompt(void)
436{ 441{
437 unsigned w;
438
439 fputs(cmdedit_prompt, stdout); 442 fputs(cmdedit_prompt, stdout);
440 fflush_all(); 443 fflush_all();
441 cursor = 0; 444 cursor = 0;
442 w = cmdedit_termw; /* read volatile var once */ 445 cmdedit_y = cmdedit_prmt_len / cmdedit_termw; /* new quasireal y */
443 cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */ 446 cmdedit_x = cmdedit_prmt_len % cmdedit_termw;
444 cmdedit_x = cmdedit_prmt_len % w;
445} 447}
446 448
447/* Move back one character */ 449/* Move back one character */
@@ -513,13 +515,11 @@ static void input_backward(unsigned num)
513 put_cur_glyph_and_inc_cursor(); 515 put_cur_glyph_and_inc_cursor();
514 } else { 516 } else {
515 int lines_up; 517 int lines_up;
516 unsigned width;
517 /* num = chars to go back from the beginning of current line: */ 518 /* num = chars to go back from the beginning of current line: */
518 num -= cmdedit_x; 519 num -= cmdedit_x;
519 width = cmdedit_termw; /* read volatile var once */
520 /* num=1...w: one line up, w+1...2w: two, etc: */ 520 /* num=1...w: one line up, w+1...2w: two, etc: */
521 lines_up = 1 + (num - 1) / width; 521 lines_up = 1 + (num - 1) / cmdedit_termw;
522 cmdedit_x = (width * cmdedit_y - num) % width; 522 cmdedit_x = (cmdedit_termw * cmdedit_y - num) % cmdedit_termw;
523 cmdedit_y -= lines_up; 523 cmdedit_y -= lines_up;
524 /* go to 1st column; go up */ 524 /* go to 1st column; go up */
525 printf("\r" ESC"[%uA", lines_up); 525 printf("\r" ESC"[%uA", lines_up);
@@ -1978,28 +1978,29 @@ static void parse_and_put_prompt(const char *prmt_ptr)
1978} 1978}
1979#endif 1979#endif
1980 1980
1981static void cmdedit_setwidth(unsigned w, int redraw_flg) 1981static void cmdedit_setwidth(int redraw_flg)
1982{ 1982{
1983 cmdedit_termw = w; 1983 get_terminal_width_height(STDIN_FILENO, &cmdedit_termw, NULL);
1984 if (redraw_flg) { 1984 if (redraw_flg) {
1985 /* new y for current cursor */ 1985 /* new y for current cursor */
1986 int new_y = (cursor + cmdedit_prmt_len) / w; 1986 int new_y = (cursor + cmdedit_prmt_len) / cmdedit_termw;
1987 /* redraw */ 1987 /* redraw */
1988 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor); 1988 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor);
1989 fflush_all(); 1989 fflush_all();
1990 } 1990 }
1991} 1991}
1992 1992
1993static void win_changed(int nsig) 1993static void win_changed(int nsig UNUSED_PARAM)
1994{ 1994{
1995 int sv_errno = errno; 1995 if (S.ok_to_redraw) {
1996 unsigned width; 1996 /* We are in read_key(), safe to redraw immediately */
1997 1997 int sv_errno = errno;
1998 get_terminal_width_height(0, &width, NULL); 1998 cmdedit_setwidth(/*redraw_flg:*/ 1);
1999//FIXME: cmdedit_setwidth() -> redraw() -> printf() -> KABOOM! (we are in signal handler!) 1999 errno = sv_errno;
2000 cmdedit_setwidth(width, /*redraw_flg:*/ nsig); 2000 } else {
2001 2001 /* Signal main loop that redraw is necessary */
2002 errno = sv_errno; 2002 S.SIGWINCH_count++;
2003 }
2003} 2004}
2004 2005
2005static int lineedit_read_key(char *read_key_buffer, int timeout) 2006static int lineedit_read_key(char *read_key_buffer, int timeout)
@@ -2018,7 +2019,9 @@ static int lineedit_read_key(char *read_key_buffer, int timeout)
2018 * 2019 *
2019 * Note: read_key sets errno to 0 on success. 2020 * Note: read_key sets errno to 0 on success.
2020 */ 2021 */
2022 S.ok_to_redraw = 1;
2021 ic = read_key(STDIN_FILENO, read_key_buffer, timeout); 2023 ic = read_key(STDIN_FILENO, read_key_buffer, timeout);
2024 S.ok_to_redraw = 0;
2022 if (errno) { 2025 if (errno) {
2023#if ENABLE_UNICODE_SUPPORT 2026#if ENABLE_UNICODE_SUPPORT
2024 if (errno == EAGAIN && unicode_idx != 0) 2027 if (errno == EAGAIN && unicode_idx != 0)
@@ -2355,9 +2358,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2355 ask_terminal(); 2358 ask_terminal();
2356 2359
2357 /* Install window resize handler (NB: after *all* init is complete) */ 2360 /* Install window resize handler (NB: after *all* init is complete) */
2358//FIXME: save entire sigaction! 2361 S.SIGWINCH_handler.sa_handler = win_changed;
2359 previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); 2362 S.SIGWINCH_handler.sa_flags = SA_RESTART;
2360 win_changed(0); /* get initial window size */ 2363 sigaction(SIGWINCH, &S.SIGWINCH_handler, &S.SIGWINCH_handler);
2364
2365 cmdedit_setwidth(/*redraw_flg:*/ 0); /* get initial window size */
2361 2366
2362 read_key_buffer[0] = 0; 2367 read_key_buffer[0] = 0;
2363 while (1) { 2368 while (1) {
@@ -2370,6 +2375,13 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2370 * in one place. 2375 * in one place.
2371 */ 2376 */
2372 int32_t ic, ic_raw; 2377 int32_t ic, ic_raw;
2378 unsigned count;
2379
2380 count = S.SIGWINCH_count;
2381 if (S.SIGWINCH_saved != count) {
2382 S.SIGWINCH_saved = count;
2383 cmdedit_setwidth(/*redraw_flg:*/ 1);
2384 }
2373 2385
2374 fflush_all(); 2386 fflush_all();
2375 ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); 2387 ic = ic_raw = lineedit_read_key(read_key_buffer, timeout);
@@ -2808,7 +2820,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2808 /* restore initial_settings */ 2820 /* restore initial_settings */
2809 tcsetattr_stdin_TCSANOW(&initial_settings); 2821 tcsetattr_stdin_TCSANOW(&initial_settings);
2810 /* restore SIGWINCH handler */ 2822 /* restore SIGWINCH handler */
2811 signal(SIGWINCH, previous_SIGWINCH_handler); 2823 sigaction_set(SIGWINCH, &S.SIGWINCH_handler);
2812 fflush_all(); 2824 fflush_all();
2813 2825
2814 len = command_len; 2826 len = command_len;