summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2009-06-13 21:17:45 +0000
committerjilles <jilles@FreeBSD.org>2009-06-13 21:17:45 +0000
commit884d344808b868ba1813aabf798a590a5a99683a (patch)
tree1ba6a6bdd17a2f3f559156b067a6e4ca4fb08707
parent7decb9c312312e3869ccb7439115644dc95ed665 (diff)
downloadFreeBSD-src-884d344808b868ba1813aabf798a590a5a99683a.zip
FreeBSD-src-884d344808b868ba1813aabf798a590a5a99683a.tar.gz
Avoid leaving unnecessary waiting shells in many forms of sh -c COMMAND.
This change only affects strings passed to -c, when the -s option is not used. The approach is to check if there may be additional data in the string after parsing each command. If there is none, use the EV_EXIT flag so that a fork may be omitted in specific cases. If there are empty lines after the command, the check will not see the end and forks will not be omitted. The same thing seems to happen in bash. Example: sh -c 'ps lT' No longer shows a shell process waiting for ps to finish. PR: bin/113860 Reviewed by: stefanf Approved by: ed (mentor)
-rw-r--r--bin/sh/eval.c19
-rw-r--r--bin/sh/eval.h5
-rw-r--r--bin/sh/input.c17
-rw-r--r--bin/sh/input.h1
-rw-r--r--bin/sh/main.c2
5 files changed, 35 insertions, 9 deletions
diff --git a/bin/sh/eval.c b/bin/sh/eval.c
index 8554943..5cee55e 100644
--- a/bin/sh/eval.c
+++ b/bin/sh/eval.c
@@ -74,11 +74,6 @@ __FBSDID("$FreeBSD$");
#endif
-/* flags in argument to evaltree */
-#define EV_EXIT 01 /* exit after evaluating tree */
-#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
-#define EV_BACKCMD 04 /* command executing within back quotes */
-
MKINIT int evalskip; /* set if we are skipping commands */
STATIC int skipcount; /* number of levels to skip */
MKINIT int loopnest; /* current loop nesting level */
@@ -163,20 +158,28 @@ evalstring(char *s, int flags)
{
union node *n;
struct stackmark smark;
+ int flags_exit;
+ flags_exit = flags & EV_EXIT;
+ flags &= ~EV_EXIT;
setstackmark(&smark);
setinputstring(s, 1);
while ((n = parsecmd(0)) != NEOF) {
- if (n != NULL)
- evaltree(n, flags);
+ if (n != NULL) {
+ if (flags_exit && preadateof())
+ evaltree(n, flags | EV_EXIT);
+ else
+ evaltree(n, flags);
+ }
popstackmark(&smark);
}
popfile();
popstackmark(&smark);
+ if (flags_exit)
+ exitshell(exitstatus);
}
-
/*
* Evaluate a parse tree. The value is left in the global variable
* exitstatus.
diff --git a/bin/sh/eval.h b/bin/sh/eval.h
index 11f7470..c82585e 100644
--- a/bin/sh/eval.h
+++ b/bin/sh/eval.h
@@ -45,6 +45,11 @@ struct backcmd { /* result of evalbackcmd */
struct job *jp; /* job structure for command */
};
+/* flags in argument to evaltree/evalstring */
+#define EV_EXIT 01 /* exit after evaluating tree */
+#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
+#define EV_BACKCMD 04 /* command executing within back quotes */
+
int evalcmd(int, char **);
void evalstring(char *, int);
union node; /* BLETCH for ansi C */
diff --git a/bin/sh/input.c b/bin/sh/input.c
index 81c1f0b..c97c496 100644
--- a/bin/sh/input.c
+++ b/bin/sh/input.c
@@ -321,6 +321,23 @@ check:
}
/*
+ * Returns if we are certain we are at EOF. Does not cause any more input
+ * to be read from the outside world.
+ */
+
+int
+preadateof(void)
+{
+ if (parsenleft > 0)
+ return 0;
+ if (parsefile->strpush)
+ return 0;
+ if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
+ return 1;
+ return 0;
+}
+
+/*
* Undo the last call to pgetc. Only one character may be pushed back.
* PEOF may be pushed back.
*/
diff --git a/bin/sh/input.h b/bin/sh/input.h
index 0d188c5..4d57b3b 100644
--- a/bin/sh/input.h
+++ b/bin/sh/input.h
@@ -48,6 +48,7 @@ extern int init_editline; /* 0 == not setup, 1 == OK, -1 == failed */
char *pfgets(char *, int);
int pgetc(void);
int preadbuffer(void);
+int preadateof(void);
void pungetc(void);
void pushstring(char *, int, void *);
void popstring(void);
diff --git a/bin/sh/main.c b/bin/sh/main.c
index 77526b5..85a6d20 100644
--- a/bin/sh/main.c
+++ b/bin/sh/main.c
@@ -178,7 +178,7 @@ state2:
state3:
state = 4;
if (minusc) {
- evalstring(minusc, 0);
+ evalstring(minusc, sflag ? 0 : EV_EXIT);
}
if (sflag || minusc == NULL) {
state4: /* XXX ??? - why isn't this before the "if" statement */
OpenPOWER on IntegriCloud