Changeset 1765 in MondoRescue for branches/2.2.5/mindi-busybox/shell/lash.c


Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (16 years ago)
Author:
Bruno Cornec
Message:

Update to busybox 1.7.2

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.5/mindi-busybox/shell/lash.c

    r821 r1765  
    2121//#define DEBUG_SHELL
    2222
    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>
    3523#include <getopt.h>
    36 #include <termios.h>
    37 #include "cmdedit.h"
    38 
    39 #ifdef CONFIG_LOCALE_SUPPORT
    40 #include <locale.h>
    41 #endif
    42 
    4324#include <glob.h>
     25
     26#include "busybox.h" /* for struct bb_applet */
     27
    4428#define expand_t    glob_t
    4529
     
    4731#define CONFIG_LASH_PIPE_N_REDIRECTS
    4832#define CONFIG_LASH_JOB_CONTROL
    49 
    50 static const int MAX_READ = 128;    /* size of input buffer for `read' builtin */
     33#define ENABLE_LASH_PIPE_N_REDIRECTS 1
     34#define ENABLE_LASH_JOB_CONTROL      1
     35
     36
     37enum { MAX_READ = 128 }; /* size of input buffer for 'read' builtin */
    5138#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
    5239
    5340
    54 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     41#if ENABLE_LASH_PIPE_N_REDIRECTS
    5542enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE,
    5643    REDIRECT_APPEND
     
    6653};
    6754
    68 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     55#define LASH_OPT_DONE (1)
     56#define LASH_OPT_SAW_QUOTE (2)
     57
     58#if ENABLE_LASH_PIPE_N_REDIRECTS
    6959struct redir_struct {
    7060    enum redir_type type;   /* type of redirection */
     
    8070    int is_stopped;             /* is the program currently running? */
    8171    struct job *family;         /* pointer back to the child's parent job */
    82 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     72#if ENABLE_LASH_PIPE_N_REDIRECTS
    8373    struct redir_struct *redirects; /* I/O redirects */
    8474#endif
     
    10595
    10696struct built_in_command {
    107     char *cmd;                  /* name */
    108     char *descr;                /* description */
     97    const char *cmd;   /* name */
     98    const char *descr; /* description */
    10999    int (*function) (struct child_prog *);  /* function ptr */
    110100};
     
    127117static void checkjobs(struct jobset *job_list);
    128118static void remove_job(struct jobset *j_list, struct job *job);
    129 static int get_command(FILE * source, char *command);
     119static int get_command_bufsiz(FILE * source, char *command);
    130120static int parse_command(char **command_ptr, struct job *job, int *inbg);
    131121static int run_command(struct job *newjob, int inbg, int outpipe[2]);
     
    137127 * can change global variables in the parent shell process but they will not
    138128 * work with pipes and redirects; 'unset foo | whatever' will not work) */
    139 static 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},
     129static const struct built_in_command bltins[] = {
     130    {"bg"    , "Resume a job in the background", builtin_fg_bg},
     131    {"cd"    , "Change working directory", builtin_cd},
     132    {"exec"  , "Exec command, replacing this shell with the exec'd process", builtin_exec},
     133    {"exit"  , "Exit from shell()", builtin_exit},
     134    {"fg"    , "Bring job into the foreground", builtin_fg_bg},
     135    {"jobs"  , "Lists the active jobs", builtin_jobs},
    146136    {"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},
     137    {"unset" , "Unset environment variable", builtin_unset},
     138    {"read"  , "Input environment variable", builtin_read},
     139    {"."     , "Source-in and run commands in a file", builtin_source},
     140    /* These were "forked applets", but distinction was nuked */
     141    /* Original comment retained: */
     142    /* Table of forking built-in functions (things that fork cannot change global
     143     * variables in the parent process, such as the current working directory) */
     144    {"pwd"   , "Print current directory", builtin_pwd},
     145    {"help"  , "List shell built-in commands", builtin_help},
    150146    /* to do: add ulimit */
    151     {NULL, NULL, NULL}
    152147};
    153148
    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) */
    156 static 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 };
     149
     150#define VEC_LAST(v) v[ARRAY_SIZE(v)-1]
    161151
    162152
     
    165155
    166156/* Globals that are static to this file */
    167 static const char *cwd;
    168 static char *local_pending_command = NULL;
     157static char *cwd;
     158static char *local_pending_command;
    169159static struct jobset job_list = { NULL, NULL };
    170160static int argc;
     
    175165static unsigned int last_jobid;
    176166static int shell_terminal;
    177 static char *PS1;
    178 static char *PS2 = "> ";
     167static const char *PS1;
     168static const char *PS2 = "> ";
    179169
    180170
     
    188178}
    189179#else
    190 static inline void debug_printf(const char *format, ...) { }
     180static inline void debug_printf(const char ATTRIBUTE_UNUSED *format, ...) { }
    191181#endif
    192182
     
    219209 */
    220210
     211
     212static void update_cwd(void)
     213{
     214    cwd = xrealloc_getcwd_or_warn(cwd);
     215    if (!cwd)
     216        cwd = xstrdup(bb_msg_unknown);
     217}
     218
    221219/* built-in 'cd <path>' handler */
    222220static int builtin_cd(struct child_prog *child)
     
    232230        return EXIT_FAILURE;
    233231    }
    234     cwd = xgetcwd((char *)cwd);
    235     if (!cwd)
    236         cwd = bb_msg_unknown;
     232    update_cwd();
    237233    return EXIT_SUCCESS;
    238234}
     
    244240        return EXIT_SUCCESS;   /* Really? */
    245241    child->argv++;
    246     while(close_me_list) close((long)llist_pop(&close_me_list));
     242    while (close_me_list)
     243        close((long)llist_pop(&close_me_list));
    247244    pseudo_exec(child);
    248245    /* never returns */
     
    255252        exit(EXIT_SUCCESS);
    256253
    257     exit (atoi(child->argv[1]));
     254    exit(atoi(child->argv[1]));
    258255}
    259256
     
    262259{
    263260    int i, jobnum;
    264     struct job *job=NULL;
     261    struct job *job;
    265262
    266263    /* If they gave us no args, assume they want the last backgrounded task */
     
    268265        for (job = child->family->job_list->head; job; job = job->next) {
    269266            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 
     267                goto found;
     268            }
     269        }
     270        bb_error_msg("%s: no current job", child->argv[0]);
     271        return EXIT_FAILURE;
     272    }
     273    if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
     274        bb_error_msg(bb_msg_invalid_arg, child->argv[1], child->argv[0]);
     275        return EXIT_FAILURE;
     276    }
     277    for (job = child->family->job_list->head; job; job = job->next) {
     278        if (job->jobid == jobnum) {
     279            goto found;
     280        }
     281    }
     282    bb_error_msg("%s: %d: no such job", child->argv[0], jobnum);
     283    return EXIT_FAILURE;
     284 found:
    293285    if (*child->argv[0] == 'f') {
    294286        /* Put the job into the foreground.  */
     
    304296    job->stopped_progs = 0;
    305297
    306     if ( (i=kill(- job->pgrp, SIGCONT)) < 0) {
    307         if (i == ESRCH) {
     298    i = kill(- job->pgrp, SIGCONT);
     299    if (i < 0) {
     300        if (errno == ESRCH) {
    308301            remove_job(&job_list, job);
    309302        } else {
     
    316309
    317310/* built-in 'help' handler */
    318 static 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)
     311static int builtin_help(struct child_prog ATTRIBUTE_UNUSED *dummy)
     312{
     313    const struct built_in_command *x;
     314
     315    printf("\nBuilt-in commands:\n"
     316           "-------------------\n");
     317    for (x = bltins; x <= &VEC_LAST(bltins); x++) {
     318        if (x->descr == NULL)
    326319            continue;
    327320        printf("%s\t%s\n", x->cmd, x->descr);
    328321    }
    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");
     322    putchar('\n');
    335323    return EXIT_SUCCESS;
    336324}
     
    340328{
    341329    struct job *job;
    342     char *status_string;
     330    const char *status_string;
    343331
    344332    for (job = child->family->job_list->head; job; job = job->next) {
     
    355343
    356344/* built-in 'pwd' handler */
    357 static int builtin_pwd(struct child_prog *dummy)
    358 {
    359     cwd = xgetcwd((char *)cwd);
    360     if (!cwd)
    361         cwd = bb_msg_unknown;
     345static int builtin_pwd(struct child_prog ATTRIBUTE_UNUSED *dummy)
     346{
     347    update_cwd();
    362348    puts(cwd);
    363349    return EXIT_SUCCESS;
     
    380366    if (res)
    381367        bb_perror_msg("export");
    382 #ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
    383     if (strncmp(v, "PS1=", 4)==0)
     368#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
     369    if (strncmp(v, "PS1=", 4) == 0)
    384370        PS1 = getenv("PS1");
    385371#endif
    386372
    387 #ifdef CONFIG_LOCALE_SUPPORT
    388     if(strncmp(v, "LC_ALL=", 7)==0)
     373#if ENABLE_LOCALE_SUPPORT
     374    // TODO: why getenv? "" would be just as good...
     375    if (strncmp(v, "LC_ALL=", 7) == 0)
    389376        setlocale(LC_ALL, getenv("LC_ALL"));
    390     if(strncmp(v, "LC_CTYPE=", 9)==0)
     377    if (strncmp(v, "LC_CTYPE=", 9) == 0)
    391378        setlocale(LC_CTYPE, getenv("LC_CTYPE"));
    392379#endif
    393380
    394     return (res);
     381    return res;
    395382}
    396383
     
    398385static int builtin_read(struct child_prog *child)
    399386{
    400     int res = 0, len, newlen;
     387    int res = 0, len;
    401388    char *s;
    402389    char string[MAX_READ];
     
    409396        string[len]   = '\0';
    410397        fgets(&string[len], sizeof(string) - len, stdin);   /* read string */
    411         newlen = strlen(string);
    412         if(newlen > len)
    413             string[--newlen] = '\0';    /* chomp trailing newline */
     398        res = strlen(string);
     399        if (res > len)
     400            string[--res] = '\0';   /* chomp trailing newline */
    414401        /*
    415402        ** string should now contain "VAR=<value>"
     
    418405        */
    419406        res = -1;
    420         if((s = strdup(string)))
     407        s = strdup(string);
     408        if (s)
    421409            res = putenv(s);
    422410        if (res)
    423411            bb_perror_msg("read");
    424     }
    425     else
     412    } else
    426413        fgets(string, sizeof(string), stdin);
    427414
    428     return (res);
     415    return res;
    429416}
    430417
     
    435422    int status;
    436423
    437     if (child->argv[1] == NULL)
    438         return EXIT_FAILURE;
    439 
    440     input = fopen(child->argv[1], "r");
     424    input = fopen_or_warn(child->argv[1], "r");
    441425    if (!input) {
    442         printf( "Couldn't open file '%s'\n", child->argv[1]);
    443426        return EXIT_FAILURE;
    444427    }
     
    449432    fclose(input);
    450433    llist_pop(&close_me_list);
    451     return (status);
     434    return status;
    452435}
    453436
     
    463446}
    464447
    465 #ifdef CONFIG_LASH_JOB_CONTROL
     448#if ENABLE_LASH_JOB_CONTROL
    466449/* free up all memory from a job */
    467450static void free_job(struct job *cmd)
     
    472455    for (i = 0; i < cmd->num_progs; i++) {
    473456        free(cmd->progs[i].argv);
    474 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     457#if ENABLE_LASH_PIPE_N_REDIRECTS
    475458        if (cmd->progs[i].redirects)
    476459            free(cmd->progs[i].redirects);
     
    527510
    528511        /* This happens on backticked commands */
    529         if(job==NULL)
     512        if (job == NULL)
    530513            return;
    531514
     
    537520            if (!job->running_progs) {
    538521                printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text);
    539                 last_jobid=0;
     522                last_jobid = 0;
    540523                remove_job(j_list, job);
    541524            }
     
    544527            job->stopped_progs++;
    545528            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
    556529        }
    557530    }
     
    572545#endif
    573546
    574 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     547#if ENABLE_LASH_PIPE_N_REDIRECTS
    575548/* squirrel != NULL means we squirrel away copies of stdin, stdout,
    576549 * and stderr if they are redirected. */
     
    595568        }
    596569
    597         openfd = open(redir->filename, mode, 0666);
     570        openfd = open3_or_warn(redir->filename, mode, 0666);
    598571        if (openfd < 0) {
    599572            /* this could get lost if stderr has been redirected, but
    600573               bash and ash both lose it as well (though zsh doesn't!) */
    601             bb_perror_msg("error opening %s", redir->filename);
    602574            return 1;
    603575        }
     
    606578            if (squirrel && redir->fd < 3) {
    607579                squirrel[redir->fd] = dup(redir->fd);
    608                 fcntl (squirrel[redir->fd], F_SETFD, FD_CLOEXEC);
     580                fcntl(squirrel[redir->fd], F_SETFD, FD_CLOEXEC);
    609581            }
    610582            dup2(openfd, redir->fd);
     
    619591{
    620592    int i, fd;
    621     for (i=0; i<3; i++) {
     593    for (i = 0; i < 3; i++) {
    622594        fd = squirrel[i];
    623595        if (fd != -1) {
     
    641613static inline void cmdedit_set_initial_prompt(void)
    642614{
    643 #ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
     615#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
    644616    PS1 = NULL;
    645617#else
    646618    PS1 = getenv("PS1");
    647     if(PS1==0)
     619    if (PS1 == 0)
    648620        PS1 = "\\w \\$ ";
    649621#endif
    650622}
    651623
    652 static inline void setup_prompt_string(char **prompt_str)
    653 {
    654 #ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
     624static inline const char* setup_prompt_string(void)
     625{
     626#if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
    655627    /* Set up the prompt */
    656628    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;
     629        char *ns;
     630        free((char*)PS1);
     631        ns = xmalloc(strlen(cwd)+4);
     632        sprintf(ns, "%s %c ", cwd, (geteuid() != 0) ? '$': '#');
     633        PS1 = ns;
     634        return ns;
    661635    } else {
    662         *prompt_str = PS2;
     636        return PS2;
    663637    }
    664638#else
    665     *prompt_str = (shell_context==0)? PS1 : PS2;
    666 #endif
    667 }
    668 
    669 static int get_command(FILE * source, char *command)
    670 {
    671     char *prompt_str;
     639    return (shell_context == 0)? PS1 : PS2;
     640#endif
     641}
     642
     643#if ENABLE_FEATURE_EDITING
     644static line_input_t *line_input_state;
     645#endif
     646
     647static int get_command_bufsiz(FILE * source, char *command)
     648{
     649    const char *prompt_str;
    672650
    673651    if (source == NULL) {
    674652        if (local_pending_command) {
    675653            /* a command specified (-c option): return it & mark it done */
    676             strcpy(command, local_pending_command);
    677             free(local_pending_command);
     654            strncpy(command, local_pending_command, BUFSIZ);
    678655            local_pending_command = NULL;
    679656            return 0;
     
    683660
    684661    if (source == stdin) {
    685         setup_prompt_string(&prompt_str);
    686 
    687 #ifdef CONFIG_FEATURE_COMMAND_EDITING
     662        prompt_str = setup_prompt_string();
     663
     664#if ENABLE_FEATURE_EDITING
    688665        /*
    689666        ** enable command line editing only while a command line
     
    692669        ** child processes (rob@sysgo.de)
    693670        */
    694         cmdedit_read_input(prompt_str, command);
     671        read_line_input(prompt_str, command, BUFSIZ, line_input_state);
    695672        return 0;
    696673#else
     
    701678    if (!fgets(command, BUFSIZ - 2, source)) {
    702679        if (source == stdin)
    703             printf("\n");
     680            puts("");
    704681        return 1;
    705682    }
     
    708685}
    709686
    710 static 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 
    730 static char * strsep_space( char *string, int * ix)
    731 {
    732     char *token;
    733 
     687static char * strsep_space(char *string, int * ix)
     688{
    734689    /* Short circuit the trivial case */
    735     if ( !string || ! string[*ix])
     690    if (!string || ! string[*ix])
    736691        return NULL;
    737692
    738693    /* Find the end of the token. */
    739     while( string[*ix] && !isspace(string[*ix]) ) {
     694    while (string[*ix] && !isspace(string[*ix]) ) {
    740695        (*ix)++;
    741696    }
     
    743698    /* Find the end of any whitespace trailing behind
    744699     * the token and let that be part of the token */
    745     while( string[*ix] && isspace(string[*ix]) ) {
     700    while (string[*ix] && (isspace)(string[*ix]) ) {
    746701        (*ix)++;
    747702    }
     
    752707    }
    753708
    754     token = bb_xstrndup(string, *ix);
    755 
    756     return token;
     709    return xstrndup(string, *ix);
    757710}
    758711
    759712static int expand_arguments(char *command)
    760713{
    761     int total_length=0, length, i, retval, ix = 0;
     714    static const char out_of_space[] ALIGN1 = "out of space during expansion";
     715
     716    int total_length = 0, length, i, retval, ix = 0;
    762717    expand_t expand_result;
    763718    char *tmpcmd, *cmd, *cmd_copy;
    764719    char *src, *dst, *var;
    765     const char *out_of_space = "out of space during expansion";
    766720    int flags = GLOB_NOCHECK
    767721#ifdef GLOB_BRACE
     
    777731
    778732    /* Fix up escape sequences to be the Real Thing(tm) */
    779     while( command && command[ix]) {
     733    while (command && command[ix]) {
    780734        if (command[ix] == '\\') {
    781735            const char *tmp = command+ix+1;
     
    793747    /* We need a clean copy, so strsep can mess up the copy while
    794748     * we write stuff into the original (in a minute) */
    795     cmd = cmd_copy = bb_xstrdup(command);
     749    cmd = cmd_copy = xstrdup(command);
    796750    *command = '\0';
    797751    for (ix = 0, tmpcmd = cmd;
    798             (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) {
     752            (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix = 0) {
    799753        if (*tmpcmd == '\0')
    800754            break;
     
    805759        if (retval == GLOB_NOSPACE) {
    806760            /* Mem may have been allocated... */
    807             globfree (&expand_result);
     761            globfree(&expand_result);
    808762            bb_error_msg(out_of_space);
    809763            return FALSE;
     
    817771            /* Convert from char** (one word per string) to a simple char*,
    818772             * 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]);
     773            for (i = 0; i < expand_result.gl_pathc; i++) {
     774                length = strlen(expand_result.gl_pathv[i]);
    821775                if (total_length+length+1 >= BUFSIZ) {
    822776                    bb_error_msg(out_of_space);
     
    824778                }
    825779                strcat(command+total_length, " ");
    826                 total_length+=1;
     780                total_length += 1;
    827781                strcat(command+total_length, expand_result.gl_pathv[i]);
    828                 total_length+=length;
    829             }
    830             globfree (&expand_result);
     782                total_length += length;
     783            }
     784            globfree(&expand_result);
    831785        }
    832786    }
     
    837791     * wordexp can't do for us, namely $? and $! */
    838792    src = command;
    839     while((dst = strchr(src,'$')) != NULL){
     793    while ((dst = strchr(src,'$')) != NULL) {
    840794        var = NULL;
    841         switch(*(dst+1)) {
     795        switch (*(dst+1)) {
    842796            case '?':
    843797                var = itoa(last_return_code);
    844798                break;
    845799            case '!':
    846                 if (last_bg_pid==-1)
    847                     *(var)='\0';
     800                if (last_bg_pid == -1)
     801                    *var = '\0';
    848802                else
    849803                    var = itoa(last_bg_pid);
     
    863817            case '5':case '6':case '7':case '8':case '9':
    864818                {
    865                     int ixx=*(dst+1)-48+1;
     819                    int ixx = *(dst+1)-48+1;
    866820                    if (ixx >= argc) {
    867                         var='\0';
     821                        var = '\0';
    868822                    } else {
    869823                        var = argv[ixx];
     
    876830            /* a single character construction was found, and
    877831             * already handled in the case statement */
    878             src=dst+2;
     832            src = dst + 2;
    879833        } else {
    880834            /* Looks like an environment variable */
    881835            char delim_hold;
    882             int num_skip_chars=0;
     836            int num_skip_chars = 0;
    883837            int dstlen = strlen(dst);
    884838            /* Is this a ${foo} type variable? */
    885             if (dstlen >=2 && *(dst+1) == '{') {
    886                 src=strchr(dst+1, '}');
    887                 num_skip_chars=1;
     839            if (dstlen >= 2 && *(dst+1) == '{') {
     840                src = strchr(dst+1, '}');
     841                num_skip_chars = 1;
    888842            } else {
    889                 src=dst+1;
    890                 while(isalnum(*src) || *src=='_') src++;
     843                src = dst + 1;
     844                while ((isalnum)(*src) || *src == '_') src++;
    891845            }
    892846            if (src == NULL) {
    893847                src = dst+dstlen;
    894848            }
    895             delim_hold=*src;
    896             *src='\0';  /* temporary */
     849            delim_hold = *src;
     850            *src = '\0';  /* temporary */
    897851            var = getenv(dst + 1 + num_skip_chars);
    898             *src=delim_hold;
     852            *src = delim_hold;
    899853            src += num_skip_chars;
    900854        }
    901855        if (var == NULL) {
    902856            /* Seems we got an un-expandable variable.  So delete it. */
    903             var = "";
     857            var = (char*)"";
    904858        }
    905859        {
     
    932886    char *return_command = NULL;
    933887    char *src, *buf;
    934     int argc_l = 0;
    935     int done = 0;
     888    int argc_l;
     889    int flag;
    936890    int argv_alloced;
    937     int saw_quote = 0;
    938891    char quote = '\0';
    939892    struct child_prog *prog;
    940 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     893#if ENABLE_LASH_PIPE_N_REDIRECTS
    941894    int i;
    942895    char *chptr;
     
    944897
    945898    /* skip leading white space */
    946     while (**command_ptr && isspace(**command_ptr))
    947         (*command_ptr)++;
     899    *command_ptr = skip_whitespace(*command_ptr);
    948900
    949901    /* this handles empty lines or leading '#' characters */
    950902    if (!**command_ptr || (**command_ptr == '#')) {
    951         job->num_progs=0;
     903        job->num_progs = 0;
    952904        return 0;
    953905    }
     
    971923    prog->is_stopped = 0;
    972924    prog->family = job;
    973 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     925#if ENABLE_LASH_PIPE_N_REDIRECTS
    974926    prog->redirects = NULL;
    975927#endif
     
    979931    prog->argv[0] = job->cmdbuf;
    980932
     933    flag = argc_l = 0;
    981934    buf = command;
    982935    src = *command_ptr;
    983     while (*src && !done) {
     936    while (*src && !(flag & LASH_OPT_DONE)) {
    984937        if (quote == *src) {
    985938            quote = '\0';
     
    1002955            *buf++ = *src;
    1003956        } else if (isspace(*src)) {
    1004             if (*prog->argv[argc_l] || saw_quote) {
     957            if (*prog->argv[argc_l] || (flag & LASH_OPT_SAW_QUOTE)) {
    1005958                buf++, argc_l++;
    1006959                /* +1 here leaves room for the NULL which ends argv */
     
    1008961                    argv_alloced += 5;
    1009962                    prog->argv = xrealloc(prog->argv,
    1010                                           sizeof(*prog->argv) *
    1011                                           argv_alloced);
     963                            sizeof(*prog->argv) * argv_alloced);
    1012964                }
    1013965                prog->argv[argc_l] = buf;
    1014                 saw_quote = 0;
     966                flag ^= LASH_OPT_SAW_QUOTE;
    1015967            }
    1016968        } else
     
    1019971            case '\'':
    1020972                quote = *src;
    1021                 saw_quote = 1;
     973                flag |= LASH_OPT_SAW_QUOTE;
    1022974                break;
    1023975
     
    1026978                    *buf++ = *src;
    1027979                else
    1028                     done = 1;
     980                    flag |= LASH_OPT_DONE;
    1029981                break;
    1030982
    1031 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
     983#if ENABLE_LASH_PIPE_N_REDIRECTS
    1032984            case '>':           /* redirects */
    1033985            case '<':
    1034986                i = prog->num_redirects++;
    1035987                prog->redirects = xrealloc(prog->redirects,
    1036                                               sizeof(*prog->redirects) *
    1037                                               (i + 1));
     988                        sizeof(*prog->redirects) * (i + 1));
    1038989
    1039990                prog->redirects[i].fd = -1;
     
    10691020                /* This isn't POSIX sh compliant. Oh well. */
    10701021                chptr = src;
    1071                 while (isspace(*chptr))
    1072                     chptr++;
     1022                chptr = skip_whitespace(chptr);
    10731023
    10741024                if (!*chptr) {
    10751025                    bb_error_msg("file name expected after %c", *(src-1));
    10761026                    free_job(job);
    1077                     job->num_progs=0;
     1027                    job->num_progs = 0;
    10781028                    return 1;
    10791029                }
     
    10891039            case '|':           /* pipe */
    10901040                /* finish this command */
    1091                 if (*prog->argv[argc_l] || saw_quote)
     1041                if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE)
    10921042                    argc_l++;
    10931043                if (!argc_l) {
    1094                     bb_error_msg("empty command in pipe");
    1095                     free_job(job);
    1096                     job->num_progs=0;
    1097                     return 1;
     1044                    goto empty_command_in_pipe;
    10981045                }
    10991046                prog->argv[argc_l] = NULL;
     
    11021049                job->num_progs++;
    11031050                job->progs = xrealloc(job->progs,
    1104                                       sizeof(*job->progs) * job->num_progs);
     1051                        sizeof(*job->progs) * job->num_progs);
    11051052                prog = job->progs + (job->num_progs - 1);
    11061053                prog->num_redirects = 0;
     
    11151062
    11161063                src++;
    1117                 while (*src && isspace(*src))
    1118                     src++;
     1064                src = skip_whitespace(src);
    11191065
    11201066                if (!*src) {
     1067empty_command_in_pipe:
    11211068                    bb_error_msg("empty command in pipe");
    11221069                    free_job(job);
    1123                     job->num_progs=0;
     1070                    job->num_progs = 0;
    11241071                    return 1;
    11251072                }
     
    11291076#endif
    11301077
    1131 #ifdef CONFIG_LASH_JOB_CONTROL
     1078#if ENABLE_LASH_JOB_CONTROL
    11321079            case '&':           /* background */
    11331080                *inbg = 1;
     1081                /* fallthrough */
    11341082#endif
    11351083            case ';':           /* multiple commands */
    1136                 done = 1;
     1084                flag |= LASH_OPT_DONE;
    11371085                return_command = *command_ptr + (src - *command_ptr) + 1;
    11381086                break;
     
    11551103    }
    11561104
    1157     if (*prog->argv[argc_l] || saw_quote) {
     1105    if (*prog->argv[argc_l] || flag & LASH_OPT_SAW_QUOTE) {
    11581106        argc_l++;
    11591107    }
     
    11651113
    11661114    if (!return_command) {
    1167         job->text = bb_xstrdup(*command_ptr);
     1115        job->text = xstrdup(*command_ptr);
    11681116    } else {
    11691117        /* This leaves any trailing spaces, which is a bit sloppy */
    1170         job->text = bb_xstrndup(*command_ptr, return_command - *command_ptr);
     1118        job->text = xstrndup(*command_ptr, return_command - *command_ptr);
    11711119    }
    11721120
     
    11801128static int pseudo_exec(struct child_prog *child)
    11811129{
    1182     struct built_in_command *x;
     1130    const struct built_in_command *x;
    11831131
    11841132    /* Check if the command matches any of the non-forking builtins.
     
    11871135     * if this is one of those cases.
    11881136     */
    1189     for (x = bltins; x->cmd; x++) {
    1190         if (strcmp(child->argv[0], x->cmd) == 0 ) {
     1137    /* Check if the command matches any of the forking builtins. */
     1138    for (x = bltins; x <= &VEC_LAST(bltins); x++) {
     1139        if (strcmp(child->argv[0], x->cmd) == 0) {
    11911140            _exit(x->function(child));
    11921141        }
    11931142    }
    11941143
    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     }
    12021144
    12031145    /* Check if the command matches any busybox internal
     
    12121154     * /bin/foo is a symlink to busybox.
    12131155     */
    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);
     1156    if (ENABLE_FEATURE_SH_STANDALONE) {
     1157        run_applet_and_exit(child->argv[0], child->argv);
    12221158    }
    12231159
     
    12331169{
    12341170    struct job *thejob;
    1235     struct jobset *j_list=newjob->job_list;
     1171    struct jobset *j_list = newjob->job_list;
    12361172
    12371173    /* find the ID for thejob to use */
     
    12551191    thejob->stopped_progs = 0;
    12561192
    1257 #ifdef CONFIG_LASH_JOB_CONTROL
     1193#if ENABLE_LASH_JOB_CONTROL
    12581194    if (inbg) {
    12591195        /* we don't wait for background thejobs to return -- append it
     
    12621198               newjob->progs[newjob->num_progs - 1].pid);
    12631199        last_jobid = newjob->jobid;
    1264         last_bg_pid=newjob->progs[newjob->num_progs - 1].pid;
     1200        last_bg_pid = newjob->progs[newjob->num_progs - 1].pid;
    12651201    } else {
    12661202        newjob->job_list->fg = thejob;
     
    12791215    int nextin, nextout;
    12801216    int pipefds[2];             /* pipefd[0] is for reading */
    1281     struct built_in_command *x;
     1217    const struct built_in_command *x;
    12821218    struct child_prog *child;
    12831219
    1284     nextin = 0, nextout = 1;
     1220    nextin = 0;
    12851221    for (i = 0; i < newjob->num_progs; i++) {
    1286         child = & (newjob->progs[i]);
    1287 
     1222        child = &(newjob->progs[i]);
     1223
     1224        nextout = 1;
    12881225        if ((i + 1) < newjob->num_progs) {
    1289             if (pipe(pipefds)<0) bb_perror_msg_and_die("pipe");
     1226            xpipe(pipefds);
    12901227            nextout = pipefds[1];
    1291         } else {
    1292             if (outpipe[1]!=-1) {
    1293                 nextout = outpipe[1];
    1294             } else {
    1295                 nextout = 1;
    1296             }
    1297         }
    1298 
     1228        } else if (outpipe[1] != -1) {
     1229            nextout = outpipe[1];
     1230        }
    12991231
    13001232        /* Check if the command matches any non-forking builtins,
     
    13051237         */
    13061238        if (newjob->num_progs == 1) {
     1239            int rcode;
     1240            int squirrel[] = {-1, -1, -1};
     1241
    13071242            /* Check if the command sets an environment variable. */
    13081243            if (strchr(child->argv[0], '=') != NULL) {
     
    13111246            }
    13121247
    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};
     1248            for (x = bltins; x <= &VEC_LAST(bltins); x++) {
     1249                if (strcmp(child->argv[0], x->cmd) == 0) {
    13171250                    setup_redirects(child, squirrel);
    13181251                    rcode = x->function(child);
     
    13211254                }
    13221255            }
    1323         }
    1324 
    1325 #if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__)
    1326         if (!(child->pid = fork()))
     1256#if ENABLE_FEATURE_SH_STANDALONE
     1257            {
     1258                const struct bb_applet *a = find_applet_by_name(child->argv[i]);
     1259                if (a && a->nofork) {
     1260                    setup_redirects(child, squirrel);
     1261                    rcode = run_nofork_applet(a, child->argv + i);
     1262                    restore_redirects(squirrel);
     1263                    return rcode;
     1264                }
     1265            }
     1266#endif
     1267        }
     1268
     1269#if BB_MMU
     1270        child->pid = fork();
    13271271#else
    1328         if (!(child->pid = vfork()))
    1329 #endif
    1330         {
     1272        child->pid = vfork();
     1273#endif
     1274        if (!child->pid) {
    13311275            /* Set the handling for job control signals back to the default.  */
    13321276            signal(SIGINT, SIG_DFL);
     
    13371281            signal(SIGCHLD, SIG_DFL);
    13381282
    1339             // Close all open filehandles.
    1340             while(close_me_list) close((long)llist_pop(&close_me_list));
    1341 
    1342             if (outpipe[1]!=-1) {
     1283            /* Close all open filehandles. */
     1284            while (close_me_list)
     1285                close((long)llist_pop(&close_me_list));
     1286
     1287            if (outpipe[1] != -1) {
    13431288                close(outpipe[0]);
    13441289            }
     
    13601305            pseudo_exec(child);
    13611306        }
    1362         if (outpipe[1]!=-1) {
     1307        if (outpipe[1] != -1) {
    13631308            close(outpipe[1]);
    13641309        }
     
    13921337    int inbg = 0;
    13931338    int status;
    1394 #ifdef CONFIG_LASH_JOB_CONTROL
     1339#if ENABLE_LASH_JOB_CONTROL
    13951340    pid_t  parent_pgrp;
    13961341    /* save current owner of TTY so we can restore it on exit */
     
    14101355
    14111356            if (!next_command) {
    1412                 if (get_command(input, command))
     1357                if (get_command_bufsiz(input, command))
    14131358                    break;
    14141359                next_command = command;
    14151360            }
    14161361
    1417             if (! expand_arguments(next_command)) {
     1362            if (!expand_arguments(next_command)) {
    14181363                free(command);
    14191364                command = xzalloc(BUFSIZ);
     
    14241369            if (!parse_command(&next_command, &newjob, &inbg) &&
    14251370                newjob.num_progs) {
    1426                 int pipefds[2] = {-1,-1};
    1427                 debug_printf( "job=%p fed to run_command by busy_loop()'\n",
     1371                int pipefds[2] = { -1, -1 };
     1372                debug_printf("job=%p fed to run_command by busy_loop()'\n",
    14281373                        &newjob);
    14291374                run_command(&newjob, inbg, pipefds);
     
    14311376            else {
    14321377                free(command);
    1433                 command = (char *) xzalloc(BUFSIZ);
     1378                command = xzalloc(BUFSIZ);
    14341379                next_command = NULL;
    14351380            }
     
    14401385                   job_list.fg->progs[i].is_stopped == 1) i++;
    14411386
    1442             if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED)<0) {
     1387            if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED) < 0) {
    14431388                if (errno != ECHILD) {
    1444                     bb_perror_msg_and_die("waitpid(%d)",job_list.fg->progs[i].pid);
     1389                    bb_perror_msg_and_die("waitpid(%d)", job_list.fg->progs[i].pid);
    14451390                }
    14461391            }
     
    14511396                job_list.fg->progs[i].pid = 0;
    14521397
    1453                 last_return_code=WEXITSTATUS(status);
     1398                last_return_code = WEXITSTATUS(status);
    14541399
    14551400                if (!job_list.fg->running_progs) {
     
    14591404                }
    14601405            }
    1461 #ifdef CONFIG_LASH_JOB_CONTROL
     1406#if ENABLE_LASH_JOB_CONTROL
    14621407            else {
    14631408                /* the child was stopped */
     
    14831428    free(command);
    14841429
    1485 #ifdef CONFIG_LASH_JOB_CONTROL
     1430#if ENABLE_LASH_JOB_CONTROL
    14861431    /* return controlling TTY back to parent process group before exiting */
    14871432    if (tcsetpgrp(shell_terminal, parent_pgrp) && errno != ENOTTY)
     
    14961441}
    14971442
    1498 #ifdef CONFIG_FEATURE_CLEAN_UP
     1443#if ENABLE_FEATURE_CLEAN_UP
    14991444static void free_memory(void)
    15001445{
    1501     if (cwd && cwd!=bb_msg_unknown) {
    1502         free((char*)cwd);
    1503     }
    1504     if (local_pending_command)
    1505         free(local_pending_command);
     1446    free(cwd);
    15061447
    15071448    if (job_list.fg && !job_list.fg->running_progs) {
     
    15131454#endif
    15141455
    1515 #ifdef CONFIG_LASH_JOB_CONTROL
     1456#if ENABLE_LASH_JOB_CONTROL
    15161457/* Make sure we have a controlling tty.  If we get started under a job
    15171458 * aware app (like bash for example), make sure we are now in charge so
     
    15231464
    15241465    /* Loop until we are in the foreground.  */
    1525     while ((status = tcgetpgrp (shell_terminal)) >= 0) {
    1526         if (status == (shell_pgrp = getpgrp ())) {
     1466    while ((status = tcgetpgrp(shell_terminal)) >= 0) {
     1467        shell_pgrp = getpgrp();
     1468        if (status == shell_pgrp) {
    15271469            break;
    15281470        }
    1529         kill (- shell_pgrp, SIGTTIN);
     1471        kill(- shell_pgrp, SIGTTIN);
    15301472    }
    15311473
     
    15401482    /* Put ourselves in our own process group.  */
    15411483    setsid();
    1542     shell_pgrp = getpid ();
     1484    shell_pgrp = getpid();
    15431485    setpgid(shell_pgrp, shell_pgrp);
    15441486
     
    15521494#endif
    15531495
     1496int lash_main(int argc_l, char **argv_l);
    15541497int lash_main(int argc_l, char **argv_l)
    15551498{
    1556     int opt, interactive=FALSE;
     1499    unsigned opt;
    15571500    FILE *input = stdin;
    15581501    argc = argc_l;
    15591502    argv = argv_l;
    15601503
     1504#if ENABLE_FEATURE_EDITING
     1505    line_input_state = new_line_input_t(FOR_SHELL);
     1506#endif
     1507
    15611508    /* These variables need re-initializing when recursing */
    15621509    last_jobid = 0;
    1563     local_pending_command = NULL;
    15641510    close_me_list = NULL;
    15651511    job_list.head = NULL;
    15661512    job_list.fg = NULL;
    1567     last_return_code=1;
     1513    last_return_code = 1;
    15681514
    15691515    if (argv[0] && argv[0][0] == '-') {
     
    15741520            /* Now run the file */
    15751521            busy_loop(prof_input);
    1576             fclose(prof_input);
     1522            fclose_if_not_stdin(prof_input);
    15771523            llist_pop(&close_me_list);
    15781524        }
    15791525    }
    15801526
    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         }
     1527    opt = getopt32(argv_l, "+ic:", &local_pending_command);
     1528#define LASH_OPT_i (1<<0)
     1529#define LASH_OPT_c (1<<1)
     1530    if (opt & LASH_OPT_c) {
     1531        input = NULL;
     1532        optind++;
     1533        argv += optind;
    15971534    }
    15981535    /* A shell is interactive if the `-i' flag was given, or if all of
     
    16031540     *    standard output is a terminal
    16041541     *    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++;
     1542    if (argv[optind] == NULL && input == stdin
     1543     && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)
     1544    ) {
     1545        opt |= LASH_OPT_i;
    16091546    }
    16101547    setup_job_control();
    1611     if (interactive) {
     1548    if (opt & LASH_OPT_i) {
    16121549        /* Looks like they want an interactive shell */
    16131550        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");
     1551            printf("\n\n%s built-in shell (lash)\n"
     1552                    "Enter 'help' for a list of built-in commands.\n\n",
     1553                    bb_banner);
    16161554        }
    16171555    } else if (!local_pending_command && argv[optind]) {
    16181556        //printf( "optind=%d  argv[optind]='%s'\n", optind, argv[optind]);
    1619         input = bb_xfopen(argv[optind], "r");
     1557        input = xfopen(argv[optind], "r");
    16201558        /* be lazy, never mark this closed */
    16211559        llist_add_to(&close_me_list, (void *)(long)fileno(input));
     
    16231561
    16241562    /* initialize the cwd -- this is never freed...*/
    1625     cwd = xgetcwd(0);
    1626     if (!cwd)
    1627         cwd = bb_msg_unknown;
     1563    update_cwd();
    16281564
    16291565    if (ENABLE_FEATURE_CLEAN_UP) atexit(free_memory);
    16301566
    1631     if (ENABLE_FEATURE_COMMAND_EDITING) cmdedit_set_initial_prompt();
     1567    if (ENABLE_FEATURE_EDITING) cmdedit_set_initial_prompt();
    16321568    else PS1 = NULL;
    16331569
    1634     return (busy_loop(input));
    1635 }
     1570    return busy_loop(input);
     1571}
Note: See TracChangeset for help on using the changeset viewer.