diff options
| author | Eric Andersen <andersen@codepoet.org> | 2000-07-25 18:06:52 +0000 |
|---|---|---|
| committer | Eric Andersen <andersen@codepoet.org> | 2000-07-25 18:06:52 +0000 |
| commit | fad9c1198aa9486f2df01fe139afa329eb893b58 (patch) | |
| tree | e4c1b0fdaff8f3b132213ddc85cd2b96a265c26d /shell | |
| parent | b040d4f3da1545225b9a58301deb29acee6aa7f3 (diff) | |
| download | busybox-w32-fad9c1198aa9486f2df01fe139afa329eb893b58.tar.gz busybox-w32-fad9c1198aa9486f2df01fe139afa329eb893b58.tar.bz2 busybox-w32-fad9c1198aa9486f2df01fe139afa329eb893b58.zip | |
Finish off fixing up the memleaks (I think). Added the beginnings of
some if-then-else-fi support (nonfunctional and turned off)
-Erik
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/lash.c | 161 |
1 files changed, 123 insertions, 38 deletions
diff --git a/shell/lash.c b/shell/lash.c index 6029eaa5c..b2d1d43d3 100644 --- a/shell/lash.c +++ b/shell/lash.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | 27 | ||
| 28 | 28 | ||
| 29 | #define BB_FEATURE_SH_BACKTICKS | 29 | #define BB_FEATURE_SH_BACKTICKS |
| 30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS | ||
| 30 | 31 | ||
| 31 | 32 | ||
| 32 | 33 | ||
| @@ -55,6 +56,14 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, | |||
| 55 | REDIRECT_APPEND | 56 | REDIRECT_APPEND |
| 56 | }; | 57 | }; |
| 57 | 58 | ||
| 59 | #define REGULAR_JOB_CONTEXT 0x1 | ||
| 60 | #define IF_EXP_CONTEXT 0x2 | ||
| 61 | #define THEN_EXP_CONTEXT 0x4 | ||
| 62 | #define ELSE_EXP_CONTEXT 0x8 | ||
| 63 | |||
| 64 | enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT | ||
| 65 | }; | ||
| 66 | |||
| 58 | struct jobSet { | 67 | struct jobSet { |
| 59 | struct job *head; /* head of list of running jobs */ | 68 | struct job *head; /* head of list of running jobs */ |
| 60 | struct job *fg; /* current foreground job */ | 69 | struct job *fg; /* current foreground job */ |
| @@ -86,12 +95,12 @@ struct job { | |||
| 86 | struct childProgram *progs; /* array of programs in job */ | 95 | struct childProgram *progs; /* array of programs in job */ |
| 87 | struct job *next; /* to track background commands */ | 96 | struct job *next; /* to track background commands */ |
| 88 | int stoppedProgs; /* number of programs alive, but stopped */ | 97 | int stoppedProgs; /* number of programs alive, but stopped */ |
| 98 | int jobContext; /* bitmask defining current context */ | ||
| 89 | }; | 99 | }; |
| 90 | 100 | ||
| 91 | struct builtInCommand { | 101 | struct builtInCommand { |
| 92 | char *cmd; /* name */ | 102 | char *cmd; /* name */ |
| 93 | char *descr; /* description */ | 103 | char *descr; /* description */ |
| 94 | char *usage; /* usage */ | ||
| 95 | int (*function) (struct job *, struct jobSet * jobList); /* function ptr */ | 104 | int (*function) (struct job *, struct jobSet * jobList); /* function ptr */ |
| 96 | }; | 105 | }; |
| 97 | 106 | ||
| @@ -107,6 +116,12 @@ static int builtin_export(struct job *cmd, struct jobSet *junk); | |||
| 107 | static int builtin_source(struct job *cmd, struct jobSet *jobList); | 116 | static int builtin_source(struct job *cmd, struct jobSet *jobList); |
| 108 | static int builtin_unset(struct job *cmd, struct jobSet *junk); | 117 | static int builtin_unset(struct job *cmd, struct jobSet *junk); |
| 109 | static int builtin_read(struct job *cmd, struct jobSet *junk); | 118 | static int builtin_read(struct job *cmd, struct jobSet *junk); |
| 119 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
| 120 | static int builtin_if(struct job *cmd, struct jobSet *junk); | ||
| 121 | static int builtin_then(struct job *cmd, struct jobSet *junk); | ||
| 122 | static int builtin_else(struct job *cmd, struct jobSet *junk); | ||
| 123 | static int builtin_fi(struct job *cmd, struct jobSet *junk); | ||
| 124 | #endif | ||
| 110 | 125 | ||
| 111 | 126 | ||
| 112 | /* function prototypes for shell stuff */ | 127 | /* function prototypes for shell stuff */ |
| @@ -122,30 +137,38 @@ static int busy_loop(FILE * input); | |||
| 122 | * can change global variables in the parent shell process but they will not | 137 | * can change global variables in the parent shell process but they will not |
| 123 | * work with pipes and redirects; 'unset foo | whatever' will not work) */ | 138 | * work with pipes and redirects; 'unset foo | whatever' will not work) */ |
| 124 | static struct builtInCommand bltins[] = { | 139 | static struct builtInCommand bltins[] = { |
| 125 | {"bg", "Resume a job in the background", "bg [%%job]", builtin_fg_bg}, | 140 | {"bg", "Resume a job in the background", builtin_fg_bg}, |
| 126 | {"cd", "Change working directory", "cd [dir]", builtin_cd}, | 141 | {"cd", "Change working directory", builtin_cd}, |
| 127 | {"exit", "Exit from shell()", "exit", builtin_exit}, | 142 | {"exit", "Exit from shell()", builtin_exit}, |
| 128 | {"fg", "Bring job into the foreground", "fg [%%job]", builtin_fg_bg}, | 143 | {"fg", "Bring job into the foreground", builtin_fg_bg}, |
| 129 | {"jobs", "Lists the active jobs", "jobs", builtin_jobs}, | 144 | {"jobs", "Lists the active jobs", builtin_jobs}, |
| 130 | {"export", "Set environment variable", "export [VAR=value]", builtin_export}, | 145 | {"export", "Set environment variable", builtin_export}, |
| 131 | {"unset", "Unset environment variable", "unset VAR", builtin_unset}, | 146 | {"unset", "Unset environment variable", builtin_unset}, |
| 132 | {"read", "Input environment variable", "read [VAR]", builtin_read}, | 147 | {"read", "Input environment variable", builtin_read}, |
| 133 | {NULL, NULL, NULL, NULL} | 148 | {NULL, NULL, NULL} |
| 134 | }; | 149 | }; |
| 135 | 150 | ||
| 136 | /* Table of forking built-in functions (things that fork cannot change global | 151 | /* Table of forking built-in functions (things that fork cannot change global |
| 137 | * variables in the parent process, such as the current working directory) */ | 152 | * variables in the parent process, such as the current working directory) */ |
| 138 | static struct builtInCommand bltins_forking[] = { | 153 | static struct builtInCommand bltins_forking[] = { |
| 139 | {"env", "Print all environment variables", "env", builtin_env}, | 154 | {"env", "Print all environment variables", builtin_env}, |
| 140 | {"pwd", "Print current directory", "pwd", builtin_pwd}, | 155 | {"pwd", "Print current directory", builtin_pwd}, |
| 141 | {".", "Source-in and run commands in a file", ". filename", builtin_source}, | 156 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS |
| 142 | {"help", "List shell built-in commands", "help", builtin_help}, | 157 | {"if", NULL, builtin_if}, |
| 143 | {NULL, NULL, NULL, NULL} | 158 | {"then", NULL, builtin_then}, |
| 159 | {"else", NULL, builtin_else}, | ||
| 160 | {"fi", NULL, builtin_fi}, | ||
| 161 | #endif | ||
| 162 | {".", "Source-in and run commands in a file", builtin_source}, | ||
| 163 | {"help", "List shell built-in commands", builtin_help}, | ||
| 164 | {NULL, NULL, NULL} | ||
| 144 | }; | 165 | }; |
| 145 | 166 | ||
| 146 | static char *prompt = "# "; | 167 | static char *prompt = "# "; |
| 147 | static char *cwd; | 168 | static char *cwd; |
| 148 | static char *local_pending_command = NULL; | 169 | static char *local_pending_command = NULL; |
| 170 | static char *promptStr = NULL; | ||
| 171 | static struct jobSet jobList = { NULL, NULL }; | ||
| 149 | 172 | ||
| 150 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 173 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
| 151 | void win_changed(int junk) | 174 | void win_changed(int junk) |
| @@ -256,9 +279,13 @@ static int builtin_help(struct job *dummy, struct jobSet *junk) | |||
| 256 | fprintf(stdout, "\nBuilt-in commands:\n"); | 279 | fprintf(stdout, "\nBuilt-in commands:\n"); |
| 257 | fprintf(stdout, "-------------------\n"); | 280 | fprintf(stdout, "-------------------\n"); |
| 258 | for (x = bltins; x->cmd; x++) { | 281 | for (x = bltins; x->cmd; x++) { |
| 282 | if (x->descr==NULL) | ||
| 283 | continue; | ||
| 259 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); | 284 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); |
| 260 | } | 285 | } |
| 261 | for (x = bltins_forking; x->cmd; x++) { | 286 | for (x = bltins_forking; x->cmd; x++) { |
| 287 | if (x->descr==NULL) | ||
| 288 | continue; | ||
| 262 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); | 289 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); |
| 263 | } | 290 | } |
| 264 | fprintf(stdout, "\n\n"); | 291 | fprintf(stdout, "\n\n"); |
| @@ -339,6 +366,44 @@ static int builtin_read(struct job *cmd, struct jobSet *junk) | |||
| 339 | return (res); | 366 | return (res); |
| 340 | } | 367 | } |
| 341 | 368 | ||
| 369 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
| 370 | /* Built-in handler for 'if' commands */ | ||
| 371 | static int builtin_if(struct job *cmd, struct jobSet *junk) | ||
| 372 | { | ||
| 373 | cmd->jobContext |= IF_EXP_CONTEXT; | ||
| 374 | printf("Hit an if -- jobContext=%d\n", cmd->jobContext); | ||
| 375 | return TRUE; | ||
| 376 | } | ||
| 377 | |||
| 378 | /* Built-in handler for 'then' (part of the 'if' command) */ | ||
| 379 | static int builtin_then(struct job *cmd, struct jobSet *junk) | ||
| 380 | { | ||
| 381 | if (cmd->jobContext & IF_EXP_CONTEXT) { | ||
| 382 | fprintf(stderr, "unexpected token `then'\n"); | ||
| 383 | fflush(stderr); | ||
| 384 | return FALSE; | ||
| 385 | } | ||
| 386 | cmd->jobContext |= THEN_EXP_CONTEXT; | ||
| 387 | printf("Hit an then -- jobContext=%d\n", cmd->jobContext); | ||
| 388 | return TRUE; | ||
| 389 | } | ||
| 390 | |||
| 391 | /* Built-in handler for 'else' (part of the 'if' command) */ | ||
| 392 | static int builtin_else(struct job *cmd, struct jobSet *junk) | ||
| 393 | { | ||
| 394 | printf("Hit an else\n"); | ||
| 395 | cmd->jobContext |= ELSE_EXP_CONTEXT; | ||
| 396 | return TRUE; | ||
| 397 | } | ||
| 398 | |||
| 399 | /* Built-in handler for 'fi' (part of the 'if' command) */ | ||
| 400 | static int builtin_fi(struct job *cmd, struct jobSet *junk) | ||
| 401 | { | ||
| 402 | printf("Hit an fi\n"); | ||
| 403 | return TRUE; | ||
| 404 | } | ||
| 405 | #endif | ||
| 406 | |||
| 342 | /* Built-in '.' handler (read-in and execute commands from file) */ | 407 | /* Built-in '.' handler (read-in and execute commands from file) */ |
| 343 | static int builtin_source(struct job *cmd, struct jobSet *junk) | 408 | static int builtin_source(struct job *cmd, struct jobSet *junk) |
| 344 | { | 409 | { |
| @@ -471,7 +536,6 @@ static int getCommand(FILE * source, char *command) | |||
| 471 | if (source == stdin) { | 536 | if (source == stdin) { |
| 472 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 537 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
| 473 | int len; | 538 | int len; |
| 474 | char *promptStr; | ||
| 475 | len=fprintf(stdout, "%s %s", cwd, prompt); | 539 | len=fprintf(stdout, "%s %s", cwd, prompt); |
| 476 | fflush(stdout); | 540 | fflush(stdout); |
| 477 | promptStr=(char*)xmalloc(sizeof(char)*(len+1)); | 541 | promptStr=(char*)xmalloc(sizeof(char)*(len+1)); |
| @@ -587,8 +651,9 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
| 587 | Getting clean memory relieves us of the task of NULL | 651 | Getting clean memory relieves us of the task of NULL |
| 588 | terminating things and makes the rest of this look a bit | 652 | terminating things and makes the rest of this look a bit |
| 589 | cleaner (though it is, admittedly, a tad less efficient) */ | 653 | cleaner (though it is, admittedly, a tad less efficient) */ |
| 590 | job->cmdBuf = command = calloc(1, 2*strlen(*commandPtr) + 1); | 654 | job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char)); |
| 591 | job->text = NULL; | 655 | job->text = NULL; |
| 656 | job->jobContext = REGULAR_JOB_CONTEXT; | ||
| 592 | 657 | ||
| 593 | prog = job->progs; | 658 | prog = job->progs; |
| 594 | prog->numRedirections = 0; | 659 | prog->numRedirections = 0; |
| @@ -863,7 +928,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
| 863 | 928 | ||
| 864 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]) | 929 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]) |
| 865 | { | 930 | { |
| 866 | struct job *job; | 931 | struct job *theJob; |
| 867 | int i; | 932 | int i; |
| 868 | int nextin, nextout; | 933 | int nextin, nextout; |
| 869 | int pipefds[2]; /* pipefd[0] is for reading */ | 934 | int pipefds[2]; /* pipefd[0] is for reading */ |
| @@ -957,33 +1022,33 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
| 957 | 1022 | ||
| 958 | newJob->pgrp = newJob->progs[0].pid; | 1023 | newJob->pgrp = newJob->progs[0].pid; |
| 959 | 1024 | ||
| 960 | /* find the ID for the job to use */ | 1025 | /* find the ID for the theJob to use */ |
| 961 | newJob->jobId = 1; | 1026 | newJob->jobId = 1; |
| 962 | for (job = jobList->head; job; job = job->next) | 1027 | for (theJob = jobList->head; theJob; theJob = theJob->next) |
| 963 | if (job->jobId >= newJob->jobId) | 1028 | if (theJob->jobId >= newJob->jobId) |
| 964 | newJob->jobId = job->jobId + 1; | 1029 | newJob->jobId = theJob->jobId + 1; |
| 965 | 1030 | ||
| 966 | /* add the job to the list of running jobs */ | 1031 | /* add the theJob to the list of running jobs */ |
| 967 | if (!jobList->head) { | 1032 | if (!jobList->head) { |
| 968 | job = jobList->head = malloc(sizeof(*job)); | 1033 | theJob = jobList->head = malloc(sizeof(*theJob)); |
| 969 | } else { | 1034 | } else { |
| 970 | for (job = jobList->head; job->next; job = job->next); | 1035 | for (theJob = jobList->head; theJob->next; theJob = theJob->next); |
| 971 | job->next = malloc(sizeof(*job)); | 1036 | theJob->next = malloc(sizeof(*theJob)); |
| 972 | job = job->next; | 1037 | theJob = theJob->next; |
| 973 | } | 1038 | } |
| 974 | 1039 | ||
| 975 | *job = *newJob; | 1040 | *theJob = *newJob; |
| 976 | job->next = NULL; | 1041 | theJob->next = NULL; |
| 977 | job->runningProgs = job->numProgs; | 1042 | theJob->runningProgs = theJob->numProgs; |
| 978 | job->stoppedProgs = 0; | 1043 | theJob->stoppedProgs = 0; |
| 979 | 1044 | ||
| 980 | if (inBg) { | 1045 | if (inBg) { |
| 981 | /* we don't wait for background jobs to return -- append it | 1046 | /* we don't wait for background theJobs to return -- append it |
| 982 | to the list of backgrounded jobs and leave it alone */ | 1047 | to the list of backgrounded theJobs and leave it alone */ |
| 983 | printf("[%d] %d\n", job->jobId, | 1048 | printf("[%d] %d\n", theJob->jobId, |
| 984 | newJob->progs[newJob->numProgs - 1].pid); | 1049 | newJob->progs[newJob->numProgs - 1].pid); |
| 985 | } else { | 1050 | } else { |
| 986 | jobList->fg = job; | 1051 | jobList->fg = theJob; |
| 987 | 1052 | ||
| 988 | /* move the new process group into the foreground */ | 1053 | /* move the new process group into the foreground */ |
| 989 | /* suppress messages when run from /linuxrc mag@sysgo.de */ | 1054 | /* suppress messages when run from /linuxrc mag@sysgo.de */ |
| @@ -1037,7 +1102,6 @@ static int busy_loop(FILE * input) | |||
| 1037 | { | 1102 | { |
| 1038 | char *command; | 1103 | char *command; |
| 1039 | char *nextCommand = NULL; | 1104 | char *nextCommand = NULL; |
| 1040 | struct jobSet jobList = { NULL, NULL }; | ||
| 1041 | struct job newJob; | 1105 | struct job newJob; |
| 1042 | pid_t parent_pgrp; | 1106 | pid_t parent_pgrp; |
| 1043 | int i; | 1107 | int i; |
| @@ -1070,7 +1134,8 @@ static int busy_loop(FILE * input) | |||
| 1070 | newJob.numProgs) { | 1134 | newJob.numProgs) { |
| 1071 | int pipefds[2] = {-1,-1}; | 1135 | int pipefds[2] = {-1,-1}; |
| 1072 | runCommand(&newJob, &jobList, inBg, pipefds); | 1136 | runCommand(&newJob, &jobList, inBg, pipefds); |
| 1073 | } else { | 1137 | } |
| 1138 | else { | ||
| 1074 | free(command); | 1139 | free(command); |
| 1075 | command = (char *) calloc(BUFSIZ, sizeof(char)); | 1140 | command = (char *) calloc(BUFSIZ, sizeof(char)); |
| 1076 | nextCommand = NULL; | 1141 | nextCommand = NULL; |
| @@ -1079,7 +1144,7 @@ static int busy_loop(FILE * input) | |||
| 1079 | /* a job is running in the foreground; wait for it */ | 1144 | /* a job is running in the foreground; wait for it */ |
| 1080 | i = 0; | 1145 | i = 0; |
| 1081 | while (!jobList.fg->progs[i].pid || | 1146 | while (!jobList.fg->progs[i].pid || |
| 1082 | jobList.fg->progs[i].isStopped) i++; | 1147 | jobList.fg->progs[i].isStopped == 1) i++; |
| 1083 | 1148 | ||
| 1084 | waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED); | 1149 | waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED); |
| 1085 | 1150 | ||
| @@ -1128,6 +1193,22 @@ static int busy_loop(FILE * input) | |||
| 1128 | } | 1193 | } |
| 1129 | 1194 | ||
| 1130 | 1195 | ||
| 1196 | #ifdef BB_FEATURE_CLEAN_UP | ||
| 1197 | void free_memory(void) | ||
| 1198 | { | ||
| 1199 | if (promptStr) | ||
| 1200 | free(promptStr); | ||
| 1201 | if (cwd) | ||
| 1202 | free(cwd); | ||
| 1203 | if (local_pending_command) | ||
| 1204 | free(local_pending_command); | ||
| 1205 | |||
| 1206 | if (jobList.fg && !jobList.fg->runningProgs) { | ||
| 1207 | removeJob(&jobList, jobList.fg); | ||
| 1208 | } | ||
| 1209 | } | ||
| 1210 | #endif | ||
| 1211 | |||
| 1131 | 1212 | ||
| 1132 | int shell_main(int argc, char **argv) | 1213 | int shell_main(int argc, char **argv) |
| 1133 | { | 1214 | { |
| @@ -1137,6 +1218,10 @@ int shell_main(int argc, char **argv) | |||
| 1137 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); | 1218 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); |
| 1138 | getcwd(cwd, sizeof(char)*MAX_LINE); | 1219 | getcwd(cwd, sizeof(char)*MAX_LINE); |
| 1139 | 1220 | ||
| 1221 | #ifdef BB_FEATURE_CLEAN_UP | ||
| 1222 | atexit(free_memory); | ||
| 1223 | #endif | ||
| 1224 | |||
| 1140 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 1225 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
| 1141 | cmdedit_init(); | 1226 | cmdedit_init(); |
| 1142 | signal(SIGWINCH, win_changed); | 1227 | signal(SIGWINCH, win_changed); |
