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