1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Job control for UNIX Shell 32 */ 33 34 #include <sys/termio.h> 35 #include <sys/types.h> 36 #include <sys/wait.h> 37 #include <sys/param.h> 38 #include <fcntl.h> 39 #include <errno.h> 40 #include <signal.h> 41 #include "defs.h" 42 43 /* 44 * one of these for each active job 45 */ 46 47 struct job 48 { 49 struct job *j_nxtp; /* next job in job ID order */ 50 struct job *j_curp; /* next job in job currency order */ 51 struct termios j_stty; /* termio save area when job stops */ 52 pid_t j_pid; /* job leader's process ID */ 53 pid_t j_pgid; /* job's process group ID */ 54 pid_t j_tgid; /* job's foreground process group ID */ 55 uint_t j_jid; /* job ID */ 56 ushort_t j_xval; /* exit code, or exit or stop signal */ 57 ushort_t j_flag; /* various status flags defined below */ 58 char *j_pwd; /* job's working directory */ 59 char *j_cmd; /* cmd used to invoke this job */ 60 }; 61 62 /* defines for j_flag */ 63 64 #define J_DUMPED 0001 /* job has core dumped */ 65 #define J_NOTIFY 0002 /* job has changed status */ 66 #define J_SAVETTY 0004 /* job was stopped in foreground, and its */ 67 /* termio settings were saved */ 68 #define J_STOPPED 0010 /* job has been stopped */ 69 #define J_SIGNALED 0020 /* job has received signal; j_xval has it */ 70 #define J_DONE 0040 /* job has finished */ 71 #define J_RUNNING 0100 /* job is currently running */ 72 #define J_FOREGND 0200 /* job was put in foreground by shell */ 73 74 /* options to the printjob() function defined below */ 75 76 #define PR_CUR 00001 /* print job currency ('+', '-', or ' ') */ 77 #define PR_JID 00002 /* print job ID */ 78 #define PR_PGID 00004 /* print job's process group ID */ 79 #define PR_STAT 00010 /* print status obtained from wait */ 80 #define PR_CMD 00020 /* print cmd that invoked job */ 81 #define PR_AMP 00040 /* print a '&' if in the background */ 82 #define PR_PWD 00100 /* print jobs present working directory */ 83 84 #define PR_DFL (PR_CUR|PR_JID|PR_STAT|PR_CMD) /* default options */ 85 #define PR_LONG (PR_DFL|PR_PGID|PR_PWD) /* long options */ 86 87 static struct termios mystty; /* default termio settings */ 88 static int eofflg, 89 jobcnt, /* number of active jobs */ 90 jobdone, /* number of active but finished jobs */ 91 jobnote; /* jobs requiring notification */ 92 static pid_t svpgid, /* saved process group ID */ 93 svtgid; /* saved foreground process group ID */ 94 static struct job *jobcur, /* active jobs listed in currency order */ 95 **nextjob, 96 *thisjob, 97 *joblst; /* active jobs listed in job ID order */ 98 99 static void printjob(struct job *, int); 100 101 static struct job * 102 pgid2job(pid_t pgid) 103 { 104 struct job *jp; 105 106 for (jp = joblst; jp != 0 && jp->j_pid != pgid; jp = jp->j_nxtp) 107 continue; 108 109 return (jp); 110 } 111 112 static struct job * 113 str2job(char *cmd, char *job, int mustbejob) 114 { 115 struct job *jp, *njp; 116 int i; 117 118 if (*job != '%') 119 jp = pgid2job(stoi(job)); 120 else if (*++job == 0 || *job == '+' || *job == '%' || *job == '-') { 121 jp = jobcur; 122 if (*job == '-' && jp) 123 jp = jp->j_curp; 124 } else if (*job >= '0' && *job <= '9') { 125 i = stoi(job); 126 for (jp = joblst; jp && jp->j_jid != i; jp = jp->j_nxtp) 127 continue; 128 } else if (*job == '?') { 129 int j; 130 char *p; 131 i = strlen(++job); 132 jp = 0; 133 for (njp = jobcur; njp; njp = njp->j_curp) { 134 if (njp->j_jid == 0) 135 continue; 136 for (p = njp->j_cmd, j = strlen(p); j >= i; p++, j--) { 137 if (strncmp(job, p, i) == 0) { 138 if (jp != 0) 139 failed((unsigned char *)cmd, 140 ambiguous); 141 jp = njp; 142 break; 143 } 144 } 145 } 146 } else { 147 i = strlen(job); 148 jp = 0; 149 for (njp = jobcur; njp; njp = njp->j_curp) { 150 if (njp->j_jid == 0) 151 continue; 152 if (strncmp(job, njp->j_cmd, i) == 0) { 153 if (jp != 0) 154 failed((unsigned char *)cmd, ambiguous); 155 jp = njp; 156 } 157 } 158 } 159 160 if (mustbejob && (jp == 0 || jp->j_jid == 0)) 161 failed((unsigned char *)cmd, nosuchjob); 162 163 return (jp); 164 } 165 166 static void 167 freejob(struct job *jp) 168 { 169 struct job **njp; 170 struct job **cjp; 171 172 for (njp = &joblst; *njp != jp; njp = &(*njp)->j_nxtp) 173 continue; 174 175 for (cjp = &jobcur; *cjp != jp; cjp = &(*cjp)->j_curp) 176 continue; 177 178 *njp = jp->j_nxtp; 179 *cjp = jp->j_curp; 180 free(jp); 181 jobcnt--; 182 jobdone--; 183 } 184 185 /* 186 * Collect the foreground job. 187 * Used in the case where the subshell wants 188 * to exit, but needs to wait until the fg job 189 * is done. 190 */ 191 void 192 collect_fg_job(void) 193 { 194 struct job *jp; 195 pid_t pid; 196 int stat; 197 198 for (jp = joblst; jp; jp = jp->j_nxtp) 199 if (jp->j_flag & J_FOREGND) 200 break; 201 202 if (!jp) 203 /* no foreground job */ 204 return; 205 206 /* 207 * Wait on fg job until wait succeeds 208 * or it fails due to no waitable children. 209 */ 210 211 while (1) { 212 errno = 0; 213 pid = waitpid(jp->j_pid, &stat, 0); 214 if (pid == jp->j_pid || (pid == -1 && errno == ECHILD)) 215 break; 216 } 217 } 218 219 /* 220 * analyze the status of a job 221 */ 222 223 static int 224 statjob(struct job *jp, int stat, int fg, int rc) 225 { 226 pid_t tgid; 227 int done = 0; 228 229 if (WIFCONTINUED(stat)) { 230 if (jp->j_flag & J_STOPPED) { 231 jp->j_flag &= ~(J_STOPPED|J_SIGNALED|J_SAVETTY); 232 jp->j_flag |= J_RUNNING; 233 if (!fg && jp->j_jid) { 234 jp->j_flag |= J_NOTIFY; 235 jobnote++; 236 } 237 } 238 } else if (WIFSTOPPED(stat)) { 239 jp->j_xval = WSTOPSIG(stat); 240 jp->j_flag &= ~J_RUNNING; 241 jp->j_flag |= (J_SIGNALED|J_STOPPED); 242 jp->j_pgid = getpgid(jp->j_pid); 243 jp->j_tgid = jp->j_pgid; 244 if (fg) { 245 if (tgid = settgid(mypgid, jp->j_pgid)) 246 jp->j_tgid = tgid; 247 else { 248 jp->j_flag |= J_SAVETTY; 249 tcgetattr(0, &jp->j_stty); 250 (void) tcsetattr(0, TCSANOW, &mystty); 251 } 252 } 253 if (jp->j_jid) { 254 jp->j_flag |= J_NOTIFY; 255 jobnote++; 256 } 257 } else { 258 jp->j_flag &= ~J_RUNNING; 259 jp->j_flag |= J_DONE; 260 done++; 261 jobdone++; 262 if (WIFSIGNALED(stat)) { 263 jp->j_xval = WTERMSIG(stat); 264 jp->j_flag |= J_SIGNALED; 265 if (WCOREDUMP(stat)) 266 jp->j_flag |= J_DUMPED; 267 if (!fg || jp->j_xval != SIGINT) { 268 jp->j_flag |= J_NOTIFY; 269 jobnote++; 270 } 271 } else { /* WIFEXITED */ 272 jp->j_xval = WEXITSTATUS(stat); 273 jp->j_flag &= ~J_SIGNALED; 274 if (!fg && jp->j_jid) { 275 jp->j_flag |= J_NOTIFY; 276 jobnote++; 277 } 278 } 279 if (fg) { 280 if (!settgid(mypgid, jp->j_pgid) || 281 !settgid(mypgid, getpgid(jp->j_pid))) 282 tcgetattr(0, &mystty); 283 } 284 } 285 if (rc) { 286 exitval = jp->j_xval; 287 if (jp->j_flag & J_SIGNALED) 288 exitval |= SIGFLG; 289 exitset(); 290 } 291 if (done && !(jp->j_flag & J_NOTIFY)) 292 freejob(jp); 293 return (done); 294 } 295 296 /* 297 * collect the status of jobs that have recently exited or stopped - 298 * if wnohang == WNOHANG, wait until error, or all jobs are accounted for; 299 * 300 * called after each command is executed, with wnohang == 0, and as part 301 * of "wait" builtin with wnohang == WNOHANG 302 * 303 * We do not need to call chktrap here if waitpid(2) is called with 304 * wnohang == 0, because that only happens from syswait() which is called 305 * from builtin() where chktrap() is already called. 306 */ 307 308 static void 309 collectjobs(wnohang) 310 { 311 pid_t pid; 312 struct job *jp; 313 int stat, n; 314 int wflags; 315 316 if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg)) 317 wflags = WUNTRACED|WCONTINUED; 318 else 319 wflags = 0; 320 321 for (n = jobcnt - jobdone; n > 0; n--) { 322 if ((pid = waitpid(-1, &stat, wnohang|wflags)) <= 0) 323 break; 324 if (jp = pgid2job(pid)) 325 (void) statjob(jp, stat, 0, 0); 326 } 327 328 } 329 330 void 331 freejobs() 332 { 333 struct job *jp; 334 335 collectjobs(WNOHANG); 336 337 if (jobnote) { 338 int savefd = setb(2); 339 for (jp = joblst; jp; jp = jp->j_nxtp) { 340 if (jp->j_flag & J_NOTIFY) { 341 if (jp->j_jid) 342 printjob(jp, PR_DFL); 343 else if (jp->j_flag & J_FOREGND) 344 printjob(jp, PR_STAT); 345 else 346 printjob(jp, PR_STAT|PR_PGID); 347 } 348 } 349 (void) setb(savefd); 350 } 351 352 if (jobdone) { 353 for (jp = joblst; jp; jp = jp->j_nxtp) { 354 if (jp->j_flag & J_DONE) 355 freejob(jp); 356 } 357 } 358 } 359 360 static void 361 waitjob(struct job *jp) 362 { 363 int stat; 364 int done; 365 pid_t pid = jp->j_pid; 366 int wflags; 367 int ret = 0; 368 int err = 0; 369 370 if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg)) 371 wflags = WUNTRACED; 372 else 373 wflags = 0; 374 do { 375 errno = 0; 376 ret = waitpid(pid, &stat, wflags|WNOWAIT); 377 err = errno; 378 if (ret == -1 && err == ECHILD) { 379 stat = 0; 380 break; 381 } 382 } while (ret != pid); 383 384 done = statjob(jp, stat, 1, 1); 385 waitpid(pid, 0, wflags); 386 if (done && exitval && (flags & errflg)) 387 exitsh(exitval); 388 flags |= eflag; 389 } 390 391 /* 392 * modify the foreground process group to *new* only if the 393 * current foreground process group is equal to *expected* 394 */ 395 396 int 397 settgid(new, expected) 398 pid_t new, expected; 399 { 400 pid_t current = tcgetpgrp(0); 401 402 if (current != expected) 403 return (current); 404 405 if (new != current) 406 tcsetpgrp(0, new); 407 408 return (0); 409 } 410 411 static void 412 restartjob(struct job *jp, int fg) 413 { 414 if (jp != jobcur) { 415 struct job *t; 416 417 for (t = jobcur; t->j_curp != jp; t = t->j_curp) 418 ; 419 t->j_curp = jp->j_curp; 420 jp->j_curp = jobcur; 421 jobcur = jp; 422 } 423 if (fg) { 424 if (jp->j_flag & J_SAVETTY) { 425 jp->j_stty.c_lflag &= ~TOSTOP; 426 jp->j_stty.c_lflag |= (mystty.c_lflag&TOSTOP); 427 jp->j_stty.c_cc[VSUSP] = mystty.c_cc[VSUSP]; 428 jp->j_stty.c_cc[VDSUSP] = mystty.c_cc[VDSUSP]; 429 (void) tcsetattr(0, TCSADRAIN, &jp->j_stty); 430 } 431 (void) settgid(jp->j_tgid, mypgid); 432 } 433 (void) kill(-(jp->j_pgid), SIGCONT); 434 if (jp->j_tgid != jp->j_pgid) 435 (void) kill(-(jp->j_tgid), SIGCONT); 436 jp->j_flag &= ~(J_STOPPED|J_SIGNALED|J_SAVETTY); 437 jp->j_flag |= J_RUNNING; 438 if (fg) { 439 jp->j_flag |= J_FOREGND; 440 printjob(jp, PR_JID|PR_CMD); 441 waitjob(jp); 442 } else { 443 jp->j_flag &= ~J_FOREGND; 444 printjob(jp, PR_JID|PR_CMD|PR_AMP); 445 } 446 } 447 448 static void 449 printjob(struct job *jp, int propts) 450 { 451 int sp = 0; 452 453 if (jp->j_flag & J_NOTIFY) { 454 jobnote--; 455 jp->j_flag &= ~J_NOTIFY; 456 } 457 458 if (propts & PR_JID) { 459 prc_buff('['); 460 prn_buff(jp->j_jid); 461 prc_buff(']'); 462 sp = 1; 463 } 464 465 if (propts & PR_CUR) { 466 while (sp-- > 0) 467 prc_buff(SPACE); 468 sp = 1; 469 if (jobcur == jp) 470 prc_buff('+'); 471 else if (jobcur != 0 && jobcur->j_curp == jp) 472 prc_buff('-'); 473 else 474 sp++; 475 } 476 477 if (propts & PR_PGID) { 478 while (sp-- > 0) 479 prc_buff(SPACE); 480 prn_buff(jp->j_pid); 481 sp = 1; 482 } 483 484 if (propts & PR_STAT) { 485 char *gmsg; 486 while (sp-- > 0) 487 prc_buff(SPACE); 488 sp = 28; 489 if (jp->j_flag & J_SIGNALED) { 490 char *sigstr, *strsignal(); 491 if ((sigstr = strsignal(jp->j_xval)) != NULL) { 492 sp -= strlen(sigstr); 493 prs_buff(sigstr); 494 } else { 495 itos(jp->j_xval); 496 gmsg = gettext(signalnum); 497 sp -= strlen(numbuf) + strlen(gmsg); 498 prs_buff((unsigned char *)gmsg); 499 prs_buff(numbuf); 500 } 501 if (jp->j_flag & J_DUMPED) { 502 gmsg = gettext(coredump); 503 sp -= strlen(gmsg); 504 prs_buff((unsigned char *)gmsg); 505 } 506 } else if (jp->j_flag & J_DONE) { 507 itos(jp->j_xval); 508 gmsg = gettext(exited); 509 sp -= strlen(gmsg) + strlen(numbuf) + 2; 510 prs_buff((unsigned char *)gmsg); 511 prc_buff('('); 512 itos(jp->j_xval); 513 prs_buff(numbuf); 514 prc_buff(')'); 515 } else { 516 gmsg = gettext(running); 517 sp -= strlen(gmsg); 518 prs_buff((unsigned char *)gmsg); 519 } 520 if (sp < 1) 521 sp = 1; 522 } 523 524 if (propts & PR_CMD) { 525 while (sp-- > 0) 526 prc_buff(SPACE); 527 prs_buff(jp->j_cmd); 528 sp = 1; 529 } 530 531 if (propts & PR_AMP) { 532 while (sp-- > 0) 533 prc_buff(SPACE); 534 prc_buff('&'); 535 sp = 1; 536 } 537 538 if (propts & PR_PWD) { 539 while (sp-- > 0) 540 prc_buff(SPACE); 541 prs_buff("(wd: "); 542 prs_buff(jp->j_pwd); 543 prc_buff(')'); 544 } 545 546 prc_buff(NL); 547 flushb(); 548 549 } 550 551 552 /* 553 * called to initialize job control for each new input file to the shell, 554 * and after the "exec" builtin 555 */ 556 557 void 558 startjobs() 559 { 560 svpgid = mypgid; 561 562 if (tcgetattr(0, &mystty) == -1 || (svtgid = tcgetpgrp(0)) == -1) { 563 flags &= ~jcflg; 564 return; 565 } 566 567 flags |= jcflg; 568 569 handle(SIGTTOU, SIG_IGN); 570 handle(SIGTSTP, SIG_DFL); 571 572 if (mysid != mypgid) { 573 setpgid(0, 0); 574 mypgid = mypid; 575 (void) settgid(mypgid, svpgid); 576 } 577 578 } 579 580 int 581 endjobs(check_if) 582 int check_if; 583 { 584 if ((flags & (jcoff|jcflg)) != jcflg) 585 return (1); 586 587 if (check_if && jobcnt && eofflg++ == 0) { 588 struct job *jp; 589 if (check_if & JOB_STOPPED) { 590 for (jp = joblst; jp; jp = jp->j_nxtp) { 591 if (jp->j_jid && (jp->j_flag & J_STOPPED)) { 592 prs(_gettext(jobsstopped)); 593 prc(NL); 594 return (0); 595 } 596 } 597 } 598 if (check_if & JOB_RUNNING) { 599 for (jp = joblst; jp; jp = jp->j_nxtp) { 600 if (jp->j_jid && (jp->j_flag & J_RUNNING)) { 601 prs(_gettext(jobsrunning)); 602 prc(NL); 603 return (0); 604 } 605 } 606 } 607 } 608 609 if (svpgid != mypgid) { 610 (void) settgid(svtgid, mypgid); 611 setpgid(0, svpgid); 612 } 613 614 return (1); 615 } 616 617 618 /* 619 * called by the shell to reserve a job slot for a job about to be spawned 620 */ 621 622 void 623 deallocjob() 624 { 625 free(thisjob); 626 jobcnt--; 627 } 628 629 void 630 allocjob(char *cmd, uchar_t *cwd, int monitor) 631 { 632 struct job *jp, **jpp; 633 int jid, cmdlen, cwdlen; 634 635 cmdlen = strlen(cmd) + 1; 636 if (cmd[cmdlen-2] == '&') { 637 cmd[cmdlen-3] = 0; 638 cmdlen -= 2; 639 } 640 cwdlen = strlen(cwd) + 1; 641 jp = (struct job *) alloc(sizeof (struct job) + cmdlen + cwdlen); 642 if (jp == 0) 643 error(nostack); 644 jobcnt++; 645 jp->j_cmd = ((char *)jp) + sizeof (struct job); 646 strcpy(jp->j_cmd, cmd); 647 jp->j_pwd = jp->j_cmd + cmdlen; 648 strcpy(jp->j_pwd, cwd); 649 650 jpp = &joblst; 651 652 if (monitor) { 653 for (; *jpp; jpp = &(*jpp)->j_nxtp) 654 if ((*jpp)->j_jid != 0) 655 break; 656 for (jid = 1; *jpp; jpp = &(*jpp)->j_nxtp, jid++) 657 if ((*jpp)->j_jid != jid) 658 break; 659 } else 660 jid = 0; 661 662 jp->j_jid = jid; 663 nextjob = jpp; 664 thisjob = jp; 665 } 666 667 void 668 clearjobs(void) 669 { 670 struct job *jp, *sjp; 671 672 for (jp = joblst; jp; jp = sjp) { 673 sjp = jp->j_nxtp; 674 free(jp); 675 } 676 joblst = NULL; 677 jobcnt = 0; 678 jobnote = 0; 679 jobdone = 0; 680 681 } 682 683 void 684 makejob(int monitor, int fg) 685 { 686 if (monitor) { 687 mypgid = mypid; 688 setpgid(0, 0); 689 if (fg) 690 tcsetpgrp(0, mypid); 691 handle(SIGTTOU, SIG_DFL); 692 handle(SIGTSTP, SIG_DFL); 693 } else if (!fg) { 694 #ifdef NICE 695 nice(NICE); 696 #endif 697 handle(SIGTTIN, SIG_IGN); 698 handle(SIGINT, SIG_IGN); 699 handle(SIGQUIT, SIG_IGN); 700 if (!ioset) 701 renamef(chkopen(devnull, 0), 0); 702 } 703 } 704 705 /* 706 * called by the shell after job has been spawned, to fill in the 707 * job slot, and wait for the job if in the foreground 708 */ 709 710 void 711 postjob(pid, fg) 712 pid_t pid; 713 int fg; 714 { 715 716 int propts; 717 718 thisjob->j_nxtp = *nextjob; 719 *nextjob = thisjob; 720 thisjob->j_curp = jobcur; 721 jobcur = thisjob; 722 723 if (thisjob->j_jid) { 724 thisjob->j_pgid = pid; 725 propts = PR_JID|PR_PGID; 726 } else { 727 thisjob->j_pgid = mypgid; 728 propts = PR_PGID; 729 } 730 731 thisjob->j_flag = J_RUNNING; 732 thisjob->j_tgid = thisjob->j_pgid; 733 thisjob->j_pid = pid; 734 eofflg = 0; 735 736 if (fg) { 737 thisjob->j_flag |= J_FOREGND; 738 waitjob(thisjob); 739 } else { 740 if (flags & ttyflg) 741 printjob(thisjob, propts); 742 assnum(&pcsadr, (long)pid); 743 } 744 } 745 746 /* 747 * the builtin "jobs" command 748 */ 749 750 void 751 sysjobs(argc, argv) 752 int argc; 753 char *argv[]; 754 { 755 char *cmd = *argv; 756 struct job *jp; 757 int propts, c; 758 extern int opterr, i; 759 int savoptind = optind; 760 int loptind = -1; 761 int savopterr = opterr; 762 int savsp = _sp; 763 char *savoptarg = optarg; 764 optind = 1; 765 opterr = 0; 766 _sp = 1; 767 propts = 0; 768 769 if ((flags & jcflg) == 0) 770 failed((unsigned char *)cmd, nojc); 771 772 while ((c = getopt(argc, argv, "lpx")) != -1) { 773 if (propts) { 774 gfailure(usage, jobsuse); 775 goto err; 776 } 777 switch (c) { 778 case 'x': 779 propts = -1; 780 break; 781 case 'p': 782 propts = PR_PGID; 783 break; 784 case 'l': 785 propts = PR_LONG; 786 break; 787 case '?': 788 gfailure(usage, jobsuse); 789 goto err; 790 } 791 } 792 793 loptind = optind; 794 err: 795 optind = savoptind; 796 optarg = savoptarg; 797 opterr = savopterr; 798 _sp = savsp; 799 if (loptind == -1) 800 return; 801 802 if (propts == -1) { 803 unsigned char *bp; 804 char *cp; 805 unsigned char *savebp; 806 for (savebp = bp = locstak(); loptind < argc; loptind++) { 807 cp = argv[loptind]; 808 if (*cp == '%') { 809 jp = str2job(cmd, cp, 1); 810 itos(jp->j_pid); 811 cp = (char *)numbuf; 812 } 813 while (*cp) { 814 if (bp >= brkend) 815 growstak(bp); 816 *bp++ = *cp++; 817 } 818 if (bp >= brkend) 819 growstak(bp); 820 *bp++ = SPACE; 821 } 822 endstak(bp); 823 execexp(savebp, 0); 824 return; 825 } 826 827 collectjobs(WNOHANG); 828 829 if (propts == 0) 830 propts = PR_DFL; 831 832 if (loptind == argc) { 833 for (jp = joblst; jp; jp = jp->j_nxtp) { 834 if (jp->j_jid) 835 printjob(jp, propts); 836 } 837 } else do 838 printjob(str2job(cmd, argv[loptind++], 1), propts); 839 while (loptind < argc); 840 841 } 842 843 /* 844 * the builtin "fg" and "bg" commands 845 */ 846 void 847 sysfgbg(int argc, char *argv[]) 848 { 849 char *cmd = *argv; 850 int fg; 851 852 if ((flags & jcflg) == 0) 853 failed((unsigned char *)cmd, nojc); 854 855 fg = eq("fg", cmd); 856 857 if (*++argv == 0) { 858 struct job *jp; 859 for (jp = jobcur; ; jp = jp->j_curp) { 860 if (jp == 0) 861 failed((unsigned char *)cmd, nocurjob); 862 if (jp->j_jid) 863 break; 864 } 865 restartjob(jp, fg); 866 } else { 867 do { 868 restartjob(str2job(cmd, *argv, 1), fg); 869 } while (*++argv); 870 } 871 } 872 873 /* 874 * the builtin "wait" commands 875 */ 876 877 void 878 syswait(argc, argv) 879 int argc; 880 char *argv[]; 881 { 882 char *cmd = *argv; 883 struct job *jp; 884 int stat; 885 int wflags; 886 887 if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg)) 888 wflags = WUNTRACED; 889 else 890 wflags = 0; 891 892 if (argc == 1) 893 collectjobs(0); 894 else while (--argc) { 895 if ((jp = str2job(cmd, *++argv, 0)) == 0) 896 continue; 897 if (!(jp->j_flag & J_RUNNING)) 898 continue; 899 if (waitpid(jp->j_pid, &stat, wflags) <= 0) 900 break; 901 (void) statjob(jp, stat, 0, 1); 902 } 903 } 904 905 static void 906 sigv(char *cmd, int sig, char *args) 907 { 908 int pgrp = 0; 909 int stopme = 0; 910 pid_t id; 911 912 if (*args == '%') { 913 struct job *jp; 914 jp = str2job(cmd, args, 1); 915 id = jp->j_pgid; 916 pgrp++; 917 } else { 918 if (*args == '-') { 919 pgrp++; 920 args++; 921 } 922 id = 0; 923 do { 924 if (*args < '0' || *args > '9') { 925 failure(cmd, badid); 926 return; 927 } 928 id = (id * 10) + (*args - '0'); 929 } while (*++args); 930 if (id == 0) { 931 id = mypgid; 932 pgrp++; 933 } 934 } 935 936 if (sig == SIGSTOP) { 937 if (id == mysid || id == mypid && mypgid == mysid) { 938 failure(cmd, loginsh); 939 return; 940 } 941 if (id == mypgid && mypgid != svpgid) { 942 (void) settgid(svtgid, mypgid); 943 setpgid(0, svpgid); 944 stopme++; 945 } 946 } 947 948 if (pgrp) 949 id = -id; 950 951 if (kill(id, sig) < 0) { 952 953 switch (errno) { 954 case EPERM: 955 failure(cmd, eacces); 956 break; 957 958 case EINVAL: 959 failure(cmd, badsig); 960 break; 961 962 default: 963 if (pgrp) 964 failure(cmd, nosuchpgid); 965 else 966 failure(cmd, nosuchpid); 967 break; 968 } 969 970 } else if (sig == SIGTERM && pgrp) 971 (void) kill(id, SIGCONT); 972 973 if (stopme) { 974 setpgid(0, mypgid); 975 (void) settgid(mypgid, svpgid); 976 } 977 978 } 979 980 void 981 sysstop(int argc, char *argv[]) 982 { 983 char *cmd = *argv; 984 if (argc <= 1) { 985 gfailure(usage, stopuse); 986 return; 987 } 988 while (*++argv) 989 sigv(cmd, SIGSTOP, *argv); 990 } 991 992 void 993 syskill(int argc, char *argv[]) 994 { 995 char *cmd = *argv; 996 int sig = SIGTERM; 997 998 if (argc == 1) { 999 gfailure(usage, killuse); 1000 return; 1001 } 1002 1003 if (argv[1][0] == '-') { 1004 1005 if (argc == 2) { 1006 1007 int i; 1008 int cnt = 0; 1009 char sep = 0; 1010 char buf[12]; 1011 1012 if (!eq(argv[1], "-l")) { 1013 gfailure(usage, killuse); 1014 return; 1015 } 1016 1017 for (i = 1; i < MAXTRAP; i++) { 1018 if (sig2str(i, buf) < 0) 1019 continue; 1020 if (sep) 1021 prc_buff(sep); 1022 prs_buff(buf); 1023 if ((flags & ttyflg) && (++cnt % 10)) 1024 sep = TAB; 1025 else 1026 sep = NL; 1027 } 1028 prc_buff(NL); 1029 return; 1030 } 1031 1032 if (str2sig(&argv[1][1], &sig)) { 1033 failure(cmd, badsig); 1034 return; 1035 } 1036 argv++; 1037 } 1038 1039 while (*++argv) 1040 sigv(cmd, sig, *argv); 1041 1042 } 1043 1044 void 1045 syssusp(int argc, char *argv[]) 1046 { 1047 if (argc != 1) 1048 failed((unsigned char *)argv[0], badopt); 1049 sigv(argv[0], SIGSTOP, "0"); 1050 } 1051 1052 void 1053 hupforegnd(void) 1054 { 1055 struct job *jp; 1056 1057 (void) sighold(SIGCHLD); 1058 for (jp = joblst; jp != NULL; jp = jp->j_nxtp) { 1059 if (jp->j_flag & J_FOREGND) { 1060 (void) kill(jp->j_pid, SIGHUP); 1061 break; 1062 } 1063 } 1064 (void) sigrelse(SIGCHLD); 1065 } 1066