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