3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
35 static char sccsid
[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95";
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD: head/bin/sh/eval.c 340284 2018-11-09 14:58:24Z jilles $");
45 #include <sys/resource.h>
72 #include "myhistedit.h"
76 int evalskip
; /* set if we are skipping commands */
77 int skipcount
; /* number of levels to skip */
78 static int loopnest
; /* current loop nesting level */
79 int funcnest
; /* depth of function calls */
80 static int builtin_flags
; /* evalcommand flags for builtins */
84 struct arglist
*cmdenviron
;
85 int exitstatus
; /* exit status of last command */
86 int oexitstatus
; /* saved exit status */
89 static void evalloop(union node
*, int);
90 static void evalfor(union node
*, int);
91 static union node
*evalcase(union node
*);
92 static void evalsubshell(union node
*, int);
93 static void evalredir(union node
*, int);
94 static void exphere(union node
*, struct arglist
*);
95 static void expredir(union node
*);
96 static void evalpipe(union node
*);
97 static int is_valid_fast_cmdsubst(union node
*n
);
98 static void evalcommand(union node
*, int, struct backcmd
*);
99 static void prehash(union node
*);
103 * Called to reset things after an exception.
119 evalcmd(int argc
, char **argv
)
128 STARTSTACKSTR(concat
);
132 if ((p
= *ap
++) == NULL
)
136 STPUTC('\0', concat
);
137 p
= grabstackstr(concat
);
139 evalstring(p
, builtin_flags
);
147 * Execute a command or commands contained in a string.
151 evalstring(const char *s
, int flags
)
154 struct stackmark smark
;
158 flags_exit
= flags
& EV_EXIT
;
161 setstackmark(&smark
);
162 setinputstring(s
, 1);
163 while ((n
= parsecmd(0)) != NEOF
) {
164 if (n
!= NULL
&& !nflag
) {
165 if (flags_exit
&& preadateof())
166 evaltree(n
, flags
| EV_EXIT
);
173 popstackmark(&smark
);
174 setstackmark(&smark
);
177 popstackmark(&smark
);
186 * Evaluate a parse tree. The value is left in the global variable
191 evaltree(union node
*n
, int flags
)
195 struct stackmark smark
;
197 setstackmark(&smark
);
200 TRACE(("evaltree(NULL) called\n"));
207 displayhist
= 1; /* show history substitutions done with fc */
209 TRACE(("evaltree(%p: %d) called\n", (void *)n
, n
->type
));
212 evaltree(n
->nbinary
.ch1
, flags
& ~EV_EXIT
);
215 next
= n
->nbinary
.ch2
;
218 evaltree(n
->nbinary
.ch1
, EV_TESTED
);
219 if (evalskip
|| exitstatus
!= 0) {
222 next
= n
->nbinary
.ch2
;
225 evaltree(n
->nbinary
.ch1
, EV_TESTED
);
226 if (evalskip
|| exitstatus
== 0)
228 next
= n
->nbinary
.ch2
;
234 evalsubshell(n
, flags
);
235 do_etest
= !(flags
& EV_TESTED
);
238 evalsubshell(n
, flags
);
241 evaltree(n
->nif
.test
, EV_TESTED
);
245 next
= n
->nif
.ifpart
;
246 else if (n
->nif
.elsepart
)
247 next
= n
->nif
.elsepart
;
254 evalloop(n
, flags
& ~EV_EXIT
);
257 evalfor(n
, flags
& ~EV_EXIT
);
263 next
= n
->nclist
.body
;
266 if (n
->nclist
.body
) {
267 evaltree(n
->nclist
.body
, flags
& ~EV_EXIT
);
271 next
= n
->nclist
.next
;
274 defun(n
->narg
.text
, n
->narg
.next
);
278 evaltree(n
->nnot
.com
, EV_TESTED
);
281 exitstatus
= !exitstatus
;
286 do_etest
= !(flags
& EV_TESTED
);
289 evalcommand(n
, flags
, (struct backcmd
*)NULL
);
290 do_etest
= !(flags
& EV_TESTED
);
293 out1fmt("Node type = %d\n", n
->type
);
298 popstackmark(&smark
);
299 setstackmark(&smark
);
302 popstackmark(&smark
);
305 if (eflag
&& exitstatus
!= 0 && do_etest
)
306 exitshell(exitstatus
);
313 evalloop(union node
*n
, int flags
)
321 evaltree(n
->nbinary
.ch1
, EV_TESTED
);
323 if (evalskip
== SKIPCONT
&& --skipcount
<= 0) {
327 if (evalskip
== SKIPBREAK
&& --skipcount
<= 0)
329 if (evalskip
== SKIPRETURN
)
333 if (n
->type
== NWHILE
) {
340 evaltree(n
->nbinary
.ch2
, flags
);
350 evalfor(union node
*n
, int flags
)
352 struct arglist arglist
;
357 emptyarglist(&arglist
);
358 for (argp
= n
->nfor
.args
; argp
; argp
= argp
->narg
.next
) {
359 oexitstatus
= exitstatus
;
360 expandarg(argp
, &arglist
, EXP_FULL
| EXP_TILDE
);
365 for (i
= 0; i
< arglist
.count
; i
++) {
366 setvar(n
->nfor
.var
, arglist
.args
[i
], 0);
367 evaltree(n
->nfor
.body
, flags
);
370 if (evalskip
== SKIPCONT
&& --skipcount
<= 0) {
374 if (evalskip
== SKIPBREAK
&& --skipcount
<= 0)
385 * Evaluate a case statement, returning the selected tree.
387 * The exit status needs care to get right.
391 evalcase(union node
*n
)
395 struct arglist arglist
;
397 emptyarglist(&arglist
);
398 oexitstatus
= exitstatus
;
399 expandarg(n
->ncase
.expr
, &arglist
, EXP_TILDE
);
400 for (cp
= n
->ncase
.cases
; cp
; cp
= cp
->nclist
.next
) {
401 for (patp
= cp
->nclist
.pattern
; patp
; patp
= patp
->narg
.next
) {
402 if (casematch(patp
, arglist
.args
[0])) {
403 while (cp
->nclist
.next
&&
404 cp
->type
== NCLISTFALLTHRU
&&
405 cp
->nclist
.body
== NULL
)
406 cp
= cp
->nclist
.next
;
407 if (cp
->nclist
.next
&&
408 cp
->type
== NCLISTFALLTHRU
)
410 if (cp
->nclist
.body
== NULL
)
412 return (cp
->nclist
.body
);
423 * Kick off a subshell to evaluate a tree.
427 evalsubshell(union node
*n
, int flags
)
430 int backgnd
= (n
->type
== NBACKGND
);
432 oexitstatus
= exitstatus
;
433 expredir(n
->nredir
.redirect
);
434 if ((!backgnd
&& flags
& EV_EXIT
&& !have_traps()) ||
435 forkshell(jp
= makejob(n
, 1), n
, backgnd
) == 0) {
438 redirect(n
->nredir
.redirect
, 0);
439 evaltree(n
->nredir
.n
, flags
| EV_EXIT
); /* never returns */
440 } else if (! backgnd
) {
442 exitstatus
= waitforjob(jp
, (int *)NULL
);
450 * Evaluate a redirected compound command.
454 evalredir(union node
*n
, int flags
)
456 struct jmploc jmploc
;
457 struct jmploc
*savehandler
;
458 volatile int in_redirect
= 1;
460 oexitstatus
= exitstatus
;
461 expredir(n
->nredir
.redirect
);
462 savehandler
= handler
;
463 if (setjmp(jmploc
.loc
)) {
466 handler
= savehandler
;
469 if (e
== EXERROR
&& in_redirect
) {
473 longjmp(handler
->loc
, 1);
477 redirect(n
->nredir
.redirect
, REDIR_PUSH
);
480 evaltree(n
->nredir
.n
, flags
);
483 handler
= savehandler
;
490 exphere(union node
*redir
, struct arglist
*fn
)
492 struct jmploc jmploc
;
493 struct jmploc
*savehandler
;
494 struct localvar
*savelocalvars
;
495 int need_longjmp
= 0;
496 unsigned char saveoptreset
;
498 redir
->nhere
.expdoc
= "";
499 savelocalvars
= localvars
;
501 saveoptreset
= shellparam
.reset
;
503 savehandler
= handler
;
504 if (setjmp(jmploc
.loc
))
505 need_longjmp
= exception
!= EXERROR
;
508 expandarg(redir
->nhere
.doc
, fn
, 0);
509 redir
->nhere
.expdoc
= fn
->args
[0];
512 handler
= savehandler
;
515 localvars
= savelocalvars
;
516 shellparam
.reset
= saveoptreset
;
518 longjmp(handler
->loc
, 1);
524 * Compute the names of the files in a redirection list.
528 expredir(union node
*n
)
532 for (redir
= n
; redir
; redir
= redir
->nfile
.next
) {
535 switch (redir
->type
) {
541 expandarg(redir
->nfile
.fname
, &fn
, EXP_TILDE
);
542 redir
->nfile
.expfname
= fn
.args
[0];
546 if (redir
->ndup
.vname
) {
547 expandarg(redir
->ndup
.vname
, &fn
, EXP_TILDE
);
548 fixredir(redir
, fn
.args
[0], 1);
561 * Evaluate a pipeline. All the processes in the pipeline are children
562 * of the process creating the pipeline. (This differs from some versions
563 * of the shell, which make the last process in a pipeline the parent
568 evalpipe(union node
*n
)
576 TRACE(("evalpipe(%p) called\n", (void *)n
));
578 for (lp
= n
->npipe
.cmdlist
; lp
; lp
= lp
->next
)
581 jp
= makejob(n
, pipelen
);
583 for (lp
= n
->npipe
.cmdlist
; lp
; lp
= lp
->next
) {
590 error("Pipe call failed: %s", strerror(errno
));
593 if (forkshell(jp
, lp
->n
, n
->npipe
.backgnd
) == 0) {
600 if (!(prevfd
>= 0 && pip
[0] == 0))
607 evaltree(lp
->n
, EV_EXIT
);
616 if (n
->npipe
.backgnd
== 0) {
618 exitstatus
= waitforjob(jp
, (int *)NULL
);
619 TRACE(("evalpipe: job done exit status %d\n", exitstatus
));
628 is_valid_fast_cmdsubst(union node
*n
)
631 return (n
->type
== NCMD
);
635 * Execute a command inside back quotes. If it's a builtin command, we
636 * want to save its output in a block obtained from malloc. Otherwise
637 * we fork off a subprocess and get the output of the command via a pipe.
638 * Should be called with interrupts off.
642 evalbackcmd(union node
*n
, struct backcmd
*result
)
646 struct stackmark smark
;
647 struct jmploc jmploc
;
648 struct jmploc
*savehandler
;
649 struct localvar
*savelocalvars
;
650 unsigned char saveoptreset
;
660 setstackmark(&smark
);
661 exitstatus
= oexitstatus
;
662 if (is_valid_fast_cmdsubst(n
)) {
663 savelocalvars
= localvars
;
665 saveoptreset
= shellparam
.reset
;
667 savehandler
= handler
;
668 if (setjmp(jmploc
.loc
)) {
669 if (exception
== EXERROR
)
671 else if (exception
!= 0) {
672 handler
= savehandler
;
675 localvars
= savelocalvars
;
676 shellparam
.reset
= saveoptreset
;
677 longjmp(handler
->loc
, 1);
681 evalcommand(n
, EV_BACKCMD
, result
);
683 handler
= savehandler
;
686 localvars
= savelocalvars
;
687 shellparam
.reset
= saveoptreset
;
690 error("Pipe call failed: %s", strerror(errno
));
692 if (forkshell(jp
, n
, FORK_NOJOB
) == 0) {
699 evaltree(n
, EV_EXIT
);
705 popstackmark(&smark
);
706 TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n",
707 result
->fd
, result
->buf
, result
->nleft
, result
->jp
));
711 mustexpandto(const char *argtext
, const char *mask
)
714 if (*argtext
== CTLQUOTEMARK
|| *argtext
== CTLQUOTEEND
) {
718 if (*argtext
== CTLESC
)
720 else if (BASESYNTAX
[(int)*argtext
] == CCTL
)
722 if (*argtext
!= *mask
)
724 if (*argtext
== '\0')
732 isdeclarationcmd(struct narg
*arg
)
734 int have_command
= 0;
738 while (mustexpandto(arg
->text
, "command")) {
740 arg
= &arg
->next
->narg
;
744 * To also allow "command -p" and "command --" as part of
745 * a declaration command, add code here.
746 * We do not do this, as ksh does not do it either and it
747 * is not required by POSIX.
750 return (mustexpandto(arg
->text
, "export") ||
751 mustexpandto(arg
->text
, "readonly") ||
752 (mustexpandto(arg
->text
, "local") &&
753 (have_command
|| !isfunc("local"))));
757 xtracecommand(struct arglist
*varlist
, int argc
, char **argv
)
760 const char *text
, *p
, *ps4
;
763 ps4
= expandstr(ps4val());
764 out2str(ps4
!= NULL
? ps4
: ps4val());
765 for (i
= 0; i
< varlist
->count
; i
++) {
766 text
= varlist
->args
[i
];
769 p
= strchr(text
, '=');
772 outbin(text
, p
- text
, out2
);
778 for (i
= 0; i
< argc
; i
++) {
790 * Check if a builtin can safely be executed in the same process,
791 * even though it should be in a subshell (command substitution).
792 * Note that jobid, jobs, times and trap can show information not
793 * available in a child process; this is deliberate.
794 * The arguments should already have been expanded.
797 safe_builtin(int idx
, int argc
, char **argv
)
799 /* Generated from builtins.def. */
800 if (safe_builtin_always(idx
))
802 if (idx
== EXPORTCMD
|| idx
== TRAPCMD
|| idx
== ULIMITCMD
||
804 return (argc
<= 1 || (argc
== 2 && argv
[1][0] == '-'));
806 return (argc
<= 1 || (argc
== 2 && (argv
[1][0] == '-' ||
807 argv
[1][0] == '+') && argv
[1][1] == 'o' &&
808 argv
[1][2] == '\0'));
813 * Execute a simple command.
814 * Note: This may or may not return if (flags & EV_EXIT).
818 evalcommand(union node
*cmd
, int flags
, struct backcmd
*backcmd
)
821 struct arglist arglist
;
822 struct arglist varlist
;
829 struct cmdentry cmdentry
;
831 struct jmploc jmploc
;
832 struct jmploc
*savehandler
;
834 struct shparam saveparam
;
835 struct localvar
*savelocalvars
;
836 struct parsefile
*savetopfile
;
840 int do_clearcmdentry
;
841 const char *path
= pathval();
844 /* First expand the arguments. */
845 TRACE(("evalcommand(%p, %d) called\n", (void *)cmd
, flags
));
846 emptyarglist(&arglist
);
847 emptyarglist(&varlist
);
850 do_clearcmdentry
= 0;
851 oexitstatus
= exitstatus
;
853 /* Add one slot at the beginning for tryexec(). */
854 appendarglist(&arglist
, nullstr
);
855 for (argp
= cmd
->ncmd
.args
; argp
; argp
= argp
->narg
.next
) {
856 if (varflag
&& isassignment(argp
->narg
.text
)) {
857 expandarg(argp
, varflag
== 1 ? &varlist
: &arglist
,
860 } else if (varflag
== 1)
861 varflag
= isdeclarationcmd(&argp
->narg
) ? 2 : 0;
862 expandarg(argp
, &arglist
, EXP_FULL
| EXP_TILDE
);
864 appendarglist(&arglist
, nullstr
);
865 expredir(cmd
->ncmd
.redirect
);
866 argc
= arglist
.count
- 2;
867 argv
= &arglist
.args
[1];
871 if (iflag
&& funcnest
== 0 && argc
> 0)
872 lastarg
= argv
[argc
- 1];
874 /* Print the command if xflag is set. */
876 xtracecommand(&varlist
, argc
, argv
);
878 /* Now locate the command. */
880 /* Variable assignment(s) without command */
881 cmdentry
.cmdtype
= CMDBUILTIN
;
882 cmdentry
.u
.index
= BLTINCMD
;
883 cmdentry
.special
= 0;
885 static const char PATH
[] = "PATH=";
886 int cmd_flags
= 0, bltinonly
= 0;
889 * Modify the command lookup path, if a PATH= assignment
892 for (i
= 0; i
< varlist
.count
; i
++)
893 if (strncmp(varlist
.args
[i
], PATH
, sizeof(PATH
) - 1) == 0) {
894 path
= varlist
.args
[i
] + sizeof(PATH
) - 1;
896 * On `PATH=... command`, we need to make
897 * sure that the command isn't using the
898 * non-updated hash table of the outer PATH
899 * setting and we need to make sure that
900 * the hash table isn't filled with items
901 * from the temporary setting.
903 * It would be better to forbit using and
904 * updating the table while this command
905 * runs, by the command finding mechanism
906 * is heavily integrated with hash handling,
907 * so we just delete the hash before and after
908 * the command runs. Partly deleting like
909 * changepatch() does doesn't seem worth the
910 * bookinging effort, since most such runs add
911 * directories in front of the new PATH.
914 do_clearcmdentry
= 1;
919 cmdentry
.u
.index
= find_builtin(*argv
, &cmdentry
.special
);
920 if (cmdentry
.u
.index
< 0) {
921 cmdentry
.u
.index
= BLTINCMD
;
927 find_command(argv
[0], &cmdentry
, cmd_flags
, path
);
928 /* implement the bltin and command builtins here */
929 if (cmdentry
.cmdtype
!= CMDBUILTIN
)
931 if (cmdentry
.u
.index
== BLTINCMD
) {
937 } else if (cmdentry
.u
.index
== COMMANDCMD
) {
940 if (!strcmp(argv
[1], "-p")) {
943 if (argv
[2][0] == '-') {
944 if (strcmp(argv
[2], "--"))
954 path
= _PATH_STDPATH
;
956 do_clearcmdentry
= 1;
957 } else if (!strcmp(argv
[1], "--")) {
962 } else if (argv
[1][0] == '-')
968 cmd_flags
|= DO_NOFUNC
;
974 * Special builtins lose their special properties when
975 * called via 'command'.
977 if (cmd_flags
& DO_NOFUNC
)
978 cmdentry
.special
= 0;
981 /* Fork off a child process if necessary. */
982 if (((cmdentry
.cmdtype
== CMDNORMAL
|| cmdentry
.cmdtype
== CMDUNKNOWN
)
983 && ((flags
& EV_EXIT
) == 0 || have_traps()))
984 || ((flags
& EV_BACKCMD
) != 0
985 && (cmdentry
.cmdtype
!= CMDBUILTIN
||
986 !safe_builtin(cmdentry
.u
.index
, argc
, argv
)))) {
987 jp
= makejob(cmd
, 1);
989 if (flags
& EV_BACKCMD
) {
992 error("Pipe call failed: %s", strerror(errno
));
994 if (cmdentry
.cmdtype
== CMDNORMAL
&&
995 cmd
->ncmd
.redirect
== NULL
&&
996 varlist
.count
== 0 &&
997 (mode
== FORK_FG
|| mode
== FORK_NOJOB
) &&
998 !disvforkset() && !iflag
&& !mflag
) {
999 vforkexecshell(jp
, argv
, environment(), path
,
1000 cmdentry
.u
.index
, flags
& EV_BACKCMD
? pip
: NULL
);
1003 if (forkshell(jp
, cmd
, mode
) != 0)
1004 goto parent
; /* at end of routine */
1005 if (flags
& EV_BACKCMD
) {
1012 flags
&= ~EV_BACKCMD
;
1017 /* This is the child process if a fork occurred. */
1018 /* Execute the command. */
1019 if (cmdentry
.cmdtype
== CMDFUNCTION
) {
1021 trputs("Shell function: "); trargs(argv
);
1023 saveparam
= shellparam
;
1024 shellparam
.malloc
= 0;
1025 shellparam
.reset
= 1;
1026 shellparam
.nparam
= argc
- 1;
1027 shellparam
.p
= argv
+ 1;
1028 shellparam
.optp
= NULL
;
1029 shellparam
.optnext
= NULL
;
1031 savelocalvars
= localvars
;
1033 reffunc(cmdentry
.u
.func
);
1034 savehandler
= handler
;
1035 if (setjmp(jmploc
.loc
)) {
1037 unreffunc(cmdentry
.u
.func
);
1039 localvars
= savelocalvars
;
1040 freeparam(&shellparam
);
1041 shellparam
= saveparam
;
1043 handler
= savehandler
;
1044 longjmp(handler
->loc
, 1);
1048 redirect(cmd
->ncmd
.redirect
, REDIR_PUSH
);
1050 for (i
= 0; i
< varlist
.count
; i
++)
1051 mklocal(varlist
.args
[i
]);
1052 exitstatus
= oexitstatus
;
1053 evaltree(getfuncnode(cmdentry
.u
.func
),
1054 flags
& (EV_TESTED
| EV_EXIT
));
1056 unreffunc(cmdentry
.u
.func
);
1058 localvars
= savelocalvars
;
1059 freeparam(&shellparam
);
1060 shellparam
= saveparam
;
1061 handler
= savehandler
;
1065 if (evalskip
== SKIPRETURN
) {
1070 exitshell(exitstatus
);
1071 } else if (cmdentry
.cmdtype
== CMDBUILTIN
) {
1073 trputs("builtin command: "); trargs(argv
);
1075 mode
= (cmdentry
.u
.index
== EXECCMD
)? 0 : REDIR_PUSH
;
1076 if (flags
== EV_BACKCMD
) {
1077 memout
.nextc
= memout
.buf
;
1078 mode
|= REDIR_BACKQ
;
1080 savecmdname
= commandname
;
1081 savetopfile
= getcurrentfile();
1082 cmdenviron
= &varlist
;
1084 savehandler
= handler
;
1085 if (setjmp(jmploc
.loc
)) {
1088 exitstatus
= SIGINT
+128;
1092 redirect(cmd
->ncmd
.redirect
, mode
);
1093 outclearerror(out1
);
1095 * If there is no command word, redirection errors should
1096 * not be fatal but assignment errors should.
1099 cmdentry
.special
= 1;
1100 listsetvar(cmdenviron
, cmdentry
.special
? 0 : VNOSET
);
1103 commandname
= argv
[0];
1105 nextopt_optptr
= NULL
; /* initialize nextopt */
1106 builtin_flags
= flags
;
1107 exitstatus
= (*builtinfunc
[cmdentry
.u
.index
])(argc
, argv
);
1109 if (outiserror(out1
)) {
1110 warning("write error on stdout");
1111 if (exitstatus
== 0 || exitstatus
== 1)
1121 handler
= savehandler
;
1122 commandname
= savecmdname
;
1124 exitshell(exitstatus
);
1125 if (flags
== EV_BACKCMD
) {
1126 backcmd
->buf
= memout
.buf
;
1127 backcmd
->nleft
= memout
.buf
!= NULL
?
1128 memout
.nextc
- memout
.buf
: 0;
1130 memout
.nextc
= NULL
;
1131 memout
.bufend
= NULL
;
1132 memout
.bufsize
= 64;
1134 if (cmdentry
.u
.index
!= EXECCMD
)
1137 if (e
!= EXERROR
|| cmdentry
.special
)
1139 popfilesupto(savetopfile
);
1140 if (flags
!= EV_BACKCMD
)
1145 trputs("normal command: "); trargs(argv
);
1147 redirect(cmd
->ncmd
.redirect
, 0);
1148 for (i
= 0; i
< varlist
.count
; i
++)
1149 setvareq(varlist
.args
[i
], VEXPORT
|VSTACK
);
1150 envp
= environment();
1151 shellexec(argv
, envp
, path
, cmdentry
.u
.index
);
1156 parent
: /* parent process gets here (if we forked) */
1157 if (mode
== FORK_FG
) { /* argument to fork */
1159 exitstatus
= waitforjob(jp
, &signaled
);
1161 if (iflag
&& loopnest
> 0 && signaled
) {
1162 evalskip
= SKIPBREAK
;
1163 skipcount
= loopnest
;
1165 } else if (mode
== FORK_NOJOB
) {
1166 backcmd
->fd
= pip
[0];
1173 setvar("_", lastarg
, 0);
1174 if (do_clearcmdentry
)
1181 * Search for a command. This is called before we fork so that the
1182 * location of the command will be available in the parent as well as
1183 * the child. The check for "goodname" is an overly conservative
1184 * check that the name will not be subject to expansion.
1188 prehash(union node
*n
)
1190 struct cmdentry entry
;
1192 if (n
&& n
->type
== NCMD
&& n
->ncmd
.args
)
1193 if (goodname(n
->ncmd
.args
->narg
.text
))
1194 find_command(n
->ncmd
.args
->narg
.text
, &entry
, 0,
1201 * Builtin commands. Builtin commands whose functions are closely
1202 * tied to evaluation are implemented here.
1206 * No command given, a bltin command with no arguments, or a bltin command
1207 * with an invalid name.
1211 bltincmd(int argc
, char **argv
)
1214 out2fmt_flush("%s: not found\n", argv
[1]);
1218 * Preserve exitstatus of a previous possible command substitution
1226 * Handle break and continue commands. Break, continue, and return are
1227 * all handled by setting the evalskip flag. The evaluation routines
1228 * above all check this flag, and if it is set they start skipping
1229 * commands rather than executing them. The variable skipcount is
1230 * the number of loops to break/continue, or the number of function
1231 * levels to return. (The latter is always 1.) It should probably
1232 * be an error to break out of more loops than exist, but it isn't
1233 * in the standard shell so we don't make it one here.
1237 breakcmd(int argc
, char **argv
)
1243 /* Allow arbitrarily large numbers. */
1244 n
= strtol(argv
[1], &end
, 10);
1245 if (!is_digit(argv
[1][0]) || *end
!= '\0')
1246 error("Illegal number: %s", argv
[1]);
1252 evalskip
= (**argv
== 'c')? SKIPCONT
: SKIPBREAK
;
1259 * The `command' command.
1262 commandcmd(int argc __unused
, char **argv __unused
)
1268 path
= bltinlookup("PATH", 1);
1270 while ((ch
= nextopt("pvV")) != '\0') {
1273 path
= _PATH_STDPATH
;
1276 cmd
= TYPECMD_SMALLV
;
1285 if (*argptr
== NULL
|| argptr
[1] != NULL
)
1286 error("wrong number of arguments");
1287 return typecmd_impl(2, argptr
- 1, cmd
, path
);
1289 if (*argptr
!= NULL
)
1290 error("commandcmd bad call");
1293 * Do nothing successfully if no command was specified;
1294 * ksh also does this.
1301 * The return command.
1305 returncmd(int argc
, char **argv
)
1307 int ret
= argc
> 1 ? number(argv
[1]) : oexitstatus
;
1309 evalskip
= SKIPRETURN
;
1316 falsecmd(int argc __unused
, char **argv __unused
)
1323 truecmd(int argc __unused
, char **argv __unused
)
1330 execcmd(int argc
, char **argv
)
1335 * Because we have historically not supported any options,
1336 * only treat "--" specially.
1338 if (argc
> 1 && strcmp(argv
[1], "--") == 0)
1341 iflag
= 0; /* exit on error */
1344 for (i
= 0; i
< cmdenviron
->count
; i
++)
1345 setvareq(cmdenviron
->args
[i
], VEXPORT
|VSTACK
);
1346 shellexec(argv
+ 1, environment(), pathval(), 0);
1354 timescmd(int argc __unused
, char **argv __unused
)
1357 long shumins
, shsmins
, chumins
, chsmins
;
1358 double shusecs
, shssecs
, chusecs
, chssecs
;
1360 if (getrusage(RUSAGE_SELF
, &ru
) < 0)
1362 shumins
= ru
.ru_utime
.tv_sec
/ 60;
1363 shusecs
= ru
.ru_utime
.tv_sec
% 60 + ru
.ru_utime
.tv_usec
/ 1000000.;
1364 shsmins
= ru
.ru_stime
.tv_sec
/ 60;
1365 shssecs
= ru
.ru_stime
.tv_sec
% 60 + ru
.ru_stime
.tv_usec
/ 1000000.;
1366 if (getrusage(RUSAGE_CHILDREN
, &ru
) < 0)
1368 chumins
= ru
.ru_utime
.tv_sec
/ 60;
1369 chusecs
= ru
.ru_utime
.tv_sec
% 60 + ru
.ru_utime
.tv_usec
/ 1000000.;
1370 chsmins
= ru
.ru_stime
.tv_sec
/ 60;
1371 chssecs
= ru
.ru_stime
.tv_sec
% 60 + ru
.ru_stime
.tv_usec
/ 1000000.;
1372 out1fmt("%ldm%.3fs %ldm%.3fs\n%ldm%.3fs %ldm%.3fs\n", shumins
,
1373 shusecs
, shsmins
, shssecs
, chumins
, chusecs
, chsmins
, chssecs
);