1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 static char sccsid[] = "@(#)popen.c 5.13 (Berkeley) 07/08/88"; 20 #endif /* not lint */ 21 22 #include "rcv.h" 23 #include <sys/signal.h> 24 #include <sys/wait.h> 25 26 #define READ 0 27 #define WRITE 1 28 static int *pid; 29 30 FILE * 31 Popen(cmd, mode) 32 char *cmd; 33 char *mode; 34 { 35 int p[2]; 36 int myside, hisside, fd0, fd1; 37 38 if (pid == 0) 39 pid = (int *) malloc((unsigned) sizeof (int) * getdtablesize()); 40 if (pipe(p) < 0) 41 return NULL; 42 if (*mode == 'r') { 43 myside = p[READ]; 44 fd0 = -1; 45 hisside = fd1 = p[WRITE]; 46 } else { 47 myside = p[WRITE]; 48 hisside = fd0 = p[READ]; 49 fd1 = -1; 50 } 51 if ((pid[myside] = start_command(cmd, 0, fd0, fd1, NOSTR)) < 0) { 52 close(p[READ]); 53 close(p[WRITE]); 54 return NULL; 55 } 56 close(hisside); 57 return fdopen(myside, mode); 58 } 59 60 Pclose(ptr) 61 FILE *ptr; 62 { 63 int i; 64 int omask; 65 66 i = fileno(ptr); 67 fclose(ptr); 68 omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP)); 69 i = wait_child(pid[i]); 70 sigsetmask(omask); 71 return i; 72 } 73 74 /* 75 * Run a command without a shell, with optional arguments and splicing 76 * of stdin and stdout. The command name can be a sequence of words. 77 * Signals must be handled by the caller. 78 * "Mask" contains the signals to ignore in the new process. 79 * SIGINT is enabled unless it's in the mask. 80 */ 81 /*VARARGS4*/ 82 run_command(cmd, mask, infd, outfd, a0, a1, a2) 83 char *cmd; 84 int mask, infd, outfd; 85 char *a0, *a1, *a2; 86 { 87 int pid; 88 89 if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0) 90 return -1; 91 return wait_command(pid); 92 } 93 94 /*VARARGS4*/ 95 start_command(cmd, mask, infd, outfd, a0, a1, a2) 96 char *cmd; 97 int mask, infd, outfd; 98 char *a0, *a1, *a2; 99 { 100 int pid; 101 102 if ((pid = vfork()) < 0) { 103 perror("fork"); 104 return -1; 105 } 106 if (pid == 0) { 107 char *argv[100]; 108 int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv); 109 110 if ((argv[i++] = a0) != NOSTR && 111 (argv[i++] = a1) != NOSTR && 112 (argv[i++] = a2) != NOSTR) 113 argv[i] = NOSTR; 114 prepare_child(mask, infd, outfd); 115 execvp(argv[0], argv); 116 perror(argv[0]); 117 _exit(1); 118 } 119 return pid; 120 } 121 122 prepare_child(mask, infd, outfd) 123 int mask, infd, outfd; 124 { 125 int i; 126 127 if (infd >= 0) 128 dup2(infd, 0); 129 if (outfd >= 0) 130 dup2(outfd, 1); 131 for (i = getdtablesize(); --i > 2;) 132 close(i); 133 for (i = 1; i <= NSIG; i++) 134 if (mask & sigmask(i)) 135 (void) signal(i, SIG_IGN); 136 if ((mask & sigmask(SIGINT)) == 0) 137 (void) signal(SIGINT, SIG_DFL); 138 (void) sigsetmask(0); 139 } 140 141 wait_command(pid) 142 int pid; 143 { 144 145 if (wait_child(pid) < 0) { 146 printf("Fatal error in process.\n"); 147 return -1; 148 } 149 return 0; 150 } 151 152 struct child { 153 int pid; 154 char done; 155 char free; 156 union wait status; 157 struct child *link; 158 }; 159 static struct child *child; 160 161 struct child * 162 findchild(pid) 163 int pid; 164 { 165 register struct child **cpp; 166 167 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 168 cpp = &(*cpp)->link) 169 ; 170 if (*cpp == NULL) { 171 *cpp = (struct child *) malloc(sizeof (struct child)); 172 (*cpp)->pid = pid; 173 (*cpp)->done = (*cpp)->free = 0; 174 (*cpp)->link = NULL; 175 } 176 return *cpp; 177 } 178 179 delchild(cp) 180 register struct child *cp; 181 { 182 register struct child **cpp; 183 184 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 185 ; 186 *cpp = cp->link; 187 free((char *) cp); 188 } 189 190 sigchild() 191 { 192 int pid; 193 union wait status; 194 register struct child *cp; 195 196 while ((pid = wait3(&status, WNOHANG, (struct timeval *)0)) > 0) { 197 cp = findchild(pid); 198 if (cp->free) 199 delchild(cp); 200 else { 201 cp->done = 1; 202 cp->status = status; 203 } 204 } 205 } 206 207 union wait wait_status; 208 209 /* 210 * Wait for a specific child to die. 211 */ 212 wait_child(pid) 213 int pid; 214 { 215 int mask = sigblock(sigmask(SIGCHLD)); 216 register struct child *cp = findchild(pid); 217 218 while (!cp->done) 219 sigpause(mask); 220 wait_status = cp->status; 221 delchild(cp); 222 sigsetmask(mask); 223 return wait_status.w_status ? -1 : 0; 224 } 225 226 /* 227 * Mark a child as don't care. 228 */ 229 free_child(pid) 230 int pid; 231 { 232 int mask = sigblock(sigmask(SIGCHLD)); 233 register struct child *cp = findchild(pid); 234 235 if (cp->done) 236 delchild(cp); 237 else 238 cp->free = 1; 239 sigsetmask(mask); 240 } 241