popen.c revision 62365
1/* 2 * Copyright (c) 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software written by Ken Arnold and 6 * published in UNIX Review, Vol. 6, No. 8. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the University of California, Berkeley. The name of the 14 * University may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 */ 21 22/* this came out of the ftpd sources; it's been modified to avoid the 23 * globbing stuff since we don't need it. also execvp instead of execv. 24 */ 25 26#ifndef lint 27#if 0 28static char sccsid[] = "@(#)popen.c 5.7 (Berkeley) 2/14/89"; 29#endif 30static const char rcsid[] = 31 "$FreeBSD: head/usr.sbin/cron/cron/popen.c 62365 2000-07-01 22:37:02Z ache $"; 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 argv[MAX_ARGS] = NULL; 84 85#if WANT_GLOBBING 86 /* glob each piece */ 87 gargv[0] = argv[0]; 88 for (gargc = argc = 1; argv[argc]; argc++) { 89 if (!(pop = glob(argv[argc]))) { /* globbing failed */ 90 vv[0] = argv[argc]; 91 vv[1] = NULL; 92 pop = copyblk(vv); 93 } 94 argv[argc] = (char *)pop; /* save to free later */ 95 while (*pop && gargc < 1000) 96 gargv[gargc++] = *pop++; 97 } 98 gargv[gargc] = NULL; 99#endif 100 101 iop = NULL; 102 switch(pid = vfork()) { 103 case -1: /* error */ 104 (void)close(pdes[0]); 105 (void)close(pdes[1]); 106 goto pfree; 107 /* NOTREACHED */ 108 case 0: /* child */ 109 if (*type == 'r') { 110 /* Do not share our parent's stdin */ 111 (void)close(0); 112 (void)open("/dev/null", O_RDWR); 113 if (pdes[1] != 1) { 114 dup2(pdes[1], 1); 115 dup2(pdes[1], 2); /* stderr, too! */ 116 (void)close(pdes[1]); 117 } 118 (void)close(pdes[0]); 119 } else { 120 if (pdes[0] != 0) { 121 dup2(pdes[0], 0); 122 (void)close(pdes[0]); 123 } 124 /* Hack: stdout gets revoked */ 125 (void)close(1); 126 (void)open("/dev/null", O_RDWR); 127 (void)close(2); 128 (void)open("/dev/null", O_RDWR); 129 (void)close(pdes[1]); 130 } 131#if WANT_GLOBBING 132 execvp(gargv[0], gargv); 133#else 134 execvp(argv[0], argv); 135#endif 136 _exit(1); 137 } 138 /* parent; assume fdopen can't fail... */ 139 if (*type == 'r') { 140 iop = fdopen(pdes[0], type); 141 (void)close(pdes[1]); 142 } else { 143 iop = fdopen(pdes[1], type); 144 (void)close(pdes[0]); 145 } 146 pids[fileno(iop)] = pid; 147 148pfree: 149#if WANT_GLOBBING 150 for (argc = 1; argv[argc] != NULL; argc++) { 151/* blkfree((char **)argv[argc]); */ 152 free((char *)argv[argc]); 153 } 154#endif 155 return(iop); 156} 157 158int 159cron_pclose(iop) 160 FILE *iop; 161{ 162 register int fdes; 163 int omask; 164 WAIT_T stat_loc; 165 PID_T pid; 166 167 /* 168 * pclose returns -1 if stream is not associated with a 169 * `popened' command, or, if already `pclosed'. 170 */ 171 if (pids == 0 || pids[fdes = fileno(iop)] == 0) 172 return(-1); 173 (void)fclose(iop); 174 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 175 while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1) 176 ; 177 (void)sigsetmask(omask); 178 pids[fdes] = 0; 179 return (pid == -1 ? -1 : WEXITSTATUS(stat_loc)); 180} 181