eval.c revision 1.126 1 /* $NetBSD: eval.c,v 1.126 2016/05/10 15:14:30 kre Exp $ */
2
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 <sys/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95";
39 #else
40 __RCSID("$NetBSD: eval.c,v 1.126 2016/05/10 15:14:30 kre Exp $");
41 #endif
42 #endif /* not lint */
43
44 #include <stdbool.h>
45 #include <stdlib.h>
46 #include <signal.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <errno.h>
50 #include <limits.h>
51 #include <unistd.h>
52 #include <sys/fcntl.h>
53 #include <sys/times.h>
54 #include <sys/param.h>
55 #include <sys/types.h>
56 #include <sys/wait.h>
57 #include <sys/sysctl.h>
58
59 /*
60 * Evaluate a command.
61 */
62
63 #include "shell.h"
64 #include "nodes.h"
65 #include "syntax.h"
66 #include "expand.h"
67 #include "parser.h"
68 #include "jobs.h"
69 #include "eval.h"
70 #include "builtins.h"
71 #include "options.h"
72 #include "exec.h"
73 #include "redir.h"
74 #include "input.h"
75 #include "output.h"
76 #include "trap.h"
77 #include "var.h"
78 #include "memalloc.h"
79 #include "error.h"
80 #include "show.h"
81 #include "mystring.h"
82 #include "main.h"
83 #ifndef SMALL
84 #include "nodenames.h"
85 #include "myhistedit.h"
86 #endif
87
88
89 STATIC enum skipstate evalskip; /* != SKIPNONE if we are skipping commands */
90 STATIC int skipcount; /* number of levels to skip */
91 STATIC int loopnest; /* current loop nesting level */
92 STATIC int funcnest; /* depth of function calls */
93 STATIC int builtin_flags; /* evalcommand flags for builtins */
94 /*
95 * Base function nesting level inside a dot command. Set to 0 initially
96 * and to (funcnest + 1) before every dot command to enable
97 * 1) detection of being in a file sourced by a dot command and
98 * 2) counting of function nesting in that file for the implementation
99 * of the return command.
100 * The value is reset to its previous value after the dot command.
101 */
102 STATIC int dot_funcnest;
103
104
105 const char *commandname;
106 struct strlist *cmdenviron;
107 int exitstatus; /* exit status of last command */
108 int back_exitstatus; /* exit status of backquoted command */
109
110
111 STATIC void evalloop(union node *, int);
112 STATIC void evalfor(union node *, int);
113 STATIC void evalcase(union node *, int);
114 STATIC void evalsubshell(union node *, int);
115 STATIC void expredir(union node *);
116 STATIC void evalpipe(union node *);
117 STATIC void evalcommand(union node *, int, struct backcmd *);
118 STATIC void prehash(union node *);
119
120 STATIC char *find_dot_file(char *);
121
122 /*
123 * Called to reset things after an exception.
124 */
125
126 #ifdef mkinit
127 INCLUDE "eval.h"
128
129 RESET {
130 reset_eval();
131 }
132
133 SHELLPROC {
134 exitstatus = 0;
135 }
136 #endif
137
138 void
139 reset_eval(void)
140 {
141 evalskip = SKIPNONE;
142 dot_funcnest = 0;
143 loopnest = 0;
144 funcnest = 0;
145 }
146
147 static int
148 sh_pipe(int fds[2])
149 {
150 int nfd;
151
152 if (pipe(fds))
153 return -1;
154
155 if (fds[0] < 3) {
156 nfd = fcntl(fds[0], F_DUPFD, 3);
157 if (nfd != -1) {
158 close(fds[0]);
159 fds[0] = nfd;
160 }
161 }
162
163 if (fds[1] < 3) {
164 nfd = fcntl(fds[1], F_DUPFD, 3);
165 if (nfd != -1) {
166 close(fds[1]);
167 fds[1] = nfd;
168 }
169 }
170 return 0;
171 }
172
173
174 /*
175 * The eval commmand.
176 */
177
178 int
179 evalcmd(int argc, char **argv)
180 {
181 char *p;
182 char *concat;
183 char **ap;
184
185 if (argc > 1) {
186 p = argv[1];
187 if (argc > 2) {
188 STARTSTACKSTR(concat);
189 ap = argv + 2;
190 for (;;) {
191 while (*p)
192 STPUTC(*p++, concat);
193 if ((p = *ap++) == NULL)
194 break;
195 STPUTC(' ', concat);
196 }
197 STPUTC('\0', concat);
198 p = grabstackstr(concat);
199 }
200 evalstring(p, builtin_flags & EV_TESTED);
201 }
202 return exitstatus;
203 }
204
205
206 /*
207 * Execute a command or commands contained in a string.
208 */
209
210 void
211 evalstring(char *s, int flag)
212 {
213 union node *n;
214 struct stackmark smark;
215
216 setstackmark(&smark);
217 setinputstring(s, 1);
218
219 while ((n = parsecmd(0)) != NEOF) {
220 TRACE(("evalstring: "); showtree(n));
221 if (nflag == 0)
222 evaltree(n, flag | EV_MORE);
223 popstackmark(&smark);
224 }
225 popfile();
226 popstackmark(&smark);
227 }
228
229
230
231 /*
232 * Evaluate a parse tree. The value is left in the global variable
233 * exitstatus.
234 */
235
236 void
237 evaltree(union node *n, int flags)
238 {
239 bool do_etest;
240
241 do_etest = false;
242 if (n == NULL || nflag) {
243 TRACE(("evaltree(%s) called\n", n == NULL ? "NULL" : "-n"));
244 if (nflag == 0)
245 exitstatus = 0;
246 goto out;
247 }
248 #ifndef SMALL
249 displayhist = 1; /* show history substitutions done with fc */
250 #endif
251 #ifdef NODETYPENAME
252 TRACE(("pid %d, evaltree(%p: %s(%d), %#x) called\n",
253 getpid(), n, NODETYPENAME(n->type), n->type, flags));
254 #else
255 TRACE(("pid %d, evaltree(%p: %d, %#x) called\n",
256 getpid(), n, n->type, flags));
257 #endif
258 switch (n->type) {
259 case NSEMI:
260 evaltree(n->nbinary.ch1, (flags & EV_TESTED) |
261 (n->nbinary.ch2 ? EV_MORE : 0));
262 if (nflag || evalskip)
263 goto out;
264 evaltree(n->nbinary.ch2, flags);
265 break;
266 case NAND:
267 evaltree(n->nbinary.ch1, EV_TESTED | EV_MORE);
268 if (nflag || evalskip || exitstatus != 0)
269 goto out;
270 evaltree(n->nbinary.ch2, flags);
271 break;
272 case NOR:
273 evaltree(n->nbinary.ch1, EV_TESTED | EV_MORE);
274 if (nflag || evalskip || exitstatus == 0)
275 goto out;
276 evaltree(n->nbinary.ch2, flags);
277 break;
278 case NREDIR:
279 expredir(n->nredir.redirect);
280 redirect(n->nredir.redirect, REDIR_PUSH | REDIR_KEEP);
281 evaltree(n->nredir.n, flags);
282 popredir();
283 break;
284 case NSUBSHELL:
285 evalsubshell(n, flags & ~EV_MORE);
286 do_etest = !(flags & EV_TESTED);
287 break;
288 case NBACKGND:
289 evalsubshell(n, flags & ~EV_MORE);
290 break;
291 case NIF: {
292 evaltree(n->nif.test, EV_TESTED | EV_MORE);
293 if (nflag || evalskip)
294 goto out;
295 if (exitstatus == 0)
296 evaltree(n->nif.ifpart, flags);
297 else if (n->nif.elsepart)
298 evaltree(n->nif.elsepart, flags);
299 else
300 exitstatus = 0;
301 break;
302 }
303 case NWHILE:
304 case NUNTIL:
305 evalloop(n, flags);
306 break;
307 case NFOR:
308 evalfor(n, flags);
309 break;
310 case NCASE:
311 evalcase(n, flags);
312 break;
313 case NDEFUN:
314 defun(n->narg.text, n->narg.next);
315 exitstatus = 0;
316 break;
317 case NNOT:
318 evaltree(n->nnot.com, (flags & EV_MORE) | EV_TESTED);
319 exitstatus = !exitstatus;
320 break;
321 case NPIPE:
322 evalpipe(n);
323 do_etest = !(flags & EV_TESTED);
324 break;
325 case NCMD:
326 evalcommand(n, flags, NULL);
327 do_etest = !(flags & EV_TESTED);
328 break;
329 default:
330 #ifdef NODETYPENAME
331 out1fmt("Node type = %d(%s)\n", n->type, NODETYPENAME(n->type));
332 #else
333 out1fmt("Node type = %d\n", n->type);
334 #endif
335 flushout(&output);
336 break;
337 }
338 out:
339 if (pendingsigs)
340 dotrap();
341 if ((flags & EV_EXIT) != 0 || (eflag && exitstatus != 0 && do_etest))
342 exitshell(exitstatus);
343 }
344
345
346 STATIC void
347 evalloop(union node *n, int flags)
348 {
349 int status;
350
351 loopnest++;
352 status = 0;
353
354 #ifdef NODETYPENAME
355 TRACE(("evalloop %s: ", NODETYPENAME(n->type)));
356 #else
357 TRACE(("evalloop %s: ", n->type == NWHILE ? "while" : "until"));
358 #endif
359 TRACE((""); showtree(n->nbinary.ch1));
360 TRACE(("evalloop do: "); showtree(n->nbinary.ch2));
361 TRACE(("evalloop done\n"));
362
363 for (;;) {
364 evaltree(n->nbinary.ch1, EV_TESTED | EV_MORE);
365 if (nflag)
366 break;
367 if (evalskip) {
368 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
369 evalskip = SKIPNONE;
370 continue;
371 }
372 if (evalskip == SKIPBREAK && --skipcount <= 0)
373 evalskip = SKIPNONE;
374 break;
375 }
376 if (n->type == NWHILE) {
377 if (exitstatus != 0)
378 break;
379 } else {
380 if (exitstatus == 0)
381 break;
382 }
383 evaltree(n->nbinary.ch2, (flags & EV_TESTED) | EV_MORE);
384 status = exitstatus;
385 if (evalskip)
386 goto skipping;
387 }
388 loopnest--;
389 exitstatus = status;
390 }
391
392
393
394 STATIC void
395 evalfor(union node *n, int flags)
396 {
397 struct arglist arglist;
398 union node *argp;
399 struct strlist *sp;
400 struct stackmark smark;
401 int status;
402
403 status = nflag ? exitstatus : 0;
404
405 setstackmark(&smark);
406 arglist.lastp = &arglist.list;
407 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
408 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
409 if (evalskip)
410 goto out;
411 }
412 *arglist.lastp = NULL;
413
414 loopnest++;
415 for (sp = arglist.list ; sp ; sp = sp->next) {
416 setvar(n->nfor.var, sp->text, 0);
417 evaltree(n->nfor.body, flags & (EV_TESTED | EV_MORE));
418 status = exitstatus;
419 if (nflag)
420 break;
421 if (evalskip) {
422 if (evalskip == SKIPCONT && --skipcount <= 0) {
423 evalskip = SKIPNONE;
424 continue;
425 }
426 if (evalskip == SKIPBREAK && --skipcount <= 0)
427 evalskip = SKIPNONE;
428 break;
429 }
430 }
431 loopnest--;
432 exitstatus = status;
433 out:
434 popstackmark(&smark);
435 }
436
437
438
439 STATIC void
440 evalcase(union node *n, int flags)
441 {
442 union node *cp;
443 union node *patp;
444 struct arglist arglist;
445 struct stackmark smark;
446 int status = 0;
447
448 setstackmark(&smark);
449 arglist.lastp = &arglist.list;
450 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
451 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
452 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
453 if (casematch(patp, arglist.list->text)) {
454 if (evalskip == 0) {
455 evaltree(cp->nclist.body, flags);
456 status = exitstatus;
457 }
458 goto out;
459 }
460 }
461 }
462 out:
463 exitstatus = status;
464 popstackmark(&smark);
465 }
466
467
468
469 /*
470 * Kick off a subshell to evaluate a tree.
471 */
472
473 STATIC void
474 evalsubshell(union node *n, int flags)
475 {
476 struct job *jp;
477 int backgnd = (n->type == NBACKGND);
478
479 expredir(n->nredir.redirect);
480 INTOFF;
481 jp = makejob(n, 1);
482 if (forkshell(jp, n, backgnd ? FORK_BG : FORK_FG) == 0) {
483 INTON;
484 if (backgnd)
485 flags &=~ EV_TESTED;
486 redirect(n->nredir.redirect, REDIR_KEEP);
487 /* never returns */
488 evaltree(n->nredir.n, flags | EV_EXIT);
489 }
490 exitstatus = backgnd ? 0 : waitforjob(jp);
491 INTON;
492 }
493
494
495
496 /*
497 * Compute the names of the files in a redirection list.
498 */
499
500 STATIC void
501 expredir(union node *n)
502 {
503 union node *redir;
504
505 for (redir = n ; redir ; redir = redir->nfile.next) {
506 struct arglist fn;
507
508 fn.lastp = &fn.list;
509 switch (redir->type) {
510 case NFROMTO:
511 case NFROM:
512 case NTO:
513 case NCLOBBER:
514 case NAPPEND:
515 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
516 redir->nfile.expfname = fn.list->text;
517 break;
518 case NFROMFD:
519 case NTOFD:
520 if (redir->ndup.vname) {
521 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
522 fixredir(redir, fn.list->text, 1);
523 }
524 break;
525 }
526 }
527 }
528
529
530
531 /*
532 * Evaluate a pipeline. All the processes in the pipeline are children
533 * of the process creating the pipeline. (This differs from some versions
534 * of the shell, which make the last process in a pipeline the parent
535 * of all the rest.)
536 */
537
538 STATIC void
539 evalpipe(union node *n)
540 {
541 struct job *jp;
542 struct nodelist *lp;
543 int pipelen;
544 int prevfd;
545 int pip[2];
546
547 TRACE(("evalpipe(0x%lx) called\n", (long)n));
548 pipelen = 0;
549 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
550 pipelen++;
551 INTOFF;
552 jp = makejob(n, pipelen);
553 prevfd = -1;
554 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
555 prehash(lp->n);
556 pip[1] = -1;
557 if (lp->next) {
558 if (sh_pipe(pip) < 0) {
559 if (prevfd >= 0)
560 close(prevfd);
561 error("Pipe call failed");
562 }
563 }
564 if (forkshell(jp, lp->n, n->npipe.backgnd ? FORK_BG : FORK_FG) == 0) {
565 INTON;
566 if (prevfd > 0)
567 movefd(prevfd, 0);
568 if (pip[1] >= 0) {
569 close(pip[0]);
570 movefd(pip[1], 1);
571 }
572 evaltree(lp->n, EV_EXIT);
573 }
574 if (prevfd >= 0)
575 close(prevfd);
576 prevfd = pip[0];
577 close(pip[1]);
578 }
579 if (n->npipe.backgnd == 0) {
580 exitstatus = waitforjob(jp);
581 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
582 } else
583 exitstatus = 0;
584 INTON;
585 }
586
587
588
589 /*
590 * Execute a command inside back quotes. If it's a builtin command, we
591 * want to save its output in a block obtained from malloc. Otherwise
592 * we fork off a subprocess and get the output of the command via a pipe.
593 * Should be called with interrupts off.
594 */
595
596 void
597 evalbackcmd(union node *n, struct backcmd *result)
598 {
599 int pip[2];
600 struct job *jp;
601 struct stackmark smark; /* unnecessary */
602
603 setstackmark(&smark);
604 result->fd = -1;
605 result->buf = NULL;
606 result->nleft = 0;
607 result->jp = NULL;
608 if (nflag || n == NULL) {
609 goto out;
610 }
611 #ifdef notyet
612 /*
613 * For now we disable executing builtins in the same
614 * context as the shell, because we are not keeping
615 * enough state to recover from changes that are
616 * supposed only to affect subshells. eg. echo "`cd /`"
617 */
618 if (n->type == NCMD) {
619 exitstatus = oexitstatus;
620 evalcommand(n, EV_BACKCMD, result);
621 } else
622 #endif
623 {
624 INTOFF;
625 if (sh_pipe(pip) < 0)
626 error("Pipe call failed");
627 jp = makejob(n, 1);
628 if (forkshell(jp, n, FORK_NOJOB) == 0) {
629 FORCEINTON;
630 close(pip[0]);
631 movefd(pip[1], 1);
632 eflag = 0;
633 evaltree(n, EV_EXIT);
634 /* NOTREACHED */
635 }
636 close(pip[1]);
637 result->fd = pip[0];
638 result->jp = jp;
639 INTON;
640 }
641 out:
642 popstackmark(&smark);
643 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
644 result->fd, result->buf, result->nleft, result->jp));
645 }
646
647 static const char *
648 syspath(void)
649 {
650 static char *sys_path = NULL;
651 static int mib[] = {CTL_USER, USER_CS_PATH};
652 static char def_path[] = "PATH=/usr/bin:/bin:/usr/sbin:/sbin";
653 size_t len;
654
655 if (sys_path == NULL) {
656 if (sysctl(mib, 2, 0, &len, 0, 0) != -1 &&
657 (sys_path = ckmalloc(len + 5)) != NULL &&
658 sysctl(mib, 2, sys_path + 5, &len, 0, 0) != -1) {
659 memcpy(sys_path, "PATH=", 5);
660 } else {
661 ckfree(sys_path);
662 /* something to keep things happy */
663 sys_path = def_path;
664 }
665 }
666 return sys_path;
667 }
668
669 static int
670 parse_command_args(int argc, char **argv, int *use_syspath)
671 {
672 int sv_argc = argc;
673 char *cp, c;
674
675 *use_syspath = 0;
676
677 for (;;) {
678 argv++;
679 if (--argc == 0)
680 break;
681 cp = *argv;
682 if (*cp++ != '-')
683 break;
684 if (*cp == '-' && cp[1] == 0) {
685 argv++;
686 argc--;
687 break;
688 }
689 while ((c = *cp++)) {
690 switch (c) {
691 case 'p':
692 *use_syspath = 1;
693 break;
694 default:
695 /* run 'typecmd' for other options */
696 return 0;
697 }
698 }
699 }
700 return sv_argc - argc;
701 }
702
703 int vforked = 0;
704 extern char *trap[];
705
706 /*
707 * Execute a simple command.
708 */
709
710 STATIC void
711 evalcommand(union node *cmd, int flgs, struct backcmd *backcmd)
712 {
713 struct stackmark smark;
714 union node *argp;
715 struct arglist arglist;
716 struct arglist varlist;
717 volatile int flags = flgs;
718 char ** volatile argv;
719 volatile int argc;
720 char **envp;
721 int varflag;
722 struct strlist *sp;
723 volatile int mode;
724 int pip[2];
725 struct cmdentry cmdentry;
726 struct job * volatile jp;
727 struct jmploc jmploc;
728 struct jmploc *volatile savehandler = NULL;
729 const char *volatile savecmdname;
730 volatile struct shparam saveparam;
731 struct localvar *volatile savelocalvars;
732 volatile int e;
733 char * volatile lastarg;
734 const char * volatile path = pathval();
735 volatile int temp_path;
736
737 vforked = 0;
738 /* First expand the arguments. */
739 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
740 setstackmark(&smark);
741 back_exitstatus = 0;
742
743 arglist.lastp = &arglist.list;
744 varflag = 1;
745 /* Expand arguments, ignoring the initial 'name=value' ones */
746 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
747 char *p = argp->narg.text;
748 if (varflag && is_name(*p)) {
749 do {
750 p++;
751 } while (is_in_name(*p));
752 if (*p == '=')
753 continue;
754 }
755 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
756 varflag = 0;
757 }
758 *arglist.lastp = NULL;
759
760 expredir(cmd->ncmd.redirect);
761
762 /* Now do the initial 'name=value' ones we skipped above */
763 varlist.lastp = &varlist.list;
764 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
765 char *p = argp->narg.text;
766 if (!is_name(*p))
767 break;
768 do
769 p++;
770 while (is_in_name(*p));
771 if (*p != '=')
772 break;
773 expandarg(argp, &varlist, EXP_VARTILDE);
774 }
775 *varlist.lastp = NULL;
776
777 argc = 0;
778 for (sp = arglist.list ; sp ; sp = sp->next)
779 argc++;
780 argv = stalloc(sizeof (char *) * (argc + 1));
781
782 for (sp = arglist.list ; sp ; sp = sp->next) {
783 TRACE(("evalcommand arg: %s\n", sp->text));
784 *argv++ = sp->text;
785 }
786 *argv = NULL;
787 lastarg = NULL;
788 if (iflag && funcnest == 0 && argc > 0)
789 lastarg = argv[-1];
790 argv -= argc;
791
792 /* Print the command if xflag is set. */
793 if (xflag) {
794 char sep = 0;
795 out2str(ps4val());
796 for (sp = varlist.list ; sp ; sp = sp->next) {
797 char *p;
798
799 if (sep != 0)
800 outc(sep, &errout);
801
802 /*
803 * The "var=" part should not be quoted, regardless
804 * of the value, or it would not represent an
805 * assignment, but rather a command
806 */
807 p = strchr(sp->text, '=');
808 if (p != NULL) {
809 *p = '\0'; /*XXX*/
810 out2shstr(sp->text);
811 out2c('=');
812 *p++ = '='; /*XXX*/
813 } else
814 p = sp->text;
815 out2shstr(p);
816 sep = ' ';
817 }
818 for (sp = arglist.list ; sp ; sp = sp->next) {
819 if (sep != 0)
820 outc(sep, &errout);
821 out2shstr(sp->text);
822 sep = ' ';
823 }
824 outc('\n', &errout);
825 flushout(&errout);
826 }
827
828 /* Now locate the command. */
829 if (argc == 0) {
830 cmdentry.cmdtype = CMDSPLBLTIN;
831 cmdentry.u.bltin = bltincmd;
832 } else {
833 static const char PATH[] = "PATH=";
834 int cmd_flags = DO_ERR;
835
836 /*
837 * Modify the command lookup path, if a PATH= assignment
838 * is present
839 */
840 for (sp = varlist.list; sp; sp = sp->next)
841 if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0)
842 path = sp->text + sizeof(PATH) - 1;
843
844 do {
845 int argsused, use_syspath;
846 find_command(argv[0], &cmdentry, cmd_flags, path);
847 if (cmdentry.cmdtype == CMDUNKNOWN) {
848 exitstatus = 127;
849 flushout(&errout);
850 goto out;
851 }
852
853 /* implement the 'command' builtin here */
854 if (cmdentry.cmdtype != CMDBUILTIN ||
855 cmdentry.u.bltin != bltincmd)
856 break;
857 cmd_flags |= DO_NOFUNC;
858 argsused = parse_command_args(argc, argv, &use_syspath);
859 if (argsused == 0) {
860 /* use 'type' builting to display info */
861 cmdentry.u.bltin = typecmd;
862 break;
863 }
864 argc -= argsused;
865 argv += argsused;
866 if (use_syspath)
867 path = syspath() + 5;
868 } while (argc != 0);
869 if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC)
870 /* posix mandates that 'command <splbltin>' act as if
871 <splbltin> was a normal builtin */
872 cmdentry.cmdtype = CMDBUILTIN;
873 }
874
875 /* Fork off a child process if necessary. */
876 if (cmd->ncmd.backgnd || (trap[0] && (flags & EV_EXIT) != 0)
877 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
878 || ((flags & EV_BACKCMD) != 0
879 && ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN)
880 || cmdentry.u.bltin == dotcmd
881 || cmdentry.u.bltin == evalcmd))) {
882 INTOFF;
883 jp = makejob(cmd, 1);
884 mode = cmd->ncmd.backgnd;
885 if (mode)
886 flags &= ~EV_MORE;
887 if (flags & EV_BACKCMD) {
888 mode = FORK_NOJOB;
889 if (sh_pipe(pip) < 0)
890 error("Pipe call failed");
891 }
892 #ifdef DO_SHAREDVFORK
893 /* It is essential that if DO_SHAREDVFORK is defined that the
894 * child's address space is actually shared with the parent as
895 * we rely on this.
896 */
897 if (usefork == 0 && cmdentry.cmdtype == CMDNORMAL) {
898 pid_t pid;
899 int serrno;
900
901 savelocalvars = localvars;
902 localvars = NULL;
903 vforked = 1;
904 switch (pid = vfork()) {
905 case -1:
906 serrno = errno;
907 TRACE(("Vfork failed, errno=%d\n", serrno));
908 INTON;
909 error("Cannot vfork (%s)", strerror(serrno));
910 break;
911 case 0:
912 /* Make sure that exceptions only unwind to
913 * after the vfork(2)
914 */
915 if (setjmp(jmploc.loc)) {
916 if (exception == EXSHELLPROC) {
917 /* We can't progress with the vfork,
918 * so, set vforked = 2 so the parent
919 * knows, and _exit();
920 */
921 vforked = 2;
922 _exit(0);
923 } else {
924 _exit(exerrno);
925 }
926 }
927 savehandler = handler;
928 handler = &jmploc;
929 listmklocal(varlist.list, VEXPORT | VNOFUNC);
930 forkchild(jp, cmd, mode, vforked);
931 break;
932 default:
933 handler = savehandler; /* restore from vfork(2) */
934 poplocalvars();
935 localvars = savelocalvars;
936 if (vforked == 2) {
937 vforked = 0;
938
939 (void)waitpid(pid, NULL, 0);
940 /* We need to progress in a normal fork fashion */
941 goto normal_fork;
942 }
943 vforked = 0;
944 forkparent(jp, cmd, mode, pid);
945 goto parent;
946 }
947 } else {
948 normal_fork:
949 #endif
950 if (forkshell(jp, cmd, mode) != 0)
951 goto parent; /* at end of routine */
952 FORCEINTON;
953 #ifdef DO_SHAREDVFORK
954 }
955 #endif
956 if (flags & EV_BACKCMD) {
957 if (!vforked) {
958 FORCEINTON;
959 }
960 close(pip[0]);
961 movefd(pip[1], 1);
962 }
963 flags |= EV_EXIT;
964 }
965
966 /* This is the child process if a fork occurred. */
967 /* Execute the command. */
968 switch (cmdentry.cmdtype) {
969 case CMDFUNCTION:
970 #ifdef DEBUG
971 trputs("Shell function: "); trargs(argv);
972 #endif
973 redirect(cmd->ncmd.redirect, flags & EV_MORE ? REDIR_PUSH : 0);
974 saveparam = shellparam;
975 shellparam.malloc = 0;
976 shellparam.reset = 1;
977 shellparam.nparam = argc - 1;
978 shellparam.p = argv + 1;
979 shellparam.optnext = NULL;
980 INTOFF;
981 savelocalvars = localvars;
982 localvars = NULL;
983 INTON;
984 if (setjmp(jmploc.loc)) {
985 if (exception == EXSHELLPROC) {
986 freeparam((volatile struct shparam *)
987 &saveparam);
988 } else {
989 freeparam(&shellparam);
990 shellparam = saveparam;
991 }
992 poplocalvars();
993 localvars = savelocalvars;
994 handler = savehandler;
995 longjmp(handler->loc, 1);
996 }
997 savehandler = handler;
998 handler = &jmploc;
999 listmklocal(varlist.list, VEXPORT);
1000 /* stop shell blowing its stack */
1001 if (++funcnest > 1000)
1002 error("too many nested function calls");
1003 evaltree(cmdentry.u.func, flags & EV_TESTED);
1004 funcnest--;
1005 INTOFF;
1006 poplocalvars();
1007 localvars = savelocalvars;
1008 freeparam(&shellparam);
1009 shellparam = saveparam;
1010 handler = savehandler;
1011 if (flags & EV_MORE)
1012 popredir();
1013 INTON;
1014 if (evalskip == SKIPFUNC) {
1015 evalskip = SKIPNONE;
1016 skipcount = 0;
1017 }
1018 if (flags & EV_EXIT)
1019 exitshell(exitstatus);
1020 break;
1021
1022 case CMDBUILTIN:
1023 case CMDSPLBLTIN:
1024 #ifdef DEBUG
1025 trputs("builtin command: "); trargs(argv);
1026 #endif
1027 mode = (cmdentry.u.bltin == execcmd) ? 0 : REDIR_PUSH;
1028 if (flags == EV_BACKCMD) {
1029 memout.nleft = 0;
1030 memout.nextc = memout.buf;
1031 memout.bufsize = 64;
1032 mode |= REDIR_BACKQ;
1033 }
1034 e = -1;
1035 savehandler = handler;
1036 savecmdname = commandname;
1037 handler = &jmploc;
1038 temp_path = 0;
1039 if (!setjmp(jmploc.loc)) {
1040 /* We need to ensure the command hash table isn't
1041 * corruped by temporary PATH assignments.
1042 * However we must ensure the 'local' command works!
1043 */
1044 if (path != pathval() && (cmdentry.u.bltin == hashcmd ||
1045 cmdentry.u.bltin == typecmd)) {
1046 savelocalvars = localvars;
1047 localvars = 0;
1048 temp_path = 1;
1049 mklocal(path - 5 /* PATH= */, 0);
1050 }
1051 redirect(cmd->ncmd.redirect, mode);
1052
1053 /* exec is a special builtin, but needs this list... */
1054 cmdenviron = varlist.list;
1055 /* we must check 'readonly' flag for all builtins */
1056 listsetvar(varlist.list,
1057 cmdentry.cmdtype == CMDSPLBLTIN ? 0 : VNOSET);
1058 commandname = argv[0];
1059 /* initialize nextopt */
1060 argptr = argv + 1;
1061 optptr = NULL;
1062 /* and getopt */
1063 optreset = 1;
1064 optind = 1;
1065 builtin_flags = flags;
1066 exitstatus = cmdentry.u.bltin(argc, argv);
1067 } else {
1068 e = exception;
1069 exitstatus = e == EXINT ? SIGINT + 128 :
1070 e == EXEXEC ? exerrno : 2;
1071 }
1072 handler = savehandler;
1073 flushall();
1074 out1 = &output;
1075 out2 = &errout;
1076 freestdout();
1077 if (temp_path) {
1078 poplocalvars();
1079 localvars = savelocalvars;
1080 }
1081 cmdenviron = NULL;
1082 if (e != EXSHELLPROC) {
1083 commandname = savecmdname;
1084 if (flags & EV_EXIT)
1085 exitshell(exitstatus);
1086 }
1087 if (e != -1) {
1088 if ((e != EXERROR && e != EXEXEC)
1089 || cmdentry.cmdtype == CMDSPLBLTIN)
1090 exraise(e);
1091 FORCEINTON;
1092 }
1093 if (cmdentry.u.bltin != execcmd)
1094 popredir();
1095 if (flags == EV_BACKCMD) {
1096 backcmd->buf = memout.buf;
1097 backcmd->nleft = memout.nextc - memout.buf;
1098 memout.buf = NULL;
1099 }
1100 break;
1101
1102 default:
1103 #ifdef DEBUG
1104 trputs("normal command: "); trargs(argv);
1105 #endif
1106 redirect(cmd->ncmd.redirect,
1107 (vforked ? REDIR_VFORK : 0) | REDIR_KEEP);
1108 if (!vforked)
1109 for (sp = varlist.list ; sp ; sp = sp->next)
1110 setvareq(sp->text, VEXPORT|VSTACK);
1111 envp = environment();
1112 shellexec(argv, envp, path, cmdentry.u.index, vforked);
1113 break;
1114 }
1115 goto out;
1116
1117 parent: /* parent process gets here (if we forked) */
1118 exitstatus = 0; /* if not altered just below */
1119 if (mode == FORK_FG) { /* argument to fork */
1120 exitstatus = waitforjob(jp);
1121 } else if (mode == FORK_NOJOB) {
1122 backcmd->fd = pip[0];
1123 close(pip[1]);
1124 backcmd->jp = jp;
1125 }
1126 FORCEINTON;
1127
1128 out:
1129 if (lastarg)
1130 /* dsl: I think this is intended to be used to support
1131 * '_' in 'vi' command mode during line editing...
1132 * However I implemented that within libedit itself.
1133 */
1134 setvar("_", lastarg, 0);
1135 popstackmark(&smark);
1136 }
1137
1138
1139 /*
1140 * Search for a command. This is called before we fork so that the
1141 * location of the command will be available in the parent as well as
1142 * the child. The check for "goodname" is an overly conservative
1143 * check that the name will not be subject to expansion.
1144 */
1145
1146 STATIC void
1147 prehash(union node *n)
1148 {
1149 struct cmdentry entry;
1150
1151 if (n && n->type == NCMD && n->ncmd.args)
1152 if (goodname(n->ncmd.args->narg.text))
1153 find_command(n->ncmd.args->narg.text, &entry, 0,
1154 pathval());
1155 }
1156
1157 int
1158 in_function(void)
1159 {
1160 return funcnest;
1161 }
1162
1163 enum skipstate
1164 current_skipstate(void)
1165 {
1166 return evalskip;
1167 }
1168
1169 void
1170 stop_skipping(void)
1171 {
1172 evalskip = SKIPNONE;
1173 skipcount = 0;
1174 }
1175
1176 /*
1177 * Builtin commands. Builtin commands whose functions are closely
1178 * tied to evaluation are implemented here.
1179 */
1180
1181 /*
1182 * No command given.
1183 */
1184
1185 int
1186 bltincmd(int argc, char **argv)
1187 {
1188 /*
1189 * Preserve exitstatus of a previous possible redirection
1190 * as POSIX mandates
1191 */
1192 return back_exitstatus;
1193 }
1194
1195
1196 /*
1197 * Handle break and continue commands. Break, continue, and return are
1198 * all handled by setting the evalskip flag. The evaluation routines
1199 * above all check this flag, and if it is set they start skipping
1200 * commands rather than executing them. The variable skipcount is
1201 * the number of loops to break/continue, or the number of function
1202 * levels to return. (The latter is always 1.) It should probably
1203 * be an error to break out of more loops than exist, but it isn't
1204 * in the standard shell so we don't make it one here.
1205 */
1206
1207 int
1208 breakcmd(int argc, char **argv)
1209 {
1210 int n = argc > 1 ? number(argv[1]) : 1;
1211
1212 if (n > loopnest)
1213 n = loopnest;
1214 if (n > 0) {
1215 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
1216 skipcount = n;
1217 }
1218 return 0;
1219 }
1220
1221 int
1222 dotcmd(int argc, char **argv)
1223 {
1224 exitstatus = 0;
1225
1226 if (argc >= 2) { /* That's what SVR2 does */
1227 char *fullname;
1228 /*
1229 * dot_funcnest needs to be 0 when not in a dotcmd, so it
1230 * cannot be restored with (funcnest + 1).
1231 */
1232 int dot_funcnest_old;
1233 struct stackmark smark;
1234
1235 setstackmark(&smark);
1236 fullname = find_dot_file(argv[1]);
1237 setinputfile(fullname, 1);
1238 commandname = fullname;
1239 dot_funcnest_old = dot_funcnest;
1240 dot_funcnest = funcnest + 1;
1241 cmdloop(0);
1242 dot_funcnest = dot_funcnest_old;
1243 popfile();
1244 popstackmark(&smark);
1245 }
1246 return exitstatus;
1247 }
1248
1249 /*
1250 * Take commands from a file. To be compatible we should do a path
1251 * search for the file, which is necessary to find sub-commands.
1252 */
1253
1254 STATIC char *
1255 find_dot_file(char *basename)
1256 {
1257 char *fullname;
1258 const char *path = pathval();
1259 struct stat statb;
1260
1261 /* don't try this for absolute or relative paths */
1262 if (strchr(basename, '/')) {
1263 if (stat(basename, &statb) == 0) {
1264 if (S_ISREG(statb.st_mode))
1265 return basename;
1266 error("%s: not a regular file", basename);
1267 /* NOTREACHED */
1268 }
1269 } else while ((fullname = padvance(&path, basename)) != NULL) {
1270 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
1271 /*
1272 * Don't bother freeing here, since it will
1273 * be freed by the caller.
1274 */
1275 return fullname;
1276 }
1277 stunalloc(fullname);
1278 }
1279
1280 /* not found in the PATH */
1281 error("%s: not found", basename);
1282 /* NOTREACHED */
1283 }
1284
1285
1286
1287 /*
1288 * The return command.
1289 *
1290 * Quoth the POSIX standard:
1291 * The return utility shall cause the shell to stop executing the current
1292 * function or dot script. If the shell is not currently executing
1293 * a function or dot script, the results are unspecified.
1294 *
1295 * As for the unspecified part, there seems to be no de-facto standard: bash
1296 * ignores the return with a warning, zsh ignores the return in interactive
1297 * mode but seems to liken it to exit in a script. (checked May 2014)
1298 *
1299 * We choose to silently ignore the return. Older versions of this shell
1300 * set evalskip to SKIPFILE causing the shell to (indirectly) exit. This
1301 * had at least the problem of circumventing the check for stopped jobs,
1302 * which would occur for exit or ^D.
1303 */
1304
1305 int
1306 returncmd(int argc, char **argv)
1307 {
1308 int ret = argc > 1 ? number(argv[1]) : exitstatus;
1309
1310 if ((dot_funcnest == 0 && funcnest)
1311 || (dot_funcnest > 0 && funcnest - (dot_funcnest - 1) > 0)) {
1312 evalskip = SKIPFUNC;
1313 skipcount = 1;
1314 } else if (dot_funcnest > 0) {
1315 evalskip = SKIPFILE;
1316 skipcount = 1;
1317 } else {
1318 /* XXX: should a warning be issued? */
1319 ret = 0;
1320 }
1321
1322 return ret;
1323 }
1324
1325
1326 int
1327 falsecmd(int argc, char **argv)
1328 {
1329 return 1;
1330 }
1331
1332
1333 int
1334 truecmd(int argc, char **argv)
1335 {
1336 return 0;
1337 }
1338
1339
1340 int
1341 execcmd(int argc, char **argv)
1342 {
1343 if (argc > 1) {
1344 struct strlist *sp;
1345
1346 iflag = 0; /* exit on error */
1347 mflag = 0;
1348 optschanged();
1349 for (sp = cmdenviron; sp; sp = sp->next)
1350 setvareq(sp->text, VEXPORT|VSTACK);
1351 shellexec(argv + 1, environment(), pathval(), 0, 0);
1352 }
1353 return 0;
1354 }
1355
1356 static int
1357 conv_time(clock_t ticks, char *seconds, size_t l)
1358 {
1359 static clock_t tpm = 0;
1360 clock_t mins;
1361 int i;
1362
1363 if (!tpm)
1364 tpm = sysconf(_SC_CLK_TCK) * 60;
1365
1366 mins = ticks / tpm;
1367 snprintf(seconds, l, "%.4f", (ticks - mins * tpm) * 60.0 / tpm );
1368
1369 if (seconds[0] == '6' && seconds[1] == '0') {
1370 /* 59.99995 got rounded up... */
1371 mins++;
1372 strlcpy(seconds, "0.0", l);
1373 return mins;
1374 }
1375
1376 /* suppress trailing zeros */
1377 i = strlen(seconds) - 1;
1378 for (; seconds[i] == '0' && seconds[i - 1] != '.'; i--)
1379 seconds[i] = 0;
1380 return mins;
1381 }
1382
1383 int
1384 timescmd(int argc, char **argv)
1385 {
1386 struct tms tms;
1387 int u, s, cu, cs;
1388 char us[8], ss[8], cus[8], css[8];
1389
1390 nextopt("");
1391
1392 times(&tms);
1393
1394 u = conv_time(tms.tms_utime, us, sizeof(us));
1395 s = conv_time(tms.tms_stime, ss, sizeof(ss));
1396 cu = conv_time(tms.tms_cutime, cus, sizeof(cus));
1397 cs = conv_time(tms.tms_cstime, css, sizeof(css));
1398
1399 outfmt(out1, "%dm%ss %dm%ss\n%dm%ss %dm%ss\n",
1400 u, us, s, ss, cu, cus, cs, css);
1401
1402 return 0;
1403 }
1404