ash: implement ">&file" bashism. ~100 bytes.
This commit is contained in:
parent
93d0776a96
commit
559691a3bf
158
shell/ash.c
158
shell/ash.c
@ -8,7 +8,6 @@
|
|||||||
* Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
|
* Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
|
||||||
* was re-ported from NetBSD and debianized.
|
* was re-ported from NetBSD and debianized.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* This code is derived from software contributed to Berkeley by
|
* This code is derived from software contributed to Berkeley by
|
||||||
* Kenneth Almquist.
|
* Kenneth Almquist.
|
||||||
*
|
*
|
||||||
@ -28,7 +27,6 @@
|
|||||||
* used in busybox and size optimizations,
|
* used in busybox and size optimizations,
|
||||||
* rewrote arith (see notes to this), added locale support,
|
* rewrote arith (see notes to this), added locale support,
|
||||||
* rewrote dynamic variables.
|
* rewrote dynamic variables.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -247,8 +245,17 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
/* ============ Interrupts / exceptions */
|
/* ============ Utility functions */
|
||||||
|
static int isdigit_str9(const char *str)
|
||||||
|
{
|
||||||
|
int maxlen = 9 + 1; /* max 9 digits: 999999999 */
|
||||||
|
while (--maxlen && isdigit(*str))
|
||||||
|
str++;
|
||||||
|
return (*str == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ============ Interrupts / exceptions */
|
||||||
/*
|
/*
|
||||||
* These macros allow the user to suspend the handling of interrupt signals
|
* These macros allow the user to suspend the handling of interrupt signals
|
||||||
* over a period of time. This is similar to SIGHOLD or to sigblock, but
|
* over a period of time. This is similar to SIGHOLD or to sigblock, but
|
||||||
@ -500,32 +507,35 @@ static const char dolatstr[] ALIGN1 = {
|
|||||||
CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
|
CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NCMD 0
|
#define NCMD 0
|
||||||
#define NPIPE 1
|
#define NPIPE 1
|
||||||
#define NREDIR 2
|
#define NREDIR 2
|
||||||
#define NBACKGND 3
|
#define NBACKGND 3
|
||||||
#define NSUBSHELL 4
|
#define NSUBSHELL 4
|
||||||
#define NAND 5
|
#define NAND 5
|
||||||
#define NOR 6
|
#define NOR 6
|
||||||
#define NSEMI 7
|
#define NSEMI 7
|
||||||
#define NIF 8
|
#define NIF 8
|
||||||
#define NWHILE 9
|
#define NWHILE 9
|
||||||
#define NUNTIL 10
|
#define NUNTIL 10
|
||||||
#define NFOR 11
|
#define NFOR 11
|
||||||
#define NCASE 12
|
#define NCASE 12
|
||||||
#define NCLIST 13
|
#define NCLIST 13
|
||||||
#define NDEFUN 14
|
#define NDEFUN 14
|
||||||
#define NARG 15
|
#define NARG 15
|
||||||
#define NTO 16
|
#define NTO 16
|
||||||
#define NCLOBBER 17
|
#if ENABLE_ASH_BASH_COMPAT
|
||||||
#define NFROM 18
|
#define NTO2 17
|
||||||
#define NFROMTO 19
|
#endif
|
||||||
#define NAPPEND 20
|
#define NCLOBBER 18
|
||||||
#define NTOFD 21
|
#define NFROM 19
|
||||||
#define NFROMFD 22
|
#define NFROMTO 20
|
||||||
#define NHERE 23
|
#define NAPPEND 21
|
||||||
#define NXHERE 24
|
#define NTOFD 22
|
||||||
#define NNOT 25
|
#define NFROMFD 23
|
||||||
|
#define NHERE 24
|
||||||
|
#define NXHERE 25
|
||||||
|
#define NNOT 26
|
||||||
|
|
||||||
union node;
|
union node;
|
||||||
|
|
||||||
@ -588,20 +598,26 @@ struct narg {
|
|||||||
struct nodelist *backquote;
|
struct nodelist *backquote;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* nfile and ndup layout must match!
|
||||||
|
* NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
|
||||||
|
* that it is actually NTO2 (>&file), and change its type.
|
||||||
|
*/
|
||||||
struct nfile {
|
struct nfile {
|
||||||
smallint type;
|
smallint type;
|
||||||
union node *next;
|
union node *next;
|
||||||
int fd;
|
int fd;
|
||||||
|
int _unused_dupfd;
|
||||||
union node *fname;
|
union node *fname;
|
||||||
char *expfname;
|
char *expfname;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ndup {
|
struct ndup {
|
||||||
smallint type;
|
smallint type;
|
||||||
union node *next; /* must match nfile's layout */
|
union node *next;
|
||||||
int fd; /* must match nfile's layout */
|
int fd;
|
||||||
int dupfd;
|
int dupfd;
|
||||||
union node *vname;
|
union node *vname;
|
||||||
|
char *_unused_expfname;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nhere {
|
struct nhere {
|
||||||
@ -904,8 +920,11 @@ shcmd(union node *cmd, FILE *fp)
|
|||||||
case NTO: s = ">>"+1; dftfd = 1; break;
|
case NTO: s = ">>"+1; dftfd = 1; break;
|
||||||
case NCLOBBER: s = ">|"; dftfd = 1; break;
|
case NCLOBBER: s = ">|"; dftfd = 1; break;
|
||||||
case NAPPEND: s = ">>"; dftfd = 1; break;
|
case NAPPEND: s = ">>"; dftfd = 1; break;
|
||||||
|
#if ENABLE_ASH_BASH_COMPAT
|
||||||
|
case NTO2:
|
||||||
|
#endif
|
||||||
case NTOFD: s = ">&"; dftfd = 1; break;
|
case NTOFD: s = ">&"; dftfd = 1; break;
|
||||||
case NFROM: s = "<"; break;
|
case NFROM: s = "<"; break;
|
||||||
case NFROMFD: s = "<&"; break;
|
case NFROMFD: s = "<&"; break;
|
||||||
case NFROMTO: s = "<>"; break;
|
case NFROMTO: s = "<>"; break;
|
||||||
default: s = "*error*"; break;
|
default: s = "*error*"; break;
|
||||||
@ -4408,6 +4427,9 @@ cmdtxt(union node *n)
|
|||||||
case NAPPEND:
|
case NAPPEND:
|
||||||
p = ">>";
|
p = ">>";
|
||||||
goto redir;
|
goto redir;
|
||||||
|
#if ENABLE_ASH_BASH_COMPAT
|
||||||
|
case NTO2:
|
||||||
|
#endif
|
||||||
case NTOFD:
|
case NTOFD:
|
||||||
p = ">&";
|
p = ">&";
|
||||||
goto redir;
|
goto redir;
|
||||||
@ -4797,6 +4819,9 @@ openredirect(union node *redir)
|
|||||||
goto ecreate;
|
goto ecreate;
|
||||||
break;
|
break;
|
||||||
case NTO:
|
case NTO:
|
||||||
|
#if ENABLE_ASH_BASH_COMPAT
|
||||||
|
case NTO2:
|
||||||
|
#endif
|
||||||
/* Take care of noclobber mode. */
|
/* Take care of noclobber mode. */
|
||||||
if (Cflag) {
|
if (Cflag) {
|
||||||
fname = redir->nfile.expfname;
|
fname = redir->nfile.expfname;
|
||||||
@ -4959,6 +4984,10 @@ redirect(union node *redir, int flags)
|
|||||||
union node *tmp = redir;
|
union node *tmp = redir;
|
||||||
do {
|
do {
|
||||||
sv_pos++;
|
sv_pos++;
|
||||||
|
#if ENABLE_ASH_BASH_COMPAT
|
||||||
|
if (redir->nfile.type == NTO2)
|
||||||
|
sv_pos++;
|
||||||
|
#endif
|
||||||
tmp = tmp->nfile.next;
|
tmp = tmp->nfile.next;
|
||||||
} while (tmp);
|
} while (tmp);
|
||||||
sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
|
sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
|
||||||
@ -4997,6 +5026,9 @@ redirect(union node *redir, int flags)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ENABLE_ASH_BASH_COMPAT
|
||||||
|
redirect_more:
|
||||||
|
#endif
|
||||||
if (need_to_remember(sv, fd)) {
|
if (need_to_remember(sv, fd)) {
|
||||||
/* Copy old descriptor */
|
/* Copy old descriptor */
|
||||||
i = fcntl(fd, F_DUPFD, 10);
|
i = fcntl(fd, F_DUPFD, 10);
|
||||||
@ -5039,8 +5071,19 @@ redirect(union node *redir, int flags)
|
|||||||
}
|
}
|
||||||
} else if (fd != newfd) { /* move newfd to fd */
|
} else if (fd != newfd) { /* move newfd to fd */
|
||||||
copyfd(newfd, fd | COPYFD_EXACT);
|
copyfd(newfd, fd | COPYFD_EXACT);
|
||||||
close(newfd);
|
#if ENABLE_ASH_BASH_COMPAT
|
||||||
|
if (!(redir->nfile.type == NTO2 && fd == 2))
|
||||||
|
#endif
|
||||||
|
close(newfd);
|
||||||
}
|
}
|
||||||
|
#if ENABLE_ASH_BASH_COMPAT
|
||||||
|
if (redir->nfile.type == NTO2 && fd == 1) {
|
||||||
|
/* We already redirected it to fd 1, now copy it to 2 */
|
||||||
|
newfd = 1;
|
||||||
|
fd = 2;
|
||||||
|
goto redirect_more;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} while ((redir = redir->nfile.next) != NULL);
|
} while ((redir = redir->nfile.next) != NULL);
|
||||||
|
|
||||||
INT_ON;
|
INT_ON;
|
||||||
@ -7641,6 +7684,9 @@ calcsize(union node *n)
|
|||||||
calcsize(n->narg.next);
|
calcsize(n->narg.next);
|
||||||
break;
|
break;
|
||||||
case NTO:
|
case NTO:
|
||||||
|
#if ENABLE_ASH_BASH_COMPAT
|
||||||
|
case NTO2:
|
||||||
|
#endif
|
||||||
case NCLOBBER:
|
case NCLOBBER:
|
||||||
case NFROM:
|
case NFROM:
|
||||||
case NFROMTO:
|
case NFROMTO:
|
||||||
@ -7754,6 +7800,9 @@ copynode(union node *n)
|
|||||||
new->narg.next = copynode(n->narg.next);
|
new->narg.next = copynode(n->narg.next);
|
||||||
break;
|
break;
|
||||||
case NTO:
|
case NTO:
|
||||||
|
#if ENABLE_ASH_BASH_COMPAT
|
||||||
|
case NTO2:
|
||||||
|
#endif
|
||||||
case NCLOBBER:
|
case NCLOBBER:
|
||||||
case NFROM:
|
case NFROM:
|
||||||
case NFROMTO:
|
case NFROMTO:
|
||||||
@ -8175,17 +8224,33 @@ expredir(union node *n)
|
|||||||
case NFROMTO:
|
case NFROMTO:
|
||||||
case NFROM:
|
case NFROM:
|
||||||
case NTO:
|
case NTO:
|
||||||
|
#if ENABLE_ASH_BASH_COMPAT
|
||||||
|
case NTO2:
|
||||||
|
#endif
|
||||||
case NCLOBBER:
|
case NCLOBBER:
|
||||||
case NAPPEND:
|
case NAPPEND:
|
||||||
expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
|
expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
|
||||||
|
#if ENABLE_ASH_BASH_COMPAT
|
||||||
|
store_expfname:
|
||||||
|
#endif
|
||||||
redir->nfile.expfname = fn.list->text;
|
redir->nfile.expfname = fn.list->text;
|
||||||
break;
|
break;
|
||||||
case NFROMFD:
|
case NFROMFD:
|
||||||
case NTOFD:
|
case NTOFD: /* >& */
|
||||||
if (redir->ndup.vname) {
|
if (redir->ndup.vname) {
|
||||||
expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
|
expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
|
||||||
if (fn.list == NULL)
|
if (fn.list == NULL)
|
||||||
ash_msg_and_raise_error("redir error");
|
ash_msg_and_raise_error("redir error");
|
||||||
|
#if ENABLE_ASH_BASH_COMPAT
|
||||||
|
//FIXME: we used expandarg with different args!
|
||||||
|
if (!isdigit_str9(fn.list->text)) {
|
||||||
|
/* >&file, not >&fd */
|
||||||
|
if (redir->nfile.fd != 1) /* 123>&file - BAD */
|
||||||
|
ash_msg_and_raise_error("redir error");
|
||||||
|
redir->type = NTO2;
|
||||||
|
goto store_expfname;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
fixredir(redir, fn.list->text, 1);
|
fixredir(redir, fn.list->text, 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -10126,7 +10191,7 @@ fixredir(union node *n, const char *text, int err)
|
|||||||
n->ndup.dupfd = -1;
|
n->ndup.dupfd = -1;
|
||||||
else {
|
else {
|
||||||
if (err)
|
if (err)
|
||||||
raise_error_syntax("Bad fd number");
|
raise_error_syntax("bad fd number");
|
||||||
n->ndup.vname = makename();
|
n->ndup.vname = makename();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -10169,7 +10234,7 @@ parsefname(void)
|
|||||||
n->type = NXHERE;
|
n->type = NXHERE;
|
||||||
TRACE(("Here document %d\n", n->type));
|
TRACE(("Here document %d\n", n->type));
|
||||||
if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
|
if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
|
||||||
raise_error_syntax("Illegal eof marker for << redirection");
|
raise_error_syntax("illegal eof marker for << redirection");
|
||||||
rmescapes(wordtext);
|
rmescapes(wordtext);
|
||||||
here->eofmark = wordtext;
|
here->eofmark = wordtext;
|
||||||
here->next = NULL;
|
here->next = NULL;
|
||||||
@ -10261,7 +10326,7 @@ simplecmd(void)
|
|||||||
if (!goodname(name)
|
if (!goodname(name)
|
||||||
|| ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
|
|| ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
|
||||||
) {
|
) {
|
||||||
raise_error_syntax("Bad function name");
|
raise_error_syntax("bad function name");
|
||||||
}
|
}
|
||||||
n->type = NDEFUN;
|
n->type = NDEFUN;
|
||||||
checkkwd = CHKNL | CHKKWD | CHKALIAS;
|
checkkwd = CHKNL | CHKKWD | CHKALIAS;
|
||||||
@ -10346,7 +10411,7 @@ parse_command(void)
|
|||||||
}
|
}
|
||||||
case TFOR:
|
case TFOR:
|
||||||
if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
|
if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
|
||||||
raise_error_syntax("Bad for loop variable");
|
raise_error_syntax("bad for loop variable");
|
||||||
n1 = stzalloc(sizeof(struct nfor));
|
n1 = stzalloc(sizeof(struct nfor));
|
||||||
n1->type = NFOR;
|
n1->type = NFOR;
|
||||||
n1->nfor.var = wordtext;
|
n1->nfor.var = wordtext;
|
||||||
@ -10748,25 +10813,21 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
|
|||||||
endword:
|
endword:
|
||||||
#if ENABLE_ASH_MATH_SUPPORT
|
#if ENABLE_ASH_MATH_SUPPORT
|
||||||
if (syntax == ARISYNTAX)
|
if (syntax == ARISYNTAX)
|
||||||
raise_error_syntax("Missing '))'");
|
raise_error_syntax("missing '))'");
|
||||||
#endif
|
#endif
|
||||||
if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
|
if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
|
||||||
raise_error_syntax("Unterminated quoted string");
|
raise_error_syntax("unterminated quoted string");
|
||||||
if (varnest != 0) {
|
if (varnest != 0) {
|
||||||
startlinno = plinno;
|
startlinno = plinno;
|
||||||
/* { */
|
/* { */
|
||||||
raise_error_syntax("Missing '}'");
|
raise_error_syntax("missing '}'");
|
||||||
}
|
}
|
||||||
USTPUTC('\0', out);
|
USTPUTC('\0', out);
|
||||||
len = out - (char *)stackblock();
|
len = out - (char *)stackblock();
|
||||||
out = stackblock();
|
out = stackblock();
|
||||||
if (eofmark == NULL) {
|
if (eofmark == NULL) {
|
||||||
if ((c == '>' || c == '<') && quotef == 0) {
|
if ((c == '>' || c == '<') && quotef == 0) {
|
||||||
int maxlen = 9 + 1; /* max 9 digit fd#: 999999999 */
|
if (isdigit_str9(out)) {
|
||||||
char *np = out;
|
|
||||||
while (--maxlen && isdigit(*np))
|
|
||||||
np++;
|
|
||||||
if (*np == '\0') {
|
|
||||||
PARSEREDIR(); /* passed as params: out, c */
|
PARSEREDIR(); /* passed as params: out, c */
|
||||||
lasttoken = TREDIR;
|
lasttoken = TREDIR;
|
||||||
return lasttoken;
|
return lasttoken;
|
||||||
@ -10841,6 +10902,7 @@ parseredir: {
|
|||||||
np->type = NCLOBBER;
|
np->type = NCLOBBER;
|
||||||
else if (c == '&')
|
else if (c == '&')
|
||||||
np->type = NTOFD;
|
np->type = NTOFD;
|
||||||
|
/* it also can be NTO2 (>&file), but we can't figure it out yet */
|
||||||
else {
|
else {
|
||||||
np->type = NTO;
|
np->type = NTO;
|
||||||
pungetc();
|
pungetc();
|
||||||
@ -10954,8 +11016,10 @@ parsesub: {
|
|||||||
} else if (is_special(c)) {
|
} else if (is_special(c)) {
|
||||||
USTPUTC(c, out);
|
USTPUTC(c, out);
|
||||||
c = pgetc();
|
c = pgetc();
|
||||||
} else
|
} else {
|
||||||
badsub: raise_error_syntax("Bad substitution");
|
badsub:
|
||||||
|
raise_error_syntax("bad substitution");
|
||||||
|
}
|
||||||
|
|
||||||
STPUTC('=', out);
|
STPUTC('=', out);
|
||||||
flags = 0;
|
flags = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user