Show More
@@ -80,6 +80,7 try: | |||
|
80 | 80 | import traceback |
|
81 | 81 | import signal |
|
82 | 82 | import codecs |
|
83 | import stat | |
|
83 | 84 | except ImportError: # pragma: no cover |
|
84 | 85 | err = sys.exc_info()[1] |
|
85 | 86 | raise ImportError(str(err) + ''' |
@@ -87,7 +88,7 except ImportError: # pragma: no cover | |||
|
87 | 88 | A critical module was not found. Probably this operating system does not |
|
88 | 89 | support it. Pexpect is intended for UNIX-like operating systems.''') |
|
89 | 90 | |
|
90 |
__version__ = '3. |
|
|
91 | __version__ = '3.3' | |
|
91 | 92 | __revision__ = '' |
|
92 | 93 | __all__ = ['ExceptionPexpect', 'EOF', 'TIMEOUT', 'spawn', 'spawnu', 'run', 'runu', |
|
93 | 94 | 'which', 'split_command_line', '__version__', '__revision__'] |
@@ -284,6 +285,7 class spawn(object): | |||
|
284 | 285 | def _chr(c): |
|
285 | 286 | return bytes([c]) |
|
286 | 287 | linesep = os.linesep.encode('ascii') |
|
288 | crlf = '\r\n'.encode('ascii') | |
|
287 | 289 | |
|
288 | 290 | @staticmethod |
|
289 | 291 | def write_to_stdout(b): |
@@ -296,13 +298,14 class spawn(object): | |||
|
296 | 298 | allowed_string_types = (basestring,) # analysis:ignore |
|
297 | 299 | _chr = staticmethod(chr) |
|
298 | 300 | linesep = os.linesep |
|
301 | crlf = '\r\n' | |
|
299 | 302 | write_to_stdout = sys.stdout.write |
|
300 | 303 | |
|
301 | 304 | encoding = None |
|
302 | 305 | |
|
303 | 306 | def __init__(self, command, args=[], timeout=30, maxread=2000, |
|
304 | 307 | searchwindowsize=None, logfile=None, cwd=None, env=None, |
|
305 | ignore_sighup=True): | |
|
308 | ignore_sighup=True, echo=True): | |
|
306 | 309 | |
|
307 | 310 | '''This is the constructor. The command parameter may be a string that |
|
308 | 311 | includes a command and any arguments to the command. For example:: |
@@ -415,7 +418,16 class spawn(object): | |||
|
415 | 418 | signalstatus will store the signal value and exitstatus will be None. |
|
416 | 419 | If you need more detail you can also read the self.status member which |
|
417 | 420 | stores the status returned by os.waitpid. You can interpret this using |
|
418 |
os.WIFEXITED/os.WEXITSTATUS or os.WIFSIGNALED/os.TERMSIG. |
|
|
421 | os.WIFEXITED/os.WEXITSTATUS or os.WIFSIGNALED/os.TERMSIG. | |
|
422 | ||
|
423 | The echo attribute may be set to False to disable echoing of input. | |
|
424 | As a pseudo-terminal, all input echoed by the "keyboard" (send() | |
|
425 | or sendline()) will be repeated to output. For many cases, it is | |
|
426 | not desirable to have echo enabled, and it may be later disabled | |
|
427 | using setecho(False) followed by waitnoecho(). However, for some | |
|
428 | platforms such as Solaris, this is not possible, and should be | |
|
429 | disabled immediately on spawn. | |
|
430 | ''' | |
|
419 | 431 | |
|
420 | 432 | self.STDIN_FILENO = pty.STDIN_FILENO |
|
421 | 433 | self.STDOUT_FILENO = pty.STDOUT_FILENO |
@@ -437,7 +449,7 class spawn(object): | |||
|
437 | 449 | self.status = None |
|
438 | 450 | self.flag_eof = False |
|
439 | 451 | self.pid = None |
|
440 |
# the chil |
|
|
452 | # the child file descriptor is initially closed | |
|
441 | 453 | self.child_fd = -1 |
|
442 | 454 | self.timeout = timeout |
|
443 | 455 | self.delimiter = EOF |
@@ -466,16 +478,30 class spawn(object): | |||
|
466 | 478 | self.closed = True |
|
467 | 479 | self.cwd = cwd |
|
468 | 480 | self.env = env |
|
481 | self.echo = echo | |
|
469 | 482 | self.ignore_sighup = ignore_sighup |
|
483 | _platform = sys.platform.lower() | |
|
470 | 484 | # This flags if we are running on irix |
|
471 |
self.__irix_hack = |
|
|
485 | self.__irix_hack = _platform.startswith('irix') | |
|
472 | 486 | # Solaris uses internal __fork_pty(). All others use pty.fork(). |
|
473 | if ((sys.platform.lower().find('solaris') >= 0) | |
|
474 | or (sys.platform.lower().find('sunos5') >= 0)): | |
|
475 | self.use_native_pty_fork = False | |
|
476 | else: | |
|
477 | self.use_native_pty_fork = True | |
|
478 | ||
|
487 | self.use_native_pty_fork = not ( | |
|
488 | _platform.startswith('solaris') or | |
|
489 | _platform.startswith('sunos')) | |
|
490 | # inherit EOF and INTR definitions from controlling process. | |
|
491 | try: | |
|
492 | from termios import VEOF, VINTR | |
|
493 | fd = sys.__stdin__.fileno() | |
|
494 | self._INTR = ord(termios.tcgetattr(fd)[6][VINTR]) | |
|
495 | self._EOF = ord(termios.tcgetattr(fd)[6][VEOF]) | |
|
496 | except (ImportError, OSError, IOError, termios.error): | |
|
497 | # unless the controlling process is also not a terminal, | |
|
498 | # such as cron(1). Fall-back to using CEOF and CINTR. | |
|
499 | try: | |
|
500 | from termios import CEOF, CINTR | |
|
501 | (self._INTR, self._EOF) = (CINTR, CEOF) | |
|
502 | except ImportError: | |
|
503 | # ^C, ^D | |
|
504 | (self._INTR, self._EOF) = (3, 4) | |
|
479 | 505 | # Support subclasses that do not use command or args. |
|
480 | 506 | if command is None: |
|
481 | 507 | self.command = None |
@@ -599,33 +625,39 class spawn(object): | |||
|
599 | 625 | if self.use_native_pty_fork: |
|
600 | 626 | try: |
|
601 | 627 | self.pid, self.child_fd = pty.fork() |
|
602 | except OSError: | |
|
628 | except OSError: # pragma: no cover | |
|
603 | 629 | err = sys.exc_info()[1] |
|
604 | 630 | raise ExceptionPexpect('pty.fork() failed: ' + str(err)) |
|
605 | 631 | else: |
|
606 | 632 | # Use internal __fork_pty |
|
607 | 633 | self.pid, self.child_fd = self.__fork_pty() |
|
608 | 634 | |
|
609 | if self.pid == 0: | |
|
635 | # Some platforms must call setwinsize() and setecho() from the | |
|
636 | # child process, and others from the master process. We do both, | |
|
637 | # allowing IOError for either. | |
|
638 | ||
|
639 | if self.pid == pty.CHILD: | |
|
610 | 640 | # Child |
|
641 | self.child_fd = self.STDIN_FILENO | |
|
642 | ||
|
643 | # set default window size of 24 rows by 80 columns | |
|
611 | 644 | try: |
|
612 | # used by setwinsize() | |
|
613 | self.child_fd = sys.stdout.fileno() | |
|
614 | 645 | self.setwinsize(24, 80) |
|
615 | # which exception, shouldnt' we catch explicitly .. ? | |
|
616 | except: | |
|
617 | # Some platforms do not like setwinsize (Cygwin). | |
|
618 | # This will cause problem when running applications that | |
|
619 | # are very picky about window size. | |
|
620 | # This is a serious limitation, but not a show stopper. | |
|
621 |
|
|
|
646 | except IOError as err: | |
|
647 | if err.args[0] not in (errno.EINVAL, errno.ENOTTY): | |
|
648 | raise | |
|
649 | ||
|
650 | # disable echo if spawn argument echo was unset | |
|
651 | if not self.echo: | |
|
652 | try: | |
|
653 | self.setecho(self.echo) | |
|
654 | except (IOError, termios.error) as err: | |
|
655 | if err.args[0] not in (errno.EINVAL, errno.ENOTTY): | |
|
656 | raise | |
|
657 | ||
|
622 | 658 | # Do not allow child to inherit open file descriptors from parent. |
|
623 | 659 | max_fd = resource.getrlimit(resource.RLIMIT_NOFILE)[0] |
|
624 |
|
|
|
625 | try: | |
|
626 | os.close(i) | |
|
627 | except OSError: | |
|
628 | pass | |
|
660 | os.closerange(3, max_fd) | |
|
629 | 661 | |
|
630 | 662 | if self.ignore_sighup: |
|
631 | 663 | signal.signal(signal.SIGHUP, signal.SIG_IGN) |
@@ -638,6 +670,13 class spawn(object): | |||
|
638 | 670 | os.execvpe(self.command, self.args, self.env) |
|
639 | 671 | |
|
640 | 672 | # Parent |
|
673 | try: | |
|
674 | self.setwinsize(24, 80) | |
|
675 | except IOError as err: | |
|
676 | if err.args[0] not in (errno.EINVAL, errno.ENOTTY): | |
|
677 | raise | |
|
678 | ||
|
679 | ||
|
641 | 680 | self.terminated = False |
|
642 | 681 | self.closed = False |
|
643 | 682 | |
@@ -660,19 +699,15 class spawn(object): | |||
|
660 | 699 | raise ExceptionPexpect("Could not open with os.openpty().") |
|
661 | 700 | |
|
662 | 701 | pid = os.fork() |
|
663 |
if pid |
|
|
664 | raise ExceptionPexpect("Failed os.fork().") | |
|
665 | elif pid == 0: | |
|
702 | if pid == pty.CHILD: | |
|
666 | 703 | # Child. |
|
667 | 704 | os.close(parent_fd) |
|
668 | 705 | self.__pty_make_controlling_tty(child_fd) |
|
669 | 706 | |
|
670 |
os.dup2(child_fd, |
|
|
671 |
os.dup2(child_fd, |
|
|
672 |
os.dup2(child_fd, |
|
|
707 | os.dup2(child_fd, self.STDIN_FILENO) | |
|
708 | os.dup2(child_fd, self.STDOUT_FILENO) | |
|
709 | os.dup2(child_fd, self.STDERR_FILENO) | |
|
673 | 710 | |
|
674 | if child_fd > 2: | |
|
675 | os.close(child_fd) | |
|
676 | 711 | else: |
|
677 | 712 | # Parent. |
|
678 | 713 | os.close(child_fd) |
@@ -686,45 +721,37 class spawn(object): | |||
|
686 | 721 | |
|
687 | 722 | child_name = os.ttyname(tty_fd) |
|
688 | 723 | |
|
689 |
# Disconnect from controlling tty |
|
|
724 | # Disconnect from controlling tty, if any. Raises OSError of ENXIO | |
|
725 | # if there was no controlling tty to begin with, such as when | |
|
726 | # executed by a cron(1) job. | |
|
690 | 727 | try: |
|
691 | 728 | fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY) |
|
692 | if fd >= 0: | |
|
693 | 729 |
|
|
694 | # which exception, shouldnt' we catch explicitly .. ? | |
|
695 | except: | |
|
696 | # Already disconnected. This happens if running inside cron. | |
|
697 | pass | |
|
730 | except OSError as err: | |
|
731 | if err.errno != errno.ENXIO: | |
|
732 | raise | |
|
698 | 733 | |
|
699 | 734 | os.setsid() |
|
700 | 735 | |
|
701 | # Verify we are disconnected from controlling tty | |
|
702 | # by attempting to open it again. | |
|
736 | # Verify we are disconnected from controlling tty by attempting to open | |
|
737 | # it again. We expect that OSError of ENXIO should always be raised. | |
|
703 | 738 | try: |
|
704 | 739 | fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY) |
|
705 | if fd >= 0: | |
|
706 | 740 |
|
|
707 | raise ExceptionPexpect('Failed to disconnect from ' + | |
|
708 | 'controlling tty. It is still possible to open /dev/tty.') | |
|
709 | # which exception, shouldnt' we catch explicitly .. ? | |
|
710 | except: | |
|
711 | # Good! We are disconnected from a controlling tty. | |
|
712 | pass | |
|
741 | raise ExceptionPexpect("OSError of errno.ENXIO should be raised.") | |
|
742 | except OSError as err: | |
|
743 | if err.errno != errno.ENXIO: | |
|
744 | raise | |
|
713 | 745 | |
|
714 | 746 | # Verify we can open child pty. |
|
715 | 747 | fd = os.open(child_name, os.O_RDWR) |
|
716 | if fd < 0: | |
|
717 | raise ExceptionPexpect("Could not open child pty, " + child_name) | |
|
718 | else: | |
|
719 | 748 |
|
|
720 | 749 | |
|
721 | 750 | # Verify we now have a controlling tty. |
|
722 | 751 | fd = os.open("/dev/tty", os.O_WRONLY) |
|
723 | if fd < 0: | |
|
724 | raise ExceptionPexpect("Could not open controlling tty, /dev/tty") | |
|
725 | else: | |
|
726 | 752 |
|
|
727 | 753 | |
|
754 | ||
|
728 | 755 | def fileno(self): |
|
729 | 756 | '''This returns the file descriptor of the pty for the child. |
|
730 | 757 | ''' |
@@ -757,7 +784,12 class spawn(object): | |||
|
757 | 784 | |
|
758 | 785 | def isatty(self): |
|
759 | 786 | '''This returns True if the file descriptor is open and connected to a |
|
760 |
tty(-like) device, else False. |
|
|
787 | tty(-like) device, else False. | |
|
788 | ||
|
789 | On SVR4-style platforms implementing streams, such as SunOS and HP-UX, | |
|
790 | the child pty may not appear as a terminal device. This means | |
|
791 | methods such as setecho(), setwinsize(), getwinsize() may raise an | |
|
792 | IOError. ''' | |
|
761 | 793 | |
|
762 | 794 | return os.isatty(self.child_fd) |
|
763 | 795 | |
@@ -794,12 +826,20 class spawn(object): | |||
|
794 | 826 | def getecho(self): |
|
795 | 827 | '''This returns the terminal echo mode. This returns True if echo is |
|
796 | 828 | on or False if echo is off. Child applications that are expecting you |
|
797 |
to enter a password often set ECHO False. See waitnoecho(). |
|
|
829 | to enter a password often set ECHO False. See waitnoecho(). | |
|
830 | ||
|
831 | Not supported on platforms where ``isatty()`` returns False. ''' | |
|
798 | 832 | |
|
833 | try: | |
|
799 | 834 | attr = termios.tcgetattr(self.child_fd) |
|
800 | if attr[3] & termios.ECHO: | |
|
801 | return True | |
|
802 | return False | |
|
835 | except termios.error as err: | |
|
836 | errmsg = 'getecho() may not be called on this platform' | |
|
837 | if err.args[0] == errno.EINVAL: | |
|
838 | raise IOError(err.args[0], '%s: %s.' % (err.args[1], errmsg)) | |
|
839 | raise | |
|
840 | ||
|
841 | self.echo = bool(attr[3] & termios.ECHO) | |
|
842 | return self.echo | |
|
803 | 843 | |
|
804 | 844 | def setecho(self, state): |
|
805 | 845 | '''This sets the terminal echo mode on or off. Note that anything the |
@@ -829,18 +869,35 class spawn(object): | |||
|
829 | 869 | p.expect(['1234']) |
|
830 | 870 | p.expect(['abcd']) |
|
831 | 871 | p.expect(['wxyz']) |
|
872 | ||
|
873 | ||
|
874 | Not supported on platforms where ``isatty()`` returns False. | |
|
832 | 875 | ''' |
|
833 | 876 | |
|
834 | self.child_fd | |
|
877 | errmsg = 'setecho() may not be called on this platform' | |
|
878 | ||
|
879 | try: | |
|
835 | 880 | attr = termios.tcgetattr(self.child_fd) |
|
881 | except termios.error as err: | |
|
882 | if err.args[0] == errno.EINVAL: | |
|
883 | raise IOError(err.args[0], '%s: %s.' % (err.args[1], errmsg)) | |
|
884 | raise | |
|
885 | ||
|
836 | 886 | if state: |
|
837 | 887 | attr[3] = attr[3] | termios.ECHO |
|
838 | 888 | else: |
|
839 | 889 | attr[3] = attr[3] & ~termios.ECHO |
|
840 | # I tried TCSADRAIN and TCSAFLUSH, but | |
|
841 | # these were inconsistent and blocked on some platforms. | |
|
842 | # TCSADRAIN would probably be ideal if it worked. | |
|
890 | ||
|
891 | try: | |
|
892 | # I tried TCSADRAIN and TCSAFLUSH, but these were inconsistent and | |
|
893 | # blocked on some platforms. TCSADRAIN would probably be ideal. | |
|
843 | 894 | termios.tcsetattr(self.child_fd, termios.TCSANOW, attr) |
|
895 | except IOError as err: | |
|
896 | if err.args[0] == errno.EINVAL: | |
|
897 | raise IOError(err.args[0], '%s: %s.' % (err.args[1], errmsg)) | |
|
898 | raise | |
|
899 | ||
|
900 | self.echo = state | |
|
844 | 901 | |
|
845 | 902 | def _log(self, s, direction): |
|
846 | 903 | if self.logfile is not None: |
@@ -913,12 +970,14 class spawn(object): | |||
|
913 | 970 | if self.child_fd in r: |
|
914 | 971 | try: |
|
915 | 972 | s = os.read(self.child_fd, size) |
|
916 | except OSError: | |
|
917 | # Linux does this | |
|
973 | except OSError as err: | |
|
974 | if err.args[0] == errno.EIO: | |
|
975 | # Linux-style EOF | |
|
918 | 976 | self.flag_eof = True |
|
919 | 977 | raise EOF('End Of File (EOF). Exception style platform.') |
|
978 | raise | |
|
920 | 979 | if s == b'': |
|
921 |
# BSD |
|
|
980 | # BSD-style EOF | |
|
922 | 981 | self.flag_eof = True |
|
923 | 982 | raise EOF('End Of File (EOF). Empty string style platform.') |
|
924 | 983 | |
@@ -926,7 +985,7 class spawn(object): | |||
|
926 | 985 | self._log(s, 'read') |
|
927 | 986 | return s |
|
928 | 987 | |
|
929 | raise ExceptionPexpect('Reached an unexpected state.') | |
|
988 | raise ExceptionPexpect('Reached an unexpected state.') # pragma: no cover | |
|
930 | 989 | |
|
931 | 990 | def read(self, size=-1): |
|
932 | 991 | '''This reads at most "size" bytes from the file (less if the read hits |
@@ -972,9 +1031,9 class spawn(object): | |||
|
972 | 1031 | if size == 0: |
|
973 | 1032 | return self.string_type() |
|
974 | 1033 | # delimiter default is EOF |
|
975 |
index = self.expect([ |
|
|
1034 | index = self.expect([self.crlf, self.delimiter]) | |
|
976 | 1035 | if index == 0: |
|
977 |
return self.before + |
|
|
1036 | return self.before + self.crlf | |
|
978 | 1037 | else: |
|
979 | 1038 | return self.before |
|
980 | 1039 | |
@@ -1075,40 +1134,14 class spawn(object): | |||
|
1075 | 1134 | It is the responsibility of the caller to ensure the eof is sent at the |
|
1076 | 1135 | beginning of a line. ''' |
|
1077 | 1136 | |
|
1078 | ### Hmmm... how do I send an EOF? | |
|
1079 | ###C if ((m = write(pty, *buf, p - *buf)) < 0) | |
|
1080 | ###C return (errno == EWOULDBLOCK) ? n : -1; | |
|
1081 | #fd = sys.stdin.fileno() | |
|
1082 | #old = termios.tcgetattr(fd) # remember current state | |
|
1083 | #attr = termios.tcgetattr(fd) | |
|
1084 | #attr[3] = attr[3] | termios.ICANON # ICANON must be set to see EOF | |
|
1085 | #try: # use try/finally to ensure state gets restored | |
|
1086 | # termios.tcsetattr(fd, termios.TCSADRAIN, attr) | |
|
1087 | # if hasattr(termios, 'CEOF'): | |
|
1088 | # os.write(self.child_fd, '%c' % termios.CEOF) | |
|
1089 | # else: | |
|
1090 | # # Silly platform does not define CEOF so assume CTRL-D | |
|
1091 | # os.write(self.child_fd, '%c' % 4) | |
|
1092 | #finally: # restore state | |
|
1093 | # termios.tcsetattr(fd, termios.TCSADRAIN, old) | |
|
1094 | if hasattr(termios, 'VEOF'): | |
|
1095 | char = ord(termios.tcgetattr(self.child_fd)[6][termios.VEOF]) | |
|
1096 | else: | |
|
1097 | # platform does not define VEOF so assume CTRL-D | |
|
1098 | char = 4 | |
|
1099 | self.send(self._chr(char)) | |
|
1137 | self.send(self._chr(self._EOF)) | |
|
1100 | 1138 | |
|
1101 | 1139 | def sendintr(self): |
|
1102 | 1140 | |
|
1103 | 1141 | '''This sends a SIGINT to the child. It does not require |
|
1104 | 1142 | the SIGINT to be the first character on a line. ''' |
|
1105 | 1143 | |
|
1106 | if hasattr(termios, 'VINTR'): | |
|
1107 | char = ord(termios.tcgetattr(self.child_fd)[6][termios.VINTR]) | |
|
1108 | else: | |
|
1109 | # platform does not define VINTR so assume CTRL-C | |
|
1110 | char = 3 | |
|
1111 | self.send(self._chr(char)) | |
|
1144 | self.send(self._chr(self._INTR)) | |
|
1112 | 1145 | |
|
1113 | 1146 | def eof(self): |
|
1114 | 1147 | |
@@ -1181,7 +1214,7 class spawn(object): | |||
|
1181 | 1214 | self.exitstatus = None |
|
1182 | 1215 | self.signalstatus = os.WTERMSIG(status) |
|
1183 | 1216 | self.terminated = True |
|
1184 | elif os.WIFSTOPPED(status): | |
|
1217 | elif os.WIFSTOPPED(status): # pragma: no cover | |
|
1185 | 1218 | # You can't call wait() on a child process in the stopped state. |
|
1186 | 1219 | raise ExceptionPexpect('Called wait() on a stopped child ' + |
|
1187 | 1220 | 'process. This is not supported. Is some other ' + |
@@ -1201,7 +1234,7 class spawn(object): | |||
|
1201 | 1234 | |
|
1202 | 1235 | if self.flag_eof: |
|
1203 | 1236 | # This is for Linux, which requires the blocking form |
|
1204 |
# of waitpid to |
|
|
1237 | # of waitpid to get the status of a defunct process. | |
|
1205 | 1238 | # This is super-lame. The flag_eof would have been set |
|
1206 | 1239 | # in read_nonblocking(), so this should be safe. |
|
1207 | 1240 | waitpid_options = 0 |
@@ -1229,7 +1262,7 class spawn(object): | |||
|
1229 | 1262 | try: |
|
1230 | 1263 | ### os.WNOHANG) # Solaris! |
|
1231 | 1264 | pid, status = os.waitpid(self.pid, waitpid_options) |
|
1232 | except OSError as e: | |
|
1265 | except OSError as e: # pragma: no cover | |
|
1233 | 1266 | # This should never happen... |
|
1234 | 1267 | if e.errno == errno.ECHILD: |
|
1235 | 1268 | raise ExceptionPexpect('isalive() encountered condition ' + |
@@ -1643,10 +1676,14 class spawn(object): | |||
|
1643 | 1676 | if self.child_fd in r: |
|
1644 | 1677 | try: |
|
1645 | 1678 | data = self.__interact_read(self.child_fd) |
|
1646 | except OSError as e: | |
|
1647 | # The subprocess may have closed before we get to reading it | |
|
1648 | if e.errno != errno.EIO: | |
|
1679 | except OSError as err: | |
|
1680 | if err.args[0] == errno.EIO: | |
|
1681 | # Linux-style EOF | |
|
1682 | break | |
|
1649 | 1683 |
|
|
1684 | if data == b'': | |
|
1685 | # BSD-style EOF | |
|
1686 | break | |
|
1650 | 1687 | if output_filter: |
|
1651 | 1688 | data = output_filter(data) |
|
1652 | 1689 | if self.logfile is not None: |
@@ -1695,7 +1732,7 class spawn(object): | |||
|
1695 | 1732 | ############################################################################## |
|
1696 | 1733 | # The following methods are no longer supported or allowed. |
|
1697 | 1734 | |
|
1698 | def setmaxread(self, maxread): | |
|
1735 | def setmaxread(self, maxread): # pragma: no cover | |
|
1699 | 1736 | |
|
1700 | 1737 | '''This method is no longer supported or allowed. I don't like getters |
|
1701 | 1738 | and setters without a good reason. ''' |
@@ -1704,7 +1741,7 class spawn(object): | |||
|
1704 | 1741 | 'or allowed. Just assign a value to the ' + |
|
1705 | 1742 | 'maxread member variable.') |
|
1706 | 1743 | |
|
1707 | def setlog(self, fileobject): | |
|
1744 | def setlog(self, fileobject): # pragma: no cover | |
|
1708 | 1745 | |
|
1709 | 1746 | '''This method is no longer supported or allowed. |
|
1710 | 1747 | ''' |
@@ -1732,11 +1769,13 class spawnu(spawn): | |||
|
1732 | 1769 | allowed_string_types = (str, ) |
|
1733 | 1770 | _chr = staticmethod(chr) |
|
1734 | 1771 | linesep = os.linesep |
|
1772 | crlf = '\r\n' | |
|
1735 | 1773 | else: |
|
1736 | 1774 | string_type = unicode |
|
1737 | 1775 | allowed_string_types = (unicode, ) |
|
1738 | 1776 | _chr = staticmethod(unichr) |
|
1739 | 1777 | linesep = os.linesep.decode('ascii') |
|
1778 | crlf = '\r\n'.decode('ascii') | |
|
1740 | 1779 | # This can handle unicode in both Python 2 and 3 |
|
1741 | 1780 | write_to_stdout = sys.stdout.write |
|
1742 | 1781 | |
@@ -1959,15 +1998,55 class searcher_re(object): | |||
|
1959 | 1998 | return best_index |
|
1960 | 1999 | |
|
1961 | 2000 | |
|
1962 | def which(filename): | |
|
2001 | def is_executable_file(path): | |
|
2002 | """Checks that path is an executable regular file (or a symlink to a file). | |
|
2003 | ||
|
2004 | This is roughly ``os.path isfile(path) and os.access(path, os.X_OK)``, but | |
|
2005 | on some platforms :func:`os.access` gives us the wrong answer, so this | |
|
2006 | checks permission bits directly. | |
|
2007 | """ | |
|
2008 | # follow symlinks, | |
|
2009 | fpath = os.path.realpath(path) | |
|
2010 | ||
|
2011 | # return False for non-files (directories, fifo, etc.) | |
|
2012 | if not os.path.isfile(fpath): | |
|
2013 | return False | |
|
2014 | ||
|
2015 | # On Solaris, etc., "If the process has appropriate privileges, an | |
|
2016 | # implementation may indicate success for X_OK even if none of the | |
|
2017 | # execute file permission bits are set." | |
|
2018 | # | |
|
2019 | # For this reason, it is necessary to explicitly check st_mode | |
|
1963 | 2020 | |
|
2021 | # get file mode using os.stat, and check if `other', | |
|
2022 | # that is anybody, may read and execute. | |
|
2023 | mode = os.stat(fpath).st_mode | |
|
2024 | if mode & stat.S_IROTH and mode & stat.S_IXOTH: | |
|
2025 | return True | |
|
2026 | ||
|
2027 | # get current user's group ids, and check if `group', | |
|
2028 | # when matching ours, may read and execute. | |
|
2029 | user_gids = os.getgroups() + [os.getgid()] | |
|
2030 | if (os.stat(fpath).st_gid in user_gids and | |
|
2031 | mode & stat.S_IRGRP and mode & stat.S_IXGRP): | |
|
2032 | return True | |
|
2033 | ||
|
2034 | # finally, if file owner matches our effective userid, | |
|
2035 | # check if `user', may read and execute. | |
|
2036 | user_gids = os.getgroups() + [os.getgid()] | |
|
2037 | if (os.stat(fpath).st_uid == os.geteuid() and | |
|
2038 | mode & stat.S_IRUSR and mode & stat.S_IXUSR): | |
|
2039 | return True | |
|
2040 | ||
|
2041 | return False | |
|
2042 | ||
|
2043 | def which(filename): | |
|
1964 | 2044 | '''This takes a given filename; tries to find it in the environment path; |
|
1965 | 2045 | then checks if it is executable. This returns the full path to the filename |
|
1966 | 2046 | if found and executable. Otherwise this returns None.''' |
|
1967 | 2047 | |
|
1968 | 2048 | # Special case where filename contains an explicit path. |
|
1969 | if os.path.dirname(filename) != '': | |
|
1970 | if os.access(filename, os.X_OK): | |
|
2049 | if os.path.dirname(filename) != '' and is_executable_file(filename): | |
|
1971 | 2050 |
|
|
1972 | 2051 | if 'PATH' not in os.environ or os.environ['PATH'] == '': |
|
1973 | 2052 | p = os.defpath |
@@ -1976,7 +2055,7 def which(filename): | |||
|
1976 | 2055 | pathlist = p.split(os.pathsep) |
|
1977 | 2056 | for path in pathlist: |
|
1978 | 2057 | ff = os.path.join(path, filename) |
|
1979 | if os.access(ff, os.X_OK): | |
|
2058 | if is_executable_file(ff): | |
|
1980 | 2059 | return ff |
|
1981 | 2060 | return None |
|
1982 | 2061 | |
@@ -2041,4 +2120,4 def split_command_line(command_line): | |||
|
2041 | 2120 | arg_list.append(arg) |
|
2042 | 2121 | return arg_list |
|
2043 | 2122 | |
|
2044 | # vi:set sr et ts=4 sw=4 ft=python : | |
|
2123 | # vim: set shiftround expandtab tabstop=4 shiftwidth=4 ft=python autoindent : |
General Comments 0
You need to be logged in to leave comments.
Login now