diff options
author | 2014-08-31 02:21:18 +0000 | |
---|---|---|
committer | 2014-08-31 02:21:18 +0000 | |
commit | ed42a740c17f7bea88482a716bacbc46a06b7249 (patch) | |
tree | 41266fb76fcd0cc0229b872cae91df94a24ad430 /lib/libc/gen/popen.c | |
parent | regen (diff) | |
download | wireguard-openbsd-ed42a740c17f7bea88482a716bacbc46a06b7249.tar.xz wireguard-openbsd-ed42a740c17f7bea88482a716bacbc46a06b7249.zip |
Add additional userland interfaces for setting close-on-exec on fds
when creating them: mkostemp(), mkostemps(), the 'e' mode letter for
fopen(), freopen(), fdopen(), and popen(). The close-on-exec flag will
be cleared by the action created by posix_spawn_file_actions_adddup2().
Also, add support for the C11 'x' mode letter for fopen() and freopen(),
setting O_EXCL when possibly creating files.
Note: this requires kernel support for pipe2() and dup3()!
ok millert@
Diffstat (limited to 'lib/libc/gen/popen.c')
-rw-r--r-- | lib/libc/gen/popen.c | 57 |
1 files changed, 29 insertions, 28 deletions
diff --git a/lib/libc/gen/popen.c b/lib/libc/gen/popen.c index d7c6c61731f..973291d2dc8 100644 --- a/lib/libc/gen/popen.c +++ b/lib/libc/gen/popen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: popen.c,v 1.18 2007/11/26 19:26:46 kurt Exp $ */ +/* $OpenBSD: popen.c,v 1.19 2014/08/31 02:21:18 guenther Exp $ */ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. @@ -36,11 +36,13 @@ #include <signal.h> #include <errno.h> +#include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <paths.h> +#include <wchar.h> #include "thread_private.h" static struct pid { @@ -57,9 +59,11 @@ popen(const char *program, const char *type) struct pid * volatile cur; FILE *iop; int pdes[2]; + int target; pid_t pid; - if ((*type != 'r' && *type != 'w') || type[1] != '\0') { + if ((*type != 'r' && *type != 'w') || + (type[1] != '\0' && (type[1] != 'e' || type[2] != '\0'))) { errno = EINVAL; return (NULL); } @@ -67,7 +71,7 @@ popen(const char *program, const char *type) if ((cur = malloc(sizeof(struct pid))) == NULL) return (NULL); - if (pipe(pdes) < 0) { + if (pipe2(pdes, O_CLOEXEC) < 0) { free(cur); return (NULL); } @@ -84,6 +88,7 @@ popen(const char *program, const char *type) case 0: /* Child. */ { struct pid *pcur; + /* * because vfork() instead of fork(), must leak FILE *, * but luckily we are terminally headed for an execl() @@ -91,26 +96,18 @@ popen(const char *program, const char *type) for (pcur = pidlist; pcur; pcur = pcur->next) close(fileno(pcur->fp)); - if (*type == 'r') { - int tpdes1 = pdes[1]; - - (void) close(pdes[0]); - /* - * We must NOT modify pdes, due to the - * semantics of vfork. - */ - if (tpdes1 != STDOUT_FILENO) { - (void)dup2(tpdes1, STDOUT_FILENO); - (void)close(tpdes1); - tpdes1 = STDOUT_FILENO; - } + target = *type == 'r'; + if (pdes[target] != target) { + if (dup2(pdes[target], target) == -1) + _exit(127); } else { - (void)close(pdes[1]); - if (pdes[0] != STDIN_FILENO) { - (void)dup2(pdes[0], STDIN_FILENO); - (void)close(pdes[0]); - } + int flags = fcntl(pdes[target], F_GETFD); + if (flags == -1 || ((flags & FD_CLOEXEC) && + fcntl(pdes[target], F_SETFD, flags & ~FD_CLOEXEC) + == -1)) + _exit(127); } + execl(_PATH_BSHELL, "sh", "-c", program, (char *)NULL); _exit(127); /* NOTREACHED */ @@ -119,13 +116,10 @@ popen(const char *program, const char *type) _MUTEX_UNLOCK(&pidlist_lock); /* Parent; assume fdopen can't fail. */ - if (*type == 'r') { - iop = fdopen(pdes[0], type); - (void)close(pdes[1]); - } else { - iop = fdopen(pdes[1], type); - (void)close(pdes[0]); - } + target = *type == 'w'; + iop = fdopen(pdes[target], type); + fwide(iop, -1); + (void)close(pdes[!target]); /* Link into list of file descriptors. */ cur->fp = iop; @@ -135,6 +129,13 @@ popen(const char *program, const char *type) pidlist = cur; _MUTEX_UNLOCK(&pidlist_lock); + /* now that it's in the list, clear FD_CLOEXEC if unwanted */ + if (type[1] != 'e') { + int flags = fcntl(pdes[target], F_GETFD); + if (flags != -1) + fcntl(pdes[target], F_SETFD, flags & ~FD_CLOEXEC); + } + return (iop); } |