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