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