#ifndef lint
#if 0
static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 4/6/94";
#endif
static const char rcsid[] =
"$FreeBSD: src/libexec/ftpd/popen.c,v 1.20 2001/03/19 19:11:00 jlemon Exp $";
#endif
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <errno.h>
#include <glob.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "extern.h"
#include "pathnames.h"
#include <syslog.h>
#include <time.h>
#include <varargs.h>
#define MAXUSRARGS 100
#define MAXGLOBARGS 1000
static int *pids;
static int fds;
FILE *
ftpd_popen(program, type)
char *program, *type;
{
char *cp;
FILE *iop;
int argc, gargc, pdes[2], pid;
char **pop, *argv[MAXUSRARGS], *gargv[MAXGLOBARGS];
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(pids, 0, fds * sizeof(int));
}
if (pipe(pdes) < 0)
return (NULL);
for (argc = 0, cp = program; argc < MAXUSRARGS; cp = NULL) {
if (!(argv[argc++] = strtok(cp, " \t\n")))
break;
}
argv[argc - 1] = NULL;
gargv[0] = argv[0];
for (gargc = argc = 1; argv[argc] && gargc < (MAXGLOBARGS-1); argc++) {
glob_t gl;
int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
memset(&gl, 0, sizeof(gl));
gl.gl_matchc = MAXGLOBARGS;
#if !defined(GLOB_MAXPATH)
#define GLOB_MAXPATH 0x1000
#endif
flags |= GLOB_MAXPATH;
if (glob(argv[argc], flags, NULL, &gl))
gargv[gargc++] = strdup(argv[argc]);
else
for (pop = gl.gl_pathv; *pop && gargc < (MAXGLOBARGS-1);
pop++)
gargv[gargc++] = strdup(*pop);
globfree(&gl);
}
gargv[gargc] = NULL;
iop = NULL;
fflush(NULL);
pid = (strcmp(gargv[0], _PATH_LS) == 0) ? fork() : vfork();
switch(pid) {
case -1:
(void)close(pdes[0]);
(void)close(pdes[1]);
goto pfree;
case 0:
if (*type == 'r') {
if (pdes[1] != STDOUT_FILENO) {
dup2(pdes[1], STDOUT_FILENO);
(void)close(pdes[1]);
}
dup2(STDOUT_FILENO, STDERR_FILENO);
(void)close(pdes[0]);
} else {
if (pdes[0] != STDIN_FILENO) {
dup2(pdes[0], STDIN_FILENO);
(void)close(pdes[0]);
}
(void)close(pdes[1]);
}
if (strcmp(gargv[0], _PATH_LS) == 0) {
optreset = optind = optopt = 1;
closelog();
if (getenv("TZ") == NULL) {
setenv("TZ", "", 0);
tzset();
unsetenv("TZ");
tzset();
}
exit(ls_main(gargc, gargv));
}
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; gargv[argc] != NULL; argc++)
free(gargv[argc]);
return (iop);
}
int
ftpd_pclose(iop)
FILE *iop;
{
int fdes, omask, status;
pid_t pid;
if (pids == 0 || pids[fdes = fileno(iop)] == 0)
return (-1);
(void)fclose(iop);
omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR)
continue;
(void)sigsetmask(omask);
pids[fdes] = 0;
if (pid < 0)
return (pid);
if (WIFEXITED(status))
return (WEXITSTATUS(status));
return (1);
}