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