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