X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=sh.c;h=7f5b9060207c30bb20c33de7a2e688c2948577d0;hb=d58ff8731ce635a75406cc8b9629f1041bb4ed32;hp=5a254736858bafb607acd89fdc13fa72adac5dd2;hpb=6085c72b6ee92d69642a85b6f5d2dff239c5b1c1;p=oweals%2Fbusybox.git diff --git a/sh.c b/sh.c index 5a2547368..7f5b90602 100644 --- a/sh.c +++ b/sh.c @@ -28,11 +28,11 @@ //#define BB_FEATURE_SH_BACKTICKS //#define BB_FEATURE_SH_IF_EXPRESSIONS -//#define BB_FEATURE_SH_ENVIRONMENT +#define BB_FEATURE_SH_ENVIRONMENT //#define DEBUG_SHELL -#include "internal.h" +#include "busybox.h" #include #include #include @@ -108,6 +108,7 @@ struct builtInCommand { /* function prototypes for builtins */ static int builtin_cd(struct job *cmd, struct jobSet *junk); static int builtin_env(struct job *dummy, struct jobSet *junk); +static int builtin_exec(struct job *cmd, struct jobSet *junk); static int builtin_exit(struct job *cmd, struct jobSet *junk); static int builtin_fg_bg(struct job *cmd, struct jobSet *jobList); static int builtin_help(struct job *cmd, struct jobSet *junk); @@ -139,12 +140,14 @@ static int busy_loop(FILE * input); static struct builtInCommand bltins[] = { {"bg", "Resume a job in the background", builtin_fg_bg}, {"cd", "Change working directory", builtin_cd}, + {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec}, {"exit", "Exit from shell()", builtin_exit}, {"fg", "Bring job into the foreground", builtin_fg_bg}, {"jobs", "Lists the active jobs", builtin_jobs}, {"export", "Set environment variable", builtin_export}, {"unset", "Unset environment variable", builtin_unset}, {"read", "Input environment variable", builtin_read}, + {".", "Source-in and run commands in a file", builtin_source}, #ifdef BB_FEATURE_SH_IF_EXPRESSIONS {"if", NULL, builtin_if}, {"then", NULL, builtin_then}, @@ -159,7 +162,6 @@ static struct builtInCommand bltins[] = { static struct builtInCommand bltins_forking[] = { {"env", "Print all environment variables", builtin_env}, {"pwd", "Print current directory", builtin_pwd}, - {".", "Source-in and run commands in a file", builtin_source}, {"help", "List shell built-in commands", builtin_help}, {NULL, NULL, NULL} }; @@ -219,13 +221,26 @@ static int builtin_env(struct job *dummy, struct jobSet *junk) return (0); } +/* built-in 'exec' handler */ +static int builtin_exec(struct job *cmd, struct jobSet *junk) +{ + if (cmd->progs[0].argv[1]) + { + cmd->progs[0].argv++; + execvp(cmd->progs[0].argv[0], cmd->progs[0].argv); + fatalError("Exec to %s failed: %s\n", cmd->progs[0].argv[0], + strerror(errno)); + } + return TRUE; +} + /* built-in 'exit' handler */ static int builtin_exit(struct job *cmd, struct jobSet *junk) { if (!cmd->progs[0].argv[1] == 1) exit TRUE; - return(atoi(cmd->progs[0].argv[1])); + exit (atoi(cmd->progs[0].argv[1])); } /* built-in 'fg' and 'bg' handler */ @@ -500,6 +515,7 @@ static int builtin_source(struct job *cmd, struct jobSet *junk) /* Now run the file */ status = busy_loop(input); + fclose(input); return (status); } @@ -611,10 +627,10 @@ static int setupRedirections(struct childProgram *prog) mode = O_RDONLY; break; case REDIRECT_OVERWRITE: - mode = O_RDWR | O_CREAT | O_TRUNC; + mode = O_WRONLY | O_CREAT | O_TRUNC; break; case REDIRECT_APPEND: - mode = O_RDWR | O_CREAT | O_APPEND; + mode = O_WRONLY | O_CREAT | O_APPEND; break; } @@ -769,31 +785,42 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr, #endif } - rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult); - if (rc == GLOB_NOSPACE) { - errorMsg("out of space during glob operation\n"); - return; - } else if (rc == GLOB_NOMATCH || + if (strpbrk(prog->argv[argc_l - 1],"*[]?")!= NULL){ + rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult); + if (rc == GLOB_NOSPACE) { + errorMsg("out of space during glob operation\n"); + return; + } else if (rc == GLOB_NOMATCH || (!rc && (prog->globResult.gl_pathc - i) == 1 && strcmp(prog->argv[argc_l - 1], prog->globResult.gl_pathv[i]) == 0)) { - /* we need to remove whatever \ quoting is still present */ - src = dst = prog->argv[argc_l - 1]; - while (*src) { - if (*src != '\\') - *dst++ = *src; - src++; + /* we need to remove whatever \ quoting is still present */ + src = dst = prog->argv[argc_l - 1]; + while (*src) { + if (*src != '\\') + *dst++ = *src; + src++; + } + *dst = '\0'; + } else if (!rc) { + argcAlloced += (prog->globResult.gl_pathc - i); + prog->argv = xrealloc(prog->argv, argcAlloced * sizeof(*prog->argv)); + memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i, + sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); + argc_l += (prog->globResult.gl_pathc - i - 1); } - *dst = '\0'; - } else if (!rc) { - argcAlloced += (prog->globResult.gl_pathc - i); - prog->argv = - realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); - memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i, - sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); - argc_l += (prog->globResult.gl_pathc - i - 1); + }else{ + src = dst = prog->argv[argc_l - 1]; + while (*src) { + if (*src != '\\') + *dst++ = *src; + src++; + } + *dst = '\0'; + prog->globResult.gl_pathc=0; + if (flags==0) + prog->globResult.gl_pathv=NULL; } - *argcAllocedPtr = argcAlloced; *argcPtr = argc_l; } @@ -837,7 +864,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi 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 = calloc(2*strlen(*commandPtr) + 1, sizeof(char)); + job->cmdBuf = command = xcalloc(2*strlen(*commandPtr) + 1, sizeof(char)); job->text = NULL; prog = job->progs; @@ -876,9 +903,9 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi /* +1 here leaves room for the NULL which ends argv */ if ((argc_l + 1) == argvAlloced) { argvAlloced += 5; - prog->argv = realloc(prog->argv, - sizeof(*prog->argv) * - argvAlloced); + prog->argv = xrealloc(prog->argv, + sizeof(*prog->argv) * + argvAlloced); } globLastArgument(prog, &argc_l, &argvAlloced); prog->argv[argc_l] = buf; @@ -900,9 +927,9 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi case '>': /* redirections */ case '<': i = prog->numRedirections++; - prog->redirections = realloc(prog->redirections, - sizeof(*prog->redirections) * - (i + 1)); + prog->redirections = xrealloc(prog->redirections, + sizeof(*prog->redirections) * + (i + 1)); prog->redirections[i].fd = -1; if (buf != prog->argv[argc_l]) { @@ -969,8 +996,8 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi /* and start the next */ job->numProgs++; - job->progs = realloc(job->progs, - sizeof(*job->progs) * job->numProgs); + job->progs = xrealloc(job->progs, + sizeof(*job->progs) * job->numProgs); prog = job->progs + (job->numProgs - 1); prog->numRedirections = 0; prog->redirections = NULL; @@ -1003,16 +1030,6 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi returnCommand = *commandPtr + (src - *commandPtr) + 1; break; - case '\\': - src++; - if (!*src) { - errorMsg("character expected after \\\n"); - freeJob(job); - return 1; - } - if (*src == '*' || *src == '[' || *src == ']' - || *src == '?') *buf++ = '\\'; - /* fallthrough */ #ifdef BB_FEATURE_SH_BACKTICKS case '`': /* Exec a backtick-ed command */ @@ -1033,7 +1050,8 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi /* Make some space to hold just the backticked command */ charptr1 = charptr2 = xmalloc(1+ptr-src); - snprintf(charptr1, 1+ptr-src, src); + memcpy(charptr1, src, ptr-src); + charptr1[ptr-src] = '\0'; newJob = xmalloc(sizeof(struct job)); /* Now parse and run the backticked command */ if (!parseCommand(&charptr1, newJob, &njobList, inBg) @@ -1058,7 +1076,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi while ( (size=fullRead(pipefd[0], charptr1, BUFSIZ-1)) >0) { int newSize=src - *commandPtr + size + 1 + strlen(charptr2); if (newSize > BUFSIZ) { - *commandPtr=realloc(*commandPtr, src - *commandPtr + + *commandPtr=xrealloc(*commandPtr, src - *commandPtr + size + 1 + strlen(charptr2)); } memcpy(src, charptr1, size); @@ -1071,7 +1089,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi /* Now paste into the *commandPtr all the stuff * leftover after the second backtick */ - memcpy(src, charptr2, strlen(charptr2)); + memcpy(src, charptr2, strlen(charptr2)+1); free(charptr2); /* Now recursively call parseCommand to deal with the new @@ -1082,6 +1100,17 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi } break; #endif // BB_FEATURE_SH_BACKTICKS + + case '\\': + src++; + if (!*src) { + errorMsg("character expected after \\\n"); + freeJob(job); + return 1; + } + if (*src == '*' || *src == '[' || *src == ']' + || *src == '?') *buf++ = '\\'; + /* fallthrough */ default: *buf++ = *src; } @@ -1111,7 +1140,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi } *commandPtr = returnCommand; - + return 0; } @@ -1123,10 +1152,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int int pipefds[2]; /* pipefd[0] is for reading */ struct builtInCommand *x; #ifdef BB_FEATURE_SH_STANDALONE_SHELL - const struct BB_applet *a = applets; + struct BB_applet search_applet, *applet; #endif - nextin = 0, nextout = 1; for (i = 0; i < newJob->numProgs; i++) { if ((i + 1) < newJob->numProgs) { @@ -1186,23 +1214,44 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int } } #ifdef BB_FEATURE_SH_STANDALONE_SHELL - /* Check if the command matches any busybox internal commands here */ - while (a->name != 0) { - if (strcmp(get_last_path_component(newJob->progs[i].argv[0]), a->name) == 0) { - int argc_l; - char** argv=newJob->progs[i].argv; - for(argc_l=0;*argv!=NULL; argv++, argc_l++); - applet_name=a->name; - optind = 1; - exit((*(a->main)) (argc_l, newJob->progs[i].argv)); - } - a++; + /* Check if the command matches any busybox internal + * commands ("applets") here. Following discussions from + * November 2000 on busybox@opensource.lineo.com, don't use + * get_last_path_component(). This way explicit (with + * slashes) filenames will never be interpreted as an + * applet, just like with builtins. This way the user can + * override an applet with an explicit filename reference. + * The only downside to this change is that an explicit + * /bin/foo invocation fill fork and exec /bin/foo, even if + * /bin/foo is a symlink to busybox. + */ + search_applet.name = newJob->progs[i].argv[0]; + +#ifdef BB_FEATURE_SH_BUILTINS_ALWAYS_WIN + /* If you enable BB_FEATURE_SH_BUILTINS_ALWAYS_WIN, then + * if you run /bin/cat, it will use BusyBox cat even if + * /bin/cat exists on the filesystem and is _not_ busybox. + * Some systems want this, others do not. Choose wisely. :-) + */ + search_applet.name = get_last_path_component(search_applet.name); +#endif + + /* Do a binary search to find the applet entry given the name. */ + applet = bsearch(&search_applet, applets, NUM_APPLETS, + sizeof(struct BB_applet), applet_name_compare); + if (applet != NULL) { + int argc_l; + char** argv=newJob->progs[i].argv; + for(argc_l=0;*argv!=NULL; argv++, argc_l++); + applet_name=applet->name; + optind = 1; + exit((*(applet->main)) (argc_l, newJob->progs[i].argv)); } #endif execvp(newJob->progs[i].argv[0], newJob->progs[i].argv); fatalError("%s: %s\n", newJob->progs[i].argv[0], - strerror(errno)); + strerror(errno)); } if (outPipe[1]!=-1) { close(outPipe[1]); @@ -1231,10 +1280,10 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int /* add the theJob to the list of running jobs */ if (!jobList->head) { - theJob = jobList->head = malloc(sizeof(*theJob)); + theJob = jobList->head = xmalloc(sizeof(*theJob)); } else { for (theJob = jobList->head; theJob->next; theJob = theJob->next); - theJob->next = malloc(sizeof(*theJob)); + theJob->next = xmalloc(sizeof(*theJob)); theJob = theJob->next; } @@ -1277,7 +1326,7 @@ static int busy_loop(FILE * input) /* save current owner of TTY so we can restore it on exit */ parent_pgrp = tcgetpgrp(0); - command = (char *) calloc(BUFSIZ, sizeof(char)); + command = (char *) xcalloc(BUFSIZ, sizeof(char)); /* don't pay any attention to this signal; it just confuses things and isn't really meant for shells anyway */ @@ -1303,7 +1352,7 @@ static int busy_loop(FILE * input) } else { free(command); - command = (char *) calloc(BUFSIZ, sizeof(char)); + command = (char *) xcalloc(BUFSIZ, sizeof(char)); nextCommand = NULL; } } else { @@ -1430,10 +1479,7 @@ int shell_main(int argc_l, char **argv_l) fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n"); } else if (local_pending_command==NULL) { //fprintf(stdout, "optind=%d argv[optind]='%s'\n", optind, argv[optind]); - input = fopen(argv[optind], "r"); - if (!input) { - fatalError("%s: %s\n", argv[optind], strerror(errno)); - } + input = xfopen(argv[optind], "r"); } /* initialize the cwd -- this is never freed...*/