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