1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1980 Regents of the University of California. 11 * All rights reserved. The Berkeley Software License Agreement 12 * specifies the terms and conditions for redistribution. 13 */ 14 15 #pragma ident "%Z%%M% %I% %E% SMI" 16 17 #include <unistd.h> 18 #include <fcntl.h> 19 #include "sh.h" 20 #include "sh.proc.h" 21 #include "sh.tconst.h" 22 23 /* 24 * C shell 25 */ 26 27 /* 28 * Return true if there is a back-quote (`) anywhere in the argument list. 29 * Its presence would cause glob() to be invoked in the child process 30 * and this would cause chaos if the child is created with vfork(). 31 */ 32 static bool 33 AnyBquote(struct command *t) 34 { 35 tchar **pp; 36 tchar *p; 37 38 if (noexec) 39 return (0); 40 for (pp = t->t_dcom; p = *pp++;) { 41 if (any('`', p)) 42 return (1); 43 } 44 return (0); 45 } 46 47 /*VARARGS 1*/ 48 execute(t, wanttty, pipein, pipeout) 49 register struct command *t; 50 int wanttty, *pipein, *pipeout; 51 { 52 bool forked = 0; 53 struct biltins *bifunc; 54 int pid = 0; 55 int pv[2]; 56 extern int globcnt; 57 #ifdef TRACE 58 tprintf("TRACE- execute()\n"); 59 #endif 60 61 if (t == 0) 62 return; 63 if ((t->t_dflg & FAND) && wanttty > 0) 64 wanttty = 0; 65 switch (t->t_dtyp) { 66 67 case TCOM: 68 if (t->t_dcom[0][0] == (tchar)S_TOPBIT[0]) 69 (void) strcpy_(t->t_dcom[0], t->t_dcom[0] + 1); 70 if ((t->t_dflg & FREDO) == 0) 71 Dfix(t); /* $ " ' \ */ 72 if (t->t_dcom[0] == 0) 73 return; 74 /* fall into... */ 75 76 case TPAR: 77 if (t->t_dflg & FPOU) 78 mypipe(pipeout); 79 /* 80 * Must do << early so parent will know 81 * where input pointer should be. 82 * If noexec then this is all we do. 83 */ 84 if (t->t_dflg & FHERE) { 85 (void) close(0); 86 unsetfd(0); 87 heredoc(t->t_dlef); 88 if (noexec) { 89 (void) close(0); 90 unsetfd(0); 91 } 92 } 93 if (noexec) 94 break; 95 96 set(S_status, S_0); 97 98 /* 99 * This mess is the necessary kludge to handle the prefix 100 * builtins: nice, nohup, time. These commands can also 101 * be used by themselves, and this is not handled here. 102 * This will also work when loops are parsed. 103 */ 104 while (t->t_dtyp == TCOM) 105 if (eq(t->t_dcom[0], S_nice /*"nice"*/)) 106 if (t->t_dcom[1]) 107 /*if (any(t->t_dcom[1][0], "+-"))*/ 108 if (t->t_dcom[1][0] == '+' || 109 t->t_dcom[1][0] == '-') 110 if (t->t_dcom[2]) { 111 setname(S_nice /*"nice"*/); 112 t->t_nice = getn(t->t_dcom[1]); 113 lshift(t->t_dcom, 2); 114 t->t_dflg |= FNICE; 115 } else 116 break; 117 else { 118 t->t_nice = 4; 119 lshift(t->t_dcom, 1); 120 t->t_dflg |= FNICE; 121 } 122 else 123 break; 124 else if (eq(t->t_dcom[0], S_nohup /*"nohup"*/)) 125 if (t->t_dcom[1]) { 126 t->t_dflg |= FNOHUP; 127 lshift(t->t_dcom, 1); 128 } else 129 break; 130 else if (eq(t->t_dcom[0], S_time /*"time"*/)) 131 if (t->t_dcom[1]) { 132 t->t_dflg |= FTIME; 133 lshift(t->t_dcom, 1); 134 } else 135 break; 136 else 137 break; 138 /* 139 * Check if we have a builtin function and remember which one. 140 */ 141 bifunc = t->t_dtyp == TCOM ? isbfunc(t) : (struct biltins *) 0; 142 143 /* 144 * We fork only if we are timed, or are not the end of 145 * a parenthesized list and not a simple builtin function. 146 * Simple meaning one that is not pipedout, niced, nohupped, 147 * or &'d. 148 * It would be nice(?) to not fork in some of these cases. 149 */ 150 if (((t->t_dflg & FTIME) || (t->t_dflg & FPAR) == 0 && 151 (!bifunc || t->t_dflg & (FPOU|FAND|FNICE|FNOHUP)))) 152 #ifdef VFORK 153 if (t->t_dtyp == TPAR || t->t_dflg&(FREDO|FAND) || 154 bifunc || AnyBquote(t)) 155 #endif 156 { forked++; pid = pfork(t, wanttty); } 157 #ifdef VFORK 158 else { 159 void vffree(); 160 struct sv { 161 int mask, child, setintr, haderr, didfds; 162 int SHIN, SHOUT, SHDIAG, OLDSTD, tpgrp; 163 struct sigvec sigv; 164 } sv; 165 166 /* 167 * Prepare for the vfork by saving everything 168 * that the child corrupts before it exec's. 169 * Note that in some signal implementations 170 * which keep the signal info in user space 171 * (e.g. Sun's) it will also be necessary to 172 * save and restore the current sigvec's for 173 * the signals the child touches before it 174 * exec's. 175 */ 176 sv.mask = sigblock(sigmask(SIGCHLD)); 177 sv.child = child; sv.setintr = setintr; 178 sv.haderr = haderr; sv.didfds = didfds; 179 sv.SHIN = SHIN; sv.SHOUT = SHOUT; 180 sv.SHDIAG = SHDIAG; sv.OLDSTD = OLDSTD; 181 sv.tpgrp = tpgrp; 182 Vsav = Vdp = 0; Vav = 0; 183 (void) sigvec(SIGINT, (struct sigvec *)0, &sv.sigv); 184 pid = vfork(); 185 if (pid < 0) { 186 (void) sigsetmask(sv.mask); 187 error("Vfork failed"); 188 } 189 forked++; 190 if (pid) { /* parent */ 191 int ppid; 192 closelog(); 193 child = sv.child; setintr = sv.setintr; 194 haderr = sv.haderr; didfds = sv.didfds; 195 SHIN = sv.SHIN; 196 SHOUT = sv.SHOUT; SHDIAG = sv.SHDIAG; 197 OLDSTD = sv.OLDSTD; tpgrp = sv.tpgrp; 198 xfree(Vsav); Vsav = 0; 199 xfree(Vdp); Vdp = 0; 200 xfree( (tchar *)Vav); Vav = 0; 201 /* this is from pfork() */ 202 ppid = pcurrjob ? pcurrjob->p_jobid : pid; 203 if (wanttty >= 0 && tpgrp >= 0) 204 setpgid (ppid, ppid); 205 palloc(pid, t); 206 /* 207 * Restore SIGINT handler. 208 */ 209 (void) sigvec(SIGINT, &sv.sigv, (struct sigvec *)0); 210 (void) sigsetmask(sv.mask); 211 } else { /* child */ 212 /* this is from pfork() */ 213 int pgrp; 214 bool ignint = 0; 215 int sigttou; 216 if (setintr) 217 ignint = 218 (tpgrp == -1 && (t->t_dflg&FINT)) 219 || gointr 220 && eq(gointr, S_MINUS/*"-"*/); 221 pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 222 child++; 223 if (setintr) { 224 setintr = 0; 225 #ifdef notdef 226 (void) signal(SIGCHLD, SIG_DFL); 227 #endif 228 (void) signal(SIGINT, ignint ? 229 SIG_IGN : vffree); 230 (void) signal(SIGQUIT, ignint ? 231 SIG_IGN : SIG_DFL); 232 if (wanttty >= 0) { 233 (void) signal(SIGTSTP, SIG_DFL); 234 (void) signal(SIGTTIN, SIG_DFL); 235 (void) signal(SIGTTOU, SIG_DFL); 236 } 237 (void) signal(SIGTERM, parterm); 238 } else if (tpgrp == -1 && (t->t_dflg&FINT)) { 239 (void) signal(SIGINT, SIG_IGN); 240 (void) signal(SIGQUIT, SIG_IGN); 241 } 242 if (wanttty >= 0 && tpgrp >= 0) 243 (void) setpgid(0, pgrp); 244 if (wanttty > 0) { 245 sigttou = sigblock ( 246 sigmask(SIGTTOU) | 247 sigmask(SIGTTIN) | 248 sigmask(SIGTSTP)); 249 (void) ioctl(FSHTTY, TIOCSPGRP, 250 (tchar *)&pgrp); 251 sigsetmask (sigttou); 252 } 253 if (tpgrp > 0) 254 tpgrp = 0; 255 if (t->t_dflg & FNOHUP) 256 (void) signal(SIGHUP, SIG_IGN); 257 if (t->t_dflg & FNICE) 258 (void) setpriority(PRIO_PROCESS, 259 0, t->t_nice); 260 } 261 262 } 263 #endif 264 if (pid != 0) { 265 /* 266 * It would be better if we could wait for the 267 * whole job when we knew the last process 268 * had been started. Pwait, in fact, does 269 * wait for the whole job anyway, but this test 270 * doesn't really express our intentions. 271 */ 272 if (didfds==0 && t->t_dflg&FPIN) { 273 (void) close(pipein[0]); 274 unsetfd(pipein[0]); 275 (void) close(pipein[1]); 276 unsetfd(pipein[1]); 277 } 278 if ((t->t_dflg & (FPOU|FAND)) == 0) 279 pwait(); 280 break; 281 } 282 doio(t, pipein, pipeout); 283 if (t->t_dflg & FPOU) { 284 (void) close(pipeout[0]); 285 (void) unsetfd(pipeout[0]); 286 (void) close(pipeout[1]); 287 (void) unsetfd(pipeout[1]); 288 } 289 290 /* 291 * Perform a builtin function. 292 * If we are not forked, arrange for possible stopping 293 */ 294 if (bifunc) { 295 func(t, bifunc); 296 if (forked) 297 exitstat(); 298 break; 299 } 300 if (t->t_dtyp != TPAR) { 301 doexec(t); 302 /*NOTREACHED*/ 303 } 304 /* 305 * For () commands must put new 0,1,2 in FSH* and recurse 306 */ 307 OLDSTD = dcopy(0, FOLDSTD); 308 SHOUT = dcopy(1, FSHOUT); 309 SHDIAG = dcopy(2, FSHDIAG); 310 (void) close(SHIN); 311 (void) unsetfd(SHIN); 312 SHIN = -1; 313 didfds = 0; 314 wanttty = -1; 315 t->t_dspr->t_dflg |= t->t_dflg & FINT; 316 execute(t->t_dspr, wanttty); 317 exitstat(); 318 319 case TFIL: 320 t->t_dcar->t_dflg |= FPOU | 321 (t->t_dflg & (FPIN|FAND|FDIAG|FINT)); 322 execute(t->t_dcar, wanttty, pipein, pv); 323 t->t_dcdr->t_dflg |= FPIN | 324 (t->t_dflg & (FPOU|FAND|FPAR|FINT)); 325 if (wanttty > 0) 326 wanttty = 0; /* got tty already */ 327 execute(t->t_dcdr, wanttty, pv, pipeout); 328 break; 329 330 case TLST: 331 if (t->t_dcar) { 332 t->t_dcar->t_dflg |= t->t_dflg & FINT; 333 execute(t->t_dcar, wanttty); 334 /* 335 * In strange case of A&B make a new job after A 336 */ 337 if (t->t_dcar->t_dflg&FAND && t->t_dcdr && 338 (t->t_dcdr->t_dflg&FAND) == 0) 339 pendjob(); 340 } 341 if (t->t_dcdr) { 342 t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT); 343 execute(t->t_dcdr, wanttty); 344 } 345 break; 346 347 case TOR: 348 case TAND: 349 if (t->t_dcar) { 350 t->t_dcar->t_dflg |= t->t_dflg & FINT; 351 execute(t->t_dcar, wanttty); 352 if ((getn(value(S_status/*"status"*/)) == 0) != (t->t_dtyp == TAND)) 353 return; 354 } 355 if (t->t_dcdr) { 356 t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT); 357 execute(t->t_dcdr, wanttty); 358 } 359 break; 360 } 361 /* 362 * Fall through for all breaks from switch 363 * 364 * If there will be no more executions of this 365 * command, flush all file descriptors. 366 * Places that turn on the FREDO bit are responsible 367 * for doing donefds after the last re-execution 368 */ 369 if (didfds && !(t->t_dflg & FREDO)) 370 donefds(); 371 372 /* 373 * If glob() was called and arguments list is not yet 374 * free'ed, free them here. 375 */ 376 if (gargv) { 377 blkfree(gargv); 378 gargv = 0; 379 globcnt = 0; 380 } 381 } 382 383 #ifdef VFORK 384 void 385 vffree() 386 { 387 register tchar **v; 388 389 #ifdef TRACE 390 tprintf("TRACE- vffree()\n"); 391 #endif 392 if (v = gargv) 393 gargv = 0, xfree( (tchar *)v); 394 if (v = pargv) 395 pargv = 0, xfree( (tchar *)v); 396 _exit(1); 397 } 398 #endif 399 400 /* 401 * Perform io redirection. 402 * We may or maynot be forked here. 403 */ 404 doio(t, pipein, pipeout) 405 register struct command *t; 406 int *pipein, *pipeout; 407 { 408 register tchar *cp, *dp; 409 register int flags = t->t_dflg; 410 int fd; 411 412 #ifdef TRACE 413 tprintf("TRACE- doio()\n"); 414 #endif 415 if (didfds || (flags & FREDO)) 416 return; 417 if ((flags & FHERE) == 0) { /* FHERE already done */ 418 (void) close(0); 419 (void) unsetfd(0); 420 if (cp = t->t_dlef) { 421 dp = Dfix1(cp); 422 cp = globone(dp); 423 xfree(dp); 424 xfree(cp); 425 if (open_(cp, 0) < 0) 426 Perror(cp); 427 } else if (flags & FPIN) { 428 fd = dup(pipein[0]); 429 if (fd != -1) 430 setfd(fd); 431 (void) close(pipein[0]); 432 (void) unsetfd(pipein[0]); 433 (void) close(pipein[1]); 434 (void) unsetfd(pipein[1]); 435 } else if ((flags & FINT) && tpgrp == -1) { 436 (void) close(0); /* no need for unsetfd */ 437 (void) open("/dev/null", 0); /* no need for setfd */ 438 } else { 439 fd = dup(OLDSTD); 440 if (fd != -1) 441 setfd(fd); 442 } 443 } 444 (void) close(1); 445 (void) unsetfd(1); 446 if (cp = t->t_drit) { 447 dp = Dfix1(cp); 448 cp = globone(dp); 449 xfree(dp); 450 if ((flags & FCAT) && open_(cp, 1) >= 0) 451 (void) lseek(1, (off_t)0, 2); 452 else { 453 if (!(flags & FANY) && adrof(S_noclobber/*"noclobber"*/)) { 454 if (flags & FCAT) 455 Perror(cp); 456 chkclob(cp); 457 } 458 if (creat_(cp, 0666) < 0) 459 Perror(cp); 460 } 461 xfree(cp); 462 } else if (flags & FPOU) { 463 fd = dup(pipeout[1]); 464 if (fd != -1) 465 setfd (fd); 466 } 467 else { 468 fd = dup(SHOUT); 469 if (fd != -1) 470 setfd(fd); 471 } 472 473 (void) close(2); 474 (void) unsetfd(2); 475 if (flags & FDIAG) { 476 fd = dup(1); 477 if (fd != -1) 478 setfd(fd); 479 } 480 else { 481 fd = dup(SHDIAG); 482 if (fd != -1) 483 setfd(fd); 484 } 485 didfds = 1; 486 } 487 488 mypipe(pv) 489 register int *pv; 490 { 491 492 #ifdef TRACE 493 tprintf("TRACE- mypipe()\n"); 494 #endif 495 if (pipe(pv) < 0) 496 goto oops; 497 setfd(pv[0]); 498 setfd(pv[1]); 499 500 pv[0] = dmove(pv[0], -1); 501 pv[1] = dmove(pv[1], -1); 502 if (pv[0] >= 0 && pv[1] >= 0) 503 return; 504 oops: 505 error("Can't make pipe"); 506 } 507 508 chkclob(cp) 509 register tchar *cp; 510 { 511 struct stat stb; 512 unsigned short type; 513 514 #ifdef TRACE 515 tprintf("TRACE- chkclob()\n"); 516 #endif 517 if (stat_(cp, &stb) < 0) 518 return; 519 type = stb.st_mode & S_IFMT; 520 if (type == S_IFCHR || type == S_IFIFO) 521 return; 522 error("%t: File exists", cp); 523 } 524