jobs.c revision 38536
1/*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#ifndef lint 38#if 0 39static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95"; 40#endif 41static const char rcsid[] = 42 "$Id: jobs.c,v 1.21 1998/08/24 10:20:36 cracauer Exp $"; 43#endif /* not lint */ 44 45#include <fcntl.h> 46#include <signal.h> 47#include <errno.h> 48#include <unistd.h> 49#include <stdlib.h> 50#include <sys/param.h> 51#ifdef BSD 52#include <sys/wait.h> 53#include <sys/time.h> 54#include <sys/resource.h> 55#endif 56#include <sys/ioctl.h> 57 58#include "shell.h" 59#if JOBS 60#if OLD_TTY_DRIVER 61#include "sgtty.h" 62#else 63#include <termios.h> 64#endif 65#undef CEOF /* syntax.h redefines this */ 66#endif 67#include "redir.h" 68#include "show.h" 69#include "main.h" 70#include "parser.h" 71#include "nodes.h" 72#include "jobs.h" 73#include "options.h" 74#include "trap.h" 75#include "syntax.h" 76#include "input.h" 77#include "output.h" 78#include "memalloc.h" 79#include "error.h" 80#include "mystring.h" 81 82 83struct job *jobtab; /* array of jobs */ 84int njobs; /* size of array */ 85MKINIT pid_t backgndpid = -1; /* pid of last background process */ 86#if JOBS 87int initialpgrp; /* pgrp of shell on invocation */ 88int curjob; /* current job */ 89#endif 90int in_waitcmd = 0; /* are we in waitcmd()? */ 91volatile sig_atomic_t breakwaitcmd = 0; /* should wait be terminated? */ 92 93#if JOBS 94STATIC void restartjob __P((struct job *)); 95#endif 96STATIC void freejob __P((struct job *)); 97STATIC struct job *getjob __P((char *)); 98STATIC int dowait __P((int, struct job *)); 99#if SYSV 100STATIC int onsigchild __P((void)); 101#endif 102STATIC int waitproc __P((int, int *)); 103STATIC void cmdtxt __P((union node *)); 104STATIC void cmdputs __P((char *)); 105 106 107/* 108 * Turn job control on and off. 109 * 110 * Note: This code assumes that the third arg to ioctl is a character 111 * pointer, which is true on Berkeley systems but not System V. Since 112 * System V doesn't have job control yet, this isn't a problem now. 113 */ 114 115MKINIT int jobctl; 116 117#if JOBS 118void 119setjobctl(on) 120 int on; 121{ 122#ifdef OLD_TTY_DRIVER 123 int ldisc; 124#endif 125 126 if (on == jobctl || rootshell == 0) 127 return; 128 if (on) { 129 do { /* while we are in the background */ 130#ifdef OLD_TTY_DRIVER 131 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) { 132#else 133 initialpgrp = tcgetpgrp(2); 134 if (initialpgrp < 0) { 135#endif 136 out2str("sh: can't access tty; job control turned off\n"); 137 mflag = 0; 138 return; 139 } 140 if (initialpgrp == -1) 141 initialpgrp = getpgrp(); 142 else if (initialpgrp != getpgrp()) { 143 killpg(initialpgrp, SIGTTIN); 144 continue; 145 } 146 } while (0); 147#ifdef OLD_TTY_DRIVER 148 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) { 149 out2str("sh: need new tty driver to run job control; job control turned off\n"); 150 mflag = 0; 151 return; 152 } 153#endif 154 setsignal(SIGTSTP); 155 setsignal(SIGTTOU); 156 setsignal(SIGTTIN); 157 setpgid(0, rootpid); 158#ifdef OLD_TTY_DRIVER 159 ioctl(2, TIOCSPGRP, (char *)&rootpid); 160#else 161 tcsetpgrp(2, rootpid); 162#endif 163 } else { /* turning job control off */ 164 setpgid(0, initialpgrp); 165#ifdef OLD_TTY_DRIVER 166 ioctl(2, TIOCSPGRP, (char *)&initialpgrp); 167#else 168 tcsetpgrp(2, initialpgrp); 169#endif 170 setsignal(SIGTSTP); 171 setsignal(SIGTTOU); 172 setsignal(SIGTTIN); 173 } 174 jobctl = on; 175} 176#endif 177 178 179#ifdef mkinit 180INCLUDE <sys/types.h> 181INCLUDE <stdlib.h> 182 183SHELLPROC { 184 backgndpid = -1; 185#if JOBS 186 jobctl = 0; 187#endif 188} 189 190#endif 191 192 193 194#if JOBS 195int 196fgcmd(argc, argv) 197 int argc __unused; 198 char **argv; 199{ 200 struct job *jp; 201 int pgrp; 202 int status; 203 204 jp = getjob(argv[1]); 205 if (jp->jobctl == 0) 206 error("job not created under job control"); 207 pgrp = jp->ps[0].pid; 208#ifdef OLD_TTY_DRIVER 209 ioctl(2, TIOCSPGRP, (char *)&pgrp); 210#else 211 tcsetpgrp(2, pgrp); 212#endif 213 restartjob(jp); 214 INTOFF; 215 status = waitforjob(jp); 216 INTON; 217 return status; 218} 219 220 221int 222bgcmd(argc, argv) 223 int argc; 224 char **argv; 225{ 226 struct job *jp; 227 228 do { 229 jp = getjob(*++argv); 230 if (jp->jobctl == 0) 231 error("job not created under job control"); 232 restartjob(jp); 233 } while (--argc > 1); 234 return 0; 235} 236 237 238STATIC void 239restartjob(jp) 240 struct job *jp; 241{ 242 struct procstat *ps; 243 int i; 244 245 if (jp->state == JOBDONE) 246 return; 247 INTOFF; 248 killpg(jp->ps[0].pid, SIGCONT); 249 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) { 250 if (WIFSTOPPED(ps->status)) { 251 ps->status = -1; 252 jp->state = 0; 253 } 254 } 255 INTON; 256} 257#endif 258 259 260int 261jobscmd(argc, argv) 262 int argc __unused; 263 char **argv __unused; 264{ 265 showjobs(0); 266 return 0; 267} 268 269 270/* 271 * Print a list of jobs. If "change" is nonzero, only print jobs whose 272 * statuses have changed since the last call to showjobs. 273 * 274 * If the shell is interrupted in the process of creating a job, the 275 * result may be a job structure containing zero processes. Such structures 276 * will be freed here. 277 */ 278 279void 280showjobs(change) 281 int change; 282{ 283 int jobno; 284 int procno; 285 int i; 286 struct job *jp; 287 struct procstat *ps; 288 int col; 289 char s[64]; 290 291 TRACE(("showjobs(%d) called\n", change)); 292 while (dowait(0, (struct job *)NULL) > 0); 293 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) { 294 if (! jp->used) 295 continue; 296 if (jp->nprocs == 0) { 297 freejob(jp); 298 continue; 299 } 300 if (change && ! jp->changed) 301 continue; 302 procno = jp->nprocs; 303 for (ps = jp->ps ; ; ps++) { /* for each process */ 304 if (ps == jp->ps) 305 fmtstr(s, 64, "[%d] %d ", jobno, ps->pid); 306 else 307 fmtstr(s, 64, " %d ", ps->pid); 308 out1str(s); 309 col = strlen(s); 310 s[0] = '\0'; 311 if (ps->status == -1) { 312 /* don't print anything */ 313 } else if (WIFEXITED(ps->status)) { 314 fmtstr(s, 64, "Exit %d", WEXITSTATUS(ps->status)); 315 } else { 316#if JOBS 317 if (WIFSTOPPED(ps->status)) 318 i = WSTOPSIG(ps->status); 319 else 320#endif 321 i = WTERMSIG(ps->status); 322 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F]) 323 scopy(sys_siglist[i & 0x7F], s); 324 else 325 fmtstr(s, 64, "Signal %d", i & 0x7F); 326 if (WCOREDUMP(ps->status)) 327 strcat(s, " (core dumped)"); 328 } 329 out1str(s); 330 col += strlen(s); 331 do { 332 out1c(' '); 333 col++; 334 } while (col < 30); 335 out1str(ps->cmd); 336 out1c('\n'); 337 if (--procno <= 0) 338 break; 339 } 340 jp->changed = 0; 341 if (jp->state == JOBDONE) { 342 freejob(jp); 343 } 344 } 345} 346 347 348/* 349 * Mark a job structure as unused. 350 */ 351 352STATIC void 353freejob(jp) 354 struct job *jp; 355 { 356 struct procstat *ps; 357 int i; 358 359 INTOFF; 360 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) { 361 if (ps->cmd != nullstr) 362 ckfree(ps->cmd); 363 } 364 if (jp->ps != &jp->ps0) 365 ckfree(jp->ps); 366 jp->used = 0; 367#if JOBS 368 if (curjob == jp - jobtab + 1) 369 curjob = 0; 370#endif 371 INTON; 372} 373 374 375 376int 377waitcmd(argc, argv) 378 int argc; 379 char **argv; 380{ 381 struct job *job; 382 int status, retval; 383 struct job *jp; 384 385 if (argc > 1) { 386 job = getjob(argv[1]); 387 } else { 388 job = NULL; 389 } 390 391 /* 392 * Loop until a process is terminated or stopped, or a SIGINT is 393 * received. 394 */ 395 396 in_waitcmd++; 397 do { 398 if (job != NULL) { 399 if (job->state) { 400 status = job->ps[job->nprocs - 1].status; 401 if (WIFEXITED(status)) 402 retval = WEXITSTATUS(status); 403#if JOBS 404 else if (WIFSTOPPED(status)) 405 retval = WSTOPSIG(status) + 128; 406#endif 407 else 408 retval = WTERMSIG(status) + 128; 409 if (! iflag) 410 freejob(job); 411 in_waitcmd--; 412 return retval; 413 } 414 } else { 415 for (jp = jobtab ; ; jp++) { 416 if (jp >= jobtab + njobs) { /* no running procs */ 417 in_waitcmd--; 418 return 0; 419 } 420 if (jp->used && jp->state == 0) 421 break; 422 } 423 } 424 } while (dowait(1, (struct job *)NULL) != -1); 425 in_waitcmd--; 426 427 return 0; 428} 429 430 431 432int 433jobidcmd(argc, argv) 434 int argc __unused; 435 char **argv; 436{ 437 struct job *jp; 438 int i; 439 440 jp = getjob(argv[1]); 441 for (i = 0 ; i < jp->nprocs ; ) { 442 out1fmt("%d", jp->ps[i].pid); 443 out1c(++i < jp->nprocs? ' ' : '\n'); 444 } 445 return 0; 446} 447 448 449 450/* 451 * Convert a job name to a job structure. 452 */ 453 454STATIC struct job * 455getjob(name) 456 char *name; 457 { 458 int jobno; 459 struct job *jp; 460 int pid; 461 int i; 462 463 if (name == NULL) { 464#if JOBS 465currentjob: 466 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0) 467 error("No current job"); 468 return &jobtab[jobno - 1]; 469#else 470 error("No current job"); 471#endif 472 } else if (name[0] == '%') { 473 if (is_digit(name[1])) { 474 jobno = number(name + 1); 475 if (jobno > 0 && jobno <= njobs 476 && jobtab[jobno - 1].used != 0) 477 return &jobtab[jobno - 1]; 478#if JOBS 479 } else if (name[1] == '%' && name[2] == '\0') { 480 goto currentjob; 481#endif 482 } else { 483 struct job *found = NULL; 484 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { 485 if (jp->used && jp->nprocs > 0 486 && prefix(name + 1, jp->ps[0].cmd)) { 487 if (found) 488 error("%s: ambiguous", name); 489 found = jp; 490 } 491 } 492 if (found) 493 return found; 494 } 495 } else if (is_number(name)) { 496 pid = number(name); 497 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { 498 if (jp->used && jp->nprocs > 0 499 && jp->ps[jp->nprocs - 1].pid == pid) 500 return jp; 501 } 502 } 503 error("No such job: %s", name); 504 /*NOTREACHED*/ 505 return NULL; 506} 507 508 509 510/* 511 * Return a new job structure, 512 */ 513 514struct job * 515makejob(node, nprocs) 516 union node *node __unused; 517 int nprocs; 518{ 519 int i; 520 struct job *jp; 521 522 for (i = njobs, jp = jobtab ; ; jp++) { 523 if (--i < 0) { 524 INTOFF; 525 if (njobs == 0) { 526 jobtab = ckmalloc(4 * sizeof jobtab[0]); 527 } else { 528 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]); 529 memcpy(jp, jobtab, njobs * sizeof jp[0]); 530 /* Relocate `ps' pointers */ 531 for (i = 0; i < njobs; i++) 532 if (jp[i].ps == &jobtab[i].ps0) 533 jp[i].ps = &jp[i].ps0; 534 ckfree(jobtab); 535 jobtab = jp; 536 } 537 jp = jobtab + njobs; 538 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0); 539 INTON; 540 break; 541 } 542 if (jp->used == 0) 543 break; 544 } 545 INTOFF; 546 jp->state = 0; 547 jp->used = 1; 548 jp->changed = 0; 549 jp->nprocs = 0; 550#if JOBS 551 jp->jobctl = jobctl; 552#endif 553 if (nprocs > 1) { 554 jp->ps = ckmalloc(nprocs * sizeof (struct procstat)); 555 } else { 556 jp->ps = &jp->ps0; 557 } 558 INTON; 559 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs, 560 jp - jobtab + 1)); 561 return jp; 562} 563 564 565/* 566 * Fork of a subshell. If we are doing job control, give the subshell its 567 * own process group. Jp is a job structure that the job is to be added to. 568 * N is the command that will be evaluated by the child. Both jp and n may 569 * be NULL. The mode parameter can be one of the following: 570 * FORK_FG - Fork off a foreground process. 571 * FORK_BG - Fork off a background process. 572 * FORK_NOJOB - Like FORK_FG, but don't give the process its own 573 * process group even if job control is on. 574 * 575 * When job control is turned off, background processes have their standard 576 * input redirected to /dev/null (except for the second and later processes 577 * in a pipeline). 578 */ 579 580int 581forkshell(jp, n, mode) 582 union node *n; 583 struct job *jp; 584 int mode; 585{ 586 int pid; 587 int pgrp; 588 589 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n, 590 mode)); 591 INTOFF; 592 pid = fork(); 593 if (pid == -1) { 594 TRACE(("Fork failed, errno=%d\n", errno)); 595 INTON; 596 error("Cannot fork"); 597 } 598 if (pid == 0) { 599 struct job *p; 600 int wasroot; 601 int i; 602 603 TRACE(("Child shell %d\n", getpid())); 604 wasroot = rootshell; 605 rootshell = 0; 606 for (i = njobs, p = jobtab ; --i >= 0 ; p++) 607 if (p->used) 608 freejob(p); 609 closescript(); 610 INTON; 611 clear_traps(); 612#if JOBS 613 jobctl = 0; /* do job control only in root shell */ 614 if (wasroot && mode != FORK_NOJOB && mflag) { 615 if (jp == NULL || jp->nprocs == 0) 616 pgrp = getpid(); 617 else 618 pgrp = jp->ps[0].pid; 619 if (setpgid(0, pgrp) == 0 && mode == FORK_FG) { 620 /*** this causes superfluous TIOCSPGRPS ***/ 621#ifdef OLD_TTY_DRIVER 622 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0) 623 error("TIOCSPGRP failed, errno=%d", errno); 624#else 625 if (tcsetpgrp(2, pgrp) < 0) 626 error("tcsetpgrp failed, errno=%d", errno); 627#endif 628 } 629 setsignal(SIGTSTP); 630 setsignal(SIGTTOU); 631 } else if (mode == FORK_BG) { 632 ignoresig(SIGINT); 633 ignoresig(SIGQUIT); 634 if ((jp == NULL || jp->nprocs == 0) && 635 ! fd0_redirected_p ()) { 636 close(0); 637 if (open("/dev/null", O_RDONLY) != 0) 638 error("Can't open /dev/null"); 639 } 640 } 641#else 642 if (mode == FORK_BG) { 643 ignoresig(SIGINT); 644 ignoresig(SIGQUIT); 645 if ((jp == NULL || jp->nprocs == 0) && 646 ! fd0_redirected_p ()) { 647 close(0); 648 if (open("/dev/null", O_RDONLY) != 0) 649 error("Can't open /dev/null"); 650 } 651 } 652#endif 653 if (wasroot && iflag) { 654 setsignal(SIGINT); 655 setsignal(SIGQUIT); 656 setsignal(SIGTERM); 657 } 658 return pid; 659 } 660 if (rootshell && mode != FORK_NOJOB && mflag) { 661 if (jp == NULL || jp->nprocs == 0) 662 pgrp = pid; 663 else 664 pgrp = jp->ps[0].pid; 665 setpgid(pid, pgrp); 666 } 667 if (mode == FORK_BG) 668 backgndpid = pid; /* set $! */ 669 if (jp) { 670 struct procstat *ps = &jp->ps[jp->nprocs++]; 671 ps->pid = pid; 672 ps->status = -1; 673 ps->cmd = nullstr; 674 if (iflag && rootshell && n) 675 ps->cmd = commandtext(n); 676 } 677 INTON; 678 TRACE(("In parent shell: child = %d\n", pid)); 679 return pid; 680} 681 682 683 684/* 685 * Wait for job to finish. 686 * 687 * Under job control we have the problem that while a child process is 688 * running interrupts generated by the user are sent to the child but not 689 * to the shell. This means that an infinite loop started by an inter- 690 * active user may be hard to kill. With job control turned off, an 691 * interactive user may place an interactive program inside a loop. If 692 * the interactive program catches interrupts, the user doesn't want 693 * these interrupts to also abort the loop. The approach we take here 694 * is to have the shell ignore interrupt signals while waiting for a 695 * forground process to terminate, and then send itself an interrupt 696 * signal if the child process was terminated by an interrupt signal. 697 * Unfortunately, some programs want to do a bit of cleanup and then 698 * exit on interrupt; unless these processes terminate themselves by 699 * sending a signal to themselves (instead of calling exit) they will 700 * confuse this approach. 701 */ 702 703int 704waitforjob(jp) 705 struct job *jp; 706 { 707#if JOBS 708 int mypgrp = getpgrp(); 709#endif 710 int status; 711 int st; 712 713 INTOFF; 714 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1)); 715 while (jp->state == 0) { 716 dowait(1, jp); 717 } 718#if JOBS 719 if (jp->jobctl) { 720#ifdef OLD_TTY_DRIVER 721 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0) 722 error("TIOCSPGRP failed, errno=%d\n", errno); 723#else 724 if (tcsetpgrp(2, mypgrp) < 0) 725 error("tcsetpgrp failed, errno=%d\n", errno); 726#endif 727 } 728 if (jp->state == JOBSTOPPED) 729 curjob = jp - jobtab + 1; 730#endif 731 status = jp->ps[jp->nprocs - 1].status; 732 /* convert to 8 bits */ 733 if (WIFEXITED(status)) 734 st = WEXITSTATUS(status); 735#if JOBS 736 else if (WIFSTOPPED(status)) 737 st = WSTOPSIG(status) + 128; 738#endif 739 else 740 st = WTERMSIG(status) + 128; 741 if (! JOBS || jp->state == JOBDONE) 742 freejob(jp); 743 if (int_pending()) { 744 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) 745 kill(getpid(), SIGINT); 746 else 747 CLEAR_PENDING_INT; 748 } 749 INTON; 750 return st; 751} 752 753 754 755/* 756 * Wait for a process to terminate. 757 */ 758 759STATIC int 760dowait(block, job) 761 int block; 762 struct job *job; 763{ 764 int pid; 765 int status; 766 struct procstat *sp; 767 struct job *jp; 768 struct job *thisjob; 769 int done; 770 int stopped; 771 int core; 772 int sig; 773 774 TRACE(("dowait(%d) called\n", block)); 775 do { 776 pid = waitproc(block, &status); 777 TRACE(("wait returns %d, status=%d\n", pid, status)); 778 } while (pid == -1 && errno == EINTR && breakwaitcmd == 0); 779 if (breakwaitcmd != 0) { 780 breakwaitcmd = 0; 781 return -1; 782 } 783 if (pid <= 0) 784 return pid; 785 INTOFF; 786 thisjob = NULL; 787 for (jp = jobtab ; jp < jobtab + njobs ; jp++) { 788 if (jp->used) { 789 done = 1; 790 stopped = 1; 791 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) { 792 if (sp->pid == -1) 793 continue; 794 if (sp->pid == pid) { 795 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", 796 pid, sp->status, status)); 797 sp->status = status; 798 thisjob = jp; 799 } 800 if (sp->status == -1) 801 stopped = 0; 802 else if (WIFSTOPPED(sp->status)) 803 done = 0; 804 } 805 if (stopped) { /* stopped or done */ 806 int state = done? JOBDONE : JOBSTOPPED; 807 if (jp->state != state) { 808 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state)); 809 jp->state = state; 810#if JOBS 811 if (done && curjob == jp - jobtab + 1) 812 curjob = 0; /* no current job */ 813#endif 814 } 815 } 816 } 817 } 818 INTON; 819 if (! rootshell || ! iflag || (job && thisjob == job)) { 820 core = WCOREDUMP(status); 821#if JOBS 822 if (WIFSTOPPED(status)) 823 sig = WSTOPSIG(status); 824 else 825#endif 826 if (WIFEXITED(status)) 827 sig = 0; 828 else 829 sig = WTERMSIG(status); 830 831 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) { 832 if (thisjob != job) 833 outfmt(out2, "%d: ", pid); 834#if JOBS 835 if (sig == SIGTSTP && rootshell && iflag) 836 outfmt(out2, "%%%d ", job - jobtab + 1); 837#endif 838 if (sig < NSIG && sys_siglist[sig]) 839 out2str(sys_siglist[sig]); 840 else 841 outfmt(out2, "Signal %d", sig); 842 if (core) 843 out2str(" - core dumped"); 844 out2c('\n'); 845 flushout(&errout); 846 } else { 847 TRACE(("Not printing status: status=%d, sig=%d\n", 848 status, sig)); 849 } 850 } else { 851 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job)); 852 if (thisjob) 853 thisjob->changed = 1; 854 } 855 return pid; 856} 857 858 859 860/* 861 * Do a wait system call. If job control is compiled in, we accept 862 * stopped processes. If block is zero, we return a value of zero 863 * rather than blocking. 864 * 865 * System V doesn't have a non-blocking wait system call. It does 866 * have a SIGCLD signal that is sent to a process when one of it's 867 * children dies. The obvious way to use SIGCLD would be to install 868 * a handler for SIGCLD which simply bumped a counter when a SIGCLD 869 * was received, and have waitproc bump another counter when it got 870 * the status of a process. Waitproc would then know that a wait 871 * system call would not block if the two counters were different. 872 * This approach doesn't work because if a process has children that 873 * have not been waited for, System V will send it a SIGCLD when it 874 * installs a signal handler for SIGCLD. What this means is that when 875 * a child exits, the shell will be sent SIGCLD signals continuously 876 * until is runs out of stack space, unless it does a wait call before 877 * restoring the signal handler. The code below takes advantage of 878 * this (mis)feature by installing a signal handler for SIGCLD and 879 * then checking to see whether it was called. If there are any 880 * children to be waited for, it will be. 881 * 882 * If neither SYSV nor BSD is defined, we don't implement nonblocking 883 * waits at all. In this case, the user will not be informed when 884 * a background process until the next time she runs a real program 885 * (as opposed to running a builtin command or just typing return), 886 * and the jobs command may give out of date information. 887 */ 888 889#ifdef SYSV 890STATIC sig_atomic_t gotsigchild; 891 892STATIC int onsigchild() { 893 gotsigchild = 1; 894} 895#endif 896 897 898STATIC int 899waitproc(block, status) 900 int block; 901 int *status; 902{ 903#ifdef BSD 904 int flags; 905 906#if JOBS 907 flags = WUNTRACED; 908#else 909 flags = 0; 910#endif 911 if (block == 0) 912 flags |= WNOHANG; 913 return wait3(status, flags, (struct rusage *)NULL); 914#else 915#ifdef SYSV 916 int (*save)(); 917 918 if (block == 0) { 919 gotsigchild = 0; 920 save = signal(SIGCLD, onsigchild); 921 signal(SIGCLD, save); 922 if (gotsigchild == 0) 923 return 0; 924 } 925 return wait(status); 926#else 927 if (block == 0) 928 return 0; 929 return wait(status); 930#endif 931#endif 932} 933 934/* 935 * return 1 if there are stopped jobs, otherwise 0 936 */ 937int job_warning = 0; 938int 939stoppedjobs() 940{ 941 int jobno; 942 struct job *jp; 943 944 if (job_warning) 945 return (0); 946 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) { 947 if (jp->used == 0) 948 continue; 949 if (jp->state == JOBSTOPPED) { 950 out2str("You have stopped jobs.\n"); 951 job_warning = 2; 952 return (1); 953 } 954 } 955 956 return (0); 957} 958 959/* 960 * Return a string identifying a command (to be printed by the 961 * jobs command. 962 */ 963 964STATIC char *cmdnextc; 965STATIC int cmdnleft; 966STATIC void cmdtxt(), cmdputs(); 967#define MAXCMDTEXT 200 968 969char * 970commandtext(n) 971 union node *n; 972 { 973 char *name; 974 975 cmdnextc = name = ckmalloc(MAXCMDTEXT); 976 cmdnleft = MAXCMDTEXT - 4; 977 cmdtxt(n); 978 *cmdnextc = '\0'; 979 return name; 980} 981 982 983STATIC void 984cmdtxt(n) 985 union node *n; 986 { 987 union node *np; 988 struct nodelist *lp; 989 char *p; 990 int i; 991 char s[2]; 992 993 if (n == NULL) 994 return; 995 switch (n->type) { 996 case NSEMI: 997 cmdtxt(n->nbinary.ch1); 998 cmdputs("; "); 999 cmdtxt(n->nbinary.ch2); 1000 break; 1001 case NAND: 1002 cmdtxt(n->nbinary.ch1); 1003 cmdputs(" && "); 1004 cmdtxt(n->nbinary.ch2); 1005 break; 1006 case NOR: 1007 cmdtxt(n->nbinary.ch1); 1008 cmdputs(" || "); 1009 cmdtxt(n->nbinary.ch2); 1010 break; 1011 case NPIPE: 1012 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 1013 cmdtxt(lp->n); 1014 if (lp->next) 1015 cmdputs(" | "); 1016 } 1017 break; 1018 case NSUBSHELL: 1019 cmdputs("("); 1020 cmdtxt(n->nredir.n); 1021 cmdputs(")"); 1022 break; 1023 case NREDIR: 1024 case NBACKGND: 1025 cmdtxt(n->nredir.n); 1026 break; 1027 case NIF: 1028 cmdputs("if "); 1029 cmdtxt(n->nif.test); 1030 cmdputs("; then "); 1031 cmdtxt(n->nif.ifpart); 1032 cmdputs("..."); 1033 break; 1034 case NWHILE: 1035 cmdputs("while "); 1036 goto until; 1037 case NUNTIL: 1038 cmdputs("until "); 1039until: 1040 cmdtxt(n->nbinary.ch1); 1041 cmdputs("; do "); 1042 cmdtxt(n->nbinary.ch2); 1043 cmdputs("; done"); 1044 break; 1045 case NFOR: 1046 cmdputs("for "); 1047 cmdputs(n->nfor.var); 1048 cmdputs(" in ..."); 1049 break; 1050 case NCASE: 1051 cmdputs("case "); 1052 cmdputs(n->ncase.expr->narg.text); 1053 cmdputs(" in ..."); 1054 break; 1055 case NDEFUN: 1056 cmdputs(n->narg.text); 1057 cmdputs("() ..."); 1058 break; 1059 case NCMD: 1060 for (np = n->ncmd.args ; np ; np = np->narg.next) { 1061 cmdtxt(np); 1062 if (np->narg.next) 1063 cmdputs(" "); 1064 } 1065 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) { 1066 cmdputs(" "); 1067 cmdtxt(np); 1068 } 1069 break; 1070 case NARG: 1071 cmdputs(n->narg.text); 1072 break; 1073 case NTO: 1074 p = ">"; i = 1; goto redir; 1075 case NAPPEND: 1076 p = ">>"; i = 1; goto redir; 1077 case NTOFD: 1078 p = ">&"; i = 1; goto redir; 1079 case NFROM: 1080 p = "<"; i = 0; goto redir; 1081 case NFROMFD: 1082 p = "<&"; i = 0; goto redir; 1083redir: 1084 if (n->nfile.fd != i) { 1085 s[0] = n->nfile.fd + '0'; 1086 s[1] = '\0'; 1087 cmdputs(s); 1088 } 1089 cmdputs(p); 1090 if (n->type == NTOFD || n->type == NFROMFD) { 1091 s[0] = n->ndup.dupfd + '0'; 1092 s[1] = '\0'; 1093 cmdputs(s); 1094 } else { 1095 cmdtxt(n->nfile.fname); 1096 } 1097 break; 1098 case NHERE: 1099 case NXHERE: 1100 cmdputs("<<..."); 1101 break; 1102 default: 1103 cmdputs("???"); 1104 break; 1105 } 1106} 1107 1108 1109 1110STATIC void 1111cmdputs(s) 1112 char *s; 1113 { 1114 char *p, *q; 1115 char c; 1116 int subtype = 0; 1117 1118 if (cmdnleft <= 0) 1119 return; 1120 p = s; 1121 q = cmdnextc; 1122 while ((c = *p++) != '\0') { 1123 if (c == CTLESC) 1124 *q++ = *p++; 1125 else if (c == CTLVAR) { 1126 *q++ = '$'; 1127 if (--cmdnleft > 0) 1128 *q++ = '{'; 1129 subtype = *p++; 1130 } else if (c == '=' && subtype != 0) { 1131 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL]; 1132 subtype = 0; 1133 } else if (c == CTLENDVAR) { 1134 *q++ = '}'; 1135 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) 1136 cmdnleft++; /* ignore it */ 1137 else 1138 *q++ = c; 1139 if (--cmdnleft <= 0) { 1140 *q++ = '.'; 1141 *q++ = '.'; 1142 *q++ = '.'; 1143 break; 1144 } 1145 } 1146 cmdnextc = q; 1147} 1148