summaryrefslogtreecommitdiffstats
path: root/bin
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2010-03-06 16:57:53 +0000
committerjilles <jilles@FreeBSD.org>2010-03-06 16:57:53 +0000
commit1bfbe947abf36034bc4aa54fb61824fb8153e43f (patch)
treea292cee82566850ab924f6b484d9ac29b205226d /bin
parentce168ed4ea9ae18aa7997ba001e291cd5b2d3c8b (diff)
downloadFreeBSD-src-1bfbe947abf36034bc4aa54fb61824fb8153e43f.zip
FreeBSD-src-1bfbe947abf36034bc4aa54fb61824fb8153e43f.tar.gz
sh: Improve the command builtin:
* avoid unnecessary fork * allow executing builtins via command * executing a special builtin via command removes its special properties Obtained from: NetBSD (parts)
Diffstat (limited to 'bin')
-rw-r--r--bin/sh/eval.c95
-rw-r--r--bin/sh/exec.c24
-rw-r--r--bin/sh/exec.h4
-rw-r--r--bin/sh/sh.110
4 files changed, 90 insertions, 43 deletions
diff --git a/bin/sh/eval.c b/bin/sh/eval.c
index 30e05b8..c0a7601 100644
--- a/bin/sh/eval.c
+++ b/bin/sh/eval.c
@@ -597,6 +597,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
char *lastarg;
int realstatus;
int do_clearcmdentry;
+ char *path = pathval();
/* First expand the arguments. */
TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags));
@@ -682,7 +683,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
cmdentry.special = 1;
} else {
static const char PATH[] = "PATH=";
- char *path = pathval();
+ int cmd_flags = 0, bltinonly = 0;
/*
* Modify the command lookup path, if a PATH= assignment
@@ -713,24 +714,68 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
do_clearcmdentry = 1;
}
- find_command(argv[0], &cmdentry, 0, path);
- /* implement the bltin builtin here */
- if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
- for (;;) {
- argv++;
- if (--argc == 0)
- break;
- if ((cmdentry.u.index = find_builtin(*argv,
- &cmdentry.special)) < 0) {
+ for (;;) {
+ if (bltinonly) {
+ cmdentry.u.index = find_builtin(*argv, &cmdentry.special);
+ if (cmdentry.u.index < 0) {
cmdentry.u.index = BLTINCMD;
argv--;
argc++;
break;
}
- if (cmdentry.u.index != BLTINCMD)
+ } else
+ find_command(argv[0], &cmdentry, cmd_flags, path);
+ /* implement the bltin and command builtins here */
+ if (cmdentry.cmdtype != CMDBUILTIN)
+ break;
+ if (cmdentry.u.index == BLTINCMD) {
+ if (argc == 1)
break;
- }
+ argv++;
+ argc--;
+ bltinonly = 1;
+ } else if (cmdentry.u.index == COMMANDCMD) {
+ if (argc == 1)
+ break;
+ if (!strcmp(argv[1], "-p")) {
+ if (argc == 2)
+ break;
+ if (argv[2][0] == '-') {
+ if (strcmp(argv[2], "--"))
+ break;
+ if (argc == 3)
+ break;
+ argv += 3;
+ argc -= 3;
+ } else {
+ argv += 2;
+ argc -= 2;
+ }
+ path = _PATH_STDPATH;
+ clearcmdentry(0);
+ do_clearcmdentry = 1;
+ } else if (!strcmp(argv[1], "--")) {
+ if (argc == 2)
+ break;
+ argv += 2;
+ argc -= 2;
+ } else if (argv[1][0] == '-')
+ break;
+ else {
+ argv++;
+ argc--;
+ }
+ cmd_flags |= DO_NOFUNC;
+ bltinonly = 0;
+ } else
+ break;
}
+ /*
+ * Special builtins lose their special properties when
+ * called via 'command'.
+ */
+ if (cmd_flags & DO_NOFUNC)
+ cmdentry.special = 0;
}
/* Fork off a child process if necessary. */
@@ -741,9 +786,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
&& (cmdentry.cmdtype != CMDBUILTIN
|| cmdentry.u.index == CDCMD
|| cmdentry.u.index == DOTCMD
- || cmdentry.u.index == EVALCMD))
- || (cmdentry.cmdtype == CMDBUILTIN &&
- cmdentry.u.index == COMMANDCMD)) {
+ || cmdentry.u.index == EVALCMD))) {
jp = makejob(cmd, 1);
mode = cmd->ncmd.backgnd;
if (flags & EV_BACKCMD) {
@@ -889,7 +932,7 @@ cmddone:
for (sp = varlist.list ; sp ; sp = sp->next)
setvareq(sp->text, VEXPORT|VSTACK);
envp = environment();
- shellexec(argv, envp, pathval(), cmdentry.u.index);
+ shellexec(argv, envp, path, cmdentry.u.index);
/*NOTREACHED*/
}
goto out;
@@ -996,15 +1039,11 @@ int
commandcmd(int argc, char **argv)
{
static char stdpath[] = _PATH_STDPATH;
- struct jmploc loc, *old;
- struct strlist *sp;
char *path;
int ch;
int cmd = -1;
- for (sp = cmdenviron; sp ; sp = sp->next)
- setvareq(sp->text, VEXPORT|VSTACK);
- path = pathval();
+ path = bltinlookup("PATH", 1);
optind = optreset = 1;
opterr = 0;
@@ -1032,22 +1071,14 @@ commandcmd(int argc, char **argv)
error("wrong number of arguments");
return typecmd_impl(2, argv - 1, cmd, path);
}
- if (argc != 0) {
- old = handler;
- handler = &loc;
- if (setjmp(handler->loc) == 0)
- shellexec(argv, environment(), path, 0);
- handler = old;
- if (exception == EXEXEC)
- exit(exerrno);
- exraise(exception);
- }
+ if (argc != 0)
+ error("commandcmd() called while it should not be");
/*
* Do nothing successfully if no command was specified;
* ksh also does this.
*/
- exit(0);
+ return 0;
}
diff --git a/bin/sh/exec.c b/bin/sh/exec.c
index a28ab03..7c15f79 100644
--- a/bin/sh/exec.c
+++ b/bin/sh/exec.c
@@ -248,7 +248,7 @@ hashcmd(int argc __unused, char **argv __unused)
&& (cmdp->cmdtype == CMDNORMAL
|| (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
delete_cmd_entry();
- find_command(name, &entry, 1, pathval());
+ find_command(name, &entry, DO_ERR, pathval());
if (verbose) {
if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */
cmdp = cmdlookup(name, 0);
@@ -310,10 +310,10 @@ printentry(struct tblentry *cmdp, int verbose)
*/
void
-find_command(const char *name, struct cmdentry *entry, int printerr,
+find_command(const char *name, struct cmdentry *entry, int act,
const char *path)
{
- struct tblentry *cmdp;
+ struct tblentry *cmdp, loc_cmd;
int idx;
int prev;
char *fullname;
@@ -330,13 +330,19 @@ find_command(const char *name, struct cmdentry *entry, int printerr,
}
/* If name is in the table, and not invalidated by cd, we're done */
- if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0)
- goto success;
+ if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
+ if (cmdp->cmdtype == CMDFUNCTION && act & DO_NOFUNC)
+ cmdp = NULL;
+ else
+ goto success;
+ }
/* If %builtin not in path, check for builtin next */
if (builtinloc < 0 && (i = find_builtin(name, &spec)) >= 0) {
INTOFF;
cmdp = cmdlookup(name, 1);
+ if (cmdp->cmdtype == CMDFUNCTION)
+ cmdp = &loc_cmd;
cmdp->cmdtype = CMDBUILTIN;
cmdp->param.index = i;
cmdp->special = spec;
@@ -365,6 +371,8 @@ loop:
goto loop;
INTOFF;
cmdp = cmdlookup(name, 1);
+ if (cmdp->cmdtype == CMDFUNCTION)
+ cmdp = &loc_cmd;
cmdp->cmdtype = CMDBUILTIN;
cmdp->param.index = i;
cmdp->special = spec;
@@ -414,6 +422,8 @@ loop:
TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
INTOFF;
cmdp = cmdlookup(name, 1);
+ if (cmdp->cmdtype == CMDFUNCTION)
+ cmdp = &loc_cmd;
cmdp->cmdtype = CMDNORMAL;
cmdp->param.index = idx;
INTON;
@@ -421,9 +431,9 @@ loop:
}
/* We failed. If there was an entry for this command, delete it */
- if (cmdp)
+ if (cmdp && cmdp->cmdtype != CMDFUNCTION)
delete_cmd_entry();
- if (printerr) {
+ if (act & DO_ERR) {
if (e == ENOENT || e == ENOTDIR)
outfmt(out2, "%s: not found\n", name);
else
diff --git a/bin/sh/exec.h b/bin/sh/exec.h
index 32bf131..45330a1 100644
--- a/bin/sh/exec.h
+++ b/bin/sh/exec.h
@@ -57,6 +57,10 @@ struct cmdentry {
};
+/* action to find_command() */
+#define DO_ERR 0x01 /* prints errors */
+#define DO_NOFUNC 0x02 /* don't return shell functions, for command */
+
extern const char *pathopt; /* set by padvance */
extern int exerrno; /* last exec error */
diff --git a/bin/sh/sh.1 b/bin/sh/sh.1
index 8ec1195..4df5212 100644
--- a/bin/sh/sh.1
+++ b/bin/sh/sh.1
@@ -32,7 +32,7 @@
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
.\" $FreeBSD$
.\"
-.Dd December 31, 2009
+.Dd March 6, 2010
.Dt SH 1
.Os
.Sh NAME
@@ -1571,10 +1571,12 @@ built-in command.
.It Ic command Oo Fl p Oc Op Ar utility Op Ar argument ...
.It Ic command Oo Fl v | V Oc Op Ar utility
The first form of invocation executes the specified
+.Ar utility ,
+ignoring shell functions in the search.
+If
.Ar utility
-as a simple command (see the
-.Sx Simple Commands
-section).
+is a special builtin,
+it is executed as if it were a regular builtin.
.Pp
If the
.Fl p
OpenPOWER on IntegriCloud