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