#ifndef lint
static char sccsid[] = "@(#)popen.c 5.9 (Berkeley) 2/25/91";
#endif
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ftpd_var.h"
static int *pids;
static int fds;
#define MAX_ARGV 100
#define MAX_GARGV 1000
FILE *
ftpd_popen(program, type)
char *program, *type;
{
register char *cp;
FILE *volatile iop;
int argc, gargc, pdes[2], pid;
char **pop, *argv[MAX_ARGV], *gargv[MAX_GARGV], *vv[2];
extern char **ftpglob(), **copyblk();
extern void blkfree(char **);
if ((*type != 'r' && *type != 'w') || type[1])
return(NULL);
if (!pids) {
if ((fds = getdtablesize()) <= 0)
return(NULL);
if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
return(NULL);
memset((char *)pids, 0, fds * sizeof(int));
}
if (pipe(pdes) < 0)
return(NULL);
for (argc = 0, cp = program; argc < MAX_ARGV - 1; cp = NULL)
if (!(argv[argc++] = strtok(cp, " \t\n")))
break;
argv[MAX_ARGV-1] = NULL;
for (argc = 0; argv[argc]; argc++)
argv[argc] = strdup(argv[argc]);
gargv[0] = argv[0];
for (gargc = argc = 1; argv[argc]; argc++) {
if (!(pop = ftpglob(argv[argc]))) {
vv[0] = argv[argc];
vv[1] = NULL;
pop = copyblk(vv);
}
argv[argc] = (char *)pop;
while (*pop && gargc < MAX_GARGV)
gargv[gargc++] = *pop++;
}
gargv[gargc] = NULL;
iop = NULL;
switch(pid = fork()) {
case -1:
(void)close(pdes[0]);
(void)close(pdes[1]);
goto pfree;
case 0:
if (*type == 'r') {
if (pdes[1] != 1) {
dup2(pdes[1], 1);
dup2(pdes[1], 2);
(void)close(pdes[1]);
}
(void)close(pdes[0]);
} else {
if (pdes[0] != 0) {
dup2(pdes[0], 0);
(void)close(pdes[0]);
}
(void)close(pdes[1]);
}
execv(gargv[0], gargv);
_exit(1);
}
if (*type == 'r') {
iop = fdopen(pdes[0], type);
(void)close(pdes[1]);
} else {
iop = fdopen(pdes[1], type);
(void)close(pdes[0]);
}
pids[fileno(iop)] = pid;
pfree: for (argc = 1; argv[argc] != NULL; argc++) {
blkfree((char **)argv[argc]);
free((char *)argv[argc]);
}
return(iop);
}
int
ftpd_pclose(iop)
FILE *iop;
{
register int fdes;
#ifdef USE_SIGPROCMASK
sigset_t old, new;
#else
int omask;
#endif
#ifdef WAIT_USES_INT
int stat_loc;
#else
union wait stat_loc;
#endif
int pid;
if (pids == 0 || pids[fdes = fileno(iop)] == 0)
return(-1);
(void)fclose(iop);
#ifdef USE_SIGPROCMASK
sigemptyset(&old);
sigemptyset(&new);
sigaddset(&new,SIGINT);
sigaddset(&new,SIGQUIT);
sigaddset(&new,SIGHUP);
sigprocmask(SIG_BLOCK, &new, &old);
while ((pid = wait((int *)&stat_loc)) != pids[fdes] && pid != -1);
sigprocmask(SIG_SETMASK, &old, NULL);
#else
omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
while ((pid = wait((int *)&stat_loc)) != pids[fdes] && pid != -1);
sigsetmask(omask);
#endif
pids[fdes] = 0;
#ifdef WAIT_USES_INT
return(pid == -1 ? -1 : stat_loc);
#else
return(pid == -1 ? -1 : stat_loc.w_status);
#endif
}