summaryrefslogtreecommitdiff
path: root/lib/libc
diff options
context:
space:
mode:
authorJilles Tjoelker <jilles@FreeBSD.org>2013-10-27 21:49:52 +0000
committerJilles Tjoelker <jilles@FreeBSD.org>2013-10-27 21:49:52 +0000
commitf7ac7dae04495f9c8eda7ef223f4c3aa4adea3a3 (patch)
treebce615ddb3d482a6ded8d654cc0812526438c177 /lib/libc
parentaa5e088c696fb748d9d20371efc367bce09a67cc (diff)
downloadsrc-test2-f7ac7dae04495f9c8eda7ef223f4c3aa4adea3a3.tar.gz
src-test2-f7ac7dae04495f9c8eda7ef223f4c3aa4adea3a3.zip
Notes
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/stdio/fdopen.c6
-rw-r--r--lib/libc/stdio/flags.c50
-rw-r--r--lib/libc/stdio/fopen.317
-rw-r--r--lib/libc/stdio/freopen.c5
4 files changed, 55 insertions, 23 deletions
diff --git a/lib/libc/stdio/fdopen.c b/lib/libc/stdio/fdopen.c
index 26e2cd70bc1e..8fc90a438b99 100644
--- a/lib/libc/stdio/fdopen.c
+++ b/lib/libc/stdio/fdopen.c
@@ -80,6 +80,12 @@ fdopen(fd, mode)
if ((fp = __sfp()) == NULL)
return (NULL);
+
+ if ((oflags & O_CLOEXEC) && _fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
+ fp->_flags = 0;
+ return (NULL);
+ }
+
fp->_flags = flags;
/*
* If opened for appending, but underlying descriptor does not have
diff --git a/lib/libc/stdio/flags.c b/lib/libc/stdio/flags.c
index 0b6b0755bd3b..d08071dd71b6 100644
--- a/lib/libc/stdio/flags.c
+++ b/lib/libc/stdio/flags.c
@@ -53,7 +53,7 @@ __sflags(mode, optr)
const char *mode;
int *optr;
{
- int ret, m, o;
+ int ret, m, o, known;
switch (*mode++) {
@@ -80,28 +80,34 @@ __sflags(mode, optr)
return (0);
}
- /* 'b' (binary) is ignored */
- if (*mode == 'b')
- mode++;
-
- /* [rwa][b]\+ means read and write */
- if (*mode == '+') {
- mode++;
- ret = __SRW;
- m = O_RDWR;
- }
-
- /* 'b' (binary) can appear here, too -- and is ignored again */
- if (*mode == 'b')
- mode++;
-
- /* 'x' means exclusive (fail if the file exists) */
- if (*mode == 'x') {
- if (m == O_RDONLY) {
- errno = EINVAL;
- return (0);
+ do {
+ known = 1;
+ switch (*mode++) {
+ case 'b':
+ /* 'b' (binary) is ignored */
+ break;
+ case '+':
+ /* [rwa][b]\+ means read and write */
+ ret = __SRW;
+ m = O_RDWR;
+ break;
+ case 'x':
+ /* 'x' means exclusive (fail if the file exists) */
+ o |= O_EXCL;
+ break;
+ case 'e':
+ /* set close-on-exec */
+ o |= O_CLOEXEC;
+ break;
+ default:
+ known = 0;
+ break;
}
- o |= O_EXCL;
+ } while (known);
+
+ if ((o & O_EXCL) != 0 && m == O_RDONLY) {
+ errno = EINVAL;
+ return (0);
}
*optr = m | o;
diff --git a/lib/libc/stdio/fopen.3 b/lib/libc/stdio/fopen.3
index 57f5a3dbf88b..f11f4e07e3de 100644
--- a/lib/libc/stdio/fopen.3
+++ b/lib/libc/stdio/fopen.3
@@ -100,6 +100,14 @@ or
causes the
.Fn fopen
call to fail if the file already exists.
+An optional
+.Dq Li e
+following the above
+causes the
+.Fn fopen
+call to set the
+.Dv FD_CLOEXEC
+flag on the underlying file descriptor.
.Pp
The
.Fa mode
@@ -149,6 +157,11 @@ of the stream must be compatible with the mode of the file descriptor.
The
.Dq Li x
mode option is ignored.
+If the
+.Dq Li e
+mode option is present, the
+.Dv FD_CLOEXEC
+flag is set, otherwise it remains unchanged.
When the stream is closed via
.Xr fclose 3 ,
.Fa fildes
@@ -313,6 +326,10 @@ function
conforms to
.St -p1003.1-88 .
The
+.Dq Li e
+mode option does not conform to any standard
+but is also supported by glibc.
+The
.Fn fmemopen
function
conforms to
diff --git a/lib/libc/stdio/freopen.c b/lib/libc/stdio/freopen.c
index be7bc8a2f8d0..8d1ec917086a 100644
--- a/lib/libc/stdio/freopen.c
+++ b/lib/libc/stdio/freopen.c
@@ -118,6 +118,8 @@ freopen(file, mode, fp)
(void) ftruncate(fp->_file, (off_t)0);
if (!(oflags & O_APPEND))
(void) _sseek(fp, (fpos_t)0, SEEK_SET);
+ if (oflags & O_CLOEXEC)
+ (void) _fcntl(fp->_file, F_SETFD, FD_CLOEXEC);
f = fp->_file;
isopen = 0;
wantfd = -1;
@@ -194,7 +196,8 @@ finish:
* assume stderr is always fd STDERR_FILENO, even if being freopen'd.
*/
if (wantfd >= 0) {
- if (_dup2(f, wantfd) >= 0) {
+ if ((oflags & O_CLOEXEC ? _fcntl(f, F_DUP2FD_CLOEXEC, wantfd) :
+ _dup2(f, wantfd)) >= 0) {
(void)_close(f);
f = wantfd;
} else