Remove all usage of the "register" storage class specifier.
[oweals/busybox.git] / shell / lash.c
index 56a3a23dd9bb8089e19e10f4f00a7dac2b0836c2..d87c5a25b25fa2ace6bbd3e2f7b576920cf5c108 100644 (file)
@@ -21,6 +21,7 @@
 //#define DEBUG_SHELL
 
 
+#include "busybox.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
@@ -33,7 +34,6 @@
 #include <unistd.h>
 #include <getopt.h>
 #include <termios.h>
-#include "busybox.h"
 #include "cmdedit.h"
 
 #ifdef CONFIG_LOCALE_SUPPORT
@@ -57,11 +57,13 @@ enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE,
 };
 #endif
 
-static const unsigned int DEFAULT_CONTEXT=0x1;
-static const unsigned int IF_TRUE_CONTEXT=0x2;
-static const unsigned int IF_FALSE_CONTEXT=0x4;
-static const unsigned int THEN_EXP_CONTEXT=0x8;
-static const unsigned int ELSE_EXP_CONTEXT=0x10;
+enum {
+       DEFAULT_CONTEXT = 0x1,
+       IF_TRUE_CONTEXT = 0x2,
+       IF_FALSE_CONTEXT = 0x4,
+       THEN_EXP_CONTEXT = 0x8,
+       ELSE_EXP_CONTEXT = 0x10
+};
 
 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
 struct redir_struct {
@@ -107,11 +109,6 @@ struct built_in_command {
        int (*function) (struct child_prog *);  /* function ptr */
 };
 
-struct close_me {
-       int fd;
-       struct close_me *next;
-};
-
 /* function prototypes for builtins */
 static int builtin_cd(struct child_prog *cmd);
 static int builtin_exec(struct child_prog *cmd);
@@ -127,9 +124,6 @@ static int builtin_read(struct child_prog *cmd);
 
 
 /* function prototypes for shell stuff */
-static void mark_open(int fd);
-static void mark_closed(int fd);
-static void close_all(void);
 static void checkjobs(struct jobset *job_list);
 static void remove_job(struct jobset *j_list, struct job *job);
 static int get_command(FILE * source, char *command);
@@ -175,7 +169,7 @@ static char *local_pending_command = NULL;
 static struct jobset job_list = { NULL, NULL };
 static int argc;
 static char **argv;
-static struct close_me *close_me_head;
+static llist_t *close_me_list;
 static int last_return_code;
 static int last_bg_pid;
 static unsigned int last_jobid;
@@ -234,7 +228,7 @@ static int builtin_cd(struct child_prog *child)
        else
                newdir = child->argv[1];
        if (chdir(newdir)) {
-               printf("cd: %s: %m\n", newdir);
+               bb_perror_msg("cd: %s", newdir);
                return EXIT_FAILURE;
        }
        cwd = xgetcwd((char *)cwd);
@@ -249,7 +243,7 @@ static int builtin_exec(struct child_prog *child)
        if (child->argv[1] == NULL)
                return EXIT_SUCCESS;   /* Really? */
        child->argv++;
-       close_all();
+       while(close_me_list) close((long)llist_pop(&close_me_list));
        pseudo_exec(child);
        /* never returns */
 }
@@ -282,7 +276,7 @@ static int builtin_fg_bg(struct child_prog *child)
                }
        } else {
                if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
-                       bb_error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
+                       bb_error_msg(bb_msg_invalid_arg, child->argv[1], child->argv[0]);
                        return EXIT_FAILURE;
                }
                for (job = child->family->job_list->head; job; job = job->next) {
@@ -384,7 +378,7 @@ static int builtin_export(struct child_prog *child)
        }
        res = putenv(v);
        if (res)
-               fprintf(stderr, "export: %m\n");
+               bb_perror_msg("export");
 #ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
        if (strncmp(v, "PS1=", 4)==0)
                PS1 = getenv("PS1");
@@ -426,7 +420,7 @@ static int builtin_read(struct child_prog *child)
                if((s = strdup(string)))
                        res = putenv(s);
                if (res)
-                       fprintf(stderr, "read: %m\n");
+                       bb_perror_msg("read");
        }
        else
                fgets(string, sizeof(string), stdin);
@@ -439,7 +433,6 @@ static int builtin_source(struct child_prog *child)
 {
        FILE *input;
        int status;
-       int fd;
 
        if (child->argv[1] == NULL)
                return EXIT_FAILURE;
@@ -450,12 +443,11 @@ static int builtin_source(struct child_prog *child)
                return EXIT_FAILURE;
        }
 
-       fd=fileno(input);
-       mark_open(fd);
+       llist_add_to(&close_me_list, (void *)(long)fileno(input));
        /* Now run the file */
        status = busy_loop(input);
        fclose(input);
-       mark_closed(fd);
+       llist_pop(&close_me_list);
        return (status);
 }
 
@@ -463,43 +455,13 @@ static int builtin_source(struct child_prog *child)
 static int builtin_unset(struct child_prog *child)
 {
        if (child->argv[1] == NULL) {
-               printf( "unset: parameter required.\n");
+               printf(bb_msg_requires_arg, "unset");
                return EXIT_FAILURE;
        }
        unsetenv(child->argv[1]);
        return EXIT_SUCCESS;
 }
 
-static void mark_open(int fd)
-{
-       struct close_me *new = xmalloc(sizeof(struct close_me));
-       new->fd = fd;
-       new->next = close_me_head;
-       close_me_head = new;
-}
-
-static void mark_closed(int fd)
-{
-       struct close_me *tmp;
-       if (close_me_head == NULL || close_me_head->fd != fd)
-               bb_error_msg_and_die("corrupt close_me");
-       tmp = close_me_head;
-       close_me_head = close_me_head->next;
-       free(tmp);
-}
-
-static void close_all()
-{
-       struct close_me *c, *tmp;
-       for (c=close_me_head; c; c=tmp) {
-               close(c->fd);
-               tmp=c->next;
-               free(c);
-       }
-       close_me_head = NULL;
-}
-
-
 #ifdef CONFIG_LASH_JOB_CONTROL
 /* free up all memory from a job */
 static void free_job(struct job *cmd)
@@ -745,10 +707,10 @@ static int get_command(FILE * source, char *command)
        return 0;
 }
 
-static char* itoa(register int i)
+static char* itoa(int i)
 {
        static char a[7]; /* Max 7 ints */
-       register char *b = a + sizeof(a) - 1;
+       char *b = a + sizeof(a) - 1;
        int   sign = (i < 0);
 
        if (sign)
@@ -767,33 +729,29 @@ static char* itoa(register int i)
 
 static char * strsep_space( char *string, int * ix)
 {
-       char *token, *begin;
-
-       begin = string;
+       char *token;
 
        /* Short circuit the trivial case */
        if ( !string || ! string[*ix])
                return NULL;
 
        /* Find the end of the token. */
-       while( string && string[*ix] && !isspace(string[*ix]) ) {
+       while( string[*ix] && !isspace(string[*ix]) ) {
                (*ix)++;
        }
 
        /* Find the end of any whitespace trailing behind
         * the token and let that be part of the token */
-       while( string && string[*ix] && isspace(string[*ix]) ) {
+       while( string[*ix] && isspace(string[*ix]) ) {
                (*ix)++;
        }
 
-       if (! string && *ix==0) {
+       if (!*ix) {
                /* Nothing useful was found */
                return NULL;
        }
 
-       token = xmalloc(*ix+1);
-       token[*ix] = '\0';
-       strncpy(token, string,  *ix);
+       token = bb_xstrndup(string, *ix);
 
        return token;
 }
@@ -978,7 +936,6 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
        int argv_alloced;
        int saw_quote = 0;
        char quote = '\0';
-       int count;
        struct child_prog *prog;
 #ifdef CONFIG_LASH_PIPE_N_REDIRECTS
        int i;
@@ -1006,7 +963,7 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
           Getting clean memory relieves us of the task of NULL
           terminating things and makes the rest of this look a bit
           cleaner (though it is, admittedly, a tad less efficient) */
-       job->cmdbuf = command = xcalloc(2*strlen(*command_ptr) + 1, sizeof(char));
+       job->cmdbuf = command = xzalloc(2*strlen(*command_ptr) + 1);
        job->text = NULL;
 
        prog = job->progs;
@@ -1207,14 +1164,10 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
        prog->argv[argc_l] = NULL;
 
        if (!return_command) {
-               job->text = xmalloc(strlen(*command_ptr) + 1);
-               strcpy(job->text, *command_ptr);
+               job->text = bb_xstrdup(*command_ptr);
        } else {
                /* This leaves any trailing spaces, which is a bit sloppy */
-               count = return_command - *command_ptr;
-               job->text = xmalloc(count + 1);
-               strncpy(job->text, *command_ptr, count);
-               job->text[count] = '\0';
+               job->text = bb_xstrndup(*command_ptr, return_command - *command_ptr);
        }
 
        *command_ptr = return_command;
@@ -1227,9 +1180,12 @@ static int parse_command(char **command_ptr, struct job *job, int *inbg)
 static int pseudo_exec(struct child_prog *child)
 {
        struct built_in_command *x;
-#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
-       char *name;
-#endif
+
+       /* Check if the command sets an environment variable. */
+       if( strchr(child->argv[0], '=') != NULL ) {
+               child->argv[1] = child->argv[0];
+               _exit(builtin_export(child));
+       }
 
        /* Check if the command matches any of the non-forking builtins.
         * Depending on context, this might be redundant.  But it's
@@ -1249,7 +1205,7 @@ static int pseudo_exec(struct child_prog *child)
                        _exit (x->function(child));
                }
        }
-#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
+
        /* Check if the command matches any busybox internal
         * commands ("applets") here.  Following discussions from
         * November 2000 on busybox@busybox.net, don't use
@@ -1261,28 +1217,21 @@ static int pseudo_exec(struct child_prog *child)
         * /bin/foo invocation will fork and exec /bin/foo, even if
         * /bin/foo is a symlink to busybox.
         */
-       name = child->argv[0];
 
-       {
-               char** argv_l=child->argv;
+       if (ENABLE_FEATURE_SH_STANDALONE_SHELL) {
+               char **argv_l = child->argv;
                int argc_l;
-#ifdef _NEWLIB_VERSION
-               /* newlib uses __getopt_initialized for getopt() in
-                * addition to optind, see newlib/libc/sys/linux/getopt.c
-                */
-               extern int __getopt_initialized = 0;
-#endif
-               for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
+
+               for(argc_l=0; *argv_l; argv_l++, argc_l++);
                optind = 1;
-               run_applet_by_name(name, argc_l, child->argv);
+               run_applet_by_name(child->argv[0], argc_l, child->argv);
        }
-#endif
 
        execvp(child->argv[0], child->argv);
 
        /* Do not use bb_perror_msg_and_die() here, since we must not
         * call exit() but should call _exit() instead */
-       fprintf(stderr, "%s: %m\n", child->argv[0]);
+       bb_perror_msg("%s", child->argv[0]);
        _exit(EXIT_FAILURE);
 }
 
@@ -1323,9 +1272,8 @@ static void insert_job(struct job *newjob, int inbg)
                newjob->job_list->fg = thejob;
 
                /* move the new process group into the foreground */
-               /* suppress messages when run from /linuxrc mag@sysgo.de */
-               if (tcsetpgrp(shell_terminal, newjob->pgrp) && errno != ENOTTY)
-                       bb_perror_msg("tcsetpgrp");
+               /* Ignore errors since child could have already exited */
+               tcsetpgrp(shell_terminal, newjob->pgrp);
        }
 #endif
 }
@@ -1388,7 +1336,8 @@ static int run_command(struct job *newjob, int inbg, int outpipe[2])
                        signal(SIGTTOU, SIG_DFL);
                        signal(SIGCHLD, SIG_DFL);
 
-                       close_all();
+                       // Close all open filehandles.
+                       while(close_me_list) close((long)llist_pop(&close_me_list));
 
                        if (outpipe[1]!=-1) {
                                close(outpipe[0]);
@@ -1440,7 +1389,7 @@ static int busy_loop(FILE * input)
        char *next_command = NULL;
        struct job newjob;
        int i;
-       int inbg;
+       int inbg = 0;
        int status;
 #ifdef CONFIG_LASH_JOB_CONTROL
        pid_t  parent_pgrp;
@@ -1450,7 +1399,7 @@ static int busy_loop(FILE * input)
        newjob.job_list = &job_list;
        newjob.job_context = DEFAULT_CONTEXT;
 
-       command = (char *) xcalloc(BUFSIZ, sizeof(char));
+       command = xzalloc(BUFSIZ);
 
        while (1) {
                if (!job_list.fg) {
@@ -1467,7 +1416,7 @@ static int busy_loop(FILE * input)
 
                        if (! expand_arguments(next_command)) {
                                free(command);
-                               command = (char *) xcalloc(BUFSIZ, sizeof(char));
+                               command = xzalloc(BUFSIZ);
                                next_command = NULL;
                                continue;
                        }
@@ -1481,7 +1430,7 @@ static int busy_loop(FILE * input)
                        }
                        else {
                                free(command);
-                               command = (char *) xcalloc(BUFSIZ, sizeof(char));
+                               command = (char *) xzalloc(BUFSIZ);
                                next_command = NULL;
                        }
                } else {
@@ -1610,7 +1559,7 @@ int lash_main(int argc_l, char **argv_l)
        /* These variables need re-initializing when recursing */
        last_jobid = 0;
        local_pending_command = NULL;
-       close_me_head = NULL;
+       close_me_list = NULL;
        job_list.head = NULL;
        job_list.fg = NULL;
        last_return_code=1;
@@ -1619,12 +1568,11 @@ int lash_main(int argc_l, char **argv_l)
                FILE *prof_input;
                prof_input = fopen("/etc/profile", "r");
                if (prof_input) {
-                       int tmp_fd = fileno(prof_input);
-                       mark_open(tmp_fd);
+                       llist_add_to(&close_me_list, (void *)(long)fileno(prof_input));
                        /* Now run the file */
                        busy_loop(prof_input);
                        fclose(prof_input);
-                       mark_closed(tmp_fd);
+                       llist_pop(&close_me_list);
                }
        }
 
@@ -1661,13 +1609,14 @@ int lash_main(int argc_l, char **argv_l)
                //printf( "optind=%d  argv[optind]='%s'\n", optind, argv[optind]);
                /* Looks like they want an interactive shell */
 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
-               printf( "\n\n" BB_BANNER " Built-in shell (lash)\n");
+               printf( "\n\n%s Built-in shell (lash)\n", BB_BANNER);
                printf( "Enter 'help' for a list of built-in commands.\n\n");
 #endif
        } else if (local_pending_command==NULL) {
                //printf( "optind=%d  argv[optind]='%s'\n", optind, argv[optind]);
                input = bb_xfopen(argv[optind], "r");
-               mark_open(fileno(input));  /* be lazy, never mark this closed */
+               /* be lazy, never mark this closed */
+               llist_add_to(&close_me_list, (void *)(long)fileno(input));
        }
 
        /* initialize the cwd -- this is never freed...*/