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