1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley Software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #if !defined(lint) && defined(DOSCCS) 8: static char *sccsid = "@(#)sh.sem.c 5.4.1 (2.11BSD GTE) 12/9/94"; 9: #endif 10: 11: #include "sh.h" 12: #include "sh.proc.h" 13: #include <fcntl.h> 14: #include <sys/ioctl.h> 15: 16: /* 17: * C shell 18: */ 19: 20: /*VARARGS 1*/ 21: execute(t, wanttty, pipein, pipeout) 22: register struct command *t; 23: int wanttty, *pipein, *pipeout; 24: { 25: bool forked = 0; 26: struct biltins *bifunc; 27: int pid = 0; 28: int pv[2]; 29: 30: if (t == 0) 31: return; 32: if ((t->t_dflg & FAND) && wanttty > 0) 33: wanttty = 0; 34: switch (t->t_dtyp) { 35: 36: case TCOM: 37: if ((t->t_dcom[0][0] & (QUOTE|TRIM)) == QUOTE) 38: (void) strcpy(t->t_dcom[0], t->t_dcom[0] + 1); 39: if ((t->t_dflg & FREDO) == 0) 40: Dfix(t); /* $ " ' \ */ 41: if (t->t_dcom[0] == 0) 42: return; 43: /* fall into... */ 44: 45: case TPAR: 46: if (t->t_dflg & FPOU) 47: mypipe(pipeout); 48: /* 49: * Must do << early so parent will know 50: * where input pointer should be. 51: * If noexec then this is all we do. 52: */ 53: if (t->t_dflg & FHERE) { 54: (void) close(0); 55: heredoc(t->t_dlef); 56: if (noexec) 57: (void) close(0); 58: } 59: if (noexec) 60: break; 61: 62: set("status", "0"); 63: 64: /* 65: * This mess is the necessary kludge to handle the prefix 66: * builtins: nice, nohup, time. These commands can also 67: * be used by themselves, and this is not handled here. 68: * This will also work when loops are parsed. 69: */ 70: while (t->t_dtyp == TCOM) 71: if (eq(t->t_dcom[0], "nice")) 72: if (t->t_dcom[1]) 73: if (any(t->t_dcom[1][0], "+-")) 74: if (t->t_dcom[2]) { 75: setname("nice"); 76: t->t_nice = getn(t->t_dcom[1]); 77: lshift(t->t_dcom, 2); 78: t->t_dflg |= FNICE; 79: } else 80: break; 81: else { 82: t->t_nice = 4; 83: lshift(t->t_dcom, 1); 84: t->t_dflg |= FNICE; 85: } 86: else 87: break; 88: else if (eq(t->t_dcom[0], "nohup")) 89: if (t->t_dcom[1]) { 90: t->t_dflg |= FNOHUP; 91: lshift(t->t_dcom, 1); 92: } else 93: break; 94: else if (eq(t->t_dcom[0], "time")) 95: if (t->t_dcom[1]) { 96: t->t_dflg |= FTIME; 97: lshift(t->t_dcom, 1); 98: } else 99: break; 100: else 101: break; 102: /* 103: * Check if we have a builtin function and remember which one. 104: */ 105: bifunc = t->t_dtyp == TCOM ? isbfunc(t) : (struct biltins *) 0; 106: 107: /* 108: * We fork only if we are timed, or are not the end of 109: * a parenthesized list and not a simple builtin function. 110: * Simple meaning one that is not pipedout, niced, nohupped, 111: * or &'d. 112: * It would be nice(?) to not fork in some of these cases. 113: */ 114: if (((t->t_dflg & FTIME) || (t->t_dflg & FPAR) == 0 && 115: (!bifunc || t->t_dflg & (FPOU|FAND|FNICE|FNOHUP)))) 116: #ifdef VFORK 117: if (t->t_dtyp == TPAR || t->t_dflg&(FREDO|FAND) || bifunc) 118: #endif 119: { forked++; pid = pfork(t, wanttty); } 120: #ifdef VFORK 121: else { 122: int vffree(); 123: int ochild, osetintr, ohaderr, odidfds; 124: int oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp; 125: long omask; 126: 127: /* 128: * Prepare for the vfork by saving everything 129: * that the child corrupts before it exec's. 130: * Note that in some signal implementations 131: * which keep the signal info in user space 132: * (e.g. Sun's) it will also be necessary to 133: * save and restore the current sigvec's for 134: * the signals the child touches before it 135: * exec's. 136: */ 137: omask = sigblock(sigmask(SIGCHLD)); 138: ochild = child; osetintr = setintr; 139: ohaderr = haderr; odidfds = didfds; 140: oSHIN = SHIN; oSHOUT = SHOUT; 141: oSHDIAG = SHDIAG; oOLDSTD = OLDSTD; otpgrp = tpgrp; 142: Vsav = Vdp = 0; Vav = 0; 143: pid = vfork(); 144: if (pid < 0) { 145: (void) sigsetmask(omask); 146: error("No more processes"); 147: } 148: forked++; 149: if (pid) { /* parent */ 150: register char **v; 151: 152: child = ochild; setintr = osetintr; 153: haderr = ohaderr; didfds = odidfds; 154: SHIN = oSHIN; 155: SHOUT = oSHOUT; SHDIAG = oSHDIAG; 156: OLDSTD = oOLDSTD; tpgrp = otpgrp; 157: xfree(Vsav); Vsav = 0; 158: xfree(Vdp); Vdp = 0; 159: xfree((char *)Vav); Vav = 0; 160: if (v = gargv) 161: gargv = 0, blkfree(v); 162: if (v = pargv) 163: pargv = 0, blkfree(v); 164: /* this is from pfork() */ 165: palloc(pid, t); 166: (void) sigsetmask(omask); 167: } else { /* child */ 168: /* this is from pfork() */ 169: int pgrp; 170: bool ignint = 0; 171: 172: if (setintr) 173: ignint = 174: (tpgrp == -1 && (t->t_dflg&FINT)) 175: || gointr && eq(gointr, "-"); 176: pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 177: child++; 178: if (setintr) { 179: setintr = 0; 180: #ifdef notdef 181: (void) signal(SIGCHLD, SIG_DFL); 182: #endif 183: (void) signal(SIGINT, ignint ? 184: SIG_IGN : vffree); 185: (void) signal(SIGQUIT, ignint ? 186: SIG_IGN : SIG_DFL); 187: if (wanttty >= 0) { 188: (void) signal(SIGTSTP, SIG_DFL); 189: (void) signal(SIGTTIN, SIG_DFL); 190: (void) signal(SIGTTOU, SIG_DFL); 191: } 192: (void) signal(SIGTERM, parterm); 193: } else if (tpgrp == -1 && (t->t_dflg&FINT)) { 194: (void) signal(SIGINT, SIG_IGN); 195: (void) signal(SIGQUIT, SIG_IGN); 196: } 197: if (wanttty > 0) 198: (void) ioctl(FSHTTY, TIOCSPGRP, 199: (char *)&pgrp); 200: if (wanttty >= 0 && tpgrp >= 0) 201: (void) setpgrp(0, pgrp); 202: if (tpgrp > 0) 203: tpgrp = 0; 204: if (t->t_dflg & FNOHUP) 205: (void) signal(SIGHUP, SIG_IGN); 206: if (t->t_dflg & FNICE) 207: (void) setpriority(PRIO_PROCESS, 208: 0, t->t_nice); 209: } 210: 211: } 212: #endif 213: if (pid != 0) { 214: /* 215: * It would be better if we could wait for the 216: * whole job when we knew the last process 217: * had been started. Pwait, in fact, does 218: * wait for the whole job anyway, but this test 219: * doesn't really express our intentions. 220: */ 221: if (didfds==0 && t->t_dflg&FPIN) { 222: (void) close(pipein[0]); 223: (void) close(pipein[1]); 224: } 225: if ((t->t_dflg & (FPOU|FAND)) == 0) 226: pwait(); 227: break; 228: } 229: doio(t, pipein, pipeout); 230: if (t->t_dflg & FPOU) { 231: (void) close(pipeout[0]); 232: (void) close(pipeout[1]); 233: } 234: 235: /* 236: * Perform a builtin function. 237: * If we are not forked, arrange for possible stopping 238: */ 239: if (bifunc) { 240: func(t, bifunc); 241: if (forked) 242: exitstat(); 243: break; 244: } 245: if (t->t_dtyp != TPAR) { 246: doexec(t); 247: /*NOTREACHED*/ 248: } 249: /* 250: * For () commands must put new 0,1,2 in FSH* and recurse 251: */ 252: OLDSTD = dcopy(0, FOLDSTD); 253: SHOUT = dcopy(1, FSHOUT); 254: SHDIAG = dcopy(2, FSHDIAG); 255: (void) close(SHIN); 256: SHIN = -1; 257: didfds = 0; 258: wanttty = -1; 259: t->t_dspr->t_dflg |= t->t_dflg & FINT; 260: execute(t->t_dspr, wanttty); 261: exitstat(); 262: 263: case TFIL: 264: t->t_dcar->t_dflg |= FPOU | 265: (t->t_dflg & (FPIN|FAND|FDIAG|FINT)); 266: execute(t->t_dcar, wanttty, pipein, pv); 267: t->t_dcdr->t_dflg |= FPIN | 268: (t->t_dflg & (FPOU|FAND|FPAR|FINT)); 269: if (wanttty > 0) 270: wanttty = 0; /* got tty already */ 271: execute(t->t_dcdr, wanttty, pv, pipeout); 272: break; 273: 274: case TLST: 275: if (t->t_dcar) { 276: t->t_dcar->t_dflg |= t->t_dflg & FINT; 277: execute(t->t_dcar, wanttty); 278: /* 279: * In strange case of A&B make a new job after A 280: */ 281: if (t->t_dcar->t_dflg&FAND && t->t_dcdr && 282: (t->t_dcdr->t_dflg&FAND) == 0) 283: pendjob(); 284: } 285: if (t->t_dcdr) { 286: t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT); 287: execute(t->t_dcdr, wanttty); 288: } 289: break; 290: 291: case TOR: 292: case TAND: 293: if (t->t_dcar) { 294: t->t_dcar->t_dflg |= t->t_dflg & FINT; 295: execute(t->t_dcar, wanttty); 296: if ((getn(value("status")) == 0) != (t->t_dtyp == TAND)) 297: return; 298: } 299: if (t->t_dcdr) { 300: t->t_dcdr->t_dflg |= t->t_dflg & (FPAR|FINT); 301: execute(t->t_dcdr, wanttty); 302: } 303: break; 304: } 305: /* 306: * Fall through for all breaks from switch 307: * 308: * If there will be no more executions of this 309: * command, flush all file descriptors. 310: * Places that turn on the FREDO bit are responsible 311: * for doing donefds after the last re-execution 312: */ 313: if (didfds && !(t->t_dflg & FREDO)) 314: donefds(); 315: } 316: 317: #ifdef VFORK 318: vffree() 319: { 320: register char **v; 321: 322: if (v = gargv) 323: gargv = 0, blkfree(v); 324: if (v = pargv) 325: pargv = 0, blkfree(v); 326: _exit(1); 327: } 328: #endif 329: 330: /* 331: * Perform io redirection. 332: * We may or maynot be forked here. 333: */ 334: doio(t, pipein, pipeout) 335: register struct command *t; 336: int *pipein, *pipeout; 337: { 338: register char *cp; 339: register int flags = t->t_dflg; 340: 341: if (didfds || (flags & FREDO)) 342: return; 343: if ((flags & FHERE) == 0) { /* FHERE already done */ 344: (void) close(0); 345: if (cp = t->t_dlef) { 346: cp = globone(Dfix1(cp)); 347: xfree(cp); 348: if (open(cp, 0) < 0) 349: Perror(cp); 350: } else if (flags & FPIN) { 351: (void) dup(pipein[0]); 352: (void) close(pipein[0]); 353: (void) close(pipein[1]); 354: } else if ((flags & FINT) && tpgrp == -1) { 355: (void) close(0); 356: (void) open("/dev/null", 0); 357: } else 358: (void) dup(OLDSTD); 359: } 360: (void) close(1); 361: if (cp = t->t_drit) { 362: cp = globone(Dfix1(cp)); 363: xfree(cp); 364: if ((flags & FCAT) && open(cp, O_WRONLY | O_APPEND) >= 0) 365: ; 366: else { 367: if (!(flags & FANY) && adrof("noclobber")) { 368: if (flags & FCAT) 369: Perror(cp); 370: chkclob(cp); 371: } 372: if (creat(cp, 0666) < 0) 373: Perror(cp); 374: } 375: } else if (flags & FPOU) 376: (void) dup(pipeout[1]); 377: else 378: (void) dup(SHOUT); 379: 380: (void) close(2); 381: if (flags & FDIAG) 382: (void) dup(1); 383: else 384: (void) dup(SHDIAG); 385: didfds = 1; 386: } 387: 388: mypipe(pv) 389: register int *pv; 390: { 391: 392: if (pipe(pv) < 0) 393: goto oops; 394: pv[0] = dmove(pv[0], -1); 395: pv[1] = dmove(pv[1], -1); 396: if (pv[0] >= 0 && pv[1] >= 0) 397: return; 398: oops: 399: error("Can't make pipe"); 400: } 401: 402: chkclob(cp) 403: register char *cp; 404: { 405: struct stat stb; 406: 407: if (stat(cp, &stb) < 0) 408: return; 409: if ((stb.st_mode & S_IFMT) == S_IFCHR) 410: return; 411: error("%s: File exists", cp); 412: }