1 0 stevel /* 2 2182 chin * Copyright 2006 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 "sh.h" 18 0 stevel #include "sh.dir.h" 19 0 stevel #include "sh.proc.h" 20 0 stevel #include "wait.h" 21 0 stevel #include "sh.tconst.h" 22 0 stevel 23 0 stevel /* 24 0 stevel * C Shell - functions that manage processes, handling hanging, termination 25 0 stevel */ 26 0 stevel 27 559 nakanon #define BIGINDEX 9 /* largest desirable job index */ 28 0 stevel 29 356 muffin void pjwait(struct process *); 30 356 muffin void pflush(struct process *); 31 356 muffin void pclrcurr(struct process *); 32 356 muffin void padd(struct command *); 33 356 muffin void pads(tchar *); 34 356 muffin void ptprint(struct process *); 35 356 muffin void pkill(tchar **, int); 36 356 muffin void pstart(struct process *, int); 37 356 muffin void okpcntl(void); 38 356 muffin struct process *pgetcurr(struct process *); 39 356 muffin struct process *pfind(tchar *); 40 356 muffin 41 0 stevel /* 42 0 stevel * pchild - called at interrupt level by the SIGCHLD signal 43 0 stevel * indicating that at least one child has terminated or stopped 44 0 stevel * thus at least one wait system call will definitely return a 45 0 stevel * childs status. Top level routines (like pwait) must be sure 46 0 stevel * to mask interrupts when playing with the proclist data structures! 47 0 stevel */ 48 0 stevel void 49 356 muffin pchild(void) 50 0 stevel { 51 356 muffin struct process *pp; 52 356 muffin struct process *fp; 53 356 muffin int pid; 54 0 stevel union wait w; 55 0 stevel int jobflags; 56 0 stevel struct rusage ru; 57 0 stevel 58 0 stevel #ifdef TRACE 59 0 stevel tprintf("TRACE- pchile()\n"); 60 0 stevel #endif 61 0 stevel loop: 62 0 stevel pid = csh_wait3(&w, (setintr ? WNOHANG|WUNTRACED:WNOHANG), &ru); 63 559 nakanon /* 64 559 nakanon * SysV sends a SIGCHLD when the child process 65 559 nakanon * receives a SIGCONT, and result of that action is ignored here 66 559 nakanon */ 67 559 nakanon if (w.w_status == WCONTFLG) 68 559 nakanon return; 69 0 stevel if (pid <= 0) { 70 0 stevel if (errno == EINTR) { 71 0 stevel errno = 0; 72 0 stevel goto loop; 73 0 stevel } 74 0 stevel pnoprocesses = pid == -1; 75 0 stevel return; 76 0 stevel } 77 0 stevel for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) 78 0 stevel if (pid == pp->p_pid) 79 0 stevel goto found; 80 0 stevel goto loop; 81 0 stevel found: 82 559 nakanon if (pid == atoi_(value(S_child /* "child" */))) 83 559 nakanon unsetv(S_child /* "child" */); 84 0 stevel pp->p_flags &= ~(PRUNNING|PSTOPPED|PREPORTED); 85 0 stevel if (WIFSTOPPED(w)) { 86 0 stevel pp->p_flags |= PSTOPPED; 87 0 stevel pp->p_reason = w.w_stopsig; 88 0 stevel } else { 89 559 nakanon if (pp->p_flags & (PTIME|PPTIME) || adrof(S_time /* "time" */)) 90 0 stevel (void) gettimeofday(&pp->p_etime, (struct timezone *)0); 91 0 stevel pp->p_rusage = ru; 92 0 stevel if (WIFSIGNALED(w)) { 93 0 stevel if (w.w_termsig == SIGINT) 94 0 stevel pp->p_flags |= PINTERRUPTED; 95 0 stevel else 96 0 stevel pp->p_flags |= PSIGNALED; 97 0 stevel if (w.w_coredump) 98 0 stevel pp->p_flags |= PDUMPED; 99 0 stevel pp->p_reason = w.w_termsig; 100 0 stevel } else { 101 0 stevel pp->p_reason = w.w_retcode; 102 0 stevel if (pp->p_reason != 0) 103 0 stevel pp->p_flags |= PAEXITED; 104 0 stevel else 105 0 stevel pp->p_flags |= PNEXITED; 106 0 stevel } 107 0 stevel } 108 0 stevel jobflags = 0; 109 0 stevel fp = pp; 110 0 stevel do { 111 0 stevel if ((fp->p_flags & (PPTIME|PRUNNING|PSTOPPED)) == 0 && 112 559 nakanon !child && adrof(S_time /* "time" */) && 113 0 stevel fp->p_rusage.ru_utime.tv_sec+fp->p_rusage.ru_stime.tv_sec >= 114 559 nakanon atoi_(value(S_time /* "time" */))) 115 0 stevel fp->p_flags |= PTIME; 116 0 stevel jobflags |= fp->p_flags; 117 0 stevel } while ((fp = fp->p_friends) != pp); 118 0 stevel pp->p_flags &= ~PFOREGND; 119 0 stevel if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 120 0 stevel pp->p_flags &= ~PPTIME; 121 0 stevel pp->p_flags |= PTIME; 122 0 stevel } 123 0 stevel if ((jobflags & (PRUNNING|PREPORTED)) == 0) { 124 0 stevel fp = pp; 125 0 stevel do { 126 0 stevel if (fp->p_flags&PSTOPPED) 127 0 stevel fp->p_flags |= PREPORTED; 128 559 nakanon } while ((fp = fp->p_friends) != pp); 129 559 nakanon while (fp->p_pid != fp->p_jobid) 130 0 stevel fp = fp->p_friends; 131 0 stevel if (jobflags&PSTOPPED) { 132 0 stevel if (pcurrent && pcurrent != fp) 133 0 stevel pprevious = pcurrent; 134 0 stevel pcurrent = fp; 135 0 stevel } else 136 0 stevel pclrcurr(fp); 137 0 stevel if (jobflags&PFOREGND) { 138 0 stevel if (jobflags & (PSIGNALED|PSTOPPED|PPTIME) || 139 0 stevel #ifdef IIASA 140 0 stevel jobflags & PAEXITED || 141 0 stevel #endif 142 0 stevel !eq(dcwd->di_name, fp->p_cwd->di_name)) { 143 0 stevel ; /* print in pjwait */ 144 0 stevel } 145 0 stevel } else { 146 559 nakanon if (jobflags&PNOTIFY || adrof(S_notify /* "notify" */)) { 147 0 stevel write_string("\015\n"); 148 0 stevel flush(); 149 0 stevel (void) pprint(pp, NUMBER|NAME|REASON); 150 0 stevel if ((jobflags&PSTOPPED) == 0) 151 0 stevel pflush(pp); 152 0 stevel } else { 153 0 stevel fp->p_flags |= PNEEDNOTE; 154 0 stevel neednote++; 155 0 stevel } 156 0 stevel } 157 0 stevel } 158 0 stevel goto loop; 159 0 stevel } 160 0 stevel 161 356 muffin void 162 356 muffin pnote(void) 163 0 stevel { 164 356 muffin struct process *pp; 165 0 stevel int flags, omask; 166 0 stevel 167 0 stevel #ifdef TRACE 168 0 stevel tprintf("TRACE- pnote()\n"); 169 0 stevel #endif 170 0 stevel neednote = 0; 171 0 stevel for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) { 172 0 stevel if (pp->p_flags & PNEEDNOTE) { 173 0 stevel omask = sigblock(sigmask(SIGCHLD)); 174 0 stevel pp->p_flags &= ~PNEEDNOTE; 175 0 stevel flags = pprint(pp, NUMBER|NAME|REASON); 176 0 stevel if ((flags&(PRUNNING|PSTOPPED)) == 0) 177 0 stevel pflush(pp); 178 0 stevel (void) sigsetmask(omask); 179 0 stevel } 180 0 stevel } 181 0 stevel } 182 0 stevel 183 0 stevel /* 184 0 stevel * pwait - wait for current job to terminate, maintaining integrity 185 0 stevel * of current and previous job indicators. 186 0 stevel */ 187 356 muffin void 188 356 muffin pwait(void) 189 0 stevel { 190 356 muffin struct process *fp, *pp; 191 0 stevel int omask; 192 0 stevel 193 0 stevel #ifdef TRACE 194 0 stevel tprintf("TRACE- pwait()\n"); 195 0 stevel #endif 196 0 stevel /* 197 0 stevel * Here's where dead procs get flushed. 198 0 stevel */ 199 0 stevel omask = sigblock(sigmask(SIGCHLD)); 200 0 stevel for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next) 201 0 stevel if (pp->p_pid == 0) { 202 0 stevel fp->p_next = pp->p_next; 203 0 stevel xfree(pp->p_command); 204 0 stevel if (pp->p_cwd && --pp->p_cwd->di_count == 0) 205 0 stevel if (pp->p_cwd->di_next == 0) 206 0 stevel dfree(pp->p_cwd); 207 559 nakanon xfree((tchar *)pp); 208 0 stevel pp = fp; 209 0 stevel } 210 0 stevel (void) sigsetmask(omask); 211 0 stevel pjwait(pcurrjob); 212 0 stevel } 213 0 stevel 214 0 stevel /* 215 0 stevel * pjwait - wait for a job to finish or become stopped 216 0 stevel * It is assumed to be in the foreground state (PFOREGND) 217 0 stevel */ 218 356 muffin void 219 356 muffin pjwait(struct process *pp) 220 0 stevel { 221 356 muffin struct process *fp; 222 0 stevel int jobflags, reason, omask; 223 0 stevel 224 0 stevel #ifdef TRACE 225 0 stevel tprintf("TRACE- pjwait()\n"); 226 0 stevel #endif 227 0 stevel while (pp->p_pid != pp->p_jobid) 228 0 stevel pp = pp->p_friends; 229 0 stevel fp = pp; 230 0 stevel do { 231 0 stevel if ((fp->p_flags&(PFOREGND|PRUNNING)) == PRUNNING) 232 0 stevel printf("BUG: waiting for background job!\n"); 233 0 stevel } while ((fp = fp->p_friends) != pp); 234 0 stevel /* 235 0 stevel * Now keep pausing as long as we are not interrupted (SIGINT), 236 0 stevel * and the target process, or any of its friends, are running 237 0 stevel */ 238 0 stevel fp = pp; 239 0 stevel omask = sigblock(sigmask(SIGCHLD)); 240 0 stevel for (;;) { 241 0 stevel jobflags = 0; 242 0 stevel do 243 0 stevel jobflags |= fp->p_flags; 244 0 stevel while ((fp = (fp->p_friends)) != pp); 245 0 stevel if ((jobflags & PRUNNING) == 0) 246 0 stevel break; 247 200 raf /* 248 200 raf * At this point, csh used to call: 249 200 raf * sigpause(sigblock(0) &~ sigmask(SIGCHLD)); 250 200 raf * expecting to receive a SIGCHLD signal from the 251 200 raf * termination of the child and to invoke the 252 200 raf * signal handler, pchild(), as a result. 253 200 raf * 254 200 raf * However, vfork() now causes a vfork()'d child to 255 200 raf * have all of its active signal handlers reset to 256 200 raf * SIG_DFL, to forstall parent memory corruption due 257 200 raf * to race conditions with signal handling. 258 200 raf * 259 200 raf * If this instance of csh is itself a child of vfork(), 260 200 raf * which can happen when the top-level csh performs a 261 200 raf * command substitution inside an i/o redirection, like: 262 200 raf * /bin/echo foo >`/bin/echo trash` 263 200 raf * then we will never receive SIGCHLD. To accommodate 264 200 raf * this, we wait until one of our children terminates 265 200 raf * (without actually reaping the child) and call the 266 200 raf * SIGCHLD signal handler (pchild()) directly. 267 200 raf */ 268 200 raf if (csh_wait_noreap() > 0) 269 200 raf pchild(); /* simulate receipt of SIGCHLD */ 270 0 stevel } 271 0 stevel (void) sigsetmask(omask); 272 0 stevel if (tpgrp > 0) /* get tty back */ 273 0 stevel (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&tpgrp); 274 0 stevel if ((jobflags&(PSIGNALED|PSTOPPED|PTIME)) || 275 559 nakanon !eq(dcwd->di_name, fp->p_cwd->di_name)) { 276 0 stevel if (jobflags&PSTOPPED) 277 0 stevel printf("\n"); 278 0 stevel (void) pprint(pp, AREASON|SHELLDIR); 279 0 stevel } 280 0 stevel if ((jobflags&(PINTERRUPTED|PSTOPPED)) && setintr && 281 559 nakanon (!gointr || !eq(gointr, S_MINUS /* "-" */))) { 282 0 stevel if ((jobflags & PSTOPPED) == 0) 283 0 stevel pflush(pp); 284 0 stevel pintr1(0); 285 0 stevel /*NOTREACHED*/ 286 0 stevel } 287 0 stevel reason = 0; 288 0 stevel fp = pp; 289 0 stevel do { 290 0 stevel if (fp->p_reason) 291 0 stevel reason = fp->p_flags & (PSIGNALED|PINTERRUPTED) ? 292 0 stevel fp->p_reason | ABN_TERM : fp->p_reason; 293 0 stevel } while ((fp = fp->p_friends) != pp); 294 559 nakanon set(S_status /* "status" */, putn(reason)); 295 0 stevel if (reason && exiterr) 296 0 stevel exitstat(); 297 0 stevel pflush(pp); 298 0 stevel } 299 0 stevel 300 0 stevel /* 301 0 stevel * dowait - wait for all processes to finish 302 0 stevel */ 303 356 muffin void 304 356 muffin dowait(void) 305 0 stevel { 306 356 muffin struct process *pp; 307 0 stevel int omask; 308 0 stevel 309 0 stevel #ifdef TRACE 310 0 stevel tprintf("TRACE- dowait()\n"); 311 0 stevel #endif 312 0 stevel pjobs++; 313 0 stevel omask = sigblock(sigmask(SIGCHLD)); 314 0 stevel loop: 315 0 stevel for (pp = proclist.p_next; pp; pp = pp->p_next) 316 0 stevel if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */ 317 0 stevel pp->p_flags&PRUNNING) { 318 0 stevel sigpause(0); 319 0 stevel goto loop; 320 0 stevel } 321 0 stevel (void) sigsetmask(omask); 322 0 stevel pjobs = 0; 323 0 stevel } 324 0 stevel 325 0 stevel /* 326 0 stevel * pflushall - flush all jobs from list (e.g. at fork()) 327 0 stevel */ 328 356 muffin void 329 356 muffin pflushall(void) 330 0 stevel { 331 356 muffin struct process *pp; 332 0 stevel 333 0 stevel #ifdef TRACE 334 0 stevel tprintf("TRACE- pflush()\n"); 335 0 stevel #endif 336 0 stevel for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) 337 0 stevel if (pp->p_pid) 338 0 stevel pflush(pp); 339 0 stevel } 340 0 stevel 341 0 stevel /* 342 0 stevel * pflush - flag all process structures in the same job as the 343 0 stevel * the argument process for deletion. The actual free of the 344 0 stevel * space is not done here since pflush is called at interrupt level. 345 0 stevel */ 346 356 muffin void 347 356 muffin pflush(struct process *pp) 348 0 stevel { 349 356 muffin struct process *np; 350 356 muffin int index; 351 0 stevel 352 0 stevel #ifdef TRACE 353 0 stevel tprintf("TRACE- pflush()\n"); 354 0 stevel #endif 355 0 stevel if (pp->p_pid == 0) { 356 0 stevel printf("BUG: process flushed twice"); 357 0 stevel return; 358 0 stevel } 359 0 stevel while (pp->p_pid != pp->p_jobid) 360 0 stevel pp = pp->p_friends; 361 0 stevel pclrcurr(pp); 362 0 stevel if (pp == pcurrjob) 363 0 stevel pcurrjob = 0; 364 0 stevel index = pp->p_index; 365 0 stevel np = pp; 366 0 stevel do { 367 0 stevel np->p_index = np->p_pid = 0; 368 0 stevel np->p_flags &= ~PNEEDNOTE; 369 0 stevel } while ((np = np->p_friends) != pp); 370 0 stevel if (index == pmaxindex) { 371 0 stevel for (np = proclist.p_next, index = 0; np; np = np->p_next) 372 0 stevel if (np->p_index > (tchar)index) 373 0 stevel index = np->p_index; 374 0 stevel pmaxindex = index; 375 0 stevel } 376 0 stevel } 377 0 stevel 378 0 stevel /* 379 0 stevel * pclrcurr - make sure the given job is not the current or previous job; 380 0 stevel * pp MUST be the job leader 381 0 stevel */ 382 356 muffin void 383 356 muffin pclrcurr(struct process *pp) 384 0 stevel { 385 0 stevel 386 0 stevel #ifdef TRACE 387 0 stevel tprintf("TRACE- pclrcurr()\n"); 388 0 stevel #endif 389 0 stevel if (pp == pcurrent) 390 0 stevel if (pprevious != PNULL) { 391 0 stevel pcurrent = pprevious; 392 0 stevel pprevious = pgetcurr(pp); 393 0 stevel } else { 394 0 stevel pcurrent = pgetcurr(pp); 395 0 stevel pprevious = pgetcurr(pp); 396 0 stevel } 397 0 stevel else if (pp == pprevious) 398 0 stevel pprevious = pgetcurr(pp); 399 0 stevel } 400 0 stevel 401 0 stevel /* +4 here is 1 for '\0', 1 ea for << >& >> */ 402 0 stevel tchar command[PMAXLEN+4]; 403 0 stevel int cmdlen; 404 0 stevel tchar *cmdp; 405 0 stevel /* 406 0 stevel * palloc - allocate a process structure and fill it up. 407 0 stevel * an important assumption is made that the process is running. 408 0 stevel */ 409 356 muffin void 410 356 muffin palloc(int pid, struct command *t) 411 0 stevel { 412 356 muffin struct process *pp; 413 0 stevel int i; 414 0 stevel 415 0 stevel #ifdef TRACE 416 0 stevel tprintf("TRACE- palloc()\n"); 417 0 stevel #endif 418 559 nakanon pp = (struct process *)xcalloc(1, sizeof (struct process)); 419 0 stevel pp->p_pid = pid; 420 0 stevel pp->p_flags = t->t_dflg & FAND ? PRUNNING : PRUNNING|PFOREGND; 421 0 stevel if (t->t_dflg & FTIME) 422 0 stevel pp->p_flags |= PPTIME; 423 0 stevel cmdp = command; 424 0 stevel cmdlen = 0; 425 0 stevel padd(t); 426 0 stevel *cmdp++ = 0; 427 0 stevel if (t->t_dflg & FPOU) { 428 0 stevel pp->p_flags |= PPOU; 429 0 stevel if (t->t_dflg & FDIAG) 430 0 stevel pp->p_flags |= PDIAG; 431 0 stevel } 432 0 stevel pp->p_command = savestr(command); 433 0 stevel if (pcurrjob) { 434 0 stevel struct process *fp; 435 0 stevel /* careful here with interrupt level */ 436 0 stevel pp->p_cwd = 0; 437 0 stevel pp->p_index = pcurrjob->p_index; 438 0 stevel pp->p_friends = pcurrjob; 439 0 stevel pp->p_jobid = pcurrjob->p_pid; 440 0 stevel for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends) 441 0 stevel ; 442 0 stevel fp->p_friends = pp; 443 0 stevel } else { 444 0 stevel pcurrjob = pp; 445 0 stevel pp->p_jobid = pid; 446 0 stevel pp->p_friends = pp; 447 0 stevel pp->p_cwd = dcwd; 448 0 stevel dcwd->di_count++; 449 0 stevel if (pmaxindex < BIGINDEX) 450 0 stevel pp->p_index = ++pmaxindex; 451 0 stevel else { 452 0 stevel struct process *np; 453 0 stevel 454 0 stevel for (i = 1; ; i++) { 455 0 stevel for (np = proclist.p_next; np; np = np->p_next) 456 0 stevel if (np->p_index == i) 457 0 stevel goto tryagain; 458 0 stevel pp->p_index = i; 459 0 stevel if (i > pmaxindex) 460 0 stevel pmaxindex = i; 461 559 nakanon break; 462 0 stevel tryagain:; 463 0 stevel } 464 0 stevel } 465 0 stevel pprevious = pcurrent; 466 0 stevel pcurrent = pp; 467 0 stevel } 468 0 stevel pp->p_next = proclist.p_next; 469 0 stevel proclist.p_next = pp; 470 0 stevel (void) gettimeofday(&pp->p_btime, (struct timezone *)0); 471 0 stevel } 472 0 stevel 473 356 muffin void 474 356 muffin padd(struct command *t) 475 0 stevel { 476 0 stevel tchar **argp; 477 0 stevel 478 0 stevel #ifdef TRACE 479 0 stevel tprintf("TRACE- padd()\n"); 480 0 stevel #endif 481 0 stevel if (t == 0) 482 0 stevel return; 483 0 stevel switch (t->t_dtyp) { 484 0 stevel 485 0 stevel case TPAR: 486 559 nakanon pads(S_LBRASP /* "( " */); 487 0 stevel padd(t->t_dspr); 488 559 nakanon pads(S_SPRBRA /* " )" */); 489 0 stevel break; 490 0 stevel 491 0 stevel case TCOM: 492 0 stevel for (argp = t->t_dcom; *argp; argp++) { 493 0 stevel pads(*argp); 494 0 stevel if (argp[1]) 495 559 nakanon pads(S_SP /* " " */); 496 0 stevel } 497 0 stevel break; 498 0 stevel 499 0 stevel case TOR: 500 0 stevel case TAND: 501 0 stevel case TFIL: 502 0 stevel case TLST: 503 0 stevel padd(t->t_dcar); 504 0 stevel switch (t->t_dtyp) { 505 0 stevel case TOR: 506 559 nakanon pads(S_SPBARBARSP /* " || " */); 507 0 stevel break; 508 0 stevel case TAND: 509 559 nakanon pads(S_SPANDANDSP /* " && " */); 510 0 stevel break; 511 0 stevel case TFIL: 512 559 nakanon pads(S_SPBARSP /* " | " */); 513 0 stevel break; 514 0 stevel case TLST: 515 559 nakanon pads(S_SEMICOLONSP /* "; " */); 516 0 stevel break; 517 0 stevel } 518 0 stevel padd(t->t_dcdr); 519 0 stevel return; 520 0 stevel } 521 0 stevel if ((t->t_dflg & FPIN) == 0 && t->t_dlef) { 522 559 nakanon pads((t->t_dflg & FHERE) ? S_SPLESLESSP /* " << " */ : S_SPLESSP /* " < " */); 523 0 stevel pads(t->t_dlef); 524 0 stevel } 525 0 stevel if ((t->t_dflg & FPOU) == 0 && t->t_drit) { 526 559 nakanon pads((t->t_dflg & FCAT) ? S_SPGTRGTRSP /* " >>" */ : S_SPGTR /* " >" */); 527 0 stevel if (t->t_dflg & FDIAG) 528 559 nakanon pads(S_AND /* "&" */); 529 559 nakanon pads(S_SP /* " " */); 530 0 stevel pads(t->t_drit); 531 0 stevel } 532 0 stevel } 533 0 stevel 534 356 muffin void 535 356 muffin pads(tchar *cp) 536 0 stevel { 537 356 muffin int i = strlen_(cp); 538 0 stevel 539 0 stevel #ifdef TRACE 540 0 stevel tprintf("TRACE- pads()\n"); 541 0 stevel #endif 542 0 stevel if (cmdlen >= PMAXLEN) 543 0 stevel return; 544 0 stevel if (cmdlen + i >= PMAXLEN) { 545 559 nakanon (void) strcpy_(cmdp, S_SPPPP /* " ..." */); 546 0 stevel cmdlen = PMAXLEN; 547 0 stevel cmdp += 4; 548 0 stevel return; 549 0 stevel } 550 0 stevel (void) strcpy_(cmdp, cp); 551 0 stevel cmdp += i; 552 0 stevel cmdlen += i; 553 0 stevel } 554 0 stevel 555 0 stevel /* 556 0 stevel * psavejob - temporarily save the current job on a one level stack 557 0 stevel * so another job can be created. Used for { } in exp6 558 0 stevel * and `` in globbing. 559 0 stevel */ 560 356 muffin void 561 356 muffin psavejob(void) 562 0 stevel { 563 0 stevel 564 0 stevel #ifdef TRACE 565 0 stevel tprintf("TRACE- psavejob()\n"); 566 0 stevel #endif 567 0 stevel pholdjob = pcurrjob; 568 0 stevel pcurrjob = PNULL; 569 0 stevel } 570 0 stevel 571 0 stevel /* 572 0 stevel * prestjob - opposite of psavejob. This may be missed if we are interrupted 573 0 stevel * somewhere, but pendjob cleans up anyway. 574 0 stevel */ 575 356 muffin void 576 356 muffin prestjob(void) 577 0 stevel { 578 0 stevel 579 0 stevel #ifdef TRACE 580 0 stevel tprintf("TRACE- prestjob()\n"); 581 0 stevel #endif 582 0 stevel pcurrjob = pholdjob; 583 0 stevel pholdjob = PNULL; 584 0 stevel } 585 0 stevel 586 0 stevel /* 587 0 stevel * pendjob - indicate that a job (set of commands) has been completed 588 0 stevel * or is about to begin. 589 0 stevel */ 590 356 muffin void 591 356 muffin pendjob(void) 592 0 stevel { 593 356 muffin struct process *pp, *tp; 594 0 stevel 595 0 stevel #ifdef TRACE 596 0 stevel tprintf("TRACE- pendjob()\n"); 597 0 stevel #endif 598 0 stevel if (pcurrjob && (pcurrjob->p_flags&(PFOREGND|PSTOPPED)) == 0) { 599 0 stevel pp = pcurrjob; 600 0 stevel while (pp->p_pid != pp->p_jobid) 601 0 stevel pp = pp->p_friends; 602 0 stevel printf("[%d]", pp->p_index); 603 0 stevel tp = pp; 604 0 stevel do { 605 0 stevel printf(" %d", pp->p_pid); 606 0 stevel pp = pp->p_friends; 607 0 stevel } while (pp != tp); 608 0 stevel printf("\n"); 609 0 stevel } 610 0 stevel pholdjob = pcurrjob = 0; 611 0 stevel } 612 0 stevel 613 0 stevel /* 614 0 stevel * pprint - print a job 615 0 stevel */ 616 356 muffin int 617 356 muffin pprint(struct process *pp, int flag) 618 0 stevel { 619 356 muffin int status, reason; 620 0 stevel struct process *tp; 621 0 stevel extern char *linp, linbuf[]; 622 0 stevel int jobflags, pstatus; 623 0 stevel char *format; 624 0 stevel 625 0 stevel #ifdef TRACE 626 0 stevel tprintf("TRACE- pprint()\n"); 627 0 stevel #endif 628 0 stevel while (pp->p_pid != pp->p_jobid) 629 0 stevel pp = pp->p_friends; 630 0 stevel if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 631 0 stevel pp->p_flags &= ~PPTIME; 632 0 stevel pp->p_flags |= PTIME; 633 0 stevel } 634 0 stevel tp = pp; 635 559 nakanon status = reason = -1; 636 0 stevel jobflags = 0; 637 0 stevel do { 638 0 stevel jobflags |= pp->p_flags; 639 0 stevel pstatus = pp->p_flags & PALLSTATES; 640 0 stevel if (tp != pp && linp != linbuf && !(flag&FANCY) && 641 0 stevel (pstatus == status && pp->p_reason == reason || 642 559 nakanon !(flag&REASON))) 643 0 stevel printf(" "); 644 0 stevel else { 645 0 stevel if (tp != pp && linp != linbuf) 646 0 stevel printf("\n"); 647 559 nakanon if (flag&NUMBER) 648 0 stevel if (pp == tp) 649 0 stevel printf("[%d]%s %c ", pp->p_index, 650 0 stevel pp->p_index < 10 ? " " : "", 651 559 nakanon pp == pcurrent ? '+' : 652 0 stevel (pp == pprevious ? (tchar) '-' 653 0 stevel : (tchar) ' ')); 654 0 stevel else 655 0 stevel printf(" "); 656 0 stevel if (flag&FANCY) 657 0 stevel printf("%5d ", pp->p_pid); 658 0 stevel if (flag&(REASON|AREASON)) { 659 0 stevel if (flag&NAME) 660 0 stevel format = "%-21s"; 661 0 stevel else 662 0 stevel format = "%s"; 663 0 stevel if (pstatus == status) 664 0 stevel if (pp->p_reason == reason) { 665 0 stevel printf(format, ""); 666 0 stevel goto prcomd; 667 0 stevel } else 668 0 stevel reason = pp->p_reason; 669 0 stevel else { 670 0 stevel status = pstatus; 671 0 stevel reason = pp->p_reason; 672 0 stevel } 673 0 stevel switch (status) { 674 0 stevel 675 0 stevel case PRUNNING: 676 0 stevel printf(format, "Running "); 677 0 stevel break; 678 0 stevel 679 0 stevel case PINTERRUPTED: 680 0 stevel case PSTOPPED: 681 0 stevel case PSIGNALED: 682 0 stevel if ((flag&(REASON|AREASON)) 683 0 stevel && reason != SIGINT 684 0 stevel && reason != SIGPIPE) 685 0 stevel printf(format, 686 0 stevel strsignal(pp->p_reason)); 687 0 stevel break; 688 0 stevel 689 0 stevel case PNEXITED: 690 0 stevel case PAEXITED: 691 0 stevel if (flag & REASON) 692 0 stevel if (pp->p_reason) 693 0 stevel printf("Exit %-16d", pp->p_reason); 694 0 stevel else 695 0 stevel printf(format, "Done"); 696 0 stevel break; 697 0 stevel 698 0 stevel default: 699 0 stevel printf("BUG: status=%-9o", status); 700 0 stevel } 701 0 stevel } 702 0 stevel } 703 0 stevel prcomd: 704 0 stevel if (flag&NAME) { 705 0 stevel printf("%t", pp->p_command); 706 0 stevel if (pp->p_flags & PPOU) 707 0 stevel printf(" |"); 708 0 stevel if (pp->p_flags & PDIAG) 709 0 stevel printf("&"); 710 0 stevel } 711 0 stevel if (flag&(REASON|AREASON) && pp->p_flags&PDUMPED) 712 0 stevel printf(" (core dumped)"); 713 0 stevel if (tp == pp->p_friends) { 714 0 stevel if (flag&ERSAND) 715 0 stevel printf(" &"); 716 0 stevel if (flag&JOBDIR && 717 0 stevel !eq(tp->p_cwd->di_name, dcwd->di_name)) { 718 0 stevel printf(" (wd: "); 719 559 nakanon dtildepr(value(S_home /* "home" */), tp->p_cwd->di_name); 720 0 stevel printf(")"); 721 0 stevel } 722 0 stevel } 723 0 stevel if (pp->p_flags&PPTIME && !(status&(PSTOPPED|PRUNNING))) { 724 0 stevel if (linp != linbuf) 725 0 stevel printf("\n\t"); 726 0 stevel { static struct rusage zru; 727 559 nakanon prusage(&zru, &pp->p_rusage, &pp->p_etime, 728 0 stevel &pp->p_btime); 729 0 stevel } 730 0 stevel } 731 0 stevel if (tp == pp->p_friends) { 732 0 stevel if (linp != linbuf) 733 0 stevel printf("\n"); 734 0 stevel if (flag&SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { 735 0 stevel printf("(wd now: "); 736 0 stevel dtildepr(value(S_home /* "home" */), dcwd->di_name); 737 0 stevel printf(")\n"); 738 0 stevel } 739 0 stevel } 740 0 stevel } while ((pp = pp->p_friends) != tp); 741 0 stevel if (jobflags&PTIME && (jobflags&(PSTOPPED|PRUNNING)) == 0) { 742 0 stevel if (jobflags & NUMBER) 743 0 stevel printf(" "); 744 0 stevel ptprint(tp); 745 0 stevel } 746 0 stevel return (jobflags); 747 0 stevel } 748 0 stevel 749 356 muffin void 750 356 muffin ptprint(struct process *tp) 751 0 stevel { 752 0 stevel struct timeval tetime, diff; 753 0 stevel static struct timeval ztime; 754 0 stevel struct rusage ru; 755 0 stevel static struct rusage zru; 756 356 muffin struct process *pp = tp; 757 0 stevel 758 0 stevel #ifdef TRACE 759 0 stevel tprintf("TRACE- ptprint()\n"); 760 0 stevel #endif 761 0 stevel ru = zru; 762 0 stevel tetime = ztime; 763 0 stevel do { 764 0 stevel ruadd(&ru, &pp->p_rusage); 765 0 stevel tvsub(&diff, &pp->p_etime, &pp->p_btime); 766 0 stevel if (timercmp(&diff, &tetime, >)) 767 0 stevel tetime = diff; 768 0 stevel } while ((pp = pp->p_friends) != tp); 769 0 stevel prusage(&zru, &ru, &tetime, &ztime); 770 0 stevel } 771 0 stevel 772 0 stevel /* 773 0 stevel * dojobs - print all jobs 774 0 stevel */ 775 356 muffin void 776 356 muffin dojobs(tchar **v) 777 0 stevel { 778 356 muffin struct process *pp; 779 356 muffin int flag = NUMBER|NAME|REASON; 780 0 stevel int i; 781 0 stevel 782 0 stevel #ifdef TRACE 783 0 stevel tprintf("TRACE- dojobs()\n"); 784 0 stevel #endif 785 0 stevel if (chkstop) 786 0 stevel chkstop = 2; 787 0 stevel if (*++v) { 788 559 nakanon if (v[1] || !eq(*v, S_DASHl /* "-l" */)) 789 0 stevel error("Usage: jobs [ -l ]"); 790 0 stevel flag |= FANCY|JOBDIR; 791 0 stevel } 792 0 stevel for (i = 1; i <= pmaxindex; i++) 793 0 stevel for (pp = proclist.p_next; pp; pp = pp->p_next) 794 0 stevel if (pp->p_index == i && pp->p_pid == pp->p_jobid) { 795 0 stevel pp->p_flags &= ~PNEEDNOTE; 796 0 stevel if (!(pprint(pp, flag) & (PRUNNING|PSTOPPED))) 797 0 stevel pflush(pp); 798 0 stevel break; 799 0 stevel } 800 0 stevel } 801 0 stevel 802 0 stevel /* 803 0 stevel * dofg - builtin - put the job into the foreground 804 0 stevel */ 805 356 muffin void 806 356 muffin dofg(tchar **v) 807 0 stevel { 808 356 muffin struct process *pp; 809 0 stevel 810 0 stevel #ifdef TRACE 811 0 stevel tprintf("TRACE- dofg()\n"); 812 0 stevel #endif 813 0 stevel okpcntl(); 814 0 stevel ++v; 815 0 stevel do { 816 0 stevel pp = pfind(*v); 817 0 stevel pstart(pp, 1); 818 0 stevel pjwait(pp); 819 0 stevel } while (*v && *++v); 820 0 stevel } 821 0 stevel 822 0 stevel /* 823 0 stevel * %... - builtin - put the job into the foreground 824 0 stevel */ 825 356 muffin void 826 356 muffin dofg1(tchar **v) 827 0 stevel { 828 356 muffin struct process *pp; 829 0 stevel 830 0 stevel #ifdef TRACE 831 0 stevel tprintf("TRACE- untty()\n"); 832 0 stevel #endif 833 0 stevel okpcntl(); 834 0 stevel pp = pfind(v[0]); 835 0 stevel pstart(pp, 1); 836 0 stevel pjwait(pp); 837 0 stevel } 838 0 stevel 839 0 stevel /* 840 0 stevel * dobg - builtin - put the job into the background 841 0 stevel */ 842 356 muffin void 843 356 muffin dobg(tchar **v) 844 0 stevel { 845 356 muffin struct process *pp; 846 0 stevel 847 0 stevel #ifdef TRACE 848 0 stevel tprintf("TRACE- dobg()\n"); 849 0 stevel #endif 850 0 stevel okpcntl(); 851 0 stevel ++v; 852 0 stevel do { 853 0 stevel pp = pfind(*v); 854 0 stevel pstart(pp, 0); 855 0 stevel } while (*v && *++v); 856 0 stevel } 857 0 stevel 858 0 stevel /* 859 0 stevel * %... & - builtin - put the job into the background 860 0 stevel */ 861 356 muffin void 862 356 muffin dobg1(tchar **v) 863 0 stevel { 864 356 muffin struct process *pp; 865 0 stevel 866 0 stevel #ifdef TRACE 867 0 stevel tprintf("TRACE- dobg1()\n"); 868 0 stevel #endif 869 0 stevel pp = pfind(v[0]); 870 0 stevel pstart(pp, 0); 871 0 stevel } 872 0 stevel 873 0 stevel /* 874 0 stevel * dostop - builtin - stop the job 875 0 stevel */ 876 356 muffin void 877 356 muffin dostop(tchar **v) 878 0 stevel { 879 0 stevel 880 0 stevel #ifdef TRACE 881 0 stevel tprintf("TRACE- dostop()\n"); 882 0 stevel #endif 883 0 stevel pkill(++v, SIGSTOP); 884 0 stevel } 885 0 stevel 886 0 stevel /* 887 0 stevel * dokill - builtin - superset of kill (1) 888 0 stevel */ 889 356 muffin void 890 356 muffin dokill(tchar **v) 891 0 stevel { 892 356 muffin int signum; 893 356 muffin tchar *name; 894 0 stevel 895 0 stevel #ifdef TRACE 896 0 stevel tprintf("TRACE- dokill()\n"); 897 0 stevel #endif 898 0 stevel v++; 899 0 stevel if (v[0] && v[0][0] == '-') { 900 0 stevel if (v[0][1] == 'l') { 901 0 stevel for (signum = 1; signum <= NSIG-1; signum++) { 902 0 stevel char sbuf[BUFSIZ]; 903 0 stevel if (sig2str(signum, sbuf) == 0) 904 0 stevel printf("%s ", sbuf); 905 0 stevel if (signum % 8 == 0) 906 0 stevel Putchar('\n'); 907 0 stevel } 908 0 stevel Putchar('\n'); 909 0 stevel return; 910 0 stevel } 911 0 stevel if (digit(v[0][1])) { 912 2182 chin if (chkalldigit_(v[0]+1) != 0) { 913 2182 chin setname(v[0]+1); 914 2182 chin bferr("Unknown signal; kill -l lists signals"); 915 2182 chin } 916 0 stevel signum = atoi_(v[0]+1); 917 0 stevel if (signum < 0 || signum > NSIG) 918 0 stevel bferr("Bad signal number"); 919 0 stevel } else { 920 0 stevel int signo; 921 0 stevel char sbuf[BUFSIZ]; 922 0 stevel name = &v[0][1]; 923 0 stevel tstostr(sbuf, name); 924 0 stevel if (str2sig(sbuf, &signo) == 0) { 925 0 stevel signum = signo; 926 0 stevel goto gotsig; 927 0 stevel } 928 559 nakanon if (eq(name, S_IOT /* "IOT" */)) { 929 0 stevel signum = SIGABRT; 930 0 stevel goto gotsig; 931 0 stevel } 932 0 stevel setname(name); 933 0 stevel bferr("Unknown signal; kill -l lists signals"); 934 0 stevel } 935 0 stevel gotsig: 936 0 stevel v++; 937 0 stevel } else 938 0 stevel signum = SIGTERM; 939 0 stevel pkill(v, signum); 940 0 stevel } 941 0 stevel 942 356 muffin void 943 356 muffin pkill(tchar **v, int signum) 944 0 stevel { 945 356 muffin struct process *pp, *np; 946 356 muffin int jobflags = 0; 947 0 stevel int omask, pid, err = 0; 948 0 stevel tchar *cp; 949 0 stevel 950 0 stevel #ifdef TRACE 951 0 stevel tprintf("TRACE- pkill()\n"); 952 0 stevel #endif 953 0 stevel omask = sigmask(SIGCHLD); 954 0 stevel if (setintr) 955 0 stevel omask |= sigmask(SIGINT); 956 0 stevel omask = sigblock(omask) & ~omask; 957 0 stevel while (*v) { 958 0 stevel cp = globone(*v); 959 0 stevel if (*cp == '%') { 960 0 stevel np = pp = pfind(cp); 961 0 stevel do 962 0 stevel jobflags |= np->p_flags; 963 0 stevel while ((np = np->p_friends) != pp); 964 0 stevel switch (signum) { 965 0 stevel 966 0 stevel case SIGSTOP: 967 0 stevel case SIGTSTP: 968 0 stevel case SIGTTIN: 969 0 stevel case SIGTTOU: 970 0 stevel if ((jobflags & PRUNNING) == 0) { 971 0 stevel /* %s -> %t */ 972 0 stevel printf("%t: Already stopped\n", cp); 973 0 stevel err++; 974 0 stevel goto cont; 975 0 stevel } 976 0 stevel } 977 0 stevel if (killpg(pp->p_jobid, signum) < 0) { 978 0 stevel /* %s -> %t */ 979 0 stevel printf("%t: ", cp); 980 0 stevel printf("%s\n", strerror(errno)); 981 0 stevel err++; 982 0 stevel } 983 0 stevel if (signum == SIGTERM || signum == SIGHUP) 984 0 stevel (void) killpg(pp->p_jobid, SIGCONT); 985 0 stevel } else if (!(digit(*cp) || *cp == '-')) 986 0 stevel bferr("Arguments should be jobs or process id's"); 987 0 stevel else { 988 0 stevel pid = atoi_(cp); 989 0 stevel if (kill(pid, signum) < 0) { 990 0 stevel printf("%d: ", pid); 991 0 stevel printf("%s\n", strerror(errno)); 992 0 stevel err++; 993 0 stevel goto cont; 994 0 stevel } 995 0 stevel if (signum == SIGTERM || signum == SIGHUP) 996 0 stevel (void) kill(pid, SIGCONT); 997 0 stevel } 998 0 stevel cont: 999 0 stevel xfree(cp); 1000 0 stevel v++; 1001 0 stevel } 1002 0 stevel (void) sigsetmask(omask); 1003 0 stevel if (err) 1004 0 stevel error(NULL); 1005 0 stevel } 1006 0 stevel 1007 0 stevel /* 1008 0 stevel * pstart - start the job in foreground/background 1009 0 stevel */ 1010 356 muffin void 1011 356 muffin pstart(struct process *pp, int foregnd) 1012 0 stevel { 1013 356 muffin struct process *np; 1014 0 stevel int omask, jobflags = 0; 1015 0 stevel 1016 0 stevel #ifdef TRACE 1017 0 stevel tprintf("TRACE- pstart()\n"); 1018 0 stevel #endif 1019 0 stevel omask = sigblock(sigmask(SIGCHLD)); 1020 0 stevel np = pp; 1021 0 stevel do { 1022 0 stevel jobflags |= np->p_flags; 1023 0 stevel if (np->p_flags&(PRUNNING|PSTOPPED)) { 1024 0 stevel np->p_flags |= PRUNNING; 1025 0 stevel np->p_flags &= ~PSTOPPED; 1026 0 stevel if (foregnd) 1027 0 stevel np->p_flags |= PFOREGND; 1028 0 stevel else 1029 0 stevel np->p_flags &= ~PFOREGND; 1030 0 stevel } 1031 559 nakanon } while ((np = np->p_friends) != pp); 1032 0 stevel 1033 0 stevel if (foregnd) 1034 0 stevel pclrcurr(pp); 1035 0 stevel else 1036 0 stevel { 1037 559 nakanon if (pprevious && (pprevious->p_flags & PSTOPPED)) 1038 0 stevel { 1039 0 stevel pcurrent = pprevious; 1040 0 stevel pprevious = pgetcurr(PNULL); 1041 0 stevel } 1042 0 stevel else 1043 559 nakanon { 1044 0 stevel pcurrent = pgetcurr(pp); 1045 559 nakanon if (!pcurrent || (pcurrent->p_flags & PRUNNING)) 1046 0 stevel pcurrent = pp; 1047 0 stevel else 1048 0 stevel pprevious = pp; 1049 0 stevel } 1050 0 stevel } 1051 0 stevel (void) pprint(pp, foregnd ? NAME|JOBDIR : NUMBER|NAME|AMPERSAND); 1052 0 stevel if (foregnd) 1053 0 stevel (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&pp->p_jobid); 1054 0 stevel if (jobflags&PSTOPPED) 1055 0 stevel (void) killpg(pp->p_jobid, SIGCONT); 1056 0 stevel (void) sigsetmask(omask); 1057 0 stevel } 1058 0 stevel 1059 356 muffin void 1060 356 muffin panystop(int neednl) 1061 0 stevel { 1062 356 muffin struct process *pp; 1063 0 stevel 1064 0 stevel #ifdef TRACE 1065 0 stevel tprintf("TRACE- panystop()\n"); 1066 0 stevel #endif 1067 0 stevel chkstop = 2; 1068 0 stevel for (pp = proclist.p_next; pp; pp = pp->p_next) 1069 0 stevel if (pp->p_flags & PSTOPPED) 1070 0 stevel error("\nThere are stopped jobs" + 1 - neednl); 1071 0 stevel } 1072 0 stevel 1073 0 stevel struct process * 1074 356 muffin pfind(tchar *cp) 1075 0 stevel { 1076 356 muffin struct process *pp, *np; 1077 0 stevel 1078 0 stevel #ifdef TRACE 1079 0 stevel tprintf("TRACE- pfind()\n"); 1080 0 stevel #endif 1081 559 nakanon if (cp == 0 || cp[1] == 0 || eq(cp, S_PARCENTPARCENT /* "%%" */) || 1082 559 nakanon eq(cp, S_PARCENTPLUS /* "%+" */)) { 1083 0 stevel if (pcurrent == PNULL) 1084 559 nakanon if ((pcurrent = pgetcurr(PNULL)) == PNULL) 1085 0 stevel bferr("No current job"); 1086 0 stevel return (pcurrent); 1087 0 stevel } 1088 559 nakanon if (eq(cp, S_PARCENTMINUS /* "%-" */) || 1089 559 nakanon eq(cp, S_PARCENTSHARP /* "%#" */)) { 1090 0 stevel if (pprevious == PNULL) 1091 0 stevel bferr("No previous job"); 1092 0 stevel return (pprevious); 1093 0 stevel } 1094 0 stevel if (digit(cp[1])) { 1095 0 stevel int index = atoi_(cp+1); 1096 0 stevel for (pp = proclist.p_next; pp; pp = pp->p_next) 1097 0 stevel if (pp->p_index == index && pp->p_pid == pp->p_jobid) 1098 0 stevel return (pp); 1099 0 stevel bferr("No such job"); 1100 0 stevel } 1101 0 stevel np = PNULL; 1102 0 stevel for (pp = proclist.p_next; pp; pp = pp->p_next) 1103 0 stevel if (pp->p_pid == pp->p_jobid) { 1104 0 stevel if (cp[1] == '?') { 1105 356 muffin tchar *dp; 1106 0 stevel for (dp = pp->p_command; *dp; dp++) { 1107 0 stevel if (*dp != cp[2]) 1108 0 stevel continue; 1109 0 stevel if (prefix(cp+2, dp)) 1110 0 stevel goto match; 1111 0 stevel } 1112 0 stevel } else if (prefix(cp+1, pp->p_command)) { 1113 0 stevel match: 1114 0 stevel if (np) 1115 0 stevel bferr("Ambiguous"); 1116 0 stevel np = pp; 1117 0 stevel } 1118 0 stevel } 1119 0 stevel if (np) 1120 0 stevel return (np); 1121 0 stevel if (cp[1] == '?') 1122 0 stevel bferr("No job matches pattern"); 1123 0 stevel else 1124 0 stevel bferr("No such job"); 1125 0 stevel /*NOTREACHED*/ 1126 0 stevel } 1127 0 stevel 1128 0 stevel /* 1129 0 stevel * pgetcurr - find most recent job that is not pp, preferably stopped 1130 0 stevel */ 1131 0 stevel struct process * 1132 356 muffin pgetcurr(struct process *pp) 1133 0 stevel { 1134 356 muffin struct process *np; 1135 356 muffin struct process *xp = PNULL; 1136 0 stevel 1137 0 stevel #ifdef TRACE 1138 0 stevel tprintf("TRACE- pgetcurr()\n"); 1139 0 stevel #endif 1140 0 stevel for (np = proclist.p_next; np; np = np->p_next) 1141 0 stevel if (np != pcurrent && np != pp && np->p_pid && 1142 0 stevel np->p_pid == np->p_jobid) { 1143 0 stevel if (np->p_flags & PSTOPPED) 1144 0 stevel return (np); 1145 0 stevel if (xp == PNULL) 1146 0 stevel xp = np; 1147 0 stevel } 1148 0 stevel return (xp); 1149 0 stevel } 1150 0 stevel 1151 0 stevel /* 1152 0 stevel * donotify - flag the job so as to report termination asynchronously 1153 0 stevel */ 1154 356 muffin void 1155 356 muffin donotify(tchar **v) 1156 0 stevel { 1157 356 muffin struct process *pp; 1158 0 stevel 1159 0 stevel #ifdef TRACE 1160 0 stevel tprintf("TRACE- donotify()\n"); 1161 0 stevel #endif 1162 0 stevel pp = pfind(*++v); 1163 0 stevel pp->p_flags |= PNOTIFY; 1164 0 stevel } 1165 0 stevel 1166 0 stevel /* 1167 0 stevel * Do the fork and whatever should be done in the child side that 1168 0 stevel * should not be done if we are not forking at all (like for simple builtin's) 1169 0 stevel * Also do everything that needs any signals fiddled with in the parent side 1170 0 stevel * 1171 0 stevel * Wanttty tells whether process and/or tty pgrps are to be manipulated: 1172 0 stevel * -1: leave tty alone; inherit pgrp from parent 1173 0 stevel * 0: already have tty; manipulate process pgrps only 1174 0 stevel * 1: want to claim tty; manipulate process and tty pgrps 1175 0 stevel * It is usually just the value of tpgrp. 1176 356 muffin * 1177 356 muffin * argument: 1178 356 muffin * t: command we are forking for 1179 0 stevel */ 1180 356 muffin int 1181 356 muffin pfork(struct command *t, int wanttty) 1182 0 stevel { 1183 356 muffin int pid; 1184 0 stevel bool ignint = 0; 1185 0 stevel int pgrp, omask; 1186 0 stevel int child_pid; 1187 0 stevel 1188 0 stevel #ifdef TRACE 1189 0 stevel tprintf("TRACE- pfork()\n"); 1190 0 stevel #endif 1191 0 stevel /* 1192 0 stevel * A child will be uninterruptible only under very special 1193 0 stevel * conditions. Remember that the semantics of '&' is 1194 0 stevel * implemented by disconnecting the process from the tty so 1195 0 stevel * signals do not need to ignored just for '&'. 1196 0 stevel * Thus signals are set to default action for children unless: 1197 0 stevel * we have had an "onintr -" (then specifically ignored) 1198 0 stevel * we are not playing with signals (inherit action) 1199 0 stevel */ 1200 0 stevel if (setintr) 1201 0 stevel ignint = (tpgrp == -1 && (t->t_dflg&FINT)) 1202 559 nakanon || (gointr && eq(gointr, S_MINUS /* "-" */)); 1203 0 stevel /* 1204 0 stevel * Hold SIGCHLD until we have the process installed in our table. 1205 0 stevel */ 1206 0 stevel omask = sigblock(sigmask(SIGCHLD)); 1207 0 stevel while ((pid = fork()) < 0) 1208 0 stevel if (setintr == 0) 1209 0 stevel sleep(FORKSLEEP); 1210 0 stevel else { 1211 0 stevel (void) sigsetmask(omask); 1212 0 stevel error("Fork failed"); 1213 0 stevel } 1214 0 stevel 1215 0 stevel /* 1216 0 stevel * setup the process group 1217 0 stevel */ 1218 0 stevel if (pid == 0) 1219 0 stevel child_pid = getpid(); 1220 0 stevel else 1221 0 stevel child_pid = pid; 1222 0 stevel pgrp = pcurrjob ? pcurrjob->p_jobid : child_pid; 1223 0 stevel 1224 0 stevel if (pid == 0) { 1225 0 stevel int sigttou; 1226 0 stevel settimes(); 1227 0 stevel pflushall(); 1228 0 stevel pcurrjob = PNULL; 1229 0 stevel child++; 1230 0 stevel if (setintr) { 1231 0 stevel setintr = 0; /* until I think otherwise */ 1232 0 stevel /* 1233 0 stevel * Children just get blown away on SIGINT, SIGQUIT 1234 0 stevel * unless "onintr -" seen. 1235 0 stevel */ 1236 0 stevel (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL); 1237 0 stevel (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); 1238 0 stevel if (wanttty >= 0) { 1239 0 stevel /* make stoppable */ 1240 0 stevel (void) signal(SIGTSTP, SIG_DFL); 1241 0 stevel (void) signal(SIGTTIN, SIG_DFL); 1242 0 stevel (void) signal(SIGTTOU, SIG_DFL); 1243 0 stevel } 1244 0 stevel (void) signal(SIGTERM, parterm); 1245 0 stevel } else if (tpgrp == -1 && (t->t_dflg&FINT)) { 1246 0 stevel (void) signal(SIGINT, SIG_IGN); 1247 0 stevel (void) signal(SIGQUIT, SIG_IGN); 1248 0 stevel } 1249 0 stevel if (wanttty >= 0 && tpgrp >= 0) 1250 0 stevel (void) setpgid(0, pgrp); 1251 0 stevel if (wanttty > 0) { 1252 559 nakanon sigttou = sigblock(sigmask(SIGTTOU) | 1253 559 nakanon sigmask(SIGTTIN) | 1254 0 stevel sigmask(SIGTSTP)); 1255 0 stevel (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&pgrp); 1256 559 nakanon sigsetmask(sigttou); 1257 0 stevel } 1258 0 stevel if (tpgrp > 0) 1259 0 stevel tpgrp = 0; /* gave tty away */ 1260 0 stevel /* 1261 0 stevel * Nohup and nice apply only to TCOM's but it would be 1262 0 stevel * nice (?!?) if you could say "nohup (foo;bar)" 1263 0 stevel * Then the parser would have to know about nice/nohup/time 1264 0 stevel */ 1265 0 stevel if (t->t_dflg & FNOHUP) 1266 0 stevel (void) signal(SIGHUP, SIG_IGN); 1267 0 stevel if (t->t_dflg & FNICE) 1268 0 stevel (void) setpriority(PRIO_PROCESS, 0, t->t_nice); 1269 0 stevel } else { 1270 0 stevel if (wanttty >= 0 && tpgrp >= 0) 1271 0 stevel setpgid(pid, pgrp); 1272 0 stevel palloc(pid, t); 1273 0 stevel (void) sigsetmask(omask); 1274 0 stevel } 1275 0 stevel 1276 0 stevel return (pid); 1277 0 stevel } 1278 0 stevel 1279 356 muffin void 1280 356 muffin okpcntl(void) 1281 0 stevel { 1282 0 stevel #ifdef TRACE 1283 0 stevel tprintf("TRACE- okpcntl()\n"); 1284 0 stevel #endif 1285 0 stevel 1286 0 stevel if (tpgrp == -1) 1287 0 stevel error("No job control in this shell"); 1288 0 stevel if (tpgrp == 0) 1289 0 stevel error("No job control in subshells"); 1290 0 stevel } 1291 2200 mg147109 1292 2200 mg147109 void 1293 2200 mg147109 hupforegnd(void) 1294 2200 mg147109 { 1295 2200 mg147109 struct process *pp; 1296 2200 mg147109 int omask; 1297 2200 mg147109 1298 2200 mg147109 omask = sigblock(sigmask(SIGCHLD)); 1299 2200 mg147109 for (pp = (&proclist)->p_next; pp != PNULL; pp = pp->p_next) 1300 2200 mg147109 if (pp->p_pid > 0) { 1301 2200 mg147109 if (pp->p_flags & PFOREGND) 1302 2200 mg147109 (void) kill(pp->p_pid, SIGHUP); 1303 2200 mg147109 } 1304 2200 mg147109 (void) sigsetmask(omask); 1305 2200 mg147109 } 1306