1 /* 2 3 * Copyright (c) 1984, 1985, 1986 AT&T 4 * All Rights Reserved 5 6 * THIS IS UNPUBLISHED PROPRIETARY SOURCE 7 * CODE OF AT&T. 8 * The copyright notice above does not 9 * evidence any actual or intended 10 * publication of such source code. 11 12 */ 13 /* @(#)xec.c 1.1 */ 14 /* 15 * UNIX shell 16 * 17 * S. R. Bourne 18 * Rewritten by David Korn 19 * AT&T Bell Laboratories 20 * 21 */ 22 23 #include <sys/types.h> 24 #include <sys/times.h> 25 #include <errno.h> 26 #ifdef SXT 27 #include <sys/tty.h> 28 #include <sys/sxt.h> 29 #endif /* SXT */ 30 #include "defs.h" 31 #include "sym.h" 32 #include "mode.h" 33 #include "flags.h" 34 #include "name.h" 35 #include "brkincr.h" 36 #include "stak.h" 37 #include "builtins.h" 38 #include "shtype.h" 39 #include "jobs.h" 40 #include "io.h" 41 #ifdef BSD 42 #define TIC_SEC 60 43 #include <sys/timeb.h> 44 #endif /* BSD */ 45 46 /* These routines are defined by this module */ 47 int execute(); 48 void trace_command(); 49 50 /* These routines are referenced by this module */ 51 extern char **arg_build(); 52 extern DOLPTR arg_use(); 53 extern DOLPTR arg_free(); 54 extern void assign(); 55 extern void await(); 56 extern FILE *chkopen(); 57 extern void builtin(); 58 extern void chktrap(); 59 extern void chkpipe(); 60 extern void done(); 61 extern void execa(); 62 extern void exfunct(); 63 extern void exitsh(); 64 extern void failed(); 65 extern void free(); 66 extern NAMPTR findnod(); 67 extern char *getpath(); 68 extern char *heap(); 69 extern char *itos(); 70 extern NAMPTR lookup(); 71 extern char *macro(); 72 extern char *mactrim(); 73 extern void mem_scope(); 74 extern void mem_unscope(); 75 extern char *movstr(); 76 extern char *malloc(); 77 extern void oldsigs(); 78 extern void p_sub(); 79 extern void p_num(); 80 extern void p_str(); 81 extern void p_time(); 82 extern void p_flush(); 83 extern void p_setout(); 84 extern void p_list(); 85 extern void pipe_close(); 86 extern void postclr(); 87 extern char *qvalup(); 88 extern void restore(); 89 extern void rmtemp(); 90 extern char *strcpy(); 91 extern void setlist(); 92 extern void swap_iodoc_nm(); 93 extern void sync_io(); 94 extern void tdystak(); 95 extern long times(); 96 #ifdef DEVFD 97 extern void close_pipes(); 98 #endif /* DEVFD */ 99 #ifdef VFORK 100 extern int vfork_check(); 101 extern int vfork_save(); 102 extern void vfork_restore(); 103 #endif /* VFORK */ 104 105 static int trim_eq(); 106 static char locbuf[TMPSIZ]; /* store last argument here if it fits */ 107 108 109 /* ======== command execution ========*/ 110 111 112 /* VARARGS */ 113 execute(argt, execflg, apf1, apf2) 114 TREPTR argt; 115 unsigned execflg; 116 FILE *apf1[],*apf2[]; 117 { 118 /* `stakbot' is preserved by this routine */ 119 register TREPTR t; 120 STKPTR sav=savstak(); 121 FILE *inpipe[2],*otpipe[2]; 122 FILE **pf1 = apf1; 123 FILE **pf2 = apf2; 124 unsigned errorflg = (execflg&ERRFLG); 125 #ifdef VFORK 126 int v_fork; 127 #endif /* VFORK */ 128 if(trapnote&SIGSET) 129 exitsh(SIGFAIL); 130 if(errorflg==0) 131 states &= ~ERRFLG; 132 if((t=argt) && execbrk==0) 133 { 134 register int type; 135 char **com; 136 int argn; 137 char *com0 = NIL; 138 type = t->tretyp; 139 oldexit=exitval; 140 exitval=0; 141 switch(type&COMMSK) 142 { 143 case TCOM: 144 { 145 register IOPTR io; 146 register ARGPTR argp; 147 NAMPTR np; 148 type >>= (COMBITS+1); 149 cmdline = ((COMPTR)t)->comline; 150 com = arg_build(&argn,((COMPTR)t)); 151 if(t->tretyp&COMSCAN) 152 { 153 argp = ((COMPTR)t)->comarg; 154 if(argp && (argp->argflag&A_RAW)==0) 155 type = syslook(com[0],commands); 156 if(trapnote&SIGSET) 157 exitsh(SIGFAIL); 158 } 159 com0 = com[0]; 160 argp = ((COMPTR)t)->comset; 161 io = t->treio; 162 if(argn==0 || (type>0 && type<=SYSSPECIAL)) 163 { 164 setlist(argp, 0); 165 argp = NULL; 166 } 167 if((io||argn) && is_option(NOEXEC)==0) 168 /* print command if EXECPR */ 169 { 170 if(argn==0) 171 { 172 /* fake a built-in */ 173 argn=1; 174 type = SYSMAX; 175 } 176 /* set +x doesn't echo */ 177 else if(type!=SYSSET) 178 { 179 trace_command(com); 180 } 181 if(io) 182 p_flush(); 183 #ifdef apollo 184 if(is_option(INPROC) && type==0 185 && (states&FORKED)==0 && 186 !findnod(com0,prnames,CHK_FOR)) 187 { 188 type = SYSINPROCESS; 189 com--; 190 argn++; 191 } 192 #endif /* apollo */ 193 /* check for builtins */ 194 if(type) 195 { 196 /* failures on built-ins not fatal */ 197 jmp_buf retbuf; 198 jmp_buf *savreturn = freturn; 199 int indx = topfd; 200 int scope=0; 201 if(type>=SYSNULL) 202 freturn = (jmp_buf*)retbuf; 203 if(setjmp(retbuf) == 0) 204 { 205 int flag = 1; 206 if(type>=SYSNULL) 207 states |= BUILTIN; 208 else 209 { 210 flag = (type!=SYSLOGIN); 211 if(type==SYSEXEC) 212 flag = -(com[1]==0); 213 } 214 indx = initio(io,flag); 215 if(argp) 216 { 217 mem_scope(argp); 218 scope++; 219 } 220 builtin(type,argn,com,t); 221 } 222 states &= ~BUILTIN; 223 freturn = savreturn; 224 if(scope) 225 mem_unscope(); 226 restore(indx); 227 goto setexit; 228 } 229 /* check for functions */ 230 if((np=findnod(com0,prnames,CHK_FOR)) 231 && np->value.namval.ip) 232 { 233 int indx; 234 indx = initio(io,1); 235 exfunct((TREPTR)(*funtree(np)) 236 ,com 237 ,execflg|(attest(np,T_FLAG)?EXECPR:0) 238 ,((COMPTR)t)->comset); 239 restore(indx); 240 goto setexit; 241 } 242 /* track alias if possible */ 243 getpath(com0); 244 } 245 else if(io==0) 246 { 247 setexit: 248 exitset(); 249 chktrap(); 250 break; 251 } 252 type = TCOM; 253 } 254 case TFORK: 255 { 256 int no_fork; 257 sync_io(); 258 #ifdef SXT 259 /* find job number and create synchronization pipe */ 260 if((jobstat.cur_job = next_job()) < jobstat.maxjob) 261 if(pipe(jobstat.pipe)<0) 262 jobstat.maxjob = 0; 263 #endif /* SXT */ 264 no_fork = (execflg&1) && (type&(FAMP|FPOU))==0; 265 if(no_fork) 266 parent=0; 267 else 268 /* FORKLIM is the max period between forks - 269 power of 2 usually. Currently shell tries after 270 2,4,8,16, and 32 seconds and then quits */ 271 { 272 register int forkcnt=1; 273 if(type&FTMP) 274 { 275 link_iodocs(iotemp); 276 linked = 1; 277 } 278 if((type&(FPCL|FPIN|FPOU)) == (FPIN|FPOU)) 279 /* set up pipe for cooperating process */ 280 { 281 if(cpid) 282 failed(cmdadr,pexists); 283 chkpipe(pf2=otpipe); 284 cpipe[INPIPE] = frenumber(pf2[INPIPE],CINPIPE); 285 chkpipe(pf1=inpipe); 286 cpipe[OTPIPE] = frenumber(pf1[OTPIPE],COTPIPE); 287 } 288 #ifdef VFORK 289 if(v_fork=vfork_check(t)) 290 vfork_save(); 291 while((parent=(v_fork?vfork():fork())) == -1) 292 #else 293 while((parent=fork()) == -1) 294 #endif /* VFORK */ 295 { 296 if((forkcnt *= 2) > FORKLIM) 297 { 298 switch(errno) 299 { 300 case ENOMEM: 301 error(noswap); 302 break; 303 default: 304 case EAGAIN: 305 error(nofork); 306 break; 307 } 308 } 309 if(trapnote&SIGSET) 310 exitsh(SIGFAIL); 311 alarm(forkcnt); 312 pause(); 313 alarm(0); 314 } 315 } 316 317 if(parent) 318 /* This is the parent branch of fork; */ 319 /* it may or may not wait for the child. */ 320 { 321 register int pno; 322 #ifdef VFORK 323 if(v_fork) 324 vfork_restore(); 325 #endif /* VFORK */ 326 #ifdef JOBS 327 # ifdef SXT 328 if(jobstat.pipe[1] > 0) 329 close(jobstat.pipe[1]); 330 # endif /* SXT */ 331 /* assign each pipeline its own process group */ 332 if(jobstat.j_flag==0||(states&MONITOR)==0) 333 jobstat.cur_pgrp = parent; 334 #endif /* JOBS */ 335 if(type&FPCL) 336 fclose(pf1[INPIPE]); 337 else if((type&FPIN)&&(type&FPOU)) 338 { 339 cpid = parent; 340 fclose(pf1[INPIPE]); 341 fclose(pf2[OTPIPE]); 342 } 343 if((type&(FAMP|FPOU))==0) 344 { 345 #ifdef DEVFD 346 close_pipes(); 347 #endif /* DEVFD */ 348 await(parent,0); 349 } 350 else if(type&(FPOU|FPIN)) 351 { 352 int flag; 353 if(cpid==parent) 354 flag = 0; 355 #ifdef JOBS 356 else 357 flag = P_PIPEJOB; 358 pno = post(parent,flag); 359 #else 360 pno = post(parent); 361 #endif /* JOBS */ 362 } 363 else 364 { 365 #ifdef JOBS 366 pno = post(parent,0); 367 #else 368 pno = post(parent); 369 #endif 370 movstr(itos(parent),pcsadr); 371 } 372 if((type&FPRS) && (states&TTYFLG)) 373 { 374 p_setout(stderr); 375 #ifdef JOBS 376 /* print job number */ 377 p_sub(pno,'\t'); 378 #endif /* JOBS */ 379 p_num(parent,NL); 380 } 381 chktrap(); 382 break; 383 } 384 385 else 386 /* 387 * this is the FORKED branch (child) of execute 388 */ 389 { 390 if(standout != stdout) 391 standout = frenumber(standout,1); 392 states |= FORKED; 393 off_option(HASHALL); 394 if(no_fork==0) 395 { 396 states &= ~(RM_TMP|IS_TMP); 397 states |= NO_TMP; 398 if(linked == 1) 399 { 400 swap_iodoc_nm(iotemp); 401 linked = 2; 402 } 403 else 404 iotemp=0; 405 } 406 #ifdef ACCT 407 suspacct(); 408 #endif /* ACCT */ 409 /* child should not unlink the tmpfile */ 410 cpipe[INPIPE] = cpipe[OTPIPE] = NULL; 411 cpid = 0; 412 /* Turn off INTR and QUIT if `FINT' */ 413 /* Reset remaining signals to parent */ 414 /* except for those `lost' by trap */ 415 oldsigs(); 416 #ifdef JOBS 417 if(states&MONITOR) 418 { 419 # ifdef BSD 420 register int pid = getpid(); 421 int pgrp; 422 if(jobstat.j_flag==0) 423 pgrp = pid; 424 else 425 pgrp = jobstat.cur_pgrp; 426 setpgrp(pid,pgrp); 427 if(states&NONSTOP) 428 signal(SIGTSTP,SIG_IGN); 429 else 430 { 431 signal(SIGTTIN,SIG_DFL); 432 signal(SIGTTOU,SIG_DFL); 433 signal(SIGTSTP,SIG_DFL); 434 } 435 #else 436 # ifdef SXT 437 if(jobstat.cur_job < jobstat.maxjob 438 || (type&FAMP)) 439 # else 440 # ifdef DEVFD 441 if((type&(FINT|FAMP))==(FINT|FAMP)) 442 # else 443 if(type&FAMP) 444 # endif /* DEVFD */ 445 # endif /* SXT */ 446 setpgrp(); 447 #endif /* BSD */ 448 } 449 else 450 #endif /* JOBS */ 451 if(type&FINT) 452 { 453 signal(SIGINT,SIG_IGN); 454 signal(SIGQUIT,SIG_IGN); 455 } 456 /* pipe in or out */ 457 if((type&FAMP) && is_option(BGNICE)) 458 nice(4); 459 #if VSH || ESH 460 if(type&(FAMP|FPOU)) 461 off_option(EMACS|EDITVI|GMACS); 462 #endif 463 if(type&FPIN) 464 { 465 frenumber(pf1[INPIPE],0); 466 if((type&FPOU)==0) 467 fclose(pf1[OTPIPE]); 468 setbuf(stdin,NIL); 469 } 470 if(type&FPOU) 471 { 472 frenumber(pf2[OTPIPE],1); 473 pipe_close(pf2); 474 } 475 /* default std input for & */ 476 #ifdef JOBS 477 # ifdef BSD 478 if((states&MONITOR) == 0) 479 # endif /* BSD */ 480 # ifdef SXT 481 if((states&MONITOR)==0 || 482 jobstat.cur_job >= jobstat.maxjob) 483 { 484 # endif /* SXT */ 485 #endif /* JOBS */ 486 if((type&FINT) && ioset==0) 487 { 488 fclose(stdin); 489 chkopen(devnull); 490 } 491 /* io redirection */ 492 #ifdef JOBS 493 # ifdef SXT 494 } 495 else 496 j_new_chan(); 497 # endif /* SXT */ 498 states &= ~MONITOR; 499 #endif /* JOBS */ 500 initio(t->treio,0); 501 if(type!=TCOM) 502 { 503 /* don't clear job table for out 504 pipes so that jobs can be 505 piped 506 */ 507 if(no_fork==0 && (type&FPOU)==0) 508 postclr(); 509 execute(((FORKPTR) t)->forktre,execflg|1); 510 } 511 else if(com0!=ENDARGS) 512 { 513 off_option(ERRFLG); 514 rmtemp((IOPTR)0); 515 execa(com,((COMPTR)t)->comset); 516 } 517 done(0); 518 } 519 } 520 521 case TSETIO: 522 { 523 /* 524 * don't create a new process, just 525 * save and restore io-streams 526 */ 527 int indx = initio(((FORKPTR)t)->forkio,1); 528 execute(((FORKPTR)t)->forktre,execflg); 529 restore(indx); 530 break; 531 } 532 533 case TPAR: 534 execute(((PARPTR) t)->partre,execflg); 535 done(0); 536 537 case TFIL: 538 { 539 /* 540 * This code sets up a pipe. 541 * All elements of the pipe are started by the parent. 542 * Only the last one is waited for. 543 */ 544 register FORKPTR tf; 545 FILE *pvo[2]; /* old pipe for multi-pipeline */ 546 FILE *pvn[2]; /* set up pipe */ 547 register int rc = 1; 548 do 549 { 550 /* create the pipe */ 551 chkpipe(pvn); 552 tf = (FORKPTR)(((LSTPTR)t)->lstlef); 553 /* rc==0 on multi-stage pipe */ 554 if(rc==0) 555 tf->forktyp |= FPCL|FPIN; 556 /* execute out part of pipe no wait */ 557 rc = execute((TREPTR)tf, errorflg, pvo, pvn); 558 tf = (FORKPTR)(((LSTPTR)t)->lstrit); 559 t = tf->forktre; 560 /* save the pipe stream-ids */ 561 pvo[0] = pvn[0]; 562 /*close out-part of pipe as soon as possible */ 563 fclose(pvn[OTPIPE]); 564 #ifdef JOBS 565 /* pipeline all in one process group */ 566 jobstat.j_flag++; 567 #endif /* JOBS */ 568 } 569 /* repeat until end of pipeline */ 570 while(rc==0 && tf->forkio==NULL && t->tretyp==TFIL); 571 if(rc == 0) 572 execute((TREPTR)tf, execflg,pvn,pf2); 573 else 574 /* execution failure, close pipe */ 575 pipe_close(pvn); 576 break; 577 } 578 579 case TLST: 580 { 581 /* a list of commands are executed here */ 582 do 583 { 584 execute(((LSTPTR) t)->lstlef,errorflg); 585 t = (TREPTR)(((LSTPTR)t)->lstrit); 586 } 587 while(t->tretyp == TLST); 588 execute(t,execflg); 589 break; 590 } 591 592 case TAND: 593 #ifdef JOBS 594 states |= NONSTOP; 595 #endif /* JOBS */ 596 if(execute(((LSTPTR) t)->lstlef,0)==0) 597 execute(((LSTPTR) t)->lstrit,execflg); 598 break; 599 600 case TORF: 601 #ifdef JOBS 602 states |= NONSTOP; 603 #endif /* JOBS */ 604 if(execute(((LSTPTR) t)->lstlef,0)!=0) 605 execute(((LSTPTR) t)->lstrit,execflg); 606 break; 607 608 case TFOR: 609 case TSELECT: 610 { 611 register char **args; 612 register int nargs; 613 NAMPTR n = lookup(((FORPTR) t)->fornam); 614 char **arglist; 615 DOLPTR argsav=NULL; 616 COMPTR tp; 617 char *nullptr = NULL; 618 #ifdef JOBS 619 states |= NONSTOP; 620 #endif /* JOBS */ 621 if((tp=((FORPTR)t)->forlst)==NULL) 622 { 623 args=dolv+1; 624 nargs = dolc; 625 argsav=arg_use(); 626 } 627 else 628 { 629 args=arg_build(&argn,tp); 630 nargs = argn; 631 } 632 if(type==TSELECT) 633 { 634 p_setout(stderr); 635 p_list(nargs,arglist=args); 636 } 637 loopcnt++; 638 while(*args !=ENDARGS && execbrk == 0) 639 { 640 if(t->tretyp==TSELECT) 641 { 642 char *val,*cp; 643 /* reuse register */ 644 #define c type 645 chkpr(1); 646 if(isatty(0)) 647 states |= PROMPT; 648 readvar(&nullptr,stdin,R_FLAG); 649 if(feof(stdin)) 650 { 651 exitval = 1; 652 clearerr(stdin); 653 break; 654 } 655 if((val=qvalup(REPLYNOD))==NULL) 656 continue; 657 else 658 { 659 if(*(cp=val) == 0) 660 { 661 p_list(nargs,args); 662 continue; 663 } 664 while(c = *cp++) 665 if(c < '0' && c > '9') 666 break; 667 if(c!=0) 668 c = nargs; 669 else 670 c = atoi(val)-1; 671 if(c<0 || c >= nargs) 672 c = nargs; 673 args += c; 674 } 675 } 676 #undef c 677 assign(n, *args); 678 if(t->tretyp != TSELECT) 679 args++; 680 else 681 args = arglist; 682 execute(((FORPTR) t)->fortre,errorflg); 683 if(breakcnt<0) 684 execbrk = (++breakcnt !=0); 685 } 686 if(breakcnt>0) 687 execbrk = (--breakcnt !=0); 688 loopcnt--; 689 arg_free(argsav,0); 690 break; 691 } 692 693 case TWH: 694 case TUN: 695 { 696 register int i=0; 697 #ifdef JOBS 698 states |= NONSTOP; 699 #endif /* JOBS */ 700 loopcnt++; 701 while(execbrk==0 && (execute(((WHPTR)t)->whtre,0)==0)==(type==TWH)) 702 { 703 i = execute(((WHPTR) t)->dotre,errorflg); 704 if(breakcnt<0) 705 execbrk = (++breakcnt !=0); 706 } 707 if(breakcnt>0) 708 execbrk = (--breakcnt !=0); 709 loopcnt--; 710 exitval= i; 711 break; 712 } 713 714 case TIF: 715 #ifdef JOBS 716 states |= NONSTOP; 717 #endif /* JOBS */ 718 if(execute(((IFPTR) t)->iftre,0)==0) 719 execute(((IFPTR) t)->thtre,execflg); 720 else if(((IFPTR) t)->eltre) 721 execute(((IFPTR) t)->eltre, execflg); 722 else 723 exitval=0; /* force zero exit for if-then-fi */ 724 break; 725 726 case TSW: 727 { 728 char *r = mactrim(((SWPTR) t)->swarg,0); 729 t=(TREPTR)((SWPTR) t)->swlst; 730 while(t) 731 { 732 register ARGPTR rex=(ARGPTR)((REGPTR)t)->regptr; 733 while(rex) 734 { 735 register char *s; 736 if(rex->argflag&A_MAC) 737 s = macro(rex->argval); 738 else 739 s = rex->argval; 740 if(((rex->argflag&A_RAW)==0&&gmatch(r,s)) 741 || trim_eq(r,s)) 742 { 743 execute(((REGPTR)t)->regcom,errorflg); 744 t=0; 745 break; 746 } 747 else 748 rex=rex->argnxt; 749 } 750 if(t) 751 t=(TREPTR)((REGPTR)t)->regnxt; 752 } 753 break; 754 } 755 756 case TTIME: 757 { 758 /* time the command */ 759 struct tms before,after; 760 long at,bt; 761 #ifdef BSD 762 struct timeb tb,ta; 763 ftime(&tb); 764 #endif /* BSD */ 765 bt = times(&before); 766 execute(((PARPTR) t)->partre,0); 767 at = times(&after); 768 #ifdef BSD 769 ftime(&ta); 770 at = TIC_SEC*(ta.time-tb.time); 771 at += ((TIC_SEC*((long)(ta.millitm-tb.millitm)))/1000); 772 #else 773 at -= bt; 774 #endif /* BSD */ 775 p_setout(stderr); 776 p_str(t_real,'\t'); 777 p_time(at,NL); 778 p_str(t_user,'\t'); 779 at = after.tms_utime - before.tms_utime; 780 at += after.tms_cutime - before.tms_cutime; 781 p_time(at,NL); 782 p_str(t_sys,'\t'); 783 at = after.tms_stime - before.tms_stime; 784 at += after.tms_cstime - before.tms_cstime; 785 p_time(at,NL); 786 break; 787 } 788 case TPROC: 789 { 790 register NAMPTR np; 791 register char *fname = ((PROCPTR)t)->procnam; 792 if(!isalpha(*fname)) 793 failed(fname,notid); 794 np = findnod(fname,prnames,1); 795 if(np->value.namval.rp) 796 free(np->value.namval.rp->ptree); 797 else 798 np->value.namval.rp = (struct Ufunction*) 799 malloc(sizeof(struct Ufunction)); 800 funtree(np) = (int**)((PROCPTR)t)->proctre; 801 np->value.namval.rp->hoffset = ((PROCPTR)t)->procloc; 802 sattrib(np,L_FLAG|INT_GER); 803 break; 804 } 805 } 806 #ifdef JOBS 807 jobstat.j_flag = 0; 808 #endif /* JOBS */ 809 /* set $. */ 810 if( com0) 811 { 812 if(lastarg!= locbuf) 813 free(lastarg); 814 if(strlen(com[argn-1]) < TMPSIZ) 815 lastarg = strcpy(locbuf,com[argn-1]); 816 else 817 lastarg = heap(com[argn-1]); 818 } 819 exitset(); 820 } 821 if(trapnote&SIGSET) 822 exitsh(SIGFAIL|exitval); 823 tdystak(sav); 824 states |= errorflg; 825 linked = 0; 826 return(exitval); 827 } 828 829 /* 830 * test for equality with second argument trimmed 831 * returns 1 if r == trim(s) otherwise 0 832 */ 833 834 static trim_eq(r,s) 835 register char *r,*s; 836 { 837 register char c; 838 while(c = *s++) 839 { 840 if(c==ESCAPE) 841 c = *s++; 842 if(c != *r++) 843 return(0); 844 } 845 return(*r==0); 846 } 847 848 /* 849 * print out the command line if set -x is on 850 */ 851 852 void trace_command(com) 853 char **com; 854 { 855 if(is_option(EXECPR)) 856 { 857 p_setout(stderr); 858 fputs(execpmsg,output); 859 echo_list(1,com,output); 860 newline(); 861 } 862 } 863 864