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