1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * David Korn <dgk@research.att.com> * 18 * * 19 ***********************************************************************/ 20 #pragma prototyped 21 /* 22 * Job control for UNIX Shell 23 * 24 * David Korn 25 * AT&T Labs 26 * 27 * Written October, 1982 28 * Rewritten April, 1988 29 * Revised January, 1992 30 */ 31 32 #include "defs.h" 33 #include <ctype.h> 34 #include <wait.h> 35 #include "io.h" 36 #include "jobs.h" 37 #include "history.h" 38 39 #if !defined(WCONTINUED) || !defined(WIFCONTINUED) 40 # undef WCONTINUED 41 # define WCONTINUED 0 42 # undef WIFCONTINUED 43 # define WIFCONTINUED(wstat) (0) 44 #endif 45 46 #define NJOB_SAVELIST 4 47 48 /* 49 * temporary hack to get W* macros to work 50 */ 51 #undef wait 52 #define wait ______wait 53 /* 54 * This struct saves a link list of processes that have non-zero exit 55 * status, have had $! saved, but haven't been waited for 56 */ 57 struct jobsave 58 { 59 struct jobsave *next; 60 pid_t pid; 61 unsigned short exitval; 62 }; 63 64 static struct jobsave *job_savelist; 65 static int njob_savelist; 66 67 static void init_savelist(void) 68 { 69 register struct jobsave *jp; 70 while(njob_savelist < NJOB_SAVELIST) 71 { 72 jp = newof(0,struct jobsave,1,0); 73 jp->next = job_savelist; 74 job_savelist = jp; 75 njob_savelist++; 76 } 77 } 78 79 /* 80 * return next on link list of jobsave free list 81 */ 82 static struct jobsave *jobsave_create(pid_t pid) 83 { 84 register struct jobsave *jp = job_savelist; 85 if(jp) 86 { 87 njob_savelist--; 88 job_savelist = jp->next; 89 } 90 else 91 jp = newof(0,struct jobsave,1,0); 92 if(jp) 93 jp->pid = pid; 94 return(jp); 95 } 96 97 struct back_save 98 { 99 int count; 100 struct jobsave *list; 101 }; 102 103 #define BYTE(n) (((n)+CHAR_BIT-1)/CHAR_BIT) 104 #define MAXMSG 25 105 #define SH_STOPSIG (SH_EXITSIG<<1) 106 107 #ifdef VSUSP 108 # ifndef CNSUSP 109 # ifdef _POSIX_VDISABLE 110 # define CNSUSP _POSIX_VDISABLE 111 # else 112 # define CNSUSP 0 113 # endif /* _POSIX_VDISABLE */ 114 # endif /* CNSUSP */ 115 # ifndef CSWTCH 116 # ifdef CSUSP 117 # define CSWTCH CSUSP 118 # else 119 # define CSWTCH ('z'&037) 120 # endif /* CSUSP */ 121 # endif /* CSWTCH */ 122 #endif /* VSUSP */ 123 124 /* Process states */ 125 #define P_EXITSAVE 01 126 #define P_STOPPED 02 127 #define P_NOTIFY 04 128 #define P_SIGNALLED 010 129 #define P_STTY 020 130 #define P_DONE 040 131 #define P_COREDUMP 0100 132 #define P_DISOWN 0200 133 #define P_FG 0400 134 135 static int job_chksave(pid_t); 136 static struct process *job_bypid(pid_t); 137 static struct process *job_byjid(int); 138 static char *job_sigmsg(int); 139 static int job_alloc(void); 140 static void job_free(int); 141 static struct process *job_unpost(struct process*,int); 142 static void job_unlink(struct process*); 143 static void job_prmsg(struct process*); 144 static struct process *freelist; 145 static char beenhere; 146 static char possible; 147 static struct process dummy; 148 static char by_number; 149 static Sfio_t *outfile; 150 static pid_t lastpid; 151 static struct back_save bck; 152 153 154 #ifdef JOBS 155 static void job_set(struct process*); 156 static void job_reset(struct process*); 157 static void job_waitsafe(int); 158 static struct process *job_byname(char*); 159 static struct process *job_bystring(char*); 160 static struct termios my_stty; /* terminal state for shell */ 161 static char *job_string; 162 #else 163 extern const char e_coredump[]; 164 #endif /* JOBS */ 165 166 #ifdef SIGTSTP 167 static void job_unstop(struct process*); 168 static void job_fgrp(struct process*, int); 169 # ifndef _lib_tcgetpgrp 170 # ifdef TIOCGPGRP 171 static int _i_; 172 # define tcgetpgrp(a) (ioctl(a, TIOCGPGRP, &_i_)>=0?_i_:-1) 173 # endif /* TIOCGPGRP */ 174 int tcsetpgrp(int fd,pid_t pgrp) 175 { 176 int pgid = pgrp; 177 # ifdef TIOCGPGRP 178 return(ioctl(fd, TIOCSPGRP, &pgid)); 179 # else 180 return(-1); 181 # endif /* TIOCGPGRP */ 182 } 183 # endif /* _lib_tcgetpgrp */ 184 #else 185 # define job_unstop(pw) 186 # undef CNSUSP 187 #endif /* SIGTSTP */ 188 189 #ifndef OTTYDISC 190 # undef NTTYDISC 191 #endif /* OTTYDISC */ 192 193 #ifdef JOBS 194 195 typedef int (*Waitevent_f)(int,long,int); 196 197 /* 198 * Reap one job 199 * When called with sig==0, it does a blocking wait 200 */ 201 int job_reap(register int sig) 202 { 203 register pid_t pid; 204 register struct process *pw; 205 struct process *px; 206 register int flags; 207 struct process dummy; 208 struct jobsave *jp; 209 int nochild=0, oerrno, wstat; 210 Waitevent_f waitevent = sh.waitevent; 211 static int wcontinued = WCONTINUED; 212 #ifdef DEBUG 213 if(sfprintf(sfstderr,"ksh: job line %4d: reap pid=%d critical=%d signal=%d\n",__LINE__,getpid(),job.in_critical,sig) <=0) 214 write(2,"waitsafe\n",9); 215 sfsync(sfstderr); 216 #endif /* DEBUG */ 217 job.savesig = 0; 218 if(sig) 219 flags = WNOHANG|WUNTRACED|wcontinued; 220 else 221 flags = WUNTRACED|wcontinued; 222 sh.waitevent = 0; 223 oerrno = errno; 224 while(1) 225 { 226 if(!(flags&WNOHANG) && !sh.intrap && waitevent && job.pwlist) 227 { 228 if((*waitevent)(-1,-1L,0)) 229 flags |= WNOHANG; 230 } 231 pid = waitpid((pid_t)-1,&wstat,flags); 232 233 /* 234 * some systems (linux 2.6) may return EINVAL 235 * when there are no continued children 236 */ 237 238 if (pid<0 && errno==EINVAL && (flags&WCONTINUED)) 239 pid = waitpid((pid_t)-1,&wstat,flags&=~WCONTINUED); 240 sh_sigcheck(); 241 if(sig && pid<0 && errno==EINTR) 242 continue; 243 if(pid<=0) 244 break; 245 flags |= WNOHANG; 246 job.waitsafe++; 247 jp = 0; 248 if(!(pw=job_bypid(pid))) 249 { 250 #ifdef DEBUG 251 sfprintf(sfstderr,"ksh: job line %4d: reap pid=%d critical=%d unknown job pid=%d pw=%x\n",__LINE__,getpid(),job.in_critical,pid,pw); 252 #endif /* DEBUG */ 253 pw = &dummy; 254 pw->p_exit = 0; 255 pw->p_pgrp = 0; 256 if(job.toclear) 257 job_clear(); 258 if(bck.count++ > sh.lim.child_max) 259 job_chksave(0); 260 if(jp = jobsave_create(pid)) 261 { 262 jp->next = bck.list; 263 bck.list = jp; 264 jp->exitval = 0; 265 } 266 pw->p_flag = 0; 267 lastpid = pw->p_pid = pid; 268 px = 0; 269 if(jp && WIFSTOPPED(wstat)) 270 { 271 jp->exitval = SH_STOPSIG; 272 continue; 273 } 274 } 275 #ifdef SIGTSTP 276 else 277 px=job_byjid(pw->p_job); 278 if(WIFSTOPPED(wstat)) 279 { 280 if(px) 281 { 282 /* move to top of job list */ 283 job_unlink(px); 284 px->p_nxtjob = job.pwlist; 285 job.pwlist = px; 286 } 287 pw->p_exit = WSTOPSIG(wstat); 288 pw->p_flag |= (P_NOTIFY|P_SIGNALLED|P_STOPPED); 289 if(pw->p_pgrp && pw->p_pgrp==job.curpgid && sh_isstate(SH_STOPOK)) 290 sh_fault(pw->p_exit); 291 continue; 292 } 293 else if (WIFCONTINUED(wstat) && wcontinued) 294 { 295 pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED); 296 pw->p_exit = 0; 297 } 298 else 299 #endif /* SIGTSTP */ 300 { 301 /* check for coprocess completion */ 302 if(pid==sh.cpid) 303 { 304 sh_close(sh.coutpipe); 305 sh_close(sh.cpipe[1]); 306 sh.cpipe[1] = -1; 307 sh.coutpipe = -1; 308 } 309 if (WIFSIGNALED(wstat)) 310 { 311 pw->p_flag &= ~P_STOPPED; 312 pw->p_flag |= (P_DONE|P_NOTIFY|P_SIGNALLED); 313 if (WTERMCORE(wstat)) 314 pw->p_flag |= P_COREDUMP; 315 pw->p_exit = WTERMSIG(wstat); 316 /* if process in current jobs terminates from 317 * an interrupt, propogate to parent shell 318 */ 319 if(pw->p_pgrp && pw->p_pgrp==job.curpgid && pw->p_exit==SIGINT && sh_isstate(SH_STOPOK)) 320 { 321 pw->p_flag &= ~P_NOTIFY; 322 sh_offstate(SH_STOPOK); 323 sh_fault(SIGINT); 324 sh_onstate(SH_STOPOK); 325 } 326 } 327 else 328 { 329 pw->p_flag |= (P_DONE|P_NOTIFY); 330 if(WEXITSTATUS(wstat) > pw->p_exit) 331 pw->p_exit = WEXITSTATUS(wstat); 332 } 333 if(pw->p_pgrp==0) 334 pw->p_flag &= ~P_NOTIFY; 335 } 336 if(jp && pw== &dummy) 337 { 338 jp->exitval = pw->p_exit; 339 if(pw->p_flag&P_SIGNALLED) 340 jp->exitval |= SH_EXITSIG; 341 } 342 #ifdef DEBUG 343 sfprintf(sfstderr,"ksh: job line %4d: reap pid=%d critical=%d job %d with pid %d flags=%o complete with status=%x exit=%d\n",__LINE__,getpid(),job.in_critical,pw->p_job,pid,pw->p_flag,wstat,pw->p_exit); 344 sfsync(sfstderr); 345 #endif /* DEBUG*/ 346 /* only top-level process in job should have notify set */ 347 if(px && pw != px) 348 pw->p_flag &= ~P_NOTIFY; 349 } 350 if(errno==ECHILD) 351 { 352 errno = oerrno; 353 nochild = 1; 354 } 355 sh.waitevent = waitevent; 356 if(!sh.intrap && sh.st.trapcom[SIGCHLD]) 357 { 358 sh.sigflag[SIGCHLD] |= SH_SIGTRAP; 359 sh.trapnote |= SH_SIGTRAP; 360 } 361 if(sh_isoption(SH_NOTIFY) && sh_isstate(SH_TTYWAIT)) 362 { 363 outfile = sfstderr; 364 job_list(pw,JOB_NFLAG|JOB_NLFLAG); 365 job_unpost(pw,1); 366 sfsync(sfstderr); 367 } 368 if(sig) 369 signal(sig, job_waitsafe); 370 return(nochild); 371 } 372 373 /* 374 * This is the SIGCLD interrupt routine 375 */ 376 static void job_waitsafe(int sig) 377 { 378 if(job.in_critical) 379 { 380 job.savesig = sig; 381 job.waitsafe++; 382 } 383 else 384 job_reap(sig); 385 } 386 387 /* 388 * initialize job control if possible 389 * if lflag is set the switching driver message will not print 390 */ 391 void job_init(int lflag) 392 { 393 register int i,ntry=0; 394 job.fd = JOBTTY; 395 signal(SIGCHLD,job_waitsafe); 396 # if defined(SIGCLD) && (SIGCLD!=SIGCHLD) 397 signal(SIGCLD,job_waitsafe); 398 # endif 399 if(njob_savelist < NJOB_SAVELIST) 400 init_savelist(); 401 if(!sh_isoption(SH_INTERACTIVE)) 402 return; 403 /* use new line discipline when available */ 404 #ifdef NTTYDISC 405 # ifdef FIOLOOKLD 406 if((job.linedisc = ioctl(JOBTTY, FIOLOOKLD, 0)) <0) 407 # else 408 if(ioctl(JOBTTY,TIOCGETD,&job.linedisc) !=0) 409 # endif /* FIOLOOKLD */ 410 return; 411 if(job.linedisc!=NTTYDISC && job.linedisc!=OTTYDISC) 412 { 413 /* no job control when running with MPX */ 414 # if SHOPT_VSH 415 sh_onoption(SH_VIRAW); 416 # endif /* SHOPT_VSH */ 417 return; 418 } 419 if(job.linedisc==NTTYDISC) 420 job.linedisc = -1; 421 #endif /* NTTYDISC */ 422 423 job.mypgid = getpgrp(); 424 /* some systems have job control, but not initialized */ 425 if(job.mypgid<=0) 426 { 427 /* Get a controlling terminal and set process group */ 428 /* This should have already been done by rlogin */ 429 register int fd; 430 register char *ttynam; 431 #ifndef SIGTSTP 432 setpgid(0,sh.pid); 433 #endif /*SIGTSTP */ 434 if(job.mypgid<0 || !(ttynam=ttyname(JOBTTY))) 435 return; 436 close(JOBTTY); 437 if((fd = open(ttynam,O_RDWR)) <0) 438 return; 439 if(fd!=JOBTTY) 440 sh_iorenumber(fd,JOBTTY); 441 job.mypgid = sh.pid; 442 #ifdef SIGTSTP 443 tcsetpgrp(JOBTTY,sh.pid); 444 setpgid(0,sh.pid); 445 #endif /* SIGTSTP */ 446 } 447 #ifdef SIGTSTP 448 if(possible = (setpgid(0,job.mypgid)>=0) || errno==EPERM) 449 { 450 /* wait until we are in the foreground */ 451 while((job.mytgid=tcgetpgrp(JOBTTY)) != job.mypgid) 452 { 453 if(job.mytgid == -1) 454 return; 455 /* Stop this shell until continued */ 456 signal(SIGTTIN,SIG_DFL); 457 kill(sh.pid,SIGTTIN); 458 /* resumes here after continue tries again */ 459 if(ntry++ > IOMAXTRY) 460 { 461 errormsg(SH_DICT,0,e_no_start); 462 return; 463 } 464 } 465 } 466 #endif /* SIGTTIN */ 467 468 #ifdef NTTYDISC 469 /* set the line discipline */ 470 if(job.linedisc>=0) 471 { 472 int linedisc = NTTYDISC; 473 # ifdef FIOPUSHLD 474 tty_get(JOBTTY,&my_stty); 475 if (ioctl(JOBTTY, FIOPOPLD, 0) < 0) 476 return; 477 if (ioctl(JOBTTY, FIOPUSHLD, &linedisc) < 0) 478 { 479 ioctl(JOBTTY, FIOPUSHLD, &job.linedisc); 480 return; 481 } 482 tty_set(JOBTTY,TCSANOW,&my_stty); 483 # else 484 if(ioctl(JOBTTY,TIOCSETD,&linedisc) !=0) 485 return; 486 # endif /* FIOPUSHLD */ 487 if(lflag==0) 488 errormsg(SH_DICT,0,e_newtty); 489 else 490 job.linedisc = -1; 491 } 492 #endif /* NTTYDISC */ 493 if(!possible) 494 return; 495 496 #ifdef SIGTSTP 497 /* make sure that we are a process group leader */ 498 setpgid(0,sh.pid); 499 # if defined(SA_NOCLDWAIT) && defined(_lib_sigflag) 500 sigflag(SIGCHLD, SA_NOCLDSTOP|SA_NOCLDWAIT, 0); 501 # endif /* SA_NOCLDWAIT */ 502 signal(SIGTTIN,SIG_IGN); 503 signal(SIGTTOU,SIG_IGN); 504 /* The shell now handles ^Z */ 505 signal(SIGTSTP,sh_fault); 506 tcsetpgrp(JOBTTY,sh.pid); 507 # ifdef CNSUSP 508 /* set the switch character */ 509 tty_get(JOBTTY,&my_stty); 510 job.suspend = (unsigned)my_stty.c_cc[VSUSP]; 511 if(job.suspend == (unsigned char)CNSUSP) 512 { 513 my_stty.c_cc[VSUSP] = CSWTCH; 514 tty_set(JOBTTY,TCSAFLUSH,&my_stty); 515 } 516 # endif /* CNSUSP */ 517 sh_onoption(SH_MONITOR); 518 job.jobcontrol++; 519 job.mypid = sh.pid; 520 #endif /* SIGTSTP */ 521 return; 522 } 523 524 525 /* 526 * see if there are any stopped jobs 527 * restore tty driver and pgrp 528 */ 529 int job_close(void) 530 { 531 register struct process *pw; 532 register int count = 0, running = 0; 533 if(possible && !job.jobcontrol) 534 return(0); 535 else if(!possible && (!sh_isstate(SH_MONITOR) || sh_isstate(SH_FORKED))) 536 return(0); 537 else if(getpid() != job.mypid) 538 return(0); 539 job_lock(); 540 if(!tty_check(0)) 541 beenhere++; 542 for(pw=job.pwlist;pw;pw=pw->p_nxtjob) 543 { 544 if(!(pw->p_flag&P_STOPPED)) 545 { 546 if(!(pw->p_flag&P_DONE)) 547 running++; 548 continue; 549 } 550 if(beenhere) 551 killpg(pw->p_pgrp,SIGTERM); 552 count++; 553 } 554 if(beenhere++ == 0 && job.pwlist) 555 { 556 if(count) 557 { 558 errormsg(SH_DICT,0,e_terminate); 559 return(-1); 560 } 561 else if(running && sh.login_sh) 562 { 563 errormsg(SH_DICT,0,e_jobsrunning); 564 return(-1); 565 } 566 } 567 job_unlock(); 568 # ifdef SIGTSTP 569 if(possible && setpgid(0,job.mypgid)>=0) 570 tcsetpgrp(job.fd,job.mypgid); 571 # endif /* SIGTSTP */ 572 # ifdef NTTYDISC 573 if(job.linedisc>=0) 574 { 575 /* restore old line discipline */ 576 # ifdef FIOPUSHLD 577 tty_get(job.fd,&my_stty); 578 if (ioctl(job.fd, FIOPOPLD, 0) < 0) 579 return(0); 580 if (ioctl(job.fd, FIOPUSHLD, &job.linedisc) < 0) 581 { 582 job.linedisc = NTTYDISC; 583 ioctl(job.fd, FIOPUSHLD, &job.linedisc); 584 return(0); 585 } 586 tty_set(job.fd,TCSAFLUSH,&my_stty); 587 # else 588 if(ioctl(job.fd,TIOCSETD,&job.linedisc) !=0) 589 return(0); 590 # endif /* FIOPUSHLD */ 591 errormsg(SH_DICT,0,e_oldtty); 592 } 593 # endif /* NTTYDISC */ 594 # ifdef CNSUSP 595 if(possible && job.suspend==CNSUSP) 596 { 597 tty_get(job.fd,&my_stty); 598 my_stty.c_cc[VSUSP] = CNSUSP; 599 tty_set(job.fd,TCSAFLUSH,&my_stty); 600 } 601 # endif /* CNSUSP */ 602 job.jobcontrol = 0; 603 return(0); 604 } 605 606 static void job_set(register struct process *pw) 607 { 608 /* save current terminal state */ 609 tty_get(job.fd,&my_stty); 610 if(pw->p_flag&P_STTY) 611 { 612 /* restore terminal state for job */ 613 tty_set(job.fd,TCSAFLUSH,&pw->p_stty); 614 } 615 #ifdef SIGTSTP 616 if((pw->p_flag&P_STOPPED) || tcgetpgrp(job.fd) == sh.pid) 617 tcsetpgrp(job.fd,pw->p_fgrp); 618 /* if job is stopped, resume it in the background */ 619 job_unstop(pw); 620 #endif /* SIGTSTP */ 621 } 622 623 static void job_reset(register struct process *pw) 624 { 625 /* save the terminal state for current job */ 626 #ifdef SIGTSTP 627 job_fgrp(pw,tcgetpgrp(job.fd)); 628 if(tcsetpgrp(job.fd,sh.pid) !=0) 629 return; 630 #endif /* SIGTSTP */ 631 /* force the following tty_get() to do a tcgetattr() unless fg */ 632 if(!(pw->p_flag&P_FG)) 633 tty_set(-1, 0, NIL(struct termios*)); 634 if(pw && (pw->p_flag&P_SIGNALLED) && pw->p_exit!=SIGHUP) 635 { 636 if(tty_get(job.fd,&pw->p_stty) == 0) 637 pw->p_flag |= P_STTY; 638 /* restore terminal state for job */ 639 tty_set(job.fd,TCSAFLUSH,&my_stty); 640 } 641 beenhere = 0; 642 } 643 #endif /* JOBS */ 644 645 /* 646 * wait built-in command 647 */ 648 649 void job_bwait(char **jobs) 650 { 651 register char *jp; 652 register struct process *pw; 653 register pid_t pid; 654 if(*jobs==0) 655 job_wait((pid_t)-1); 656 else while(jp = *jobs++) 657 { 658 #ifdef JOBS 659 if(*jp == '%') 660 { 661 job_lock(); 662 pw = job_bystring(jp); 663 job_unlock(); 664 if(pw) 665 pid = pw->p_pid; 666 else 667 return; 668 } 669 else 670 #endif /* JOBS */ 671 pid = (int)strtol(jp, (char**)0, 10); 672 job_wait(-pid); 673 } 674 } 675 676 #ifdef JOBS 677 /* 678 * execute function <fun> for each job 679 */ 680 681 int job_walk(Sfio_t *file,int (*fun)(struct process*,int),int arg,char *joblist[]) 682 { 683 register struct process *pw; 684 register int r = 0; 685 register char *jobid, **jobs=joblist; 686 register struct process *px; 687 job_string = 0; 688 outfile = file; 689 by_number = 0; 690 job_lock(); 691 pw = job.pwlist; 692 if(jobs==0) 693 { 694 /* do all jobs */ 695 for(;pw;pw=px) 696 { 697 px = pw->p_nxtjob; 698 if(pw->p_env != sh.jobenv) 699 continue; 700 if((*fun)(pw,arg)) 701 r = 2; 702 } 703 } 704 else if(*jobs==0) /* current job */ 705 { 706 /* skip over non-stop jobs */ 707 while(pw && (pw->p_env!=sh.jobenv || pw->p_pgrp==0)) 708 pw = pw->p_nxtjob; 709 if((*fun)(pw,arg)) 710 r = 2; 711 } 712 else while(jobid = *jobs++) 713 { 714 job_string = jobid; 715 if(*jobid==0) 716 errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string); 717 if(*jobid == '%') 718 pw = job_bystring(jobid); 719 else 720 { 721 int pid = (int)strtol(jobid, (char**)0, 10); 722 if(pid<0) 723 jobid++; 724 while(isdigit(*jobid)) 725 jobid++; 726 if(*jobid) 727 errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string); 728 if(!(pw = job_bypid(pid))) 729 { 730 pw = &dummy; 731 pw->p_pid = pid; 732 pw->p_pgrp = pid; 733 } 734 by_number = 1; 735 } 736 if((*fun)(pw,arg)) 737 r = 2; 738 by_number = 0; 739 } 740 job_unlock(); 741 return(r); 742 } 743 744 /* 745 * send signal <sig> to background process group if not disowned 746 */ 747 int job_terminate(register struct process *pw,register int sig) 748 { 749 if(pw->p_pgrp && !(pw->p_flag&P_DISOWN)) 750 job_kill(pw,sig); 751 return(0); 752 } 753 754 /* 755 * list the given job 756 * flag JOB_LFLAG for long listing 757 * flag JOB_NFLAG for list only jobs marked for notification 758 * flag JOB_PFLAG for process id(s) only 759 */ 760 761 int job_list(struct process *pw,register int flag) 762 { 763 register struct process *px = pw; 764 register int n; 765 register const char *msg; 766 register int msize; 767 if(!pw || pw->p_job<=0) 768 return(1); 769 if(pw->p_env != sh.jobenv) 770 return(0); 771 if((flag&JOB_NFLAG) && (!(px->p_flag&P_NOTIFY)||px->p_pgrp==0)) 772 return(0); 773 if((flag&JOB_PFLAG)) 774 { 775 sfprintf(outfile,"%d\n",px->p_pgrp?px->p_pgrp:px->p_pid); 776 return(0); 777 } 778 if((px->p_flag&P_DONE) && job.waitall && !(flag&JOB_LFLAG)) 779 return(0); 780 job_lock(); 781 n = px->p_job; 782 if(px==job.pwlist) 783 msize = '+'; 784 else if(px==job.pwlist->p_nxtjob) 785 msize = '-'; 786 else 787 msize = ' '; 788 if(flag&JOB_NLFLAG) 789 sfputc(outfile,'\n'); 790 sfprintf(outfile,"[%d] %c ",n, msize); 791 do 792 { 793 n = 0; 794 if(flag&JOB_LFLAG) 795 sfprintf(outfile,"%d\t",px->p_pid); 796 if(px->p_flag&P_SIGNALLED) 797 msg = job_sigmsg((int)(px->p_exit)); 798 else if(px->p_flag&P_NOTIFY) 799 { 800 msg = sh_translate(e_done); 801 n = px->p_exit; 802 } 803 else 804 msg = sh_translate(e_running); 805 px->p_flag &= ~P_NOTIFY; 806 sfputr(outfile,msg,-1); 807 msize = strlen(msg); 808 if(n) 809 { 810 sfprintf(outfile,"(%d)",(int)n); 811 msize += (3+(n>10)+(n>100)); 812 } 813 if(px->p_flag&P_COREDUMP) 814 { 815 msg = sh_translate(e_coredump); 816 sfputr(outfile, msg, -1); 817 msize += strlen(msg); 818 } 819 sfnputc(outfile,' ',MAXMSG>msize?MAXMSG-msize:1); 820 if(flag&JOB_LFLAG) 821 px = px->p_nxtproc; 822 else 823 { 824 while(px=px->p_nxtproc) 825 px->p_flag &= ~P_NOTIFY; 826 px = 0; 827 } 828 if(!px) 829 hist_list(sh.hist_ptr,outfile,pw->p_name,0,";"); 830 else 831 sfputr(outfile, e_nlspace, -1); 832 } 833 while(px); 834 job_unlock(); 835 return(0); 836 } 837 838 /* 839 * get the process group given the job number 840 * This routine returns the process group number or -1 841 */ 842 static struct process *job_bystring(register char *ajob) 843 { 844 register struct process *pw=job.pwlist; 845 register int c; 846 if(*ajob++ != '%' || !pw) 847 return(NIL(struct process*)); 848 c = *ajob; 849 if(isdigit(c)) 850 pw = job_byjid((int)strtol(ajob, (char**)0, 10)); 851 else if(c=='+' || c=='%') 852 ; 853 else if(c=='-') 854 { 855 if(pw) 856 pw = job.pwlist->p_nxtjob; 857 } 858 else 859 pw = job_byname(ajob); 860 if(pw && pw->p_flag) 861 return(pw); 862 return(NIL(struct process*)); 863 } 864 865 /* 866 * Kill a job or process 867 */ 868 869 int job_kill(register struct process *pw,register int sig) 870 { 871 register pid_t pid; 872 register int r; 873 const char *msg; 874 #ifdef SIGTSTP 875 int stopsig = (sig==SIGSTOP||sig==SIGTSTP||sig==SIGTTIN||sig==SIGTTOU); 876 #else 877 # define stopsig 1 878 #endif /* SIGTSTP */ 879 job_lock(); 880 errno = ECHILD; 881 if(pw==0) 882 goto error; 883 pid = pw->p_pid; 884 if(by_number) 885 { 886 if(pid==0 && job.jobcontrol) 887 r = job_walk(outfile, job_kill,sig, (char**)0); 888 #ifdef SIGTSTP 889 if(sig==SIGSTOP && pid==sh.pid && sh.ppid==1) 890 { 891 /* can't stop login shell */ 892 errno = EPERM; 893 r = -1; 894 } 895 else 896 { 897 if(pid>=0) 898 { 899 if((r = kill(pid,sig))>=0 && !stopsig) 900 { 901 if(pw->p_flag&P_STOPPED) 902 pw->p_flag &= ~(P_STOPPED|P_SIGNALLED); 903 if(sig) 904 kill(pid,SIGCONT); 905 } 906 } 907 else 908 { 909 if((r = killpg(-pid,sig))>=0 && !stopsig) 910 { 911 job_unstop(job_bypid(pw->p_pid)); 912 if(sig) 913 killpg(-pid,SIGCONT); 914 } 915 } 916 } 917 #else 918 if(pid>=0) 919 r = kill(pid,sig); 920 else 921 r = killpg(-pid,sig); 922 #endif /* SIGTSTP */ 923 } 924 else 925 { 926 if(pid = pw->p_pgrp) 927 { 928 r = killpg(pid,sig); 929 #ifdef SIGTSTP 930 if(r>=0 && (sig==SIGHUP||sig==SIGTERM || sig==SIGCONT)) 931 job_unstop(pw); 932 #endif /* SIGTSTP */ 933 if(r>=0) 934 sh_delay(.05); 935 } 936 while(pw && pw->p_pgrp==0 && (r=kill(pw->p_pid,sig))>=0) 937 { 938 #ifdef SIGTSTP 939 if(sig==SIGHUP || sig==SIGTERM) 940 kill(pw->p_pid,SIGCONT); 941 #endif /* SIGTSTP */ 942 pw = pw->p_nxtproc; 943 } 944 } 945 if(r<0 && job_string) 946 { 947 error: 948 if(pw && by_number) 949 msg = sh_translate(e_no_proc); 950 else 951 msg = sh_translate(e_no_job); 952 if(errno == EPERM) 953 msg = sh_translate(e_access); 954 sfprintf(sfstderr,"kill: %s: %s\n",job_string, msg); 955 r = 2; 956 } 957 sh_delay(.001); 958 job_unlock(); 959 return(r); 960 } 961 962 /* 963 * Get process structure from first letters of jobname 964 * 965 */ 966 967 static struct process *job_byname(char *name) 968 { 969 register struct process *pw = job.pwlist; 970 register struct process *pz = 0; 971 register int *flag = 0; 972 register char *cp = name; 973 int offset; 974 if(!sh.hist_ptr) 975 return(NIL(struct process*)); 976 if(*cp=='?') 977 cp++,flag= &offset; 978 for(;pw;pw=pw->p_nxtjob) 979 { 980 if(hist_match(sh.hist_ptr,pw->p_name,cp,flag)>=0) 981 { 982 if(pz) 983 errormsg(SH_DICT,ERROR_exit(1),e_jobusage,name-1); 984 pz = pw; 985 } 986 } 987 return(pz); 988 } 989 990 #else 991 # define job_set(x) 992 # define job_reset(x) 993 #endif /* JOBS */ 994 995 996 997 /* 998 * Initialize the process posting array 999 */ 1000 1001 void job_clear(void) 1002 { 1003 register struct process *pw, *px; 1004 register struct process *pwnext; 1005 register int j = BYTE(sh.lim.child_max); 1006 register struct jobsave *jp,*jpnext; 1007 job_lock(); 1008 for(pw=job.pwlist; pw; pw=pwnext) 1009 { 1010 pwnext = pw->p_nxtjob; 1011 while(px=pw) 1012 { 1013 pw = pw->p_nxtproc; 1014 free((void*)px); 1015 } 1016 } 1017 for(jp=bck.list; jp;jp=jpnext) 1018 { 1019 jpnext = jp->next; 1020 free((void*)jp); 1021 } 1022 bck.list = 0; 1023 if(njob_savelist < NJOB_SAVELIST) 1024 init_savelist(); 1025 job.pwlist = NIL(struct process*); 1026 job.numpost=0; 1027 job.waitall = 0; 1028 job.curpgid = 0; 1029 job.toclear = 0; 1030 if(!job.freejobs) 1031 job.freejobs = (unsigned char*)malloc((unsigned)(j+1)); 1032 while(j >=0) 1033 job.freejobs[j--] = 0; 1034 job_unlock(); 1035 } 1036 1037 /* 1038 * put the process <pid> on the process list and return the job number 1039 * if non-zero, <join> is the process id of the job to join 1040 */ 1041 1042 int job_post(pid_t pid, pid_t join) 1043 { 1044 register struct process *pw; 1045 register History_t *hp = sh.hist_ptr; 1046 sh.jobenv = sh.curenv; 1047 if(njob_savelist < NJOB_SAVELIST) 1048 init_savelist(); 1049 if(job.toclear) 1050 { 1051 job_clear(); 1052 return(0); 1053 } 1054 job_lock(); 1055 if(pw = job_bypid(pid)) 1056 job_unpost(pw,0); 1057 if(join && (pw=job_bypid(join))) 1058 { 1059 /* if job to join is not first move it to front */ 1060 if((pw=job_byjid(pw->p_job)) != job.pwlist) 1061 { 1062 job_unlink(pw); 1063 pw->p_nxtjob = job.pwlist; 1064 job.pwlist = pw; 1065 } 1066 } 1067 if(pw=freelist) 1068 freelist = pw->p_nxtjob; 1069 else 1070 pw = new_of(struct process,0); 1071 job.numpost++; 1072 if(join && job.pwlist) 1073 { 1074 /* join existing current job */ 1075 pw->p_nxtjob = job.pwlist->p_nxtjob; 1076 pw->p_nxtproc = job.pwlist; 1077 pw->p_job = job.pwlist->p_job; 1078 } 1079 else 1080 { 1081 /* create a new job */ 1082 while((pw->p_job = job_alloc()) < 0) 1083 job_wait((pid_t)1); 1084 pw->p_nxtjob = job.pwlist; 1085 pw->p_nxtproc = 0; 1086 } 1087 job.pwlist = pw; 1088 pw->p_env = sh.curenv; 1089 pw->p_pid = pid; 1090 pw->p_flag = P_EXITSAVE; 1091 pw->p_exit = sh.xargexit; 1092 sh.xargexit = 0; 1093 if(sh_isstate(SH_MONITOR)) 1094 { 1095 if(killpg(job.curpgid,0)<0 && errno==ESRCH) 1096 job.curpgid = pid; 1097 pw->p_fgrp = job.curpgid; 1098 } 1099 else 1100 pw->p_fgrp = 0; 1101 pw->p_pgrp = pw->p_fgrp; 1102 #ifdef DEBUG 1103 sfprintf(sfstderr,"ksh: job line %4d: post pid=%d critical=%d job=%d pid=%d pgid=%d savesig=%d join=%d\n",__LINE__,getpid(),job.in_critical,pw->p_job, 1104 pw->p_pid,pw->p_pgrp,job.savesig,join); 1105 sfsync(sfstderr); 1106 #endif /* DEBUG */ 1107 #ifdef JOBS 1108 if(hp && !sh_isstate(SH_PROFILE)) 1109 pw->p_name=hist_tell(sh.hist_ptr,(int)hp->histind-1); 1110 else 1111 pw->p_name = -1; 1112 #endif /* JOBS */ 1113 if(pid==lastpid) 1114 { 1115 int val = job_chksave(pid); 1116 pw->p_exit = val>0?val:0; 1117 if(pw->p_exit==SH_STOPSIG) 1118 { 1119 pw->p_flag |= (P_SIGNALLED|P_STOPPED); 1120 pw->p_exit = 0; 1121 } 1122 else 1123 pw->p_flag |= (P_DONE|P_NOTIFY); 1124 } 1125 lastpid = 0; 1126 job_unlock(); 1127 return(pw->p_job); 1128 } 1129 1130 /* 1131 * Returns a process structure give a process id 1132 */ 1133 1134 static struct process *job_bypid(pid_t pid) 1135 { 1136 register struct process *pw, *px; 1137 for(pw=job.pwlist; pw; pw=pw->p_nxtjob) 1138 for(px=pw; px; px=px->p_nxtproc) 1139 { 1140 if(px->p_pid==pid) 1141 return(px); 1142 } 1143 return(NIL(struct process*)); 1144 } 1145 1146 /* 1147 * return a pointer to a job given the job id 1148 */ 1149 1150 static struct process *job_byjid(int jobid) 1151 { 1152 register struct process *pw; 1153 for(pw=job.pwlist;pw; pw = pw->p_nxtjob) 1154 { 1155 if(pw->p_job==jobid) 1156 break; 1157 } 1158 return(pw); 1159 } 1160 1161 /* 1162 * print a signal message 1163 */ 1164 static void job_prmsg(register struct process *pw) 1165 { 1166 if(pw->p_exit!=SIGINT && pw->p_exit!=SIGPIPE) 1167 { 1168 register const char *msg, *dump; 1169 msg = job_sigmsg((int)(pw->p_exit)); 1170 msg = sh_translate(msg); 1171 if(pw->p_flag&P_COREDUMP) 1172 dump = sh_translate(e_coredump); 1173 else 1174 dump = ""; 1175 if(sh_isstate(SH_INTERACTIVE)) 1176 sfprintf(sfstderr,"%s%s\n",msg,dump); 1177 else 1178 errormsg(SH_DICT,2,"%d: %s%s",pw->p_pid,msg,dump); 1179 } 1180 } 1181 1182 /* 1183 * Wait for process pid to complete 1184 * If pid < -1, then wait can be interrupted, -pid is waited for (wait builtin) 1185 * pid=0 to unpost all done processes 1186 * pid=1 to wait for at least one process to complete 1187 * pid=-1 to wait for all runing processes 1188 */ 1189 1190 void job_wait(register pid_t pid) 1191 { 1192 register struct process *pw=0,*px; 1193 register int jobid = 0; 1194 int nochild; 1195 char intr = 0; 1196 if(pid <= 0) 1197 { 1198 if(pid==0) 1199 goto done; 1200 pid = -pid; 1201 intr = 1; 1202 } 1203 job_lock(); 1204 if(pid > 1) 1205 { 1206 if(!(pw=job_bypid(pid))) 1207 { 1208 /* check to see whether job status has been saved */ 1209 if((sh.exitval = job_chksave(pid)) < 0) 1210 sh.exitval = ERROR_NOENT; 1211 exitset(); 1212 job_unlock(); 1213 return; 1214 } 1215 else if(intr && pw->p_env!=sh.curenv) 1216 { 1217 sh.exitval = ERROR_NOENT; 1218 job_unlock(); 1219 return; 1220 } 1221 jobid = pw->p_job; 1222 if(!intr) 1223 pw->p_flag &= ~P_EXITSAVE; 1224 if(pw->p_pgrp && job.parent!= (pid_t)-1) 1225 job_set(job_byjid(jobid)); 1226 } 1227 #ifdef DEBUG 1228 sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d job=%d pid=%d\n",__LINE__,getpid(),job.in_critical,jobid,pid); 1229 if(pw) 1230 sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d flags=%o\n",__LINE__,getpid(),job.in_critical,pw->p_flag); 1231 #endif /* DEBUG*/ 1232 errno = 0; 1233 while(1) 1234 { 1235 if(job.waitsafe) 1236 { 1237 for(px=job.pwlist;px; px = px->p_nxtjob) 1238 { 1239 if(px!=pw && (px->p_flag&P_NOTIFY)) 1240 { 1241 if(sh_isoption(SH_NOTIFY)) 1242 { 1243 outfile = sfstderr; 1244 job_list(px,JOB_NFLAG|JOB_NLFLAG); 1245 sfsync(sfstderr); 1246 } 1247 else if(!sh_isoption(SH_INTERACTIVE) && (px->p_flag&P_SIGNALLED)) 1248 { 1249 job_prmsg(px); 1250 px->p_flag &= ~P_NOTIFY; 1251 } 1252 } 1253 } 1254 } 1255 if(pw && (pw->p_flag&(P_DONE|P_STOPPED))) 1256 { 1257 #ifdef SIGTSTP 1258 if(pw->p_flag&P_STOPPED) 1259 { 1260 pw->p_flag |= P_EXITSAVE; 1261 if(sh_isoption(SH_INTERACTIVE) && !sh_isstate(SH_FORKED)) 1262 { 1263 if( pw->p_exit!=SIGTTIN && pw->p_exit!=SIGTTOU) 1264 break; 1265 1266 killpg(pw->p_pgrp,SIGCONT); 1267 } 1268 else /* ignore stop when non-interactive */ 1269 pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED|P_EXITSAVE); 1270 } 1271 else 1272 #endif /* SIGTSTP */ 1273 { 1274 if(pw->p_flag&P_SIGNALLED) 1275 { 1276 pw->p_flag &= ~P_NOTIFY; 1277 job_prmsg(pw); 1278 } 1279 else if(pw->p_flag&P_DONE) 1280 pw->p_flag &= ~P_NOTIFY; 1281 if(pw->p_job==jobid) 1282 { 1283 px = job_byjid(jobid); 1284 /* last process in job */ 1285 if(sh_isoption(SH_PIPEFAIL)) 1286 { 1287 /* last non-zero exit */ 1288 for(;px;px=px->p_nxtproc) 1289 { 1290 if(px->p_exit) 1291 break; 1292 } 1293 if(!px) 1294 px = pw; 1295 } 1296 else if(px!=pw) 1297 px = 0; 1298 if(px) 1299 { 1300 sh.exitval=px->p_exit; 1301 if(px->p_flag&P_SIGNALLED) 1302 sh.exitval |= SH_EXITSIG; 1303 if(intr) 1304 px->p_flag &= ~P_EXITSAVE; 1305 } 1306 } 1307 if(!job.waitall) 1308 { 1309 if(!sh_isoption(SH_PIPEFAIL)) 1310 job_unpost(pw,1); 1311 break; 1312 } 1313 else if(!(px=job_unpost(pw,1))) 1314 break; 1315 pw = px; 1316 continue; 1317 } 1318 } 1319 sfsync(sfstderr); 1320 job.waitsafe = 0; 1321 nochild = job_reap(job.savesig); 1322 if(job.waitsafe) 1323 continue; 1324 if(nochild) 1325 break; 1326 if(sh.sigflag[SIGALRM]&SH_SIGTRAP) 1327 sh_timetraps(); 1328 if((intr && sh.trapnote) || (pid==1 && !intr)) 1329 break; 1330 } 1331 job_unlock(); 1332 if(pid==1) 1333 return; 1334 exitset(); 1335 if(pw->p_pgrp) 1336 { 1337 job_reset(pw); 1338 /* propogate keyboard interrupts to parent */ 1339 if((pw->p_flag&P_SIGNALLED) && pw->p_exit==SIGINT && !(sh.sigflag[SIGINT]&SH_SIGOFF)) 1340 sh_fault(SIGINT); 1341 #ifdef SIGTSTP 1342 else if((pw->p_flag&P_STOPPED) && pw->p_exit==SIGTSTP) 1343 { 1344 job.parent = 0; 1345 sh_fault(SIGTSTP); 1346 } 1347 #endif /* SIGTSTP */ 1348 } 1349 else 1350 tty_set(-1, 0, NIL(struct termios*)); 1351 done: 1352 if(!job.waitall && sh_isoption(SH_PIPEFAIL)) 1353 return; 1354 if(!sh.intrap) 1355 { 1356 job_lock(); 1357 for(pw=job.pwlist; pw; pw=px) 1358 { 1359 px = pw->p_nxtjob; 1360 job_unpost(pw,0); 1361 } 1362 job_unlock(); 1363 } 1364 } 1365 1366 /* 1367 * move job to foreground if bgflag == 'f' 1368 * move job to background if bgflag == 'b' 1369 * disown job if bgflag == 'd' 1370 */ 1371 1372 int job_switch(register struct process *pw,int bgflag) 1373 { 1374 register const char *msg; 1375 job_lock(); 1376 if(!pw || !(pw=job_byjid((int)pw->p_job))) 1377 { 1378 job_unlock(); 1379 return(1); 1380 } 1381 if(bgflag=='d') 1382 { 1383 for(; pw; pw=pw->p_nxtproc) 1384 pw->p_flag |= P_DISOWN; 1385 job_unlock(); 1386 return(0); 1387 } 1388 #ifdef SIGTSTP 1389 if(bgflag=='b') 1390 { 1391 sfprintf(outfile,"[%d]\t",(int)pw->p_job); 1392 sh.bckpid = pw->p_pid; 1393 msg = "&"; 1394 } 1395 else 1396 { 1397 job_unlink(pw); 1398 pw->p_nxtjob = job.pwlist; 1399 job.pwlist = pw; 1400 msg = ""; 1401 } 1402 hist_list(sh.hist_ptr,outfile,pw->p_name,'&',";"); 1403 sfputr(outfile,msg,'\n'); 1404 sfsync(outfile); 1405 if(bgflag=='f') 1406 { 1407 if(!(pw=job_unpost(pw,1))) 1408 { 1409 job_unlock(); 1410 return(1); 1411 } 1412 job.waitall = 1; 1413 pw->p_flag |= P_FG; 1414 job_wait(pw->p_pid); 1415 job.waitall = 0; 1416 } 1417 else if(pw->p_flag&P_STOPPED) 1418 job_unstop(pw); 1419 #endif /* SIGTSTP */ 1420 job_unlock(); 1421 return(0); 1422 } 1423 1424 1425 #ifdef SIGTSTP 1426 /* 1427 * Set the foreground group associated with a job 1428 */ 1429 1430 static void job_fgrp(register struct process *pw, int newgrp) 1431 { 1432 for(; pw; pw=pw->p_nxtproc) 1433 pw->p_fgrp = newgrp; 1434 } 1435 1436 /* 1437 * turn off STOP state of a process group and send CONT signals 1438 */ 1439 1440 static void job_unstop(register struct process *px) 1441 { 1442 register struct process *pw; 1443 register int num = 0; 1444 for(pw=px ;pw ;pw=pw->p_nxtproc) 1445 { 1446 if(pw->p_flag&P_STOPPED) 1447 { 1448 num++; 1449 pw->p_flag &= ~(P_STOPPED|P_SIGNALLED|P_NOTIFY); 1450 } 1451 } 1452 if(num!=0) 1453 { 1454 if(px->p_fgrp != px->p_pgrp) 1455 killpg(px->p_fgrp,SIGCONT); 1456 killpg(px->p_pgrp,SIGCONT); 1457 } 1458 } 1459 #endif /* SIGTSTP */ 1460 1461 /* 1462 * remove a job from table 1463 * If all the processes have not completed, unpost first non-completed process 1464 * Otherwise the job is removed and job_unpost returns NULL. 1465 * pwlist is reset if the first job is removed 1466 * if <notify> is non-zero, then jobs with pending notifications are unposted 1467 */ 1468 1469 static struct process *job_unpost(register struct process *pwtop,int notify) 1470 { 1471 register struct process *pw; 1472 /* make sure all processes are done */ 1473 #ifdef DEBUG 1474 sfprintf(sfstderr,"ksh: job line %4d: drop pid=%d critical=%d pid=%d env=%d\n",__LINE__,getpid(),job.in_critical,pwtop->p_pid,pwtop->p_env); 1475 sfsync(sfstderr); 1476 #endif /* DEBUG */ 1477 pwtop = pw = job_byjid((int)pwtop->p_job); 1478 for(; pw && (pw->p_flag&P_DONE)&&(notify||!(pw->p_flag&P_NOTIFY)||pw->p_env); pw=pw->p_nxtproc); 1479 if(pw) 1480 return(pw); 1481 /* all processes complete, unpost job */ 1482 job_unlink(pwtop); 1483 for(pw=pwtop; pw; pw=pw->p_nxtproc) 1484 { 1485 /* save the exit status for background jobs */ 1486 if(pw->p_flag&P_EXITSAVE) 1487 { 1488 struct jobsave *jp; 1489 /* save status for future wait */ 1490 if(bck.count++ > sh.lim.child_max) 1491 job_chksave(0); 1492 if(jp = jobsave_create(pw->p_pid)) 1493 { 1494 jp->next = bck.list; 1495 bck.list = jp; 1496 jp->exitval = pw->p_exit; 1497 if(pw->p_flag&P_SIGNALLED) 1498 jp->exitval |= SH_EXITSIG; 1499 } 1500 pw->p_flag &= ~P_EXITSAVE; 1501 } 1502 pw->p_flag &= ~P_DONE; 1503 job.numpost--; 1504 pw->p_nxtjob = freelist; 1505 freelist = pw; 1506 } 1507 #ifdef DEBUG 1508 sfprintf(sfstderr,"ksh: job line %4d: free pid=%d critical=%d job=%d\n",__LINE__,getpid(),job.in_critical,pwtop->p_job); 1509 sfsync(sfstderr); 1510 #endif /* DEBUG */ 1511 job_free((int)pwtop->p_job); 1512 return((struct process*)0); 1513 } 1514 1515 /* 1516 * unlink a job form the job list 1517 */ 1518 static void job_unlink(register struct process *pw) 1519 { 1520 register struct process *px; 1521 if(pw==job.pwlist) 1522 { 1523 job.pwlist = pw->p_nxtjob; 1524 job.curpgid = 0; 1525 return; 1526 } 1527 for(px=job.pwlist;px;px=px->p_nxtjob) 1528 if(px->p_nxtjob == pw) 1529 { 1530 px->p_nxtjob = pw->p_nxtjob; 1531 return; 1532 } 1533 } 1534 1535 /* 1536 * get an unused job number 1537 * freejobs is a bit vector, 0 is unused 1538 */ 1539 1540 static int job_alloc(void) 1541 { 1542 register int j=0; 1543 register unsigned mask = 1; 1544 register unsigned char *freeword; 1545 register int jmax = BYTE(sh.lim.child_max); 1546 /* skip to first word with a free slot */ 1547 for(j=0;job.freejobs[j] == UCHAR_MAX; j++); 1548 if(j >= jmax) 1549 { 1550 register struct process *pw; 1551 for(j=1; j < sh.lim.child_max; j++) 1552 { 1553 if((pw=job_byjid(j))&& !job_unpost(pw,0)) 1554 break; 1555 } 1556 j /= CHAR_BIT; 1557 if(j >= jmax) 1558 return(-1); 1559 } 1560 freeword = &job.freejobs[j]; 1561 j *= CHAR_BIT; 1562 for(j++;mask&(*freeword);j++,mask <<=1); 1563 *freeword |= mask; 1564 return(j); 1565 } 1566 1567 /* 1568 * return a job number 1569 */ 1570 1571 static void job_free(register int n) 1572 { 1573 register int j = (--n)/CHAR_BIT; 1574 register unsigned mask; 1575 n -= j*CHAR_BIT; 1576 mask = 1 << n; 1577 job.freejobs[j] &= ~mask; 1578 } 1579 1580 static char *job_sigmsg(int sig) 1581 { 1582 static char signo[40]; 1583 #ifdef apollo 1584 /* 1585 * This code handles the formatting for the apollo specific signal 1586 * SIGAPOLLO. 1587 */ 1588 extern char *apollo_error(void); 1589 1590 if ( sig == SIGAPOLLO ) 1591 return( apollo_error() ); 1592 #endif /* apollo */ 1593 if(sig<sh.sigmax && sh.sigmsg[sig]) 1594 return(sh.sigmsg[sig]); 1595 #if defined(SIGRTMIN) && defined(SIGRTMAX) 1596 if(sig>=SIGRTMIN && sig<=SIGRTMAX) 1597 { 1598 static char sigrt[20]; 1599 sfsprintf(sigrt,sizeof(sigrt),"SIGRTMIN+%d",sig-SIGRTMIN); 1600 return(sigrt); 1601 } 1602 #endif 1603 sfsprintf(signo,sizeof(signo),sh_translate(e_signo),sig); 1604 return(signo); 1605 } 1606 1607 /* 1608 * see whether exit status has been saved and delete it 1609 * if pid==0, then oldest saved process is deleted 1610 * If pid is not found a -1 is returned. 1611 */ 1612 static int job_chksave(register pid_t pid) 1613 { 1614 register struct jobsave *jp = bck.list, *jpold=0; 1615 register int r= -1; 1616 while(jp) 1617 { 1618 if(jp->pid==pid) 1619 break; 1620 if(pid==0 && !jp->next) 1621 break; 1622 jpold = jp; 1623 jp = jp->next; 1624 } 1625 if(jp) 1626 { 1627 r = 0; 1628 if(pid) 1629 r = jp->exitval; 1630 if(jpold) 1631 jpold->next = jp->next; 1632 else 1633 bck.list = jp->next; 1634 bck.count--; 1635 if(njob_savelist < NJOB_SAVELIST) 1636 { 1637 njob_savelist++; 1638 jp->next = job_savelist; 1639 job_savelist = jp; 1640 } 1641 else 1642 free((void*)jp); 1643 } 1644 return(r); 1645 } 1646 1647 void *job_subsave(void) 1648 { 1649 struct back_save *bp = new_of(struct back_save,0); 1650 job_lock(); 1651 *bp = bck; 1652 bck.count = 0; 1653 bck.list = 0; 1654 job_unlock(); 1655 return((void*)bp); 1656 } 1657 1658 void job_subrestore(void* ptr) 1659 { 1660 register struct jobsave *jp,*jpnext; 1661 register struct back_save *bp = (struct back_save*)ptr; 1662 register struct process *pw, *px, *pwnext; 1663 job_lock(); 1664 for(pw=job.pwlist; pw; pw=pwnext) 1665 { 1666 pwnext = pw->p_nxtjob; 1667 if(pw->p_env != sh.curenv) 1668 continue; 1669 for(px=pw; px; px=px->p_nxtproc) 1670 px->p_flag |= P_DONE; 1671 job_unpost(pw,0); 1672 } 1673 for(jp=bck.list,bck= *bp; jp; jp=jpnext) 1674 { 1675 jpnext = jp->next; 1676 free((void*)jp); 1677 } 1678 free(ptr); 1679 job_unlock(); 1680 } 1681 1682 int sh_waitsafe(void) 1683 { 1684 return(job.waitsafe); 1685 } 1686 1687 void job_fork(pid_t parent) 1688 { 1689 #ifdef DEBUG 1690 sfprintf(sfstderr,"ksh: job line %4d: fork pid=%d critical=%d parent=%d\n",__LINE__,getpid(),job.in_critical,parent); 1691 #endif /* DEBUG */ 1692 switch (parent) 1693 { 1694 case -1: 1695 job_lock(); 1696 break; 1697 case 0: 1698 job_unlock(); 1699 job.waitsafe = 0; 1700 job.in_critical = 0; 1701 break; 1702 default: 1703 job_unlock(); 1704 break; 1705 } 1706 } 1707