redir.c
来自「android-w.song.android.widget」· C语言 代码 · 共 1,315 行 · 第 1/3 页
C
1,315 行
if (r) { close (fd); unlink (filename); free (filename); errno = r; return (-1); } /* In an attempt to avoid races, we close the first fd only after opening the second. */ /* Make the document really temporary. Also make it the input. */ fd2 = open (filename, O_RDONLY|O_BINARY, 0600); if (fd2 < 0) { r = errno; unlink (filename); free (filename); close (fd); errno = r; return -1; } close (fd); if (unlink (filename) < 0) { r = errno; close (fd2); free (filename); errno = r; return (-1); } free (filename); return (fd2);}#define RF_DEVFD 1#define RF_DEVSTDERR 2#define RF_DEVSTDIN 3#define RF_DEVSTDOUT 4#define RF_DEVTCP 5#define RF_DEVUDP 6/* A list of pattern/value pairs for filenames that the redirection code handles specially. */static STRING_INT_ALIST _redir_special_filenames[] = {#if !defined (HAVE_DEV_FD) { "/dev/fd/[0-9]*", RF_DEVFD },#endif#if !defined (HAVE_DEV_STDIN) { "/dev/stderr", RF_DEVSTDERR }, { "/dev/stdin", RF_DEVSTDIN }, { "/dev/stdout", RF_DEVSTDOUT },#endif#if defined (NETWORK_REDIRECTIONS) { "/dev/tcp/*/*", RF_DEVTCP }, { "/dev/udp/*/*", RF_DEVUDP },#endif { (char *)NULL, -1 }};static intredir_special_open (spec, filename, flags, mode, ri) int spec; char *filename; int flags, mode; enum r_instruction ri;{ int fd;#if !defined (HAVE_DEV_FD) intmax_t lfd;#endif fd = -1; switch (spec) {#if !defined (HAVE_DEV_FD) case RF_DEVFD: if (all_digits (filename+8) && legal_number (filename+8, &lfd) && lfd == (int)lfd) { fd = lfd; fd = fcntl (fd, F_DUPFD, SHELL_FD_BASE); } else fd = AMBIGUOUS_REDIRECT; break;#endif#if !defined (HAVE_DEV_STDIN) case RF_DEVSTDIN: fd = fcntl (0, F_DUPFD, SHELL_FD_BASE); break; case RF_DEVSTDOUT: fd = fcntl (1, F_DUPFD, SHELL_FD_BASE); break; case RF_DEVSTDERR: fd = fcntl (2, F_DUPFD, SHELL_FD_BASE); break;#endif#if defined (NETWORK_REDIRECTIONS) case RF_DEVTCP: case RF_DEVUDP:#if defined (HAVE_NETWORK) fd = netopen (filename);#else internal_warning (_("/dev/(tcp|udp)/host/port not supported without networking")); fd = open (filename, flags, mode);#endif break;#endif /* NETWORK_REDIRECTIONS */ } return fd;} /* Open FILENAME with FLAGS in noclobber mode, hopefully avoiding most race conditions and avoiding the problem where the file is replaced between the stat(2) and open(2). */static intnoclobber_open (filename, flags, mode, ri) char *filename; int flags, mode; enum r_instruction ri;{ int r, fd; struct stat finfo, finfo2; /* If the file exists and is a regular file, return an error immediately. */ r = stat (filename, &finfo); if (r == 0 && (S_ISREG (finfo.st_mode))) return (NOCLOBBER_REDIRECT); /* If the file was not present (r != 0), make sure we open it exclusively so that if it is created before we open it, our open will fail. Make sure that we do not truncate an existing file. Note that we don't turn on O_EXCL unless the stat failed -- if the file was not a regular file, we leave O_EXCL off. */ flags &= ~O_TRUNC; if (r != 0) { fd = open (filename, flags|O_EXCL, mode); return ((fd < 0 && errno == EEXIST) ? NOCLOBBER_REDIRECT : fd); } fd = open (filename, flags, mode); /* If the open failed, return the file descriptor right away. */ if (fd < 0) return (errno == EEXIST ? NOCLOBBER_REDIRECT : fd); /* OK, the open succeeded, but the file may have been changed from a non-regular file to a regular file between the stat and the open. We are assuming that the O_EXCL open handles the case where FILENAME did not exist and is symlinked to an existing file between the stat and open. */ /* If we can open it and fstat the file descriptor, and neither check revealed that it was a regular file, and the file has not been replaced, return the file descriptor. */ if ((fstat (fd, &finfo2) == 0) && (S_ISREG (finfo2.st_mode) == 0) && r == 0 && (S_ISREG (finfo.st_mode) == 0) && same_file (filename, filename, &finfo, &finfo2)) return fd; /* The file has been replaced. badness. */ close (fd); errno = EEXIST; return (NOCLOBBER_REDIRECT);}static intredir_open (filename, flags, mode, ri) char *filename; int flags, mode; enum r_instruction ri;{ int fd, r; r = find_string_in_alist (filename, _redir_special_filenames, 1); if (r >= 0) return (redir_special_open (r, filename, flags, mode, ri)); /* If we are in noclobber mode, you are not allowed to overwrite existing files. Check before opening. */ if (noclobber && CLOBBERING_REDIRECT (ri)) { fd = noclobber_open (filename, flags, mode, ri); if (fd == NOCLOBBER_REDIRECT) return (NOCLOBBER_REDIRECT); } else { fd = open (filename, flags, mode);#if defined (AFS) if ((fd < 0) && (errno == EACCES)) { fd = open (filename, flags & ~O_CREAT, mode); errno = EACCES; /* restore errno */ }#endif /* AFS */ } return fd;}static intundoablefd (fd) int fd;{ int clexec; clexec = fcntl (fd, F_GETFD, 0); if (clexec == -1 || (fd >= SHELL_FD_BASE && clexec == 1)) return 0; return 1;}/* Do the specific redirection requested. Returns errno or one of the special redirection errors (*_REDIRECT) in case of error, 0 on success. If flags & RX_ACTIVE is zero, then just do whatever is neccessary to produce the appropriate side effects. flags & RX_UNDOABLE, if non-zero, says to remember how to undo each redirection. If flags & RX_CLEXEC is non-zero, then we set all file descriptors > 2 that we open to be close-on-exec. */static intdo_redirection_internal (redirect, flags) REDIRECT *redirect; int flags;{ WORD_DESC *redirectee; int redir_fd, fd, redirector, r, oflags; intmax_t lfd; char *redirectee_word; enum r_instruction ri; REDIRECT *new_redirect; REDIRECTEE sd; redirectee = redirect->redirectee.filename; redir_fd = redirect->redirectee.dest; redirector = redirect->redirector.dest; ri = redirect->instruction; if (redirect->flags & RX_INTERNAL) flags |= RX_INTERNAL; if (TRANSLATE_REDIRECT (ri)) { /* We have [N]>&WORD[-] or [N]<&WORD[-] (or {V}>&WORD[-] or {V}<&WORD-). and WORD, then translate the redirection into a new one and continue. */ redirectee_word = redirection_expand (redirectee); /* XXX - what to do with [N]<&$w- where w is unset or null? ksh93 closes N. */ if (redirectee_word == 0) return (AMBIGUOUS_REDIRECT); else if (redirectee_word[0] == '-' && redirectee_word[1] == '\0') { sd = redirect->redirector; rd.dest = 0; new_redirect = make_redirection (sd, r_close_this, rd, 0); } else if (all_digits (redirectee_word)) { sd = redirect->redirector; if (legal_number (redirectee_word, &lfd) && (int)lfd == lfd) rd.dest = lfd; else rd.dest = -1; /* XXX */ switch (ri) { case r_duplicating_input_word: new_redirect = make_redirection (sd, r_duplicating_input, rd, 0); break; case r_duplicating_output_word: new_redirect = make_redirection (sd, r_duplicating_output, rd, 0); break; case r_move_input_word: new_redirect = make_redirection (sd, r_move_input, rd, 0); break; case r_move_output_word: new_redirect = make_redirection (sd, r_move_output, rd, 0); break; } } else if (ri == r_duplicating_output_word && (redirect->rflags & REDIR_VARASSIGN) == 0 && redirector == 1) { sd = redirect->redirector; rd.filename = make_bare_word (redirectee_word); new_redirect = make_redirection (sd, r_err_and_out, rd, 0); } else { free (redirectee_word); return (AMBIGUOUS_REDIRECT); } free (redirectee_word); /* Set up the variables needed by the rest of the function from the new redirection. */ if (new_redirect->instruction == r_err_and_out) { char *alloca_hack; /* Copy the word without allocating any memory that must be explicitly freed. */ redirectee = (WORD_DESC *)alloca (sizeof (WORD_DESC)); xbcopy ((char *)new_redirect->redirectee.filename, (char *)redirectee, sizeof (WORD_DESC)); alloca_hack = (char *) alloca (1 + strlen (new_redirect->redirectee.filename->word)); redirectee->word = alloca_hack; strcpy (redirectee->word, new_redirect->redirectee.filename->word); } else /* It's guaranteed to be an integer, and shouldn't be freed. */ redirectee = new_redirect->redirectee.filename; redir_fd = new_redirect->redirectee.dest; redirector = new_redirect->redirector.dest; ri = new_redirect->instruction; /* Overwrite the flags element of the old redirect with the new value. */ redirect->flags = new_redirect->flags; dispose_redirects (new_redirect); } switch (ri) { case r_output_direction: case r_appending_to: case r_input_direction: case r_inputa_direction: case r_err_and_out: /* command &>filename */ case r_append_err_and_out: /* command &>> filename */ case r_input_output: case r_output_force: if (posixly_correct && interactive_shell == 0) { oflags = redirectee->flags; redirectee->flags |= W_NOGLOB; } redirectee_word = redirection_expand (redirectee); if (posixly_correct && interactive_shell == 0) redirectee->flags = oflags; if (redirectee_word == 0) return (AMBIGUOUS_REDIRECT);#if defined (RESTRICTED_SHELL) if (restricted && (WRITE_REDIRECT (ri))) { free (redirectee_word); return (RESTRICTED_REDIRECT); }#endif /* RESTRICTED_SHELL */ fd = redir_open (redirectee_word, redirect->flags, 0666, ri); free (redirectee_word); if (fd == NOCLOBBER_REDIRECT) return (fd); if (fd < 0) return (errno); if (flags & RX_ACTIVE) { 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_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 /* Make sure there is no pending output before we change the state of the underlying file descriptor, since the builtins use stdio for output. */ if (redirector == 1 && fileno (stdout) == redirector) { fflush (stdout); fpurge (stdout); } else if (redirector == 2 && fileno (stderr) == redirector) { fflush (stderr); fpurge (stderr); } 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)) return (errno);#if defined (BUFFERED_INPUT) /* Do not change the buffered stream for an implicit redirection of /dev/null to fd 0 for asynchronous commands without job control (r_inputa_direction). */ if (ri == r_input_direction || ri == r_input_output) duplicate_buffered_stream (fd, redirector);#endif /* BUFFERED_INPUT */ /* * If we're remembering, then this is the result of a while, for * or until loop with a loop redirection, or a function/builtin * executing in the parent shell with a redirection. In the * function/builtin case, we want to set all file descriptors > 2 * to be close-on-exec to duplicate the effect of the old * for i = 3 to NOFILE close(i) loop. In the case of the loops,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?