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