📄 redir.c
字号:
* both sh and ksh leave the file descriptors open across execs. * The Posix standard mentions only the exec builtin. */ if ((flags & RX_CLEXEC) && (redirector > 2)) SET_CLOSE_ON_EXEC (redirector); } if (fd != redirector) {#if defined (BUFFERED_INPUT) if (INPUT_REDIRECT (ri)) close_buffered_fd (fd); else#endif /* !BUFFERED_INPUT */ close (fd); /* Don't close what we just opened! */ } /* If we are hacking both stdout and stderr, do the stderr redirection here. XXX - handle {var} here? */ if (ri == r_err_and_out || ri == r_append_err_and_out) { if (flags & RX_ACTIVE) { if (flags & RX_UNDOABLE) add_undo_redirect (2, ri, -1); if (dup2 (1, 2) < 0) return (errno); } } break; case r_reading_until: case r_deblank_reading_until: case r_reading_string: /* REDIRECTEE is a pointer to a WORD_DESC containing the text of the new input. Place it in a temporary file. */ if (redirectee) { fd = here_document_to_fd (redirectee, ri); if (fd < 0) { heredoc_errno = errno; return (HEREDOC_REDIRECT); } if (redirect->rflags & REDIR_VARASSIGN) { redirector = fcntl (fd, F_DUPFD, SHELL_FD_BASE); /* XXX try this for now */ r = errno; if (redirector < 0) sys_error (_("redirection error: cannot duplicate fd")); REDIRECTION_ERROR (redirector, r, fd); } if (flags & RX_ACTIVE) { if (flags & RX_UNDOABLE) { /* Only setup to undo it if the thing to undo is active. */ if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1)) r = add_undo_redirect (redirector, ri, -1); else r = add_undo_close_redirect (redirector); if (r < 0 && (redirect->rflags & REDIR_VARASSIGN)) close (redirector); REDIRECTION_ERROR (r, errno, fd); }#if defined (BUFFERED_INPUT) check_bash_input (redirector);#endif if (redirect->rflags & REDIR_VARASSIGN) { if ((r = redir_varassign (redirect, redirector)) < 0) { close (redirector); close (fd); return (r); /* XXX */ } } else if (fd != redirector && dup2 (fd, redirector) < 0) { r = errno; close (fd); return (r); }#if defined (BUFFERED_INPUT) duplicate_buffered_stream (fd, redirector);#endif if ((flags & RX_CLEXEC) && (redirector > 2)) SET_CLOSE_ON_EXEC (redirector); } if (fd != redirector)#if defined (BUFFERED_INPUT) close_buffered_fd (fd);#else close (fd);#endif } break; case r_duplicating_input: case r_duplicating_output: case r_move_input: case r_move_output: if ((flags & RX_ACTIVE) && (redirect->rflags & REDIR_VARASSIGN)) { redirector = fcntl (redir_fd, F_DUPFD, SHELL_FD_BASE); /* XXX try this for now */ r = errno; if (redirector < 0) sys_error (_("redirection error: cannot duplicate fd")); REDIRECTION_ERROR (redirector, r, -1); } if ((flags & RX_ACTIVE) && (redir_fd != redirector)) { if (flags & RX_UNDOABLE) { /* Only setup to undo it if the thing to undo is active. */ if (fcntl (redirector, F_GETFD, 0) != -1) r = add_undo_redirect (redirector, ri, redir_fd); else r = add_undo_close_redirect (redirector); if (r < 0 && (redirect->rflags & REDIR_VARASSIGN)) close (redirector); REDIRECTION_ERROR (r, errno, -1); }#if defined (BUFFERED_INPUT) check_bash_input (redirector);#endif if (redirect->rflags & REDIR_VARASSIGN) { if ((r = redir_varassign (redirect, redirector)) < 0) { close (redirector); return (r); /* XXX */ } } /* This is correct. 2>&1 means dup2 (1, 2); */ else if (dup2 (redir_fd, redirector) < 0) return (errno);#if defined (BUFFERED_INPUT) if (ri == r_duplicating_input || ri == r_move_input) duplicate_buffered_stream (redir_fd, redirector);#endif /* BUFFERED_INPUT */ /* First duplicate the close-on-exec state of redirectee. dup2 leaves the flag unset on the new descriptor, which means it stays open. Only set the close-on-exec bit for file descriptors greater than 2 in any case, since 0-2 should always be open unless closed by something like `exec 2<&-'. It should always be safe to set fds > 2 to close-on-exec if they're being used to save file descriptors < 2, since we don't need to preserve the state of the close-on-exec flag for those fds -- they should always be open. */ /* if ((already_set || set_unconditionally) && (ok_to_set)) set_it () */#if 0 if (((fcntl (redir_fd, F_GETFD, 0) == 1) || redir_fd < 2 || (flags & RX_CLEXEC)) && (redirector > 2))#else if (((fcntl (redir_fd, F_GETFD, 0) == 1) || (redir_fd < 2 && (flags & RX_INTERNAL)) || (flags & RX_CLEXEC)) && (redirector > 2))#endif SET_CLOSE_ON_EXEC (redirector); /* When undoing saving of non-standard file descriptors (>=3) using file descriptors >= SHELL_FD_BASE, we set the saving fd to be close-on-exec and use a flag to decide how to set close-on-exec when the fd is restored. */ if ((redirect->flags & RX_INTERNAL) && (redirect->flags & RX_SAVCLEXEC) && redirector >= 3 && redir_fd >= SHELL_FD_BASE) SET_OPEN_ON_EXEC (redirector); /* dup-and-close redirection */ if (ri == r_move_input || ri == r_move_output) { xtrace_fdchk (redir_fd); close (redir_fd);#if defined (COPROCESS_SUPPORT) coproc_fdchk (redir_fd); /* XXX - loses coproc fds */#endif } } break; case r_close_this: if (flags & RX_ACTIVE) { if (redirect->rflags & REDIR_VARASSIGN) { redirector = redir_varvalue (redirect); if (redirector < 0) return AMBIGUOUS_REDIRECT; } r = 0; if ((flags & RX_UNDOABLE) && (fcntl (redirector, F_GETFD, 0) != -1)) { r = add_undo_redirect (redirector, ri, -1); REDIRECTION_ERROR (r, errno, redirector); }#if defined (COPROCESS_SUPPORT) coproc_fdchk (redirector);#endif xtrace_fdchk (redirector);#if defined (BUFFERED_INPUT) check_bash_input (redirector); close_buffered_fd (redirector);#else /* !BUFFERED_INPUT */ close (redirector);#endif /* !BUFFERED_INPUT */ } break; case r_duplicating_input_word: case r_duplicating_output_word: break; } return (0);}/* Remember the file descriptor associated with the slot FD, on REDIRECTION_UNDO_LIST. Note that the list will be reversed before it is executed. Any redirections that need to be undone even if REDIRECTION_UNDO_LIST is discarded by the exec builtin are also saved on EXEC_REDIRECTION_UNDO_LIST. FDBASE says where to start the duplicating. If it's less than SHELL_FD_BASE, we're ok, and can use SHELL_FD_BASE (-1 == don't care). If it's >= SHELL_FD_BASE, we have to make sure we don't use fdbase to save a file descriptor, since we're going to use it later (e.g., make sure we don't save fd 0 to fd 10 if we have a redirection like 0<&10). If the value of fdbase puts the process over its fd limit, causing fcntl to fail, we try again with SHELL_FD_BASE. Return 0 on success, -1 on error. */static intadd_undo_redirect (fd, ri, fdbase) int fd; enum r_instruction ri; int fdbase;{ int new_fd, clexec_flag; REDIRECT *new_redirect, *closer, *dummy_redirect; REDIRECTEE sd; new_fd = fcntl (fd, F_DUPFD, (fdbase < SHELL_FD_BASE) ? SHELL_FD_BASE : fdbase+1); if (new_fd < 0) new_fd = fcntl (fd, F_DUPFD, SHELL_FD_BASE); if (new_fd < 0) { sys_error (_("redirection error: cannot duplicate fd")); return (-1); } clexec_flag = fcntl (fd, F_GETFD, 0); sd.dest = new_fd; rd.dest = 0; closer = make_redirection (sd, r_close_this, rd, 0); closer->flags |= RX_INTERNAL; dummy_redirect = copy_redirects (closer); sd.dest = fd; rd.dest = new_fd; if (fd == 0) new_redirect = make_redirection (sd, r_duplicating_input, rd, 0); else new_redirect = make_redirection (sd, r_duplicating_output, rd, 0); new_redirect->flags |= RX_INTERNAL; if (clexec_flag == 0 && fd >= 3 && new_fd >= SHELL_FD_BASE) new_redirect->flags |= RX_SAVCLEXEC; new_redirect->next = closer; closer->next = redirection_undo_list; redirection_undo_list = new_redirect; /* Save redirections that need to be undone even if the undo list is thrown away by the `exec' builtin. */ add_exec_redirect (dummy_redirect); /* experimental: if we're saving a redirection to undo for a file descriptor above SHELL_FD_BASE, add a redirection to be undone if the exec builtin causes redirections to be discarded. There needs to be a difference between fds that are used to save other fds and then are the target of user redirections and fds that are just the target of user redirections. We use the close-on-exec flag to tell the difference; fds > SHELL_FD_BASE that have the close-on-exec flag set are assumed to be fds used internally to save others. */ if (fd >= SHELL_FD_BASE && ri != r_close_this && clexec_flag) { sd.dest = fd; rd.dest = new_fd; new_redirect = make_redirection (sd, r_duplicating_output, rd, 0); new_redirect->flags |= RX_INTERNAL; add_exec_redirect (new_redirect); } /* File descriptors used only for saving others should always be marked close-on-exec. Unfortunately, we have to preserve the close-on-exec state of the file descriptor we are saving, since fcntl (F_DUPFD) sets the new file descriptor to remain open across execs. If, however, the file descriptor whose state we are saving is <= 2, we can just set the close-on-exec flag, because file descriptors 0-2 should always be open-on-exec, and the restore above in do_redirection() will take care of it. */ if (clexec_flag || fd < 3) SET_CLOSE_ON_EXEC (new_fd); else if (redirection_undo_list->flags & RX_SAVCLEXEC) SET_CLOSE_ON_EXEC (new_fd); return (0);}/* Set up to close FD when we are finished with the current command and its redirections. Return 0 on success, -1 on error. */static intadd_undo_close_redirect (fd) int fd;{ REDIRECT *closer; REDIRECTEE sd; sd.dest = fd; rd.dest = 0; closer = make_redirection (sd, r_close_this, rd, 0); closer->flags |= RX_INTERNAL; closer->next = redirection_undo_list; redirection_undo_list = closer; return 0;}static voidadd_exec_redirect (dummy_redirect) REDIRECT *dummy_redirect;{ dummy_redirect->next = exec_redirection_undo_list; exec_redirection_undo_list = dummy_redirect;}/* Return 1 if the redirection specified by RI and REDIRECTOR alters the standard input. */static intstdin_redirection (ri, redirector) enum r_instruction ri; int redirector;{ switch (ri) { case r_input_direction: case r_inputa_direction: case r_input_output: case r_reading_until: case r_deblank_reading_until: case r_reading_string: return (1); case r_duplicating_input: case r_duplicating_input_word: case r_close_this: return (redirector == 0); case r_output_direction: case r_appending_to: case r_duplicating_output: case r_err_and_out: case r_append_err_and_out: case r_output_force: case r_duplicating_output_word: return (0); } return (0);}/* Return non-zero if any of the redirections in REDIRS alter the standard input. */intstdin_redirects (redirs) REDIRECT *redirs;{ REDIRECT *rp; int n; for (n = 0, rp = redirs; rp; rp = rp->next) if ((rp->rflags & REDIR_VARASSIGN) == 0) n += stdin_redirection (rp->instruction, rp->redirector.dest); return n;}/* These don't yet handle array references */static intredir_varassign (redir, fd) REDIRECT *redir; int fd;{ WORD_DESC *w; SHELL_VAR *v; w = redir->redirector.filename; v = bind_var_to_int (w->word, fd); if (v == 0 || readonly_p (v) || noassign_p (v)) return BADVAR_REDIRECT; return 0;}static intredir_varvalue (redir) REDIRECT *redir;{ SHELL_VAR *v; char *val; intmax_t vmax; int i; /* XXX - handle set -u here? */ v = find_variable (redir->redirector.filename->word); if (v == 0 || invisible_p (v)) return -1; val = get_variable_value (v); if (val == 0 || *val == 0) return -1; if (legal_number (val, &vmax) < 0) return -1; i = vmax; /* integer truncation */ return i;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -