?? hush.c
字號:
/* need to double check i->file because we might be doing something * more complicated by now, like sourcing or substituting. */ if (i->__promptme && interactive && i->file == stdin) { while(! i->p || (interactive && strlen(i->p)==0) ) { get_user_input(i); } i->promptmode=2; i->__promptme = 0; if (i->p && *i->p) { ch=*i->p++; } } else { ch = fgetc(i->file); } debug_printf("b_getch: got a %d\n", ch); } if (ch == '\n') i->__promptme=1; return ch;}/* All the callers guarantee this routine will never be * used right after a newline, so prompting is not needed. */static int file_peek(struct in_str *i){ if (i->p && *i->p) { return *i->p; } else { i->peek_buf[0] = fgetc(i->file); i->peek_buf[1] = '\0'; i->p = i->peek_buf; debug_printf("b_peek: got a %d\n", *i->p); return *i->p; }}static void setup_file_in_str(struct in_str *i, FILE *f){ i->peek = file_peek; i->get = file_get; i->__promptme=1; i->promptmode=1; i->file = f; i->p = NULL;}static void setup_string_in_str(struct in_str *i, const char *s){ i->peek = static_peek; i->get = static_get; i->__promptme=1; i->promptmode=1; i->p = s;}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) 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; for (c=close_me_head; c; c=c->next) { close(c->fd); } close_me_head = NULL;}/* squirrel != NULL means we squirrel away copies of stdin, stdout, * and stderr if they are redirected. */static int setup_redirects(struct child_prog *prog, int squirrel[]){ int openfd, mode; struct redir_struct *redir; for (redir=prog->redirects; redir; redir=redir->next) { if (redir->dup == -1 && redir->word.gl_pathv == NULL) { /* something went wrong in the parse. Pretend it didn't happen */ continue; } if (redir->dup == -1) { mode=redir_table[redir->type].mode; openfd = open(redir->word.gl_pathv[0], mode, 0666); if (openfd < 0) { /* this could get lost if stderr has been redirected, but bash and ash both lose it as well (though zsh doesn't!) */ perror_msg("error opening %s", redir->word.gl_pathv[0]); return 1; } } else { openfd = redir->dup; } if (openfd != redir->fd) { if (squirrel && redir->fd < 3) { squirrel[redir->fd] = dup(redir->fd); } if (openfd == -3) { close(openfd); } else { dup2(openfd, redir->fd); if (redir->dup == -1) close (openfd); } } } return 0;}static void restore_redirects(int squirrel[]){ int i, fd; for (i=0; i<3; i++) { fd = squirrel[i]; if (fd != -1) { /* No error checking. I sure wouldn't know what * to do with an error if I found one! */ dup2(fd, i); close(fd); } }}/* never returns *//* XXX no exit() here. If you don't exec, use _exit instead. * The at_exit handlers apparently confuse the calling process, * in particular stdin handling. Not sure why? */static void pseudo_exec(struct child_prog *child){ int i, rcode; char *p; struct built_in_command *x; if (child->argv) { for (i=0; is_assignment(child->argv[i]); i++) { debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]); p = insert_var_value(child->argv[i]); putenv(strdup(p)); if (p != child->argv[i]) free(p); } child->argv+=i; /* XXX this hack isn't so horrible, since we are about to exit, and therefore don't need to keep data structures consistent for free() use. */ /* If a variable is assigned in a forest, and nobody listens, * was it ever really set? */ if (child->argv[0] == NULL) { _exit(EXIT_SUCCESS); } /* * Check if the command matches any of the builtins. * Depending on context, this might be redundant. But it's * easier to waste a few CPU cycles than it is to figure out * if this is one of those cases. */ for (x = bltins; x->cmd; x++) { if (strcmp(child->argv[0], x->cmd) == 0 ) { debug_printf("builtin exec %s\n", child->argv[0]); rcode = x->function(child); fflush(stdout); _exit(rcode); } } /* Check if the command matches any busybox internal commands * ("applets") here. * FIXME: This feature is not 100% safe, since * BusyBox is not fully reentrant, so we have no guarantee the things * from the .bss are still zeroed, or that things from .data are still * at their defaults. We could exec ourself from /proc/self/exe, but I * really dislike relying on /proc for things. We could exec ourself * from global_argv[0], but if we are in a chroot, we may not be able * to find ourself... */ #ifdef BB_FEATURE_SH_STANDALONE_SHELL { int argc_l; char** argv_l=child->argv; char *name = child->argv[0];#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN /* Following discussions from November 2000 on the busybox mailing * list, the default configuration, (without * get_last_path_component()) lets the user force use of an * external command by specifying the full (with slashes) filename. * If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then applets * _aways_ override external commands, so if you want to run * /bin/cat, it will use BusyBox cat even if /bin/cat exists on the * filesystem and is _not_ busybox. Some systems may want this, * most do not. */ name = get_last_path_component(name);#endif /* Count argc for use in a second... */ for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++); optind = 1; debug_printf("running applet %s\n", name); run_applet_by_name(name, argc_l, child->argv); }#endif debug_printf("exec of %s\n",child->argv[0]); execvp(child->argv[0],child->argv); perror_msg("couldn't exec: %s",child->argv[0]); _exit(1); } else if (child->group) { debug_printf("runtime nesting to group\n"); interactive=0; /* crucial!!!! */ rcode = run_list_real(child->group); /* OK to leak memory by not calling free_pipe_list, * since this process is about to exit */ _exit(rcode); } else { /* Can happen. See what bash does with ">foo" by itself. */ debug_printf("trying to pseudo_exec null command\n"); _exit(EXIT_SUCCESS); }}static void insert_bg_job(struct pipe *pi){ struct pipe *thejob; /* Linear search for the ID of the job to use */ pi->jobid = 1; for (thejob = job_list; thejob; thejob = thejob->next) if (thejob->jobid >= pi->jobid) pi->jobid = thejob->jobid + 1; /* add thejob to the list of running jobs */ if (!job_list) { thejob = job_list = xmalloc(sizeof(*thejob)); } else { for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */; thejob->next = xmalloc(sizeof(*thejob)); thejob = thejob->next; } /* physically copy the struct job */ memcpy(thejob, pi, sizeof(struct pipe)); thejob->next = NULL; thejob->running_progs = thejob->num_progs; thejob->stopped_progs = 0; thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */ //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0]) { char *bar=thejob->text; char **foo=pi->progs[0].argv; while(foo && *foo) { bar += sprintf(bar, "%s ", *foo++); } } /* we don't wait for background thejobs to return -- append it to the list of backgrounded thejobs and leave it alone */ printf("[%d] %d\n", thejob->jobid, thejob->progs[0].pid); last_bg_pid = thejob->progs[0].pid; last_jobid = thejob->jobid;}/* remove a backgrounded job */static void remove_bg_job(struct pipe *pi){ struct pipe *prev_pipe; if (pi == job_list) { job_list = pi->next; } else { prev_pipe = job_list; while (prev_pipe->next != pi) prev_pipe = prev_pipe->next; prev_pipe->next = pi->next; } if (job_list) last_jobid = job_list->jobid; else last_jobid = 0; pi->stopped_progs = 0; free_pipe(pi, 0); free(pi);}/* Checks to see if any processes have exited -- if they have, figure out why and see if a job has completed */static int checkjobs(struct pipe* fg_pipe){ int attributes; int status; int prognum = 0; struct pipe *pi; pid_t childpid; attributes = WUNTRACED; if (fg_pipe==NULL) { attributes |= WNOHANG; } while ((childpid = waitpid(-1, &status, attributes)) > 0) { if (fg_pipe) { int i, rcode = 0; for (i=0; i < fg_pipe->num_progs; i++) { if (fg_pipe->progs[i].pid == childpid) { if (i==fg_pipe->num_progs-1) rcode=WEXITSTATUS(status); (fg_pipe->num_progs)--; return(rcode); } } } for (pi = job_list; pi; pi = pi->next) { prognum = 0; while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) { prognum++; } if (prognum < pi->num_progs) break; } debug_printf("checkjobs: pid %d was not in our list!\n", childpid); continue; } if (WIFEXITED(status) || WIFSIGNALED(status)) { /* child exited */ pi->running_progs--; pi->progs[prognum].pid = 0; if (!pi->running_progs) { printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text); remove_bg_job(pi); } } else { /* child stopped */ pi->stopped_progs++; pi->progs[prognum].is_stopped = 1;#if 0 /* Printing this stuff is a pain, since it tends to * overwrite the prompt an inconveinient moments. So * don't do that. */ if (pi->stopped_progs == pi->num_progs) { printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text); }#endif } } if (childpid == -1 && errno != ECHILD) perror_msg("waitpid"); /* move the shell to the foreground */ //if (interactive && tcsetpgrp(shell_terminal, getpgid(0))) // perror_msg("tcsetpgrp-2"); return -1;}/* Figure out our controlling tty, checking in order stderr, * stdin, and stdout. If check_pgrp is set, also check that * we belong to the foreground process group associated with * that tty. The value of shell_terminal is needed in order to call * tcsetpgrp(shell_terminal, ...); */void controlling_tty(int check_pgrp){ pid_t curpgrp; if ((curpgrp = tcgetpgrp(shell_terminal = 2)) < 0 && (curpgrp = tcgetpgrp(shell_terminal = 0)) < 0 && (curpgrp = tcgetpgrp(shell_terminal = 1)) < 0) goto shell_terminal_error; if (check_pgrp && curpgrp != getpgid(0)) goto shell_terminal_error; return;shell_terminal_error: shell_terminal = -1; return;}/* run_pipe_real() starts all the jobs, but doesn't wait for anything * to finish. See checkjobs(). * * return code is normally -1, when the caller has to wait for children * to finish to determine the exit status of the pipe. If the pipe * is a simple builtin command, however, the action is done by the * time run_pipe_real returns, and the exit code is provided as the * return value. * * The input of the pipe is always stdin, the output is always * stdout. The outpipe[] mechanism in BusyBox-0.48 lash is bogus, * because it tries to avoid running the command substitution in * subshell, when that is in fact necessary. The subshell process * now has its stdout directed to the input of the appropriate pipe, * so this routine is noticeably simpler. */static int run_pipe_real(struct pipe *pi){ int i; int nextin, nextout; int pipefds[2]; /* pipefds[0] is for reading */ struct child_prog *child; struct built_in_command *x; char *p;#if __GNUC__ /* Avoid longjmp clobbering */ (void) &i; (void) &nextin; (void) &nextout; (void) &child;#endif nextin = 0; pi->pgrp = -1; /* Check if this is a simple builtin (not part of a pipe). * Builtins within pipes have to fork anyway, and are handled in * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. */ if (pi->num_progs == 1) child = & (pi->progs[0]); if (pi->num_progs == 1 && child->group && child->subshell == 0) { int squirrel[] = {-1, -1, -1}; int rcode; debug_printf("non-subshell grouping\n"); setup_redirects(child, squirrel); /* XXX could we merge code with following builtin case, * by creating a pseudo builtin that calls run_list_real? */ rcode = run_list_real(child->group); restore_redirects(squirrel); return rcode; } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) { for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ } if (i!=0 && child->argv[i]==NULL) { /* assignments, but no command: set the local environment */ for (i=0; child->argv[i]!=NULL; i++) { /* Ok, this case is tricky. We have to decide if this is a * local variable, or an already exported variable. If it is * already exported, we have to export the new value. If it is * not exported, we need only set this as a local variable. * This junk is all to decide whether or not to export this * variable. */ int export_me=0; char *name, *value; name = xstrdup(child->argv[i]); debug_printf("Local environment set: %s\n", name); value = strchr(name, '='); if (value) *value=0; if ( get_local_var(name)) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -