jobs.c revision 216217
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1991, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Kenneth Almquist. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 4. Neither the name of the University nor the names of its contributors 171556Srgrimes * may be used to endorse or promote products derived from this software 181556Srgrimes * without specific prior written permission. 191556Srgrimes * 201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301556Srgrimes * SUCH DAMAGE. 311556Srgrimes */ 321556Srgrimes 331556Srgrimes#ifndef lint 3436150Scharnier#if 0 3536150Scharnierstatic char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95"; 3636150Scharnier#endif 371556Srgrimes#endif /* not lint */ 3899110Sobrien#include <sys/cdefs.h> 3999110Sobrien__FBSDID("$FreeBSD: head/bin/sh/jobs.c 216217 2010-12-05 22:37:01Z jilles $"); 401556Srgrimes 41111422Smarcel#include <sys/ioctl.h> 421556Srgrimes#include <sys/param.h> 431556Srgrimes#include <sys/resource.h> 441556Srgrimes#include <sys/time.h> 451556Srgrimes#include <sys/wait.h> 461556Srgrimes#include <errno.h> 4739049Scracauer#include <fcntl.h> 4817987Speter#include <paths.h> 4917987Speter#include <signal.h> 501556Srgrimes#include <stddef.h> 511556Srgrimes#include <stdlib.h> 521556Srgrimes#include <unistd.h> 531556Srgrimes 541556Srgrimes#include "shell.h" 551556Srgrimes#if JOBS 56193221Srse#include <termios.h> 5717987Speter#undef CEOF /* syntax.h redefines this */ 5825222Ssteve#endif 591556Srgrimes#include "redir.h" 60151795Sstefanf#include "show.h" 61151795Sstefanf#include "main.h" 62151795Sstefanf#include "parser.h" 63151795Sstefanf#include "nodes.h" 641556Srgrimes#include "jobs.h" 651556Srgrimes#include "options.h" 661556Srgrimes#include "trap.h" 671556Srgrimes#include "syntax.h" 681556Srgrimes#include "input.h" 691556Srgrimes#include "output.h" 701556Srgrimes#include "memalloc.h" 711556Srgrimes#include "error.h" 721556Srgrimes#include "mystring.h" 731556Srgrimes 7490111Simp 7517987Speterstatic struct job *jobtab; /* array of jobs */ 76151795Sstefanfstatic int njobs; /* size of array */ 77151795SstefanfMKINIT pid_t backgndpid = -1; /* pid of last background process */ 78151795SstefanfMKINIT struct job *bgjob = NULL; /* last background process */ 79151795Sstefanf#if JOBS 801556Srgrimesstatic struct job *jobmru; /* most recently used job list */ 811556Srgrimesstatic pid_t initialpgrp; /* pgrp of shell on invocation */ 821556Srgrimes#endif 831556Srgrimesint in_waitcmd = 0; /* are we in waitcmd()? */ 84151795Sstefanfint in_dowait = 0; /* are we in dowait()? */ 85151795Sstefanfvolatile sig_atomic_t breakwaitcmd = 0; /* should wait be terminated? */ 86151795Sstefanfstatic int ttyfd = -1; 87151795Sstefanf 88151795Sstefanf#if JOBS 89151795Sstefanfstatic void restartjob(struct job *); 90151795Sstefanf#endif 911556Srgrimesstatic void freejob(struct job *); 92151795Sstefanfstatic struct job *getjob(char *); 931556Srgrimesstatic pid_t dowait(int, struct job *); 941556Srgrimesstatic pid_t waitproc(int, int *); 951556Srgrimesstatic void checkzombies(void); 961556Srgrimesstatic void cmdtxt(union node *); 971556Srgrimesstatic void cmdputs(const char *); 98200956Sjilles#if JOBS 9945618Scracauerstatic void setcurjob(struct job *); 10025222Sstevestatic void deljob(struct job *); 1011556Srgrimesstatic struct job *getcurjob(struct job *); 1021556Srgrimes#endif 1031556Srgrimesstatic void printjobcmd(struct job *); 1041556Srgrimesstatic void showjob(struct job *, int); 1051556Srgrimes 1061556Srgrimes 1071556Srgrimes/* 1081556Srgrimes * Turn job control on and off. 1091556Srgrimes */ 1101556Srgrimes 1111556SrgrimesMKINIT int jobctl; 1121556Srgrimes 113111422Smarcel#if JOBS 114111422Smarcelvoid 1151556Srgrimessetjobctl(int on) 1161556Srgrimes{ 117111422Smarcel int i; 1181556Srgrimes 1191556Srgrimes if (on == jobctl || rootshell == 0) 1201556Srgrimes return; 1211556Srgrimes if (on) { 122111422Smarcel if (ttyfd != -1) 1231556Srgrimes close(ttyfd); 124111422Smarcel if ((ttyfd = open(_PATH_TTY, O_RDWR)) < 0) { 1251556Srgrimes i = 0; 126213760Sobrien while (i <= 2 && !isatty(i)) 127213760Sobrien i++; 128111422Smarcel if (i > 2 || (ttyfd = fcntl(i, F_DUPFD, 10)) < 0) 129111422Smarcel goto out; 130216743Sjilles } 1311556Srgrimes if (ttyfd < 10) { 1321556Srgrimes /* 133213811Sobrien * Keep our TTY file descriptor out of the way of 134111422Smarcel * the user's redirections. 135111422Smarcel */ 136111422Smarcel if ((i = fcntl(ttyfd, F_DUPFD, 10)) < 0) { 137111422Smarcel close(ttyfd); 1381556Srgrimes ttyfd = -1; 139111422Smarcel goto out; 140111422Smarcel } 141111422Smarcel close(ttyfd); 142111422Smarcel ttyfd = i; 143111422Smarcel } 144111422Smarcel if (fcntl(ttyfd, F_SETFD, FD_CLOEXEC) < 0) { 145111422Smarcel close(ttyfd); 146111422Smarcel ttyfd = -1; 147111422Smarcel goto out; 148111422Smarcel } 149216743Sjilles do { /* while we are in the background */ 150111422Smarcel initialpgrp = tcgetpgrp(ttyfd); 151111422Smarcel if (initialpgrp < 0) { 152111422Smarcelout: out2fmt_flush("sh: can't access tty; job control turned off\n"); 153111422Smarcel mflag = 0; 154111422Smarcel return; 1551556Srgrimes } 15690111Simp if (initialpgrp == -1) 15717987Speter initialpgrp = getpgrp(); 15825222Ssteve else if (initialpgrp != getpgrp()) { 1591556Srgrimes killpg(0, SIGTTIN); 1601556Srgrimes continue; 161111422Smarcel } 162111422Smarcel } while (0); 1631556Srgrimes setsignal(SIGTSTP); 1641556Srgrimes setsignal(SIGTTOU); 1651556Srgrimes setsignal(SIGTTIN); 1661556Srgrimes setpgid(0, rootpid); 1671556Srgrimes tcsetpgrp(ttyfd, rootpid); 1681556Srgrimes } else { /* turning job control off */ 1691556Srgrimes setpgid(0, initialpgrp); 1701556Srgrimes tcsetpgrp(ttyfd, initialpgrp); 17190111Simp close(ttyfd); 17245618Scracauer ttyfd = -1; 1731556Srgrimes setsignal(SIGTSTP); 17480381Ssheldonh setsignal(SIGTTOU); 1751556Srgrimes setsignal(SIGTTIN); 1761556Srgrimes } 1771556Srgrimes jobctl = on; 1781556Srgrimes} 1791556Srgrimes#endif 1801556Srgrimes 1811556Srgrimes 1821556Srgrimes#ifdef mkinit 1831556SrgrimesINCLUDE <sys/types.h> 18490111SimpINCLUDE <stdlib.h> 18545618Scracauer 1861556SrgrimesSHELLPROC { 1871556Srgrimes backgndpid = -1; 1881556Srgrimes bgjob = NULL; 18964702Scracauer#if JOBS 19064702Scracauer jobctl = 0; 1911556Srgrimes#endif 1921556Srgrimes} 1931556Srgrimes 1941556Srgrimes#endif 19590111Simp 19645618Scracauer 1971556Srgrimes 1981556Srgrimes#if JOBS 1991556Srgrimesint 20064702Scracauerfgcmd(int argc __unused, char **argv) 2011556Srgrimes{ 2021556Srgrimes struct job *jp; 2031556Srgrimes pid_t pgrp; 2041556Srgrimes int status; 2051556Srgrimes 2061556Srgrimes jp = getjob(argv[1]); 2071556Srgrimes if (jp->jobctl == 0) 208216743Sjilles error("job not created under job control"); 2091556Srgrimes printjobcmd(jp); 2101556Srgrimes flushout(&output); 2111556Srgrimes pgrp = jp->ps[0].pid; 2121556Srgrimes tcsetpgrp(ttyfd, pgrp); 2131556Srgrimes restartjob(jp); 2141556Srgrimes jp->foreground = 1; 2151556Srgrimes INTOFF; 2161556Srgrimes status = waitforjob(jp, (int *)NULL); 2171556Srgrimes INTON; 2181556Srgrimes return status; 2191556Srgrimes} 2201556Srgrimes 2211556Srgrimes 2221556Srgrimesint 223216706Sjillesbgcmd(int argc, char **argv) 224216706Sjilles{ 22545618Scracauer char s[64]; 2261556Srgrimes struct job *jp; 22745618Scracauer 22845618Scracauer do { 22945618Scracauer jp = getjob(*++argv); 2301556Srgrimes if (jp->jobctl == 0) 23164702Scracauer error("job not created under job control"); 232111422Smarcel if (jp->state == JOBDONE) 2331556Srgrimes continue; 234216706Sjilles restartjob(jp); 235216706Sjilles jp->foreground = 0; 236216707Sjilles fmtstr(s, 64, "[%td] ", jp - jobtab + 1); 237216706Sjilles out1str(s); 238216706Sjilles printjobcmd(jp); 239216706Sjilles } while (--argc > 1); 240216706Sjilles return 0; 241216706Sjilles} 242216706Sjilles 24345618Scracauer 24445618Scracauerstatic void 24545618Scracauerrestartjob(struct job *jp) 246111422Smarcel{ 2471556Srgrimes struct procstat *ps; 24864702Scracauer int i; 249111422Smarcel 250111422Smarcel if (jp->state == JOBDONE) 2511556Srgrimes return; 2521556Srgrimes setcurjob(jp); 253111422Smarcel INTOFF; 254111422Smarcel killpg(jp->ps[0].pid, SIGCONT); 255216743Sjilles for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) { 256111422Smarcel if (WIFSTOPPED(ps->status)) { 257111422Smarcel ps->status = -1; 258111422Smarcel jp->state = 0; 259111422Smarcel } 260111422Smarcel } 261111422Smarcel INTON; 262111422Smarcel} 263111422Smarcel#endif 264111422Smarcel 265111422Smarcel 266111422Smarcelint 26764702Scracauerjobscmd(int argc, char *argv[]) 2681556Srgrimes{ 2691556Srgrimes char *id; 270216706Sjilles int ch, mode; 2711556Srgrimes 272111422Smarcel optind = optreset = 1; 273111422Smarcel opterr = 0; 274111422Smarcel mode = SHOWJOBS_DEFAULT; 2751556Srgrimes while ((ch = getopt(argc, argv, "lps")) != -1) { 2761556Srgrimes switch (ch) { 2771556Srgrimes case 'l': 2781556Srgrimes mode = SHOWJOBS_VERBOSE; 2791556Srgrimes break; 2801556Srgrimes case 'p': 28190111Simp mode = SHOWJOBS_PGIDS; 28217987Speter break; 2831556Srgrimes case 's': 2841556Srgrimes mode = SHOWJOBS_PIDS; 2851556Srgrimes break; 2861556Srgrimes case '?': 2871556Srgrimes default: 2881556Srgrimes error("unknown option: -%c", optopt); 2891556Srgrimes } 2901556Srgrimes } 2911556Srgrimes argc -= optind; 2921556Srgrimes argv += optind; 2931556Srgrimes 2941556Srgrimes if (argc == 0) 2951556Srgrimes showjobs(0, mode); 2961556Srgrimes else 2971556Srgrimes while ((id = *argv++) != NULL) 2981556Srgrimes showjob(getjob(id), mode); 2991556Srgrimes 3001556Srgrimes return (0); 3011556Srgrimes} 3021556Srgrimes 3031556Srgrimesstatic void 3041556Srgrimesprintjobcmd(struct job *jp) 3051556Srgrimes{ 3061556Srgrimes struct procstat *ps; 3071556Srgrimes int i; 308213814Sobrien 309216706Sjilles for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) { 310213814Sobrien out1str(ps->cmd); 311216706Sjilles if (i > 0) 312213814Sobrien out1str(" | "); 313213814Sobrien } 3141556Srgrimes out1c('\n'); 3151556Srgrimes} 31690111Simp 31745618Scracauerstatic void 31845618Scracauershowjob(struct job *jp, int mode) 31945618Scracauer{ 32045618Scracauer char s[64]; 321216706Sjilles char statestr[64]; 3221556Srgrimes struct procstat *ps; 3231556Srgrimes struct job *j; 3241556Srgrimes int col, curr, i, jobno, prev, procno; 3251556Srgrimes char c; 3261556Srgrimes 3271556Srgrimes procno = (mode == SHOWJOBS_PGIDS) ? 1 : jp->nprocs; 3281556Srgrimes jobno = jp - jobtab + 1; 3291556Srgrimes curr = prev = 0; 330216743Sjilles#if JOBS 33145618Scracauer if ((j = getcurjob(NULL)) != NULL) { 33245618Scracauer curr = j - jobtab + 1; 33345618Scracauer if ((j = getcurjob(j)) != NULL) 334216743Sjilles prev = j - jobtab + 1; 335216706Sjilles } 3361556Srgrimes#endif 3371556Srgrimes ps = jp->ps + jp->nprocs - 1; 3381556Srgrimes if (jp->state == 0) { 339215783Sjilles strcpy(statestr, "Running"); 340215783Sjilles#if JOBS 341215783Sjilles } else if (jp->state == JOBSTOPPED) { 342216706Sjilles while (!WIFSTOPPED(ps->status) && ps > jp->ps) 343216706Sjilles ps--; 344216706Sjilles if (WIFSTOPPED(ps->status)) 345215783Sjilles i = WSTOPSIG(ps->status); 346215783Sjilles else 347215783Sjilles i = -1; 348215783Sjilles if (i > 0 && i < sys_nsig && sys_siglist[i]) 349215783Sjilles strcpy(statestr, sys_siglist[i]); 350215783Sjilles else 351215783Sjilles strcpy(statestr, "Suspended"); 352#endif 353 } else if (WIFEXITED(ps->status)) { 354 if (WEXITSTATUS(ps->status) == 0) 355 strcpy(statestr, "Done"); 356 else 357 fmtstr(statestr, 64, "Done (%d)", 358 WEXITSTATUS(ps->status)); 359 } else { 360 i = WTERMSIG(ps->status); 361 if (i > 0 && i < sys_nsig && sys_siglist[i]) 362 strcpy(statestr, sys_siglist[i]); 363 else 364 fmtstr(statestr, 64, "Signal %d", i); 365 if (WCOREDUMP(ps->status)) 366 strcat(statestr, " (core dumped)"); 367 } 368 369 for (ps = jp->ps ; ; ps++) { /* for each process */ 370 if (mode == SHOWJOBS_PIDS || mode == SHOWJOBS_PGIDS) { 371 out1fmt("%d\n", (int)ps->pid); 372 goto skip; 373 } 374 if (mode != SHOWJOBS_VERBOSE && ps != jp->ps) 375 goto skip; 376 if (jobno == curr && ps == jp->ps) 377 c = '+'; 378 else if (jobno == prev && ps == jp->ps) 379 c = '-'; 380 else 381 c = ' '; 382 if (ps == jp->ps) 383 fmtstr(s, 64, "[%d] %c ", jobno, c); 384 else 385 fmtstr(s, 64, " %c ", c); 386 out1str(s); 387 col = strlen(s); 388 if (mode == SHOWJOBS_VERBOSE) { 389 fmtstr(s, 64, "%d ", (int)ps->pid); 390 out1str(s); 391 col += strlen(s); 392 } 393 if (ps == jp->ps) { 394 out1str(statestr); 395 col += strlen(statestr); 396 } 397 do { 398 out1c(' '); 399 col++; 400 } while (col < 30); 401 if (mode == SHOWJOBS_VERBOSE) { 402 out1str(ps->cmd); 403 out1c('\n'); 404 } else 405 printjobcmd(jp); 406skip: if (--procno <= 0) 407 break; 408 } 409} 410 411/* 412 * Print a list of jobs. If "change" is nonzero, only print jobs whose 413 * statuses have changed since the last call to showjobs. 414 * 415 * If the shell is interrupted in the process of creating a job, the 416 * result may be a job structure containing zero processes. Such structures 417 * will be freed here. 418 */ 419 420void 421showjobs(int change, int mode) 422{ 423 int jobno; 424 struct job *jp; 425 426 TRACE(("showjobs(%d) called\n", change)); 427 checkzombies(); 428 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) { 429 if (! jp->used) 430 continue; 431 if (jp->nprocs == 0) { 432 freejob(jp); 433 continue; 434 } 435 if (change && ! jp->changed) 436 continue; 437 showjob(jp, mode); 438 jp->changed = 0; 439 /* Hack: discard jobs for which $! has not been referenced 440 * in interactive mode when they terminate. 441 */ 442 if (jp->state == JOBDONE && !jp->remembered && 443 (iflag || jp != bgjob)) { 444 freejob(jp); 445 } 446 } 447} 448 449 450/* 451 * Mark a job structure as unused. 452 */ 453 454static void 455freejob(struct job *jp) 456{ 457 struct procstat *ps; 458 int i; 459 460 INTOFF; 461 if (bgjob == jp) 462 bgjob = NULL; 463 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) { 464 if (ps->cmd != nullstr) 465 ckfree(ps->cmd); 466 } 467 if (jp->ps != &jp->ps0) 468 ckfree(jp->ps); 469 jp->used = 0; 470#if JOBS 471 deljob(jp); 472#endif 473 INTON; 474} 475 476 477 478int 479waitcmd(int argc, char **argv) 480{ 481 struct job *job; 482 int status, retval; 483 struct job *jp; 484 485 if (argc > 1) { 486 job = getjob(argv[1]); 487 } else { 488 job = NULL; 489 } 490 491 /* 492 * Loop until a process is terminated or stopped, or a SIGINT is 493 * received. 494 */ 495 496 in_waitcmd++; 497 do { 498 if (job != NULL) { 499 if (job->state) { 500 status = job->ps[job->nprocs - 1].status; 501 if (WIFEXITED(status)) 502 retval = WEXITSTATUS(status); 503#if JOBS 504 else if (WIFSTOPPED(status)) 505 retval = WSTOPSIG(status) + 128; 506#endif 507 else 508 retval = WTERMSIG(status) + 128; 509 if (! iflag || ! job->changed) 510 freejob(job); 511 else { 512 job->remembered = 0; 513 if (job == bgjob) 514 bgjob = NULL; 515 } 516 in_waitcmd--; 517 return retval; 518 } 519 } else { 520 for (jp = jobtab ; jp < jobtab + njobs; jp++) 521 if (jp->used && jp->state == JOBDONE) { 522 if (! iflag || ! jp->changed) 523 freejob(jp); 524 else { 525 jp->remembered = 0; 526 if (jp == bgjob) 527 bgjob = NULL; 528 } 529 } 530 for (jp = jobtab ; ; jp++) { 531 if (jp >= jobtab + njobs) { /* no running procs */ 532 in_waitcmd--; 533 return 0; 534 } 535 if (jp->used && jp->state == 0) 536 break; 537 } 538 } 539 } while (dowait(1, (struct job *)NULL) != -1); 540 in_waitcmd--; 541 542 return 0; 543} 544 545 546 547int 548jobidcmd(int argc __unused, char **argv) 549{ 550 struct job *jp; 551 int i; 552 553 jp = getjob(argv[1]); 554 for (i = 0 ; i < jp->nprocs ; ) { 555 out1fmt("%d", (int)jp->ps[i].pid); 556 out1c(++i < jp->nprocs? ' ' : '\n'); 557 } 558 return 0; 559} 560 561 562 563/* 564 * Convert a job name to a job structure. 565 */ 566 567static struct job * 568getjob(char *name) 569{ 570 int jobno; 571 struct job *found, *jp; 572 pid_t pid; 573 int i; 574 575 if (name == NULL) { 576#if JOBS 577currentjob: if ((jp = getcurjob(NULL)) == NULL) 578 error("No current job"); 579 return (jp); 580#else 581 error("No current job"); 582#endif 583 } else if (name[0] == '%') { 584 if (is_digit(name[1])) { 585 jobno = number(name + 1); 586 if (jobno > 0 && jobno <= njobs 587 && jobtab[jobno - 1].used != 0) 588 return &jobtab[jobno - 1]; 589#if JOBS 590 } else if (name[1] == '%' && name[2] == '\0') { 591 goto currentjob; 592 } else if (name[1] == '+' && name[2] == '\0') { 593 goto currentjob; 594 } else if (name[1] == '-' && name[2] == '\0') { 595 if ((jp = getcurjob(NULL)) == NULL || 596 (jp = getcurjob(jp)) == NULL) 597 error("No previous job"); 598 return (jp); 599#endif 600 } else if (name[1] == '?') { 601 found = NULL; 602 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { 603 if (jp->used && jp->nprocs > 0 604 && strstr(jp->ps[0].cmd, name + 2) != NULL) { 605 if (found) 606 error("%s: ambiguous", name); 607 found = jp; 608 } 609 } 610 if (found != NULL) 611 return (found); 612 } else { 613 found = NULL; 614 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { 615 if (jp->used && jp->nprocs > 0 616 && prefix(name + 1, jp->ps[0].cmd)) { 617 if (found) 618 error("%s: ambiguous", name); 619 found = jp; 620 } 621 } 622 if (found) 623 return found; 624 } 625 } else if (is_number(name)) { 626 pid = (pid_t)number(name); 627 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { 628 if (jp->used && jp->nprocs > 0 629 && jp->ps[jp->nprocs - 1].pid == pid) 630 return jp; 631 } 632 } 633 error("No such job: %s", name); 634 /*NOTREACHED*/ 635 return NULL; 636} 637 638 639 640/* 641 * Return a new job structure, 642 */ 643 644struct job * 645makejob(union node *node __unused, int nprocs) 646{ 647 int i; 648 struct job *jp; 649 650 for (i = njobs, jp = jobtab ; ; jp++) { 651 if (--i < 0) { 652 INTOFF; 653 if (njobs == 0) { 654 jobtab = ckmalloc(4 * sizeof jobtab[0]); 655#if JOBS 656 jobmru = NULL; 657#endif 658 } else { 659 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]); 660 memcpy(jp, jobtab, njobs * sizeof jp[0]); 661#if JOBS 662 /* Relocate `next' pointers and list head */ 663 if (jobmru != NULL) 664 jobmru = &jp[jobmru - jobtab]; 665 for (i = 0; i < njobs; i++) 666 if (jp[i].next != NULL) 667 jp[i].next = &jp[jp[i].next - 668 jobtab]; 669#endif 670 if (bgjob != NULL) 671 bgjob = &jp[bgjob - jobtab]; 672 /* Relocate `ps' pointers */ 673 for (i = 0; i < njobs; i++) 674 if (jp[i].ps == &jobtab[i].ps0) 675 jp[i].ps = &jp[i].ps0; 676 ckfree(jobtab); 677 jobtab = jp; 678 } 679 jp = jobtab + njobs; 680 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0); 681 INTON; 682 break; 683 } 684 if (jp->used == 0) 685 break; 686 } 687 INTOFF; 688 jp->state = 0; 689 jp->used = 1; 690 jp->changed = 0; 691 jp->nprocs = 0; 692 jp->foreground = 0; 693 jp->remembered = 0; 694#if JOBS 695 jp->jobctl = jobctl; 696 jp->next = NULL; 697#endif 698 if (nprocs > 1) { 699 jp->ps = ckmalloc(nprocs * sizeof (struct procstat)); 700 } else { 701 jp->ps = &jp->ps0; 702 } 703 INTON; 704 TRACE(("makejob(%p, %d) returns %%%td\n", (void *)node, nprocs, 705 jp - jobtab + 1)); 706 return jp; 707} 708 709#if JOBS 710static void 711setcurjob(struct job *cj) 712{ 713 struct job *jp, *prev; 714 715 for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) { 716 if (jp == cj) { 717 if (prev != NULL) 718 prev->next = jp->next; 719 else 720 jobmru = jp->next; 721 jp->next = jobmru; 722 jobmru = cj; 723 return; 724 } 725 } 726 cj->next = jobmru; 727 jobmru = cj; 728} 729 730static void 731deljob(struct job *j) 732{ 733 struct job *jp, *prev; 734 735 for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) { 736 if (jp == j) { 737 if (prev != NULL) 738 prev->next = jp->next; 739 else 740 jobmru = jp->next; 741 return; 742 } 743 } 744} 745 746/* 747 * Return the most recently used job that isn't `nj', and preferably one 748 * that is stopped. 749 */ 750static struct job * 751getcurjob(struct job *nj) 752{ 753 struct job *jp; 754 755 /* Try to find a stopped one.. */ 756 for (jp = jobmru; jp != NULL; jp = jp->next) 757 if (jp->used && jp != nj && jp->state == JOBSTOPPED) 758 return (jp); 759 /* Otherwise the most recently used job that isn't `nj' */ 760 for (jp = jobmru; jp != NULL; jp = jp->next) 761 if (jp->used && jp != nj) 762 return (jp); 763 764 return (NULL); 765} 766 767#endif 768 769/* 770 * Fork of a subshell. If we are doing job control, give the subshell its 771 * own process group. Jp is a job structure that the job is to be added to. 772 * N is the command that will be evaluated by the child. Both jp and n may 773 * be NULL. The mode parameter can be one of the following: 774 * FORK_FG - Fork off a foreground process. 775 * FORK_BG - Fork off a background process. 776 * FORK_NOJOB - Like FORK_FG, but don't give the process its own 777 * process group even if job control is on. 778 * 779 * When job control is turned off, background processes have their standard 780 * input redirected to /dev/null (except for the second and later processes 781 * in a pipeline). 782 */ 783 784pid_t 785forkshell(struct job *jp, union node *n, int mode) 786{ 787 pid_t pid; 788 pid_t pgrp; 789 790 TRACE(("forkshell(%%%td, %p, %d) called\n", jp - jobtab, (void *)n, 791 mode)); 792 INTOFF; 793 if (mode == FORK_BG && (jp == NULL || jp->nprocs == 0)) 794 checkzombies(); 795 flushall(); 796 pid = fork(); 797 if (pid == -1) { 798 TRACE(("Fork failed, errno=%d\n", errno)); 799 INTON; 800 error("Cannot fork: %s", strerror(errno)); 801 } 802 if (pid == 0) { 803 struct job *p; 804 int wasroot; 805 int i; 806 807 TRACE(("Child shell %d\n", (int)getpid())); 808 wasroot = rootshell; 809 rootshell = 0; 810 handler = &main_handler; 811 closescript(); 812 INTON; 813 clear_traps(); 814#if JOBS 815 jobctl = 0; /* do job control only in root shell */ 816 if (wasroot && mode != FORK_NOJOB && mflag) { 817 if (jp == NULL || jp->nprocs == 0) 818 pgrp = getpid(); 819 else 820 pgrp = jp->ps[0].pid; 821 if (setpgid(0, pgrp) == 0 && mode == FORK_FG) { 822 /*** this causes superfluous TIOCSPGRPS ***/ 823 if (tcsetpgrp(ttyfd, pgrp) < 0) 824 error("tcsetpgrp failed, errno=%d", errno); 825 } 826 setsignal(SIGTSTP); 827 setsignal(SIGTTOU); 828 } else if (mode == FORK_BG) { 829 ignoresig(SIGINT); 830 ignoresig(SIGQUIT); 831 if ((jp == NULL || jp->nprocs == 0) && 832 ! fd0_redirected_p ()) { 833 close(0); 834 if (open(_PATH_DEVNULL, O_RDONLY) != 0) 835 error("Can't open %s: %s", 836 _PATH_DEVNULL, strerror(errno)); 837 } 838 } 839#else 840 if (mode == FORK_BG) { 841 ignoresig(SIGINT); 842 ignoresig(SIGQUIT); 843 if ((jp == NULL || jp->nprocs == 0) && 844 ! fd0_redirected_p ()) { 845 close(0); 846 if (open(_PATH_DEVNULL, O_RDONLY) != 0) 847 error("Can't open %s: %s", 848 _PATH_DEVNULL, strerror(errno)); 849 } 850 } 851#endif 852 INTOFF; 853 for (i = njobs, p = jobtab ; --i >= 0 ; p++) 854 if (p->used) 855 freejob(p); 856 INTON; 857 if (wasroot && iflag) { 858 setsignal(SIGINT); 859 setsignal(SIGQUIT); 860 setsignal(SIGTERM); 861 } 862 return pid; 863 } 864 if (rootshell && mode != FORK_NOJOB && mflag) { 865 if (jp == NULL || jp->nprocs == 0) 866 pgrp = pid; 867 else 868 pgrp = jp->ps[0].pid; 869 setpgid(pid, pgrp); 870 } 871 if (mode == FORK_BG) { 872 if (bgjob != NULL && bgjob->state == JOBDONE && 873 !bgjob->remembered && !iflag) 874 freejob(bgjob); 875 backgndpid = pid; /* set $! */ 876 bgjob = jp; 877 } 878 if (jp) { 879 struct procstat *ps = &jp->ps[jp->nprocs++]; 880 ps->pid = pid; 881 ps->status = -1; 882 ps->cmd = nullstr; 883 if (iflag && rootshell && n) 884 ps->cmd = commandtext(n); 885 jp->foreground = mode == FORK_FG; 886#if JOBS 887 setcurjob(jp); 888#endif 889 } 890 INTON; 891 TRACE(("In parent shell: child = %d\n", (int)pid)); 892 return pid; 893} 894 895 896 897/* 898 * Wait for job to finish. 899 * 900 * Under job control we have the problem that while a child process is 901 * running interrupts generated by the user are sent to the child but not 902 * to the shell. This means that an infinite loop started by an inter- 903 * active user may be hard to kill. With job control turned off, an 904 * interactive user may place an interactive program inside a loop. If 905 * the interactive program catches interrupts, the user doesn't want 906 * these interrupts to also abort the loop. The approach we take here 907 * is to have the shell ignore interrupt signals while waiting for a 908 * foreground process to terminate, and then send itself an interrupt 909 * signal if the child process was terminated by an interrupt signal. 910 * Unfortunately, some programs want to do a bit of cleanup and then 911 * exit on interrupt; unless these processes terminate themselves by 912 * sending a signal to themselves (instead of calling exit) they will 913 * confuse this approach. 914 */ 915 916int 917waitforjob(struct job *jp, int *origstatus) 918{ 919#if JOBS 920 pid_t mypgrp = getpgrp(); 921 int propagate_int = jp->jobctl && jp->foreground; 922#endif 923 int status; 924 int st; 925 926 INTOFF; 927 TRACE(("waitforjob(%%%td) called\n", jp - jobtab + 1)); 928 while (jp->state == 0) 929 if (dowait(1, jp) == -1) 930 dotrap(); 931#if JOBS 932 if (jp->jobctl) { 933 if (tcsetpgrp(ttyfd, mypgrp) < 0) 934 error("tcsetpgrp failed, errno=%d\n", errno); 935 } 936 if (jp->state == JOBSTOPPED) 937 setcurjob(jp); 938#endif 939 status = jp->ps[jp->nprocs - 1].status; 940 if (origstatus != NULL) 941 *origstatus = status; 942 /* convert to 8 bits */ 943 if (WIFEXITED(status)) 944 st = WEXITSTATUS(status); 945#if JOBS 946 else if (WIFSTOPPED(status)) 947 st = WSTOPSIG(status) + 128; 948#endif 949 else 950 st = WTERMSIG(status) + 128; 951 if (! JOBS || jp->state == JOBDONE) 952 freejob(jp); 953 if (int_pending()) { 954 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) 955 kill(getpid(), SIGINT); 956 else 957 CLEAR_PENDING_INT; 958 } 959#if JOBS 960 else if (rootshell && iflag && propagate_int && 961 WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) 962 kill(getpid(), SIGINT); 963#endif 964 INTON; 965 return st; 966} 967 968 969 970/* 971 * Wait for a process to terminate. 972 */ 973 974static pid_t 975dowait(int block, struct job *job) 976{ 977 pid_t pid; 978 int status; 979 struct procstat *sp; 980 struct job *jp; 981 struct job *thisjob; 982 int done; 983 int stopped; 984 int sig; 985 int coredump; 986 987 in_dowait++; 988 TRACE(("dowait(%d) called\n", block)); 989 do { 990 pid = waitproc(block, &status); 991 TRACE(("wait returns %d, status=%d\n", (int)pid, status)); 992 } while ((pid == -1 && errno == EINTR && breakwaitcmd == 0) || 993 (pid > 0 && WIFSTOPPED(status) && !iflag)); 994 in_dowait--; 995 if (pid == -1 && errno == ECHILD && job != NULL) 996 job->state = JOBDONE; 997 if (breakwaitcmd != 0) { 998 breakwaitcmd = 0; 999 if (pid <= 0) 1000 return -1; 1001 } 1002 if (pid <= 0) 1003 return pid; 1004 INTOFF; 1005 thisjob = NULL; 1006 for (jp = jobtab ; jp < jobtab + njobs ; jp++) { 1007 if (jp->used && jp->nprocs > 0) { 1008 done = 1; 1009 stopped = 1; 1010 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) { 1011 if (sp->pid == -1) 1012 continue; 1013 if (sp->pid == pid) { 1014 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", 1015 (int)pid, sp->status, 1016 status)); 1017 sp->status = status; 1018 thisjob = jp; 1019 } 1020 if (sp->status == -1) 1021 stopped = 0; 1022 else if (WIFSTOPPED(sp->status)) 1023 done = 0; 1024 } 1025 if (stopped) { /* stopped or done */ 1026 int state = done? JOBDONE : JOBSTOPPED; 1027 if (jp->state != state) { 1028 TRACE(("Job %td: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state)); 1029 jp->state = state; 1030 if (jp != job) { 1031 if (done && !jp->remembered && 1032 !iflag && jp != bgjob) 1033 freejob(jp); 1034#if JOBS 1035 else if (done) 1036 deljob(jp); 1037#endif 1038 } 1039 } 1040 } 1041 } 1042 } 1043 INTON; 1044 if (!thisjob || thisjob->state == 0) 1045 ; 1046 else if ((!rootshell || !iflag || thisjob == job) && 1047 thisjob->foreground && thisjob->state != JOBSTOPPED) { 1048 sig = 0; 1049 coredump = 0; 1050 for (sp = thisjob->ps; sp < thisjob->ps + thisjob->nprocs; sp++) 1051 if (WIFSIGNALED(sp->status)) { 1052 sig = WTERMSIG(sp->status); 1053 coredump = WCOREDUMP(sp->status); 1054 } 1055 if (sig > 0 && sig != SIGINT && sig != SIGPIPE) { 1056 if (sig < sys_nsig && sys_siglist[sig]) 1057 out1str(sys_siglist[sig]); 1058 else 1059 out1fmt("Signal %d", sig); 1060 if (coredump) 1061 out1str(" (core dumped)"); 1062 out1c('\n'); 1063 } 1064 } else { 1065 TRACE(("Not printing status, rootshell=%d, job=%p\n", rootshell, job)); 1066 thisjob->changed = 1; 1067 } 1068 return pid; 1069} 1070 1071 1072 1073/* 1074 * Do a wait system call. If job control is compiled in, we accept 1075 * stopped processes. If block is zero, we return a value of zero 1076 * rather than blocking. 1077 */ 1078static pid_t 1079waitproc(int block, int *status) 1080{ 1081 int flags; 1082 1083#if JOBS 1084 flags = WUNTRACED; 1085#else 1086 flags = 0; 1087#endif 1088 if (block == 0) 1089 flags |= WNOHANG; 1090 return wait3(status, flags, (struct rusage *)NULL); 1091} 1092 1093/* 1094 * return 1 if there are stopped jobs, otherwise 0 1095 */ 1096int job_warning = 0; 1097int 1098stoppedjobs(void) 1099{ 1100 int jobno; 1101 struct job *jp; 1102 1103 if (job_warning) 1104 return (0); 1105 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) { 1106 if (jp->used == 0) 1107 continue; 1108 if (jp->state == JOBSTOPPED) { 1109 out2fmt_flush("You have stopped jobs.\n"); 1110 job_warning = 2; 1111 return (1); 1112 } 1113 } 1114 1115 return (0); 1116} 1117 1118 1119static void 1120checkzombies(void) 1121{ 1122 while (njobs > 0 && dowait(0, NULL) > 0) 1123 ; 1124} 1125 1126 1127int 1128backgndpidset(void) 1129{ 1130 return backgndpid != -1; 1131} 1132 1133 1134pid_t 1135backgndpidval(void) 1136{ 1137 if (bgjob != NULL) 1138 bgjob->remembered = 1; 1139 return backgndpid; 1140} 1141 1142/* 1143 * Return a string identifying a command (to be printed by the 1144 * jobs command. 1145 */ 1146 1147static char *cmdnextc; 1148static int cmdnleft; 1149#define MAXCMDTEXT 200 1150 1151char * 1152commandtext(union node *n) 1153{ 1154 char *name; 1155 1156 cmdnextc = name = ckmalloc(MAXCMDTEXT); 1157 cmdnleft = MAXCMDTEXT - 4; 1158 cmdtxt(n); 1159 *cmdnextc = '\0'; 1160 return name; 1161} 1162 1163 1164static void 1165cmdtxt(union node *n) 1166{ 1167 union node *np; 1168 struct nodelist *lp; 1169 const char *p; 1170 int i; 1171 char s[2]; 1172 1173 if (n == NULL) 1174 return; 1175 switch (n->type) { 1176 case NSEMI: 1177 cmdtxt(n->nbinary.ch1); 1178 cmdputs("; "); 1179 cmdtxt(n->nbinary.ch2); 1180 break; 1181 case NAND: 1182 cmdtxt(n->nbinary.ch1); 1183 cmdputs(" && "); 1184 cmdtxt(n->nbinary.ch2); 1185 break; 1186 case NOR: 1187 cmdtxt(n->nbinary.ch1); 1188 cmdputs(" || "); 1189 cmdtxt(n->nbinary.ch2); 1190 break; 1191 case NPIPE: 1192 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 1193 cmdtxt(lp->n); 1194 if (lp->next) 1195 cmdputs(" | "); 1196 } 1197 break; 1198 case NSUBSHELL: 1199 cmdputs("("); 1200 cmdtxt(n->nredir.n); 1201 cmdputs(")"); 1202 break; 1203 case NREDIR: 1204 case NBACKGND: 1205 cmdtxt(n->nredir.n); 1206 break; 1207 case NIF: 1208 cmdputs("if "); 1209 cmdtxt(n->nif.test); 1210 cmdputs("; then "); 1211 cmdtxt(n->nif.ifpart); 1212 cmdputs("..."); 1213 break; 1214 case NWHILE: 1215 cmdputs("while "); 1216 goto until; 1217 case NUNTIL: 1218 cmdputs("until "); 1219until: 1220 cmdtxt(n->nbinary.ch1); 1221 cmdputs("; do "); 1222 cmdtxt(n->nbinary.ch2); 1223 cmdputs("; done"); 1224 break; 1225 case NFOR: 1226 cmdputs("for "); 1227 cmdputs(n->nfor.var); 1228 cmdputs(" in ..."); 1229 break; 1230 case NCASE: 1231 cmdputs("case "); 1232 cmdputs(n->ncase.expr->narg.text); 1233 cmdputs(" in ..."); 1234 break; 1235 case NDEFUN: 1236 cmdputs(n->narg.text); 1237 cmdputs("() ..."); 1238 break; 1239 case NCMD: 1240 for (np = n->ncmd.args ; np ; np = np->narg.next) { 1241 cmdtxt(np); 1242 if (np->narg.next) 1243 cmdputs(" "); 1244 } 1245 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) { 1246 cmdputs(" "); 1247 cmdtxt(np); 1248 } 1249 break; 1250 case NARG: 1251 cmdputs(n->narg.text); 1252 break; 1253 case NTO: 1254 p = ">"; i = 1; goto redir; 1255 case NAPPEND: 1256 p = ">>"; i = 1; goto redir; 1257 case NTOFD: 1258 p = ">&"; i = 1; goto redir; 1259 case NCLOBBER: 1260 p = ">|"; i = 1; goto redir; 1261 case NFROM: 1262 p = "<"; i = 0; goto redir; 1263 case NFROMTO: 1264 p = "<>"; i = 0; goto redir; 1265 case NFROMFD: 1266 p = "<&"; i = 0; goto redir; 1267redir: 1268 if (n->nfile.fd != i) { 1269 s[0] = n->nfile.fd + '0'; 1270 s[1] = '\0'; 1271 cmdputs(s); 1272 } 1273 cmdputs(p); 1274 if (n->type == NTOFD || n->type == NFROMFD) { 1275 if (n->ndup.dupfd >= 0) 1276 s[0] = n->ndup.dupfd + '0'; 1277 else 1278 s[0] = '-'; 1279 s[1] = '\0'; 1280 cmdputs(s); 1281 } else { 1282 cmdtxt(n->nfile.fname); 1283 } 1284 break; 1285 case NHERE: 1286 case NXHERE: 1287 cmdputs("<<..."); 1288 break; 1289 default: 1290 cmdputs("???"); 1291 break; 1292 } 1293} 1294 1295 1296 1297static void 1298cmdputs(const char *s) 1299{ 1300 const char *p; 1301 char *q; 1302 char c; 1303 int subtype = 0; 1304 1305 if (cmdnleft <= 0) 1306 return; 1307 p = s; 1308 q = cmdnextc; 1309 while ((c = *p++) != '\0') { 1310 if (c == CTLESC) 1311 *q++ = *p++; 1312 else if (c == CTLVAR) { 1313 *q++ = '$'; 1314 if (--cmdnleft > 0) 1315 *q++ = '{'; 1316 subtype = *p++; 1317 } else if (c == '=' && subtype != 0) { 1318 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL]; 1319 subtype = 0; 1320 } else if (c == CTLENDVAR) { 1321 *q++ = '}'; 1322 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) 1323 cmdnleft++; /* ignore it */ 1324 else 1325 *q++ = c; 1326 if (--cmdnleft <= 0) { 1327 *q++ = '.'; 1328 *q++ = '.'; 1329 *q++ = '.'; 1330 break; 1331 } 1332 } 1333 cmdnextc = q; 1334} 1335