def Pop(self): # type: () -> None frame = self.stack.pop() #log('< Pop %s', frame) for rf in reversed(frame.saved): if rf.saved_fd == NO_FD: #log('Close %d', orig) try: posix.close(rf.orig_fd) except OSError as e: log('Error closing descriptor %d: %s', rf.orig_fd, pyutil.strerror(e)) raise else: try: posix.dup2(rf.saved_fd, rf.orig_fd) except OSError as e: log('dup2(%d, %d) error: %s', rf.saved_fd, rf.orig_fd, pyutil.strerror(e)) #log('fd state:') #posix.system('ls -l /proc/%s/fd' % posix.getpid()) raise posix.close(rf.saved_fd) #log('dup2 %s %s', saved, orig) # Wait for here doc processes to finish. for proc, waiter in frame.need_wait: unused_status = proc.Wait(waiter)
def _PushDup(self, fd1, loc): # type: (int, redir_loc_t) -> int """Save fd2 in a higher range, and dup fd1 onto fd2. Returns whether F_DUPFD/dup2 succeeded, and the new descriptor. """ UP_loc = loc if loc.tag_() == redir_loc_e.VarName: fd2_name = cast(redir_loc__VarName, UP_loc).name try: # F_DUPFD: GREATER than range new_fd = fcntl_.fcntl(fd1, fcntl_.F_DUPFD, _SHELL_MIN_FD) # type: int except IOError as e: if e.errno == errno_.EBADF: self.errfmt.Print_('%d: %s' % (fd1, pyutil.strerror(e))) return NO_FD else: raise # this redirect failed self._WriteFdToMem(fd2_name, new_fd) elif loc.tag_() == redir_loc_e.Fd: fd2 = cast(redir_loc__Fd, UP_loc).fd if fd1 == fd2: # The user could have asked for it to be open on descrptor 3, but open() # already returned 3, e.g. echo 3>out.txt return NO_FD # Check the validity of fd1 before _PushSave(fd2) try: fcntl_.fcntl(fd1, fcntl_.F_GETFD) except IOError as e: self.errfmt.Print_('%d: %s' % (fd1, pyutil.strerror(e))) raise need_restore = self._PushSave(fd2) #log('==== dup2 %s %s\n' % (fd1, fd2)) try: posix.dup2(fd1, fd2) except OSError as e: # bash/dash give this error too, e.g. for 'echo hi 1>&3' self.errfmt.Print_('%d: %s' % (fd1, pyutil.strerror(e))) # Restore and return error if need_restore: rf = self.cur_frame.saved.pop() posix.dup2(rf.saved_fd, rf.orig_fd) posix.close(rf.saved_fd) raise # this redirect failed new_fd = fd2 else: raise AssertionError() return new_fd
def Pop(self): # type: () -> None frame = self.stack.pop() #log('< Pop %s', frame) for saved, orig in reversed(frame.saved): try: posix.dup2(saved, orig) except OSError as e: log('dup2(%d, %d) error: %s', saved, orig, e) #log('fd state:') #posix.system('ls -l /proc/%s/fd' % posix.getpid()) raise posix.close(saved) #log('dup2 %s %s', saved, orig) for fd in frame.need_close: #log('Close %d', fd) try: posix.close(fd) except OSError as e: log('Error closing descriptor %d: %s', fd, e) raise # Wait for here doc processes to finish. for proc, waiter in frame.need_wait: unused_status = proc.Wait(waiter)
def Open(self, path, mode='r'): # type: (str, str) -> mylib.LineReader """Opens a path for read, but moves it out of the reserved 3-9 fd range. Returns: A Python file object. The caller is responsible for Close(). Raises: OSError if the path can't be found. """ if mode == 'r': fd_mode = posix.O_RDONLY elif mode == 'w': fd_mode = posix.O_CREAT | posix.O_RDWR else: raise AssertionError(mode) fd = posix.open(path, fd_mode, 0o666) # may raise OSError new_fd = self._GetFreeDescriptor() posix.dup2(fd, new_fd) posix.close(fd) try: f = posix.fdopen(new_fd, mode) # Might raise IOError except IOError as e: raise OSError(*e.args) # Consistently raise OSError return f
def _PushDup(self, fd1, fd2): # type: (int, int) -> bool """Save fd2, and dup fd1 onto fd2. Mutates self.cur_frame.saved. Returns: success Bool """ new_fd = self._GetFreeDescriptor() #log('---- _PushDup %s %s', fd1, fd2) need_restore = True try: fcntl.fcntl(fd2, fcntl.F_DUPFD, new_fd) except IOError as e: # Example program that causes this error: exec 4>&1. Descriptor 4 isn't # open. # This seems to be ignored in dash too in savefd()? if e.errno == errno.EBADF: #log('ERROR %s', e) need_restore = False else: raise else: posix.close(fd2) fcntl.fcntl(new_fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC) #log('==== dup %s %s\n' % (fd1, fd2)) try: posix.dup2(fd1, fd2) except OSError as e: # bash/dash give this error too, e.g. for 'echo hi 1>&3' self.errfmt.Print('%d: %s', fd1, posix.strerror(e.errno)) # Restore and return error posix.dup2(new_fd, fd2) posix.close(new_fd) # Undo it return False if need_restore: self.cur_frame.saved.append((new_fd, fd2)) return True
def Apply(self): # type: () -> None posix.dup2(self.w, 1) posix.close(self.w) # close after dup posix.close(self.r) # we're writing to the pipe, not reading
def Apply(self): # type: () -> None posix.dup2(self.r, 0) posix.close(self.r) # close after dup posix.close(self.w) # we're reading from the pipe, not writing