summaryrefslogtreecommitdiffstats
path: root/libcrecovery/popen.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcrecovery/popen.c')
-rw-r--r--libcrecovery/popen.c169
1 files changed, 169 insertions, 0 deletions
diff --git a/libcrecovery/popen.c b/libcrecovery/popen.c
new file mode 100644
index 000000000..73d3c7437
--- /dev/null
+++ b/libcrecovery/popen.c
@@ -0,0 +1,169 @@
+/* $OpenBSD: popen.c,v 1.17 2005/08/08 08:05:34 espie 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/param.h>
+#include <sys/wait.h>
+
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+
+#include "defines.h"
+
+static struct pid {
+ struct pid *next;
+ FILE *fp;
+ pid_t pid;
+} *pidlist;
+
+FILE *
+__popen(const char *program, const char *type)
+{
+ struct pid * volatile cur;
+ FILE *iop;
+ int pdes[2];
+ pid_t pid;
+
+ if ((*type != 'r' && *type != 'w') || type[1] != '\0') {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if ((cur = malloc(sizeof(struct pid))) == NULL)
+ return (NULL);
+
+ if (pipe(pdes) < 0) {
+ free(cur);
+ return (NULL);
+ }
+
+ switch (pid = vfork()) {
+ case -1: /* Error. */
+ (void)close(pdes[0]);
+ (void)close(pdes[1]);
+ free(cur);
+ return (NULL);
+ /* NOTREACHED */
+ case 0: /* Child. */
+ {
+ struct pid *pcur;
+ /*
+ * because vfork() instead of fork(), must leak FILE *,
+ * but luckily we are terminally headed for an execl()
+ */
+ 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;
+ }
+ } 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", program, (char *)NULL);
+ _exit(127);
+ /* NOTREACHED */
+ }
+ }
+
+ /* 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]);
+ }
+
+ /* Link into list of file descriptors. */
+ cur->fp = iop;
+ cur->pid = pid;
+ cur->next = pidlist;
+ pidlist = cur;
+
+ 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;
+
+ /* Find the appropriate file pointer. */
+ for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
+ if (cur->fp == iop)
+ break;
+
+ if (cur == NULL)
+ return (-1);
+
+ (void)fclose(iop);
+
+ do {
+ pid = waitpid(cur->pid, &pstat, 0);
+ } while (pid == -1 && errno == EINTR);
+
+ /* Remove the entry from the linked list. */
+ if (last == NULL)
+ pidlist = cur->next;
+ else
+ last->next = cur->next;
+ free(cur);
+
+ return (pid == -1 ? -1 : pstat);
+}