1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1980, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #ifndef lint 33 #if 0 34 static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93"; 35 #endif 36 #endif /* not lint */ 37 #include <sys/cdefs.h> 38 #include "rcv.h" 39 #include <sys/wait.h> 40 #include <fcntl.h> 41 #include <errno.h> 42 #include <stdarg.h> 43 #include "extern.h" 44 45 #define READ 0 46 #define WRITE 1 47 48 struct fp { 49 FILE *fp; 50 int pipe; 51 pid_t pid; 52 struct fp *link; 53 }; 54 static struct fp *fp_head; 55 56 struct child { 57 pid_t pid; 58 char done; 59 char free; 60 int status; 61 struct child *link; 62 }; 63 static struct child *child, *child_freelist = NULL; 64 65 static void delchild(struct child *); 66 static pid_t file_pid(FILE *); 67 static pid_t start_commandv(char *, sigset_t *, int, int, va_list); 68 69 FILE * 70 Fopen(const char *path, const char *mode) 71 { 72 FILE *fp; 73 74 if ((fp = fopen(path, mode)) != NULL) { 75 register_file(fp, 0, 0); 76 (void)fcntl(fileno(fp), F_SETFD, 1); 77 } 78 return (fp); 79 } 80 81 FILE * 82 Fdopen(int fd, const char *mode) 83 { 84 FILE *fp; 85 86 if ((fp = fdopen(fd, mode)) != NULL) { 87 register_file(fp, 0, 0); 88 (void)fcntl(fileno(fp), F_SETFD, 1); 89 } 90 return (fp); 91 } 92 93 int 94 Fclose(FILE *fp) 95 { 96 97 unregister_file(fp); 98 return (fclose(fp)); 99 } 100 101 FILE * 102 Popen(char *cmd, const char *mode) 103 { 104 int p[2]; 105 int myside, hisside, fd0, fd1; 106 pid_t pid; 107 sigset_t nset; 108 FILE *fp; 109 110 if (pipe(p) < 0) 111 return (NULL); 112 (void)fcntl(p[READ], F_SETFD, 1); 113 (void)fcntl(p[WRITE], F_SETFD, 1); 114 if (*mode == 'r') { 115 myside = p[READ]; 116 hisside = fd0 = fd1 = p[WRITE]; 117 } else { 118 myside = p[WRITE]; 119 hisside = fd0 = p[READ]; 120 fd1 = -1; 121 } 122 (void)sigemptyset(&nset); 123 pid = start_command(value("SHELL"), &nset, fd0, fd1, "-c", cmd, NULL); 124 if (pid < 0) { 125 (void)close(p[READ]); 126 (void)close(p[WRITE]); 127 return (NULL); 128 } 129 (void)close(hisside); 130 if ((fp = fdopen(myside, mode)) != NULL) 131 register_file(fp, 1, pid); 132 return (fp); 133 } 134 135 int 136 Pclose(FILE *ptr) 137 { 138 int i; 139 sigset_t nset, oset; 140 141 i = file_pid(ptr); 142 unregister_file(ptr); 143 (void)fclose(ptr); 144 (void)sigemptyset(&nset); 145 (void)sigaddset(&nset, SIGINT); 146 (void)sigaddset(&nset, SIGHUP); 147 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 148 i = wait_child(i); 149 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 150 return (i); 151 } 152 153 void 154 close_all_files(void) 155 { 156 157 while (fp_head != NULL) 158 if (fp_head->pipe) 159 (void)Pclose(fp_head->fp); 160 else 161 (void)Fclose(fp_head->fp); 162 } 163 164 void 165 register_file(FILE *fp, int pipe, pid_t pid) 166 { 167 struct fp *fpp; 168 169 if ((fpp = malloc(sizeof(*fpp))) == NULL) 170 err(1, "Out of memory"); 171 fpp->fp = fp; 172 fpp->pipe = pipe; 173 fpp->pid = pid; 174 fpp->link = fp_head; 175 fp_head = fpp; 176 } 177 178 void 179 unregister_file(FILE *fp) 180 { 181 struct fp **pp, *p; 182 183 for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link) 184 if (p->fp == fp) { 185 *pp = p->link; 186 (void)free(p); 187 return; 188 } 189 errx(1, "Invalid file pointer"); 190 /*NOTREACHED*/ 191 } 192 193 pid_t 194 file_pid(FILE *fp) 195 { 196 struct fp *p; 197 198 for (p = fp_head; p != NULL; p = p->link) 199 if (p->fp == fp) 200 return (p->pid); 201 errx(1, "Invalid file pointer"); 202 /*NOTREACHED*/ 203 } 204 205 /* 206 * Run a command without a shell, with optional arguments and splicing 207 * of stdin (-1 means none) and stdout. The command name can be a sequence 208 * of words. 209 * Signals must be handled by the caller. 210 * "nset" contains the signals to ignore in the new process. 211 * SIGINT is enabled unless it's in "nset". 212 */ 213 static pid_t 214 start_commandv(char *cmd, sigset_t *nset, int infd, int outfd, va_list args) 215 { 216 pid_t pid; 217 218 if ((pid = fork()) < 0) { 219 warn("fork"); 220 return (-1); 221 } 222 if (pid == 0) { 223 char *argv[100]; 224 int i = getrawlist(cmd, argv, sizeof(argv) / sizeof(*argv)); 225 226 while ((argv[i++] = va_arg(args, char *))) 227 ; 228 argv[i] = NULL; 229 prepare_child(nset, infd, outfd); 230 execvp(argv[0], argv); 231 warn("%s", argv[0]); 232 _exit(1); 233 } 234 return (pid); 235 } 236 237 int 238 run_command(char *cmd, sigset_t *nset, int infd, int outfd, ...) 239 { 240 pid_t pid; 241 va_list args; 242 243 va_start(args, outfd); 244 pid = start_commandv(cmd, nset, infd, outfd, args); 245 va_end(args); 246 if (pid < 0) 247 return -1; 248 return wait_command(pid); 249 } 250 251 int 252 start_command(char *cmd, sigset_t *nset, int infd, int outfd, ...) 253 { 254 va_list args; 255 int r; 256 257 va_start(args, outfd); 258 r = start_commandv(cmd, nset, infd, outfd, args); 259 va_end(args); 260 return r; 261 } 262 263 void 264 prepare_child(sigset_t *nset, int infd, int outfd) 265 { 266 int i; 267 sigset_t eset; 268 269 /* 270 * All file descriptors other than 0, 1, and 2 are supposed to be 271 * close-on-exec. 272 */ 273 if (infd >= 0) 274 dup2(infd, 0); 275 if (outfd >= 0) 276 dup2(outfd, 1); 277 for (i = 1; i < NSIG; i++) 278 if (nset != NULL && sigismember(nset, i)) 279 (void)signal(i, SIG_IGN); 280 if (nset == NULL || !sigismember(nset, SIGINT)) 281 (void)signal(SIGINT, SIG_DFL); 282 (void)sigemptyset(&eset); 283 (void)sigprocmask(SIG_SETMASK, &eset, NULL); 284 } 285 286 int 287 wait_command(pid_t pid) 288 { 289 290 if (wait_child(pid) < 0) { 291 printf("Fatal error in process.\n"); 292 return (-1); 293 } 294 return (0); 295 } 296 297 static struct child * 298 findchild(pid_t pid, int dont_alloc) 299 { 300 struct child **cpp; 301 302 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 303 cpp = &(*cpp)->link) 304 ; 305 if (*cpp == NULL) { 306 if (dont_alloc) 307 return(NULL); 308 if (child_freelist) { 309 *cpp = child_freelist; 310 child_freelist = (*cpp)->link; 311 } else { 312 *cpp = malloc(sizeof(struct child)); 313 if (*cpp == NULL) 314 err(1, "malloc"); 315 } 316 (*cpp)->pid = pid; 317 (*cpp)->done = (*cpp)->free = 0; 318 (*cpp)->link = NULL; 319 } 320 return (*cpp); 321 } 322 323 static void 324 delchild(struct child *cp) 325 { 326 struct child **cpp; 327 328 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 329 ; 330 *cpp = cp->link; 331 cp->link = child_freelist; 332 child_freelist = cp; 333 } 334 335 /*ARGSUSED*/ 336 void 337 sigchild(int signo __unused) 338 { 339 pid_t pid; 340 int status; 341 struct child *cp; 342 int save_errno; 343 344 save_errno = errno; 345 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { 346 cp = findchild(pid, 1); 347 if (cp == NULL) 348 continue; 349 if (cp->free) 350 delchild(cp); 351 else { 352 cp->done = 1; 353 cp->status = status; 354 } 355 } 356 errno = save_errno; 357 } 358 359 int wait_status; 360 361 /* 362 * Wait for a specific child to die. 363 */ 364 int 365 wait_child(pid_t pid) 366 { 367 struct child *cp; 368 sigset_t nset, oset; 369 pid_t rv = 0; 370 371 (void)sigemptyset(&nset); 372 (void)sigaddset(&nset, SIGCHLD); 373 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 374 /* 375 * If we have not already waited on the pid (via sigchild) 376 * wait on it now. Otherwise, use the wait status stashed 377 * by sigchild. 378 */ 379 cp = findchild(pid, 1); 380 if (cp == NULL || !cp->done) 381 rv = waitpid(pid, &wait_status, 0); 382 else 383 wait_status = cp->status; 384 if (cp != NULL) 385 delchild(cp); 386 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 387 if (rv == -1 || (WIFEXITED(wait_status) && WEXITSTATUS(wait_status))) 388 return -1; 389 else 390 return 0; 391 } 392 393 /* 394 * Mark a child as don't care. 395 */ 396 void 397 free_child(pid_t pid) 398 { 399 struct child *cp; 400 sigset_t nset, oset; 401 402 (void)sigemptyset(&nset); 403 (void)sigaddset(&nset, SIGCHLD); 404 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 405 if ((cp = findchild(pid, 0)) != NULL) { 406 if (cp->done) 407 delchild(cp); 408 else 409 cp->free = 1; 410 } 411 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 412 } 413