diff options
author | Eric Andersen <andersen@codepoet.org> | 2001-06-21 16:38:11 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2001-06-21 16:38:11 +0000 |
commit | 8a646dd2933bc37e67e1b09fd3461816e38fc677 (patch) | |
tree | f2e436f413c07809fe5b8f21c3eb5b86e309ee11 | |
parent | ea4abff59530709ae423482220f65e37ecd1ac24 (diff) | |
download | busybox-w32-8a646dd2933bc37e67e1b09fd3461816e38fc677.tar.gz busybox-w32-8a646dd2933bc37e67e1b09fd3461816e38fc677.tar.bz2 busybox-w32-8a646dd2933bc37e67e1b09fd3461816e38fc677.zip |
This commit guts lash, restoring it to what it was originally intended to do,
just be a simple command line interpreter with basic pipe, redirect, and job
control. For all the more fancy things, people should use hush or ash.
-Erik
-rw-r--r-- | lash.c | 614 | ||||
-rw-r--r-- | shell/lash.c | 614 |
2 files changed, 64 insertions, 1164 deletions
@@ -25,30 +25,10 @@ | |||
25 | * | 25 | * |
26 | */ | 26 | */ |
27 | 27 | ||
28 | /* The parsing engine of this program is officially at a dead-end. | 28 | /* This shell's parsing engine is officially at a dead-end. |
29 | * Future work in that direction should move to the work posted | 29 | * Future work shell work should be done using hush.c |
30 | * at http://doolittle.faludi.com/~larry/parser.html . | ||
31 | * A start on the integration of that work with the rest of sh.c | ||
32 | * is at http://codepoet.org/sh.c . | ||
33 | */ | 30 | */ |
34 | // | 31 | |
35 | //This works pretty well now, and is now on by default. | ||
36 | #define BB_FEATURE_SH_ENVIRONMENT | ||
37 | // | ||
38 | //Backtick support has some problems, use at your own risk! | ||
39 | //#define BB_FEATURE_SH_BACKTICKS | ||
40 | // | ||
41 | //If, then, else, etc. support.. This should now behave basically | ||
42 | //like any other Bourne shell -- sortof... | ||
43 | #define BB_FEATURE_SH_IF_EXPRESSIONS | ||
44 | // | ||
45 | /* This is currently sortof broken, only for the brave... */ | ||
46 | #undef HANDLE_CONTINUATION_CHARS | ||
47 | // | ||
48 | /* This would be great -- if wordexp wouldn't strip all quoting | ||
49 | * out from the target strings... As is, a parser needs */ | ||
50 | #undef BB_FEATURE_SH_WORDEXP | ||
51 | // | ||
52 | //For debugging/development on the shell only... | 32 | //For debugging/development on the shell only... |
53 | //#define DEBUG_SHELL | 33 | //#define DEBUG_SHELL |
54 | 34 | ||
@@ -71,16 +51,8 @@ | |||
71 | #include <locale.h> | 51 | #include <locale.h> |
72 | #endif | 52 | #endif |
73 | 53 | ||
74 | //#define BB_FEATURE_SH_WORDEXP | ||
75 | |||
76 | #ifdef BB_FEATURE_SH_WORDEXP | ||
77 | #include <wordexp.h> | ||
78 | #define expand_t wordexp_t | ||
79 | #undef BB_FEATURE_SH_BACKTICKS | ||
80 | #else | ||
81 | #include <glob.h> | 54 | #include <glob.h> |
82 | #define expand_t glob_t | 55 | #define expand_t glob_t |
83 | #endif | ||
84 | 56 | ||
85 | 57 | ||
86 | static const int MAX_READ = 128; /* size of input buffer for `read' builtin */ | 58 | static const int MAX_READ = 128; /* size of input buffer for `read' builtin */ |
@@ -155,14 +127,6 @@ static int builtin_export(struct child_prog *cmd); | |||
155 | static int builtin_source(struct child_prog *cmd); | 127 | static int builtin_source(struct child_prog *cmd); |
156 | static int builtin_unset(struct child_prog *cmd); | 128 | static int builtin_unset(struct child_prog *cmd); |
157 | static int builtin_read(struct child_prog *cmd); | 129 | static int builtin_read(struct child_prog *cmd); |
158 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
159 | static int builtin_if(struct child_prog *cmd); | ||
160 | static int builtin_then(struct child_prog *cmd); | ||
161 | static int builtin_else(struct child_prog *cmd); | ||
162 | static int builtin_fi(struct child_prog *cmd); | ||
163 | /* function prototypes for shell stuff */ | ||
164 | static int run_command_predicate(char *cmd); | ||
165 | #endif | ||
166 | 130 | ||
167 | 131 | ||
168 | /* function prototypes for shell stuff */ | 132 | /* function prototypes for shell stuff */ |
@@ -192,12 +156,6 @@ static struct built_in_command bltins[] = { | |||
192 | {"read", "Input environment variable", builtin_read}, | 156 | {"read", "Input environment variable", builtin_read}, |
193 | {".", "Source-in and run commands in a file", builtin_source}, | 157 | {".", "Source-in and run commands in a file", builtin_source}, |
194 | /* to do: add ulimit */ | 158 | /* to do: add ulimit */ |
195 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
196 | {"if", NULL, builtin_if}, | ||
197 | {"then", NULL, builtin_then}, | ||
198 | {"else", NULL, builtin_else}, | ||
199 | {"fi", NULL, builtin_fi}, | ||
200 | #endif | ||
201 | {NULL, NULL, NULL} | 159 | {NULL, NULL, NULL} |
202 | }; | 160 | }; |
203 | 161 | ||
@@ -222,14 +180,7 @@ static struct jobset job_list = { NULL, NULL }; | |||
222 | static int argc; | 180 | static int argc; |
223 | static char **argv; | 181 | static char **argv; |
224 | static struct close_me *close_me_head; | 182 | static struct close_me *close_me_head; |
225 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 183 | static unsigned int last_jobid; |
226 | static int last_bg_pid; | ||
227 | static int last_return_code; | ||
228 | static int show_x_trace; | ||
229 | #endif | ||
230 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
231 | static char syntax_err[]="syntax error near unexpected token"; | ||
232 | #endif | ||
233 | 184 | ||
234 | static char *PS1; | 185 | static char *PS1; |
235 | static char *PS2 = "> "; | 186 | static char *PS2 = "> "; |
@@ -266,14 +217,6 @@ export cmd->progs[0] | |||
266 | source cmd->progs[0] | 217 | source cmd->progs[0] |
267 | unset cmd->progs[0] | 218 | unset cmd->progs[0] |
268 | read cmd->progs[0] | 219 | read cmd->progs[0] |
269 | if cmd->job_context, cmd->text | ||
270 | then cmd->job_context, cmd->text | ||
271 | else cmd->job_context, cmd->text | ||
272 | fi cmd->job_context | ||
273 | |||
274 | The use of cmd->text by if/then/else/fi is hopelessly hacky. | ||
275 | Would it work to increment cmd->progs[0]->argv and recurse, | ||
276 | somewhat like builtin_exec does? | ||
277 | 220 | ||
278 | I added "struct job *family;" to struct child_prog, | 221 | I added "struct job *family;" to struct child_prog, |
279 | and switched API to builtin_foo(struct child_prog *child); | 222 | and switched API to builtin_foo(struct child_prog *child); |
@@ -325,31 +268,34 @@ static int builtin_exit(struct child_prog *child) | |||
325 | /* built-in 'fg' and 'bg' handler */ | 268 | /* built-in 'fg' and 'bg' handler */ |
326 | static int builtin_fg_bg(struct child_prog *child) | 269 | static int builtin_fg_bg(struct child_prog *child) |
327 | { | 270 | { |
328 | int i, jobNum; | 271 | int i, jobnum; |
329 | struct job *job=NULL; | 272 | struct job *job=NULL; |
330 | |||
331 | if (!child->argv[1] || child->argv[2]) { | ||
332 | error_msg("%s: exactly one argument is expected", | ||
333 | child->argv[0]); | ||
334 | return EXIT_FAILURE; | ||
335 | } | ||
336 | |||
337 | if (sscanf(child->argv[1], "%%%d", &jobNum) != 1) { | ||
338 | error_msg("%s: bad argument '%s'", | ||
339 | child->argv[0], child->argv[1]); | ||
340 | return EXIT_FAILURE; | ||
341 | } | ||
342 | 273 | ||
343 | for (job = child->family->job_list->head; job; job = job->next) { | 274 | /* If they gave us no args, assume they want the last backgrounded task */ |
344 | if (job->jobid == jobNum) { | 275 | if (!child->argv[1]) { |
345 | break; | 276 | for (job = child->family->job_list->head; job; job = job->next) { |
277 | if (job->jobid == last_jobid) { | ||
278 | break; | ||
279 | } | ||
280 | } | ||
281 | if (!job) { | ||
282 | error_msg("%s: no current job", child->argv[0]); | ||
283 | return EXIT_FAILURE; | ||
284 | } | ||
285 | } else { | ||
286 | if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { | ||
287 | error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]); | ||
288 | return EXIT_FAILURE; | ||
289 | } | ||
290 | for (job = child->family->job_list->head; job; job = job->next) { | ||
291 | if (job->jobid == jobnum) { | ||
292 | break; | ||
293 | } | ||
294 | } | ||
295 | if (!job) { | ||
296 | error_msg("%s: %d: no such job", child->argv[0], jobnum); | ||
297 | return EXIT_FAILURE; | ||
346 | } | 298 | } |
347 | } | ||
348 | |||
349 | if (!job) { | ||
350 | error_msg("%s: unknown job %d", | ||
351 | child->argv[0], jobNum); | ||
352 | return EXIT_FAILURE; | ||
353 | } | 299 | } |
354 | 300 | ||
355 | if (*child->argv[0] == 'f') { | 301 | if (*child->argv[0] == 'f') { |
@@ -485,102 +431,6 @@ static int builtin_read(struct child_prog *child) | |||
485 | return (res); | 431 | return (res); |
486 | } | 432 | } |
487 | 433 | ||
488 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
489 | /* Built-in handler for 'if' commands */ | ||
490 | static int builtin_if(struct child_prog *child) | ||
491 | { | ||
492 | struct job *cmd = child->family; | ||
493 | int status; | ||
494 | char* charptr1=cmd->text+3; /* skip over the leading 'if ' */ | ||
495 | |||
496 | /* Now run the 'if' command */ | ||
497 | debug_printf( "job=%p entering builtin_if ('%s')-- context=%d\n", cmd, charptr1, cmd->job_context); | ||
498 | status = run_command_predicate(charptr1); | ||
499 | debug_printf( "if test returned "); | ||
500 | if (status == 0) { | ||
501 | debug_printf( "TRUE\n"); | ||
502 | cmd->job_context |= IF_TRUE_CONTEXT; | ||
503 | } else { | ||
504 | debug_printf( "FALSE\n"); | ||
505 | cmd->job_context |= IF_FALSE_CONTEXT; | ||
506 | } | ||
507 | debug_printf("job=%p builtin_if set job context to %x\n", cmd, cmd->job_context); | ||
508 | shell_context++; | ||
509 | |||
510 | return status; | ||
511 | } | ||
512 | |||
513 | /* Built-in handler for 'then' (part of the 'if' command) */ | ||
514 | static int builtin_then(struct child_prog *child) | ||
515 | { | ||
516 | struct job *cmd = child->family; | ||
517 | char* charptr1=cmd->text+5; /* skip over the leading 'then ' */ | ||
518 | |||
519 | debug_printf( "job=%p entering builtin_then ('%s')-- context=%d\n", cmd, charptr1, cmd->job_context); | ||
520 | if (! (cmd->job_context & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { | ||
521 | shell_context = 0; /* Reset the shell's context on an error */ | ||
522 | error_msg("%s `then'", syntax_err); | ||
523 | return EXIT_FAILURE; | ||
524 | } | ||
525 | |||
526 | cmd->job_context |= THEN_EXP_CONTEXT; | ||
527 | debug_printf("job=%p builtin_then set job context to %x\n", cmd, cmd->job_context); | ||
528 | |||
529 | /* If the if result was FALSE, skip the 'then' stuff */ | ||
530 | if (cmd->job_context & IF_FALSE_CONTEXT) { | ||
531 | return EXIT_SUCCESS; | ||
532 | } | ||
533 | |||
534 | /* Seems the if result was TRUE, so run the 'then' command */ | ||
535 | debug_printf( "'then' now running '%s'\n", charptr1); | ||
536 | |||
537 | return(run_command_predicate(charptr1)); | ||
538 | } | ||
539 | |||
540 | /* Built-in handler for 'else' (part of the 'if' command) */ | ||
541 | static int builtin_else(struct child_prog *child) | ||
542 | { | ||
543 | struct job *cmd = child->family; | ||
544 | char* charptr1=cmd->text+5; /* skip over the leading 'else ' */ | ||
545 | |||
546 | debug_printf( "job=%p entering builtin_else ('%s')-- context=%d\n", cmd, charptr1, cmd->job_context); | ||
547 | |||
548 | if (! (cmd->job_context & THEN_EXP_CONTEXT)) { | ||
549 | shell_context = 0; /* Reset the shell's context on an error */ | ||
550 | error_msg("%s `else'", syntax_err); | ||
551 | return EXIT_FAILURE; | ||
552 | } | ||
553 | /* If the if result was TRUE, skip the 'else' stuff */ | ||
554 | if (cmd->job_context & IF_TRUE_CONTEXT) { | ||
555 | return EXIT_SUCCESS; | ||
556 | } | ||
557 | |||
558 | cmd->job_context |= ELSE_EXP_CONTEXT; | ||
559 | debug_printf("job=%p builtin_else set job context to %x\n", cmd, cmd->job_context); | ||
560 | |||
561 | /* Now run the 'else' command */ | ||
562 | debug_printf( "'else' now running '%s'\n", charptr1); | ||
563 | return(run_command_predicate(charptr1)); | ||
564 | } | ||
565 | |||
566 | /* Built-in handler for 'fi' (part of the 'if' command) */ | ||
567 | static int builtin_fi(struct child_prog *child) | ||
568 | { | ||
569 | struct job *cmd = child->family; | ||
570 | debug_printf( "job=%p entering builtin_fi ('%s')-- context=%d\n", cmd, "", cmd->job_context); | ||
571 | if (! (cmd->job_context & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { | ||
572 | shell_context = 0; /* Reset the shell's context on an error */ | ||
573 | error_msg("%s `fi'", syntax_err); | ||
574 | return EXIT_FAILURE; | ||
575 | } | ||
576 | /* Clear out the if and then context bits */ | ||
577 | cmd->job_context &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT); | ||
578 | debug_printf("job=%p builtin_fi set job context to %x\n", cmd, cmd->job_context); | ||
579 | shell_context--; | ||
580 | return EXIT_SUCCESS; | ||
581 | } | ||
582 | #endif | ||
583 | |||
584 | /* Built-in '.' handler (read-in and execute commands from file) */ | 434 | /* Built-in '.' handler (read-in and execute commands from file) */ |
585 | static int builtin_source(struct child_prog *child) | 435 | static int builtin_source(struct child_prog *child) |
586 | { | 436 | { |
@@ -617,23 +467,6 @@ static int builtin_unset(struct child_prog *child) | |||
617 | return EXIT_SUCCESS; | 467 | return EXIT_SUCCESS; |
618 | } | 468 | } |
619 | 469 | ||
620 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
621 | /* currently used by if/then/else. | ||
622 | * | ||
623 | * Reparsing the command line for this purpose is gross, | ||
624 | * incorrect, and fundamentally unfixable; in particular, | ||
625 | * think about what happens with command substitution. | ||
626 | * We really need to pull out the run, wait, return status | ||
627 | * functionality out of busy_loop so we can child->argv++ | ||
628 | * and use that, without going back through parse_command. | ||
629 | */ | ||
630 | static int run_command_predicate(char *cmd) | ||
631 | { | ||
632 | local_pending_command = xstrdup(cmd); | ||
633 | return( busy_loop(NULL)); | ||
634 | } | ||
635 | #endif | ||
636 | |||
637 | static void mark_open(int fd) | 470 | static void mark_open(int fd) |
638 | { | 471 | { |
639 | struct close_me *new = xmalloc(sizeof(struct close_me)); | 472 | struct close_me *new = xmalloc(sizeof(struct close_me)); |
@@ -733,6 +566,7 @@ static void checkjobs(struct jobset *j_list) | |||
733 | 566 | ||
734 | if (!job->running_progs) { | 567 | if (!job->running_progs) { |
735 | printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text); | 568 | printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text); |
569 | last_jobid=0; | ||
736 | remove_job(j_list, job); | 570 | remove_job(j_list, job); |
737 | } | 571 | } |
738 | } else { | 572 | } else { |
@@ -878,73 +712,10 @@ static int get_command(FILE * source, char *command) | |||
878 | return 0; | 712 | return 0; |
879 | } | 713 | } |
880 | 714 | ||
881 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
882 | static char* itoa(register int i) | ||
883 | { | ||
884 | static char a[7]; /* Max 7 ints */ | ||
885 | register char *b = a + sizeof(a) - 1; | ||
886 | int sign = (i < 0); | ||
887 | |||
888 | if (sign) | ||
889 | i = -i; | ||
890 | *b = 0; | ||
891 | do | ||
892 | { | ||
893 | *--b = '0' + (i % 10); | ||
894 | i /= 10; | ||
895 | } | ||
896 | while (i); | ||
897 | if (sign) | ||
898 | *--b = '-'; | ||
899 | return b; | ||
900 | } | ||
901 | #endif | ||
902 | |||
903 | #if defined BB_FEATURE_SH_ENVIRONMENT && ! defined BB_FEATURE_SH_WORDEXP | ||
904 | char * strsep_space( char *string, int * ix) | ||
905 | { | ||
906 | char *token, *begin; | ||
907 | |||
908 | begin = string; | ||
909 | |||
910 | /* Short circuit the trivial case */ | ||
911 | if ( !string || ! string[*ix]) | ||
912 | return NULL; | ||
913 | |||
914 | /* Find the end of the token. */ | ||
915 | while( string && string[*ix] && !isspace(string[*ix]) ) { | ||
916 | (*ix)++; | ||
917 | } | ||
918 | |||
919 | /* Find the end of any whitespace trailing behind | ||
920 | * the token and let that be part of the token */ | ||
921 | while( string && string[*ix] && isspace(string[*ix]) ) { | ||
922 | (*ix)++; | ||
923 | } | ||
924 | |||
925 | if (! string && *ix==0) { | ||
926 | /* Nothing useful was found */ | ||
927 | return NULL; | ||
928 | } | ||
929 | |||
930 | token = xmalloc(*ix+1); | ||
931 | token[*ix] = '\0'; | ||
932 | strncpy(token, string, *ix); | ||
933 | |||
934 | return token; | ||
935 | } | ||
936 | #endif | ||
937 | |||
938 | 715 | ||
939 | static int expand_arguments(char *command) | 716 | static int expand_arguments(char *command) |
940 | { | 717 | { |
941 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
942 | expand_t expand_result; | ||
943 | char *src, *dst, *var; | ||
944 | int ix = 0; | 718 | int ix = 0; |
945 | int i=0, length, total_length=0, retval; | ||
946 | const char *out_of_space = "out of space during expansion"; | ||
947 | #endif | ||
948 | 719 | ||
949 | /* get rid of the terminating \n */ | 720 | /* get rid of the terminating \n */ |
950 | chomp(command); | 721 | chomp(command); |
@@ -959,194 +730,6 @@ static int expand_arguments(char *command) | |||
959 | ix++; | 730 | ix++; |
960 | } | 731 | } |
961 | 732 | ||
962 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
963 | |||
964 | |||
965 | #ifdef BB_FEATURE_SH_WORDEXP | ||
966 | /* This first part uses wordexp() which is a wonderful C lib | ||
967 | * function which expands nearly everything. */ | ||
968 | retval = wordexp (command, &expand_result, WRDE_SHOWERR); | ||
969 | if (retval == WRDE_NOSPACE) { | ||
970 | /* Mem may have been allocated... */ | ||
971 | wordfree (&expand_result); | ||
972 | error_msg(out_of_space); | ||
973 | return FALSE; | ||
974 | } | ||
975 | if (retval < 0) { | ||
976 | /* Some other error. */ | ||
977 | error_msg("syntax error"); | ||
978 | return FALSE; | ||
979 | } | ||
980 | |||
981 | if (expand_result.we_wordc > 0) { | ||
982 | /* Convert from char** (one word per string) to a simple char*, | ||
983 | * but don't overflow command which is BUFSIZ in length */ | ||
984 | *command = '\0'; | ||
985 | while (i < expand_result.we_wordc && total_length < BUFSIZ) { | ||
986 | length=strlen(expand_result.we_wordv[i])+1; | ||
987 | if (BUFSIZ-total_length-length <= 0) { | ||
988 | error_msg(out_of_space); | ||
989 | return FALSE; | ||
990 | } | ||
991 | strcat(command+total_length, expand_result.we_wordv[i++]); | ||
992 | strcat(command+total_length, " "); | ||
993 | total_length+=length; | ||
994 | } | ||
995 | wordfree (&expand_result); | ||
996 | } | ||
997 | #else | ||
998 | |||
999 | /* Ok. They don't have a recent glibc and they don't have uClibc. Chances | ||
1000 | * are about 100% they don't have wordexp(). So instead the best we can do | ||
1001 | * is use glob and then fixup environment variables and such ourselves. | ||
1002 | * This is better then nothing, but certainly not perfect */ | ||
1003 | |||
1004 | /* It turns out that glob is very stupid. We have to feed it one word at a | ||
1005 | * time since it can't cope with a full string. Here we convert command | ||
1006 | * (char*) into cmd (char**, one word per string) */ | ||
1007 | { | ||
1008 | |||
1009 | int flags = GLOB_NOCHECK | ||
1010 | #ifdef GLOB_BRACE | ||
1011 | | GLOB_BRACE | ||
1012 | #endif | ||
1013 | #ifdef GLOB_TILDE | ||
1014 | | GLOB_TILDE | ||
1015 | #endif | ||
1016 | ; | ||
1017 | char *tmpcmd, *cmd, *cmd_copy; | ||
1018 | /* We need a clean copy, so strsep can mess up the copy while | ||
1019 | * we write stuff into the original (in a minute) */ | ||
1020 | cmd = cmd_copy = strdup(command); | ||
1021 | *command = '\0'; | ||
1022 | for (ix = 0, tmpcmd = cmd; | ||
1023 | (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) { | ||
1024 | if (*tmpcmd == '\0') | ||
1025 | break; | ||
1026 | /* we need to trim() the result for glob! */ | ||
1027 | trim(tmpcmd); | ||
1028 | retval = glob(tmpcmd, flags, NULL, &expand_result); | ||
1029 | free(tmpcmd); /* Free mem allocated by strsep_space */ | ||
1030 | if (retval == GLOB_NOSPACE) { | ||
1031 | /* Mem may have been allocated... */ | ||
1032 | globfree (&expand_result); | ||
1033 | error_msg(out_of_space); | ||
1034 | return FALSE; | ||
1035 | } else if (retval != 0) { | ||
1036 | /* Some other error. GLOB_NOMATCH shouldn't | ||
1037 | * happen because of the GLOB_NOCHECK flag in | ||
1038 | * the glob call. */ | ||
1039 | error_msg("syntax error"); | ||
1040 | return FALSE; | ||
1041 | } else { | ||
1042 | /* Convert from char** (one word per string) to a simple char*, | ||
1043 | * but don't overflow command which is BUFSIZ in length */ | ||
1044 | for (i=0; i < expand_result.gl_pathc; i++) { | ||
1045 | length=strlen(expand_result.gl_pathv[i]); | ||
1046 | if (total_length+length+1 >= BUFSIZ) { | ||
1047 | error_msg(out_of_space); | ||
1048 | return FALSE; | ||
1049 | } | ||
1050 | strcat(command+total_length, " "); | ||
1051 | total_length+=1; | ||
1052 | strcat(command+total_length, expand_result.gl_pathv[i]); | ||
1053 | total_length+=length; | ||
1054 | } | ||
1055 | globfree (&expand_result); | ||
1056 | } | ||
1057 | } | ||
1058 | free(cmd_copy); | ||
1059 | trim(command); | ||
1060 | } | ||
1061 | |||
1062 | #endif | ||
1063 | |||
1064 | /* Now do the shell variable substitutions which | ||
1065 | * wordexp can't do for us, namely $? and $! */ | ||
1066 | src = command; | ||
1067 | while((dst = strchr(src,'$')) != NULL){ | ||
1068 | var = NULL; | ||
1069 | switch(*(dst+1)) { | ||
1070 | case '?': | ||
1071 | var = itoa(last_return_code); | ||
1072 | break; | ||
1073 | case '!': | ||
1074 | if (last_bg_pid==-1) | ||
1075 | *(var)='\0'; | ||
1076 | else | ||
1077 | var = itoa(last_bg_pid); | ||
1078 | break; | ||
1079 | /* Everything else like $$, $#, $[0-9], etc. should all be | ||
1080 | * expanded by wordexp(), so we can in theory skip that stuff | ||
1081 | * here, but just to be on the safe side (i.e., since uClibc | ||
1082 | * wordexp doesn't do this stuff yet), lets leave it in for | ||
1083 | * now. */ | ||
1084 | case '$': | ||
1085 | var = itoa(getpid()); | ||
1086 | break; | ||
1087 | case '#': | ||
1088 | var = itoa(argc-1); | ||
1089 | break; | ||
1090 | case '0':case '1':case '2':case '3':case '4': | ||
1091 | case '5':case '6':case '7':case '8':case '9': | ||
1092 | { | ||
1093 | int ixx=*(dst + 1)-48; | ||
1094 | if (ixx >= argc) { | ||
1095 | var='\0'; | ||
1096 | } else { | ||
1097 | var = argv[ixx]; | ||
1098 | } | ||
1099 | } | ||
1100 | break; | ||
1101 | |||
1102 | } | ||
1103 | if (var) { | ||
1104 | /* a single character construction was found, and | ||
1105 | * already handled in the case statement */ | ||
1106 | src=dst+2; | ||
1107 | } else { | ||
1108 | /* Looks like an environment variable */ | ||
1109 | char delim_hold; | ||
1110 | int num_skip_chars=0; | ||
1111 | int dstlen = strlen(dst); | ||
1112 | /* Is this a ${foo} type variable? */ | ||
1113 | if (dstlen >=2 && *(dst+1) == '{') { | ||
1114 | src=strchr(dst+1, '}'); | ||
1115 | num_skip_chars=1; | ||
1116 | } else { | ||
1117 | src=dst+1; | ||
1118 | while(isalnum(*src) || *src=='_') src++; | ||
1119 | } | ||
1120 | if (src == NULL) { | ||
1121 | src = dst+dstlen; | ||
1122 | } | ||
1123 | delim_hold=*src; | ||
1124 | *src='\0'; /* temporary */ | ||
1125 | var = getenv(dst + 1 + num_skip_chars); | ||
1126 | *src=delim_hold; | ||
1127 | src += num_skip_chars; | ||
1128 | } | ||
1129 | if (var == NULL) { | ||
1130 | /* Seems we got an un-expandable variable. So delete it. */ | ||
1131 | var = ""; | ||
1132 | } | ||
1133 | { | ||
1134 | int subst_len = strlen(var); | ||
1135 | int trail_len = strlen(src); | ||
1136 | if (dst+subst_len+trail_len >= command+BUFSIZ) { | ||
1137 | error_msg(out_of_space); | ||
1138 | return FALSE; | ||
1139 | } | ||
1140 | /* Move stuff to the end of the string to accommodate | ||
1141 | * filling the created gap with the new stuff */ | ||
1142 | memmove(dst+subst_len, src, trail_len+1); | ||
1143 | /* Now copy in the new stuff */ | ||
1144 | memcpy(dst, var, subst_len); | ||
1145 | src = dst+subst_len; | ||
1146 | } | ||
1147 | } | ||
1148 | |||
1149 | #endif | ||
1150 | return TRUE; | 733 | return TRUE; |
1151 | } | 734 | } |
1152 | 735 | ||
@@ -1357,118 +940,12 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg) | |||
1357 | return_command = *command_ptr + (src - *command_ptr) + 1; | 940 | return_command = *command_ptr + (src - *command_ptr) + 1; |
1358 | break; | 941 | break; |
1359 | 942 | ||
1360 | #ifdef BB_FEATURE_SH_BACKTICKS | ||
1361 | case '`': | ||
1362 | /* Exec a backtick-ed command */ | ||
1363 | /* Besides any previous brokenness, I have not | ||
1364 | * updated backtick handling for close_me support. | ||
1365 | * I don't know if it needs it or not. -- LRD */ | ||
1366 | { | ||
1367 | char* charptr1=NULL, *charptr2; | ||
1368 | char* ptr=NULL; | ||
1369 | struct job *newjob; | ||
1370 | struct jobset njob_list = { NULL, NULL }; | ||
1371 | int pipefd[2]; | ||
1372 | int size; | ||
1373 | |||
1374 | ptr=strchr(++src, '`'); | ||
1375 | if (ptr==NULL) { | ||
1376 | fprintf(stderr, "Unmatched '`' in command\n"); | ||
1377 | free_job(job); | ||
1378 | return 1; | ||
1379 | } | ||
1380 | |||
1381 | /* Make some space to hold just the backticked command */ | ||
1382 | charptr1 = charptr2 = xmalloc(1+ptr-src); | ||
1383 | memcpy(charptr1, src, ptr-src); | ||
1384 | charptr1[ptr-src] = '\0'; | ||
1385 | newjob = xmalloc(sizeof(struct job)); | ||
1386 | newjob->job_list = &njob_list; | ||
1387 | /* Now parse and run the backticked command */ | ||
1388 | if (!parse_command(&charptr1, newjob, inbg) | ||
1389 | && newjob->num_progs) { | ||
1390 | pipe(pipefd); | ||
1391 | run_command(newjob, 0, pipefd); | ||
1392 | } | ||
1393 | checkjobs(job->job_list); | ||
1394 | free_job(newjob); /* doesn't actually free newjob, | ||
1395 | looks like a memory leak */ | ||
1396 | free(charptr2); | ||
1397 | |||
1398 | /* Make a copy of any stuff left over in the command | ||
1399 | * line after the second backtick */ | ||
1400 | charptr2 = xmalloc(strlen(ptr)+1); | ||
1401 | memcpy(charptr2, ptr+1, strlen(ptr)); | ||
1402 | |||
1403 | |||
1404 | /* Copy the output from the backtick-ed command into the | ||
1405 | * command line, making extra room as needed */ | ||
1406 | --src; | ||
1407 | charptr1 = xmalloc(BUFSIZ); | ||
1408 | while ( (size=full_read(pipefd[0], charptr1, BUFSIZ-1)) >0) { | ||
1409 | int newsize=src - *command_ptr + size + 1 + strlen(charptr2); | ||
1410 | if (newsize > BUFSIZ) { | ||
1411 | *command_ptr=xrealloc(*command_ptr, newsize); | ||
1412 | } | ||
1413 | memcpy(src, charptr1, size); | ||
1414 | src+=size; | ||
1415 | } | ||
1416 | free(charptr1); | ||
1417 | close(pipefd[0]); | ||
1418 | if (*(src-1)=='\n') | ||
1419 | --src; | ||
1420 | |||
1421 | /* Now paste into the *command_ptr all the stuff | ||
1422 | * leftover after the second backtick */ | ||
1423 | memcpy(src, charptr2, strlen(charptr2)+1); | ||
1424 | free(charptr2); | ||
1425 | |||
1426 | /* Now recursively call parse_command to deal with the new | ||
1427 | * and improved version of the command line with the backtick | ||
1428 | * results expanded in place... */ | ||
1429 | { | ||
1430 | struct jobset *jl=job->job_list; | ||
1431 | free_job(job); | ||
1432 | job->job_list = jl; | ||
1433 | } | ||
1434 | return(parse_command(command_ptr, job, inbg)); | ||
1435 | } | ||
1436 | break; | ||
1437 | #endif // BB_FEATURE_SH_BACKTICKS | ||
1438 | |||
1439 | case '\\': | 943 | case '\\': |
1440 | src++; | 944 | src++; |
1441 | if (!*src) { | 945 | if (!*src) { |
1442 | /* This is currently a little broken... */ | ||
1443 | #ifdef HANDLE_CONTINUATION_CHARS | ||
1444 | /* They fed us a continuation char, so continue reading stuff | ||
1445 | * on the next line, then tack that onto the end of the current | ||
1446 | * command */ | ||
1447 | char *command; | ||
1448 | int newsize; | ||
1449 | printf("erik: found a continue char at EOL...\n"); | ||
1450 | command = (char *) xcalloc(BUFSIZ, sizeof(char)); | ||
1451 | if (get_command(input, command)) { | ||
1452 | error_msg("character expected after \\"); | ||
1453 | free(command); | ||
1454 | free_job(job); | ||
1455 | return 1; | ||
1456 | } | ||
1457 | newsize = strlen(*command_ptr) + strlen(command) + 2; | ||
1458 | if (newsize > BUFSIZ) { | ||
1459 | printf("erik: doing realloc\n"); | ||
1460 | *command_ptr=xrealloc(*command_ptr, newsize); | ||
1461 | } | ||
1462 | printf("erik: A: *command_ptr='%s'\n", *command_ptr); | ||
1463 | memcpy(--src, command, strlen(command)); | ||
1464 | printf("erik: B: *command_ptr='%s'\n", *command_ptr); | ||
1465 | free(command); | ||
1466 | break; | ||
1467 | #else | ||
1468 | error_msg("character expected after \\"); | 946 | error_msg("character expected after \\"); |
1469 | free_job(job); | 947 | free_job(job); |
1470 | return 1; | 948 | return 1; |
1471 | #endif | ||
1472 | } | 949 | } |
1473 | if (*src == '*' || *src == '[' || *src == ']' | 950 | if (*src == '*' || *src == '[' || *src == ']' |
1474 | || *src == '?') *buf++ = '\\'; | 951 | || *src == '?') *buf++ = '\\'; |
@@ -1598,9 +1075,7 @@ static void insert_job(struct job *newjob, int inbg) | |||
1598 | to the list of backgrounded thejobs and leave it alone */ | 1075 | to the list of backgrounded thejobs and leave it alone */ |
1599 | printf("[%d] %d\n", thejob->jobid, | 1076 | printf("[%d] %d\n", thejob->jobid, |
1600 | newjob->progs[newjob->num_progs - 1].pid); | 1077 | newjob->progs[newjob->num_progs - 1].pid); |
1601 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 1078 | last_jobid = newjob->jobid; |
1602 | last_bg_pid=newjob->progs[newjob->num_progs - 1].pid; | ||
1603 | #endif | ||
1604 | } else { | 1079 | } else { |
1605 | newjob->job_list->fg = thejob; | 1080 | newjob->job_list->fg = thejob; |
1606 | 1081 | ||
@@ -1635,17 +1110,6 @@ static int run_command(struct job *newjob, int inbg, int outpipe[2]) | |||
1635 | } | 1110 | } |
1636 | } | 1111 | } |
1637 | 1112 | ||
1638 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1639 | if (show_x_trace==TRUE) { | ||
1640 | int j; | ||
1641 | fputc('+', stderr); | ||
1642 | for (j = 0; child->argv[j]; j++) { | ||
1643 | fputc(' ', stderr); | ||
1644 | fputs(child->argv[j], stderr); | ||
1645 | } | ||
1646 | fputc('\n', stderr); | ||
1647 | } | ||
1648 | #endif | ||
1649 | 1113 | ||
1650 | /* Check if the command matches any non-forking builtins, | 1114 | /* Check if the command matches any non-forking builtins, |
1651 | * but only if this is a simple command. | 1115 | * but only if this is a simple command. |
@@ -1782,11 +1246,6 @@ static int busy_loop(FILE * input) | |||
1782 | job_list.fg->running_progs--; | 1246 | job_list.fg->running_progs--; |
1783 | job_list.fg->progs[i].pid = 0; | 1247 | job_list.fg->progs[i].pid = 0; |
1784 | 1248 | ||
1785 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1786 | last_return_code=WEXITSTATUS(status); | ||
1787 | debug_printf("'%s' exited -- return code %d\n", | ||
1788 | job_list.fg->text, last_return_code); | ||
1789 | #endif | ||
1790 | if (!job_list.fg->running_progs) { | 1249 | if (!job_list.fg->running_progs) { |
1791 | /* child exited */ | 1250 | /* child exited */ |
1792 | remove_job(&job_list, job_list.fg); | 1251 | remove_job(&job_list, job_list.fg); |
@@ -1850,16 +1309,12 @@ int shell_main(int argc_l, char **argv_l) | |||
1850 | argv = argv_l; | 1309 | argv = argv_l; |
1851 | 1310 | ||
1852 | /* These variables need re-initializing when recursing */ | 1311 | /* These variables need re-initializing when recursing */ |
1312 | last_jobid = 0; | ||
1853 | shell_context = 0; | 1313 | shell_context = 0; |
1854 | local_pending_command = NULL; | 1314 | local_pending_command = NULL; |
1855 | close_me_head = NULL; | 1315 | close_me_head = NULL; |
1856 | job_list.head = NULL; | 1316 | job_list.head = NULL; |
1857 | job_list.fg = NULL; | 1317 | job_list.fg = NULL; |
1858 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1859 | last_bg_pid=1; | ||
1860 | last_return_code=1; | ||
1861 | show_x_trace=FALSE; | ||
1862 | #endif | ||
1863 | 1318 | ||
1864 | if (argv[0] && argv[0][0] == '-') { | 1319 | if (argv[0] && argv[0][0] == '-') { |
1865 | FILE *prof_input; | 1320 | FILE *prof_input; |
@@ -1886,11 +1341,6 @@ int shell_main(int argc_l, char **argv_l) | |||
1886 | optind++; | 1341 | optind++; |
1887 | argv = argv+optind; | 1342 | argv = argv+optind; |
1888 | break; | 1343 | break; |
1889 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1890 | case 'x': | ||
1891 | show_x_trace = TRUE; | ||
1892 | break; | ||
1893 | #endif | ||
1894 | case 'i': | 1344 | case 'i': |
1895 | interactive = TRUE; | 1345 | interactive = TRUE; |
1896 | break; | 1346 | break; |
diff --git a/shell/lash.c b/shell/lash.c index 3a421b372..689c720f6 100644 --- a/shell/lash.c +++ b/shell/lash.c | |||
@@ -25,30 +25,10 @@ | |||
25 | * | 25 | * |
26 | */ | 26 | */ |
27 | 27 | ||
28 | /* The parsing engine of this program is officially at a dead-end. | 28 | /* This shell's parsing engine is officially at a dead-end. |
29 | * Future work in that direction should move to the work posted | 29 | * Future work shell work should be done using hush.c |
30 | * at http://doolittle.faludi.com/~larry/parser.html . | ||
31 | * A start on the integration of that work with the rest of sh.c | ||
32 | * is at http://codepoet.org/sh.c . | ||
33 | */ | 30 | */ |
34 | // | 31 | |
35 | //This works pretty well now, and is now on by default. | ||
36 | #define BB_FEATURE_SH_ENVIRONMENT | ||
37 | // | ||
38 | //Backtick support has some problems, use at your own risk! | ||
39 | //#define BB_FEATURE_SH_BACKTICKS | ||
40 | // | ||
41 | //If, then, else, etc. support.. This should now behave basically | ||
42 | //like any other Bourne shell -- sortof... | ||
43 | #define BB_FEATURE_SH_IF_EXPRESSIONS | ||
44 | // | ||
45 | /* This is currently sortof broken, only for the brave... */ | ||
46 | #undef HANDLE_CONTINUATION_CHARS | ||
47 | // | ||
48 | /* This would be great -- if wordexp wouldn't strip all quoting | ||
49 | * out from the target strings... As is, a parser needs */ | ||
50 | #undef BB_FEATURE_SH_WORDEXP | ||
51 | // | ||
52 | //For debugging/development on the shell only... | 32 | //For debugging/development on the shell only... |
53 | //#define DEBUG_SHELL | 33 | //#define DEBUG_SHELL |
54 | 34 | ||
@@ -71,16 +51,8 @@ | |||
71 | #include <locale.h> | 51 | #include <locale.h> |
72 | #endif | 52 | #endif |
73 | 53 | ||
74 | //#define BB_FEATURE_SH_WORDEXP | ||
75 | |||
76 | #ifdef BB_FEATURE_SH_WORDEXP | ||
77 | #include <wordexp.h> | ||
78 | #define expand_t wordexp_t | ||
79 | #undef BB_FEATURE_SH_BACKTICKS | ||
80 | #else | ||
81 | #include <glob.h> | 54 | #include <glob.h> |
82 | #define expand_t glob_t | 55 | #define expand_t glob_t |
83 | #endif | ||
84 | 56 | ||
85 | 57 | ||
86 | static const int MAX_READ = 128; /* size of input buffer for `read' builtin */ | 58 | static const int MAX_READ = 128; /* size of input buffer for `read' builtin */ |
@@ -155,14 +127,6 @@ static int builtin_export(struct child_prog *cmd); | |||
155 | static int builtin_source(struct child_prog *cmd); | 127 | static int builtin_source(struct child_prog *cmd); |
156 | static int builtin_unset(struct child_prog *cmd); | 128 | static int builtin_unset(struct child_prog *cmd); |
157 | static int builtin_read(struct child_prog *cmd); | 129 | static int builtin_read(struct child_prog *cmd); |
158 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
159 | static int builtin_if(struct child_prog *cmd); | ||
160 | static int builtin_then(struct child_prog *cmd); | ||
161 | static int builtin_else(struct child_prog *cmd); | ||
162 | static int builtin_fi(struct child_prog *cmd); | ||
163 | /* function prototypes for shell stuff */ | ||
164 | static int run_command_predicate(char *cmd); | ||
165 | #endif | ||
166 | 130 | ||
167 | 131 | ||
168 | /* function prototypes for shell stuff */ | 132 | /* function prototypes for shell stuff */ |
@@ -192,12 +156,6 @@ static struct built_in_command bltins[] = { | |||
192 | {"read", "Input environment variable", builtin_read}, | 156 | {"read", "Input environment variable", builtin_read}, |
193 | {".", "Source-in and run commands in a file", builtin_source}, | 157 | {".", "Source-in and run commands in a file", builtin_source}, |
194 | /* to do: add ulimit */ | 158 | /* to do: add ulimit */ |
195 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
196 | {"if", NULL, builtin_if}, | ||
197 | {"then", NULL, builtin_then}, | ||
198 | {"else", NULL, builtin_else}, | ||
199 | {"fi", NULL, builtin_fi}, | ||
200 | #endif | ||
201 | {NULL, NULL, NULL} | 159 | {NULL, NULL, NULL} |
202 | }; | 160 | }; |
203 | 161 | ||
@@ -222,14 +180,7 @@ static struct jobset job_list = { NULL, NULL }; | |||
222 | static int argc; | 180 | static int argc; |
223 | static char **argv; | 181 | static char **argv; |
224 | static struct close_me *close_me_head; | 182 | static struct close_me *close_me_head; |
225 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 183 | static unsigned int last_jobid; |
226 | static int last_bg_pid; | ||
227 | static int last_return_code; | ||
228 | static int show_x_trace; | ||
229 | #endif | ||
230 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
231 | static char syntax_err[]="syntax error near unexpected token"; | ||
232 | #endif | ||
233 | 184 | ||
234 | static char *PS1; | 185 | static char *PS1; |
235 | static char *PS2 = "> "; | 186 | static char *PS2 = "> "; |
@@ -266,14 +217,6 @@ export cmd->progs[0] | |||
266 | source cmd->progs[0] | 217 | source cmd->progs[0] |
267 | unset cmd->progs[0] | 218 | unset cmd->progs[0] |
268 | read cmd->progs[0] | 219 | read cmd->progs[0] |
269 | if cmd->job_context, cmd->text | ||
270 | then cmd->job_context, cmd->text | ||
271 | else cmd->job_context, cmd->text | ||
272 | fi cmd->job_context | ||
273 | |||
274 | The use of cmd->text by if/then/else/fi is hopelessly hacky. | ||
275 | Would it work to increment cmd->progs[0]->argv and recurse, | ||
276 | somewhat like builtin_exec does? | ||
277 | 220 | ||
278 | I added "struct job *family;" to struct child_prog, | 221 | I added "struct job *family;" to struct child_prog, |
279 | and switched API to builtin_foo(struct child_prog *child); | 222 | and switched API to builtin_foo(struct child_prog *child); |
@@ -325,31 +268,34 @@ static int builtin_exit(struct child_prog *child) | |||
325 | /* built-in 'fg' and 'bg' handler */ | 268 | /* built-in 'fg' and 'bg' handler */ |
326 | static int builtin_fg_bg(struct child_prog *child) | 269 | static int builtin_fg_bg(struct child_prog *child) |
327 | { | 270 | { |
328 | int i, jobNum; | 271 | int i, jobnum; |
329 | struct job *job=NULL; | 272 | struct job *job=NULL; |
330 | |||
331 | if (!child->argv[1] || child->argv[2]) { | ||
332 | error_msg("%s: exactly one argument is expected", | ||
333 | child->argv[0]); | ||
334 | return EXIT_FAILURE; | ||
335 | } | ||
336 | |||
337 | if (sscanf(child->argv[1], "%%%d", &jobNum) != 1) { | ||
338 | error_msg("%s: bad argument '%s'", | ||
339 | child->argv[0], child->argv[1]); | ||
340 | return EXIT_FAILURE; | ||
341 | } | ||
342 | 273 | ||
343 | for (job = child->family->job_list->head; job; job = job->next) { | 274 | /* If they gave us no args, assume they want the last backgrounded task */ |
344 | if (job->jobid == jobNum) { | 275 | if (!child->argv[1]) { |
345 | break; | 276 | for (job = child->family->job_list->head; job; job = job->next) { |
277 | if (job->jobid == last_jobid) { | ||
278 | break; | ||
279 | } | ||
280 | } | ||
281 | if (!job) { | ||
282 | error_msg("%s: no current job", child->argv[0]); | ||
283 | return EXIT_FAILURE; | ||
284 | } | ||
285 | } else { | ||
286 | if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { | ||
287 | error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]); | ||
288 | return EXIT_FAILURE; | ||
289 | } | ||
290 | for (job = child->family->job_list->head; job; job = job->next) { | ||
291 | if (job->jobid == jobnum) { | ||
292 | break; | ||
293 | } | ||
294 | } | ||
295 | if (!job) { | ||
296 | error_msg("%s: %d: no such job", child->argv[0], jobnum); | ||
297 | return EXIT_FAILURE; | ||
346 | } | 298 | } |
347 | } | ||
348 | |||
349 | if (!job) { | ||
350 | error_msg("%s: unknown job %d", | ||
351 | child->argv[0], jobNum); | ||
352 | return EXIT_FAILURE; | ||
353 | } | 299 | } |
354 | 300 | ||
355 | if (*child->argv[0] == 'f') { | 301 | if (*child->argv[0] == 'f') { |
@@ -485,102 +431,6 @@ static int builtin_read(struct child_prog *child) | |||
485 | return (res); | 431 | return (res); |
486 | } | 432 | } |
487 | 433 | ||
488 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
489 | /* Built-in handler for 'if' commands */ | ||
490 | static int builtin_if(struct child_prog *child) | ||
491 | { | ||
492 | struct job *cmd = child->family; | ||
493 | int status; | ||
494 | char* charptr1=cmd->text+3; /* skip over the leading 'if ' */ | ||
495 | |||
496 | /* Now run the 'if' command */ | ||
497 | debug_printf( "job=%p entering builtin_if ('%s')-- context=%d\n", cmd, charptr1, cmd->job_context); | ||
498 | status = run_command_predicate(charptr1); | ||
499 | debug_printf( "if test returned "); | ||
500 | if (status == 0) { | ||
501 | debug_printf( "TRUE\n"); | ||
502 | cmd->job_context |= IF_TRUE_CONTEXT; | ||
503 | } else { | ||
504 | debug_printf( "FALSE\n"); | ||
505 | cmd->job_context |= IF_FALSE_CONTEXT; | ||
506 | } | ||
507 | debug_printf("job=%p builtin_if set job context to %x\n", cmd, cmd->job_context); | ||
508 | shell_context++; | ||
509 | |||
510 | return status; | ||
511 | } | ||
512 | |||
513 | /* Built-in handler for 'then' (part of the 'if' command) */ | ||
514 | static int builtin_then(struct child_prog *child) | ||
515 | { | ||
516 | struct job *cmd = child->family; | ||
517 | char* charptr1=cmd->text+5; /* skip over the leading 'then ' */ | ||
518 | |||
519 | debug_printf( "job=%p entering builtin_then ('%s')-- context=%d\n", cmd, charptr1, cmd->job_context); | ||
520 | if (! (cmd->job_context & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { | ||
521 | shell_context = 0; /* Reset the shell's context on an error */ | ||
522 | error_msg("%s `then'", syntax_err); | ||
523 | return EXIT_FAILURE; | ||
524 | } | ||
525 | |||
526 | cmd->job_context |= THEN_EXP_CONTEXT; | ||
527 | debug_printf("job=%p builtin_then set job context to %x\n", cmd, cmd->job_context); | ||
528 | |||
529 | /* If the if result was FALSE, skip the 'then' stuff */ | ||
530 | if (cmd->job_context & IF_FALSE_CONTEXT) { | ||
531 | return EXIT_SUCCESS; | ||
532 | } | ||
533 | |||
534 | /* Seems the if result was TRUE, so run the 'then' command */ | ||
535 | debug_printf( "'then' now running '%s'\n", charptr1); | ||
536 | |||
537 | return(run_command_predicate(charptr1)); | ||
538 | } | ||
539 | |||
540 | /* Built-in handler for 'else' (part of the 'if' command) */ | ||
541 | static int builtin_else(struct child_prog *child) | ||
542 | { | ||
543 | struct job *cmd = child->family; | ||
544 | char* charptr1=cmd->text+5; /* skip over the leading 'else ' */ | ||
545 | |||
546 | debug_printf( "job=%p entering builtin_else ('%s')-- context=%d\n", cmd, charptr1, cmd->job_context); | ||
547 | |||
548 | if (! (cmd->job_context & THEN_EXP_CONTEXT)) { | ||
549 | shell_context = 0; /* Reset the shell's context on an error */ | ||
550 | error_msg("%s `else'", syntax_err); | ||
551 | return EXIT_FAILURE; | ||
552 | } | ||
553 | /* If the if result was TRUE, skip the 'else' stuff */ | ||
554 | if (cmd->job_context & IF_TRUE_CONTEXT) { | ||
555 | return EXIT_SUCCESS; | ||
556 | } | ||
557 | |||
558 | cmd->job_context |= ELSE_EXP_CONTEXT; | ||
559 | debug_printf("job=%p builtin_else set job context to %x\n", cmd, cmd->job_context); | ||
560 | |||
561 | /* Now run the 'else' command */ | ||
562 | debug_printf( "'else' now running '%s'\n", charptr1); | ||
563 | return(run_command_predicate(charptr1)); | ||
564 | } | ||
565 | |||
566 | /* Built-in handler for 'fi' (part of the 'if' command) */ | ||
567 | static int builtin_fi(struct child_prog *child) | ||
568 | { | ||
569 | struct job *cmd = child->family; | ||
570 | debug_printf( "job=%p entering builtin_fi ('%s')-- context=%d\n", cmd, "", cmd->job_context); | ||
571 | if (! (cmd->job_context & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { | ||
572 | shell_context = 0; /* Reset the shell's context on an error */ | ||
573 | error_msg("%s `fi'", syntax_err); | ||
574 | return EXIT_FAILURE; | ||
575 | } | ||
576 | /* Clear out the if and then context bits */ | ||
577 | cmd->job_context &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT); | ||
578 | debug_printf("job=%p builtin_fi set job context to %x\n", cmd, cmd->job_context); | ||
579 | shell_context--; | ||
580 | return EXIT_SUCCESS; | ||
581 | } | ||
582 | #endif | ||
583 | |||
584 | /* Built-in '.' handler (read-in and execute commands from file) */ | 434 | /* Built-in '.' handler (read-in and execute commands from file) */ |
585 | static int builtin_source(struct child_prog *child) | 435 | static int builtin_source(struct child_prog *child) |
586 | { | 436 | { |
@@ -617,23 +467,6 @@ static int builtin_unset(struct child_prog *child) | |||
617 | return EXIT_SUCCESS; | 467 | return EXIT_SUCCESS; |
618 | } | 468 | } |
619 | 469 | ||
620 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
621 | /* currently used by if/then/else. | ||
622 | * | ||
623 | * Reparsing the command line for this purpose is gross, | ||
624 | * incorrect, and fundamentally unfixable; in particular, | ||
625 | * think about what happens with command substitution. | ||
626 | * We really need to pull out the run, wait, return status | ||
627 | * functionality out of busy_loop so we can child->argv++ | ||
628 | * and use that, without going back through parse_command. | ||
629 | */ | ||
630 | static int run_command_predicate(char *cmd) | ||
631 | { | ||
632 | local_pending_command = xstrdup(cmd); | ||
633 | return( busy_loop(NULL)); | ||
634 | } | ||
635 | #endif | ||
636 | |||
637 | static void mark_open(int fd) | 470 | static void mark_open(int fd) |
638 | { | 471 | { |
639 | struct close_me *new = xmalloc(sizeof(struct close_me)); | 472 | struct close_me *new = xmalloc(sizeof(struct close_me)); |
@@ -733,6 +566,7 @@ static void checkjobs(struct jobset *j_list) | |||
733 | 566 | ||
734 | if (!job->running_progs) { | 567 | if (!job->running_progs) { |
735 | printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text); | 568 | printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text); |
569 | last_jobid=0; | ||
736 | remove_job(j_list, job); | 570 | remove_job(j_list, job); |
737 | } | 571 | } |
738 | } else { | 572 | } else { |
@@ -878,73 +712,10 @@ static int get_command(FILE * source, char *command) | |||
878 | return 0; | 712 | return 0; |
879 | } | 713 | } |
880 | 714 | ||
881 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
882 | static char* itoa(register int i) | ||
883 | { | ||
884 | static char a[7]; /* Max 7 ints */ | ||
885 | register char *b = a + sizeof(a) - 1; | ||
886 | int sign = (i < 0); | ||
887 | |||
888 | if (sign) | ||
889 | i = -i; | ||
890 | *b = 0; | ||
891 | do | ||
892 | { | ||
893 | *--b = '0' + (i % 10); | ||
894 | i /= 10; | ||
895 | } | ||
896 | while (i); | ||
897 | if (sign) | ||
898 | *--b = '-'; | ||
899 | return b; | ||
900 | } | ||
901 | #endif | ||
902 | |||
903 | #if defined BB_FEATURE_SH_ENVIRONMENT && ! defined BB_FEATURE_SH_WORDEXP | ||
904 | char * strsep_space( char *string, int * ix) | ||
905 | { | ||
906 | char *token, *begin; | ||
907 | |||
908 | begin = string; | ||
909 | |||
910 | /* Short circuit the trivial case */ | ||
911 | if ( !string || ! string[*ix]) | ||
912 | return NULL; | ||
913 | |||
914 | /* Find the end of the token. */ | ||
915 | while( string && string[*ix] && !isspace(string[*ix]) ) { | ||
916 | (*ix)++; | ||
917 | } | ||
918 | |||
919 | /* Find the end of any whitespace trailing behind | ||
920 | * the token and let that be part of the token */ | ||
921 | while( string && string[*ix] && isspace(string[*ix]) ) { | ||
922 | (*ix)++; | ||
923 | } | ||
924 | |||
925 | if (! string && *ix==0) { | ||
926 | /* Nothing useful was found */ | ||
927 | return NULL; | ||
928 | } | ||
929 | |||
930 | token = xmalloc(*ix+1); | ||
931 | token[*ix] = '\0'; | ||
932 | strncpy(token, string, *ix); | ||
933 | |||
934 | return token; | ||
935 | } | ||
936 | #endif | ||
937 | |||
938 | 715 | ||
939 | static int expand_arguments(char *command) | 716 | static int expand_arguments(char *command) |
940 | { | 717 | { |
941 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
942 | expand_t expand_result; | ||
943 | char *src, *dst, *var; | ||
944 | int ix = 0; | 718 | int ix = 0; |
945 | int i=0, length, total_length=0, retval; | ||
946 | const char *out_of_space = "out of space during expansion"; | ||
947 | #endif | ||
948 | 719 | ||
949 | /* get rid of the terminating \n */ | 720 | /* get rid of the terminating \n */ |
950 | chomp(command); | 721 | chomp(command); |
@@ -959,194 +730,6 @@ static int expand_arguments(char *command) | |||
959 | ix++; | 730 | ix++; |
960 | } | 731 | } |
961 | 732 | ||
962 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
963 | |||
964 | |||
965 | #ifdef BB_FEATURE_SH_WORDEXP | ||
966 | /* This first part uses wordexp() which is a wonderful C lib | ||
967 | * function which expands nearly everything. */ | ||
968 | retval = wordexp (command, &expand_result, WRDE_SHOWERR); | ||
969 | if (retval == WRDE_NOSPACE) { | ||
970 | /* Mem may have been allocated... */ | ||
971 | wordfree (&expand_result); | ||
972 | error_msg(out_of_space); | ||
973 | return FALSE; | ||
974 | } | ||
975 | if (retval < 0) { | ||
976 | /* Some other error. */ | ||
977 | error_msg("syntax error"); | ||
978 | return FALSE; | ||
979 | } | ||
980 | |||
981 | if (expand_result.we_wordc > 0) { | ||
982 | /* Convert from char** (one word per string) to a simple char*, | ||
983 | * but don't overflow command which is BUFSIZ in length */ | ||
984 | *command = '\0'; | ||
985 | while (i < expand_result.we_wordc && total_length < BUFSIZ) { | ||
986 | length=strlen(expand_result.we_wordv[i])+1; | ||
987 | if (BUFSIZ-total_length-length <= 0) { | ||
988 | error_msg(out_of_space); | ||
989 | return FALSE; | ||
990 | } | ||
991 | strcat(command+total_length, expand_result.we_wordv[i++]); | ||
992 | strcat(command+total_length, " "); | ||
993 | total_length+=length; | ||
994 | } | ||
995 | wordfree (&expand_result); | ||
996 | } | ||
997 | #else | ||
998 | |||
999 | /* Ok. They don't have a recent glibc and they don't have uClibc. Chances | ||
1000 | * are about 100% they don't have wordexp(). So instead the best we can do | ||
1001 | * is use glob and then fixup environment variables and such ourselves. | ||
1002 | * This is better then nothing, but certainly not perfect */ | ||
1003 | |||
1004 | /* It turns out that glob is very stupid. We have to feed it one word at a | ||
1005 | * time since it can't cope with a full string. Here we convert command | ||
1006 | * (char*) into cmd (char**, one word per string) */ | ||
1007 | { | ||
1008 | |||
1009 | int flags = GLOB_NOCHECK | ||
1010 | #ifdef GLOB_BRACE | ||
1011 | | GLOB_BRACE | ||
1012 | #endif | ||
1013 | #ifdef GLOB_TILDE | ||
1014 | | GLOB_TILDE | ||
1015 | #endif | ||
1016 | ; | ||
1017 | char *tmpcmd, *cmd, *cmd_copy; | ||
1018 | /* We need a clean copy, so strsep can mess up the copy while | ||
1019 | * we write stuff into the original (in a minute) */ | ||
1020 | cmd = cmd_copy = strdup(command); | ||
1021 | *command = '\0'; | ||
1022 | for (ix = 0, tmpcmd = cmd; | ||
1023 | (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) { | ||
1024 | if (*tmpcmd == '\0') | ||
1025 | break; | ||
1026 | /* we need to trim() the result for glob! */ | ||
1027 | trim(tmpcmd); | ||
1028 | retval = glob(tmpcmd, flags, NULL, &expand_result); | ||
1029 | free(tmpcmd); /* Free mem allocated by strsep_space */ | ||
1030 | if (retval == GLOB_NOSPACE) { | ||
1031 | /* Mem may have been allocated... */ | ||
1032 | globfree (&expand_result); | ||
1033 | error_msg(out_of_space); | ||
1034 | return FALSE; | ||
1035 | } else if (retval != 0) { | ||
1036 | /* Some other error. GLOB_NOMATCH shouldn't | ||
1037 | * happen because of the GLOB_NOCHECK flag in | ||
1038 | * the glob call. */ | ||
1039 | error_msg("syntax error"); | ||
1040 | return FALSE; | ||
1041 | } else { | ||
1042 | /* Convert from char** (one word per string) to a simple char*, | ||
1043 | * but don't overflow command which is BUFSIZ in length */ | ||
1044 | for (i=0; i < expand_result.gl_pathc; i++) { | ||
1045 | length=strlen(expand_result.gl_pathv[i]); | ||
1046 | if (total_length+length+1 >= BUFSIZ) { | ||
1047 | error_msg(out_of_space); | ||
1048 | return FALSE; | ||
1049 | } | ||
1050 | strcat(command+total_length, " "); | ||
1051 | total_length+=1; | ||
1052 | strcat(command+total_length, expand_result.gl_pathv[i]); | ||
1053 | total_length+=length; | ||
1054 | } | ||
1055 | globfree (&expand_result); | ||
1056 | } | ||
1057 | } | ||
1058 | free(cmd_copy); | ||
1059 | trim(command); | ||
1060 | } | ||
1061 | |||
1062 | #endif | ||
1063 | |||
1064 | /* Now do the shell variable substitutions which | ||
1065 | * wordexp can't do for us, namely $? and $! */ | ||
1066 | src = command; | ||
1067 | while((dst = strchr(src,'$')) != NULL){ | ||
1068 | var = NULL; | ||
1069 | switch(*(dst+1)) { | ||
1070 | case '?': | ||
1071 | var = itoa(last_return_code); | ||
1072 | break; | ||
1073 | case '!': | ||
1074 | if (last_bg_pid==-1) | ||
1075 | *(var)='\0'; | ||
1076 | else | ||
1077 | var = itoa(last_bg_pid); | ||
1078 | break; | ||
1079 | /* Everything else like $$, $#, $[0-9], etc. should all be | ||
1080 | * expanded by wordexp(), so we can in theory skip that stuff | ||
1081 | * here, but just to be on the safe side (i.e., since uClibc | ||
1082 | * wordexp doesn't do this stuff yet), lets leave it in for | ||
1083 | * now. */ | ||
1084 | case '$': | ||
1085 | var = itoa(getpid()); | ||
1086 | break; | ||
1087 | case '#': | ||
1088 | var = itoa(argc-1); | ||
1089 | break; | ||
1090 | case '0':case '1':case '2':case '3':case '4': | ||
1091 | case '5':case '6':case '7':case '8':case '9': | ||
1092 | { | ||
1093 | int ixx=*(dst + 1)-48; | ||
1094 | if (ixx >= argc) { | ||
1095 | var='\0'; | ||
1096 | } else { | ||
1097 | var = argv[ixx]; | ||
1098 | } | ||
1099 | } | ||
1100 | break; | ||
1101 | |||
1102 | } | ||
1103 | if (var) { | ||
1104 | /* a single character construction was found, and | ||
1105 | * already handled in the case statement */ | ||
1106 | src=dst+2; | ||
1107 | } else { | ||
1108 | /* Looks like an environment variable */ | ||
1109 | char delim_hold; | ||
1110 | int num_skip_chars=0; | ||
1111 | int dstlen = strlen(dst); | ||
1112 | /* Is this a ${foo} type variable? */ | ||
1113 | if (dstlen >=2 && *(dst+1) == '{') { | ||
1114 | src=strchr(dst+1, '}'); | ||
1115 | num_skip_chars=1; | ||
1116 | } else { | ||
1117 | src=dst+1; | ||
1118 | while(isalnum(*src) || *src=='_') src++; | ||
1119 | } | ||
1120 | if (src == NULL) { | ||
1121 | src = dst+dstlen; | ||
1122 | } | ||
1123 | delim_hold=*src; | ||
1124 | *src='\0'; /* temporary */ | ||
1125 | var = getenv(dst + 1 + num_skip_chars); | ||
1126 | *src=delim_hold; | ||
1127 | src += num_skip_chars; | ||
1128 | } | ||
1129 | if (var == NULL) { | ||
1130 | /* Seems we got an un-expandable variable. So delete it. */ | ||
1131 | var = ""; | ||
1132 | } | ||
1133 | { | ||
1134 | int subst_len = strlen(var); | ||
1135 | int trail_len = strlen(src); | ||
1136 | if (dst+subst_len+trail_len >= command+BUFSIZ) { | ||
1137 | error_msg(out_of_space); | ||
1138 | return FALSE; | ||
1139 | } | ||
1140 | /* Move stuff to the end of the string to accommodate | ||
1141 | * filling the created gap with the new stuff */ | ||
1142 | memmove(dst+subst_len, src, trail_len+1); | ||
1143 | /* Now copy in the new stuff */ | ||
1144 | memcpy(dst, var, subst_len); | ||
1145 | src = dst+subst_len; | ||
1146 | } | ||
1147 | } | ||
1148 | |||
1149 | #endif | ||
1150 | return TRUE; | 733 | return TRUE; |
1151 | } | 734 | } |
1152 | 735 | ||
@@ -1357,118 +940,12 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg) | |||
1357 | return_command = *command_ptr + (src - *command_ptr) + 1; | 940 | return_command = *command_ptr + (src - *command_ptr) + 1; |
1358 | break; | 941 | break; |
1359 | 942 | ||
1360 | #ifdef BB_FEATURE_SH_BACKTICKS | ||
1361 | case '`': | ||
1362 | /* Exec a backtick-ed command */ | ||
1363 | /* Besides any previous brokenness, I have not | ||
1364 | * updated backtick handling for close_me support. | ||
1365 | * I don't know if it needs it or not. -- LRD */ | ||
1366 | { | ||
1367 | char* charptr1=NULL, *charptr2; | ||
1368 | char* ptr=NULL; | ||
1369 | struct job *newjob; | ||
1370 | struct jobset njob_list = { NULL, NULL }; | ||
1371 | int pipefd[2]; | ||
1372 | int size; | ||
1373 | |||
1374 | ptr=strchr(++src, '`'); | ||
1375 | if (ptr==NULL) { | ||
1376 | fprintf(stderr, "Unmatched '`' in command\n"); | ||
1377 | free_job(job); | ||
1378 | return 1; | ||
1379 | } | ||
1380 | |||
1381 | /* Make some space to hold just the backticked command */ | ||
1382 | charptr1 = charptr2 = xmalloc(1+ptr-src); | ||
1383 | memcpy(charptr1, src, ptr-src); | ||
1384 | charptr1[ptr-src] = '\0'; | ||
1385 | newjob = xmalloc(sizeof(struct job)); | ||
1386 | newjob->job_list = &njob_list; | ||
1387 | /* Now parse and run the backticked command */ | ||
1388 | if (!parse_command(&charptr1, newjob, inbg) | ||
1389 | && newjob->num_progs) { | ||
1390 | pipe(pipefd); | ||
1391 | run_command(newjob, 0, pipefd); | ||
1392 | } | ||
1393 | checkjobs(job->job_list); | ||
1394 | free_job(newjob); /* doesn't actually free newjob, | ||
1395 | looks like a memory leak */ | ||
1396 | free(charptr2); | ||
1397 | |||
1398 | /* Make a copy of any stuff left over in the command | ||
1399 | * line after the second backtick */ | ||
1400 | charptr2 = xmalloc(strlen(ptr)+1); | ||
1401 | memcpy(charptr2, ptr+1, strlen(ptr)); | ||
1402 | |||
1403 | |||
1404 | /* Copy the output from the backtick-ed command into the | ||
1405 | * command line, making extra room as needed */ | ||
1406 | --src; | ||
1407 | charptr1 = xmalloc(BUFSIZ); | ||
1408 | while ( (size=full_read(pipefd[0], charptr1, BUFSIZ-1)) >0) { | ||
1409 | int newsize=src - *command_ptr + size + 1 + strlen(charptr2); | ||
1410 | if (newsize > BUFSIZ) { | ||
1411 | *command_ptr=xrealloc(*command_ptr, newsize); | ||
1412 | } | ||
1413 | memcpy(src, charptr1, size); | ||
1414 | src+=size; | ||
1415 | } | ||
1416 | free(charptr1); | ||
1417 | close(pipefd[0]); | ||
1418 | if (*(src-1)=='\n') | ||
1419 | --src; | ||
1420 | |||
1421 | /* Now paste into the *command_ptr all the stuff | ||
1422 | * leftover after the second backtick */ | ||
1423 | memcpy(src, charptr2, strlen(charptr2)+1); | ||
1424 | free(charptr2); | ||
1425 | |||
1426 | /* Now recursively call parse_command to deal with the new | ||
1427 | * and improved version of the command line with the backtick | ||
1428 | * results expanded in place... */ | ||
1429 | { | ||
1430 | struct jobset *jl=job->job_list; | ||
1431 | free_job(job); | ||
1432 | job->job_list = jl; | ||
1433 | } | ||
1434 | return(parse_command(command_ptr, job, inbg)); | ||
1435 | } | ||
1436 | break; | ||
1437 | #endif // BB_FEATURE_SH_BACKTICKS | ||
1438 | |||
1439 | case '\\': | 943 | case '\\': |
1440 | src++; | 944 | src++; |
1441 | if (!*src) { | 945 | if (!*src) { |
1442 | /* This is currently a little broken... */ | ||
1443 | #ifdef HANDLE_CONTINUATION_CHARS | ||
1444 | /* They fed us a continuation char, so continue reading stuff | ||
1445 | * on the next line, then tack that onto the end of the current | ||
1446 | * command */ | ||
1447 | char *command; | ||
1448 | int newsize; | ||
1449 | printf("erik: found a continue char at EOL...\n"); | ||
1450 | command = (char *) xcalloc(BUFSIZ, sizeof(char)); | ||
1451 | if (get_command(input, command)) { | ||
1452 | error_msg("character expected after \\"); | ||
1453 | free(command); | ||
1454 | free_job(job); | ||
1455 | return 1; | ||
1456 | } | ||
1457 | newsize = strlen(*command_ptr) + strlen(command) + 2; | ||
1458 | if (newsize > BUFSIZ) { | ||
1459 | printf("erik: doing realloc\n"); | ||
1460 | *command_ptr=xrealloc(*command_ptr, newsize); | ||
1461 | } | ||
1462 | printf("erik: A: *command_ptr='%s'\n", *command_ptr); | ||
1463 | memcpy(--src, command, strlen(command)); | ||
1464 | printf("erik: B: *command_ptr='%s'\n", *command_ptr); | ||
1465 | free(command); | ||
1466 | break; | ||
1467 | #else | ||
1468 | error_msg("character expected after \\"); | 946 | error_msg("character expected after \\"); |
1469 | free_job(job); | 947 | free_job(job); |
1470 | return 1; | 948 | return 1; |
1471 | #endif | ||
1472 | } | 949 | } |
1473 | if (*src == '*' || *src == '[' || *src == ']' | 950 | if (*src == '*' || *src == '[' || *src == ']' |
1474 | || *src == '?') *buf++ = '\\'; | 951 | || *src == '?') *buf++ = '\\'; |
@@ -1598,9 +1075,7 @@ static void insert_job(struct job *newjob, int inbg) | |||
1598 | to the list of backgrounded thejobs and leave it alone */ | 1075 | to the list of backgrounded thejobs and leave it alone */ |
1599 | printf("[%d] %d\n", thejob->jobid, | 1076 | printf("[%d] %d\n", thejob->jobid, |
1600 | newjob->progs[newjob->num_progs - 1].pid); | 1077 | newjob->progs[newjob->num_progs - 1].pid); |
1601 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 1078 | last_jobid = newjob->jobid; |
1602 | last_bg_pid=newjob->progs[newjob->num_progs - 1].pid; | ||
1603 | #endif | ||
1604 | } else { | 1079 | } else { |
1605 | newjob->job_list->fg = thejob; | 1080 | newjob->job_list->fg = thejob; |
1606 | 1081 | ||
@@ -1635,17 +1110,6 @@ static int run_command(struct job *newjob, int inbg, int outpipe[2]) | |||
1635 | } | 1110 | } |
1636 | } | 1111 | } |
1637 | 1112 | ||
1638 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1639 | if (show_x_trace==TRUE) { | ||
1640 | int j; | ||
1641 | fputc('+', stderr); | ||
1642 | for (j = 0; child->argv[j]; j++) { | ||
1643 | fputc(' ', stderr); | ||
1644 | fputs(child->argv[j], stderr); | ||
1645 | } | ||
1646 | fputc('\n', stderr); | ||
1647 | } | ||
1648 | #endif | ||
1649 | 1113 | ||
1650 | /* Check if the command matches any non-forking builtins, | 1114 | /* Check if the command matches any non-forking builtins, |
1651 | * but only if this is a simple command. | 1115 | * but only if this is a simple command. |
@@ -1782,11 +1246,6 @@ static int busy_loop(FILE * input) | |||
1782 | job_list.fg->running_progs--; | 1246 | job_list.fg->running_progs--; |
1783 | job_list.fg->progs[i].pid = 0; | 1247 | job_list.fg->progs[i].pid = 0; |
1784 | 1248 | ||
1785 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1786 | last_return_code=WEXITSTATUS(status); | ||
1787 | debug_printf("'%s' exited -- return code %d\n", | ||
1788 | job_list.fg->text, last_return_code); | ||
1789 | #endif | ||
1790 | if (!job_list.fg->running_progs) { | 1249 | if (!job_list.fg->running_progs) { |
1791 | /* child exited */ | 1250 | /* child exited */ |
1792 | remove_job(&job_list, job_list.fg); | 1251 | remove_job(&job_list, job_list.fg); |
@@ -1850,16 +1309,12 @@ int shell_main(int argc_l, char **argv_l) | |||
1850 | argv = argv_l; | 1309 | argv = argv_l; |
1851 | 1310 | ||
1852 | /* These variables need re-initializing when recursing */ | 1311 | /* These variables need re-initializing when recursing */ |
1312 | last_jobid = 0; | ||
1853 | shell_context = 0; | 1313 | shell_context = 0; |
1854 | local_pending_command = NULL; | 1314 | local_pending_command = NULL; |
1855 | close_me_head = NULL; | 1315 | close_me_head = NULL; |
1856 | job_list.head = NULL; | 1316 | job_list.head = NULL; |
1857 | job_list.fg = NULL; | 1317 | job_list.fg = NULL; |
1858 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1859 | last_bg_pid=1; | ||
1860 | last_return_code=1; | ||
1861 | show_x_trace=FALSE; | ||
1862 | #endif | ||
1863 | 1318 | ||
1864 | if (argv[0] && argv[0][0] == '-') { | 1319 | if (argv[0] && argv[0][0] == '-') { |
1865 | FILE *prof_input; | 1320 | FILE *prof_input; |
@@ -1886,11 +1341,6 @@ int shell_main(int argc_l, char **argv_l) | |||
1886 | optind++; | 1341 | optind++; |
1887 | argv = argv+optind; | 1342 | argv = argv+optind; |
1888 | break; | 1343 | break; |
1889 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1890 | case 'x': | ||
1891 | show_x_trace = TRUE; | ||
1892 | break; | ||
1893 | #endif | ||
1894 | case 'i': | 1344 | case 'i': |
1895 | interactive = TRUE; | 1345 | interactive = TRUE; |
1896 | break; | 1346 | break; |