Use both open and the ioctl to set the controlling terminal

This commit is contained in:
Kovid Goyal
2022-07-08 22:30:11 +05:30
parent 0841be7803
commit 9535bc94ff
3 changed files with 18 additions and 12 deletions

View File

@@ -121,10 +121,8 @@ spawn(PyObject *self UNUSED, PyObject *args) {
// Establish the controlling terminal (see man 7 credentials)
int tfd = safe_open(name, O_RDWR, 0);
if (tfd == -1) exit_on_err("Failed to open controlling terminal");
#ifdef TIOCSCTTY
// On BSD open() does not establish the controlling terminal
if (ioctl(tfd, TIOCSCTTY, 0) == -1) exit_on_err("Failed to set controlling terminal with TIOCSCTTY");
#endif
safe_close(tfd, __FILE__, __LINE__);
// Redirect stdin/stdout/stderr to the pty
@@ -185,13 +183,21 @@ spawn(PyObject *self UNUSED, PyObject *args) {
static PyObject*
establish_controlling_tty(PyObject *self UNUSED, PyObject *args) {
int tty_fd, stdin_fd = -1, stdout_fd = -1, stderr_fd = -1;
if (!PyArg_ParseTuple(args, "i|iii", &tty_fd, &stdin_fd, &stdout_fd, &stderr_fd)) return NULL;
if (ioctl(tty_fd, TIOCSCTTY, 0) == -1) { safe_close(tty_fd, __FILE__, __LINE__); return PyErr_SetFromErrno(PyExc_OSError); }
if (stdin_fd > -1 && safe_dup2(tty_fd, stdin_fd) == -1) { safe_close(tty_fd, __FILE__, __LINE__); return PyErr_SetFromErrno(PyExc_OSError); }
if (stdout_fd > -1 && safe_dup2(tty_fd, stdout_fd) == -1) { safe_close(tty_fd, __FILE__, __LINE__); return PyErr_SetFromErrno(PyExc_OSError); }
if (stderr_fd > -1 && safe_dup2(tty_fd, stderr_fd) == -1) { safe_close(tty_fd, __FILE__, __LINE__); return PyErr_SetFromErrno(PyExc_OSError); }
safe_close(tty_fd, __FILE__, __LINE__);
int tty_fd=-1, stdin_fd = -1, stdout_fd = -1, stderr_fd = -1;
const char *tty_name;
if (!PyArg_ParseTuple(args, "s|iiii", &tty_name, &tty_fd, &stdin_fd, &stdout_fd, &stderr_fd)) return NULL;
int tfd = safe_open(tty_name, O_RDWR, 0);
#define cleanup() if (tfd >= 0) safe_close(tfd, __FILE__, __LINE__); if (tty_fd >= 0) safe_close(tty_fd, __FILE__, __LINE__);
#define fail() { cleanup(); return PyErr_SetFromErrno(PyExc_OSError); }
if (tfd < 0) { cleanup(); return PyErr_SetFromErrnoWithFilename(PyExc_OSError, tty_name); }
if (tty_fd < 0) { tty_fd = tfd; tfd = -1; }
if (ioctl(tty_fd, TIOCSCTTY, 0) == -1) fail();
if (stdin_fd > -1 && safe_dup2(tty_fd, stdin_fd) == -1) fail();
if (stdout_fd > -1 && safe_dup2(tty_fd, stdout_fd) == -1) fail();
if (stderr_fd > -1 && safe_dup2(tty_fd, stderr_fd) == -1) fail();
cleanup();
#undef cleanup
#undef fail
Py_RETURN_NONE;
}

View File

@@ -1395,7 +1395,7 @@ def sigqueue(pid: int, signal: int, value: int) -> None:
pass
def establish_controlling_tty(tty_fd: int, stdin: int = -1, stdout: int = -1, stderr: int = -1) -> None:
def establish_controlling_tty(tty_name: str, tty_fd: int = -1, stdin: int = -1, stdout: int = -1, stderr: int = -1) -> None:
pass

View File

@@ -351,7 +351,7 @@ def fork(shm_address: str, free_non_child_resources: Callable[[], None]) -> Tupl
if tty_name:
sys.__stdout__.flush()
sys.__stderr__.flush()
establish_controlling_tty(os.open(tty_name, os.O_RDWR | os.O_CLOEXEC, 0), sys.__stdin__.fileno(), sys.__stdout__.fileno(), sys.__stderr__.fileno())
establish_controlling_tty(tty_name, -1, sys.__stdin__.fileno(), sys.__stdout__.fileno(), sys.__stderr__.fileno())
os.close(w)
if shm.unlink_on_exit:
child_main(cmd, ready_fd_read)
@@ -490,7 +490,7 @@ class SocketChild:
sys.__stdout__.flush()
sys.__stderr__.flush()
establish_controlling_tty(
self.tty_fd,
os.ttyname(self.tty_fd), self.tty_fd,
sys.__stdin__.fileno() if self.stdin < 0 else -1,
sys.__stdout__.fileno() if self.stdout < 0 else -1,
sys.__stderr__.fileno() if self.stderr < 0 else -1)