mirror of
https://github.com/python/cpython.git
synced 2025-11-01 18:51:43 +00:00
Issue #18571: Implementation of the PEP 446: file descriptors and file handles
are now created non-inheritable; add functions os.get/set_inheritable(), os.get/set_handle_inheritable() and socket.socket.get/set_inheritable().
This commit is contained in:
parent
46e1ce214b
commit
daf455554b
51 changed files with 1448 additions and 317 deletions
|
|
@ -3535,10 +3535,7 @@ _posix_listdir(path_t *path, PyObject *list)
|
|||
#ifdef HAVE_FDOPENDIR
|
||||
if (path->fd != -1) {
|
||||
/* closedir() closes the FD, so we duplicate it */
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
fd = dup(path->fd);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
fd = _Py_dup(path->fd);
|
||||
if (fd == -1) {
|
||||
list = posix_error();
|
||||
goto exit;
|
||||
|
|
@ -5768,7 +5765,7 @@ Open a pseudo-terminal, returning open fd's for both master and slave end.\n");
|
|||
static PyObject *
|
||||
posix_openpty(PyObject *self, PyObject *noargs)
|
||||
{
|
||||
int master_fd, slave_fd;
|
||||
int master_fd = -1, slave_fd = -1;
|
||||
#ifndef HAVE_OPENPTY
|
||||
char * slave_name;
|
||||
#endif
|
||||
|
|
@ -5781,37 +5778,52 @@ posix_openpty(PyObject *self, PyObject *noargs)
|
|||
|
||||
#ifdef HAVE_OPENPTY
|
||||
if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) != 0)
|
||||
return posix_error();
|
||||
goto posix_error;
|
||||
|
||||
if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
|
||||
goto error;
|
||||
if (_Py_set_inheritable(slave_fd, 0, NULL) < 0)
|
||||
goto error;
|
||||
|
||||
#elif defined(HAVE__GETPTY)
|
||||
slave_name = _getpty(&master_fd, O_RDWR, 0666, 0);
|
||||
if (slave_name == NULL)
|
||||
return posix_error();
|
||||
goto posix_error;
|
||||
if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
|
||||
goto error;
|
||||
|
||||
slave_fd = open(slave_name, O_RDWR);
|
||||
slave_fd = _Py_open(slave_name, O_RDWR);
|
||||
if (slave_fd < 0)
|
||||
return posix_error();
|
||||
goto posix_error;
|
||||
|
||||
#else
|
||||
master_fd = open(DEV_PTY_FILE, O_RDWR | O_NOCTTY); /* open master */
|
||||
master_fd = _Py_open(DEV_PTY_FILE, O_RDWR | O_NOCTTY); /* open master */
|
||||
if (master_fd < 0)
|
||||
return posix_error();
|
||||
goto posix_error;
|
||||
|
||||
sig_saved = PyOS_setsig(SIGCHLD, SIG_DFL);
|
||||
|
||||
/* change permission of slave */
|
||||
if (grantpt(master_fd) < 0) {
|
||||
PyOS_setsig(SIGCHLD, sig_saved);
|
||||
return posix_error();
|
||||
goto posix_error;
|
||||
}
|
||||
|
||||
/* unlock slave */
|
||||
if (unlockpt(master_fd) < 0) {
|
||||
PyOS_setsig(SIGCHLD, sig_saved);
|
||||
return posix_error();
|
||||
goto posix_error;
|
||||
}
|
||||
|
||||
PyOS_setsig(SIGCHLD, sig_saved);
|
||||
|
||||
slave_name = ptsname(master_fd); /* get name of slave */
|
||||
if (slave_name == NULL)
|
||||
return posix_error();
|
||||
slave_fd = open(slave_name, O_RDWR | O_NOCTTY); /* open slave */
|
||||
goto posix_error;
|
||||
|
||||
slave_fd = _Py_open(slave_name, O_RDWR | O_NOCTTY); /* open slave */
|
||||
if (slave_fd < 0)
|
||||
return posix_error();
|
||||
goto posix_error;
|
||||
#if !defined(__CYGWIN__) && !defined(HAVE_DEV_PTC)
|
||||
ioctl(slave_fd, I_PUSH, "ptem"); /* push ptem */
|
||||
ioctl(slave_fd, I_PUSH, "ldterm"); /* push ldterm */
|
||||
|
|
@ -5823,6 +5835,14 @@ posix_openpty(PyObject *self, PyObject *noargs)
|
|||
|
||||
return Py_BuildValue("(ii)", master_fd, slave_fd);
|
||||
|
||||
posix_error:
|
||||
posix_error();
|
||||
error:
|
||||
if (master_fd != -1)
|
||||
close(master_fd);
|
||||
if (slave_fd != -1)
|
||||
close(slave_fd);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) */
|
||||
|
||||
|
|
@ -7432,6 +7452,10 @@ posix_tcsetpgrp(PyObject *self, PyObject *args)
|
|||
|
||||
/* Functions acting on file descriptors */
|
||||
|
||||
#ifdef O_CLOEXEC
|
||||
extern int _Py_open_cloexec_works;
|
||||
#endif
|
||||
|
||||
PyDoc_STRVAR(posix_open__doc__,
|
||||
"open(path, flags, mode=0o777, *, dir_fd=None)\n\n\
|
||||
Open a file for low level IO. Returns a file handle (integer).\n\
|
||||
|
|
@ -7451,6 +7475,11 @@ posix_open(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
int fd;
|
||||
PyObject *return_value = NULL;
|
||||
static char *keywords[] = {"path", "flags", "mode", "dir_fd", NULL};
|
||||
#ifdef O_CLOEXEC
|
||||
int *atomic_flag_works = &_Py_open_cloexec_works;
|
||||
#elif !defined(MS_WINDOWS)
|
||||
int *atomic_flag_works = NULL;
|
||||
#endif
|
||||
|
||||
memset(&path, 0, sizeof(path));
|
||||
path.function_name = "open";
|
||||
|
|
@ -7465,6 +7494,12 @@ posix_open(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
))
|
||||
return NULL;
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
flags |= O_NOINHERIT;
|
||||
#elif defined(O_CLOEXEC)
|
||||
flags |= O_CLOEXEC;
|
||||
#endif
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
#ifdef MS_WINDOWS
|
||||
if (path.wide)
|
||||
|
|
@ -7484,6 +7519,13 @@ posix_open(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
goto exit;
|
||||
}
|
||||
|
||||
#ifndef MS_WINDOWS
|
||||
if (_Py_set_inheritable(fd, 0, atomic_flag_works) < 0) {
|
||||
close(fd);
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
|
||||
return_value = PyLong_FromLong((long)fd);
|
||||
|
||||
exit:
|
||||
|
|
@ -7540,13 +7582,14 @@ static PyObject *
|
|||
posix_dup(PyObject *self, PyObject *args)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:dup", &fd))
|
||||
return NULL;
|
||||
if (!_PyVerify_fd(fd))
|
||||
return posix_error();
|
||||
fd = dup(fd);
|
||||
if (fd < 0)
|
||||
return posix_error();
|
||||
|
||||
fd = _Py_dup(fd);
|
||||
if (fd == -1)
|
||||
return NULL;
|
||||
|
||||
return PyLong_FromLong((long)fd);
|
||||
}
|
||||
|
||||
|
|
@ -7556,16 +7599,82 @@ PyDoc_STRVAR(posix_dup2__doc__,
|
|||
Duplicate file descriptor.");
|
||||
|
||||
static PyObject *
|
||||
posix_dup2(PyObject *self, PyObject *args)
|
||||
posix_dup2(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
int fd, fd2, res;
|
||||
if (!PyArg_ParseTuple(args, "ii:dup2", &fd, &fd2))
|
||||
static char *keywords[] = {"fd", "fd2", "inheritable", NULL};
|
||||
int fd, fd2;
|
||||
int inheritable = 1;
|
||||
int res;
|
||||
#if defined(HAVE_DUP3) && \
|
||||
!(defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC))
|
||||
/* dup3() is available on Linux 2.6.27+ and glibc 2.9 */
|
||||
int dup3_works = -1;
|
||||
#endif
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|i:dup2", keywords,
|
||||
&fd, &fd2, &inheritable))
|
||||
return NULL;
|
||||
|
||||
if (!_PyVerify_fd_dup2(fd, fd2))
|
||||
return posix_error();
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = dup2(fd, fd2);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (res < 0)
|
||||
return posix_error();
|
||||
|
||||
/* Character files like console cannot be make non-inheritable */
|
||||
if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
|
||||
close(fd2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC)
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
if (!inheritable)
|
||||
res = fcntl(fd, F_DUP2FD_CLOEXEC, fd2);
|
||||
else
|
||||
res = dup2(fd, fd2);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (res < 0)
|
||||
return posix_error();
|
||||
|
||||
#else
|
||||
|
||||
#ifdef HAVE_DUP3
|
||||
if (!inheritable && dup3_works != 0) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = dup3(fd, fd2, O_CLOEXEC);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (res < 0) {
|
||||
if (dup3_works == -1)
|
||||
dup3_works = (errno != ENOSYS);
|
||||
if (dup3_works)
|
||||
return posix_error();
|
||||
}
|
||||
}
|
||||
|
||||
if (inheritable || dup3_works == 0)
|
||||
{
|
||||
#endif
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = dup2(fd, fd2);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (res < 0)
|
||||
return posix_error();
|
||||
|
||||
if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
|
||||
close(fd2);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef HAVE_DUP3
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
|
@ -8052,24 +8161,69 @@ Create a pipe.");
|
|||
static PyObject *
|
||||
posix_pipe(PyObject *self, PyObject *noargs)
|
||||
{
|
||||
#if !defined(MS_WINDOWS)
|
||||
int fds[2];
|
||||
int res;
|
||||
res = pipe(fds);
|
||||
if (res != 0)
|
||||
return posix_error();
|
||||
return Py_BuildValue("(ii)", fds[0], fds[1]);
|
||||
#else /* MS_WINDOWS */
|
||||
#ifdef MS_WINDOWS
|
||||
HANDLE read, write;
|
||||
int read_fd, write_fd;
|
||||
SECURITY_ATTRIBUTES attr;
|
||||
BOOL ok;
|
||||
ok = CreatePipe(&read, &write, NULL, 0);
|
||||
#else
|
||||
int res;
|
||||
#endif
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
attr.nLength = sizeof(attr);
|
||||
attr.lpSecurityDescriptor = NULL;
|
||||
attr.bInheritHandle = FALSE;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ok = CreatePipe(&read, &write, &attr, 0);
|
||||
if (ok) {
|
||||
fds[0] = _open_osfhandle((Py_intptr_t)read, _O_RDONLY);
|
||||
fds[1] = _open_osfhandle((Py_intptr_t)write, _O_WRONLY);
|
||||
if (fds[0] == -1 || fds[1] == -1) {
|
||||
CloseHandle(read);
|
||||
CloseHandle(write);
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (!ok)
|
||||
return PyErr_SetFromWindowsErr(0);
|
||||
read_fd = _open_osfhandle((Py_intptr_t)read, 0);
|
||||
write_fd = _open_osfhandle((Py_intptr_t)write, 1);
|
||||
return Py_BuildValue("(ii)", read_fd, write_fd);
|
||||
#endif /* MS_WINDOWS */
|
||||
#else
|
||||
|
||||
#ifdef HAVE_PIPE2
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = pipe2(fds, O_CLOEXEC);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (res != 0 && errno == ENOSYS)
|
||||
{
|
||||
#endif
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = pipe(fds);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (res == 0) {
|
||||
if (_Py_set_inheritable(fds[0], 0, NULL) < 0) {
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return NULL;
|
||||
}
|
||||
if (_Py_set_inheritable(fds[1], 0, NULL) < 0) {
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_PIPE2
|
||||
}
|
||||
#endif
|
||||
|
||||
if (res != 0)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
#endif /* !MS_WINDOWS */
|
||||
return Py_BuildValue("(ii)", fds[0], fds[1]);
|
||||
}
|
||||
#endif /* HAVE_PIPE */
|
||||
|
||||
|
|
@ -10659,6 +10813,102 @@ posix_cpu_count(PyObject *self)
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(get_inheritable__doc__,
|
||||
"get_inheritable(fd) -> bool\n" \
|
||||
"\n" \
|
||||
"Get the close-on-exe flag of the specified file descriptor.");
|
||||
|
||||
static PyObject*
|
||||
posix_get_inheritable(PyObject *self, PyObject *args)
|
||||
{
|
||||
int fd;
|
||||
int inheritable;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i:get_inheritable", &fd))
|
||||
return NULL;
|
||||
|
||||
if (!_PyVerify_fd(fd))
|
||||
return posix_error();
|
||||
|
||||
inheritable = _Py_get_inheritable(fd);
|
||||
if (inheritable < 0)
|
||||
return NULL;
|
||||
return PyBool_FromLong(inheritable);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(set_inheritable__doc__,
|
||||
"set_inheritable(fd, inheritable)\n" \
|
||||
"\n" \
|
||||
"Set the inheritable flag of the specified file descriptor.");
|
||||
|
||||
static PyObject*
|
||||
posix_set_inheritable(PyObject *self, PyObject *args)
|
||||
{
|
||||
int fd, inheritable;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ii:set_inheritable", &fd, &inheritable))
|
||||
return NULL;
|
||||
|
||||
if (!_PyVerify_fd(fd))
|
||||
return posix_error();
|
||||
|
||||
if (_Py_set_inheritable(fd, inheritable, NULL) < 0)
|
||||
return NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
PyDoc_STRVAR(get_handle_inheritable__doc__,
|
||||
"get_handle_inheritable(fd) -> bool\n" \
|
||||
"\n" \
|
||||
"Get the close-on-exe flag of the specified file descriptor.");
|
||||
|
||||
static PyObject*
|
||||
posix_get_handle_inheritable(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_intptr_t handle;
|
||||
DWORD flags;
|
||||
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_INTPTR ":get_handle_inheritable", &handle))
|
||||
return NULL;
|
||||
|
||||
if (!GetHandleInformation((HANDLE)handle, &flags)) {
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyBool_FromLong(flags & HANDLE_FLAG_INHERIT);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(set_handle_inheritable__doc__,
|
||||
"set_handle_inheritable(fd, inheritable)\n" \
|
||||
"\n" \
|
||||
"Set the inheritable flag of the specified handle.");
|
||||
|
||||
static PyObject*
|
||||
posix_set_handle_inheritable(PyObject *self, PyObject *args)
|
||||
{
|
||||
int inheritable = 1;
|
||||
Py_intptr_t handle;
|
||||
DWORD flags;
|
||||
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_INTPTR "i:set_handle_inheritable",
|
||||
&handle, &inheritable))
|
||||
return NULL;
|
||||
|
||||
if (inheritable)
|
||||
flags = HANDLE_FLAG_INHERIT;
|
||||
else
|
||||
flags = 0;
|
||||
if (!SetHandleInformation((HANDLE)handle, HANDLE_FLAG_INHERIT, flags)) {
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
#endif /* MS_WINDOWS */
|
||||
|
||||
|
||||
static PyMethodDef posix_methods[] = {
|
||||
{"access", (PyCFunction)posix_access,
|
||||
|
|
@ -10934,7 +11184,8 @@ static PyMethodDef posix_methods[] = {
|
|||
{"closerange", posix_closerange, METH_VARARGS, posix_closerange__doc__},
|
||||
{"device_encoding", device_encoding, METH_VARARGS, device_encoding__doc__},
|
||||
{"dup", posix_dup, METH_VARARGS, posix_dup__doc__},
|
||||
{"dup2", posix_dup2, METH_VARARGS, posix_dup2__doc__},
|
||||
{"dup2", (PyCFunction)posix_dup2,
|
||||
METH_VARARGS | METH_KEYWORDS, posix_dup2__doc__},
|
||||
#ifdef HAVE_LOCKF
|
||||
{"lockf", posix_lockf, METH_VARARGS, posix_lockf__doc__},
|
||||
#endif
|
||||
|
|
@ -11105,6 +11356,14 @@ static PyMethodDef posix_methods[] = {
|
|||
#endif
|
||||
{"cpu_count", (PyCFunction)posix_cpu_count,
|
||||
METH_NOARGS, posix_cpu_count__doc__},
|
||||
{"get_inheritable", posix_get_inheritable, METH_VARARGS, get_inheritable__doc__},
|
||||
{"set_inheritable", posix_set_inheritable, METH_VARARGS, set_inheritable__doc__},
|
||||
#ifdef MS_WINDOWS
|
||||
{"get_handle_inheritable", posix_get_handle_inheritable,
|
||||
METH_VARARGS, get_handle_inheritable__doc__},
|
||||
{"set_handle_inheritable", posix_set_handle_inheritable,
|
||||
METH_VARARGS, set_handle_inheritable__doc__},
|
||||
#endif
|
||||
{NULL, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue