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