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 __FBSDID("$FreeBSD$"); 39 40 #include "rcv.h" 41 #include <sys/wait.h> 42 #include <fcntl.h> 43 #include <errno.h> 44 #include <stdarg.h> 45 #include "extern.h" 46 47 #define READ 0 48 #define WRITE 1 49 50 struct fp { 51 FILE *fp; 52 int pipe; 53 pid_t pid; 54 struct fp *link; 55 }; 56 static struct fp *fp_head; 57 58 struct child { 59 pid_t pid; 60 char done; 61 char free; 62 int status; 63 struct child *link; 64 }; 65 static struct child *child, *child_freelist = NULL; 66 67 static void delchild(struct child *); 68 static pid_t file_pid(FILE *); 69 static pid_t start_commandv(char *, sigset_t *, int, int, va_list); 70 71 FILE * 72 Fopen(const char *path, const char *mode) 73 { 74 FILE *fp; 75 76 if ((fp = fopen(path, mode)) != NULL) { 77 register_file(fp, 0, 0); 78 (void)fcntl(fileno(fp), F_SETFD, 1); 79 } 80 return (fp); 81 } 82 83 FILE * 84 Fdopen(int fd, const char *mode) 85 { 86 FILE *fp; 87 88 if ((fp = fdopen(fd, mode)) != NULL) { 89 register_file(fp, 0, 0); 90 (void)fcntl(fileno(fp), F_SETFD, 1); 91 } 92 return (fp); 93 } 94 95 int 96 Fclose(FILE *fp) 97 { 98 99 unregister_file(fp); 100 return (fclose(fp)); 101 } 102 103 FILE * 104 Popen(char *cmd, const char *mode) 105 { 106 int p[2]; 107 int myside, hisside, fd0, fd1; 108 pid_t pid; 109 sigset_t nset; 110 FILE *fp; 111 112 if (pipe(p) < 0) 113 return (NULL); 114 (void)fcntl(p[READ], F_SETFD, 1); 115 (void)fcntl(p[WRITE], F_SETFD, 1); 116 if (*mode == 'r') { 117 myside = p[READ]; 118 hisside = fd0 = fd1 = p[WRITE]; 119 } else { 120 myside = p[WRITE]; 121 hisside = fd0 = p[READ]; 122 fd1 = -1; 123 } 124 (void)sigemptyset(&nset); 125 pid = start_command(value("SHELL"), &nset, fd0, fd1, "-c", cmd, NULL); 126 if (pid < 0) { 127 (void)close(p[READ]); 128 (void)close(p[WRITE]); 129 return (NULL); 130 } 131 (void)close(hisside); 132 if ((fp = fdopen(myside, mode)) != NULL) 133 register_file(fp, 1, pid); 134 return (fp); 135 } 136 137 int 138 Pclose(FILE *ptr) 139 { 140 int i; 141 sigset_t nset, oset; 142 143 i = file_pid(ptr); 144 unregister_file(ptr); 145 (void)fclose(ptr); 146 (void)sigemptyset(&nset); 147 (void)sigaddset(&nset, SIGINT); 148 (void)sigaddset(&nset, SIGHUP); 149 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 150 i = wait_child(i); 151 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 152 return (i); 153 } 154 155 void 156 close_all_files(void) 157 { 158 159 while (fp_head != NULL) 160 if (fp_head->pipe) 161 (void)Pclose(fp_head->fp); 162 else 163 (void)Fclose(fp_head->fp); 164 } 165 166 void 167 register_file(FILE *fp, int pipe, pid_t pid) 168 { 169 struct fp *fpp; 170 171 if ((fpp = malloc(sizeof(*fpp))) == NULL) 172 err(1, "Out of memory"); 173 fpp->fp = fp; 174 fpp->pipe = pipe; 175 fpp->pid = pid; 176 fpp->link = fp_head; 177 fp_head = fpp; 178 } 179 180 void 181 unregister_file(FILE *fp) 182 { 183 struct fp **pp, *p; 184 185 for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link) 186 if (p->fp == fp) { 187 *pp = p->link; 188 (void)free(p); 189 return; 190 } 191 errx(1, "Invalid file pointer"); 192 /*NOTREACHED*/ 193 } 194 195 pid_t 196 file_pid(FILE *fp) 197 { 198 struct fp *p; 199 200 for (p = fp_head; p != NULL; p = p->link) 201 if (p->fp == fp) 202 return (p->pid); 203 errx(1, "Invalid file pointer"); 204 /*NOTREACHED*/ 205 } 206 207 /* 208 * Run a command without a shell, with optional arguments and splicing 209 * of stdin (-1 means none) and stdout. The command name can be a sequence 210 * of words. 211 * Signals must be handled by the caller. 212 * "nset" contains the signals to ignore in the new process. 213 * SIGINT is enabled unless it's in "nset". 214 */ 215 static pid_t 216 start_commandv(char *cmd, sigset_t *nset, int infd, int outfd, va_list args) 217 { 218 pid_t pid; 219 220 if ((pid = fork()) < 0) { 221 warn("fork"); 222 return (-1); 223 } 224 if (pid == 0) { 225 char *argv[100]; 226 int i = getrawlist(cmd, argv, sizeof(argv) / sizeof(*argv)); 227 228 while ((argv[i++] = va_arg(args, char *))) 229 ; 230 argv[i] = NULL; 231 prepare_child(nset, infd, outfd); 232 execvp(argv[0], argv); 233 warn("%s", argv[0]); 234 _exit(1); 235 } 236 return (pid); 237 } 238 239 int 240 run_command(char *cmd, sigset_t *nset, int infd, int outfd, ...) 241 { 242 pid_t pid; 243 va_list args; 244 245 va_start(args, outfd); 246 pid = start_commandv(cmd, nset, infd, outfd, args); 247 va_end(args); 248 if (pid < 0) 249 return -1; 250 return wait_command(pid); 251 } 252 253 int 254 start_command(char *cmd, sigset_t *nset, int infd, int outfd, ...) 255 { 256 va_list args; 257 int r; 258 259 va_start(args, outfd); 260 r = start_commandv(cmd, nset, infd, outfd, args); 261 va_end(args); 262 return r; 263 } 264 265 void 266 prepare_child(sigset_t *nset, int infd, int outfd) 267 { 268 int i; 269 sigset_t eset; 270 271 /* 272 * All file descriptors other than 0, 1, and 2 are supposed to be 273 * close-on-exec. 274 */ 275 if (infd >= 0) 276 dup2(infd, 0); 277 if (outfd >= 0) 278 dup2(outfd, 1); 279 for (i = 1; i < NSIG; i++) 280 if (nset != NULL && sigismember(nset, i)) 281 (void)signal(i, SIG_IGN); 282 if (nset == NULL || !sigismember(nset, SIGINT)) 283 (void)signal(SIGINT, SIG_DFL); 284 (void)sigemptyset(&eset); 285 (void)sigprocmask(SIG_SETMASK, &eset, NULL); 286 } 287 288 int 289 wait_command(pid_t pid) 290 { 291 292 if (wait_child(pid) < 0) { 293 printf("Fatal error in process.\n"); 294 return (-1); 295 } 296 return (0); 297 } 298 299 static struct child * 300 findchild(pid_t pid, int dont_alloc) 301 { 302 struct child **cpp; 303 304 for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; 305 cpp = &(*cpp)->link) 306 ; 307 if (*cpp == NULL) { 308 if (dont_alloc) 309 return(NULL); 310 if (child_freelist) { 311 *cpp = child_freelist; 312 child_freelist = (*cpp)->link; 313 } else { 314 *cpp = malloc(sizeof(struct child)); 315 if (*cpp == NULL) 316 err(1, "malloc"); 317 } 318 (*cpp)->pid = pid; 319 (*cpp)->done = (*cpp)->free = 0; 320 (*cpp)->link = NULL; 321 } 322 return (*cpp); 323 } 324 325 static void 326 delchild(struct child *cp) 327 { 328 struct child **cpp; 329 330 for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) 331 ; 332 *cpp = cp->link; 333 cp->link = child_freelist; 334 child_freelist = cp; 335 } 336 337 /*ARGSUSED*/ 338 void 339 sigchild(int signo __unused) 340 { 341 pid_t pid; 342 int status; 343 struct child *cp; 344 int save_errno; 345 346 save_errno = errno; 347 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { 348 cp = findchild(pid, 1); 349 if (cp == NULL) 350 continue; 351 if (cp->free) 352 delchild(cp); 353 else { 354 cp->done = 1; 355 cp->status = status; 356 } 357 } 358 errno = save_errno; 359 } 360 361 int wait_status; 362 363 /* 364 * Wait for a specific child to die. 365 */ 366 int 367 wait_child(pid_t pid) 368 { 369 struct child *cp; 370 sigset_t nset, oset; 371 pid_t rv = 0; 372 373 (void)sigemptyset(&nset); 374 (void)sigaddset(&nset, SIGCHLD); 375 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 376 /* 377 * If we have not already waited on the pid (via sigchild) 378 * wait on it now. Otherwise, use the wait status stashed 379 * by sigchild. 380 */ 381 cp = findchild(pid, 1); 382 if (cp == NULL || !cp->done) 383 rv = waitpid(pid, &wait_status, 0); 384 else 385 wait_status = cp->status; 386 if (cp != NULL) 387 delchild(cp); 388 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 389 if (rv == -1 || (WIFEXITED(wait_status) && WEXITSTATUS(wait_status))) 390 return -1; 391 else 392 return 0; 393 } 394 395 /* 396 * Mark a child as don't care. 397 */ 398 void 399 free_child(pid_t pid) 400 { 401 struct child *cp; 402 sigset_t nset, oset; 403 404 (void)sigemptyset(&nset); 405 (void)sigaddset(&nset, SIGCHLD); 406 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 407 if ((cp = findchild(pid, 0)) != NULL) { 408 if (cp->done) 409 delchild(cp); 410 else 411 cp->free = 1; 412 } 413 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 414 } 415