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