Magellan Linux

Contents of /trunk/mkinitrd-magellan/busybox/shell/lash.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (show annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 39840 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

1 /* vi: set sw=4 ts=4: */
2 /*
3 * lash -- the BusyBox Lame-Ass SHell
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Based in part on ladsh.c by Michael K. Johnson and Erik W. Troan, which is
8 * under the following liberal license: "We have placed this source code in the
9 * public domain. Use it in any project, free or commercial."
10 *
11 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
12 */
13
14 /* This shell's parsing engine is officially at a dead-end. Future
15 * work shell work should be done using hush, msh, or ash. This is
16 * still a very useful, small shell -- it just don't need any more
17 * features beyond what it already has...
18 */
19
20 //For debugging/development on the shell only...
21 //#define DEBUG_SHELL
22
23
24 #include "busybox.h"
25 #include <getopt.h>
26 #include "cmdedit.h"
27
28 #include <glob.h>
29 #define expand_t glob_t
30
31 /* Always enable for the moment... */
32 #define CONFIG_LASH_PIPE_N_REDIRECTS
33 #define CONFIG_LASH_JOB_CONTROL
34
35 static const int MAX_READ = 128; /* size of input buffer for `read' builtin */
36 #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
37
38
39 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
40 enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE,
41 REDIRECT_APPEND
42 };
43 #endif
44
45 enum {
46 DEFAULT_CONTEXT = 0x1,
47 IF_TRUE_CONTEXT = 0x2,
48 IF_FALSE_CONTEXT = 0x4,
49 THEN_EXP_CONTEXT = 0x8,
50 ELSE_EXP_CONTEXT = 0x10
51 };
52
53 #define LASH_OPT_DONE (1)
54 #define LASH_OPT_SAW_QUOTE (2)
55
56 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
57 struct redir_struct {
58 enum redir_type type; /* type of redirection */
59 int fd; /* file descriptor being redirected */
60 char *filename; /* file to redirect fd to */
61 };
62 #endif
63
64 struct child_prog {
65 pid_t pid; /* 0 if exited */
66 char **argv; /* program name and arguments */
67 int num_redirects; /* elements in redirection array */
68 int is_stopped; /* is the program currently running? */
69 struct job *family; /* pointer back to the child's parent job */
70 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
71 struct redir_struct *redirects; /* I/O redirects */
72 #endif
73 };
74
75 struct jobset {
76 struct job *head; /* head of list of running jobs */
77 struct job *fg; /* current foreground job */
78 };
79
80 struct job {
81 int jobid; /* job number */
82 int num_progs; /* total number of programs in job */
83 int running_progs; /* number of programs running */
84 char *text; /* name of job */
85 char *cmdbuf; /* buffer various argv's point into */
86 pid_t pgrp; /* process group ID for the job */
87 struct child_prog *progs; /* array of programs in job */
88 struct job *next; /* to track background commands */
89 int stopped_progs; /* number of programs alive, but stopped */
90 unsigned int job_context; /* bitmask defining current context */
91 struct jobset *job_list;
92 };
93
94 struct built_in_command {
95 char *cmd; /* name */
96 char *descr; /* description */
97 int (*function) (struct child_prog *); /* function ptr */
98 };
99
100 /* function prototypes for builtins */
101 static int builtin_cd(struct child_prog *cmd);
102 static int builtin_exec(struct child_prog *cmd);
103 static int builtin_exit(struct child_prog *cmd);
104 static int builtin_fg_bg(struct child_prog *cmd);
105 static int builtin_help(struct child_prog *cmd);
106 static int builtin_jobs(struct child_prog *dummy);
107 static int builtin_pwd(struct child_prog *dummy);
108 static int builtin_export(struct child_prog *cmd);
109 static int builtin_source(struct child_prog *cmd);
110 static int builtin_unset(struct child_prog *cmd);
111 static int builtin_read(struct child_prog *cmd);
112
113
114 /* function prototypes for shell stuff */
115 static void checkjobs(struct jobset *job_list);
116 static void remove_job(struct jobset *j_list, struct job *job);
117 static int get_command(FILE * source, char *command);
118 static int parse_command(char **command_ptr, struct job *job, int *inbg);
119 static int run_command(struct job *newjob, int inbg, int outpipe[2]);
120 static int pseudo_exec(struct child_prog *cmd) ATTRIBUTE_NORETURN;
121 static int busy_loop(FILE * input);
122
123
124 /* Table of built-in functions (these are non-forking builtins, meaning they
125 * can change global variables in the parent shell process but they will not
126 * work with pipes and redirects; 'unset foo | whatever' will not work) */
127 static struct built_in_command bltins[] = {
128 {"bg", "Resume a job in the background", builtin_fg_bg},
129 {"cd", "Change working directory", builtin_cd},
130 {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec},
131 {"exit", "Exit from shell()", builtin_exit},
132 {"fg", "Bring job into the foreground", builtin_fg_bg},
133 {"jobs", "Lists the active jobs", builtin_jobs},
134 {"export", "Set environment variable", builtin_export},
135 {"unset", "Unset environment variable", builtin_unset},
136 {"read", "Input environment variable", builtin_read},
137 {".", "Source-in and run commands in a file", builtin_source},
138 /* to do: add ulimit */
139 {NULL, NULL, NULL}
140 };
141
142 /* Table of forking built-in functions (things that fork cannot change global
143 * variables in the parent process, such as the current working directory) */
144 static struct built_in_command bltins_forking[] = {
145 {"pwd", "Print current directory", builtin_pwd},
146 {"help", "List shell built-in commands", builtin_help},
147 {NULL, NULL, NULL}
148 };
149
150
151 static int shell_context; /* Type prompt trigger (PS1 or PS2) */
152
153
154 /* Globals that are static to this file */
155 static const char *cwd;
156 static char *local_pending_command;
157 static struct jobset job_list = { NULL, NULL };
158 static int argc;
159 static char **argv;
160 static llist_t *close_me_list;
161 static int last_return_code;
162 static int last_bg_pid;
163 static unsigned int last_jobid;
164 static int shell_terminal;
165 static char *PS1;
166 static char *PS2 = "> ";
167
168
169 #ifdef DEBUG_SHELL
170 static inline void debug_printf(const char *format, ...)
171 {
172 va_list args;
173 va_start(args, format);
174 vfprintf(stderr, format, args);
175 va_end(args);
176 }
177 #else
178 static inline void debug_printf(const char ATTRIBUTE_UNUSED *format, ...) { }
179 #endif
180
181 /*
182 Most builtins need access to the struct child_prog that has
183 their arguments, previously coded as cmd->progs[0]. That coding
184 can exhibit a bug, if the builtin is not the first command in
185 a pipeline: "echo foo | exec sort" will attempt to exec foo.
186
187 builtin previous use notes
188 ------ ----------------- ---------
189 cd cmd->progs[0]
190 exec cmd->progs[0] squashed bug: didn't look for applets or forking builtins
191 exit cmd->progs[0]
192 fg_bg cmd->progs[0], job_list->head, job_list->fg
193 help 0
194 jobs job_list->head
195 pwd 0
196 export cmd->progs[0]
197 source cmd->progs[0]
198 unset cmd->progs[0]
199 read cmd->progs[0]
200
201 I added "struct job *family;" to struct child_prog,
202 and switched API to builtin_foo(struct child_prog *child);
203 So cmd->text becomes child->family->text
204 cmd->job_context becomes child->family->job_context
205 cmd->progs[0] becomes *child
206 job_list becomes child->family->job_list
207 */
208
209 /* built-in 'cd <path>' handler */
210 static int builtin_cd(struct child_prog *child)
211 {
212 char *newdir;
213
214 if (child->argv[1] == NULL)
215 newdir = getenv("HOME");
216 else
217 newdir = child->argv[1];
218 if (chdir(newdir)) {
219 bb_perror_msg("cd: %s", newdir);
220 return EXIT_FAILURE;
221 }
222 cwd = xgetcwd((char *)cwd);
223 if (!cwd)
224 cwd = bb_msg_unknown;
225 return EXIT_SUCCESS;
226 }
227
228 /* built-in 'exec' handler */
229 static int builtin_exec(struct child_prog *child)
230 {
231 if (child->argv[1] == NULL)
232 return EXIT_SUCCESS; /* Really? */
233 child->argv++;
234 while(close_me_list) close((long)llist_pop(&close_me_list));
235 pseudo_exec(child);
236 /* never returns */
237 }
238
239 /* built-in 'exit' handler */
240 static int builtin_exit(struct child_prog *child)
241 {
242 if (child->argv[1] == NULL)
243 exit(EXIT_SUCCESS);
244
245 exit (atoi(child->argv[1]));
246 }
247
248 /* built-in 'fg' and 'bg' handler */
249 static int builtin_fg_bg(struct child_prog *child)
250 {
251 int i, jobnum;
252 struct job *job=NULL;
253
254 /* If they gave us no args, assume they want the last backgrounded task */
255 if (!child->argv[1]) {
256 for (job = child->family->job_list->head; job; job = job->next) {
257 if (job->jobid == last_jobid) {
258 break;
259 }
260 }
261 if (!job) {
262 bb_error_msg("%s: no current job", child->argv[0]);
263 return EXIT_FAILURE;
264 }
265 } else {
266 if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
267 bb_error_msg(bb_msg_invalid_arg, child->argv[1], child->argv[0]);
268 return EXIT_FAILURE;
269 }
270 for (job = child->family->job_list->head; job; job = job->next) {
271 if (job->jobid == jobnum) {
272 break;
273 }
274 }
275 if (!job) {
276 bb_error_msg("%s: %d: no such job", child->argv[0], jobnum);
277 return EXIT_FAILURE;
278 }
279 }
280
281 if (*child->argv[0] == 'f') {
282 /* Put the job into the foreground. */
283 tcsetpgrp(shell_terminal, job->pgrp);
284
285 child->family->job_list->fg = job;
286 }
287
288 /* Restart the processes in the job */
289 for (i = 0; i < job->num_progs; i++)
290 job->progs[i].is_stopped = 0;
291
292 job->stopped_progs = 0;
293
294 if ( (i=kill(- job->pgrp, SIGCONT)) < 0) {
295 if (i == ESRCH) {
296 remove_job(&job_list, job);
297 } else {
298 bb_perror_msg("kill (SIGCONT)");
299 }
300 }
301
302 return EXIT_SUCCESS;
303 }
304
305 /* built-in 'help' handler */
306 static int builtin_help(struct child_prog ATTRIBUTE_UNUSED *dummy)
307 {
308 struct built_in_command *x;
309
310 printf("\nBuilt-in commands:\n"
311 "-------------------\n");
312 for (x = bltins; x->cmd; x++) {
313 if (x->descr==NULL)
314 continue;
315 printf("%s\t%s\n", x->cmd, x->descr);
316 }
317 for (x = bltins_forking; x->cmd; x++) {
318 if (x->descr==NULL)
319 continue;
320 printf("%s\t%s\n", x->cmd, x->descr);
321 }
322 putchar('\n');
323 return EXIT_SUCCESS;
324 }
325
326 /* built-in 'jobs' handler */
327 static int builtin_jobs(struct child_prog *child)
328 {
329 struct job *job;
330 char *status_string;
331
332 for (job = child->family->job_list->head; job; job = job->next) {
333 if (job->running_progs == job->stopped_progs)
334 status_string = "Stopped";
335 else
336 status_string = "Running";
337
338 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
339 }
340 return EXIT_SUCCESS;
341 }
342
343
344 /* built-in 'pwd' handler */
345 static int builtin_pwd(struct child_prog ATTRIBUTE_UNUSED *dummy)
346 {
347 cwd = xgetcwd((char *)cwd);
348 if (!cwd)
349 cwd = bb_msg_unknown;
350 puts(cwd);
351 return EXIT_SUCCESS;
352 }
353
354 /* built-in 'export VAR=value' handler */
355 static int builtin_export(struct child_prog *child)
356 {
357 int res;
358 char *v = child->argv[1];
359
360 if (v == NULL) {
361 char **e;
362 for (e = environ; *e; e++) {
363 puts(*e);
364 }
365 return 0;
366 }
367 res = putenv(v);
368 if (res)
369 bb_perror_msg("export");
370 #ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
371 if (strncmp(v, "PS1=", 4)==0)
372 PS1 = getenv("PS1");
373 #endif
374
375 #ifdef CONFIG_LOCALE_SUPPORT
376 // TODO: why getenv? "" would be just as good...
377 if(strncmp(v, "LC_ALL=", 7)==0)
378 setlocale(LC_ALL, getenv("LC_ALL"));
379 if(strncmp(v, "LC_CTYPE=", 9)==0)
380 setlocale(LC_CTYPE, getenv("LC_CTYPE"));
381 #endif
382
383 return res;
384 }
385
386 /* built-in 'read VAR' handler */
387 static int builtin_read(struct child_prog *child)
388 {
389 int res = 0, len;
390 char *s;
391 char string[MAX_READ];
392
393 if (child->argv[1]) {
394 /* argument (VAR) given: put "VAR=" into buffer */
395 safe_strncpy(string, child->argv[1], MAX_READ-1);
396 len = strlen(string);
397 string[len++] = '=';
398 string[len] = '\0';
399 fgets(&string[len], sizeof(string) - len, stdin); /* read string */
400 res = strlen(string);
401 if (res > len)
402 string[--res] = '\0'; /* chomp trailing newline */
403 /*
404 ** string should now contain "VAR=<value>"
405 ** copy it (putenv() won't do that, so we must make sure
406 ** the string resides in a static buffer!)
407 */
408 res = -1;
409 if ((s = strdup(string)))
410 res = putenv(s);
411 if (res)
412 bb_perror_msg("read");
413 }
414 else
415 fgets(string, sizeof(string), stdin);
416
417 return res;
418 }
419
420 /* Built-in '.' handler (read-in and execute commands from file) */
421 static int builtin_source(struct child_prog *child)
422 {
423 FILE *input;
424 int status;
425
426 input = fopen_or_warn(child->argv[1], "r");
427 if (!input) {
428 return EXIT_FAILURE;
429 }
430
431 llist_add_to(&close_me_list, (void *)(long)fileno(input));
432 /* Now run the file */
433 status = busy_loop(input);
434 fclose(input);
435 llist_pop(&close_me_list);
436 return status;
437 }
438
439 /* built-in 'unset VAR' handler */
440 static int builtin_unset(struct child_prog *child)
441 {
442 if (child->argv[1] == NULL) {
443 printf(bb_msg_requires_arg, "unset");
444 return EXIT_FAILURE;
445 }
446 unsetenv(child->argv[1]);
447 return EXIT_SUCCESS;
448 }
449
450 #ifdef CONFIG_LASH_JOB_CONTROL
451 /* free up all memory from a job */
452 static void free_job(struct job *cmd)
453 {
454 int i;
455 struct jobset *keep;
456
457 for (i = 0; i < cmd->num_progs; i++) {
458 free(cmd->progs[i].argv);
459 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
460 if (cmd->progs[i].redirects)
461 free(cmd->progs[i].redirects);
462 #endif
463 }
464 free(cmd->progs);
465 free(cmd->text);
466 free(cmd->cmdbuf);
467 keep = cmd->job_list;
468 memset(cmd, 0, sizeof(struct job));
469 cmd->job_list = keep;
470 }
471
472 /* remove a job from a jobset */
473 static void remove_job(struct jobset *j_list, struct job *job)
474 {
475 struct job *prevjob;
476
477 free_job(job);
478 if (job == j_list->head) {
479 j_list->head = job->next;
480 } else {
481 prevjob = j_list->head;
482 while (prevjob->next != job)
483 prevjob = prevjob->next;
484 prevjob->next = job->next;
485 }
486
487 if (j_list->head)
488 last_jobid = j_list->head->jobid;
489 else
490 last_jobid = 0;
491
492 free(job);
493 }
494
495 /* Checks to see if any background processes have exited -- if they
496 have, figure out why and see if a job has completed */
497 static void checkjobs(struct jobset *j_list)
498 {
499 struct job *job;
500 pid_t childpid;
501 int status;
502 int prognum = 0;
503
504 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
505 for (job = j_list->head; job; job = job->next) {
506 prognum = 0;
507 while (prognum < job->num_progs &&
508 job->progs[prognum].pid != childpid) prognum++;
509 if (prognum < job->num_progs)
510 break;
511 }
512
513 /* This happens on backticked commands */
514 if(job==NULL)
515 return;
516
517 if (WIFEXITED(status) || WIFSIGNALED(status)) {
518 /* child exited */
519 job->running_progs--;
520 job->progs[prognum].pid = 0;
521
522 if (!job->running_progs) {
523 printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text);
524 last_jobid=0;
525 remove_job(j_list, job);
526 }
527 } else {
528 /* child stopped */
529 job->stopped_progs++;
530 job->progs[prognum].is_stopped = 1;
531 }
532 }
533
534 if (childpid == -1 && errno != ECHILD)
535 bb_perror_msg("waitpid");
536 }
537 #else
538 static void checkjobs(struct jobset *j_list)
539 {
540 }
541 static void free_job(struct job *cmd)
542 {
543 }
544 static void remove_job(struct jobset *j_list, struct job *job)
545 {
546 }
547 #endif
548
549 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
550 /* squirrel != NULL means we squirrel away copies of stdin, stdout,
551 * and stderr if they are redirected. */
552 static int setup_redirects(struct child_prog *prog, int squirrel[])
553 {
554 int i;
555 int openfd;
556 int mode = O_RDONLY;
557 struct redir_struct *redir = prog->redirects;
558
559 for (i = 0; i < prog->num_redirects; i++, redir++) {
560 switch (redir->type) {
561 case REDIRECT_INPUT:
562 mode = O_RDONLY;
563 break;
564 case REDIRECT_OVERWRITE:
565 mode = O_WRONLY | O_CREAT | O_TRUNC;
566 break;
567 case REDIRECT_APPEND:
568 mode = O_WRONLY | O_CREAT | O_APPEND;
569 break;
570 }
571
572 openfd = open(redir->filename, mode, 0666);
573 if (openfd < 0) {
574 /* this could get lost if stderr has been redirected, but
575 bash and ash both lose it as well (though zsh doesn't!) */
576 bb_perror_msg("error opening %s", redir->filename);
577 return 1;
578 }
579
580 if (openfd != redir->fd) {
581 if (squirrel && redir->fd < 3) {
582 squirrel[redir->fd] = dup(redir->fd);
583 fcntl (squirrel[redir->fd], F_SETFD, FD_CLOEXEC);
584 }
585 dup2(openfd, redir->fd);
586 close(openfd);
587 }
588 }
589
590 return 0;
591 }
592
593 static void restore_redirects(int squirrel[])
594 {
595 int i, fd;
596 for (i=0; i<3; i++) {
597 fd = squirrel[i];
598 if (fd != -1) {
599 /* No error checking. I sure wouldn't know what
600 * to do with an error if I found one! */
601 dup2(fd, i);
602 close(fd);
603 }
604 }
605 }
606 #else
607 static inline int setup_redirects(struct child_prog *prog, int squirrel[])
608 {
609 return 0;
610 }
611 static inline void restore_redirects(int squirrel[])
612 {
613 }
614 #endif
615
616 static inline void cmdedit_set_initial_prompt(void)
617 {
618 #ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
619 PS1 = NULL;
620 #else
621 PS1 = getenv("PS1");
622 if(PS1==0)
623 PS1 = "\\w \\$ ";
624 #endif
625 }
626
627 static inline void setup_prompt_string(char **prompt_str)
628 {
629 #ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
630 /* Set up the prompt */
631 if (shell_context == 0) {
632 free(PS1);
633 PS1=xmalloc(strlen(cwd)+4);
634 sprintf(PS1, "%s %c ", cwd, ( geteuid() != 0 ) ? '$': '#');
635 *prompt_str = PS1;
636 } else {
637 *prompt_str = PS2;
638 }
639 #else
640 *prompt_str = (shell_context==0)? PS1 : PS2;
641 #endif
642 }
643
644 static int get_command(FILE * source, char *command)
645 {
646 char *prompt_str;
647
648 if (source == NULL) {
649 if (local_pending_command) {
650 /* a command specified (-c option): return it & mark it done */
651 strcpy(command, local_pending_command);
652 free(local_pending_command);
653 local_pending_command = NULL;
654 return 0;
655 }
656 return 1;
657 }
658
659 if (source == stdin) {
660 setup_prompt_string(&prompt_str);
661
662 #ifdef CONFIG_FEATURE_COMMAND_EDITING
663 /*
664 ** enable command line editing only while a command line
665 ** is actually being read; otherwise, we'll end up bequeathing
666 ** atexit() handlers and other unwanted stuff to our
667 ** child processes (rob@sysgo.de)
668 */
669 cmdedit_read_input(prompt_str, command);
670 return 0;
671 #else
672 fputs(prompt_str, stdout);
673 #endif
674 }
675
676 if (!fgets(command, BUFSIZ - 2, source)) {
677 if (source == stdin)
678 puts("");
679 return 1;
680 }
681
682 return 0;
683 }
684
685 static char * strsep_space( char *string, int * ix)
686 {
687 /* Short circuit the trivial case */
688 if ( !string || ! string[*ix])
689 return NULL;
690
691 /* Find the end of the token. */
692 while (string[*ix] && !isspace(string[*ix]) ) {
693 (*ix)++;
694 }
695
696 /* Find the end of any whitespace trailing behind
697 * the token and let that be part of the token */
698 while (string[*ix] && (isspace)(string[*ix]) ) {
699 (*ix)++;
700 }
701
702 if (!*ix) {
703 /* Nothing useful was found */
704 return NULL;
705 }
706
707 return xstrndup(string, *ix);
708 }
709
710 static int expand_arguments(char *command)
711 {
712 int total_length=0, length, i, retval, ix = 0;
713 expand_t expand_result;
714 char *tmpcmd, *cmd, *cmd_copy;
715 char *src, *dst, *var;
716 const char * const out_of_space = "out of space during expansion";
717 int flags = GLOB_NOCHECK
718 #ifdef GLOB_BRACE
719 | GLOB_BRACE
720 #endif
721 #ifdef GLOB_TILDE
722 | GLOB_TILDE
723 #endif
724 ;
725
726 /* get rid of the terminating \n */
727 chomp(command);
728
729 /* Fix up escape sequences to be the Real Thing(tm) */
730 while( command && command[ix]) {
731 if (command[ix] == '\\') {
732 const char *tmp = command+ix+1;
733 command[ix] = bb_process_escape_sequence( &tmp );
734 memmove(command+ix + 1, tmp, strlen(tmp)+1);
735 }
736 ix++;
737 }
738 /* Use glob and then fixup environment variables and such */
739
740 /* It turns out that glob is very stupid. We have to feed it one word at a
741 * time since it can't cope with a full string. Here we convert command
742 * (char*) into cmd (char**, one word per string) */
743
744 /* We need a clean copy, so strsep can mess up the copy while
745 * we write stuff into the original (in a minute) */
746 cmd = cmd_copy = xstrdup(command);
747 *command = '\0';
748 for (ix = 0, tmpcmd = cmd;
749 (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) {
750 if (*tmpcmd == '\0')
751 break;
752 /* we need to trim() the result for glob! */
753 trim(tmpcmd);
754 retval = glob(tmpcmd, flags, NULL, &expand_result);
755 free(tmpcmd); /* Free mem allocated by strsep_space */
756 if (retval == GLOB_NOSPACE) {
757 /* Mem may have been allocated... */
758 globfree (&expand_result);
759 bb_error_msg(out_of_space);
760 return FALSE;
761 } else if (retval != 0) {
762 /* Some other error. GLOB_NOMATCH shouldn't
763 * happen because of the GLOB_NOCHECK flag in
764 * the glob call. */
765 bb_error_msg("syntax error");
766 return FALSE;
767 } else {
768 /* Convert from char** (one word per string) to a simple char*,
769 * but don't overflow command which is BUFSIZ in length */
770 for (i=0; i < expand_result.gl_pathc; i++) {
771 length=strlen(expand_result.gl_pathv[i]);
772 if (total_length+length+1 >= BUFSIZ) {
773 bb_error_msg(out_of_space);
774 return FALSE;
775 }
776 strcat(command+total_length, " ");
777 total_length+=1;
778 strcat(command+total_length, expand_result.gl_pathv[i]);
779 total_length+=length;
780 }
781 globfree (&expand_result);
782 }
783 }
784 free(cmd_copy);
785 trim(command);
786
787 /* Now do the shell variable substitutions which
788 * wordexp can't do for us, namely $? and $! */
789 src = command;
790 while((dst = strchr(src,'$')) != NULL){
791 var = NULL;
792 switch (*(dst+1)) {
793 case '?':
794 var = itoa(last_return_code);
795 break;
796 case '!':
797 if (last_bg_pid==-1)
798 *(var)='\0';
799 else
800 var = itoa(last_bg_pid);
801 break;
802 /* Everything else like $$, $#, $[0-9], etc. should all be
803 * expanded by wordexp(), so we can in theory skip that stuff
804 * here, but just to be on the safe side (i.e., since uClibc
805 * wordexp doesn't do this stuff yet), lets leave it in for
806 * now. */
807 case '$':
808 var = itoa(getpid());
809 break;
810 case '#':
811 var = itoa(argc-1);
812 break;
813 case '0':case '1':case '2':case '3':case '4':
814 case '5':case '6':case '7':case '8':case '9':
815 {
816 int ixx=*(dst+1)-48+1;
817 if (ixx >= argc) {
818 var='\0';
819 } else {
820 var = argv[ixx];
821 }
822 }
823 break;
824
825 }
826 if (var) {
827 /* a single character construction was found, and
828 * already handled in the case statement */
829 src=dst+2;
830 } else {
831 /* Looks like an environment variable */
832 char delim_hold;
833 int num_skip_chars=0;
834 int dstlen = strlen(dst);
835 /* Is this a ${foo} type variable? */
836 if (dstlen >=2 && *(dst+1) == '{') {
837 src=strchr(dst+1, '}');
838 num_skip_chars=1;
839 } else {
840 src=dst+1;
841 while((isalnum)(*src) || *src=='_') src++;
842 }
843 if (src == NULL) {
844 src = dst+dstlen;
845 }
846 delim_hold=*src;
847 *src='\0'; /* temporary */
848 var = getenv(dst + 1 + num_skip_chars);
849 *src=delim_hold;
850 src += num_skip_chars;
851 }
852 if (var == NULL) {
853 /* Seems we got an un-expandable variable. So delete it. */
854 var = "";
855 }
856 {
857 int subst_len = strlen(var);
858 int trail_len = strlen(src);
859 if (dst+subst_len+trail_len >= command+BUFSIZ) {
860 bb_error_msg(out_of_space);
861 return FALSE;
862 }
863 /* Move stuff to the end of the string to accommodate
864 * filling the created gap with the new stuff */
865 memmove(dst+subst_len, src, trail_len+1);
866 /* Now copy in the new stuff */
867 memcpy(dst, var, subst_len);
868 src = dst+subst_len;
869 }
870 }
871
872 return TRUE;
873 }
874
875 /* Return cmd->num_progs as 0 if no command is present (e.g. an empty
876 line). If a valid command is found, command_ptr is set to point to
877 the beginning of the next command (if the original command had more
878 then one job associated with it) or NULL if no more commands are
879 present. */
880 static int parse_command(char **command_ptr, struct job *job, int *inbg)
881 {
882 char *command;
883 char *return_command = NULL;
884 char *src, *buf;
885 int argc_l;
886 int flag;
887 int argv_alloced;
888 char quote = '\0';
889 struct child_prog *prog;
890 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
891 int i;
892 char *chptr;
893 #endif
894
895 /* skip leading white space */
896 *command_ptr = skip_whitespace(*command_ptr);
897
898 /* this handles empty lines or leading '#' characters */
899 if (!**command_ptr || (**command_ptr == '#')) {
900 job->num_progs=0;
901 return 0;
902 }
903
904 *inbg = 0;
905 job->num_progs = 1;
906 job->progs = xmalloc(sizeof(*job->progs));
907
908 /* We set the argv elements to point inside of this string. The
909 memory is freed by free_job(). Allocate twice the original
910 length in case we need to quote every single character.
911
912 Getting clean memory relieves us of the task of NULL
913 terminating things and makes the rest of this look a bit
914 cleaner (though it is, admittedly, a tad less efficient) */
915 job->cmdbuf = command = xzalloc(2*strlen(*command_ptr) + 1);
916 job->text = NULL;
917
918 prog = job->progs;
919 prog->num_redirects = 0;
920 prog->is_stopped = 0;
921 prog->family = job;
922 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
923 prog->redirects = NULL;
924 #endif
925
926 argv_alloced = 5;
927 prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
928 prog->argv[0] = job->cmdbuf;
929
930 flag = argc_l = 0;
931 buf = command;
932 src = *command_ptr;
933 while (*src && !(flag & LASH_OPT_DONE)) {
934 if (quote == *src) {
935 quote = '\0';
936 } else if (quote) {
937 if (*src == '\\') {
938 src++;
939 if (!*src) {
940 bb_error_msg("character expected after \\");
941 free_job(job);
942 return 1;
943 }
944
945 /* in shell, "\'" should yield \' */
946 if (*src != quote) {
947 *buf++ = '\\';
948 *buf++ = '\\';
949 }
950 } else if (*src == '*' || *src == '?' || *src == '[' ||
951 *src == ']') *buf++ = '\\';
952 *buf++ = *src;
953 } else if (isspace(*src)) {
954 if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE) {
955 buf++, argc_l++;
956 /* +1 here leaves room for the NULL which ends argv */
957 if ((argc_l + 1) == argv_alloced) {
958 argv_alloced += 5;
959 prog->argv = xrealloc(prog->argv,
960 sizeof(*prog->argv) *
961 argv_alloced);
962 }
963 prog->argv[argc_l] = buf;
964 flag ^= LASH_OPT_SAW_QUOTE;
965 }
966 } else
967 switch (*src) {
968 case '"':
969 case '\'':
970 quote = *src;
971 flag |= LASH_OPT_SAW_QUOTE;
972 break;
973
974 case '#': /* comment */
975 if (*(src-1)== '$')
976 *buf++ = *src;
977 else
978 flag |= LASH_OPT_DONE;
979 break;
980
981 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
982 case '>': /* redirects */
983 case '<':
984 i = prog->num_redirects++;
985 prog->redirects = xrealloc(prog->redirects,
986 sizeof(*prog->redirects) *
987 (i + 1));
988
989 prog->redirects[i].fd = -1;
990 if (buf != prog->argv[argc_l]) {
991 /* the stuff before this character may be the file number
992 being redirected */
993 prog->redirects[i].fd =
994 strtol(prog->argv[argc_l], &chptr, 10);
995
996 if (*chptr && *prog->argv[argc_l]) {
997 buf++, argc_l++;
998 prog->argv[argc_l] = buf;
999 }
1000 }
1001
1002 if (prog->redirects[i].fd == -1) {
1003 if (*src == '>')
1004 prog->redirects[i].fd = 1;
1005 else
1006 prog->redirects[i].fd = 0;
1007 }
1008
1009 if (*src++ == '>') {
1010 if (*src == '>')
1011 prog->redirects[i].type =
1012 REDIRECT_APPEND, src++;
1013 else
1014 prog->redirects[i].type = REDIRECT_OVERWRITE;
1015 } else {
1016 prog->redirects[i].type = REDIRECT_INPUT;
1017 }
1018
1019 /* This isn't POSIX sh compliant. Oh well. */
1020 chptr = src;
1021 chptr = skip_whitespace(chptr);
1022
1023 if (!*chptr) {
1024 bb_error_msg("file name expected after %c", *(src-1));
1025 free_job(job);
1026 job->num_progs=0;
1027 return 1;
1028 }
1029
1030 prog->redirects[i].filename = buf;
1031 while (*chptr && !isspace(*chptr))
1032 *buf++ = *chptr++;
1033
1034 src = chptr - 1; /* we src++ later */
1035 prog->argv[argc_l] = ++buf;
1036 break;
1037
1038 case '|': /* pipe */
1039 /* finish this command */
1040 if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE)
1041 argc_l++;
1042 if (!argc_l) {
1043 goto empty_command_in_pipe;
1044 }
1045 prog->argv[argc_l] = NULL;
1046
1047 /* and start the next */
1048 job->num_progs++;
1049 job->progs = xrealloc(job->progs,
1050 sizeof(*job->progs) * job->num_progs);
1051 prog = job->progs + (job->num_progs - 1);
1052 prog->num_redirects = 0;
1053 prog->redirects = NULL;
1054 prog->is_stopped = 0;
1055 prog->family = job;
1056 argc_l = 0;
1057
1058 argv_alloced = 5;
1059 prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
1060 prog->argv[0] = ++buf;
1061
1062 src++;
1063 src = skip_whitespace(src);
1064
1065 if (!*src) {
1066 empty_command_in_pipe:
1067 bb_error_msg("empty command in pipe");
1068 free_job(job);
1069 job->num_progs=0;
1070 return 1;
1071 }
1072 src--; /* we'll ++ it at the end of the loop */
1073
1074 break;
1075 #endif
1076
1077 #ifdef CONFIG_LASH_JOB_CONTROL
1078 case '&': /* background */
1079 *inbg = 1;
1080 /* fallthrough */
1081 #endif
1082 case ';': /* multiple commands */
1083 flag |= LASH_OPT_DONE;
1084 return_command = *command_ptr + (src - *command_ptr) + 1;
1085 break;
1086
1087 case '\\':
1088 src++;
1089 if (!*src) {
1090 bb_error_msg("character expected after \\");
1091 free_job(job);
1092 return 1;
1093 }
1094 if (*src == '*' || *src == '[' || *src == ']'
1095 || *src == '?') *buf++ = '\\';
1096 /* fallthrough */
1097 default:
1098 *buf++ = *src;
1099 }
1100
1101 src++;
1102 }
1103
1104 if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE) {
1105 argc_l++;
1106 }
1107 if (!argc_l) {
1108 free_job(job);
1109 return 0;
1110 }
1111 prog->argv[argc_l] = NULL;
1112
1113 if (!return_command) {
1114 job->text = xstrdup(*command_ptr);
1115 } else {
1116 /* This leaves any trailing spaces, which is a bit sloppy */
1117 job->text = xstrndup(*command_ptr, return_command - *command_ptr);
1118 }
1119
1120 *command_ptr = return_command;
1121
1122 return 0;
1123 }
1124
1125 /* Run the child_prog, no matter what kind of command it uses.
1126 */
1127 static int pseudo_exec(struct child_prog *child)
1128 {
1129 struct built_in_command *x;
1130
1131 /* Check if the command matches any of the non-forking builtins.
1132 * Depending on context, this might be redundant. But it's
1133 * easier to waste a few CPU cycles than it is to figure out
1134 * if this is one of those cases.
1135 */
1136 for (x = bltins; x->cmd; x++) {
1137 if (strcmp(child->argv[0], x->cmd) == 0 ) {
1138 _exit(x->function(child));
1139 }
1140 }
1141
1142 /* Check if the command matches any of the forking builtins. */
1143 for (x = bltins_forking; x->cmd; x++) {
1144 if (strcmp(child->argv[0], x->cmd) == 0) {
1145 applet_name=x->cmd;
1146 _exit (x->function(child));
1147 }
1148 }
1149
1150 /* Check if the command matches any busybox internal
1151 * commands ("applets") here. Following discussions from
1152 * November 2000 on busybox@busybox.net, don't use
1153 * bb_get_last_path_component(). This way explicit (with
1154 * slashes) filenames will never be interpreted as an
1155 * applet, just like with builtins. This way the user can
1156 * override an applet with an explicit filename reference.
1157 * The only downside to this change is that an explicit
1158 * /bin/foo invocation will fork and exec /bin/foo, even if
1159 * /bin/foo is a symlink to busybox.
1160 */
1161
1162 if (ENABLE_FEATURE_SH_STANDALONE_SHELL) {
1163 char **argv_l = child->argv;
1164 int argc_l;
1165
1166 for (argc_l=0; *argv_l; argv_l++, argc_l++);
1167 optind = 1;
1168 run_applet_by_name(child->argv[0], argc_l, child->argv);
1169 }
1170
1171 execvp(child->argv[0], child->argv);
1172
1173 /* Do not use bb_perror_msg_and_die() here, since we must not
1174 * call exit() but should call _exit() instead */
1175 bb_perror_msg("%s", child->argv[0]);
1176 _exit(EXIT_FAILURE);
1177 }
1178
1179 static void insert_job(struct job *newjob, int inbg)
1180 {
1181 struct job *thejob;
1182 struct jobset *j_list=newjob->job_list;
1183
1184 /* find the ID for thejob to use */
1185 newjob->jobid = 1;
1186 for (thejob = j_list->head; thejob; thejob = thejob->next)
1187 if (thejob->jobid >= newjob->jobid)
1188 newjob->jobid = thejob->jobid + 1;
1189
1190 /* add thejob to the list of running jobs */
1191 if (!j_list->head) {
1192 thejob = j_list->head = xmalloc(sizeof(*thejob));
1193 } else {
1194 for (thejob = j_list->head; thejob->next; thejob = thejob->next) /* nothing */;
1195 thejob->next = xmalloc(sizeof(*thejob));
1196 thejob = thejob->next;
1197 }
1198
1199 *thejob = *newjob; /* physically copy the struct job */
1200 thejob->next = NULL;
1201 thejob->running_progs = thejob->num_progs;
1202 thejob->stopped_progs = 0;
1203
1204 #ifdef CONFIG_LASH_JOB_CONTROL
1205 if (inbg) {
1206 /* we don't wait for background thejobs to return -- append it
1207 to the list of backgrounded thejobs and leave it alone */
1208 printf("[%d] %d\n", thejob->jobid,
1209 newjob->progs[newjob->num_progs - 1].pid);
1210 last_jobid = newjob->jobid;
1211 last_bg_pid=newjob->progs[newjob->num_progs - 1].pid;
1212 } else {
1213 newjob->job_list->fg = thejob;
1214
1215 /* move the new process group into the foreground */
1216 /* Ignore errors since child could have already exited */
1217 tcsetpgrp(shell_terminal, newjob->pgrp);
1218 }
1219 #endif
1220 }
1221
1222 static int run_command(struct job *newjob, int inbg, int outpipe[2])
1223 {
1224 /* struct job *thejob; */
1225 int i;
1226 int nextin, nextout;
1227 int pipefds[2]; /* pipefd[0] is for reading */
1228 struct built_in_command *x;
1229 struct child_prog *child;
1230
1231 nextin = 0, nextout = 1;
1232 for (i = 0; i < newjob->num_progs; i++) {
1233 child = & (newjob->progs[i]);
1234
1235 if ((i + 1) < newjob->num_progs) {
1236 if (pipe(pipefds)<0) bb_perror_msg_and_die("pipe");
1237 nextout = pipefds[1];
1238 } else {
1239 if (outpipe[1]!=-1) {
1240 nextout = outpipe[1];
1241 } else {
1242 nextout = 1;
1243 }
1244 }
1245
1246
1247 /* Check if the command matches any non-forking builtins,
1248 * but only if this is a simple command.
1249 * Non-forking builtins within pipes have to fork anyway,
1250 * and are handled in pseudo_exec. "echo foo | read bar"
1251 * is doomed to failure, and doesn't work on bash, either.
1252 */
1253 if (newjob->num_progs == 1) {
1254 /* Check if the command sets an environment variable. */
1255 if (strchr(child->argv[0], '=') != NULL) {
1256 child->argv[1] = child->argv[0];
1257 return builtin_export(child);
1258 }
1259
1260 for (x = bltins; x->cmd; x++) {
1261 if (strcmp(child->argv[0], x->cmd) == 0 ) {
1262 int rcode;
1263 int squirrel[] = {-1, -1, -1};
1264 setup_redirects(child, squirrel);
1265 rcode = x->function(child);
1266 restore_redirects(squirrel);
1267 return rcode;
1268 }
1269 }
1270 }
1271
1272 #if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__)
1273 if (!(child->pid = fork()))
1274 #else
1275 if (!(child->pid = vfork()))
1276 #endif
1277 {
1278 /* Set the handling for job control signals back to the default. */
1279 signal(SIGINT, SIG_DFL);
1280 signal(SIGQUIT, SIG_DFL);
1281 signal(SIGTSTP, SIG_DFL);
1282 signal(SIGTTIN, SIG_DFL);
1283 signal(SIGTTOU, SIG_DFL);
1284 signal(SIGCHLD, SIG_DFL);
1285
1286 /* Close all open filehandles. */
1287 while(close_me_list) close((long)llist_pop(&close_me_list));
1288
1289 if (outpipe[1]!=-1) {
1290 close(outpipe[0]);
1291 }
1292 if (nextin != 0) {
1293 dup2(nextin, 0);
1294 close(nextin);
1295 }
1296
1297 if (nextout != 1) {
1298 dup2(nextout, 1);
1299 dup2(nextout, 2); /* Really? */
1300 close(nextout);
1301 close(pipefds[0]);
1302 }
1303
1304 /* explicit redirects override pipes */
1305 setup_redirects(child,NULL);
1306
1307 pseudo_exec(child);
1308 }
1309 if (outpipe[1]!=-1) {
1310 close(outpipe[1]);
1311 }
1312
1313 /* put our child in the process group whose leader is the
1314 first process in this pipe */
1315 setpgid(child->pid, newjob->progs[0].pid);
1316 if (nextin != 0)
1317 close(nextin);
1318 if (nextout != 1)
1319 close(nextout);
1320
1321 /* If there isn't another process, nextin is garbage
1322 but it doesn't matter */
1323 nextin = pipefds[0];
1324 }
1325
1326 newjob->pgrp = newjob->progs[0].pid;
1327
1328 insert_job(newjob, inbg);
1329
1330 return 0;
1331 }
1332
1333 static int busy_loop(FILE * input)
1334 {
1335 char *command;
1336 char *next_command = NULL;
1337 struct job newjob;
1338 int i;
1339 int inbg = 0;
1340 int status;
1341 #ifdef CONFIG_LASH_JOB_CONTROL
1342 pid_t parent_pgrp;
1343 /* save current owner of TTY so we can restore it on exit */
1344 parent_pgrp = tcgetpgrp(shell_terminal);
1345 #endif
1346 newjob.job_list = &job_list;
1347 newjob.job_context = DEFAULT_CONTEXT;
1348
1349 command = xzalloc(BUFSIZ);
1350
1351 while (1) {
1352 if (!job_list.fg) {
1353 /* no job is in the foreground */
1354
1355 /* see if any background processes have exited */
1356 checkjobs(&job_list);
1357
1358 if (!next_command) {
1359 if (get_command(input, command))
1360 break;
1361 next_command = command;
1362 }
1363
1364 if (! expand_arguments(next_command)) {
1365 free(command);
1366 command = xzalloc(BUFSIZ);
1367 next_command = NULL;
1368 continue;
1369 }
1370
1371 if (!parse_command(&next_command, &newjob, &inbg) &&
1372 newjob.num_progs) {
1373 int pipefds[2] = {-1,-1};
1374 debug_printf( "job=%p fed to run_command by busy_loop()'\n",
1375 &newjob);
1376 run_command(&newjob, inbg, pipefds);
1377 }
1378 else {
1379 free(command);
1380 command = xzalloc(BUFSIZ);
1381 next_command = NULL;
1382 }
1383 } else {
1384 /* a job is running in the foreground; wait for it */
1385 i = 0;
1386 while (!job_list.fg->progs[i].pid ||
1387 job_list.fg->progs[i].is_stopped == 1) i++;
1388
1389 if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED)<0) {
1390 if (errno != ECHILD) {
1391 bb_perror_msg_and_die("waitpid(%d)",job_list.fg->progs[i].pid);
1392 }
1393 }
1394
1395 if (WIFEXITED(status) || WIFSIGNALED(status)) {
1396 /* the child exited */
1397 job_list.fg->running_progs--;
1398 job_list.fg->progs[i].pid = 0;
1399
1400 last_return_code=WEXITSTATUS(status);
1401
1402 if (!job_list.fg->running_progs) {
1403 /* child exited */
1404 remove_job(&job_list, job_list.fg);
1405 job_list.fg = NULL;
1406 }
1407 }
1408 #ifdef CONFIG_LASH_JOB_CONTROL
1409 else {
1410 /* the child was stopped */
1411 job_list.fg->stopped_progs++;
1412 job_list.fg->progs[i].is_stopped = 1;
1413
1414 if (job_list.fg->stopped_progs == job_list.fg->running_progs) {
1415 printf("\n" JOB_STATUS_FORMAT, job_list.fg->jobid,
1416 "Stopped", job_list.fg->text);
1417 job_list.fg = NULL;
1418 }
1419 }
1420
1421 if (!job_list.fg) {
1422 /* move the shell to the foreground */
1423 /* suppress messages when run from /linuxrc mag@sysgo.de */
1424 if (tcsetpgrp(shell_terminal, getpgrp()) && errno != ENOTTY)
1425 bb_perror_msg("tcsetpgrp");
1426 }
1427 #endif
1428 }
1429 }
1430 free(command);
1431
1432 #ifdef CONFIG_LASH_JOB_CONTROL
1433 /* return controlling TTY back to parent process group before exiting */
1434 if (tcsetpgrp(shell_terminal, parent_pgrp) && errno != ENOTTY)
1435 bb_perror_msg("tcsetpgrp");
1436 #endif
1437
1438 /* return exit status if called with "-c" */
1439 if (input == NULL && WIFEXITED(status))
1440 return WEXITSTATUS(status);
1441
1442 return 0;
1443 }
1444
1445 #ifdef CONFIG_FEATURE_CLEAN_UP
1446 static void free_memory(void)
1447 {
1448 if (cwd && cwd!=bb_msg_unknown) {
1449 free((char*)cwd);
1450 }
1451 if (local_pending_command)
1452 free(local_pending_command);
1453
1454 if (job_list.fg && !job_list.fg->running_progs) {
1455 remove_job(&job_list, job_list.fg);
1456 }
1457 }
1458 #else
1459 void free_memory(void);
1460 #endif
1461
1462 #ifdef CONFIG_LASH_JOB_CONTROL
1463 /* Make sure we have a controlling tty. If we get started under a job
1464 * aware app (like bash for example), make sure we are now in charge so
1465 * we don't fight over who gets the foreground */
1466 static void setup_job_control(void)
1467 {
1468 int status;
1469 pid_t shell_pgrp;
1470
1471 /* Loop until we are in the foreground. */
1472 while ((status = tcgetpgrp (shell_terminal)) >= 0) {
1473 if (status == (shell_pgrp = getpgrp ())) {
1474 break;
1475 }
1476 kill (- shell_pgrp, SIGTTIN);
1477 }
1478
1479 /* Ignore interactive and job-control signals. */
1480 signal(SIGINT, SIG_IGN);
1481 signal(SIGQUIT, SIG_IGN);
1482 signal(SIGTSTP, SIG_IGN);
1483 signal(SIGTTIN, SIG_IGN);
1484 signal(SIGTTOU, SIG_IGN);
1485 signal(SIGCHLD, SIG_IGN);
1486
1487 /* Put ourselves in our own process group. */
1488 setsid();
1489 shell_pgrp = getpid();
1490 setpgid(shell_pgrp, shell_pgrp);
1491
1492 /* Grab control of the terminal. */
1493 tcsetpgrp(shell_terminal, shell_pgrp);
1494 }
1495 #else
1496 static inline void setup_job_control(void)
1497 {
1498 }
1499 #endif
1500
1501 int lash_main(int argc_l, char **argv_l)
1502 {
1503 unsigned opt;
1504 FILE *input = stdin;
1505 argc = argc_l;
1506 argv = argv_l;
1507
1508 /* These variables need re-initializing when recursing */
1509 last_jobid = 0;
1510 close_me_list = NULL;
1511 job_list.head = NULL;
1512 job_list.fg = NULL;
1513 last_return_code=1;
1514
1515 if (argv[0] && argv[0][0] == '-') {
1516 FILE *prof_input;
1517 prof_input = fopen("/etc/profile", "r");
1518 if (prof_input) {
1519 llist_add_to(&close_me_list, (void *)(long)fileno(prof_input));
1520 /* Now run the file */
1521 busy_loop(prof_input);
1522 fclose_if_not_stdin(prof_input);
1523 llist_pop(&close_me_list);
1524 }
1525 }
1526
1527 opt = getopt32(argc_l, argv_l, "+ic:", &local_pending_command);
1528 #define LASH_OPT_i (1<<0)
1529 #define LASH_OPT_c (1<<2)
1530 if (opt & LASH_OPT_c) {
1531 input = NULL;
1532 optind++;
1533 argv += optind;
1534 }
1535 /* A shell is interactive if the `-i' flag was given, or if all of
1536 * the following conditions are met:
1537 * no -c command
1538 * no arguments remaining or the -s flag given
1539 * standard input is a terminal
1540 * standard output is a terminal
1541 * Refer to Posix.2, the description of the `sh' utility. */
1542 if (argv[optind]==NULL && input==stdin &&
1543 isatty(STDIN_FILENO) && isatty(STDOUT_FILENO))
1544 {
1545 opt |= LASH_OPT_i;
1546 }
1547 setup_job_control();
1548 if (opt & LASH_OPT_i) {
1549 /* Looks like they want an interactive shell */
1550 if (!ENABLE_FEATURE_SH_EXTRA_QUIET) {
1551 printf("\n\n%s Built-in shell (lash)\n"
1552 "Enter 'help' for a list of built-in commands.\n\n",
1553 BB_BANNER);
1554 }
1555 } else if (!local_pending_command && argv[optind]) {
1556 //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]);
1557 input = xfopen(argv[optind], "r");
1558 /* be lazy, never mark this closed */
1559 llist_add_to(&close_me_list, (void *)(long)fileno(input));
1560 }
1561
1562 /* initialize the cwd -- this is never freed...*/
1563 cwd = xgetcwd(0);
1564 if (!cwd)
1565 cwd = bb_msg_unknown;
1566
1567 if (ENABLE_FEATURE_CLEAN_UP) atexit(free_memory);
1568
1569 if (ENABLE_FEATURE_COMMAND_EDITING) cmdedit_set_initial_prompt();
1570 else PS1 = NULL;
1571
1572 return (busy_loop(input));
1573 }