xref: /onnv-gate/usr/src/cmd/sh/xec.c (revision 0)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*0Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*0Sstevel@tonic-gate 
25*0Sstevel@tonic-gate 
26*0Sstevel@tonic-gate /*
27*0Sstevel@tonic-gate  * Copyright 1996,2002-2003 Sun Microsystems, Inc.  All rights reserved.
28*0Sstevel@tonic-gate  * Use is subject to license terms.
29*0Sstevel@tonic-gate  */
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*0Sstevel@tonic-gate /*
33*0Sstevel@tonic-gate  *
34*0Sstevel@tonic-gate  * UNIX shell
35*0Sstevel@tonic-gate  *
36*0Sstevel@tonic-gate  */
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate #include	"defs.h"
40*0Sstevel@tonic-gate #include	<errno.h>
41*0Sstevel@tonic-gate #include	"sym.h"
42*0Sstevel@tonic-gate #include	"hash.h"
43*0Sstevel@tonic-gate #include	<sys/types.h>
44*0Sstevel@tonic-gate #include	<sys/times.h>
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate pid_t parent;
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate /* ========	command execution	======== */
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate execute(argt, xflags, errorflg, pf1, pf2)
52*0Sstevel@tonic-gate struct trenod	*argt;
53*0Sstevel@tonic-gate int	*pf1, *pf2;
54*0Sstevel@tonic-gate {
55*0Sstevel@tonic-gate 	/*
56*0Sstevel@tonic-gate 	 * `stakbot' is preserved by this routine
57*0Sstevel@tonic-gate 	 */
58*0Sstevel@tonic-gate 	register struct trenod	*t;
59*0Sstevel@tonic-gate 	unsigned char		*sav = savstak();
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate 	sigchk();
62*0Sstevel@tonic-gate 	if (!errorflg)
63*0Sstevel@tonic-gate 		flags &= ~errflg;
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate 	if ((t = argt) && execbrk == 0) {
66*0Sstevel@tonic-gate 		register int treeflgs;
67*0Sstevel@tonic-gate 		register unsigned char **com;
68*0Sstevel@tonic-gate 		int type;
69*0Sstevel@tonic-gate 		short pos;
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate 		treeflgs = t->tretyp;
72*0Sstevel@tonic-gate 		type = treeflgs & COMMSK;
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate 		switch (type)
75*0Sstevel@tonic-gate 		{
76*0Sstevel@tonic-gate 		case TFND:
77*0Sstevel@tonic-gate 			{
78*0Sstevel@tonic-gate 				struct fndnod	*f = (struct fndnod *)t;
79*0Sstevel@tonic-gate 				struct namnod	*n = lookup(f->fndnam);
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate 				exitval = 0;
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 				if (n->namflg & N_RDONLY)
84*0Sstevel@tonic-gate 					failed(n->namid, wtfailed);
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 				if (flags & rshflg && (n == &pathnod ||
87*0Sstevel@tonic-gate 					eq(n->namid, "SHELL")))
88*0Sstevel@tonic-gate 					failed(n->namid, restricted);
89*0Sstevel@tonic-gate 				if (n->namflg & N_FUNCTN)
90*0Sstevel@tonic-gate 					freefunc(n);
91*0Sstevel@tonic-gate 				else
92*0Sstevel@tonic-gate 				{
93*0Sstevel@tonic-gate 					free(n->namval);
94*0Sstevel@tonic-gate 					free(n->namenv);
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 					n->namval = 0;
97*0Sstevel@tonic-gate 					n->namflg &= ~(N_EXPORT | N_ENVCHG);
98*0Sstevel@tonic-gate 				}
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate 				if (funcnt)
101*0Sstevel@tonic-gate 					f->fndval->tretyp++;
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate 				n->namenv = (unsigned char *)f->fndval;
104*0Sstevel@tonic-gate 				attrib(n, N_FUNCTN);
105*0Sstevel@tonic-gate 				hash_func(n->namid);
106*0Sstevel@tonic-gate 				break;
107*0Sstevel@tonic-gate 			}
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 		case TCOM:
110*0Sstevel@tonic-gate 			{
111*0Sstevel@tonic-gate 				unsigned char	*a1, *name;
112*0Sstevel@tonic-gate 				int	argn, internal;
113*0Sstevel@tonic-gate 				struct argnod	*schain = gchain;
114*0Sstevel@tonic-gate 				struct ionod	*io = t->treio;
115*0Sstevel@tonic-gate 				short 	cmdhash;
116*0Sstevel@tonic-gate 				short	comtype;
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 				exitval = 0;
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 				gchain = 0;
121*0Sstevel@tonic-gate 				argn = getarg(t);
122*0Sstevel@tonic-gate 				com = scan(argn);
123*0Sstevel@tonic-gate 				a1 = com[1];
124*0Sstevel@tonic-gate 				gchain = schain;
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 				if (argn != 0)
127*0Sstevel@tonic-gate 					cmdhash = pathlook(com[0], 1, comptr(t)->comset);
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 				if (argn == 0 || (comtype = hashtype(cmdhash)) == BUILTIN) {
130*0Sstevel@tonic-gate 					setlist(comptr(t)->comset, 0);
131*0Sstevel@tonic-gate 				}
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate 				if (argn && (flags&noexec) == 0)
134*0Sstevel@tonic-gate 				{
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 					/* print command if execpr */
137*0Sstevel@tonic-gate 					if (flags & execpr)
138*0Sstevel@tonic-gate 						execprint(com);
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 					if (comtype == NOTFOUND)
141*0Sstevel@tonic-gate 					{
142*0Sstevel@tonic-gate 						pos = hashdata(cmdhash);
143*0Sstevel@tonic-gate 						if (pos == 1)
144*0Sstevel@tonic-gate 							failure(*com, notfound);
145*0Sstevel@tonic-gate 						else if (pos == 2)
146*0Sstevel@tonic-gate 							failure(*com, badexec);
147*0Sstevel@tonic-gate 						else
148*0Sstevel@tonic-gate 							failure(*com, badperm);
149*0Sstevel@tonic-gate 						break;
150*0Sstevel@tonic-gate 					}
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 					else if (comtype == PATH_COMMAND)
153*0Sstevel@tonic-gate 					{
154*0Sstevel@tonic-gate 						pos = -1;
155*0Sstevel@tonic-gate 					}
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 					else if (comtype & (COMMAND | REL_COMMAND))
158*0Sstevel@tonic-gate 					{
159*0Sstevel@tonic-gate 						pos = hashdata(cmdhash);
160*0Sstevel@tonic-gate 					}
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 					else if (comtype == BUILTIN) {
163*0Sstevel@tonic-gate 						builtin(hashdata(cmdhash),argn,com,t);
164*0Sstevel@tonic-gate 						freejobs();
165*0Sstevel@tonic-gate 						break;
166*0Sstevel@tonic-gate 					}
167*0Sstevel@tonic-gate 					else if (comtype == FUNCTION)
168*0Sstevel@tonic-gate 					{
169*0Sstevel@tonic-gate 						struct dolnod *olddolh;
170*0Sstevel@tonic-gate 						struct namnod *n, *opt;
171*0Sstevel@tonic-gate 						short index;
172*0Sstevel@tonic-gate 						unsigned char **olddolv = dolv;
173*0Sstevel@tonic-gate 						int olddolc = dolc;
174*0Sstevel@tonic-gate 						n = findnam(com[0]);
175*0Sstevel@tonic-gate 					/* save current positional parameters */
176*0Sstevel@tonic-gate 						olddolh = (struct dolnod *)savargs(funcnt);
177*0Sstevel@tonic-gate 						funcnt++;
178*0Sstevel@tonic-gate 						index = initio(io, 1);
179*0Sstevel@tonic-gate 						setargs(com);
180*0Sstevel@tonic-gate 						execute((struct trenod *)(n->namenv), xflags, errorflg, pf1, pf2);
181*0Sstevel@tonic-gate 						execbrk = 0;
182*0Sstevel@tonic-gate 						restore(index);
183*0Sstevel@tonic-gate 						(void) restorargs(olddolh, funcnt);
184*0Sstevel@tonic-gate 						dolv = olddolv;
185*0Sstevel@tonic-gate 						dolc = olddolc;
186*0Sstevel@tonic-gate 						funcnt--;
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 						break;
189*0Sstevel@tonic-gate 					}
190*0Sstevel@tonic-gate 				}
191*0Sstevel@tonic-gate 				else if (t->treio == 0)
192*0Sstevel@tonic-gate 				{
193*0Sstevel@tonic-gate 					chktrap();
194*0Sstevel@tonic-gate 					break;
195*0Sstevel@tonic-gate 				}
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate 			}
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 		case TFORK:
200*0Sstevel@tonic-gate 		{
201*0Sstevel@tonic-gate 			int monitor = 0;
202*0Sstevel@tonic-gate 			int linked = 0;
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 			exitval = 0;
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 			if (!(xflags & XEC_EXECED) || treeflgs&(FPOU|FAMP))
207*0Sstevel@tonic-gate 			{
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 				int forkcnt = 1;
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 				if (!(treeflgs&FPOU))
212*0Sstevel@tonic-gate 				{
213*0Sstevel@tonic-gate 					monitor = (!(xflags & XEC_NOSTOP)
214*0Sstevel@tonic-gate 					  && (flags&(monitorflg|jcflg|jcoff))
215*0Sstevel@tonic-gate 					  == (monitorflg|jcflg));
216*0Sstevel@tonic-gate 					if (monitor) {
217*0Sstevel@tonic-gate 						int savefd;
218*0Sstevel@tonic-gate 						unsigned char *savebot;
219*0Sstevel@tonic-gate 						savefd = setb(-1);
220*0Sstevel@tonic-gate 						savebot = stakbot;
221*0Sstevel@tonic-gate 						prcmd(t);
222*0Sstevel@tonic-gate 						(void)setb(savefd);
223*0Sstevel@tonic-gate 						allocjob(savebot, cwdget(), monitor);
224*0Sstevel@tonic-gate 					} else
225*0Sstevel@tonic-gate 						allocjob("", "", 0);
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 				}
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 				if (treeflgs & (FPOU|FAMP)) {
230*0Sstevel@tonic-gate 					link_iodocs(iotemp);
231*0Sstevel@tonic-gate 					linked = 1;
232*0Sstevel@tonic-gate 				}
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 				while ((parent = fork()) == -1)
235*0Sstevel@tonic-gate 				{
236*0Sstevel@tonic-gate 				/*
237*0Sstevel@tonic-gate 				 * FORKLIM is the max period between forks -
238*0Sstevel@tonic-gate 				 * power of 2 usually.	Currently shell tries
239*0Sstevel@tonic-gate 				 * after 2,4,8,16, and 32 seconds and then quits
240*0Sstevel@tonic-gate 				 */
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 				if ((forkcnt = (forkcnt * 2)) > FORKLIM)
243*0Sstevel@tonic-gate 				{
244*0Sstevel@tonic-gate 					switch (errno)
245*0Sstevel@tonic-gate 					{
246*0Sstevel@tonic-gate 					case ENOMEM:
247*0Sstevel@tonic-gate 						deallocjob();
248*0Sstevel@tonic-gate 						error(noswap);
249*0Sstevel@tonic-gate 						break;
250*0Sstevel@tonic-gate 					default:
251*0Sstevel@tonic-gate 						deallocjob();
252*0Sstevel@tonic-gate 						error(nofork);
253*0Sstevel@tonic-gate 						break;
254*0Sstevel@tonic-gate 					}
255*0Sstevel@tonic-gate 				} else if (errno == EPERM) {
256*0Sstevel@tonic-gate 					deallocjob();
257*0Sstevel@tonic-gate 					error(eacces);
258*0Sstevel@tonic-gate 					break;
259*0Sstevel@tonic-gate 				}
260*0Sstevel@tonic-gate 				sigchk();
261*0Sstevel@tonic-gate 				sleep(forkcnt);
262*0Sstevel@tonic-gate 				}
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 				if (parent) {
265*0Sstevel@tonic-gate 					if (monitor)
266*0Sstevel@tonic-gate 						setpgid(parent, 0);
267*0Sstevel@tonic-gate 					if (treeflgs & FPIN)
268*0Sstevel@tonic-gate 						closepipe(pf1);
269*0Sstevel@tonic-gate 					if (!(treeflgs&FPOU)) {
270*0Sstevel@tonic-gate 						postjob(parent,!(treeflgs&FAMP));
271*0Sstevel@tonic-gate 						freejobs();
272*0Sstevel@tonic-gate 					}
273*0Sstevel@tonic-gate 					chktrap();
274*0Sstevel@tonic-gate 					break;
275*0Sstevel@tonic-gate 				}
276*0Sstevel@tonic-gate 				mypid = getpid();
277*0Sstevel@tonic-gate 			}
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 			/*
280*0Sstevel@tonic-gate 			 * Forked process:  assume it is not a subshell for
281*0Sstevel@tonic-gate 			 * now.  If it is, the presence of a left parenthesis
282*0Sstevel@tonic-gate 			 * will trigger the jcoff flag to be turned off.
283*0Sstevel@tonic-gate 			 * When jcoff is turned on, monitoring is not going on
284*0Sstevel@tonic-gate 			 * and waitpid will not look for WUNTRACED.
285*0Sstevel@tonic-gate 			 */
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 			flags |= (forked|jcoff);
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 			fiotemp  = 0;
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 			if (linked == 1) {
292*0Sstevel@tonic-gate 				swap_iodoc_nm(iotemp);
293*0Sstevel@tonic-gate 				xflags |= XEC_LINKED;
294*0Sstevel@tonic-gate 			} else if (!(xflags & XEC_LINKED))
295*0Sstevel@tonic-gate 				iotemp = 0;
296*0Sstevel@tonic-gate #ifdef ACCT
297*0Sstevel@tonic-gate 			suspacct();
298*0Sstevel@tonic-gate #endif
299*0Sstevel@tonic-gate 			settmp();
300*0Sstevel@tonic-gate 			oldsigs();
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 			if (!(treeflgs & FPOU))
303*0Sstevel@tonic-gate 				makejob(monitor, !(treeflgs & FAMP));
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 			/*
306*0Sstevel@tonic-gate 			 * pipe in or out
307*0Sstevel@tonic-gate 			 */
308*0Sstevel@tonic-gate 			if (treeflgs & FPIN)
309*0Sstevel@tonic-gate 			{
310*0Sstevel@tonic-gate 				renamef(pf1[INPIPE], 0);
311*0Sstevel@tonic-gate 				close(pf1[OTPIPE]);
312*0Sstevel@tonic-gate 			}
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 			if (treeflgs & FPOU)
315*0Sstevel@tonic-gate 			{
316*0Sstevel@tonic-gate 				close(pf2[INPIPE]);
317*0Sstevel@tonic-gate 				renamef(pf2[OTPIPE], 1);
318*0Sstevel@tonic-gate 			}
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 			/*
321*0Sstevel@tonic-gate 			 * io redirection
322*0Sstevel@tonic-gate 			 */
323*0Sstevel@tonic-gate 			initio(t->treio, 0);
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 			if (type == TFORK)
326*0Sstevel@tonic-gate 				execute(forkptr(t)->forktre, xflags | XEC_EXECED, errorflg);
327*0Sstevel@tonic-gate 			else if (com[0] != ENDARGS)
328*0Sstevel@tonic-gate 			{
329*0Sstevel@tonic-gate 				eflag = 0;
330*0Sstevel@tonic-gate 				setlist(comptr(t)->comset, N_EXPORT);
331*0Sstevel@tonic-gate 				rmtemp(0);
332*0Sstevel@tonic-gate 				clearjobs();
333*0Sstevel@tonic-gate 				execa(com, pos);
334*0Sstevel@tonic-gate 			}
335*0Sstevel@tonic-gate 			done(0);
336*0Sstevel@tonic-gate 		}
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 		case TPAR:
339*0Sstevel@tonic-gate 			/* Forked process is subshell:  may want job control */
340*0Sstevel@tonic-gate 			flags &= ~jcoff;
341*0Sstevel@tonic-gate 			clearjobs();
342*0Sstevel@tonic-gate 			execute(parptr(t)->partre, xflags, errorflg);
343*0Sstevel@tonic-gate 			done(0);
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 		case TFIL:
346*0Sstevel@tonic-gate 			{
347*0Sstevel@tonic-gate 				int pv[2];
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 				chkpipe(pv);
350*0Sstevel@tonic-gate 				if (execute(lstptr(t)->lstlef, xflags & XEC_NOSTOP, errorflg, pf1, pv) == 0)
351*0Sstevel@tonic-gate 					execute(lstptr(t)->lstrit, xflags, errorflg, pv, pf2);
352*0Sstevel@tonic-gate 				else
353*0Sstevel@tonic-gate 					closepipe(pv);
354*0Sstevel@tonic-gate 			}
355*0Sstevel@tonic-gate 			break;
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 		case TLST:
358*0Sstevel@tonic-gate 			execute(lstptr(t)->lstlef, xflags&XEC_NOSTOP, errorflg);
359*0Sstevel@tonic-gate 			/* Update errorflg if set -e is invoked in the sub-sh*/
360*0Sstevel@tonic-gate 			execute(lstptr(t)->lstrit, xflags, (errorflg | (eflag & errflg)));
361*0Sstevel@tonic-gate 			break;
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 		case TAND:
364*0Sstevel@tonic-gate 		case TORF:
365*0Sstevel@tonic-gate 		{
366*0Sstevel@tonic-gate 			register xval;
367*0Sstevel@tonic-gate 			xval = execute(lstptr(t)->lstlef, XEC_NOSTOP, 0);
368*0Sstevel@tonic-gate 			if ((xval == 0) == (type == TAND))
369*0Sstevel@tonic-gate 				execute(lstptr(t)->lstrit, xflags|XEC_NOSTOP, errorflg);
370*0Sstevel@tonic-gate 			break;
371*0Sstevel@tonic-gate 		}
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 		case TFOR:
374*0Sstevel@tonic-gate 			{
375*0Sstevel@tonic-gate 				struct namnod *n = lookup(forptr(t)->fornam);
376*0Sstevel@tonic-gate 				unsigned char	**args;
377*0Sstevel@tonic-gate 				struct dolnod *argsav = 0;
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 				if (forptr(t)->forlst == 0)
380*0Sstevel@tonic-gate 				{
381*0Sstevel@tonic-gate 					args = dolv + 1;
382*0Sstevel@tonic-gate 					argsav = useargs();
383*0Sstevel@tonic-gate 				}
384*0Sstevel@tonic-gate 				else
385*0Sstevel@tonic-gate 				{
386*0Sstevel@tonic-gate 					struct argnod *schain = gchain;
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 					gchain = 0;
389*0Sstevel@tonic-gate 					args = scan(getarg(forptr(t)->forlst));
390*0Sstevel@tonic-gate 					gchain = schain;
391*0Sstevel@tonic-gate 				}
392*0Sstevel@tonic-gate 				loopcnt++;
393*0Sstevel@tonic-gate 				while (*args != ENDARGS && execbrk == 0)
394*0Sstevel@tonic-gate 				{
395*0Sstevel@tonic-gate 					assign(n, *args++);
396*0Sstevel@tonic-gate 					execute(forptr(t)->fortre, XEC_NOSTOP, errorflg);
397*0Sstevel@tonic-gate 					if (breakcnt < 0)
398*0Sstevel@tonic-gate 						execbrk = (++breakcnt != 0);
399*0Sstevel@tonic-gate 				}
400*0Sstevel@tonic-gate 				if (breakcnt > 0)
401*0Sstevel@tonic-gate 						execbrk = (--breakcnt != 0);
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 				loopcnt--;
404*0Sstevel@tonic-gate 				if(argsav)
405*0Sstevel@tonic-gate 					argfor = (struct dolnod *)freeargs(argsav);
406*0Sstevel@tonic-gate 			}
407*0Sstevel@tonic-gate 			break;
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 		case TWH:
410*0Sstevel@tonic-gate 		case TUN:
411*0Sstevel@tonic-gate 			{
412*0Sstevel@tonic-gate 				int	i = 0;
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 				loopcnt++;
415*0Sstevel@tonic-gate 				while (execbrk == 0 && (execute(whptr(t)->whtre,
416*0Sstevel@tonic-gate 				    XEC_NOSTOP, 0) == 0) == (type == TWH) &&
417*0Sstevel@tonic-gate 				    (flags&noexec) == 0)
418*0Sstevel@tonic-gate {
419*0Sstevel@tonic-gate 					i = execute(whptr(t)->dotre, XEC_NOSTOP, errorflg);
420*0Sstevel@tonic-gate 					if (breakcnt < 0)
421*0Sstevel@tonic-gate 						execbrk = (++breakcnt != 0);
422*0Sstevel@tonic-gate 				}
423*0Sstevel@tonic-gate 				if (breakcnt > 0)
424*0Sstevel@tonic-gate 						execbrk = (--breakcnt != 0);
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 				loopcnt--;
427*0Sstevel@tonic-gate 				exitval = i;
428*0Sstevel@tonic-gate 			}
429*0Sstevel@tonic-gate 			break;
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 		case TIF:
432*0Sstevel@tonic-gate 			if (execute(ifptr(t)->iftre, XEC_NOSTOP, 0) == 0)
433*0Sstevel@tonic-gate 				execute(ifptr(t)->thtre, xflags|XEC_NOSTOP, errorflg);
434*0Sstevel@tonic-gate 			else if (ifptr(t)->eltre)
435*0Sstevel@tonic-gate 				execute(ifptr(t)->eltre, xflags|XEC_NOSTOP, errorflg);
436*0Sstevel@tonic-gate 			else
437*0Sstevel@tonic-gate 				exitval = 0;	/* force zero exit for if-then-fi */
438*0Sstevel@tonic-gate 			break;
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 		case TSW:
441*0Sstevel@tonic-gate 			{
442*0Sstevel@tonic-gate 				register unsigned char	*r = mactrim(swptr(t)->swarg);
443*0Sstevel@tonic-gate 				register struct regnod *regp;
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 				regp = swptr(t)->swlst;
446*0Sstevel@tonic-gate 				while (regp)
447*0Sstevel@tonic-gate 				{
448*0Sstevel@tonic-gate 					struct argnod *rex = regp->regptr;
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 					while (rex)
451*0Sstevel@tonic-gate 					{
452*0Sstevel@tonic-gate 						register unsigned char	*s;
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 						if (gmatch(r, s = macro(rex->argval)) || (trim(s), eq(r, s)))
455*0Sstevel@tonic-gate 						{
456*0Sstevel@tonic-gate 							execute(regp->regcom, XEC_NOSTOP, errorflg);
457*0Sstevel@tonic-gate 							regp = 0;
458*0Sstevel@tonic-gate 							break;
459*0Sstevel@tonic-gate 						}
460*0Sstevel@tonic-gate 						else
461*0Sstevel@tonic-gate 							rex = rex->argnxt;
462*0Sstevel@tonic-gate 					}
463*0Sstevel@tonic-gate 					if (regp)
464*0Sstevel@tonic-gate 						regp = regp->regnxt;
465*0Sstevel@tonic-gate 				}
466*0Sstevel@tonic-gate 			}
467*0Sstevel@tonic-gate 			break;
468*0Sstevel@tonic-gate 		}
469*0Sstevel@tonic-gate 		exitset();
470*0Sstevel@tonic-gate 	}
471*0Sstevel@tonic-gate 	sigchk();
472*0Sstevel@tonic-gate 	tdystak(sav);
473*0Sstevel@tonic-gate 	flags |= eflag;
474*0Sstevel@tonic-gate 	return(exitval);
475*0Sstevel@tonic-gate }
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate execexp(s, f)
478*0Sstevel@tonic-gate unsigned char	*s;
479*0Sstevel@tonic-gate int	f;
480*0Sstevel@tonic-gate {
481*0Sstevel@tonic-gate 	struct fileblk	fb;
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 	push(&fb);
484*0Sstevel@tonic-gate 	if (s)
485*0Sstevel@tonic-gate 	{
486*0Sstevel@tonic-gate 		estabf(s);
487*0Sstevel@tonic-gate 		fb.feval = (unsigned char **)(f);
488*0Sstevel@tonic-gate 	}
489*0Sstevel@tonic-gate 	else if (f >= 0)
490*0Sstevel@tonic-gate 		initf(f);
491*0Sstevel@tonic-gate 	execute(cmd(NL, NLFLG | MTFLG), 0, (int)(flags & errflg));
492*0Sstevel@tonic-gate 	pop();
493*0Sstevel@tonic-gate }
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate execprint(com)
496*0Sstevel@tonic-gate 	unsigned char **com;
497*0Sstevel@tonic-gate {
498*0Sstevel@tonic-gate 	register int 	argn = 0;
499*0Sstevel@tonic-gate 	unsigned char	*s;
500*0Sstevel@tonic-gate 
501*0Sstevel@tonic-gate 	prs(execpmsg);
502*0Sstevel@tonic-gate 	while(com[argn] != ENDARGS)
503*0Sstevel@tonic-gate 	{
504*0Sstevel@tonic-gate 		s = com[argn++];
505*0Sstevel@tonic-gate 		write(output, s, length(s) - 1);
506*0Sstevel@tonic-gate 		blank();
507*0Sstevel@tonic-gate 	}
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 	newline();
510*0Sstevel@tonic-gate }
511