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