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