aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2001-06-21 16:38:11 +0000
committerEric Andersen <andersen@codepoet.org>2001-06-21 16:38:11 +0000
commit8a646dd2933bc37e67e1b09fd3461816e38fc677 (patch)
treef2e436f413c07809fe5b8f21c3eb5b86e309ee11
parentea4abff59530709ae423482220f65e37ecd1ac24 (diff)
downloadbusybox-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.c614
-rw-r--r--shell/lash.c614
2 files changed, 64 insertions, 1164 deletions
diff --git a/lash.c b/lash.c
index 3a421b372..689c720f6 100644
--- a/lash.c
+++ b/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
86static const int MAX_READ = 128; /* size of input buffer for `read' builtin */ 58static const int MAX_READ = 128; /* size of input buffer for `read' builtin */
@@ -155,14 +127,6 @@ static int builtin_export(struct child_prog *cmd);
155static int builtin_source(struct child_prog *cmd); 127static int builtin_source(struct child_prog *cmd);
156static int builtin_unset(struct child_prog *cmd); 128static int builtin_unset(struct child_prog *cmd);
157static int builtin_read(struct child_prog *cmd); 129static int builtin_read(struct child_prog *cmd);
158#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
159static int builtin_if(struct child_prog *cmd);
160static int builtin_then(struct child_prog *cmd);
161static int builtin_else(struct child_prog *cmd);
162static int builtin_fi(struct child_prog *cmd);
163/* function prototypes for shell stuff */
164static 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 };
222static int argc; 180static int argc;
223static char **argv; 181static char **argv;
224static struct close_me *close_me_head; 182static struct close_me *close_me_head;
225#ifdef BB_FEATURE_SH_ENVIRONMENT 183static unsigned int last_jobid;
226static int last_bg_pid;
227static int last_return_code;
228static int show_x_trace;
229#endif
230#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
231static char syntax_err[]="syntax error near unexpected token";
232#endif
233 184
234static char *PS1; 185static char *PS1;
235static char *PS2 = "> "; 186static char *PS2 = "> ";
@@ -266,14 +217,6 @@ export cmd->progs[0]
266source cmd->progs[0] 217source cmd->progs[0]
267unset cmd->progs[0] 218unset cmd->progs[0]
268read cmd->progs[0] 219read cmd->progs[0]
269if cmd->job_context, cmd->text
270then cmd->job_context, cmd->text
271else cmd->job_context, cmd->text
272fi cmd->job_context
273
274The use of cmd->text by if/then/else/fi is hopelessly hacky.
275Would it work to increment cmd->progs[0]->argv and recurse,
276somewhat like builtin_exec does?
277 220
278I added "struct job *family;" to struct child_prog, 221I added "struct job *family;" to struct child_prog,
279and switched API to builtin_foo(struct child_prog *child); 222and 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 */
326static int builtin_fg_bg(struct child_prog *child) 269static 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 */
490static 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) */
514static 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) */
541static 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) */
567static 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) */
585static int builtin_source(struct child_prog *child) 435static 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 */
630static int run_command_predicate(char *cmd)
631{
632 local_pending_command = xstrdup(cmd);
633 return( busy_loop(NULL));
634}
635#endif
636
637static void mark_open(int fd) 470static 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
882static 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
904char * 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
939static int expand_arguments(char *command) 716static 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
86static const int MAX_READ = 128; /* size of input buffer for `read' builtin */ 58static const int MAX_READ = 128; /* size of input buffer for `read' builtin */
@@ -155,14 +127,6 @@ static int builtin_export(struct child_prog *cmd);
155static int builtin_source(struct child_prog *cmd); 127static int builtin_source(struct child_prog *cmd);
156static int builtin_unset(struct child_prog *cmd); 128static int builtin_unset(struct child_prog *cmd);
157static int builtin_read(struct child_prog *cmd); 129static int builtin_read(struct child_prog *cmd);
158#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
159static int builtin_if(struct child_prog *cmd);
160static int builtin_then(struct child_prog *cmd);
161static int builtin_else(struct child_prog *cmd);
162static int builtin_fi(struct child_prog *cmd);
163/* function prototypes for shell stuff */
164static 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 };
222static int argc; 180static int argc;
223static char **argv; 181static char **argv;
224static struct close_me *close_me_head; 182static struct close_me *close_me_head;
225#ifdef BB_FEATURE_SH_ENVIRONMENT 183static unsigned int last_jobid;
226static int last_bg_pid;
227static int last_return_code;
228static int show_x_trace;
229#endif
230#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
231static char syntax_err[]="syntax error near unexpected token";
232#endif
233 184
234static char *PS1; 185static char *PS1;
235static char *PS2 = "> "; 186static char *PS2 = "> ";
@@ -266,14 +217,6 @@ export cmd->progs[0]
266source cmd->progs[0] 217source cmd->progs[0]
267unset cmd->progs[0] 218unset cmd->progs[0]
268read cmd->progs[0] 219read cmd->progs[0]
269if cmd->job_context, cmd->text
270then cmd->job_context, cmd->text
271else cmd->job_context, cmd->text
272fi cmd->job_context
273
274The use of cmd->text by if/then/else/fi is hopelessly hacky.
275Would it work to increment cmd->progs[0]->argv and recurse,
276somewhat like builtin_exec does?
277 220
278I added "struct job *family;" to struct child_prog, 221I added "struct job *family;" to struct child_prog,
279and switched API to builtin_foo(struct child_prog *child); 222and 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 */
326static int builtin_fg_bg(struct child_prog *child) 269static 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 */
490static 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) */
514static 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) */
541static 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) */
567static 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) */
585static int builtin_source(struct child_prog *child) 435static 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 */
630static int run_command_predicate(char *cmd)
631{
632 local_pending_command = xstrdup(cmd);
633 return( busy_loop(NULL));
634}
635#endif
636
637static void mark_open(int fd) 470static 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
882static 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
904char * 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
939static int expand_arguments(char *command) 716static 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;