Implement some of the differences between special built-ins and other builtins
demanded by POSIX. - A redirection error is only fatal (meaning the execution of a shell script is terminated) for special built-ins. Previously it was fatal for all shell builtins, causing problems like the one reported in PR 88845. - Variable assignments remain in effect for special built-ins. - Option or operand errors are only fatal for special built-ins. This change also makes errors from 'fc' non-fatal (I could not find any reasons for this behaviour). Somewhat independently from the above down-grade the error handling in the shift built-in if the operand is bigger than $# from an error() call (which is now fatal) to a return 1. I'm not sure if this should be considered a POSIX "operand error", however this change is needed for now as we trigger that error while building libncurses. Comparing with other shells, zsh does the same as our sh before this change (write a diagnostic, return 1), bash behaves as our sh after this commit (no diagnostic, return 1) and ksh93 and NetBSD's sh treat it as a fatal error.
This commit is contained in:
parent
8af87209e3
commit
85170a4a2a
@ -658,8 +658,10 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
||||
|
||||
/* Now locate the command. */
|
||||
if (argc == 0) {
|
||||
/* Variable assignment(s) without command */
|
||||
cmdentry.cmdtype = CMDBUILTIN;
|
||||
cmdentry.u.index = BLTINCMD;
|
||||
cmdentry.special = 1;
|
||||
} else {
|
||||
static const char PATH[] = "PATH=";
|
||||
char *path = pathval();
|
||||
@ -705,7 +707,8 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
||||
argv++;
|
||||
if (--argc == 0)
|
||||
break;
|
||||
if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
|
||||
if ((cmdentry.u.index = find_builtin(*argv,
|
||||
&cmdentry.special)) < 0) {
|
||||
outfmt(&errout, "%s: not found\n", *argv);
|
||||
exitstatus = 127;
|
||||
flushout(&errout);
|
||||
@ -812,7 +815,6 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
||||
memout.bufsize = 64;
|
||||
mode |= REDIR_BACKQ;
|
||||
}
|
||||
redirect(cmd->ncmd.redirect, mode);
|
||||
savecmdname = commandname;
|
||||
cmdenviron = varlist.list;
|
||||
e = -1;
|
||||
@ -823,6 +825,9 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
||||
}
|
||||
savehandler = handler;
|
||||
handler = &jmploc;
|
||||
redirect(cmd->ncmd.redirect, mode);
|
||||
if (cmdentry.special)
|
||||
listsetvar(cmdenviron);
|
||||
commandname = argv[0];
|
||||
argptr = argv + 1;
|
||||
optptr = NULL; /* initialize nextopt */
|
||||
@ -842,14 +847,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
||||
handler = savehandler;
|
||||
if (e != -1) {
|
||||
if ((e != EXERROR && e != EXEXEC)
|
||||
|| cmdentry.u.index == BLTINCMD
|
||||
|| cmdentry.u.index == DOTCMD
|
||||
|| cmdentry.u.index == EVALCMD
|
||||
#ifndef NO_HISTORY
|
||||
|| cmdentry.u.index == HISTCMD
|
||||
#endif
|
||||
|| cmdentry.u.index == EXECCMD
|
||||
|| cmdentry.u.index == COMMANDCMD)
|
||||
|| cmdentry.special)
|
||||
exraise(e);
|
||||
FORCEINTON;
|
||||
}
|
||||
@ -925,14 +923,12 @@ prehash(union node *n)
|
||||
*/
|
||||
|
||||
/*
|
||||
* No command given, or a bltin command with no arguments. Set the
|
||||
* specified variables.
|
||||
* No command given, or a bltin command with no arguments.
|
||||
*/
|
||||
|
||||
int
|
||||
bltincmd(int argc __unused, char **argv __unused)
|
||||
{
|
||||
listsetvar(cmdenviron);
|
||||
/*
|
||||
* Preserve exitstatus of a previous possible redirection
|
||||
* as POSIX mandates
|
||||
|
@ -84,6 +84,7 @@ __FBSDID("$FreeBSD$");
|
||||
struct tblentry {
|
||||
struct tblentry *next; /* next entry in hash chain */
|
||||
union param param; /* definition of builtin function */
|
||||
int special; /* flag for special builtin commands */
|
||||
short cmdtype; /* index identifying command */
|
||||
char rehash; /* if set, cd done since entry created */
|
||||
char cmdname[ARB]; /* name of command */
|
||||
@ -317,6 +318,7 @@ find_command(char *name, struct cmdentry *entry, int printerr, char *path)
|
||||
struct stat statb;
|
||||
int e;
|
||||
int i;
|
||||
int spec;
|
||||
|
||||
/* If name contains a slash, don't use the hash table */
|
||||
if (strchr(name, '/') != NULL) {
|
||||
@ -330,11 +332,12 @@ find_command(char *name, struct cmdentry *entry, int printerr, char *path)
|
||||
goto success;
|
||||
|
||||
/* If %builtin not in path, check for builtin next */
|
||||
if (builtinloc < 0 && (i = find_builtin(name)) >= 0) {
|
||||
if (builtinloc < 0 && (i = find_builtin(name, &spec)) >= 0) {
|
||||
INTOFF;
|
||||
cmdp = cmdlookup(name, 1);
|
||||
cmdp->cmdtype = CMDBUILTIN;
|
||||
cmdp->param.index = i;
|
||||
cmdp->special = spec;
|
||||
INTON;
|
||||
goto success;
|
||||
}
|
||||
@ -356,12 +359,13 @@ find_command(char *name, struct cmdentry *entry, int printerr, char *path)
|
||||
index++;
|
||||
if (pathopt) {
|
||||
if (prefix("builtin", pathopt)) {
|
||||
if ((i = find_builtin(name)) < 0)
|
||||
if ((i = find_builtin(name, &spec)) < 0)
|
||||
goto loop;
|
||||
INTOFF;
|
||||
cmdp = cmdlookup(name, 1);
|
||||
cmdp->cmdtype = CMDBUILTIN;
|
||||
cmdp->param.index = i;
|
||||
cmdp->special = spec;
|
||||
INTON;
|
||||
goto success;
|
||||
} else if (prefix("func", pathopt)) {
|
||||
@ -430,6 +434,7 @@ find_command(char *name, struct cmdentry *entry, int printerr, char *path)
|
||||
cmdp->rehash = 0;
|
||||
entry->cmdtype = cmdp->cmdtype;
|
||||
entry->u = cmdp->param;
|
||||
entry->special = cmdp->special;
|
||||
}
|
||||
|
||||
|
||||
@ -439,13 +444,15 @@ find_command(char *name, struct cmdentry *entry, int printerr, char *path)
|
||||
*/
|
||||
|
||||
int
|
||||
find_builtin(char *name)
|
||||
find_builtin(char *name, int *special)
|
||||
{
|
||||
const struct builtincmd *bp;
|
||||
|
||||
for (bp = builtincmd ; bp->name ; bp++) {
|
||||
if (*bp->name == *name && equal(bp->name, name))
|
||||
if (*bp->name == *name && equal(bp->name, name)) {
|
||||
*special = bp->special;
|
||||
return bp->code;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ struct cmdentry {
|
||||
int index;
|
||||
union node *func;
|
||||
} u;
|
||||
int special;
|
||||
};
|
||||
|
||||
|
||||
@ -62,7 +63,7 @@ void shellexec(char **, char **, char *, int);
|
||||
char *padvance(char **, char *);
|
||||
int hashcmd(int, char **);
|
||||
void find_command(char *, struct cmdentry *, int, char *);
|
||||
int find_builtin(char *);
|
||||
int find_builtin(char *, int *);
|
||||
void hashcd(void);
|
||||
void changepath(const char *);
|
||||
void deletefuncs(void);
|
||||
|
@ -374,7 +374,7 @@ shiftcmd(int argc, char **argv)
|
||||
if (argc > 1)
|
||||
n = number(argv[1]);
|
||||
if (n > shellparam.nparam)
|
||||
error("can't shift that many");
|
||||
return 1;
|
||||
INTOFF;
|
||||
shellparam.nparam -= n;
|
||||
for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
|
||||
|
Loading…
Reference in New Issue
Block a user