From 064e99646a233240e91f453ba49f6baeab7c2c70 Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Wed, 13 Jul 2011 09:26:58 +0200 Subject: cttyhack: check sysfs for the name of the active console Signed-off-by: Kevin Cernekee Signed-off-by: Denys Vlasenko --- shell/cttyhack.c | 79 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 31 deletions(-) (limited to 'shell') diff --git a/shell/cttyhack.c b/shell/cttyhack.c index d1ac2cd23..522a1ba73 100644 --- a/shell/cttyhack.c +++ b/shell/cttyhack.c @@ -14,18 +14,22 @@ //config: bool "cttyhack" //config: default y //config: help -//config: One common problem reported on the mailing list is "can't access tty; -//config: job control turned off" error message which typically appears when -//config: one tries to use shell with stdin/stdout opened to /dev/console. +//config: One common problem reported on the mailing list is the "can't +//config: access tty; job control turned off" error message, which typically +//config: appears when one tries to use a shell with stdin/stdout on +//config: /dev/console. //config: This device is special - it cannot be a controlling tty. //config: -//config: Proper solution is to use correct device instead of /dev/console. +//config: The proper solution is to use the correct device instead of +//config: /dev/console. //config: -//config: cttyhack provides "quick and dirty" solution to this problem. +//config: cttyhack provides a "quick and dirty" solution to this problem. //config: It analyzes stdin with various ioctls, trying to determine whether //config: it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line). -//config: If it detects one, it closes stdin/out/err and reopens that device. -//config: Then it executes given program. Opening the device will make +//config: On Linux it also checks sysfs for a pointer to the active console. +//config: If cttyhack is able to find the real console device, it closes +//config: stdin/out/err and reopens that device. +//config: Then it executes the given program. Opening the device will make //config: that device a controlling tty. This may require cttyhack //config: to be a session leader. //config: @@ -115,33 +119,46 @@ int cttyhack_main(int argc UNUSED_PARAM, char **argv) close(fd); } else { /* We don't have ctty (or don't have "/dev/tty" node...) */ - if (0) {} -#ifdef TIOCGSERIAL - else if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { - /* this is a serial console */ - sprintf(console + 8, "S%d", u.sr.line); - } -#endif + do { #ifdef __linux__ - else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { - /* this is linux virtual tty */ - sprintf(console + 8, "S%d" + 1, u.vt.v_active); - } + int s = open_read_close("/sys/class/tty/console/active", + console + 5, sizeof(console) - 5 - 1); + if (s > 0) { + /* found active console via sysfs (Linux 2.6.38+) */ + console[5 + s] = '\0'; + break; + } + + if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { + /* this is linux virtual tty */ + sprintf(console + 8, "S%d" + 1, u.vt.v_active); + break; + } #endif - if (console[8]) { - fd = xopen(console, O_RDWR); - //bb_error_msg("switching to '%s'", console); - dup2(fd, 0); - dup2(fd, 1); - dup2(fd, 2); - while (fd > 2) - close(fd--); - /* Some other session may have it as ctty, - * steal it from them: - */ - ioctl(0, TIOCSCTTY, 1); - } +#ifdef TIOCGSERIAL + if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { + /* this is a serial console, asuming it is named /dev/ttySn */ + sprintf(console + 8, "S%d", u.sr.line); + break; + } +#endif + /* nope, could not find it */ + goto ret; + } while (0); + + fd = xopen(console, O_RDWR); + //bb_error_msg("switching to '%s'", console); + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + while (fd > 2) + close(fd--); + /* Some other session may have it as ctty, + * steal it from them: + */ + ioctl(0, TIOCSCTTY, 1); } +ret: BB_EXECVP_or_die(argv); } -- cgit v1.2.3-55-g6feb From 43a668b2eef5f77d1fe0bee1289cea6649fa793d Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Wed, 13 Jul 2011 09:30:36 +0200 Subject: cttyhack: fail gracefully if the device node is missing Signed-off-by: Kevin Cernekee Signed-off-by: Denys Vlasenko --- shell/cttyhack.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'shell') diff --git a/shell/cttyhack.c b/shell/cttyhack.c index 522a1ba73..4261289b4 100644 --- a/shell/cttyhack.c +++ b/shell/cttyhack.c @@ -146,7 +146,9 @@ int cttyhack_main(int argc UNUSED_PARAM, char **argv) goto ret; } while (0); - fd = xopen(console, O_RDWR); + fd = open_or_warn(console, O_RDWR); + if (fd < 0) + goto ret; //bb_error_msg("switching to '%s'", console); dup2(fd, 0); dup2(fd, 1); -- cgit v1.2.3-55-g6feb From 4fb53fb08ce3da8eac13438ce613df20e523c75d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 1 Aug 2011 14:06:20 +0200 Subject: hush: partially fix wrong expansion on $IFS (bug 4027). In the added testcase, before patch we failed 8 out of 9 tests, now we fail only 2 (4th and 5th). function old new delta expand_on_ifs 225 258 +33 expand_vars_to_list 1038 1054 +16 o_save_ptr_helper 115 119 +4 builtin_umask 132 133 +1 o_addQstr 165 161 -4 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/1 up/down: 54/-4) Total: 50 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 39 +++++++++++++++++------ shell/hush_test/hush-vars/var_expand_on_ifs.right | 9 ++++++ shell/hush_test/hush-vars/var_expand_on_ifs.tests | 11 +++++++ 3 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 shell/hush_test/hush-vars/var_expand_on_ifs.right create mode 100755 shell/hush_test/hush-vars/var_expand_on_ifs.tests (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index 1082738a2..503cb770b 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -2281,7 +2281,7 @@ static void o_addqblock(o_string *o, const char *str, int len) ordinary_cnt = len; o_addblock(o, str, ordinary_cnt); if (ordinary_cnt == len) - return; + return; /* NUL is already added by o_addblock */ str += ordinary_cnt; len -= ordinary_cnt + 1; /* we are processing + 1 char below */ @@ -2295,8 +2295,8 @@ static void o_addqblock(o_string *o, const char *str, int len) o_grow_by(o, sz); o->data[o->length] = ch; o->length++; - o->data[o->length] = '\0'; } + o->data[o->length] = '\0'; } static void o_addQblock(o_string *o, const char *str, int len) @@ -2385,6 +2385,7 @@ static int o_save_ptr_helper(o_string *o, int n) n, string_len, string_start); o->has_empty_slot = 0; } + o->has_quoted_part = 0; list[n] = (char*)(uintptr_t)string_len; return n + 1; } @@ -4754,8 +4755,13 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len static int expand_on_ifs(o_string *output, int n, const char *str) { while (1) { - int word_len = strcspn(str, G.ifs); + int word_len; + + if (!*str) /* EOL - do not finalize word */ + break; + word_len = strcspn(str, G.ifs); if (word_len) { + /* We have WORD_LEN leading non-IFS chars */ if (!(output->o_expflags & EXP_FLAG_GLOB)) { o_addblock(output, str, word_len); } else { @@ -4769,13 +4775,25 @@ static int expand_on_ifs(o_string *output, int n, const char *str) /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ } str += word_len; + if (!*str) /* EOL - do not finalize word */ + break; + goto finalize; /* optimization (can just fall thru) */ + } + /* Case "v=' a'; echo ''$v": we do need to finalize empty word */ + if (output->has_quoted_part + /* Case "v=' a'; echo $v": + * here nothing precedes the space in $v expansion, + * therefore we should not finish the word + * (IOW: if there *is* word to finalize, only then do it) + */ + || (output->length && output->data[output->length - 1]) + ) { + finalize: + o_addchr(output, '\0'); + debug_print_list("expand_on_ifs", output, n); + n = o_save_ptr(output, n); } - if (!*str) /* EOL - do not finalize word */ - break; - o_addchr(output, '\0'); - debug_print_list("expand_on_ifs", output, n); - n = o_save_ptr(output, n); - str += strspn(str, G.ifs); /* skip ifs chars */ + str += strspn(str, G.ifs); /* skip IFS chars */ } debug_print_list("expand_on_ifs[1]", output, n); return n; @@ -5270,11 +5288,13 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) if (G.ifs[0]) o_addchr(output, G.ifs[0]); } + output->has_quoted_part = 1; } break; } case SPECIAL_VAR_SYMBOL: /* */ /* "Empty variable", used to make "" etc to not disappear */ + output->has_quoted_part = 1; arg++; cant_be_null = 0x80; break; @@ -5316,6 +5336,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) val = NULL; } } else { /* quoted $VAR, val will be appended below */ + output->has_quoted_part = 1; debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); } diff --git a/shell/hush_test/hush-vars/var_expand_on_ifs.right b/shell/hush_test/hush-vars/var_expand_on_ifs.right new file mode 100644 index 000000000..2ed2069f7 --- /dev/null +++ b/shell/hush_test/hush-vars/var_expand_on_ifs.right @@ -0,0 +1,9 @@ +1 a b c +2 a + b c +3 a b c +4 a b c +5 a b c +6 a b + c +7 a b c +8 a b c +9 a b c diff --git a/shell/hush_test/hush-vars/var_expand_on_ifs.tests b/shell/hush_test/hush-vars/var_expand_on_ifs.tests new file mode 100755 index 000000000..a12ff8ec8 --- /dev/null +++ b/shell/hush_test/hush-vars/var_expand_on_ifs.tests @@ -0,0 +1,11 @@ +b=' b ' +e='' +echo 1 a $b c +echo 2 a +$b c +echo 3 a $e$b c +echo 4 a "$e"$b c +echo 5 a ""$b c +echo 6 a $b+ c +echo 7 a $b$e c +echo 8 a $b"$e" c +echo 9 a $b"" c -- cgit v1.2.3-55-g6feb From 6e42b89b8d136316e1b97b56cf885e8ef9d64caf Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 1 Aug 2011 18:16:43 +0200 Subject: hush: fix remaining known two bugs with IFS expansion. Closes 4027. function old new delta expand_vars_to_list 1054 1140 +86 parse_stream 2425 2479 +54 expand_on_ifs 258 310 +52 builtin_umask 133 132 -1 done_word 820 779 -41 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/2 up/down: 192/-42) Total: 150 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 82 +++++++++++++++++--------- shell/hush_test/hush-parsing/starquoted2.right | 3 + shell/hush_test/hush-parsing/starquoted2.tests | 6 +- 3 files changed, 61 insertions(+), 30 deletions(-) (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index 503cb770b..6b3027771 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -3265,14 +3265,6 @@ static int done_word(o_string *word, struct parse_context *ctx) ) { p += 3; } - if (p == word->data || p[0] != '\0') { - /* saw no "$@", or not only "$@" but some - * real text is there too */ - /* insert "empty variable" reference, this makes - * e.g. "", $empty"" etc to not disappear */ - o_addchr(word, SPECIAL_VAR_SYMBOL); - o_addchr(word, SPECIAL_VAR_SYMBOL); - } } command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); debug_print_strings("word appended to argv", command->argv); @@ -4516,20 +4508,30 @@ static struct pipe *parse_stream(char **pstring, break; case '\'': dest.has_quoted_part = 1; - while (1) { - ch = i_getch(input); - if (ch == EOF) { - syntax_error_unterm_ch('\''); - goto parse_error; + if (next == '\'' && !ctx.pending_redirect) { + insert_empty_quoted_str_marker: + nommu_addchr(&ctx.as_string, next); + i_getch(input); /* eat second ' */ + o_addchr(&dest, SPECIAL_VAR_SYMBOL); + o_addchr(&dest, SPECIAL_VAR_SYMBOL); + } else { + while (1) { + ch = i_getch(input); + if (ch == EOF) { + syntax_error_unterm_ch('\''); + goto parse_error; + } + nommu_addchr(&ctx.as_string, ch); + if (ch == '\'') + break; + o_addqchr(&dest, ch); } - nommu_addchr(&ctx.as_string, ch); - if (ch == '\'') - break; - o_addqchr(&dest, ch); } break; case '"': dest.has_quoted_part = 1; + if (next == '"' && !ctx.pending_redirect) + goto insert_empty_quoted_str_marker; if (dest.o_assignment == NOT_ASSIGNMENT) dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) @@ -4751,9 +4753,14 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len /* Store given string, finalizing the word and starting new one whenever * we encounter IFS char(s). This is used for expanding variable values. - * End-of-string does NOT finalize word: think about 'echo -$VAR-' */ -static int expand_on_ifs(o_string *output, int n, const char *str) + * End-of-string does NOT finalize word: think about 'echo -$VAR-'. + * Return in *ended_with_ifs: + * 1 - ended with IFS char, else 0 (this includes case of empty str). + */ +static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const char *str) { + int last_is_ifs = 0; + while (1) { int word_len; @@ -4774,27 +4781,36 @@ static int expand_on_ifs(o_string *output, int n, const char *str) /*o_addblock(output, str, word_len); - WRONG: "v='\*'; echo Z$v" prints "Z*" instead of "Z\*" */ /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ } + last_is_ifs = 0; str += word_len; if (!*str) /* EOL - do not finalize word */ break; - goto finalize; /* optimization (can just fall thru) */ } - /* Case "v=' a'; echo ''$v": we do need to finalize empty word */ + + /* We know str here points to at least one IFS char */ + last_is_ifs = 1; + str += strspn(str, G.ifs); /* skip IFS chars */ + if (!*str) /* EOL - do not finalize word */ + break; + + /* Start new word... but not always! */ + /* Case "v=' a'; echo ''$v": we do need to finalize empty word: */ if (output->has_quoted_part /* Case "v=' a'; echo $v": * here nothing precedes the space in $v expansion, * therefore we should not finish the word - * (IOW: if there *is* word to finalize, only then do it) + * (IOW: if there *is* word to finalize, only then do it): */ - || (output->length && output->data[output->length - 1]) + || (n > 0 && output->data[output->length - 1]) ) { - finalize: o_addchr(output, '\0'); debug_print_list("expand_on_ifs", output, n); n = o_save_ptr(output, n); } - str += strspn(str, G.ifs); /* skip IFS chars */ } + + if (ended_with_ifs) + *ended_with_ifs = last_is_ifs; debug_print_list("expand_on_ifs[1]", output, n); return n; } @@ -5209,6 +5225,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) * expansion of right-hand side of assignment == 1-element expand. */ char cant_be_null = 0; /* only bit 0x80 matters */ + int ended_in_ifs = 0; /* did last unquoted expansion end with IFS chars? */ char *p; debug_printf_expand("expand_vars_to_list: arg:'%s' singleword:%x\n", arg, @@ -5227,6 +5244,13 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) #if ENABLE_SH_MATH_SUPPORT char arith_buf[sizeof(arith_t)*3 + 2]; #endif + + if (ended_in_ifs) { + o_addchr(output, '\0'); + n = o_save_ptr(output, n); + ended_in_ifs = 0; + } + o_addblock(output, arg, p - arg); debug_print_list("expand_vars_to_list[1]", output, n); arg = ++p; @@ -5255,7 +5279,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) cant_be_null |= first_ch; /* do it for "$@" _now_, when we know it's not empty */ if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ while (G.global_argv[i]) { - n = expand_on_ifs(output, n, G.global_argv[i]); + n = expand_on_ifs(NULL, output, n, G.global_argv[i]); debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1); if (G.global_argv[i++][0] && G.global_argv[i]) { /* this argv[] is not empty and not last: @@ -5332,7 +5356,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val, !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); if (val && val[0]) { - n = expand_on_ifs(output, n, val); + n = expand_on_ifs(&ended_in_ifs, output, n, val); val = NULL; } } else { /* quoted $VAR, val will be appended below */ @@ -5361,6 +5385,10 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */ if (arg[0]) { + if (ended_in_ifs) { + o_addchr(output, '\0'); + n = o_save_ptr(output, n); + } debug_print_list("expand_vars_to_list[a]", output, n); /* this part is literal, and it was already pre-quoted * if needed (much earlier), do not use o_addQstr here! */ diff --git a/shell/hush_test/hush-parsing/starquoted2.right b/shell/hush_test/hush-parsing/starquoted2.right index e1562ed6d..1bff408ca 100644 --- a/shell/hush_test/hush-parsing/starquoted2.right +++ b/shell/hush_test/hush-parsing/starquoted2.right @@ -1,4 +1,7 @@ Should be printed +Would not be printed by bash +Would not be printed by bash +Would not be printed by bash Should be printed Empty: Empty: diff --git a/shell/hush_test/hush-parsing/starquoted2.tests b/shell/hush_test/hush-parsing/starquoted2.tests index f305c4cd9..7c5ff45b8 100755 --- a/shell/hush_test/hush-parsing/starquoted2.tests +++ b/shell/hush_test/hush-parsing/starquoted2.tests @@ -8,9 +8,9 @@ for a in "$@"; do echo Should not be printed; done # Yes, believe it or not, bash is mesmerized by "$@" and stops # treating "" as "this word cannot be expanded to nothing, # but must be at least null string". Now it can be expanded to nothing. -for a in "$@"""; do echo Should not be printed; done -for a in """$@"; do echo Should not be printed; done -for a in """$@"''"$@"''; do echo Should not be printed; done +for a in "$@"""; do echo Would not be printed by bash; done +for a in """$@"; do echo Would not be printed by bash; done +for a in """$@"''"$@"''; do echo Would not be printed by bash; done for a in ""; do echo Should be printed; done # Bug 207: "$@" expands to nothing, and we erroneously glob "%s\n" twice: -- cgit v1.2.3-55-g6feb From b347df91317ca05910e930c94fdba30baf9e2de8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 9 Aug 2011 22:49:15 +0200 Subject: randomconfig fixes Signed-off-by: Denys Vlasenko --- shell/hush.c | 12 ++++++------ util-linux/fdisk.c | 56 +++++++++++++++++++++++++++++++----------------------- 2 files changed, 38 insertions(+), 30 deletions(-) (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index 6b3027771..e4138adf7 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -5519,12 +5519,6 @@ static char **expand_assignments(char **argv, int count) } -#if BB_MMU -/* never called */ -void re_execute_shell(char ***to_free, const char *s, - char *g_argv0, char **g_argv, - char **builtin_argv) NORETURN; - static void switch_off_special_sigs(unsigned mask) { unsigned sig = 0; @@ -5544,6 +5538,12 @@ static void switch_off_special_sigs(unsigned mask) } } +#if BB_MMU +/* never called */ +void re_execute_shell(char ***to_free, const char *s, + char *g_argv0, char **g_argv, + char **builtin_argv) NORETURN; + static void reset_traps_to_defaults(void) { /* This function is always called in a child shell diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index 976558693..c0be15a3a 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c @@ -201,6 +201,7 @@ enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN }; static void update_units(void); #if ENABLE_FEATURE_FDISK_WRITABLE static void change_units(void); +static void reread_partition_table(int leave); static void delete_partition(int i); static unsigned get_partition(int warn, unsigned max); static void list_types(const char *const *sys); @@ -2541,6 +2542,35 @@ new_partition(void) } } +static void +reread_partition_table(int leave) +{ + int i; + + printf("Calling ioctl() to re-read partition table\n"); + sync(); + /* Users with slow external USB disks on a 320MHz ARM system (year 2011) + * report that sleep is needed, otherwise BLKRRPART may fail with -EIO: + */ + sleep(1); + i = ioctl_or_perror(dev_fd, BLKRRPART, NULL, + "WARNING: rereading partition table " + "failed, kernel still uses old table"); +#if 0 + if (dos_changed) + printf( + "\nWARNING: If you have created or modified any DOS 6.x\n" + "partitions, please see the fdisk manual page for additional\n" + "information\n"); +#endif + + if (leave) { + if (ENABLE_FEATURE_CLEAN_UP) + close_dev_fd(); + exit(i != 0); + } +} + static void write_table(void) { @@ -2571,30 +2601,8 @@ write_table(void) } } - printf( - "The partition table has been altered.\n" - "Calling ioctl(BLKRRPART) to re-read partition table.\n" - ); - - sync(); - /* Users with slow external USB disks on a 320MHz ARM system (year 2011) - * report that sleep is needed, otherwise BLKRRPART may fail with -EIO: - */ - sleep(1); - i = ioctl_or_perror(dev_fd, BLKRRPART, NULL, - "WARNING: rereading partition table " - "failed, kernel still uses old table"); -#if 0 - if (dos_changed) - printf( - "\nWARNING: If you have created or modified any DOS 6.x\n" - "partitions, please see the fdisk manual page for additional\n" - "information\n"); -#endif - - if (ENABLE_FEATURE_CLEAN_UP) - close_dev_fd(); - exit(i != 0); + printf("The partition table has been altered.\n"); + reread_partition_table(1); } #endif /* FEATURE_FDISK_WRITABLE */ -- cgit v1.2.3-55-g6feb