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 */
|
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
|
It pulls this code out into routines which are when particular
|
||||||
events occur. The intent is to improve modularity by isolating
|
events occur. The intent is to improve modularity by isolating
|
||||||
the information about which modules need to be explicitly
|
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,
|
exceptions.c. The C language doesn't include exception handling,
|
||||||
so I implement it using setjmp and longjmp. The global variable
|
so I implement it using setjmp and longjmp. The global variable
|
||||||
exception contains the type of exception. EXERROR is raised by
|
exception contains the type of exception. EXERROR is raised by
|
||||||
calling error. EXINT is an interrupt. EXSHELLPROC is an excep-
|
calling error. EXINT is an interrupt.
|
||||||
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.
|
|
||||||
|
|
||||||
INTERRUPTS: In an interactive shell, an interrupt will cause an
|
INTERRUPTS: In an interactive shell, an interrupt will cause an
|
||||||
EXINT exception to return to the main command loop. (Exception:
|
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
|
variables which precede the command (as in "PATH=xxx command") in
|
||||||
the variable table as the simplest way to strip duplicates, and
|
the variable table as the simplest way to strip duplicates, and
|
||||||
then calls "environment" to get the value of the environment.
|
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-
|
BUILTIN COMMANDS: The procedures for handling these are scat-
|
||||||
tered throughout the code, depending on which location appears
|
tered throughout the code, depending on which location appears
|
||||||
|
@ -145,15 +145,7 @@ unalias(const char *name)
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef mkinit
|
static void
|
||||||
MKINIT void rmaliases(void);
|
|
||||||
|
|
||||||
SHELLPROC {
|
|
||||||
rmaliases();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
|
||||||
rmaliases(void)
|
rmaliases(void)
|
||||||
{
|
{
|
||||||
struct alias *ap, *tmp;
|
struct alias *ap, *tmp;
|
||||||
|
@ -45,4 +45,3 @@ struct alias {
|
|||||||
struct alias *lookupalias(const char *, int);
|
struct alias *lookupalias(const char *, int);
|
||||||
int aliascmd(int, char **);
|
int aliascmd(int, char **);
|
||||||
int unaliascmd(int, char **);
|
int unaliascmd(int, char **);
|
||||||
void rmaliases(void);
|
|
||||||
|
@ -56,8 +56,7 @@ extern volatile sig_atomic_t exception;
|
|||||||
/* exceptions */
|
/* exceptions */
|
||||||
#define EXINT 0 /* SIGINT received */
|
#define EXINT 0 /* SIGINT received */
|
||||||
#define EXERROR 1 /* a generic error */
|
#define EXERROR 1 /* a generic error */
|
||||||
#define EXSHELLPROC 2 /* execute a shell procedure */
|
#define EXEXEC 2 /* command execution failed */
|
||||||
#define EXEXEC 3 /* command execution failed */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -111,10 +111,6 @@ RESET {
|
|||||||
loopnest = 0;
|
loopnest = 0;
|
||||||
funcnest = 0;
|
funcnest = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHELLPROC {
|
|
||||||
exitstatus = 0;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -732,7 +728,9 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
|||||||
argc = 0;
|
argc = 0;
|
||||||
for (sp = arglist.list ; sp ; sp = sp->next)
|
for (sp = arglist.list ; sp ; sp = sp->next)
|
||||||
argc++;
|
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) {
|
for (sp = arglist.list ; sp ; sp = sp->next) {
|
||||||
TRACE(("evalcommand arg: %s\n", sp->text));
|
TRACE(("evalcommand arg: %s\n", sp->text));
|
||||||
@ -927,14 +925,10 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
|||||||
reffunc(cmdentry.u.func);
|
reffunc(cmdentry.u.func);
|
||||||
savehandler = handler;
|
savehandler = handler;
|
||||||
if (setjmp(jmploc.loc)) {
|
if (setjmp(jmploc.loc)) {
|
||||||
if (exception == EXSHELLPROC)
|
freeparam(&shellparam);
|
||||||
freeparam(&saveparam);
|
shellparam = saveparam;
|
||||||
else {
|
if (exception == EXERROR || exception == EXEXEC)
|
||||||
freeparam(&shellparam);
|
popredir();
|
||||||
shellparam = saveparam;
|
|
||||||
if (exception == EXERROR || exception == EXEXEC)
|
|
||||||
popredir();
|
|
||||||
}
|
|
||||||
unreffunc(cmdentry.u.func);
|
unreffunc(cmdentry.u.func);
|
||||||
poplocalvars();
|
poplocalvars();
|
||||||
localvars = savelocalvars;
|
localvars = savelocalvars;
|
||||||
@ -1016,11 +1010,9 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
|||||||
out2 = &errout;
|
out2 = &errout;
|
||||||
freestdout();
|
freestdout();
|
||||||
handler = savehandler;
|
handler = savehandler;
|
||||||
if (e != EXSHELLPROC) {
|
commandname = savecmdname;
|
||||||
commandname = savecmdname;
|
if (jp)
|
||||||
if (jp)
|
exitshell(exitstatus);
|
||||||
exitshell(exitstatus);
|
|
||||||
}
|
|
||||||
if (flags == EV_BACKCMD) {
|
if (flags == EV_BACKCMD) {
|
||||||
backcmd->buf = memout.buf;
|
backcmd->buf = memout.buf;
|
||||||
backcmd->nleft = memout.nextc - memout.buf;
|
backcmd->nleft = memout.nextc - memout.buf;
|
||||||
|
@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <paths.h>
|
||||||
#include <stdlib.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
|
* Exec a program. Never returns. If you change this routine, you may
|
||||||
* have to change the find_command routine as well.
|
* have to change the find_command routine as well.
|
||||||
|
*
|
||||||
|
* The argv array may be changed and element argv[-1] should be writable.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -147,12 +150,9 @@ tryexec(char *cmd, char **argv, char **envp)
|
|||||||
execve(cmd, argv, envp);
|
execve(cmd, argv, envp);
|
||||||
e = errno;
|
e = errno;
|
||||||
if (e == ENOEXEC) {
|
if (e == ENOEXEC) {
|
||||||
initshellproc();
|
*argv = cmd;
|
||||||
setinputfile(cmd, 0);
|
*--argv = _PATH_BSHELL;
|
||||||
commandname = arg0 = savestr(argv[0]);
|
execve(_PATH_BSHELL, argv, envp);
|
||||||
setparam(argv + 1);
|
|
||||||
exraise(EXSHELLPROC);
|
|
||||||
/*NOTREACHED*/
|
|
||||||
}
|
}
|
||||||
errno = e;
|
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,
|
* 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
|
* 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 *);
|
int find_builtin(const char *, int *);
|
||||||
void hashcd(void);
|
void hashcd(void);
|
||||||
void changepath(const char *);
|
void changepath(const char *);
|
||||||
void deletefuncs(void);
|
|
||||||
void addcmdentry(const char *, struct cmdentry *);
|
void addcmdentry(const char *, struct cmdentry *);
|
||||||
void defun(const char *, union node *);
|
void defun(const char *, union node *);
|
||||||
int unsetfunc(const char *);
|
int unsetfunc(const char *);
|
||||||
|
@ -35,4 +35,3 @@
|
|||||||
|
|
||||||
void init(void);
|
void init(void);
|
||||||
void reset(void);
|
void reset(void);
|
||||||
void initshellproc(void);
|
|
||||||
|
@ -119,12 +119,7 @@ INIT {
|
|||||||
|
|
||||||
RESET {
|
RESET {
|
||||||
popallfiles();
|
popallfiles();
|
||||||
if (exception != EXSHELLPROC)
|
parselleft = parsenleft = 0; /* clear input buffer */
|
||||||
parselleft = parsenleft = 0; /* clear input buffer */
|
|
||||||
}
|
|
||||||
|
|
||||||
SHELLPROC {
|
|
||||||
popallfiles();
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -177,22 +177,6 @@ out: out2fmt_flush("sh: can't access tty; job control turned off\n");
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef mkinit
|
|
||||||
INCLUDE <sys/types.h>
|
|
||||||
INCLUDE <stdlib.h>
|
|
||||||
|
|
||||||
SHELLPROC {
|
|
||||||
backgndpid = -1;
|
|
||||||
bgjob = NULL;
|
|
||||||
#if JOBS
|
|
||||||
jobctl = 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if JOBS
|
#if JOBS
|
||||||
int
|
int
|
||||||
fgcmd(int argc __unused, char **argv)
|
fgcmd(int argc __unused, char **argv)
|
||||||
|
@ -98,19 +98,7 @@ main(int argc, char *argv[])
|
|||||||
(void) setlocale(LC_ALL, "");
|
(void) setlocale(LC_ALL, "");
|
||||||
state = 0;
|
state = 0;
|
||||||
if (setjmp(main_handler.loc)) {
|
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) {
|
switch (exception) {
|
||||||
case EXSHELLPROC:
|
|
||||||
rootpid = getpid();
|
|
||||||
rootshell = 1;
|
|
||||||
minusc = NULL;
|
|
||||||
state = 3;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EXEXEC:
|
case EXEXEC:
|
||||||
exitstatus = exerrno;
|
exitstatus = exerrno;
|
||||||
break;
|
break;
|
||||||
@ -123,10 +111,8 @@ main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exception != EXSHELLPROC) {
|
if (state == 0 || iflag == 0 || ! rootshell)
|
||||||
if (state == 0 || iflag == 0 || ! rootshell)
|
exitshell(exitstatus);
|
||||||
exitshell(exitstatus);
|
|
||||||
}
|
|
||||||
reset();
|
reset();
|
||||||
if (exception == EXINT)
|
if (exception == EXINT)
|
||||||
out2fmt_flush("\n");
|
out2fmt_flush("\n");
|
||||||
|
@ -126,16 +126,10 @@ char reset[] = "\
|
|||||||
* interactive shell and control is returned to the main command loop.\n\
|
* interactive shell and control is returned to the main command loop.\n\
|
||||||
*/\n";
|
*/\n";
|
||||||
|
|
||||||
char shellproc[] = "\
|
|
||||||
/*\n\
|
|
||||||
* This routine is called to initialize the shell to run a shell procedure.\n\
|
|
||||||
*/\n";
|
|
||||||
|
|
||||||
|
|
||||||
struct event event[] = {
|
struct event event[] = {
|
||||||
{ "INIT", "init", init, { NULL, 0, NULL, NULL } },
|
{ "INIT", "init", init, { NULL, 0, NULL, NULL } },
|
||||||
{ "RESET", "reset", reset, { 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 } }
|
{ 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.
|
* Set the shell parameters.
|
||||||
*/
|
*/
|
||||||
|
@ -324,10 +324,6 @@ RESET {
|
|||||||
popredir();
|
popredir();
|
||||||
}
|
}
|
||||||
|
|
||||||
SHELLPROC {
|
|
||||||
clearredir();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Return true if fd 0 has already been redirected at least once. */
|
/* 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
|
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd January 16, 2011
|
.Dd February 4, 2011
|
||||||
.Dt SH 1
|
.Dt SH 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -647,15 +647,9 @@ resulting in an
|
|||||||
.Er ENOEXEC
|
.Er ENOEXEC
|
||||||
return value from
|
return value from
|
||||||
.Xr execve 2 )
|
.Xr execve 2 )
|
||||||
the shell will interpret the program in a subshell.
|
the shell will run a new instance of
|
||||||
The child shell will reinitialize itself in this case,
|
.Nm
|
||||||
so that the effect will be
|
to interpret it.
|
||||||
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).
|
|
||||||
.Pp
|
.Pp
|
||||||
Note that previous versions of this document
|
Note that previous versions of this document
|
||||||
and the source code itself misleadingly and sporadically
|
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.
|
* 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
|
* 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
|
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
|
static int
|
||||||
var_compare(const void *a, const void *b)
|
var_compare(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user