aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-10-26 15:23:32 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2009-10-26 15:23:32 +0100
commit727e1b536e5478b8f28c93990a5bf34091144608 (patch)
treec8993291a1a03a06fcb7a2382e6cc211e6d7861e
parentd31a8793ebedb53b686c9ea01be33d3d564760b9 (diff)
downloadbusybox-w32-727e1b536e5478b8f28c93990a5bf34091144608.tar.gz
busybox-w32-727e1b536e5478b8f28c93990a5bf34091144608.tar.bz2
busybox-w32-727e1b536e5478b8f28c93990a5bf34091144608.zip
read_key,lineeedit: parse position answerback faster; sanitize its use
it's still not reliable, and probably cannot be made so... added comment with explanation. function old new delta put_prompt 52 110 +58 read_key 601 607 +6 lineedit_read_key 201 207 +6 win_changed 108 104 -4 read_line_input 4824 4809 -15 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/2 up/down: 70/-19) Total: 51 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--libbb/lineedit.c38
-rw-r--r--libbb/read_key.c53
2 files changed, 58 insertions, 33 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index bfd0e3346..2e1bc5d2e 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -370,6 +370,7 @@ static void input_backward(unsigned num)
370static void put_prompt(void) 370static void put_prompt(void)
371{ 371{
372 out1str(cmdedit_prompt); 372 out1str(cmdedit_prompt);
373 fflush(NULL);
373 if (ENABLE_FEATURE_EDITING_ASK_TERMINAL) { 374 if (ENABLE_FEATURE_EDITING_ASK_TERMINAL) {
374 /* Ask terminal where is the cursor now. 375 /* Ask terminal where is the cursor now.
375 * lineedit_read_key handles response and corrects 376 * lineedit_read_key handles response and corrects
@@ -380,7 +381,33 @@ static void put_prompt(void)
380 * Note: we print it _after_ prompt, because 381 * Note: we print it _after_ prompt, because
381 * prompt may contain CR. Example: PS1='\[\r\n\]\w ' 382 * prompt may contain CR. Example: PS1='\[\r\n\]\w '
382 */ 383 */
383 out1str("\033" "[6n"); 384 /* Problem: if there is buffered input on stdin,
385 * the response will be delivered later,
386 * possibly to an unsuspecting application.
387 * Testcase: "sleep 1; busybox ash" + press and hold [Enter].
388 * Result:
389 * ~/srcdevel/bbox/fix/busybox.t4 #
390 * ~/srcdevel/bbox/fix/busybox.t4 #
391 * ^[[59;34~/srcdevel/bbox/fix/busybox.t4 # <-- garbage
392 * ~/srcdevel/bbox/fix/busybox.t4 #
393 *
394 * Checking for input with poll only makes the race narrower,
395 * I still can trigger it. Strace:
396 *
397 * write(1, "~/srcdevel/bbox/fix/busybox.t4 # ", 33) = 33
398 * poll([{fd=0, events=POLLIN}], 1, 0) = 0 (Timeout) <-- no input exists
399 * write(1, "\33[6n", 4) = 4 <-- send the ESC sequence, quick!
400 * poll([{fd=0, events=POLLIN}], 1, 4294967295) = 1 ([{fd=0, revents=POLLIN}])
401 * read(0, "\n", 1) = 1 <-- oh crap, user's input got in first
402 */
403 struct pollfd pfd;
404
405 pfd.fd = STDIN_FILENO;
406 pfd.events = POLLIN;
407 if (safe_poll(&pfd, 1, 0) == 0) {
408 out1str("\033" "[6n");
409 fflush(NULL); /* make terminal see it ASAP! */
410 }
384 } 411 }
385 cursor = 0; 412 cursor = 0;
386 { 413 {
@@ -1603,7 +1630,7 @@ static void cmdedit_setwidth(unsigned w, int redraw_flg)
1603 int new_y = (cursor + cmdedit_prmt_len) / w; 1630 int new_y = (cursor + cmdedit_prmt_len) / w;
1604 /* redraw */ 1631 /* redraw */
1605 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor); 1632 redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor);
1606 fflush(stdout); 1633 fflush(NULL);
1607 } 1634 }
1608} 1635}
1609 1636
@@ -1640,6 +1667,7 @@ static int lineedit_read_key(char *read_key_buffer)
1640 ic = read_key(STDIN_FILENO, read_key_buffer); 1667 ic = read_key(STDIN_FILENO, read_key_buffer);
1641 1668
1642 if (ENABLE_FEATURE_EDITING_ASK_TERMINAL 1669 if (ENABLE_FEATURE_EDITING_ASK_TERMINAL
1670 && cursor == 0 /* otherwise it may be bogus */
1643 && (int32_t)ic == KEYCODE_CURSOR_POS 1671 && (int32_t)ic == KEYCODE_CURSOR_POS
1644 ) { 1672 ) {
1645 int col = ((ic >> 32) & 0x7fff) - 1; 1673 int col = ((ic >> 32) & 0x7fff) - 1;
@@ -1708,7 +1736,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1708 ) { 1736 ) {
1709 /* Happens when e.g. stty -echo was run before */ 1737 /* Happens when e.g. stty -echo was run before */
1710 parse_and_put_prompt(prompt); 1738 parse_and_put_prompt(prompt);
1711 fflush(stdout); 1739 /* fflush(stdout); - done by parse_and_put_prompt */
1712 if (fgets(command, maxsize, stdin) == NULL) 1740 if (fgets(command, maxsize, stdin) == NULL)
1713 len = -1; /* EOF or error */ 1741 len = -1; /* EOF or error */
1714 else 1742 else
@@ -2190,7 +2218,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
2190 tcsetattr_stdin_TCSANOW(&initial_settings); 2218 tcsetattr_stdin_TCSANOW(&initial_settings);
2191 /* restore SIGWINCH handler */ 2219 /* restore SIGWINCH handler */
2192 signal(SIGWINCH, previous_SIGWINCH_handler); 2220 signal(SIGWINCH, previous_SIGWINCH_handler);
2193 fflush(stdout); 2221 fflush(NULL);
2194 2222
2195 len = command_len; 2223 len = command_len;
2196 DEINIT_S(); 2224 DEINIT_S();
@@ -2204,7 +2232,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
2204int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize) 2232int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize)
2205{ 2233{
2206 fputs(prompt, stdout); 2234 fputs(prompt, stdout);
2207 fflush(stdout); 2235 fflush(NULL);
2208 fgets(command, maxsize, stdin); 2236 fgets(command, maxsize, stdin);
2209 return strlen(command); 2237 return strlen(command);
2210} 2238}
diff --git a/libbb/read_key.c b/libbb/read_key.c
index ec1b3a4a8..a2253ce3e 100644
--- a/libbb/read_key.c
+++ b/libbb/read_key.c
@@ -202,6 +202,31 @@ int64_t FAST_FUNC read_key(int fd, char *buffer)
202 break; 202 break;
203 } 203 }
204 n++; 204 n++;
205 /* Try to decipher "ESC [ NNN ; NNN R" sequence */
206 if (ENABLE_FEATURE_EDITING_ASK_TERMINAL
207 && n >= 5
208 && buffer[0] == '['
209 && buffer[n-1] == 'R'
210 && isdigit(buffer[1])
211 ) {
212 char *end;
213 unsigned long row, col;
214
215 row = strtoul(buffer + 1, &end, 10);
216 if (*end != ';' || !isdigit(end[1]))
217 continue;
218 col = strtoul(end + 1, &end, 10);
219 if (*end != 'R')
220 continue;
221 if (row < 1 || col < 1 || (row | col) > 0x7fff)
222 continue;
223
224 buffer[-1] = 0;
225 /* Pack into "1 <row15bits> <col16bits>" 32-bit sequence */
226 col |= (((-1 << 15) | row) << 16);
227 /* Return it in high-order word */
228 return ((int64_t) col << 32) | (uint32_t)KEYCODE_CURSOR_POS;
229 }
205 } 230 }
206 got_all: 231 got_all:
207 232
@@ -213,34 +238,6 @@ int64_t FAST_FUNC read_key(int fd, char *buffer)
213 return 27; 238 return 27;
214 } 239 }
215 240
216 /* Try to decipher "ESC [ NNN ; NNN R" sequence */
217 if (ENABLE_FEATURE_EDITING_ASK_TERMINAL
218 && n >= 5
219 && buffer[0] == '['
220 && isdigit(buffer[1])
221 && buffer[n-1] == 'R'
222 ) {
223 char *end;
224 unsigned long row, col;
225
226 row = strtoul(buffer + 1, &end, 10);
227 if (*end != ';' || !isdigit(end[1]))
228 goto not_R;
229 col = strtoul(end + 1, &end, 10);
230 if (*end != 'R')
231 goto not_R;
232 if (row < 1 || col < 1 || (row | col) > 0x7fff)
233 goto not_R;
234
235 buffer[-1] = 0;
236
237 /* Pack into "1 <row15bits> <col16bits>" 32-bit sequence */
238 col |= (((-1 << 15) | row) << 16);
239 /* Return it in high-order word */
240 return ((int64_t) col << 32) | (uint32_t)KEYCODE_CURSOR_POS;
241 }
242 not_R:
243
244 /* We were doing "buffer[-1] = n; return c;" here, but this results 241 /* We were doing "buffer[-1] = n; return c;" here, but this results
245 * in unknown key sequences being interpreted as ESC + garbage. 242 * in unknown key sequences being interpreted as ESC + garbage.
246 * This was not useful. Pretend there was no key pressed, 243 * This was not useful. Pretend there was no key pressed,