aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2000-07-28 15:14:45 +0000
committerEric Andersen <andersen@codepoet.org>2000-07-28 15:14:45 +0000
commit501c88b245fdc63f3f2a044fd7704bb468db3904 (patch)
tree3fff440532d8d380ae7e4f2933bc7163360f8279
parent6a99aaf0208151b7f5e5058efaa409496e2b7c4b (diff)
downloadbusybox-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.c6
-rw-r--r--busybox.c6
-rw-r--r--cmdedit.c25
-rw-r--r--cmdedit.h1
-rw-r--r--internal.h3
-rw-r--r--lash.c179
-rw-r--r--sh.c179
-rw-r--r--shell/cmdedit.c25
-rw-r--r--shell/cmdedit.h1
-rw-r--r--shell/lash.c179
-rw-r--r--utility.c10
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
340char *applet_name; 340const 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
417int main(int argc, char **argv) 417int 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 == '-'
diff --git a/busybox.c b/busybox.c
index 291d31b19..1ed44ed9b 100644
--- a/busybox.c
+++ b/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
340char *applet_name; 340const 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
417int main(int argc, char **argv) 417int 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 == '-'
diff --git a/cmdedit.c b/cmdedit.c
index 0ce64beeb..042064f1e 100644
--- a/cmdedit.c
+++ b/cmdedit.c
@@ -84,6 +84,7 @@ static int cmdedit_termw = 80; /* actual terminal width */
84static int cmdedit_scroll = 27; /* width of EOL scrolling region */ 84static int cmdedit_scroll = 27; /* width of EOL scrolling region */
85static int history_counter = 0; /* Number of commands in history list */ 85static int history_counter = 0; /* Number of commands in history list */
86static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */ 86static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */
87static int exithandler_set = 0; /* Set to true when atexit() has been called */
87 88
88struct history { 89struct history {
89 char *s; 90 char *s;
@@ -709,10 +710,32 @@ extern void cmdedit_read_input(char* prompt, char command[BUFSIZ])
709 710
710extern void cmdedit_init(void) 711extern 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*/
729extern 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/cmdedit.h b/cmdedit.h
index b621ae8ec..27f7b5500 100644
--- a/cmdedit.h
+++ b/cmdedit.h
@@ -11,6 +11,7 @@
11typedef size_t (*cmdedit_strwidth_proc)(char *); 11typedef size_t (*cmdedit_strwidth_proc)(char *);
12 12
13void cmdedit_init(void); 13void cmdedit_init(void);
14void cmdedit_terminate(void);
14void cmdedit_read_input(char* promptStr, char* command); /* read a line of input */ 15void cmdedit_read_input(char* promptStr, char* command); /* read a line of input */
15void cmdedit_setwidth(int); /* specify width of screen */ 16void cmdedit_setwidth(int); /* specify width of screen */
16void cmdedit_histadd(char *); /* adds entries to hist */ 17void 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[];
317extern const char whoami_usage[]; 317extern const char whoami_usage[];
318extern const char yes_usage[]; 318extern const char yes_usage[];
319 319
320extern char *applet_name; 320extern const char *applet_name;
321 321
322extern void usage(const char *usage) __attribute__ ((noreturn)); 322extern void usage(const char *usage) __attribute__ ((noreturn));
323extern void errorMsg(const char *s, ...) __attribute__ ((format (printf, 1, 2))); 323extern 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
381extern void *xmalloc (size_t size); 381extern void *xmalloc (size_t size);
382extern void *xrealloc(void *old, size_t size); 382extern void *xrealloc(void *old, size_t size);
383extern void *xcalloc(size_t nmemb, size_t size);
383extern char *xstrdup (const char *s); 384extern char *xstrdup (const char *s);
384#endif 385#endif
385extern char *xstrndup (const char *s, int n); 386extern char *xstrndup (const char *s, int n);
diff --git a/lash.c b/lash.c
index e57567608..836fc9bab 100644
--- a/lash.c
+++ b/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
173static int lastBgPid=-1; 175static int lastBgPid=-1;
174static int lastReturnCode=-1; 176static int lastReturnCode=-1;
177static 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
179void win_changed(int junk) 182void 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
1338int shell_main(int argc_l, char **argv_l) 1384int 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/sh.c b/sh.c
index e57567608..836fc9bab 100644
--- a/sh.c
+++ b/sh.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
173static int lastBgPid=-1; 175static int lastBgPid=-1;
174static int lastReturnCode=-1; 176static int lastReturnCode=-1;
177static 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
179void win_changed(int junk) 182void 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
1338int shell_main(int argc_l, char **argv_l) 1384int 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 */
84static int cmdedit_scroll = 27; /* width of EOL scrolling region */ 84static int cmdedit_scroll = 27; /* width of EOL scrolling region */
85static int history_counter = 0; /* Number of commands in history list */ 85static int history_counter = 0; /* Number of commands in history list */
86static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */ 86static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */
87static int exithandler_set = 0; /* Set to true when atexit() has been called */
87 88
88struct history { 89struct history {
89 char *s; 90 char *s;
@@ -709,10 +710,32 @@ extern void cmdedit_read_input(char* prompt, char command[BUFSIZ])
709 710
710extern void cmdedit_init(void) 711extern 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*/
729extern 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 @@
11typedef size_t (*cmdedit_strwidth_proc)(char *); 11typedef size_t (*cmdedit_strwidth_proc)(char *);
12 12
13void cmdedit_init(void); 13void cmdedit_init(void);
14void cmdedit_terminate(void);
14void cmdedit_read_input(char* promptStr, char* command); /* read a line of input */ 15void cmdedit_read_input(char* promptStr, char* command); /* read a line of input */
15void cmdedit_setwidth(int); /* specify width of screen */ 16void cmdedit_setwidth(int); /* specify width of screen */
16void cmdedit_histadd(char *); /* adds entries to hist */ 17void 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
173static int lastBgPid=-1; 175static int lastBgPid=-1;
174static int lastReturnCode=-1; 176static int lastReturnCode=-1;
177static 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
179void win_changed(int junk) 182void 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
1338int shell_main(int argc_l, char **argv_l) 1384int 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/utility.c b/utility.c
index 50f497ff6..565fd735c 100644
--- a/utility.c
+++ b/utility.c
@@ -1465,13 +1465,21 @@ extern void *xmalloc(size_t size)
1465 return ptr; 1465 return ptr;
1466} 1466}
1467 1467
1468void *xrealloc(void *old, size_t size) 1468extern 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
1476extern 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