diff options
-rw-r--r-- | cmdedit.c | 16 | ||||
-rw-r--r-- | lash.c | 1090 | ||||
-rw-r--r-- | sh.c | 1090 | ||||
-rw-r--r-- | shell/cmdedit.c | 16 | ||||
-rw-r--r-- | shell/lash.c | 1090 |
5 files changed, 1880 insertions, 1422 deletions
@@ -85,6 +85,12 @@ static int cmdedit_scroll = 27; /* width of EOL scrolling region */ | |||
85 | static int history_counter = 0; /* Number of commands in history list */ | 85 | static int history_counter = 0; /* Number of commands in history list */ |
86 | static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */ | 86 | static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */ |
87 | static int exithandler_set = 0; /* Set to true when atexit() has been called */ | 87 | static 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 */ | ||
92 | extern unsigned int shell_context; | ||
93 | |||
88 | 94 | ||
89 | struct history { | 95 | struct 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 */ |
@@ -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" |
61 | extern size_t NUM_APPLETS; | 64 | extern size_t NUM_APPLETS; |
62 | 65 | ||
63 | 66 | ||
64 | 67 | enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE, | |
65 | |||
66 | enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, | ||
67 | REDIRECT_APPEND | 68 | REDIRECT_APPEND |
68 | }; | 69 | }; |
69 | 70 | ||
70 | static const unsigned int REGULAR_JOB_CONTEXT=0x1; | 71 | static const unsigned int DEFAULT_CONTEXT=0x1; |
71 | static const unsigned int IF_TRUE_CONTEXT=0x2; | 72 | static const unsigned int IF_TRUE_CONTEXT=0x2; |
72 | static const unsigned int IF_FALSE_CONTEXT=0x4; | 73 | static const unsigned int IF_FALSE_CONTEXT=0x4; |
73 | static const unsigned int THEN_EXP_CONTEXT=0x8; | 74 | static const unsigned int THEN_EXP_CONTEXT=0x8; |
74 | static const unsigned int ELSE_EXP_CONTEXT=0x10; | 75 | static const unsigned int ELSE_EXP_CONTEXT=0x10; |
76 | unsigned int shell_context = 0; | ||
77 | |||
75 | 78 | ||
76 | 79 | ||
77 | struct jobSet { | 80 | struct 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 | ||
82 | struct redirectionSpecifier { | 85 | struct 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 | ||
88 | struct childProgram { | 91 | struct 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 | ||
98 | struct job { | 102 | struct 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 | ||
111 | struct builtInCommand { | 116 | struct 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 */ |
118 | static int builtin_cd(struct job *cmd, struct jobSet *junk); | 123 | static int builtin_cd(struct child_prog *cmd); |
119 | static int builtin_env(struct job *dummy, struct jobSet *junk); | 124 | static int builtin_env(struct child_prog *dummy); |
120 | static int builtin_exec(struct job *cmd, struct jobSet *junk); | 125 | static int builtin_exec(struct child_prog *cmd); |
121 | static int builtin_exit(struct job *cmd, struct jobSet *junk); | 126 | static int builtin_exit(struct child_prog *cmd); |
122 | static int builtin_fg_bg(struct job *cmd, struct jobSet *jobList); | 127 | static int builtin_fg_bg(struct child_prog *cmd); |
123 | static int builtin_help(struct job *cmd, struct jobSet *junk); | 128 | static int builtin_help(struct child_prog *cmd); |
124 | static int builtin_jobs(struct job *dummy, struct jobSet *jobList); | 129 | static int builtin_jobs(struct child_prog *dummy); |
125 | static int builtin_pwd(struct job *dummy, struct jobSet *junk); | 130 | static int builtin_pwd(struct child_prog *dummy); |
126 | static int builtin_export(struct job *cmd, struct jobSet *junk); | 131 | static int builtin_export(struct child_prog *cmd); |
127 | static int builtin_source(struct job *cmd, struct jobSet *jobList); | 132 | static int builtin_source(struct child_prog *cmd); |
128 | static int builtin_unset(struct job *cmd, struct jobSet *junk); | 133 | static int builtin_unset(struct child_prog *cmd); |
129 | static int builtin_read(struct job *cmd, struct jobSet *junk); | 134 | static int builtin_read(struct child_prog *cmd); |
130 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | 135 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS |
131 | static int builtin_if(struct job *cmd, struct jobSet *junk); | 136 | static int builtin_if(struct child_prog *cmd); |
132 | static int builtin_then(struct job *cmd, struct jobSet *junk); | 137 | static int builtin_then(struct child_prog *cmd); |
133 | static int builtin_else(struct job *cmd, struct jobSet *junk); | 138 | static int builtin_else(struct child_prog *cmd); |
134 | static int builtin_fi(struct job *cmd, struct jobSet *junk); | 139 | static 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 */ |
139 | static void checkJobs(struct jobSet *jobList); | 144 | static void checkjobs(struct jobset *job_list); |
140 | static int getCommand(FILE * source, char *command); | 145 | static int get_command(FILE * source, char *command); |
141 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg); | 146 | static int parse_command(char **command_ptr, struct job *job, int *inbg); |
142 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]); | 147 | static int run_command(struct job *newjob, int inbg, int outpipe[2]); |
148 | static int pseudo_exec(struct child_prog *cmd) __attribute__ ((noreturn)); | ||
149 | static int run_command_predicate(char *cmd); | ||
143 | static int busy_loop(FILE * input); | 150 | static 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) */ |
149 | static struct builtInCommand bltins[] = { | 156 | static 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) */ |
171 | static struct builtInCommand bltins_forking[] = { | 179 | static 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[] = { | |||
178 | static char prompt[3]; | 186 | static char prompt[3]; |
179 | static char *cwd; | 187 | static char *cwd; |
180 | static char *local_pending_command = NULL; | 188 | static char *local_pending_command = NULL; |
181 | static char *promptStr = NULL; | 189 | static char *prompt_str = NULL; |
182 | static struct jobSet jobList = { NULL, NULL }; | 190 | static struct jobset job_list = { NULL, NULL }; |
183 | static int argc; | 191 | static int argc; |
184 | static char **argv; | 192 | static char **argv; |
185 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 193 | #ifdef BB_FEATURE_SH_ENVIRONMENT |
186 | static int lastBgPid=-1; | 194 | static int last_bg_pid=-1; |
187 | static int lastReturnCode=-1; | 195 | static int last_return_code=-1; |
188 | static int showXtrace=FALSE; | 196 | static int show_x_trace=FALSE; |
189 | #endif | 197 | #endif |
190 | 198 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | |
199 | static char syntax_err[]="syntax error near unexpected token"; | ||
200 | #endif | ||
201 | |||
191 | #ifdef DEBUG_SHELL | 202 | #ifdef DEBUG_SHELL |
192 | static inline void debug_printf(const char *format, ...) | 203 | static 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) | |||
213 | static inline void win_changed(int junk) {} | 224 | static 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 | |||
233 | builtin previous use notes | ||
234 | ------ ----------------- --------- | ||
235 | cd cmd->progs[0] | ||
236 | env 0 | ||
237 | exec cmd->progs[0] squashed bug: didn't look for applets or forking builtins | ||
238 | exit cmd->progs[0] | ||
239 | fg_bg cmd->progs[0], job_list->head, job_list->fg | ||
240 | help 0 | ||
241 | jobs job_list->head | ||
242 | pwd 0 | ||
243 | export cmd->progs[0] passes cmd, job_list to builtin_env(), which ignores them | ||
244 | source cmd->progs[0] | ||
245 | unset cmd->progs[0] | ||
246 | read cmd->progs[0] | ||
247 | if cmd->job_context, cmd->text | ||
248 | then cmd->job_context, cmd->text | ||
249 | else cmd->job_context, cmd->text | ||
250 | fi cmd->job_context | ||
251 | |||
252 | The use of cmd->text by if/then/else/fi is hopelessly hacky. | ||
253 | Would it work to increment cmd->progs[0]->argv and recurse, | ||
254 | somewhat like builtin_exec does? | ||
255 | |||
256 | I added "struct job *family;" to struct child_prog, | ||
257 | and switched API to builtin_foo(struct child_prog *child); | ||
258 | So 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 */ |
218 | static int builtin_cd(struct job *cmd, struct jobSet *junk) | 265 | static 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 */ |
236 | static int builtin_env(struct job *dummy, struct jobSet *junk) | 283 | static 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 */ |
247 | static int builtin_exec(struct job *cmd, struct jobSet *junk) | 294 | static 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 */ |
260 | static int builtin_exit(struct job *cmd, struct jobSet *junk) | 304 | static 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 */ |
269 | static int builtin_fg_bg(struct job *cmd, struct jobSet *jobList) | 313 | static 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 */ |
320 | static int builtin_help(struct job *dummy, struct jobSet *junk) | 361 | static 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 */ |
341 | static int builtin_jobs(struct job *dummy, struct jobSet *jobList) | 382 | static 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 */ |
359 | static int builtin_pwd(struct job *dummy, struct jobSet *junk) | 400 | static 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 */ |
367 | static int builtin_export(struct job *cmd, struct jobSet *junk) | 408 | static 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 */ |
381 | static int builtin_read(struct job *cmd, struct jobSet *junk) | 422 | static 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 */ |
416 | static int builtin_if(struct job *cmd, struct jobSet *jobList) | 457 | static 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) */ |
441 | static int builtin_then(struct job *cmd, struct jobSet *junk) | 481 | static 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) */ |
468 | static int builtin_else(struct job *cmd, struct jobSet *junk) | 508 | static 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) */ |
495 | static int builtin_fi(struct job *cmd, struct jobSet *junk) | 534 | static 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) */ |
509 | static int builtin_source(struct job *cmd, struct jobSet *junk) | 552 | static 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 */ |
531 | static int builtin_unset(struct job *cmd, struct jobSet *junk) | 573 | static 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 | */ | ||
591 | static 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 */ |
542 | static void freeJob(struct job *cmd) | 601 | static 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 */ |
561 | static void removeJob(struct jobSet *jobList, struct job *job) | 620 | static 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 */ |
580 | static void checkJobs(struct jobSet *jobList) | 639 | static 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 | ||
625 | static int setupRedirections(struct childProgram *prog) | 684 | static 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 | ||
664 | static int getCommand(FILE * source, char *command) | 723 | static 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 | ||
759 | static void globLastArgument(struct childProgram *prog, int *argcPtr, | 833 | static 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. */ |
870 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg) | 944 | static 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 | ||
1186 | static 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 | */ | ||
1297 | static 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 | |||
1356 | static 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 | |||
1399 | static 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 | |||
1354 | static int busy_loop(FILE * input) | 1494 | static 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 |
1455 | void free_memory(void) | 1597 | void 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]); |
@@ -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" |
61 | extern size_t NUM_APPLETS; | 64 | extern size_t NUM_APPLETS; |
62 | 65 | ||
63 | 66 | ||
64 | 67 | enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE, | |
65 | |||
66 | enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, | ||
67 | REDIRECT_APPEND | 68 | REDIRECT_APPEND |
68 | }; | 69 | }; |
69 | 70 | ||
70 | static const unsigned int REGULAR_JOB_CONTEXT=0x1; | 71 | static const unsigned int DEFAULT_CONTEXT=0x1; |
71 | static const unsigned int IF_TRUE_CONTEXT=0x2; | 72 | static const unsigned int IF_TRUE_CONTEXT=0x2; |
72 | static const unsigned int IF_FALSE_CONTEXT=0x4; | 73 | static const unsigned int IF_FALSE_CONTEXT=0x4; |
73 | static const unsigned int THEN_EXP_CONTEXT=0x8; | 74 | static const unsigned int THEN_EXP_CONTEXT=0x8; |
74 | static const unsigned int ELSE_EXP_CONTEXT=0x10; | 75 | static const unsigned int ELSE_EXP_CONTEXT=0x10; |
76 | unsigned int shell_context = 0; | ||
77 | |||
75 | 78 | ||
76 | 79 | ||
77 | struct jobSet { | 80 | struct 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 | ||
82 | struct redirectionSpecifier { | 85 | struct 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 | ||
88 | struct childProgram { | 91 | struct 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 | ||
98 | struct job { | 102 | struct 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 | ||
111 | struct builtInCommand { | 116 | struct 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 */ |
118 | static int builtin_cd(struct job *cmd, struct jobSet *junk); | 123 | static int builtin_cd(struct child_prog *cmd); |
119 | static int builtin_env(struct job *dummy, struct jobSet *junk); | 124 | static int builtin_env(struct child_prog *dummy); |
120 | static int builtin_exec(struct job *cmd, struct jobSet *junk); | 125 | static int builtin_exec(struct child_prog *cmd); |
121 | static int builtin_exit(struct job *cmd, struct jobSet *junk); | 126 | static int builtin_exit(struct child_prog *cmd); |
122 | static int builtin_fg_bg(struct job *cmd, struct jobSet *jobList); | 127 | static int builtin_fg_bg(struct child_prog *cmd); |
123 | static int builtin_help(struct job *cmd, struct jobSet *junk); | 128 | static int builtin_help(struct child_prog *cmd); |
124 | static int builtin_jobs(struct job *dummy, struct jobSet *jobList); | 129 | static int builtin_jobs(struct child_prog *dummy); |
125 | static int builtin_pwd(struct job *dummy, struct jobSet *junk); | 130 | static int builtin_pwd(struct child_prog *dummy); |
126 | static int builtin_export(struct job *cmd, struct jobSet *junk); | 131 | static int builtin_export(struct child_prog *cmd); |
127 | static int builtin_source(struct job *cmd, struct jobSet *jobList); | 132 | static int builtin_source(struct child_prog *cmd); |
128 | static int builtin_unset(struct job *cmd, struct jobSet *junk); | 133 | static int builtin_unset(struct child_prog *cmd); |
129 | static int builtin_read(struct job *cmd, struct jobSet *junk); | 134 | static int builtin_read(struct child_prog *cmd); |
130 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | 135 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS |
131 | static int builtin_if(struct job *cmd, struct jobSet *junk); | 136 | static int builtin_if(struct child_prog *cmd); |
132 | static int builtin_then(struct job *cmd, struct jobSet *junk); | 137 | static int builtin_then(struct child_prog *cmd); |
133 | static int builtin_else(struct job *cmd, struct jobSet *junk); | 138 | static int builtin_else(struct child_prog *cmd); |
134 | static int builtin_fi(struct job *cmd, struct jobSet *junk); | 139 | static 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 */ |
139 | static void checkJobs(struct jobSet *jobList); | 144 | static void checkjobs(struct jobset *job_list); |
140 | static int getCommand(FILE * source, char *command); | 145 | static int get_command(FILE * source, char *command); |
141 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg); | 146 | static int parse_command(char **command_ptr, struct job *job, int *inbg); |
142 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]); | 147 | static int run_command(struct job *newjob, int inbg, int outpipe[2]); |
148 | static int pseudo_exec(struct child_prog *cmd) __attribute__ ((noreturn)); | ||
149 | static int run_command_predicate(char *cmd); | ||
143 | static int busy_loop(FILE * input); | 150 | static 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) */ |
149 | static struct builtInCommand bltins[] = { | 156 | static 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) */ |
171 | static struct builtInCommand bltins_forking[] = { | 179 | static 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[] = { | |||
178 | static char prompt[3]; | 186 | static char prompt[3]; |
179 | static char *cwd; | 187 | static char *cwd; |
180 | static char *local_pending_command = NULL; | 188 | static char *local_pending_command = NULL; |
181 | static char *promptStr = NULL; | 189 | static char *prompt_str = NULL; |
182 | static struct jobSet jobList = { NULL, NULL }; | 190 | static struct jobset job_list = { NULL, NULL }; |
183 | static int argc; | 191 | static int argc; |
184 | static char **argv; | 192 | static char **argv; |
185 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 193 | #ifdef BB_FEATURE_SH_ENVIRONMENT |
186 | static int lastBgPid=-1; | 194 | static int last_bg_pid=-1; |
187 | static int lastReturnCode=-1; | 195 | static int last_return_code=-1; |
188 | static int showXtrace=FALSE; | 196 | static int show_x_trace=FALSE; |
189 | #endif | 197 | #endif |
190 | 198 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | |
199 | static char syntax_err[]="syntax error near unexpected token"; | ||
200 | #endif | ||
201 | |||
191 | #ifdef DEBUG_SHELL | 202 | #ifdef DEBUG_SHELL |
192 | static inline void debug_printf(const char *format, ...) | 203 | static 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) | |||
213 | static inline void win_changed(int junk) {} | 224 | static 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 | |||
233 | builtin previous use notes | ||
234 | ------ ----------------- --------- | ||
235 | cd cmd->progs[0] | ||
236 | env 0 | ||
237 | exec cmd->progs[0] squashed bug: didn't look for applets or forking builtins | ||
238 | exit cmd->progs[0] | ||
239 | fg_bg cmd->progs[0], job_list->head, job_list->fg | ||
240 | help 0 | ||
241 | jobs job_list->head | ||
242 | pwd 0 | ||
243 | export cmd->progs[0] passes cmd, job_list to builtin_env(), which ignores them | ||
244 | source cmd->progs[0] | ||
245 | unset cmd->progs[0] | ||
246 | read cmd->progs[0] | ||
247 | if cmd->job_context, cmd->text | ||
248 | then cmd->job_context, cmd->text | ||
249 | else cmd->job_context, cmd->text | ||
250 | fi cmd->job_context | ||
251 | |||
252 | The use of cmd->text by if/then/else/fi is hopelessly hacky. | ||
253 | Would it work to increment cmd->progs[0]->argv and recurse, | ||
254 | somewhat like builtin_exec does? | ||
255 | |||
256 | I added "struct job *family;" to struct child_prog, | ||
257 | and switched API to builtin_foo(struct child_prog *child); | ||
258 | So 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 */ |
218 | static int builtin_cd(struct job *cmd, struct jobSet *junk) | 265 | static 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 */ |
236 | static int builtin_env(struct job *dummy, struct jobSet *junk) | 283 | static 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 */ |
247 | static int builtin_exec(struct job *cmd, struct jobSet *junk) | 294 | static 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 */ |
260 | static int builtin_exit(struct job *cmd, struct jobSet *junk) | 304 | static 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 */ |
269 | static int builtin_fg_bg(struct job *cmd, struct jobSet *jobList) | 313 | static 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 */ |
320 | static int builtin_help(struct job *dummy, struct jobSet *junk) | 361 | static 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 */ |
341 | static int builtin_jobs(struct job *dummy, struct jobSet *jobList) | 382 | static 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 */ |
359 | static int builtin_pwd(struct job *dummy, struct jobSet *junk) | 400 | static 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 */ |
367 | static int builtin_export(struct job *cmd, struct jobSet *junk) | 408 | static 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 */ |
381 | static int builtin_read(struct job *cmd, struct jobSet *junk) | 422 | static 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 */ |
416 | static int builtin_if(struct job *cmd, struct jobSet *jobList) | 457 | static 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) */ |
441 | static int builtin_then(struct job *cmd, struct jobSet *junk) | 481 | static 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) */ |
468 | static int builtin_else(struct job *cmd, struct jobSet *junk) | 508 | static 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) */ |
495 | static int builtin_fi(struct job *cmd, struct jobSet *junk) | 534 | static 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) */ |
509 | static int builtin_source(struct job *cmd, struct jobSet *junk) | 552 | static 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 */ |
531 | static int builtin_unset(struct job *cmd, struct jobSet *junk) | 573 | static 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 | */ | ||
591 | static 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 */ |
542 | static void freeJob(struct job *cmd) | 601 | static 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 */ |
561 | static void removeJob(struct jobSet *jobList, struct job *job) | 620 | static 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 */ |
580 | static void checkJobs(struct jobSet *jobList) | 639 | static 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 | ||
625 | static int setupRedirections(struct childProgram *prog) | 684 | static 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 | ||
664 | static int getCommand(FILE * source, char *command) | 723 | static 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 | ||
759 | static void globLastArgument(struct childProgram *prog, int *argcPtr, | 833 | static 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. */ |
870 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg) | 944 | static 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 | ||
1186 | static 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 | */ | ||
1297 | static 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 | |||
1356 | static 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 | |||
1399 | static 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 | |||
1354 | static int busy_loop(FILE * input) | 1494 | static 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 |
1455 | void free_memory(void) | 1597 | void 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 */ | |||
85 | static int history_counter = 0; /* Number of commands in history list */ | 85 | static int history_counter = 0; /* Number of commands in history list */ |
86 | static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */ | 86 | static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */ |
87 | static int exithandler_set = 0; /* Set to true when atexit() has been called */ | 87 | static 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 */ | ||
92 | extern unsigned int shell_context; | ||
93 | |||
88 | 94 | ||
89 | struct history { | 95 | struct 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" |
61 | extern size_t NUM_APPLETS; | 64 | extern size_t NUM_APPLETS; |
62 | 65 | ||
63 | 66 | ||
64 | 67 | enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE, | |
65 | |||
66 | enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, | ||
67 | REDIRECT_APPEND | 68 | REDIRECT_APPEND |
68 | }; | 69 | }; |
69 | 70 | ||
70 | static const unsigned int REGULAR_JOB_CONTEXT=0x1; | 71 | static const unsigned int DEFAULT_CONTEXT=0x1; |
71 | static const unsigned int IF_TRUE_CONTEXT=0x2; | 72 | static const unsigned int IF_TRUE_CONTEXT=0x2; |
72 | static const unsigned int IF_FALSE_CONTEXT=0x4; | 73 | static const unsigned int IF_FALSE_CONTEXT=0x4; |
73 | static const unsigned int THEN_EXP_CONTEXT=0x8; | 74 | static const unsigned int THEN_EXP_CONTEXT=0x8; |
74 | static const unsigned int ELSE_EXP_CONTEXT=0x10; | 75 | static const unsigned int ELSE_EXP_CONTEXT=0x10; |
76 | unsigned int shell_context = 0; | ||
77 | |||
75 | 78 | ||
76 | 79 | ||
77 | struct jobSet { | 80 | struct 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 | ||
82 | struct redirectionSpecifier { | 85 | struct 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 | ||
88 | struct childProgram { | 91 | struct 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 | ||
98 | struct job { | 102 | struct 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 | ||
111 | struct builtInCommand { | 116 | struct 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 */ |
118 | static int builtin_cd(struct job *cmd, struct jobSet *junk); | 123 | static int builtin_cd(struct child_prog *cmd); |
119 | static int builtin_env(struct job *dummy, struct jobSet *junk); | 124 | static int builtin_env(struct child_prog *dummy); |
120 | static int builtin_exec(struct job *cmd, struct jobSet *junk); | 125 | static int builtin_exec(struct child_prog *cmd); |
121 | static int builtin_exit(struct job *cmd, struct jobSet *junk); | 126 | static int builtin_exit(struct child_prog *cmd); |
122 | static int builtin_fg_bg(struct job *cmd, struct jobSet *jobList); | 127 | static int builtin_fg_bg(struct child_prog *cmd); |
123 | static int builtin_help(struct job *cmd, struct jobSet *junk); | 128 | static int builtin_help(struct child_prog *cmd); |
124 | static int builtin_jobs(struct job *dummy, struct jobSet *jobList); | 129 | static int builtin_jobs(struct child_prog *dummy); |
125 | static int builtin_pwd(struct job *dummy, struct jobSet *junk); | 130 | static int builtin_pwd(struct child_prog *dummy); |
126 | static int builtin_export(struct job *cmd, struct jobSet *junk); | 131 | static int builtin_export(struct child_prog *cmd); |
127 | static int builtin_source(struct job *cmd, struct jobSet *jobList); | 132 | static int builtin_source(struct child_prog *cmd); |
128 | static int builtin_unset(struct job *cmd, struct jobSet *junk); | 133 | static int builtin_unset(struct child_prog *cmd); |
129 | static int builtin_read(struct job *cmd, struct jobSet *junk); | 134 | static int builtin_read(struct child_prog *cmd); |
130 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | 135 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS |
131 | static int builtin_if(struct job *cmd, struct jobSet *junk); | 136 | static int builtin_if(struct child_prog *cmd); |
132 | static int builtin_then(struct job *cmd, struct jobSet *junk); | 137 | static int builtin_then(struct child_prog *cmd); |
133 | static int builtin_else(struct job *cmd, struct jobSet *junk); | 138 | static int builtin_else(struct child_prog *cmd); |
134 | static int builtin_fi(struct job *cmd, struct jobSet *junk); | 139 | static 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 */ |
139 | static void checkJobs(struct jobSet *jobList); | 144 | static void checkjobs(struct jobset *job_list); |
140 | static int getCommand(FILE * source, char *command); | 145 | static int get_command(FILE * source, char *command); |
141 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg); | 146 | static int parse_command(char **command_ptr, struct job *job, int *inbg); |
142 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]); | 147 | static int run_command(struct job *newjob, int inbg, int outpipe[2]); |
148 | static int pseudo_exec(struct child_prog *cmd) __attribute__ ((noreturn)); | ||
149 | static int run_command_predicate(char *cmd); | ||
143 | static int busy_loop(FILE * input); | 150 | static 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) */ |
149 | static struct builtInCommand bltins[] = { | 156 | static 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) */ |
171 | static struct builtInCommand bltins_forking[] = { | 179 | static 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[] = { | |||
178 | static char prompt[3]; | 186 | static char prompt[3]; |
179 | static char *cwd; | 187 | static char *cwd; |
180 | static char *local_pending_command = NULL; | 188 | static char *local_pending_command = NULL; |
181 | static char *promptStr = NULL; | 189 | static char *prompt_str = NULL; |
182 | static struct jobSet jobList = { NULL, NULL }; | 190 | static struct jobset job_list = { NULL, NULL }; |
183 | static int argc; | 191 | static int argc; |
184 | static char **argv; | 192 | static char **argv; |
185 | #ifdef BB_FEATURE_SH_ENVIRONMENT | 193 | #ifdef BB_FEATURE_SH_ENVIRONMENT |
186 | static int lastBgPid=-1; | 194 | static int last_bg_pid=-1; |
187 | static int lastReturnCode=-1; | 195 | static int last_return_code=-1; |
188 | static int showXtrace=FALSE; | 196 | static int show_x_trace=FALSE; |
189 | #endif | 197 | #endif |
190 | 198 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | |
199 | static char syntax_err[]="syntax error near unexpected token"; | ||
200 | #endif | ||
201 | |||
191 | #ifdef DEBUG_SHELL | 202 | #ifdef DEBUG_SHELL |
192 | static inline void debug_printf(const char *format, ...) | 203 | static 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) | |||
213 | static inline void win_changed(int junk) {} | 224 | static 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 | |||
233 | builtin previous use notes | ||
234 | ------ ----------------- --------- | ||
235 | cd cmd->progs[0] | ||
236 | env 0 | ||
237 | exec cmd->progs[0] squashed bug: didn't look for applets or forking builtins | ||
238 | exit cmd->progs[0] | ||
239 | fg_bg cmd->progs[0], job_list->head, job_list->fg | ||
240 | help 0 | ||
241 | jobs job_list->head | ||
242 | pwd 0 | ||
243 | export cmd->progs[0] passes cmd, job_list to builtin_env(), which ignores them | ||
244 | source cmd->progs[0] | ||
245 | unset cmd->progs[0] | ||
246 | read cmd->progs[0] | ||
247 | if cmd->job_context, cmd->text | ||
248 | then cmd->job_context, cmd->text | ||
249 | else cmd->job_context, cmd->text | ||
250 | fi cmd->job_context | ||
251 | |||
252 | The use of cmd->text by if/then/else/fi is hopelessly hacky. | ||
253 | Would it work to increment cmd->progs[0]->argv and recurse, | ||
254 | somewhat like builtin_exec does? | ||
255 | |||
256 | I added "struct job *family;" to struct child_prog, | ||
257 | and switched API to builtin_foo(struct child_prog *child); | ||
258 | So 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 */ |
218 | static int builtin_cd(struct job *cmd, struct jobSet *junk) | 265 | static 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 */ |
236 | static int builtin_env(struct job *dummy, struct jobSet *junk) | 283 | static 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 */ |
247 | static int builtin_exec(struct job *cmd, struct jobSet *junk) | 294 | static 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 */ |
260 | static int builtin_exit(struct job *cmd, struct jobSet *junk) | 304 | static 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 */ |
269 | static int builtin_fg_bg(struct job *cmd, struct jobSet *jobList) | 313 | static 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 */ |
320 | static int builtin_help(struct job *dummy, struct jobSet *junk) | 361 | static 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 */ |
341 | static int builtin_jobs(struct job *dummy, struct jobSet *jobList) | 382 | static 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 */ |
359 | static int builtin_pwd(struct job *dummy, struct jobSet *junk) | 400 | static 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 */ |
367 | static int builtin_export(struct job *cmd, struct jobSet *junk) | 408 | static 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 */ |
381 | static int builtin_read(struct job *cmd, struct jobSet *junk) | 422 | static 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 */ |
416 | static int builtin_if(struct job *cmd, struct jobSet *jobList) | 457 | static 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) */ |
441 | static int builtin_then(struct job *cmd, struct jobSet *junk) | 481 | static 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) */ |
468 | static int builtin_else(struct job *cmd, struct jobSet *junk) | 508 | static 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) */ |
495 | static int builtin_fi(struct job *cmd, struct jobSet *junk) | 534 | static 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) */ |
509 | static int builtin_source(struct job *cmd, struct jobSet *junk) | 552 | static 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 */ |
531 | static int builtin_unset(struct job *cmd, struct jobSet *junk) | 573 | static 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 | */ | ||
591 | static 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 */ |
542 | static void freeJob(struct job *cmd) | 601 | static 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 */ |
561 | static void removeJob(struct jobSet *jobList, struct job *job) | 620 | static 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 */ |
580 | static void checkJobs(struct jobSet *jobList) | 639 | static 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 | ||
625 | static int setupRedirections(struct childProgram *prog) | 684 | static 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 | ||
664 | static int getCommand(FILE * source, char *command) | 723 | static 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 | ||
759 | static void globLastArgument(struct childProgram *prog, int *argcPtr, | 833 | static 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. */ |
870 | static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg) | 944 | static 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 | ||
1186 | static 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 | */ | ||
1297 | static 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 | |||
1356 | static 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 | |||
1399 | static 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 | |||
1354 | static int busy_loop(FILE * input) | 1494 | static 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 |
1455 | void free_memory(void) | 1597 | void 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]); |