diff options
Diffstat (limited to 'sh.c')
-rw-r--r-- | sh.c | 179 |
1 files changed, 118 insertions, 61 deletions
@@ -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 | } |