aboutsummaryrefslogtreecommitdiff
path: root/sh.c
diff options
context:
space:
mode:
Diffstat (limited to 'sh.c')
-rw-r--r--sh.c1255
1 files changed, 649 insertions, 606 deletions
diff --git a/sh.c b/sh.c
index 9e467dc54..498f43779 100644
--- a/sh.c
+++ b/sh.c
@@ -39,293 +39,306 @@
39#include <unistd.h> 39#include <unistd.h>
40 40
41 41
42#define MAX_COMMAND_LEN 250 /* max length of a single command 42#ifdef BB_FEATURE_SH_COMMAND_EDITING
43 string */ 43#include "cmdedit.h"
44#endif
45
44#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" 46#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
45 47
46enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, REDIRECT_APPEND }; 48
49enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
50 REDIRECT_APPEND };
47 51
48struct jobSet { 52struct jobSet {
49 struct job * head; /* head of list of running jobs */ 53 struct job *head; /* head of list of running jobs */
50 struct job * fg; /* current foreground job */ 54 struct job *fg; /* current foreground job */
51}; 55};
52 56
53struct redirectionSpecifier { 57struct redirectionSpecifier {
54 enum redirectionType type; /* type of redirection */ 58 enum redirectionType type; /* type of redirection */
55 int fd; /* file descriptor being redirected */ 59 int fd; /* file descriptor being redirected */
56 char * filename; /* file to redirect fd to */ 60 char *filename; /* file to redirect fd to */
57}; 61};
58 62
59struct childProgram { 63struct childProgram {
60 pid_t pid; /* 0 if exited */ 64 pid_t pid; /* 0 if exited */
61 char ** argv; /* program name and arguments */ 65 char **argv; /* program name and arguments */
62 int numRedirections; /* elements in redirection array */ 66 int numRedirections; /* elements in redirection array */
63 struct redirectionSpecifier * redirections; /* I/O redirections */ 67 struct redirectionSpecifier *redirections; /* I/O redirections */
64 glob_t globResult; /* result of parameter globbing */ 68 glob_t globResult; /* result of parameter globbing */
65 int freeGlob; /* should we globfree(&globResult)? */ 69 int freeGlob; /* should we globfree(&globResult)? */
66 int isStopped; /* is the program currently running? */ 70 int isStopped; /* is the program currently running? */
67}; 71};
68 72
69struct job { 73struct job {
70 int jobId; /* job number */ 74 int jobId; /* job number */
71 int numProgs; /* total number of programs in job */ 75 int numProgs; /* total number of programs in job */
72 int runningProgs; /* number of programs running */ 76 int runningProgs; /* number of programs running */
73 char * text; /* name of job */ 77 char *text; /* name of job */
74 char * cmdBuf; /* buffer various argv's point into */ 78 char *cmdBuf; /* buffer various argv's point into */
75 pid_t pgrp; /* process group ID for the job */ 79 pid_t pgrp; /* process group ID for the job */
76 struct childProgram * progs; /* array of programs in job */ 80 struct childProgram *progs; /* array of programs in job */
77 struct job * next; /* to track background commands */ 81 struct job *next; /* to track background commands */
78 int stoppedProgs; /* number of programs alive, but stopped */ 82 int stoppedProgs; /* number of programs alive, but stopped */
79}; 83};
80 84
81struct builtInCommand { 85struct builtInCommand {
82 char *cmd; /* name */ 86 char *cmd; /* name */
83 char *descr; /* description */ 87 char *descr; /* description */
84 char *usage; /* usage */ 88 char *usage; /* usage */
85 int (*function) (struct job *, struct jobSet * jobList); /* function ptr */ 89 int (*function) (struct job *, struct jobSet * jobList); /* function ptr */
86}; 90};
87 91
88/* Some function prototypes */ 92/* Some function prototypes */
89static int shell_cd(struct job* cmd, struct jobSet* junk); 93static int shell_cd(struct job *cmd, struct jobSet *junk);
90static int shell_env(struct job* dummy, struct jobSet* junk); 94static int shell_env(struct job *dummy, struct jobSet *junk);
91static int shell_exit(struct job* cmd, struct jobSet* junk); 95static int shell_exit(struct job *cmd, struct jobSet *junk);
92static int shell_fg_bg(struct job* cmd, struct jobSet* jobList); 96static int shell_fg_bg(struct job *cmd, struct jobSet *jobList);
93static int shell_help(struct job* cmd, struct jobSet* junk); 97static int shell_help(struct job *cmd, struct jobSet *junk);
94static int shell_jobs(struct job* dummy, struct jobSet* jobList); 98static int shell_jobs(struct job *dummy, struct jobSet *jobList);
95static int shell_pwd(struct job* dummy, struct jobSet* junk); 99static int shell_pwd(struct job *dummy, struct jobSet *junk);
96static int shell_set(struct job* cmd, struct jobSet* junk); 100static int shell_set(struct job *cmd, struct jobSet *junk);
97static int shell_source(struct job* cmd, struct jobSet* jobList); 101static int shell_source(struct job *cmd, struct jobSet *jobList);
98static int shell_unset(struct job* cmd, struct jobSet* junk); 102static int shell_unset(struct job *cmd, struct jobSet *junk);
99 103
100static void checkJobs(struct jobSet * jobList); 104static void checkJobs(struct jobSet *jobList);
101static int getCommand(FILE * source, char * command); 105static int getCommand(FILE * source, char *command);
102static int parseCommand(char ** commandPtr, struct job * job, int * isBg); 106static int parseCommand(char **commandPtr, struct job *job, int *isBg);
103static int setupRedirections(struct childProgram * prog); 107static int setupRedirections(struct childProgram *prog);
104static int runCommand(struct job newJob, struct jobSet * jobList, int inBg); 108static int runCommand(struct job newJob, struct jobSet *jobList, int inBg);
105static int busy_loop(FILE * input); 109static int busy_loop(FILE * input);
106 110
107 111
108/* Table of built-in functions */ 112/* Table of built-in functions */
109static struct builtInCommand bltins[] = { 113static struct builtInCommand bltins[] = {
110 {"bg", "Resume a job in the background", "bg [%%job]", shell_fg_bg}, 114 {"bg", "Resume a job in the background", "bg [%%job]", shell_fg_bg},
111 {"cd", "Change working directory", "cd [dir]", shell_cd}, 115 {"cd", "Change working directory", "cd [dir]", shell_cd},
112 {"env", "Print all environment variables", "env", shell_env}, 116 //{"echo", "Echo arguments on stdout", "echo arg1 [...]", shell_echo},
113 {"exit", "Exit from shell()", "exit", shell_exit}, 117 {"env", "Print all environment variables", "env", shell_env},
114 {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg}, 118 {"exit", "Exit from shell()", "exit", shell_exit},
115 {"jobs", "Lists the active jobs", "jobs", shell_jobs}, 119 {"fg", "Bring job into the foreground", "fg [%%job]", shell_fg_bg},
116 {"pwd", "Print current directory", "pwd", shell_pwd}, 120 {"jobs", "Lists the active jobs", "jobs", shell_jobs},
117 {"set", "Set environment variable", "set [VAR=value]", shell_set}, 121 {"pwd", "Print current directory", "pwd", shell_pwd},
118 {"unset", "Unset environment variable", "unset VAR", shell_unset}, 122 {"set", "Set environment variable", "set [VAR=value]", shell_set},
119 //{"echo", "Echo arguments on stdout", "echo arg1 [...]", shell_echo}, 123 {"unset", "Unset environment variable", "unset VAR", shell_unset},
120 {".", "Source-in and run commands in a file", ". filename", shell_source}, 124 {".", "Source-in and run commands in a file", ". filename",
121 {"help", "List shell built-in commands", "help", shell_help}, 125 shell_source},
122 {NULL, NULL, NULL, NULL} 126 {"help", "List shell built-in commands", "help", shell_help},
127 {NULL, NULL, NULL, NULL}
123}; 128};
124 129
125static const char shell_usage[] = 130static const char shell_usage[] =
126 "sh [FILE]...\n\n" 131 "sh [FILE]...\n\n" "The BusyBox command interpreter (shell).\n\n";
127 "The BusyBox command interpreter (shell).\n\n";
128 132
129 133
130static char cwd[1024]; 134static char cwd[1024];
131static char *prompt = "# "; 135static char *prompt = "# ";
132 136
133 137
138
134/* built-in 'cd <path>' handler */ 139/* built-in 'cd <path>' handler */
135static int shell_cd(struct job* cmd, struct jobSet* junk) 140static int shell_cd(struct job *cmd, struct jobSet *junk)
136{ 141{
137 char *newdir; 142 char *newdir;
138 if (!cmd->progs[0].argv[1] == 1) 143 if (!cmd->progs[0].argv[1] == 1)
139 newdir = getenv("HOME"); 144 newdir = getenv("HOME");
140 else 145 else
141 newdir = cmd->progs[0].argv[1]; 146 newdir = cmd->progs[0].argv[1];
142 if (chdir(newdir)) { 147 if (chdir(newdir)) {
143 printf("cd: %s: %s\n", newdir, strerror(errno)); 148 printf("cd: %s: %s\n", newdir, strerror(errno));
144 return FALSE; 149 return FALSE;
145 } 150 }
146 getcwd(cwd, sizeof(cwd)); 151 getcwd(cwd, sizeof(cwd));
147 152
148 return TRUE; 153 return TRUE;
149} 154}
150 155
151/* built-in 'env' handler */ 156/* built-in 'env' handler */
152static int shell_env(struct job* dummy, struct jobSet* junk) 157static int shell_env(struct job *dummy, struct jobSet *junk)
153{ 158{
154 char **e; 159 char **e;
155 160
156 for (e = environ ; *e ; e++) { 161 for (e = environ; *e; e++) {
157 fprintf(stdout, "%s\n", *e); 162 fprintf(stdout, "%s\n", *e);
158 } 163 }
159 return (0); 164 return (0);
160} 165}
161 166
162/* built-in 'exit' handler */ 167/* built-in 'exit' handler */
163static int shell_exit(struct job* cmd, struct jobSet* junk) 168static int shell_exit(struct job *cmd, struct jobSet *junk)
164{ 169{
165 if (!cmd->progs[0].argv[1] == 1) 170 if (!cmd->progs[0].argv[1] == 1)
166 exit TRUE; 171 exit TRUE;
167 else 172 else
168 exit(atoi(cmd->progs[0].argv[1])); 173 exit(atoi(cmd->progs[0].argv[1]));
169} 174}
170 175
171/* built-in 'fg' and 'bg' handler */ 176/* built-in 'fg' and 'bg' handler */
172static int shell_fg_bg(struct job* cmd, struct jobSet* jobList) 177static int shell_fg_bg(struct job *cmd, struct jobSet *jobList)
173{ 178{
174 int i, jobNum; 179 int i, jobNum;
175 struct job* job; 180 struct job *job;
176 181
177 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) { 182 if (!jobList->head) {
178 fprintf(stderr, "%s: exactly one argument is expected\n", 183 if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) {
179 cmd->progs[0].argv[0]); 184 fprintf(stderr, "%s: exactly one argument is expected\n",
180 return FALSE; 185 cmd->progs[0].argv[0]);
181 } 186 return FALSE;
182 187 }
183 if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) { 188 if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) {
184 fprintf(stderr, "%s: bad argument '%s'\n", 189 fprintf(stderr, "%s: bad argument '%s'\n",
185 cmd->progs[0].argv[0], cmd->progs[0].argv[1]); 190 cmd->progs[0].argv[0], cmd->progs[0].argv[1]);
186 return FALSE; 191 return FALSE;
187 } 192 }
188 193 } else {
189 for (job = jobList->head; job; job = job->next) 194 job = jobList->head;
190 if (job->jobId == jobNum) break; 195 }
191 196
192 if (!job) { 197 for (job = jobList->head; job; job = job->next)
193 fprintf(stderr, "%s: unknown job %d\n", 198 if (job->jobId == jobNum)
194 cmd->progs[0].argv[0], jobNum); 199 break;
195 return FALSE; 200
196 } 201 if (!job) {
197 202 fprintf(stderr, "%s: unknown job %d\n",
198 if (*cmd->progs[0].argv[0] == 'f') { 203 cmd->progs[0].argv[0], jobNum);
199 /* Make this job the foreground job */ 204 return FALSE;
200 205 }
201 if (tcsetpgrp(0, job->pgrp)) 206
202 perror("tcsetpgrp"); 207 if (*cmd->progs[0].argv[0] == 'f') {
203 jobList->fg = job; 208 /* Make this job the foreground job */
204 } 209
205 210 if (tcsetpgrp(0, job->pgrp))
206 /* Restart the processes in the job */ 211 perror("tcsetpgrp");
207 for (i = 0; i < job->numProgs; i++) 212 jobList->fg = job;
208 job->progs[i].isStopped = 0; 213 }
209 214
210 kill(-job->pgrp, SIGCONT); 215 /* Restart the processes in the job */
211 216 for (i = 0; i < job->numProgs; i++)
212 job->stoppedProgs = 0; 217 job->progs[i].isStopped = 0;
213 218
214 return TRUE; 219 kill(-job->pgrp, SIGCONT);
220
221 job->stoppedProgs = 0;
222
223 return TRUE;
215} 224}
216 225
217/* built-in 'help' handler */ 226/* built-in 'help' handler */
218static int shell_help(struct job* cmd, struct jobSet* junk) 227static int shell_help(struct job *cmd, struct jobSet *junk)
219{ 228{
220 struct builtInCommand *x; 229 struct builtInCommand *x;
221 230
222 fprintf(stdout, "\nBuilt-in commands:\n"); 231 fprintf(stdout, "\nBuilt-in commands:\n");
223 fprintf(stdout, "-------------------\n"); 232 fprintf(stdout, "-------------------\n");
224 for ( x=bltins; x->cmd; x++) { 233 for (x = bltins; x->cmd; x++) {
225 fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); 234 fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
226 } 235 }
227 fprintf(stdout, "\n\n"); 236 fprintf(stdout, "\n\n");
228 return TRUE; 237 return TRUE;
229} 238}
230 239
231/* built-in 'jobs' handler */ 240/* built-in 'jobs' handler */
232static int shell_jobs(struct job* dummy, struct jobSet* jobList) 241static int shell_jobs(struct job *dummy, struct jobSet *jobList)
233{ 242{
234 struct job * job; 243 struct job *job;
235 char * statusString; 244 char *statusString;
236 for (job = jobList->head; job; job = job->next) { 245 for (job = jobList->head; job; job = job->next) {
237 if (job->runningProgs == job->stoppedProgs) 246 if (job->runningProgs == job->stoppedProgs)
238 statusString = "Stopped"; 247 statusString = "Stopped";
239 else 248 else
240 statusString = "Running"; 249 statusString = "Running";
241 250
242 printf(JOB_STATUS_FORMAT, job->jobId, statusString, 251 printf(JOB_STATUS_FORMAT, job->jobId, statusString, job->text);
243 job->text); 252 }
244 } 253 return TRUE;
245 return TRUE;
246} 254}
247 255
248 256
249/* built-in 'pwd' handler */ 257/* built-in 'pwd' handler */
250static int shell_pwd(struct job* dummy, struct jobSet* junk) 258static int shell_pwd(struct job *dummy, struct jobSet *junk)
251{ 259{
252 getcwd(cwd, sizeof(cwd)); 260 getcwd(cwd, sizeof(cwd));
253 fprintf(stdout, "%s\n", cwd); 261 fprintf(stdout, "%s\n", cwd);
254 return TRUE; 262 return TRUE;
255} 263}
256 264
257/* built-in 'set VAR=value' handler */ 265/* built-in 'set VAR=value' handler */
258static int shell_set(struct job* cmd, struct jobSet* junk) 266static int shell_set(struct job *cmd, struct jobSet *junk)
259{ 267{
260 int res; 268 int res;
261 269
262 if (!cmd->progs[0].argv[1] == 1) { 270 if (!cmd->progs[0].argv[1] == 1) {
263 return (shell_env(cmd, junk)); 271 return (shell_env(cmd, junk));
264 } 272 }
265 res = putenv(cmd->progs[0].argv[1]); 273 res = putenv(cmd->progs[0].argv[1]);
266 if (res) 274 if (res)
267 fprintf(stdout, "set: %s\n", strerror(errno)); 275 fprintf(stdout, "set: %s\n", strerror(errno));
268 return (res); 276 return (res);
269} 277}
270 278
271/* Built-in '.' handler (read-in and execute commands from file) */ 279/* Built-in '.' handler (read-in and execute commands from file) */
272static int shell_source(struct job* cmd, struct jobSet* junk) 280static int shell_source(struct job *cmd, struct jobSet *junk)
273{ 281{
274 FILE *input; 282 FILE *input;
275 int status; 283 int status;
276
277 if (!cmd->progs[0].argv[1] == 1)
278 return FALSE;
279
280 input = fopen(cmd->progs[0].argv[1], "r");
281 if (!input) {
282 fprintf(stdout, "Couldn't open file '%s'\n", cmd->progs[0].argv[1]);
283 return FALSE;
284 }
285 284
286 /* Now run the file */ 285 if (!cmd->progs[0].argv[1] == 1)
287 status = busy_loop(input); 286 return FALSE;
288 return (status); 287
288 input = fopen(cmd->progs[0].argv[1], "r");
289 if (!input) {
290 fprintf(stdout, "Couldn't open file '%s'\n",
291 cmd->progs[0].argv[1]);
292 return FALSE;
293 }
294
295 /* Now run the file */
296 status = busy_loop(input);
297 return (status);
289} 298}
290 299
291/* built-in 'unset VAR' handler */ 300/* built-in 'unset VAR' handler */
292static int shell_unset(struct job* cmd, struct jobSet* junk) 301static int shell_unset(struct job *cmd, struct jobSet *junk)
293{ 302{
294 if (!cmd->progs[0].argv[1] == 1) { 303 if (!cmd->progs[0].argv[1] == 1) {
295 fprintf(stdout, "unset: parameter required.\n"); 304 fprintf(stdout, "unset: parameter required.\n");
296 return FALSE; 305 return FALSE;
297 } 306 }
298 unsetenv(cmd->progs[0].argv[1]); 307 unsetenv(cmd->progs[0].argv[1]);
299 return TRUE; 308 return TRUE;
300} 309}
301 310
302/* free up all memory from a job */ 311/* free up all memory from a job */
303static void freeJob(struct job * cmd) 312static void freeJob(struct job *cmd)
304{ 313{
305 int i; 314 int i;
306 315
307 for (i = 0; i < cmd->numProgs; i++) { 316 for (i = 0; i < cmd->numProgs; i++) {
308 free(cmd->progs[i].argv); 317 free(cmd->progs[i].argv);
309 if (cmd->progs[i].redirections) free(cmd->progs[i].redirections); 318 if (cmd->progs[i].redirections)
310 if (cmd->progs[i].freeGlob) globfree(&cmd->progs[i].globResult); 319 free(cmd->progs[i].redirections);
320 if (cmd->progs[i].freeGlob)
321 globfree(&cmd->progs[i].globResult);
311 } 322 }
312 free(cmd->progs); 323 free(cmd->progs);
313 if (cmd->text) free(cmd->text); 324 if (cmd->text)
325 free(cmd->text);
314 free(cmd->cmdBuf); 326 free(cmd->cmdBuf);
315} 327}
316 328
317/* remove a job from the jobList */ 329/* remove a job from the jobList */
318static void removeJob(struct jobSet * jobList, struct job * job) 330static void removeJob(struct jobSet *jobList, struct job *job)
319{ 331{
320 struct job * prevJob; 332 struct job *prevJob;
321 333
322 freeJob(job); 334 freeJob(job);
323 if (job == jobList->head) { 335 if (job == jobList->head) {
324 jobList->head = job->next; 336 jobList->head = job->next;
325 } else { 337 } else {
326 prevJob = jobList->head; 338 prevJob = jobList->head;
327 while (prevJob->next != job) prevJob = prevJob->next; 339 while (prevJob->next != job)
328 prevJob->next = job->next; 340 prevJob = prevJob->next;
341 prevJob->next = job->next;
329 } 342 }
330 343
331 free(job); 344 free(job);
@@ -333,56 +346,62 @@ static void removeJob(struct jobSet * jobList, struct job * job)
333 346
334/* Checks to see if any background processes have exited -- if they 347/* Checks to see if any background processes have exited -- if they
335 have, figure out why and see if a job has completed */ 348 have, figure out why and see if a job has completed */
336static void checkJobs(struct jobSet * jobList) 349static void checkJobs(struct jobSet *jobList)
337{ 350{
338 struct job * job; 351 struct job *job;
339 pid_t childpid; 352 pid_t childpid;
340 int status; 353 int status;
341 int progNum=0; 354 int progNum = 0;
342 355
343 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { 356 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
344 for (job = jobList->head; job; job = job->next) { 357 for (job = jobList->head; job; job = job->next) {
345 progNum = 0; 358 progNum = 0;
346 while (progNum < job->numProgs && 359 while (progNum < job->numProgs &&
347 job->progs[progNum].pid != childpid) 360 job->progs[progNum].pid != childpid) progNum++;
348 progNum++; 361 if (progNum < job->numProgs)
349 if (progNum < job->numProgs) break; 362 break;
350 } 363 }
351 364
352 if (WIFEXITED(status) || WIFSIGNALED(status)) { 365 if (WIFEXITED(status) || WIFSIGNALED(status)) {
353 /* child exited */ 366 /* child exited */
354 job->runningProgs--; 367 job->runningProgs--;
355 job->progs[progNum].pid = 0; 368 job->progs[progNum].pid = 0;
356 369
357 if (!job->runningProgs) { 370 if (!job->runningProgs) {
358 printf(JOB_STATUS_FORMAT, job->jobId, "Done", job->text); 371 printf(JOB_STATUS_FORMAT, job->jobId, "Done", job->text);
359 removeJob(jobList, job); 372 removeJob(jobList, job);
360 } 373 }
361 } else { 374 } else {
362 /* child stopped */ 375 /* child stopped */
363 job->stoppedProgs++; 376 job->stoppedProgs++;
364 job->progs[progNum].isStopped = 1; 377 job->progs[progNum].isStopped = 1;
365 378
366 if (job->stoppedProgs == job->numProgs) { 379 if (job->stoppedProgs == job->numProgs) {
367 printf(JOB_STATUS_FORMAT, job->jobId, "Stopped", job->text); 380 printf(JOB_STATUS_FORMAT, job->jobId, "Stopped",
368 } 381 job->text);
369 } 382 }
383 }
370 } 384 }
371 385
372 if (childpid == -1 && errno != ECHILD) 386 if (childpid == -1 && errno != ECHILD)
373 perror("waitpid"); 387 perror("waitpid");
374} 388}
375 389
376static int getCommand(FILE * source, char * command) 390static int getCommand(FILE * source, char *command)
377{ 391{
378 if (source == stdin) { 392 if (source == stdin) {
379 fprintf(stdout, "%s %s", cwd, prompt); 393 fprintf(stdout, "BBSHELL %s %s", cwd, prompt);
380 fflush(stdout); 394 fflush(stdout);
395#ifdef BB_FEATURE_SH_COMMAND_EDITING
396 cmdedit_read_input(fileno(stdin), fileno(stdout), command);
397 return 0;
398#endif
381 } 399 }
382 400
383 if (!fgets(command, MAX_COMMAND_LEN, source)) { 401 if (!fgets(command, BUFSIZ - 2, source)) {
384 if (source == stdin) printf("\n"); 402 if (source == stdin)
385 return 1; 403 printf("\n");
404 return 1;
386 } 405 }
387 406
388 /* remove trailing newline */ 407 /* remove trailing newline */
@@ -391,46 +410,48 @@ static int getCommand(FILE * source, char * command)
391 return 0; 410 return 0;
392} 411}
393 412
394static void globLastArgument(struct childProgram * prog, int * argcPtr, 413static void globLastArgument(struct childProgram *prog, int *argcPtr,
395 int * argcAllocedPtr) 414 int *argcAllocedPtr)
396{ 415{
397 int argc = *argcPtr; 416 int argc = *argcPtr;
398 int argcAlloced = *argcAllocedPtr; 417 int argcAlloced = *argcAllocedPtr;
399 int rc; 418 int rc;
400 int flags; 419 int flags;
401 int i; 420 int i;
402 char * src, * dst; 421 char *src, *dst;
403 422
404 if (argc > 1) { /* cmd->globResult is already initialized */ 423 if (argc > 1) { /* cmd->globResult is already initialized */
405 flags = GLOB_APPEND; 424 flags = GLOB_APPEND;
406 i = prog->globResult.gl_pathc; 425 i = prog->globResult.gl_pathc;
407 } else { 426 } else {
408 prog->freeGlob = 1; 427 prog->freeGlob = 1;
409 flags = 0; 428 flags = 0;
410 i = 0; 429 i = 0;
411 } 430 }
412 431
413 rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult); 432 rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult);
414 if (rc == GLOB_NOSPACE) { 433 if (rc == GLOB_NOSPACE) {
415 fprintf(stderr, "out of space during glob operation\n"); 434 fprintf(stderr, "out of space during glob operation\n");
416 return; 435 return;
417 } else if (rc == GLOB_NOMATCH || 436 } else if (rc == GLOB_NOMATCH ||
418 (!rc && (prog->globResult.gl_pathc - i) == 1 && 437 (!rc && (prog->globResult.gl_pathc - i) == 1 &&
419 !strcmp(prog->argv[argc - 1], 438 !strcmp(prog->argv[argc - 1],
420 prog->globResult.gl_pathv[i]))) { 439 prog->globResult.gl_pathv[i]))) {
421 /* we need to remove whatever \ quoting is still present */ 440 /* we need to remove whatever \ quoting is still present */
422 src = dst = prog->argv[argc - 1]; 441 src = dst = prog->argv[argc - 1];
423 while (*src) { 442 while (*src) {
424 if (*src != '\\') *dst++ = *src; 443 if (*src != '\\')
425 src++; 444 *dst++ = *src;
426 } 445 src++;
427 *dst = '\0'; 446 }
447 *dst = '\0';
428 } else if (!rc) { 448 } else if (!rc) {
429 argcAlloced += (prog->globResult.gl_pathc - i); 449 argcAlloced += (prog->globResult.gl_pathc - i);
430 prog->argv = realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); 450 prog->argv =
431 memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i, 451 realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
432 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); 452 memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i,
433 argc += (prog->globResult.gl_pathc - i - 1); 453 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
454 argc += (prog->globResult.gl_pathc - i - 1);
434 } 455 }
435 456
436 *argcAllocedPtr = argcAlloced; 457 *argcAllocedPtr = argcAlloced;
@@ -442,27 +463,28 @@ static void globLastArgument(struct childProgram * prog, int * argcPtr,
442 the beginning of the next command (if the original command had more 463 the beginning of the next command (if the original command had more
443 then one job associated with it) or NULL if no more commands are 464 then one job associated with it) or NULL if no more commands are
444 present. */ 465 present. */
445static int parseCommand(char ** commandPtr, struct job * job, int * isBg) 466static int parseCommand(char **commandPtr, struct job *job, int *isBg)
446{ 467{
447 char * command; 468 char *command;
448 char * returnCommand = NULL; 469 char *returnCommand = NULL;
449 char * src, * buf, * chptr; 470 char *src, *buf, *chptr;
450 int argc = 0; 471 int argc = 0;
451 int done = 0; 472 int done = 0;
452 int argvAlloced; 473 int argvAlloced;
453 int i; 474 int i;
454 char quote = '\0'; 475 char quote = '\0';
455 int count; 476 int count;
456 struct childProgram * prog; 477 struct childProgram *prog;
457 478
458 /* skip leading white space */ 479 /* skip leading white space */
459 while (**commandPtr && isspace(**commandPtr)) (*commandPtr)++; 480 while (**commandPtr && isspace(**commandPtr))
460 481 (*commandPtr)++;
461 /* this handles empty lines or leading '#' characters */ 482
462 if (!**commandPtr || (**commandPtr=='#')) { 483 /* this handles empty lines or leading '#' characters */
463 job->numProgs = 0; 484 if (!**commandPtr || (**commandPtr == '#')) {
464 *commandPtr = NULL; 485 job->numProgs = 0;
465 return 0; 486 *commandPtr = NULL;
487 return 0;
466 } 488 }
467 489
468 *isBg = 0; 490 *isBg = 0;
@@ -491,177 +513,185 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
491 buf = command; 513 buf = command;
492 src = *commandPtr; 514 src = *commandPtr;
493 while (*src && !done) { 515 while (*src && !done) {
494 if (quote == *src) { 516 if (quote == *src) {
495 quote = '\0'; 517 quote = '\0';
496 } else if (quote) { 518 } else if (quote) {
497 if (*src == '\\') { 519 if (*src == '\\') {
498 src++; 520 src++;
499 if (!*src) { 521 if (!*src) {
500 fprintf(stderr, "character expected after \\\n"); 522 fprintf(stderr, "character expected after \\\n");
501 freeJob(job); 523 freeJob(job);
502 return 1; 524 return 1;
503 } 525 }
504 526
505 /* in shell, "\'" should yield \' */ 527 /* in shell, "\'" should yield \' */
506 if (*src != quote) *buf++ = '\\'; 528 if (*src != quote)
507 } else if (*src == '*' || *src == '?' || *src == '[' || 529 *buf++ = '\\';
508 *src == ']') 530 } else if (*src == '*' || *src == '?' || *src == '[' ||
509 *buf++ = '\\'; 531 *src == ']') *buf++ = '\\';
510 *buf++ = *src; 532 *buf++ = *src;
511 } else if (isspace(*src)) { 533 } else if (isspace(*src)) {
512 if (*prog->argv[argc]) { 534 if (*prog->argv[argc]) {
513 buf++, argc++; 535 buf++, argc++;
514 /* +1 here leaves room for the NULL which ends argv */ 536 /* +1 here leaves room for the NULL which ends argv */
515 if ((argc + 1) == argvAlloced) { 537 if ((argc + 1) == argvAlloced) {
516 argvAlloced += 5; 538 argvAlloced += 5;
517 prog->argv = realloc(prog->argv, 539 prog->argv = realloc(prog->argv,
518 sizeof(*prog->argv) * argvAlloced); 540 sizeof(*prog->argv) *
519 } 541 argvAlloced);
520 prog->argv[argc] = buf; 542 }
521 543 prog->argv[argc] = buf;
522 globLastArgument(prog, &argc, &argvAlloced); 544
523 } 545 globLastArgument(prog, &argc, &argvAlloced);
524 } else switch (*src) { 546 }
525 case '"': 547 } else
526 case '\'': 548 switch (*src) {
527 quote = *src; 549 case '"':
528 break; 550 case '\'':
529 551 quote = *src;
530 case '#': /* comment */ 552 break;
531 done = 1; 553
532 break; 554 case '#': /* comment */
533 555 done = 1;
534 case '>': /* redirections */ 556 break;
535 case '<': 557
536 i = prog->numRedirections++; 558 case '>': /* redirections */
537 prog->redirections = realloc(prog->redirections, 559 case '<':
538 sizeof(*prog->redirections) * (i + 1)); 560 i = prog->numRedirections++;
539 561 prog->redirections = realloc(prog->redirections,
540 prog->redirections[i].fd = -1; 562 sizeof(*prog->redirections) *
541 if (buf != prog->argv[argc]) { 563 (i + 1));
542 /* the stuff before this character may be the file number 564
543 being redirected */ 565 prog->redirections[i].fd = -1;
544 prog->redirections[i].fd = strtol(prog->argv[argc], &chptr, 10); 566 if (buf != prog->argv[argc]) {
545 567 /* the stuff before this character may be the file number
546 if (*chptr && *prog->argv[argc]) { 568 being redirected */
547 buf++, argc++; 569 prog->redirections[i].fd =
548 globLastArgument(prog, &argc, &argvAlloced); 570 strtol(prog->argv[argc], &chptr, 10);
549 } 571
550 } 572 if (*chptr && *prog->argv[argc]) {
551 573 buf++, argc++;
552 if (prog->redirections[i].fd == -1) { 574 globLastArgument(prog, &argc, &argvAlloced);
553 if (*src == '>') 575 }
554 prog->redirections[i].fd = 1; 576 }
555 else 577
556 prog->redirections[i].fd = 0; 578 if (prog->redirections[i].fd == -1) {
557 } 579 if (*src == '>')
558 580 prog->redirections[i].fd = 1;
559 if (*src++ == '>') { 581 else
560 if (*src == '>') 582 prog->redirections[i].fd = 0;
561 prog->redirections[i].type = REDIRECT_APPEND, src++; 583 }
562 else 584
563 prog->redirections[i].type = REDIRECT_OVERWRITE; 585 if (*src++ == '>') {
564 } else { 586 if (*src == '>')
565 prog->redirections[i].type = REDIRECT_INPUT; 587 prog->redirections[i].type =
566 } 588 REDIRECT_APPEND, src++;
567 589 else
568 /* This isn't POSIX sh compliant. Oh well. */ 590 prog->redirections[i].type = REDIRECT_OVERWRITE;
569 chptr = src; 591 } else {
570 while (isspace(*chptr)) chptr++; 592 prog->redirections[i].type = REDIRECT_INPUT;
571 593 }
572 if (!*chptr) { 594
573 fprintf(stderr, "file name expected after %c\n", *src); 595 /* This isn't POSIX sh compliant. Oh well. */
574 freeJob(job); 596 chptr = src;
575 return 1; 597 while (isspace(*chptr))
576 } 598 chptr++;
577 599
578 prog->redirections[i].filename = buf; 600 if (!*chptr) {
579 while (*chptr && !isspace(*chptr)) 601 fprintf(stderr, "file name expected after %c\n", *src);
580 *buf++ = *chptr++; 602 freeJob(job);
581 603 return 1;
582 src = chptr - 1; /* we src++ later */ 604 }
583 prog->argv[argc] = ++buf; 605
584 break; 606 prog->redirections[i].filename = buf;
585 607 while (*chptr && !isspace(*chptr))
586 case '|': /* pipe */ 608 *buf++ = *chptr++;
587 /* finish this command */ 609
588 if (*prog->argv[argc]) argc++; 610 src = chptr - 1; /* we src++ later */
589 if (!argc) { 611 prog->argv[argc] = ++buf;
590 fprintf(stderr, "empty command in pipe\n"); 612 break;
591 freeJob(job); 613
592 return 1; 614 case '|': /* pipe */
593 } 615 /* finish this command */
594 prog->argv[argc] = NULL; 616 if (*prog->argv[argc])
595 617 argc++;
596 /* and start the next */ 618 if (!argc) {
597 job->numProgs++; 619 fprintf(stderr, "empty command in pipe\n");
598 job->progs = realloc(job->progs, 620 freeJob(job);
599 sizeof(*job->progs) * job->numProgs); 621 return 1;
600 prog = job->progs + (job->numProgs - 1); 622 }
601 prog->numRedirections = 0; 623 prog->argv[argc] = NULL;
602 prog->redirections = NULL; 624
603 prog->freeGlob = 0; 625 /* and start the next */
604 argc = 0; 626 job->numProgs++;
605 627 job->progs = realloc(job->progs,
606 argvAlloced = 5; 628 sizeof(*job->progs) * job->numProgs);
607 prog->argv = malloc(sizeof(*prog->argv) * argvAlloced); 629 prog = job->progs + (job->numProgs - 1);
608 prog->argv[0] = ++buf; 630 prog->numRedirections = 0;
609 631 prog->redirections = NULL;
610 src++; 632 prog->freeGlob = 0;
611 while (*src && isspace(*src)) src++; 633 argc = 0;
612 634
613 if (!*src) { 635 argvAlloced = 5;
614 fprintf(stderr, "empty command in pipe\n"); 636 prog->argv = malloc(sizeof(*prog->argv) * argvAlloced);
615 return 1; 637 prog->argv[0] = ++buf;
616 } 638
617 src--; /* we'll ++ it at the end of the loop */ 639 src++;
618 640 while (*src && isspace(*src))
619 break; 641 src++;
620 642
621 case '&': /* background */ 643 if (!*src) {
622 *isBg = 1; 644 fprintf(stderr, "empty command in pipe\n");
623 case ';': /* multiple commands */ 645 return 1;
624 done = 1; 646 }
625 returnCommand = *commandPtr + (src - *commandPtr) + 1; 647 src--; /* we'll ++ it at the end of the loop */
626 break; 648
627 649 break;
628 case '\\': 650
629 src++; 651 case '&': /* background */
630 if (!*src) { 652 *isBg = 1;
631 freeJob(job); 653 case ';': /* multiple commands */
632 fprintf(stderr, "character expected after \\\n"); 654 done = 1;
633 return 1; 655 returnCommand = *commandPtr + (src - *commandPtr) + 1;
634 } 656 break;
635 if (*src == '*' || *src == '[' || *src == ']' || *src == '?') 657
636 *buf++ = '\\'; 658 case '\\':
637 /* fallthrough */ 659 src++;
638 default: 660 if (!*src) {
639 *buf++ = *src; 661 freeJob(job);
640 } 662 fprintf(stderr, "character expected after \\\n");
641 663 return 1;
642 src++; 664 }
665 if (*src == '*' || *src == '[' || *src == ']'
666 || *src == '?') *buf++ = '\\';
667 /* fallthrough */
668 default:
669 *buf++ = *src;
670 }
671
672 src++;
643 } 673 }
644 674
645 if (*prog->argv[argc]) { 675 if (*prog->argv[argc]) {
646 argc++; 676 argc++;
647 globLastArgument(prog, &argc, &argvAlloced); 677 globLastArgument(prog, &argc, &argvAlloced);
648 } 678 }
649 if (!argc) { 679 if (!argc) {
650 freeJob(job); 680 freeJob(job);
651 return 0; 681 return 0;
652 } 682 }
653 prog->argv[argc] = NULL; 683 prog->argv[argc] = NULL;
654 684
655 if (!returnCommand) { 685 if (!returnCommand) {
656 job->text = malloc(strlen(*commandPtr) + 1); 686 job->text = malloc(strlen(*commandPtr) + 1);
657 strcpy(job->text, *commandPtr); 687 strcpy(job->text, *commandPtr);
658 } else { 688 } else {
659 /* This leaves any trailing spaces, which is a bit sloppy */ 689 /* This leaves any trailing spaces, which is a bit sloppy */
660 690
661 count = returnCommand - *commandPtr; 691 count = returnCommand - *commandPtr;
662 job->text = malloc(count + 1); 692 job->text = malloc(count + 1);
663 strncpy(job->text, *commandPtr, count); 693 strncpy(job->text, *commandPtr, count);
664 job->text[count] = '\0'; 694 job->text[count] = '\0';
665 } 695 }
666 696
667 *commandPtr = returnCommand; 697 *commandPtr = returnCommand;
@@ -669,63 +699,64 @@ static int parseCommand(char ** commandPtr, struct job * job, int * isBg)
669 return 0; 699 return 0;
670} 700}
671 701
672static int runCommand(struct job newJob, struct jobSet * jobList, 702static int runCommand(struct job newJob, struct jobSet *jobList, int inBg)
673 int inBg)
674{ 703{
675 struct job * job; 704 struct job *job;
676 int i; 705 int i;
677 int nextin, nextout; 706 int nextin, nextout;
678 int pipefds[2]; /* pipefd[0] is for reading */ 707 int pipefds[2]; /* pipefd[0] is for reading */
679 struct builtInCommand *x; 708 struct builtInCommand *x;
680 709
681 /* handle built-ins here -- we don't fork() so we can't background 710 /* handle built-ins here -- we don't fork() so we can't background
682 these very easily */ 711 these very easily */
683 for( x=bltins ; x->cmd ; x++) { 712 for (x = bltins; x->cmd; x++) {
684 if (!strcmp(newJob.progs[0].argv[0], x->cmd)) { 713 if (!strcmp(newJob.progs[0].argv[0], x->cmd)) {
685 return(x->function(&newJob, jobList)); 714 return (x->function(&newJob, jobList));
686 } 715 }
687 } 716 }
688 717
689 nextin = 0, nextout = 1; 718 nextin = 0, nextout = 1;
690 for (i = 0; i < newJob.numProgs; i++) { 719 for (i = 0; i < newJob.numProgs; i++) {
691 if ((i + 1) < newJob.numProgs) { 720 if ((i + 1) < newJob.numProgs) {
692 pipe(pipefds); 721 pipe(pipefds);
693 nextout = pipefds[1]; 722 nextout = pipefds[1];
694 } else { 723 } else {
695 nextout = 1; 724 nextout = 1;
696 } 725 }
697 726
698 if (!(newJob.progs[i].pid = fork())) { 727 if (!(newJob.progs[i].pid = fork())) {
699 signal(SIGTTOU, SIG_DFL); 728 signal(SIGTTOU, SIG_DFL);
700 729
701 if (nextin != 0) { 730 if (nextin != 0) {
702 dup2(nextin, 0); 731 dup2(nextin, 0);
703 close(nextin); 732 close(nextin);
704 } 733 }
705 734
706 if (nextout != 1) { 735 if (nextout != 1) {
707 dup2(nextout, 1); 736 dup2(nextout, 1);
708 close(nextout); 737 close(nextout);
709 } 738 }
710 739
711 /* explicit redirections override pipes */ 740 /* explicit redirections override pipes */
712 setupRedirections(newJob.progs + i); 741 setupRedirections(newJob.progs + i);
713 742
714 execvp(newJob.progs[i].argv[0], newJob.progs[i].argv); 743 execvp(newJob.progs[i].argv[0], newJob.progs[i].argv);
715 fatalError( "sh: %s: %s\n", newJob.progs[i].argv[0], 744 fatalError("sh: %s: %s\n", newJob.progs[i].argv[0],
716 strerror(errno)); 745 strerror(errno));
717 } 746 }
718 747
719 /* put our child in the process group whose leader is the 748 /* put our child in the process group whose leader is the
720 first process in this pipe */ 749 first process in this pipe */
721 setpgid(newJob.progs[i].pid, newJob.progs[0].pid); 750 setpgid(newJob.progs[i].pid, newJob.progs[0].pid);
722 751
723 if (nextin != 0) close(nextin); 752 if (nextin != 0)
724 if (nextout != 1) close(nextout); 753 close(nextin);
725 754 if (nextout != 1)
726 /* If there isn't another process, nextin is garbage 755 close(nextout);
727 but it doesn't matter */ 756
728 nextin = pipefds[0]; 757 /* If there isn't another process, nextin is garbage
758 but it doesn't matter */
759 nextin = pipefds[0];
729 } 760 }
730 761
731 newJob.pgrp = newJob.progs[0].pid; 762 newJob.pgrp = newJob.progs[0].pid;
@@ -733,16 +764,16 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
733 /* find the ID for the job to use */ 764 /* find the ID for the job to use */
734 newJob.jobId = 1; 765 newJob.jobId = 1;
735 for (job = jobList->head; job; job = job->next) 766 for (job = jobList->head; job; job = job->next)
736 if (job->jobId >= newJob.jobId) 767 if (job->jobId >= newJob.jobId)
737 newJob.jobId = job->jobId + 1; 768 newJob.jobId = job->jobId + 1;
738 769
739 /* add the job to the list of running jobs */ 770 /* add the job to the list of running jobs */
740 if (!jobList->head) { 771 if (!jobList->head) {
741 job = jobList->head = malloc(sizeof(*job)); 772 job = jobList->head = malloc(sizeof(*job));
742 } else { 773 } else {
743 for (job = jobList->head; job->next; job = job->next); 774 for (job = jobList->head; job->next; job = job->next);
744 job->next = malloc(sizeof(*job)); 775 job->next = malloc(sizeof(*job));
745 job = job->next; 776 job = job->next;
746 } 777 }
747 778
748 *job = newJob; 779 *job = newJob;
@@ -751,165 +782,177 @@ static int runCommand(struct job newJob, struct jobSet * jobList,
751 job->stoppedProgs = 0; 782 job->stoppedProgs = 0;
752 783
753 if (inBg) { 784 if (inBg) {
754 /* we don't wait for background jobs to return -- append it 785 /* we don't wait for background jobs to return -- append it
755 to the list of backgrounded jobs and leave it alone */ 786 to the list of backgrounded jobs and leave it alone */
756 787
757 printf("[%d] %d\n", job->jobId, 788 printf("[%d] %d\n", job->jobId,
758 newJob.progs[newJob.numProgs - 1].pid); 789 newJob.progs[newJob.numProgs - 1].pid);
759 } else { 790 } else {
760 jobList->fg = job; 791 jobList->fg = job;
792
793 /* move the new process group into the foreground */
761 794
762 /* move the new process group into the foreground */ 795 if (tcsetpgrp(0, newJob.pgrp))
763 796 perror("tcsetpgrp");
764 if (tcsetpgrp(0, newJob.pgrp))
765 perror("tcsetpgrp");
766 } 797 }
767 798
768 return 0; 799 return 0;
769} 800}
770 801
771static int setupRedirections(struct childProgram * prog) 802static int setupRedirections(struct childProgram *prog)
772{ 803{
773 int i; 804 int i;
774 int openfd; 805 int openfd;
775 int mode=O_RDONLY; 806 int mode = O_RDONLY;
776 struct redirectionSpecifier * redir = prog->redirections; 807 struct redirectionSpecifier *redir = prog->redirections;
777 808
778 for (i = 0; i < prog->numRedirections; i++, redir++) { 809 for (i = 0; i < prog->numRedirections; i++, redir++) {
779 switch (redir->type) { 810 switch (redir->type) {
780 case REDIRECT_INPUT: 811 case REDIRECT_INPUT:
781 mode = O_RDONLY; 812 mode = O_RDONLY;
782 break; 813 break;
783 case REDIRECT_OVERWRITE: 814 case REDIRECT_OVERWRITE:
784 mode = O_RDWR | O_CREAT | O_TRUNC; 815 mode = O_RDWR | O_CREAT | O_TRUNC;
785 break; 816 break;
786 case REDIRECT_APPEND: 817 case REDIRECT_APPEND:
787 mode = O_RDWR | O_CREAT | O_APPEND; 818 mode = O_RDWR | O_CREAT | O_APPEND;
788 break; 819 break;
789 } 820 }
790 821
791 openfd = open(redir->filename, mode, 0666); 822 openfd = open(redir->filename, mode, 0666);
792 if (openfd < 0) { 823 if (openfd < 0) {
793 /* this could get lost if stderr has been redirected, but 824 /* this could get lost if stderr has been redirected, but
794 bash and ash both lose it as well (though zsh doesn't!) */ 825 bash and ash both lose it as well (though zsh doesn't!) */
795 fprintf(stderr, "error opening %s: %s\n", redir->filename, 826 fprintf(stderr, "error opening %s: %s\n", redir->filename,
796 strerror(errno)); 827 strerror(errno));
797 return 1; 828 return 1;
798 } 829 }
799 830
800 if (openfd != redir->fd) { 831 if (openfd != redir->fd) {
801 dup2(openfd, redir->fd); 832 dup2(openfd, redir->fd);
802 close(openfd); 833 close(openfd);
803 } 834 }
804 } 835 }
805 836
806 return 0; 837 return 0;
807} 838}
808 839
809 840
810static int busy_loop(FILE * input) 841static int busy_loop(FILE * input)
811{ 842{
812 char command[MAX_COMMAND_LEN + 1]; 843 char *command;
813 char * nextCommand = NULL; 844 char *nextCommand = NULL;
814 struct jobSet jobList = { NULL, NULL }; 845 struct jobSet jobList = { NULL, NULL };
815 struct job newJob; 846 struct job newJob;
816 int i; 847 int i;
817 int status; 848 int status;
818 int inBg; 849 int inBg;
819 850
851 command = (char*) calloc(BUFSIZ, sizeof(char));
852
820 /* don't pay any attention to this signal; it just confuses 853 /* don't pay any attention to this signal; it just confuses
821 things and isn't really meant for shells anyway */ 854 things and isn't really meant for shells anyway */
822 signal(SIGTTOU, SIG_IGN); 855 signal(SIGTTOU, SIG_IGN);
823 856
824 while (1) { 857 while (1) {
825 if (!jobList.fg) { 858 if (!jobList.fg) {
826 /* no job is in the foreground */ 859 /* no job is in the foreground */
827 860
828 /* see if any background processes have exited */ 861 /* see if any background processes have exited */
829 checkJobs(&jobList); 862 checkJobs(&jobList);
830 863
831 if (!nextCommand) { 864 if (!nextCommand) {
832 if (getCommand(input, command)) break; 865 if (getCommand(input, command))
833 nextCommand = command; 866 break;
834 } 867 nextCommand = command;
835 868 }
836 if (!parseCommand(&nextCommand, &newJob, &inBg) && 869
837 newJob.numProgs) { 870 if (!parseCommand(&nextCommand, &newJob, &inBg) &&
838 runCommand(newJob, &jobList, inBg); 871 newJob.numProgs) {
839 } 872 runCommand(newJob, &jobList, inBg);
840 } else { 873 }
841 /* a job is running in the foreground; wait for it */ 874 } else {
842 i = 0; 875 /* a job is running in the foreground; wait for it */
843 while (!jobList.fg->progs[i].pid || 876 i = 0;
844 jobList.fg->progs[i].isStopped) i++; 877 while (!jobList.fg->progs[i].pid ||
845 878 jobList.fg->progs[i].isStopped) i++;
846 waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED); 879
847 880 waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED);
848 if (WIFEXITED(status) || WIFSIGNALED(status)) { 881
849 /* the child exited */ 882 if (WIFEXITED(status) || WIFSIGNALED(status)) {
850 jobList.fg->runningProgs--; 883 /* the child exited */
851 jobList.fg->progs[i].pid = 0; 884 jobList.fg->runningProgs--;
852 885 jobList.fg->progs[i].pid = 0;
853 if (!jobList.fg->runningProgs) { 886
854 /* child exited */ 887 if (!jobList.fg->runningProgs) {
855 888 /* child exited */
856 removeJob(&jobList, jobList.fg); 889
857 jobList.fg = NULL; 890 removeJob(&jobList, jobList.fg);
858 891 jobList.fg = NULL;
859 /* move the shell to the foreground */ 892
860 if (tcsetpgrp(0, getpid())) 893 /* move the shell to the foreground */
861 perror("tcsetpgrp"); 894 if (tcsetpgrp(0, getpid()))
862 } 895 perror("tcsetpgrp");
863 } else { 896 }
864 /* the child was stopped */ 897 } else {
865 jobList.fg->stoppedProgs++; 898 /* the child was stopped */
866 jobList.fg->progs[i].isStopped = 1; 899 jobList.fg->stoppedProgs++;
867 900 jobList.fg->progs[i].isStopped = 1;
868 if (jobList.fg->stoppedProgs == jobList.fg->runningProgs) { 901
869 printf("\n" JOB_STATUS_FORMAT, jobList.fg->jobId, 902 if (jobList.fg->stoppedProgs == jobList.fg->runningProgs) {
870 "Stopped", jobList.fg->text); 903 printf("\n" JOB_STATUS_FORMAT, jobList.fg->jobId,
871 jobList.fg = NULL; 904 "Stopped", jobList.fg->text);
872 } 905 jobList.fg = NULL;
873 } 906 }
874 907 }
875 if (!jobList.fg) { 908
876 /* move the shell to the foreground */ 909 if (!jobList.fg) {
877 if (tcsetpgrp(0, getpid())) 910 /* move the shell to the foreground */
878 perror("tcsetpgrp"); 911 if (tcsetpgrp(0, getpid()))
879 } 912 perror("tcsetpgrp");
880 } 913 }
881 } 914 }
915 }
916 free( command);
882 917
883 return 0; 918 return 0;
884} 919}
885 920
886 921
887int shell_main(int argc, char ** argv) 922int shell_main(int argc, char **argv)
888{ 923{
889 FILE * input = stdin; 924 FILE *input = stdin;
890 925
891 if (argc > 2) { 926 if (argc > 2) {
892 usage( shell_usage); 927 usage(shell_usage);
893 } 928 }
894 /* initialize the cwd */ 929 /* initialize the cwd */
895 getcwd(cwd, sizeof(cwd)); 930 getcwd(cwd, sizeof(cwd));
896 931
897 932
898 //if (argv[0] && argv[0][0] == '-') { 933 //if (argv[0] && argv[0][0] == '-') {
899 // shell_source("/etc/profile"); 934 // shell_source("/etc/profile");
900 //} 935 //}
901 936
902 if (argc < 2) { 937 if (argc < 2) {
903 fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER, BB_BT); 938 fprintf(stdout, "\n\nBusyBox v%s (%s) Built-in shell\n", BB_VER,
904 fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); 939 BB_BT);
905 } else { 940 fprintf(stdout,
906 input = fopen(argv[1], "r"); 941 "Enter 'help' for a list of built-in commands.\n\n");
907 if (!input) 942 } else {
908 fatalError("A: Couldn't open file '%s': %s\n", argv[1], strerror(errno)); 943 input = fopen(argv[1], "r");
909// else 944 if (!input)
910// fatalError("Got it.\n"); 945 fatalError("A: Couldn't open file '%s': %s\n", argv[1],
911 //exit(shell_source(argv[1])); 946 strerror(errno));
912 } 947// else
913 948// fatalError("Got it.\n");
914 return (busy_loop( input)); 949 //exit(shell_source(argv[1]));
950
951 /* Set terminal IO to canonical mode, and save old term settings. */
952#ifdef BB_FEATURE_SH_COMMAND_EDITING
953 cmdedit_init();
954#endif
955 }
956
957 return (busy_loop(input));
915} 958}