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