popen.c revision 29452
1262152Sluigi/* 2262152Sluigi * Copyright (c) 1988 The Regents of the University of California. 3262152Sluigi * All rights reserved. 4262152Sluigi * 5262152Sluigi * This code is derived from software written by Ken Arnold and 6262152Sluigi * published in UNIX Review, Vol. 6, No. 8. 7262152Sluigi * 8262152Sluigi * Redistribution and use in source and binary forms are permitted 9262152Sluigi * provided that the above copyright notice and this paragraph are 10262152Sluigi * duplicated in all such forms and that any documentation, 11262152Sluigi * advertising materials, and other materials related to such 12262152Sluigi * distribution and use acknowledge that the software was developed 13262152Sluigi * by the University of California, Berkeley. The name of the 14262152Sluigi * University may not be used to endorse or promote products derived 15262152Sluigi * from this software without specific prior written permission. 16262152Sluigi * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17262152Sluigi * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18262152Sluigi * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19262152Sluigi * 20262152Sluigi */ 21262152Sluigi 22262152Sluigi/* this came out of the ftpd sources; it's been modified to avoid the 23262152Sluigi * globbing stuff since we don't need it. also execvp instead of execv. 24262152Sluigi */ 25262152Sluigi 26262152Sluigi#ifndef lint 27262152Sluigi#if 0 28262152Sluigistatic char sccsid[] = "@(#)popen.c 5.7 (Berkeley) 2/14/89"; 29262152Sluigi#endif 30262152Sluigistatic const char rcsid[] = 31262152Sluigi "$Id$"; 32262152Sluigi#endif /* not lint */ 33262152Sluigi 34262152Sluigi#include "cron.h" 35262152Sluigi#include <sys/signal.h> 36262152Sluigi 37262152Sluigi 38262152Sluigi#define MAX_ARGS 100 39262152Sluigi#define WANT_GLOBBING 0 40262152Sluigi 41262152Sluigi/* 42262152Sluigi * Special version of popen which avoids call to shell. This insures noone 43262152Sluigi * may create a pipe to a hidden program as a side effect of a list or dir 44262152Sluigi * command. 45262152Sluigi */ 46262152Sluigistatic PID_T *pids; 47262152Sluigistatic int fds; 48262152Sluigi 49262152SluigiFILE * 50262152Sluigicron_popen(program, type) 51262152Sluigi char *program, *type; 52262152Sluigi{ 53262152Sluigi register char *cp; 54262152Sluigi FILE *iop; 55262152Sluigi int argc, pdes[2]; 56262152Sluigi PID_T pid; 57262152Sluigi char *argv[MAX_ARGS + 1]; 58262152Sluigi#if WANT_GLOBBING 59262152Sluigi char **pop, *vv[2]; 60262152Sluigi int gargc; 61262152Sluigi char *gargv[1000]; 62262152Sluigi extern char **glob(), **copyblk(); 63262152Sluigi#endif 64262152Sluigi 65262152Sluigi if ((*type != 'r' && *type != 'w') || type[1]) 66262152Sluigi return(NULL); 67262152Sluigi 68262152Sluigi if (!pids) { 69262152Sluigi if ((fds = getdtablesize()) <= 0) 70262152Sluigi return(NULL); 71262152Sluigi if (!(pids = (PID_T *)malloc((u_int)(fds * sizeof(PID_T))))) 72262152Sluigi return(NULL); 73262152Sluigi bzero((char *)pids, fds * sizeof(PID_T)); 74262152Sluigi } 75262152Sluigi if (pipe(pdes) < 0) 76262152Sluigi return(NULL); 77262152Sluigi 78262152Sluigi /* break up string into pieces */ 79262152Sluigi for (argc = 0, cp = program; argc < MAX_ARGS; cp = NULL) 80262152Sluigi if (!(argv[argc++] = strtok(cp, " \t\n"))) 81262152Sluigi break; 82262152Sluigi 83262152Sluigi#if WANT_GLOBBING 84262152Sluigi /* glob each piece */ 85262152Sluigi gargv[0] = argv[0]; 86262152Sluigi for (gargc = argc = 1; argv[argc]; argc++) { 87262152Sluigi if (!(pop = glob(argv[argc]))) { /* globbing failed */ 88262152Sluigi vv[0] = argv[argc]; 89262152Sluigi vv[1] = NULL; 90262152Sluigi pop = copyblk(vv); 91262152Sluigi } 92262152Sluigi argv[argc] = (char *)pop; /* save to free later */ 93262152Sluigi while (*pop && gargc < 1000) 94262152Sluigi gargv[gargc++] = *pop++; 95262152Sluigi } 96262152Sluigi gargv[gargc] = NULL; 97262152Sluigi#endif 98262152Sluigi 99262152Sluigi iop = NULL; 100262152Sluigi switch(pid = vfork()) { 101262152Sluigi case -1: /* error */ 102262152Sluigi (void)close(pdes[0]); 103262152Sluigi (void)close(pdes[1]); 104262152Sluigi goto pfree; 105262152Sluigi /* NOTREACHED */ 106262152Sluigi case 0: /* child */ 107262152Sluigi if (*type == 'r') { 108262152Sluigi if (pdes[1] != 1) { 109262152Sluigi dup2(pdes[1], 1); 110262152Sluigi dup2(pdes[1], 2); /* stderr, too! */ 111262152Sluigi (void)close(pdes[1]); 112262152Sluigi } 113262152Sluigi (void)close(pdes[0]); 114262152Sluigi } else { 115262152Sluigi if (pdes[0] != 0) { 116262152Sluigi dup2(pdes[0], 0); 117262152Sluigi (void)close(pdes[0]); 118262152Sluigi } 119262152Sluigi (void)close(pdes[1]); 120262152Sluigi } 121262152Sluigi#if WANT_GLOBBING 122262152Sluigi execvp(gargv[0], gargv); 123262152Sluigi#else 124262152Sluigi execvp(argv[0], argv); 125262152Sluigi#endif 126262152Sluigi _exit(1); 127262152Sluigi } 128262152Sluigi /* parent; assume fdopen can't fail... */ 129262152Sluigi if (*type == 'r') { 130262152Sluigi iop = fdopen(pdes[0], type); 131262152Sluigi (void)close(pdes[1]); 132262152Sluigi } else { 133262152Sluigi iop = fdopen(pdes[1], type); 134262152Sluigi (void)close(pdes[0]); 135262152Sluigi } 136262152Sluigi pids[fileno(iop)] = pid; 137262152Sluigi 138262152Sluigipfree: 139262152Sluigi#if WANT_GLOBBING 140262152Sluigi for (argc = 1; argv[argc] != NULL; argc++) { 141262152Sluigi/* blkfree((char **)argv[argc]); */ 142262152Sluigi free((char *)argv[argc]); 143262152Sluigi } 144262152Sluigi#endif 145262152Sluigi return(iop); 146262152Sluigi} 147262152Sluigi 148262152Sluigiint 149262152Sluigicron_pclose(iop) 150262152Sluigi FILE *iop; 151262152Sluigi{ 152262152Sluigi register int fdes; 153262152Sluigi int omask; 154262152Sluigi WAIT_T stat_loc; 155262152Sluigi PID_T pid; 156262152Sluigi 157262152Sluigi /* 158262152Sluigi * pclose returns -1 if stream is not associated with a 159262152Sluigi * `popened' command, or, if already `pclosed'. 160262152Sluigi */ 161262152Sluigi if (pids == 0 || pids[fdes = fileno(iop)] == 0) 162270252Sluigi return(-1); 163262152Sluigi (void)fclose(iop); 164262152Sluigi omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 165262152Sluigi while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1) 166262152Sluigi ; 167262152Sluigi (void)sigsetmask(omask); 168262152Sluigi pids[fdes] = 0; 169262152Sluigi return (pid == -1 ? -1 : WEXITSTATUS(stat_loc)); 170262152Sluigi} 171262152Sluigi