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