aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2000-12-18 20:25:50 +0000
committerEric Andersen <andersen@codepoet.org>2000-12-18 20:25:50 +0000
commit86349776d0006440c0fefab7dc05a38329bcc466 (patch)
treee859688d5a9399aad84f23a59dfb48533f1d7fcb
parent1fa1adea2ae16d4f4c82d7466905dce4c6edd5f5 (diff)
downloadbusybox-w32-86349776d0006440c0fefab7dc05a38329bcc466.tar.gz
busybox-w32-86349776d0006440c0fefab7dc05a38329bcc466.tar.bz2
busybox-w32-86349776d0006440c0fefab7dc05a38329bcc466.zip
Ok, this is a pretty major update to sh.c. I renamed all the variables and
function names to conform with the style guide. I also did a lot of work on the if-then-alse-fi logic and added prototype (i.e. it segfaults when enabled) line continuation support. Furthermore, this patch includes Larry Doolittle's work on restructuring some of the data structures that represent the job and child_program, allowing several simplifications and fixing several bugs. -Erik
-rw-r--r--cmdedit.c16
-rw-r--r--lash.c1090
-rw-r--r--sh.c1090
-rw-r--r--shell/cmdedit.c16
-rw-r--r--shell/lash.c1090
5 files changed, 1880 insertions, 1422 deletions
diff --git a/cmdedit.c b/cmdedit.c
index c32330bfd..0c9bda760 100644
--- a/cmdedit.c
+++ b/cmdedit.c
@@ -85,6 +85,12 @@ static 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 */ 87static int exithandler_set = 0; /* Set to true when atexit() has been called */
88
89
90/* Link into lash to reset context to 0
91 * on ^C and such */
92extern unsigned int shell_context;
93
88 94
89struct history { 95struct history {
90 char *s; 96 char *s;
@@ -466,20 +472,24 @@ extern void cmdedit_read_input(char* prompt, char command[BUFSIZ])
466 input_backward(outputFd, &cursor); 472 input_backward(outputFd, &cursor);
467 break; 473 break;
468 case 3: 474 case 3:
469 /* Control-c -- leave the current line, 475 /* Control-c -- stop gathering input */
470 * and start over on the next line */ 476
477 /* Link into lash to reset context to 0 on ^C and such */
478 shell_context = 0;
471 479
472 /* Go to the next line */ 480 /* Go to the next line */
473 xwrite(outputFd, "\n", 1); 481 xwrite(outputFd, "\n", 1);
474 482
483#if 0
475 /* Rewrite the prompt */ 484 /* Rewrite the prompt */
476 xwrite(outputFd, prompt, strlen(prompt)); 485 xwrite(outputFd, prompt, strlen(prompt));
477 486
478 /* Reset the command string */ 487 /* Reset the command string */
479 memset(command, 0, BUFSIZ); 488 memset(command, 0, BUFSIZ);
480 len = cursor = 0; 489 len = cursor = 0;
490#endif
491 return;
481 492
482 break;
483 case 4: 493 case 4:
484 /* Control-d -- Delete one character, or exit 494 /* Control-d -- Delete one character, or exit
485 * if the len=0 and no chars to delete */ 495 * if the len=0 and no chars to delete */
diff --git a/lash.c b/lash.c
index 164d6f5c5..590f5ee89 100644
--- a/lash.c
+++ b/lash.c
@@ -32,10 +32,13 @@
32//Backtick support has some problems, use at your own risk! 32//Backtick support has some problems, use at your own risk!
33//#define BB_FEATURE_SH_BACKTICKS 33//#define BB_FEATURE_SH_BACKTICKS
34// 34//
35//If, then, else, etc. support is really, really broken. Don't even 35//If, then, else, etc. support.. This should now behave basically
36//bother to mess with this yet, since you will not be happy with it. 36//like any other Bourne shell...
37//#define BB_FEATURE_SH_IF_EXPRESSIONS 37//#define BB_FEATURE_SH_IF_EXPRESSIONS
38// 38//
39/* This is currently a little broken... */
40//#define HANDLE_CONTINUATION_CHARS
41//
39//For debugging/development on the shell only... 42//For debugging/development on the shell only...
40//#define DEBUG_SHELL 43//#define DEBUG_SHELL
41 44
@@ -55,98 +58,102 @@
55#include <getopt.h> 58#include <getopt.h>
56#include "cmdedit.h" 59#include "cmdedit.h"
57 60
58#define MAX_LINE 256 /* size of input buffer for `read' builtin */ 61#define MAX_LINE 256 /* size of input buffer for cwd data */
59#define MAX_READ 128 /* size of input buffer for `read' builtin */ 62#define MAX_READ 128 /* size of input buffer for `read' builtin */
60#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 63#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
61extern size_t NUM_APPLETS; 64extern size_t NUM_APPLETS;
62 65
63 66
64 67enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE,
65
66enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
67 REDIRECT_APPEND 68 REDIRECT_APPEND
68}; 69};
69 70
70static const unsigned int REGULAR_JOB_CONTEXT=0x1; 71static const unsigned int DEFAULT_CONTEXT=0x1;
71static const unsigned int IF_TRUE_CONTEXT=0x2; 72static const unsigned int IF_TRUE_CONTEXT=0x2;
72static const unsigned int IF_FALSE_CONTEXT=0x4; 73static const unsigned int IF_FALSE_CONTEXT=0x4;
73static const unsigned int THEN_EXP_CONTEXT=0x8; 74static const unsigned int THEN_EXP_CONTEXT=0x8;
74static const unsigned int ELSE_EXP_CONTEXT=0x10; 75static const unsigned int ELSE_EXP_CONTEXT=0x10;
76unsigned int shell_context = 0;
77
75 78
76 79
77struct jobSet { 80struct jobset {
78 struct job *head; /* head of list of running jobs */ 81 struct job *head; /* head of list of running jobs */
79 struct job *fg; /* current foreground job */ 82 struct job *fg; /* current foreground job */
80}; 83};
81 84
82struct redirectionSpecifier { 85struct redir_struct {
83 enum redirectionType type; /* type of redirection */ 86 enum redir_type type; /* type of redirection */
84 int fd; /* file descriptor being redirected */ 87 int fd; /* file descriptor being redirected */
85 char *filename; /* file to redirect fd to */ 88 char *filename; /* file to redirect fd to */
86}; 89};
87 90
88struct childProgram { 91struct child_prog {
89 pid_t pid; /* 0 if exited */ 92 pid_t pid; /* 0 if exited */
90 char **argv; /* program name and arguments */ 93 char **argv; /* program name and arguments */
91 int numRedirections; /* elements in redirection array */ 94 int num_redirects; /* elements in redirection array */
92 struct redirectionSpecifier *redirections; /* I/O redirections */ 95 struct redir_struct *redirects; /* I/O redirects */
93 glob_t globResult; /* result of parameter globbing */ 96 glob_t glob_result; /* result of parameter globbing */
94 int freeGlob; /* should we globfree(&globResult)? */ 97 int free_glob; /* should we globfree(&glob_result)? */
95 int isStopped; /* is the program currently running? */ 98 int is_stopped; /* is the program currently running? */
99 struct job *family; /* pointer back to the child's parent job */
96}; 100};
97 101
98struct job { 102struct job {
99 int jobId; /* job number */ 103 int jobid; /* job number */
100 int numProgs; /* total number of programs in job */ 104 int num_progs; /* total number of programs in job */
101 int runningProgs; /* number of programs running */ 105 int running_progs; /* number of programs running */
102 char *text; /* name of job */ 106 char *text; /* name of job */
103 char *cmdBuf; /* buffer various argv's point into */ 107 char *cmdbuf; /* buffer various argv's point into */
104 pid_t pgrp; /* process group ID for the job */ 108 pid_t pgrp; /* process group ID for the job */
105 struct childProgram *progs; /* array of programs in job */ 109 struct child_prog *progs; /* array of programs in job */
106 struct job *next; /* to track background commands */ 110 struct job *next; /* to track background commands */
107 int stoppedProgs; /* number of programs alive, but stopped */ 111 int stopped_progs; /* number of programs alive, but stopped */
108 int jobContext; /* bitmask defining current context */ 112 unsigned int job_context; /* bitmask defining current context */
113 struct jobset *job_list;
109}; 114};
110 115
111struct builtInCommand { 116struct built_in_command {
112 char *cmd; /* name */ 117 char *cmd; /* name */
113 char *descr; /* description */ 118 char *descr; /* description */
114 int (*function) (struct job *, struct jobSet * jobList); /* function ptr */ 119 int (*function) (struct child_prog *); /* function ptr */
115}; 120};
116 121
117/* function prototypes for builtins */ 122/* function prototypes for builtins */
118static int builtin_cd(struct job *cmd, struct jobSet *junk); 123static int builtin_cd(struct child_prog *cmd);
119static int builtin_env(struct job *dummy, struct jobSet *junk); 124static int builtin_env(struct child_prog *dummy);
120static int builtin_exec(struct job *cmd, struct jobSet *junk); 125static int builtin_exec(struct child_prog *cmd);
121static int builtin_exit(struct job *cmd, struct jobSet *junk); 126static int builtin_exit(struct child_prog *cmd);
122static int builtin_fg_bg(struct job *cmd, struct jobSet *jobList); 127static int builtin_fg_bg(struct child_prog *cmd);
123static int builtin_help(struct job *cmd, struct jobSet *junk); 128static int builtin_help(struct child_prog *cmd);
124static int builtin_jobs(struct job *dummy, struct jobSet *jobList); 129static int builtin_jobs(struct child_prog *dummy);
125static int builtin_pwd(struct job *dummy, struct jobSet *junk); 130static int builtin_pwd(struct child_prog *dummy);
126static int builtin_export(struct job *cmd, struct jobSet *junk); 131static int builtin_export(struct child_prog *cmd);
127static int builtin_source(struct job *cmd, struct jobSet *jobList); 132static int builtin_source(struct child_prog *cmd);
128static int builtin_unset(struct job *cmd, struct jobSet *junk); 133static int builtin_unset(struct child_prog *cmd);
129static int builtin_read(struct job *cmd, struct jobSet *junk); 134static int builtin_read(struct child_prog *cmd);
130#ifdef BB_FEATURE_SH_IF_EXPRESSIONS 135#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
131static int builtin_if(struct job *cmd, struct jobSet *junk); 136static int builtin_if(struct child_prog *cmd);
132static int builtin_then(struct job *cmd, struct jobSet *junk); 137static int builtin_then(struct child_prog *cmd);
133static int builtin_else(struct job *cmd, struct jobSet *junk); 138static int builtin_else(struct child_prog *cmd);
134static int builtin_fi(struct job *cmd, struct jobSet *junk); 139static int builtin_fi(struct child_prog *cmd);
135#endif 140#endif
136 141
137 142
138/* function prototypes for shell stuff */ 143/* function prototypes for shell stuff */
139static void checkJobs(struct jobSet *jobList); 144static void checkjobs(struct jobset *job_list);
140static int getCommand(FILE * source, char *command); 145static int get_command(FILE * source, char *command);
141static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg); 146static int parse_command(char **command_ptr, struct job *job, int *inbg);
142static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]); 147static int run_command(struct job *newjob, int inbg, int outpipe[2]);
148static int pseudo_exec(struct child_prog *cmd) __attribute__ ((noreturn));
149static int run_command_predicate(char *cmd);
143static int busy_loop(FILE * input); 150static int busy_loop(FILE * input);
144 151
145 152
146/* Table of built-in functions (these are non-forking builtins, meaning they 153/* Table of built-in functions (these are non-forking builtins, meaning they
147 * can change global variables in the parent shell process but they will not 154 * can change global variables in the parent shell process but they will not
148 * work with pipes and redirects; 'unset foo | whatever' will not work) */ 155 * work with pipes and redirects; 'unset foo | whatever' will not work) */
149static struct builtInCommand bltins[] = { 156static struct built_in_command bltins[] = {
150 {"bg", "Resume a job in the background", builtin_fg_bg}, 157 {"bg", "Resume a job in the background", builtin_fg_bg},
151 {"cd", "Change working directory", builtin_cd}, 158 {"cd", "Change working directory", builtin_cd},
152 {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec}, 159 {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec},
@@ -157,6 +164,7 @@ static struct builtInCommand bltins[] = {
157 {"unset", "Unset environment variable", builtin_unset}, 164 {"unset", "Unset environment variable", builtin_unset},
158 {"read", "Input environment variable", builtin_read}, 165 {"read", "Input environment variable", builtin_read},
159 {".", "Source-in and run commands in a file", builtin_source}, 166 {".", "Source-in and run commands in a file", builtin_source},
167 /* to do: add ulimit */
160#ifdef BB_FEATURE_SH_IF_EXPRESSIONS 168#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
161 {"if", NULL, builtin_if}, 169 {"if", NULL, builtin_if},
162 {"then", NULL, builtin_then}, 170 {"then", NULL, builtin_then},
@@ -168,7 +176,7 @@ static struct builtInCommand bltins[] = {
168 176
169/* Table of forking built-in functions (things that fork cannot change global 177/* Table of forking built-in functions (things that fork cannot change global
170 * variables in the parent process, such as the current working directory) */ 178 * variables in the parent process, such as the current working directory) */
171static struct builtInCommand bltins_forking[] = { 179static struct built_in_command bltins_forking[] = {
172 {"env", "Print all environment variables", builtin_env}, 180 {"env", "Print all environment variables", builtin_env},
173 {"pwd", "Print current directory", builtin_pwd}, 181 {"pwd", "Print current directory", builtin_pwd},
174 {"help", "List shell built-in commands", builtin_help}, 182 {"help", "List shell built-in commands", builtin_help},
@@ -178,22 +186,25 @@ static struct builtInCommand bltins_forking[] = {
178static char prompt[3]; 186static char prompt[3];
179static char *cwd; 187static char *cwd;
180static char *local_pending_command = NULL; 188static char *local_pending_command = NULL;
181static char *promptStr = NULL; 189static char *prompt_str = NULL;
182static struct jobSet jobList = { NULL, NULL }; 190static struct jobset job_list = { NULL, NULL };
183static int argc; 191static int argc;
184static char **argv; 192static char **argv;
185#ifdef BB_FEATURE_SH_ENVIRONMENT 193#ifdef BB_FEATURE_SH_ENVIRONMENT
186static int lastBgPid=-1; 194static int last_bg_pid=-1;
187static int lastReturnCode=-1; 195static int last_return_code=-1;
188static int showXtrace=FALSE; 196static int show_x_trace=FALSE;
189#endif 197#endif
190 198#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
199static char syntax_err[]="syntax error near unexpected token";
200#endif
201
191#ifdef DEBUG_SHELL 202#ifdef DEBUG_SHELL
192static inline void debug_printf(const char *format, ...) 203static inline void debug_printf(const char *format, ...)
193{ 204{
194 va_list args; 205 va_list args;
195 va_start(args, format); 206 va_start(args, format);
196 vfprintf(stderr, s, p); 207 vfprintf(stderr, format, args);
197 va_end(args); 208 va_end(args);
198} 209}
199#else 210#else
@@ -213,16 +224,52 @@ static inline void win_changed(int junk)
213static inline void win_changed(int junk) {} 224static inline void win_changed(int junk) {}
214#endif 225#endif
215 226
227/*
228 Most builtins need access to the struct child_prog that has
229 their arguments, previously coded as cmd->progs[0]. That coding
230 can exhibit a bug, if the builtin is not the first command in
231 a pipeline: "echo foo | exec sort" will attempt to exec foo.
232
233builtin previous use notes
234------ ----------------- ---------
235cd cmd->progs[0]
236env 0
237exec cmd->progs[0] squashed bug: didn't look for applets or forking builtins
238exit cmd->progs[0]
239fg_bg cmd->progs[0], job_list->head, job_list->fg
240help 0
241jobs job_list->head
242pwd 0
243export cmd->progs[0] passes cmd, job_list to builtin_env(), which ignores them
244source cmd->progs[0]
245unset cmd->progs[0]
246read cmd->progs[0]
247if cmd->job_context, cmd->text
248then cmd->job_context, cmd->text
249else cmd->job_context, cmd->text
250fi cmd->job_context
251
252The use of cmd->text by if/then/else/fi is hopelessly hacky.
253Would it work to increment cmd->progs[0]->argv and recurse,
254somewhat like builtin_exec does?
255
256I added "struct job *family;" to struct child_prog,
257and switched API to builtin_foo(struct child_prog *child);
258So cmd->text becomes child->family->text
259 cmd->job_context becomes child->family->job_context
260 cmd->progs[0] becomes *child
261 job_list becomes child->family->job_list
262 */
216 263
217/* built-in 'cd <path>' handler */ 264/* built-in 'cd <path>' handler */
218static int builtin_cd(struct job *cmd, struct jobSet *junk) 265static int builtin_cd(struct child_prog *child)
219{ 266{
220 char *newdir; 267 char *newdir;
221 268
222 if (!cmd->progs[0].argv[1] == 1) 269 if (child->argv[1] == NULL)
223 newdir = getenv("HOME"); 270 newdir = getenv("HOME");
224 else 271 else
225 newdir = cmd->progs[0].argv[1]; 272 newdir = child->argv[1];
226 if (chdir(newdir)) { 273 if (chdir(newdir)) {
227 printf("cd: %s: %s\n", newdir, strerror(errno)); 274 printf("cd: %s: %s\n", newdir, strerror(errno));
228 return EXIT_FAILURE; 275 return EXIT_FAILURE;
@@ -233,7 +280,7 @@ static int builtin_cd(struct job *cmd, struct jobSet *junk)
233} 280}
234 281
235/* built-in 'env' handler */ 282/* built-in 'env' handler */
236static int builtin_env(struct job *dummy, struct jobSet *junk) 283static int builtin_env(struct child_prog *dummy)
237{ 284{
238 char **e; 285 char **e;
239 286
@@ -244,149 +291,143 @@ static int builtin_env(struct job *dummy, struct jobSet *junk)
244} 291}
245 292
246/* built-in 'exec' handler */ 293/* built-in 'exec' handler */
247static int builtin_exec(struct job *cmd, struct jobSet *junk) 294static int builtin_exec(struct child_prog *child)
248{ 295{
249 if (cmd->progs[0].argv[1]) 296 if (child->argv[1] == NULL)
250 { 297 return EXIT_SUCCESS; /* Really? */
251 cmd->progs[0].argv++; 298 child->argv++;
252 execvp(cmd->progs[0].argv[0], cmd->progs[0].argv); 299 pseudo_exec(child);
253 error_msg_and_die("Exec to %s failed: %s\n", cmd->progs[0].argv[0], 300 /* never returns */
254 strerror(errno));
255 }
256 return EXIT_SUCCESS;
257} 301}
258 302
259/* built-in 'exit' handler */ 303/* built-in 'exit' handler */
260static int builtin_exit(struct job *cmd, struct jobSet *junk) 304static int builtin_exit(struct child_prog *child)
261{ 305{
262 if (!cmd->progs[0].argv[1] == 1) 306 if (child->argv[1] == NULL)
263 exit(EXIT_SUCCESS); 307 exit(EXIT_SUCCESS);
264 308
265 exit (atoi(cmd->progs[0].argv[1])); 309 exit (atoi(child->argv[1]));
266} 310}
267 311
268/* built-in 'fg' and 'bg' handler */ 312/* built-in 'fg' and 'bg' handler */
269static int builtin_fg_bg(struct job *cmd, struct jobSet *jobList) 313static int builtin_fg_bg(struct child_prog *child)
270{ 314{
271 int i, jobNum; 315 int i, jobNum;
272 struct job *job=NULL; 316 struct job *job=NULL;
317
273 318
274 if (!jobList->head) { 319 if (!child->argv[1] || child->argv[2]) {
275 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) {
276 error_msg("%s: exactly one argument is expected\n", 320 error_msg("%s: exactly one argument is expected\n",
277 cmd->progs[0].argv[0]); 321 child->argv[0]);
278 return EXIT_FAILURE; 322 return EXIT_FAILURE;
279 } 323 }
280 if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) { 324 if (sscanf(child->argv[1], "%%%d", &jobNum) != 1) {
281 error_msg("%s: bad argument '%s'\n", 325 error_msg("%s: bad argument '%s'\n",
282 cmd->progs[0].argv[0], cmd->progs[0].argv[1]); 326 child->argv[0], child->argv[1]);
283 return EXIT_FAILURE; 327 return EXIT_FAILURE;
284 for (job = jobList->head; job; job = job->next) { 328 }
285 if (job->jobId == jobNum) { 329 for (job = child->family->job_list->head; job; job = job->next) {
286 break; 330 if (job->jobid == jobNum) {
287 } 331 break;
288 } 332 }
289 } 333 }
290 } else {
291 job = jobList->head;
292 }
293 334
294 if (!job) { 335 if (!job) {
295 error_msg("%s: unknown job %d\n", 336 error_msg("%s: unknown job %d\n",
296 cmd->progs[0].argv[0], jobNum); 337 child->argv[0], jobNum);
297 return EXIT_FAILURE; 338 return EXIT_FAILURE;
298 } 339 }
299 340
300 if (*cmd->progs[0].argv[0] == 'f') { 341 if (*child->argv[0] == 'f') {
301 /* Make this job the foreground job */ 342 /* Make this job the foreground job */
302 /* suppress messages when run from /linuxrc mag@sysgo.de */ 343 /* suppress messages when run from /linuxrc mag@sysgo.de */
303 if (tcsetpgrp(0, job->pgrp) && errno != ENOTTY) 344 if (tcsetpgrp(0, job->pgrp) && errno != ENOTTY)
304 perror("tcsetpgrp"); 345 perror("tcsetpgrp");
305 jobList->fg = job; 346 child->family->job_list->fg = job;
306 } 347 }
307 348
308 /* Restart the processes in the job */ 349 /* Restart the processes in the job */
309 for (i = 0; i < job->numProgs; i++) 350 for (i = 0; i < job->num_progs; i++)
310 job->progs[i].isStopped = 0; 351 job->progs[i].is_stopped = 0;
311 352
312 kill(-job->pgrp, SIGCONT); 353 kill(-job->pgrp, SIGCONT);
313 354
314 job->stoppedProgs = 0; 355 job->stopped_progs = 0;
315 356
316 return EXIT_SUCCESS; 357 return EXIT_SUCCESS;
317} 358}
318 359
319/* built-in 'help' handler */ 360/* built-in 'help' handler */
320static int builtin_help(struct job *dummy, struct jobSet *junk) 361static int builtin_help(struct child_prog *dummy)
321{ 362{
322 struct builtInCommand *x; 363 struct built_in_command *x;
323 364
324 fprintf(stdout, "\nBuilt-in commands:\n"); 365 printf("\nBuilt-in commands:\n");
325 fprintf(stdout, "-------------------\n"); 366 printf("-------------------\n");
326 for (x = bltins; x->cmd; x++) { 367 for (x = bltins; x->cmd; x++) {
327 if (x->descr==NULL) 368 if (x->descr==NULL)
328 continue; 369 continue;
329 fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); 370 printf("%s\t%s\n", x->cmd, x->descr);
330 } 371 }
331 for (x = bltins_forking; x->cmd; x++) { 372 for (x = bltins_forking; x->cmd; x++) {
332 if (x->descr==NULL) 373 if (x->descr==NULL)
333 continue; 374 continue;
334 fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); 375 printf("%s\t%s\n", x->cmd, x->descr);
335 } 376 }
336 fprintf(stdout, "\n\n"); 377 printf("\n\n");
337 return EXIT_SUCCESS; 378 return EXIT_SUCCESS;
338} 379}
339 380
340/* built-in 'jobs' handler */ 381/* built-in 'jobs' handler */
341static int builtin_jobs(struct job *dummy, struct jobSet *jobList) 382static int builtin_jobs(struct child_prog *child)
342{ 383{
343 struct job *job; 384 struct job *job;
344 char *statusString; 385 char *status_string;
345 386
346 for (job = jobList->head; job; job = job->next) { 387 for (job = child->family->job_list->head; job; job = job->next) {
347 if (job->runningProgs == job->stoppedProgs) 388 if (job->running_progs == job->stopped_progs)
348 statusString = "Stopped"; 389 status_string = "Stopped";
349 else 390 else
350 statusString = "Running"; 391 status_string = "Running";
351 392
352 printf(JOB_STATUS_FORMAT, job->jobId, statusString, job->text); 393 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
353 } 394 }
354 return EXIT_SUCCESS; 395 return EXIT_SUCCESS;
355} 396}
356 397
357 398
358/* built-in 'pwd' handler */ 399/* built-in 'pwd' handler */
359static int builtin_pwd(struct job *dummy, struct jobSet *junk) 400static int builtin_pwd(struct child_prog *dummy)
360{ 401{
361 getcwd(cwd, sizeof(char)*MAX_LINE); 402 getcwd(cwd, MAX_LINE);
362 fprintf(stdout, "%s\n", cwd); 403 fprintf(stdout, "%s\n", cwd);
363 return EXIT_SUCCESS; 404 return EXIT_SUCCESS;
364} 405}
365 406
366/* built-in 'export VAR=value' handler */ 407/* built-in 'export VAR=value' handler */
367static int builtin_export(struct job *cmd, struct jobSet *junk) 408static int builtin_export(struct child_prog *child)
368{ 409{
369 int res; 410 int res;
370 411
371 if (!cmd->progs[0].argv[1] == 1) { 412 if (child->argv[1] == NULL) {
372 return (builtin_env(cmd, junk)); 413 return (builtin_env(child));
373 } 414 }
374 res = putenv(cmd->progs[0].argv[1]); 415 res = putenv(child->argv[1]);
375 if (res) 416 if (res)
376 fprintf(stdout, "export: %s\n", strerror(errno)); 417 fprintf(stderr, "export: %s\n", strerror(errno));
377 return (res); 418 return (res);
378} 419}
379 420
380/* built-in 'read VAR' handler */ 421/* built-in 'read VAR' handler */
381static int builtin_read(struct job *cmd, struct jobSet *junk) 422static int builtin_read(struct child_prog *child)
382{ 423{
383 int res = 0, len, newlen; 424 int res = 0, len, newlen;
384 char *s; 425 char *s;
385 char string[MAX_READ]; 426 char string[MAX_READ];
386 427
387 if (cmd->progs[0].argv[1]) { 428 if (child->argv[1]) {
388 /* argument (VAR) given: put "VAR=" into buffer */ 429 /* argument (VAR) given: put "VAR=" into buffer */
389 strcpy(string, cmd->progs[0].argv[1]); 430 strcpy(string, child->argv[1]);
390 len = strlen(string); 431 len = strlen(string);
391 string[len++] = '='; 432 string[len++] = '=';
392 string[len] = '\0'; 433 string[len] = '\0';
@@ -403,7 +444,7 @@ static int builtin_read(struct job *cmd, struct jobSet *junk)
403 if((s = strdup(string))) 444 if((s = strdup(string)))
404 res = putenv(s); 445 res = putenv(s);
405 if (res) 446 if (res)
406 fprintf(stdout, "read: %s\n", strerror(errno)); 447 fprintf(stderr, "read: %s\n", strerror(errno));
407 } 448 }
408 else 449 else
409 fgets(string, sizeof(string), stdin); 450 fgets(string, sizeof(string), stdin);
@@ -413,111 +454,112 @@ static int builtin_read(struct job *cmd, struct jobSet *junk)
413 454
414#ifdef BB_FEATURE_SH_IF_EXPRESSIONS 455#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
415/* Built-in handler for 'if' commands */ 456/* Built-in handler for 'if' commands */
416static int builtin_if(struct job *cmd, struct jobSet *jobList) 457static int builtin_if(struct child_prog *child)
417{ 458{
459 struct job *cmd = child->family;
418 int status; 460 int status;
419 char* charptr1=cmd->text+3; /* skip over the leading 'if ' */ 461 char* charptr1=cmd->text+3; /* skip over the leading 'if ' */
420 462
421 /* Now run the 'if' command */ 463 /* Now run the 'if' command */
422 status=strlen(charptr1); 464 debug_printf( "job=%p entering builtin_if ('%s')-- context=%d\n", cmd, charptr1, cmd->job_context);
423 local_pending_command = xmalloc(status+1); 465 status = run_command_predicate(charptr1);
424 strncpy(local_pending_command, charptr1, status); 466 debug_printf( "if test returned ");
425 local_pending_command[status]='\0';
426 debug_printf(stderr, "'if' now testing '%s'\n", local_pending_command);
427 status = busy_loop(NULL); /* Frees local_pending_command */
428 debug_printf(stderr, "if test returned ");
429 if (status == 0) { 467 if (status == 0) {
430 debug_printf(stderr, "TRUE\n"); 468 debug_printf( "TRUE\n");
431 cmd->jobContext |= IF_TRUE_CONTEXT; 469 cmd->job_context |= IF_TRUE_CONTEXT;
432 } else { 470 } else {
433 debug_printf(stderr, "FALSE\n"); 471 debug_printf( "FALSE\n");
434 cmd->jobContext |= IF_FALSE_CONTEXT; 472 cmd->job_context |= IF_FALSE_CONTEXT;
435 } 473 }
474 debug_printf("job=%p builtin_if set job context to %x\n", cmd, cmd->job_context);
475 shell_context++;
436 476
437 return status; 477 return status;
438} 478}
439 479
440/* Built-in handler for 'then' (part of the 'if' command) */ 480/* Built-in handler for 'then' (part of the 'if' command) */
441static int builtin_then(struct job *cmd, struct jobSet *junk) 481static int builtin_then(struct child_prog *child)
442{ 482{
443 int status; 483 struct job *cmd = child->family;
444 char* charptr1=cmd->text+5; /* skip over the leading 'then ' */ 484 char* charptr1=cmd->text+5; /* skip over the leading 'then ' */
445 485
446 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { 486 debug_printf( "job=%p entering builtin_then ('%s')-- context=%d\n", cmd, charptr1, cmd->job_context);
447 error_msg("unexpected token `then'\n"); 487 if (! (cmd->job_context & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
488 shell_context = 0; /* Reset the shell's context on an error */
489 error_msg("%s `then'\n", syntax_err);
448 return EXIT_FAILURE; 490 return EXIT_FAILURE;
449 } 491 }
492
493 cmd->job_context |= THEN_EXP_CONTEXT;
494 debug_printf("job=%p builtin_then set job context to %x\n", cmd, cmd->job_context);
495
450 /* If the if result was FALSE, skip the 'then' stuff */ 496 /* If the if result was FALSE, skip the 'then' stuff */
451 if (cmd->jobContext & IF_FALSE_CONTEXT) { 497 if (cmd->job_context & IF_FALSE_CONTEXT) {
452 return EXIT_SUCCESS; 498 return EXIT_SUCCESS;
453 } 499 }
454 500
455 cmd->jobContext |= THEN_EXP_CONTEXT; 501 /* Seems the if result was TRUE, so run the 'then' command */
456 //printf("Hit an then -- jobContext=%d\n", cmd->jobContext); 502 debug_printf( "'then' now running '%s'\n", charptr1);
457 503
458 /* Now run the 'then' command */ 504 return(run_command_predicate(charptr1));
459 status=strlen(charptr1);
460 local_pending_command = xmalloc(status+1);
461 strncpy(local_pending_command, charptr1, status);
462 local_pending_command[status]='\0';
463 debug_printf(stderr, "'then' now running '%s'\n", charptr1);
464 return( busy_loop(NULL));
465} 505}
466 506
467/* Built-in handler for 'else' (part of the 'if' command) */ 507/* Built-in handler for 'else' (part of the 'if' command) */
468static int builtin_else(struct job *cmd, struct jobSet *junk) 508static int builtin_else(struct child_prog *child)
469{ 509{
470 int status; 510 struct job *cmd = child->family;
471 char* charptr1=cmd->text+5; /* skip over the leading 'else ' */ 511 char* charptr1=cmd->text+5; /* skip over the leading 'else ' */
472 512
473 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { 513 debug_printf( "job=%p entering builtin_else ('%s')-- context=%d\n", cmd, charptr1, cmd->job_context);
474 error_msg("unexpected token `else'\n"); 514
515 if (! (cmd->job_context & THEN_EXP_CONTEXT)) {
516 shell_context = 0; /* Reset the shell's context on an error */
517 error_msg("%s `else'\n", syntax_err);
475 return EXIT_FAILURE; 518 return EXIT_FAILURE;
476 } 519 }
477 /* If the if result was TRUE, skip the 'else' stuff */ 520 /* If the if result was TRUE, skip the 'else' stuff */
478 if (cmd->jobContext & IF_TRUE_CONTEXT) { 521 if (cmd->job_context & IF_TRUE_CONTEXT) {
479 return EXIT_SUCCESS; 522 return EXIT_SUCCESS;
480 } 523 }
481 524
482 cmd->jobContext |= ELSE_EXP_CONTEXT; 525 cmd->job_context |= ELSE_EXP_CONTEXT;
483 //printf("Hit an else -- jobContext=%d\n", cmd->jobContext); 526 debug_printf("job=%p builtin_else set job context to %x\n", child->family, cmd->job_context);
484 527
485 /* Now run the 'else' command */ 528 /* Now run the 'else' command */
486 status=strlen(charptr1); 529 debug_printf( "'else' now running '%s'\n", charptr1);
487 local_pending_command = xmalloc(status+1); 530 return(run_command_predicate(charptr1));
488 strncpy(local_pending_command, charptr1, status);
489 local_pending_command[status]='\0';
490 debug_printf(stderr, "'else' now running '%s'\n", charptr1);
491 return( busy_loop(NULL));
492} 531}
493 532
494/* Built-in handler for 'fi' (part of the 'if' command) */ 533/* Built-in handler for 'fi' (part of the 'if' command) */
495static int builtin_fi(struct job *cmd, struct jobSet *junk) 534static int builtin_fi(struct child_prog *child)
496{ 535{
497 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { 536 struct job *cmd = child->family;
498 error_msg("unexpected token `fi'\n"); 537 debug_printf( "job=%p entering builtin_fi ('%s')-- context=%d\n", cmd, "", cmd->job_context);
538 if (! (cmd->job_context & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
539 shell_context = 0; /* Reset the shell's context on an error */
540 error_msg("%s `fi'\n", syntax_err);
499 return EXIT_FAILURE; 541 return EXIT_FAILURE;
500 } 542 }
501 /* Clear out the if and then context bits */ 543 /* Clear out the if and then context bits */
502 cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT); 544 cmd->job_context &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT);
503 debug_printf(stderr, "Hit an fi -- jobContext=%d\n", cmd->jobContext); 545 debug_printf("job=%p builtin_fi set job context to %x\n", cmd, cmd->job_context);
546 shell_context--;
504 return EXIT_SUCCESS; 547 return EXIT_SUCCESS;
505} 548}
506#endif 549#endif
507 550
508/* Built-in '.' handler (read-in and execute commands from file) */ 551/* Built-in '.' handler (read-in and execute commands from file) */
509static int builtin_source(struct job *cmd, struct jobSet *junk) 552static int builtin_source(struct child_prog *child)
510{ 553{
511 FILE *input; 554 FILE *input;
512 int status; 555 int status;
513 556
514 if (!cmd->progs[0].argv[1] == 1) 557 if (child->argv[1] == NULL)
515 return EXIT_FAILURE; 558 return EXIT_FAILURE;
516 559
517 input = fopen(cmd->progs[0].argv[1], "r"); 560 input = fopen(child->argv[1], "r");
518 if (!input) { 561 if (!input) {
519 fprintf(stdout, "Couldn't open file '%s'\n", 562 fprintf(stdout, "Couldn't open file '%s'\n", child->argv[1]);
520 cmd->progs[0].argv[1]);
521 return EXIT_FAILURE; 563 return EXIT_FAILURE;
522 } 564 }
523 565
@@ -528,48 +570,65 @@ static int builtin_source(struct job *cmd, struct jobSet *junk)
528} 570}
529 571
530/* built-in 'unset VAR' handler */ 572/* built-in 'unset VAR' handler */
531static int builtin_unset(struct job *cmd, struct jobSet *junk) 573static int builtin_unset(struct child_prog *child)
532{ 574{
533 if (!cmd->progs[0].argv[1] == 1) { 575 if (child->argv[1] == NULL) {
534 fprintf(stdout, "unset: parameter required.\n"); 576 fprintf(stdout, "unset: parameter required.\n");
535 return EXIT_FAILURE; 577 return EXIT_FAILURE;
536 } 578 }
537 unsetenv(cmd->progs[0].argv[1]); 579 unsetenv(child->argv[1]);
538 return EXIT_SUCCESS; 580 return EXIT_SUCCESS;
539} 581}
540 582
583/* currently used by if/then/else.
584 * Needlessly (?) forks and reparses the command line.
585 * But pseudo_exec on the pre-parsed args doesn't have the
586 * "fork, stick around until the child exits, and find it's return code"
587 * functionality. The fork is not needed if the predicate is
588 * non-forking builtin, and maybe not even if it's a forking builtin.
589 * applets pretty clearly need the fork.
590 */
591static int run_command_predicate(char *cmd)
592{
593 int n=strlen(cmd);
594 local_pending_command = xmalloc(n+1);
595 strncpy(local_pending_command, cmd, n);
596 local_pending_command[n]='\0';
597 return( busy_loop(NULL));
598}
599
541/* free up all memory from a job */ 600/* free up all memory from a job */
542static void freeJob(struct job *cmd) 601static void free_job(struct job *cmd)
543{ 602{
544 int i; 603 int i;
545 604
546 for (i = 0; i < cmd->numProgs; i++) { 605 for (i = 0; i < cmd->num_progs; i++) {
547 free(cmd->progs[i].argv); 606 free(cmd->progs[i].argv);
548 if (cmd->progs[i].redirections) 607 if (cmd->progs[i].redirects)
549 free(cmd->progs[i].redirections); 608 free(cmd->progs[i].redirects);
550 if (cmd->progs[i].freeGlob) 609 if (cmd->progs[i].free_glob)
551 globfree(&cmd->progs[i].globResult); 610 globfree(&cmd->progs[i].glob_result);
552 } 611 }
553 free(cmd->progs); 612 free(cmd->progs);
554 if (cmd->text) 613 if (cmd->text)
555 free(cmd->text); 614 free(cmd->text);
556 free(cmd->cmdBuf); 615 free(cmd->cmdbuf);
557 memset(cmd, 0, sizeof(struct job)); 616 memset(cmd, 0, sizeof(struct job));
558} 617}
559 618
560/* remove a job from the jobList */ 619/* remove a job from the job_list */
561static void removeJob(struct jobSet *jobList, struct job *job) 620static void remove_job(struct jobset *job_list, struct job *job)
562{ 621{
563 struct job *prevJob; 622 struct job *prevjob;
564 623
565 freeJob(job); 624 free_job(job);
566 if (job == jobList->head) { 625 if (job == job_list->head) {
567 jobList->head = job->next; 626 job_list->head = job->next;
568 } else { 627 } else {
569 prevJob = jobList->head; 628 prevjob = job_list->head;
570 while (prevJob->next != job) 629 while (prevjob->next != job)
571 prevJob = prevJob->next; 630 prevjob = prevjob->next;
572 prevJob->next = job->next; 631 prevjob->next = job->next;
573 } 632 }
574 633
575 free(job); 634 free(job);
@@ -577,19 +636,19 @@ static void removeJob(struct jobSet *jobList, struct job *job)
577 636
578/* Checks to see if any background processes have exited -- if they 637/* Checks to see if any background processes have exited -- if they
579 have, figure out why and see if a job has completed */ 638 have, figure out why and see if a job has completed */
580static void checkJobs(struct jobSet *jobList) 639static void checkjobs(struct jobset *job_list)
581{ 640{
582 struct job *job; 641 struct job *job;
583 pid_t childpid; 642 pid_t childpid;
584 int status; 643 int status;
585 int progNum = 0; 644 int prognum = 0;
586 645
587 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { 646 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
588 for (job = jobList->head; job; job = job->next) { 647 for (job = job_list->head; job; job = job->next) {
589 progNum = 0; 648 prognum = 0;
590 while (progNum < job->numProgs && 649 while (prognum < job->num_progs &&
591 job->progs[progNum].pid != childpid) progNum++; 650 job->progs[prognum].pid != childpid) prognum++;
592 if (progNum < job->numProgs) 651 if (prognum < job->num_progs)
593 break; 652 break;
594 } 653 }
595 654
@@ -599,20 +658,20 @@ static void checkJobs(struct jobSet *jobList)
599 658
600 if (WIFEXITED(status) || WIFSIGNALED(status)) { 659 if (WIFEXITED(status) || WIFSIGNALED(status)) {
601 /* child exited */ 660 /* child exited */
602 job->runningProgs--; 661 job->running_progs--;
603 job->progs[progNum].pid = 0; 662 job->progs[prognum].pid = 0;
604 663
605 if (!job->runningProgs) { 664 if (!job->running_progs) {
606 printf(JOB_STATUS_FORMAT, job->jobId, "Done", job->text); 665 printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text);
607 removeJob(jobList, job); 666 remove_job(job_list, job);
608 } 667 }
609 } else { 668 } else {
610 /* child stopped */ 669 /* child stopped */
611 job->stoppedProgs++; 670 job->stopped_progs++;
612 job->progs[progNum].isStopped = 1; 671 job->progs[prognum].is_stopped = 1;
613 672
614 if (job->stoppedProgs == job->numProgs) { 673 if (job->stopped_progs == job->num_progs) {
615 printf(JOB_STATUS_FORMAT, job->jobId, "Stopped", 674 printf(JOB_STATUS_FORMAT, job->jobid, "Stopped",
616 job->text); 675 job->text);
617 } 676 }
618 } 677 }
@@ -622,14 +681,14 @@ static void checkJobs(struct jobSet *jobList)
622 perror("waitpid"); 681 perror("waitpid");
623} 682}
624 683
625static int setupRedirections(struct childProgram *prog) 684static int setup_redirects(struct child_prog *prog)
626{ 685{
627 int i; 686 int i;
628 int openfd; 687 int openfd;
629 int mode = O_RDONLY; 688 int mode = O_RDONLY;
630 struct redirectionSpecifier *redir = prog->redirections; 689 struct redir_struct *redir = prog->redirects;
631 690
632 for (i = 0; i < prog->numRedirections; i++, redir++) { 691 for (i = 0; i < prog->num_redirects; i++, redir++) {
633 switch (redir->type) { 692 switch (redir->type) {
634 case REDIRECT_INPUT: 693 case REDIRECT_INPUT:
635 mode = O_RDONLY; 694 mode = O_RDONLY;
@@ -661,7 +720,7 @@ static int setupRedirections(struct childProgram *prog)
661} 720}
662 721
663 722
664static int getCommand(FILE * source, char *command) 723static int get_command(FILE * source, char *command)
665{ 724{
666 char user[9],buf[255],*s; 725 char user[9],buf[255],*s;
667 726
@@ -676,15 +735,20 @@ static int getCommand(FILE * source, char *command)
676 return 1; 735 return 1;
677 } 736 }
678 737
679 /* get User Name and setup prompt */ 738 if (shell_context == 0) {
680 strcpy(prompt,( geteuid() != 0 ) ? "$ ":"# "); 739 /* get User Name and setup prompt */
681 my_getpwuid(user, geteuid()); 740 strcpy(prompt,( geteuid() != 0 ) ? "$ ":"# ");
682 741 my_getpwuid(user, geteuid());
683 /* get HostName */ 742
684 gethostname(buf, 255); 743 /* get HostName */
685 s = strchr(buf, '.'); 744 gethostname(buf, 255);
686 if (s) 745 s = strchr(buf, '.');
687 *s = 0; 746 if (s) {
747 *s = 0;
748 }
749 } else {
750 strcpy(prompt,"> ");
751 }
688 752
689 if (source == stdin) { 753 if (source == stdin) {
690#ifdef BB_FEATURE_SH_COMMAND_EDITING 754#ifdef BB_FEATURE_SH_COMMAND_EDITING
@@ -698,14 +762,24 @@ static int getCommand(FILE * source, char *command)
698 */ 762 */
699 cmdedit_init(); 763 cmdedit_init();
700 signal(SIGWINCH, win_changed); 764 signal(SIGWINCH, win_changed);
701 len=fprintf(stdout, "[%s@%s %s]%s", user, buf, 765 debug_printf( "in get_command() -- job_context=%d\n", shell_context);
702 get_last_path_component(cwd), prompt); 766 fflush(stdout);
767 if (shell_context == 0) {
768 len=fprintf(stdout, "[%s@%s %s]%s", user, buf,
769 get_last_path_component(cwd), prompt);
770 } else {
771 len=fprintf(stdout, "%s", prompt);
772 }
703 fflush(stdout); 773 fflush(stdout);
704 promptStr=(char*)xmalloc(sizeof(char)*(len+1)); 774 prompt_str=(char*)xmalloc(sizeof(char)*(len+1));
705 sprintf(promptStr, "[%s@%s %s]%s", user, buf, 775 if (shell_context == 0) {
706 get_last_path_component(cwd), prompt); 776 sprintf(prompt_str, "[%s@%s %s]%s", user, buf,
707 cmdedit_read_input(promptStr, command); 777 get_last_path_component(cwd), prompt);
708 free( promptStr); 778 } else {
779 sprintf(prompt_str, "%s", prompt);
780 }
781 cmdedit_read_input(prompt_str, command);
782 free( prompt_str);
709 cmdedit_terminate(); 783 cmdedit_terminate();
710 signal(SIGWINCH, SIG_DFL); 784 signal(SIGWINCH, SIG_DFL);
711 return 0; 785 return 0;
@@ -756,21 +830,21 @@ static char* itoa(register int i)
756} 830}
757#endif 831#endif
758 832
759static void globLastArgument(struct childProgram *prog, int *argcPtr, 833static void expand_argument(struct child_prog *prog, int *argcPtr,
760 int *argcAllocedPtr) 834 int *argv_alloced_ptr)
761{ 835{
762 int argc_l = *argcPtr; 836 int argc_l = *argcPtr;
763 int argcAlloced = *argcAllocedPtr; 837 int argv_alloced = *argv_alloced_ptr;
764 int rc; 838 int rc;
765 int flags; 839 int flags;
766 int i; 840 int i;
767 char *src, *dst, *var; 841 char *src, *dst, *var;
768 842
769 if (argc_l > 1) { /* cmd->globResult is already initialized */ 843 if (argc_l > 1) { /* cmd->glob_result is already initialized */
770 flags = GLOB_APPEND; 844 flags = GLOB_APPEND;
771 i = prog->globResult.gl_pathc; 845 i = prog->glob_result.gl_pathc;
772 } else { 846 } else {
773 prog->freeGlob = 1; 847 prog->free_glob = 1;
774 flags = 0; 848 flags = 0;
775 i = 0; 849 i = 0;
776 } 850 }
@@ -783,7 +857,7 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
783 else { 857 else {
784 switch(*(prog->argv[argc_l - 1] + 1)) { 858 switch(*(prog->argv[argc_l - 1] + 1)) {
785 case '?': 859 case '?':
786 prog->argv[argc_l - 1] = itoa(lastReturnCode); 860 prog->argv[argc_l - 1] = itoa(last_return_code);
787 break; 861 break;
788 case '$': 862 case '$':
789 prog->argv[argc_l - 1] = itoa(getpid()); 863 prog->argv[argc_l - 1] = itoa(getpid());
@@ -792,10 +866,10 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
792 prog->argv[argc_l - 1] = itoa(argc-1); 866 prog->argv[argc_l - 1] = itoa(argc-1);
793 break; 867 break;
794 case '!': 868 case '!':
795 if (lastBgPid==-1) 869 if (last_bg_pid==-1)
796 *(prog->argv[argc_l - 1])='\0'; 870 *(prog->argv[argc_l - 1])='\0';
797 else 871 else
798 prog->argv[argc_l - 1] = itoa(lastBgPid); 872 prog->argv[argc_l - 1] = itoa(last_bg_pid);
799 break; 873 break;
800 case '0':case '1':case '2':case '3':case '4': 874 case '0':case '1':case '2':case '3':case '4':
801 case '5':case '6':case '7':case '8':case '9': 875 case '5':case '6':case '7':case '8':case '9':
@@ -814,14 +888,14 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
814 } 888 }
815 889
816 if (strpbrk(prog->argv[argc_l - 1],"*[]?")!= NULL){ 890 if (strpbrk(prog->argv[argc_l - 1],"*[]?")!= NULL){
817 rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult); 891 rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->glob_result);
818 if (rc == GLOB_NOSPACE) { 892 if (rc == GLOB_NOSPACE) {
819 error_msg("out of space during glob operation\n"); 893 error_msg("out of space during glob operation\n");
820 return; 894 return;
821 } else if (rc == GLOB_NOMATCH || 895 } else if (rc == GLOB_NOMATCH ||
822 (!rc && (prog->globResult.gl_pathc - i) == 1 && 896 (!rc && (prog->glob_result.gl_pathc - i) == 1 &&
823 strcmp(prog->argv[argc_l - 1], 897 strcmp(prog->argv[argc_l - 1],
824 prog->globResult.gl_pathv[i]) == 0)) { 898 prog->glob_result.gl_pathv[i]) == 0)) {
825 /* we need to remove whatever \ quoting is still present */ 899 /* we need to remove whatever \ quoting is still present */
826 src = dst = prog->argv[argc_l - 1]; 900 src = dst = prog->argv[argc_l - 1];
827 while (*src) { 901 while (*src) {
@@ -835,11 +909,11 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
835 } 909 }
836 *dst = '\0'; 910 *dst = '\0';
837 } else if (!rc) { 911 } else if (!rc) {
838 argcAlloced += (prog->globResult.gl_pathc - i); 912 argv_alloced += (prog->glob_result.gl_pathc - i);
839 prog->argv = xrealloc(prog->argv, argcAlloced * sizeof(*prog->argv)); 913 prog->argv = xrealloc(prog->argv, argv_alloced * sizeof(*prog->argv));
840 memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i, 914 memcpy(prog->argv + (argc_l - 1), prog->glob_result.gl_pathv + i,
841 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); 915 sizeof(*(prog->argv)) * (prog->glob_result.gl_pathc - i));
842 argc_l += (prog->globResult.gl_pathc - i - 1); 916 argc_l += (prog->glob_result.gl_pathc - i - 1);
843 } 917 }
844 }else{ 918 }else{
845 src = dst = prog->argv[argc_l - 1]; 919 src = dst = prog->argv[argc_l - 1];
@@ -854,68 +928,69 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
854 } 928 }
855 *dst = '\0'; 929 *dst = '\0';
856 930
857 prog->globResult.gl_pathc=0; 931 prog->glob_result.gl_pathc=0;
858 if (flags==0) 932 if (flags==0)
859 prog->globResult.gl_pathv=NULL; 933 prog->glob_result.gl_pathv=NULL;
860 } 934 }
861 *argcAllocedPtr = argcAlloced; 935 *argv_alloced_ptr = argv_alloced;
862 *argcPtr = argc_l; 936 *argcPtr = argc_l;
863} 937}
864 938
865/* Return cmd->numProgs as 0 if no command is present (e.g. an empty 939/* Return cmd->num_progs as 0 if no command is present (e.g. an empty
866 line). If a valid command is found, commandPtr is set to point to 940 line). If a valid command is found, command_ptr is set to point to
867 the beginning of the next command (if the original command had more 941 the beginning of the next command (if the original command had more
868 then one job associated with it) or NULL if no more commands are 942 then one job associated with it) or NULL if no more commands are
869 present. */ 943 present. */
870static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg) 944static int parse_command(char **command_ptr, struct job *job, int *inbg)
871{ 945{
872 char *command; 946 char *command;
873 char *returnCommand = NULL; 947 char *return_command = NULL;
874 char *src, *buf, *chptr; 948 char *src, *buf, *chptr;
875 int argc_l = 0; 949 int argc_l = 0;
876 int done = 0; 950 int done = 0;
877 int argvAlloced; 951 int argv_alloced;
878 int i; 952 int i;
879 char quote = '\0'; 953 char quote = '\0';
880 int count; 954 int count;
881 struct childProgram *prog; 955 struct child_prog *prog;
882 956
883 /* skip leading white space */ 957 /* skip leading white space */
884 while (**commandPtr && isspace(**commandPtr)) 958 while (**command_ptr && isspace(**command_ptr))
885 (*commandPtr)++; 959 (*command_ptr)++;
886 960
887 /* this handles empty lines or leading '#' characters */ 961 /* this handles empty lines or leading '#' characters */
888 if (!**commandPtr || (**commandPtr == '#')) { 962 if (!**command_ptr || (**command_ptr == '#')) {
889 job->numProgs=0; 963 job->num_progs=0;
890 return 0; 964 return 0;
891 } 965 }
892 966
893 *inBg = 0; 967 *inbg = 0;
894 job->numProgs = 1; 968 job->num_progs = 1;
895 job->progs = xmalloc(sizeof(*job->progs)); 969 job->progs = xmalloc(sizeof(*job->progs));
896 970
897 /* We set the argv elements to point inside of this string. The 971 /* We set the argv elements to point inside of this string. The
898 memory is freed by freeJob(). Allocate twice the original 972 memory is freed by free_job(). Allocate twice the original
899 length in case we need to quote every single character. 973 length in case we need to quote every single character.
900 974
901 Getting clean memory relieves us of the task of NULL 975 Getting clean memory relieves us of the task of NULL
902 terminating things and makes the rest of this look a bit 976 terminating things and makes the rest of this look a bit
903 cleaner (though it is, admittedly, a tad less efficient) */ 977 cleaner (though it is, admittedly, a tad less efficient) */
904 job->cmdBuf = command = xcalloc(2*strlen(*commandPtr) + 1, sizeof(char)); 978 job->cmdbuf = command = xcalloc(2*strlen(*command_ptr) + 1, sizeof(char));
905 job->text = NULL; 979 job->text = NULL;
906 980
907 prog = job->progs; 981 prog = job->progs;
908 prog->numRedirections = 0; 982 prog->num_redirects = 0;
909 prog->redirections = NULL; 983 prog->redirects = NULL;
910 prog->freeGlob = 0; 984 prog->free_glob = 0;
911 prog->isStopped = 0; 985 prog->is_stopped = 0;
986 prog->family = job;
912 987
913 argvAlloced = 5; 988 argv_alloced = 5;
914 prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced); 989 prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
915 prog->argv[0] = job->cmdBuf; 990 prog->argv[0] = job->cmdbuf;
916 991
917 buf = command; 992 buf = command;
918 src = *commandPtr; 993 src = *command_ptr;
919 while (*src && !done) { 994 while (*src && !done) {
920 if (quote == *src) { 995 if (quote == *src) {
921 quote = '\0'; 996 quote = '\0';
@@ -924,7 +999,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
924 src++; 999 src++;
925 if (!*src) { 1000 if (!*src) {
926 error_msg("character expected after \\\n"); 1001 error_msg("character expected after \\\n");
927 freeJob(job); 1002 free_job(job);
928 return 1; 1003 return 1;
929 } 1004 }
930 1005
@@ -940,13 +1015,13 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
940 if (*prog->argv[argc_l]) { 1015 if (*prog->argv[argc_l]) {
941 buf++, argc_l++; 1016 buf++, argc_l++;
942 /* +1 here leaves room for the NULL which ends argv */ 1017 /* +1 here leaves room for the NULL which ends argv */
943 if ((argc_l + 1) == argvAlloced) { 1018 if ((argc_l + 1) == argv_alloced) {
944 argvAlloced += 5; 1019 argv_alloced += 5;
945 prog->argv = xrealloc(prog->argv, 1020 prog->argv = xrealloc(prog->argv,
946 sizeof(*prog->argv) * 1021 sizeof(*prog->argv) *
947 argvAlloced); 1022 argv_alloced);
948 } 1023 }
949 globLastArgument(prog, &argc_l, &argvAlloced); 1024 expand_argument(prog, &argc_l, &argv_alloced);
950 prog->argv[argc_l] = buf; 1025 prog->argv[argc_l] = buf;
951 } 1026 }
952 } else 1027 } else
@@ -963,42 +1038,42 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
963 done = 1; 1038 done = 1;
964 break; 1039 break;
965 1040
966 case '>': /* redirections */ 1041 case '>': /* redirects */
967 case '<': 1042 case '<':
968 i = prog->numRedirections++; 1043 i = prog->num_redirects++;
969 prog->redirections = xrealloc(prog->redirections, 1044 prog->redirects = xrealloc(prog->redirects,
970 sizeof(*prog->redirections) * 1045 sizeof(*prog->redirects) *
971 (i + 1)); 1046 (i + 1));
972 1047
973 prog->redirections[i].fd = -1; 1048 prog->redirects[i].fd = -1;
974 if (buf != prog->argv[argc_l]) { 1049 if (buf != prog->argv[argc_l]) {
975 /* the stuff before this character may be the file number 1050 /* the stuff before this character may be the file number
976 being redirected */ 1051 being redirected */
977 prog->redirections[i].fd = 1052 prog->redirects[i].fd =
978 strtol(prog->argv[argc_l], &chptr, 10); 1053 strtol(prog->argv[argc_l], &chptr, 10);
979 1054
980 if (*chptr && *prog->argv[argc_l]) { 1055 if (*chptr && *prog->argv[argc_l]) {
981 buf++, argc_l++; 1056 buf++, argc_l++;
982 globLastArgument(prog, &argc_l, &argvAlloced); 1057 expand_argument(prog, &argc_l, &argv_alloced);
983 prog->argv[argc_l] = buf; 1058 prog->argv[argc_l] = buf;
984 } 1059 }
985 } 1060 }
986 1061
987 if (prog->redirections[i].fd == -1) { 1062 if (prog->redirects[i].fd == -1) {
988 if (*src == '>') 1063 if (*src == '>')
989 prog->redirections[i].fd = 1; 1064 prog->redirects[i].fd = 1;
990 else 1065 else
991 prog->redirections[i].fd = 0; 1066 prog->redirects[i].fd = 0;
992 } 1067 }
993 1068
994 if (*src++ == '>') { 1069 if (*src++ == '>') {
995 if (*src == '>') 1070 if (*src == '>')
996 prog->redirections[i].type = 1071 prog->redirects[i].type =
997 REDIRECT_APPEND, src++; 1072 REDIRECT_APPEND, src++;
998 else 1073 else
999 prog->redirections[i].type = REDIRECT_OVERWRITE; 1074 prog->redirects[i].type = REDIRECT_OVERWRITE;
1000 } else { 1075 } else {
1001 prog->redirections[i].type = REDIRECT_INPUT; 1076 prog->redirects[i].type = REDIRECT_INPUT;
1002 } 1077 }
1003 1078
1004 /* This isn't POSIX sh compliant. Oh well. */ 1079 /* This isn't POSIX sh compliant. Oh well. */
@@ -1008,12 +1083,12 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1008 1083
1009 if (!*chptr) { 1084 if (!*chptr) {
1010 error_msg("file name expected after %c\n", *src); 1085 error_msg("file name expected after %c\n", *src);
1011 freeJob(job); 1086 free_job(job);
1012 job->numProgs=0; 1087 job->num_progs=0;
1013 return 1; 1088 return 1;
1014 } 1089 }
1015 1090
1016 prog->redirections[i].filename = buf; 1091 prog->redirects[i].filename = buf;
1017 while (*chptr && !isspace(*chptr)) 1092 while (*chptr && !isspace(*chptr))
1018 *buf++ = *chptr++; 1093 *buf++ = *chptr++;
1019 1094
@@ -1027,25 +1102,26 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1027 argc_l++; 1102 argc_l++;
1028 if (!argc_l) { 1103 if (!argc_l) {
1029 error_msg("empty command in pipe\n"); 1104 error_msg("empty command in pipe\n");
1030 freeJob(job); 1105 free_job(job);
1031 job->numProgs=0; 1106 job->num_progs=0;
1032 return 1; 1107 return 1;
1033 } 1108 }
1034 prog->argv[argc_l] = NULL; 1109 prog->argv[argc_l] = NULL;
1035 1110
1036 /* and start the next */ 1111 /* and start the next */
1037 job->numProgs++; 1112 job->num_progs++;
1038 job->progs = xrealloc(job->progs, 1113 job->progs = xrealloc(job->progs,
1039 sizeof(*job->progs) * job->numProgs); 1114 sizeof(*job->progs) * job->num_progs);
1040 prog = job->progs + (job->numProgs - 1); 1115 prog = job->progs + (job->num_progs - 1);
1041 prog->numRedirections = 0; 1116 prog->num_redirects = 0;
1042 prog->redirections = NULL; 1117 prog->redirects = NULL;
1043 prog->freeGlob = 0; 1118 prog->free_glob = 0;
1044 prog->isStopped = 0; 1119 prog->is_stopped = 0;
1120 prog->family = job;
1045 argc_l = 0; 1121 argc_l = 0;
1046 1122
1047 argvAlloced = 5; 1123 argv_alloced = 5;
1048 prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced); 1124 prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
1049 prog->argv[0] = ++buf; 1125 prog->argv[0] = ++buf;
1050 1126
1051 src++; 1127 src++;
@@ -1054,8 +1130,8 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1054 1130
1055 if (!*src) { 1131 if (!*src) {
1056 error_msg("empty command in pipe\n"); 1132 error_msg("empty command in pipe\n");
1057 freeJob(job); 1133 free_job(job);
1058 job->numProgs=0; 1134 job->num_progs=0;
1059 return 1; 1135 return 1;
1060 } 1136 }
1061 src--; /* we'll ++ it at the end of the loop */ 1137 src--; /* we'll ++ it at the end of the loop */
@@ -1063,10 +1139,10 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1063 break; 1139 break;
1064 1140
1065 case '&': /* background */ 1141 case '&': /* background */
1066 *inBg = 1; 1142 *inbg = 1;
1067 case ';': /* multiple commands */ 1143 case ';': /* multiple commands */
1068 done = 1; 1144 done = 1;
1069 returnCommand = *commandPtr + (src - *commandPtr) + 1; 1145 return_command = *command_ptr + (src - *command_ptr) + 1;
1070 break; 1146 break;
1071 1147
1072#ifdef BB_FEATURE_SH_BACKTICKS 1148#ifdef BB_FEATURE_SH_BACKTICKS
@@ -1075,15 +1151,15 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1075 { 1151 {
1076 char* charptr1=NULL, *charptr2; 1152 char* charptr1=NULL, *charptr2;
1077 char* ptr=NULL; 1153 char* ptr=NULL;
1078 struct job *newJob; 1154 struct job *newjob;
1079 struct jobSet njobList = { NULL, NULL }; 1155 struct jobset njob_list = { NULL, NULL };
1080 int pipefd[2]; 1156 int pipefd[2];
1081 int size; 1157 int size;
1082 1158
1083 ptr=strchr(++src, '`'); 1159 ptr=strchr(++src, '`');
1084 if (ptr==NULL) { 1160 if (ptr==NULL) {
1085 fprintf(stderr, "Unmatched '`' in command\n"); 1161 fprintf(stderr, "Unmatched '`' in command\n");
1086 freeJob(job); 1162 free_job(job);
1087 return 1; 1163 return 1;
1088 } 1164 }
1089 1165
@@ -1091,15 +1167,17 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1091 charptr1 = charptr2 = xmalloc(1+ptr-src); 1167 charptr1 = charptr2 = xmalloc(1+ptr-src);
1092 memcpy(charptr1, src, ptr-src); 1168 memcpy(charptr1, src, ptr-src);
1093 charptr1[ptr-src] = '\0'; 1169 charptr1[ptr-src] = '\0';
1094 newJob = xmalloc(sizeof(struct job)); 1170 newjob = xmalloc(sizeof(struct job));
1171 newjob->job_list = &njob_list;
1095 /* Now parse and run the backticked command */ 1172 /* Now parse and run the backticked command */
1096 if (!parseCommand(&charptr1, newJob, &njobList, inBg) 1173 if (!parse_command(&charptr1, newjob, inbg)
1097 && newJob->numProgs) { 1174 && newjob->num_progs) {
1098 pipe(pipefd); 1175 pipe(pipefd);
1099 runCommand(newJob, &njobList, 0, pipefd); 1176 run_command(newjob, 0, pipefd);
1100 } 1177 }
1101 checkJobs(jobList); 1178 checkjobs(job->job_list);
1102 freeJob(newJob); 1179 free_job(newjob); /* doesn't actually free newjob,
1180 looks like a memory leak */
1103 free(charptr2); 1181 free(charptr2);
1104 1182
1105 /* Make a copy of any stuff left over in the command 1183 /* Make a copy of any stuff left over in the command
@@ -1113,10 +1191,9 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1113 --src; 1191 --src;
1114 charptr1 = xmalloc(BUFSIZ); 1192 charptr1 = xmalloc(BUFSIZ);
1115 while ( (size=full_read(pipefd[0], charptr1, BUFSIZ-1)) >0) { 1193 while ( (size=full_read(pipefd[0], charptr1, BUFSIZ-1)) >0) {
1116 int newSize=src - *commandPtr + size + 1 + strlen(charptr2); 1194 int newsize=src - *command_ptr + size + 1 + strlen(charptr2);
1117 if (newSize > BUFSIZ) { 1195 if (newsize > BUFSIZ) {
1118 *commandPtr=xrealloc(*commandPtr, src - *commandPtr + 1196 *command_ptr=xrealloc(*command_ptr, newsize);
1119 size + 1 + strlen(charptr2));
1120 } 1197 }
1121 memcpy(src, charptr1, size); 1198 memcpy(src, charptr1, size);
1122 src+=size; 1199 src+=size;
@@ -1126,16 +1203,20 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1126 if (*(src-1)=='\n') 1203 if (*(src-1)=='\n')
1127 --src; 1204 --src;
1128 1205
1129 /* Now paste into the *commandPtr all the stuff 1206 /* Now paste into the *command_ptr all the stuff
1130 * leftover after the second backtick */ 1207 * leftover after the second backtick */
1131 memcpy(src, charptr2, strlen(charptr2)+1); 1208 memcpy(src, charptr2, strlen(charptr2)+1);
1132 free(charptr2); 1209 free(charptr2);
1133 1210
1134 /* Now recursively call parseCommand to deal with the new 1211 /* Now recursively call parse_command to deal with the new
1135 * and improved version of the command line with the backtick 1212 * and improved version of the command line with the backtick
1136 * results expanded in place... */ 1213 * results expanded in place... */
1137 freeJob(job); 1214 {
1138 return(parseCommand(commandPtr, job, jobList, inBg)); 1215 struct jobset *jl=job->job_list;
1216 free_job(job);
1217 job->job_list = jl;
1218 }
1219 return(parse_command(command_ptr, job, inbg));
1139 } 1220 }
1140 break; 1221 break;
1141#endif // BB_FEATURE_SH_BACKTICKS 1222#endif // BB_FEATURE_SH_BACKTICKS
@@ -1143,9 +1224,37 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1143 case '\\': 1224 case '\\':
1144 src++; 1225 src++;
1145 if (!*src) { 1226 if (!*src) {
1227/* This is currently a little broken... */
1228#ifdef HANDLE_CONTINUATION_CHARS
1229 /* They fed us a continuation char, so continue reading stuff
1230 * on the next line, then tack that onto the end of the current
1231 * command */
1232 char *command;
1233 int newsize;
1234 printf("erik: found a continue char at EOL...\n");
1235 command = (char *) xcalloc(BUFSIZ, sizeof(char));
1236 if (get_command(input, command)) {
1237 error_msg("character expected after \\\n");
1238 free(command);
1239 free_job(job);
1240 return 1;
1241 }
1242 newsize = strlen(*command_ptr) + strlen(command) + 2;
1243 if (newsize > BUFSIZ) {
1244 printf("erik: doing realloc\n");
1245 *command_ptr=xrealloc(*command_ptr, newsize);
1246 }
1247 printf("erik: A: *command_ptr='%s'\n", *command_ptr);
1248 memcpy(--src, command, strlen(command));
1249 printf("erik: B: *command_ptr='%s'\n", *command_ptr);
1250 free(command);
1251 break;
1252#else
1146 error_msg("character expected after \\\n"); 1253 error_msg("character expected after \\\n");
1147 freeJob(job); 1254 free(command);
1255 free_job(job);
1148 return 1; 1256 return 1;
1257#endif
1149 } 1258 }
1150 if (*src == '*' || *src == '[' || *src == ']' 1259 if (*src == '*' || *src == '[' || *src == ']'
1151 || *src == '?') *buf++ = '\\'; 1260 || *src == '?') *buf++ = '\\';
@@ -1159,76 +1268,187 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1159 1268
1160 if (*prog->argv[argc_l]) { 1269 if (*prog->argv[argc_l]) {
1161 argc_l++; 1270 argc_l++;
1162 globLastArgument(prog, &argc_l, &argvAlloced); 1271 expand_argument(prog, &argc_l, &argv_alloced);
1163 } 1272 }
1164 if (!argc_l) { 1273 if (!argc_l) {
1165 freeJob(job); 1274 free_job(job);
1166 return 0; 1275 return 0;
1167 } 1276 }
1168 prog->argv[argc_l] = NULL; 1277 prog->argv[argc_l] = NULL;
1169 1278
1170 if (!returnCommand) { 1279 if (!return_command) {
1171 job->text = xmalloc(strlen(*commandPtr) + 1); 1280 job->text = xmalloc(strlen(*command_ptr) + 1);
1172 strcpy(job->text, *commandPtr); 1281 strcpy(job->text, *command_ptr);
1173 } else { 1282 } else {
1174 /* This leaves any trailing spaces, which is a bit sloppy */ 1283 /* This leaves any trailing spaces, which is a bit sloppy */
1175 count = returnCommand - *commandPtr; 1284 count = return_command - *command_ptr;
1176 job->text = xmalloc(count + 1); 1285 job->text = xmalloc(count + 1);
1177 strncpy(job->text, *commandPtr, count); 1286 strncpy(job->text, *command_ptr, count);
1178 job->text[count] = '\0'; 1287 job->text[count] = '\0';
1179 } 1288 }
1180 1289
1181 *commandPtr = returnCommand; 1290 *command_ptr = return_command;
1182 1291
1183 return 0; 1292 return 0;
1184} 1293}
1185 1294
1186static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]) 1295/* Run the child_prog, no matter what kind of command it uses.
1296 */
1297static int pseudo_exec(struct child_prog *child)
1187{ 1298{
1188 struct job *theJob; 1299 struct built_in_command *x;
1189 int i;
1190 int nextin, nextout;
1191 int pipefds[2]; /* pipefd[0] is for reading */
1192 struct builtInCommand *x;
1193#ifdef BB_FEATURE_SH_STANDALONE_SHELL 1300#ifdef BB_FEATURE_SH_STANDALONE_SHELL
1194 struct BB_applet search_applet, *applet; 1301 struct BB_applet search_applet, *applet;
1195#endif 1302#endif
1196 1303
1304 /* Check if the command matches any of the forking builtins.
1305 * XXX It would probably be wise to check for non-forking builtins
1306 * here as well, since in some context the non-forking path
1307 * is disabled or bypassed. See comment in run_command.
1308 */
1309 for (x = bltins_forking; x->cmd; x++) {
1310 if (strcmp(child->argv[0], x->cmd) == 0) {
1311 applet_name=x->cmd;
1312 exit (x->function(child));
1313 }
1314 }
1315#ifdef BB_FEATURE_SH_STANDALONE_SHELL
1316 /* Check if the command matches any busybox internal
1317 * commands ("applets") here. Following discussions from
1318 * November 2000 on busybox@opensource.lineo.com, don't use
1319 * get_last_path_component(). This way explicit (with
1320 * slashes) filenames will never be interpreted as an
1321 * applet, just like with builtins. This way the user can
1322 * override an applet with an explicit filename reference.
1323 * The only downside to this change is that an explicit
1324 * /bin/foo invocation will fork and exec /bin/foo, even if
1325 * /bin/foo is a symlink to busybox.
1326 */
1327 search_applet.name = child->argv[0];
1328
1329#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
1330 /* If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then
1331 * if you run /bin/cat, it will use BusyBox cat even if
1332 * /bin/cat exists on the filesystem and is _not_ busybox.
1333 * Some systems want this, others do not. Choose wisely. :-)
1334 */
1335 search_applet.name = get_last_path_component(search_applet.name);
1336#endif
1337
1338 /* Do a binary search to find the applet entry given the name. */
1339 applet = bsearch(&search_applet, applets, NUM_APPLETS,
1340 sizeof(struct BB_applet), applet_name_compare);
1341 if (applet != NULL) {
1342 int argc_l;
1343 char** argv=child->argv;
1344 for(argc_l=0;*argv!=NULL; argv++, argc_l++);
1345 applet_name=applet->name;
1346 optind = 1;
1347 exit((*(applet->main)) (argc_l, child->argv));
1348 }
1349#endif
1350
1351 execvp(child->argv[0], child->argv);
1352 error_msg_and_die("%s: %s\n", child->argv[0],
1353 strerror(errno));
1354}
1355
1356static void insert_job(struct job *newjob, int inbg)
1357{
1358 struct job *thejob;
1359 struct jobset *job_list=newjob->job_list;
1360
1361 /* find the ID for thejob to use */
1362 newjob->jobid = 1;
1363 for (thejob = job_list->head; thejob; thejob = thejob->next)
1364 if (thejob->jobid >= newjob->jobid)
1365 newjob->jobid = thejob->jobid + 1;
1366
1367 /* add thejob to the list of running jobs */
1368 if (!job_list->head) {
1369 thejob = job_list->head = xmalloc(sizeof(*thejob));
1370 } else {
1371 for (thejob = job_list->head; thejob->next; thejob = thejob->next) /* nothing */;
1372 thejob->next = xmalloc(sizeof(*thejob));
1373 thejob = thejob->next;
1374 }
1375
1376 *thejob = *newjob; /* physically copy the struct job */
1377 thejob->next = NULL;
1378 thejob->running_progs = thejob->num_progs;
1379 thejob->stopped_progs = 0;
1380
1381 if (inbg) {
1382 /* we don't wait for background thejobs to return -- append it
1383 to the list of backgrounded thejobs and leave it alone */
1384 printf("[%d] %d\n", thejob->jobid,
1385 newjob->progs[newjob->num_progs - 1].pid);
1386#ifdef BB_FEATURE_SH_ENVIRONMENT
1387 last_bg_pid=newjob->progs[newjob->num_progs - 1].pid;
1388#endif
1389 } else {
1390 newjob->job_list->fg = thejob;
1391
1392 /* move the new process group into the foreground */
1393 /* suppress messages when run from /linuxrc mag@sysgo.de */
1394 if (tcsetpgrp(0, newjob->pgrp) && errno != ENOTTY)
1395 perror("tcsetpgrp");
1396 }
1397}
1398
1399static int run_command(struct job *newjob, int inbg, int outpipe[2])
1400{
1401 /* struct job *thejob; */
1402 int i;
1403 int nextin, nextout;
1404 int pipefds[2]; /* pipefd[0] is for reading */
1405 struct built_in_command *x;
1406 struct child_prog *child;
1407
1197 nextin = 0, nextout = 1; 1408 nextin = 0, nextout = 1;
1198 for (i = 0; i < newJob->numProgs; i++) { 1409 for (i = 0; i < newjob->num_progs; i++) {
1199 if ((i + 1) < newJob->numProgs) { 1410 child = & (newjob->progs[i]);
1200 pipe(pipefds); 1411
1412 if ((i + 1) < newjob->num_progs) {
1413 if (pipe(pipefds)<0) perror_msg_and_die("pipe");
1201 nextout = pipefds[1]; 1414 nextout = pipefds[1];
1202 } else { 1415 } else {
1203 if (outPipe[1]!=-1) { 1416 if (outpipe[1]!=-1) {
1204 nextout = outPipe[1]; 1417 nextout = outpipe[1];
1205 } else { 1418 } else {
1206 nextout = 1; 1419 nextout = 1;
1207 } 1420 }
1208 } 1421 }
1209 1422
1210#ifdef BB_FEATURE_SH_ENVIRONMENT 1423#ifdef BB_FEATURE_SH_ENVIRONMENT
1211 if (showXtrace==TRUE) { 1424 if (show_x_trace==TRUE) {
1212 int j; 1425 int j;
1213 fprintf(stderr, "+ "); 1426 fputc('+', stderr);
1214 for (j = 0; newJob->progs[i].argv[j]; j++) 1427 for (j = 0; child->argv[j]; j++) {
1215 fprintf(stderr, "%s ", newJob->progs[i].argv[j]); 1428 fputc(' ', stderr);
1216 fprintf(stderr, "\n"); 1429 fputs(child->argv[j], stderr);
1430 }
1431 fputc('\n', stderr);
1217 } 1432 }
1218#endif 1433#endif
1219 1434
1220 /* Check if the command matches any non-forking builtins */ 1435 /* Check if the command matches any non-forking builtins.
1436 * XXX should probably skip this test, and fork anyway, if
1437 * there redirects of some kind demand forking to work right.
1438 * pseudo_exec would then need to handle the non-forking command
1439 * in a forked context.
1440 */
1221 for (x = bltins; x->cmd; x++) { 1441 for (x = bltins; x->cmd; x++) {
1222 if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0 ) { 1442 if (strcmp(child->argv[0], x->cmd) == 0 ) {
1223 return(x->function(newJob, jobList)); 1443 return(x->function(child));
1224 } 1444 }
1225 } 1445 }
1226 1446
1227 if (!(newJob->progs[i].pid = fork())) { 1447 if (!(child->pid = fork())) {
1228 signal(SIGTTOU, SIG_DFL); 1448 signal(SIGTTOU, SIG_DFL);
1229 1449
1230 if (outPipe[1]!=-1) { 1450 if (outpipe[1]!=-1) {
1231 close(outPipe[0]); 1451 close(outpipe[0]);
1232 } 1452 }
1233 if (nextin != 0) { 1453 if (nextin != 0) {
1234 dup2(nextin, 0); 1454 dup2(nextin, 0);
@@ -1237,68 +1457,23 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
1237 1457
1238 if (nextout != 1) { 1458 if (nextout != 1) {
1239 dup2(nextout, 1); 1459 dup2(nextout, 1);
1240 dup2(nextout, 2); 1460 dup2(nextout, 2); /* Really? */
1241 close(nextout); 1461 close(nextout);
1242 close(pipefds[0]); 1462 close(pipefds[0]);
1243 } 1463 }
1244 1464
1245 /* explicit redirections override pipes */ 1465 /* explicit redirects override pipes */
1246 setupRedirections(newJob->progs + i); 1466 setup_redirects(child);
1247
1248 /* Check if the command matches any of the other builtins */
1249 for (x = bltins_forking; x->cmd; x++) {
1250 if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0) {
1251 applet_name=x->cmd;
1252 exit (x->function(newJob, jobList));
1253 }
1254 }
1255#ifdef BB_FEATURE_SH_STANDALONE_SHELL
1256 /* Check if the command matches any busybox internal
1257 * commands ("applets") here. Following discussions from
1258 * November 2000 on busybox@opensource.lineo.com, don't use
1259 * get_last_path_component(). This way explicit (with
1260 * slashes) filenames will never be interpreted as an
1261 * applet, just like with builtins. This way the user can
1262 * override an applet with an explicit filename reference.
1263 * The only downside to this change is that an explicit
1264 * /bin/foo invocation fill fork and exec /bin/foo, even if
1265 * /bin/foo is a symlink to busybox.
1266 */
1267 search_applet.name = newJob->progs[i].argv[0];
1268 1467
1269#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN 1468 pseudo_exec(child);
1270 /* If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then
1271 * if you run /bin/cat, it will use BusyBox cat even if
1272 * /bin/cat exists on the filesystem and is _not_ busybox.
1273 * Some systems want this, others do not. Choose wisely. :-)
1274 */
1275 search_applet.name = get_last_path_component(search_applet.name);
1276#endif
1277
1278 /* Do a binary search to find the applet entry given the name. */
1279 applet = bsearch(&search_applet, applets, NUM_APPLETS,
1280 sizeof(struct BB_applet), applet_name_compare);
1281 if (applet != NULL) {
1282 int argc_l;
1283 char** argv=newJob->progs[i].argv;
1284 for(argc_l=0;*argv!=NULL; argv++, argc_l++);
1285 applet_name=applet->name;
1286 optind = 1;
1287 exit((*(applet->main)) (argc_l, newJob->progs[i].argv));
1288 }
1289#endif
1290
1291 execvp(newJob->progs[i].argv[0], newJob->progs[i].argv);
1292 error_msg_and_die("%s: %s\n", newJob->progs[i].argv[0],
1293 strerror(errno));
1294 } 1469 }
1295 if (outPipe[1]!=-1) { 1470 if (outpipe[1]!=-1) {
1296 close(outPipe[1]); 1471 close(outpipe[1]);
1297 } 1472 }
1298 1473
1299 /* put our child in the process group whose leader is the 1474 /* put our child in the process group whose leader is the
1300 first process in this pipe */ 1475 first process in this pipe */
1301 setpgid(newJob->progs[i].pid, newJob->progs[0].pid); 1476 setpgid(child->pid, newjob->progs[0].pid);
1302 if (nextin != 0) 1477 if (nextin != 0)
1303 close(nextin); 1478 close(nextin);
1304 if (nextout != 1) 1479 if (nextout != 1)
@@ -1309,44 +1484,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
1309 nextin = pipefds[0]; 1484 nextin = pipefds[0];
1310 } 1485 }
1311 1486
1312 newJob->pgrp = newJob->progs[0].pid; 1487 newjob->pgrp = newjob->progs[0].pid;
1313 1488
1314 /* find the ID for the theJob to use */ 1489 insert_job(newjob, inbg);
1315 newJob->jobId = 1;
1316 for (theJob = jobList->head; theJob; theJob = theJob->next)
1317 if (theJob->jobId >= newJob->jobId)
1318 newJob->jobId = theJob->jobId + 1;
1319
1320 /* add the theJob to the list of running jobs */
1321 if (!jobList->head) {
1322 theJob = jobList->head = xmalloc(sizeof(*theJob));
1323 } else {
1324 for (theJob = jobList->head; theJob->next; theJob = theJob->next);
1325 theJob->next = xmalloc(sizeof(*theJob));
1326 theJob = theJob->next;
1327 }
1328
1329 *theJob = *newJob;
1330 theJob->next = NULL;
1331 theJob->runningProgs = theJob->numProgs;
1332 theJob->stoppedProgs = 0;
1333
1334 if (inBg) {
1335 /* we don't wait for background theJobs to return -- append it
1336 to the list of backgrounded theJobs and leave it alone */
1337 printf("[%d] %d\n", theJob->jobId,
1338 newJob->progs[newJob->numProgs - 1].pid);
1339#ifdef BB_FEATURE_SH_ENVIRONMENT
1340 lastBgPid=newJob->progs[newJob->numProgs - 1].pid;
1341#endif
1342 } else {
1343 jobList->fg = theJob;
1344
1345 /* move the new process group into the foreground */
1346 /* suppress messages when run from /linuxrc mag@sysgo.de */
1347 if (tcsetpgrp(0, newJob->pgrp) && errno != ENOTTY)
1348 perror("tcsetpgrp");
1349 }
1350 1490
1351 return 0; 1491 return 0;
1352} 1492}
@@ -1354,13 +1494,14 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
1354static int busy_loop(FILE * input) 1494static int busy_loop(FILE * input)
1355{ 1495{
1356 char *command; 1496 char *command;
1357 char *nextCommand = NULL; 1497 char *next_command = NULL;
1358 struct job newJob; 1498 struct job newjob;
1359 pid_t parent_pgrp; 1499 pid_t parent_pgrp;
1360 int i; 1500 int i;
1361 int inBg; 1501 int inbg;
1362 int status; 1502 int status;
1363 newJob.jobContext = REGULAR_JOB_CONTEXT; 1503 newjob.job_list = &job_list;
1504 newjob.job_context = DEFAULT_CONTEXT;
1364 1505
1365 /* save current owner of TTY so we can restore it on exit */ 1506 /* save current owner of TTY so we can restore it on exit */
1366 parent_pgrp = tcgetpgrp(0); 1507 parent_pgrp = tcgetpgrp(0);
@@ -1372,64 +1513,65 @@ static int busy_loop(FILE * input)
1372 signal(SIGTTOU, SIG_IGN); 1513 signal(SIGTTOU, SIG_IGN);
1373 1514
1374 while (1) { 1515 while (1) {
1375 if (!jobList.fg) { 1516 if (!job_list.fg) {
1376 /* no job is in the foreground */ 1517 /* no job is in the foreground */
1377 1518
1378 /* see if any background processes have exited */ 1519 /* see if any background processes have exited */
1379 checkJobs(&jobList); 1520 checkjobs(&job_list);
1380 1521
1381 if (!nextCommand) { 1522 if (!next_command) {
1382 if (getCommand(input, command)) 1523 if (get_command(input, command))
1383 break; 1524 break;
1384 nextCommand = command; 1525 next_command = command;
1385 } 1526 }
1386 1527
1387 if (!parseCommand(&nextCommand, &newJob, &jobList, &inBg) && 1528 if (!parse_command(&next_command, &newjob, &inbg) &&
1388 newJob.numProgs) { 1529 newjob.num_progs) {
1389 int pipefds[2] = {-1,-1}; 1530 int pipefds[2] = {-1,-1};
1390 runCommand(&newJob, &jobList, inBg, pipefds); 1531 debug_printf( "job=%p being fed to run_command by busy_loop()'\n", &newjob);
1532 run_command(&newjob, inbg, pipefds);
1391 } 1533 }
1392 else { 1534 else {
1393 free(command); 1535 free(command);
1394 command = (char *) xcalloc(BUFSIZ, sizeof(char)); 1536 command = (char *) xcalloc(BUFSIZ, sizeof(char));
1395 nextCommand = NULL; 1537 next_command = NULL;
1396 } 1538 }
1397 } else { 1539 } else {
1398 /* a job is running in the foreground; wait for it */ 1540 /* a job is running in the foreground; wait for it */
1399 i = 0; 1541 i = 0;
1400 while (!jobList.fg->progs[i].pid || 1542 while (!job_list.fg->progs[i].pid ||
1401 jobList.fg->progs[i].isStopped == 1) i++; 1543 job_list.fg->progs[i].is_stopped == 1) i++;
1402 1544
1403 waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED); 1545 waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED);
1404 1546
1405 if (WIFEXITED(status) || WIFSIGNALED(status)) { 1547 if (WIFEXITED(status) || WIFSIGNALED(status)) {
1406 /* the child exited */ 1548 /* the child exited */
1407 jobList.fg->runningProgs--; 1549 job_list.fg->running_progs--;
1408 jobList.fg->progs[i].pid = 0; 1550 job_list.fg->progs[i].pid = 0;
1409 1551
1410#ifdef BB_FEATURE_SH_ENVIRONMENT 1552#ifdef BB_FEATURE_SH_ENVIRONMENT
1411 lastReturnCode=WEXITSTATUS(status); 1553 last_return_code=WEXITSTATUS(status);
1412#endif 1554#endif
1413 debug_printf("'%s' exited -- return code %d\n", jobList.fg->text, lastReturnCode); 1555 debug_printf("'%s' exited -- return code %d\n",
1414 if (!jobList.fg->runningProgs) { 1556 job_list.fg->text, last_return_code);
1557 if (!job_list.fg->running_progs) {
1415 /* child exited */ 1558 /* child exited */
1416 1559 remove_job(&job_list, job_list.fg);
1417 removeJob(&jobList, jobList.fg); 1560 job_list.fg = NULL;
1418 jobList.fg = NULL;
1419 } 1561 }
1420 } else { 1562 } else {
1421 /* the child was stopped */ 1563 /* the child was stopped */
1422 jobList.fg->stoppedProgs++; 1564 job_list.fg->stopped_progs++;
1423 jobList.fg->progs[i].isStopped = 1; 1565 job_list.fg->progs[i].is_stopped = 1;
1424 1566
1425 if (jobList.fg->stoppedProgs == jobList.fg->runningProgs) { 1567 if (job_list.fg->stopped_progs == job_list.fg->running_progs) {
1426 printf("\n" JOB_STATUS_FORMAT, jobList.fg->jobId, 1568 printf("\n" JOB_STATUS_FORMAT, job_list.fg->jobid,
1427 "Stopped", jobList.fg->text); 1569 "Stopped", job_list.fg->text);
1428 jobList.fg = NULL; 1570 job_list.fg = NULL;
1429 } 1571 }
1430 } 1572 }
1431 1573
1432 if (!jobList.fg) { 1574 if (!job_list.fg) {
1433 /* move the shell to the foreground */ 1575 /* move the shell to the foreground */
1434 /* suppress messages when run from /linuxrc mag@sysgo.de */ 1576 /* suppress messages when run from /linuxrc mag@sysgo.de */
1435 if (tcsetpgrp(0, getpid()) && errno != ENOTTY) 1577 if (tcsetpgrp(0, getpid()) && errno != ENOTTY)
@@ -1454,15 +1596,15 @@ static int busy_loop(FILE * input)
1454#ifdef BB_FEATURE_CLEAN_UP 1596#ifdef BB_FEATURE_CLEAN_UP
1455void free_memory(void) 1597void free_memory(void)
1456{ 1598{
1457 if (promptStr) 1599 if (prompt_str)
1458 free(promptStr); 1600 free(prompt_str);
1459 if (cwd) 1601 if (cwd)
1460 free(cwd); 1602 free(cwd);
1461 if (local_pending_command) 1603 if (local_pending_command)
1462 free(local_pending_command); 1604 free(local_pending_command);
1463 1605
1464 if (jobList.fg && !jobList.fg->runningProgs) { 1606 if (job_list.fg && !job_list.fg->running_progs) {
1465 removeJob(&jobList, jobList.fg); 1607 remove_job(&job_list, job_list.fg);
1466 } 1608 }
1467} 1609}
1468#endif 1610#endif
@@ -1500,7 +1642,7 @@ int shell_main(int argc_l, char **argv_l)
1500 break; 1642 break;
1501#ifdef BB_FEATURE_SH_ENVIRONMENT 1643#ifdef BB_FEATURE_SH_ENVIRONMENT
1502 case 'x': 1644 case 'x':
1503 showXtrace = TRUE; 1645 show_x_trace = TRUE;
1504 break; 1646 break;
1505#endif 1647#endif
1506 case 'i': 1648 case 'i':
@@ -1517,10 +1659,14 @@ int shell_main(int argc_l, char **argv_l)
1517 * standard input is a terminal 1659 * standard input is a terminal
1518 * standard output is a terminal 1660 * standard output is a terminal
1519 * Refer to Posix.2, the description of the `sh' utility. */ 1661 * Refer to Posix.2, the description of the `sh' utility. */
1520 if (interactive==TRUE || ( argv[optind]==NULL && input==stdin && isatty(fileno(stdin)) && isatty(fileno(stdout)))) { 1662 if (argv[optind]==NULL && input==stdin &&
1663 isatty(fileno(stdin)) && isatty(fileno(stdout))) {
1664 interactive=TRUE;
1665 }
1666 if (interactive==TRUE) {
1521 //fprintf(stdout, "optind=%d argv[optind]='%s'\n", optind, argv[optind]); 1667 //fprintf(stdout, "optind=%d argv[optind]='%s'\n", optind, argv[optind]);
1522 /* Looks like they want an interactive shell */ 1668 /* Looks like they want an interactive shell */
1523 fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); 1669 fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell (lash)\n", BB_VER, BB_BT);
1524 fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); 1670 fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n");
1525 } else if (local_pending_command==NULL) { 1671 } else if (local_pending_command==NULL) {
1526 //fprintf(stdout, "optind=%d argv[optind]='%s'\n", optind, argv[optind]); 1672 //fprintf(stdout, "optind=%d argv[optind]='%s'\n", optind, argv[optind]);
diff --git a/sh.c b/sh.c
index 164d6f5c5..590f5ee89 100644
--- a/sh.c
+++ b/sh.c
@@ -32,10 +32,13 @@
32//Backtick support has some problems, use at your own risk! 32//Backtick support has some problems, use at your own risk!
33//#define BB_FEATURE_SH_BACKTICKS 33//#define BB_FEATURE_SH_BACKTICKS
34// 34//
35//If, then, else, etc. support is really, really broken. Don't even 35//If, then, else, etc. support.. This should now behave basically
36//bother to mess with this yet, since you will not be happy with it. 36//like any other Bourne shell...
37//#define BB_FEATURE_SH_IF_EXPRESSIONS 37//#define BB_FEATURE_SH_IF_EXPRESSIONS
38// 38//
39/* This is currently a little broken... */
40//#define HANDLE_CONTINUATION_CHARS
41//
39//For debugging/development on the shell only... 42//For debugging/development on the shell only...
40//#define DEBUG_SHELL 43//#define DEBUG_SHELL
41 44
@@ -55,98 +58,102 @@
55#include <getopt.h> 58#include <getopt.h>
56#include "cmdedit.h" 59#include "cmdedit.h"
57 60
58#define MAX_LINE 256 /* size of input buffer for `read' builtin */ 61#define MAX_LINE 256 /* size of input buffer for cwd data */
59#define MAX_READ 128 /* size of input buffer for `read' builtin */ 62#define MAX_READ 128 /* size of input buffer for `read' builtin */
60#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 63#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
61extern size_t NUM_APPLETS; 64extern size_t NUM_APPLETS;
62 65
63 66
64 67enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE,
65
66enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
67 REDIRECT_APPEND 68 REDIRECT_APPEND
68}; 69};
69 70
70static const unsigned int REGULAR_JOB_CONTEXT=0x1; 71static const unsigned int DEFAULT_CONTEXT=0x1;
71static const unsigned int IF_TRUE_CONTEXT=0x2; 72static const unsigned int IF_TRUE_CONTEXT=0x2;
72static const unsigned int IF_FALSE_CONTEXT=0x4; 73static const unsigned int IF_FALSE_CONTEXT=0x4;
73static const unsigned int THEN_EXP_CONTEXT=0x8; 74static const unsigned int THEN_EXP_CONTEXT=0x8;
74static const unsigned int ELSE_EXP_CONTEXT=0x10; 75static const unsigned int ELSE_EXP_CONTEXT=0x10;
76unsigned int shell_context = 0;
77
75 78
76 79
77struct jobSet { 80struct jobset {
78 struct job *head; /* head of list of running jobs */ 81 struct job *head; /* head of list of running jobs */
79 struct job *fg; /* current foreground job */ 82 struct job *fg; /* current foreground job */
80}; 83};
81 84
82struct redirectionSpecifier { 85struct redir_struct {
83 enum redirectionType type; /* type of redirection */ 86 enum redir_type type; /* type of redirection */
84 int fd; /* file descriptor being redirected */ 87 int fd; /* file descriptor being redirected */
85 char *filename; /* file to redirect fd to */ 88 char *filename; /* file to redirect fd to */
86}; 89};
87 90
88struct childProgram { 91struct child_prog {
89 pid_t pid; /* 0 if exited */ 92 pid_t pid; /* 0 if exited */
90 char **argv; /* program name and arguments */ 93 char **argv; /* program name and arguments */
91 int numRedirections; /* elements in redirection array */ 94 int num_redirects; /* elements in redirection array */
92 struct redirectionSpecifier *redirections; /* I/O redirections */ 95 struct redir_struct *redirects; /* I/O redirects */
93 glob_t globResult; /* result of parameter globbing */ 96 glob_t glob_result; /* result of parameter globbing */
94 int freeGlob; /* should we globfree(&globResult)? */ 97 int free_glob; /* should we globfree(&glob_result)? */
95 int isStopped; /* is the program currently running? */ 98 int is_stopped; /* is the program currently running? */
99 struct job *family; /* pointer back to the child's parent job */
96}; 100};
97 101
98struct job { 102struct job {
99 int jobId; /* job number */ 103 int jobid; /* job number */
100 int numProgs; /* total number of programs in job */ 104 int num_progs; /* total number of programs in job */
101 int runningProgs; /* number of programs running */ 105 int running_progs; /* number of programs running */
102 char *text; /* name of job */ 106 char *text; /* name of job */
103 char *cmdBuf; /* buffer various argv's point into */ 107 char *cmdbuf; /* buffer various argv's point into */
104 pid_t pgrp; /* process group ID for the job */ 108 pid_t pgrp; /* process group ID for the job */
105 struct childProgram *progs; /* array of programs in job */ 109 struct child_prog *progs; /* array of programs in job */
106 struct job *next; /* to track background commands */ 110 struct job *next; /* to track background commands */
107 int stoppedProgs; /* number of programs alive, but stopped */ 111 int stopped_progs; /* number of programs alive, but stopped */
108 int jobContext; /* bitmask defining current context */ 112 unsigned int job_context; /* bitmask defining current context */
113 struct jobset *job_list;
109}; 114};
110 115
111struct builtInCommand { 116struct built_in_command {
112 char *cmd; /* name */ 117 char *cmd; /* name */
113 char *descr; /* description */ 118 char *descr; /* description */
114 int (*function) (struct job *, struct jobSet * jobList); /* function ptr */ 119 int (*function) (struct child_prog *); /* function ptr */
115}; 120};
116 121
117/* function prototypes for builtins */ 122/* function prototypes for builtins */
118static int builtin_cd(struct job *cmd, struct jobSet *junk); 123static int builtin_cd(struct child_prog *cmd);
119static int builtin_env(struct job *dummy, struct jobSet *junk); 124static int builtin_env(struct child_prog *dummy);
120static int builtin_exec(struct job *cmd, struct jobSet *junk); 125static int builtin_exec(struct child_prog *cmd);
121static int builtin_exit(struct job *cmd, struct jobSet *junk); 126static int builtin_exit(struct child_prog *cmd);
122static int builtin_fg_bg(struct job *cmd, struct jobSet *jobList); 127static int builtin_fg_bg(struct child_prog *cmd);
123static int builtin_help(struct job *cmd, struct jobSet *junk); 128static int builtin_help(struct child_prog *cmd);
124static int builtin_jobs(struct job *dummy, struct jobSet *jobList); 129static int builtin_jobs(struct child_prog *dummy);
125static int builtin_pwd(struct job *dummy, struct jobSet *junk); 130static int builtin_pwd(struct child_prog *dummy);
126static int builtin_export(struct job *cmd, struct jobSet *junk); 131static int builtin_export(struct child_prog *cmd);
127static int builtin_source(struct job *cmd, struct jobSet *jobList); 132static int builtin_source(struct child_prog *cmd);
128static int builtin_unset(struct job *cmd, struct jobSet *junk); 133static int builtin_unset(struct child_prog *cmd);
129static int builtin_read(struct job *cmd, struct jobSet *junk); 134static int builtin_read(struct child_prog *cmd);
130#ifdef BB_FEATURE_SH_IF_EXPRESSIONS 135#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
131static int builtin_if(struct job *cmd, struct jobSet *junk); 136static int builtin_if(struct child_prog *cmd);
132static int builtin_then(struct job *cmd, struct jobSet *junk); 137static int builtin_then(struct child_prog *cmd);
133static int builtin_else(struct job *cmd, struct jobSet *junk); 138static int builtin_else(struct child_prog *cmd);
134static int builtin_fi(struct job *cmd, struct jobSet *junk); 139static int builtin_fi(struct child_prog *cmd);
135#endif 140#endif
136 141
137 142
138/* function prototypes for shell stuff */ 143/* function prototypes for shell stuff */
139static void checkJobs(struct jobSet *jobList); 144static void checkjobs(struct jobset *job_list);
140static int getCommand(FILE * source, char *command); 145static int get_command(FILE * source, char *command);
141static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg); 146static int parse_command(char **command_ptr, struct job *job, int *inbg);
142static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]); 147static int run_command(struct job *newjob, int inbg, int outpipe[2]);
148static int pseudo_exec(struct child_prog *cmd) __attribute__ ((noreturn));
149static int run_command_predicate(char *cmd);
143static int busy_loop(FILE * input); 150static int busy_loop(FILE * input);
144 151
145 152
146/* Table of built-in functions (these are non-forking builtins, meaning they 153/* Table of built-in functions (these are non-forking builtins, meaning they
147 * can change global variables in the parent shell process but they will not 154 * can change global variables in the parent shell process but they will not
148 * work with pipes and redirects; 'unset foo | whatever' will not work) */ 155 * work with pipes and redirects; 'unset foo | whatever' will not work) */
149static struct builtInCommand bltins[] = { 156static struct built_in_command bltins[] = {
150 {"bg", "Resume a job in the background", builtin_fg_bg}, 157 {"bg", "Resume a job in the background", builtin_fg_bg},
151 {"cd", "Change working directory", builtin_cd}, 158 {"cd", "Change working directory", builtin_cd},
152 {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec}, 159 {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec},
@@ -157,6 +164,7 @@ static struct builtInCommand bltins[] = {
157 {"unset", "Unset environment variable", builtin_unset}, 164 {"unset", "Unset environment variable", builtin_unset},
158 {"read", "Input environment variable", builtin_read}, 165 {"read", "Input environment variable", builtin_read},
159 {".", "Source-in and run commands in a file", builtin_source}, 166 {".", "Source-in and run commands in a file", builtin_source},
167 /* to do: add ulimit */
160#ifdef BB_FEATURE_SH_IF_EXPRESSIONS 168#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
161 {"if", NULL, builtin_if}, 169 {"if", NULL, builtin_if},
162 {"then", NULL, builtin_then}, 170 {"then", NULL, builtin_then},
@@ -168,7 +176,7 @@ static struct builtInCommand bltins[] = {
168 176
169/* Table of forking built-in functions (things that fork cannot change global 177/* Table of forking built-in functions (things that fork cannot change global
170 * variables in the parent process, such as the current working directory) */ 178 * variables in the parent process, such as the current working directory) */
171static struct builtInCommand bltins_forking[] = { 179static struct built_in_command bltins_forking[] = {
172 {"env", "Print all environment variables", builtin_env}, 180 {"env", "Print all environment variables", builtin_env},
173 {"pwd", "Print current directory", builtin_pwd}, 181 {"pwd", "Print current directory", builtin_pwd},
174 {"help", "List shell built-in commands", builtin_help}, 182 {"help", "List shell built-in commands", builtin_help},
@@ -178,22 +186,25 @@ static struct builtInCommand bltins_forking[] = {
178static char prompt[3]; 186static char prompt[3];
179static char *cwd; 187static char *cwd;
180static char *local_pending_command = NULL; 188static char *local_pending_command = NULL;
181static char *promptStr = NULL; 189static char *prompt_str = NULL;
182static struct jobSet jobList = { NULL, NULL }; 190static struct jobset job_list = { NULL, NULL };
183static int argc; 191static int argc;
184static char **argv; 192static char **argv;
185#ifdef BB_FEATURE_SH_ENVIRONMENT 193#ifdef BB_FEATURE_SH_ENVIRONMENT
186static int lastBgPid=-1; 194static int last_bg_pid=-1;
187static int lastReturnCode=-1; 195static int last_return_code=-1;
188static int showXtrace=FALSE; 196static int show_x_trace=FALSE;
189#endif 197#endif
190 198#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
199static char syntax_err[]="syntax error near unexpected token";
200#endif
201
191#ifdef DEBUG_SHELL 202#ifdef DEBUG_SHELL
192static inline void debug_printf(const char *format, ...) 203static inline void debug_printf(const char *format, ...)
193{ 204{
194 va_list args; 205 va_list args;
195 va_start(args, format); 206 va_start(args, format);
196 vfprintf(stderr, s, p); 207 vfprintf(stderr, format, args);
197 va_end(args); 208 va_end(args);
198} 209}
199#else 210#else
@@ -213,16 +224,52 @@ static inline void win_changed(int junk)
213static inline void win_changed(int junk) {} 224static inline void win_changed(int junk) {}
214#endif 225#endif
215 226
227/*
228 Most builtins need access to the struct child_prog that has
229 their arguments, previously coded as cmd->progs[0]. That coding
230 can exhibit a bug, if the builtin is not the first command in
231 a pipeline: "echo foo | exec sort" will attempt to exec foo.
232
233builtin previous use notes
234------ ----------------- ---------
235cd cmd->progs[0]
236env 0
237exec cmd->progs[0] squashed bug: didn't look for applets or forking builtins
238exit cmd->progs[0]
239fg_bg cmd->progs[0], job_list->head, job_list->fg
240help 0
241jobs job_list->head
242pwd 0
243export cmd->progs[0] passes cmd, job_list to builtin_env(), which ignores them
244source cmd->progs[0]
245unset cmd->progs[0]
246read cmd->progs[0]
247if cmd->job_context, cmd->text
248then cmd->job_context, cmd->text
249else cmd->job_context, cmd->text
250fi cmd->job_context
251
252The use of cmd->text by if/then/else/fi is hopelessly hacky.
253Would it work to increment cmd->progs[0]->argv and recurse,
254somewhat like builtin_exec does?
255
256I added "struct job *family;" to struct child_prog,
257and switched API to builtin_foo(struct child_prog *child);
258So cmd->text becomes child->family->text
259 cmd->job_context becomes child->family->job_context
260 cmd->progs[0] becomes *child
261 job_list becomes child->family->job_list
262 */
216 263
217/* built-in 'cd <path>' handler */ 264/* built-in 'cd <path>' handler */
218static int builtin_cd(struct job *cmd, struct jobSet *junk) 265static int builtin_cd(struct child_prog *child)
219{ 266{
220 char *newdir; 267 char *newdir;
221 268
222 if (!cmd->progs[0].argv[1] == 1) 269 if (child->argv[1] == NULL)
223 newdir = getenv("HOME"); 270 newdir = getenv("HOME");
224 else 271 else
225 newdir = cmd->progs[0].argv[1]; 272 newdir = child->argv[1];
226 if (chdir(newdir)) { 273 if (chdir(newdir)) {
227 printf("cd: %s: %s\n", newdir, strerror(errno)); 274 printf("cd: %s: %s\n", newdir, strerror(errno));
228 return EXIT_FAILURE; 275 return EXIT_FAILURE;
@@ -233,7 +280,7 @@ static int builtin_cd(struct job *cmd, struct jobSet *junk)
233} 280}
234 281
235/* built-in 'env' handler */ 282/* built-in 'env' handler */
236static int builtin_env(struct job *dummy, struct jobSet *junk) 283static int builtin_env(struct child_prog *dummy)
237{ 284{
238 char **e; 285 char **e;
239 286
@@ -244,149 +291,143 @@ static int builtin_env(struct job *dummy, struct jobSet *junk)
244} 291}
245 292
246/* built-in 'exec' handler */ 293/* built-in 'exec' handler */
247static int builtin_exec(struct job *cmd, struct jobSet *junk) 294static int builtin_exec(struct child_prog *child)
248{ 295{
249 if (cmd->progs[0].argv[1]) 296 if (child->argv[1] == NULL)
250 { 297 return EXIT_SUCCESS; /* Really? */
251 cmd->progs[0].argv++; 298 child->argv++;
252 execvp(cmd->progs[0].argv[0], cmd->progs[0].argv); 299 pseudo_exec(child);
253 error_msg_and_die("Exec to %s failed: %s\n", cmd->progs[0].argv[0], 300 /* never returns */
254 strerror(errno));
255 }
256 return EXIT_SUCCESS;
257} 301}
258 302
259/* built-in 'exit' handler */ 303/* built-in 'exit' handler */
260static int builtin_exit(struct job *cmd, struct jobSet *junk) 304static int builtin_exit(struct child_prog *child)
261{ 305{
262 if (!cmd->progs[0].argv[1] == 1) 306 if (child->argv[1] == NULL)
263 exit(EXIT_SUCCESS); 307 exit(EXIT_SUCCESS);
264 308
265 exit (atoi(cmd->progs[0].argv[1])); 309 exit (atoi(child->argv[1]));
266} 310}
267 311
268/* built-in 'fg' and 'bg' handler */ 312/* built-in 'fg' and 'bg' handler */
269static int builtin_fg_bg(struct job *cmd, struct jobSet *jobList) 313static int builtin_fg_bg(struct child_prog *child)
270{ 314{
271 int i, jobNum; 315 int i, jobNum;
272 struct job *job=NULL; 316 struct job *job=NULL;
317
273 318
274 if (!jobList->head) { 319 if (!child->argv[1] || child->argv[2]) {
275 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) {
276 error_msg("%s: exactly one argument is expected\n", 320 error_msg("%s: exactly one argument is expected\n",
277 cmd->progs[0].argv[0]); 321 child->argv[0]);
278 return EXIT_FAILURE; 322 return EXIT_FAILURE;
279 } 323 }
280 if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) { 324 if (sscanf(child->argv[1], "%%%d", &jobNum) != 1) {
281 error_msg("%s: bad argument '%s'\n", 325 error_msg("%s: bad argument '%s'\n",
282 cmd->progs[0].argv[0], cmd->progs[0].argv[1]); 326 child->argv[0], child->argv[1]);
283 return EXIT_FAILURE; 327 return EXIT_FAILURE;
284 for (job = jobList->head; job; job = job->next) { 328 }
285 if (job->jobId == jobNum) { 329 for (job = child->family->job_list->head; job; job = job->next) {
286 break; 330 if (job->jobid == jobNum) {
287 } 331 break;
288 } 332 }
289 } 333 }
290 } else {
291 job = jobList->head;
292 }
293 334
294 if (!job) { 335 if (!job) {
295 error_msg("%s: unknown job %d\n", 336 error_msg("%s: unknown job %d\n",
296 cmd->progs[0].argv[0], jobNum); 337 child->argv[0], jobNum);
297 return EXIT_FAILURE; 338 return EXIT_FAILURE;
298 } 339 }
299 340
300 if (*cmd->progs[0].argv[0] == 'f') { 341 if (*child->argv[0] == 'f') {
301 /* Make this job the foreground job */ 342 /* Make this job the foreground job */
302 /* suppress messages when run from /linuxrc mag@sysgo.de */ 343 /* suppress messages when run from /linuxrc mag@sysgo.de */
303 if (tcsetpgrp(0, job->pgrp) && errno != ENOTTY) 344 if (tcsetpgrp(0, job->pgrp) && errno != ENOTTY)
304 perror("tcsetpgrp"); 345 perror("tcsetpgrp");
305 jobList->fg = job; 346 child->family->job_list->fg = job;
306 } 347 }
307 348
308 /* Restart the processes in the job */ 349 /* Restart the processes in the job */
309 for (i = 0; i < job->numProgs; i++) 350 for (i = 0; i < job->num_progs; i++)
310 job->progs[i].isStopped = 0; 351 job->progs[i].is_stopped = 0;
311 352
312 kill(-job->pgrp, SIGCONT); 353 kill(-job->pgrp, SIGCONT);
313 354
314 job->stoppedProgs = 0; 355 job->stopped_progs = 0;
315 356
316 return EXIT_SUCCESS; 357 return EXIT_SUCCESS;
317} 358}
318 359
319/* built-in 'help' handler */ 360/* built-in 'help' handler */
320static int builtin_help(struct job *dummy, struct jobSet *junk) 361static int builtin_help(struct child_prog *dummy)
321{ 362{
322 struct builtInCommand *x; 363 struct built_in_command *x;
323 364
324 fprintf(stdout, "\nBuilt-in commands:\n"); 365 printf("\nBuilt-in commands:\n");
325 fprintf(stdout, "-------------------\n"); 366 printf("-------------------\n");
326 for (x = bltins; x->cmd; x++) { 367 for (x = bltins; x->cmd; x++) {
327 if (x->descr==NULL) 368 if (x->descr==NULL)
328 continue; 369 continue;
329 fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); 370 printf("%s\t%s\n", x->cmd, x->descr);
330 } 371 }
331 for (x = bltins_forking; x->cmd; x++) { 372 for (x = bltins_forking; x->cmd; x++) {
332 if (x->descr==NULL) 373 if (x->descr==NULL)
333 continue; 374 continue;
334 fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); 375 printf("%s\t%s\n", x->cmd, x->descr);
335 } 376 }
336 fprintf(stdout, "\n\n"); 377 printf("\n\n");
337 return EXIT_SUCCESS; 378 return EXIT_SUCCESS;
338} 379}
339 380
340/* built-in 'jobs' handler */ 381/* built-in 'jobs' handler */
341static int builtin_jobs(struct job *dummy, struct jobSet *jobList) 382static int builtin_jobs(struct child_prog *child)
342{ 383{
343 struct job *job; 384 struct job *job;
344 char *statusString; 385 char *status_string;
345 386
346 for (job = jobList->head; job; job = job->next) { 387 for (job = child->family->job_list->head; job; job = job->next) {
347 if (job->runningProgs == job->stoppedProgs) 388 if (job->running_progs == job->stopped_progs)
348 statusString = "Stopped"; 389 status_string = "Stopped";
349 else 390 else
350 statusString = "Running"; 391 status_string = "Running";
351 392
352 printf(JOB_STATUS_FORMAT, job->jobId, statusString, job->text); 393 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
353 } 394 }
354 return EXIT_SUCCESS; 395 return EXIT_SUCCESS;
355} 396}
356 397
357 398
358/* built-in 'pwd' handler */ 399/* built-in 'pwd' handler */
359static int builtin_pwd(struct job *dummy, struct jobSet *junk) 400static int builtin_pwd(struct child_prog *dummy)
360{ 401{
361 getcwd(cwd, sizeof(char)*MAX_LINE); 402 getcwd(cwd, MAX_LINE);
362 fprintf(stdout, "%s\n", cwd); 403 fprintf(stdout, "%s\n", cwd);
363 return EXIT_SUCCESS; 404 return EXIT_SUCCESS;
364} 405}
365 406
366/* built-in 'export VAR=value' handler */ 407/* built-in 'export VAR=value' handler */
367static int builtin_export(struct job *cmd, struct jobSet *junk) 408static int builtin_export(struct child_prog *child)
368{ 409{
369 int res; 410 int res;
370 411
371 if (!cmd->progs[0].argv[1] == 1) { 412 if (child->argv[1] == NULL) {
372 return (builtin_env(cmd, junk)); 413 return (builtin_env(child));
373 } 414 }
374 res = putenv(cmd->progs[0].argv[1]); 415 res = putenv(child->argv[1]);
375 if (res) 416 if (res)
376 fprintf(stdout, "export: %s\n", strerror(errno)); 417 fprintf(stderr, "export: %s\n", strerror(errno));
377 return (res); 418 return (res);
378} 419}
379 420
380/* built-in 'read VAR' handler */ 421/* built-in 'read VAR' handler */
381static int builtin_read(struct job *cmd, struct jobSet *junk) 422static int builtin_read(struct child_prog *child)
382{ 423{
383 int res = 0, len, newlen; 424 int res = 0, len, newlen;
384 char *s; 425 char *s;
385 char string[MAX_READ]; 426 char string[MAX_READ];
386 427
387 if (cmd->progs[0].argv[1]) { 428 if (child->argv[1]) {
388 /* argument (VAR) given: put "VAR=" into buffer */ 429 /* argument (VAR) given: put "VAR=" into buffer */
389 strcpy(string, cmd->progs[0].argv[1]); 430 strcpy(string, child->argv[1]);
390 len = strlen(string); 431 len = strlen(string);
391 string[len++] = '='; 432 string[len++] = '=';
392 string[len] = '\0'; 433 string[len] = '\0';
@@ -403,7 +444,7 @@ static int builtin_read(struct job *cmd, struct jobSet *junk)
403 if((s = strdup(string))) 444 if((s = strdup(string)))
404 res = putenv(s); 445 res = putenv(s);
405 if (res) 446 if (res)
406 fprintf(stdout, "read: %s\n", strerror(errno)); 447 fprintf(stderr, "read: %s\n", strerror(errno));
407 } 448 }
408 else 449 else
409 fgets(string, sizeof(string), stdin); 450 fgets(string, sizeof(string), stdin);
@@ -413,111 +454,112 @@ static int builtin_read(struct job *cmd, struct jobSet *junk)
413 454
414#ifdef BB_FEATURE_SH_IF_EXPRESSIONS 455#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
415/* Built-in handler for 'if' commands */ 456/* Built-in handler for 'if' commands */
416static int builtin_if(struct job *cmd, struct jobSet *jobList) 457static int builtin_if(struct child_prog *child)
417{ 458{
459 struct job *cmd = child->family;
418 int status; 460 int status;
419 char* charptr1=cmd->text+3; /* skip over the leading 'if ' */ 461 char* charptr1=cmd->text+3; /* skip over the leading 'if ' */
420 462
421 /* Now run the 'if' command */ 463 /* Now run the 'if' command */
422 status=strlen(charptr1); 464 debug_printf( "job=%p entering builtin_if ('%s')-- context=%d\n", cmd, charptr1, cmd->job_context);
423 local_pending_command = xmalloc(status+1); 465 status = run_command_predicate(charptr1);
424 strncpy(local_pending_command, charptr1, status); 466 debug_printf( "if test returned ");
425 local_pending_command[status]='\0';
426 debug_printf(stderr, "'if' now testing '%s'\n", local_pending_command);
427 status = busy_loop(NULL); /* Frees local_pending_command */
428 debug_printf(stderr, "if test returned ");
429 if (status == 0) { 467 if (status == 0) {
430 debug_printf(stderr, "TRUE\n"); 468 debug_printf( "TRUE\n");
431 cmd->jobContext |= IF_TRUE_CONTEXT; 469 cmd->job_context |= IF_TRUE_CONTEXT;
432 } else { 470 } else {
433 debug_printf(stderr, "FALSE\n"); 471 debug_printf( "FALSE\n");
434 cmd->jobContext |= IF_FALSE_CONTEXT; 472 cmd->job_context |= IF_FALSE_CONTEXT;
435 } 473 }
474 debug_printf("job=%p builtin_if set job context to %x\n", cmd, cmd->job_context);
475 shell_context++;
436 476
437 return status; 477 return status;
438} 478}
439 479
440/* Built-in handler for 'then' (part of the 'if' command) */ 480/* Built-in handler for 'then' (part of the 'if' command) */
441static int builtin_then(struct job *cmd, struct jobSet *junk) 481static int builtin_then(struct child_prog *child)
442{ 482{
443 int status; 483 struct job *cmd = child->family;
444 char* charptr1=cmd->text+5; /* skip over the leading 'then ' */ 484 char* charptr1=cmd->text+5; /* skip over the leading 'then ' */
445 485
446 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { 486 debug_printf( "job=%p entering builtin_then ('%s')-- context=%d\n", cmd, charptr1, cmd->job_context);
447 error_msg("unexpected token `then'\n"); 487 if (! (cmd->job_context & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
488 shell_context = 0; /* Reset the shell's context on an error */
489 error_msg("%s `then'\n", syntax_err);
448 return EXIT_FAILURE; 490 return EXIT_FAILURE;
449 } 491 }
492
493 cmd->job_context |= THEN_EXP_CONTEXT;
494 debug_printf("job=%p builtin_then set job context to %x\n", cmd, cmd->job_context);
495
450 /* If the if result was FALSE, skip the 'then' stuff */ 496 /* If the if result was FALSE, skip the 'then' stuff */
451 if (cmd->jobContext & IF_FALSE_CONTEXT) { 497 if (cmd->job_context & IF_FALSE_CONTEXT) {
452 return EXIT_SUCCESS; 498 return EXIT_SUCCESS;
453 } 499 }
454 500
455 cmd->jobContext |= THEN_EXP_CONTEXT; 501 /* Seems the if result was TRUE, so run the 'then' command */
456 //printf("Hit an then -- jobContext=%d\n", cmd->jobContext); 502 debug_printf( "'then' now running '%s'\n", charptr1);
457 503
458 /* Now run the 'then' command */ 504 return(run_command_predicate(charptr1));
459 status=strlen(charptr1);
460 local_pending_command = xmalloc(status+1);
461 strncpy(local_pending_command, charptr1, status);
462 local_pending_command[status]='\0';
463 debug_printf(stderr, "'then' now running '%s'\n", charptr1);
464 return( busy_loop(NULL));
465} 505}
466 506
467/* Built-in handler for 'else' (part of the 'if' command) */ 507/* Built-in handler for 'else' (part of the 'if' command) */
468static int builtin_else(struct job *cmd, struct jobSet *junk) 508static int builtin_else(struct child_prog *child)
469{ 509{
470 int status; 510 struct job *cmd = child->family;
471 char* charptr1=cmd->text+5; /* skip over the leading 'else ' */ 511 char* charptr1=cmd->text+5; /* skip over the leading 'else ' */
472 512
473 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { 513 debug_printf( "job=%p entering builtin_else ('%s')-- context=%d\n", cmd, charptr1, cmd->job_context);
474 error_msg("unexpected token `else'\n"); 514
515 if (! (cmd->job_context & THEN_EXP_CONTEXT)) {
516 shell_context = 0; /* Reset the shell's context on an error */
517 error_msg("%s `else'\n", syntax_err);
475 return EXIT_FAILURE; 518 return EXIT_FAILURE;
476 } 519 }
477 /* If the if result was TRUE, skip the 'else' stuff */ 520 /* If the if result was TRUE, skip the 'else' stuff */
478 if (cmd->jobContext & IF_TRUE_CONTEXT) { 521 if (cmd->job_context & IF_TRUE_CONTEXT) {
479 return EXIT_SUCCESS; 522 return EXIT_SUCCESS;
480 } 523 }
481 524
482 cmd->jobContext |= ELSE_EXP_CONTEXT; 525 cmd->job_context |= ELSE_EXP_CONTEXT;
483 //printf("Hit an else -- jobContext=%d\n", cmd->jobContext); 526 debug_printf("job=%p builtin_else set job context to %x\n", child->family, cmd->job_context);
484 527
485 /* Now run the 'else' command */ 528 /* Now run the 'else' command */
486 status=strlen(charptr1); 529 debug_printf( "'else' now running '%s'\n", charptr1);
487 local_pending_command = xmalloc(status+1); 530 return(run_command_predicate(charptr1));
488 strncpy(local_pending_command, charptr1, status);
489 local_pending_command[status]='\0';
490 debug_printf(stderr, "'else' now running '%s'\n", charptr1);
491 return( busy_loop(NULL));
492} 531}
493 532
494/* Built-in handler for 'fi' (part of the 'if' command) */ 533/* Built-in handler for 'fi' (part of the 'if' command) */
495static int builtin_fi(struct job *cmd, struct jobSet *junk) 534static int builtin_fi(struct child_prog *child)
496{ 535{
497 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { 536 struct job *cmd = child->family;
498 error_msg("unexpected token `fi'\n"); 537 debug_printf( "job=%p entering builtin_fi ('%s')-- context=%d\n", cmd, "", cmd->job_context);
538 if (! (cmd->job_context & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
539 shell_context = 0; /* Reset the shell's context on an error */
540 error_msg("%s `fi'\n", syntax_err);
499 return EXIT_FAILURE; 541 return EXIT_FAILURE;
500 } 542 }
501 /* Clear out the if and then context bits */ 543 /* Clear out the if and then context bits */
502 cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT); 544 cmd->job_context &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT);
503 debug_printf(stderr, "Hit an fi -- jobContext=%d\n", cmd->jobContext); 545 debug_printf("job=%p builtin_fi set job context to %x\n", cmd, cmd->job_context);
546 shell_context--;
504 return EXIT_SUCCESS; 547 return EXIT_SUCCESS;
505} 548}
506#endif 549#endif
507 550
508/* Built-in '.' handler (read-in and execute commands from file) */ 551/* Built-in '.' handler (read-in and execute commands from file) */
509static int builtin_source(struct job *cmd, struct jobSet *junk) 552static int builtin_source(struct child_prog *child)
510{ 553{
511 FILE *input; 554 FILE *input;
512 int status; 555 int status;
513 556
514 if (!cmd->progs[0].argv[1] == 1) 557 if (child->argv[1] == NULL)
515 return EXIT_FAILURE; 558 return EXIT_FAILURE;
516 559
517 input = fopen(cmd->progs[0].argv[1], "r"); 560 input = fopen(child->argv[1], "r");
518 if (!input) { 561 if (!input) {
519 fprintf(stdout, "Couldn't open file '%s'\n", 562 fprintf(stdout, "Couldn't open file '%s'\n", child->argv[1]);
520 cmd->progs[0].argv[1]);
521 return EXIT_FAILURE; 563 return EXIT_FAILURE;
522 } 564 }
523 565
@@ -528,48 +570,65 @@ static int builtin_source(struct job *cmd, struct jobSet *junk)
528} 570}
529 571
530/* built-in 'unset VAR' handler */ 572/* built-in 'unset VAR' handler */
531static int builtin_unset(struct job *cmd, struct jobSet *junk) 573static int builtin_unset(struct child_prog *child)
532{ 574{
533 if (!cmd->progs[0].argv[1] == 1) { 575 if (child->argv[1] == NULL) {
534 fprintf(stdout, "unset: parameter required.\n"); 576 fprintf(stdout, "unset: parameter required.\n");
535 return EXIT_FAILURE; 577 return EXIT_FAILURE;
536 } 578 }
537 unsetenv(cmd->progs[0].argv[1]); 579 unsetenv(child->argv[1]);
538 return EXIT_SUCCESS; 580 return EXIT_SUCCESS;
539} 581}
540 582
583/* currently used by if/then/else.
584 * Needlessly (?) forks and reparses the command line.
585 * But pseudo_exec on the pre-parsed args doesn't have the
586 * "fork, stick around until the child exits, and find it's return code"
587 * functionality. The fork is not needed if the predicate is
588 * non-forking builtin, and maybe not even if it's a forking builtin.
589 * applets pretty clearly need the fork.
590 */
591static int run_command_predicate(char *cmd)
592{
593 int n=strlen(cmd);
594 local_pending_command = xmalloc(n+1);
595 strncpy(local_pending_command, cmd, n);
596 local_pending_command[n]='\0';
597 return( busy_loop(NULL));
598}
599
541/* free up all memory from a job */ 600/* free up all memory from a job */
542static void freeJob(struct job *cmd) 601static void free_job(struct job *cmd)
543{ 602{
544 int i; 603 int i;
545 604
546 for (i = 0; i < cmd->numProgs; i++) { 605 for (i = 0; i < cmd->num_progs; i++) {
547 free(cmd->progs[i].argv); 606 free(cmd->progs[i].argv);
548 if (cmd->progs[i].redirections) 607 if (cmd->progs[i].redirects)
549 free(cmd->progs[i].redirections); 608 free(cmd->progs[i].redirects);
550 if (cmd->progs[i].freeGlob) 609 if (cmd->progs[i].free_glob)
551 globfree(&cmd->progs[i].globResult); 610 globfree(&cmd->progs[i].glob_result);
552 } 611 }
553 free(cmd->progs); 612 free(cmd->progs);
554 if (cmd->text) 613 if (cmd->text)
555 free(cmd->text); 614 free(cmd->text);
556 free(cmd->cmdBuf); 615 free(cmd->cmdbuf);
557 memset(cmd, 0, sizeof(struct job)); 616 memset(cmd, 0, sizeof(struct job));
558} 617}
559 618
560/* remove a job from the jobList */ 619/* remove a job from the job_list */
561static void removeJob(struct jobSet *jobList, struct job *job) 620static void remove_job(struct jobset *job_list, struct job *job)
562{ 621{
563 struct job *prevJob; 622 struct job *prevjob;
564 623
565 freeJob(job); 624 free_job(job);
566 if (job == jobList->head) { 625 if (job == job_list->head) {
567 jobList->head = job->next; 626 job_list->head = job->next;
568 } else { 627 } else {
569 prevJob = jobList->head; 628 prevjob = job_list->head;
570 while (prevJob->next != job) 629 while (prevjob->next != job)
571 prevJob = prevJob->next; 630 prevjob = prevjob->next;
572 prevJob->next = job->next; 631 prevjob->next = job->next;
573 } 632 }
574 633
575 free(job); 634 free(job);
@@ -577,19 +636,19 @@ static void removeJob(struct jobSet *jobList, struct job *job)
577 636
578/* Checks to see if any background processes have exited -- if they 637/* Checks to see if any background processes have exited -- if they
579 have, figure out why and see if a job has completed */ 638 have, figure out why and see if a job has completed */
580static void checkJobs(struct jobSet *jobList) 639static void checkjobs(struct jobset *job_list)
581{ 640{
582 struct job *job; 641 struct job *job;
583 pid_t childpid; 642 pid_t childpid;
584 int status; 643 int status;
585 int progNum = 0; 644 int prognum = 0;
586 645
587 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { 646 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
588 for (job = jobList->head; job; job = job->next) { 647 for (job = job_list->head; job; job = job->next) {
589 progNum = 0; 648 prognum = 0;
590 while (progNum < job->numProgs && 649 while (prognum < job->num_progs &&
591 job->progs[progNum].pid != childpid) progNum++; 650 job->progs[prognum].pid != childpid) prognum++;
592 if (progNum < job->numProgs) 651 if (prognum < job->num_progs)
593 break; 652 break;
594 } 653 }
595 654
@@ -599,20 +658,20 @@ static void checkJobs(struct jobSet *jobList)
599 658
600 if (WIFEXITED(status) || WIFSIGNALED(status)) { 659 if (WIFEXITED(status) || WIFSIGNALED(status)) {
601 /* child exited */ 660 /* child exited */
602 job->runningProgs--; 661 job->running_progs--;
603 job->progs[progNum].pid = 0; 662 job->progs[prognum].pid = 0;
604 663
605 if (!job->runningProgs) { 664 if (!job->running_progs) {
606 printf(JOB_STATUS_FORMAT, job->jobId, "Done", job->text); 665 printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text);
607 removeJob(jobList, job); 666 remove_job(job_list, job);
608 } 667 }
609 } else { 668 } else {
610 /* child stopped */ 669 /* child stopped */
611 job->stoppedProgs++; 670 job->stopped_progs++;
612 job->progs[progNum].isStopped = 1; 671 job->progs[prognum].is_stopped = 1;
613 672
614 if (job->stoppedProgs == job->numProgs) { 673 if (job->stopped_progs == job->num_progs) {
615 printf(JOB_STATUS_FORMAT, job->jobId, "Stopped", 674 printf(JOB_STATUS_FORMAT, job->jobid, "Stopped",
616 job->text); 675 job->text);
617 } 676 }
618 } 677 }
@@ -622,14 +681,14 @@ static void checkJobs(struct jobSet *jobList)
622 perror("waitpid"); 681 perror("waitpid");
623} 682}
624 683
625static int setupRedirections(struct childProgram *prog) 684static int setup_redirects(struct child_prog *prog)
626{ 685{
627 int i; 686 int i;
628 int openfd; 687 int openfd;
629 int mode = O_RDONLY; 688 int mode = O_RDONLY;
630 struct redirectionSpecifier *redir = prog->redirections; 689 struct redir_struct *redir = prog->redirects;
631 690
632 for (i = 0; i < prog->numRedirections; i++, redir++) { 691 for (i = 0; i < prog->num_redirects; i++, redir++) {
633 switch (redir->type) { 692 switch (redir->type) {
634 case REDIRECT_INPUT: 693 case REDIRECT_INPUT:
635 mode = O_RDONLY; 694 mode = O_RDONLY;
@@ -661,7 +720,7 @@ static int setupRedirections(struct childProgram *prog)
661} 720}
662 721
663 722
664static int getCommand(FILE * source, char *command) 723static int get_command(FILE * source, char *command)
665{ 724{
666 char user[9],buf[255],*s; 725 char user[9],buf[255],*s;
667 726
@@ -676,15 +735,20 @@ static int getCommand(FILE * source, char *command)
676 return 1; 735 return 1;
677 } 736 }
678 737
679 /* get User Name and setup prompt */ 738 if (shell_context == 0) {
680 strcpy(prompt,( geteuid() != 0 ) ? "$ ":"# "); 739 /* get User Name and setup prompt */
681 my_getpwuid(user, geteuid()); 740 strcpy(prompt,( geteuid() != 0 ) ? "$ ":"# ");
682 741 my_getpwuid(user, geteuid());
683 /* get HostName */ 742
684 gethostname(buf, 255); 743 /* get HostName */
685 s = strchr(buf, '.'); 744 gethostname(buf, 255);
686 if (s) 745 s = strchr(buf, '.');
687 *s = 0; 746 if (s) {
747 *s = 0;
748 }
749 } else {
750 strcpy(prompt,"> ");
751 }
688 752
689 if (source == stdin) { 753 if (source == stdin) {
690#ifdef BB_FEATURE_SH_COMMAND_EDITING 754#ifdef BB_FEATURE_SH_COMMAND_EDITING
@@ -698,14 +762,24 @@ static int getCommand(FILE * source, char *command)
698 */ 762 */
699 cmdedit_init(); 763 cmdedit_init();
700 signal(SIGWINCH, win_changed); 764 signal(SIGWINCH, win_changed);
701 len=fprintf(stdout, "[%s@%s %s]%s", user, buf, 765 debug_printf( "in get_command() -- job_context=%d\n", shell_context);
702 get_last_path_component(cwd), prompt); 766 fflush(stdout);
767 if (shell_context == 0) {
768 len=fprintf(stdout, "[%s@%s %s]%s", user, buf,
769 get_last_path_component(cwd), prompt);
770 } else {
771 len=fprintf(stdout, "%s", prompt);
772 }
703 fflush(stdout); 773 fflush(stdout);
704 promptStr=(char*)xmalloc(sizeof(char)*(len+1)); 774 prompt_str=(char*)xmalloc(sizeof(char)*(len+1));
705 sprintf(promptStr, "[%s@%s %s]%s", user, buf, 775 if (shell_context == 0) {
706 get_last_path_component(cwd), prompt); 776 sprintf(prompt_str, "[%s@%s %s]%s", user, buf,
707 cmdedit_read_input(promptStr, command); 777 get_last_path_component(cwd), prompt);
708 free( promptStr); 778 } else {
779 sprintf(prompt_str, "%s", prompt);
780 }
781 cmdedit_read_input(prompt_str, command);
782 free( prompt_str);
709 cmdedit_terminate(); 783 cmdedit_terminate();
710 signal(SIGWINCH, SIG_DFL); 784 signal(SIGWINCH, SIG_DFL);
711 return 0; 785 return 0;
@@ -756,21 +830,21 @@ static char* itoa(register int i)
756} 830}
757#endif 831#endif
758 832
759static void globLastArgument(struct childProgram *prog, int *argcPtr, 833static void expand_argument(struct child_prog *prog, int *argcPtr,
760 int *argcAllocedPtr) 834 int *argv_alloced_ptr)
761{ 835{
762 int argc_l = *argcPtr; 836 int argc_l = *argcPtr;
763 int argcAlloced = *argcAllocedPtr; 837 int argv_alloced = *argv_alloced_ptr;
764 int rc; 838 int rc;
765 int flags; 839 int flags;
766 int i; 840 int i;
767 char *src, *dst, *var; 841 char *src, *dst, *var;
768 842
769 if (argc_l > 1) { /* cmd->globResult is already initialized */ 843 if (argc_l > 1) { /* cmd->glob_result is already initialized */
770 flags = GLOB_APPEND; 844 flags = GLOB_APPEND;
771 i = prog->globResult.gl_pathc; 845 i = prog->glob_result.gl_pathc;
772 } else { 846 } else {
773 prog->freeGlob = 1; 847 prog->free_glob = 1;
774 flags = 0; 848 flags = 0;
775 i = 0; 849 i = 0;
776 } 850 }
@@ -783,7 +857,7 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
783 else { 857 else {
784 switch(*(prog->argv[argc_l - 1] + 1)) { 858 switch(*(prog->argv[argc_l - 1] + 1)) {
785 case '?': 859 case '?':
786 prog->argv[argc_l - 1] = itoa(lastReturnCode); 860 prog->argv[argc_l - 1] = itoa(last_return_code);
787 break; 861 break;
788 case '$': 862 case '$':
789 prog->argv[argc_l - 1] = itoa(getpid()); 863 prog->argv[argc_l - 1] = itoa(getpid());
@@ -792,10 +866,10 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
792 prog->argv[argc_l - 1] = itoa(argc-1); 866 prog->argv[argc_l - 1] = itoa(argc-1);
793 break; 867 break;
794 case '!': 868 case '!':
795 if (lastBgPid==-1) 869 if (last_bg_pid==-1)
796 *(prog->argv[argc_l - 1])='\0'; 870 *(prog->argv[argc_l - 1])='\0';
797 else 871 else
798 prog->argv[argc_l - 1] = itoa(lastBgPid); 872 prog->argv[argc_l - 1] = itoa(last_bg_pid);
799 break; 873 break;
800 case '0':case '1':case '2':case '3':case '4': 874 case '0':case '1':case '2':case '3':case '4':
801 case '5':case '6':case '7':case '8':case '9': 875 case '5':case '6':case '7':case '8':case '9':
@@ -814,14 +888,14 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
814 } 888 }
815 889
816 if (strpbrk(prog->argv[argc_l - 1],"*[]?")!= NULL){ 890 if (strpbrk(prog->argv[argc_l - 1],"*[]?")!= NULL){
817 rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult); 891 rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->glob_result);
818 if (rc == GLOB_NOSPACE) { 892 if (rc == GLOB_NOSPACE) {
819 error_msg("out of space during glob operation\n"); 893 error_msg("out of space during glob operation\n");
820 return; 894 return;
821 } else if (rc == GLOB_NOMATCH || 895 } else if (rc == GLOB_NOMATCH ||
822 (!rc && (prog->globResult.gl_pathc - i) == 1 && 896 (!rc && (prog->glob_result.gl_pathc - i) == 1 &&
823 strcmp(prog->argv[argc_l - 1], 897 strcmp(prog->argv[argc_l - 1],
824 prog->globResult.gl_pathv[i]) == 0)) { 898 prog->glob_result.gl_pathv[i]) == 0)) {
825 /* we need to remove whatever \ quoting is still present */ 899 /* we need to remove whatever \ quoting is still present */
826 src = dst = prog->argv[argc_l - 1]; 900 src = dst = prog->argv[argc_l - 1];
827 while (*src) { 901 while (*src) {
@@ -835,11 +909,11 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
835 } 909 }
836 *dst = '\0'; 910 *dst = '\0';
837 } else if (!rc) { 911 } else if (!rc) {
838 argcAlloced += (prog->globResult.gl_pathc - i); 912 argv_alloced += (prog->glob_result.gl_pathc - i);
839 prog->argv = xrealloc(prog->argv, argcAlloced * sizeof(*prog->argv)); 913 prog->argv = xrealloc(prog->argv, argv_alloced * sizeof(*prog->argv));
840 memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i, 914 memcpy(prog->argv + (argc_l - 1), prog->glob_result.gl_pathv + i,
841 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); 915 sizeof(*(prog->argv)) * (prog->glob_result.gl_pathc - i));
842 argc_l += (prog->globResult.gl_pathc - i - 1); 916 argc_l += (prog->glob_result.gl_pathc - i - 1);
843 } 917 }
844 }else{ 918 }else{
845 src = dst = prog->argv[argc_l - 1]; 919 src = dst = prog->argv[argc_l - 1];
@@ -854,68 +928,69 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
854 } 928 }
855 *dst = '\0'; 929 *dst = '\0';
856 930
857 prog->globResult.gl_pathc=0; 931 prog->glob_result.gl_pathc=0;
858 if (flags==0) 932 if (flags==0)
859 prog->globResult.gl_pathv=NULL; 933 prog->glob_result.gl_pathv=NULL;
860 } 934 }
861 *argcAllocedPtr = argcAlloced; 935 *argv_alloced_ptr = argv_alloced;
862 *argcPtr = argc_l; 936 *argcPtr = argc_l;
863} 937}
864 938
865/* Return cmd->numProgs as 0 if no command is present (e.g. an empty 939/* Return cmd->num_progs as 0 if no command is present (e.g. an empty
866 line). If a valid command is found, commandPtr is set to point to 940 line). If a valid command is found, command_ptr is set to point to
867 the beginning of the next command (if the original command had more 941 the beginning of the next command (if the original command had more
868 then one job associated with it) or NULL if no more commands are 942 then one job associated with it) or NULL if no more commands are
869 present. */ 943 present. */
870static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg) 944static int parse_command(char **command_ptr, struct job *job, int *inbg)
871{ 945{
872 char *command; 946 char *command;
873 char *returnCommand = NULL; 947 char *return_command = NULL;
874 char *src, *buf, *chptr; 948 char *src, *buf, *chptr;
875 int argc_l = 0; 949 int argc_l = 0;
876 int done = 0; 950 int done = 0;
877 int argvAlloced; 951 int argv_alloced;
878 int i; 952 int i;
879 char quote = '\0'; 953 char quote = '\0';
880 int count; 954 int count;
881 struct childProgram *prog; 955 struct child_prog *prog;
882 956
883 /* skip leading white space */ 957 /* skip leading white space */
884 while (**commandPtr && isspace(**commandPtr)) 958 while (**command_ptr && isspace(**command_ptr))
885 (*commandPtr)++; 959 (*command_ptr)++;
886 960
887 /* this handles empty lines or leading '#' characters */ 961 /* this handles empty lines or leading '#' characters */
888 if (!**commandPtr || (**commandPtr == '#')) { 962 if (!**command_ptr || (**command_ptr == '#')) {
889 job->numProgs=0; 963 job->num_progs=0;
890 return 0; 964 return 0;
891 } 965 }
892 966
893 *inBg = 0; 967 *inbg = 0;
894 job->numProgs = 1; 968 job->num_progs = 1;
895 job->progs = xmalloc(sizeof(*job->progs)); 969 job->progs = xmalloc(sizeof(*job->progs));
896 970
897 /* We set the argv elements to point inside of this string. The 971 /* We set the argv elements to point inside of this string. The
898 memory is freed by freeJob(). Allocate twice the original 972 memory is freed by free_job(). Allocate twice the original
899 length in case we need to quote every single character. 973 length in case we need to quote every single character.
900 974
901 Getting clean memory relieves us of the task of NULL 975 Getting clean memory relieves us of the task of NULL
902 terminating things and makes the rest of this look a bit 976 terminating things and makes the rest of this look a bit
903 cleaner (though it is, admittedly, a tad less efficient) */ 977 cleaner (though it is, admittedly, a tad less efficient) */
904 job->cmdBuf = command = xcalloc(2*strlen(*commandPtr) + 1, sizeof(char)); 978 job->cmdbuf = command = xcalloc(2*strlen(*command_ptr) + 1, sizeof(char));
905 job->text = NULL; 979 job->text = NULL;
906 980
907 prog = job->progs; 981 prog = job->progs;
908 prog->numRedirections = 0; 982 prog->num_redirects = 0;
909 prog->redirections = NULL; 983 prog->redirects = NULL;
910 prog->freeGlob = 0; 984 prog->free_glob = 0;
911 prog->isStopped = 0; 985 prog->is_stopped = 0;
986 prog->family = job;
912 987
913 argvAlloced = 5; 988 argv_alloced = 5;
914 prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced); 989 prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
915 prog->argv[0] = job->cmdBuf; 990 prog->argv[0] = job->cmdbuf;
916 991
917 buf = command; 992 buf = command;
918 src = *commandPtr; 993 src = *command_ptr;
919 while (*src && !done) { 994 while (*src && !done) {
920 if (quote == *src) { 995 if (quote == *src) {
921 quote = '\0'; 996 quote = '\0';
@@ -924,7 +999,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
924 src++; 999 src++;
925 if (!*src) { 1000 if (!*src) {
926 error_msg("character expected after \\\n"); 1001 error_msg("character expected after \\\n");
927 freeJob(job); 1002 free_job(job);
928 return 1; 1003 return 1;
929 } 1004 }
930 1005
@@ -940,13 +1015,13 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
940 if (*prog->argv[argc_l]) { 1015 if (*prog->argv[argc_l]) {
941 buf++, argc_l++; 1016 buf++, argc_l++;
942 /* +1 here leaves room for the NULL which ends argv */ 1017 /* +1 here leaves room for the NULL which ends argv */
943 if ((argc_l + 1) == argvAlloced) { 1018 if ((argc_l + 1) == argv_alloced) {
944 argvAlloced += 5; 1019 argv_alloced += 5;
945 prog->argv = xrealloc(prog->argv, 1020 prog->argv = xrealloc(prog->argv,
946 sizeof(*prog->argv) * 1021 sizeof(*prog->argv) *
947 argvAlloced); 1022 argv_alloced);
948 } 1023 }
949 globLastArgument(prog, &argc_l, &argvAlloced); 1024 expand_argument(prog, &argc_l, &argv_alloced);
950 prog->argv[argc_l] = buf; 1025 prog->argv[argc_l] = buf;
951 } 1026 }
952 } else 1027 } else
@@ -963,42 +1038,42 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
963 done = 1; 1038 done = 1;
964 break; 1039 break;
965 1040
966 case '>': /* redirections */ 1041 case '>': /* redirects */
967 case '<': 1042 case '<':
968 i = prog->numRedirections++; 1043 i = prog->num_redirects++;
969 prog->redirections = xrealloc(prog->redirections, 1044 prog->redirects = xrealloc(prog->redirects,
970 sizeof(*prog->redirections) * 1045 sizeof(*prog->redirects) *
971 (i + 1)); 1046 (i + 1));
972 1047
973 prog->redirections[i].fd = -1; 1048 prog->redirects[i].fd = -1;
974 if (buf != prog->argv[argc_l]) { 1049 if (buf != prog->argv[argc_l]) {
975 /* the stuff before this character may be the file number 1050 /* the stuff before this character may be the file number
976 being redirected */ 1051 being redirected */
977 prog->redirections[i].fd = 1052 prog->redirects[i].fd =
978 strtol(prog->argv[argc_l], &chptr, 10); 1053 strtol(prog->argv[argc_l], &chptr, 10);
979 1054
980 if (*chptr && *prog->argv[argc_l]) { 1055 if (*chptr && *prog->argv[argc_l]) {
981 buf++, argc_l++; 1056 buf++, argc_l++;
982 globLastArgument(prog, &argc_l, &argvAlloced); 1057 expand_argument(prog, &argc_l, &argv_alloced);
983 prog->argv[argc_l] = buf; 1058 prog->argv[argc_l] = buf;
984 } 1059 }
985 } 1060 }
986 1061
987 if (prog->redirections[i].fd == -1) { 1062 if (prog->redirects[i].fd == -1) {
988 if (*src == '>') 1063 if (*src == '>')
989 prog->redirections[i].fd = 1; 1064 prog->redirects[i].fd = 1;
990 else 1065 else
991 prog->redirections[i].fd = 0; 1066 prog->redirects[i].fd = 0;
992 } 1067 }
993 1068
994 if (*src++ == '>') { 1069 if (*src++ == '>') {
995 if (*src == '>') 1070 if (*src == '>')
996 prog->redirections[i].type = 1071 prog->redirects[i].type =
997 REDIRECT_APPEND, src++; 1072 REDIRECT_APPEND, src++;
998 else 1073 else
999 prog->redirections[i].type = REDIRECT_OVERWRITE; 1074 prog->redirects[i].type = REDIRECT_OVERWRITE;
1000 } else { 1075 } else {
1001 prog->redirections[i].type = REDIRECT_INPUT; 1076 prog->redirects[i].type = REDIRECT_INPUT;
1002 } 1077 }
1003 1078
1004 /* This isn't POSIX sh compliant. Oh well. */ 1079 /* This isn't POSIX sh compliant. Oh well. */
@@ -1008,12 +1083,12 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1008 1083
1009 if (!*chptr) { 1084 if (!*chptr) {
1010 error_msg("file name expected after %c\n", *src); 1085 error_msg("file name expected after %c\n", *src);
1011 freeJob(job); 1086 free_job(job);
1012 job->numProgs=0; 1087 job->num_progs=0;
1013 return 1; 1088 return 1;
1014 } 1089 }
1015 1090
1016 prog->redirections[i].filename = buf; 1091 prog->redirects[i].filename = buf;
1017 while (*chptr && !isspace(*chptr)) 1092 while (*chptr && !isspace(*chptr))
1018 *buf++ = *chptr++; 1093 *buf++ = *chptr++;
1019 1094
@@ -1027,25 +1102,26 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1027 argc_l++; 1102 argc_l++;
1028 if (!argc_l) { 1103 if (!argc_l) {
1029 error_msg("empty command in pipe\n"); 1104 error_msg("empty command in pipe\n");
1030 freeJob(job); 1105 free_job(job);
1031 job->numProgs=0; 1106 job->num_progs=0;
1032 return 1; 1107 return 1;
1033 } 1108 }
1034 prog->argv[argc_l] = NULL; 1109 prog->argv[argc_l] = NULL;
1035 1110
1036 /* and start the next */ 1111 /* and start the next */
1037 job->numProgs++; 1112 job->num_progs++;
1038 job->progs = xrealloc(job->progs, 1113 job->progs = xrealloc(job->progs,
1039 sizeof(*job->progs) * job->numProgs); 1114 sizeof(*job->progs) * job->num_progs);
1040 prog = job->progs + (job->numProgs - 1); 1115 prog = job->progs + (job->num_progs - 1);
1041 prog->numRedirections = 0; 1116 prog->num_redirects = 0;
1042 prog->redirections = NULL; 1117 prog->redirects = NULL;
1043 prog->freeGlob = 0; 1118 prog->free_glob = 0;
1044 prog->isStopped = 0; 1119 prog->is_stopped = 0;
1120 prog->family = job;
1045 argc_l = 0; 1121 argc_l = 0;
1046 1122
1047 argvAlloced = 5; 1123 argv_alloced = 5;
1048 prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced); 1124 prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
1049 prog->argv[0] = ++buf; 1125 prog->argv[0] = ++buf;
1050 1126
1051 src++; 1127 src++;
@@ -1054,8 +1130,8 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1054 1130
1055 if (!*src) { 1131 if (!*src) {
1056 error_msg("empty command in pipe\n"); 1132 error_msg("empty command in pipe\n");
1057 freeJob(job); 1133 free_job(job);
1058 job->numProgs=0; 1134 job->num_progs=0;
1059 return 1; 1135 return 1;
1060 } 1136 }
1061 src--; /* we'll ++ it at the end of the loop */ 1137 src--; /* we'll ++ it at the end of the loop */
@@ -1063,10 +1139,10 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1063 break; 1139 break;
1064 1140
1065 case '&': /* background */ 1141 case '&': /* background */
1066 *inBg = 1; 1142 *inbg = 1;
1067 case ';': /* multiple commands */ 1143 case ';': /* multiple commands */
1068 done = 1; 1144 done = 1;
1069 returnCommand = *commandPtr + (src - *commandPtr) + 1; 1145 return_command = *command_ptr + (src - *command_ptr) + 1;
1070 break; 1146 break;
1071 1147
1072#ifdef BB_FEATURE_SH_BACKTICKS 1148#ifdef BB_FEATURE_SH_BACKTICKS
@@ -1075,15 +1151,15 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1075 { 1151 {
1076 char* charptr1=NULL, *charptr2; 1152 char* charptr1=NULL, *charptr2;
1077 char* ptr=NULL; 1153 char* ptr=NULL;
1078 struct job *newJob; 1154 struct job *newjob;
1079 struct jobSet njobList = { NULL, NULL }; 1155 struct jobset njob_list = { NULL, NULL };
1080 int pipefd[2]; 1156 int pipefd[2];
1081 int size; 1157 int size;
1082 1158
1083 ptr=strchr(++src, '`'); 1159 ptr=strchr(++src, '`');
1084 if (ptr==NULL) { 1160 if (ptr==NULL) {
1085 fprintf(stderr, "Unmatched '`' in command\n"); 1161 fprintf(stderr, "Unmatched '`' in command\n");
1086 freeJob(job); 1162 free_job(job);
1087 return 1; 1163 return 1;
1088 } 1164 }
1089 1165
@@ -1091,15 +1167,17 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1091 charptr1 = charptr2 = xmalloc(1+ptr-src); 1167 charptr1 = charptr2 = xmalloc(1+ptr-src);
1092 memcpy(charptr1, src, ptr-src); 1168 memcpy(charptr1, src, ptr-src);
1093 charptr1[ptr-src] = '\0'; 1169 charptr1[ptr-src] = '\0';
1094 newJob = xmalloc(sizeof(struct job)); 1170 newjob = xmalloc(sizeof(struct job));
1171 newjob->job_list = &njob_list;
1095 /* Now parse and run the backticked command */ 1172 /* Now parse and run the backticked command */
1096 if (!parseCommand(&charptr1, newJob, &njobList, inBg) 1173 if (!parse_command(&charptr1, newjob, inbg)
1097 && newJob->numProgs) { 1174 && newjob->num_progs) {
1098 pipe(pipefd); 1175 pipe(pipefd);
1099 runCommand(newJob, &njobList, 0, pipefd); 1176 run_command(newjob, 0, pipefd);
1100 } 1177 }
1101 checkJobs(jobList); 1178 checkjobs(job->job_list);
1102 freeJob(newJob); 1179 free_job(newjob); /* doesn't actually free newjob,
1180 looks like a memory leak */
1103 free(charptr2); 1181 free(charptr2);
1104 1182
1105 /* Make a copy of any stuff left over in the command 1183 /* Make a copy of any stuff left over in the command
@@ -1113,10 +1191,9 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1113 --src; 1191 --src;
1114 charptr1 = xmalloc(BUFSIZ); 1192 charptr1 = xmalloc(BUFSIZ);
1115 while ( (size=full_read(pipefd[0], charptr1, BUFSIZ-1)) >0) { 1193 while ( (size=full_read(pipefd[0], charptr1, BUFSIZ-1)) >0) {
1116 int newSize=src - *commandPtr + size + 1 + strlen(charptr2); 1194 int newsize=src - *command_ptr + size + 1 + strlen(charptr2);
1117 if (newSize > BUFSIZ) { 1195 if (newsize > BUFSIZ) {
1118 *commandPtr=xrealloc(*commandPtr, src - *commandPtr + 1196 *command_ptr=xrealloc(*command_ptr, newsize);
1119 size + 1 + strlen(charptr2));
1120 } 1197 }
1121 memcpy(src, charptr1, size); 1198 memcpy(src, charptr1, size);
1122 src+=size; 1199 src+=size;
@@ -1126,16 +1203,20 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1126 if (*(src-1)=='\n') 1203 if (*(src-1)=='\n')
1127 --src; 1204 --src;
1128 1205
1129 /* Now paste into the *commandPtr all the stuff 1206 /* Now paste into the *command_ptr all the stuff
1130 * leftover after the second backtick */ 1207 * leftover after the second backtick */
1131 memcpy(src, charptr2, strlen(charptr2)+1); 1208 memcpy(src, charptr2, strlen(charptr2)+1);
1132 free(charptr2); 1209 free(charptr2);
1133 1210
1134 /* Now recursively call parseCommand to deal with the new 1211 /* Now recursively call parse_command to deal with the new
1135 * and improved version of the command line with the backtick 1212 * and improved version of the command line with the backtick
1136 * results expanded in place... */ 1213 * results expanded in place... */
1137 freeJob(job); 1214 {
1138 return(parseCommand(commandPtr, job, jobList, inBg)); 1215 struct jobset *jl=job->job_list;
1216 free_job(job);
1217 job->job_list = jl;
1218 }
1219 return(parse_command(command_ptr, job, inbg));
1139 } 1220 }
1140 break; 1221 break;
1141#endif // BB_FEATURE_SH_BACKTICKS 1222#endif // BB_FEATURE_SH_BACKTICKS
@@ -1143,9 +1224,37 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1143 case '\\': 1224 case '\\':
1144 src++; 1225 src++;
1145 if (!*src) { 1226 if (!*src) {
1227/* This is currently a little broken... */
1228#ifdef HANDLE_CONTINUATION_CHARS
1229 /* They fed us a continuation char, so continue reading stuff
1230 * on the next line, then tack that onto the end of the current
1231 * command */
1232 char *command;
1233 int newsize;
1234 printf("erik: found a continue char at EOL...\n");
1235 command = (char *) xcalloc(BUFSIZ, sizeof(char));
1236 if (get_command(input, command)) {
1237 error_msg("character expected after \\\n");
1238 free(command);
1239 free_job(job);
1240 return 1;
1241 }
1242 newsize = strlen(*command_ptr) + strlen(command) + 2;
1243 if (newsize > BUFSIZ) {
1244 printf("erik: doing realloc\n");
1245 *command_ptr=xrealloc(*command_ptr, newsize);
1246 }
1247 printf("erik: A: *command_ptr='%s'\n", *command_ptr);
1248 memcpy(--src, command, strlen(command));
1249 printf("erik: B: *command_ptr='%s'\n", *command_ptr);
1250 free(command);
1251 break;
1252#else
1146 error_msg("character expected after \\\n"); 1253 error_msg("character expected after \\\n");
1147 freeJob(job); 1254 free(command);
1255 free_job(job);
1148 return 1; 1256 return 1;
1257#endif
1149 } 1258 }
1150 if (*src == '*' || *src == '[' || *src == ']' 1259 if (*src == '*' || *src == '[' || *src == ']'
1151 || *src == '?') *buf++ = '\\'; 1260 || *src == '?') *buf++ = '\\';
@@ -1159,76 +1268,187 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1159 1268
1160 if (*prog->argv[argc_l]) { 1269 if (*prog->argv[argc_l]) {
1161 argc_l++; 1270 argc_l++;
1162 globLastArgument(prog, &argc_l, &argvAlloced); 1271 expand_argument(prog, &argc_l, &argv_alloced);
1163 } 1272 }
1164 if (!argc_l) { 1273 if (!argc_l) {
1165 freeJob(job); 1274 free_job(job);
1166 return 0; 1275 return 0;
1167 } 1276 }
1168 prog->argv[argc_l] = NULL; 1277 prog->argv[argc_l] = NULL;
1169 1278
1170 if (!returnCommand) { 1279 if (!return_command) {
1171 job->text = xmalloc(strlen(*commandPtr) + 1); 1280 job->text = xmalloc(strlen(*command_ptr) + 1);
1172 strcpy(job->text, *commandPtr); 1281 strcpy(job->text, *command_ptr);
1173 } else { 1282 } else {
1174 /* This leaves any trailing spaces, which is a bit sloppy */ 1283 /* This leaves any trailing spaces, which is a bit sloppy */
1175 count = returnCommand - *commandPtr; 1284 count = return_command - *command_ptr;
1176 job->text = xmalloc(count + 1); 1285 job->text = xmalloc(count + 1);
1177 strncpy(job->text, *commandPtr, count); 1286 strncpy(job->text, *command_ptr, count);
1178 job->text[count] = '\0'; 1287 job->text[count] = '\0';
1179 } 1288 }
1180 1289
1181 *commandPtr = returnCommand; 1290 *command_ptr = return_command;
1182 1291
1183 return 0; 1292 return 0;
1184} 1293}
1185 1294
1186static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]) 1295/* Run the child_prog, no matter what kind of command it uses.
1296 */
1297static int pseudo_exec(struct child_prog *child)
1187{ 1298{
1188 struct job *theJob; 1299 struct built_in_command *x;
1189 int i;
1190 int nextin, nextout;
1191 int pipefds[2]; /* pipefd[0] is for reading */
1192 struct builtInCommand *x;
1193#ifdef BB_FEATURE_SH_STANDALONE_SHELL 1300#ifdef BB_FEATURE_SH_STANDALONE_SHELL
1194 struct BB_applet search_applet, *applet; 1301 struct BB_applet search_applet, *applet;
1195#endif 1302#endif
1196 1303
1304 /* Check if the command matches any of the forking builtins.
1305 * XXX It would probably be wise to check for non-forking builtins
1306 * here as well, since in some context the non-forking path
1307 * is disabled or bypassed. See comment in run_command.
1308 */
1309 for (x = bltins_forking; x->cmd; x++) {
1310 if (strcmp(child->argv[0], x->cmd) == 0) {
1311 applet_name=x->cmd;
1312 exit (x->function(child));
1313 }
1314 }
1315#ifdef BB_FEATURE_SH_STANDALONE_SHELL
1316 /* Check if the command matches any busybox internal
1317 * commands ("applets") here. Following discussions from
1318 * November 2000 on busybox@opensource.lineo.com, don't use
1319 * get_last_path_component(). This way explicit (with
1320 * slashes) filenames will never be interpreted as an
1321 * applet, just like with builtins. This way the user can
1322 * override an applet with an explicit filename reference.
1323 * The only downside to this change is that an explicit
1324 * /bin/foo invocation will fork and exec /bin/foo, even if
1325 * /bin/foo is a symlink to busybox.
1326 */
1327 search_applet.name = child->argv[0];
1328
1329#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
1330 /* If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then
1331 * if you run /bin/cat, it will use BusyBox cat even if
1332 * /bin/cat exists on the filesystem and is _not_ busybox.
1333 * Some systems want this, others do not. Choose wisely. :-)
1334 */
1335 search_applet.name = get_last_path_component(search_applet.name);
1336#endif
1337
1338 /* Do a binary search to find the applet entry given the name. */
1339 applet = bsearch(&search_applet, applets, NUM_APPLETS,
1340 sizeof(struct BB_applet), applet_name_compare);
1341 if (applet != NULL) {
1342 int argc_l;
1343 char** argv=child->argv;
1344 for(argc_l=0;*argv!=NULL; argv++, argc_l++);
1345 applet_name=applet->name;
1346 optind = 1;
1347 exit((*(applet->main)) (argc_l, child->argv));
1348 }
1349#endif
1350
1351 execvp(child->argv[0], child->argv);
1352 error_msg_and_die("%s: %s\n", child->argv[0],
1353 strerror(errno));
1354}
1355
1356static void insert_job(struct job *newjob, int inbg)
1357{
1358 struct job *thejob;
1359 struct jobset *job_list=newjob->job_list;
1360
1361 /* find the ID for thejob to use */
1362 newjob->jobid = 1;
1363 for (thejob = job_list->head; thejob; thejob = thejob->next)
1364 if (thejob->jobid >= newjob->jobid)
1365 newjob->jobid = thejob->jobid + 1;
1366
1367 /* add thejob to the list of running jobs */
1368 if (!job_list->head) {
1369 thejob = job_list->head = xmalloc(sizeof(*thejob));
1370 } else {
1371 for (thejob = job_list->head; thejob->next; thejob = thejob->next) /* nothing */;
1372 thejob->next = xmalloc(sizeof(*thejob));
1373 thejob = thejob->next;
1374 }
1375
1376 *thejob = *newjob; /* physically copy the struct job */
1377 thejob->next = NULL;
1378 thejob->running_progs = thejob->num_progs;
1379 thejob->stopped_progs = 0;
1380
1381 if (inbg) {
1382 /* we don't wait for background thejobs to return -- append it
1383 to the list of backgrounded thejobs and leave it alone */
1384 printf("[%d] %d\n", thejob->jobid,
1385 newjob->progs[newjob->num_progs - 1].pid);
1386#ifdef BB_FEATURE_SH_ENVIRONMENT
1387 last_bg_pid=newjob->progs[newjob->num_progs - 1].pid;
1388#endif
1389 } else {
1390 newjob->job_list->fg = thejob;
1391
1392 /* move the new process group into the foreground */
1393 /* suppress messages when run from /linuxrc mag@sysgo.de */
1394 if (tcsetpgrp(0, newjob->pgrp) && errno != ENOTTY)
1395 perror("tcsetpgrp");
1396 }
1397}
1398
1399static int run_command(struct job *newjob, int inbg, int outpipe[2])
1400{
1401 /* struct job *thejob; */
1402 int i;
1403 int nextin, nextout;
1404 int pipefds[2]; /* pipefd[0] is for reading */
1405 struct built_in_command *x;
1406 struct child_prog *child;
1407
1197 nextin = 0, nextout = 1; 1408 nextin = 0, nextout = 1;
1198 for (i = 0; i < newJob->numProgs; i++) { 1409 for (i = 0; i < newjob->num_progs; i++) {
1199 if ((i + 1) < newJob->numProgs) { 1410 child = & (newjob->progs[i]);
1200 pipe(pipefds); 1411
1412 if ((i + 1) < newjob->num_progs) {
1413 if (pipe(pipefds)<0) perror_msg_and_die("pipe");
1201 nextout = pipefds[1]; 1414 nextout = pipefds[1];
1202 } else { 1415 } else {
1203 if (outPipe[1]!=-1) { 1416 if (outpipe[1]!=-1) {
1204 nextout = outPipe[1]; 1417 nextout = outpipe[1];
1205 } else { 1418 } else {
1206 nextout = 1; 1419 nextout = 1;
1207 } 1420 }
1208 } 1421 }
1209 1422
1210#ifdef BB_FEATURE_SH_ENVIRONMENT 1423#ifdef BB_FEATURE_SH_ENVIRONMENT
1211 if (showXtrace==TRUE) { 1424 if (show_x_trace==TRUE) {
1212 int j; 1425 int j;
1213 fprintf(stderr, "+ "); 1426 fputc('+', stderr);
1214 for (j = 0; newJob->progs[i].argv[j]; j++) 1427 for (j = 0; child->argv[j]; j++) {
1215 fprintf(stderr, "%s ", newJob->progs[i].argv[j]); 1428 fputc(' ', stderr);
1216 fprintf(stderr, "\n"); 1429 fputs(child->argv[j], stderr);
1430 }
1431 fputc('\n', stderr);
1217 } 1432 }
1218#endif 1433#endif
1219 1434
1220 /* Check if the command matches any non-forking builtins */ 1435 /* Check if the command matches any non-forking builtins.
1436 * XXX should probably skip this test, and fork anyway, if
1437 * there redirects of some kind demand forking to work right.
1438 * pseudo_exec would then need to handle the non-forking command
1439 * in a forked context.
1440 */
1221 for (x = bltins; x->cmd; x++) { 1441 for (x = bltins; x->cmd; x++) {
1222 if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0 ) { 1442 if (strcmp(child->argv[0], x->cmd) == 0 ) {
1223 return(x->function(newJob, jobList)); 1443 return(x->function(child));
1224 } 1444 }
1225 } 1445 }
1226 1446
1227 if (!(newJob->progs[i].pid = fork())) { 1447 if (!(child->pid = fork())) {
1228 signal(SIGTTOU, SIG_DFL); 1448 signal(SIGTTOU, SIG_DFL);
1229 1449
1230 if (outPipe[1]!=-1) { 1450 if (outpipe[1]!=-1) {
1231 close(outPipe[0]); 1451 close(outpipe[0]);
1232 } 1452 }
1233 if (nextin != 0) { 1453 if (nextin != 0) {
1234 dup2(nextin, 0); 1454 dup2(nextin, 0);
@@ -1237,68 +1457,23 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
1237 1457
1238 if (nextout != 1) { 1458 if (nextout != 1) {
1239 dup2(nextout, 1); 1459 dup2(nextout, 1);
1240 dup2(nextout, 2); 1460 dup2(nextout, 2); /* Really? */
1241 close(nextout); 1461 close(nextout);
1242 close(pipefds[0]); 1462 close(pipefds[0]);
1243 } 1463 }
1244 1464
1245 /* explicit redirections override pipes */ 1465 /* explicit redirects override pipes */
1246 setupRedirections(newJob->progs + i); 1466 setup_redirects(child);
1247
1248 /* Check if the command matches any of the other builtins */
1249 for (x = bltins_forking; x->cmd; x++) {
1250 if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0) {
1251 applet_name=x->cmd;
1252 exit (x->function(newJob, jobList));
1253 }
1254 }
1255#ifdef BB_FEATURE_SH_STANDALONE_SHELL
1256 /* Check if the command matches any busybox internal
1257 * commands ("applets") here. Following discussions from
1258 * November 2000 on busybox@opensource.lineo.com, don't use
1259 * get_last_path_component(). This way explicit (with
1260 * slashes) filenames will never be interpreted as an
1261 * applet, just like with builtins. This way the user can
1262 * override an applet with an explicit filename reference.
1263 * The only downside to this change is that an explicit
1264 * /bin/foo invocation fill fork and exec /bin/foo, even if
1265 * /bin/foo is a symlink to busybox.
1266 */
1267 search_applet.name = newJob->progs[i].argv[0];
1268 1467
1269#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN 1468 pseudo_exec(child);
1270 /* If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then
1271 * if you run /bin/cat, it will use BusyBox cat even if
1272 * /bin/cat exists on the filesystem and is _not_ busybox.
1273 * Some systems want this, others do not. Choose wisely. :-)
1274 */
1275 search_applet.name = get_last_path_component(search_applet.name);
1276#endif
1277
1278 /* Do a binary search to find the applet entry given the name. */
1279 applet = bsearch(&search_applet, applets, NUM_APPLETS,
1280 sizeof(struct BB_applet), applet_name_compare);
1281 if (applet != NULL) {
1282 int argc_l;
1283 char** argv=newJob->progs[i].argv;
1284 for(argc_l=0;*argv!=NULL; argv++, argc_l++);
1285 applet_name=applet->name;
1286 optind = 1;
1287 exit((*(applet->main)) (argc_l, newJob->progs[i].argv));
1288 }
1289#endif
1290
1291 execvp(newJob->progs[i].argv[0], newJob->progs[i].argv);
1292 error_msg_and_die("%s: %s\n", newJob->progs[i].argv[0],
1293 strerror(errno));
1294 } 1469 }
1295 if (outPipe[1]!=-1) { 1470 if (outpipe[1]!=-1) {
1296 close(outPipe[1]); 1471 close(outpipe[1]);
1297 } 1472 }
1298 1473
1299 /* put our child in the process group whose leader is the 1474 /* put our child in the process group whose leader is the
1300 first process in this pipe */ 1475 first process in this pipe */
1301 setpgid(newJob->progs[i].pid, newJob->progs[0].pid); 1476 setpgid(child->pid, newjob->progs[0].pid);
1302 if (nextin != 0) 1477 if (nextin != 0)
1303 close(nextin); 1478 close(nextin);
1304 if (nextout != 1) 1479 if (nextout != 1)
@@ -1309,44 +1484,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
1309 nextin = pipefds[0]; 1484 nextin = pipefds[0];
1310 } 1485 }
1311 1486
1312 newJob->pgrp = newJob->progs[0].pid; 1487 newjob->pgrp = newjob->progs[0].pid;
1313 1488
1314 /* find the ID for the theJob to use */ 1489 insert_job(newjob, inbg);
1315 newJob->jobId = 1;
1316 for (theJob = jobList->head; theJob; theJob = theJob->next)
1317 if (theJob->jobId >= newJob->jobId)
1318 newJob->jobId = theJob->jobId + 1;
1319
1320 /* add the theJob to the list of running jobs */
1321 if (!jobList->head) {
1322 theJob = jobList->head = xmalloc(sizeof(*theJob));
1323 } else {
1324 for (theJob = jobList->head; theJob->next; theJob = theJob->next);
1325 theJob->next = xmalloc(sizeof(*theJob));
1326 theJob = theJob->next;
1327 }
1328
1329 *theJob = *newJob;
1330 theJob->next = NULL;
1331 theJob->runningProgs = theJob->numProgs;
1332 theJob->stoppedProgs = 0;
1333
1334 if (inBg) {
1335 /* we don't wait for background theJobs to return -- append it
1336 to the list of backgrounded theJobs and leave it alone */
1337 printf("[%d] %d\n", theJob->jobId,
1338 newJob->progs[newJob->numProgs - 1].pid);
1339#ifdef BB_FEATURE_SH_ENVIRONMENT
1340 lastBgPid=newJob->progs[newJob->numProgs - 1].pid;
1341#endif
1342 } else {
1343 jobList->fg = theJob;
1344
1345 /* move the new process group into the foreground */
1346 /* suppress messages when run from /linuxrc mag@sysgo.de */
1347 if (tcsetpgrp(0, newJob->pgrp) && errno != ENOTTY)
1348 perror("tcsetpgrp");
1349 }
1350 1490
1351 return 0; 1491 return 0;
1352} 1492}
@@ -1354,13 +1494,14 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
1354static int busy_loop(FILE * input) 1494static int busy_loop(FILE * input)
1355{ 1495{
1356 char *command; 1496 char *command;
1357 char *nextCommand = NULL; 1497 char *next_command = NULL;
1358 struct job newJob; 1498 struct job newjob;
1359 pid_t parent_pgrp; 1499 pid_t parent_pgrp;
1360 int i; 1500 int i;
1361 int inBg; 1501 int inbg;
1362 int status; 1502 int status;
1363 newJob.jobContext = REGULAR_JOB_CONTEXT; 1503 newjob.job_list = &job_list;
1504 newjob.job_context = DEFAULT_CONTEXT;
1364 1505
1365 /* save current owner of TTY so we can restore it on exit */ 1506 /* save current owner of TTY so we can restore it on exit */
1366 parent_pgrp = tcgetpgrp(0); 1507 parent_pgrp = tcgetpgrp(0);
@@ -1372,64 +1513,65 @@ static int busy_loop(FILE * input)
1372 signal(SIGTTOU, SIG_IGN); 1513 signal(SIGTTOU, SIG_IGN);
1373 1514
1374 while (1) { 1515 while (1) {
1375 if (!jobList.fg) { 1516 if (!job_list.fg) {
1376 /* no job is in the foreground */ 1517 /* no job is in the foreground */
1377 1518
1378 /* see if any background processes have exited */ 1519 /* see if any background processes have exited */
1379 checkJobs(&jobList); 1520 checkjobs(&job_list);
1380 1521
1381 if (!nextCommand) { 1522 if (!next_command) {
1382 if (getCommand(input, command)) 1523 if (get_command(input, command))
1383 break; 1524 break;
1384 nextCommand = command; 1525 next_command = command;
1385 } 1526 }
1386 1527
1387 if (!parseCommand(&nextCommand, &newJob, &jobList, &inBg) && 1528 if (!parse_command(&next_command, &newjob, &inbg) &&
1388 newJob.numProgs) { 1529 newjob.num_progs) {
1389 int pipefds[2] = {-1,-1}; 1530 int pipefds[2] = {-1,-1};
1390 runCommand(&newJob, &jobList, inBg, pipefds); 1531 debug_printf( "job=%p being fed to run_command by busy_loop()'\n", &newjob);
1532 run_command(&newjob, inbg, pipefds);
1391 } 1533 }
1392 else { 1534 else {
1393 free(command); 1535 free(command);
1394 command = (char *) xcalloc(BUFSIZ, sizeof(char)); 1536 command = (char *) xcalloc(BUFSIZ, sizeof(char));
1395 nextCommand = NULL; 1537 next_command = NULL;
1396 } 1538 }
1397 } else { 1539 } else {
1398 /* a job is running in the foreground; wait for it */ 1540 /* a job is running in the foreground; wait for it */
1399 i = 0; 1541 i = 0;
1400 while (!jobList.fg->progs[i].pid || 1542 while (!job_list.fg->progs[i].pid ||
1401 jobList.fg->progs[i].isStopped == 1) i++; 1543 job_list.fg->progs[i].is_stopped == 1) i++;
1402 1544
1403 waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED); 1545 waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED);
1404 1546
1405 if (WIFEXITED(status) || WIFSIGNALED(status)) { 1547 if (WIFEXITED(status) || WIFSIGNALED(status)) {
1406 /* the child exited */ 1548 /* the child exited */
1407 jobList.fg->runningProgs--; 1549 job_list.fg->running_progs--;
1408 jobList.fg->progs[i].pid = 0; 1550 job_list.fg->progs[i].pid = 0;
1409 1551
1410#ifdef BB_FEATURE_SH_ENVIRONMENT 1552#ifdef BB_FEATURE_SH_ENVIRONMENT
1411 lastReturnCode=WEXITSTATUS(status); 1553 last_return_code=WEXITSTATUS(status);
1412#endif 1554#endif
1413 debug_printf("'%s' exited -- return code %d\n", jobList.fg->text, lastReturnCode); 1555 debug_printf("'%s' exited -- return code %d\n",
1414 if (!jobList.fg->runningProgs) { 1556 job_list.fg->text, last_return_code);
1557 if (!job_list.fg->running_progs) {
1415 /* child exited */ 1558 /* child exited */
1416 1559 remove_job(&job_list, job_list.fg);
1417 removeJob(&jobList, jobList.fg); 1560 job_list.fg = NULL;
1418 jobList.fg = NULL;
1419 } 1561 }
1420 } else { 1562 } else {
1421 /* the child was stopped */ 1563 /* the child was stopped */
1422 jobList.fg->stoppedProgs++; 1564 job_list.fg->stopped_progs++;
1423 jobList.fg->progs[i].isStopped = 1; 1565 job_list.fg->progs[i].is_stopped = 1;
1424 1566
1425 if (jobList.fg->stoppedProgs == jobList.fg->runningProgs) { 1567 if (job_list.fg->stopped_progs == job_list.fg->running_progs) {
1426 printf("\n" JOB_STATUS_FORMAT, jobList.fg->jobId, 1568 printf("\n" JOB_STATUS_FORMAT, job_list.fg->jobid,
1427 "Stopped", jobList.fg->text); 1569 "Stopped", job_list.fg->text);
1428 jobList.fg = NULL; 1570 job_list.fg = NULL;
1429 } 1571 }
1430 } 1572 }
1431 1573
1432 if (!jobList.fg) { 1574 if (!job_list.fg) {
1433 /* move the shell to the foreground */ 1575 /* move the shell to the foreground */
1434 /* suppress messages when run from /linuxrc mag@sysgo.de */ 1576 /* suppress messages when run from /linuxrc mag@sysgo.de */
1435 if (tcsetpgrp(0, getpid()) && errno != ENOTTY) 1577 if (tcsetpgrp(0, getpid()) && errno != ENOTTY)
@@ -1454,15 +1596,15 @@ static int busy_loop(FILE * input)
1454#ifdef BB_FEATURE_CLEAN_UP 1596#ifdef BB_FEATURE_CLEAN_UP
1455void free_memory(void) 1597void free_memory(void)
1456{ 1598{
1457 if (promptStr) 1599 if (prompt_str)
1458 free(promptStr); 1600 free(prompt_str);
1459 if (cwd) 1601 if (cwd)
1460 free(cwd); 1602 free(cwd);
1461 if (local_pending_command) 1603 if (local_pending_command)
1462 free(local_pending_command); 1604 free(local_pending_command);
1463 1605
1464 if (jobList.fg && !jobList.fg->runningProgs) { 1606 if (job_list.fg && !job_list.fg->running_progs) {
1465 removeJob(&jobList, jobList.fg); 1607 remove_job(&job_list, job_list.fg);
1466 } 1608 }
1467} 1609}
1468#endif 1610#endif
@@ -1500,7 +1642,7 @@ int shell_main(int argc_l, char **argv_l)
1500 break; 1642 break;
1501#ifdef BB_FEATURE_SH_ENVIRONMENT 1643#ifdef BB_FEATURE_SH_ENVIRONMENT
1502 case 'x': 1644 case 'x':
1503 showXtrace = TRUE; 1645 show_x_trace = TRUE;
1504 break; 1646 break;
1505#endif 1647#endif
1506 case 'i': 1648 case 'i':
@@ -1517,10 +1659,14 @@ int shell_main(int argc_l, char **argv_l)
1517 * standard input is a terminal 1659 * standard input is a terminal
1518 * standard output is a terminal 1660 * standard output is a terminal
1519 * Refer to Posix.2, the description of the `sh' utility. */ 1661 * Refer to Posix.2, the description of the `sh' utility. */
1520 if (interactive==TRUE || ( argv[optind]==NULL && input==stdin && isatty(fileno(stdin)) && isatty(fileno(stdout)))) { 1662 if (argv[optind]==NULL && input==stdin &&
1663 isatty(fileno(stdin)) && isatty(fileno(stdout))) {
1664 interactive=TRUE;
1665 }
1666 if (interactive==TRUE) {
1521 //fprintf(stdout, "optind=%d argv[optind]='%s'\n", optind, argv[optind]); 1667 //fprintf(stdout, "optind=%d argv[optind]='%s'\n", optind, argv[optind]);
1522 /* Looks like they want an interactive shell */ 1668 /* Looks like they want an interactive shell */
1523 fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); 1669 fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell (lash)\n", BB_VER, BB_BT);
1524 fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); 1670 fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n");
1525 } else if (local_pending_command==NULL) { 1671 } else if (local_pending_command==NULL) {
1526 //fprintf(stdout, "optind=%d argv[optind]='%s'\n", optind, argv[optind]); 1672 //fprintf(stdout, "optind=%d argv[optind]='%s'\n", optind, argv[optind]);
diff --git a/shell/cmdedit.c b/shell/cmdedit.c
index c32330bfd..0c9bda760 100644
--- a/shell/cmdedit.c
+++ b/shell/cmdedit.c
@@ -85,6 +85,12 @@ static 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 */ 87static int exithandler_set = 0; /* Set to true when atexit() has been called */
88
89
90/* Link into lash to reset context to 0
91 * on ^C and such */
92extern unsigned int shell_context;
93
88 94
89struct history { 95struct history {
90 char *s; 96 char *s;
@@ -466,20 +472,24 @@ extern void cmdedit_read_input(char* prompt, char command[BUFSIZ])
466 input_backward(outputFd, &cursor); 472 input_backward(outputFd, &cursor);
467 break; 473 break;
468 case 3: 474 case 3:
469 /* Control-c -- leave the current line, 475 /* Control-c -- stop gathering input */
470 * and start over on the next line */ 476
477 /* Link into lash to reset context to 0 on ^C and such */
478 shell_context = 0;
471 479
472 /* Go to the next line */ 480 /* Go to the next line */
473 xwrite(outputFd, "\n", 1); 481 xwrite(outputFd, "\n", 1);
474 482
483#if 0
475 /* Rewrite the prompt */ 484 /* Rewrite the prompt */
476 xwrite(outputFd, prompt, strlen(prompt)); 485 xwrite(outputFd, prompt, strlen(prompt));
477 486
478 /* Reset the command string */ 487 /* Reset the command string */
479 memset(command, 0, BUFSIZ); 488 memset(command, 0, BUFSIZ);
480 len = cursor = 0; 489 len = cursor = 0;
490#endif
491 return;
481 492
482 break;
483 case 4: 493 case 4:
484 /* Control-d -- Delete one character, or exit 494 /* Control-d -- Delete one character, or exit
485 * if the len=0 and no chars to delete */ 495 * if the len=0 and no chars to delete */
diff --git a/shell/lash.c b/shell/lash.c
index 164d6f5c5..590f5ee89 100644
--- a/shell/lash.c
+++ b/shell/lash.c
@@ -32,10 +32,13 @@
32//Backtick support has some problems, use at your own risk! 32//Backtick support has some problems, use at your own risk!
33//#define BB_FEATURE_SH_BACKTICKS 33//#define BB_FEATURE_SH_BACKTICKS
34// 34//
35//If, then, else, etc. support is really, really broken. Don't even 35//If, then, else, etc. support.. This should now behave basically
36//bother to mess with this yet, since you will not be happy with it. 36//like any other Bourne shell...
37//#define BB_FEATURE_SH_IF_EXPRESSIONS 37//#define BB_FEATURE_SH_IF_EXPRESSIONS
38// 38//
39/* This is currently a little broken... */
40//#define HANDLE_CONTINUATION_CHARS
41//
39//For debugging/development on the shell only... 42//For debugging/development on the shell only...
40//#define DEBUG_SHELL 43//#define DEBUG_SHELL
41 44
@@ -55,98 +58,102 @@
55#include <getopt.h> 58#include <getopt.h>
56#include "cmdedit.h" 59#include "cmdedit.h"
57 60
58#define MAX_LINE 256 /* size of input buffer for `read' builtin */ 61#define MAX_LINE 256 /* size of input buffer for cwd data */
59#define MAX_READ 128 /* size of input buffer for `read' builtin */ 62#define MAX_READ 128 /* size of input buffer for `read' builtin */
60#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 63#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
61extern size_t NUM_APPLETS; 64extern size_t NUM_APPLETS;
62 65
63 66
64 67enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE,
65
66enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
67 REDIRECT_APPEND 68 REDIRECT_APPEND
68}; 69};
69 70
70static const unsigned int REGULAR_JOB_CONTEXT=0x1; 71static const unsigned int DEFAULT_CONTEXT=0x1;
71static const unsigned int IF_TRUE_CONTEXT=0x2; 72static const unsigned int IF_TRUE_CONTEXT=0x2;
72static const unsigned int IF_FALSE_CONTEXT=0x4; 73static const unsigned int IF_FALSE_CONTEXT=0x4;
73static const unsigned int THEN_EXP_CONTEXT=0x8; 74static const unsigned int THEN_EXP_CONTEXT=0x8;
74static const unsigned int ELSE_EXP_CONTEXT=0x10; 75static const unsigned int ELSE_EXP_CONTEXT=0x10;
76unsigned int shell_context = 0;
77
75 78
76 79
77struct jobSet { 80struct jobset {
78 struct job *head; /* head of list of running jobs */ 81 struct job *head; /* head of list of running jobs */
79 struct job *fg; /* current foreground job */ 82 struct job *fg; /* current foreground job */
80}; 83};
81 84
82struct redirectionSpecifier { 85struct redir_struct {
83 enum redirectionType type; /* type of redirection */ 86 enum redir_type type; /* type of redirection */
84 int fd; /* file descriptor being redirected */ 87 int fd; /* file descriptor being redirected */
85 char *filename; /* file to redirect fd to */ 88 char *filename; /* file to redirect fd to */
86}; 89};
87 90
88struct childProgram { 91struct child_prog {
89 pid_t pid; /* 0 if exited */ 92 pid_t pid; /* 0 if exited */
90 char **argv; /* program name and arguments */ 93 char **argv; /* program name and arguments */
91 int numRedirections; /* elements in redirection array */ 94 int num_redirects; /* elements in redirection array */
92 struct redirectionSpecifier *redirections; /* I/O redirections */ 95 struct redir_struct *redirects; /* I/O redirects */
93 glob_t globResult; /* result of parameter globbing */ 96 glob_t glob_result; /* result of parameter globbing */
94 int freeGlob; /* should we globfree(&globResult)? */ 97 int free_glob; /* should we globfree(&glob_result)? */
95 int isStopped; /* is the program currently running? */ 98 int is_stopped; /* is the program currently running? */
99 struct job *family; /* pointer back to the child's parent job */
96}; 100};
97 101
98struct job { 102struct job {
99 int jobId; /* job number */ 103 int jobid; /* job number */
100 int numProgs; /* total number of programs in job */ 104 int num_progs; /* total number of programs in job */
101 int runningProgs; /* number of programs running */ 105 int running_progs; /* number of programs running */
102 char *text; /* name of job */ 106 char *text; /* name of job */
103 char *cmdBuf; /* buffer various argv's point into */ 107 char *cmdbuf; /* buffer various argv's point into */
104 pid_t pgrp; /* process group ID for the job */ 108 pid_t pgrp; /* process group ID for the job */
105 struct childProgram *progs; /* array of programs in job */ 109 struct child_prog *progs; /* array of programs in job */
106 struct job *next; /* to track background commands */ 110 struct job *next; /* to track background commands */
107 int stoppedProgs; /* number of programs alive, but stopped */ 111 int stopped_progs; /* number of programs alive, but stopped */
108 int jobContext; /* bitmask defining current context */ 112 unsigned int job_context; /* bitmask defining current context */
113 struct jobset *job_list;
109}; 114};
110 115
111struct builtInCommand { 116struct built_in_command {
112 char *cmd; /* name */ 117 char *cmd; /* name */
113 char *descr; /* description */ 118 char *descr; /* description */
114 int (*function) (struct job *, struct jobSet * jobList); /* function ptr */ 119 int (*function) (struct child_prog *); /* function ptr */
115}; 120};
116 121
117/* function prototypes for builtins */ 122/* function prototypes for builtins */
118static int builtin_cd(struct job *cmd, struct jobSet *junk); 123static int builtin_cd(struct child_prog *cmd);
119static int builtin_env(struct job *dummy, struct jobSet *junk); 124static int builtin_env(struct child_prog *dummy);
120static int builtin_exec(struct job *cmd, struct jobSet *junk); 125static int builtin_exec(struct child_prog *cmd);
121static int builtin_exit(struct job *cmd, struct jobSet *junk); 126static int builtin_exit(struct child_prog *cmd);
122static int builtin_fg_bg(struct job *cmd, struct jobSet *jobList); 127static int builtin_fg_bg(struct child_prog *cmd);
123static int builtin_help(struct job *cmd, struct jobSet *junk); 128static int builtin_help(struct child_prog *cmd);
124static int builtin_jobs(struct job *dummy, struct jobSet *jobList); 129static int builtin_jobs(struct child_prog *dummy);
125static int builtin_pwd(struct job *dummy, struct jobSet *junk); 130static int builtin_pwd(struct child_prog *dummy);
126static int builtin_export(struct job *cmd, struct jobSet *junk); 131static int builtin_export(struct child_prog *cmd);
127static int builtin_source(struct job *cmd, struct jobSet *jobList); 132static int builtin_source(struct child_prog *cmd);
128static int builtin_unset(struct job *cmd, struct jobSet *junk); 133static int builtin_unset(struct child_prog *cmd);
129static int builtin_read(struct job *cmd, struct jobSet *junk); 134static int builtin_read(struct child_prog *cmd);
130#ifdef BB_FEATURE_SH_IF_EXPRESSIONS 135#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
131static int builtin_if(struct job *cmd, struct jobSet *junk); 136static int builtin_if(struct child_prog *cmd);
132static int builtin_then(struct job *cmd, struct jobSet *junk); 137static int builtin_then(struct child_prog *cmd);
133static int builtin_else(struct job *cmd, struct jobSet *junk); 138static int builtin_else(struct child_prog *cmd);
134static int builtin_fi(struct job *cmd, struct jobSet *junk); 139static int builtin_fi(struct child_prog *cmd);
135#endif 140#endif
136 141
137 142
138/* function prototypes for shell stuff */ 143/* function prototypes for shell stuff */
139static void checkJobs(struct jobSet *jobList); 144static void checkjobs(struct jobset *job_list);
140static int getCommand(FILE * source, char *command); 145static int get_command(FILE * source, char *command);
141static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg); 146static int parse_command(char **command_ptr, struct job *job, int *inbg);
142static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]); 147static int run_command(struct job *newjob, int inbg, int outpipe[2]);
148static int pseudo_exec(struct child_prog *cmd) __attribute__ ((noreturn));
149static int run_command_predicate(char *cmd);
143static int busy_loop(FILE * input); 150static int busy_loop(FILE * input);
144 151
145 152
146/* Table of built-in functions (these are non-forking builtins, meaning they 153/* Table of built-in functions (these are non-forking builtins, meaning they
147 * can change global variables in the parent shell process but they will not 154 * can change global variables in the parent shell process but they will not
148 * work with pipes and redirects; 'unset foo | whatever' will not work) */ 155 * work with pipes and redirects; 'unset foo | whatever' will not work) */
149static struct builtInCommand bltins[] = { 156static struct built_in_command bltins[] = {
150 {"bg", "Resume a job in the background", builtin_fg_bg}, 157 {"bg", "Resume a job in the background", builtin_fg_bg},
151 {"cd", "Change working directory", builtin_cd}, 158 {"cd", "Change working directory", builtin_cd},
152 {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec}, 159 {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec},
@@ -157,6 +164,7 @@ static struct builtInCommand bltins[] = {
157 {"unset", "Unset environment variable", builtin_unset}, 164 {"unset", "Unset environment variable", builtin_unset},
158 {"read", "Input environment variable", builtin_read}, 165 {"read", "Input environment variable", builtin_read},
159 {".", "Source-in and run commands in a file", builtin_source}, 166 {".", "Source-in and run commands in a file", builtin_source},
167 /* to do: add ulimit */
160#ifdef BB_FEATURE_SH_IF_EXPRESSIONS 168#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
161 {"if", NULL, builtin_if}, 169 {"if", NULL, builtin_if},
162 {"then", NULL, builtin_then}, 170 {"then", NULL, builtin_then},
@@ -168,7 +176,7 @@ static struct builtInCommand bltins[] = {
168 176
169/* Table of forking built-in functions (things that fork cannot change global 177/* Table of forking built-in functions (things that fork cannot change global
170 * variables in the parent process, such as the current working directory) */ 178 * variables in the parent process, such as the current working directory) */
171static struct builtInCommand bltins_forking[] = { 179static struct built_in_command bltins_forking[] = {
172 {"env", "Print all environment variables", builtin_env}, 180 {"env", "Print all environment variables", builtin_env},
173 {"pwd", "Print current directory", builtin_pwd}, 181 {"pwd", "Print current directory", builtin_pwd},
174 {"help", "List shell built-in commands", builtin_help}, 182 {"help", "List shell built-in commands", builtin_help},
@@ -178,22 +186,25 @@ static struct builtInCommand bltins_forking[] = {
178static char prompt[3]; 186static char prompt[3];
179static char *cwd; 187static char *cwd;
180static char *local_pending_command = NULL; 188static char *local_pending_command = NULL;
181static char *promptStr = NULL; 189static char *prompt_str = NULL;
182static struct jobSet jobList = { NULL, NULL }; 190static struct jobset job_list = { NULL, NULL };
183static int argc; 191static int argc;
184static char **argv; 192static char **argv;
185#ifdef BB_FEATURE_SH_ENVIRONMENT 193#ifdef BB_FEATURE_SH_ENVIRONMENT
186static int lastBgPid=-1; 194static int last_bg_pid=-1;
187static int lastReturnCode=-1; 195static int last_return_code=-1;
188static int showXtrace=FALSE; 196static int show_x_trace=FALSE;
189#endif 197#endif
190 198#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
199static char syntax_err[]="syntax error near unexpected token";
200#endif
201
191#ifdef DEBUG_SHELL 202#ifdef DEBUG_SHELL
192static inline void debug_printf(const char *format, ...) 203static inline void debug_printf(const char *format, ...)
193{ 204{
194 va_list args; 205 va_list args;
195 va_start(args, format); 206 va_start(args, format);
196 vfprintf(stderr, s, p); 207 vfprintf(stderr, format, args);
197 va_end(args); 208 va_end(args);
198} 209}
199#else 210#else
@@ -213,16 +224,52 @@ static inline void win_changed(int junk)
213static inline void win_changed(int junk) {} 224static inline void win_changed(int junk) {}
214#endif 225#endif
215 226
227/*
228 Most builtins need access to the struct child_prog that has
229 their arguments, previously coded as cmd->progs[0]. That coding
230 can exhibit a bug, if the builtin is not the first command in
231 a pipeline: "echo foo | exec sort" will attempt to exec foo.
232
233builtin previous use notes
234------ ----------------- ---------
235cd cmd->progs[0]
236env 0
237exec cmd->progs[0] squashed bug: didn't look for applets or forking builtins
238exit cmd->progs[0]
239fg_bg cmd->progs[0], job_list->head, job_list->fg
240help 0
241jobs job_list->head
242pwd 0
243export cmd->progs[0] passes cmd, job_list to builtin_env(), which ignores them
244source cmd->progs[0]
245unset cmd->progs[0]
246read cmd->progs[0]
247if cmd->job_context, cmd->text
248then cmd->job_context, cmd->text
249else cmd->job_context, cmd->text
250fi cmd->job_context
251
252The use of cmd->text by if/then/else/fi is hopelessly hacky.
253Would it work to increment cmd->progs[0]->argv and recurse,
254somewhat like builtin_exec does?
255
256I added "struct job *family;" to struct child_prog,
257and switched API to builtin_foo(struct child_prog *child);
258So cmd->text becomes child->family->text
259 cmd->job_context becomes child->family->job_context
260 cmd->progs[0] becomes *child
261 job_list becomes child->family->job_list
262 */
216 263
217/* built-in 'cd <path>' handler */ 264/* built-in 'cd <path>' handler */
218static int builtin_cd(struct job *cmd, struct jobSet *junk) 265static int builtin_cd(struct child_prog *child)
219{ 266{
220 char *newdir; 267 char *newdir;
221 268
222 if (!cmd->progs[0].argv[1] == 1) 269 if (child->argv[1] == NULL)
223 newdir = getenv("HOME"); 270 newdir = getenv("HOME");
224 else 271 else
225 newdir = cmd->progs[0].argv[1]; 272 newdir = child->argv[1];
226 if (chdir(newdir)) { 273 if (chdir(newdir)) {
227 printf("cd: %s: %s\n", newdir, strerror(errno)); 274 printf("cd: %s: %s\n", newdir, strerror(errno));
228 return EXIT_FAILURE; 275 return EXIT_FAILURE;
@@ -233,7 +280,7 @@ static int builtin_cd(struct job *cmd, struct jobSet *junk)
233} 280}
234 281
235/* built-in 'env' handler */ 282/* built-in 'env' handler */
236static int builtin_env(struct job *dummy, struct jobSet *junk) 283static int builtin_env(struct child_prog *dummy)
237{ 284{
238 char **e; 285 char **e;
239 286
@@ -244,149 +291,143 @@ static int builtin_env(struct job *dummy, struct jobSet *junk)
244} 291}
245 292
246/* built-in 'exec' handler */ 293/* built-in 'exec' handler */
247static int builtin_exec(struct job *cmd, struct jobSet *junk) 294static int builtin_exec(struct child_prog *child)
248{ 295{
249 if (cmd->progs[0].argv[1]) 296 if (child->argv[1] == NULL)
250 { 297 return EXIT_SUCCESS; /* Really? */
251 cmd->progs[0].argv++; 298 child->argv++;
252 execvp(cmd->progs[0].argv[0], cmd->progs[0].argv); 299 pseudo_exec(child);
253 error_msg_and_die("Exec to %s failed: %s\n", cmd->progs[0].argv[0], 300 /* never returns */
254 strerror(errno));
255 }
256 return EXIT_SUCCESS;
257} 301}
258 302
259/* built-in 'exit' handler */ 303/* built-in 'exit' handler */
260static int builtin_exit(struct job *cmd, struct jobSet *junk) 304static int builtin_exit(struct child_prog *child)
261{ 305{
262 if (!cmd->progs[0].argv[1] == 1) 306 if (child->argv[1] == NULL)
263 exit(EXIT_SUCCESS); 307 exit(EXIT_SUCCESS);
264 308
265 exit (atoi(cmd->progs[0].argv[1])); 309 exit (atoi(child->argv[1]));
266} 310}
267 311
268/* built-in 'fg' and 'bg' handler */ 312/* built-in 'fg' and 'bg' handler */
269static int builtin_fg_bg(struct job *cmd, struct jobSet *jobList) 313static int builtin_fg_bg(struct child_prog *child)
270{ 314{
271 int i, jobNum; 315 int i, jobNum;
272 struct job *job=NULL; 316 struct job *job=NULL;
317
273 318
274 if (!jobList->head) { 319 if (!child->argv[1] || child->argv[2]) {
275 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) {
276 error_msg("%s: exactly one argument is expected\n", 320 error_msg("%s: exactly one argument is expected\n",
277 cmd->progs[0].argv[0]); 321 child->argv[0]);
278 return EXIT_FAILURE; 322 return EXIT_FAILURE;
279 } 323 }
280 if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) { 324 if (sscanf(child->argv[1], "%%%d", &jobNum) != 1) {
281 error_msg("%s: bad argument '%s'\n", 325 error_msg("%s: bad argument '%s'\n",
282 cmd->progs[0].argv[0], cmd->progs[0].argv[1]); 326 child->argv[0], child->argv[1]);
283 return EXIT_FAILURE; 327 return EXIT_FAILURE;
284 for (job = jobList->head; job; job = job->next) { 328 }
285 if (job->jobId == jobNum) { 329 for (job = child->family->job_list->head; job; job = job->next) {
286 break; 330 if (job->jobid == jobNum) {
287 } 331 break;
288 } 332 }
289 } 333 }
290 } else {
291 job = jobList->head;
292 }
293 334
294 if (!job) { 335 if (!job) {
295 error_msg("%s: unknown job %d\n", 336 error_msg("%s: unknown job %d\n",
296 cmd->progs[0].argv[0], jobNum); 337 child->argv[0], jobNum);
297 return EXIT_FAILURE; 338 return EXIT_FAILURE;
298 } 339 }
299 340
300 if (*cmd->progs[0].argv[0] == 'f') { 341 if (*child->argv[0] == 'f') {
301 /* Make this job the foreground job */ 342 /* Make this job the foreground job */
302 /* suppress messages when run from /linuxrc mag@sysgo.de */ 343 /* suppress messages when run from /linuxrc mag@sysgo.de */
303 if (tcsetpgrp(0, job->pgrp) && errno != ENOTTY) 344 if (tcsetpgrp(0, job->pgrp) && errno != ENOTTY)
304 perror("tcsetpgrp"); 345 perror("tcsetpgrp");
305 jobList->fg = job; 346 child->family->job_list->fg = job;
306 } 347 }
307 348
308 /* Restart the processes in the job */ 349 /* Restart the processes in the job */
309 for (i = 0; i < job->numProgs; i++) 350 for (i = 0; i < job->num_progs; i++)
310 job->progs[i].isStopped = 0; 351 job->progs[i].is_stopped = 0;
311 352
312 kill(-job->pgrp, SIGCONT); 353 kill(-job->pgrp, SIGCONT);
313 354
314 job->stoppedProgs = 0; 355 job->stopped_progs = 0;
315 356
316 return EXIT_SUCCESS; 357 return EXIT_SUCCESS;
317} 358}
318 359
319/* built-in 'help' handler */ 360/* built-in 'help' handler */
320static int builtin_help(struct job *dummy, struct jobSet *junk) 361static int builtin_help(struct child_prog *dummy)
321{ 362{
322 struct builtInCommand *x; 363 struct built_in_command *x;
323 364
324 fprintf(stdout, "\nBuilt-in commands:\n"); 365 printf("\nBuilt-in commands:\n");
325 fprintf(stdout, "-------------------\n"); 366 printf("-------------------\n");
326 for (x = bltins; x->cmd; x++) { 367 for (x = bltins; x->cmd; x++) {
327 if (x->descr==NULL) 368 if (x->descr==NULL)
328 continue; 369 continue;
329 fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); 370 printf("%s\t%s\n", x->cmd, x->descr);
330 } 371 }
331 for (x = bltins_forking; x->cmd; x++) { 372 for (x = bltins_forking; x->cmd; x++) {
332 if (x->descr==NULL) 373 if (x->descr==NULL)
333 continue; 374 continue;
334 fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); 375 printf("%s\t%s\n", x->cmd, x->descr);
335 } 376 }
336 fprintf(stdout, "\n\n"); 377 printf("\n\n");
337 return EXIT_SUCCESS; 378 return EXIT_SUCCESS;
338} 379}
339 380
340/* built-in 'jobs' handler */ 381/* built-in 'jobs' handler */
341static int builtin_jobs(struct job *dummy, struct jobSet *jobList) 382static int builtin_jobs(struct child_prog *child)
342{ 383{
343 struct job *job; 384 struct job *job;
344 char *statusString; 385 char *status_string;
345 386
346 for (job = jobList->head; job; job = job->next) { 387 for (job = child->family->job_list->head; job; job = job->next) {
347 if (job->runningProgs == job->stoppedProgs) 388 if (job->running_progs == job->stopped_progs)
348 statusString = "Stopped"; 389 status_string = "Stopped";
349 else 390 else
350 statusString = "Running"; 391 status_string = "Running";
351 392
352 printf(JOB_STATUS_FORMAT, job->jobId, statusString, job->text); 393 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
353 } 394 }
354 return EXIT_SUCCESS; 395 return EXIT_SUCCESS;
355} 396}
356 397
357 398
358/* built-in 'pwd' handler */ 399/* built-in 'pwd' handler */
359static int builtin_pwd(struct job *dummy, struct jobSet *junk) 400static int builtin_pwd(struct child_prog *dummy)
360{ 401{
361 getcwd(cwd, sizeof(char)*MAX_LINE); 402 getcwd(cwd, MAX_LINE);
362 fprintf(stdout, "%s\n", cwd); 403 fprintf(stdout, "%s\n", cwd);
363 return EXIT_SUCCESS; 404 return EXIT_SUCCESS;
364} 405}
365 406
366/* built-in 'export VAR=value' handler */ 407/* built-in 'export VAR=value' handler */
367static int builtin_export(struct job *cmd, struct jobSet *junk) 408static int builtin_export(struct child_prog *child)
368{ 409{
369 int res; 410 int res;
370 411
371 if (!cmd->progs[0].argv[1] == 1) { 412 if (child->argv[1] == NULL) {
372 return (builtin_env(cmd, junk)); 413 return (builtin_env(child));
373 } 414 }
374 res = putenv(cmd->progs[0].argv[1]); 415 res = putenv(child->argv[1]);
375 if (res) 416 if (res)
376 fprintf(stdout, "export: %s\n", strerror(errno)); 417 fprintf(stderr, "export: %s\n", strerror(errno));
377 return (res); 418 return (res);
378} 419}
379 420
380/* built-in 'read VAR' handler */ 421/* built-in 'read VAR' handler */
381static int builtin_read(struct job *cmd, struct jobSet *junk) 422static int builtin_read(struct child_prog *child)
382{ 423{
383 int res = 0, len, newlen; 424 int res = 0, len, newlen;
384 char *s; 425 char *s;
385 char string[MAX_READ]; 426 char string[MAX_READ];
386 427
387 if (cmd->progs[0].argv[1]) { 428 if (child->argv[1]) {
388 /* argument (VAR) given: put "VAR=" into buffer */ 429 /* argument (VAR) given: put "VAR=" into buffer */
389 strcpy(string, cmd->progs[0].argv[1]); 430 strcpy(string, child->argv[1]);
390 len = strlen(string); 431 len = strlen(string);
391 string[len++] = '='; 432 string[len++] = '=';
392 string[len] = '\0'; 433 string[len] = '\0';
@@ -403,7 +444,7 @@ static int builtin_read(struct job *cmd, struct jobSet *junk)
403 if((s = strdup(string))) 444 if((s = strdup(string)))
404 res = putenv(s); 445 res = putenv(s);
405 if (res) 446 if (res)
406 fprintf(stdout, "read: %s\n", strerror(errno)); 447 fprintf(stderr, "read: %s\n", strerror(errno));
407 } 448 }
408 else 449 else
409 fgets(string, sizeof(string), stdin); 450 fgets(string, sizeof(string), stdin);
@@ -413,111 +454,112 @@ static int builtin_read(struct job *cmd, struct jobSet *junk)
413 454
414#ifdef BB_FEATURE_SH_IF_EXPRESSIONS 455#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
415/* Built-in handler for 'if' commands */ 456/* Built-in handler for 'if' commands */
416static int builtin_if(struct job *cmd, struct jobSet *jobList) 457static int builtin_if(struct child_prog *child)
417{ 458{
459 struct job *cmd = child->family;
418 int status; 460 int status;
419 char* charptr1=cmd->text+3; /* skip over the leading 'if ' */ 461 char* charptr1=cmd->text+3; /* skip over the leading 'if ' */
420 462
421 /* Now run the 'if' command */ 463 /* Now run the 'if' command */
422 status=strlen(charptr1); 464 debug_printf( "job=%p entering builtin_if ('%s')-- context=%d\n", cmd, charptr1, cmd->job_context);
423 local_pending_command = xmalloc(status+1); 465 status = run_command_predicate(charptr1);
424 strncpy(local_pending_command, charptr1, status); 466 debug_printf( "if test returned ");
425 local_pending_command[status]='\0';
426 debug_printf(stderr, "'if' now testing '%s'\n", local_pending_command);
427 status = busy_loop(NULL); /* Frees local_pending_command */
428 debug_printf(stderr, "if test returned ");
429 if (status == 0) { 467 if (status == 0) {
430 debug_printf(stderr, "TRUE\n"); 468 debug_printf( "TRUE\n");
431 cmd->jobContext |= IF_TRUE_CONTEXT; 469 cmd->job_context |= IF_TRUE_CONTEXT;
432 } else { 470 } else {
433 debug_printf(stderr, "FALSE\n"); 471 debug_printf( "FALSE\n");
434 cmd->jobContext |= IF_FALSE_CONTEXT; 472 cmd->job_context |= IF_FALSE_CONTEXT;
435 } 473 }
474 debug_printf("job=%p builtin_if set job context to %x\n", cmd, cmd->job_context);
475 shell_context++;
436 476
437 return status; 477 return status;
438} 478}
439 479
440/* Built-in handler for 'then' (part of the 'if' command) */ 480/* Built-in handler for 'then' (part of the 'if' command) */
441static int builtin_then(struct job *cmd, struct jobSet *junk) 481static int builtin_then(struct child_prog *child)
442{ 482{
443 int status; 483 struct job *cmd = child->family;
444 char* charptr1=cmd->text+5; /* skip over the leading 'then ' */ 484 char* charptr1=cmd->text+5; /* skip over the leading 'then ' */
445 485
446 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { 486 debug_printf( "job=%p entering builtin_then ('%s')-- context=%d\n", cmd, charptr1, cmd->job_context);
447 error_msg("unexpected token `then'\n"); 487 if (! (cmd->job_context & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
488 shell_context = 0; /* Reset the shell's context on an error */
489 error_msg("%s `then'\n", syntax_err);
448 return EXIT_FAILURE; 490 return EXIT_FAILURE;
449 } 491 }
492
493 cmd->job_context |= THEN_EXP_CONTEXT;
494 debug_printf("job=%p builtin_then set job context to %x\n", cmd, cmd->job_context);
495
450 /* If the if result was FALSE, skip the 'then' stuff */ 496 /* If the if result was FALSE, skip the 'then' stuff */
451 if (cmd->jobContext & IF_FALSE_CONTEXT) { 497 if (cmd->job_context & IF_FALSE_CONTEXT) {
452 return EXIT_SUCCESS; 498 return EXIT_SUCCESS;
453 } 499 }
454 500
455 cmd->jobContext |= THEN_EXP_CONTEXT; 501 /* Seems the if result was TRUE, so run the 'then' command */
456 //printf("Hit an then -- jobContext=%d\n", cmd->jobContext); 502 debug_printf( "'then' now running '%s'\n", charptr1);
457 503
458 /* Now run the 'then' command */ 504 return(run_command_predicate(charptr1));
459 status=strlen(charptr1);
460 local_pending_command = xmalloc(status+1);
461 strncpy(local_pending_command, charptr1, status);
462 local_pending_command[status]='\0';
463 debug_printf(stderr, "'then' now running '%s'\n", charptr1);
464 return( busy_loop(NULL));
465} 505}
466 506
467/* Built-in handler for 'else' (part of the 'if' command) */ 507/* Built-in handler for 'else' (part of the 'if' command) */
468static int builtin_else(struct job *cmd, struct jobSet *junk) 508static int builtin_else(struct child_prog *child)
469{ 509{
470 int status; 510 struct job *cmd = child->family;
471 char* charptr1=cmd->text+5; /* skip over the leading 'else ' */ 511 char* charptr1=cmd->text+5; /* skip over the leading 'else ' */
472 512
473 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { 513 debug_printf( "job=%p entering builtin_else ('%s')-- context=%d\n", cmd, charptr1, cmd->job_context);
474 error_msg("unexpected token `else'\n"); 514
515 if (! (cmd->job_context & THEN_EXP_CONTEXT)) {
516 shell_context = 0; /* Reset the shell's context on an error */
517 error_msg("%s `else'\n", syntax_err);
475 return EXIT_FAILURE; 518 return EXIT_FAILURE;
476 } 519 }
477 /* If the if result was TRUE, skip the 'else' stuff */ 520 /* If the if result was TRUE, skip the 'else' stuff */
478 if (cmd->jobContext & IF_TRUE_CONTEXT) { 521 if (cmd->job_context & IF_TRUE_CONTEXT) {
479 return EXIT_SUCCESS; 522 return EXIT_SUCCESS;
480 } 523 }
481 524
482 cmd->jobContext |= ELSE_EXP_CONTEXT; 525 cmd->job_context |= ELSE_EXP_CONTEXT;
483 //printf("Hit an else -- jobContext=%d\n", cmd->jobContext); 526 debug_printf("job=%p builtin_else set job context to %x\n", child->family, cmd->job_context);
484 527
485 /* Now run the 'else' command */ 528 /* Now run the 'else' command */
486 status=strlen(charptr1); 529 debug_printf( "'else' now running '%s'\n", charptr1);
487 local_pending_command = xmalloc(status+1); 530 return(run_command_predicate(charptr1));
488 strncpy(local_pending_command, charptr1, status);
489 local_pending_command[status]='\0';
490 debug_printf(stderr, "'else' now running '%s'\n", charptr1);
491 return( busy_loop(NULL));
492} 531}
493 532
494/* Built-in handler for 'fi' (part of the 'if' command) */ 533/* Built-in handler for 'fi' (part of the 'if' command) */
495static int builtin_fi(struct job *cmd, struct jobSet *junk) 534static int builtin_fi(struct child_prog *child)
496{ 535{
497 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) { 536 struct job *cmd = child->family;
498 error_msg("unexpected token `fi'\n"); 537 debug_printf( "job=%p entering builtin_fi ('%s')-- context=%d\n", cmd, "", cmd->job_context);
538 if (! (cmd->job_context & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
539 shell_context = 0; /* Reset the shell's context on an error */
540 error_msg("%s `fi'\n", syntax_err);
499 return EXIT_FAILURE; 541 return EXIT_FAILURE;
500 } 542 }
501 /* Clear out the if and then context bits */ 543 /* Clear out the if and then context bits */
502 cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT); 544 cmd->job_context &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT);
503 debug_printf(stderr, "Hit an fi -- jobContext=%d\n", cmd->jobContext); 545 debug_printf("job=%p builtin_fi set job context to %x\n", cmd, cmd->job_context);
546 shell_context--;
504 return EXIT_SUCCESS; 547 return EXIT_SUCCESS;
505} 548}
506#endif 549#endif
507 550
508/* Built-in '.' handler (read-in and execute commands from file) */ 551/* Built-in '.' handler (read-in and execute commands from file) */
509static int builtin_source(struct job *cmd, struct jobSet *junk) 552static int builtin_source(struct child_prog *child)
510{ 553{
511 FILE *input; 554 FILE *input;
512 int status; 555 int status;
513 556
514 if (!cmd->progs[0].argv[1] == 1) 557 if (child->argv[1] == NULL)
515 return EXIT_FAILURE; 558 return EXIT_FAILURE;
516 559
517 input = fopen(cmd->progs[0].argv[1], "r"); 560 input = fopen(child->argv[1], "r");
518 if (!input) { 561 if (!input) {
519 fprintf(stdout, "Couldn't open file '%s'\n", 562 fprintf(stdout, "Couldn't open file '%s'\n", child->argv[1]);
520 cmd->progs[0].argv[1]);
521 return EXIT_FAILURE; 563 return EXIT_FAILURE;
522 } 564 }
523 565
@@ -528,48 +570,65 @@ static int builtin_source(struct job *cmd, struct jobSet *junk)
528} 570}
529 571
530/* built-in 'unset VAR' handler */ 572/* built-in 'unset VAR' handler */
531static int builtin_unset(struct job *cmd, struct jobSet *junk) 573static int builtin_unset(struct child_prog *child)
532{ 574{
533 if (!cmd->progs[0].argv[1] == 1) { 575 if (child->argv[1] == NULL) {
534 fprintf(stdout, "unset: parameter required.\n"); 576 fprintf(stdout, "unset: parameter required.\n");
535 return EXIT_FAILURE; 577 return EXIT_FAILURE;
536 } 578 }
537 unsetenv(cmd->progs[0].argv[1]); 579 unsetenv(child->argv[1]);
538 return EXIT_SUCCESS; 580 return EXIT_SUCCESS;
539} 581}
540 582
583/* currently used by if/then/else.
584 * Needlessly (?) forks and reparses the command line.
585 * But pseudo_exec on the pre-parsed args doesn't have the
586 * "fork, stick around until the child exits, and find it's return code"
587 * functionality. The fork is not needed if the predicate is
588 * non-forking builtin, and maybe not even if it's a forking builtin.
589 * applets pretty clearly need the fork.
590 */
591static int run_command_predicate(char *cmd)
592{
593 int n=strlen(cmd);
594 local_pending_command = xmalloc(n+1);
595 strncpy(local_pending_command, cmd, n);
596 local_pending_command[n]='\0';
597 return( busy_loop(NULL));
598}
599
541/* free up all memory from a job */ 600/* free up all memory from a job */
542static void freeJob(struct job *cmd) 601static void free_job(struct job *cmd)
543{ 602{
544 int i; 603 int i;
545 604
546 for (i = 0; i < cmd->numProgs; i++) { 605 for (i = 0; i < cmd->num_progs; i++) {
547 free(cmd->progs[i].argv); 606 free(cmd->progs[i].argv);
548 if (cmd->progs[i].redirections) 607 if (cmd->progs[i].redirects)
549 free(cmd->progs[i].redirections); 608 free(cmd->progs[i].redirects);
550 if (cmd->progs[i].freeGlob) 609 if (cmd->progs[i].free_glob)
551 globfree(&cmd->progs[i].globResult); 610 globfree(&cmd->progs[i].glob_result);
552 } 611 }
553 free(cmd->progs); 612 free(cmd->progs);
554 if (cmd->text) 613 if (cmd->text)
555 free(cmd->text); 614 free(cmd->text);
556 free(cmd->cmdBuf); 615 free(cmd->cmdbuf);
557 memset(cmd, 0, sizeof(struct job)); 616 memset(cmd, 0, sizeof(struct job));
558} 617}
559 618
560/* remove a job from the jobList */ 619/* remove a job from the job_list */
561static void removeJob(struct jobSet *jobList, struct job *job) 620static void remove_job(struct jobset *job_list, struct job *job)
562{ 621{
563 struct job *prevJob; 622 struct job *prevjob;
564 623
565 freeJob(job); 624 free_job(job);
566 if (job == jobList->head) { 625 if (job == job_list->head) {
567 jobList->head = job->next; 626 job_list->head = job->next;
568 } else { 627 } else {
569 prevJob = jobList->head; 628 prevjob = job_list->head;
570 while (prevJob->next != job) 629 while (prevjob->next != job)
571 prevJob = prevJob->next; 630 prevjob = prevjob->next;
572 prevJob->next = job->next; 631 prevjob->next = job->next;
573 } 632 }
574 633
575 free(job); 634 free(job);
@@ -577,19 +636,19 @@ static void removeJob(struct jobSet *jobList, struct job *job)
577 636
578/* Checks to see if any background processes have exited -- if they 637/* Checks to see if any background processes have exited -- if they
579 have, figure out why and see if a job has completed */ 638 have, figure out why and see if a job has completed */
580static void checkJobs(struct jobSet *jobList) 639static void checkjobs(struct jobset *job_list)
581{ 640{
582 struct job *job; 641 struct job *job;
583 pid_t childpid; 642 pid_t childpid;
584 int status; 643 int status;
585 int progNum = 0; 644 int prognum = 0;
586 645
587 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { 646 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
588 for (job = jobList->head; job; job = job->next) { 647 for (job = job_list->head; job; job = job->next) {
589 progNum = 0; 648 prognum = 0;
590 while (progNum < job->numProgs && 649 while (prognum < job->num_progs &&
591 job->progs[progNum].pid != childpid) progNum++; 650 job->progs[prognum].pid != childpid) prognum++;
592 if (progNum < job->numProgs) 651 if (prognum < job->num_progs)
593 break; 652 break;
594 } 653 }
595 654
@@ -599,20 +658,20 @@ static void checkJobs(struct jobSet *jobList)
599 658
600 if (WIFEXITED(status) || WIFSIGNALED(status)) { 659 if (WIFEXITED(status) || WIFSIGNALED(status)) {
601 /* child exited */ 660 /* child exited */
602 job->runningProgs--; 661 job->running_progs--;
603 job->progs[progNum].pid = 0; 662 job->progs[prognum].pid = 0;
604 663
605 if (!job->runningProgs) { 664 if (!job->running_progs) {
606 printf(JOB_STATUS_FORMAT, job->jobId, "Done", job->text); 665 printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text);
607 removeJob(jobList, job); 666 remove_job(job_list, job);
608 } 667 }
609 } else { 668 } else {
610 /* child stopped */ 669 /* child stopped */
611 job->stoppedProgs++; 670 job->stopped_progs++;
612 job->progs[progNum].isStopped = 1; 671 job->progs[prognum].is_stopped = 1;
613 672
614 if (job->stoppedProgs == job->numProgs) { 673 if (job->stopped_progs == job->num_progs) {
615 printf(JOB_STATUS_FORMAT, job->jobId, "Stopped", 674 printf(JOB_STATUS_FORMAT, job->jobid, "Stopped",
616 job->text); 675 job->text);
617 } 676 }
618 } 677 }
@@ -622,14 +681,14 @@ static void checkJobs(struct jobSet *jobList)
622 perror("waitpid"); 681 perror("waitpid");
623} 682}
624 683
625static int setupRedirections(struct childProgram *prog) 684static int setup_redirects(struct child_prog *prog)
626{ 685{
627 int i; 686 int i;
628 int openfd; 687 int openfd;
629 int mode = O_RDONLY; 688 int mode = O_RDONLY;
630 struct redirectionSpecifier *redir = prog->redirections; 689 struct redir_struct *redir = prog->redirects;
631 690
632 for (i = 0; i < prog->numRedirections; i++, redir++) { 691 for (i = 0; i < prog->num_redirects; i++, redir++) {
633 switch (redir->type) { 692 switch (redir->type) {
634 case REDIRECT_INPUT: 693 case REDIRECT_INPUT:
635 mode = O_RDONLY; 694 mode = O_RDONLY;
@@ -661,7 +720,7 @@ static int setupRedirections(struct childProgram *prog)
661} 720}
662 721
663 722
664static int getCommand(FILE * source, char *command) 723static int get_command(FILE * source, char *command)
665{ 724{
666 char user[9],buf[255],*s; 725 char user[9],buf[255],*s;
667 726
@@ -676,15 +735,20 @@ static int getCommand(FILE * source, char *command)
676 return 1; 735 return 1;
677 } 736 }
678 737
679 /* get User Name and setup prompt */ 738 if (shell_context == 0) {
680 strcpy(prompt,( geteuid() != 0 ) ? "$ ":"# "); 739 /* get User Name and setup prompt */
681 my_getpwuid(user, geteuid()); 740 strcpy(prompt,( geteuid() != 0 ) ? "$ ":"# ");
682 741 my_getpwuid(user, geteuid());
683 /* get HostName */ 742
684 gethostname(buf, 255); 743 /* get HostName */
685 s = strchr(buf, '.'); 744 gethostname(buf, 255);
686 if (s) 745 s = strchr(buf, '.');
687 *s = 0; 746 if (s) {
747 *s = 0;
748 }
749 } else {
750 strcpy(prompt,"> ");
751 }
688 752
689 if (source == stdin) { 753 if (source == stdin) {
690#ifdef BB_FEATURE_SH_COMMAND_EDITING 754#ifdef BB_FEATURE_SH_COMMAND_EDITING
@@ -698,14 +762,24 @@ static int getCommand(FILE * source, char *command)
698 */ 762 */
699 cmdedit_init(); 763 cmdedit_init();
700 signal(SIGWINCH, win_changed); 764 signal(SIGWINCH, win_changed);
701 len=fprintf(stdout, "[%s@%s %s]%s", user, buf, 765 debug_printf( "in get_command() -- job_context=%d\n", shell_context);
702 get_last_path_component(cwd), prompt); 766 fflush(stdout);
767 if (shell_context == 0) {
768 len=fprintf(stdout, "[%s@%s %s]%s", user, buf,
769 get_last_path_component(cwd), prompt);
770 } else {
771 len=fprintf(stdout, "%s", prompt);
772 }
703 fflush(stdout); 773 fflush(stdout);
704 promptStr=(char*)xmalloc(sizeof(char)*(len+1)); 774 prompt_str=(char*)xmalloc(sizeof(char)*(len+1));
705 sprintf(promptStr, "[%s@%s %s]%s", user, buf, 775 if (shell_context == 0) {
706 get_last_path_component(cwd), prompt); 776 sprintf(prompt_str, "[%s@%s %s]%s", user, buf,
707 cmdedit_read_input(promptStr, command); 777 get_last_path_component(cwd), prompt);
708 free( promptStr); 778 } else {
779 sprintf(prompt_str, "%s", prompt);
780 }
781 cmdedit_read_input(prompt_str, command);
782 free( prompt_str);
709 cmdedit_terminate(); 783 cmdedit_terminate();
710 signal(SIGWINCH, SIG_DFL); 784 signal(SIGWINCH, SIG_DFL);
711 return 0; 785 return 0;
@@ -756,21 +830,21 @@ static char* itoa(register int i)
756} 830}
757#endif 831#endif
758 832
759static void globLastArgument(struct childProgram *prog, int *argcPtr, 833static void expand_argument(struct child_prog *prog, int *argcPtr,
760 int *argcAllocedPtr) 834 int *argv_alloced_ptr)
761{ 835{
762 int argc_l = *argcPtr; 836 int argc_l = *argcPtr;
763 int argcAlloced = *argcAllocedPtr; 837 int argv_alloced = *argv_alloced_ptr;
764 int rc; 838 int rc;
765 int flags; 839 int flags;
766 int i; 840 int i;
767 char *src, *dst, *var; 841 char *src, *dst, *var;
768 842
769 if (argc_l > 1) { /* cmd->globResult is already initialized */ 843 if (argc_l > 1) { /* cmd->glob_result is already initialized */
770 flags = GLOB_APPEND; 844 flags = GLOB_APPEND;
771 i = prog->globResult.gl_pathc; 845 i = prog->glob_result.gl_pathc;
772 } else { 846 } else {
773 prog->freeGlob = 1; 847 prog->free_glob = 1;
774 flags = 0; 848 flags = 0;
775 i = 0; 849 i = 0;
776 } 850 }
@@ -783,7 +857,7 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
783 else { 857 else {
784 switch(*(prog->argv[argc_l - 1] + 1)) { 858 switch(*(prog->argv[argc_l - 1] + 1)) {
785 case '?': 859 case '?':
786 prog->argv[argc_l - 1] = itoa(lastReturnCode); 860 prog->argv[argc_l - 1] = itoa(last_return_code);
787 break; 861 break;
788 case '$': 862 case '$':
789 prog->argv[argc_l - 1] = itoa(getpid()); 863 prog->argv[argc_l - 1] = itoa(getpid());
@@ -792,10 +866,10 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
792 prog->argv[argc_l - 1] = itoa(argc-1); 866 prog->argv[argc_l - 1] = itoa(argc-1);
793 break; 867 break;
794 case '!': 868 case '!':
795 if (lastBgPid==-1) 869 if (last_bg_pid==-1)
796 *(prog->argv[argc_l - 1])='\0'; 870 *(prog->argv[argc_l - 1])='\0';
797 else 871 else
798 prog->argv[argc_l - 1] = itoa(lastBgPid); 872 prog->argv[argc_l - 1] = itoa(last_bg_pid);
799 break; 873 break;
800 case '0':case '1':case '2':case '3':case '4': 874 case '0':case '1':case '2':case '3':case '4':
801 case '5':case '6':case '7':case '8':case '9': 875 case '5':case '6':case '7':case '8':case '9':
@@ -814,14 +888,14 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
814 } 888 }
815 889
816 if (strpbrk(prog->argv[argc_l - 1],"*[]?")!= NULL){ 890 if (strpbrk(prog->argv[argc_l - 1],"*[]?")!= NULL){
817 rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult); 891 rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->glob_result);
818 if (rc == GLOB_NOSPACE) { 892 if (rc == GLOB_NOSPACE) {
819 error_msg("out of space during glob operation\n"); 893 error_msg("out of space during glob operation\n");
820 return; 894 return;
821 } else if (rc == GLOB_NOMATCH || 895 } else if (rc == GLOB_NOMATCH ||
822 (!rc && (prog->globResult.gl_pathc - i) == 1 && 896 (!rc && (prog->glob_result.gl_pathc - i) == 1 &&
823 strcmp(prog->argv[argc_l - 1], 897 strcmp(prog->argv[argc_l - 1],
824 prog->globResult.gl_pathv[i]) == 0)) { 898 prog->glob_result.gl_pathv[i]) == 0)) {
825 /* we need to remove whatever \ quoting is still present */ 899 /* we need to remove whatever \ quoting is still present */
826 src = dst = prog->argv[argc_l - 1]; 900 src = dst = prog->argv[argc_l - 1];
827 while (*src) { 901 while (*src) {
@@ -835,11 +909,11 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
835 } 909 }
836 *dst = '\0'; 910 *dst = '\0';
837 } else if (!rc) { 911 } else if (!rc) {
838 argcAlloced += (prog->globResult.gl_pathc - i); 912 argv_alloced += (prog->glob_result.gl_pathc - i);
839 prog->argv = xrealloc(prog->argv, argcAlloced * sizeof(*prog->argv)); 913 prog->argv = xrealloc(prog->argv, argv_alloced * sizeof(*prog->argv));
840 memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i, 914 memcpy(prog->argv + (argc_l - 1), prog->glob_result.gl_pathv + i,
841 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); 915 sizeof(*(prog->argv)) * (prog->glob_result.gl_pathc - i));
842 argc_l += (prog->globResult.gl_pathc - i - 1); 916 argc_l += (prog->glob_result.gl_pathc - i - 1);
843 } 917 }
844 }else{ 918 }else{
845 src = dst = prog->argv[argc_l - 1]; 919 src = dst = prog->argv[argc_l - 1];
@@ -854,68 +928,69 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
854 } 928 }
855 *dst = '\0'; 929 *dst = '\0';
856 930
857 prog->globResult.gl_pathc=0; 931 prog->glob_result.gl_pathc=0;
858 if (flags==0) 932 if (flags==0)
859 prog->globResult.gl_pathv=NULL; 933 prog->glob_result.gl_pathv=NULL;
860 } 934 }
861 *argcAllocedPtr = argcAlloced; 935 *argv_alloced_ptr = argv_alloced;
862 *argcPtr = argc_l; 936 *argcPtr = argc_l;
863} 937}
864 938
865/* Return cmd->numProgs as 0 if no command is present (e.g. an empty 939/* Return cmd->num_progs as 0 if no command is present (e.g. an empty
866 line). If a valid command is found, commandPtr is set to point to 940 line). If a valid command is found, command_ptr is set to point to
867 the beginning of the next command (if the original command had more 941 the beginning of the next command (if the original command had more
868 then one job associated with it) or NULL if no more commands are 942 then one job associated with it) or NULL if no more commands are
869 present. */ 943 present. */
870static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg) 944static int parse_command(char **command_ptr, struct job *job, int *inbg)
871{ 945{
872 char *command; 946 char *command;
873 char *returnCommand = NULL; 947 char *return_command = NULL;
874 char *src, *buf, *chptr; 948 char *src, *buf, *chptr;
875 int argc_l = 0; 949 int argc_l = 0;
876 int done = 0; 950 int done = 0;
877 int argvAlloced; 951 int argv_alloced;
878 int i; 952 int i;
879 char quote = '\0'; 953 char quote = '\0';
880 int count; 954 int count;
881 struct childProgram *prog; 955 struct child_prog *prog;
882 956
883 /* skip leading white space */ 957 /* skip leading white space */
884 while (**commandPtr && isspace(**commandPtr)) 958 while (**command_ptr && isspace(**command_ptr))
885 (*commandPtr)++; 959 (*command_ptr)++;
886 960
887 /* this handles empty lines or leading '#' characters */ 961 /* this handles empty lines or leading '#' characters */
888 if (!**commandPtr || (**commandPtr == '#')) { 962 if (!**command_ptr || (**command_ptr == '#')) {
889 job->numProgs=0; 963 job->num_progs=0;
890 return 0; 964 return 0;
891 } 965 }
892 966
893 *inBg = 0; 967 *inbg = 0;
894 job->numProgs = 1; 968 job->num_progs = 1;
895 job->progs = xmalloc(sizeof(*job->progs)); 969 job->progs = xmalloc(sizeof(*job->progs));
896 970
897 /* We set the argv elements to point inside of this string. The 971 /* We set the argv elements to point inside of this string. The
898 memory is freed by freeJob(). Allocate twice the original 972 memory is freed by free_job(). Allocate twice the original
899 length in case we need to quote every single character. 973 length in case we need to quote every single character.
900 974
901 Getting clean memory relieves us of the task of NULL 975 Getting clean memory relieves us of the task of NULL
902 terminating things and makes the rest of this look a bit 976 terminating things and makes the rest of this look a bit
903 cleaner (though it is, admittedly, a tad less efficient) */ 977 cleaner (though it is, admittedly, a tad less efficient) */
904 job->cmdBuf = command = xcalloc(2*strlen(*commandPtr) + 1, sizeof(char)); 978 job->cmdbuf = command = xcalloc(2*strlen(*command_ptr) + 1, sizeof(char));
905 job->text = NULL; 979 job->text = NULL;
906 980
907 prog = job->progs; 981 prog = job->progs;
908 prog->numRedirections = 0; 982 prog->num_redirects = 0;
909 prog->redirections = NULL; 983 prog->redirects = NULL;
910 prog->freeGlob = 0; 984 prog->free_glob = 0;
911 prog->isStopped = 0; 985 prog->is_stopped = 0;
986 prog->family = job;
912 987
913 argvAlloced = 5; 988 argv_alloced = 5;
914 prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced); 989 prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
915 prog->argv[0] = job->cmdBuf; 990 prog->argv[0] = job->cmdbuf;
916 991
917 buf = command; 992 buf = command;
918 src = *commandPtr; 993 src = *command_ptr;
919 while (*src && !done) { 994 while (*src && !done) {
920 if (quote == *src) { 995 if (quote == *src) {
921 quote = '\0'; 996 quote = '\0';
@@ -924,7 +999,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
924 src++; 999 src++;
925 if (!*src) { 1000 if (!*src) {
926 error_msg("character expected after \\\n"); 1001 error_msg("character expected after \\\n");
927 freeJob(job); 1002 free_job(job);
928 return 1; 1003 return 1;
929 } 1004 }
930 1005
@@ -940,13 +1015,13 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
940 if (*prog->argv[argc_l]) { 1015 if (*prog->argv[argc_l]) {
941 buf++, argc_l++; 1016 buf++, argc_l++;
942 /* +1 here leaves room for the NULL which ends argv */ 1017 /* +1 here leaves room for the NULL which ends argv */
943 if ((argc_l + 1) == argvAlloced) { 1018 if ((argc_l + 1) == argv_alloced) {
944 argvAlloced += 5; 1019 argv_alloced += 5;
945 prog->argv = xrealloc(prog->argv, 1020 prog->argv = xrealloc(prog->argv,
946 sizeof(*prog->argv) * 1021 sizeof(*prog->argv) *
947 argvAlloced); 1022 argv_alloced);
948 } 1023 }
949 globLastArgument(prog, &argc_l, &argvAlloced); 1024 expand_argument(prog, &argc_l, &argv_alloced);
950 prog->argv[argc_l] = buf; 1025 prog->argv[argc_l] = buf;
951 } 1026 }
952 } else 1027 } else
@@ -963,42 +1038,42 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
963 done = 1; 1038 done = 1;
964 break; 1039 break;
965 1040
966 case '>': /* redirections */ 1041 case '>': /* redirects */
967 case '<': 1042 case '<':
968 i = prog->numRedirections++; 1043 i = prog->num_redirects++;
969 prog->redirections = xrealloc(prog->redirections, 1044 prog->redirects = xrealloc(prog->redirects,
970 sizeof(*prog->redirections) * 1045 sizeof(*prog->redirects) *
971 (i + 1)); 1046 (i + 1));
972 1047
973 prog->redirections[i].fd = -1; 1048 prog->redirects[i].fd = -1;
974 if (buf != prog->argv[argc_l]) { 1049 if (buf != prog->argv[argc_l]) {
975 /* the stuff before this character may be the file number 1050 /* the stuff before this character may be the file number
976 being redirected */ 1051 being redirected */
977 prog->redirections[i].fd = 1052 prog->redirects[i].fd =
978 strtol(prog->argv[argc_l], &chptr, 10); 1053 strtol(prog->argv[argc_l], &chptr, 10);
979 1054
980 if (*chptr && *prog->argv[argc_l]) { 1055 if (*chptr && *prog->argv[argc_l]) {
981 buf++, argc_l++; 1056 buf++, argc_l++;
982 globLastArgument(prog, &argc_l, &argvAlloced); 1057 expand_argument(prog, &argc_l, &argv_alloced);
983 prog->argv[argc_l] = buf; 1058 prog->argv[argc_l] = buf;
984 } 1059 }
985 } 1060 }
986 1061
987 if (prog->redirections[i].fd == -1) { 1062 if (prog->redirects[i].fd == -1) {
988 if (*src == '>') 1063 if (*src == '>')
989 prog->redirections[i].fd = 1; 1064 prog->redirects[i].fd = 1;
990 else 1065 else
991 prog->redirections[i].fd = 0; 1066 prog->redirects[i].fd = 0;
992 } 1067 }
993 1068
994 if (*src++ == '>') { 1069 if (*src++ == '>') {
995 if (*src == '>') 1070 if (*src == '>')
996 prog->redirections[i].type = 1071 prog->redirects[i].type =
997 REDIRECT_APPEND, src++; 1072 REDIRECT_APPEND, src++;
998 else 1073 else
999 prog->redirections[i].type = REDIRECT_OVERWRITE; 1074 prog->redirects[i].type = REDIRECT_OVERWRITE;
1000 } else { 1075 } else {
1001 prog->redirections[i].type = REDIRECT_INPUT; 1076 prog->redirects[i].type = REDIRECT_INPUT;
1002 } 1077 }
1003 1078
1004 /* This isn't POSIX sh compliant. Oh well. */ 1079 /* This isn't POSIX sh compliant. Oh well. */
@@ -1008,12 +1083,12 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1008 1083
1009 if (!*chptr) { 1084 if (!*chptr) {
1010 error_msg("file name expected after %c\n", *src); 1085 error_msg("file name expected after %c\n", *src);
1011 freeJob(job); 1086 free_job(job);
1012 job->numProgs=0; 1087 job->num_progs=0;
1013 return 1; 1088 return 1;
1014 } 1089 }
1015 1090
1016 prog->redirections[i].filename = buf; 1091 prog->redirects[i].filename = buf;
1017 while (*chptr && !isspace(*chptr)) 1092 while (*chptr && !isspace(*chptr))
1018 *buf++ = *chptr++; 1093 *buf++ = *chptr++;
1019 1094
@@ -1027,25 +1102,26 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1027 argc_l++; 1102 argc_l++;
1028 if (!argc_l) { 1103 if (!argc_l) {
1029 error_msg("empty command in pipe\n"); 1104 error_msg("empty command in pipe\n");
1030 freeJob(job); 1105 free_job(job);
1031 job->numProgs=0; 1106 job->num_progs=0;
1032 return 1; 1107 return 1;
1033 } 1108 }
1034 prog->argv[argc_l] = NULL; 1109 prog->argv[argc_l] = NULL;
1035 1110
1036 /* and start the next */ 1111 /* and start the next */
1037 job->numProgs++; 1112 job->num_progs++;
1038 job->progs = xrealloc(job->progs, 1113 job->progs = xrealloc(job->progs,
1039 sizeof(*job->progs) * job->numProgs); 1114 sizeof(*job->progs) * job->num_progs);
1040 prog = job->progs + (job->numProgs - 1); 1115 prog = job->progs + (job->num_progs - 1);
1041 prog->numRedirections = 0; 1116 prog->num_redirects = 0;
1042 prog->redirections = NULL; 1117 prog->redirects = NULL;
1043 prog->freeGlob = 0; 1118 prog->free_glob = 0;
1044 prog->isStopped = 0; 1119 prog->is_stopped = 0;
1120 prog->family = job;
1045 argc_l = 0; 1121 argc_l = 0;
1046 1122
1047 argvAlloced = 5; 1123 argv_alloced = 5;
1048 prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced); 1124 prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
1049 prog->argv[0] = ++buf; 1125 prog->argv[0] = ++buf;
1050 1126
1051 src++; 1127 src++;
@@ -1054,8 +1130,8 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1054 1130
1055 if (!*src) { 1131 if (!*src) {
1056 error_msg("empty command in pipe\n"); 1132 error_msg("empty command in pipe\n");
1057 freeJob(job); 1133 free_job(job);
1058 job->numProgs=0; 1134 job->num_progs=0;
1059 return 1; 1135 return 1;
1060 } 1136 }
1061 src--; /* we'll ++ it at the end of the loop */ 1137 src--; /* we'll ++ it at the end of the loop */
@@ -1063,10 +1139,10 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1063 break; 1139 break;
1064 1140
1065 case '&': /* background */ 1141 case '&': /* background */
1066 *inBg = 1; 1142 *inbg = 1;
1067 case ';': /* multiple commands */ 1143 case ';': /* multiple commands */
1068 done = 1; 1144 done = 1;
1069 returnCommand = *commandPtr + (src - *commandPtr) + 1; 1145 return_command = *command_ptr + (src - *command_ptr) + 1;
1070 break; 1146 break;
1071 1147
1072#ifdef BB_FEATURE_SH_BACKTICKS 1148#ifdef BB_FEATURE_SH_BACKTICKS
@@ -1075,15 +1151,15 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1075 { 1151 {
1076 char* charptr1=NULL, *charptr2; 1152 char* charptr1=NULL, *charptr2;
1077 char* ptr=NULL; 1153 char* ptr=NULL;
1078 struct job *newJob; 1154 struct job *newjob;
1079 struct jobSet njobList = { NULL, NULL }; 1155 struct jobset njob_list = { NULL, NULL };
1080 int pipefd[2]; 1156 int pipefd[2];
1081 int size; 1157 int size;
1082 1158
1083 ptr=strchr(++src, '`'); 1159 ptr=strchr(++src, '`');
1084 if (ptr==NULL) { 1160 if (ptr==NULL) {
1085 fprintf(stderr, "Unmatched '`' in command\n"); 1161 fprintf(stderr, "Unmatched '`' in command\n");
1086 freeJob(job); 1162 free_job(job);
1087 return 1; 1163 return 1;
1088 } 1164 }
1089 1165
@@ -1091,15 +1167,17 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1091 charptr1 = charptr2 = xmalloc(1+ptr-src); 1167 charptr1 = charptr2 = xmalloc(1+ptr-src);
1092 memcpy(charptr1, src, ptr-src); 1168 memcpy(charptr1, src, ptr-src);
1093 charptr1[ptr-src] = '\0'; 1169 charptr1[ptr-src] = '\0';
1094 newJob = xmalloc(sizeof(struct job)); 1170 newjob = xmalloc(sizeof(struct job));
1171 newjob->job_list = &njob_list;
1095 /* Now parse and run the backticked command */ 1172 /* Now parse and run the backticked command */
1096 if (!parseCommand(&charptr1, newJob, &njobList, inBg) 1173 if (!parse_command(&charptr1, newjob, inbg)
1097 && newJob->numProgs) { 1174 && newjob->num_progs) {
1098 pipe(pipefd); 1175 pipe(pipefd);
1099 runCommand(newJob, &njobList, 0, pipefd); 1176 run_command(newjob, 0, pipefd);
1100 } 1177 }
1101 checkJobs(jobList); 1178 checkjobs(job->job_list);
1102 freeJob(newJob); 1179 free_job(newjob); /* doesn't actually free newjob,
1180 looks like a memory leak */
1103 free(charptr2); 1181 free(charptr2);
1104 1182
1105 /* Make a copy of any stuff left over in the command 1183 /* Make a copy of any stuff left over in the command
@@ -1113,10 +1191,9 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1113 --src; 1191 --src;
1114 charptr1 = xmalloc(BUFSIZ); 1192 charptr1 = xmalloc(BUFSIZ);
1115 while ( (size=full_read(pipefd[0], charptr1, BUFSIZ-1)) >0) { 1193 while ( (size=full_read(pipefd[0], charptr1, BUFSIZ-1)) >0) {
1116 int newSize=src - *commandPtr + size + 1 + strlen(charptr2); 1194 int newsize=src - *command_ptr + size + 1 + strlen(charptr2);
1117 if (newSize > BUFSIZ) { 1195 if (newsize > BUFSIZ) {
1118 *commandPtr=xrealloc(*commandPtr, src - *commandPtr + 1196 *command_ptr=xrealloc(*command_ptr, newsize);
1119 size + 1 + strlen(charptr2));
1120 } 1197 }
1121 memcpy(src, charptr1, size); 1198 memcpy(src, charptr1, size);
1122 src+=size; 1199 src+=size;
@@ -1126,16 +1203,20 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1126 if (*(src-1)=='\n') 1203 if (*(src-1)=='\n')
1127 --src; 1204 --src;
1128 1205
1129 /* Now paste into the *commandPtr all the stuff 1206 /* Now paste into the *command_ptr all the stuff
1130 * leftover after the second backtick */ 1207 * leftover after the second backtick */
1131 memcpy(src, charptr2, strlen(charptr2)+1); 1208 memcpy(src, charptr2, strlen(charptr2)+1);
1132 free(charptr2); 1209 free(charptr2);
1133 1210
1134 /* Now recursively call parseCommand to deal with the new 1211 /* Now recursively call parse_command to deal with the new
1135 * and improved version of the command line with the backtick 1212 * and improved version of the command line with the backtick
1136 * results expanded in place... */ 1213 * results expanded in place... */
1137 freeJob(job); 1214 {
1138 return(parseCommand(commandPtr, job, jobList, inBg)); 1215 struct jobset *jl=job->job_list;
1216 free_job(job);
1217 job->job_list = jl;
1218 }
1219 return(parse_command(command_ptr, job, inbg));
1139 } 1220 }
1140 break; 1221 break;
1141#endif // BB_FEATURE_SH_BACKTICKS 1222#endif // BB_FEATURE_SH_BACKTICKS
@@ -1143,9 +1224,37 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1143 case '\\': 1224 case '\\':
1144 src++; 1225 src++;
1145 if (!*src) { 1226 if (!*src) {
1227/* This is currently a little broken... */
1228#ifdef HANDLE_CONTINUATION_CHARS
1229 /* They fed us a continuation char, so continue reading stuff
1230 * on the next line, then tack that onto the end of the current
1231 * command */
1232 char *command;
1233 int newsize;
1234 printf("erik: found a continue char at EOL...\n");
1235 command = (char *) xcalloc(BUFSIZ, sizeof(char));
1236 if (get_command(input, command)) {
1237 error_msg("character expected after \\\n");
1238 free(command);
1239 free_job(job);
1240 return 1;
1241 }
1242 newsize = strlen(*command_ptr) + strlen(command) + 2;
1243 if (newsize > BUFSIZ) {
1244 printf("erik: doing realloc\n");
1245 *command_ptr=xrealloc(*command_ptr, newsize);
1246 }
1247 printf("erik: A: *command_ptr='%s'\n", *command_ptr);
1248 memcpy(--src, command, strlen(command));
1249 printf("erik: B: *command_ptr='%s'\n", *command_ptr);
1250 free(command);
1251 break;
1252#else
1146 error_msg("character expected after \\\n"); 1253 error_msg("character expected after \\\n");
1147 freeJob(job); 1254 free(command);
1255 free_job(job);
1148 return 1; 1256 return 1;
1257#endif
1149 } 1258 }
1150 if (*src == '*' || *src == '[' || *src == ']' 1259 if (*src == '*' || *src == '[' || *src == ']'
1151 || *src == '?') *buf++ = '\\'; 1260 || *src == '?') *buf++ = '\\';
@@ -1159,76 +1268,187 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
1159 1268
1160 if (*prog->argv[argc_l]) { 1269 if (*prog->argv[argc_l]) {
1161 argc_l++; 1270 argc_l++;
1162 globLastArgument(prog, &argc_l, &argvAlloced); 1271 expand_argument(prog, &argc_l, &argv_alloced);
1163 } 1272 }
1164 if (!argc_l) { 1273 if (!argc_l) {
1165 freeJob(job); 1274 free_job(job);
1166 return 0; 1275 return 0;
1167 } 1276 }
1168 prog->argv[argc_l] = NULL; 1277 prog->argv[argc_l] = NULL;
1169 1278
1170 if (!returnCommand) { 1279 if (!return_command) {
1171 job->text = xmalloc(strlen(*commandPtr) + 1); 1280 job->text = xmalloc(strlen(*command_ptr) + 1);
1172 strcpy(job->text, *commandPtr); 1281 strcpy(job->text, *command_ptr);
1173 } else { 1282 } else {
1174 /* This leaves any trailing spaces, which is a bit sloppy */ 1283 /* This leaves any trailing spaces, which is a bit sloppy */
1175 count = returnCommand - *commandPtr; 1284 count = return_command - *command_ptr;
1176 job->text = xmalloc(count + 1); 1285 job->text = xmalloc(count + 1);
1177 strncpy(job->text, *commandPtr, count); 1286 strncpy(job->text, *command_ptr, count);
1178 job->text[count] = '\0'; 1287 job->text[count] = '\0';
1179 } 1288 }
1180 1289
1181 *commandPtr = returnCommand; 1290 *command_ptr = return_command;
1182 1291
1183 return 0; 1292 return 0;
1184} 1293}
1185 1294
1186static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]) 1295/* Run the child_prog, no matter what kind of command it uses.
1296 */
1297static int pseudo_exec(struct child_prog *child)
1187{ 1298{
1188 struct job *theJob; 1299 struct built_in_command *x;
1189 int i;
1190 int nextin, nextout;
1191 int pipefds[2]; /* pipefd[0] is for reading */
1192 struct builtInCommand *x;
1193#ifdef BB_FEATURE_SH_STANDALONE_SHELL 1300#ifdef BB_FEATURE_SH_STANDALONE_SHELL
1194 struct BB_applet search_applet, *applet; 1301 struct BB_applet search_applet, *applet;
1195#endif 1302#endif
1196 1303
1304 /* Check if the command matches any of the forking builtins.
1305 * XXX It would probably be wise to check for non-forking builtins
1306 * here as well, since in some context the non-forking path
1307 * is disabled or bypassed. See comment in run_command.
1308 */
1309 for (x = bltins_forking; x->cmd; x++) {
1310 if (strcmp(child->argv[0], x->cmd) == 0) {
1311 applet_name=x->cmd;
1312 exit (x->function(child));
1313 }
1314 }
1315#ifdef BB_FEATURE_SH_STANDALONE_SHELL
1316 /* Check if the command matches any busybox internal
1317 * commands ("applets") here. Following discussions from
1318 * November 2000 on busybox@opensource.lineo.com, don't use
1319 * get_last_path_component(). This way explicit (with
1320 * slashes) filenames will never be interpreted as an
1321 * applet, just like with builtins. This way the user can
1322 * override an applet with an explicit filename reference.
1323 * The only downside to this change is that an explicit
1324 * /bin/foo invocation will fork and exec /bin/foo, even if
1325 * /bin/foo is a symlink to busybox.
1326 */
1327 search_applet.name = child->argv[0];
1328
1329#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
1330 /* If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then
1331 * if you run /bin/cat, it will use BusyBox cat even if
1332 * /bin/cat exists on the filesystem and is _not_ busybox.
1333 * Some systems want this, others do not. Choose wisely. :-)
1334 */
1335 search_applet.name = get_last_path_component(search_applet.name);
1336#endif
1337
1338 /* Do a binary search to find the applet entry given the name. */
1339 applet = bsearch(&search_applet, applets, NUM_APPLETS,
1340 sizeof(struct BB_applet), applet_name_compare);
1341 if (applet != NULL) {
1342 int argc_l;
1343 char** argv=child->argv;
1344 for(argc_l=0;*argv!=NULL; argv++, argc_l++);
1345 applet_name=applet->name;
1346 optind = 1;
1347 exit((*(applet->main)) (argc_l, child->argv));
1348 }
1349#endif
1350
1351 execvp(child->argv[0], child->argv);
1352 error_msg_and_die("%s: %s\n", child->argv[0],
1353 strerror(errno));
1354}
1355
1356static void insert_job(struct job *newjob, int inbg)
1357{
1358 struct job *thejob;
1359 struct jobset *job_list=newjob->job_list;
1360
1361 /* find the ID for thejob to use */
1362 newjob->jobid = 1;
1363 for (thejob = job_list->head; thejob; thejob = thejob->next)
1364 if (thejob->jobid >= newjob->jobid)
1365 newjob->jobid = thejob->jobid + 1;
1366
1367 /* add thejob to the list of running jobs */
1368 if (!job_list->head) {
1369 thejob = job_list->head = xmalloc(sizeof(*thejob));
1370 } else {
1371 for (thejob = job_list->head; thejob->next; thejob = thejob->next) /* nothing */;
1372 thejob->next = xmalloc(sizeof(*thejob));
1373 thejob = thejob->next;
1374 }
1375
1376 *thejob = *newjob; /* physically copy the struct job */
1377 thejob->next = NULL;
1378 thejob->running_progs = thejob->num_progs;
1379 thejob->stopped_progs = 0;
1380
1381 if (inbg) {
1382 /* we don't wait for background thejobs to return -- append it
1383 to the list of backgrounded thejobs and leave it alone */
1384 printf("[%d] %d\n", thejob->jobid,
1385 newjob->progs[newjob->num_progs - 1].pid);
1386#ifdef BB_FEATURE_SH_ENVIRONMENT
1387 last_bg_pid=newjob->progs[newjob->num_progs - 1].pid;
1388#endif
1389 } else {
1390 newjob->job_list->fg = thejob;
1391
1392 /* move the new process group into the foreground */
1393 /* suppress messages when run from /linuxrc mag@sysgo.de */
1394 if (tcsetpgrp(0, newjob->pgrp) && errno != ENOTTY)
1395 perror("tcsetpgrp");
1396 }
1397}
1398
1399static int run_command(struct job *newjob, int inbg, int outpipe[2])
1400{
1401 /* struct job *thejob; */
1402 int i;
1403 int nextin, nextout;
1404 int pipefds[2]; /* pipefd[0] is for reading */
1405 struct built_in_command *x;
1406 struct child_prog *child;
1407
1197 nextin = 0, nextout = 1; 1408 nextin = 0, nextout = 1;
1198 for (i = 0; i < newJob->numProgs; i++) { 1409 for (i = 0; i < newjob->num_progs; i++) {
1199 if ((i + 1) < newJob->numProgs) { 1410 child = & (newjob->progs[i]);
1200 pipe(pipefds); 1411
1412 if ((i + 1) < newjob->num_progs) {
1413 if (pipe(pipefds)<0) perror_msg_and_die("pipe");
1201 nextout = pipefds[1]; 1414 nextout = pipefds[1];
1202 } else { 1415 } else {
1203 if (outPipe[1]!=-1) { 1416 if (outpipe[1]!=-1) {
1204 nextout = outPipe[1]; 1417 nextout = outpipe[1];
1205 } else { 1418 } else {
1206 nextout = 1; 1419 nextout = 1;
1207 } 1420 }
1208 } 1421 }
1209 1422
1210#ifdef BB_FEATURE_SH_ENVIRONMENT 1423#ifdef BB_FEATURE_SH_ENVIRONMENT
1211 if (showXtrace==TRUE) { 1424 if (show_x_trace==TRUE) {
1212 int j; 1425 int j;
1213 fprintf(stderr, "+ "); 1426 fputc('+', stderr);
1214 for (j = 0; newJob->progs[i].argv[j]; j++) 1427 for (j = 0; child->argv[j]; j++) {
1215 fprintf(stderr, "%s ", newJob->progs[i].argv[j]); 1428 fputc(' ', stderr);
1216 fprintf(stderr, "\n"); 1429 fputs(child->argv[j], stderr);
1430 }
1431 fputc('\n', stderr);
1217 } 1432 }
1218#endif 1433#endif
1219 1434
1220 /* Check if the command matches any non-forking builtins */ 1435 /* Check if the command matches any non-forking builtins.
1436 * XXX should probably skip this test, and fork anyway, if
1437 * there redirects of some kind demand forking to work right.
1438 * pseudo_exec would then need to handle the non-forking command
1439 * in a forked context.
1440 */
1221 for (x = bltins; x->cmd; x++) { 1441 for (x = bltins; x->cmd; x++) {
1222 if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0 ) { 1442 if (strcmp(child->argv[0], x->cmd) == 0 ) {
1223 return(x->function(newJob, jobList)); 1443 return(x->function(child));
1224 } 1444 }
1225 } 1445 }
1226 1446
1227 if (!(newJob->progs[i].pid = fork())) { 1447 if (!(child->pid = fork())) {
1228 signal(SIGTTOU, SIG_DFL); 1448 signal(SIGTTOU, SIG_DFL);
1229 1449
1230 if (outPipe[1]!=-1) { 1450 if (outpipe[1]!=-1) {
1231 close(outPipe[0]); 1451 close(outpipe[0]);
1232 } 1452 }
1233 if (nextin != 0) { 1453 if (nextin != 0) {
1234 dup2(nextin, 0); 1454 dup2(nextin, 0);
@@ -1237,68 +1457,23 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
1237 1457
1238 if (nextout != 1) { 1458 if (nextout != 1) {
1239 dup2(nextout, 1); 1459 dup2(nextout, 1);
1240 dup2(nextout, 2); 1460 dup2(nextout, 2); /* Really? */
1241 close(nextout); 1461 close(nextout);
1242 close(pipefds[0]); 1462 close(pipefds[0]);
1243 } 1463 }
1244 1464
1245 /* explicit redirections override pipes */ 1465 /* explicit redirects override pipes */
1246 setupRedirections(newJob->progs + i); 1466 setup_redirects(child);
1247
1248 /* Check if the command matches any of the other builtins */
1249 for (x = bltins_forking; x->cmd; x++) {
1250 if (strcmp(newJob->progs[i].argv[0], x->cmd) == 0) {
1251 applet_name=x->cmd;
1252 exit (x->function(newJob, jobList));
1253 }
1254 }
1255#ifdef BB_FEATURE_SH_STANDALONE_SHELL
1256 /* Check if the command matches any busybox internal
1257 * commands ("applets") here. Following discussions from
1258 * November 2000 on busybox@opensource.lineo.com, don't use
1259 * get_last_path_component(). This way explicit (with
1260 * slashes) filenames will never be interpreted as an
1261 * applet, just like with builtins. This way the user can
1262 * override an applet with an explicit filename reference.
1263 * The only downside to this change is that an explicit
1264 * /bin/foo invocation fill fork and exec /bin/foo, even if
1265 * /bin/foo is a symlink to busybox.
1266 */
1267 search_applet.name = newJob->progs[i].argv[0];
1268 1467
1269#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN 1468 pseudo_exec(child);
1270 /* If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then
1271 * if you run /bin/cat, it will use BusyBox cat even if
1272 * /bin/cat exists on the filesystem and is _not_ busybox.
1273 * Some systems want this, others do not. Choose wisely. :-)
1274 */
1275 search_applet.name = get_last_path_component(search_applet.name);
1276#endif
1277
1278 /* Do a binary search to find the applet entry given the name. */
1279 applet = bsearch(&search_applet, applets, NUM_APPLETS,
1280 sizeof(struct BB_applet), applet_name_compare);
1281 if (applet != NULL) {
1282 int argc_l;
1283 char** argv=newJob->progs[i].argv;
1284 for(argc_l=0;*argv!=NULL; argv++, argc_l++);
1285 applet_name=applet->name;
1286 optind = 1;
1287 exit((*(applet->main)) (argc_l, newJob->progs[i].argv));
1288 }
1289#endif
1290
1291 execvp(newJob->progs[i].argv[0], newJob->progs[i].argv);
1292 error_msg_and_die("%s: %s\n", newJob->progs[i].argv[0],
1293 strerror(errno));
1294 } 1469 }
1295 if (outPipe[1]!=-1) { 1470 if (outpipe[1]!=-1) {
1296 close(outPipe[1]); 1471 close(outpipe[1]);
1297 } 1472 }
1298 1473
1299 /* put our child in the process group whose leader is the 1474 /* put our child in the process group whose leader is the
1300 first process in this pipe */ 1475 first process in this pipe */
1301 setpgid(newJob->progs[i].pid, newJob->progs[0].pid); 1476 setpgid(child->pid, newjob->progs[0].pid);
1302 if (nextin != 0) 1477 if (nextin != 0)
1303 close(nextin); 1478 close(nextin);
1304 if (nextout != 1) 1479 if (nextout != 1)
@@ -1309,44 +1484,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
1309 nextin = pipefds[0]; 1484 nextin = pipefds[0];
1310 } 1485 }
1311 1486
1312 newJob->pgrp = newJob->progs[0].pid; 1487 newjob->pgrp = newjob->progs[0].pid;
1313 1488
1314 /* find the ID for the theJob to use */ 1489 insert_job(newjob, inbg);
1315 newJob->jobId = 1;
1316 for (theJob = jobList->head; theJob; theJob = theJob->next)
1317 if (theJob->jobId >= newJob->jobId)
1318 newJob->jobId = theJob->jobId + 1;
1319
1320 /* add the theJob to the list of running jobs */
1321 if (!jobList->head) {
1322 theJob = jobList->head = xmalloc(sizeof(*theJob));
1323 } else {
1324 for (theJob = jobList->head; theJob->next; theJob = theJob->next);
1325 theJob->next = xmalloc(sizeof(*theJob));
1326 theJob = theJob->next;
1327 }
1328
1329 *theJob = *newJob;
1330 theJob->next = NULL;
1331 theJob->runningProgs = theJob->numProgs;
1332 theJob->stoppedProgs = 0;
1333
1334 if (inBg) {
1335 /* we don't wait for background theJobs to return -- append it
1336 to the list of backgrounded theJobs and leave it alone */
1337 printf("[%d] %d\n", theJob->jobId,
1338 newJob->progs[newJob->numProgs - 1].pid);
1339#ifdef BB_FEATURE_SH_ENVIRONMENT
1340 lastBgPid=newJob->progs[newJob->numProgs - 1].pid;
1341#endif
1342 } else {
1343 jobList->fg = theJob;
1344
1345 /* move the new process group into the foreground */
1346 /* suppress messages when run from /linuxrc mag@sysgo.de */
1347 if (tcsetpgrp(0, newJob->pgrp) && errno != ENOTTY)
1348 perror("tcsetpgrp");
1349 }
1350 1490
1351 return 0; 1491 return 0;
1352} 1492}
@@ -1354,13 +1494,14 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
1354static int busy_loop(FILE * input) 1494static int busy_loop(FILE * input)
1355{ 1495{
1356 char *command; 1496 char *command;
1357 char *nextCommand = NULL; 1497 char *next_command = NULL;
1358 struct job newJob; 1498 struct job newjob;
1359 pid_t parent_pgrp; 1499 pid_t parent_pgrp;
1360 int i; 1500 int i;
1361 int inBg; 1501 int inbg;
1362 int status; 1502 int status;
1363 newJob.jobContext = REGULAR_JOB_CONTEXT; 1503 newjob.job_list = &job_list;
1504 newjob.job_context = DEFAULT_CONTEXT;
1364 1505
1365 /* save current owner of TTY so we can restore it on exit */ 1506 /* save current owner of TTY so we can restore it on exit */
1366 parent_pgrp = tcgetpgrp(0); 1507 parent_pgrp = tcgetpgrp(0);
@@ -1372,64 +1513,65 @@ static int busy_loop(FILE * input)
1372 signal(SIGTTOU, SIG_IGN); 1513 signal(SIGTTOU, SIG_IGN);
1373 1514
1374 while (1) { 1515 while (1) {
1375 if (!jobList.fg) { 1516 if (!job_list.fg) {
1376 /* no job is in the foreground */ 1517 /* no job is in the foreground */
1377 1518
1378 /* see if any background processes have exited */ 1519 /* see if any background processes have exited */
1379 checkJobs(&jobList); 1520 checkjobs(&job_list);
1380 1521
1381 if (!nextCommand) { 1522 if (!next_command) {
1382 if (getCommand(input, command)) 1523 if (get_command(input, command))
1383 break; 1524 break;
1384 nextCommand = command; 1525 next_command = command;
1385 } 1526 }
1386 1527
1387 if (!parseCommand(&nextCommand, &newJob, &jobList, &inBg) && 1528 if (!parse_command(&next_command, &newjob, &inbg) &&
1388 newJob.numProgs) { 1529 newjob.num_progs) {
1389 int pipefds[2] = {-1,-1}; 1530 int pipefds[2] = {-1,-1};
1390 runCommand(&newJob, &jobList, inBg, pipefds); 1531 debug_printf( "job=%p being fed to run_command by busy_loop()'\n", &newjob);
1532 run_command(&newjob, inbg, pipefds);
1391 } 1533 }
1392 else { 1534 else {
1393 free(command); 1535 free(command);
1394 command = (char *) xcalloc(BUFSIZ, sizeof(char)); 1536 command = (char *) xcalloc(BUFSIZ, sizeof(char));
1395 nextCommand = NULL; 1537 next_command = NULL;
1396 } 1538 }
1397 } else { 1539 } else {
1398 /* a job is running in the foreground; wait for it */ 1540 /* a job is running in the foreground; wait for it */
1399 i = 0; 1541 i = 0;
1400 while (!jobList.fg->progs[i].pid || 1542 while (!job_list.fg->progs[i].pid ||
1401 jobList.fg->progs[i].isStopped == 1) i++; 1543 job_list.fg->progs[i].is_stopped == 1) i++;
1402 1544
1403 waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED); 1545 waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED);
1404 1546
1405 if (WIFEXITED(status) || WIFSIGNALED(status)) { 1547 if (WIFEXITED(status) || WIFSIGNALED(status)) {
1406 /* the child exited */ 1548 /* the child exited */
1407 jobList.fg->runningProgs--; 1549 job_list.fg->running_progs--;
1408 jobList.fg->progs[i].pid = 0; 1550 job_list.fg->progs[i].pid = 0;
1409 1551
1410#ifdef BB_FEATURE_SH_ENVIRONMENT 1552#ifdef BB_FEATURE_SH_ENVIRONMENT
1411 lastReturnCode=WEXITSTATUS(status); 1553 last_return_code=WEXITSTATUS(status);
1412#endif 1554#endif
1413 debug_printf("'%s' exited -- return code %d\n", jobList.fg->text, lastReturnCode); 1555 debug_printf("'%s' exited -- return code %d\n",
1414 if (!jobList.fg->runningProgs) { 1556 job_list.fg->text, last_return_code);
1557 if (!job_list.fg->running_progs) {
1415 /* child exited */ 1558 /* child exited */
1416 1559 remove_job(&job_list, job_list.fg);
1417 removeJob(&jobList, jobList.fg); 1560 job_list.fg = NULL;
1418 jobList.fg = NULL;
1419 } 1561 }
1420 } else { 1562 } else {
1421 /* the child was stopped */ 1563 /* the child was stopped */
1422 jobList.fg->stoppedProgs++; 1564 job_list.fg->stopped_progs++;
1423 jobList.fg->progs[i].isStopped = 1; 1565 job_list.fg->progs[i].is_stopped = 1;
1424 1566
1425 if (jobList.fg->stoppedProgs == jobList.fg->runningProgs) { 1567 if (job_list.fg->stopped_progs == job_list.fg->running_progs) {
1426 printf("\n" JOB_STATUS_FORMAT, jobList.fg->jobId, 1568 printf("\n" JOB_STATUS_FORMAT, job_list.fg->jobid,
1427 "Stopped", jobList.fg->text); 1569 "Stopped", job_list.fg->text);
1428 jobList.fg = NULL; 1570 job_list.fg = NULL;
1429 } 1571 }
1430 } 1572 }
1431 1573
1432 if (!jobList.fg) { 1574 if (!job_list.fg) {
1433 /* move the shell to the foreground */ 1575 /* move the shell to the foreground */
1434 /* suppress messages when run from /linuxrc mag@sysgo.de */ 1576 /* suppress messages when run from /linuxrc mag@sysgo.de */
1435 if (tcsetpgrp(0, getpid()) && errno != ENOTTY) 1577 if (tcsetpgrp(0, getpid()) && errno != ENOTTY)
@@ -1454,15 +1596,15 @@ static int busy_loop(FILE * input)
1454#ifdef BB_FEATURE_CLEAN_UP 1596#ifdef BB_FEATURE_CLEAN_UP
1455void free_memory(void) 1597void free_memory(void)
1456{ 1598{
1457 if (promptStr) 1599 if (prompt_str)
1458 free(promptStr); 1600 free(prompt_str);
1459 if (cwd) 1601 if (cwd)
1460 free(cwd); 1602 free(cwd);
1461 if (local_pending_command) 1603 if (local_pending_command)
1462 free(local_pending_command); 1604 free(local_pending_command);
1463 1605
1464 if (jobList.fg && !jobList.fg->runningProgs) { 1606 if (job_list.fg && !job_list.fg->running_progs) {
1465 removeJob(&jobList, jobList.fg); 1607 remove_job(&job_list, job_list.fg);
1466 } 1608 }
1467} 1609}
1468#endif 1610#endif
@@ -1500,7 +1642,7 @@ int shell_main(int argc_l, char **argv_l)
1500 break; 1642 break;
1501#ifdef BB_FEATURE_SH_ENVIRONMENT 1643#ifdef BB_FEATURE_SH_ENVIRONMENT
1502 case 'x': 1644 case 'x':
1503 showXtrace = TRUE; 1645 show_x_trace = TRUE;
1504 break; 1646 break;
1505#endif 1647#endif
1506 case 'i': 1648 case 'i':
@@ -1517,10 +1659,14 @@ int shell_main(int argc_l, char **argv_l)
1517 * standard input is a terminal 1659 * standard input is a terminal
1518 * standard output is a terminal 1660 * standard output is a terminal
1519 * Refer to Posix.2, the description of the `sh' utility. */ 1661 * Refer to Posix.2, the description of the `sh' utility. */
1520 if (interactive==TRUE || ( argv[optind]==NULL && input==stdin && isatty(fileno(stdin)) && isatty(fileno(stdout)))) { 1662 if (argv[optind]==NULL && input==stdin &&
1663 isatty(fileno(stdin)) && isatty(fileno(stdout))) {
1664 interactive=TRUE;
1665 }
1666 if (interactive==TRUE) {
1521 //fprintf(stdout, "optind=%d argv[optind]='%s'\n", optind, argv[optind]); 1667 //fprintf(stdout, "optind=%d argv[optind]='%s'\n", optind, argv[optind]);
1522 /* Looks like they want an interactive shell */ 1668 /* Looks like they want an interactive shell */
1523 fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); 1669 fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell (lash)\n", BB_VER, BB_BT);
1524 fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); 1670 fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n");
1525 } else if (local_pending_command==NULL) { 1671 } else if (local_pending_command==NULL) {
1526 //fprintf(stdout, "optind=%d argv[optind]='%s'\n", optind, argv[optind]); 1672 //fprintf(stdout, "optind=%d argv[optind]='%s'\n", optind, argv[optind]);