summaryrefslogtreecommitdiffstats
path: root/lib/ptyprocess/_fork_pty.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ptyprocess/_fork_pty.py')
-rw-r--r--lib/ptyprocess/_fork_pty.py78
1 files changed, 78 insertions, 0 deletions
diff --git a/lib/ptyprocess/_fork_pty.py b/lib/ptyprocess/_fork_pty.py
new file mode 100644
index 0000000..a8d05fe
--- /dev/null
+++ b/lib/ptyprocess/_fork_pty.py
@@ -0,0 +1,78 @@
+"""Substitute for the forkpty system call, to support Solaris.
+"""
+import os
+import errno
+
+from pty import (STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, CHILD)
+from .util import PtyProcessError
+
+def fork_pty():
+ '''This implements a substitute for the forkpty system call. This
+ should be more portable than the pty.fork() function. Specifically,
+ this should work on Solaris.
+
+ Modified 10.06.05 by Geoff Marshall: Implemented __fork_pty() method to
+ resolve the issue with Python's pty.fork() not supporting Solaris,
+ particularly ssh. Based on patch to posixmodule.c authored by Noah
+ Spurrier::
+
+ http://mail.python.org/pipermail/python-dev/2003-May/035281.html
+
+ '''
+
+ parent_fd, child_fd = os.openpty()
+ if parent_fd < 0 or child_fd < 0:
+ raise OSError("os.openpty() failed")
+
+ pid = os.fork()
+ if pid == CHILD:
+ # Child.
+ os.close(parent_fd)
+ pty_make_controlling_tty(child_fd)
+
+ os.dup2(child_fd, STDIN_FILENO)
+ os.dup2(child_fd, STDOUT_FILENO)
+ os.dup2(child_fd, STDERR_FILENO)
+
+ else:
+ # Parent.
+ os.close(child_fd)
+
+ return pid, parent_fd
+
+def pty_make_controlling_tty(tty_fd):
+ '''This makes the pseudo-terminal the controlling tty. This should be
+ more portable than the pty.fork() function. Specifically, this should
+ work on Solaris. '''
+
+ child_name = os.ttyname(tty_fd)
+
+ # Disconnect from controlling tty, if any. Raises OSError of ENXIO
+ # if there was no controlling tty to begin with, such as when
+ # executed by a cron(1) job.
+ try:
+ fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY)
+ os.close(fd)
+ except OSError as err:
+ if err.errno != errno.ENXIO:
+ raise
+
+ os.setsid()
+
+ # Verify we are disconnected from controlling tty by attempting to open
+ # it again. We expect that OSError of ENXIO should always be raised.
+ try:
+ fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY)
+ os.close(fd)
+ raise PtyProcessError("OSError of errno.ENXIO should be raised.")
+ except OSError as err:
+ if err.errno != errno.ENXIO:
+ raise
+
+ # Verify we can open child pty.
+ fd = os.open(child_name, os.O_RDWR)
+ os.close(fd)
+
+ # Verify we now have a controlling tty.
+ fd = os.open("/dev/tty", os.O_WRONLY)
+ os.close(fd)