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 */
execute(argt,execflg,apf1,apf2)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
trim_eq(r,s)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
trace_command(com)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