diff options
author | Eric Andersen <andersen@codepoet.org> | 2000-07-28 15:14:45 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2000-07-28 15:14:45 +0000 |
commit | 501c88b245fdc63f3f2a044fd7704bb468db3904 (patch) | |
tree | 3fff440532d8d380ae7e4f2933bc7163360f8279 | |
parent | 6a99aaf0208151b7f5e5058efaa409496e2b7c4b (diff) | |
download | busybox-w32-501c88b245fdc63f3f2a044fd7704bb468db3904.tar.gz busybox-w32-501c88b245fdc63f3f2a044fd7704bb468db3904.tar.bz2 busybox-w32-501c88b245fdc63f3f2a044fd7704bb468db3904.zip |
More sh updates (with related changes to everything else). Switched
to using getopt and cleaned up the resulting mess. if-then-else-fi
is now basically working (given a bunch of constraints).
-Erik
-rw-r--r-- | applets/busybox.c | 6 | ||||
-rw-r--r-- | busybox.c | 6 | ||||
-rw-r--r-- | cmdedit.c | 25 | ||||
-rw-r--r-- | cmdedit.h | 1 | ||||
-rw-r--r-- | internal.h | 3 | ||||
-rw-r--r-- | lash.c | 179 | ||||
-rw-r--r-- | sh.c | 179 | ||||
-rw-r--r-- | shell/cmdedit.c | 25 | ||||
-rw-r--r-- | shell/cmdedit.h | 1 | ||||
-rw-r--r-- | shell/lash.c | 179 | ||||
-rw-r--r-- | utility.c | 10 |
11 files changed, 421 insertions, 193 deletions
diff --git a/applets/busybox.c b/applets/busybox.c index 291d31b19..1ed44ed9b 100644 --- a/applets/busybox.c +++ b/applets/busybox.c | |||
@@ -337,7 +337,7 @@ const struct BB_applet applets[] = { | |||
337 | {0,NULL,0,NULL} | 337 | {0,NULL,0,NULL} |
338 | }; | 338 | }; |
339 | 339 | ||
340 | char *applet_name; | 340 | const char *applet_name; |
341 | 341 | ||
342 | #ifdef BB_FEATURE_INSTALLER | 342 | #ifdef BB_FEATURE_INSTALLER |
343 | /* | 343 | /* |
@@ -416,7 +416,7 @@ static int install_links(const char *busybox, int use_symbolic_links) | |||
416 | 416 | ||
417 | int main(int argc, char **argv) | 417 | int main(int argc, char **argv) |
418 | { | 418 | { |
419 | char *s; | 419 | const char *s; |
420 | const struct BB_applet *a = applets; | 420 | const struct BB_applet *a = applets; |
421 | applet_name = "busybox"; | 421 | applet_name = "busybox"; |
422 | 422 | ||
@@ -455,7 +455,7 @@ int main(int argc, char **argv) | |||
455 | applet_name = s; | 455 | applet_name = s; |
456 | } | 456 | } |
457 | 457 | ||
458 | *argv = applet_name; | 458 | *argv = (char*)applet_name; |
459 | 459 | ||
460 | #ifdef BB_SH | 460 | #ifdef BB_SH |
461 | /* Add in a special case hack -- whenever **argv == '-' | 461 | /* Add in a special case hack -- whenever **argv == '-' |
@@ -337,7 +337,7 @@ const struct BB_applet applets[] = { | |||
337 | {0,NULL,0,NULL} | 337 | {0,NULL,0,NULL} |
338 | }; | 338 | }; |
339 | 339 | ||
340 | char *applet_name; | 340 | const char *applet_name; |
341 | 341 | ||
342 | #ifdef BB_FEATURE_INSTALLER | 342 | #ifdef BB_FEATURE_INSTALLER |
343 | /* | 343 | /* |
@@ -416,7 +416,7 @@ static int install_links(const char *busybox, int use_symbolic_links) | |||
416 | 416 | ||
417 | int main(int argc, char **argv) | 417 | int main(int argc, char **argv) |
418 | { | 418 | { |
419 | char *s; | 419 | const char *s; |
420 | const struct BB_applet *a = applets; | 420 | const struct BB_applet *a = applets; |
421 | applet_name = "busybox"; | 421 | applet_name = "busybox"; |
422 | 422 | ||
@@ -455,7 +455,7 @@ int main(int argc, char **argv) | |||
455 | applet_name = s; | 455 | applet_name = s; |
456 | } | 456 | } |
457 | 457 | ||
458 | *argv = applet_name; | 458 | *argv = (char*)applet_name; |
459 | 459 | ||
460 | #ifdef BB_SH | 460 | #ifdef BB_SH |
461 | /* Add in a special case hack -- whenever **argv == '-' | 461 | /* Add in a special case hack -- whenever **argv == '-' |
@@ -84,6 +84,7 @@ static int cmdedit_termw = 80; /* actual terminal width */ | |||
84 | static int cmdedit_scroll = 27; /* width of EOL scrolling region */ | 84 | static int cmdedit_scroll = 27; /* width of EOL scrolling region */ |
85 | static int history_counter = 0; /* Number of commands in history list */ | 85 | static int history_counter = 0; /* Number of commands in history list */ |
86 | static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */ | 86 | static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */ |
87 | static int exithandler_set = 0; /* Set to true when atexit() has been called */ | ||
87 | 88 | ||
88 | struct history { | 89 | struct history { |
89 | char *s; | 90 | char *s; |
@@ -709,10 +710,32 @@ extern void cmdedit_read_input(char* prompt, char command[BUFSIZ]) | |||
709 | 710 | ||
710 | extern void cmdedit_init(void) | 711 | extern void cmdedit_init(void) |
711 | { | 712 | { |
712 | atexit(cmdedit_reset_term); | 713 | if(exithandler_set == 0) { |
714 | atexit(cmdedit_reset_term); /* be sure to do this only once */ | ||
715 | exithandler_set = 1; | ||
716 | } | ||
713 | signal(SIGKILL, clean_up_and_die); | 717 | signal(SIGKILL, clean_up_and_die); |
714 | signal(SIGINT, clean_up_and_die); | 718 | signal(SIGINT, clean_up_and_die); |
715 | signal(SIGQUIT, clean_up_and_die); | 719 | signal(SIGQUIT, clean_up_and_die); |
716 | signal(SIGTERM, clean_up_and_die); | 720 | signal(SIGTERM, clean_up_and_die); |
717 | } | 721 | } |
722 | |||
723 | /* | ||
724 | ** Undo the effects of cmdedit_init() as good as we can: | ||
725 | ** I am not aware of a way to revoke an atexit() handler, | ||
726 | ** but, fortunately, our particular handler can be made | ||
727 | ** a no-op by setting reset_term = 0. | ||
728 | */ | ||
729 | extern void cmdedit_terminate(void) | ||
730 | { | ||
731 | cmdedit_reset_term(); | ||
732 | reset_term = 0; | ||
733 | signal(SIGKILL, SIG_DFL); | ||
734 | signal(SIGINT, SIG_DFL); | ||
735 | signal(SIGQUIT, SIG_DFL); | ||
736 | signal(SIGTERM, SIG_DFL); | ||
737 | } | ||
738 | |||
739 | |||
740 | |||
718 | #endif /* BB_FEATURE_SH_COMMAND_EDITING */ | 741 | #endif /* BB_FEATURE_SH_COMMAND_EDITING */ |
@@ -11,6 +11,7 @@ | |||
11 | typedef size_t (*cmdedit_strwidth_proc)(char *); | 11 | typedef size_t (*cmdedit_strwidth_proc)(char *); |
12 | 12 | ||
13 | void cmdedit_init(void); | 13 | void cmdedit_init(void); |
14 | void cmdedit_terminate(void); | ||
14 | void cmdedit_read_input(char* promptStr, char* command); /* read a line of input */ | 15 | void cmdedit_read_input(char* promptStr, char* command); /* read a line of input */ |
15 | void cmdedit_setwidth(int); /* specify width of screen */ | 16 | void cmdedit_setwidth(int); /* specify width of screen */ |
16 | void cmdedit_histadd(char *); /* adds entries to hist */ | 17 | void cmdedit_histadd(char *); /* adds entries to hist */ |
diff --git a/internal.h b/internal.h index 7f0b77475..9de1c9372 100644 --- a/internal.h +++ b/internal.h | |||
@@ -317,7 +317,7 @@ extern const char which_usage[]; | |||
317 | extern const char whoami_usage[]; | 317 | extern const char whoami_usage[]; |
318 | extern const char yes_usage[]; | 318 | extern const char yes_usage[]; |
319 | 319 | ||
320 | extern char *applet_name; | 320 | extern const char *applet_name; |
321 | 321 | ||
322 | extern void usage(const char *usage) __attribute__ ((noreturn)); | 322 | extern void usage(const char *usage) __attribute__ ((noreturn)); |
323 | extern void errorMsg(const char *s, ...) __attribute__ ((format (printf, 1, 2))); | 323 | extern void errorMsg(const char *s, ...) __attribute__ ((format (printf, 1, 2))); |
@@ -380,6 +380,7 @@ extern void xregcomp(regex_t *preg, const char *regex, int cflags); | |||
380 | #ifndef DMALLOC | 380 | #ifndef DMALLOC |
381 | extern void *xmalloc (size_t size); | 381 | extern void *xmalloc (size_t size); |
382 | extern void *xrealloc(void *old, size_t size); | 382 | extern void *xrealloc(void *old, size_t size); |
383 | extern void *xcalloc(size_t nmemb, size_t size); | ||
383 | extern char *xstrdup (const char *s); | 384 | extern char *xstrdup (const char *s); |
384 | #endif | 385 | #endif |
385 | extern char *xstrndup (const char *s, int n); | 386 | extern char *xstrndup (const char *s, int n); |
@@ -29,6 +29,7 @@ | |||
29 | //#define BB_FEATURE_SH_BACKTICKS | 29 | //#define BB_FEATURE_SH_BACKTICKS |
30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS | 30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS |
31 | //#define BB_FEATURE_SH_ENVIRONMENT | 31 | //#define BB_FEATURE_SH_ENVIRONMENT |
32 | //#define DEBUG_SHELL | ||
32 | 33 | ||
33 | 34 | ||
34 | #include "internal.h" | 35 | #include "internal.h" |
@@ -43,6 +44,7 @@ | |||
43 | #include <sys/ioctl.h> | 44 | #include <sys/ioctl.h> |
44 | #include <sys/wait.h> | 45 | #include <sys/wait.h> |
45 | #include <unistd.h> | 46 | #include <unistd.h> |
47 | #include <getopt.h> | ||
46 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 48 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
47 | #include "cmdedit.h" | 49 | #include "cmdedit.h" |
48 | #endif | 50 | #endif |
@@ -172,8 +174,9 @@ static char **argv; | |||
172 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 174 | #ifdef BB_FEATURE_SH_ENVIRONMENT |
173 | static int lastBgPid=-1; | 175 | static int lastBgPid=-1; |
174 | static int lastReturnCode=-1; | 176 | static int lastReturnCode=-1; |
177 | static int showXtrace=FALSE; | ||
175 | #endif | 178 | #endif |
176 | 179 | ||
177 | 180 | ||
178 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 181 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
179 | void win_changed(int junk) | 182 | void win_changed(int junk) |
@@ -382,14 +385,23 @@ static int builtin_if(struct job *cmd, struct jobSet *jobList) | |||
382 | status=strlen(charptr1); | 385 | status=strlen(charptr1); |
383 | local_pending_command = xmalloc(status+1); | 386 | local_pending_command = xmalloc(status+1); |
384 | strncpy(local_pending_command, charptr1, status); | 387 | strncpy(local_pending_command, charptr1, status); |
385 | printf("'if' now running '%s'\n", charptr1); | 388 | local_pending_command[status]='\0'; |
389 | #ifdef DEBUG_SHELL | ||
390 | fprintf(stderr, "'if' now testing '%s'\n", local_pending_command); | ||
391 | #endif | ||
386 | status = busy_loop(NULL); /* Frees local_pending_command */ | 392 | status = busy_loop(NULL); /* Frees local_pending_command */ |
387 | printf("if test returned "); | 393 | #ifdef DEBUG_SHELL |
394 | fprintf(stderr, "if test returned "); | ||
395 | #endif | ||
388 | if (status == 0) { | 396 | if (status == 0) { |
389 | printf("TRUE\n"); | 397 | #ifdef DEBUG_SHELL |
398 | fprintf(stderr, "TRUE\n"); | ||
399 | #endif | ||
390 | cmd->jobContext |= IF_TRUE_CONTEXT; | 400 | cmd->jobContext |= IF_TRUE_CONTEXT; |
391 | } else { | 401 | } else { |
392 | printf("FALSE\n"); | 402 | #ifdef DEBUG_SHELL |
403 | fprintf(stderr, "FALSE\n"); | ||
404 | #endif | ||
393 | cmd->jobContext |= IF_FALSE_CONTEXT; | 405 | cmd->jobContext |= IF_FALSE_CONTEXT; |
394 | } | 406 | } |
395 | 407 | ||
@@ -407,7 +419,7 @@ static int builtin_then(struct job *cmd, struct jobSet *junk) | |||
407 | return FALSE; | 419 | return FALSE; |
408 | } | 420 | } |
409 | /* If the if result was FALSE, skip the 'then' stuff */ | 421 | /* If the if result was FALSE, skip the 'then' stuff */ |
410 | if (cmd->jobContext & IF_TRUE_CONTEXT) { | 422 | if (cmd->jobContext & IF_FALSE_CONTEXT) { |
411 | return TRUE; | 423 | return TRUE; |
412 | } | 424 | } |
413 | 425 | ||
@@ -418,7 +430,10 @@ static int builtin_then(struct job *cmd, struct jobSet *junk) | |||
418 | status=strlen(charptr1); | 430 | status=strlen(charptr1); |
419 | local_pending_command = xmalloc(status+1); | 431 | local_pending_command = xmalloc(status+1); |
420 | strncpy(local_pending_command, charptr1, status); | 432 | strncpy(local_pending_command, charptr1, status); |
421 | printf("'then' now running '%s'\n", charptr1); | 433 | local_pending_command[status]='\0'; |
434 | #ifdef DEBUG_SHELL | ||
435 | fprintf(stderr, "'then' now running '%s'\n", charptr1); | ||
436 | #endif | ||
422 | return( busy_loop(NULL)); | 437 | return( busy_loop(NULL)); |
423 | } | 438 | } |
424 | 439 | ||
@@ -433,7 +448,7 @@ static int builtin_else(struct job *cmd, struct jobSet *junk) | |||
433 | return FALSE; | 448 | return FALSE; |
434 | } | 449 | } |
435 | /* If the if result was TRUE, skip the 'else' stuff */ | 450 | /* If the if result was TRUE, skip the 'else' stuff */ |
436 | if (cmd->jobContext & IF_FALSE_CONTEXT) { | 451 | if (cmd->jobContext & IF_TRUE_CONTEXT) { |
437 | return TRUE; | 452 | return TRUE; |
438 | } | 453 | } |
439 | 454 | ||
@@ -444,7 +459,10 @@ static int builtin_else(struct job *cmd, struct jobSet *junk) | |||
444 | status=strlen(charptr1); | 459 | status=strlen(charptr1); |
445 | local_pending_command = xmalloc(status+1); | 460 | local_pending_command = xmalloc(status+1); |
446 | strncpy(local_pending_command, charptr1, status); | 461 | strncpy(local_pending_command, charptr1, status); |
447 | printf("'else' now running '%s'\n", charptr1); | 462 | local_pending_command[status]='\0'; |
463 | #ifdef DEBUG_SHELL | ||
464 | fprintf(stderr, "'else' now running '%s'\n", charptr1); | ||
465 | #endif | ||
448 | return( busy_loop(NULL)); | 466 | return( busy_loop(NULL)); |
449 | } | 467 | } |
450 | 468 | ||
@@ -457,7 +475,9 @@ static int builtin_fi(struct job *cmd, struct jobSet *junk) | |||
457 | } | 475 | } |
458 | /* Clear out the if and then context bits */ | 476 | /* Clear out the if and then context bits */ |
459 | cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT); | 477 | cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT); |
460 | printf("Hit an fi -- jobContext=%d\n", cmd->jobContext); | 478 | #ifdef DEBUG_SHELL |
479 | fprintf(stderr, "Hit an fi -- jobContext=%d\n", cmd->jobContext); | ||
480 | #endif | ||
461 | return TRUE; | 481 | return TRUE; |
462 | } | 482 | } |
463 | #endif | 483 | #endif |
@@ -633,12 +653,23 @@ static int getCommand(FILE * source, char *command) | |||
633 | if (source == stdin) { | 653 | if (source == stdin) { |
634 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 654 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
635 | int len; | 655 | int len; |
656 | |||
657 | /* | ||
658 | ** enable command line editing only while a command line | ||
659 | ** is actually being read; otherwise, we'll end up bequeathing | ||
660 | ** atexit() handlers and other unwanted stuff to our | ||
661 | ** child processes (rob@sysgo.de) | ||
662 | */ | ||
663 | cmdedit_init(); | ||
664 | signal(SIGWINCH, win_changed); | ||
636 | len=fprintf(stdout, "%s %s", cwd, prompt); | 665 | len=fprintf(stdout, "%s %s", cwd, prompt); |
637 | fflush(stdout); | 666 | fflush(stdout); |
638 | promptStr=(char*)xmalloc(sizeof(char)*(len+1)); | 667 | promptStr=(char*)xmalloc(sizeof(char)*(len+1)); |
639 | sprintf(promptStr, "%s %s", cwd, prompt); | 668 | sprintf(promptStr, "%s %s", cwd, prompt); |
640 | cmdedit_read_input(promptStr, command); | 669 | cmdedit_read_input(promptStr, command); |
641 | free( promptStr); | 670 | free( promptStr); |
671 | cmdedit_terminate(); | ||
672 | signal(SIGWINCH, SIG_DFL); | ||
642 | return 0; | 673 | return 0; |
643 | #else | 674 | #else |
644 | fprintf(stdout, "%s %s", cwd, prompt); | 675 | fprintf(stdout, "%s %s", cwd, prompt); |
@@ -944,6 +975,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
944 | prog->numRedirections = 0; | 975 | prog->numRedirections = 0; |
945 | prog->redirections = NULL; | 976 | prog->redirections = NULL; |
946 | prog->freeGlob = 0; | 977 | prog->freeGlob = 0; |
978 | prog->isStopped = 0; | ||
947 | argc_l = 0; | 979 | argc_l = 0; |
948 | 980 | ||
949 | argvAlloced = 5; | 981 | argvAlloced = 5; |
@@ -1108,10 +1140,20 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
1108 | } | 1140 | } |
1109 | } | 1141 | } |
1110 | 1142 | ||
1143 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1144 | if (showXtrace==TRUE) { | ||
1145 | int j; | ||
1146 | fprintf(stderr, "+ "); | ||
1147 | for (j = 0; newJob->progs[i].argv[j]; j++) | ||
1148 | fprintf(stderr, "%s ", newJob->progs[i].argv[j]); | ||
1149 | fprintf(stderr, "\n"); | ||
1150 | } | ||
1151 | #endif | ||
1152 | |||
1111 | /* Check if the command matches any non-forking builtins */ | 1153 | /* Check if the command matches any non-forking builtins */ |
1112 | for (x = bltins; x->cmd; x++) { | 1154 | for (x = bltins; x->cmd; x++) { |
1113 | if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0 ) { | 1155 | if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0 ) { |
1114 | return (x->function(newJob, jobList)); | 1156 | return(x->function(newJob, jobList)); |
1115 | } | 1157 | } |
1116 | } | 1158 | } |
1117 | 1159 | ||
@@ -1130,6 +1172,7 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
1130 | dup2(nextout, 1); | 1172 | dup2(nextout, 1); |
1131 | dup2(nextout, 2); | 1173 | dup2(nextout, 2); |
1132 | close(nextout); | 1174 | close(nextout); |
1175 | close(pipefds[0]); | ||
1133 | } | 1176 | } |
1134 | 1177 | ||
1135 | /* explicit redirections override pipes */ | 1178 | /* explicit redirections override pipes */ |
@@ -1138,18 +1181,18 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
1138 | /* Check if the command matches any of the other builtins */ | 1181 | /* Check if the command matches any of the other builtins */ |
1139 | for (x = bltins_forking; x->cmd; x++) { | 1182 | for (x = bltins_forking; x->cmd; x++) { |
1140 | if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0) { | 1183 | if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0) { |
1184 | applet_name=x->cmd; | ||
1141 | exit (x->function(newJob, jobList)); | 1185 | exit (x->function(newJob, jobList)); |
1142 | } | 1186 | } |
1143 | } | 1187 | } |
1144 | #ifdef BB_FEATURE_SH_STANDALONE_SHELL | 1188 | #ifdef BB_FEATURE_SH_STANDALONE_SHELL |
1145 | /* Check if the command matches any busybox internal commands here */ | 1189 | /* Check if the command matches any busybox internal commands here */ |
1146 | /* TODO: Add matching when paths are appended (i.e. 'cat' currently | ||
1147 | * works, but '/bin/cat' doesn't ) */ | ||
1148 | while (a->name != 0) { | 1190 | while (a->name != 0) { |
1149 | if (strcmp(newJob->progs[i].argv[0], a->name) == 0) { | 1191 | if (strcmp(get_last_path_component(newJob->progs[i].argv[0]), a->name) == 0) { |
1150 | int argc_l; | 1192 | int argc_l; |
1151 | char** argv=newJob->progs[i].argv; | 1193 | char** argv=newJob->progs[i].argv; |
1152 | for(argc_l=0;*argv!=NULL; argv++, argc_l++); | 1194 | for(argc_l=0;*argv!=NULL; argv++, argc_l++); |
1195 | applet_name=a->name; | ||
1153 | exit((*(a->main)) (argc_l, newJob->progs[i].argv)); | 1196 | exit((*(a->main)) (argc_l, newJob->progs[i].argv)); |
1154 | } | 1197 | } |
1155 | a++; | 1198 | a++; |
@@ -1275,15 +1318,18 @@ static int busy_loop(FILE * input) | |||
1275 | jobList.fg->runningProgs--; | 1318 | jobList.fg->runningProgs--; |
1276 | jobList.fg->progs[i].pid = 0; | 1319 | jobList.fg->progs[i].pid = 0; |
1277 | 1320 | ||
1321 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1322 | lastReturnCode=WEXITSTATUS(status); | ||
1323 | #endif | ||
1324 | #if 0 | ||
1325 | printf("'%s' exited -- return code %d\n", jobList.fg->text, lastReturnCode); | ||
1326 | #endif | ||
1278 | if (!jobList.fg->runningProgs) { | 1327 | if (!jobList.fg->runningProgs) { |
1279 | /* child exited */ | 1328 | /* child exited */ |
1280 | 1329 | ||
1281 | removeJob(&jobList, jobList.fg); | 1330 | removeJob(&jobList, jobList.fg); |
1282 | jobList.fg = NULL; | 1331 | jobList.fg = NULL; |
1283 | } | 1332 | } |
1284 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1285 | lastReturnCode=WEXITSTATUS(status); | ||
1286 | #endif | ||
1287 | } else { | 1333 | } else { |
1288 | /* the child was stopped */ | 1334 | /* the child was stopped */ |
1289 | jobList.fg->stoppedProgs++; | 1335 | jobList.fg->stoppedProgs++; |
@@ -1337,10 +1383,65 @@ void free_memory(void) | |||
1337 | 1383 | ||
1338 | int shell_main(int argc_l, char **argv_l) | 1384 | int shell_main(int argc_l, char **argv_l) |
1339 | { | 1385 | { |
1386 | int opt; | ||
1340 | FILE *input = stdin; | 1387 | FILE *input = stdin; |
1341 | argc = argc_l; | 1388 | argc = argc_l; |
1342 | argv = argv_l; | 1389 | argv = argv_l; |
1343 | 1390 | ||
1391 | |||
1392 | //if (argv[0] && argv[0][0] == '-') { | ||
1393 | // builtin_source("/etc/profile"); | ||
1394 | //} | ||
1395 | |||
1396 | while ((opt = getopt(argc, argv, "cx")) > 0) { | ||
1397 | switch (opt) { | ||
1398 | case 'c': | ||
1399 | input = NULL; | ||
1400 | local_pending_command = (char *) calloc(BUFSIZ, sizeof(char)); | ||
1401 | if (local_pending_command == 0) { | ||
1402 | fatalError("sh: out of memory\n"); | ||
1403 | } | ||
1404 | for(; optind<argc; optind++) | ||
1405 | { | ||
1406 | if (strlen(local_pending_command) + strlen(argv[optind]) >= BUFSIZ) { | ||
1407 | local_pending_command = realloc(local_pending_command, | ||
1408 | strlen(local_pending_command) + strlen(argv[optind])); | ||
1409 | if (local_pending_command==NULL) | ||
1410 | fatalError("sh: command too long\n"); | ||
1411 | } | ||
1412 | strcat(local_pending_command, argv[optind]); | ||
1413 | if ( (optind + 1) < argc) | ||
1414 | strcat(local_pending_command, " "); | ||
1415 | } | ||
1416 | break; | ||
1417 | case 'x': | ||
1418 | showXtrace = TRUE; | ||
1419 | break; | ||
1420 | default: | ||
1421 | usage(shell_usage); | ||
1422 | } | ||
1423 | } | ||
1424 | |||
1425 | |||
1426 | if (optind<1 && input == stdin) { | ||
1427 | /* Looks like they want an interactive shell */ | ||
1428 | fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); | ||
1429 | fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); | ||
1430 | } else if (1==(argc-optind)) { | ||
1431 | input = fopen(argv[optind], "r"); | ||
1432 | if (!input) { | ||
1433 | fatalError("%s: %s\n", argv[optind], strerror(errno)); | ||
1434 | } | ||
1435 | } else { | ||
1436 | char *oldpath, *newpath; | ||
1437 | oldpath = getenv("PATH"); | ||
1438 | newpath=(char*)xmalloc(strlen(oldpath)+12); | ||
1439 | snprintf(newpath, strlen(oldpath)+9, "PATH=./:%s", oldpath); | ||
1440 | putenv(newpath); | ||
1441 | execvp(argv[optind], argv+optind); | ||
1442 | fatalError("%s: %s\n", argv[optind], strerror(errno)); | ||
1443 | } | ||
1444 | |||
1344 | /* initialize the cwd -- this is never freed...*/ | 1445 | /* initialize the cwd -- this is never freed...*/ |
1345 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); | 1446 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); |
1346 | getcwd(cwd, sizeof(char)*MAX_LINE); | 1447 | getcwd(cwd, sizeof(char)*MAX_LINE); |
@@ -1350,52 +1451,8 @@ int shell_main(int argc_l, char **argv_l) | |||
1350 | #endif | 1451 | #endif |
1351 | 1452 | ||
1352 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 1453 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
1353 | cmdedit_init(); | ||
1354 | signal(SIGWINCH, win_changed); | ||
1355 | win_changed(0); | 1454 | win_changed(0); |
1356 | #endif | 1455 | #endif |
1357 | 1456 | ||
1358 | //if (argv[0] && argv[0][0] == '-') { | ||
1359 | // builtin_source("/etc/profile"); | ||
1360 | //} | ||
1361 | |||
1362 | |||
1363 | if (argc < 2) { | ||
1364 | fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); | ||
1365 | fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); | ||
1366 | } else { | ||
1367 | if (argv[1][0]=='-' && argv[1][1]=='c') { | ||
1368 | int i; | ||
1369 | local_pending_command = (char *) calloc(BUFSIZ, sizeof(char)); | ||
1370 | if (local_pending_command == 0) { | ||
1371 | fatalError("out of memory\n"); | ||
1372 | } | ||
1373 | for(i=2; i<argc; i++) | ||
1374 | { | ||
1375 | if (strlen(local_pending_command) + strlen(argv[i]) >= BUFSIZ) { | ||
1376 | local_pending_command = realloc(local_pending_command, | ||
1377 | strlen(local_pending_command) + strlen(argv[i])); | ||
1378 | if (local_pending_command==NULL) | ||
1379 | fatalError("commands for -c option too long\n"); | ||
1380 | } | ||
1381 | strcat(local_pending_command, argv[i]); | ||
1382 | if ( (i + 1) < argc) | ||
1383 | strcat(local_pending_command, " "); | ||
1384 | } | ||
1385 | input = NULL; | ||
1386 | |||
1387 | } | ||
1388 | else if (argv[1][0]=='-') { | ||
1389 | usage(shell_usage); | ||
1390 | } | ||
1391 | else { | ||
1392 | input = fopen(argv[1], "r"); | ||
1393 | if (!input) { | ||
1394 | fatalError("Couldn't open file '%s': %s\n", argv[1], | ||
1395 | strerror(errno)); | ||
1396 | } | ||
1397 | } | ||
1398 | } | ||
1399 | |||
1400 | return (busy_loop(input)); | 1457 | return (busy_loop(input)); |
1401 | } | 1458 | } |
@@ -29,6 +29,7 @@ | |||
29 | //#define BB_FEATURE_SH_BACKTICKS | 29 | //#define BB_FEATURE_SH_BACKTICKS |
30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS | 30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS |
31 | //#define BB_FEATURE_SH_ENVIRONMENT | 31 | //#define BB_FEATURE_SH_ENVIRONMENT |
32 | //#define DEBUG_SHELL | ||
32 | 33 | ||
33 | 34 | ||
34 | #include "internal.h" | 35 | #include "internal.h" |
@@ -43,6 +44,7 @@ | |||
43 | #include <sys/ioctl.h> | 44 | #include <sys/ioctl.h> |
44 | #include <sys/wait.h> | 45 | #include <sys/wait.h> |
45 | #include <unistd.h> | 46 | #include <unistd.h> |
47 | #include <getopt.h> | ||
46 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 48 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
47 | #include "cmdedit.h" | 49 | #include "cmdedit.h" |
48 | #endif | 50 | #endif |
@@ -172,8 +174,9 @@ static char **argv; | |||
172 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 174 | #ifdef BB_FEATURE_SH_ENVIRONMENT |
173 | static int lastBgPid=-1; | 175 | static int lastBgPid=-1; |
174 | static int lastReturnCode=-1; | 176 | static int lastReturnCode=-1; |
177 | static int showXtrace=FALSE; | ||
175 | #endif | 178 | #endif |
176 | 179 | ||
177 | 180 | ||
178 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 181 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
179 | void win_changed(int junk) | 182 | void win_changed(int junk) |
@@ -382,14 +385,23 @@ static int builtin_if(struct job *cmd, struct jobSet *jobList) | |||
382 | status=strlen(charptr1); | 385 | status=strlen(charptr1); |
383 | local_pending_command = xmalloc(status+1); | 386 | local_pending_command = xmalloc(status+1); |
384 | strncpy(local_pending_command, charptr1, status); | 387 | strncpy(local_pending_command, charptr1, status); |
385 | printf("'if' now running '%s'\n", charptr1); | 388 | local_pending_command[status]='\0'; |
389 | #ifdef DEBUG_SHELL | ||
390 | fprintf(stderr, "'if' now testing '%s'\n", local_pending_command); | ||
391 | #endif | ||
386 | status = busy_loop(NULL); /* Frees local_pending_command */ | 392 | status = busy_loop(NULL); /* Frees local_pending_command */ |
387 | printf("if test returned "); | 393 | #ifdef DEBUG_SHELL |
394 | fprintf(stderr, "if test returned "); | ||
395 | #endif | ||
388 | if (status == 0) { | 396 | if (status == 0) { |
389 | printf("TRUE\n"); | 397 | #ifdef DEBUG_SHELL |
398 | fprintf(stderr, "TRUE\n"); | ||
399 | #endif | ||
390 | cmd->jobContext |= IF_TRUE_CONTEXT; | 400 | cmd->jobContext |= IF_TRUE_CONTEXT; |
391 | } else { | 401 | } else { |
392 | printf("FALSE\n"); | 402 | #ifdef DEBUG_SHELL |
403 | fprintf(stderr, "FALSE\n"); | ||
404 | #endif | ||
393 | cmd->jobContext |= IF_FALSE_CONTEXT; | 405 | cmd->jobContext |= IF_FALSE_CONTEXT; |
394 | } | 406 | } |
395 | 407 | ||
@@ -407,7 +419,7 @@ static int builtin_then(struct job *cmd, struct jobSet *junk) | |||
407 | return FALSE; | 419 | return FALSE; |
408 | } | 420 | } |
409 | /* If the if result was FALSE, skip the 'then' stuff */ | 421 | /* If the if result was FALSE, skip the 'then' stuff */ |
410 | if (cmd->jobContext & IF_TRUE_CONTEXT) { | 422 | if (cmd->jobContext & IF_FALSE_CONTEXT) { |
411 | return TRUE; | 423 | return TRUE; |
412 | } | 424 | } |
413 | 425 | ||
@@ -418,7 +430,10 @@ static int builtin_then(struct job *cmd, struct jobSet *junk) | |||
418 | status=strlen(charptr1); | 430 | status=strlen(charptr1); |
419 | local_pending_command = xmalloc(status+1); | 431 | local_pending_command = xmalloc(status+1); |
420 | strncpy(local_pending_command, charptr1, status); | 432 | strncpy(local_pending_command, charptr1, status); |
421 | printf("'then' now running '%s'\n", charptr1); | 433 | local_pending_command[status]='\0'; |
434 | #ifdef DEBUG_SHELL | ||
435 | fprintf(stderr, "'then' now running '%s'\n", charptr1); | ||
436 | #endif | ||
422 | return( busy_loop(NULL)); | 437 | return( busy_loop(NULL)); |
423 | } | 438 | } |
424 | 439 | ||
@@ -433,7 +448,7 @@ static int builtin_else(struct job *cmd, struct jobSet *junk) | |||
433 | return FALSE; | 448 | return FALSE; |
434 | } | 449 | } |
435 | /* If the if result was TRUE, skip the 'else' stuff */ | 450 | /* If the if result was TRUE, skip the 'else' stuff */ |
436 | if (cmd->jobContext & IF_FALSE_CONTEXT) { | 451 | if (cmd->jobContext & IF_TRUE_CONTEXT) { |
437 | return TRUE; | 452 | return TRUE; |
438 | } | 453 | } |
439 | 454 | ||
@@ -444,7 +459,10 @@ static int builtin_else(struct job *cmd, struct jobSet *junk) | |||
444 | status=strlen(charptr1); | 459 | status=strlen(charptr1); |
445 | local_pending_command = xmalloc(status+1); | 460 | local_pending_command = xmalloc(status+1); |
446 | strncpy(local_pending_command, charptr1, status); | 461 | strncpy(local_pending_command, charptr1, status); |
447 | printf("'else' now running '%s'\n", charptr1); | 462 | local_pending_command[status]='\0'; |
463 | #ifdef DEBUG_SHELL | ||
464 | fprintf(stderr, "'else' now running '%s'\n", charptr1); | ||
465 | #endif | ||
448 | return( busy_loop(NULL)); | 466 | return( busy_loop(NULL)); |
449 | } | 467 | } |
450 | 468 | ||
@@ -457,7 +475,9 @@ static int builtin_fi(struct job *cmd, struct jobSet *junk) | |||
457 | } | 475 | } |
458 | /* Clear out the if and then context bits */ | 476 | /* Clear out the if and then context bits */ |
459 | cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT); | 477 | cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT); |
460 | printf("Hit an fi -- jobContext=%d\n", cmd->jobContext); | 478 | #ifdef DEBUG_SHELL |
479 | fprintf(stderr, "Hit an fi -- jobContext=%d\n", cmd->jobContext); | ||
480 | #endif | ||
461 | return TRUE; | 481 | return TRUE; |
462 | } | 482 | } |
463 | #endif | 483 | #endif |
@@ -633,12 +653,23 @@ static int getCommand(FILE * source, char *command) | |||
633 | if (source == stdin) { | 653 | if (source == stdin) { |
634 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 654 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
635 | int len; | 655 | int len; |
656 | |||
657 | /* | ||
658 | ** enable command line editing only while a command line | ||
659 | ** is actually being read; otherwise, we'll end up bequeathing | ||
660 | ** atexit() handlers and other unwanted stuff to our | ||
661 | ** child processes (rob@sysgo.de) | ||
662 | */ | ||
663 | cmdedit_init(); | ||
664 | signal(SIGWINCH, win_changed); | ||
636 | len=fprintf(stdout, "%s %s", cwd, prompt); | 665 | len=fprintf(stdout, "%s %s", cwd, prompt); |
637 | fflush(stdout); | 666 | fflush(stdout); |
638 | promptStr=(char*)xmalloc(sizeof(char)*(len+1)); | 667 | promptStr=(char*)xmalloc(sizeof(char)*(len+1)); |
639 | sprintf(promptStr, "%s %s", cwd, prompt); | 668 | sprintf(promptStr, "%s %s", cwd, prompt); |
640 | cmdedit_read_input(promptStr, command); | 669 | cmdedit_read_input(promptStr, command); |
641 | free( promptStr); | 670 | free( promptStr); |
671 | cmdedit_terminate(); | ||
672 | signal(SIGWINCH, SIG_DFL); | ||
642 | return 0; | 673 | return 0; |
643 | #else | 674 | #else |
644 | fprintf(stdout, "%s %s", cwd, prompt); | 675 | fprintf(stdout, "%s %s", cwd, prompt); |
@@ -944,6 +975,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
944 | prog->numRedirections = 0; | 975 | prog->numRedirections = 0; |
945 | prog->redirections = NULL; | 976 | prog->redirections = NULL; |
946 | prog->freeGlob = 0; | 977 | prog->freeGlob = 0; |
978 | prog->isStopped = 0; | ||
947 | argc_l = 0; | 979 | argc_l = 0; |
948 | 980 | ||
949 | argvAlloced = 5; | 981 | argvAlloced = 5; |
@@ -1108,10 +1140,20 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
1108 | } | 1140 | } |
1109 | } | 1141 | } |
1110 | 1142 | ||
1143 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1144 | if (showXtrace==TRUE) { | ||
1145 | int j; | ||
1146 | fprintf(stderr, "+ "); | ||
1147 | for (j = 0; newJob->progs[i].argv[j]; j++) | ||
1148 | fprintf(stderr, "%s ", newJob->progs[i].argv[j]); | ||
1149 | fprintf(stderr, "\n"); | ||
1150 | } | ||
1151 | #endif | ||
1152 | |||
1111 | /* Check if the command matches any non-forking builtins */ | 1153 | /* Check if the command matches any non-forking builtins */ |
1112 | for (x = bltins; x->cmd; x++) { | 1154 | for (x = bltins; x->cmd; x++) { |
1113 | if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0 ) { | 1155 | if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0 ) { |
1114 | return (x->function(newJob, jobList)); | 1156 | return(x->function(newJob, jobList)); |
1115 | } | 1157 | } |
1116 | } | 1158 | } |
1117 | 1159 | ||
@@ -1130,6 +1172,7 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
1130 | dup2(nextout, 1); | 1172 | dup2(nextout, 1); |
1131 | dup2(nextout, 2); | 1173 | dup2(nextout, 2); |
1132 | close(nextout); | 1174 | close(nextout); |
1175 | close(pipefds[0]); | ||
1133 | } | 1176 | } |
1134 | 1177 | ||
1135 | /* explicit redirections override pipes */ | 1178 | /* explicit redirections override pipes */ |
@@ -1138,18 +1181,18 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
1138 | /* Check if the command matches any of the other builtins */ | 1181 | /* Check if the command matches any of the other builtins */ |
1139 | for (x = bltins_forking; x->cmd; x++) { | 1182 | for (x = bltins_forking; x->cmd; x++) { |
1140 | if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0) { | 1183 | if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0) { |
1184 | applet_name=x->cmd; | ||
1141 | exit (x->function(newJob, jobList)); | 1185 | exit (x->function(newJob, jobList)); |
1142 | } | 1186 | } |
1143 | } | 1187 | } |
1144 | #ifdef BB_FEATURE_SH_STANDALONE_SHELL | 1188 | #ifdef BB_FEATURE_SH_STANDALONE_SHELL |
1145 | /* Check if the command matches any busybox internal commands here */ | 1189 | /* Check if the command matches any busybox internal commands here */ |
1146 | /* TODO: Add matching when paths are appended (i.e. 'cat' currently | ||
1147 | * works, but '/bin/cat' doesn't ) */ | ||
1148 | while (a->name != 0) { | 1190 | while (a->name != 0) { |
1149 | if (strcmp(newJob->progs[i].argv[0], a->name) == 0) { | 1191 | if (strcmp(get_last_path_component(newJob->progs[i].argv[0]), a->name) == 0) { |
1150 | int argc_l; | 1192 | int argc_l; |
1151 | char** argv=newJob->progs[i].argv; | 1193 | char** argv=newJob->progs[i].argv; |
1152 | for(argc_l=0;*argv!=NULL; argv++, argc_l++); | 1194 | for(argc_l=0;*argv!=NULL; argv++, argc_l++); |
1195 | applet_name=a->name; | ||
1153 | exit((*(a->main)) (argc_l, newJob->progs[i].argv)); | 1196 | exit((*(a->main)) (argc_l, newJob->progs[i].argv)); |
1154 | } | 1197 | } |
1155 | a++; | 1198 | a++; |
@@ -1275,15 +1318,18 @@ static int busy_loop(FILE * input) | |||
1275 | jobList.fg->runningProgs--; | 1318 | jobList.fg->runningProgs--; |
1276 | jobList.fg->progs[i].pid = 0; | 1319 | jobList.fg->progs[i].pid = 0; |
1277 | 1320 | ||
1321 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1322 | lastReturnCode=WEXITSTATUS(status); | ||
1323 | #endif | ||
1324 | #if 0 | ||
1325 | printf("'%s' exited -- return code %d\n", jobList.fg->text, lastReturnCode); | ||
1326 | #endif | ||
1278 | if (!jobList.fg->runningProgs) { | 1327 | if (!jobList.fg->runningProgs) { |
1279 | /* child exited */ | 1328 | /* child exited */ |
1280 | 1329 | ||
1281 | removeJob(&jobList, jobList.fg); | 1330 | removeJob(&jobList, jobList.fg); |
1282 | jobList.fg = NULL; | 1331 | jobList.fg = NULL; |
1283 | } | 1332 | } |
1284 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1285 | lastReturnCode=WEXITSTATUS(status); | ||
1286 | #endif | ||
1287 | } else { | 1333 | } else { |
1288 | /* the child was stopped */ | 1334 | /* the child was stopped */ |
1289 | jobList.fg->stoppedProgs++; | 1335 | jobList.fg->stoppedProgs++; |
@@ -1337,10 +1383,65 @@ void free_memory(void) | |||
1337 | 1383 | ||
1338 | int shell_main(int argc_l, char **argv_l) | 1384 | int shell_main(int argc_l, char **argv_l) |
1339 | { | 1385 | { |
1386 | int opt; | ||
1340 | FILE *input = stdin; | 1387 | FILE *input = stdin; |
1341 | argc = argc_l; | 1388 | argc = argc_l; |
1342 | argv = argv_l; | 1389 | argv = argv_l; |
1343 | 1390 | ||
1391 | |||
1392 | //if (argv[0] && argv[0][0] == '-') { | ||
1393 | // builtin_source("/etc/profile"); | ||
1394 | //} | ||
1395 | |||
1396 | while ((opt = getopt(argc, argv, "cx")) > 0) { | ||
1397 | switch (opt) { | ||
1398 | case 'c': | ||
1399 | input = NULL; | ||
1400 | local_pending_command = (char *) calloc(BUFSIZ, sizeof(char)); | ||
1401 | if (local_pending_command == 0) { | ||
1402 | fatalError("sh: out of memory\n"); | ||
1403 | } | ||
1404 | for(; optind<argc; optind++) | ||
1405 | { | ||
1406 | if (strlen(local_pending_command) + strlen(argv[optind]) >= BUFSIZ) { | ||
1407 | local_pending_command = realloc(local_pending_command, | ||
1408 | strlen(local_pending_command) + strlen(argv[optind])); | ||
1409 | if (local_pending_command==NULL) | ||
1410 | fatalError("sh: command too long\n"); | ||
1411 | } | ||
1412 | strcat(local_pending_command, argv[optind]); | ||
1413 | if ( (optind + 1) < argc) | ||
1414 | strcat(local_pending_command, " "); | ||
1415 | } | ||
1416 | break; | ||
1417 | case 'x': | ||
1418 | showXtrace = TRUE; | ||
1419 | break; | ||
1420 | default: | ||
1421 | usage(shell_usage); | ||
1422 | } | ||
1423 | } | ||
1424 | |||
1425 | |||
1426 | if (optind<1 && input == stdin) { | ||
1427 | /* Looks like they want an interactive shell */ | ||
1428 | fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); | ||
1429 | fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); | ||
1430 | } else if (1==(argc-optind)) { | ||
1431 | input = fopen(argv[optind], "r"); | ||
1432 | if (!input) { | ||
1433 | fatalError("%s: %s\n", argv[optind], strerror(errno)); | ||
1434 | } | ||
1435 | } else { | ||
1436 | char *oldpath, *newpath; | ||
1437 | oldpath = getenv("PATH"); | ||
1438 | newpath=(char*)xmalloc(strlen(oldpath)+12); | ||
1439 | snprintf(newpath, strlen(oldpath)+9, "PATH=./:%s", oldpath); | ||
1440 | putenv(newpath); | ||
1441 | execvp(argv[optind], argv+optind); | ||
1442 | fatalError("%s: %s\n", argv[optind], strerror(errno)); | ||
1443 | } | ||
1444 | |||
1344 | /* initialize the cwd -- this is never freed...*/ | 1445 | /* initialize the cwd -- this is never freed...*/ |
1345 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); | 1446 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); |
1346 | getcwd(cwd, sizeof(char)*MAX_LINE); | 1447 | getcwd(cwd, sizeof(char)*MAX_LINE); |
@@ -1350,52 +1451,8 @@ int shell_main(int argc_l, char **argv_l) | |||
1350 | #endif | 1451 | #endif |
1351 | 1452 | ||
1352 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 1453 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
1353 | cmdedit_init(); | ||
1354 | signal(SIGWINCH, win_changed); | ||
1355 | win_changed(0); | 1454 | win_changed(0); |
1356 | #endif | 1455 | #endif |
1357 | 1456 | ||
1358 | //if (argv[0] && argv[0][0] == '-') { | ||
1359 | // builtin_source("/etc/profile"); | ||
1360 | //} | ||
1361 | |||
1362 | |||
1363 | if (argc < 2) { | ||
1364 | fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); | ||
1365 | fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); | ||
1366 | } else { | ||
1367 | if (argv[1][0]=='-' && argv[1][1]=='c') { | ||
1368 | int i; | ||
1369 | local_pending_command = (char *) calloc(BUFSIZ, sizeof(char)); | ||
1370 | if (local_pending_command == 0) { | ||
1371 | fatalError("out of memory\n"); | ||
1372 | } | ||
1373 | for(i=2; i<argc; i++) | ||
1374 | { | ||
1375 | if (strlen(local_pending_command) + strlen(argv[i]) >= BUFSIZ) { | ||
1376 | local_pending_command = realloc(local_pending_command, | ||
1377 | strlen(local_pending_command) + strlen(argv[i])); | ||
1378 | if (local_pending_command==NULL) | ||
1379 | fatalError("commands for -c option too long\n"); | ||
1380 | } | ||
1381 | strcat(local_pending_command, argv[i]); | ||
1382 | if ( (i + 1) < argc) | ||
1383 | strcat(local_pending_command, " "); | ||
1384 | } | ||
1385 | input = NULL; | ||
1386 | |||
1387 | } | ||
1388 | else if (argv[1][0]=='-') { | ||
1389 | usage(shell_usage); | ||
1390 | } | ||
1391 | else { | ||
1392 | input = fopen(argv[1], "r"); | ||
1393 | if (!input) { | ||
1394 | fatalError("Couldn't open file '%s': %s\n", argv[1], | ||
1395 | strerror(errno)); | ||
1396 | } | ||
1397 | } | ||
1398 | } | ||
1399 | |||
1400 | return (busy_loop(input)); | 1457 | return (busy_loop(input)); |
1401 | } | 1458 | } |
diff --git a/shell/cmdedit.c b/shell/cmdedit.c index 0ce64beeb..042064f1e 100644 --- a/shell/cmdedit.c +++ b/shell/cmdedit.c | |||
@@ -84,6 +84,7 @@ static int cmdedit_termw = 80; /* actual terminal width */ | |||
84 | static int cmdedit_scroll = 27; /* width of EOL scrolling region */ | 84 | static int cmdedit_scroll = 27; /* width of EOL scrolling region */ |
85 | static int history_counter = 0; /* Number of commands in history list */ | 85 | static int history_counter = 0; /* Number of commands in history list */ |
86 | static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */ | 86 | static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */ |
87 | static int exithandler_set = 0; /* Set to true when atexit() has been called */ | ||
87 | 88 | ||
88 | struct history { | 89 | struct history { |
89 | char *s; | 90 | char *s; |
@@ -709,10 +710,32 @@ extern void cmdedit_read_input(char* prompt, char command[BUFSIZ]) | |||
709 | 710 | ||
710 | extern void cmdedit_init(void) | 711 | extern void cmdedit_init(void) |
711 | { | 712 | { |
712 | atexit(cmdedit_reset_term); | 713 | if(exithandler_set == 0) { |
714 | atexit(cmdedit_reset_term); /* be sure to do this only once */ | ||
715 | exithandler_set = 1; | ||
716 | } | ||
713 | signal(SIGKILL, clean_up_and_die); | 717 | signal(SIGKILL, clean_up_and_die); |
714 | signal(SIGINT, clean_up_and_die); | 718 | signal(SIGINT, clean_up_and_die); |
715 | signal(SIGQUIT, clean_up_and_die); | 719 | signal(SIGQUIT, clean_up_and_die); |
716 | signal(SIGTERM, clean_up_and_die); | 720 | signal(SIGTERM, clean_up_and_die); |
717 | } | 721 | } |
722 | |||
723 | /* | ||
724 | ** Undo the effects of cmdedit_init() as good as we can: | ||
725 | ** I am not aware of a way to revoke an atexit() handler, | ||
726 | ** but, fortunately, our particular handler can be made | ||
727 | ** a no-op by setting reset_term = 0. | ||
728 | */ | ||
729 | extern void cmdedit_terminate(void) | ||
730 | { | ||
731 | cmdedit_reset_term(); | ||
732 | reset_term = 0; | ||
733 | signal(SIGKILL, SIG_DFL); | ||
734 | signal(SIGINT, SIG_DFL); | ||
735 | signal(SIGQUIT, SIG_DFL); | ||
736 | signal(SIGTERM, SIG_DFL); | ||
737 | } | ||
738 | |||
739 | |||
740 | |||
718 | #endif /* BB_FEATURE_SH_COMMAND_EDITING */ | 741 | #endif /* BB_FEATURE_SH_COMMAND_EDITING */ |
diff --git a/shell/cmdedit.h b/shell/cmdedit.h index b621ae8ec..27f7b5500 100644 --- a/shell/cmdedit.h +++ b/shell/cmdedit.h | |||
@@ -11,6 +11,7 @@ | |||
11 | typedef size_t (*cmdedit_strwidth_proc)(char *); | 11 | typedef size_t (*cmdedit_strwidth_proc)(char *); |
12 | 12 | ||
13 | void cmdedit_init(void); | 13 | void cmdedit_init(void); |
14 | void cmdedit_terminate(void); | ||
14 | void cmdedit_read_input(char* promptStr, char* command); /* read a line of input */ | 15 | void cmdedit_read_input(char* promptStr, char* command); /* read a line of input */ |
15 | void cmdedit_setwidth(int); /* specify width of screen */ | 16 | void cmdedit_setwidth(int); /* specify width of screen */ |
16 | void cmdedit_histadd(char *); /* adds entries to hist */ | 17 | void cmdedit_histadd(char *); /* adds entries to hist */ |
diff --git a/shell/lash.c b/shell/lash.c index e57567608..836fc9bab 100644 --- a/shell/lash.c +++ b/shell/lash.c | |||
@@ -29,6 +29,7 @@ | |||
29 | //#define BB_FEATURE_SH_BACKTICKS | 29 | //#define BB_FEATURE_SH_BACKTICKS |
30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS | 30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS |
31 | //#define BB_FEATURE_SH_ENVIRONMENT | 31 | //#define BB_FEATURE_SH_ENVIRONMENT |
32 | //#define DEBUG_SHELL | ||
32 | 33 | ||
33 | 34 | ||
34 | #include "internal.h" | 35 | #include "internal.h" |
@@ -43,6 +44,7 @@ | |||
43 | #include <sys/ioctl.h> | 44 | #include <sys/ioctl.h> |
44 | #include <sys/wait.h> | 45 | #include <sys/wait.h> |
45 | #include <unistd.h> | 46 | #include <unistd.h> |
47 | #include <getopt.h> | ||
46 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 48 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
47 | #include "cmdedit.h" | 49 | #include "cmdedit.h" |
48 | #endif | 50 | #endif |
@@ -172,8 +174,9 @@ static char **argv; | |||
172 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 174 | #ifdef BB_FEATURE_SH_ENVIRONMENT |
173 | static int lastBgPid=-1; | 175 | static int lastBgPid=-1; |
174 | static int lastReturnCode=-1; | 176 | static int lastReturnCode=-1; |
177 | static int showXtrace=FALSE; | ||
175 | #endif | 178 | #endif |
176 | 179 | ||
177 | 180 | ||
178 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 181 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
179 | void win_changed(int junk) | 182 | void win_changed(int junk) |
@@ -382,14 +385,23 @@ static int builtin_if(struct job *cmd, struct jobSet *jobList) | |||
382 | status=strlen(charptr1); | 385 | status=strlen(charptr1); |
383 | local_pending_command = xmalloc(status+1); | 386 | local_pending_command = xmalloc(status+1); |
384 | strncpy(local_pending_command, charptr1, status); | 387 | strncpy(local_pending_command, charptr1, status); |
385 | printf("'if' now running '%s'\n", charptr1); | 388 | local_pending_command[status]='\0'; |
389 | #ifdef DEBUG_SHELL | ||
390 | fprintf(stderr, "'if' now testing '%s'\n", local_pending_command); | ||
391 | #endif | ||
386 | status = busy_loop(NULL); /* Frees local_pending_command */ | 392 | status = busy_loop(NULL); /* Frees local_pending_command */ |
387 | printf("if test returned "); | 393 | #ifdef DEBUG_SHELL |
394 | fprintf(stderr, "if test returned "); | ||
395 | #endif | ||
388 | if (status == 0) { | 396 | if (status == 0) { |
389 | printf("TRUE\n"); | 397 | #ifdef DEBUG_SHELL |
398 | fprintf(stderr, "TRUE\n"); | ||
399 | #endif | ||
390 | cmd->jobContext |= IF_TRUE_CONTEXT; | 400 | cmd->jobContext |= IF_TRUE_CONTEXT; |
391 | } else { | 401 | } else { |
392 | printf("FALSE\n"); | 402 | #ifdef DEBUG_SHELL |
403 | fprintf(stderr, "FALSE\n"); | ||
404 | #endif | ||
393 | cmd->jobContext |= IF_FALSE_CONTEXT; | 405 | cmd->jobContext |= IF_FALSE_CONTEXT; |
394 | } | 406 | } |
395 | 407 | ||
@@ -407,7 +419,7 @@ static int builtin_then(struct job *cmd, struct jobSet *junk) | |||
407 | return FALSE; | 419 | return FALSE; |
408 | } | 420 | } |
409 | /* If the if result was FALSE, skip the 'then' stuff */ | 421 | /* If the if result was FALSE, skip the 'then' stuff */ |
410 | if (cmd->jobContext & IF_TRUE_CONTEXT) { | 422 | if (cmd->jobContext & IF_FALSE_CONTEXT) { |
411 | return TRUE; | 423 | return TRUE; |
412 | } | 424 | } |
413 | 425 | ||
@@ -418,7 +430,10 @@ static int builtin_then(struct job *cmd, struct jobSet *junk) | |||
418 | status=strlen(charptr1); | 430 | status=strlen(charptr1); |
419 | local_pending_command = xmalloc(status+1); | 431 | local_pending_command = xmalloc(status+1); |
420 | strncpy(local_pending_command, charptr1, status); | 432 | strncpy(local_pending_command, charptr1, status); |
421 | printf("'then' now running '%s'\n", charptr1); | 433 | local_pending_command[status]='\0'; |
434 | #ifdef DEBUG_SHELL | ||
435 | fprintf(stderr, "'then' now running '%s'\n", charptr1); | ||
436 | #endif | ||
422 | return( busy_loop(NULL)); | 437 | return( busy_loop(NULL)); |
423 | } | 438 | } |
424 | 439 | ||
@@ -433,7 +448,7 @@ static int builtin_else(struct job *cmd, struct jobSet *junk) | |||
433 | return FALSE; | 448 | return FALSE; |
434 | } | 449 | } |
435 | /* If the if result was TRUE, skip the 'else' stuff */ | 450 | /* If the if result was TRUE, skip the 'else' stuff */ |
436 | if (cmd->jobContext & IF_FALSE_CONTEXT) { | 451 | if (cmd->jobContext & IF_TRUE_CONTEXT) { |
437 | return TRUE; | 452 | return TRUE; |
438 | } | 453 | } |
439 | 454 | ||
@@ -444,7 +459,10 @@ static int builtin_else(struct job *cmd, struct jobSet *junk) | |||
444 | status=strlen(charptr1); | 459 | status=strlen(charptr1); |
445 | local_pending_command = xmalloc(status+1); | 460 | local_pending_command = xmalloc(status+1); |
446 | strncpy(local_pending_command, charptr1, status); | 461 | strncpy(local_pending_command, charptr1, status); |
447 | printf("'else' now running '%s'\n", charptr1); | 462 | local_pending_command[status]='\0'; |
463 | #ifdef DEBUG_SHELL | ||
464 | fprintf(stderr, "'else' now running '%s'\n", charptr1); | ||
465 | #endif | ||
448 | return( busy_loop(NULL)); | 466 | return( busy_loop(NULL)); |
449 | } | 467 | } |
450 | 468 | ||
@@ -457,7 +475,9 @@ static int builtin_fi(struct job *cmd, struct jobSet *junk) | |||
457 | } | 475 | } |
458 | /* Clear out the if and then context bits */ | 476 | /* Clear out the if and then context bits */ |
459 | cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT); | 477 | cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT); |
460 | printf("Hit an fi -- jobContext=%d\n", cmd->jobContext); | 478 | #ifdef DEBUG_SHELL |
479 | fprintf(stderr, "Hit an fi -- jobContext=%d\n", cmd->jobContext); | ||
480 | #endif | ||
461 | return TRUE; | 481 | return TRUE; |
462 | } | 482 | } |
463 | #endif | 483 | #endif |
@@ -633,12 +653,23 @@ static int getCommand(FILE * source, char *command) | |||
633 | if (source == stdin) { | 653 | if (source == stdin) { |
634 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 654 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
635 | int len; | 655 | int len; |
656 | |||
657 | /* | ||
658 | ** enable command line editing only while a command line | ||
659 | ** is actually being read; otherwise, we'll end up bequeathing | ||
660 | ** atexit() handlers and other unwanted stuff to our | ||
661 | ** child processes (rob@sysgo.de) | ||
662 | */ | ||
663 | cmdedit_init(); | ||
664 | signal(SIGWINCH, win_changed); | ||
636 | len=fprintf(stdout, "%s %s", cwd, prompt); | 665 | len=fprintf(stdout, "%s %s", cwd, prompt); |
637 | fflush(stdout); | 666 | fflush(stdout); |
638 | promptStr=(char*)xmalloc(sizeof(char)*(len+1)); | 667 | promptStr=(char*)xmalloc(sizeof(char)*(len+1)); |
639 | sprintf(promptStr, "%s %s", cwd, prompt); | 668 | sprintf(promptStr, "%s %s", cwd, prompt); |
640 | cmdedit_read_input(promptStr, command); | 669 | cmdedit_read_input(promptStr, command); |
641 | free( promptStr); | 670 | free( promptStr); |
671 | cmdedit_terminate(); | ||
672 | signal(SIGWINCH, SIG_DFL); | ||
642 | return 0; | 673 | return 0; |
643 | #else | 674 | #else |
644 | fprintf(stdout, "%s %s", cwd, prompt); | 675 | fprintf(stdout, "%s %s", cwd, prompt); |
@@ -944,6 +975,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
944 | prog->numRedirections = 0; | 975 | prog->numRedirections = 0; |
945 | prog->redirections = NULL; | 976 | prog->redirections = NULL; |
946 | prog->freeGlob = 0; | 977 | prog->freeGlob = 0; |
978 | prog->isStopped = 0; | ||
947 | argc_l = 0; | 979 | argc_l = 0; |
948 | 980 | ||
949 | argvAlloced = 5; | 981 | argvAlloced = 5; |
@@ -1108,10 +1140,20 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
1108 | } | 1140 | } |
1109 | } | 1141 | } |
1110 | 1142 | ||
1143 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1144 | if (showXtrace==TRUE) { | ||
1145 | int j; | ||
1146 | fprintf(stderr, "+ "); | ||
1147 | for (j = 0; newJob->progs[i].argv[j]; j++) | ||
1148 | fprintf(stderr, "%s ", newJob->progs[i].argv[j]); | ||
1149 | fprintf(stderr, "\n"); | ||
1150 | } | ||
1151 | #endif | ||
1152 | |||
1111 | /* Check if the command matches any non-forking builtins */ | 1153 | /* Check if the command matches any non-forking builtins */ |
1112 | for (x = bltins; x->cmd; x++) { | 1154 | for (x = bltins; x->cmd; x++) { |
1113 | if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0 ) { | 1155 | if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0 ) { |
1114 | return (x->function(newJob, jobList)); | 1156 | return(x->function(newJob, jobList)); |
1115 | } | 1157 | } |
1116 | } | 1158 | } |
1117 | 1159 | ||
@@ -1130,6 +1172,7 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
1130 | dup2(nextout, 1); | 1172 | dup2(nextout, 1); |
1131 | dup2(nextout, 2); | 1173 | dup2(nextout, 2); |
1132 | close(nextout); | 1174 | close(nextout); |
1175 | close(pipefds[0]); | ||
1133 | } | 1176 | } |
1134 | 1177 | ||
1135 | /* explicit redirections override pipes */ | 1178 | /* explicit redirections override pipes */ |
@@ -1138,18 +1181,18 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
1138 | /* Check if the command matches any of the other builtins */ | 1181 | /* Check if the command matches any of the other builtins */ |
1139 | for (x = bltins_forking; x->cmd; x++) { | 1182 | for (x = bltins_forking; x->cmd; x++) { |
1140 | if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0) { | 1183 | if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0) { |
1184 | applet_name=x->cmd; | ||
1141 | exit (x->function(newJob, jobList)); | 1185 | exit (x->function(newJob, jobList)); |
1142 | } | 1186 | } |
1143 | } | 1187 | } |
1144 | #ifdef BB_FEATURE_SH_STANDALONE_SHELL | 1188 | #ifdef BB_FEATURE_SH_STANDALONE_SHELL |
1145 | /* Check if the command matches any busybox internal commands here */ | 1189 | /* Check if the command matches any busybox internal commands here */ |
1146 | /* TODO: Add matching when paths are appended (i.e. 'cat' currently | ||
1147 | * works, but '/bin/cat' doesn't ) */ | ||
1148 | while (a->name != 0) { | 1190 | while (a->name != 0) { |
1149 | if (strcmp(newJob->progs[i].argv[0], a->name) == 0) { | 1191 | if (strcmp(get_last_path_component(newJob->progs[i].argv[0]), a->name) == 0) { |
1150 | int argc_l; | 1192 | int argc_l; |
1151 | char** argv=newJob->progs[i].argv; | 1193 | char** argv=newJob->progs[i].argv; |
1152 | for(argc_l=0;*argv!=NULL; argv++, argc_l++); | 1194 | for(argc_l=0;*argv!=NULL; argv++, argc_l++); |
1195 | applet_name=a->name; | ||
1153 | exit((*(a->main)) (argc_l, newJob->progs[i].argv)); | 1196 | exit((*(a->main)) (argc_l, newJob->progs[i].argv)); |
1154 | } | 1197 | } |
1155 | a++; | 1198 | a++; |
@@ -1275,15 +1318,18 @@ static int busy_loop(FILE * input) | |||
1275 | jobList.fg->runningProgs--; | 1318 | jobList.fg->runningProgs--; |
1276 | jobList.fg->progs[i].pid = 0; | 1319 | jobList.fg->progs[i].pid = 0; |
1277 | 1320 | ||
1321 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1322 | lastReturnCode=WEXITSTATUS(status); | ||
1323 | #endif | ||
1324 | #if 0 | ||
1325 | printf("'%s' exited -- return code %d\n", jobList.fg->text, lastReturnCode); | ||
1326 | #endif | ||
1278 | if (!jobList.fg->runningProgs) { | 1327 | if (!jobList.fg->runningProgs) { |
1279 | /* child exited */ | 1328 | /* child exited */ |
1280 | 1329 | ||
1281 | removeJob(&jobList, jobList.fg); | 1330 | removeJob(&jobList, jobList.fg); |
1282 | jobList.fg = NULL; | 1331 | jobList.fg = NULL; |
1283 | } | 1332 | } |
1284 | #ifdef BB_FEATURE_SH_ENVIRONMENT | ||
1285 | lastReturnCode=WEXITSTATUS(status); | ||
1286 | #endif | ||
1287 | } else { | 1333 | } else { |
1288 | /* the child was stopped */ | 1334 | /* the child was stopped */ |
1289 | jobList.fg->stoppedProgs++; | 1335 | jobList.fg->stoppedProgs++; |
@@ -1337,10 +1383,65 @@ void free_memory(void) | |||
1337 | 1383 | ||
1338 | int shell_main(int argc_l, char **argv_l) | 1384 | int shell_main(int argc_l, char **argv_l) |
1339 | { | 1385 | { |
1386 | int opt; | ||
1340 | FILE *input = stdin; | 1387 | FILE *input = stdin; |
1341 | argc = argc_l; | 1388 | argc = argc_l; |
1342 | argv = argv_l; | 1389 | argv = argv_l; |
1343 | 1390 | ||
1391 | |||
1392 | //if (argv[0] && argv[0][0] == '-') { | ||
1393 | // builtin_source("/etc/profile"); | ||
1394 | //} | ||
1395 | |||
1396 | while ((opt = getopt(argc, argv, "cx")) > 0) { | ||
1397 | switch (opt) { | ||
1398 | case 'c': | ||
1399 | input = NULL; | ||
1400 | local_pending_command = (char *) calloc(BUFSIZ, sizeof(char)); | ||
1401 | if (local_pending_command == 0) { | ||
1402 | fatalError("sh: out of memory\n"); | ||
1403 | } | ||
1404 | for(; optind<argc; optind++) | ||
1405 | { | ||
1406 | if (strlen(local_pending_command) + strlen(argv[optind]) >= BUFSIZ) { | ||
1407 | local_pending_command = realloc(local_pending_command, | ||
1408 | strlen(local_pending_command) + strlen(argv[optind])); | ||
1409 | if (local_pending_command==NULL) | ||
1410 | fatalError("sh: command too long\n"); | ||
1411 | } | ||
1412 | strcat(local_pending_command, argv[optind]); | ||
1413 | if ( (optind + 1) < argc) | ||
1414 | strcat(local_pending_command, " "); | ||
1415 | } | ||
1416 | break; | ||
1417 | case 'x': | ||
1418 | showXtrace = TRUE; | ||
1419 | break; | ||
1420 | default: | ||
1421 | usage(shell_usage); | ||
1422 | } | ||
1423 | } | ||
1424 | |||
1425 | |||
1426 | if (optind<1 && input == stdin) { | ||
1427 | /* Looks like they want an interactive shell */ | ||
1428 | fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); | ||
1429 | fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); | ||
1430 | } else if (1==(argc-optind)) { | ||
1431 | input = fopen(argv[optind], "r"); | ||
1432 | if (!input) { | ||
1433 | fatalError("%s: %s\n", argv[optind], strerror(errno)); | ||
1434 | } | ||
1435 | } else { | ||
1436 | char *oldpath, *newpath; | ||
1437 | oldpath = getenv("PATH"); | ||
1438 | newpath=(char*)xmalloc(strlen(oldpath)+12); | ||
1439 | snprintf(newpath, strlen(oldpath)+9, "PATH=./:%s", oldpath); | ||
1440 | putenv(newpath); | ||
1441 | execvp(argv[optind], argv+optind); | ||
1442 | fatalError("%s: %s\n", argv[optind], strerror(errno)); | ||
1443 | } | ||
1444 | |||
1344 | /* initialize the cwd -- this is never freed...*/ | 1445 | /* initialize the cwd -- this is never freed...*/ |
1345 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); | 1446 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); |
1346 | getcwd(cwd, sizeof(char)*MAX_LINE); | 1447 | getcwd(cwd, sizeof(char)*MAX_LINE); |
@@ -1350,52 +1451,8 @@ int shell_main(int argc_l, char **argv_l) | |||
1350 | #endif | 1451 | #endif |
1351 | 1452 | ||
1352 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 1453 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
1353 | cmdedit_init(); | ||
1354 | signal(SIGWINCH, win_changed); | ||
1355 | win_changed(0); | 1454 | win_changed(0); |
1356 | #endif | 1455 | #endif |
1357 | 1456 | ||
1358 | //if (argv[0] && argv[0][0] == '-') { | ||
1359 | // builtin_source("/etc/profile"); | ||
1360 | //} | ||
1361 | |||
1362 | |||
1363 | if (argc < 2) { | ||
1364 | fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); | ||
1365 | fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); | ||
1366 | } else { | ||
1367 | if (argv[1][0]=='-' && argv[1][1]=='c') { | ||
1368 | int i; | ||
1369 | local_pending_command = (char *) calloc(BUFSIZ, sizeof(char)); | ||
1370 | if (local_pending_command == 0) { | ||
1371 | fatalError("out of memory\n"); | ||
1372 | } | ||
1373 | for(i=2; i<argc; i++) | ||
1374 | { | ||
1375 | if (strlen(local_pending_command) + strlen(argv[i]) >= BUFSIZ) { | ||
1376 | local_pending_command = realloc(local_pending_command, | ||
1377 | strlen(local_pending_command) + strlen(argv[i])); | ||
1378 | if (local_pending_command==NULL) | ||
1379 | fatalError("commands for -c option too long\n"); | ||
1380 | } | ||
1381 | strcat(local_pending_command, argv[i]); | ||
1382 | if ( (i + 1) < argc) | ||
1383 | strcat(local_pending_command, " "); | ||
1384 | } | ||
1385 | input = NULL; | ||
1386 | |||
1387 | } | ||
1388 | else if (argv[1][0]=='-') { | ||
1389 | usage(shell_usage); | ||
1390 | } | ||
1391 | else { | ||
1392 | input = fopen(argv[1], "r"); | ||
1393 | if (!input) { | ||
1394 | fatalError("Couldn't open file '%s': %s\n", argv[1], | ||
1395 | strerror(errno)); | ||
1396 | } | ||
1397 | } | ||
1398 | } | ||
1399 | |||
1400 | return (busy_loop(input)); | 1457 | return (busy_loop(input)); |
1401 | } | 1458 | } |
@@ -1465,13 +1465,21 @@ extern void *xmalloc(size_t size) | |||
1465 | return ptr; | 1465 | return ptr; |
1466 | } | 1466 | } |
1467 | 1467 | ||
1468 | void *xrealloc(void *old, size_t size) | 1468 | extern void *xrealloc(void *old, size_t size) |
1469 | { | 1469 | { |
1470 | void *ptr = realloc(old, size); | 1470 | void *ptr = realloc(old, size); |
1471 | if (!ptr) | 1471 | if (!ptr) |
1472 | fatalError(memory_exhausted); | 1472 | fatalError(memory_exhausted); |
1473 | return ptr; | 1473 | return ptr; |
1474 | } | 1474 | } |
1475 | |||
1476 | extern void *xcalloc(size_t nmemb, size_t size) | ||
1477 | { | ||
1478 | void *ptr = calloc(nmemb, size); | ||
1479 | if (!ptr) | ||
1480 | fatalError(memory_exhausted); | ||
1481 | return ptr; | ||
1482 | } | ||
1475 | #endif | 1483 | #endif |
1476 | 1484 | ||
1477 | #if defined BB_FEATURE_NFSMOUNT | 1485 | #if defined BB_FEATURE_NFSMOUNT |