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