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