diff options
author | Elliott Hughes <enh@google.com> | 2013-03-06 16:20:55 -0800 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2013-03-06 16:20:55 -0800 |
commit | 6b3f49a5374305ce9690c3c5ca2aadc90f54c521 (patch) | |
tree | 7dcd0542e0e59e974bb6aae6a2c861e38f7d5dd1 /libc/upstream-netbsd | |
parent | db794197cc880e3805bcefbea780476a359066c2 (diff) | |
download | bionic-6b3f49a5374305ce9690c3c5ca2aadc90f54c521.zip bionic-6b3f49a5374305ce9690c3c5ca2aadc90f54c521.tar.gz bionic-6b3f49a5374305ce9690c3c5ca2aadc90f54c521.tar.bz2 |
Upgrade to current NetBSD popen/pclose.
This gets us back to using vfork now our ARM vfork assembler stub is
fixed, and adds the missing thread safety for the 'pidlist'.
Bug: 5335385
Change-Id: Ib08bfa65b2cb9fa695717aae629ea14816bf988d
Diffstat (limited to 'libc/upstream-netbsd')
-rw-r--r-- | libc/upstream-netbsd/env.h | 22 | ||||
-rw-r--r-- | libc/upstream-netbsd/libc/gen/popen.c | 227 | ||||
-rw-r--r-- | libc/upstream-netbsd/netbsd-compat.h | 9 | ||||
-rw-r--r-- | libc/upstream-netbsd/reentrant.h | 15 |
4 files changed, 272 insertions, 1 deletions
diff --git a/libc/upstream-netbsd/env.h b/libc/upstream-netbsd/env.h new file mode 100644 index 0000000..8f99f9d --- /dev/null +++ b/libc/upstream-netbsd/env.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _BIONIC_NETBSD_ENV_H_included +#define _BIONIC_NETBSD_ENV_H_included + +/* Placeholder. */ + +#endif diff --git a/libc/upstream-netbsd/libc/gen/popen.c b/libc/upstream-netbsd/libc/gen/popen.c new file mode 100644 index 0000000..593e346 --- /dev/null +++ b/libc/upstream-netbsd/libc/gen/popen.c @@ -0,0 +1,227 @@ +/* $NetBSD: popen.c,v 1.32 2012/06/25 22:32:43 abs Exp $ */ + +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software written by Ken Arnold and + * published in UNIX Review, Vol. 6, No. 8. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 5/3/95"; +#else +__RCSID("$NetBSD: popen.c,v 1.32 2012/06/25 22:32:43 abs Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/wait.h> +#include <sys/socket.h> + +#include <assert.h> +#include <errno.h> +#include <paths.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +#include "env.h" +#include "reentrant.h" + +#ifdef __weak_alias +__weak_alias(popen,_popen) +__weak_alias(pclose,_pclose) +#endif + +static struct pid { + struct pid *next; + FILE *fp; +#ifdef _REENTRANT + int fd; +#endif + pid_t pid; +} *pidlist; + +#ifdef _REENTRANT +static rwlock_t pidlist_lock = RWLOCK_INITIALIZER; +#endif + +FILE * +popen(const char *command, const char *type) +{ + struct pid *cur, *old; + FILE *iop; + const char * volatile xtype = type; + int pdes[2], pid, serrno; + volatile int twoway; + int flags; + + _DIAGASSERT(command != NULL); + _DIAGASSERT(xtype != NULL); + + flags = strchr(xtype, 'e') ? O_CLOEXEC : 0; + if (strchr(xtype, '+')) { + int stype = flags ? (SOCK_STREAM | SOCK_CLOEXEC) : SOCK_STREAM; + twoway = 1; + xtype = "r+"; + if (socketpair(AF_LOCAL, stype, 0, pdes) < 0) + return NULL; + } else { + twoway = 0; + xtype = strrchr(xtype, 'r') ? "r" : "w"; + if (pipe2(pdes, flags) == -1) + return NULL; + } + + if ((cur = malloc(sizeof(struct pid))) == NULL) { + (void)close(pdes[0]); + (void)close(pdes[1]); + errno = ENOMEM; + return (NULL); + } + + (void)rwlock_rdlock(&pidlist_lock); + (void)__readlockenv(); + switch (pid = vfork()) { + case -1: /* Error. */ + serrno = errno; + (void)__unlockenv(); + (void)rwlock_unlock(&pidlist_lock); + free(cur); + (void)close(pdes[0]); + (void)close(pdes[1]); + errno = serrno; + return (NULL); + /* NOTREACHED */ + case 0: /* Child. */ + /* POSIX.2 B.3.2.2 "popen() shall ensure that any streams + from previous popen() calls that remain open in the + parent process are closed in the new child process. */ + for (old = pidlist; old; old = old->next) +#ifdef _REENTRANT + close(old->fd); /* don't allow a flush */ +#else + close(fileno(old->fp)); /* don't allow a flush */ +#endif + + if (*xtype == 'r') { + (void)close(pdes[0]); + if (pdes[1] != STDOUT_FILENO) { + (void)dup2(pdes[1], STDOUT_FILENO); + (void)close(pdes[1]); + } + if (twoway) + (void)dup2(STDOUT_FILENO, STDIN_FILENO); + } else { + (void)close(pdes[1]); + if (pdes[0] != STDIN_FILENO) { + (void)dup2(pdes[0], STDIN_FILENO); + (void)close(pdes[0]); + } + } + + execl(_PATH_BSHELL, "sh", "-c", command, NULL); + _exit(127); + /* NOTREACHED */ + } + (void)__unlockenv(); + + /* Parent; assume fdopen can't fail. */ + if (*xtype == 'r') { + iop = fdopen(pdes[0], xtype); +#ifdef _REENTRANT + cur->fd = pdes[0]; +#endif + (void)close(pdes[1]); + } else { + iop = fdopen(pdes[1], xtype); +#ifdef _REENTRANT + cur->fd = pdes[1]; +#endif + (void)close(pdes[0]); + } + + /* Link into list of file descriptors. */ + cur->fp = iop; + cur->pid = pid; + cur->next = pidlist; + pidlist = cur; + (void)rwlock_unlock(&pidlist_lock); + + return (iop); +} + +/* + * pclose -- + * Pclose returns -1 if stream is not associated with a `popened' command, + * if already `pclosed', or waitpid returns an error. + */ +int +pclose(FILE *iop) +{ + struct pid *cur, *last; + int pstat; + pid_t pid; + + _DIAGASSERT(iop != NULL); + + rwlock_wrlock(&pidlist_lock); + + /* Find the appropriate file pointer. */ + for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) + if (cur->fp == iop) + break; + if (cur == NULL) { + (void)rwlock_unlock(&pidlist_lock); + return (-1); + } + + (void)fclose(iop); + + /* Remove the entry from the linked list. */ + if (last == NULL) + pidlist = cur->next; + else + last->next = cur->next; + + (void)rwlock_unlock(&pidlist_lock); + + do { + pid = waitpid(cur->pid, &pstat, 0); + } while (pid == -1 && errno == EINTR); + + free(cur); + + return (pid == -1 ? -1 : pstat); +} diff --git a/libc/upstream-netbsd/netbsd-compat.h b/libc/upstream-netbsd/netbsd-compat.h index 3833c1d..e33885e 100644 --- a/libc/upstream-netbsd/netbsd-compat.h +++ b/libc/upstream-netbsd/netbsd-compat.h @@ -24,4 +24,13 @@ // TODO: update our <sys/cdefs.h> to support this properly. #define __type_fit(t, a) (0 == 0) +// TODO: our 2.6 emulator kernels don't support SOCK_CLOEXEC yet, so we have to do without. +#define SOCK_CLOEXEC 0 + +#define _GNU_SOURCE + +// TODO: we don't yet have thread-safe environment variables. +#define __readlockenv() 0 +#define __unlockenv() 0 + #endif diff --git a/libc/upstream-netbsd/reentrant.h b/libc/upstream-netbsd/reentrant.h index a4381d4..e2945da 100644 --- a/libc/upstream-netbsd/reentrant.h +++ b/libc/upstream-netbsd/reentrant.h @@ -17,9 +17,22 @@ #ifndef _BIONIC_NETBSD_REENTRANT_H_included #define _BIONIC_NETBSD_REENTRANT_H_included +#define _REENTRANT + #include <pthread.h> #include <signal.h> -// Placeholder. +// +// Map NetBSD libc internal locking to pthread locking. +// + +#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#define mutex_t pthread_mutex_t + +#define RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER +#define rwlock_t pthread_rwlock_t +#define rwlock_rdlock pthread_rwlock_rdlock +#define rwlock_unlock pthread_rwlock_unlock +#define rwlock_wrlock pthread_rwlock_wrlock #endif |