xref: /openbsd-src/gnu/llvm/lldb/third_party/Python/module/ptyprocess-0.6.0/ptyprocess/_fork_pty.py (revision 061da546b983eb767bad15e67af1174fb0bcf31c)
1"""Substitute for the forkpty system call, to support Solaris.
2"""
3import os
4import errno
5
6from pty import (STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, CHILD)
7from .util import PtyProcessError
8
9def fork_pty():
10    '''This implements a substitute for the forkpty system call. This
11    should be more portable than the pty.fork() function. Specifically,
12    this should work on Solaris.
13
14    Modified 10.06.05 by Geoff Marshall: Implemented __fork_pty() method to
15    resolve the issue with Python's pty.fork() not supporting Solaris,
16    particularly ssh. Based on patch to posixmodule.c authored by Noah
17    Spurrier::
18
19        http://mail.python.org/pipermail/python-dev/2003-May/035281.html
20
21    '''
22
23    parent_fd, child_fd = os.openpty()
24    if parent_fd < 0 or child_fd < 0:
25        raise OSError("os.openpty() failed")
26
27    pid = os.fork()
28    if pid == CHILD:
29        # Child.
30        os.close(parent_fd)
31        pty_make_controlling_tty(child_fd)
32
33        os.dup2(child_fd, STDIN_FILENO)
34        os.dup2(child_fd, STDOUT_FILENO)
35        os.dup2(child_fd, STDERR_FILENO)
36
37    else:
38        # Parent.
39        os.close(child_fd)
40
41    return pid, parent_fd
42
43def pty_make_controlling_tty(tty_fd):
44    '''This makes the pseudo-terminal the controlling tty. This should be
45    more portable than the pty.fork() function. Specifically, this should
46    work on Solaris. '''
47
48    child_name = os.ttyname(tty_fd)
49
50    # Disconnect from controlling tty, if any.  Raises OSError of ENXIO
51    # if there was no controlling tty to begin with, such as when
52    # executed by a cron(1) job.
53    try:
54        fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY)
55        os.close(fd)
56    except OSError as err:
57        if err.errno != errno.ENXIO:
58            raise
59
60    os.setsid()
61
62    # Verify we are disconnected from controlling tty by attempting to open
63    # it again.  We expect that OSError of ENXIO should always be raised.
64    try:
65        fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY)
66        os.close(fd)
67        raise PtyProcessError("OSError of errno.ENXIO should be raised.")
68    except OSError as err:
69        if err.errno != errno.ENXIO:
70            raise
71
72    # Verify we can open child pty.
73    fd = os.open(child_name, os.O_RDWR)
74    os.close(fd)
75
76    # Verify we now have a controlling tty.
77    fd = os.open("/dev/tty", os.O_WRONLY)
78    os.close(fd)
79