source: MondoRescue/branches/stable/mindi-busybox/shell/lash.c @ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 14 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

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