@@ -180,8 +180,27 @@ spawn(PyObject *self UNUSED, PyObject *args) {
180180 return PyLong_FromLong (pid );
181181}
182182
183+ static PyObject *
184+ establish_controlling_tty (PyObject * self UNUSED , PyObject * args ) {
185+ const char * ttyname ;
186+ int stdin_fd , stdout_fd , stderr_fd ;
187+ if (!PyArg_ParseTuple (args , "siii" , & ttyname , & stdin_fd , & stdout_fd , & stderr_fd )) return NULL ;
188+ int tfd = safe_open (ttyname , O_RDWR , 0 );
189+ if (tfd == -1 ) return PyErr_SetFromErrnoWithFilename (PyExc_OSError , ttyname );
190+ #ifdef TIOCSCTTY
191+ // On BSD open() does not establish the controlling terminal
192+ if (ioctl (tfd , TIOCSCTTY , 0 ) == -1 ) return PyErr_SetFromErrno (PyExc_OSError );
193+ #endif
194+ if (dup2 (tfd , stdin_fd ) == -1 ) return PyErr_SetFromErrno (PyExc_OSError );
195+ if (dup2 (tfd , stdout_fd ) == -1 ) return PyErr_SetFromErrno (PyExc_OSError );
196+ if (dup2 (tfd , stderr_fd ) == -1 ) return PyErr_SetFromErrno (PyExc_OSError );
197+ safe_close (tfd , __FILE__ , __LINE__ );
198+ Py_RETURN_NONE ;
199+ }
200+
183201static PyMethodDef module_methods [] = {
184202 METHODB (spawn , METH_VARARGS ),
203+ METHODB (establish_controlling_tty , METH_VARARGS ),
185204 {NULL , NULL , 0 , NULL } /* Sentinel */
186205};
187206
0 commit comments