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