sh: Remove special code for shell scripts without magic number.
These are called "shell procedures" in the source. If execve() failed with [ENOEXEC], the shell would reinitialize itself and execute the program as a script. This requires a fair amount of code which is not frequently used (most scripts have a #! magic number). Therefore just execute a new instance of sh (_PATH_BSHELL) to run the script.
This commit is contained in:
parent
9f2e8bdff3
commit
3835f47c7e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=218306
19
bin/sh/TOUR
19
bin/sh/TOUR
@ -44,10 +44,6 @@ C source files for entries looking like:
|
||||
back to the main command loop */
|
||||
}
|
||||
|
||||
SHELLPROC {
|
||||
x = 3; /* executed when the shell runs a shell procedure */
|
||||
}
|
||||
|
||||
It pulls this code out into routines which are when particular
|
||||
events occur. The intent is to improve modularity by isolating
|
||||
the information about which modules need to be explicitly
|
||||
@ -80,12 +76,7 @@ EXCEPTIONS: Code for dealing with exceptions appears in
|
||||
exceptions.c. The C language doesn't include exception handling,
|
||||
so I implement it using setjmp and longjmp. The global variable
|
||||
exception contains the type of exception. EXERROR is raised by
|
||||
calling error. EXINT is an interrupt. EXSHELLPROC is an excep-
|
||||
tion which is raised when a shell procedure is invoked. The pur-
|
||||
pose of EXSHELLPROC is to perform the cleanup actions associated
|
||||
with other exceptions. After these cleanup actions, the shell
|
||||
can interpret a shell procedure itself without exec'ing a new
|
||||
copy of the shell.
|
||||
calling error. EXINT is an interrupt.
|
||||
|
||||
INTERRUPTS: In an interactive shell, an interrupt will cause an
|
||||
EXINT exception to return to the main command loop. (Exception:
|
||||
@ -270,14 +261,6 @@ When a program is run, the code in eval.c sticks any environment
|
||||
variables which precede the command (as in "PATH=xxx command") in
|
||||
the variable table as the simplest way to strip duplicates, and
|
||||
then calls "environment" to get the value of the environment.
|
||||
There are two consequences of this. First, if an assignment to
|
||||
PATH precedes the command, the value of PATH before the assign-
|
||||
ment must be remembered and passed to shellexec. Second, if the
|
||||
program turns out to be a shell procedure, the strings from the
|
||||
environment variables which preceded the command must be pulled
|
||||
out of the table and replaced with strings obtained from malloc,
|
||||
since the former will automatically be freed when the stack (see
|
||||
the entry on memalloc.c) is emptied.
|
||||
|
||||
BUILTIN COMMANDS: The procedures for handling these are scat-
|
||||
tered throughout the code, depending on which location appears
|
||||
|
@ -145,15 +145,7 @@ unalias(const char *name)
|
||||
return (1);
|
||||
}
|
||||
|
||||
#ifdef mkinit
|
||||
MKINIT void rmaliases(void);
|
||||
|
||||
SHELLPROC {
|
||||
rmaliases();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
static void
|
||||
rmaliases(void)
|
||||
{
|
||||
struct alias *ap, *tmp;
|
||||
|
@ -45,4 +45,3 @@ struct alias {
|
||||
struct alias *lookupalias(const char *, int);
|
||||
int aliascmd(int, char **);
|
||||
int unaliascmd(int, char **);
|
||||
void rmaliases(void);
|
||||
|
@ -56,8 +56,7 @@ extern volatile sig_atomic_t exception;
|
||||
/* exceptions */
|
||||
#define EXINT 0 /* SIGINT received */
|
||||
#define EXERROR 1 /* a generic error */
|
||||
#define EXSHELLPROC 2 /* execute a shell procedure */
|
||||
#define EXEXEC 3 /* command execution failed */
|
||||
#define EXEXEC 2 /* command execution failed */
|
||||
|
||||
|
||||
/*
|
||||
|
@ -111,10 +111,6 @@ RESET {
|
||||
loopnest = 0;
|
||||
funcnest = 0;
|
||||
}
|
||||
|
||||
SHELLPROC {
|
||||
exitstatus = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -732,7 +728,9 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
||||
argc = 0;
|
||||
for (sp = arglist.list ; sp ; sp = sp->next)
|
||||
argc++;
|
||||
argv = stalloc(sizeof (char *) * (argc + 1));
|
||||
/* Add one slot at the beginning for tryexec(). */
|
||||
argv = stalloc(sizeof (char *) * (argc + 2));
|
||||
argv++;
|
||||
|
||||
for (sp = arglist.list ; sp ; sp = sp->next) {
|
||||
TRACE(("evalcommand arg: %s\n", sp->text));
|
||||
@ -927,14 +925,10 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
||||
reffunc(cmdentry.u.func);
|
||||
savehandler = handler;
|
||||
if (setjmp(jmploc.loc)) {
|
||||
if (exception == EXSHELLPROC)
|
||||
freeparam(&saveparam);
|
||||
else {
|
||||
freeparam(&shellparam);
|
||||
shellparam = saveparam;
|
||||
if (exception == EXERROR || exception == EXEXEC)
|
||||
popredir();
|
||||
}
|
||||
unreffunc(cmdentry.u.func);
|
||||
poplocalvars();
|
||||
localvars = savelocalvars;
|
||||
@ -1016,11 +1010,9 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
||||
out2 = &errout;
|
||||
freestdout();
|
||||
handler = savehandler;
|
||||
if (e != EXSHELLPROC) {
|
||||
commandname = savecmdname;
|
||||
if (jp)
|
||||
exitshell(exitstatus);
|
||||
}
|
||||
if (flags == EV_BACKCMD) {
|
||||
backcmd->buf = memout.buf;
|
||||
backcmd->nleft = memout.nextc - memout.buf;
|
||||
|
@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <paths.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
@ -105,6 +106,8 @@ static void delete_cmd_entry(void);
|
||||
/*
|
||||
* Exec a program. Never returns. If you change this routine, you may
|
||||
* have to change the find_command routine as well.
|
||||
*
|
||||
* The argv array may be changed and element argv[-1] should be writable.
|
||||
*/
|
||||
|
||||
void
|
||||
@ -147,12 +150,9 @@ tryexec(char *cmd, char **argv, char **envp)
|
||||
execve(cmd, argv, envp);
|
||||
e = errno;
|
||||
if (e == ENOEXEC) {
|
||||
initshellproc();
|
||||
setinputfile(cmd, 0);
|
||||
commandname = arg0 = savestr(argv[0]);
|
||||
setparam(argv + 1);
|
||||
exraise(EXSHELLPROC);
|
||||
/*NOTREACHED*/
|
||||
*argv = cmd;
|
||||
*--argv = _PATH_BSHELL;
|
||||
execve(_PATH_BSHELL, argv, envp);
|
||||
}
|
||||
errno = e;
|
||||
}
|
||||
@ -536,43 +536,6 @@ clearcmdentry(int firstchange)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Delete all functions.
|
||||
*/
|
||||
|
||||
#ifdef mkinit
|
||||
MKINIT void deletefuncs(void);
|
||||
|
||||
SHELLPROC {
|
||||
deletefuncs();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
deletefuncs(void)
|
||||
{
|
||||
struct tblentry **tblp;
|
||||
struct tblentry **pp;
|
||||
struct tblentry *cmdp;
|
||||
|
||||
INTOFF;
|
||||
for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
|
||||
pp = tblp;
|
||||
while ((cmdp = *pp) != NULL) {
|
||||
if (cmdp->cmdtype == CMDFUNCTION) {
|
||||
*pp = cmdp->next;
|
||||
unreffunc(cmdp->param.func);
|
||||
ckfree(cmdp);
|
||||
} else {
|
||||
pp = &cmdp->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
INTON;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Locate a command in the command hash table. If "add" is nonzero,
|
||||
* add the command to the table if it is not already present. The
|
||||
|
@ -71,7 +71,6 @@ void find_command(const char *, struct cmdentry *, int, const char *);
|
||||
int find_builtin(const char *, int *);
|
||||
void hashcd(void);
|
||||
void changepath(const char *);
|
||||
void deletefuncs(void);
|
||||
void addcmdentry(const char *, struct cmdentry *);
|
||||
void defun(const char *, union node *);
|
||||
int unsetfunc(const char *);
|
||||
|
@ -35,4 +35,3 @@
|
||||
|
||||
void init(void);
|
||||
void reset(void);
|
||||
void initshellproc(void);
|
||||
|
@ -119,13 +119,8 @@ INIT {
|
||||
|
||||
RESET {
|
||||
popallfiles();
|
||||
if (exception != EXSHELLPROC)
|
||||
parselleft = parsenleft = 0; /* clear input buffer */
|
||||
}
|
||||
|
||||
SHELLPROC {
|
||||
popallfiles();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -177,22 +177,6 @@ out: out2fmt_flush("sh: can't access tty; job control turned off\n");
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef mkinit
|
||||
INCLUDE <sys/types.h>
|
||||
INCLUDE <stdlib.h>
|
||||
|
||||
SHELLPROC {
|
||||
backgndpid = -1;
|
||||
bgjob = NULL;
|
||||
#if JOBS
|
||||
jobctl = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if JOBS
|
||||
int
|
||||
fgcmd(int argc __unused, char **argv)
|
||||
|
@ -98,19 +98,7 @@ main(int argc, char *argv[])
|
||||
(void) setlocale(LC_ALL, "");
|
||||
state = 0;
|
||||
if (setjmp(main_handler.loc)) {
|
||||
/*
|
||||
* When a shell procedure is executed, we raise the
|
||||
* exception EXSHELLPROC to clean up before executing
|
||||
* the shell procedure.
|
||||
*/
|
||||
switch (exception) {
|
||||
case EXSHELLPROC:
|
||||
rootpid = getpid();
|
||||
rootshell = 1;
|
||||
minusc = NULL;
|
||||
state = 3;
|
||||
break;
|
||||
|
||||
case EXEXEC:
|
||||
exitstatus = exerrno;
|
||||
break;
|
||||
@ -123,10 +111,8 @@ main(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
|
||||
if (exception != EXSHELLPROC) {
|
||||
if (state == 0 || iflag == 0 || ! rootshell)
|
||||
exitshell(exitstatus);
|
||||
}
|
||||
reset();
|
||||
if (exception == EXINT)
|
||||
out2fmt_flush("\n");
|
||||
|
@ -126,16 +126,10 @@ char reset[] = "\
|
||||
* interactive shell and control is returned to the main command loop.\n\
|
||||
*/\n";
|
||||
|
||||
char shellproc[] = "\
|
||||
/*\n\
|
||||
* This routine is called to initialize the shell to run a shell procedure.\n\
|
||||
*/\n";
|
||||
|
||||
|
||||
struct event event[] = {
|
||||
{ "INIT", "init", init, { NULL, 0, NULL, NULL } },
|
||||
{ "RESET", "reset", reset, { NULL, 0, NULL, NULL } },
|
||||
{ "SHELLPROC", "initshellproc", shellproc, { NULL, 0, NULL, NULL } },
|
||||
{ NULL, NULL, NULL, { NULL, 0, NULL, NULL } }
|
||||
};
|
||||
|
||||
|
@ -304,21 +304,6 @@ setoption(int flag, int val)
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef mkinit
|
||||
INCLUDE "options.h"
|
||||
|
||||
SHELLPROC {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NOPTS; i++)
|
||||
optlist[i].val = 0;
|
||||
optschanged();
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Set the shell parameters.
|
||||
*/
|
||||
|
@ -324,10 +324,6 @@ RESET {
|
||||
popredir();
|
||||
}
|
||||
|
||||
SHELLPROC {
|
||||
clearredir();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Return true if fd 0 has already been redirected at least once. */
|
||||
|
14
bin/sh/sh.1
14
bin/sh/sh.1
@ -32,7 +32,7 @@
|
||||
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd January 16, 2011
|
||||
.Dd February 4, 2011
|
||||
.Dt SH 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -647,15 +647,9 @@ resulting in an
|
||||
.Er ENOEXEC
|
||||
return value from
|
||||
.Xr execve 2 )
|
||||
the shell will interpret the program in a subshell.
|
||||
The child shell will reinitialize itself in this case,
|
||||
so that the effect will be
|
||||
as if a new shell had been invoked to handle the ad-hoc shell script,
|
||||
except that the location of hashed commands located in
|
||||
the parent shell will be remembered by the child
|
||||
(see the description of the
|
||||
.Ic hash
|
||||
built-in command below).
|
||||
the shell will run a new instance of
|
||||
.Nm
|
||||
to interpret it.
|
||||
.Pp
|
||||
Note that previous versions of this document
|
||||
and the source code itself misleadingly and sporadically
|
||||
|
@ -367,22 +367,6 @@ ignoresig(int signo)
|
||||
}
|
||||
|
||||
|
||||
#ifdef mkinit
|
||||
INCLUDE <signal.h>
|
||||
INCLUDE "trap.h"
|
||||
|
||||
SHELLPROC {
|
||||
char *sm;
|
||||
|
||||
clear_traps();
|
||||
for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
|
||||
if (*sm == S_IGN)
|
||||
*sm = S_HARD_IGN;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Signal handler.
|
||||
*/
|
||||
|
43
bin/sh/var.c
43
bin/sh/var.c
@ -161,7 +161,7 @@ INIT {
|
||||
|
||||
/*
|
||||
* This routine initializes the builtin variables. It is called when the
|
||||
* shell is initialized and again when a shell procedure is spawned.
|
||||
* shell is initialized.
|
||||
*/
|
||||
|
||||
void
|
||||
@ -542,47 +542,6 @@ environment(void)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called when a shell procedure is invoked to clear out nonexported
|
||||
* variables. It is also necessary to reallocate variables of with
|
||||
* VSTACK set since these are currently allocated on the stack.
|
||||
*/
|
||||
|
||||
MKINIT void shprocvar(void);
|
||||
|
||||
#ifdef mkinit
|
||||
SHELLPROC {
|
||||
shprocvar();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
shprocvar(void)
|
||||
{
|
||||
struct var **vpp;
|
||||
struct var *vp, **prev;
|
||||
|
||||
for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
|
||||
for (prev = vpp ; (vp = *prev) != NULL ; ) {
|
||||
if ((vp->flags & VEXPORT) == 0) {
|
||||
*prev = vp->next;
|
||||
if ((vp->flags & VTEXTFIXED) == 0)
|
||||
ckfree(vp->text);
|
||||
if ((vp->flags & VSTRFIXED) == 0)
|
||||
ckfree(vp);
|
||||
} else {
|
||||
if (vp->flags & VSTACK) {
|
||||
vp->text = savestr(vp->text);
|
||||
vp->flags &=~ VSTACK;
|
||||
}
|
||||
prev = &vp->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
initvar();
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
var_compare(const void *a, const void *b)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user