📄 execute_cmd.c
字号:
coproc_fdrestore (cp) struct coproc *cp;{ cp->c_rfd = cp->c_rsave; cp->c_wfd = cp->c_wsave;}voidcoproc_pidchk (pid, status) pid_t pid;{ struct coproc *cp; cp = getcoprocbypid (pid);#if 0 if (cp) itrace("coproc_pidchk: pid %d has died", pid);#endif if (cp) { cp->c_status = status; cp->c_flags |= COPROC_DEAD; cp->c_flags &= ~COPROC_RUNNING;#if 0 coproc_dispose (cp);#endif }}voidcoproc_setvars (cp) struct coproc *cp;{ SHELL_VAR *v; char *namevar, *t; int l;#if defined (ARRAY_VARS) arrayind_t ind;#endif if (cp->c_name == 0) return; l = strlen (cp->c_name); namevar = xmalloc (l + 16);#if defined (ARRAY_VARS) v = find_variable (cp->c_name); if (v == 0) v = make_new_array_variable (cp->c_name); if (array_p (v) == 0) v = convert_var_to_array (v); t = itos (cp->c_rfd); ind = 0; v = bind_array_variable (cp->c_name, ind, t, 0); free (t); t = itos (cp->c_wfd); ind = 1; bind_array_variable (cp->c_name, ind, t, 0); free (t);#else sprintf (namevar, "%s_READ", cp->c_name); t = itos (cp->c_rfd); bind_variable (namevar, t, 0); free (t); sprintf (namevar, "%s_WRITE", cp->c_name); t = itos (cp->c_wfd); bind_variable (namevar, t, 0); free (t);#endif sprintf (namevar, "%s_PID", cp->c_name); t = itos (cp->c_pid); bind_variable (namevar, t, 0); free (t); free (namevar);}voidcoproc_unsetvars (cp) struct coproc *cp;{ int l; char *namevar; if (cp->c_name == 0) return; l = strlen (cp->c_name); namevar = xmalloc (l + 16); sprintf (namevar, "%s_PID", cp->c_name); unbind_variable (namevar); #if defined (ARRAY_VARS) unbind_variable (cp->c_name);#else sprintf (namevar, "%s_READ", cp->c_name); unbind_variable (namevar); sprintf (namevar, "%s_WRITE", cp->c_name); unbind_variable (namevar);#endif free (namevar);}static intexecute_coproc (command, pipe_in, pipe_out, fds_to_close) COMMAND *command; int pipe_in, pipe_out; struct fd_bitmap *fds_to_close;{ int rpipe[2], wpipe[2], estat; pid_t coproc_pid; Coproc *cp; char *tcmd; /* XXX -- will require changes to handle multiple coprocs */ if (sh_coproc.c_pid != NO_PID) {#if 0 internal_error ("execute_coproc: coproc [%d:%s] already exists", sh_coproc.c_pid, sh_coproc.c_name); return (last_command_exit_value = EXECUTION_FAILURE);#else internal_warning ("execute_coproc: coproc [%d:%s] still exists", sh_coproc.c_pid, sh_coproc.c_name);#endif } coproc_init (&sh_coproc); command_string_index = 0; tcmd = make_command_string (command); sh_openpipe ((int *)&rpipe); /* 0 = parent read, 1 = child write */ sh_openpipe ((int *)&wpipe); /* 0 = child read, 1 = parent write */ coproc_pid = make_child (savestring (tcmd), 1); if (coproc_pid == 0) { close (rpipe[0]); close (wpipe[1]); estat = execute_in_subshell (command, 1, wpipe[0], rpipe[1], fds_to_close); fflush (stdout); fflush (stderr); exit (estat); } close (rpipe[1]); close (wpipe[0]); cp = coproc_alloc (command->value.Coproc->name, coproc_pid); cp->c_rfd = rpipe[0]; cp->c_wfd = wpipe[1]; SET_CLOSE_ON_EXEC (cp->c_rfd); SET_CLOSE_ON_EXEC (cp->c_wfd); coproc_setvars (cp);#if 0 itrace ("execute_coproc: [%d] %s", coproc_pid, the_printed_command);#endif close_pipes (pipe_in, pipe_out);#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD) unlink_fifo_list ();#endif stop_pipeline (1, (COMMAND *)NULL); DESCRIBE_PID (coproc_pid); run_pending_traps (); return (EXECUTION_SUCCESS);}#endifstatic voidrestore_stdin (s) int s;{ dup2 (s, 0); close (s);}/* Catch-all cleanup function for lastpipe code for unwind-protects */static voidlastpipe_cleanup (s) int s;{ unfreeze_jobs_list ();}static intexecute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close) COMMAND *command; int asynchronous, pipe_in, pipe_out; struct fd_bitmap *fds_to_close;{ int prev, fildes[2], new_bitmap_size, dummyfd, ignore_return, exec_result; int lstdin, lastpipe_flag, lastpipe_jid; COMMAND *cmd; struct fd_bitmap *fd_bitmap; pid_t lastpid;#if defined (JOB_CONTROL) sigset_t set, oset; BLOCK_CHILD (set, oset);#endif /* JOB_CONTROL */ ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; prev = pipe_in; cmd = command; while (cmd && cmd->type == cm_connection && cmd->value.Connection && cmd->value.Connection->connector == '|') { /* Make a pipeline between the two commands. */ if (pipe (fildes) < 0) { sys_error (_("pipe error"));#if defined (JOB_CONTROL) terminate_current_pipeline (); kill_current_pipeline (); UNBLOCK_CHILD (oset);#endif /* JOB_CONTROL */ last_command_exit_value = EXECUTION_FAILURE; /* The unwind-protects installed below will take care of closing all of the open file descriptors. */ throw_to_top_level (); return (EXECUTION_FAILURE); /* XXX */ } /* Here is a problem: with the new file close-on-exec code, the read end of the pipe (fildes[0]) stays open in the first process, so that process will never get a SIGPIPE. There is no way to signal the first process that it should close fildes[0] after forking, so it remains open. No SIGPIPE is ever sent because there is still a file descriptor open for reading connected to the pipe. We take care of that here. This passes around a bitmap of file descriptors that must be closed after making a child process in execute_simple_command. */ /* We need fd_bitmap to be at least as big as fildes[0]. If fildes[0] is less than fds_to_close->size, then use fds_to_close->size. */ new_bitmap_size = (fildes[0] < fds_to_close->size) ? fds_to_close->size : fildes[0] + 8; fd_bitmap = new_fd_bitmap (new_bitmap_size); /* Now copy the old information into the new bitmap. */ xbcopy ((char *)fds_to_close->bitmap, (char *)fd_bitmap->bitmap, fds_to_close->size); /* And mark the pipe file descriptors to be closed. */ fd_bitmap->bitmap[fildes[0]] = 1; /* In case there are pipe or out-of-processes errors, we want all these file descriptors to be closed when unwind-protects are run, and the storage used for the bitmaps freed up. */ begin_unwind_frame ("pipe-file-descriptors"); add_unwind_protect (dispose_fd_bitmap, fd_bitmap); add_unwind_protect (close_fd_bitmap, fd_bitmap); if (prev >= 0) add_unwind_protect (close, prev); dummyfd = fildes[1]; add_unwind_protect (close, dummyfd);#if defined (JOB_CONTROL) add_unwind_protect (restore_signal_mask, &oset);#endif /* JOB_CONTROL */ if (ignore_return && cmd->value.Connection->first) cmd->value.Connection->first->flags |= CMD_IGNORE_RETURN; execute_command_internal (cmd->value.Connection->first, asynchronous, prev, fildes[1], fd_bitmap); if (prev >= 0) close (prev); prev = fildes[0]; close (fildes[1]); dispose_fd_bitmap (fd_bitmap); discard_unwind_frame ("pipe-file-descriptors"); cmd = cmd->value.Connection->second; } lastpid = last_made_pid; /* Now execute the rightmost command in the pipeline. */ if (ignore_return && cmd) cmd->flags |= CMD_IGNORE_RETURN; lastpipe_flag = 0; begin_unwind_frame ("lastpipe-exec"); lstdin = -1; /* If the `lastpipe' option is set with shopt, and job control is not enabled, execute the last element of non-async pipelines in the current shell environment. */ if (lastpipe_opt && job_control == 0 && asynchronous == 0 && pipe_out == NO_PIPE && prev > 0) { lstdin = move_to_high_fd (0, 0, 255); if (lstdin > 0) { do_piping (prev, pipe_out); prev = NO_PIPE; add_unwind_protect (restore_stdin, lstdin); lastpipe_flag = 1; freeze_jobs_list (); lastpipe_jid = stop_pipeline (0, (COMMAND *)NULL); /* XXX */ add_unwind_protect (lastpipe_cleanup, lastpipe_jid); } cmd->flags |= CMD_LASTPIPE; } if (prev >= 0) add_unwind_protect (close, prev); exec_result = execute_command_internal (cmd, asynchronous, prev, pipe_out, fds_to_close); if (lstdin > 0) restore_stdin (lstdin); if (prev >= 0) close (prev);#if defined (JOB_CONTROL) UNBLOCK_CHILD (oset);#endif QUIT; if (lastpipe_flag) {#if defined (JOB_CONTROL) append_process (savestring (the_printed_command), dollar_dollar_pid, exec_result, lastpipe_jid);#endif lstdin = wait_for (lastpid);#if defined (JOB_CONTROL) exec_result = job_exit_status (lastpipe_jid);#endif unfreeze_jobs_list (); } discard_unwind_frame ("lastpipe-exec"); return (exec_result);}static intexecute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close) COMMAND *command; int asynchronous, pipe_in, pipe_out; struct fd_bitmap *fds_to_close;{ COMMAND *tc, *second; int ignore_return, exec_result, was_error_trap, invert; volatile int save_line_number; ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; switch (command->value.Connection->connector) { /* Do the first command asynchronously. */ case '&': tc = command->value.Connection->first; if (tc == 0) return (EXECUTION_SUCCESS); if (ignore_return) tc->flags |= CMD_IGNORE_RETURN; tc->flags |= CMD_AMPERSAND; /* If this shell was compiled without job control support, if we are currently in a subshell via `( xxx )', or if job control is not active then the standard input for an asynchronous command is forced to /dev/null. */#if defined (JOB_CONTROL) if ((subshell_environment || !job_control) && !stdin_redir)#else if (!stdin_redir)#endif /* JOB_CONTROL */ tc->flags |= CMD_STDIN_REDIR; exec_result = execute_command_internal (tc, 1, pipe_in, pipe_out, fds_to_close); QUIT; if (tc->flags & CMD_STDIN_REDIR) tc->flags &= ~CMD_STDIN_REDIR; second = command->value.Connection->second; if (second) { if (ignore_return) second->flags |= CMD_IGNORE_RETURN; exec_result = execute_command_internal (second, asynchronous, pipe_in, pipe_out, fds_to_close); } break; /* Just call execute command on both sides. */ case ';': if (ignore_return) { if (command->value.Connection->first) command->value.Connection->first->flags |= CMD_IGNORE_RETURN; if (command->value.Connection->second) command->value.Connection->second->flags |= CMD_IGNORE_RETURN; } executing_list++; QUIT; execute_command (command->value.Connection->first); QUIT; exec_result = execute_command_internal (command->value.Connection->second, asynchronous, pipe_in, pipe_out, fds_to_close); executing_list--; break; case '|': was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0; invert = (command->flags & CMD_INVERT_RETURN) != 0; ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0; line_number_for_err_trap = line_number; exec_result = execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close); if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS) { last_command_exit_value = exec_result; save_line_number = line_number; line_number = line_number_for_err_trap; run_error_trap (); line_number = save_line_number; } if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS) { last_command_exit_value = exec_result; run_pending_traps (); jump_to_top_level (ERREXIT); } break; case AND_AND: case OR_OR: if (asynchronous) { /* If we have something like `a && b &' or `a || b &', run the && or || stuff in a subshell. Force a subshell and just call execute_command_internal again. Leave asynchronous on so that we get a report from the parent shell about the background job. */ command->flags |= CMD_FORCE_SUBSHELL; exec_result = execute_command_internal (command, 1, pipe_in, pipe_out, fds_to_close); break; } /* Execute the first command. If the result of that is successful and the connector is AND_AND, or the result is not succes
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -