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