gh-85984: Add POSIX pseudo-terminal functions. (GH-102413)

Signed-off-by: Soumendra Ganguly <soumendraganguly@gmail.com>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
Co-authored-by: Petr Viktorin <encukou@gmail.com>
This commit is contained in:
Soumendra Ganguly 2024-01-29 17:10:28 +01:00 committed by GitHub
parent 0f54ee4c6c
commit e351ca3c20
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 468 additions and 11 deletions

View file

@ -4465,6 +4465,156 @@ exit:
#endif /* defined(HAVE_SCHED_H) && defined(HAVE_SCHED_SETAFFINITY) */
#if defined(HAVE_POSIX_OPENPT)
PyDoc_STRVAR(os_posix_openpt__doc__,
"posix_openpt($module, oflag, /)\n"
"--\n"
"\n"
"Open and return a file descriptor for a master pseudo-terminal device.\n"
"\n"
"Performs a posix_openpt() C function call. The oflag argument is used to\n"
"set file status flags and file access modes as specified in the manual page\n"
"of posix_openpt() of your system.");
#define OS_POSIX_OPENPT_METHODDEF \
{"posix_openpt", (PyCFunction)os_posix_openpt, METH_O, os_posix_openpt__doc__},
static int
os_posix_openpt_impl(PyObject *module, int oflag);
static PyObject *
os_posix_openpt(PyObject *module, PyObject *arg)
{
PyObject *return_value = NULL;
int oflag;
int _return_value;
oflag = PyLong_AsInt(arg);
if (oflag == -1 && PyErr_Occurred()) {
goto exit;
}
_return_value = os_posix_openpt_impl(module, oflag);
if ((_return_value == -1) && PyErr_Occurred()) {
goto exit;
}
return_value = PyLong_FromLong((long)_return_value);
exit:
return return_value;
}
#endif /* defined(HAVE_POSIX_OPENPT) */
#if defined(HAVE_GRANTPT)
PyDoc_STRVAR(os_grantpt__doc__,
"grantpt($module, fd, /)\n"
"--\n"
"\n"
"Grant access to the slave pseudo-terminal device.\n"
"\n"
" fd\n"
" File descriptor of a master pseudo-terminal device.\n"
"\n"
"Performs a grantpt() C function call.");
#define OS_GRANTPT_METHODDEF \
{"grantpt", (PyCFunction)os_grantpt, METH_O, os_grantpt__doc__},
static PyObject *
os_grantpt_impl(PyObject *module, int fd);
static PyObject *
os_grantpt(PyObject *module, PyObject *arg)
{
PyObject *return_value = NULL;
int fd;
if (!_PyLong_FileDescriptor_Converter(arg, &fd)) {
goto exit;
}
return_value = os_grantpt_impl(module, fd);
exit:
return return_value;
}
#endif /* defined(HAVE_GRANTPT) */
#if defined(HAVE_UNLOCKPT)
PyDoc_STRVAR(os_unlockpt__doc__,
"unlockpt($module, fd, /)\n"
"--\n"
"\n"
"Unlock a pseudo-terminal master/slave pair.\n"
"\n"
" fd\n"
" File descriptor of a master pseudo-terminal device.\n"
"\n"
"Performs an unlockpt() C function call.");
#define OS_UNLOCKPT_METHODDEF \
{"unlockpt", (PyCFunction)os_unlockpt, METH_O, os_unlockpt__doc__},
static PyObject *
os_unlockpt_impl(PyObject *module, int fd);
static PyObject *
os_unlockpt(PyObject *module, PyObject *arg)
{
PyObject *return_value = NULL;
int fd;
if (!_PyLong_FileDescriptor_Converter(arg, &fd)) {
goto exit;
}
return_value = os_unlockpt_impl(module, fd);
exit:
return return_value;
}
#endif /* defined(HAVE_UNLOCKPT) */
#if (defined(HAVE_PTSNAME) || defined(HAVE_PTSNAME_R))
PyDoc_STRVAR(os_ptsname__doc__,
"ptsname($module, fd, /)\n"
"--\n"
"\n"
"Return the name of the slave pseudo-terminal device.\n"
"\n"
" fd\n"
" File descriptor of a master pseudo-terminal device.\n"
"\n"
"If the ptsname_r() C function is available, it is called;\n"
"otherwise, performs a ptsname() C function call.");
#define OS_PTSNAME_METHODDEF \
{"ptsname", (PyCFunction)os_ptsname, METH_O, os_ptsname__doc__},
static PyObject *
os_ptsname_impl(PyObject *module, int fd);
static PyObject *
os_ptsname(PyObject *module, PyObject *arg)
{
PyObject *return_value = NULL;
int fd;
if (!_PyLong_FileDescriptor_Converter(arg, &fd)) {
goto exit;
}
return_value = os_ptsname_impl(module, fd);
exit:
return return_value;
}
#endif /* (defined(HAVE_PTSNAME) || defined(HAVE_PTSNAME_R)) */
#if (defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX))
PyDoc_STRVAR(os_openpty__doc__,
@ -11991,6 +12141,22 @@ os__supports_virtual_terminal(PyObject *module, PyObject *Py_UNUSED(ignored))
#define OS_SCHED_GETAFFINITY_METHODDEF
#endif /* !defined(OS_SCHED_GETAFFINITY_METHODDEF) */
#ifndef OS_POSIX_OPENPT_METHODDEF
#define OS_POSIX_OPENPT_METHODDEF
#endif /* !defined(OS_POSIX_OPENPT_METHODDEF) */
#ifndef OS_GRANTPT_METHODDEF
#define OS_GRANTPT_METHODDEF
#endif /* !defined(OS_GRANTPT_METHODDEF) */
#ifndef OS_UNLOCKPT_METHODDEF
#define OS_UNLOCKPT_METHODDEF
#endif /* !defined(OS_UNLOCKPT_METHODDEF) */
#ifndef OS_PTSNAME_METHODDEF
#define OS_PTSNAME_METHODDEF
#endif /* !defined(OS_PTSNAME_METHODDEF) */
#ifndef OS_OPENPTY_METHODDEF
#define OS_OPENPTY_METHODDEF
#endif /* !defined(OS_OPENPTY_METHODDEF) */
@ -12422,4 +12588,4 @@ os__supports_virtual_terminal(PyObject *module, PyObject *Py_UNUSED(ignored))
#ifndef OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF
#define OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF
#endif /* !defined(OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF) */
/*[clinic end generated code: output=18c128534c355d84 input=a9049054013a1b77]*/
/*[clinic end generated code: output=43e4e557c771358a input=a9049054013a1b77]*/

View file

@ -8358,6 +8358,149 @@ error:
#endif /* HAVE_SCHED_H */
#ifdef HAVE_POSIX_OPENPT
/*[clinic input]
os.posix_openpt -> int
oflag: int
/
Open and return a file descriptor for a master pseudo-terminal device.
Performs a posix_openpt() C function call. The oflag argument is used to
set file status flags and file access modes as specified in the manual page
of posix_openpt() of your system.
[clinic start generated code]*/
static int
os_posix_openpt_impl(PyObject *module, int oflag)
/*[clinic end generated code: output=ee0bc2624305fc79 input=0de33d0e29693caa]*/
{
int fd;
#if defined(O_CLOEXEC)
oflag |= O_CLOEXEC;
#endif
fd = posix_openpt(oflag);
if (fd == -1) {
posix_error();
return -1;
}
// Just in case, likely a no-op given O_CLOEXEC above.
if (_Py_set_inheritable(fd, 0, NULL) < 0) {
close(fd);
return -1;
}
return fd;
}
#endif /* HAVE_POSIX_OPENPT */
#ifdef HAVE_GRANTPT
/*[clinic input]
os.grantpt
fd: fildes
File descriptor of a master pseudo-terminal device.
/
Grant access to the slave pseudo-terminal device.
Performs a grantpt() C function call.
[clinic start generated code]*/
static PyObject *
os_grantpt_impl(PyObject *module, int fd)
/*[clinic end generated code: output=dfd580015cf548ab input=0668e3b96760e849]*/
{
int ret;
int saved_errno;
PyOS_sighandler_t sig_saved;
sig_saved = PyOS_setsig(SIGCHLD, SIG_DFL);
ret = grantpt(fd);
if (ret == -1)
saved_errno = errno;
PyOS_setsig(SIGCHLD, sig_saved);
if (ret == -1) {
errno = saved_errno;
return posix_error();
}
Py_RETURN_NONE;
}
#endif /* HAVE_GRANTPT */
#ifdef HAVE_UNLOCKPT
/*[clinic input]
os.unlockpt
fd: fildes
File descriptor of a master pseudo-terminal device.
/
Unlock a pseudo-terminal master/slave pair.
Performs an unlockpt() C function call.
[clinic start generated code]*/
static PyObject *
os_unlockpt_impl(PyObject *module, int fd)
/*[clinic end generated code: output=e08d354dec12d30c input=de7ab1f59f69a2b4]*/
{
if (unlockpt(fd) == -1)
return posix_error();
Py_RETURN_NONE;
}
#endif /* HAVE_UNLOCKPT */
#if defined(HAVE_PTSNAME) || defined(HAVE_PTSNAME_R)
/*[clinic input]
os.ptsname
fd: fildes
File descriptor of a master pseudo-terminal device.
/
Return the name of the slave pseudo-terminal device.
If the ptsname_r() C function is available, it is called;
otherwise, performs a ptsname() C function call.
[clinic start generated code]*/
static PyObject *
os_ptsname_impl(PyObject *module, int fd)
/*[clinic end generated code: output=ef300fadc5675872 input=1369ccc0546f3130]*/
{
#ifdef HAVE_PTSNAME_R
int ret;
char name[MAXPATHLEN+1];
ret = ptsname_r(fd, name, sizeof(name));
if (ret != 0) {
errno = ret;
return posix_error();
}
#else
char *name;
name = ptsname(fd);
/* POSIX manpage: Upon failure, ptsname() shall return a null pointer and may set errno.
*MAY* set errno? Hmm... */
if (name == NULL)
return posix_error();
#endif /* HAVE_PTSNAME_R */
return PyUnicode_DecodeFSDefault(name);
}
#endif /* defined(HAVE_PTSNAME) || defined(HAVE_PTSNAME_R) */
/* AIX uses /dev/ptc but is otherwise the same as /dev/ptmx */
#if defined(HAVE_DEV_PTC) && !defined(HAVE_DEV_PTMX)
# define DEV_PTY_FILE "/dev/ptc"
@ -16275,6 +16418,10 @@ static PyMethodDef posix_methods[] = {
OS_SCHED_YIELD_METHODDEF
OS_SCHED_SETAFFINITY_METHODDEF
OS_SCHED_GETAFFINITY_METHODDEF
OS_POSIX_OPENPT_METHODDEF
OS_GRANTPT_METHODDEF
OS_UNLOCKPT_METHODDEF
OS_PTSNAME_METHODDEF
OS_OPENPTY_METHODDEF
OS_LOGIN_TTY_METHODDEF
OS_FORKPTY_METHODDEF