summaryrefslogtreecommitdiffstats
path: root/Modules/posixmodule.c
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2013-08-27 22:53:59 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2013-08-27 22:53:59 (GMT)
commitdaf455554bc21b6b5df0a016ab5fa639d36cc595 (patch)
tree216f52f9f6d9aed0406b2ce2574e5a02aa93e327 /Modules/posixmodule.c
parent46e1ce214b5711e8dae63a1b5a0a7aafb371baf0 (diff)
downloadcpython-daf455554bc21b6b5df0a016ab5fa639d36cc595.zip
cpython-daf455554bc21b6b5df0a016ab5fa639d36cc595.tar.gz
cpython-daf455554bc21b6b5df0a016ab5fa639d36cc595.tar.bz2
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().
Diffstat (limited to 'Modules/posixmodule.c')
-rw-r--r--Modules/posixmodule.c335
1 files changed, 297 insertions, 38 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index fde6752..6570142 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -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 */
};