1 /* $NetBSD: proc.c,v 1.42 2021/09/16 19:34:21 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1980, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)proc.c 8.1 (Berkeley) 5/31/93"; 36 #else 37 __RCSID("$NetBSD: proc.c,v 1.42 2021/09/16 19:34:21 christos Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/types.h> 42 #include <sys/wait.h> 43 44 #include <errno.h> 45 #include <stdarg.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 50 #include "csh.h" 51 #include "dir.h" 52 #include "extern.h" 53 #include "proc.h" 54 55 #define BIGINDEX 9 /* largest desirable job index */ 56 57 extern int insource; 58 59 struct process proclist; 60 int pnoprocesses; 61 62 struct process *pholdjob; 63 64 struct process *pcurrjob; 65 struct process *pcurrent; 66 struct process *pprevious; 67 68 int pmaxindex; 69 70 static void pflushall(void); 71 static void pflush(struct process *); 72 static void pclrcurr(struct process *); 73 static void padd(struct command *); 74 static int pprint(struct process *, int); 75 static void ptprint(struct process *); 76 static void pads(Char *); 77 static void pkill(Char **v, int); 78 static struct process *pgetcurr(struct process *); 79 static void okpcntl(void); 80 81 /* 82 * pchild - called at interrupt level by the SIGCHLD signal 83 * indicating that at least one child has terminated or stopped 84 * thus at least one wait system call will definitely return a 85 * childs status. Top level routines (like pwait) must be sure 86 * to mask interrupts when playing with the proclist data structures! 87 */ 88 /* ARGSUSED */ 89 void 90 pchild(int notused) 91 { 92 struct rusage ru; 93 struct process *fp, *pp; 94 int jobflags, pid, w; 95 96 loop: 97 errno = 0; /* reset, just in case */ 98 pid = wait3(&w, 99 (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 100 101 if (pid <= 0) { 102 if (errno == EINTR) { 103 errno = 0; 104 goto loop; 105 } 106 pnoprocesses = pid == -1; 107 return; 108 } 109 for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 110 if (pid == pp->p_pid) 111 goto found; 112 goto loop; 113 found: 114 if (pid == atoi(short2str(value(STRchild)))) 115 unsetv(STRchild); 116 pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED); 117 if (WIFSTOPPED(w)) { 118 pp->p_flags |= PSTOPPED; 119 pp->p_reason = WSTOPSIG(w); 120 } 121 else { 122 if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime)) 123 (void)clock_gettime(CLOCK_MONOTONIC, &pp->p_etime); 124 125 pp->p_rusage = ru; 126 if (WIFSIGNALED(w)) { 127 if (WTERMSIG(w) == SIGINT) 128 pp->p_flags |= PINTERRUPTED; 129 else 130 pp->p_flags |= PSIGNALED; 131 if (WCOREDUMP(w)) 132 pp->p_flags |= PDUMPED; 133 pp->p_reason = WTERMSIG(w); 134 } 135 else { 136 pp->p_reason = WEXITSTATUS(w); 137 if (pp->p_reason != 0) 138 pp->p_flags |= PAEXITED; 139 else 140 pp->p_flags |= PNEXITED; 141 } 142 } 143 jobflags = 0; 144 fp = pp; 145 do { 146 if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 && 147 !child && adrof(STRtime) && 148 fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec 149 >= atoi(short2str(value(STRtime)))) 150 fp->p_flags |= PTIME; 151 jobflags |= fp->p_flags; 152 } while ((fp = fp->p_friends) != pp); 153 pp->p_flags &= ~PFOREGND; 154 if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 155 pp->p_flags &= ~PPTIME; 156 pp->p_flags |= PTIME; 157 } 158 if ((jobflags & (PRUNNING | PREPORTED)) == 0) { 159 fp = pp; 160 do { 161 if (fp->p_flags & PSTOPPED) 162 fp->p_flags |= PREPORTED; 163 } while ((fp = fp->p_friends) != pp); 164 while (fp->p_pid != fp->p_jobid) 165 fp = fp->p_friends; 166 if (jobflags & PSTOPPED) { 167 if (pcurrent && pcurrent != fp) 168 pprevious = pcurrent; 169 pcurrent = fp; 170 } 171 else 172 pclrcurr(fp); 173 if (jobflags & PFOREGND) { 174 if (jobflags & (PSIGNALED | PSTOPPED | PPTIME) || 175 #ifdef IIASA 176 jobflags & PAEXITED || 177 #endif 178 !eq(dcwd->di_name, fp->p_cwd->di_name)) { 179 ; /* print in pjwait */ 180 } 181 /* PWP: print a newline after ^C */ 182 else if (jobflags & PINTERRUPTED) { 183 (void)vis_fputc('\r' | QUOTE, cshout); 184 (void)fputc('\n', cshout); 185 } 186 } 187 else { 188 if (jobflags & PNOTIFY || adrof(STRnotify)) { 189 (void)vis_fputc('\r' | QUOTE, cshout); 190 (void)fputc('\n', cshout); 191 (void)pprint(pp, NUMBER | NAME | REASON); 192 if ((jobflags & PSTOPPED) == 0) 193 pflush(pp); 194 } 195 else { 196 fp->p_flags |= PNEEDNOTE; 197 neednote++; 198 } 199 } 200 } 201 goto loop; 202 } 203 204 void 205 pnote(void) 206 { 207 struct process *pp; 208 sigset_t osigset, nsigset; 209 int flags; 210 211 neednote = 0; 212 sigemptyset(&nsigset); 213 (void)sigaddset(&nsigset, SIGCHLD); 214 for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) { 215 if (pp->p_flags & PNEEDNOTE) { 216 (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); 217 pp->p_flags &= ~PNEEDNOTE; 218 flags = pprint(pp, NUMBER | NAME | REASON); 219 if ((flags & (PRUNNING | PSTOPPED)) == 0) 220 pflush(pp); 221 (void)sigprocmask(SIG_SETMASK, &osigset, NULL); 222 } 223 } 224 } 225 226 /* 227 * pwait - wait for current job to terminate, maintaining integrity 228 * of current and previous job indicators. 229 */ 230 void 231 pwait(void) 232 { 233 struct process *fp, *pp; 234 sigset_t osigset, nsigset; 235 236 /* 237 * Here's where dead procs get flushed. 238 */ 239 sigemptyset(&nsigset); 240 (void)sigaddset(&nsigset, SIGCHLD); 241 (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); 242 for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next) 243 if (pp->p_pid == 0) { 244 fp->p_next = pp->p_next; 245 free(pp->p_command); 246 if (pp->p_cwd && --pp->p_cwd->di_count == 0) 247 if (pp->p_cwd->di_next == 0) 248 dfree(pp->p_cwd); 249 free(pp); 250 pp = fp; 251 } 252 (void)sigprocmask(SIG_SETMASK, &osigset, NULL); 253 pjwait(pcurrjob); 254 } 255 256 257 /* 258 * pjwait - wait for a job to finish or become stopped 259 * It is assumed to be in the foreground state (PFOREGND) 260 */ 261 void 262 pjwait(struct process *pp) 263 { 264 struct process *fp; 265 sigset_t osigset, nsigset; 266 int jobflags, reason; 267 268 while (pp->p_pid != pp->p_jobid) 269 pp = pp->p_friends; 270 fp = pp; 271 272 do { 273 if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING) 274 (void)fprintf(csherr, "BUG: waiting for background job!\n"); 275 } while ((fp = fp->p_friends) != pp); 276 /* 277 * Now keep pausing as long as we are not interrupted (SIGINT), and the 278 * target process, or any of its friends, are running 279 */ 280 fp = pp; 281 sigemptyset(&nsigset); 282 (void)sigaddset(&nsigset, SIGCHLD); 283 (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); 284 for (;;) { 285 sigemptyset(&nsigset); 286 (void)sigaddset(&nsigset, SIGCHLD); 287 (void)sigprocmask(SIG_BLOCK, &nsigset, NULL); 288 jobflags = 0; 289 do 290 jobflags |= fp->p_flags; 291 while ((fp = (fp->p_friends)) != pp); 292 if ((jobflags & PRUNNING) == 0) 293 break; 294 #ifdef JOBDEBUG 295 (void)fprintf(csherr, "starting to sigsuspend for SIGCHLD on %d\n", 296 fp->p_pid); 297 #endif /* JOBDEBUG */ 298 nsigset = osigset; 299 (void)sigdelset(&nsigset, SIGCHLD); 300 (void)sigsuspend(&nsigset); 301 } 302 (void)sigprocmask(SIG_SETMASK, &osigset, NULL); 303 if (tpgrp > 0) /* get tty back */ 304 (void)tcsetpgrp(FSHTTY, tpgrp); 305 if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) || 306 !eq(dcwd->di_name, fp->p_cwd->di_name)) { 307 if (jobflags & PSTOPPED) { 308 (void) fputc('\n', cshout); 309 if (adrof(STRlistjobs)) { 310 Char *jobcommand[3]; 311 312 jobcommand[0] = STRjobs; 313 if (eq(value(STRlistjobs), STRlong)) 314 jobcommand[1] = STRml; 315 else 316 jobcommand[1] = NULL; 317 jobcommand[2] = NULL; 318 319 dojobs(jobcommand, NULL); 320 (void)pprint(pp, SHELLDIR); 321 } 322 else 323 (void)pprint(pp, AREASON | SHELLDIR); 324 } 325 else 326 (void)pprint(pp, AREASON | SHELLDIR); 327 } 328 if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr && 329 (!gointr || !eq(gointr, STRminus))) { 330 if ((jobflags & PSTOPPED) == 0) 331 pflush(pp); 332 pintr1(0); 333 } 334 reason = 0; 335 fp = pp; 336 do { 337 if (fp->p_reason) 338 reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ? 339 fp->p_reason | META : fp->p_reason; 340 } while ((fp = fp->p_friends) != pp); 341 if ((reason != 0) && (adrof(STRprintexitvalue))) { 342 (void)fprintf(cshout, "Exit %d\n", reason); 343 } 344 set(STRstatus, putn(reason)); 345 if (reason && exiterr) 346 exitstat(); 347 pflush(pp); 348 } 349 350 /* 351 * dowait - wait for all processes to finish 352 */ 353 void 354 /*ARGSUSED*/ 355 dowait(Char **v, struct command *t) 356 { 357 struct process *pp; 358 sigset_t osigset, nsigset; 359 360 pjobs++; 361 sigemptyset(&nsigset); 362 (void)sigaddset(&nsigset, SIGCHLD); 363 (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); 364 loop: 365 for (pp = proclist.p_next; pp; pp = pp->p_next) 366 if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */ 367 pp->p_flags & PRUNNING) { 368 sigemptyset(&nsigset); 369 (void)sigsuspend(&nsigset); 370 goto loop; 371 } 372 (void)sigprocmask(SIG_SETMASK, &osigset, NULL); 373 pjobs = 0; 374 } 375 376 /* 377 * pflushall - flush all jobs from list (e.g. at fork()) 378 */ 379 static void 380 pflushall(void) 381 { 382 struct process *pp; 383 384 for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 385 if (pp->p_pid) 386 pflush(pp); 387 } 388 389 /* 390 * pflush - flag all process structures in the same job as the 391 * the argument process for deletion. The actual free of the 392 * space is not done here since pflush is called at interrupt level. 393 */ 394 static void 395 pflush(struct process *pp) 396 { 397 struct process *np; 398 int idx; 399 400 if (pp->p_pid == 0) { 401 (void)fprintf(csherr, "BUG: process flushed twice"); 402 return; 403 } 404 while (pp->p_pid != pp->p_jobid) 405 pp = pp->p_friends; 406 pclrcurr(pp); 407 if (pp == pcurrjob) 408 pcurrjob = 0; 409 idx = pp->p_index; 410 np = pp; 411 do { 412 np->p_index = np->p_pid = 0; 413 np->p_flags &= ~PNEEDNOTE; 414 } while ((np = np->p_friends) != pp); 415 if (idx == pmaxindex) { 416 for (np = proclist.p_next, idx = 0; np; np = np->p_next) 417 if (np->p_index > idx) 418 idx = np->p_index; 419 pmaxindex = idx; 420 } 421 } 422 423 /* 424 * pclrcurr - make sure the given job is not the current or previous job; 425 * pp MUST be the job leader 426 */ 427 static void 428 pclrcurr(struct process *pp) 429 { 430 if (pp == pcurrent) { 431 if (pprevious != NULL) { 432 pcurrent = pprevious; 433 pprevious = pgetcurr(pp); 434 } 435 else { 436 pcurrent = pgetcurr(pp); 437 pprevious = pgetcurr(pp); 438 } 439 } else if (pp == pprevious) 440 pprevious = pgetcurr(pp); 441 } 442 443 /* +4 here is 1 for '\0', 1 ea for << >& >> */ 444 static Char command[PMAXLEN + 4]; 445 static size_t cmdlen; 446 static Char *cmdp; 447 448 /* 449 * palloc - allocate a process structure and fill it up. 450 * an important assumption is made that the process is running. 451 */ 452 void 453 palloc(int pid, struct command *t) 454 { 455 struct process *pp; 456 int i; 457 458 pp = xcalloc(1, sizeof(*pp)); 459 pp->p_pid = pid; 460 pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND; 461 if (t->t_dflg & F_TIME) 462 pp->p_flags |= PPTIME; 463 cmdp = command; 464 cmdlen = 0; 465 padd(t); 466 *cmdp++ = 0; 467 if (t->t_dflg & F_PIPEOUT) { 468 pp->p_flags |= PPOU; 469 if (t->t_dflg & F_STDERR) 470 pp->p_flags |= PERR; 471 } 472 pp->p_command = Strsave(command); 473 if (pcurrjob) { 474 struct process *fp; 475 476 /* careful here with interrupt level */ 477 pp->p_cwd = 0; 478 pp->p_index = pcurrjob->p_index; 479 pp->p_friends = pcurrjob; 480 pp->p_jobid = pcurrjob->p_pid; 481 for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends) 482 continue; 483 fp->p_friends = pp; 484 } 485 else { 486 pcurrjob = pp; 487 pp->p_jobid = pid; 488 pp->p_friends = pp; 489 pp->p_cwd = dcwd; 490 dcwd->di_count++; 491 if (pmaxindex < BIGINDEX) 492 pp->p_index = ++pmaxindex; 493 else { 494 struct process *np; 495 496 for (i = 1;; i++) { 497 for (np = proclist.p_next; np; np = np->p_next) 498 if (np->p_index == i) 499 goto tryagain; 500 pp->p_index = i; 501 if (i > pmaxindex) 502 pmaxindex = i; 503 break; 504 tryagain:; 505 } 506 } 507 if (pcurrent == NULL) 508 pcurrent = pp; 509 else if (pprevious == NULL) 510 pprevious = pp; 511 } 512 pp->p_next = proclist.p_next; 513 proclist.p_next = pp; 514 (void)clock_gettime(CLOCK_MONOTONIC, &pp->p_btime); 515 } 516 517 static void 518 padd(struct command *t) 519 { 520 Char **argp; 521 522 if (t == 0) 523 return; 524 switch (t->t_dtyp) { 525 case NODE_PAREN: 526 pads(STRLparensp); 527 padd(t->t_dspr); 528 pads(STRspRparen); 529 break; 530 case NODE_COMMAND: 531 for (argp = t->t_dcom; *argp; argp++) { 532 pads(*argp); 533 if (argp[1]) 534 pads(STRspace); 535 } 536 break; 537 case NODE_OR: 538 case NODE_AND: 539 case NODE_PIPE: 540 case NODE_LIST: 541 padd(t->t_dcar); 542 switch (t->t_dtyp) { 543 case NODE_OR: 544 pads(STRspor2sp); 545 break; 546 case NODE_AND: 547 pads(STRspand2sp); 548 break; 549 case NODE_PIPE: 550 pads(STRsporsp); 551 break; 552 case NODE_LIST: 553 pads(STRsemisp); 554 break; 555 } 556 padd(t->t_dcdr); 557 return; 558 } 559 if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) { 560 pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp); 561 pads(t->t_dlef); 562 } 563 if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) { 564 pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow); 565 if (t->t_dflg & F_STDERR) 566 pads(STRand); 567 pads(STRspace); 568 pads(t->t_drit); 569 } 570 } 571 572 static void 573 pads(Char *cp) 574 { 575 size_t i; 576 577 /* 578 * Avoid the Quoted Space alias hack! Reported by: 579 * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks) 580 */ 581 if (cp[0] == STRQNULL[0]) 582 cp++; 583 584 i = Strlen(cp); 585 586 if (cmdlen >= PMAXLEN) 587 return; 588 if (cmdlen + i >= PMAXLEN) { 589 (void)Strcpy(cmdp, STRsp3dots); 590 cmdlen = PMAXLEN; 591 cmdp += 4; 592 return; 593 } 594 (void)Strcpy(cmdp, cp); 595 cmdp += i; 596 cmdlen += i; 597 } 598 599 /* 600 * psavejob - temporarily save the current job on a one level stack 601 * so another job can be created. Used for { } in exp6 602 * and `` in globbing. 603 */ 604 void 605 psavejob(void) 606 { 607 pholdjob = pcurrjob; 608 pcurrjob = NULL; 609 } 610 611 /* 612 * prestjob - opposite of psavejob. This may be missed if we are interrupted 613 * somewhere, but pendjob cleans up anyway. 614 */ 615 void 616 prestjob(void) 617 { 618 pcurrjob = pholdjob; 619 pholdjob = NULL; 620 } 621 622 /* 623 * pendjob - indicate that a job (set of commands) has been completed 624 * or is about to begin. 625 */ 626 void 627 pendjob(void) 628 { 629 struct process *pp, *tp; 630 631 if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) { 632 pp = pcurrjob; 633 while (pp->p_pid != pp->p_jobid) 634 pp = pp->p_friends; 635 (void)fprintf(cshout, "[%d]", pp->p_index); 636 tp = pp; 637 do { 638 (void)fprintf(cshout, " %ld", (long)pp->p_pid); 639 pp = pp->p_friends; 640 } while (pp != tp); 641 (void)fputc('\n', cshout); 642 } 643 pholdjob = pcurrjob = 0; 644 } 645 646 /* 647 * pprint - print a job 648 */ 649 static int 650 pprint(struct process *pp, int flag) 651 { 652 static struct rusage zru; 653 struct process *tp; 654 const char *format; 655 int jobflags, pstatus, reason, status; 656 int hadnl; 657 658 hadnl = 1; /* did we just have a newline */ 659 (void)fpurge(cshout); 660 661 while (pp->p_pid != pp->p_jobid) 662 pp = pp->p_friends; 663 if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 664 pp->p_flags &= ~PPTIME; 665 pp->p_flags |= PTIME; 666 } 667 tp = pp; 668 status = reason = -1; 669 jobflags = 0; 670 do { 671 jobflags |= pp->p_flags; 672 pstatus = pp->p_flags & PALLSTATES; 673 if (tp != pp && !hadnl && !(flag & FANCY) && 674 ((pstatus == status && pp->p_reason == reason) || 675 !(flag & REASON))) { 676 (void)fputc(' ', cshout); 677 hadnl = 0; 678 } 679 else { 680 if (tp != pp && !hadnl) { 681 (void)fputc('\n', cshout); 682 hadnl = 1; 683 } 684 if (flag & NUMBER) { 685 if (pp == tp) 686 (void)fprintf(cshout, "[%d]%s %c ", pp->p_index, 687 pp->p_index < 10 ? " " : "", 688 pp == pcurrent ? '+' : 689 (pp == pprevious ? '-' : ' ')); 690 else 691 (void)fprintf(cshout, " "); 692 hadnl = 0; 693 } 694 if (flag & FANCY) { 695 (void)fprintf(cshout, "%5ld ", (long)pp->p_pid); 696 hadnl = 0; 697 } 698 if (flag & (REASON | AREASON)) { 699 if (flag & NAME) 700 format = "%-23s"; 701 else 702 format = "%s"; 703 if (pstatus == status) { 704 if (pp->p_reason == reason) { 705 (void)fprintf(cshout, format, ""); 706 hadnl = 0; 707 goto prcomd; 708 } 709 else 710 reason = pp->p_reason; 711 } else { 712 status = pstatus; 713 reason = pp->p_reason; 714 } 715 switch (status) { 716 case PRUNNING: 717 (void)fprintf(cshout, format, "Running "); 718 hadnl = 0; 719 break; 720 case PINTERRUPTED: 721 case PSTOPPED: 722 case PSIGNALED: 723 /* 724 * tell what happened to the background job 725 * From: Michael Schroeder 726 * <mlschroe@immd4.informatik.uni-erlangen.de> 727 */ 728 if ((flag & REASON) 729 || ((flag & AREASON) 730 && reason != SIGINT 731 && (reason != SIGPIPE 732 || (pp->p_flags & PPOU) == 0))) { 733 (void)fprintf(cshout, format, 734 sys_siglist[(unsigned char) 735 pp->p_reason]); 736 hadnl = 0; 737 } 738 break; 739 case PNEXITED: 740 case PAEXITED: 741 if (flag & REASON) { 742 if (pp->p_reason) 743 (void)fprintf(cshout, "Exit %-18d", pp->p_reason); 744 else 745 (void)fprintf(cshout, format, "Done"); 746 hadnl = 0; 747 } 748 break; 749 default: 750 (void)fprintf(csherr, "BUG: status=%-9o", status); 751 } 752 } 753 } 754 prcomd: 755 if (flag & NAME) { 756 (void)fprintf(cshout, "%s", vis_str(pp->p_command)); 757 if (pp->p_flags & PPOU) 758 (void)fprintf(cshout, " |"); 759 if (pp->p_flags & PERR) 760 (void)fputc('&', cshout); 761 hadnl = 0; 762 } 763 if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) { 764 (void)fprintf(cshout, " (core dumped)"); 765 hadnl = 0; 766 } 767 if (tp == pp->p_friends) { 768 if (flag & AMPERSAND) { 769 (void)fprintf(cshout, " &"); 770 hadnl = 0; 771 } 772 if (flag & JOBDIR && 773 !eq(tp->p_cwd->di_name, dcwd->di_name)) { 774 (void)fprintf(cshout, " (wd: "); 775 dtildepr(value(STRhome), tp->p_cwd->di_name); 776 (void)fputc(')', cshout); 777 hadnl = 0; 778 } 779 } 780 if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) { 781 if (!hadnl) 782 (void)fprintf(cshout, "\n\t"); 783 prusage(cshout, &zru, &pp->p_rusage, &pp->p_etime, 784 &pp->p_btime); 785 hadnl = 1; 786 } 787 if (tp == pp->p_friends) { 788 if (!hadnl) { 789 (void)fputc('\n', cshout); 790 hadnl = 1; 791 } 792 if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { 793 (void)fprintf(cshout, "(wd now: "); 794 dtildepr(value(STRhome), dcwd->di_name); 795 (void)fprintf(cshout, ")\n"); 796 hadnl = 1; 797 } 798 } 799 } while ((pp = pp->p_friends) != tp); 800 if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) { 801 if (jobflags & NUMBER) 802 (void)fprintf(cshout, " "); 803 ptprint(tp); 804 hadnl = 1; 805 } 806 (void)fflush(cshout); 807 return (jobflags); 808 } 809 810 static void 811 ptprint(struct process *tp) 812 { 813 static struct rusage zru; 814 static struct timespec ztime; 815 struct rusage ru; 816 struct timespec tetime, diff; 817 struct process *pp; 818 819 pp = tp; 820 ru = zru; 821 tetime = ztime; 822 do { 823 ruadd(&ru, &pp->p_rusage); 824 timespecsub(&pp->p_etime, &pp->p_btime, &diff); 825 if (timespeccmp(&diff, &tetime, >)) 826 tetime = diff; 827 } while ((pp = pp->p_friends) != tp); 828 prusage(cshout, &zru, &ru, &tetime, &ztime); 829 } 830 831 /* 832 * dojobs - print all jobs 833 */ 834 void 835 /*ARGSUSED*/ 836 dojobs(Char **v, struct command *t) 837 { 838 struct process *pp; 839 int flag, i; 840 841 flag = NUMBER | NAME | REASON; 842 if (chkstop) 843 chkstop = 2; 844 if (*++v) { 845 if (v[1]) { 846 if (eq(*v, STRml)) { 847 flag |= FANCY | JOBDIR; 848 } else if (eq(*v, STRmZ)) { 849 if (v[1] && v[1][0]) { 850 setproctitle("%s", short2str(v[1])); 851 } else { 852 setproctitle(NULL); 853 } 854 return; 855 } else { 856 stderror(ERR_JOBS); 857 } 858 } 859 } 860 for (i = 1; i <= pmaxindex; i++) 861 for (pp = proclist.p_next; pp; pp = pp->p_next) 862 if (pp->p_index == i && pp->p_pid == pp->p_jobid) { 863 pp->p_flags &= ~PNEEDNOTE; 864 if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED))) 865 pflush(pp); 866 break; 867 } 868 } 869 870 /* 871 * dofg - builtin - put the job into the foreground 872 */ 873 void 874 /*ARGSUSED*/ 875 dofg(Char **v, struct command *t) 876 { 877 struct process *pp; 878 879 okpcntl(); 880 ++v; 881 do { 882 pp = pfind(*v); 883 pstart(pp, 1); 884 pjwait(pp); 885 } while (*v && *++v); 886 } 887 888 /* 889 * %... - builtin - put the job into the foreground 890 */ 891 void 892 /*ARGSUSED*/ 893 dofg1(Char **v, struct command *t) 894 { 895 struct process *pp; 896 897 okpcntl(); 898 pp = pfind(v[0]); 899 pstart(pp, 1); 900 pjwait(pp); 901 } 902 903 /* 904 * dobg - builtin - put the job into the background 905 */ 906 void 907 /*ARGSUSED*/ 908 dobg(Char **v, struct command *t) 909 { 910 struct process *pp; 911 912 okpcntl(); 913 ++v; 914 do { 915 pp = pfind(*v); 916 pstart(pp, 0); 917 } while (*v && *++v); 918 } 919 920 /* 921 * %... & - builtin - put the job into the background 922 */ 923 void 924 /*ARGSUSED*/ 925 dobg1(Char **v, struct command *t) 926 { 927 struct process *pp; 928 929 pp = pfind(v[0]); 930 pstart(pp, 0); 931 } 932 933 /* 934 * dostop - builtin - stop the job 935 */ 936 void 937 /*ARGSUSED*/ 938 dostop(Char **v, struct command *t) 939 { 940 pkill(++v, SIGSTOP); 941 } 942 943 /* 944 * dokill - builtin - superset of kill (1) 945 */ 946 void 947 /*ARGSUSED*/ 948 dokill(Char **v, struct command *t) 949 { 950 Char *signame; 951 char *name; 952 long signum; 953 char *ep; 954 955 signum = SIGTERM; 956 v++; 957 if (v[0] && v[0][0] == '-') { 958 if (v[0][1] == 'l') { 959 if (v[1]) { 960 if (!Isdigit(v[1][0])) 961 stderror(ERR_NAME | ERR_BADSIG); 962 963 signum = strtol(short2str(v[1]), &ep, 10); 964 if (signum < 0 || signum >= NSIG) 965 stderror(ERR_NAME | ERR_BADSIG); 966 else if (signum == 0) 967 (void)fputc('0', cshout); /* 0's symbolic name is '0' */ 968 else 969 (void)fprintf(cshout, "%s ", sys_signame[signum]); 970 } else { 971 for (signum = 1; signum < NSIG; signum++) { 972 (void)fprintf(cshout, "%s ", sys_signame[signum]); 973 if (signum == NSIG / 2) 974 (void)fputc('\n', cshout); 975 } 976 } 977 (void)fputc('\n', cshout); 978 return; 979 } 980 if (Isdigit(v[0][1])) { 981 signum = strtol(short2str(v[0] + 1), &ep, 10); 982 if (signum < 0 || signum >= NSIG || *ep) 983 stderror(ERR_NAME | ERR_BADSIG); 984 } 985 else { 986 if (v[0][1] == 's' && v[0][2] == '\0') 987 signame = *(++v); 988 else 989 signame = &v[0][1]; 990 991 if (signame == NULL || v[1] == NULL) 992 stderror(ERR_NAME | ERR_TOOFEW); 993 994 name = short2str(signame); 995 for (signum = 1; signum < NSIG; signum++) 996 if (!strcasecmp(sys_signame[signum], name) || 997 (!strncasecmp("SIG", name, 3) && /* skip "SIG" prefix */ 998 !strcasecmp(sys_signame[signum], name + 3))) 999 break; 1000 1001 if (signum == NSIG) { 1002 if (signame[0] == '0') 1003 signum = 0; 1004 else { 1005 setname(vis_str(signame)); 1006 stderror(ERR_NAME | ERR_UNKSIG); 1007 } 1008 } 1009 } 1010 v++; 1011 } 1012 pkill(v, (int)signum); 1013 } 1014 1015 static void 1016 pkill(Char **v, int signum) 1017 { 1018 struct process *pp, *np; 1019 Char *cp; 1020 sigset_t nsigset; 1021 int err1, jobflags, pid; 1022 char *ep; 1023 1024 jobflags = 0; 1025 err1 = 0; 1026 sigemptyset(&nsigset); 1027 (void)sigaddset(&nsigset, SIGCHLD); 1028 if (setintr) 1029 (void)sigaddset(&nsigset, SIGINT); 1030 (void)sigprocmask(SIG_BLOCK, &nsigset, NULL); 1031 gflag = 0, tglob(v); 1032 if (gflag) { 1033 v = globall(v); 1034 if (v == 0) 1035 stderror(ERR_NAME | ERR_NOMATCH); 1036 } 1037 else { 1038 v = gargv = saveblk(v); 1039 trim(v); 1040 } 1041 1042 while (v && (cp = *v)) { 1043 if (*cp == '%') { 1044 np = pp = pfind(cp); 1045 do 1046 jobflags |= np->p_flags; 1047 while ((np = np->p_friends) != pp); 1048 switch (signum) { 1049 case SIGSTOP: 1050 case SIGTSTP: 1051 case SIGTTIN: 1052 case SIGTTOU: 1053 if ((jobflags & PRUNNING) == 0) { 1054 (void)fprintf(csherr, "%s: Already suspended\n", 1055 vis_str(cp)); 1056 err1++; 1057 goto cont; 1058 } 1059 break; 1060 /* 1061 * suspend a process, kill -CONT %, then type jobs; the shell 1062 * says it is suspended, but it is running; thanks jaap.. 1063 */ 1064 case SIGCONT: 1065 pstart(pp, 0); 1066 goto cont; 1067 } 1068 if (kill(-pp->p_jobid, signum) < 0) { 1069 (void)fprintf(csherr, "%s: %s\n", vis_str(cp), 1070 strerror(errno)); 1071 err1++; 1072 } 1073 if (signum == SIGTERM || signum == SIGHUP) 1074 (void)kill(-pp->p_jobid, SIGCONT); 1075 } 1076 else if (!(Isdigit(*cp) || *cp == '-')) 1077 stderror(ERR_NAME | ERR_JOBARGS); 1078 else { 1079 pid = (pid_t)strtoul(short2str(cp), &ep, 0); 1080 if (*ep) { 1081 (void)fprintf(csherr, "%s: Badly formed number\n", 1082 short2str(cp)); 1083 err1++; 1084 goto cont; 1085 } else if (kill(pid, signum) < 0) { 1086 (void)fprintf(csherr, "%d: %s\n", pid, strerror(errno)); 1087 err1++; 1088 goto cont; 1089 } 1090 if (signum == SIGTERM || signum == SIGHUP) 1091 (void)kill((pid_t) pid, SIGCONT); 1092 } 1093 cont: 1094 v++; 1095 } 1096 if (gargv) 1097 blkfree(gargv), gargv = 0; 1098 (void)sigprocmask(SIG_UNBLOCK, &nsigset, NULL); 1099 if (err1) 1100 stderror(ERR_SILENT); 1101 } 1102 1103 /* 1104 * pstart - start the job in foreground/background 1105 */ 1106 void 1107 pstart(struct process *pp, int foregnd) 1108 { 1109 struct process *np; 1110 sigset_t osigset, nsigset; 1111 long jobflags; 1112 1113 jobflags = 0; 1114 sigemptyset(&nsigset); 1115 (void)sigaddset(&nsigset, SIGCHLD); 1116 (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); 1117 np = pp; 1118 do { 1119 jobflags |= np->p_flags; 1120 if (np->p_flags & (PRUNNING | PSTOPPED)) { 1121 np->p_flags |= PRUNNING; 1122 np->p_flags &= ~PSTOPPED; 1123 if (foregnd) 1124 np->p_flags |= PFOREGND; 1125 else 1126 np->p_flags &= ~PFOREGND; 1127 } 1128 } while ((np = np->p_friends) != pp); 1129 if (!foregnd) 1130 pclrcurr(pp); 1131 (void)pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND); 1132 if (foregnd) 1133 (void)tcsetpgrp(FSHTTY, pp->p_jobid); 1134 if (jobflags & PSTOPPED) 1135 (void)kill(-pp->p_jobid, SIGCONT); 1136 (void)sigprocmask(SIG_SETMASK, &osigset, NULL); 1137 } 1138 1139 void 1140 panystop(int neednl) 1141 { 1142 struct process *pp; 1143 1144 chkstop = 2; 1145 for (pp = proclist.p_next; pp; pp = pp->p_next) 1146 if (pp->p_flags & PSTOPPED) 1147 stderror(ERR_STOPPED, neednl ? "\n" : ""); 1148 } 1149 1150 struct process * 1151 pfind(Char *cp) 1152 { 1153 struct process *pp, *np; 1154 1155 if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) { 1156 if (pcurrent == NULL) 1157 stderror(ERR_NAME | ERR_JOBCUR); 1158 return (pcurrent); 1159 } 1160 if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) { 1161 if (pprevious == NULL) 1162 stderror(ERR_NAME | ERR_JOBPREV); 1163 return (pprevious); 1164 } 1165 if (Isdigit(cp[1])) { 1166 int idx = atoi(short2str(cp + 1)); 1167 1168 for (pp = proclist.p_next; pp; pp = pp->p_next) 1169 if (pp->p_index == idx && pp->p_pid == pp->p_jobid) 1170 return (pp); 1171 stderror(ERR_NAME | ERR_NOSUCHJOB); 1172 } 1173 np = NULL; 1174 for (pp = proclist.p_next; pp; pp = pp->p_next) 1175 if (pp->p_pid == pp->p_jobid) { 1176 if (cp[1] == '?') { 1177 Char *dp; 1178 1179 for (dp = pp->p_command; *dp; dp++) { 1180 if (*dp != cp[2]) 1181 continue; 1182 if (prefix(cp + 2, dp)) 1183 goto match; 1184 } 1185 } 1186 else if (prefix(cp + 1, pp->p_command)) { 1187 match: 1188 if (np) 1189 stderror(ERR_NAME | ERR_AMBIG); 1190 np = pp; 1191 } 1192 } 1193 if (np) 1194 return (np); 1195 stderror(ERR_NAME | (cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB)); 1196 /* NOTREACHED */ 1197 } 1198 1199 /* 1200 * pgetcurr - find most recent job that is not pp, preferably stopped 1201 */ 1202 static struct process * 1203 pgetcurr(struct process *pp) 1204 { 1205 struct process *np, *xp; 1206 1207 xp = NULL; 1208 for (np = proclist.p_next; np; np = np->p_next) 1209 if (np != pcurrent && np != pp && np->p_pid && 1210 np->p_pid == np->p_jobid) { 1211 if (np->p_flags & PSTOPPED) 1212 return (np); 1213 if (xp == NULL) 1214 xp = np; 1215 } 1216 return (xp); 1217 } 1218 1219 /* 1220 * donotify - flag the job so as to report termination asynchronously 1221 */ 1222 void 1223 /*ARGSUSED*/ 1224 donotify(Char **v, struct command *t) 1225 { 1226 struct process *pp; 1227 1228 pp = pfind(*++v); 1229 pp->p_flags |= PNOTIFY; 1230 } 1231 1232 /* 1233 * Do the fork and whatever should be done in the child side that 1234 * should not be done if we are not forking at all (like for simple builtin's) 1235 * Also do everything that needs any signals fiddled with in the parent side 1236 * 1237 * Wanttty tells whether process and/or tty pgrps are to be manipulated: 1238 * -1: leave tty alone; inherit pgrp from parent 1239 * 0: already have tty; manipulate process pgrps only 1240 * 1: want to claim tty; manipulate process and tty pgrps 1241 * It is usually just the value of tpgrp. 1242 */ 1243 1244 int 1245 pfork(struct command *t /* command we are forking for */, int wanttty) 1246 { 1247 int pgrp, pid; 1248 sigset_t osigset, nsigset; 1249 int ignint; 1250 1251 ignint = 0; 1252 /* 1253 * A child will be uninterruptible only under very special conditions. 1254 * Remember that the semantics of '&' is implemented by disconnecting the 1255 * process from the tty so signals do not need to ignored just for '&'. 1256 * Thus signals are set to default action for children unless: we have had 1257 * an "onintr -" (then specifically ignored) we are not playing with 1258 * signals (inherit action) 1259 */ 1260 if (setintr) 1261 ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) 1262 || (gointr && eq(gointr, STRminus)); 1263 /* 1264 * Check for maximum nesting of 16 processes to avoid Forking loops 1265 */ 1266 if (child == 16) 1267 stderror(ERR_NESTING, 16); 1268 /* 1269 * Hold SIGCHLD until we have the process installed in our table. 1270 */ 1271 sigemptyset(&nsigset); 1272 (void)sigaddset(&nsigset, SIGCHLD); 1273 (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); 1274 while ((pid = fork()) < 0) 1275 if (setintr == 0) 1276 (void)sleep(FORKSLEEP); 1277 else { 1278 (void)sigprocmask(SIG_SETMASK, &osigset, NULL); 1279 stderror(ERR_NOPROC); 1280 } 1281 if (pid == 0) { 1282 settimes(); 1283 pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 1284 pflushall(); 1285 pcurrjob = NULL; 1286 child++; 1287 if (setintr) { 1288 setintr = 0; /* until I think otherwise */ 1289 /* 1290 * Children just get blown away on SIGINT, SIGQUIT unless "onintr 1291 * -" seen. 1292 */ 1293 (void)signal(SIGINT, ignint ? SIG_IGN : SIG_DFL); 1294 (void)signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); 1295 if (wanttty >= 0) { 1296 /* make stoppable */ 1297 (void)signal(SIGTSTP, SIG_DFL); 1298 (void)signal(SIGTTIN, SIG_DFL); 1299 (void)signal(SIGTTOU, SIG_DFL); 1300 } 1301 (void)signal(SIGTERM, parterm); 1302 } 1303 else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { 1304 (void)signal(SIGINT, SIG_IGN); 1305 (void)signal(SIGQUIT, SIG_IGN); 1306 } 1307 pgetty(wanttty, pgrp); 1308 /* 1309 * Nohup and nice apply only to NODE_COMMAND's but it would be nice 1310 * (?!?) if you could say "nohup (foo;bar)" Then the parser would have 1311 * to know about nice/nohup/time 1312 */ 1313 if (t->t_dflg & F_NOHUP) 1314 (void)signal(SIGHUP, SIG_IGN); 1315 if (t->t_dflg & F_NICE) 1316 (void)setpriority(PRIO_PROCESS, 0, t->t_nice); 1317 } 1318 else { 1319 if (wanttty >= 0) 1320 (void)setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid); 1321 palloc(pid, t); 1322 (void)sigprocmask(SIG_SETMASK, &osigset, NULL); 1323 } 1324 1325 return (pid); 1326 } 1327 1328 static void 1329 okpcntl(void) 1330 { 1331 if (tpgrp == -1) 1332 stderror(ERR_JOBCONTROL); 1333 if (tpgrp == 0) 1334 stderror(ERR_JOBCTRLSUB); 1335 /* NOTREACHED */ 1336 } 1337 1338 /* 1339 * if we don't have vfork(), things can still go in the wrong order 1340 * resulting in the famous 'Stopped (tty output)'. But some systems 1341 * don't permit the setpgid() call, (these are more recent secure 1342 * systems such as ibm's aix). Then we'd rather print an error message 1343 * than hang the shell! 1344 * I am open to suggestions how to fix that. 1345 */ 1346 void 1347 pgetty(int wanttty, int pgrp) 1348 { 1349 sigset_t osigset, nsigset; 1350 1351 /* 1352 * christos: I am blocking the tty signals till I've set things 1353 * correctly.... 1354 */ 1355 if (wanttty > 0) { 1356 sigemptyset(&nsigset); 1357 (void)sigaddset(&nsigset, SIGTSTP); 1358 (void)sigaddset(&nsigset, SIGTTIN); 1359 (void)sigaddset(&nsigset, SIGTTOU); 1360 (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); 1361 } 1362 /* 1363 * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 1364 * Don't check for tpgrp >= 0 so even non-interactive shells give 1365 * background jobs process groups Same for the comparison in the other part 1366 * of the #ifdef 1367 */ 1368 if (wanttty >= 0) 1369 if (setpgid(0, pgrp) == -1) { 1370 (void)fprintf(csherr, "csh: setpgid error.\n"); 1371 xexit(0); 1372 } 1373 1374 if (wanttty > 0) { 1375 (void)tcsetpgrp(FSHTTY, pgrp); 1376 (void)sigprocmask(SIG_SETMASK, &osigset, NULL); 1377 } 1378 1379 if (tpgrp > 0) 1380 tpgrp = 0; /* gave tty away */ 1381 } 1382