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