1 /*-
2 * Copyright (c) 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95";
36 #endif
37 #endif /* not lint */
38 #include <sys/cdefs.h>
39 #include <paths.h>
40 #include <signal.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include <sys/resource.h>
44 #include <errno.h>
45
46 /*
47 * Evaluate a command.
48 */
49
50 #include "shell.h"
51 #include "nodes.h"
52 #include "syntax.h"
53 #include "expand.h"
54 #include "parser.h"
55 #include "jobs.h"
56 #include "eval.h"
57 #include "builtins.h"
58 #include "options.h"
59 #include "exec.h"
60 #include "redir.h"
61 #include "input.h"
62 #include "output.h"
63 #include "trap.h"
64 #include "var.h"
65 #include "memalloc.h"
66 #include "error.h"
67 #include "show.h"
68 #include "mystring.h"
69 #ifndef NO_HISTORY
70 #include "myhistedit.h"
71 #endif
72
73
74 int evalskip; /* set if we are skipping commands */
75 int skipcount; /* number of levels to skip */
76 static int loopnest; /* current loop nesting level */
77 int funcnest; /* depth of function calls */
78 static int builtin_flags; /* evalcommand flags for builtins */
79
80
81 char *commandname;
82 struct arglist *cmdenviron;
83 int exitstatus; /* exit status of last command */
84 int oexitstatus; /* saved exit status */
85
86
87 static void evalloop(union node *, int);
88 static void evalfor(union node *, int);
89 static union node *evalcase(union node *);
90 static void evalsubshell(union node *, int);
91 static void evalredir(union node *, int);
92 static void exphere(union node *, struct arglist *);
93 static void expredir(union node *);
94 static void evalpipe(union node *);
95 static int is_valid_fast_cmdsubst(union node *n);
96 static void evalcommand(union node *, int, struct backcmd *);
97 static void prehash(union node *);
98
99
100 /*
101 * Called to reset things after an exception.
102 */
103
104 void
reseteval(void)105 reseteval(void)
106 {
107 evalskip = 0;
108 loopnest = 0;
109 }
110
111
112 /*
113 * The eval command.
114 */
115
116 int
evalcmd(int argc,char ** argv)117 evalcmd(int argc, char **argv)
118 {
119 char *p;
120 char *concat;
121 char **ap;
122
123 if (argc > 1) {
124 p = argv[1];
125 if (argc > 2) {
126 STARTSTACKSTR(concat);
127 ap = argv + 2;
128 for (;;) {
129 STPUTS(p, concat);
130 if ((p = *ap++) == NULL)
131 break;
132 STPUTC(' ', concat);
133 }
134 STPUTC('\0', concat);
135 p = grabstackstr(concat);
136 }
137 evalstring(p, builtin_flags);
138 } else
139 exitstatus = 0;
140 return exitstatus;
141 }
142
143
144 /*
145 * Execute a command or commands contained in a string.
146 */
147
148 void
evalstring(const char * s,int flags)149 evalstring(const char *s, int flags)
150 {
151 union node *n;
152 struct stackmark smark;
153 int flags_exit;
154 int any;
155
156 flags_exit = flags & EV_EXIT;
157 flags &= ~EV_EXIT;
158 any = 0;
159 setstackmark(&smark);
160 setinputstring(s, 1);
161 while ((n = parsecmd(0)) != NEOF) {
162 if (n != NULL && !nflag) {
163 if (flags_exit && preadateof())
164 evaltree(n, flags | EV_EXIT);
165 else
166 evaltree(n, flags);
167 any = 1;
168 if (evalskip)
169 break;
170 }
171 popstackmark(&smark);
172 setstackmark(&smark);
173 }
174 popfile();
175 popstackmark(&smark);
176 if (!any)
177 exitstatus = 0;
178 if (flags_exit)
179 exraise(EXEXIT);
180 }
181
182
183 /*
184 * Evaluate a parse tree. The value is left in the global variable
185 * exitstatus.
186 */
187
188 void
evaltree(union node * n,int flags)189 evaltree(union node *n, int flags)
190 {
191 int do_etest;
192 union node *next;
193 struct stackmark smark;
194
195 setstackmark(&smark);
196 do_etest = 0;
197 if (n == NULL) {
198 TRACE(("evaltree(NULL) called\n"));
199 exitstatus = 0;
200 goto out;
201 }
202 do {
203 next = NULL;
204 #ifndef NO_HISTORY
205 displayhist = 1; /* show history substitutions done with fc */
206 #endif
207 TRACE(("evaltree(%p: %d) called\n", (void *)n, n->type));
208 switch (n->type) {
209 case NSEMI:
210 evaltree(n->nbinary.ch1, flags & ~EV_EXIT);
211 if (evalskip)
212 goto out;
213 next = n->nbinary.ch2;
214 break;
215 case NAND:
216 evaltree(n->nbinary.ch1, EV_TESTED);
217 if (evalskip || exitstatus != 0) {
218 goto out;
219 }
220 next = n->nbinary.ch2;
221 break;
222 case NOR:
223 evaltree(n->nbinary.ch1, EV_TESTED);
224 if (evalskip || exitstatus == 0)
225 goto out;
226 next = n->nbinary.ch2;
227 break;
228 case NREDIR:
229 evalredir(n, flags);
230 break;
231 case NSUBSHELL:
232 evalsubshell(n, flags);
233 do_etest = !(flags & EV_TESTED);
234 break;
235 case NBACKGND:
236 evalsubshell(n, flags);
237 break;
238 case NIF: {
239 evaltree(n->nif.test, EV_TESTED);
240 if (evalskip)
241 goto out;
242 if (exitstatus == 0)
243 next = n->nif.ifpart;
244 else if (n->nif.elsepart)
245 next = n->nif.elsepart;
246 else
247 exitstatus = 0;
248 break;
249 }
250 case NWHILE:
251 case NUNTIL:
252 evalloop(n, flags & ~EV_EXIT);
253 break;
254 case NFOR:
255 evalfor(n, flags & ~EV_EXIT);
256 break;
257 case NCASE:
258 next = evalcase(n);
259 break;
260 case NCLIST:
261 next = n->nclist.body;
262 break;
263 case NCLISTFALLTHRU:
264 if (n->nclist.body) {
265 evaltree(n->nclist.body, flags & ~EV_EXIT);
266 if (evalskip)
267 goto out;
268 }
269 next = n->nclist.next;
270 break;
271 case NDEFUN:
272 defun(n->narg.text, n->narg.next);
273 exitstatus = 0;
274 break;
275 case NNOT:
276 evaltree(n->nnot.com, EV_TESTED);
277 if (evalskip)
278 goto out;
279 exitstatus = !exitstatus;
280 break;
281
282 case NPIPE:
283 evalpipe(n);
284 do_etest = !(flags & EV_TESTED);
285 break;
286 case NCMD:
287 evalcommand(n, flags, (struct backcmd *)NULL);
288 do_etest = !(flags & EV_TESTED);
289 break;
290 default:
291 out1fmt("Node type = %d\n", n->type);
292 flushout(&output);
293 break;
294 }
295 n = next;
296 popstackmark(&smark);
297 setstackmark(&smark);
298 } while (n != NULL);
299 out:
300 popstackmark(&smark);
301 if (pendingsig)
302 dotrap();
303 if (eflag && exitstatus != 0 && do_etest)
304 exitshell(exitstatus);
305 if (flags & EV_EXIT)
306 exraise(EXEXIT);
307 }
308
309
310 static void
evalloop(union node * n,int flags)311 evalloop(union node *n, int flags)
312 {
313 int status;
314
315 loopnest++;
316 status = 0;
317 for (;;) {
318 if (!evalskip)
319 evaltree(n->nbinary.ch1, EV_TESTED);
320 if (evalskip) {
321 if (evalskip == SKIPCONT && --skipcount <= 0) {
322 evalskip = 0;
323 continue;
324 }
325 if (evalskip == SKIPBREAK && --skipcount <= 0)
326 evalskip = 0;
327 if (evalskip == SKIPRETURN)
328 status = exitstatus;
329 break;
330 }
331 if (n->type == NWHILE) {
332 if (exitstatus != 0)
333 break;
334 } else {
335 if (exitstatus == 0)
336 break;
337 }
338 evaltree(n->nbinary.ch2, flags);
339 status = exitstatus;
340 }
341 loopnest--;
342 exitstatus = status;
343 }
344
345
346
347 static void
evalfor(union node * n,int flags)348 evalfor(union node *n, int flags)
349 {
350 struct arglist arglist;
351 union node *argp;
352 int i;
353 int status;
354
355 emptyarglist(&arglist);
356 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
357 oexitstatus = exitstatus;
358 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
359 }
360
361 loopnest++;
362 status = 0;
363 for (i = 0; i < arglist.count; i++) {
364 setvar(n->nfor.var, arglist.args[i], 0);
365 evaltree(n->nfor.body, flags);
366 status = exitstatus;
367 if (evalskip) {
368 if (evalskip == SKIPCONT && --skipcount <= 0) {
369 evalskip = 0;
370 continue;
371 }
372 if (evalskip == SKIPBREAK && --skipcount <= 0)
373 evalskip = 0;
374 break;
375 }
376 }
377 loopnest--;
378 exitstatus = status;
379 }
380
381
382 /*
383 * Evaluate a case statement, returning the selected tree.
384 *
385 * The exit status needs care to get right.
386 */
387
388 static union node *
evalcase(union node * n)389 evalcase(union node *n)
390 {
391 union node *cp;
392 union node *patp;
393 struct arglist arglist;
394
395 emptyarglist(&arglist);
396 oexitstatus = exitstatus;
397 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
398 for (cp = n->ncase.cases ; cp ; cp = cp->nclist.next) {
399 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
400 if (casematch(patp, arglist.args[0])) {
401 while (cp->nclist.next &&
402 cp->type == NCLISTFALLTHRU &&
403 cp->nclist.body == NULL)
404 cp = cp->nclist.next;
405 if (cp->nclist.next &&
406 cp->type == NCLISTFALLTHRU)
407 return (cp);
408 if (cp->nclist.body == NULL)
409 exitstatus = 0;
410 return (cp->nclist.body);
411 }
412 }
413 }
414 exitstatus = 0;
415 return (NULL);
416 }
417
418
419
420 /*
421 * Kick off a subshell to evaluate a tree.
422 */
423
424 static void
evalsubshell(union node * n,int flags)425 evalsubshell(union node *n, int flags)
426 {
427 struct job *jp;
428 int backgnd = (n->type == NBACKGND);
429
430 oexitstatus = exitstatus;
431 expredir(n->nredir.redirect);
432 if ((!backgnd && flags & EV_EXIT && !have_traps()) ||
433 forkshell(jp = makejob(n, 1), n, backgnd) == 0) {
434 if (backgnd)
435 flags &=~ EV_TESTED;
436 redirect(n->nredir.redirect, 0);
437 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
438 } else if (! backgnd) {
439 INTOFF;
440 exitstatus = waitforjob(jp, (int *)NULL);
441 INTON;
442 } else
443 exitstatus = 0;
444 }
445
446
447 /*
448 * Evaluate a redirected compound command.
449 */
450
451 static void
evalredir(union node * n,int flags)452 evalredir(union node *n, int flags)
453 {
454 struct jmploc jmploc;
455 struct jmploc *savehandler;
456 volatile int in_redirect = 1;
457
458 oexitstatus = exitstatus;
459 expredir(n->nredir.redirect);
460 savehandler = handler;
461 if (setjmp(jmploc.loc)) {
462 int e;
463
464 handler = savehandler;
465 e = exception;
466 popredir();
467 if (e == EXERROR && in_redirect) {
468 FORCEINTON;
469 return;
470 }
471 longjmp(handler->loc, 1);
472 } else {
473 INTOFF;
474 handler = &jmploc;
475 redirect(n->nredir.redirect, REDIR_PUSH);
476 in_redirect = 0;
477 INTON;
478 evaltree(n->nredir.n, flags);
479 }
480 INTOFF;
481 handler = savehandler;
482 popredir();
483 INTON;
484 }
485
486
487 static void
exphere(union node * redir,struct arglist * fn)488 exphere(union node *redir, struct arglist *fn)
489 {
490 struct jmploc jmploc;
491 struct jmploc *savehandler;
492 struct localvar *savelocalvars;
493 int need_longjmp = 0;
494 unsigned char saveoptreset;
495
496 redir->nhere.expdoc = "";
497 savelocalvars = localvars;
498 localvars = NULL;
499 saveoptreset = shellparam.reset;
500 forcelocal++;
501 savehandler = handler;
502 if (setjmp(jmploc.loc))
503 need_longjmp = exception != EXERROR;
504 else {
505 handler = &jmploc;
506 expandarg(redir->nhere.doc, fn, 0);
507 redir->nhere.expdoc = fn->args[0];
508 INTOFF;
509 }
510 handler = savehandler;
511 forcelocal--;
512 poplocalvars();
513 localvars = savelocalvars;
514 shellparam.reset = saveoptreset;
515 if (need_longjmp)
516 longjmp(handler->loc, 1);
517 INTON;
518 }
519
520
521 /*
522 * Compute the names of the files in a redirection list.
523 */
524
525 static void
expredir(union node * n)526 expredir(union node *n)
527 {
528 union node *redir;
529
530 for (redir = n ; redir ; redir = redir->nfile.next) {
531 struct arglist fn;
532 emptyarglist(&fn);
533 switch (redir->type) {
534 case NFROM:
535 case NTO:
536 case NFROMTO:
537 case NAPPEND:
538 case NCLOBBER:
539 expandarg(redir->nfile.fname, &fn, EXP_TILDE);
540 redir->nfile.expfname = fn.args[0];
541 break;
542 case NFROMFD:
543 case NTOFD:
544 if (redir->ndup.vname) {
545 expandarg(redir->ndup.vname, &fn, EXP_TILDE);
546 fixredir(redir, fn.args[0], 1);
547 }
548 break;
549 case NXHERE:
550 exphere(redir, &fn);
551 break;
552 }
553 }
554 }
555
556
557
558 /*
559 * Evaluate a pipeline. All the processes in the pipeline are children
560 * of the process creating the pipeline. (This differs from some versions
561 * of the shell, which make the last process in a pipeline the parent
562 * of all the rest.)
563 */
564
565 static void
evalpipe(union node * n)566 evalpipe(union node *n)
567 {
568 struct job *jp;
569 struct nodelist *lp;
570 int pipelen;
571 int prevfd;
572 int pip[2];
573
574 TRACE(("evalpipe(%p) called\n", (void *)n));
575 pipelen = 0;
576 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
577 pipelen++;
578 INTOFF;
579 jp = makejob(n, pipelen);
580 prevfd = -1;
581 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
582 prehash(lp->n);
583 pip[1] = -1;
584 if (lp->next) {
585 if (pipe(pip) < 0) {
586 if (prevfd >= 0)
587 close(prevfd);
588 error("Pipe call failed: %s", strerror(errno));
589 }
590 }
591 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
592 INTON;
593 if (prevfd > 0) {
594 dup2(prevfd, 0);
595 close(prevfd);
596 }
597 if (pip[1] >= 0) {
598 if (!(prevfd >= 0 && pip[0] == 0))
599 close(pip[0]);
600 if (pip[1] != 1) {
601 dup2(pip[1], 1);
602 close(pip[1]);
603 }
604 }
605 evaltree(lp->n, EV_EXIT);
606 }
607 if (prevfd >= 0)
608 close(prevfd);
609 prevfd = pip[0];
610 if (pip[1] != -1)
611 close(pip[1]);
612 }
613 INTON;
614 if (n->npipe.backgnd == 0) {
615 INTOFF;
616 exitstatus = waitforjob(jp, (int *)NULL);
617 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
618 INTON;
619 } else
620 exitstatus = 0;
621 }
622
623
624
625 static int
is_valid_fast_cmdsubst(union node * n)626 is_valid_fast_cmdsubst(union node *n)
627 {
628
629 return (n->type == NCMD);
630 }
631
632 /*
633 * Execute a command inside back quotes. If it's a builtin command, we
634 * want to save its output in a block obtained from malloc. Otherwise
635 * we fork off a subprocess and get the output of the command via a pipe.
636 * Should be called with interrupts off.
637 */
638
639 void
evalbackcmd(union node * n,struct backcmd * result)640 evalbackcmd(union node *n, struct backcmd *result)
641 {
642 int pip[2];
643 struct job *jp;
644 struct stackmark smark;
645 struct jmploc jmploc;
646 struct jmploc *savehandler;
647 struct localvar *savelocalvars;
648 unsigned char saveoptreset;
649
650 result->fd = -1;
651 result->buf = NULL;
652 result->nleft = 0;
653 result->jp = NULL;
654 if (n == NULL) {
655 exitstatus = 0;
656 return;
657 }
658 setstackmark(&smark);
659 exitstatus = oexitstatus;
660 if (is_valid_fast_cmdsubst(n)) {
661 savelocalvars = localvars;
662 localvars = NULL;
663 saveoptreset = shellparam.reset;
664 forcelocal++;
665 savehandler = handler;
666 if (setjmp(jmploc.loc)) {
667 if (exception == EXERROR)
668 /* nothing */;
669 else if (exception != 0) {
670 handler = savehandler;
671 forcelocal--;
672 poplocalvars();
673 localvars = savelocalvars;
674 shellparam.reset = saveoptreset;
675 longjmp(handler->loc, 1);
676 }
677 } else {
678 handler = &jmploc;
679 evalcommand(n, EV_BACKCMD, result);
680 }
681 handler = savehandler;
682 forcelocal--;
683 poplocalvars();
684 localvars = savelocalvars;
685 shellparam.reset = saveoptreset;
686 } else {
687 if (pipe(pip) < 0)
688 error("Pipe call failed: %s", strerror(errno));
689 jp = makejob(n, 1);
690 if (forkshell(jp, n, FORK_NOJOB) == 0) {
691 FORCEINTON;
692 close(pip[0]);
693 if (pip[1] != 1) {
694 dup2(pip[1], 1);
695 close(pip[1]);
696 }
697 evaltree(n, EV_EXIT);
698 }
699 close(pip[1]);
700 result->fd = pip[0];
701 result->jp = jp;
702 }
703 popstackmark(&smark);
704 TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n",
705 result->fd, result->buf, result->nleft, result->jp));
706 }
707
708 static int
mustexpandto(const char * argtext,const char * mask)709 mustexpandto(const char *argtext, const char *mask)
710 {
711 for (;;) {
712 if (*argtext == CTLQUOTEMARK || *argtext == CTLQUOTEEND) {
713 argtext++;
714 continue;
715 }
716 if (*argtext == CTLESC)
717 argtext++;
718 else if (BASESYNTAX[(int)*argtext] == CCTL)
719 return (0);
720 if (*argtext != *mask)
721 return (0);
722 if (*argtext == '\0')
723 return (1);
724 argtext++;
725 mask++;
726 }
727 }
728
729 static int
isdeclarationcmd(struct narg * arg)730 isdeclarationcmd(struct narg *arg)
731 {
732 int have_command = 0;
733
734 if (arg == NULL)
735 return (0);
736 while (mustexpandto(arg->text, "command")) {
737 have_command = 1;
738 arg = &arg->next->narg;
739 if (arg == NULL)
740 return (0);
741 /*
742 * To also allow "command -p" and "command --" as part of
743 * a declaration command, add code here.
744 * We do not do this, as ksh does not do it either and it
745 * is not required by POSIX.
746 */
747 }
748 return (mustexpandto(arg->text, "export") ||
749 mustexpandto(arg->text, "readonly") ||
750 (mustexpandto(arg->text, "local") &&
751 (have_command || !isfunc("local"))));
752 }
753
754 static void
xtracecommand(struct arglist * varlist,int argc,char ** argv)755 xtracecommand(struct arglist *varlist, int argc, char **argv)
756 {
757 char sep = 0;
758 const char *text, *p, *ps4;
759 int i;
760
761 ps4 = expandstr(ps4val());
762 out2str(ps4 != NULL ? ps4 : ps4val());
763 for (i = 0; i < varlist->count; i++) {
764 text = varlist->args[i];
765 if (sep != 0)
766 out2c(' ');
767 p = strchr(text, '=');
768 if (p != NULL) {
769 p++;
770 outbin(text, p - text, out2);
771 out2qstr(p);
772 } else
773 out2qstr(text);
774 sep = ' ';
775 }
776 for (i = 0; i < argc; i++) {
777 text = argv[i];
778 if (sep != 0)
779 out2c(' ');
780 out2qstr(text);
781 sep = ' ';
782 }
783 out2c('\n');
784 flushout(&errout);
785 }
786
787 /*
788 * Check if a builtin can safely be executed in the same process,
789 * even though it should be in a subshell (command substitution).
790 * Note that jobid, jobs, times and trap can show information not
791 * available in a child process; this is deliberate.
792 * The arguments should already have been expanded.
793 */
794 static int
safe_builtin(int idx,int argc,char ** argv)795 safe_builtin(int idx, int argc, char **argv)
796 {
797 /* Generated from builtins.def. */
798 if (safe_builtin_always(idx))
799 return (1);
800 if (idx == EXPORTCMD || idx == TRAPCMD || idx == ULIMITCMD ||
801 idx == UMASKCMD)
802 return (argc <= 1 || (argc == 2 && argv[1][0] == '-'));
803 if (idx == SETCMD)
804 return (argc <= 1 || (argc == 2 && (argv[1][0] == '-' ||
805 argv[1][0] == '+') && argv[1][1] == 'o' &&
806 argv[1][2] == '\0'));
807 return (0);
808 }
809
810 /*
811 * Execute a simple command.
812 * Note: This may or may not return if (flags & EV_EXIT).
813 */
814
815 static void
evalcommand(union node * cmd,int flags,struct backcmd * backcmd)816 evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
817 {
818 union node *argp;
819 struct arglist arglist;
820 struct arglist varlist;
821 char **argv;
822 int argc;
823 char **envp;
824 int varflag;
825 int mode;
826 int pip[2];
827 struct cmdentry cmdentry;
828 struct job *jp;
829 struct jmploc jmploc;
830 struct jmploc *savehandler;
831 char *savecmdname;
832 struct shparam saveparam;
833 struct localvar *savelocalvars;
834 struct parsefile *savetopfile;
835 volatile int e;
836 char *lastarg;
837 int signaled;
838 int do_clearcmdentry;
839 const char *path = pathval();
840 int i;
841
842 /* First expand the arguments. */
843 TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags));
844 emptyarglist(&arglist);
845 emptyarglist(&varlist);
846 varflag = 1;
847 jp = NULL;
848 do_clearcmdentry = 0;
849 oexitstatus = exitstatus;
850 exitstatus = 0;
851 /* Add one slot at the beginning for tryexec(). */
852 appendarglist(&arglist, nullstr);
853 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
854 if (varflag && isassignment(argp->narg.text)) {
855 expandarg(argp, varflag == 1 ? &varlist : &arglist,
856 EXP_VARTILDE);
857 continue;
858 } else if (varflag == 1)
859 varflag = isdeclarationcmd(&argp->narg) ? 2 : 0;
860 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
861 }
862 appendarglist(&arglist, nullstr);
863 expredir(cmd->ncmd.redirect);
864 argc = arglist.count - 2;
865 argv = &arglist.args[1];
866
867 argv[argc] = NULL;
868 lastarg = NULL;
869 if (iflag && funcnest == 0 && argc > 0)
870 lastarg = argv[argc - 1];
871
872 /* Print the command if xflag is set. */
873 if (xflag)
874 xtracecommand(&varlist, argc, argv);
875
876 /* Now locate the command. */
877 if (argc == 0) {
878 /* Variable assignment(s) without command */
879 cmdentry.cmdtype = CMDBUILTIN;
880 cmdentry.u.index = BLTINCMD;
881 cmdentry.special = 0;
882 } else {
883 static const char PATH[] = "PATH=";
884 int cmd_flags = 0, bltinonly = 0;
885
886 /*
887 * Modify the command lookup path, if a PATH= assignment
888 * is present
889 */
890 for (i = 0; i < varlist.count; i++)
891 if (strncmp(varlist.args[i], PATH, sizeof(PATH) - 1) == 0) {
892 path = varlist.args[i] + sizeof(PATH) - 1;
893 /*
894 * On `PATH=... command`, we need to make
895 * sure that the command isn't using the
896 * non-updated hash table of the outer PATH
897 * setting and we need to make sure that
898 * the hash table isn't filled with items
899 * from the temporary setting.
900 *
901 * It would be better to forbid using and
902 * updating the table while this command
903 * runs, by the command finding mechanism
904 * is heavily integrated with hash handling,
905 * so we just delete the hash before and after
906 * the command runs. Partly deleting like
907 * changepatch() does doesn't seem worth the
908 * bookinging effort, since most such runs add
909 * directories in front of the new PATH.
910 */
911 clearcmdentry();
912 do_clearcmdentry = 1;
913 }
914
915 for (;;) {
916 if (bltinonly) {
917 cmdentry.u.index = find_builtin(*argv, &cmdentry.special);
918 if (cmdentry.u.index < 0) {
919 cmdentry.u.index = BLTINCMD;
920 argv--;
921 argc++;
922 break;
923 }
924 } else
925 find_command(argv[0], &cmdentry, cmd_flags, path);
926 /* implement the bltin and command builtins here */
927 if (cmdentry.cmdtype != CMDBUILTIN)
928 break;
929 if (cmdentry.u.index == BLTINCMD) {
930 if (argc == 1)
931 break;
932 argv++;
933 argc--;
934 bltinonly = 1;
935 } else if (cmdentry.u.index == COMMANDCMD) {
936 if (argc == 1)
937 break;
938 if (!strcmp(argv[1], "-p")) {
939 if (argc == 2)
940 break;
941 if (argv[2][0] == '-') {
942 if (strcmp(argv[2], "--"))
943 break;
944 if (argc == 3)
945 break;
946 argv += 3;
947 argc -= 3;
948 } else {
949 argv += 2;
950 argc -= 2;
951 }
952 path = _PATH_STDPATH;
953 clearcmdentry();
954 do_clearcmdentry = 1;
955 } else if (!strcmp(argv[1], "--")) {
956 if (argc == 2)
957 break;
958 argv += 2;
959 argc -= 2;
960 } else if (argv[1][0] == '-')
961 break;
962 else {
963 argv++;
964 argc--;
965 }
966 cmd_flags |= DO_NOFUNC;
967 bltinonly = 0;
968 } else
969 break;
970 }
971 /*
972 * Special builtins lose their special properties when
973 * called via 'command'.
974 */
975 if (cmd_flags & DO_NOFUNC)
976 cmdentry.special = 0;
977 }
978
979 /* Fork off a child process if necessary. */
980 if (((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN)
981 && ((flags & EV_EXIT) == 0 || have_traps()))
982 || ((flags & EV_BACKCMD) != 0
983 && (cmdentry.cmdtype != CMDBUILTIN ||
984 !safe_builtin(cmdentry.u.index, argc, argv)))) {
985 jp = makejob(cmd, 1);
986 mode = FORK_FG;
987 if (flags & EV_BACKCMD) {
988 mode = FORK_NOJOB;
989 if (pipe(pip) < 0)
990 error("Pipe call failed: %s", strerror(errno));
991 }
992 if (cmdentry.cmdtype == CMDNORMAL &&
993 cmd->ncmd.redirect == NULL &&
994 varlist.count == 0 &&
995 (mode == FORK_FG || mode == FORK_NOJOB) &&
996 !disvforkset() && !iflag && !mflag) {
997 vforkexecshell(jp, argv, environment(), path,
998 cmdentry.u.index, flags & EV_BACKCMD ? pip : NULL);
999 goto parent;
1000 }
1001 if (forkshell(jp, cmd, mode) != 0)
1002 goto parent; /* at end of routine */
1003 if (flags & EV_BACKCMD) {
1004 FORCEINTON;
1005 close(pip[0]);
1006 if (pip[1] != 1) {
1007 dup2(pip[1], 1);
1008 close(pip[1]);
1009 }
1010 flags &= ~EV_BACKCMD;
1011 }
1012 flags |= EV_EXIT;
1013 }
1014
1015 /* This is the child process if a fork occurred. */
1016 /* Execute the command. */
1017 if (cmdentry.cmdtype == CMDFUNCTION) {
1018 #ifdef DEBUG
1019 trputs("Shell function: "); trargs(argv);
1020 #endif
1021 saveparam = shellparam;
1022 shellparam.malloc = 0;
1023 shellparam.reset = 1;
1024 shellparam.nparam = argc - 1;
1025 shellparam.p = argv + 1;
1026 shellparam.optp = NULL;
1027 shellparam.optnext = NULL;
1028 INTOFF;
1029 savelocalvars = localvars;
1030 localvars = NULL;
1031 reffunc(cmdentry.u.func);
1032 savehandler = handler;
1033 if (setjmp(jmploc.loc)) {
1034 popredir();
1035 unreffunc(cmdentry.u.func);
1036 poplocalvars();
1037 localvars = savelocalvars;
1038 freeparam(&shellparam);
1039 shellparam = saveparam;
1040 funcnest--;
1041 handler = savehandler;
1042 longjmp(handler->loc, 1);
1043 }
1044 handler = &jmploc;
1045 funcnest++;
1046 redirect(cmd->ncmd.redirect, REDIR_PUSH);
1047 INTON;
1048 for (i = 0; i < varlist.count; i++)
1049 mklocal(varlist.args[i]);
1050 exitstatus = oexitstatus;
1051 evaltree(getfuncnode(cmdentry.u.func),
1052 flags & (EV_TESTED | EV_EXIT));
1053 INTOFF;
1054 unreffunc(cmdentry.u.func);
1055 poplocalvars();
1056 localvars = savelocalvars;
1057 freeparam(&shellparam);
1058 shellparam = saveparam;
1059 handler = savehandler;
1060 funcnest--;
1061 popredir();
1062 INTON;
1063 if (evalskip == SKIPRETURN) {
1064 evalskip = 0;
1065 skipcount = 0;
1066 }
1067 if (jp)
1068 exitshell(exitstatus);
1069 } else if (cmdentry.cmdtype == CMDBUILTIN) {
1070 #ifdef DEBUG
1071 trputs("builtin command: "); trargs(argv);
1072 #endif
1073 mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
1074 if (flags == EV_BACKCMD) {
1075 memout.nextc = memout.buf;
1076 mode |= REDIR_BACKQ;
1077 }
1078 savecmdname = commandname;
1079 savetopfile = getcurrentfile();
1080 cmdenviron = &varlist;
1081 e = -1;
1082 savehandler = handler;
1083 if (setjmp(jmploc.loc)) {
1084 e = exception;
1085 if (e == EXINT)
1086 exitstatus = SIGINT+128;
1087 goto cmddone;
1088 }
1089 handler = &jmploc;
1090 redirect(cmd->ncmd.redirect, mode);
1091 outclearerror(out1);
1092 /*
1093 * If there is no command word, redirection errors should
1094 * not be fatal but assignment errors should.
1095 */
1096 if (argc == 0)
1097 cmdentry.special = 1;
1098 listsetvar(cmdenviron, cmdentry.special ? 0 : VNOSET);
1099 if (argc > 0)
1100 bltinsetlocale();
1101 commandname = argv[0];
1102 argptr = argv + 1;
1103 nextopt_optptr = NULL; /* initialize nextopt */
1104 builtin_flags = flags;
1105 exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
1106 flushall();
1107 if (outiserror(out1)) {
1108 warning("write error on stdout");
1109 if (exitstatus == 0 || exitstatus == 1)
1110 exitstatus = 2;
1111 }
1112 cmddone:
1113 if (argc > 0)
1114 bltinunsetlocale();
1115 cmdenviron = NULL;
1116 out1 = &output;
1117 out2 = &errout;
1118 freestdout();
1119 handler = savehandler;
1120 commandname = savecmdname;
1121 if (jp)
1122 exitshell(exitstatus);
1123 if (flags == EV_BACKCMD) {
1124 backcmd->buf = memout.buf;
1125 backcmd->nleft = memout.buf != NULL ?
1126 memout.nextc - memout.buf : 0;
1127 memout.buf = NULL;
1128 memout.nextc = NULL;
1129 memout.bufend = NULL;
1130 memout.bufsize = 64;
1131 }
1132 if (cmdentry.u.index != EXECCMD)
1133 popredir();
1134 if (e != -1) {
1135 if (e != EXERROR || cmdentry.special)
1136 exraise(e);
1137 popfilesupto(savetopfile);
1138 if (flags != EV_BACKCMD)
1139 FORCEINTON;
1140 }
1141 } else {
1142 #ifdef DEBUG
1143 trputs("normal command: "); trargs(argv);
1144 #endif
1145 redirect(cmd->ncmd.redirect, 0);
1146 for (i = 0; i < varlist.count; i++)
1147 setvareq(varlist.args[i], VEXPORT|VSTACK);
1148 envp = environment();
1149 shellexec(argv, envp, path, cmdentry.u.index);
1150 /*NOTREACHED*/
1151 }
1152 goto out;
1153
1154 parent: /* parent process gets here (if we forked) */
1155 if (mode == FORK_FG) { /* argument to fork */
1156 INTOFF;
1157 exitstatus = waitforjob(jp, &signaled);
1158 INTON;
1159 if (iflag && loopnest > 0 && signaled) {
1160 evalskip = SKIPBREAK;
1161 skipcount = loopnest;
1162 }
1163 } else if (mode == FORK_NOJOB) {
1164 backcmd->fd = pip[0];
1165 close(pip[1]);
1166 backcmd->jp = jp;
1167 }
1168
1169 out:
1170 if (lastarg)
1171 setvar("_", lastarg, 0);
1172 if (do_clearcmdentry)
1173 clearcmdentry();
1174 }
1175
1176
1177
1178 /*
1179 * Search for a command. This is called before we fork so that the
1180 * location of the command will be available in the parent as well as
1181 * the child. The check for "goodname" is an overly conservative
1182 * check that the name will not be subject to expansion.
1183 */
1184
1185 static void
prehash(union node * n)1186 prehash(union node *n)
1187 {
1188 struct cmdentry entry;
1189
1190 if (n && n->type == NCMD && n->ncmd.args)
1191 if (goodname(n->ncmd.args->narg.text))
1192 find_command(n->ncmd.args->narg.text, &entry, 0,
1193 pathval());
1194 }
1195
1196
1197
1198 /*
1199 * Builtin commands. Builtin commands whose functions are closely
1200 * tied to evaluation are implemented here.
1201 */
1202
1203 /*
1204 * No command given, a bltin command with no arguments, or a bltin command
1205 * with an invalid name.
1206 */
1207
1208 int
bltincmd(int argc,char ** argv)1209 bltincmd(int argc, char **argv)
1210 {
1211 if (argc > 1) {
1212 out2fmt_flush("%s: not found\n", argv[1]);
1213 return 127;
1214 }
1215 /*
1216 * Preserve exitstatus of a previous possible command substitution
1217 * as POSIX mandates
1218 */
1219 return exitstatus;
1220 }
1221
1222
1223 /*
1224 * Handle break and continue commands. Break, continue, and return are
1225 * all handled by setting the evalskip flag. The evaluation routines
1226 * above all check this flag, and if it is set they start skipping
1227 * commands rather than executing them. The variable skipcount is
1228 * the number of loops to break/continue, or the number of function
1229 * levels to return. (The latter is always 1.) It should probably
1230 * be an error to break out of more loops than exist, but it isn't
1231 * in the standard shell so we don't make it one here.
1232 */
1233
1234 int
breakcmd(int argc,char ** argv)1235 breakcmd(int argc, char **argv)
1236 {
1237 long n;
1238 char *end;
1239
1240 if (argc > 1) {
1241 /* Allow arbitrarily large numbers. */
1242 n = strtol(argv[1], &end, 10);
1243 if (!is_digit(argv[1][0]) || *end != '\0')
1244 error("Illegal number: %s", argv[1]);
1245 } else
1246 n = 1;
1247 if (n > loopnest)
1248 n = loopnest;
1249 if (n > 0) {
1250 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
1251 skipcount = n;
1252 }
1253 return 0;
1254 }
1255
1256 /*
1257 * The `command' command.
1258 */
1259 int
commandcmd(int argc __unused,char ** argv __unused)1260 commandcmd(int argc __unused, char **argv __unused)
1261 {
1262 const char *path;
1263 int ch;
1264 int cmd = -1;
1265
1266 path = bltinlookup("PATH", 1);
1267
1268 while ((ch = nextopt("pvV")) != '\0') {
1269 switch (ch) {
1270 case 'p':
1271 path = _PATH_STDPATH;
1272 break;
1273 case 'v':
1274 cmd = TYPECMD_SMALLV;
1275 break;
1276 case 'V':
1277 cmd = TYPECMD_BIGV;
1278 break;
1279 }
1280 }
1281
1282 if (cmd != -1) {
1283 if (*argptr == NULL || argptr[1] != NULL)
1284 error("wrong number of arguments");
1285 return typecmd_impl(2, argptr - 1, cmd, path);
1286 }
1287 if (*argptr != NULL)
1288 error("commandcmd bad call");
1289
1290 /*
1291 * Do nothing successfully if no command was specified;
1292 * ksh also does this.
1293 */
1294 return 0;
1295 }
1296
1297
1298 /*
1299 * The return command.
1300 */
1301
1302 int
returncmd(int argc,char ** argv)1303 returncmd(int argc, char **argv)
1304 {
1305 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
1306
1307 evalskip = SKIPRETURN;
1308 skipcount = 1;
1309 return ret;
1310 }
1311
1312
1313 int
falsecmd(int argc __unused,char ** argv __unused)1314 falsecmd(int argc __unused, char **argv __unused)
1315 {
1316 return 1;
1317 }
1318
1319
1320 int
truecmd(int argc __unused,char ** argv __unused)1321 truecmd(int argc __unused, char **argv __unused)
1322 {
1323 return 0;
1324 }
1325
1326
1327 int
execcmd(int argc,char ** argv)1328 execcmd(int argc, char **argv)
1329 {
1330 int i;
1331
1332 /*
1333 * Because we have historically not supported any options,
1334 * only treat "--" specially.
1335 */
1336 if (argc > 1 && strcmp(argv[1], "--") == 0)
1337 argc--, argv++;
1338 if (argc > 1) {
1339 iflag = 0; /* exit on error */
1340 mflag = 0;
1341 optschanged();
1342 for (i = 0; i < cmdenviron->count; i++)
1343 setvareq(cmdenviron->args[i], VEXPORT|VSTACK);
1344 shellexec(argv + 1, environment(), pathval(), 0);
1345
1346 }
1347 return 0;
1348 }
1349
1350
1351 int
timescmd(int argc __unused,char ** argv __unused)1352 timescmd(int argc __unused, char **argv __unused)
1353 {
1354 struct rusage ru;
1355 long shumins, shsmins, chumins, chsmins;
1356 double shusecs, shssecs, chusecs, chssecs;
1357
1358 if (getrusage(RUSAGE_SELF, &ru) < 0)
1359 return 1;
1360 shumins = ru.ru_utime.tv_sec / 60;
1361 shusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
1362 shsmins = ru.ru_stime.tv_sec / 60;
1363 shssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
1364 if (getrusage(RUSAGE_CHILDREN, &ru) < 0)
1365 return 1;
1366 chumins = ru.ru_utime.tv_sec / 60;
1367 chusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
1368 chsmins = ru.ru_stime.tv_sec / 60;
1369 chssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
1370 out1fmt("%ldm%.3fs %ldm%.3fs\n%ldm%.3fs %ldm%.3fs\n", shumins,
1371 shusecs, shsmins, shssecs, chumins, chusecs, chsmins, chssecs);
1372 return 0;
1373 }
1374