version 1.1.1.1, 1993/03/21 09:45:37 |
version 1.12, 1996/06/29 00:51:49 |
|
|
|
/* $NetBSD$ */ |
|
|
/* |
/* |
* Copyright (c) 1988 The Regents of the University of California. |
* Copyright (c) 1988, 1993 |
* All rights reserved. |
* The Regents of the University of California. All rights reserved. |
* |
* |
* This code is derived from software written by Ken Arnold and |
* This code is derived from software written by Ken Arnold and |
* published in UNIX Review, Vol. 6, No. 8. |
* published in UNIX Review, Vol. 6, No. 8. |
|
|
*/ |
*/ |
|
|
#if defined(LIBC_SCCS) && !defined(lint) |
#if defined(LIBC_SCCS) && !defined(lint) |
static char sccsid[] = "@(#)popen.c 5.15 (Berkeley) 2/23/91"; |
#if 0 |
|
static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/4/93"; |
|
#else |
|
static char rcsid[] = "$NetBSD$"; |
|
#endif |
#endif /* LIBC_SCCS and not lint */ |
#endif /* LIBC_SCCS and not lint */ |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/signal.h> |
|
#include <sys/wait.h> |
#include <sys/wait.h> |
|
|
|
#include <signal.h> |
#include <errno.h> |
#include <errno.h> |
|
#include <unistd.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <unistd.h> |
|
#include <paths.h> |
#include <paths.h> |
|
|
static pid_t *pids; |
static struct pid { |
|
struct pid *next; |
|
FILE *fp; |
|
pid_t pid; |
|
} *pidlist; |
|
|
FILE * |
FILE * |
popen(program, type) |
popen(program, type) |
const char *program; |
const char *program; |
const char *type; |
const char *type; |
{ |
{ |
|
struct pid *cur; |
FILE *iop; |
FILE *iop; |
int pdes[2], fds, pid; |
int pdes[2], pid; |
|
|
if (*type != 'r' && *type != 'w' || type[1]) |
if (*type != 'r' && *type != 'w' || type[1]) { |
|
errno = EINVAL; |
return (NULL); |
return (NULL); |
|
|
if (pids == NULL) { |
|
if ((fds = getdtablesize()) <= 0) |
|
return (NULL); |
|
if ((pids = (pid_t *)malloc((u_int)(fds * sizeof(int)))) == NULL) |
|
return (NULL); |
|
bzero((char *)pids, fds * sizeof(pid_t)); |
|
} |
} |
if (pipe(pdes) < 0) |
|
|
if ((cur = malloc(sizeof(struct pid))) == NULL) |
return (NULL); |
return (NULL); |
|
|
|
if (pipe(pdes) < 0) { |
|
free(cur); |
|
return (NULL); |
|
} |
|
|
switch (pid = vfork()) { |
switch (pid = vfork()) { |
case -1: /* error */ |
case -1: /* Error. */ |
(void) close(pdes[0]); |
(void)close(pdes[0]); |
(void) close(pdes[1]); |
(void)close(pdes[1]); |
|
free(cur); |
return (NULL); |
return (NULL); |
/* NOTREACHED */ |
/* NOTREACHED */ |
case 0: /* child */ |
case 0: /* Child. */ |
if (*type == 'r') { |
if (*type == 'r') { |
if (pdes[1] != STDOUT_FILENO) { |
if (pdes[1] != STDOUT_FILENO) { |
(void) dup2(pdes[1], STDOUT_FILENO); |
(void)dup2(pdes[1], STDOUT_FILENO); |
(void) close(pdes[1]); |
(void)close(pdes[1]); |
} |
} |
(void) close(pdes[0]); |
(void) close(pdes[0]); |
} else { |
} else { |
if (pdes[0] != STDIN_FILENO) { |
if (pdes[0] != STDIN_FILENO) { |
(void) dup2(pdes[0], STDIN_FILENO); |
(void)dup2(pdes[0], STDIN_FILENO); |
(void) close(pdes[0]); |
(void)close(pdes[0]); |
} |
} |
(void) close(pdes[1]); |
(void)close(pdes[1]); |
} |
} |
|
|
|
/* 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 (cur = pidlist; cur; cur = cur->next) |
|
close(fileno(cur->fp)); |
|
|
execl(_PATH_BSHELL, "sh", "-c", program, NULL); |
execl(_PATH_BSHELL, "sh", "-c", program, NULL); |
_exit(127); |
_exit(127); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
/* parent; assume fdopen can't fail... */ |
|
|
/* Parent; assume fdopen can't fail. */ |
if (*type == 'r') { |
if (*type == 'r') { |
iop = fdopen(pdes[0], type); |
iop = fdopen(pdes[0], type); |
(void) close(pdes[1]); |
(void)close(pdes[1]); |
} else { |
} else { |
iop = fdopen(pdes[1], type); |
iop = fdopen(pdes[1], type); |
(void) close(pdes[0]); |
(void)close(pdes[0]); |
} |
} |
pids[fileno(iop)] = pid; |
|
|
/* Link into list of file descriptors. */ |
|
cur->fp = iop; |
|
cur->pid = pid; |
|
cur->next = pidlist; |
|
pidlist = cur; |
|
|
return (iop); |
return (iop); |
} |
} |
|
|
|
/* |
|
* pclose -- |
|
* Pclose returns -1 if stream is not associated with a `popened' command, |
|
* if already `pclosed', or waitpid returns an error. |
|
*/ |
int |
int |
pclose(iop) |
pclose(iop) |
FILE *iop; |
FILE *iop; |
{ |
{ |
register int fdes; |
register struct pid *cur, *last; |
int omask; |
int pstat; |
union wait pstat; |
|
pid_t pid; |
pid_t pid; |
|
|
/* |
(void)fclose(iop); |
* pclose returns -1 if stream is not associated with a |
|
* `popened' command, if already `pclosed', or waitpid |
/* Find the appropriate file pointer. */ |
* returns an error. |
for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) |
*/ |
if (cur->fp == iop) |
if (pids == NULL || pids[fdes = fileno(iop)] == 0) |
break; |
|
if (cur == NULL) |
return (-1); |
return (-1); |
(void) fclose(iop); |
|
omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); |
|
do { |
do { |
pid = waitpid(pids[fdes], (int *) &pstat, 0); |
pid = waitpid(cur->pid, &pstat, 0); |
} while (pid == -1 && errno == EINTR); |
} while (pid == -1 && errno == EINTR); |
(void) sigsetmask(omask); |
|
pids[fdes] = 0; |
/* Remove the entry from the linked list. */ |
return (pid == -1 ? -1 : pstat.w_status); |
if (last == NULL) |
|
pidlist = cur->next; |
|
else |
|
last->next = cur->next; |
|
free(cur); |
|
|
|
return (pid == -1 ? -1 : pstat); |
} |
} |