📄 hush.c
字号:
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;}#endif/* 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;#ifndef __U_BOOT__ 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#else int nextin; int flag = do_repeat ? CMD_FLAG_REPEAT : 0; struct child_prog *child; cmd_tbl_t *cmdtp; char *p;# if __GNUC__ /* Avoid longjmp clobbering */ (void) &i; (void) &nextin; (void) &child;# endif#endif /* __U_BOOT__ */ nextin = 0;#ifndef __U_BOOT__ pi->pgrp = -1;#endif /* 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]);#ifndef __U_BOOT__ 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);#else if (pi->num_progs == 1 && child->group) { int rcode; debug_printf("non-subshell grouping\n"); rcode = run_list_real(child->group);#endif 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;#ifndef __U_BOOT__ if ( get_local_var(name)) { export_me=1; }#endif free(name); p = insert_var_value(child->argv[i]); set_local_var(p, export_me); if (p != child->argv[i]) free(p); } return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ } for (i = 0; is_assignment(child->argv[i]); i++) { p = insert_var_value(child->argv[i]);#ifndef __U_BOOT__ putenv(strdup(p));#else set_local_var(p, 0);#endif if (p != child->argv[i]) { child->sp--; free(p); } } if (child->sp) { char * str = NULL; str = make_string((child->argv + i)); parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING); free(str); return last_return_code; }#ifndef __U_BOOT__ for (x = bltins; x->cmd; x++) { if (strcmp(child->argv[i], x->cmd) == 0 ) { int squirrel[] = {-1, -1, -1}; int rcode; if (x->function == builtin_exec && child->argv[i+1]==NULL) { debug_printf("magic exec\n"); setup_redirects(child,NULL); return EXIT_SUCCESS; } debug_printf("builtin inline %s\n", child->argv[0]); /* XXX setup_redirects acts on file descriptors, not FILEs. * This is perfect for work that comes after exec(). * Is it really safe for inline use? Experimentally, * things seem to work with glibc. */ setup_redirects(child, squirrel);#else /* check ";", because ,example , argv consist from * "help;flinfo" must not execute */ if (strchr(child->argv[i], ';')) { printf ("Unknown command '%s' - try 'help' or use 'run' command\n", child->argv[i]); return -1; } /* Look up command in command table */ if ((cmdtp = find_cmd(child->argv[i])) == NULL) { printf ("Unknown command '%s' - try 'help'\n", child->argv[i]); return -1; /* give up after bad command */ } else { int rcode;#if defined(CONFIG_CMD_BOOTD) extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); /* avoid "bootd" recursion */ if (cmdtp->cmd == do_bootd) { if (flag & CMD_FLAG_BOOTD) { printf ("'bootd' recursion detected\n"); return -1; } else flag |= CMD_FLAG_BOOTD; }#endif /* found - check max args */ if ((child->argc - i) > cmdtp->maxargs) { printf ("Usage:\n%s\n", cmdtp->usage); return -1; }#endif child->argv+=i; /* XXX horrible hack */#ifndef __U_BOOT__ rcode = x->function(child);#else /* OK - call function to do the command */ rcode = (cmdtp->cmd)(cmdtp, flag,child->argc-i,&child->argv[i]); if ( !cmdtp->repeatable ) flag_repeat = 0;#endif child->argv-=i; /* XXX restore hack so free() can work right */#ifndef __U_BOOT__ restore_redirects(squirrel);#endif return rcode; } }#ifndef __U_BOOT__ } for (i = 0; i < pi->num_progs; i++) { child = & (pi->progs[i]); /* pipes are inserted between pairs of commands */ if ((i + 1) < pi->num_progs) { if (pipe(pipefds)<0) perror_msg_and_die("pipe"); nextout = pipefds[1]; } else { nextout=1; pipefds[0] = -1; } /* XXX test for failed fork()? */ if (!(child->pid = fork())) { /* Set the handling for job control signals back to the default. */ signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGTSTP, SIG_DFL); signal(SIGTTIN, SIG_DFL); signal(SIGTTOU, SIG_DFL); signal(SIGCHLD, SIG_DFL); close_all(); if (nextin != 0) { dup2(nextin, 0); close(nextin); } if (nextout != 1) { dup2(nextout, 1); close(nextout); } if (pipefds[0]!=-1) { close(pipefds[0]); /* opposite end of our output pipe */ } /* Like bash, explicit redirects override pipes, * and the pipe fd is available for dup'ing. */ setup_redirects(child,NULL); if (interactive && pi->followup!=PIPE_BG) { /* If we (the child) win the race, put ourselves in the process * group whose leader is the first process in this pipe. */ if (pi->pgrp < 0) { pi->pgrp = getpid(); } if (setpgid(0, pi->pgrp) == 0) { tcsetpgrp(2, pi->pgrp); } } pseudo_exec(child); } /* put our child in the process group whose leader is the first process in this pipe */ if (pi->pgrp < 0) { pi->pgrp = child->pid; } /* Don't check for errors. The child may be dead already, * in which case setpgid returns error code EACCES. */ setpgid(child->pid, pi->pgrp); if (nextin != 0) close(nextin); if (nextout != 1) close(nextout); /* If there isn't another process, nextin is garbage but it doesn't matter */ nextin = pipefds[0]; }#endif return -1;}static int run_list_real(struct pipe *pi){ char *save_name = NULL; char **list = NULL; char **save_list = NULL; struct pipe *rpipe; int flag_rep = 0;#ifndef __U_BOOT__ int save_num_progs;#endif int rcode=0, flag_skip=1; int flag_restore = 0; int if_code=0, next_if_code=0; /* need double-buffer to handle elif */ reserved_style rmode, skip_more_in_this_rmode=RES_XXXX; /* check syntax for "for" */ for (rpipe = pi; rpipe; rpipe = rpipe->next) { if ((rpipe->r_mode == RES_IN || rpipe->r_mode == RES_FOR) && (rpipe->next == NULL)) { syntax();#ifdef __U_BOOT__ flag_repeat = 0;#endif return 1; } if ((rpipe->r_mode == RES_IN && (rpipe->next->r_mode == RES_IN && rpipe->next->progs->argv != NULL))|| (rpipe->r_mode == RES_FOR && rpipe->next->r_mode != RES_IN)) { syntax();#ifdef __U_BOOT__ flag_repeat = 0;#endif return 1; } } for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) { if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL || pi->r_mode == RES_FOR) {#ifdef __U_BOOT__ /* check Ctrl-C */ ctrlc(); if ((had_ctrlc())) { return 1; }#endif flag_restore = 0; if (!rpipe) { flag_rep = 0; rpipe = pi; } } rmode = pi->r_mode; debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode); if (rmode == skip_more_in_this_rmode && flag_skip) { if (pi->followup == PIPE_SEQ) flag_skip=0; continue; } flag_skip = 1; skip_more_in_this_rmode = RES_XXXX; if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code; if (rmode == RES_THEN && if_code) continue; if (rmode == RES_ELSE && !if_code) continue; if (rmode == RES_ELIF && !if_code) break; if (rmode == RES_FOR && pi->num_progs) { if (!list) { /* if no variable values after "in" we skip "for" */ if (!pi->next->progs->argv) continue; /* create list of variable values */ list = make_list_in(pi->next->progs->argv, pi->progs->argv[0]); save_list = list; save_name = pi->progs->argv[0]; pi->progs->argv[0] = NULL; flag_rep = 1; } if (!(*list)) { free(pi->progs->argv[0]); free(save_list); list = NULL; flag_rep = 0; pi->progs->argv[0] = save_name;#ifndef __U_BOOT__ pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0];#endif continue; } else { /* insert new value from list for variable */ if (pi->progs->argv[0]) free(pi->progs->argv[0]); pi->progs->argv[0] = *list++;#ifndef __U_BOOT__ pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0];#endif } } if (rmode == RES_IN) continue; if (rmode == RES_DO) { if (!flag_rep) continue; } if ((rmode == RES_DONE)) { if (flag_rep) { flag_restore = 1; } else { rpipe = NULL; } } if (pi->num_progs == 0) continue;#ifndef __U_BOOT__ save_num_progs = pi->num_progs; /* save number of programs */#endif rcode = run_pipe_real(pi); debug_printf("run_pipe_real returned %d\n",rcode);#ifndef __U_BOOT__ if (rcode!=-1) { /* We only ran a builtin: rcode was set by the return value * of run_pipe_real(), and we don't need to wait for anything. */ } else if (pi->followup==PIPE_BG) { /* XXX check bash's behavior with nontrivial pipes */ /* XXX compute jobid */ /* XXX what does bash do with attempts to background builtins? */ insert_bg_job(pi); rcode = EXIT_SUCCESS; } else { if (interactive) { /* move the new process group into the foreground */ if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY) perror_msg("tcsetpgrp-3"); rcode = checkjobs(pi); /* move the shell to the foreground */ if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY) perror_msg("tcsetpgrp-4"); } else { rcode = checkjobs(pi); } debug_printf("checkjobs returned %d\n",rcode); } last_return_code=rcode;#else if (rcode < -1) { last_return_code = -rcode - 2; return -2; /* exit */ } last_return_code=(rcode == 0) ? 0 : 1;#endif#ifndef __U_BOOT__ pi->num_progs = save_num_progs; /* restore number of programs */#endif if ( rmode == RES_IF || rmode == RES_ELIF ) next_if_code=rcode; /* can be overwritten a number of times */ if (rmode == RES_WHILE) flag_rep = !last_return_code;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -