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