X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=shell%2Fash.c;h=c7deffd08ea08dcd2ff70ede0ac66d71b94277b0;hb=7306727d1b2ed05afc91548ba374f7400a2389e3;hp=4360770d4b3c4b101a69fb52675f6a920c7b866e;hpb=1166d7b1360285659aa7585e5c5bd4e1321aeeaf;p=oweals%2Fbusybox.git diff --git a/shell/ash.c b/shell/ash.c index 4360770d4..c7deffd08 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -2,18 +2,18 @@ /* * ash shell port for busybox * + * This code is derived from software contributed to Berkeley by + * Kenneth Almquist. + * + * Original BSD copyright notice is retained at the end of this file. + * * Copyright (c) 1989, 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Copyright (c) 1997-2005 Herbert Xu * was re-ported from NetBSD and debianized. * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. - * - * Original BSD copyright notice is retained at the end of this file. */ /* @@ -34,8 +34,6 @@ #define PROFILE 0 -#define IFS_BROKEN - #define JOBS ENABLE_ASH_JOB_CONTROL #if DEBUG @@ -50,17 +48,25 @@ #include #include #include + +#include "shell_common.h" +#include "builtin_read.h" #include "math.h" +#if ENABLE_ASH_RANDOM_SUPPORT +# include "random.h" +#else +# define CLEAR_RANDOM_T(rnd) ((void)0) +#endif #if defined SINGLE_APPLET_MAIN /* STANDALONE does not make sense, and won't compile */ -#undef CONFIG_FEATURE_SH_STANDALONE -#undef ENABLE_FEATURE_SH_STANDALONE -#undef IF_FEATURE_SH_STANDALONE -#undef IF_NOT_FEATURE_SH_STANDALONE(...) -#define ENABLE_FEATURE_SH_STANDALONE 0 -#define IF_FEATURE_SH_STANDALONE(...) -#define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__ +# undef CONFIG_FEATURE_SH_STANDALONE +# undef ENABLE_FEATURE_SH_STANDALONE +# undef IF_FEATURE_SH_STANDALONE +# undef IF_NOT_FEATURE_SH_STANDALONE(...) +# define ENABLE_FEATURE_SH_STANDALONE 0 +# define IF_FEATURE_SH_STANDALONE(...) +# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__ #endif #ifndef PIPE_BUF @@ -96,14 +102,17 @@ static const char *const optletters_optnames[] = { "b" "notify", "u" "nounset", "\0" "vi" +#if ENABLE_ASH_BASH_COMPAT + ,"\0" "pipefail" +#endif #if DEBUG ,"\0" "nolog" ,"\0" "debug" #endif }; -#define optletters(n) optletters_optnames[(n)][0] -#define optnames(n) (&optletters_optnames[(n)][1]) +#define optletters(n) optletters_optnames[n][0] +#define optnames(n) (optletters_optnames[n] + 1) enum { NOPTS = ARRAY_SIZE(optletters_optnames) }; @@ -173,9 +182,14 @@ struct globals_misc { #define bflag optlist[11] #define uflag optlist[12] #define viflag optlist[13] +#if ENABLE_ASH_BASH_COMPAT +# define pipefail optlist[14] +#else +# define pipefail 0 +#endif #if DEBUG -#define nolog optlist[14] -#define debug optlist[15] +# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] +# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] #endif /* trap handler commands */ @@ -193,12 +207,11 @@ struct globals_misc { /* indicates specified signal received */ uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ char *trap[NSIG]; + char **trap_ptr; /* used only by "trap hack" */ /* Rarely referenced stuff */ #if ENABLE_ASH_RANDOM_SUPPORT - /* Random number generators */ - int32_t random_galois_LFSR; /* Galois LFSR (fast but weak). signed! */ - uint32_t random_LCG; /* LCG (fast but weak) */ + random_t random_gen; #endif pid_t backgndpid; /* pid of last background process */ smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ @@ -222,8 +235,8 @@ extern struct globals_misc *const ash_ptr_to_globals_misc; #define sigmode (G_misc.sigmode ) #define gotsig (G_misc.gotsig ) #define trap (G_misc.trap ) -#define random_galois_LFSR (G_misc.random_galois_LFSR) -#define random_LCG (G_misc.random_LCG ) +#define trap_ptr (G_misc.trap_ptr ) +#define random_gen (G_misc.random_gen ) #define backgndpid (G_misc.backgndpid ) #define job_warning (G_misc.job_warning) #define INIT_G_misc() do { \ @@ -231,6 +244,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc; barrier(); \ curdir = nullstr; \ physdir = nullstr; \ + trap_ptr = trap; \ } while (0) @@ -255,9 +269,6 @@ static void trace_vprintf(const char *fmt, va_list va); /* ============ Utility functions */ #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) -/* C99 says: "char" declaration may be signed or unsigned by default */ -#define signed_char2int(sc) ((int)(signed char)(sc)) - static int isdigit_str9(const char *str) { int maxlen = 9 + 1; /* max 9 digits: 999999999 */ @@ -384,16 +395,7 @@ static void flush_stdout_stderr(void) { INT_OFF; - fflush(stdout); - fflush(stderr); - INT_ON; -} - -static void -flush_stderr(void) -{ - INT_OFF; - fflush(stderr); + fflush_all(); INT_ON; } @@ -446,13 +448,14 @@ static void out2str(const char *p) { outstr(p, stderr); - flush_stderr(); + flush_stdout_stderr(); } /* ============ Parser structures */ /* control characters in argument strings */ +#define CTL_FIRST CTLESC #define CTLESC ((unsigned char)'\201') /* escape next character */ #define CTLVAR ((unsigned char)'\202') /* variable defn */ #define CTLENDVAR ((unsigned char)'\203') @@ -462,6 +465,7 @@ out2str(const char *p) #define CTLARI ((unsigned char)'\206') /* arithmetic expression */ #define CTLENDARI ((unsigned char)'\207') #define CTLQUOTEMARK ((unsigned char)'\210') +#define CTL_LAST CTLQUOTEMARK /* variable substitution byte (follows CTLVAR) */ #define VSTYPE 0x0f /* type of variable substitution */ @@ -715,17 +719,17 @@ trace_puts_quoted(char *s) return; putc('"', tracefile); for (p = s; *p; p++) { - switch (*p) { - case '\n': c = 'n'; goto backslash; - case '\t': c = 't'; goto backslash; - case '\r': c = 'r'; goto backslash; - case '"': c = '"'; goto backslash; - case '\\': c = '\\'; goto backslash; - case CTLESC: c = 'e'; goto backslash; - case CTLVAR: c = 'v'; goto backslash; - case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; - case CTLBACKQ: c = 'q'; goto backslash; - case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; + switch ((unsigned char)*p) { + case '\n': c = 'n'; goto backslash; + case '\t': c = 't'; goto backslash; + case '\r': c = 'r'; goto backslash; + case '\"': c = '\"'; goto backslash; + case '\\': c = '\\'; goto backslash; + case CTLESC: c = 'e'; goto backslash; + case CTLVAR: c = 'v'; goto backslash; + case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; + case CTLBACKQ: c = 'q'; goto backslash; + case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; backslash: putc('\\', tracefile); putc(c, tracefile); @@ -735,8 +739,8 @@ trace_puts_quoted(char *s) putc(*p, tracefile); else { putc('\\', tracefile); - putc(*p >> 6 & 03, tracefile); - putc(*p >> 3 & 07, tracefile); + putc((*p >> 6) & 03, tracefile); + putc((*p >> 3) & 07, tracefile); putc(*p & 07, tracefile); } break; @@ -820,7 +824,7 @@ sharg(union node *arg, FILE *fp) { char *p; struct nodelist *bqlist; - int subtype; + unsigned char subtype; if (arg->type != NARG) { out1fmt("\n", arg->type); @@ -828,7 +832,7 @@ sharg(union node *arg, FILE *fp) } bqlist = arg->narg.backquote; for (p = arg->narg.text; *p; p++) { - switch (*p) { + switch ((unsigned char)*p) { case CTLESC: putc(*++p, fp); break; @@ -1152,6 +1156,49 @@ errmsg(int e, const char *em) /* ============ Memory allocation */ +#if 0 +/* I consider these wrappers nearly useless: + * ok, they return you to nearest exception handler, but + * how much memory do you leak in the process, making + * memory starvation worse? + */ +static void * +ckrealloc(void * p, size_t nbytes) +{ + p = realloc(p, nbytes); + if (!p) + ash_msg_and_raise_error(bb_msg_memory_exhausted); + return p; +} + +static void * +ckmalloc(size_t nbytes) +{ + return ckrealloc(NULL, nbytes); +} + +static void * +ckzalloc(size_t nbytes) +{ + return memset(ckmalloc(nbytes), 0, nbytes); +} + +static char * +ckstrdup(const char *s) +{ + char *p = strdup(s); + if (!p) + ash_msg_and_raise_error(bb_msg_memory_exhausted); + return p; +} +#else +/* Using bbox equivalents. They exit if out of memory */ +# define ckrealloc xrealloc +# define ckmalloc xmalloc +# define ckzalloc xzalloc +# define ckstrdup xstrdup +#endif + /* * It appears that grabstackstr() will barf with such alignments * because stalloc() will return a string allocated in a new stackblock. @@ -1161,7 +1208,7 @@ enum { /* Most machines require the value returned from malloc to be aligned * in some way. The following macro will get this right * on many machines. */ - SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1, + SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1, /* Minimum size of a block */ MINSIZE = SHELL_ALIGN(504), }; @@ -1207,43 +1254,10 @@ extern struct globals_memstack *const ash_ptr_to_globals_memstack; herefd = -1; \ } while (0) + #define stackblock() ((void *)g_stacknxt) #define stackblocksize() g_stacknleft - -static void * -ckrealloc(void * p, size_t nbytes) -{ - p = realloc(p, nbytes); - if (!p) - ash_msg_and_raise_error(bb_msg_memory_exhausted); - return p; -} - -static void * -ckmalloc(size_t nbytes) -{ - return ckrealloc(NULL, nbytes); -} - -static void * -ckzalloc(size_t nbytes) -{ - return memset(ckmalloc(nbytes), 0, nbytes); -} - -/* - * Make a copy of a string in safe storage. - */ -static char * -ckstrdup(const char *s) -{ - char *p = strdup(s); - if (!p) - ash_msg_and_raise_error(bb_msg_memory_exhausted); - return p; -} - /* * Parse trees for commands are allocated in lifo order, so we use a stack * to make this more efficient, and also to avoid all sorts of exception @@ -1578,21 +1592,21 @@ single_quote(const char *s) STADJUST(q - p, p); - len = strspn(s, "'"); - if (!len) + if (*s != '\'') break; + len = 0; + do len++; while (*++s == '\''); q = p = makestrspace(len + 3, p); *q++ = '"'; - q = (char *)memcpy(q, s, len) + len; + q = (char *)memcpy(q, s - len, len) + len; *q++ = '"'; - s += len; STADJUST(q - p, p); } while (*s); - USTPUTC(0, p); + USTPUTC('\0', p); return stackblock(); } @@ -1724,13 +1738,6 @@ struct localvar { # define VDYNAMIC 0 #endif -#ifdef IFS_BROKEN -static const char defifsvar[] ALIGN1 = "IFS= \t\n"; -#define defifs (defifsvar + 4) -#else -static const char defifs[] ALIGN1 = " \t\n"; -#endif - /* Need to be before varinit_data[] */ #if ENABLE_LOCALE_SUPPORT @@ -1761,7 +1768,7 @@ static const struct { const char *text; void (*func)(const char *) FAST_FUNC; } varinit_data[] = { -#ifdef IFS_BROKEN +#if IFS_BROKEN { VSTRFIXED|VTEXTFIXED , defifsvar , NULL }, #else { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL }, @@ -2599,423 +2606,387 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) #define CSPCL 13 /* these terminate a word */ #define CIGN 14 /* character should be ignored */ +#define PEOF 256 #if ENABLE_ASH_ALIAS -#define SYNBASE 130 -#define PEOF -130 -#define PEOA -129 -#define PEOA_OR_PEOF PEOA -#else -#define SYNBASE 129 -#define PEOF -129 -#define PEOA_OR_PEOF PEOF +# define PEOA 257 #endif -/* number syntax index */ -#define BASESYNTAX 0 /* not in quotes */ -#define DQSYNTAX 1 /* in double quotes */ -#define SQSYNTAX 2 /* in single quotes */ -#define ARISYNTAX 3 /* in arithmetic */ -#define PSSYNTAX 4 /* prompt */ - -#if ENABLE_ASH_OPTIMIZE_FOR_SIZE -#define USE_SIT_FUNCTION -#endif +#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE #if ENABLE_SH_MATH_SUPPORT -static const char S_I_T[][4] = { -#if ENABLE_ASH_ALIAS - { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */ -#endif - { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */ - { CNL, CNL, CNL, CNL }, /* 2, \n */ - { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */ - { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */ - { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */ - { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */ - { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */ - { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */ - { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */ - { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */ - { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */ -#ifndef USE_SIT_FUNCTION - { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */ - { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */ - { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */ +# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12)) +#else +# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8)) #endif +static const uint16_t S_I_T[] = { +#if ENABLE_ASH_ALIAS + SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */ +#endif + SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */ + SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */ + SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */ + SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */ + SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */ + SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */ + SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */ + SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */ + SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */ + SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */ + SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */ +#if !USE_SIT_FUNCTION + SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */ + SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */ + SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */ +#endif +#undef SIT_ITEM }; -#else -static const char S_I_T[][3] = { +/* Constants below must match table above */ +enum { #if ENABLE_ASH_ALIAS - { CSPCL, CIGN, CIGN }, /* 0, PEOA */ -#endif - { CSPCL, CWORD, CWORD }, /* 1, ' ' */ - { CNL, CNL, CNL }, /* 2, \n */ - { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */ - { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */ - { CVAR, CVAR, CWORD }, /* 5, $ */ - { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */ - { CSPCL, CWORD, CWORD }, /* 7, ( */ - { CSPCL, CWORD, CWORD }, /* 8, ) */ - { CBACK, CBACK, CCTL }, /* 9, \ */ - { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */ - { CENDVAR, CENDVAR, CWORD }, /* 11, } */ -#ifndef USE_SIT_FUNCTION - { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */ - { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */ - { CCTL, CCTL, CCTL } /* 14, CTLESC ... */ -#endif + CSPCL_CIGN_CIGN_CIGN , /* 0 */ +#endif + CSPCL_CWORD_CWORD_CWORD , /* 1 */ + CNL_CNL_CNL_CNL , /* 2 */ + CWORD_CCTL_CCTL_CWORD , /* 3 */ + CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */ + CVAR_CVAR_CWORD_CVAR , /* 5 */ + CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */ + CSPCL_CWORD_CWORD_CLP , /* 7 */ + CSPCL_CWORD_CWORD_CRP , /* 8 */ + CBACK_CBACK_CCTL_CBACK , /* 9 */ + CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */ + CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */ + CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */ + CWORD_CWORD_CWORD_CWORD , /* 13 */ + CCTL_CCTL_CCTL_CCTL , /* 14 */ }; -#endif /* SH_MATH_SUPPORT */ -#ifdef USE_SIT_FUNCTION +/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF, + * caller must ensure proper cast on it if c is *char_ptr! + */ +/* Values for syntax param */ +#define BASESYNTAX 0 /* not in quotes */ +#define DQSYNTAX 1 /* in double quotes */ +#define SQSYNTAX 2 /* in single quotes */ +#define ARISYNTAX 3 /* in arithmetic */ +#define PSSYNTAX 4 /* prompt. never passed to SIT() */ + +#if USE_SIT_FUNCTION static int SIT(int c, int syntax) { static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~"; -#if ENABLE_ASH_ALIAS - static const char syntax_index_table[] ALIGN1 = { +# if ENABLE_ASH_ALIAS + static const uint8_t syntax_index_table[] ALIGN1 = { 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */ 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */ 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */ 11, 3 /* "}~" */ }; -#else - static const char syntax_index_table[] ALIGN1 = { +# else + static const uint8_t syntax_index_table[] ALIGN1 = { 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */ 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */ 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */ 10, 2 /* "}~" */ }; -#endif +# endif const char *s; int indx; - if (c == PEOF) { /* 2^8+2 */ + if (c == PEOF) return CENDFILE; - } -#if ENABLE_ASH_ALIAS - if (c == PEOA) { /* 2^8+1 */ +# if ENABLE_ASH_ALIAS + if (c == PEOA) indx = 0; - } else -#endif + else +# endif { - if ((unsigned char)c >= CTLESC - && (unsigned char)c <= CTLQUOTEMARK + /* Cast is purely for paranoia here, + * just in case someone passed signed char to us */ + if ((unsigned char)c >= CTL_FIRST + && (unsigned char)c <= CTL_LAST ) { return CCTL; } s = strchrnul(spec_symbls, c); - if (*s == '\0') { + if (*s == '\0') return CWORD; - } indx = syntax_index_table[s - spec_symbls]; } - return S_I_T[indx][syntax]; + return (S_I_T[indx] >> (syntax*4)) & 0xf; } #else /* !USE_SIT_FUNCTION */ -#if ENABLE_ASH_ALIAS -#define CSPCL_CIGN_CIGN_CIGN 0 -#define CSPCL_CWORD_CWORD_CWORD 1 -#define CNL_CNL_CNL_CNL 2 -#define CWORD_CCTL_CCTL_CWORD 3 -#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4 -#define CVAR_CVAR_CWORD_CVAR 5 -#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6 -#define CSPCL_CWORD_CWORD_CLP 7 -#define CSPCL_CWORD_CWORD_CRP 8 -#define CBACK_CBACK_CCTL_CBACK 9 -#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10 -#define CENDVAR_CENDVAR_CWORD_CENDVAR 11 -#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12 -#define CWORD_CWORD_CWORD_CWORD 13 -#define CCTL_CCTL_CCTL_CCTL 14 -#else -#define CSPCL_CWORD_CWORD_CWORD 0 -#define CNL_CNL_CNL_CNL 1 -#define CWORD_CCTL_CCTL_CWORD 2 -#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3 -#define CVAR_CVAR_CWORD_CVAR 4 -#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5 -#define CSPCL_CWORD_CWORD_CLP 6 -#define CSPCL_CWORD_CWORD_CRP 7 -#define CBACK_CBACK_CCTL_CBACK 8 -#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9 -#define CENDVAR_CENDVAR_CWORD_CENDVAR 10 -#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11 -#define CWORD_CWORD_CWORD_CWORD 12 -#define CCTL_CCTL_CCTL_CCTL 13 -#endif - -static const char syntax_index_table[258] = { +static const uint8_t syntax_index_table[] = { /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */ - /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE, -#if ENABLE_ASH_ALIAS - /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN, -#endif - /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD, - /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL, - /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL, - /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL, - /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL, - /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL, - /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL, - /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL, - /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL, - /* 11 -119 */ CWORD_CWORD_CWORD_CWORD, - /* 12 -118 */ CWORD_CWORD_CWORD_CWORD, - /* 13 -117 */ CWORD_CWORD_CWORD_CWORD, - /* 14 -116 */ CWORD_CWORD_CWORD_CWORD, - /* 15 -115 */ CWORD_CWORD_CWORD_CWORD, - /* 16 -114 */ CWORD_CWORD_CWORD_CWORD, - /* 17 -113 */ CWORD_CWORD_CWORD_CWORD, - /* 18 -112 */ CWORD_CWORD_CWORD_CWORD, - /* 19 -111 */ CWORD_CWORD_CWORD_CWORD, - /* 20 -110 */ CWORD_CWORD_CWORD_CWORD, - /* 21 -109 */ CWORD_CWORD_CWORD_CWORD, - /* 22 -108 */ CWORD_CWORD_CWORD_CWORD, - /* 23 -107 */ CWORD_CWORD_CWORD_CWORD, - /* 24 -106 */ CWORD_CWORD_CWORD_CWORD, - /* 25 -105 */ CWORD_CWORD_CWORD_CWORD, - /* 26 -104 */ CWORD_CWORD_CWORD_CWORD, - /* 27 -103 */ CWORD_CWORD_CWORD_CWORD, - /* 28 -102 */ CWORD_CWORD_CWORD_CWORD, - /* 29 -101 */ CWORD_CWORD_CWORD_CWORD, - /* 30 -100 */ CWORD_CWORD_CWORD_CWORD, - /* 31 -99 */ CWORD_CWORD_CWORD_CWORD, - /* 32 -98 */ CWORD_CWORD_CWORD_CWORD, - /* 33 -97 */ CWORD_CWORD_CWORD_CWORD, - /* 34 -96 */ CWORD_CWORD_CWORD_CWORD, - /* 35 -95 */ CWORD_CWORD_CWORD_CWORD, - /* 36 -94 */ CWORD_CWORD_CWORD_CWORD, - /* 37 -93 */ CWORD_CWORD_CWORD_CWORD, - /* 38 -92 */ CWORD_CWORD_CWORD_CWORD, - /* 39 -91 */ CWORD_CWORD_CWORD_CWORD, - /* 40 -90 */ CWORD_CWORD_CWORD_CWORD, - /* 41 -89 */ CWORD_CWORD_CWORD_CWORD, - /* 42 -88 */ CWORD_CWORD_CWORD_CWORD, - /* 43 -87 */ CWORD_CWORD_CWORD_CWORD, - /* 44 -86 */ CWORD_CWORD_CWORD_CWORD, - /* 45 -85 */ CWORD_CWORD_CWORD_CWORD, - /* 46 -84 */ CWORD_CWORD_CWORD_CWORD, - /* 47 -83 */ CWORD_CWORD_CWORD_CWORD, - /* 48 -82 */ CWORD_CWORD_CWORD_CWORD, - /* 49 -81 */ CWORD_CWORD_CWORD_CWORD, - /* 50 -80 */ CWORD_CWORD_CWORD_CWORD, - /* 51 -79 */ CWORD_CWORD_CWORD_CWORD, - /* 52 -78 */ CWORD_CWORD_CWORD_CWORD, - /* 53 -77 */ CWORD_CWORD_CWORD_CWORD, - /* 54 -76 */ CWORD_CWORD_CWORD_CWORD, - /* 55 -75 */ CWORD_CWORD_CWORD_CWORD, - /* 56 -74 */ CWORD_CWORD_CWORD_CWORD, - /* 57 -73 */ CWORD_CWORD_CWORD_CWORD, - /* 58 -72 */ CWORD_CWORD_CWORD_CWORD, - /* 59 -71 */ CWORD_CWORD_CWORD_CWORD, - /* 60 -70 */ CWORD_CWORD_CWORD_CWORD, - /* 61 -69 */ CWORD_CWORD_CWORD_CWORD, - /* 62 -68 */ CWORD_CWORD_CWORD_CWORD, - /* 63 -67 */ CWORD_CWORD_CWORD_CWORD, - /* 64 -66 */ CWORD_CWORD_CWORD_CWORD, - /* 65 -65 */ CWORD_CWORD_CWORD_CWORD, - /* 66 -64 */ CWORD_CWORD_CWORD_CWORD, - /* 67 -63 */ CWORD_CWORD_CWORD_CWORD, - /* 68 -62 */ CWORD_CWORD_CWORD_CWORD, - /* 69 -61 */ CWORD_CWORD_CWORD_CWORD, - /* 70 -60 */ CWORD_CWORD_CWORD_CWORD, - /* 71 -59 */ CWORD_CWORD_CWORD_CWORD, - /* 72 -58 */ CWORD_CWORD_CWORD_CWORD, - /* 73 -57 */ CWORD_CWORD_CWORD_CWORD, - /* 74 -56 */ CWORD_CWORD_CWORD_CWORD, - /* 75 -55 */ CWORD_CWORD_CWORD_CWORD, - /* 76 -54 */ CWORD_CWORD_CWORD_CWORD, - /* 77 -53 */ CWORD_CWORD_CWORD_CWORD, - /* 78 -52 */ CWORD_CWORD_CWORD_CWORD, - /* 79 -51 */ CWORD_CWORD_CWORD_CWORD, - /* 80 -50 */ CWORD_CWORD_CWORD_CWORD, - /* 81 -49 */ CWORD_CWORD_CWORD_CWORD, - /* 82 -48 */ CWORD_CWORD_CWORD_CWORD, - /* 83 -47 */ CWORD_CWORD_CWORD_CWORD, - /* 84 -46 */ CWORD_CWORD_CWORD_CWORD, - /* 85 -45 */ CWORD_CWORD_CWORD_CWORD, - /* 86 -44 */ CWORD_CWORD_CWORD_CWORD, - /* 87 -43 */ CWORD_CWORD_CWORD_CWORD, - /* 88 -42 */ CWORD_CWORD_CWORD_CWORD, - /* 89 -41 */ CWORD_CWORD_CWORD_CWORD, - /* 90 -40 */ CWORD_CWORD_CWORD_CWORD, - /* 91 -39 */ CWORD_CWORD_CWORD_CWORD, - /* 92 -38 */ CWORD_CWORD_CWORD_CWORD, - /* 93 -37 */ CWORD_CWORD_CWORD_CWORD, - /* 94 -36 */ CWORD_CWORD_CWORD_CWORD, - /* 95 -35 */ CWORD_CWORD_CWORD_CWORD, - /* 96 -34 */ CWORD_CWORD_CWORD_CWORD, - /* 97 -33 */ CWORD_CWORD_CWORD_CWORD, - /* 98 -32 */ CWORD_CWORD_CWORD_CWORD, - /* 99 -31 */ CWORD_CWORD_CWORD_CWORD, - /* 100 -30 */ CWORD_CWORD_CWORD_CWORD, - /* 101 -29 */ CWORD_CWORD_CWORD_CWORD, - /* 102 -28 */ CWORD_CWORD_CWORD_CWORD, - /* 103 -27 */ CWORD_CWORD_CWORD_CWORD, - /* 104 -26 */ CWORD_CWORD_CWORD_CWORD, - /* 105 -25 */ CWORD_CWORD_CWORD_CWORD, - /* 106 -24 */ CWORD_CWORD_CWORD_CWORD, - /* 107 -23 */ CWORD_CWORD_CWORD_CWORD, - /* 108 -22 */ CWORD_CWORD_CWORD_CWORD, - /* 109 -21 */ CWORD_CWORD_CWORD_CWORD, - /* 110 -20 */ CWORD_CWORD_CWORD_CWORD, - /* 111 -19 */ CWORD_CWORD_CWORD_CWORD, - /* 112 -18 */ CWORD_CWORD_CWORD_CWORD, - /* 113 -17 */ CWORD_CWORD_CWORD_CWORD, - /* 114 -16 */ CWORD_CWORD_CWORD_CWORD, - /* 115 -15 */ CWORD_CWORD_CWORD_CWORD, - /* 116 -14 */ CWORD_CWORD_CWORD_CWORD, - /* 117 -13 */ CWORD_CWORD_CWORD_CWORD, - /* 118 -12 */ CWORD_CWORD_CWORD_CWORD, - /* 119 -11 */ CWORD_CWORD_CWORD_CWORD, - /* 120 -10 */ CWORD_CWORD_CWORD_CWORD, - /* 121 -9 */ CWORD_CWORD_CWORD_CWORD, - /* 122 -8 */ CWORD_CWORD_CWORD_CWORD, - /* 123 -7 */ CWORD_CWORD_CWORD_CWORD, - /* 124 -6 */ CWORD_CWORD_CWORD_CWORD, - /* 125 -5 */ CWORD_CWORD_CWORD_CWORD, - /* 126 -4 */ CWORD_CWORD_CWORD_CWORD, - /* 127 -3 */ CWORD_CWORD_CWORD_CWORD, - /* 128 -2 */ CWORD_CWORD_CWORD_CWORD, - /* 129 -1 */ CWORD_CWORD_CWORD_CWORD, - /* 130 0 */ CWORD_CWORD_CWORD_CWORD, - /* 131 1 */ CWORD_CWORD_CWORD_CWORD, - /* 132 2 */ CWORD_CWORD_CWORD_CWORD, - /* 133 3 */ CWORD_CWORD_CWORD_CWORD, - /* 134 4 */ CWORD_CWORD_CWORD_CWORD, - /* 135 5 */ CWORD_CWORD_CWORD_CWORD, - /* 136 6 */ CWORD_CWORD_CWORD_CWORD, - /* 137 7 */ CWORD_CWORD_CWORD_CWORD, - /* 138 8 */ CWORD_CWORD_CWORD_CWORD, - /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD, - /* 140 10 "\n" */ CNL_CNL_CNL_CNL, - /* 141 11 */ CWORD_CWORD_CWORD_CWORD, - /* 142 12 */ CWORD_CWORD_CWORD_CWORD, - /* 143 13 */ CWORD_CWORD_CWORD_CWORD, - /* 144 14 */ CWORD_CWORD_CWORD_CWORD, - /* 145 15 */ CWORD_CWORD_CWORD_CWORD, - /* 146 16 */ CWORD_CWORD_CWORD_CWORD, - /* 147 17 */ CWORD_CWORD_CWORD_CWORD, - /* 148 18 */ CWORD_CWORD_CWORD_CWORD, - /* 149 19 */ CWORD_CWORD_CWORD_CWORD, - /* 150 20 */ CWORD_CWORD_CWORD_CWORD, - /* 151 21 */ CWORD_CWORD_CWORD_CWORD, - /* 152 22 */ CWORD_CWORD_CWORD_CWORD, - /* 153 23 */ CWORD_CWORD_CWORD_CWORD, - /* 154 24 */ CWORD_CWORD_CWORD_CWORD, - /* 155 25 */ CWORD_CWORD_CWORD_CWORD, - /* 156 26 */ CWORD_CWORD_CWORD_CWORD, - /* 157 27 */ CWORD_CWORD_CWORD_CWORD, - /* 158 28 */ CWORD_CWORD_CWORD_CWORD, - /* 159 29 */ CWORD_CWORD_CWORD_CWORD, - /* 160 30 */ CWORD_CWORD_CWORD_CWORD, - /* 161 31 */ CWORD_CWORD_CWORD_CWORD, - /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD, - /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD, - /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD, - /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD, - /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR, - /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD, - /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD, - /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD, - /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP, - /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP, - /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD, - /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD, - /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD, - /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD, - /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD, - /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD, - /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD, - /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD, - /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD, - /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD, - /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD, - /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD, - /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD, - /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD, - /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD, - /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD, - /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD, - /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD, - /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD, - /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD, - /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD, - /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD, - /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD, - /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD, - /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD, - /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD, - /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD, - /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD, - /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD, - /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD, - /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD, - /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD, - /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD, - /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD, - /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD, - /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD, - /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD, - /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD, - /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD, - /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD, - /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD, - /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD, - /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD, - /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD, - /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD, - /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD, - /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD, - /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD, - /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD, - /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD, - /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK, - /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD, - /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD, - /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD, - /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE, - /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD, - /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD, - /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD, - /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD, - /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD, - /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD, - /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD, - /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD, - /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD, - /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD, - /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD, - /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD, - /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD, - /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD, - /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD, - /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD, - /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD, - /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD, - /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD, - /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD, - /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD, - /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD, - /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD, - /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD, - /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD, - /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD, - /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD, - /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD, - /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR, - /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD, - /* 257 127 */ CWORD_CWORD_CWORD_CWORD, + /* 0 */ CWORD_CWORD_CWORD_CWORD, + /* 1 */ CWORD_CWORD_CWORD_CWORD, + /* 2 */ CWORD_CWORD_CWORD_CWORD, + /* 3 */ CWORD_CWORD_CWORD_CWORD, + /* 4 */ CWORD_CWORD_CWORD_CWORD, + /* 5 */ CWORD_CWORD_CWORD_CWORD, + /* 6 */ CWORD_CWORD_CWORD_CWORD, + /* 7 */ CWORD_CWORD_CWORD_CWORD, + /* 8 */ CWORD_CWORD_CWORD_CWORD, + /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD, + /* 10 "\n" */ CNL_CNL_CNL_CNL, + /* 11 */ CWORD_CWORD_CWORD_CWORD, + /* 12 */ CWORD_CWORD_CWORD_CWORD, + /* 13 */ CWORD_CWORD_CWORD_CWORD, + /* 14 */ CWORD_CWORD_CWORD_CWORD, + /* 15 */ CWORD_CWORD_CWORD_CWORD, + /* 16 */ CWORD_CWORD_CWORD_CWORD, + /* 17 */ CWORD_CWORD_CWORD_CWORD, + /* 18 */ CWORD_CWORD_CWORD_CWORD, + /* 19 */ CWORD_CWORD_CWORD_CWORD, + /* 20 */ CWORD_CWORD_CWORD_CWORD, + /* 21 */ CWORD_CWORD_CWORD_CWORD, + /* 22 */ CWORD_CWORD_CWORD_CWORD, + /* 23 */ CWORD_CWORD_CWORD_CWORD, + /* 24 */ CWORD_CWORD_CWORD_CWORD, + /* 25 */ CWORD_CWORD_CWORD_CWORD, + /* 26 */ CWORD_CWORD_CWORD_CWORD, + /* 27 */ CWORD_CWORD_CWORD_CWORD, + /* 28 */ CWORD_CWORD_CWORD_CWORD, + /* 29 */ CWORD_CWORD_CWORD_CWORD, + /* 30 */ CWORD_CWORD_CWORD_CWORD, + /* 31 */ CWORD_CWORD_CWORD_CWORD, + /* 32 " " */ CSPCL_CWORD_CWORD_CWORD, + /* 33 "!" */ CWORD_CCTL_CCTL_CWORD, + /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD, + /* 35 "#" */ CWORD_CWORD_CWORD_CWORD, + /* 36 "$" */ CVAR_CVAR_CWORD_CVAR, + /* 37 "%" */ CWORD_CWORD_CWORD_CWORD, + /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD, + /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD, + /* 40 "(" */ CSPCL_CWORD_CWORD_CLP, + /* 41 ")" */ CSPCL_CWORD_CWORD_CRP, + /* 42 "*" */ CWORD_CCTL_CCTL_CWORD, + /* 43 "+" */ CWORD_CWORD_CWORD_CWORD, + /* 44 "," */ CWORD_CWORD_CWORD_CWORD, + /* 45 "-" */ CWORD_CCTL_CCTL_CWORD, + /* 46 "." */ CWORD_CWORD_CWORD_CWORD, + /* 47 "/" */ CWORD_CCTL_CCTL_CWORD, + /* 48 "0" */ CWORD_CWORD_CWORD_CWORD, + /* 49 "1" */ CWORD_CWORD_CWORD_CWORD, + /* 50 "2" */ CWORD_CWORD_CWORD_CWORD, + /* 51 "3" */ CWORD_CWORD_CWORD_CWORD, + /* 52 "4" */ CWORD_CWORD_CWORD_CWORD, + /* 53 "5" */ CWORD_CWORD_CWORD_CWORD, + /* 54 "6" */ CWORD_CWORD_CWORD_CWORD, + /* 55 "7" */ CWORD_CWORD_CWORD_CWORD, + /* 56 "8" */ CWORD_CWORD_CWORD_CWORD, + /* 57 "9" */ CWORD_CWORD_CWORD_CWORD, + /* 58 ":" */ CWORD_CCTL_CCTL_CWORD, + /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD, + /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD, + /* 61 "=" */ CWORD_CCTL_CCTL_CWORD, + /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD, + /* 63 "?" */ CWORD_CCTL_CCTL_CWORD, + /* 64 "@" */ CWORD_CWORD_CWORD_CWORD, + /* 65 "A" */ CWORD_CWORD_CWORD_CWORD, + /* 66 "B" */ CWORD_CWORD_CWORD_CWORD, + /* 67 "C" */ CWORD_CWORD_CWORD_CWORD, + /* 68 "D" */ CWORD_CWORD_CWORD_CWORD, + /* 69 "E" */ CWORD_CWORD_CWORD_CWORD, + /* 70 "F" */ CWORD_CWORD_CWORD_CWORD, + /* 71 "G" */ CWORD_CWORD_CWORD_CWORD, + /* 72 "H" */ CWORD_CWORD_CWORD_CWORD, + /* 73 "I" */ CWORD_CWORD_CWORD_CWORD, + /* 74 "J" */ CWORD_CWORD_CWORD_CWORD, + /* 75 "K" */ CWORD_CWORD_CWORD_CWORD, + /* 76 "L" */ CWORD_CWORD_CWORD_CWORD, + /* 77 "M" */ CWORD_CWORD_CWORD_CWORD, + /* 78 "N" */ CWORD_CWORD_CWORD_CWORD, + /* 79 "O" */ CWORD_CWORD_CWORD_CWORD, + /* 80 "P" */ CWORD_CWORD_CWORD_CWORD, + /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD, + /* 82 "R" */ CWORD_CWORD_CWORD_CWORD, + /* 83 "S" */ CWORD_CWORD_CWORD_CWORD, + /* 84 "T" */ CWORD_CWORD_CWORD_CWORD, + /* 85 "U" */ CWORD_CWORD_CWORD_CWORD, + /* 86 "V" */ CWORD_CWORD_CWORD_CWORD, + /* 87 "W" */ CWORD_CWORD_CWORD_CWORD, + /* 88 "X" */ CWORD_CWORD_CWORD_CWORD, + /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD, + /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD, + /* 91 "[" */ CWORD_CCTL_CCTL_CWORD, + /* 92 "\" */ CBACK_CBACK_CCTL_CBACK, + /* 93 "]" */ CWORD_CCTL_CCTL_CWORD, + /* 94 "^" */ CWORD_CWORD_CWORD_CWORD, + /* 95 "_" */ CWORD_CWORD_CWORD_CWORD, + /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE, + /* 97 "a" */ CWORD_CWORD_CWORD_CWORD, + /* 98 "b" */ CWORD_CWORD_CWORD_CWORD, + /* 99 "c" */ CWORD_CWORD_CWORD_CWORD, + /* 100 "d" */ CWORD_CWORD_CWORD_CWORD, + /* 101 "e" */ CWORD_CWORD_CWORD_CWORD, + /* 102 "f" */ CWORD_CWORD_CWORD_CWORD, + /* 103 "g" */ CWORD_CWORD_CWORD_CWORD, + /* 104 "h" */ CWORD_CWORD_CWORD_CWORD, + /* 105 "i" */ CWORD_CWORD_CWORD_CWORD, + /* 106 "j" */ CWORD_CWORD_CWORD_CWORD, + /* 107 "k" */ CWORD_CWORD_CWORD_CWORD, + /* 108 "l" */ CWORD_CWORD_CWORD_CWORD, + /* 109 "m" */ CWORD_CWORD_CWORD_CWORD, + /* 110 "n" */ CWORD_CWORD_CWORD_CWORD, + /* 111 "o" */ CWORD_CWORD_CWORD_CWORD, + /* 112 "p" */ CWORD_CWORD_CWORD_CWORD, + /* 113 "q" */ CWORD_CWORD_CWORD_CWORD, + /* 114 "r" */ CWORD_CWORD_CWORD_CWORD, + /* 115 "s" */ CWORD_CWORD_CWORD_CWORD, + /* 116 "t" */ CWORD_CWORD_CWORD_CWORD, + /* 117 "u" */ CWORD_CWORD_CWORD_CWORD, + /* 118 "v" */ CWORD_CWORD_CWORD_CWORD, + /* 119 "w" */ CWORD_CWORD_CWORD_CWORD, + /* 120 "x" */ CWORD_CWORD_CWORD_CWORD, + /* 121 "y" */ CWORD_CWORD_CWORD_CWORD, + /* 122 "z" */ CWORD_CWORD_CWORD_CWORD, + /* 123 "{" */ CWORD_CWORD_CWORD_CWORD, + /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD, + /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR, + /* 126 "~" */ CWORD_CCTL_CCTL_CWORD, + /* 127 del */ CWORD_CWORD_CWORD_CWORD, + /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD, + /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL, + /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL, + /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL, + /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL, + /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL, + /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL, + /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL, + /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL, + /* 137 */ CWORD_CWORD_CWORD_CWORD, + /* 138 */ CWORD_CWORD_CWORD_CWORD, + /* 139 */ CWORD_CWORD_CWORD_CWORD, + /* 140 */ CWORD_CWORD_CWORD_CWORD, + /* 141 */ CWORD_CWORD_CWORD_CWORD, + /* 142 */ CWORD_CWORD_CWORD_CWORD, + /* 143 */ CWORD_CWORD_CWORD_CWORD, + /* 144 */ CWORD_CWORD_CWORD_CWORD, + /* 145 */ CWORD_CWORD_CWORD_CWORD, + /* 146 */ CWORD_CWORD_CWORD_CWORD, + /* 147 */ CWORD_CWORD_CWORD_CWORD, + /* 148 */ CWORD_CWORD_CWORD_CWORD, + /* 149 */ CWORD_CWORD_CWORD_CWORD, + /* 150 */ CWORD_CWORD_CWORD_CWORD, + /* 151 */ CWORD_CWORD_CWORD_CWORD, + /* 152 */ CWORD_CWORD_CWORD_CWORD, + /* 153 */ CWORD_CWORD_CWORD_CWORD, + /* 154 */ CWORD_CWORD_CWORD_CWORD, + /* 155 */ CWORD_CWORD_CWORD_CWORD, + /* 156 */ CWORD_CWORD_CWORD_CWORD, + /* 157 */ CWORD_CWORD_CWORD_CWORD, + /* 158 */ CWORD_CWORD_CWORD_CWORD, + /* 159 */ CWORD_CWORD_CWORD_CWORD, + /* 160 */ CWORD_CWORD_CWORD_CWORD, + /* 161 */ CWORD_CWORD_CWORD_CWORD, + /* 162 */ CWORD_CWORD_CWORD_CWORD, + /* 163 */ CWORD_CWORD_CWORD_CWORD, + /* 164 */ CWORD_CWORD_CWORD_CWORD, + /* 165 */ CWORD_CWORD_CWORD_CWORD, + /* 166 */ CWORD_CWORD_CWORD_CWORD, + /* 167 */ CWORD_CWORD_CWORD_CWORD, + /* 168 */ CWORD_CWORD_CWORD_CWORD, + /* 169 */ CWORD_CWORD_CWORD_CWORD, + /* 170 */ CWORD_CWORD_CWORD_CWORD, + /* 171 */ CWORD_CWORD_CWORD_CWORD, + /* 172 */ CWORD_CWORD_CWORD_CWORD, + /* 173 */ CWORD_CWORD_CWORD_CWORD, + /* 174 */ CWORD_CWORD_CWORD_CWORD, + /* 175 */ CWORD_CWORD_CWORD_CWORD, + /* 176 */ CWORD_CWORD_CWORD_CWORD, + /* 177 */ CWORD_CWORD_CWORD_CWORD, + /* 178 */ CWORD_CWORD_CWORD_CWORD, + /* 179 */ CWORD_CWORD_CWORD_CWORD, + /* 180 */ CWORD_CWORD_CWORD_CWORD, + /* 181 */ CWORD_CWORD_CWORD_CWORD, + /* 182 */ CWORD_CWORD_CWORD_CWORD, + /* 183 */ CWORD_CWORD_CWORD_CWORD, + /* 184 */ CWORD_CWORD_CWORD_CWORD, + /* 185 */ CWORD_CWORD_CWORD_CWORD, + /* 186 */ CWORD_CWORD_CWORD_CWORD, + /* 187 */ CWORD_CWORD_CWORD_CWORD, + /* 188 */ CWORD_CWORD_CWORD_CWORD, + /* 189 */ CWORD_CWORD_CWORD_CWORD, + /* 190 */ CWORD_CWORD_CWORD_CWORD, + /* 191 */ CWORD_CWORD_CWORD_CWORD, + /* 192 */ CWORD_CWORD_CWORD_CWORD, + /* 193 */ CWORD_CWORD_CWORD_CWORD, + /* 194 */ CWORD_CWORD_CWORD_CWORD, + /* 195 */ CWORD_CWORD_CWORD_CWORD, + /* 196 */ CWORD_CWORD_CWORD_CWORD, + /* 197 */ CWORD_CWORD_CWORD_CWORD, + /* 198 */ CWORD_CWORD_CWORD_CWORD, + /* 199 */ CWORD_CWORD_CWORD_CWORD, + /* 200 */ CWORD_CWORD_CWORD_CWORD, + /* 201 */ CWORD_CWORD_CWORD_CWORD, + /* 202 */ CWORD_CWORD_CWORD_CWORD, + /* 203 */ CWORD_CWORD_CWORD_CWORD, + /* 204 */ CWORD_CWORD_CWORD_CWORD, + /* 205 */ CWORD_CWORD_CWORD_CWORD, + /* 206 */ CWORD_CWORD_CWORD_CWORD, + /* 207 */ CWORD_CWORD_CWORD_CWORD, + /* 208 */ CWORD_CWORD_CWORD_CWORD, + /* 209 */ CWORD_CWORD_CWORD_CWORD, + /* 210 */ CWORD_CWORD_CWORD_CWORD, + /* 211 */ CWORD_CWORD_CWORD_CWORD, + /* 212 */ CWORD_CWORD_CWORD_CWORD, + /* 213 */ CWORD_CWORD_CWORD_CWORD, + /* 214 */ CWORD_CWORD_CWORD_CWORD, + /* 215 */ CWORD_CWORD_CWORD_CWORD, + /* 216 */ CWORD_CWORD_CWORD_CWORD, + /* 217 */ CWORD_CWORD_CWORD_CWORD, + /* 218 */ CWORD_CWORD_CWORD_CWORD, + /* 219 */ CWORD_CWORD_CWORD_CWORD, + /* 220 */ CWORD_CWORD_CWORD_CWORD, + /* 221 */ CWORD_CWORD_CWORD_CWORD, + /* 222 */ CWORD_CWORD_CWORD_CWORD, + /* 223 */ CWORD_CWORD_CWORD_CWORD, + /* 224 */ CWORD_CWORD_CWORD_CWORD, + /* 225 */ CWORD_CWORD_CWORD_CWORD, + /* 226 */ CWORD_CWORD_CWORD_CWORD, + /* 227 */ CWORD_CWORD_CWORD_CWORD, + /* 228 */ CWORD_CWORD_CWORD_CWORD, + /* 229 */ CWORD_CWORD_CWORD_CWORD, + /* 230 */ CWORD_CWORD_CWORD_CWORD, + /* 231 */ CWORD_CWORD_CWORD_CWORD, + /* 232 */ CWORD_CWORD_CWORD_CWORD, + /* 233 */ CWORD_CWORD_CWORD_CWORD, + /* 234 */ CWORD_CWORD_CWORD_CWORD, + /* 235 */ CWORD_CWORD_CWORD_CWORD, + /* 236 */ CWORD_CWORD_CWORD_CWORD, + /* 237 */ CWORD_CWORD_CWORD_CWORD, + /* 238 */ CWORD_CWORD_CWORD_CWORD, + /* 239 */ CWORD_CWORD_CWORD_CWORD, + /* 230 */ CWORD_CWORD_CWORD_CWORD, + /* 241 */ CWORD_CWORD_CWORD_CWORD, + /* 242 */ CWORD_CWORD_CWORD_CWORD, + /* 243 */ CWORD_CWORD_CWORD_CWORD, + /* 244 */ CWORD_CWORD_CWORD_CWORD, + /* 245 */ CWORD_CWORD_CWORD_CWORD, + /* 246 */ CWORD_CWORD_CWORD_CWORD, + /* 247 */ CWORD_CWORD_CWORD_CWORD, + /* 248 */ CWORD_CWORD_CWORD_CWORD, + /* 249 */ CWORD_CWORD_CWORD_CWORD, + /* 250 */ CWORD_CWORD_CWORD_CWORD, + /* 251 */ CWORD_CWORD_CWORD_CWORD, + /* 252 */ CWORD_CWORD_CWORD_CWORD, + /* 253 */ CWORD_CWORD_CWORD_CWORD, + /* 254 */ CWORD_CWORD_CWORD_CWORD, + /* 255 */ CWORD_CWORD_CWORD_CWORD, + /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE, +# if ENABLE_ASH_ALIAS + /* PEOA */ CSPCL_CIGN_CIGN_CIGN, +# endif }; -#define SIT(c, syntax) (S_I_T[(int)syntax_index_table[(int)(c) + SYNBASE]][syntax]) +# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf) -#endif /* USE_SIT_FUNCTION */ +#endif /* !USE_SIT_FUNCTION */ /* ============ Alias handling */ @@ -3225,8 +3196,8 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) /* ============ jobs.c */ /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ -#define FORK_FG 0 -#define FORK_BG 1 +#define FORK_FG 0 +#define FORK_BG 1 #define FORK_NOJOB 2 /* mode flags for showjob(s) */ @@ -3241,9 +3212,9 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) * array of pids. */ struct procstat { - pid_t pid; /* process id */ - int status; /* last process status from wait() */ - char *cmd; /* text of command being run */ + pid_t ps_pid; /* process id */ + int ps_status; /* last process status from wait() */ + char *ps_cmd; /* text of command being run */ }; struct job { @@ -3269,9 +3240,6 @@ struct job { }; static struct job *makejob(/*union node *,*/ int); -#if !JOBS -#define forkshell(job, node, mode) forkshell(job, mode) -#endif static int forkshell(struct job *, union node *, int); static int waitforjob(struct job *); @@ -3552,7 +3520,7 @@ getjob(const char *name, int getctl) found = NULL; while (jp) { - if (match(jp->ps[0].cmd, p)) { + if (match(jp->ps[0].ps_cmd, p)) { if (found) goto err; found = jp; @@ -3586,8 +3554,8 @@ freejob(struct job *jp) INT_OFF; for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { - if (ps->cmd != nullstr) - free(ps->cmd); + if (ps->ps_cmd != nullstr) + free(ps->ps_cmd); } if (jp->ps != &jp->ps0) free(jp->ps); @@ -3689,7 +3657,7 @@ killcmd(int argc, char **argv) do { if (argv[i][0] == '%') { struct job *jp = getjob(argv[i], 0); - unsigned pid = jp->ps[0].pid; + unsigned pid = jp->ps[0].ps_pid; /* Enough space for ' -NNN' */ argv[i] = alloca(sizeof(int)*3 + 3); /* kill_main has matching code to expect @@ -3703,15 +3671,15 @@ killcmd(int argc, char **argv) } static void -showpipe(struct job *jp, FILE *out) +showpipe(struct job *jp /*, FILE *out*/) { - struct procstat *sp; - struct procstat *spend; + struct procstat *ps; + struct procstat *psend; - spend = jp->ps + jp->nprocs; - for (sp = jp->ps + 1; sp < spend; sp++) - fprintf(out, " | %s", sp->cmd); - outcslow('\n', out); + psend = jp->ps + jp->nprocs; + for (ps = jp->ps + 1; ps < psend; ps++) + printf(" | %s", ps->ps_cmd); + outcslow('\n', stdout); flush_stdout_stderr(); } @@ -3728,15 +3696,15 @@ restartjob(struct job *jp, int mode) if (jp->state == JOBDONE) goto out; jp->state = JOBRUNNING; - pgid = jp->ps->pid; + pgid = jp->ps[0].ps_pid; if (mode == FORK_FG) xtcsetpgrp(ttyfd, pgid); killpg(pgid, SIGCONT); ps = jp->ps; i = jp->nprocs; do { - if (WIFSTOPPED(ps->status)) { - ps->status = -1; + if (WIFSTOPPED(ps->ps_status)) { + ps->ps_status = -1; } ps++; } while (--i); @@ -3750,22 +3718,20 @@ static int FAST_FUNC fg_bgcmd(int argc UNUSED_PARAM, char **argv) { struct job *jp; - FILE *out; int mode; int retval; mode = (**argv == 'f') ? FORK_FG : FORK_BG; nextopt(nullstr); argv = argptr; - out = stdout; do { jp = getjob(*argv, 1); if (mode == FORK_BG) { set_curjob(jp, CUR_RUNNING); - fprintf(out, "[%d] ", jobno(jp)); + printf("[%d] ", jobno(jp)); } - outstr(jp->ps->cmd, out); - showpipe(jp, out); + out1str(jp->ps[0].ps_cmd); + showpipe(jp /*, stdout*/); retval = restartjob(jp, mode); } while (*argv && *++argv); return retval; @@ -3824,8 +3790,9 @@ dowait(int wait_flags, struct job *job) /* Do a wait system call. If job control is compiled in, we accept * stopped processes. wait_flags may have WNOHANG, preventing blocking. * NB: _not_ safe_waitpid, we need to detect EINTR */ - pid = waitpid(-1, &status, - (doing_jobctl ? (wait_flags | WUNTRACED) : wait_flags)); + if (doing_jobctl) + wait_flags |= WUNTRACED; + pid = waitpid(-1, &status, wait_flags); TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", pid, status, errno, strerror(errno))); if (pid <= 0) @@ -3834,32 +3801,32 @@ dowait(int wait_flags, struct job *job) INT_OFF; thisjob = NULL; for (jp = curjob; jp; jp = jp->prev_job) { - struct procstat *sp; - struct procstat *spend; + struct procstat *ps; + struct procstat *psend; if (jp->state == JOBDONE) continue; state = JOBDONE; - spend = jp->ps + jp->nprocs; - sp = jp->ps; + ps = jp->ps; + psend = ps + jp->nprocs; do { - if (sp->pid == pid) { + if (ps->ps_pid == pid) { TRACE(("Job %d: changing status of proc %d " "from 0x%x to 0x%x\n", - jobno(jp), pid, sp->status, status)); - sp->status = status; + jobno(jp), pid, ps->ps_status, status)); + ps->ps_status = status; thisjob = jp; } - if (sp->status == -1) + if (ps->ps_status == -1) state = JOBRUNNING; #if JOBS if (state == JOBRUNNING) continue; - if (WIFSTOPPED(sp->status)) { - jp->stopstatus = sp->status; + if (WIFSTOPPED(ps->ps_status)) { + jp->stopstatus = ps->ps_status; state = JOBSTOPPED; } #endif - } while (++sp < spend); + } while (++ps < psend); if (thisjob) goto gotjob; } @@ -3925,7 +3892,7 @@ showjob(FILE *out, struct job *jp, int mode) if (mode & SHOW_ONLY_PGID) { /* jobs -p */ /* just output process (group) id of pipeline */ - fprintf(out, "%d\n", ps->pid); + fprintf(out, "%d\n", ps->ps_pid); return; } @@ -3938,7 +3905,7 @@ showjob(FILE *out, struct job *jp, int mode) s[col - 3] = '-'; if (mode & SHOW_PIDS) - col += fmtstr(s + col, 16, "%d ", ps->pid); + col += fmtstr(s + col, 16, "%d ", ps->ps_pid); psend = ps + jp->nprocs; @@ -3946,7 +3913,7 @@ showjob(FILE *out, struct job *jp, int mode) strcpy(s + col, "Running"); col += sizeof("Running") - 1; } else { - int status = psend[-1].status; + int status = psend[-1].ps_status; if (jp->state == JOBSTOPPED) status = jp->stopstatus; col += sprint_status(s + col, status, 0); @@ -3962,20 +3929,20 @@ showjob(FILE *out, struct job *jp, int mode) * making it impossible to know 1st process status. */ goto start; - while (1) { + do { /* for each process */ s[0] = '\0'; col = 33; if (mode & SHOW_PIDS) - col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->pid) - 1; + col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1; start: - fprintf(out, "%s%*c", s, 33 - col >= 0 ? 33 - col : 0, ' '); - if (ps != jp->ps) - fprintf(out, "| "); - fprintf(out, "%s", ps->cmd); - if (++ps == psend) - break; - } + fprintf(out, "%s%*c%s%s", + s, + 33 - col >= 0 ? 33 - col : 0, ' ', + ps == jp->ps ? "" : "| ", + ps->ps_cmd + ); + } while (++ps != psend); outcslow('\n', out); jp->changed = 0; @@ -4026,20 +3993,31 @@ jobscmd(int argc UNUSED_PARAM, char **argv) do showjob(stdout, getjob(*argv, 0), mode); while (*++argv); - } else + } else { showjobs(stdout, mode); + } return 0; } #endif /* JOBS */ +/* Called only on finished or stopped jobs (no members are running) */ static int getstatus(struct job *job) { int status; int retval; + struct procstat *ps; + + /* Fetch last member's status */ + ps = job->ps + job->nprocs - 1; + status = ps->ps_status; + if (pipefail) { + /* "set -o pipefail" mode: use last _nonzero_ status */ + while (status == 0 && --ps >= job->ps) + status = ps->ps_status; + } - status = job->ps[job->nprocs - 1].status; retval = WEXITSTATUS(status); if (!WIFEXITED(status)) { #if JOBS @@ -4106,7 +4084,7 @@ waitcmd(int argc UNUSED_PARAM, char **argv) while (1) { if (!job) goto repeat; - if (job->ps[job->nprocs - 1].pid == pid) + if (job->ps[job->nprocs - 1].ps_pid == pid) break; job = job->prev_job; } @@ -4229,14 +4207,16 @@ cmdputs(const char *s) }; const char *p, *str; - char c, cc[2] = " "; + char cc[2]; char *nextc; - int subtype = 0; + unsigned char c; + unsigned char subtype = 0; int quoted = 0; + cc[1] = '\0'; nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc); p = s; - while ((c = *p++) != 0) { + while ((c = *p++) != '\0') { str = NULL; switch (c) { case CTLESC: @@ -4307,7 +4287,8 @@ cmdputs(const char *s) while ((c = *str++) != '\0') { USTPUTC(c, nextc); } - } + } /* while *p++ not NUL */ + if (quoted & 1) { USTPUTC('"', nextc); } @@ -4523,9 +4504,11 @@ clear_traps(void) for (tp = trap; tp < &trap[NSIG]; tp++) { if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */ INT_OFF; - free(*tp); + if (trap_ptr == trap) + free(*tp); + /* else: it "belongs" to trap_ptr vector, don't free */ *tp = NULL; - if (tp != &trap[0]) + if ((tp - trap) != 0) setsignal(tp - trap); INT_ON; } @@ -4536,10 +4519,7 @@ clear_traps(void) static void closescript(void); /* Called after fork(), in child */ -#if !JOBS -# define forkchild(jp, n, mode) forkchild(jp, mode) -#endif -static void +static NOINLINE void forkchild(struct job *jp, union node *n, int mode) { int oldlvl; @@ -4553,6 +4533,53 @@ forkchild(struct job *jp, union node *n, int mode) * Do we do it correctly? */ closescript(); + + if (mode == FORK_NOJOB /* is it `xxx` ? */ + && n && n->type == NCMD /* is it single cmd? */ + /* && n->ncmd.args->type == NARG - always true? */ + && strcmp(n->ncmd.args->narg.text, "trap") == 0 + && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */ + /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */ + ) { + TRACE(("Trap hack\n")); + /* Awful hack for `trap` or $(trap). + * + * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html + * contains an example where "trap" is executed in a subshell: + * + * save_traps=$(trap) + * ... + * eval "$save_traps" + * + * Standard does not say that "trap" in subshell shall print + * parent shell's traps. It only says that its output + * must have suitable form, but then, in the above example + * (which is not supposed to be normative), it implies that. + * + * bash (and probably other shell) does implement it + * (traps are reset to defaults, but "trap" still shows them), + * but as a result, "trap" logic is hopelessly messed up: + * + * # trap + * trap -- 'echo Ho' SIGWINCH <--- we have a handler + * # (trap) <--- trap is in subshell - no output (correct, traps are reset) + * # true | trap <--- trap is in subshell - no output (ditto) + * # echo `true | trap` <--- in subshell - output (but traps are reset!) + * trap -- 'echo Ho' SIGWINCH + * # echo `(trap)` <--- in subshell in subshell - output + * trap -- 'echo Ho' SIGWINCH + * # echo `true | (trap)` <--- in subshell in subshell in subshell - output! + * trap -- 'echo Ho' SIGWINCH + * + * The rules when to forget and when to not forget traps + * get really complex and nonsensical. + * + * Our solution: ONLY bare $(trap) or `trap` is special. + */ + /* Save trap handler strings for trap builtin to print */ + trap_ptr = memcpy(xmalloc(sizeof(trap)), trap, sizeof(trap)); + /* Fall through into clearing traps */ + } clear_traps(); #if JOBS /* do job control only in root shell */ @@ -4563,7 +4590,7 @@ forkchild(struct job *jp, union node *n, int mode) if (jp->nprocs == 0) pgrp = getpid(); else - pgrp = jp->ps[0].pid; + pgrp = jp->ps[0].ps_pid; /* this can fail because we are doing it in the parent also */ setpgid(0, pgrp); if (mode == FORK_FG) @@ -4597,8 +4624,14 @@ forkchild(struct job *jp, union node *n, int mode) setsignal(SIGQUIT); } #if JOBS - if (n && n->type == NCMD && strcmp(n->ncmd.args->narg.text, "jobs") == 0) { + if (n && n->type == NCMD + && strcmp(n->ncmd.args->narg.text, "jobs") == 0 + ) { TRACE(("Job hack\n")); + /* "jobs": we do not want to clear job list for it, + * instead we remove only _its_ own_ job from job list. + * This makes "jobs .... | cat" more useful. + */ freejob(curjob); return; } @@ -4629,7 +4662,7 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) if (jp->nprocs == 0) pgrp = pid; else - pgrp = jp->ps[0].pid; + pgrp = jp->ps[0].ps_pid; /* This can fail because we are doing it in the child also */ setpgid(pid, pgrp); } @@ -4640,12 +4673,12 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid) } if (jp) { struct procstat *ps = &jp->ps[jp->nprocs++]; - ps->pid = pid; - ps->status = -1; - ps->cmd = nullstr; + ps->ps_pid = pid; + ps->ps_status = -1; + ps->ps_cmd = nullstr; #if JOBS if (doing_jobctl && n) - ps->cmd = commandtext(n); + ps->ps_cmd = commandtext(n); #endif } } @@ -4663,10 +4696,12 @@ forkshell(struct job *jp, union node *n, int mode) freejob(jp); ash_msg_and_raise_error("can't fork"); } - if (pid == 0) + if (pid == 0) { + CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */ forkchild(jp, n, mode); - else + } else { forkparent(jp, n, mode, pid); + } return pid; } @@ -4991,7 +5026,7 @@ struct redirtab { struct redirtab *next; int nullredirs; int pair_count; - struct two_fd_t two_fd[0]; + struct two_fd_t two_fd[]; }; #define redirlist (G_var.redirlist) @@ -5070,7 +5105,7 @@ redirect(union node *redir, int flags) do { sv_pos++; #if ENABLE_ASH_BASH_COMPAT - if (redir->nfile.type == NTO2) + if (tmp->nfile.type == NTO2) sv_pos++; #endif tmp = tmp->nfile.next; @@ -5402,7 +5437,7 @@ rmescapes(char *str, int flag) globbing = flag & RMESCAPE_GLOB; protect_against_glob = globbing; while (*p) { - if (*p == CTLQUOTEMARK) { + if ((unsigned char)*p == CTLQUOTEMARK) { // TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0 // (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok? // Note: both inquotes and protect_against_glob only affect whether @@ -5417,7 +5452,7 @@ rmescapes(char *str, int flag) protect_against_glob = 0; goto copy; } - if (*p == CTLESC) { + if ((unsigned char)*p == CTLESC) { p++; if (protect_against_glob && inquotes && *p != '/') { *q++ = '\\'; @@ -5462,8 +5497,8 @@ memtodest(const char *p, size_t len, int syntax, int quotes) q = makestrspace(quotes ? len * 2 : len, q); while (len--) { - int c = signed_char2int(*p++); - if (!c) + unsigned char c = *p++; + if (c == '\0') continue; if (quotes) { int n = SIT(c, syntax); @@ -5548,7 +5583,7 @@ removerecordregions(int endoff) static char * exptilde(char *startp, char *p, int flags) { - char c; + unsigned char c; char *name; struct passwd *pw; const char *home; @@ -5743,7 +5778,7 @@ expari(int quotes) do { int esc; - while (*p != CTLARI) { + while ((unsigned char)*p != CTLARI) { p--; #if DEBUG if (p < start) { @@ -5805,10 +5840,9 @@ argstr(char *p, int flags, struct strlist *var_str_list) #if ENABLE_SH_MATH_SUPPORT CTLENDARI, #endif - 0 + '\0' }; const char *reject = spclchars; - int c; int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */ int breakall = flags & EXP_WORD; int inquotes; @@ -5836,8 +5870,10 @@ argstr(char *p, int flags, struct strlist *var_str_list) start: startloc = expdest - (char *)stackblock(); for (;;) { + unsigned char c; + length += strcspn(p + length, reject); - c = (unsigned char) p[length]; + c = p[length]; if (c) { if (!(c & 0x80) #if ENABLE_SH_MATH_SUPPORT @@ -5992,7 +6028,7 @@ scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int *loc2 = c; if (match) // if (!match) return loc; - if (quotes && *loc == CTLESC) + if (quotes && (unsigned char)*loc == CTLESC) loc++; loc++; loc2++; @@ -6044,7 +6080,7 @@ varunset(const char *end, const char *var, const char *umsg, int varflags) tail = nullstr; msg = "parameter not set"; if (umsg) { - if (*end == CTLENDVAR) { + if ((unsigned char)*end == CTLENDVAR) { if (varflags & VSNUL) tail = " or null"; } else { @@ -6128,7 +6164,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, /* Adjust the length by the number of escapes */ for (ptr = startp; ptr < (str - 1); ptr++) { - if (*ptr == CTLESC) { + if ((unsigned char)*ptr == CTLESC) { len--; ptr++; } @@ -6162,11 +6198,11 @@ subevalvar(char *p, char *str, int strloc, int subtype, len = orig_len - pos; for (str = startp; pos; str++, pos--) { - if (quotes && *str == CTLESC) + if (quotes && (unsigned char)*str == CTLESC) str++; } for (loc = startp; len; len--) { - if (quotes && *str == CTLESC) + if (quotes && (unsigned char)*str == CTLESC) *loc++ = *str++; *loc++ = *str++; } @@ -6230,7 +6266,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, /* No match, advance */ restart_detect = stackblock(); STPUTC(*idx, expdest); - if (quotes && *idx == CTLESC) { + if (quotes && (unsigned char)*idx == CTLESC) { idx++; len++; STPUTC(*idx, expdest); @@ -6245,7 +6281,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, if (subtype == VSREPLACEALL) { while (idx < loc) { - if (quotes && *idx == CTLESC) + if (quotes && (unsigned char)*idx == CTLESC) idx++; idx++; rmesc++; @@ -6313,26 +6349,30 @@ subevalvar(char *p, char *str, int strloc, int subtype, /* * Add the value of a specialized variable to the stack string. - */ -static ssize_t + * name parameter (examples): + * ash -c 'echo $1' name:'1=' + * ash -c 'echo $qwe' name:'qwe=' + * ash -c 'echo $$' name:'$=' + * ash -c 'echo ${$}' name:'$=' + * ash -c 'echo ${$##q}' name:'$=q' + * ash -c 'echo ${#$}' name:'$=' + * note: examples with bad shell syntax: + * ash -c 'echo ${#$1}' name:'$=1' + * ash -c 'echo ${#1#}' name:'1=#' + */ +static NOINLINE ssize_t varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) { - int num; const char *p; + int num; int i; - int sep = 0; int sepq = 0; ssize_t len = 0; - char **ap; - int syntax; - int quoted = varflags & VSQUOTE; int subtype = varflags & VSTYPE; int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); + int quoted = varflags & VSQUOTE; + int syntax = quoted ? DQSYNTAX : BASESYNTAX; - if (quoted && (flags & EXP_FULL)) - sep = 1 << CHAR_BIT; - - syntax = quoted ? DQSYNTAX : BASESYNTAX; switch (*name) { case '$': num = rootpid; @@ -6349,7 +6389,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) return -1; numvar: len = cvtnum(num); - break; + goto check_1char_name; case '-': expdest = makestrspace(NOPTS, expdest); for (i = NOPTS - 1; i >= 0; i--) { @@ -6358,14 +6398,27 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) len++; } } + check_1char_name: +#if 0 + /* handles cases similar to ${#$1} */ + if (name[2] != '\0') + raise_error_syntax("bad substitution"); +#endif break; - case '@': - if (sep) + case '@': { + char **ap; + int sep; + + if (quoted && (flags & EXP_FULL)) { + /* note: this is not meant as PEOF value */ + sep = 1 << CHAR_BIT; goto param; + } /* fall through */ case '*': - sep = ifsset() ? signed_char2int(ifsval()[0]) : ' '; - if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK)) + sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' '; + i = SIT(sep, syntax); + if (quotes && (i == CCTL || i == CBACK)) sepq = 1; param: ap = shellparam.p; @@ -6390,11 +6443,14 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) q = expdest; if (sepq) STPUTC(CTLESC, q); + /* note: may put NUL despite sep != 0 + * (see sep = 1 << CHAR_BIT above) */ STPUTC(sep, q); expdest = q; } } return len; + } /* case '@' and '*' */ case '0': case '1': case '2': @@ -6426,7 +6482,8 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) break; eq++; if (name_len == (unsigned)(eq - str) - && strncmp(str, name, name_len) == 0) { + && strncmp(str, name, name_len) == 0 + ) { p = eq; /* goto value; - WRONG! */ /* think "A=1 A=2 B=$A" */ @@ -6582,7 +6639,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) if (subtype != VSNORMAL) { /* skip to end of alternative */ int nesting = 1; for (;;) { - char c = *p++; + unsigned char c = *p++; if (c == CTLESC) p++; else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { @@ -6630,7 +6687,7 @@ ifsbreakup(char *string, struct arglist *arglist) ifsspc = 0; while (p < string + ifsp->endoff) { q = p; - if (*p == CTLESC) + if ((unsigned char)*p == CTLESC) p++; if (!strchr(ifs, *p)) { p++; @@ -6656,7 +6713,7 @@ ifsbreakup(char *string, struct arglist *arglist) break; } q = p; - if (*p == CTLESC) + if ((unsigned char)*p == CTLESC) p++; if (strchr(ifs, *p) == NULL) { p = q; @@ -7640,7 +7697,7 @@ describe_command(char *command, int describe_command_verbose) return 127; } out: - outstr("\n", stdout); + out1str("\n"); return 0; } @@ -7703,7 +7760,7 @@ static char *funcstring; /* block to allocate strings from */ #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ #define EV_BACKCMD 04 /* command executing within back quotes */ -static const short nodesize[N_NUMBER] = { +static const uint8_t nodesize[N_NUMBER] = { [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)), [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)), @@ -8102,7 +8159,7 @@ evaltree(union node *n, int flags) default: #if DEBUG out1fmt("Node type = %d\n", n->type); - fflush(stdout); + fflush_all(); break; #endif case NNOT: @@ -8481,12 +8538,13 @@ setinteractive(int on) static smallint did_banner; if (!did_banner) { - out1fmt( - "\n\n" - "%s built-in shell (ash)\n" + /* note: ash and hush share this string */ + out1fmt("\n\n%s %s\n" "Enter 'help' for a list of built-in commands." "\n\n", - bb_banner); + bb_banner, + "built-in shell (ash)" + ); did_banner = 1; } } @@ -9018,7 +9076,7 @@ evalcommand(union node *cmd, int flags) for (;;) { find_command(argv[0], &cmdentry, cmd_flag, path); if (cmdentry.cmdtype == CMDUNKNOWN) { - flush_stderr(); + flush_stdout_stderr(); status = 127; goto bail; } @@ -9382,12 +9440,6 @@ preadfd(void) */ //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__) #define pgetc_debug(...) ((void)0) -/* - * NB: due to SIT(c) internals (syntax_index_table[] vector), - * pgetc() and related functions must return chars SIGN-EXTENDED into ints, - * not zero-extended. Seems fragile to me. Affects only !USE_SIT_FUNCTION case, - * so we can fix it by ditching !USE_SIT_FUNCTION if Unicode requires that. - */ static int preadbuffer(void) { @@ -9488,12 +9540,12 @@ preadbuffer(void) g_parsefile->left_in_line, g_parsefile->next_to_pgetc, g_parsefile->next_to_pgetc); - return signed_char2int(*g_parsefile->next_to_pgetc++); + return (unsigned char)*g_parsefile->next_to_pgetc++; } #define pgetc_as_macro() \ (--g_parsefile->left_in_line >= 0 \ - ? signed_char2int(*g_parsefile->next_to_pgetc++) \ + ? (unsigned char)*g_parsefile->next_to_pgetc++ \ : preadbuffer() \ ) @@ -9508,17 +9560,14 @@ pgetc(void) } #if ENABLE_ASH_OPTIMIZE_FOR_SIZE -#define pgetc_fast() pgetc() +# define pgetc_fast() pgetc() #else -#define pgetc_fast() pgetc_as_macro() +# define pgetc_fast() pgetc_as_macro() #endif -/* - * Same as pgetc(), but ignores PEOA. - */ #if ENABLE_ASH_ALIAS static int -pgetc2(void) +pgetc_without_PEOA(void) { int c; do { @@ -9531,7 +9580,7 @@ pgetc2(void) return c; } #else -#define pgetc2() pgetc() +# define pgetc_without_PEOA() pgetc() #endif /* @@ -9545,7 +9594,7 @@ pfgets(char *line, int len) int c; while (--nleft > 0) { - c = pgetc2(); + c = pgetc_without_PEOA(); if (c == PEOF) { if (p == line) return NULL; @@ -10000,34 +10049,18 @@ setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) static void FAST_FUNC change_random(const char *value) { - /* Galois LFSR parameter */ - /* Taps at 32 31 29 1: */ - enum { MASK = 0x8000000b }; - /* Another example - taps at 32 31 30 10: */ - /* MASK = 0x00400007 */ + uint32_t t; if (value == NULL) { /* "get", generate */ - uint32_t t; - - /* LCG has period of 2^32 and alternating lowest bit */ - random_LCG = 1664525 * random_LCG + 1013904223; - /* Galois LFSR has period of 2^32-1 = 3 * 5 * 17 * 257 * 65537 */ - t = (random_galois_LFSR << 1); - if (random_galois_LFSR < 0) /* if we just shifted 1 out of msb... */ - t ^= MASK; - random_galois_LFSR = t; - /* Both are weak, combining them gives better randomness - * and ~2^64 period. & 0x7fff is probably bash compat - * for $RANDOM range. Combining with subtraction is - * just for fun. + and ^ would work equally well. */ - t = (t - random_LCG) & 0x7fff; + t = next_random(&random_gen); /* set without recursion */ setvar(vrandom.text, utoa(t), VNOFUNC); vrandom.flags &= ~VNOFUNC; } else { /* set/reset */ - random_galois_LFSR = random_LCG = strtoul(value, (char **)NULL, 10); + t = strtoul(value, NULL, 10); + INIT_RANDOM_T(&random_gen, (t ? t : 1), t); } } #endif @@ -10379,16 +10412,14 @@ fixredir(union node *n, const char *text, int err) static int noexpand(const char *text) { - const char *p; - char c; + unsigned char c; - p = text; - while ((c = *p++) != '\0') { + while ((c = *text++) != '\0') { if (c == CTLQUOTEMARK) continue; if (c == CTLESC) - p++; - else if (SIT((signed char)c, BASESYNTAX) == CCTL) + text++; + else if (SIT(c, BASESYNTAX) == CCTL) return 0; } return 1; @@ -10773,7 +10804,7 @@ static int decode_dollar_squote(void) * If eofmark is NULL, read a word or a redirection symbol. If eofmark * is not NULL, read a here document. In the latter case, eofmark is the * word which marks the end of the document and striptabs is true if - * leading tabs should be stripped from the document. The argument firstc + * leading tabs should be stripped from the document. The argument c * is the first character of the input token or document. * * Because C does not have internal subroutines, I have simulated them @@ -10787,10 +10818,10 @@ static int decode_dollar_squote(void) #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} #define PARSEARITH() {goto parsearith; parsearith_return:;} static int -readtoken1(int firstc, int syntax, char *eofmark, int striptabs) +readtoken1(int c, int syntax, char *eofmark, int striptabs) { /* NB: syntax parameter fits into smallint */ - int c = firstc; + /* c parameter is an unsigned char or PEOF or PEOA */ char *out; int len; char line[EOFMARKLEN + 1]; @@ -10873,7 +10904,7 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs) USTPUTC(c, out); break; case CBACK: /* backslash */ - c = pgetc2(); + c = pgetc_without_PEOA(); if (c == PEOF) { USTPUTC(CTLESC, out); USTPUTC('\\', out); @@ -10987,9 +11018,7 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs) #endif goto endword; /* exit outer loop */ } -#if ENABLE_ASH_ALIAS - if (c != PEOA) -#endif + IF_ASH_ALIAS(if (c != PEOA)) USTPUTC(c, out); } @@ -11041,13 +11070,12 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs) checkend: { if (eofmark) { #if ENABLE_ASH_ALIAS - if (c == PEOA) { - c = pgetc2(); - } + if (c == PEOA) + c = pgetc_without_PEOA(); #endif if (striptabs) { while (c == '\t') { - c = pgetc2(); + c = pgetc_without_PEOA(); } } if (c == *eofmark) { @@ -11155,14 +11183,14 @@ parseredir: { (((unsigned)(c) - 33 < 32) \ && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1)) parsesub: { - int subtype; + unsigned char subtype; int typeloc; int flags; char *p; static const char types[] ALIGN1 = "}-+?="; c = pgetc(); - if (c <= PEOA_OR_PEOF + if (c > 255 /* PEOA or PEOF */ || (c != '(' && c != '{' && !is_name(c) && !is_special(c)) ) { #if ENABLE_ASH_BASH_COMPAT @@ -11199,11 +11227,11 @@ parsesub: { } else subtype = 0; } - if (c > PEOA_OR_PEOF && is_name(c)) { + if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) { do { STPUTC(c, out); c = pgetc(); - } while (c > PEOA_OR_PEOF && is_in_name(c)); + } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c)); } else if (isdigit(c)) { do { STPUTC(c, out); @@ -11216,6 +11244,8 @@ parsesub: { badsub: raise_error_syntax("bad substitution"); } + if (c != '}' && subtype == VSLENGTH) + goto badsub; STPUTC('=', out); flags = 0; @@ -11265,7 +11295,7 @@ parsesub: { } if (dblquote || arinest) flags |= VSQUOTE; - *((char *)stackblock() + typeloc) = subtype | flags; + ((unsigned char *)stackblock())[typeloc] = subtype | flags; if (subtype != VSNORMAL) { varnest++; if (dblquote || arinest) { @@ -11347,17 +11377,17 @@ parsebackq: { continue; } if (pc != '\\' && pc != '`' && pc != '$' - && (!dblquote || pc != '"')) + && (!dblquote || pc != '"') + ) { STPUTC('\\', pout); - if (pc > PEOA_OR_PEOF) { + } + if (pc <= 255 /* not PEOA or PEOF */) { break; } /* fall through */ case PEOF: -#if ENABLE_ASH_ALIAS - case PEOA: -#endif + IF_ASH_ALIAS(case PEOA:) startlinno = g_parsefile->linno; raise_error_syntax("EOF in backquote substitution"); @@ -11574,9 +11604,7 @@ xxreadtoken(void) c = pgetc_fast(); switch (c) { case ' ': case '\t': -#if ENABLE_ASH_ALIAS - case PEOA: -#endif + IF_ASH_ALIAS(case PEOA:) continue; case '#': while ((c = pgetc()) != '\n' && c != PEOF) @@ -11838,8 +11866,9 @@ evalcmd(int argc UNUSED_PARAM, char **argv) } /* - * Read and execute commands. "Top" is nonzero for the top level command - * loop; it turns on prompting if the shell is interactive. + * Read and execute commands. + * "Top" is nonzero for the top level command loop; + * it turns on prompting if the shell is interactive. */ static int cmdloop(int top) @@ -12207,14 +12236,30 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) ap = argptr; if (!*ap) { for (signo = 0; signo < NSIG; signo++) { - if (trap[signo] != NULL) { + char *tr = trap_ptr[signo]; + if (tr) { + /* note: bash adds "SIG", but only if invoked + * as "bash". If called as "sh", or if set -o posix, + * then it prints short signal names. + * We are printing short names: */ out1fmt("trap -- %s %s\n", - single_quote(trap[signo]), + single_quote(tr), get_signame(signo)); + /* trap_ptr != trap only if we are in special-cased `trap` code. + * In this case, we will exit very soon, no need to free(). */ + /* if (trap_ptr != trap && tp[0]) */ + /* free(tr); */ } } + /* + if (trap_ptr != trap) { + free(trap_ptr); + trap_ptr = trap; + } + */ return 0; } + action = NULL; if (ap[1]) action = *ap++; @@ -12448,211 +12493,53 @@ typedef enum __rlimit_resource rlim_t; static int FAST_FUNC readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) { - static const char *const arg_REPLY[] = { "REPLY", NULL }; - - char **ap; - int backslash; - char c; - int rflag; - char *prompt; - const char *ifs; - char *p; - int startword; - int status; + char *opt_n = NULL; + char *opt_p = NULL; + char *opt_t = NULL; + char *opt_u = NULL; + int read_flags = 0; + const char *r; int i; - int fd = 0; -#if ENABLE_ASH_READ_NCHARS - int nchars = 0; /* if != 0, -n is in effect */ - int silent = 0; - struct termios tty, old_tty; -#endif -#if ENABLE_ASH_READ_TIMEOUT - unsigned end_ms = 0; - unsigned timeout = 0; -#endif - - rflag = 0; - prompt = NULL; - while ((i = nextopt("p:u:r" - IF_ASH_READ_TIMEOUT("t:") - IF_ASH_READ_NCHARS("n:s") - )) != '\0') { + + while ((i = nextopt("p:u:rt:n:s")) != '\0') { switch (i) { case 'p': - prompt = optionarg; + opt_p = optionarg; break; -#if ENABLE_ASH_READ_NCHARS case 'n': - nchars = bb_strtou(optionarg, NULL, 10); - if (nchars < 0 || errno) - ash_msg_and_raise_error("invalid count"); - /* nchars == 0: off (bash 3.2 does this too) */ + opt_n = optionarg; break; case 's': - silent = 1; + read_flags |= BUILTIN_READ_SILENT; break; -#endif -#if ENABLE_ASH_READ_TIMEOUT case 't': - timeout = bb_strtou(optionarg, NULL, 10); - if (errno || timeout > UINT_MAX / 2048) - ash_msg_and_raise_error("invalid timeout"); - timeout *= 1000; -#if 0 /* even bash have no -t N.NNN support */ - ts.tv_sec = bb_strtou(optionarg, &p, 10); - ts.tv_usec = 0; - /* EINVAL means number is ok, but not terminated by NUL */ - if (*p == '.' && errno == EINVAL) { - char *p2; - if (*++p) { - int scale; - ts.tv_usec = bb_strtou(p, &p2, 10); - if (errno) - ash_msg_and_raise_error("invalid timeout"); - scale = p2 - p; - /* normalize to usec */ - if (scale > 6) - ash_msg_and_raise_error("invalid timeout"); - while (scale++ < 6) - ts.tv_usec *= 10; - } - } else if (ts.tv_sec < 0 || errno) { - ash_msg_and_raise_error("invalid timeout"); - } - if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */ - ash_msg_and_raise_error("invalid timeout"); - } -#endif /* if 0 */ + opt_t = optionarg; break; -#endif case 'r': - rflag = 1; + read_flags |= BUILTIN_READ_RAW; break; case 'u': - fd = bb_strtou(optionarg, NULL, 10); - if (fd < 0 || errno) - ash_msg_and_raise_error("invalid file descriptor"); + opt_u = optionarg; break; default: break; } } - if (prompt && isatty(fd)) { - out2str(prompt); - } - ap = argptr; - if (*ap == NULL) - ap = (char**)arg_REPLY; - ifs = bltinlookup("IFS"); - if (ifs == NULL) - ifs = defifs; -#if ENABLE_ASH_READ_NCHARS - tcgetattr(fd, &tty); - old_tty = tty; - if (nchars || silent) { - if (nchars) { - tty.c_lflag &= ~ICANON; - tty.c_cc[VMIN] = nchars < 256 ? nchars : 255; - } - if (silent) { - tty.c_lflag &= ~(ECHO | ECHOK | ECHONL); - } - /* if tcgetattr failed, tcsetattr will fail too. - * Ignoring, it's harmless. */ - tcsetattr(fd, TCSANOW, &tty); - } -#endif - status = 0; - startword = 2; - backslash = 0; -#if ENABLE_ASH_READ_TIMEOUT - if (timeout) /* NB: ensuring end_ms is nonzero */ - end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1; -#endif - STARTSTACKSTR(p); - do { - const char *is_ifs; - -#if ENABLE_ASH_READ_TIMEOUT - if (end_ms) { - struct pollfd pfd[1]; - pfd[0].fd = fd; - pfd[0].events = POLLIN; - timeout = end_ms - (unsigned)(monotonic_us() / 1000); - if ((int)timeout <= 0 /* already late? */ - || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */ - ) { /* timed out! */ -#if ENABLE_ASH_READ_NCHARS - tcsetattr(fd, TCSANOW, &old_tty); -#endif - return 1; - } - } -#endif - if (nonblock_safe_read(fd, &c, 1) != 1) { - status = 1; - break; - } - if (c == '\0') - continue; - if (backslash) { - backslash = 0; - if (c != '\n') - goto put; - continue; - } - if (!rflag && c == '\\') { - backslash = 1; - continue; - } - if (c == '\n') - break; - /* $IFS splitting */ -/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ - is_ifs = strchr(ifs, c); - if (startword && is_ifs) { - if (isspace(c)) - continue; - /* it is a non-space ifs char */ - startword--; - if (startword == 1) /* first one? */ - continue; /* yes, it is not next word yet */ - } - startword = 0; - if (ap[1] != NULL && is_ifs) { - const char *beg; - STACKSTRNUL(p); - beg = stackblock(); - setvar(*ap, beg, 0); - ap++; - /* can we skip one non-space ifs char? (2: yes) */ - startword = isspace(c) ? 2 : 1; - STARTSTACKSTR(p); - continue; - } - put: - STPUTC(c, p); - } -/* end of do {} while: */ -#if ENABLE_ASH_READ_NCHARS - while (--nchars); -#else - while (1); -#endif + r = builtin_read(setvar, + argptr, + bltinlookup("IFS"), /* can be NULL */ + read_flags, + opt_n, + opt_p, + opt_t, + opt_u + ); -#if ENABLE_ASH_READ_NCHARS - tcsetattr(fd, TCSANOW, &old_tty); -#endif + if ((uintptr_t)r > 1) + ash_msg_and_raise_error(r); - STACKSTRNUL(p); - /* Remove trailing space ifs chars */ - while ((char *)stackblock() <= --p && isspace(*p) && strchr(ifs, *p) != NULL) - *p = '\0'; - setvar(*ap, stackblock(), 0); - while (*++ap != NULL) - setvar(*ap, nullstr, 0); - return status; + return (uintptr_t)r; } static int FAST_FUNC @@ -12834,8 +12721,7 @@ printlim(enum limtype how, const struct rlimit *limit, static int FAST_FUNC ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) { - int c; - rlim_t val = 0; + rlim_t val; enum limtype how = SOFT | HARD; const struct limits *l; int set, all = 0; @@ -12896,6 +12782,7 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) continue; set = *argptr ? 1 : 0; + val = 0; if (set) { char *p = *argptr; @@ -12904,15 +12791,13 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) if (strncmp(p, "unlimited\n", 9) == 0) val = RLIM_INFINITY; else { - val = (rlim_t) 0; - - while ((c = *p++) >= '0' && c <= '9') { - val = (val * 10) + (long)(c - '0'); - // val is actually 'unsigned long int' and can't get < 0 - if (val < (rlim_t) 0) - break; - } - if (c) + if (sizeof(val) == sizeof(int)) + val = bb_strtou(p, NULL, 10); + else if (sizeof(val) == sizeof(long)) + val = bb_strtoul(p, NULL, 10); + else + val = bb_strtoull(p, NULL, 10); + if (errno) ash_msg_and_raise_error("bad number"); val <<= l->factor_shift; } @@ -12971,6 +12856,7 @@ exitshell(void) if (p) { trap[0] = NULL; evalstring(p, 0); + free(p); } flush_stdout_stderr(); out: @@ -12987,11 +12873,14 @@ init(void) /* from trap.c: */ signal(SIGCHLD, SIG_DFL); + /* bash re-enables SIGHUP which is SIG_IGNed on entry. + * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" + */ + signal(SIGHUP, SIG_DFL); /* from var.c: */ { char **envp; - char ppid[sizeof(int)*3 + 2]; const char *p; struct stat st1, st2; @@ -13002,8 +12891,7 @@ init(void) } } - sprintf(ppid, "%u", (unsigned) getppid()); - setvar("PPID", ppid, 0); + setvar("PPID", utoa(getppid()), 0); p = lookupvar("PWD"); if (p) @@ -13184,11 +13072,6 @@ int ash_main(int argc UNUSED_PARAM, char **argv) #endif rootpid = getpid(); -#if ENABLE_ASH_RANDOM_SUPPORT - /* Can use monotonic_ns() for better randomness but for now it is - * not used anywhere else in busybox... so avoid bloat */ - random_galois_LFSR = random_LCG = rootpid + monotonic_us(); -#endif init(); setstackmark(&smark); procargs(argv); @@ -13242,7 +13125,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) } if (sflag || minusc == NULL) { -#if ENABLE_FEATURE_EDITING_SAVEHISTORY +#if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY if (iflag) { const char *hp = lookupvar("HISTFILE"); if (hp)