sh: Ensure the same command input file is on top after executing a builtin.

This avoids weirdness when 'fc -e vi' or the like is done and there is a
syntax error in the file. Formerly an interactive shell tried to execute
stuff after the syntax error and exited.

This should also avoid similar issues with 'command eval' and 'command .'
when 'command' is implemented properly as in NetBSD sh.

Special builtins did not have this problem since errors in them cause the
shell to exit or to reset various state such as the current command input
file.
This commit is contained in:
Jilles Tjoelker 2009-11-22 14:04:20 +00:00
parent 301f81f0fb
commit eaa3489312
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=199647
4 changed files with 60 additions and 0 deletions

View File

@ -593,6 +593,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
char *savecmdname;
struct shparam saveparam;
struct localvar *savelocalvars;
struct parsefile *savetopfile;
volatile int e;
char *lastarg;
int realstatus;
@ -833,6 +834,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
mode |= REDIR_BACKQ;
}
savecmdname = commandname;
savetopfile = getcurrentfile();
cmdenviron = varlist.list;
e = -1;
savehandler = handler;
@ -867,6 +869,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
if ((e != EXERROR && e != EXEXEC)
|| cmdentry.special)
exraise(e);
popfilesupto(savetopfile);
FORCEINTON;
}
if (cmdentry.u.index != EXECCMD)

View File

@ -508,6 +508,32 @@ popfile(void)
}
/*
* Return current file (to go back to it later using popfilesupto()).
*/
struct parsefile *
getcurrentfile(void)
{
return parsefile;
}
/*
* Pop files until the given file is on top again. Useful for regular
* builtins that read shell commands from files or strings.
* If the given file is not an active file, an error is raised.
*/
void
popfilesupto(struct parsefile *file)
{
while (parsefile != file && parsefile != &basepf)
popfile();
if (parsefile != file)
error("popfilesupto() misused");
}
/*
* Return to top level.
*/

View File

@ -45,6 +45,8 @@ extern int parsenleft; /* number of characters left in input buffer */
extern char *parsenextc; /* next character in input buffer */
extern int init_editline; /* 0 == not setup, 1 == OK, -1 == failed */
struct parsefile;
char *pfgets(char *, int);
int pgetc(void);
int preadbuffer(void);
@ -56,6 +58,8 @@ void setinputfile(char *, int);
void setinputfd(int, int);
void setinputstring(char *, int);
void popfile(void);
struct parsefile *getcurrentfile(void);
void popfilesupto(struct parsefile *);
void popallfiles(void);
void closescript(void);

View File

@ -0,0 +1,27 @@
# $FreeBSD$
set -e
trap 'echo Broken pipe -- test failed' pipe
P=${TMPDIR:-/tmp}
cd $P
T=$(mktemp -d sh-test.XXXXXX)
cd $T
mkfifo input output error
HISTFILE=/dev/null sh -i <input >output 2>error &
{
# Syntax error
echo ')' >&3
# Read error message, shell will read new input now
read dummy <&5
# Execute bad command again
echo 'fc -e true' >&3
# Verify that the shell is still running
echo 'echo continued' >&3 || rc=3
echo 'exit' >&3 || rc=3
read line <&4 && [ "$line" = continued ] && : ${rc:=0}
} 3>input 4<output 5<error
rm input output error
rmdir ${P}/${T}
exit ${rc:-3}