1 /*- 2 * Copyright (c) 1980, 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)sem.c 5.20 (Berkeley) 09/04/91"; 10 #endif /* not lint */ 11 12 #include <sys/param.h> 13 #include <sys/ioctl.h> 14 #include <sys/stat.h> 15 #include <errno.h> 16 #include <fcntl.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <unistd.h> 20 #if __STDC__ 21 # include <stdarg.h> 22 #else 23 # include <varargs.h> 24 #endif 25 26 #include "csh.h" 27 #include "proc.h" 28 #include "extern.h" 29 30 static void vffree __P((int)); 31 static void doio __P((struct command *t, int *, int *)); 32 static void chkclob __P((char *)); 33 34 void 35 execute(t, wanttty, pipein, pipeout) 36 register struct command *t; 37 int wanttty, *pipein, *pipeout; 38 { 39 bool forked = 0; 40 struct biltins *bifunc; 41 int pid = 0; 42 int pv[2]; 43 44 static sigset_t csigmask; 45 46 static sigset_t ocsigmask; 47 static int onosigchld = 0; 48 static int nosigchld = 0; 49 50 if (t == 0) 51 return; 52 53 if (t->t_dflg & F_AMPERSAND) 54 wanttty = 0; 55 switch (t->t_dtyp) { 56 57 case NODE_COMMAND: 58 if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE) 59 (void) Strcpy(t->t_dcom[0], t->t_dcom[0] + 1); 60 if ((t->t_dflg & F_REPEAT) == 0) 61 Dfix(t); /* $ " ' \ */ 62 if (t->t_dcom[0] == 0) 63 return; 64 /* fall into... */ 65 66 case NODE_PAREN: 67 if (t->t_dflg & F_PIPEOUT) 68 mypipe(pipeout); 69 /* 70 * Must do << early so parent will know where input pointer should be. 71 * If noexec then this is all we do. 72 */ 73 if (t->t_dflg & F_READ) { 74 (void) close(0); 75 heredoc(t->t_dlef); 76 if (noexec) 77 (void) close(0); 78 } 79 80 set(STRstatus, Strsave(STR0)); 81 82 /* 83 * This mess is the necessary kludge to handle the prefix builtins: 84 * nice, nohup, time. These commands can also be used by themselves, 85 * and this is not handled here. This will also work when loops are 86 * parsed. 87 */ 88 while (t->t_dtyp == NODE_COMMAND) 89 if (eq(t->t_dcom[0], STRnice)) 90 if (t->t_dcom[1]) 91 if (strchr("+-", t->t_dcom[1][0])) 92 if (t->t_dcom[2]) { 93 setname("nice"); 94 t->t_nice = 95 getn(t->t_dcom[1]); 96 lshift(t->t_dcom, 2); 97 t->t_dflg |= F_NICE; 98 } 99 else 100 break; 101 else { 102 t->t_nice = 4; 103 lshift(t->t_dcom, 1); 104 t->t_dflg |= F_NICE; 105 } 106 else 107 break; 108 else if (eq(t->t_dcom[0], STRnohup)) 109 if (t->t_dcom[1]) { 110 t->t_dflg |= F_NOHUP; 111 lshift(t->t_dcom, 1); 112 } 113 else 114 break; 115 else if (eq(t->t_dcom[0], STRtime)) 116 if (t->t_dcom[1]) { 117 t->t_dflg |= F_TIME; 118 lshift(t->t_dcom, 1); 119 } 120 else 121 break; 122 else 123 break; 124 125 /* is it a command */ 126 if (t->t_dtyp == NODE_COMMAND) { 127 /* 128 * Check if we have a builtin function and remember which one. 129 */ 130 bifunc = isbfunc(t); 131 if (noexec) { 132 /* 133 * Continue for builtins that are part of the scripting language 134 */ 135 if (bifunc->bfunct != dobreak && bifunc->bfunct != docontin && 136 bifunc->bfunct != doelse && bifunc->bfunct != doend && 137 bifunc->bfunct != doforeach && bifunc->bfunct != dogoto && 138 bifunc->bfunct != doif && bifunc->bfunct != dorepeat && 139 bifunc->bfunct != doswbrk && bifunc->bfunct != doswitch && 140 bifunc->bfunct != dowhile && bifunc->bfunct != dozip) 141 break; 142 } 143 } 144 else { /* not a command */ 145 bifunc = NULL; 146 if (noexec) 147 break; 148 } 149 150 /* 151 * We fork only if we are timed, or are not the end of a parenthesized 152 * list and not a simple builtin function. Simple meaning one that is 153 * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not 154 * fork in some of these cases. 155 */ 156 /* 157 * Prevent forking cd, pushd, popd, chdir cause this will cause the 158 * shell not to change dir! 159 */ 160 if (bifunc && (bifunc->bfunct == dochngd || 161 bifunc->bfunct == dopushd || 162 bifunc->bfunct == dopopd)) 163 t->t_dflg &= ~(F_NICE); 164 if (((t->t_dflg & F_TIME) || (t->t_dflg & F_NOFORK) == 0 && 165 (!bifunc || t->t_dflg & 166 (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP))) || 167 /* 168 * We have to fork for eval too. 169 */ 170 (bifunc && (t->t_dflg & (F_PIPEIN | F_PIPEOUT)) != 0 && 171 bifunc->bfunct == doeval)) 172 if (t->t_dtyp == NODE_PAREN || 173 t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) { 174 forked++; 175 /* 176 * We need to block SIGCHLD here, so that if the process does 177 * not die before we can set the process group 178 */ 179 if (wanttty >= 0 && !nosigchld) { 180 csigmask = sigblock(sigmask(SIGCHLD)); 181 nosigchld = 1; 182 } 183 184 pid = pfork(t, wanttty); 185 if (pid == 0 && nosigchld) { 186 (void) sigsetmask(csigmask); 187 nosigchld = 0; 188 } 189 } 190 else { 191 int ochild, osetintr, ohaderr, odidfds; 192 int oSHIN, oSHOUT, oSHERR, oOLDSTD, otpgrp; 193 sigset_t omask; 194 195 /* 196 * Prepare for the vfork by saving everything that the child 197 * corrupts before it exec's. Note that in some signal 198 * implementations which keep the signal info in user space 199 * (e.g. Sun's) it will also be necessary to save and restore 200 * the current sigvec's for the signals the child touches 201 * before it exec's. 202 */ 203 if (wanttty >= 0 && !nosigchld && !noexec) { 204 csigmask = sigblock(sigmask(SIGCHLD)); 205 nosigchld = 1; 206 } 207 omask = sigblock(sigmask(SIGCHLD) | sigmask(SIGINT)); 208 ochild = child; 209 osetintr = setintr; 210 ohaderr = haderr; 211 odidfds = didfds; 212 oSHIN = SHIN; 213 oSHOUT = SHOUT; 214 oSHERR = SHERR; 215 oOLDSTD = OLDSTD; 216 otpgrp = tpgrp; 217 ocsigmask = csigmask; 218 onosigchld = nosigchld; 219 Vsav = Vdp = 0; 220 Vexpath = 0; 221 Vt = 0; 222 pid = vfork(); 223 224 if (pid < 0) { 225 (void) sigsetmask(omask); 226 stderror(ERR_NOPROC); 227 } 228 forked++; 229 if (pid) { /* parent */ 230 child = ochild; 231 setintr = osetintr; 232 haderr = ohaderr; 233 didfds = odidfds; 234 SHIN = oSHIN; 235 SHOUT = oSHOUT; 236 SHERR = oSHERR; 237 OLDSTD = oOLDSTD; 238 tpgrp = otpgrp; 239 csigmask = ocsigmask; 240 nosigchld = onosigchld; 241 242 xfree((ptr_t) Vsav); 243 Vsav = 0; 244 xfree((ptr_t) Vdp); 245 Vdp = 0; 246 xfree((ptr_t) Vexpath); 247 Vexpath = 0; 248 blkfree((Char **) Vt); 249 Vt = 0; 250 /* this is from pfork() */ 251 palloc(pid, t); 252 (void) sigsetmask(omask); 253 } 254 else { /* child */ 255 /* this is from pfork() */ 256 int pgrp; 257 bool ignint = 0; 258 259 if (nosigchld) { 260 (void) sigsetmask(csigmask); 261 nosigchld = 0; 262 } 263 264 if (setintr) 265 ignint = 266 (tpgrp == -1 && 267 (t->t_dflg & F_NOINTERRUPT)) 268 || gointr && eq(gointr, STRminus); 269 pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 270 child++; 271 if (setintr) { 272 setintr = 0; 273 if (ignint) { 274 (void) signal(SIGINT, SIG_IGN); 275 (void) signal(SIGQUIT, SIG_IGN); 276 } 277 else { 278 (void) signal(SIGINT, vffree); 279 (void) signal(SIGQUIT, SIG_DFL); 280 } 281 282 if (wanttty >= 0) { 283 (void) signal(SIGTSTP, SIG_DFL); 284 (void) signal(SIGTTIN, SIG_DFL); 285 (void) signal(SIGTTOU, SIG_DFL); 286 } 287 288 (void) signal(SIGTERM, parterm); 289 } 290 else if (tpgrp == -1 && 291 (t->t_dflg & F_NOINTERRUPT)) { 292 (void) signal(SIGINT, SIG_IGN); 293 (void) signal(SIGQUIT, SIG_IGN); 294 } 295 296 pgetty(wanttty, pgrp); 297 if (t->t_dflg & F_NOHUP) 298 (void) signal(SIGHUP, SIG_IGN); 299 if (t->t_dflg & F_NICE) 300 (void) setpriority(PRIO_PROCESS, 0, t->t_nice); 301 } 302 303 } 304 if (pid != 0) { 305 /* 306 * It would be better if we could wait for the whole job when we 307 * knew the last process had been started. Pwait, in fact, does 308 * wait for the whole job anyway, but this test doesn't really 309 * express our intentions. 310 */ 311 if (didfds == 0 && t->t_dflg & F_PIPEIN) { 312 (void) close(pipein[0]); 313 (void) close(pipein[1]); 314 } 315 if ((t->t_dflg & F_PIPEOUT) == 0) { 316 if (nosigchld) { 317 (void) sigsetmask(csigmask); 318 nosigchld = 0; 319 } 320 if ((t->t_dflg & F_AMPERSAND) == 0) 321 pwait(); 322 } 323 break; 324 } 325 doio(t, pipein, pipeout); 326 if (t->t_dflg & F_PIPEOUT) { 327 (void) close(pipeout[0]); 328 (void) close(pipeout[1]); 329 } 330 /* 331 * Perform a builtin function. If we are not forked, arrange for 332 * possible stopping 333 */ 334 if (bifunc) { 335 func(t, bifunc); 336 if (forked) 337 exitstat(); 338 break; 339 } 340 if (t->t_dtyp != NODE_PAREN) { 341 doexec(NULL, t); 342 /* NOTREACHED */ 343 } 344 /* 345 * For () commands must put new 0,1,2 in FSH* and recurse 346 */ 347 OLDSTD = dcopy(0, FOLDSTD); 348 SHOUT = dcopy(1, FSHOUT); 349 SHERR = dcopy(2, FSHERR); 350 (void) close(SHIN); 351 SHIN = -1; 352 didfds = 0; 353 wanttty = -1; 354 t->t_dspr->t_dflg |= t->t_dflg & F_NOINTERRUPT; 355 execute(t->t_dspr, wanttty, NULL, NULL); 356 exitstat(); 357 358 case NODE_PIPE: 359 t->t_dcar->t_dflg |= F_PIPEOUT | 360 (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT)); 361 execute(t->t_dcar, wanttty, pipein, pv); 362 t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg & 363 (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT)); 364 if (wanttty > 0) 365 wanttty = 0; /* got tty already */ 366 execute(t->t_dcdr, wanttty, pv, pipeout); 367 break; 368 369 case NODE_LIST: 370 if (t->t_dcar) { 371 t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT; 372 execute(t->t_dcar, wanttty, NULL, NULL); 373 /* 374 * In strange case of A&B make a new job after A 375 */ 376 if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr && 377 (t->t_dcdr->t_dflg & F_AMPERSAND) == 0) 378 pendjob(); 379 } 380 if (t->t_dcdr) { 381 t->t_dcdr->t_dflg |= t->t_dflg & 382 (F_NOFORK | F_NOINTERRUPT); 383 execute(t->t_dcdr, wanttty, NULL, NULL); 384 } 385 break; 386 387 case NODE_OR: 388 case NODE_AND: 389 if (t->t_dcar) { 390 t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT; 391 execute(t->t_dcar, wanttty, NULL, NULL); 392 if ((getn(value(STRstatus)) == 0) != 393 (t->t_dtyp == NODE_AND)) 394 return; 395 } 396 if (t->t_dcdr) { 397 t->t_dcdr->t_dflg |= t->t_dflg & 398 (F_NOFORK | F_NOINTERRUPT); 399 execute(t->t_dcdr, wanttty, NULL, NULL); 400 } 401 break; 402 } 403 /* 404 * Fall through for all breaks from switch 405 * 406 * If there will be no more executions of this command, flush all file 407 * descriptors. Places that turn on the F_REPEAT bit are responsible for 408 * doing donefds after the last re-execution 409 */ 410 if (didfds && !(t->t_dflg & F_REPEAT)) 411 donefds(); 412 } 413 414 static void 415 vffree(i) 416 int i; 417 { 418 register Char **v; 419 420 if (v = gargv) { 421 gargv = 0; 422 xfree((ptr_t) v); 423 } 424 if (v = pargv) { 425 pargv = 0; 426 xfree((ptr_t) v); 427 } 428 _exit(i); 429 } 430 431 /* 432 * Perform io redirection. 433 * We may or maynot be forked here. 434 */ 435 static void 436 doio(t, pipein, pipeout) 437 register struct command *t; 438 int *pipein, *pipeout; 439 { 440 register int fd; 441 register Char *cp, *dp; 442 register int flags = t->t_dflg; 443 444 if (didfds || (flags & F_REPEAT)) 445 return; 446 if ((flags & F_READ) == 0) {/* F_READ already done */ 447 if (cp = t->t_dlef) { 448 char tmp[MAXPATHLEN+1]; 449 450 /* 451 * so < /dev/std{in,out,err} work 452 */ 453 (void) dcopy(SHIN, 0); 454 (void) dcopy(SHOUT, 1); 455 (void) dcopy(SHERR, 2); 456 cp = globone(dp = Dfix1(cp), G_IGNORE); 457 (void) strncpy(tmp, short2str(cp), MAXPATHLEN); 458 tmp[MAXPATHLEN] = '\0'; 459 xfree((ptr_t) cp); 460 xfree((ptr_t) dp); 461 if ((fd = open(tmp, O_RDONLY)) < 0) 462 stderror(ERR_SYSTEM, tmp, strerror(errno)); 463 (void) dmove(fd, 0); 464 } 465 else if (flags & F_PIPEIN) { 466 (void) close(0); 467 (void) dup(pipein[0]); 468 (void) close(pipein[0]); 469 (void) close(pipein[1]); 470 } 471 else if ((flags & F_NOINTERRUPT) && tpgrp == -1) { 472 (void) close(0); 473 (void) open(_PATH_DEVNULL, O_RDONLY); 474 } 475 else { 476 (void) close(0); 477 (void) dup(OLDSTD); 478 (void) ioctl(0, FIONCLEX, NULL); 479 } 480 } 481 if (cp = t->t_drit) { 482 char tmp[MAXPATHLEN+1]; 483 484 cp = globone(dp = Dfix1(cp), G_IGNORE); 485 (void) strncpy(tmp, short2str(cp), MAXPATHLEN); 486 tmp[MAXPATHLEN] = '\0'; 487 xfree((ptr_t) cp); 488 xfree((ptr_t) dp); 489 /* 490 * so > /dev/std{out,err} work 491 */ 492 (void) dcopy(SHOUT, 1); 493 (void) dcopy(SHERR, 2); 494 if ((flags & F_APPEND) && 495 #ifdef O_APPEND 496 (fd = open(tmp, O_WRONLY | O_APPEND)) >= 0); 497 #else 498 (fd = open(tmp, O_WRONLY)) >= 0) 499 (void) lseek(1, (off_t) 0, L_XTND); 500 #endif 501 else { 502 if (!(flags & F_OVERWRITE) && adrof(STRnoclobber)) { 503 if (flags & F_APPEND) 504 stderror(ERR_SYSTEM, tmp, strerror(errno)); 505 chkclob(tmp); 506 } 507 if ((fd = creat(tmp, 0666)) < 0) 508 stderror(ERR_SYSTEM, tmp, strerror(errno)); 509 } 510 (void) dmove(fd, 1); 511 } 512 else if (flags & F_PIPEOUT) { 513 (void) close(1); 514 (void) dup(pipeout[1]); 515 } 516 else { 517 (void) close(1); 518 (void) dup(SHOUT); 519 (void) ioctl(1, FIONCLEX, NULL); 520 } 521 522 (void) close(2); 523 if (flags & F_STDERR) { 524 (void) dup(1); 525 } 526 else { 527 (void) dup(SHERR); 528 (void) ioctl(2, FIONCLEX, NULL); 529 } 530 didfds = 1; 531 } 532 533 void 534 mypipe(pv) 535 register int *pv; 536 { 537 538 if (pipe(pv) < 0) 539 goto oops; 540 pv[0] = dmove(pv[0], -1); 541 pv[1] = dmove(pv[1], -1); 542 if (pv[0] >= 0 && pv[1] >= 0) 543 return; 544 oops: 545 stderror(ERR_PIPE); 546 } 547 548 static void 549 chkclob(cp) 550 register char *cp; 551 { 552 struct stat stb; 553 554 if (stat(cp, &stb) < 0) 555 return; 556 if ((stb.st_mode & S_IFMT) == S_IFCHR) 557 return; 558 stderror(ERR_EXISTS, cp); 559 } 560