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 2007 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 #pragma ident "%Z%%M% %I% %E% SMI" 31 /* 32 * Job control for UNIX Shell 33 */ 34 35 #include <sys/termio.h> 36 #include <sys/types.h> 37 #include <sys/wait.h> 38 #include <sys/param.h> 39 #include <fcntl.h> 40 #include <errno.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 for (t = jobcur; t->j_curp != jp; t = t->j_curp); 417 t->j_curp = jp->j_curp; 418 jp->j_curp = jobcur; 419 jobcur = jp; 420 } 421 if (fg) { 422 if (jp->j_flag & J_SAVETTY) { 423 jp->j_stty.c_lflag &= ~TOSTOP; 424 jp->j_stty.c_lflag |= (mystty.c_lflag&TOSTOP); 425 jp->j_stty.c_cc[VSUSP] = mystty.c_cc[VSUSP]; 426 jp->j_stty.c_cc[VDSUSP] = mystty.c_cc[VDSUSP]; 427 (void) tcsetattr(0, TCSADRAIN, &jp->j_stty); 428 } 429 (void) settgid(jp->j_tgid, mypgid); 430 } 431 (void) kill(-(jp->j_pgid), SIGCONT); 432 if (jp->j_tgid != jp->j_pgid) 433 (void) kill(-(jp->j_tgid), SIGCONT); 434 jp->j_flag &= ~(J_STOPPED|J_SIGNALED|J_SAVETTY); 435 jp->j_flag |= J_RUNNING; 436 if (fg) { 437 jp->j_flag |= J_FOREGND; 438 printjob(jp, PR_JID|PR_CMD); 439 waitjob(jp); 440 } else { 441 jp->j_flag &= ~J_FOREGND; 442 printjob(jp, PR_JID|PR_CMD|PR_AMP); 443 } 444 } 445 446 static void 447 printjob(struct job *jp, int propts) 448 { 449 int sp = 0; 450 451 if (jp->j_flag & J_NOTIFY) { 452 jobnote--; 453 jp->j_flag &= ~J_NOTIFY; 454 } 455 456 if (propts & PR_JID) { 457 prc_buff('['); 458 prn_buff(jp->j_jid); 459 prc_buff(']'); 460 sp = 1; 461 } 462 463 if (propts & PR_CUR) { 464 while (sp-- > 0) 465 prc_buff(SPACE); 466 sp = 1; 467 if (jobcur == jp) 468 prc_buff('+'); 469 else if (jobcur != 0 && jobcur->j_curp == jp) 470 prc_buff('-'); 471 else 472 sp++; 473 } 474 475 if (propts & PR_PGID) { 476 while (sp-- > 0) 477 prc_buff(SPACE); 478 prn_buff(jp->j_pid); 479 sp = 1; 480 } 481 482 if (propts & PR_STAT) { 483 char *gmsg; 484 while (sp-- > 0) 485 prc_buff(SPACE); 486 sp = 28; 487 if (jp->j_flag & J_SIGNALED) { 488 char *sigstr, *strsignal(); 489 if ((sigstr = strsignal(jp->j_xval)) != NULL) { 490 sp -= strlen(sigstr); 491 prs_buff(sigstr); 492 } else { 493 itos(jp->j_xval); 494 gmsg = gettext(signalnum); 495 sp -= strlen(numbuf) + strlen(gmsg); 496 prs_buff((unsigned char *)gmsg); 497 prs_buff(numbuf); 498 } 499 if (jp->j_flag & J_DUMPED) { 500 gmsg = gettext(coredump); 501 sp -= strlen(gmsg); 502 prs_buff((unsigned char *)gmsg); 503 } 504 } else if (jp->j_flag & J_DONE) { 505 itos(jp->j_xval); 506 gmsg = gettext(exited); 507 sp -= strlen(gmsg) + strlen(numbuf) + 2; 508 prs_buff((unsigned char *)gmsg); 509 prc_buff('('); 510 itos(jp->j_xval); 511 prs_buff(numbuf); 512 prc_buff(')'); 513 } else { 514 gmsg = gettext(running); 515 sp -= strlen(gmsg); 516 prs_buff((unsigned char *)gmsg); 517 } 518 if (sp < 1) 519 sp = 1; 520 } 521 522 if (propts & PR_CMD) { 523 while (sp-- > 0) 524 prc_buff(SPACE); 525 prs_buff(jp->j_cmd); 526 sp = 1; 527 } 528 529 if (propts & PR_AMP) { 530 while (sp-- > 0) 531 prc_buff(SPACE); 532 prc_buff('&'); 533 sp = 1; 534 } 535 536 if (propts & PR_PWD) { 537 while (sp-- > 0) 538 prc_buff(SPACE); 539 prs_buff("(wd: "); 540 prs_buff(jp->j_pwd); 541 prc_buff(')'); 542 } 543 544 prc_buff(NL); 545 flushb(); 546 547 } 548 549 550 /* 551 * called to initialize job control for each new input file to the shell, 552 * and after the "exec" builtin 553 */ 554 555 void 556 startjobs() 557 { 558 svpgid = mypgid; 559 560 if (tcgetattr(0, &mystty) == -1 || (svtgid = tcgetpgrp(0)) == -1) { 561 flags &= ~jcflg; 562 return; 563 } 564 565 flags |= jcflg; 566 567 handle(SIGTTOU, SIG_IGN); 568 handle(SIGTSTP, SIG_DFL); 569 570 if (mysid != mypgid) { 571 setpgid(0, 0); 572 mypgid = mypid; 573 (void) settgid(mypgid, svpgid); 574 } 575 576 } 577 578 int 579 endjobs(check_if) 580 int check_if; 581 { 582 if ((flags & (jcoff|jcflg)) != jcflg) 583 return (1); 584 585 if (check_if && jobcnt && eofflg++ == 0) { 586 struct job *jp; 587 if (check_if & JOB_STOPPED) { 588 for (jp = joblst; jp; jp = jp->j_nxtp) { 589 if (jp->j_jid && (jp->j_flag & J_STOPPED)) { 590 prs(_gettext(jobsstopped)); 591 prc(NL); 592 return (0); 593 } 594 } 595 } 596 if (check_if & JOB_RUNNING) { 597 for (jp = joblst; jp; jp = jp->j_nxtp) { 598 if (jp->j_jid && (jp->j_flag & J_RUNNING)) { 599 prs(_gettext(jobsrunning)); 600 prc(NL); 601 return (0); 602 } 603 } 604 } 605 } 606 607 if (svpgid != mypgid) { 608 (void) settgid(svtgid, mypgid); 609 setpgid(0, svpgid); 610 } 611 612 return (1); 613 } 614 615 616 /* 617 * called by the shell to reserve a job slot for a job about to be spawned 618 */ 619 620 void 621 deallocjob() 622 { 623 free(thisjob); 624 jobcnt--; 625 } 626 627 void 628 allocjob(char *cmd, uchar_t *cwd, int monitor) 629 { 630 struct job *jp, **jpp; 631 int jid, cmdlen, cwdlen; 632 633 cmdlen = strlen(cmd) + 1; 634 if (cmd[cmdlen-2] == '&') { 635 cmd[cmdlen-3] = 0; 636 cmdlen -= 2; 637 } 638 cwdlen = strlen(cwd) + 1; 639 jp = (struct job *) alloc(sizeof (struct job) + cmdlen + cwdlen); 640 if (jp == 0) 641 error(nostack); 642 jobcnt++; 643 jp->j_cmd = ((char *)jp) + sizeof (struct job); 644 strcpy(jp->j_cmd, cmd); 645 jp->j_pwd = jp->j_cmd + cmdlen; 646 strcpy(jp->j_pwd, cwd); 647 648 jpp = &joblst; 649 650 if (monitor) { 651 for (; *jpp; jpp = &(*jpp)->j_nxtp) 652 if ((*jpp)->j_jid != 0) 653 break; 654 for (jid = 1; *jpp; jpp = &(*jpp)->j_nxtp, jid++) 655 if ((*jpp)->j_jid != jid) 656 break; 657 } else 658 jid = 0; 659 660 jp->j_jid = jid; 661 nextjob = jpp; 662 thisjob = jp; 663 } 664 665 void 666 clearjobs(void) 667 { 668 struct job *jp, *sjp; 669 670 for (jp = joblst; jp; jp = sjp) { 671 sjp = jp->j_nxtp; 672 free(jp); 673 } 674 joblst = NULL; 675 jobcnt = 0; 676 jobnote = 0; 677 jobdone = 0; 678 679 } 680 681 void 682 makejob(int monitor, int fg) 683 { 684 if (monitor) { 685 mypgid = mypid; 686 setpgid(0, 0); 687 if (fg) 688 tcsetpgrp(0, mypid); 689 handle(SIGTTOU, SIG_DFL); 690 handle(SIGTSTP, SIG_DFL); 691 } else if (!fg) { 692 #ifdef NICE 693 nice(NICE); 694 #endif 695 handle(SIGTTIN, SIG_IGN); 696 handle(SIGINT, SIG_IGN); 697 handle(SIGQUIT, SIG_IGN); 698 if (!ioset) 699 renamef(chkopen(devnull, 0), 0); 700 } 701 } 702 703 /* 704 * called by the shell after job has been spawned, to fill in the 705 * job slot, and wait for the job if in the foreground 706 */ 707 708 void 709 postjob(pid, fg) 710 pid_t pid; 711 int fg; 712 { 713 714 int propts; 715 716 thisjob->j_nxtp = *nextjob; 717 *nextjob = thisjob; 718 thisjob->j_curp = jobcur; 719 jobcur = thisjob; 720 721 if (thisjob->j_jid) { 722 thisjob->j_pgid = pid; 723 propts = PR_JID|PR_PGID; 724 } else { 725 thisjob->j_pgid = mypgid; 726 propts = PR_PGID; 727 } 728 729 thisjob->j_flag = J_RUNNING; 730 thisjob->j_tgid = thisjob->j_pgid; 731 thisjob->j_pid = pid; 732 eofflg = 0; 733 734 if (fg) { 735 thisjob->j_flag |= J_FOREGND; 736 waitjob(thisjob); 737 } else { 738 if (flags & ttyflg) 739 printjob(thisjob, propts); 740 assnum(&pcsadr, (long)pid); 741 } 742 } 743 744 /* 745 * the builtin "jobs" command 746 */ 747 748 void 749 sysjobs(argc, argv) 750 int argc; 751 char *argv[]; 752 { 753 char *cmd = *argv; 754 struct job *jp; 755 int propts, c; 756 extern int opterr, i; 757 int savoptind = optind; 758 int loptind = -1; 759 int savopterr = opterr; 760 int savsp = _sp; 761 char *savoptarg = optarg; 762 optind = 1; 763 opterr = 0; 764 _sp = 1; 765 propts = 0; 766 767 if ((flags & jcflg) == 0) 768 failed((unsigned char *)cmd, nojc); 769 770 while ((c = getopt(argc, argv, "lpx")) != -1) { 771 if (propts) { 772 gfailure(usage, jobsuse); 773 goto err; 774 } 775 switch (c) { 776 case 'x': 777 propts = -1; 778 break; 779 case 'p': 780 propts = PR_PGID; 781 break; 782 case 'l': 783 propts = PR_LONG; 784 break; 785 case '?': 786 gfailure(usage, jobsuse); 787 goto err; 788 } 789 } 790 791 loptind = optind; 792 err: 793 optind = savoptind; 794 optarg = savoptarg; 795 opterr = savopterr; 796 _sp = savsp; 797 if (loptind == -1) 798 return; 799 800 if (propts == -1) { 801 unsigned char *bp; 802 char *cp; 803 unsigned char *savebp; 804 for (savebp = bp = locstak(); loptind < argc; loptind++) { 805 cp = argv[loptind]; 806 if (*cp == '%') { 807 jp = str2job(cmd, cp, 1); 808 itos(jp->j_pid); 809 cp = (char *)numbuf; 810 } 811 while (*cp) { 812 if (bp >= brkend) 813 growstak(bp); 814 *bp++ = *cp++; 815 } 816 if (bp >= brkend) 817 growstak(bp); 818 *bp++ = SPACE; 819 } 820 endstak(bp); 821 execexp(savebp, 0); 822 return; 823 } 824 825 collectjobs(WNOHANG); 826 827 if (propts == 0) 828 propts = PR_DFL; 829 830 if (loptind == argc) { 831 for (jp = joblst; jp; jp = jp->j_nxtp) { 832 if (jp->j_jid) 833 printjob(jp, propts); 834 } 835 } else do 836 printjob(str2job(cmd, argv[loptind++], 1), propts); 837 while (loptind < argc); 838 839 } 840 841 /* 842 * the builtin "fg" and "bg" commands 843 */ 844 void 845 sysfgbg(int argc, char *argv[]) 846 { 847 char *cmd = *argv; 848 int fg; 849 850 if ((flags & jcflg) == 0) 851 failed((unsigned char *)cmd, nojc); 852 853 fg = eq("fg", cmd); 854 855 if (*++argv == 0) { 856 struct job *jp; 857 for (jp = jobcur; ; jp = jp->j_curp) { 858 if (jp == 0) 859 failed((unsigned char *)cmd, nocurjob); 860 if (jp->j_jid) 861 break; 862 } 863 restartjob(jp, fg); 864 } 865 866 else do 867 restartjob(str2job(cmd, *argv, 1), fg); 868 while (*++argv); 869 870 } 871 872 /* 873 * the builtin "wait" commands 874 */ 875 876 void 877 syswait(argc, argv) 878 int argc; 879 char *argv[]; 880 { 881 char *cmd = *argv; 882 struct job *jp; 883 int stat; 884 int wflags; 885 886 if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg)) 887 wflags = WUNTRACED; 888 else 889 wflags = 0; 890 891 if (argc == 1) 892 collectjobs(0); 893 else while (--argc) { 894 if ((jp = str2job(cmd, *++argv, 0)) == 0) 895 continue; 896 if (!(jp->j_flag & J_RUNNING)) 897 continue; 898 if (waitpid(jp->j_pid, &stat, wflags) <= 0) 899 break; 900 (void) statjob(jp, stat, 0, 1); 901 } 902 } 903 904 static void 905 sigv(char *cmd, int sig, char *args) 906 { 907 int pgrp = 0; 908 int stopme = 0; 909 pid_t id; 910 911 if (*args == '%') { 912 struct job *jp; 913 jp = str2job(cmd, args, 1); 914 id = jp->j_pgid; 915 pgrp++; 916 } else { 917 if (*args == '-') { 918 pgrp++; 919 args++; 920 } 921 id = 0; 922 do { 923 if (*args < '0' || *args > '9') { 924 failure(cmd, badid); 925 return; 926 } 927 id = (id * 10) + (*args - '0'); 928 } while (*++args); 929 if (id == 0) { 930 id = mypgid; 931 pgrp++; 932 } 933 } 934 935 if (sig == SIGSTOP) { 936 if (id == mysid || id == mypid && mypgid == mysid) { 937 failure(cmd, loginsh); 938 return; 939 } 940 if (id == mypgid && mypgid != svpgid) { 941 (void) settgid(svtgid, mypgid); 942 setpgid(0, svpgid); 943 stopme++; 944 } 945 } 946 947 if (pgrp) 948 id = -id; 949 950 if (kill(id, sig) < 0) { 951 952 switch (errno) { 953 case EPERM: 954 failure(cmd, eacces); 955 break; 956 957 case EINVAL: 958 failure(cmd, badsig); 959 break; 960 961 default: 962 if (pgrp) 963 failure(cmd, nosuchpgid); 964 else 965 failure(cmd, nosuchpid); 966 break; 967 } 968 969 } else if (sig == SIGTERM && pgrp) 970 (void) kill(id, SIGCONT); 971 972 if (stopme) { 973 setpgid(0, mypgid); 974 (void) settgid(mypgid, svpgid); 975 } 976 977 } 978 979 void 980 sysstop(int argc, char *argv[]) 981 { 982 char *cmd = *argv; 983 if (argc <= 1) { 984 gfailure(usage, stopuse); 985 return; 986 } 987 while (*++argv) 988 sigv(cmd, SIGSTOP, *argv); 989 } 990 991 void 992 syskill(int argc, char *argv[]) 993 { 994 char *cmd = *argv; 995 int sig = SIGTERM; 996 997 if (argc == 1) { 998 gfailure(usage, killuse); 999 return; 1000 } 1001 1002 if (argv[1][0] == '-') { 1003 1004 if (argc == 2) { 1005 1006 int i; 1007 int cnt = 0; 1008 char sep = 0; 1009 char buf[12]; 1010 1011 if (!eq(argv[1], "-l")) { 1012 gfailure(usage, killuse); 1013 return; 1014 } 1015 1016 for (i = 1; i < MAXTRAP; i++) { 1017 if (sig2str(i, buf) < 0) 1018 continue; 1019 if (sep) 1020 prc_buff(sep); 1021 prs_buff(buf); 1022 if ((flags & ttyflg) && (++cnt % 10)) 1023 sep = TAB; 1024 else 1025 sep = NL; 1026 } 1027 prc_buff(NL); 1028 return; 1029 } 1030 1031 if (str2sig(&argv[1][1], &sig)) { 1032 failure(cmd, badsig); 1033 return; 1034 } 1035 argv++; 1036 } 1037 1038 while (*++argv) 1039 sigv(cmd, sig, *argv); 1040 1041 } 1042 1043 void 1044 syssusp(int argc, char *argv[]) 1045 { 1046 if (argc != 1) 1047 failed((unsigned char *)argv[0], badopt); 1048 sigv(argv[0], SIGSTOP, "0"); 1049 } 1050