popen.c revision 50479
1178580Simp/* 2178580Simp * Copyright (c) 1988 The Regents of the University of California. 3178580Simp * All rights reserved. 4178580Simp * 5178580Simp * This code is derived from software written by Ken Arnold and 6178580Simp * published in UNIX Review, Vol. 6, No. 8. 7178580Simp * 8178580Simp * Redistribution and use in source and binary forms are permitted 9178580Simp * provided that the above copyright notice and this paragraph are 10178580Simp * duplicated in all such forms and that any documentation, 11178580Simp * advertising materials, and other materials related to such 12178580Simp * distribution and use acknowledge that the software was developed 13178580Simp * by the University of California, Berkeley. The name of the 14178580Simp * University may not be used to endorse or promote products derived 15178580Simp * from this software without specific prior written permission. 16178580Simp * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17178580Simp * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18178580Simp * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19178580Simp * 20178580Simp */ 21178580Simp 22178580Simp/* this came out of the ftpd sources; it's been modified to avoid the 23178580Simp * globbing stuff since we don't need it. also execvp instead of execv. 24178580Simp */ 25178580Simp 26178580Simp#ifndef lint 27178580Simp#if 0 28178580Simpstatic char sccsid[] = "@(#)popen.c 5.7 (Berkeley) 2/14/89"; 29178580Simp#endif 30static const char rcsid[] = 31 "$FreeBSD: head/usr.sbin/cron/cron/popen.c 50479 1999-08-28 01:35:59Z peter $"; 32#endif /* not lint */ 33 34#include "cron.h" 35#include <sys/signal.h> 36#include <fcntl.h> 37 38 39#define MAX_ARGS 100 40#define WANT_GLOBBING 0 41 42/* 43 * Special version of popen which avoids call to shell. This insures noone 44 * may create a pipe to a hidden program as a side effect of a list or dir 45 * command. 46 */ 47static PID_T *pids; 48static int fds; 49 50FILE * 51cron_popen(program, type) 52 char *program, *type; 53{ 54 register char *cp; 55 FILE *iop; 56 int argc, pdes[2]; 57 PID_T pid; 58 char *argv[MAX_ARGS + 1]; 59#if WANT_GLOBBING 60 char **pop, *vv[2]; 61 int gargc; 62 char *gargv[1000]; 63 extern char **glob(), **copyblk(); 64#endif 65 66 if ((*type != 'r' && *type != 'w') || type[1]) 67 return(NULL); 68 69 if (!pids) { 70 if ((fds = getdtablesize()) <= 0) 71 return(NULL); 72 if (!(pids = (PID_T *)malloc((u_int)(fds * sizeof(PID_T))))) 73 return(NULL); 74 bzero((char *)pids, fds * sizeof(PID_T)); 75 } 76 if (pipe(pdes) < 0) 77 return(NULL); 78 79 /* break up string into pieces */ 80 for (argc = 0, cp = program; argc < MAX_ARGS; cp = NULL) 81 if (!(argv[argc++] = strtok(cp, " \t\n"))) 82 break; 83 84#if WANT_GLOBBING 85 /* glob each piece */ 86 gargv[0] = argv[0]; 87 for (gargc = argc = 1; argv[argc]; argc++) { 88 if (!(pop = glob(argv[argc]))) { /* globbing failed */ 89 vv[0] = argv[argc]; 90 vv[1] = NULL; 91 pop = copyblk(vv); 92 } 93 argv[argc] = (char *)pop; /* save to free later */ 94 while (*pop && gargc < 1000) 95 gargv[gargc++] = *pop++; 96 } 97 gargv[gargc] = NULL; 98#endif 99 100 iop = NULL; 101 switch(pid = vfork()) { 102 case -1: /* error */ 103 (void)close(pdes[0]); 104 (void)close(pdes[1]); 105 goto pfree; 106 /* NOTREACHED */ 107 case 0: /* child */ 108 if (*type == 'r') { 109 /* Do not share our parent's stdin */ 110 (void)close(0); 111 (void)open("/dev/null", O_RDWR); 112 if (pdes[1] != 1) { 113 dup2(pdes[1], 1); 114 dup2(pdes[1], 2); /* stderr, too! */ 115 (void)close(pdes[1]); 116 } 117 (void)close(pdes[0]); 118 } else { 119 if (pdes[0] != 0) { 120 dup2(pdes[0], 0); 121 (void)close(pdes[0]); 122 } 123 /* Hack: stdout gets revoked */ 124 (void)close(1); 125 (void)open("/dev/null", O_RDWR); 126 (void)close(2); 127 (void)open("/dev/null", O_RDWR); 128 (void)close(pdes[1]); 129 } 130#if WANT_GLOBBING 131 execvp(gargv[0], gargv); 132#else 133 execvp(argv[0], argv); 134#endif 135 _exit(1); 136 } 137 /* parent; assume fdopen can't fail... */ 138 if (*type == 'r') { 139 iop = fdopen(pdes[0], type); 140 (void)close(pdes[1]); 141 } else { 142 iop = fdopen(pdes[1], type); 143 (void)close(pdes[0]); 144 } 145 pids[fileno(iop)] = pid; 146 147pfree: 148#if WANT_GLOBBING 149 for (argc = 1; argv[argc] != NULL; argc++) { 150/* blkfree((char **)argv[argc]); */ 151 free((char *)argv[argc]); 152 } 153#endif 154 return(iop); 155} 156 157int 158cron_pclose(iop) 159 FILE *iop; 160{ 161 register int fdes; 162 int omask; 163 WAIT_T stat_loc; 164 PID_T pid; 165 166 /* 167 * pclose returns -1 if stream is not associated with a 168 * `popened' command, or, if already `pclosed'. 169 */ 170 if (pids == 0 || pids[fdes = fileno(iop)] == 0) 171 return(-1); 172 (void)fclose(iop); 173 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 174 while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1) 175 ; 176 (void)sigsetmask(omask); 177 pids[fdes] = 0; 178 return (pid == -1 ? -1 : WEXITSTATUS(stat_loc)); 179} 180