1 /* $NetBSD: sem.c,v 1.11 1997/07/04 21:24:08 christos 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 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)sem.c 8.1 (Berkeley) 5/31/93"; 40 #else 41 __RCSID("$NetBSD: sem.c,v 1.11 1997/07/04 21:24:08 christos 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 #if __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 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->bfunct != dobreak && bifunc->bfunct != docontin && 175 bifunc->bfunct != doelse && bifunc->bfunct != doend && 176 bifunc->bfunct != doforeach && bifunc->bfunct != dogoto && 177 bifunc->bfunct != doif && bifunc->bfunct != dorepeat && 178 bifunc->bfunct != doswbrk && bifunc->bfunct != doswitch && 179 bifunc->bfunct != dowhile && bifunc->bfunct != dozip) 180 break; 181 } 182 } 183 else { /* not a command */ 184 bifunc = NULL; 185 if (noexec) 186 break; 187 } 188 189 /* 190 * We fork only if we are timed, or are not the end of a parenthesized 191 * list and not a simple builtin function. Simple meaning one that is 192 * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not 193 * fork in some of these cases. 194 */ 195 /* 196 * Prevent forking cd, pushd, popd, chdir cause this will cause the 197 * shell not to change dir! 198 */ 199 if (bifunc && (bifunc->bfunct == dochngd || 200 bifunc->bfunct == dopushd || 201 bifunc->bfunct == dopopd)) 202 t->t_dflg &= ~(F_NICE); 203 if (((t->t_dflg & F_TIME) || ((t->t_dflg & F_NOFORK) == 0 && 204 (!bifunc || t->t_dflg & 205 (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP)))) || 206 /* 207 * We have to fork for eval too. 208 */ 209 (bifunc && (t->t_dflg & (F_PIPEIN | F_PIPEOUT)) != 0 && 210 bifunc->bfunct == doeval)) 211 if (t->t_dtyp == NODE_PAREN || 212 t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) { 213 forked++; 214 /* 215 * We need to block SIGCHLD here, so that if the process does 216 * not die before we can set the process group 217 */ 218 if (wanttty >= 0 && !nosigchld) { 219 sigemptyset(&sigset); 220 sigaddset(&sigset, SIGCHLD); 221 sigprocmask(SIG_BLOCK, &sigset, &csigset); 222 nosigchld = 1; 223 } 224 225 pid = pfork(t, wanttty); 226 if (pid == 0 && nosigchld) { 227 sigprocmask(SIG_SETMASK, &csigset, NULL); 228 nosigchld = 0; 229 } 230 else if (pid != 0 && (t->t_dflg & F_AMPERSAND)) 231 backpid = pid; 232 233 } 234 else { 235 int ochild, osetintr, ohaderr, odidfds; 236 int oSHIN, oSHOUT, oSHERR, oOLDSTD, otpgrp; 237 sigset_t osigset; 238 239 /* 240 * Prepare for the vfork by saving everything that the child 241 * corrupts before it exec's. Note that in some signal 242 * implementations which keep the signal info in user space 243 * (e.g. Sun's) it will also be necessary to save and restore 244 * the current sigaction's for the signals the child touches 245 * before it exec's. 246 */ 247 if (wanttty >= 0 && !nosigchld && !noexec) { 248 sigemptyset(&sigset); 249 sigaddset(&sigset, SIGCHLD); 250 sigprocmask(SIG_BLOCK, &sigset, &csigset); 251 nosigchld = 1; 252 } 253 sigemptyset(&sigset); 254 sigaddset(&sigset, SIGCHLD); 255 sigaddset(&sigset, SIGINT); 256 sigprocmask(SIG_BLOCK, &sigset, &osigset); 257 ochild = child; 258 osetintr = setintr; 259 ohaderr = haderr; 260 odidfds = didfds; 261 oSHIN = SHIN; 262 oSHOUT = SHOUT; 263 oSHERR = SHERR; 264 oOLDSTD = OLDSTD; 265 otpgrp = tpgrp; 266 ocsigset = csigset; 267 onosigchld = nosigchld; 268 Vsav = Vdp = 0; 269 Vexpath = 0; 270 Vt = 0; 271 pid = vfork(); 272 273 if (pid < 0) { 274 sigprocmask(SIG_SETMASK, &osigset, NULL); 275 stderror(ERR_NOPROC); 276 } 277 forked++; 278 if (pid) { /* parent */ 279 child = ochild; 280 setintr = osetintr; 281 haderr = ohaderr; 282 didfds = odidfds; 283 SHIN = oSHIN; 284 SHOUT = oSHOUT; 285 SHERR = oSHERR; 286 OLDSTD = oOLDSTD; 287 tpgrp = otpgrp; 288 csigset = ocsigset; 289 nosigchld = onosigchld; 290 291 xfree((ptr_t) Vsav); 292 Vsav = 0; 293 xfree((ptr_t) Vdp); 294 Vdp = 0; 295 xfree((ptr_t) Vexpath); 296 Vexpath = 0; 297 blkfree((Char **) Vt); 298 Vt = 0; 299 /* this is from pfork() */ 300 palloc(pid, t); 301 sigprocmask(SIG_SETMASK, &osigset, NULL); 302 } 303 else { /* child */ 304 /* this is from pfork() */ 305 int pgrp; 306 bool ignint = 0; 307 308 if (nosigchld) { 309 sigprocmask(SIG_SETMASK, &csigset, NULL); 310 nosigchld = 0; 311 } 312 313 if (setintr) 314 ignint = 315 (tpgrp == -1 && 316 (t->t_dflg & F_NOINTERRUPT)) 317 || (gointr && eq(gointr, STRminus)); 318 pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 319 child++; 320 if (setintr) { 321 setintr = 0; 322 if (ignint) { 323 (void) signal(SIGINT, SIG_IGN); 324 (void) signal(SIGQUIT, SIG_IGN); 325 } 326 else { 327 (void) signal(SIGINT, vffree); 328 (void) signal(SIGQUIT, SIG_DFL); 329 } 330 331 if (wanttty >= 0) { 332 (void) signal(SIGTSTP, SIG_DFL); 333 (void) signal(SIGTTIN, SIG_DFL); 334 (void) signal(SIGTTOU, SIG_DFL); 335 } 336 337 (void) signal(SIGTERM, parterm); 338 } 339 else if (tpgrp == -1 && 340 (t->t_dflg & F_NOINTERRUPT)) { 341 (void) signal(SIGINT, SIG_IGN); 342 (void) signal(SIGQUIT, SIG_IGN); 343 } 344 345 pgetty(wanttty, pgrp); 346 if (t->t_dflg & F_NOHUP) 347 (void) signal(SIGHUP, SIG_IGN); 348 if (t->t_dflg & F_NICE) 349 (void) setpriority(PRIO_PROCESS, 0, t->t_nice); 350 } 351 352 } 353 if (pid != 0) { 354 /* 355 * It would be better if we could wait for the whole job when we 356 * knew the last process had been started. Pwait, in fact, does 357 * wait for the whole job anyway, but this test doesn't really 358 * express our intentions. 359 */ 360 if (didfds == 0 && t->t_dflg & F_PIPEIN) { 361 (void) close(pipein[0]); 362 (void) close(pipein[1]); 363 } 364 if ((t->t_dflg & F_PIPEOUT) == 0) { 365 if (nosigchld) { 366 sigprocmask(SIG_SETMASK, &csigset, NULL); 367 nosigchld = 0; 368 } 369 if ((t->t_dflg & F_AMPERSAND) == 0) 370 pwait(); 371 } 372 break; 373 } 374 doio(t, pipein, pipeout); 375 if (t->t_dflg & F_PIPEOUT) { 376 (void) close(pipeout[0]); 377 (void) close(pipeout[1]); 378 } 379 /* 380 * Perform a builtin function. If we are not forked, arrange for 381 * possible stopping 382 */ 383 if (bifunc) { 384 func(t, bifunc); 385 if (forked) 386 exitstat(); 387 break; 388 } 389 if (t->t_dtyp != NODE_PAREN) { 390 doexec(NULL, t); 391 /* NOTREACHED */ 392 } 393 /* 394 * For () commands must put new 0,1,2 in FSH* and recurse 395 */ 396 OLDSTD = dcopy(0, FOLDSTD); 397 SHOUT = dcopy(1, FSHOUT); 398 SHERR = dcopy(2, FSHERR); 399 (void) close(SHIN); 400 SHIN = -1; 401 didfds = 0; 402 wanttty = -1; 403 t->t_dspr->t_dflg |= t->t_dflg & F_NOINTERRUPT; 404 execute(t->t_dspr, wanttty, NULL, NULL); 405 exitstat(); 406 407 case NODE_PIPE: 408 t->t_dcar->t_dflg |= F_PIPEOUT | 409 (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT)); 410 execute(t->t_dcar, wanttty, pipein, pv); 411 t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg & 412 (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT)); 413 if (wanttty > 0) 414 wanttty = 0; /* got tty already */ 415 execute(t->t_dcdr, wanttty, pv, pipeout); 416 break; 417 418 case NODE_LIST: 419 if (t->t_dcar) { 420 t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT; 421 execute(t->t_dcar, wanttty, NULL, NULL); 422 /* 423 * In strange case of A&B make a new job after A 424 */ 425 if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr && 426 (t->t_dcdr->t_dflg & F_AMPERSAND) == 0) 427 pendjob(); 428 } 429 if (t->t_dcdr) { 430 t->t_dcdr->t_dflg |= t->t_dflg & 431 (F_NOFORK | F_NOINTERRUPT); 432 execute(t->t_dcdr, wanttty, NULL, NULL); 433 } 434 break; 435 436 case NODE_OR: 437 case NODE_AND: 438 if (t->t_dcar) { 439 t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT; 440 execute(t->t_dcar, wanttty, NULL, NULL); 441 if ((getn(value(STRstatus)) == 0) != 442 (t->t_dtyp == NODE_AND)) 443 return; 444 } 445 if (t->t_dcdr) { 446 t->t_dcdr->t_dflg |= t->t_dflg & 447 (F_NOFORK | F_NOINTERRUPT); 448 execute(t->t_dcdr, wanttty, NULL, NULL); 449 } 450 break; 451 } 452 /* 453 * Fall through for all breaks from switch 454 * 455 * If there will be no more executions of this command, flush all file 456 * descriptors. Places that turn on the F_REPEAT bit are responsible for 457 * doing donefds after the last re-execution 458 */ 459 if (didfds && !(t->t_dflg & F_REPEAT)) 460 donefds(); 461 } 462 463 static void 464 vffree(i) 465 int i; 466 { 467 Char **v; 468 469 if ((v = gargv) != NULL) { 470 gargv = 0; 471 xfree((ptr_t) v); 472 } 473 if ((v = pargv) != NULL) { 474 pargv = 0; 475 xfree((ptr_t) v); 476 } 477 _exit(i); 478 } 479 480 /* 481 * Expand and glob the words after an i/o redirection. 482 * If more than one word is generated, then update the command vector. 483 * 484 * This is done differently in all the shells: 485 * 1. in the bourne shell and ksh globbing is not performed 486 * 2. Bash/csh say ambiguous 487 * 3. zsh does i/o to/from all the files 488 * 4. itcsh concatenates the words. 489 * 490 * I don't know what is best to do. I think that Ambiguous is better 491 * than restructuring the command vector, because the user can get 492 * unexpected results. In any case, the command vector restructuring 493 * code is present and the user can choose it by setting noambiguous 494 */ 495 static Char * 496 splicepipe(t, cp) 497 struct command *t; 498 Char *cp; /* word after < or > */ 499 { 500 Char *blk[2]; 501 502 if (adrof(STRnoambiguous)) { 503 Char **pv; 504 505 blk[0] = Dfix1(cp); /* expand $ */ 506 blk[1] = NULL; 507 508 gflag = 0, tglob(blk); 509 if (gflag) { 510 pv = globall(blk); 511 if (pv == NULL) { 512 setname(vis_str(blk[0])); 513 xfree((ptr_t) blk[0]); 514 stderror(ERR_NAME | ERR_NOMATCH); 515 } 516 gargv = NULL; 517 if (pv[1] != NULL) { /* we need to fix the command vector */ 518 Char **av = blkspl(t->t_dcom, &pv[1]); 519 xfree((ptr_t) t->t_dcom); 520 t->t_dcom = av; 521 } 522 xfree((ptr_t) blk[0]); 523 blk[0] = pv[0]; 524 xfree((ptr_t) pv); 525 } 526 } 527 else { 528 blk[0] = globone(blk[1] = Dfix1(cp), G_ERROR); 529 xfree((ptr_t) blk[1]); 530 } 531 return(blk[0]); 532 } 533 534 /* 535 * Perform io redirection. 536 * We may or maynot be forked here. 537 */ 538 static void 539 doio(t, pipein, pipeout) 540 struct command *t; 541 int *pipein, *pipeout; 542 { 543 int fd; 544 Char *cp; 545 int flags = t->t_dflg; 546 547 if (didfds || (flags & F_REPEAT)) 548 return; 549 if ((flags & F_READ) == 0) {/* F_READ already done */ 550 if (t->t_dlef) { 551 char tmp[MAXPATHLEN+1]; 552 553 /* 554 * so < /dev/std{in,out,err} work 555 */ 556 (void) dcopy(SHIN, 0); 557 (void) dcopy(SHOUT, 1); 558 (void) dcopy(SHERR, 2); 559 cp = splicepipe(t, t->t_dlef); 560 (void) strncpy(tmp, short2str(cp), MAXPATHLEN); 561 tmp[MAXPATHLEN] = '\0'; 562 xfree((ptr_t) cp); 563 if ((fd = open(tmp, O_RDONLY)) < 0) 564 stderror(ERR_SYSTEM, tmp, strerror(errno)); 565 (void) dmove(fd, 0); 566 } 567 else if (flags & F_PIPEIN) { 568 (void) close(0); 569 (void) dup(pipein[0]); 570 (void) close(pipein[0]); 571 (void) close(pipein[1]); 572 } 573 else if ((flags & F_NOINTERRUPT) && tpgrp == -1) { 574 (void) close(0); 575 (void) open(_PATH_DEVNULL, O_RDONLY); 576 } 577 else { 578 (void) close(0); 579 (void) dup(OLDSTD); 580 (void) ioctl(0, FIONCLEX, NULL); 581 } 582 } 583 if (t->t_drit) { 584 char tmp[MAXPATHLEN+1]; 585 586 cp = splicepipe(t, t->t_drit); 587 (void) strncpy(tmp, short2str(cp), MAXPATHLEN); 588 tmp[MAXPATHLEN] = '\0'; 589 xfree((ptr_t) cp); 590 /* 591 * so > /dev/std{out,err} work 592 */ 593 (void) dcopy(SHOUT, 1); 594 (void) dcopy(SHERR, 2); 595 if ((flags & F_APPEND) && 596 #ifdef O_APPEND 597 (fd = open(tmp, O_WRONLY | O_APPEND)) >= 0); 598 #else 599 (fd = open(tmp, O_WRONLY)) >= 0) 600 (void) lseek(1, (off_t) 0, SEEK_END); 601 #endif 602 else { 603 if (!(flags & F_OVERWRITE) && adrof(STRnoclobber)) { 604 if (flags & F_APPEND) 605 stderror(ERR_SYSTEM, tmp, strerror(errno)); 606 chkclob(tmp); 607 } 608 if ((fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) 609 stderror(ERR_SYSTEM, tmp, strerror(errno)); 610 } 611 (void) dmove(fd, 1); 612 } 613 else if (flags & F_PIPEOUT) { 614 (void) close(1); 615 (void) dup(pipeout[1]); 616 } 617 else { 618 (void) close(1); 619 (void) dup(SHOUT); 620 (void) ioctl(1, FIONCLEX, NULL); 621 } 622 623 (void) close(2); 624 if (flags & F_STDERR) { 625 (void) dup(1); 626 } 627 else { 628 (void) dup(SHERR); 629 (void) ioctl(2, FIONCLEX, NULL); 630 } 631 didfds = 1; 632 } 633 634 void 635 mypipe(pv) 636 int *pv; 637 { 638 639 if (pipe(pv) < 0) 640 goto oops; 641 pv[0] = dmove(pv[0], -1); 642 pv[1] = dmove(pv[1], -1); 643 if (pv[0] >= 0 && pv[1] >= 0) 644 return; 645 oops: 646 stderror(ERR_PIPE); 647 } 648 649 static void 650 chkclob(cp) 651 char *cp; 652 { 653 struct stat stb; 654 655 if (stat(cp, &stb) < 0) 656 return; 657 if (S_ISCHR(stb.st_mode)) 658 return; 659 stderror(ERR_EXISTS, cp); 660 } 661