diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-11 12:56:43 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-11 12:56:43 +0000 |
commit | 3e9aaae5dc384ae070c49507a92b1375397954cd (patch) | |
tree | 048661e5d8448c8cb39a4453fe36f4e6c8746384 /shell/hush.c | |
parent | e0a336747c2061d0d555c4e15287b513831d2947 (diff) | |
download | busybox-w32-3e9aaae5dc384ae070c49507a92b1375397954cd.tar.gz busybox-w32-3e9aaae5dc384ae070c49507a92b1375397954cd.tar.bz2 busybox-w32-3e9aaae5dc384ae070c49507a92b1375397954cd.zip |
hush: fix bug in interactive shell introduced yesterday
hush: fix `process subst` (2 bugs)
NB: will delete and re-add hush_test in order to change file modes
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 88 |
1 files changed, 46 insertions, 42 deletions
diff --git a/shell/hush.c b/shell/hush.c index 32cd65c72..04fb00dc7 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -317,10 +317,10 @@ typedef struct { | |||
317 | /* I can almost use ordinary FILE *. Is open_memstream() universally | 317 | /* I can almost use ordinary FILE *. Is open_memstream() universally |
318 | * available? Where is it documented? */ | 318 | * available? Where is it documented? */ |
319 | struct in_str { | 319 | struct in_str { |
320 | union { | 320 | const char *p; |
321 | const char *p; | 321 | /* eof_flag=1: last char in ->p is really an EOF */ |
322 | int cached_ch; | 322 | char eof_flag; /* meaningless if ->p == NULL */ |
323 | }; | 323 | char peek_buf[2]; |
324 | #if ENABLE_HUSH_INTERACTIVE | 324 | #if ENABLE_HUSH_INTERACTIVE |
325 | int __promptme; | 325 | int __promptme; |
326 | int promptmode; | 326 | int promptmode; |
@@ -976,7 +976,7 @@ static int b_check_space(o_string *o, int len) | |||
976 | 976 | ||
977 | static int b_addchr(o_string *o, int ch) | 977 | static int b_addchr(o_string *o, int ch) |
978 | { | 978 | { |
979 | debug_printf("b_addchr: %c %d %p\n", ch, o->length, o); | 979 | debug_printf("b_addchr: '%c' o->lengtt=%d o=%p\n", ch, o->length, o); |
980 | if (b_check_space(o, 1)) | 980 | if (b_check_space(o, 1)) |
981 | return B_NOSPAC; | 981 | return B_NOSPAC; |
982 | o->data[o->length] = ch; | 982 | o->data[o->length] = ch; |
@@ -1079,12 +1079,13 @@ static const char* setup_prompt_string(int promptmode) | |||
1079 | static line_input_t *line_input_state; | 1079 | static line_input_t *line_input_state; |
1080 | #endif | 1080 | #endif |
1081 | 1081 | ||
1082 | static int get_user_input(struct in_str *i) | 1082 | static void get_user_input(struct in_str *i) |
1083 | { | 1083 | { |
1084 | static char the_command[ENABLE_FEATURE_EDITING ? BUFSIZ : 2]; | 1084 | static char the_command[ENABLE_FEATURE_EDITING ? BUFSIZ : 2]; |
1085 | 1085 | ||
1086 | int r; | 1086 | int r; |
1087 | const char *prompt_str; | 1087 | const char *prompt_str; |
1088 | |||
1088 | prompt_str = setup_prompt_string(i->promptmode); | 1089 | prompt_str = setup_prompt_string(i->promptmode); |
1089 | #if ENABLE_FEATURE_EDITING | 1090 | #if ENABLE_FEATURE_EDITING |
1090 | /* | 1091 | /* |
@@ -1094,15 +1095,19 @@ static int get_user_input(struct in_str *i) | |||
1094 | ** child processes (rob@sysgo.de) | 1095 | ** child processes (rob@sysgo.de) |
1095 | */ | 1096 | */ |
1096 | r = read_line_input(prompt_str, the_command, BUFSIZ-1, line_input_state); | 1097 | r = read_line_input(prompt_str, the_command, BUFSIZ-1, line_input_state); |
1098 | i->eof_flag = (r < 0); | ||
1099 | if (i->eof_flag) { /* EOF/error detected */ | ||
1100 | the_command[0] = EOF; /* yes, it will be truncated, it's ok */ | ||
1101 | the_command[1] = '\0'; | ||
1102 | } | ||
1097 | #else | 1103 | #else |
1098 | fputs(prompt_str, stdout); | 1104 | fputs(prompt_str, stdout); |
1099 | fflush(stdout); | 1105 | fflush(stdout); |
1100 | the_command[0] = r = fgetc(i->file); | 1106 | the_command[0] = r = fgetc(i->file); |
1101 | /*the_command[1] = '\0'; - already is and never changed */ | 1107 | /*the_command[1] = '\0'; - already is and never changed */ |
1108 | i->eof_flag = (r == EOF); | ||
1102 | #endif | 1109 | #endif |
1103 | fflush(stdout); | ||
1104 | i->p = the_command; | 1110 | i->p = the_command; |
1105 | return r; /* < 0 == EOF. Not meaningful otherwise */ | ||
1106 | } | 1111 | } |
1107 | #endif /* INTERACTIVE */ | 1112 | #endif /* INTERACTIVE */ |
1108 | 1113 | ||
@@ -1112,33 +1117,30 @@ static int file_get(struct in_str *i) | |||
1112 | { | 1117 | { |
1113 | int ch; | 1118 | int ch; |
1114 | 1119 | ||
1115 | ch = 0; | ||
1116 | /* If there is data waiting, eat it up */ | 1120 | /* If there is data waiting, eat it up */ |
1117 | if (i->cached_ch) { | 1121 | if (i->p && *i->p) { |
1118 | ch = i->cached_ch ^ 0x100; | 1122 | take_cached: |
1119 | if (ch != EOF) | 1123 | ch = *i->p++; |
1120 | i->cached_ch = 0; | 1124 | if (i->eof_flag && !*i->p) |
1125 | ch = EOF; | ||
1121 | } else { | 1126 | } else { |
1122 | /* need to double check i->file because we might be doing something | 1127 | /* need to double check i->file because we might be doing something |
1123 | * more complicated by now, like sourcing or substituting. */ | 1128 | * more complicated by now, like sourcing or substituting. */ |
1124 | #if ENABLE_HUSH_INTERACTIVE | 1129 | #if ENABLE_HUSH_INTERACTIVE |
1125 | if (interactive_fd && i->__promptme && i->file == stdin) { | 1130 | if (interactive_fd && i->__promptme && i->file == stdin) { |
1126 | while (!i->p || !(interactive_fd && i->p[0])) { | 1131 | do { |
1127 | if (get_user_input(i) < 0) | 1132 | get_user_input(i); |
1128 | return EOF; | 1133 | } while (!*i->p); /* need non-empty line */ |
1129 | } | ||
1130 | i->promptmode = 2; | 1134 | i->promptmode = 2; |
1131 | i->__promptme = 0; | 1135 | i->__promptme = 0; |
1132 | if (i->p && *i->p) { | 1136 | goto take_cached; |
1133 | ch = *i->p++; | ||
1134 | } | ||
1135 | } else | 1137 | } else |
1136 | #endif | 1138 | #endif |
1137 | { | 1139 | { |
1138 | ch = fgetc(i->file); | 1140 | ch = fgetc(i->file); |
1139 | } | 1141 | } |
1140 | debug_printf("file_get: got a %d\n", ch); | ||
1141 | } | 1142 | } |
1143 | debug_printf("file_get: got a '%c' %d\n", ch, ch); | ||
1142 | #if ENABLE_HUSH_INTERACTIVE | 1144 | #if ENABLE_HUSH_INTERACTIVE |
1143 | if (ch == '\n') | 1145 | if (ch == '\n') |
1144 | i->__promptme = 1; | 1146 | i->__promptme = 1; |
@@ -1152,12 +1154,17 @@ static int file_get(struct in_str *i) | |||
1152 | static int file_peek(struct in_str *i) | 1154 | static int file_peek(struct in_str *i) |
1153 | { | 1155 | { |
1154 | int ch; | 1156 | int ch; |
1155 | if (i->cached_ch) { | 1157 | if (i->p && *i->p) { |
1156 | return i->cached_ch ^ 0x100; | 1158 | if (i->eof_flag && !i->p[1]) |
1159 | return EOF; | ||
1160 | return *i->p; | ||
1157 | } | 1161 | } |
1158 | ch = fgetc(i->file); | 1162 | ch = fgetc(i->file); |
1159 | i->cached_ch = ch ^ 0x100; /* ^ 0x100 so that it is never 0 */ | 1163 | i->eof_flag = (ch == EOF); |
1160 | debug_printf("file_peek: got a %d '%c'\n", ch, ch); | 1164 | i->peek_buf[0] = ch; |
1165 | i->peek_buf[1] = '\0'; | ||
1166 | i->p = i->peek_buf; | ||
1167 | debug_printf("file_peek: got a '%c' %d\n", *i->p, *i->p); | ||
1161 | return ch; | 1168 | return ch; |
1162 | } | 1169 | } |
1163 | 1170 | ||
@@ -1182,6 +1189,7 @@ static void setup_string_in_str(struct in_str *i, const char *s) | |||
1182 | i->promptmode = 1; | 1189 | i->promptmode = 1; |
1183 | #endif | 1190 | #endif |
1184 | i->p = s; | 1191 | i->p = s; |
1192 | i->eof_flag = 0; | ||
1185 | } | 1193 | } |
1186 | 1194 | ||
1187 | static void mark_open(int fd) | 1195 | static void mark_open(int fd) |
@@ -2846,11 +2854,12 @@ static FILE *generate_stream_from_list(struct pipe *head) | |||
2846 | static int process_command_subs(o_string *dest, struct p_context *ctx, | 2854 | static int process_command_subs(o_string *dest, struct p_context *ctx, |
2847 | struct in_str *input, const char *subst_end) | 2855 | struct in_str *input, const char *subst_end) |
2848 | { | 2856 | { |
2849 | int retcode; | 2857 | int retcode, ch, eol_cnt; |
2850 | o_string result = NULL_O_STRING; | 2858 | o_string result = NULL_O_STRING; |
2851 | struct p_context inner; | 2859 | struct p_context inner; |
2852 | FILE *p; | 2860 | FILE *p; |
2853 | struct in_str pipe_str; | 2861 | struct in_str pipe_str; |
2862 | |||
2854 | initialize_context(&inner); | 2863 | initialize_context(&inner); |
2855 | 2864 | ||
2856 | /* recursion to generate command */ | 2865 | /* recursion to generate command */ |
@@ -2863,25 +2872,20 @@ static int process_command_subs(o_string *dest, struct p_context *ctx, | |||
2863 | p = generate_stream_from_list(inner.list_head); | 2872 | p = generate_stream_from_list(inner.list_head); |
2864 | if (p == NULL) return 1; | 2873 | if (p == NULL) return 1; |
2865 | mark_open(fileno(p)); | 2874 | mark_open(fileno(p)); |
2866 | // FIXME: need to flag pipe_str to somehow discard all trailing newlines. | ||
2867 | // Example: echo "TEST`date;echo;echo`BEST" | ||
2868 | // must produce one line: TEST<date>BEST | ||
2869 | setup_file_in_str(&pipe_str, p); | 2875 | setup_file_in_str(&pipe_str, p); |
2870 | 2876 | ||
2871 | /* now send results of command back into original context */ | 2877 | /* now send results of command back into original context */ |
2872 | // FIXME: must not do quote parsing of the output! | 2878 | eol_cnt = 0; |
2873 | // Example: echo "TEST`echo '$(echo ZZ)'`BEST" | 2879 | while ((ch = b_getch(&pipe_str)) != EOF) { |
2874 | // must produce TEST$(echo ZZ)BEST, not TESTZZBEST. | 2880 | if (ch == '\n') { |
2875 | // Example: echo "TEST`echo "'"`BEST" | 2881 | eol_cnt++; |
2876 | // must produce TEST'BEST | 2882 | continue; |
2877 | // (maybe by setting all chars flagged as literals in map[]?) | 2883 | } |
2878 | 2884 | while (eol_cnt) { | |
2879 | retcode = parse_stream(dest, ctx, &pipe_str, NULL); | 2885 | b_addqchr(dest, '\n', dest->quote); |
2880 | /* XXX In case of a syntax error, should we try to kill the child? | 2886 | eol_cnt--; |
2881 | * That would be tough to do right, so just read until EOF. */ | 2887 | } |
2882 | if (retcode == 1) { | 2888 | b_addqchr(dest, ch, dest->quote); |
2883 | while (b_getch(&pipe_str) != EOF) | ||
2884 | /* discard */; | ||
2885 | } | 2889 | } |
2886 | 2890 | ||
2887 | debug_printf("done reading from pipe, pclose()ing\n"); | 2891 | debug_printf("done reading from pipe, pclose()ing\n"); |