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