1 /* $OpenBSD: sem.c,v 1.23 2019/06/28 13:34:58 deraadt Exp $ */ 2 /* $NetBSD: sem.c,v 1.9 1995/09/27 00:38:50 jtc Exp $ */ 3 4 /*- 5 * Copyright (c) 1980, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 #include <limits.h> 41 #include <stdarg.h> 42 43 #include "csh.h" 44 #include "proc.h" 45 #include "extern.h" 46 47 static void vffree(int); 48 static Char *splicepipe(struct command *t, Char *); 49 static void doio(struct command *t, int *, int *); 50 static void chkclob(char *); 51 52 void 53 execute(struct command *t, int wanttty, int *pipein, int *pipeout) 54 { 55 bool forked = 0; 56 struct biltins *bifunc; 57 int pid = 0; 58 int pv[2]; 59 sigset_t sigset; 60 61 static sigset_t csigset; 62 63 static sigset_t ocsigset; 64 static int onosigchld = 0; 65 static int nosigchld = 0; 66 67 UNREGISTER(forked); 68 UNREGISTER(bifunc); 69 UNREGISTER(wanttty); 70 71 if (t == 0) 72 return; 73 74 if (t->t_dflg & F_AMPERSAND) 75 wanttty = 0; 76 switch (t->t_dtyp) { 77 78 case NODE_COMMAND: 79 if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE) 80 (void) memmove(t->t_dcom[0], t->t_dcom[0] + 1, 81 (Strlen(t->t_dcom[0] + 1) + 1) * sizeof(Char)); 82 if ((t->t_dflg & F_REPEAT) == 0) 83 Dfix(t); /* $ " ' \ */ 84 if (t->t_dcom[0] == 0) 85 return; 86 /* fall into... */ 87 88 case NODE_PAREN: 89 if (t->t_dflg & F_PIPEOUT) 90 mypipe(pipeout); 91 /* 92 * Must do << early so parent will know where input pointer should be. 93 * If noexec then this is all we do. 94 */ 95 if (t->t_dflg & F_READ) { 96 (void) close(0); 97 heredoc(t->t_dlef); 98 if (noexec) 99 (void) close(0); 100 } 101 102 set(STRstatus, Strsave(STR0)); 103 104 /* 105 * This mess is the necessary kludge to handle the prefix builtins: 106 * nice, nohup, time. These commands can also be used by themselves, 107 * and this is not handled here. This will also work when loops are 108 * parsed. 109 */ 110 while (t->t_dtyp == NODE_COMMAND) 111 if (eq(t->t_dcom[0], STRnice)) 112 if (t->t_dcom[1]) 113 if (strchr("+-", t->t_dcom[1][0])) 114 if (t->t_dcom[2]) { 115 setname("nice"); 116 t->t_nice = 117 getn(t->t_dcom[1]); 118 lshift(t->t_dcom, 2); 119 t->t_dflg |= F_NICE; 120 } 121 else 122 break; 123 else { 124 t->t_nice = 4; 125 lshift(t->t_dcom, 1); 126 t->t_dflg |= F_NICE; 127 } 128 else 129 break; 130 else if (eq(t->t_dcom[0], STRnohup)) 131 if (t->t_dcom[1]) { 132 t->t_dflg |= F_NOHUP; 133 lshift(t->t_dcom, 1); 134 } 135 else 136 break; 137 else if (eq(t->t_dcom[0], STRtime)) 138 if (t->t_dcom[1]) { 139 t->t_dflg |= F_TIME; 140 lshift(t->t_dcom, 1); 141 } 142 else 143 break; 144 else 145 break; 146 147 /* is it a command */ 148 if (t->t_dtyp == NODE_COMMAND) { 149 /* 150 * Check if we have a builtin function and remember which one. 151 */ 152 bifunc = isbfunc(t); 153 if (noexec) { 154 /* 155 * Continue for builtins that are part of the scripting language 156 */ 157 if (bifunc && 158 bifunc->bfunct != dobreak && bifunc->bfunct != docontin && 159 bifunc->bfunct != doelse && bifunc->bfunct != doend && 160 bifunc->bfunct != doforeach && bifunc->bfunct != dogoto && 161 bifunc->bfunct != doif && bifunc->bfunct != dorepeat && 162 bifunc->bfunct != doswbrk && bifunc->bfunct != doswitch && 163 bifunc->bfunct != dowhile && bifunc->bfunct != dozip) 164 break; 165 } 166 } 167 else { /* not a command */ 168 bifunc = NULL; 169 if (noexec) 170 break; 171 } 172 173 /* 174 * We fork only if we are timed, or are not the end of a parenthesized 175 * list and not a simple builtin function. Simple meaning one that is 176 * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not 177 * fork in some of these cases. 178 */ 179 /* 180 * Prevent forking cd, pushd, popd, chdir cause this will cause the 181 * shell not to change dir! 182 */ 183 if (bifunc && (bifunc->bfunct == dochngd || 184 bifunc->bfunct == dopushd || 185 bifunc->bfunct == dopopd)) 186 t->t_dflg &= ~(F_NICE); 187 if (((t->t_dflg & F_TIME) || ((t->t_dflg & F_NOFORK) == 0 && 188 (!bifunc || t->t_dflg & 189 (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP)))) || 190 /* 191 * We have to fork for eval too. 192 */ 193 (bifunc && (t->t_dflg & (F_PIPEIN | F_PIPEOUT)) != 0 && 194 bifunc->bfunct == doeval)) { 195 if (t->t_dtyp == NODE_PAREN || 196 t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) { 197 forked++; 198 /* 199 * We need to block SIGCHLD here, so that if the process does 200 * not die before we can set the process group 201 */ 202 if (wanttty >= 0 && !nosigchld) { 203 sigemptyset(&sigset); 204 sigaddset(&sigset, SIGCHLD); 205 sigprocmask(SIG_BLOCK, &sigset, &csigset); 206 nosigchld = 1; 207 } 208 209 pid = pfork(t, wanttty); 210 if (pid == 0 && nosigchld) { 211 sigprocmask(SIG_SETMASK, &csigset, NULL); 212 nosigchld = 0; 213 } 214 else if (pid != 0 && (t->t_dflg & F_AMPERSAND)) 215 backpid = pid; 216 217 } 218 else { 219 int ochild, osetintr, ohaderr, odidfds; 220 int oSHIN, oSHOUT, oSHERR, oOLDSTD, otpgrp; 221 sigset_t osigset; 222 223 /* 224 * Prepare for the vfork by saving everything that the child 225 * corrupts before it exec's. Note that in some signal 226 * implementations which keep the signal info in user space 227 * (e.g. Sun's) it will also be necessary to save and restore 228 * the current sigaction's for the signals the child touches 229 * before it exec's. 230 */ 231 if (wanttty >= 0 && !nosigchld && !noexec) { 232 sigemptyset(&sigset); 233 sigaddset(&sigset, SIGCHLD); 234 sigprocmask(SIG_BLOCK, &sigset, &csigset); 235 nosigchld = 1; 236 } 237 sigemptyset(&sigset); 238 sigaddset(&sigset, SIGCHLD); 239 sigaddset(&sigset, SIGINT); 240 sigprocmask(SIG_BLOCK, &sigset, &osigset); 241 ochild = child; 242 osetintr = setintr; 243 ohaderr = haderr; 244 odidfds = didfds; 245 oSHIN = SHIN; 246 oSHOUT = SHOUT; 247 oSHERR = SHERR; 248 oOLDSTD = OLDSTD; 249 otpgrp = tpgrp; 250 ocsigset = csigset; 251 onosigchld = nosigchld; 252 Vsav = Vdp = NULL; 253 Vexpath = 0; 254 Vt = 0; 255 pid = vfork(); 256 257 if (pid == -1) { 258 sigprocmask(SIG_SETMASK, &osigset, NULL); 259 stderror(ERR_NOPROC); 260 } 261 forked++; 262 if (pid) { /* parent */ 263 child = ochild; 264 setintr = osetintr; 265 haderr = ohaderr; 266 didfds = odidfds; 267 SHIN = oSHIN; 268 SHOUT = oSHOUT; 269 SHERR = oSHERR; 270 OLDSTD = oOLDSTD; 271 tpgrp = otpgrp; 272 csigset = ocsigset; 273 nosigchld = onosigchld; 274 275 free(Vsav); 276 Vsav = NULL; 277 free(Vdp); 278 Vdp = NULL; 279 free(Vexpath); 280 Vexpath = NULL; 281 blkfree((Char **) Vt); 282 Vt = NULL; 283 /* this is from pfork() */ 284 palloc(pid, t); 285 sigprocmask(SIG_SETMASK, &osigset, NULL); 286 } 287 else { /* child */ 288 /* this is from pfork() */ 289 int pgrp; 290 bool ignint = 0; 291 292 if (nosigchld) { 293 sigprocmask(SIG_SETMASK, &csigset, NULL); 294 nosigchld = 0; 295 } 296 297 if (setintr) 298 ignint = 299 (tpgrp == -1 && 300 (t->t_dflg & F_NOINTERRUPT)) 301 || (gointr && eq(gointr, STRminus)); 302 pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 303 child++; 304 if (setintr) { 305 setintr = 0; 306 if (ignint) { 307 (void) signal(SIGINT, SIG_IGN); 308 (void) signal(SIGQUIT, SIG_IGN); 309 } 310 else { 311 (void) signal(SIGINT, vffree); 312 (void) signal(SIGQUIT, SIG_DFL); 313 } 314 315 if (wanttty >= 0) { 316 (void) signal(SIGTSTP, SIG_DFL); 317 (void) signal(SIGTTIN, SIG_DFL); 318 (void) signal(SIGTTOU, SIG_DFL); 319 } 320 321 (void) signal(SIGTERM, parterm); 322 } 323 else if (tpgrp == -1 && 324 (t->t_dflg & F_NOINTERRUPT)) { 325 (void) signal(SIGINT, SIG_IGN); 326 (void) signal(SIGQUIT, SIG_IGN); 327 } 328 329 pgetty(wanttty, pgrp); 330 if (t->t_dflg & F_NOHUP) 331 (void) signal(SIGHUP, SIG_IGN); 332 if (t->t_dflg & F_NICE) 333 (void) setpriority(PRIO_PROCESS, 0, t->t_nice); 334 } 335 336 } 337 } 338 if (pid != 0) { 339 /* 340 * It would be better if we could wait for the whole job when we 341 * knew the last process had been started. Pwait, in fact, does 342 * wait for the whole job anyway, but this test doesn't really 343 * express our intentions. 344 */ 345 if (didfds == 0 && t->t_dflg & F_PIPEIN) { 346 (void) close(pipein[0]); 347 (void) close(pipein[1]); 348 } 349 if ((t->t_dflg & F_PIPEOUT) == 0) { 350 if (nosigchld) { 351 sigprocmask(SIG_SETMASK, &csigset, NULL); 352 nosigchld = 0; 353 } 354 if ((t->t_dflg & F_AMPERSAND) == 0) 355 pwait(); 356 } 357 break; 358 } 359 doio(t, pipein, pipeout); 360 if (t->t_dflg & F_PIPEOUT) { 361 (void) close(pipeout[0]); 362 (void) close(pipeout[1]); 363 } 364 /* 365 * Perform a builtin function. If we are not forked, arrange for 366 * possible stopping 367 */ 368 if (bifunc) { 369 func(t, bifunc); 370 if (forked) 371 exitstat(); 372 break; 373 } 374 if (t->t_dtyp != NODE_PAREN) { 375 doexec(NULL, t); 376 /* NOTREACHED */ 377 } 378 /* 379 * For () commands must put new 0,1,2 in FSH* and recurse 380 */ 381 OLDSTD = dcopy(0, FOLDSTD); 382 SHOUT = dcopy(1, FSHOUT); 383 SHERR = dcopy(2, FSHERR); 384 (void) close(SHIN); 385 SHIN = -1; 386 didfds = 0; 387 wanttty = -1; 388 t->t_dspr->t_dflg |= t->t_dflg & F_NOINTERRUPT; 389 execute(t->t_dspr, wanttty, NULL, NULL); 390 exitstat(); 391 392 case NODE_PIPE: 393 t->t_dcar->t_dflg |= F_PIPEOUT | 394 (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT)); 395 execute(t->t_dcar, wanttty, pipein, pv); 396 t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg & 397 (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT)); 398 if (wanttty > 0) 399 wanttty = 0; /* got tty already */ 400 execute(t->t_dcdr, wanttty, pv, pipeout); 401 break; 402 403 case NODE_LIST: 404 if (t->t_dcar) { 405 t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT; 406 execute(t->t_dcar, wanttty, NULL, NULL); 407 /* 408 * In strange case of A&B make a new job after A 409 */ 410 if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr && 411 (t->t_dcdr->t_dflg & F_AMPERSAND) == 0) 412 pendjob(); 413 } 414 if (t->t_dcdr) { 415 t->t_dcdr->t_dflg |= t->t_dflg & 416 (F_NOFORK | F_NOINTERRUPT); 417 execute(t->t_dcdr, wanttty, NULL, NULL); 418 } 419 break; 420 421 case NODE_OR: 422 case NODE_AND: 423 if (t->t_dcar) { 424 t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT; 425 execute(t->t_dcar, wanttty, NULL, NULL); 426 if ((getn(value(STRstatus)) == 0) != 427 (t->t_dtyp == NODE_AND)) 428 return; 429 } 430 if (t->t_dcdr) { 431 t->t_dcdr->t_dflg |= t->t_dflg & 432 (F_NOFORK | F_NOINTERRUPT); 433 execute(t->t_dcdr, wanttty, NULL, NULL); 434 } 435 break; 436 } 437 /* 438 * Fall through for all breaks from switch 439 * 440 * If there will be no more executions of this command, flush all file 441 * descriptors. Places that turn on the F_REPEAT bit are responsible for 442 * doing donefds after the last re-execution 443 */ 444 if (didfds && !(t->t_dflg & F_REPEAT)) 445 donefds(); 446 } 447 448 static void 449 vffree(int i) 450 { 451 _exit(i); 452 } 453 454 /* 455 * Expand and glob the words after an i/o redirection. 456 * If more than one word is generated, then update the command vector. 457 * 458 * This is done differently in all the shells: 459 * 1. in the bourne shell and ksh globbing is not performed 460 * 2. Bash/csh say ambiguous 461 * 3. zsh does i/o to/from all the files 462 * 4. itcsh concatenates the words. 463 * 464 * I don't know what is best to do. I think that Ambiguous is better 465 * than restructuring the command vector, because the user can get 466 * unexpected results. In any case, the command vector restructuring 467 * code is present and the user can choose it by setting noambiguous 468 */ 469 static Char * 470 splicepipe(struct command *t, Char *cp) /* word after < or > */ 471 { 472 Char *blk[2]; 473 474 if (adrof(STRnoambiguous)) { 475 Char **pv; 476 477 blk[0] = Dfix1(cp); /* expand $ */ 478 blk[1] = NULL; 479 480 gflag = 0, tglob(blk); 481 if (gflag) { 482 pv = globall(blk); 483 if (pv == NULL) { 484 setname(vis_str(blk[0])); 485 free(blk[0]); 486 stderror(ERR_NAME | ERR_NOMATCH); 487 } 488 gargv = NULL; 489 if (pv[1] != NULL) { /* we need to fix the command vector */ 490 Char **av = blkspl(t->t_dcom, &pv[1]); 491 free(t->t_dcom); 492 t->t_dcom = av; 493 } 494 free(blk[0]); 495 blk[0] = pv[0]; 496 free(pv); 497 } 498 } 499 else { 500 blk[0] = globone(blk[1] = Dfix1(cp), G_ERROR); 501 free(blk[1]); 502 } 503 return(blk[0]); 504 } 505 506 /* 507 * Perform io redirection. 508 * We may or maynot be forked here. 509 */ 510 static void 511 doio(struct command *t, int *pipein, int *pipeout) 512 { 513 int fd; 514 Char *cp; 515 int flags = t->t_dflg; 516 517 if (didfds || (flags & F_REPEAT)) 518 return; 519 if ((flags & F_READ) == 0) {/* F_READ already done */ 520 if (t->t_dlef) { 521 char tmp[PATH_MAX]; 522 523 /* 524 * so < /dev/std{in,out,err} work 525 */ 526 (void) dcopy(SHIN, 0); 527 (void) dcopy(SHOUT, 1); 528 (void) dcopy(SHERR, 2); 529 cp = splicepipe(t, t->t_dlef); 530 strlcpy(tmp, short2str(cp), sizeof tmp); 531 free(cp); 532 if ((fd = open(tmp, O_RDONLY)) == -1) 533 stderror(ERR_SYSTEM, tmp, strerror(errno)); 534 (void) dmove(fd, 0); 535 } 536 else if (flags & F_PIPEIN) { 537 (void) close(0); 538 (void) dup(pipein[0]); 539 (void) close(pipein[0]); 540 (void) close(pipein[1]); 541 } 542 else if ((flags & F_NOINTERRUPT) && tpgrp == -1) { 543 (void) close(0); 544 (void) open(_PATH_DEVNULL, O_RDONLY); 545 } 546 else { 547 (void) close(0); 548 (void) dup(OLDSTD); 549 (void) fcntl(STDIN_FILENO, F_SETFD, 0); 550 } 551 } 552 if (t->t_drit) { 553 char tmp[PATH_MAX]; 554 555 cp = splicepipe(t, t->t_drit); 556 strlcpy(tmp, short2str(cp), sizeof tmp); 557 free(cp); 558 /* 559 * so > /dev/std{out,err} work 560 */ 561 (void) dcopy(SHOUT, 1); 562 (void) dcopy(SHERR, 2); 563 if ((flags & F_APPEND) && 564 (fd = open(tmp, O_WRONLY | O_APPEND)) >= 0); 565 else { 566 if (!(flags & F_OVERWRITE) && adrof(STRnoclobber)) { 567 if (flags & F_APPEND) 568 stderror(ERR_SYSTEM, tmp, strerror(errno)); 569 chkclob(tmp); 570 } 571 if ((fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) 572 stderror(ERR_SYSTEM, tmp, strerror(errno)); 573 } 574 (void) dmove(fd, 1); 575 } 576 else if (flags & F_PIPEOUT) { 577 (void) close(1); 578 (void) dup(pipeout[1]); 579 } 580 else { 581 (void) close(1); 582 (void) dup(SHOUT); 583 (void) fcntl(STDOUT_FILENO, F_SETFD, 0); 584 } 585 586 (void) close(2); 587 if (flags & F_STDERR) { 588 (void) dup(1); 589 } 590 else { 591 (void) dup(SHERR); 592 (void) fcntl(STDERR_FILENO, F_SETFD, 0); 593 } 594 didfds = 1; 595 } 596 597 void 598 mypipe(int *pv) 599 { 600 601 if (pipe(pv) == -1) 602 goto oops; 603 pv[0] = dmove(pv[0], -1); 604 pv[1] = dmove(pv[1], -1); 605 if (pv[0] >= 0 && pv[1] >= 0) 606 return; 607 oops: 608 stderror(ERR_PIPE); 609 } 610 611 static void 612 chkclob(char *cp) 613 { 614 struct stat stb; 615 616 if (stat(cp, &stb) == -1) 617 return; 618 if (S_ISCHR(stb.st_mode)) 619 return; 620 stderror(ERR_EXISTS, cp); 621 } 622