1 /* vi: set sw=4 ts=4: */
3 * ash shell port for busybox
5 * Copyright (c) 1989, 1991, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
8 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
9 * was re-ported from NetBSD and debianized.
12 * This code is derived from software contributed to Berkeley by
15 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
17 * Original BSD copyright notice is retained at the end of this file.
21 * rewrite arith.y to micro stack based cryptic algorithm by
22 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
24 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
27 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be
28 * used in busybox and size optimizations,
29 * rewrote arith (see notes to this), added locale support,
30 * rewrote dynamic variables.
35 * The follow should be set to reflect the type of system you have:
36 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
37 * define SYSV if you are running under System V.
38 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
39 * define DEBUG=2 to compile in and turn on debugging.
41 * When debugging is on, debugging info will be written to ./trace and
42 * a quit signal will generate a core dump.
47 #if ENABLE_ASH_JOB_CONTROL
58 #include "busybox.h" /* for applet_names */
62 #if JOBS || ENABLE_ASH_READ_NCHARS
66 #if defined(__uClinux__)
67 #error "Do not even bother, ash will not run on uClinux"
71 /* ============ Hash table sizes. Configurable. */
75 #define CMDTABLESIZE 31 /* should be prime */
78 /* ============ Misc helpers */
80 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
82 /* C99 say: "char" declaration may be signed or unsigned default */
83 #define signed_char2int(sc) ((int)((signed char)sc))
86 /* ============ Shell options */
88 static const char *const optletters_optnames[] = {
109 #define optletters(n) optletters_optnames[(n)][0]
110 #define optnames(n) (&optletters_optnames[(n)][1])
112 enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
114 static char optlist[NOPTS] ALIGN1;
116 #define eflag optlist[0]
117 #define fflag optlist[1]
118 #define Iflag optlist[2]
119 #define iflag optlist[3]
120 #define mflag optlist[4]
121 #define nflag optlist[5]
122 #define sflag optlist[6]
123 #define xflag optlist[7]
124 #define vflag optlist[8]
125 #define Cflag optlist[9]
126 #define aflag optlist[10]
127 #define bflag optlist[11]
128 #define uflag optlist[12]
129 #define viflag optlist[13]
131 #define nolog optlist[14]
132 #define debug optlist[15]
136 /* ============ Misc data */
138 static const char homestr[] ALIGN1 = "HOME";
139 static const char snlfmt[] ALIGN1 = "%s\n";
140 static const char illnum[] ALIGN1 = "Illegal number: %s";
143 * We enclose jmp_buf in a structure so that we can declare pointers to
144 * jump locations. The global variable handler contains the location to
145 * jump to when an exception occurs, and the global variable exception
146 * contains a code identifying the exception. To implement nested
147 * exception handlers, the user should save the value of handler on entry
148 * to an inner scope, set handler to point to a jmploc structure for the
149 * inner scope, and restore handler on exit from the scope.
155 struct globals_misc {
156 /* pid of main shell */
158 /* shell level: 0 for the main shell, 1 for its children, and so on */
160 #define rootshell (!shlvl)
161 char *minusc; /* argument to -c option */
163 char *curdir; // = nullstr; /* current working directory */
164 char *physdir; // = nullstr; /* physical working directory */
166 char *arg0; /* value of $0 */
168 struct jmploc *exception_handler;
170 // disabled by vda: cannot understand how it was supposed to work -
171 // cannot fix bugs. That's why you have to explain your non-trivial designs!
172 // /* do we generate EXSIG events */
173 // int exsig; /* counter */
174 volatile int suppressint; /* counter */
175 volatile /*sig_atomic_t*/ smallint intpending; /* 1 = got SIGINT */
176 /* last pending signal */
177 volatile /*sig_atomic_t*/ smallint pendingsig;
178 smallint exception; /* kind of exception (0..5) */
180 #define EXINT 0 /* SIGINT received */
181 #define EXERROR 1 /* a generic error */
182 #define EXSHELLPROC 2 /* execute a shell procedure */
183 #define EXEXEC 3 /* command execution failed */
184 #define EXEXIT 4 /* exit the shell */
185 #define EXSIG 5 /* trapped signal in wait(1) */
187 /* trap handler commands */
190 char nullstr[1]; /* zero length string */
192 * Sigmode records the current value of the signal handlers for the various
193 * modes. A value of zero means that the current handler is not known.
194 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
196 char sigmode[NSIG - 1];
197 #define S_DFL 1 /* default signal handling (SIG_DFL) */
198 #define S_CATCH 2 /* signal is caught */
199 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
200 #define S_HARD_IGN 4 /* signal is ignored permenantly */
201 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
203 /* indicates specified signal received */
204 char gotsig[NSIG - 1];
206 /* Make it reside in writable memory, yet make compiler understand that it is not going to change. */
207 static struct globals_misc *const ptr_to_globals_misc __attribute__ ((section (".data")));
208 #define G_misc (*ptr_to_globals_misc)
209 #define rootpid (G_misc.rootpid )
210 #define shlvl (G_misc.shlvl )
211 #define minusc (G_misc.minusc )
212 #define curdir (G_misc.curdir )
213 #define physdir (G_misc.physdir )
214 #define arg0 (G_misc.arg0 )
215 #define exception_handler (G_misc.exception_handler)
216 #define exception (G_misc.exception )
217 #define suppressint (G_misc.suppressint )
218 #define intpending (G_misc.intpending )
219 //#define exsig (G_misc.exsig )
220 #define pendingsig (G_misc.pendingsig )
221 #define trap (G_misc.trap )
222 #define isloginsh (G_misc.isloginsh)
223 #define nullstr (G_misc.nullstr )
224 #define sigmode (G_misc.sigmode )
225 #define gotsig (G_misc.gotsig )
226 #define INIT_G_misc() do { \
227 (*(struct globals_misc**)&ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
233 /* ============ Interrupts / exceptions */
236 * These macros allow the user to suspend the handling of interrupt signals
237 * over a period of time. This is similar to SIGHOLD or to sigblock, but
238 * much more efficient and portable. (But hacking the kernel is so much
239 * more fun than worrying about efficiency and portability. :-))
248 * Called to raise an exception. Since C doesn't include exceptions, we
249 * just do a longjmp to the exception handler. The type of exception is
250 * stored in the global variable "exception".
252 static void raise_exception(int) ATTRIBUTE_NORETURN;
254 raise_exception(int e)
257 if (exception_handler == NULL)
262 longjmp(exception_handler->loc, 1);
266 * Called from trap.c when a SIGINT is received. (If the user specifies
267 * that SIGINT is to be trapped or ignored using the trap builtin, then
268 * this routine is not called.) Suppressint is nonzero when interrupts
269 * are held using the INT_OFF macro. (The test for iflag is just
270 * defensive programming.)
272 static void raise_interrupt(void) ATTRIBUTE_NORETURN;
274 raise_interrupt(void)
280 /* Signal is not automatically unmasked after it is raised,
281 * do it ourself - unmask all signals */
283 sigprocmask(SIG_SETMASK, &mask, NULL);
284 /* pendingsig = 0; - now done in onsig() */
287 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
288 if (!(rootshell && iflag)) {
289 /* Kill ourself with SIGINT */
290 signal(SIGINT, SIG_DFL);
299 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
303 if (--suppressint == 0 && intpending) {
307 #define INT_ON int_on()
315 #define FORCE_INT_ON force_int_on()
320 if (--suppressint == 0 && intpending) \
323 #define FORCE_INT_ON \
330 #endif /* ASH_OPTIMIZE_FOR_SIZE */
332 #define SAVE_INT(v) ((v) = suppressint)
334 #define RESTORE_INT(v) \
338 if (suppressint == 0 && intpending) \
343 * Ignore a signal. Only one usage site - in forkchild()
348 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
349 signal(signo, SIG_IGN);
351 sigmode[signo - 1] = S_HARD_IGN;
355 * Signal handler. Only one usage site - in setsignal()
360 gotsig[signo - 1] = 1;
363 if ( /* exsig || */ (signo == SIGINT && !trap[SIGINT])) {
366 raise_interrupt(); /* does not return */
373 /* ============ Stdout/stderr output */
376 outstr(const char *p, FILE *file)
384 flush_stdout_stderr(void)
401 outcslow(int c, FILE *dest)
409 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
411 out1fmt(const char *fmt, ...)
418 r = vprintf(fmt, ap);
424 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
426 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
433 ret = vsnprintf(outbuf, length, fmt, ap);
440 out1str(const char *p)
446 out2str(const char *p)
453 /* ============ Parser structures */
455 /* control characters in argument strings */
456 #define CTLESC '\201' /* escape next character */
457 #define CTLVAR '\202' /* variable defn */
458 #define CTLENDVAR '\203'
459 #define CTLBACKQ '\204'
460 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
461 /* CTLBACKQ | CTLQUOTE == '\205' */
462 #define CTLARI '\206' /* arithmetic expression */
463 #define CTLENDARI '\207'
464 #define CTLQUOTEMARK '\210'
466 /* variable substitution byte (follows CTLVAR) */
467 #define VSTYPE 0x0f /* type of variable substitution */
468 #define VSNUL 0x10 /* colon--treat the empty string as unset */
469 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
471 /* values of VSTYPE field */
472 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
473 #define VSMINUS 0x2 /* ${var-text} */
474 #define VSPLUS 0x3 /* ${var+text} */
475 #define VSQUESTION 0x4 /* ${var?message} */
476 #define VSASSIGN 0x5 /* ${var=text} */
477 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
478 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
479 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
480 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
481 #define VSLENGTH 0xa /* ${#var} */
483 static const char dolatstr[] ALIGN1 = {
484 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
520 union node *redirect;
526 struct nodelist *cmdlist;
532 union node *redirect;
545 union node *elsepart;
572 struct nodelist *backquote;
607 struct nredir nredir;
608 struct nbinary nbinary;
612 struct nclist nclist;
621 struct nodelist *next;
634 freefunc(struct funcnode *f)
636 if (f && --f->count < 0)
641 /* ============ Debugging output */
645 static FILE *tracefile;
648 trace_printf(const char *fmt, ...)
655 vfprintf(tracefile, fmt, va);
660 trace_vprintf(const char *fmt, va_list va)
664 vfprintf(tracefile, fmt, va);
668 trace_puts(const char *s)
676 trace_puts_quoted(char *s)
683 putc('"', tracefile);
684 for (p = s; *p; p++) {
686 case '\n': c = 'n'; goto backslash;
687 case '\t': c = 't'; goto backslash;
688 case '\r': c = 'r'; goto backslash;
689 case '"': c = '"'; goto backslash;
690 case '\\': c = '\\'; goto backslash;
691 case CTLESC: c = 'e'; goto backslash;
692 case CTLVAR: c = 'v'; goto backslash;
693 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
694 case CTLBACKQ: c = 'q'; goto backslash;
695 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
697 putc('\\', tracefile);
701 if (*p >= ' ' && *p <= '~')
704 putc('\\', tracefile);
705 putc(*p >> 6 & 03, tracefile);
706 putc(*p >> 3 & 07, tracefile);
707 putc(*p & 07, tracefile);
712 putc('"', tracefile);
716 trace_puts_args(char **ap)
723 trace_puts_quoted(*ap);
725 putc('\n', tracefile);
728 putc(' ', tracefile);
743 /* leave open because libedit might be using it */
746 strcpy(s, "./trace");
748 if (!freopen(s, "a", tracefile)) {
749 fprintf(stderr, "Can't re-open %s\n", s);
754 tracefile = fopen(s, "a");
755 if (tracefile == NULL) {
756 fprintf(stderr, "Can't open %s\n", s);
762 flags = fcntl(fileno(tracefile), F_GETFL);
764 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
766 setlinebuf(tracefile);
767 fputs("\nTracing started.\n", tracefile);
771 indent(int amount, char *pfx, FILE *fp)
775 for (i = 0; i < amount; i++) {
776 if (pfx && i == amount - 1)
782 /* little circular references here... */
783 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
786 sharg(union node *arg, FILE *fp)
789 struct nodelist *bqlist;
792 if (arg->type != NARG) {
793 out1fmt("<node type %d>\n", arg->type);
796 bqlist = arg->narg.backquote;
797 for (p = arg->narg.text; *p; p++) {
806 if (subtype == VSLENGTH)
815 switch (subtype & VSTYPE) {
848 out1fmt("<subtype %d>", subtype);
855 case CTLBACKQ|CTLQUOTE:
858 shtree(bqlist->n, -1, NULL, fp);
869 shcmd(union node *cmd, FILE *fp)
877 for (np = cmd->ncmd.args; np; np = np->narg.next) {
883 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
887 switch (np->nfile.type) {
888 case NTO: s = ">>"+1; dftfd = 1; break;
889 case NCLOBBER: s = ">|"; dftfd = 1; break;
890 case NAPPEND: s = ">>"; dftfd = 1; break;
891 case NTOFD: s = ">&"; dftfd = 1; break;
892 case NFROM: s = "<"; break;
893 case NFROMFD: s = "<&"; break;
894 case NFROMTO: s = "<>"; break;
895 default: s = "*error*"; break;
897 if (np->nfile.fd != dftfd)
898 fprintf(fp, "%d", np->nfile.fd);
900 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
901 fprintf(fp, "%d", np->ndup.dupfd);
903 sharg(np->nfile.fname, fp);
910 shtree(union node *n, int ind, char *pfx, FILE *fp)
918 indent(ind, pfx, fp);
929 shtree(n->nbinary.ch1, ind, NULL, fp);
932 shtree(n->nbinary.ch2, ind, NULL, fp);
940 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
945 if (n->npipe.backgnd)
951 fprintf(fp, "<node type %d>", n->type);
959 showtree(union node *n)
961 trace_puts("showtree called\n");
962 shtree(n, 1, NULL, stdout);
965 #define TRACE(param) trace_printf param
966 #define TRACEV(param) trace_vprintf param
971 #define TRACEV(param)
976 /* ============ Parser data */
979 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
982 struct strlist *next;
991 struct strpush *prev; /* preceding string on stack */
995 struct alias *ap; /* if push was associated with an alias */
997 char *string; /* remember the string since it may change */
1001 struct parsefile *prev; /* preceding file on stack */
1002 int linno; /* current line */
1003 int fd; /* file descriptor (or -1 if string) */
1004 int nleft; /* number of chars left in this line */
1005 int lleft; /* number of chars left in this buffer */
1006 char *nextc; /* next char in buffer */
1007 char *buf; /* input buffer */
1008 struct strpush *strpush; /* for pushing strings at this level */
1009 struct strpush basestrpush; /* so pushing one is fast */
1012 static struct parsefile basepf; /* top level input file */
1013 static struct parsefile *parsefile = &basepf; /* current input file */
1014 static int startlinno; /* line # where last token started */
1015 static char *commandname; /* currently executing command */
1016 static struct strlist *cmdenviron; /* environment for builtin command */
1017 static int exitstatus; /* exit status of last command */
1020 /* ============ Message printing */
1023 ash_vmsg(const char *msg, va_list ap)
1025 fprintf(stderr, "%s: ", arg0);
1027 if (strcmp(arg0, commandname))
1028 fprintf(stderr, "%s: ", commandname);
1029 if (!iflag || parsefile->fd)
1030 fprintf(stderr, "line %d: ", startlinno);
1032 vfprintf(stderr, msg, ap);
1033 outcslow('\n', stderr);
1037 * Exverror is called to raise the error exception. If the second argument
1038 * is not NULL then error prints an error message using printf style
1039 * formatting. It then raises the error exception.
1041 static void ash_vmsg_and_raise(int, const char *, va_list) ATTRIBUTE_NORETURN;
1043 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1047 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1049 TRACE(("\") pid=%d\n", getpid()));
1051 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1056 flush_stdout_stderr();
1057 raise_exception(cond);
1061 static void ash_msg_and_raise_error(const char *, ...) ATTRIBUTE_NORETURN;
1063 ash_msg_and_raise_error(const char *msg, ...)
1068 ash_vmsg_and_raise(EXERROR, msg, ap);
1073 static void ash_msg_and_raise(int, const char *, ...) ATTRIBUTE_NORETURN;
1075 ash_msg_and_raise(int cond, const char *msg, ...)
1080 ash_vmsg_and_raise(cond, msg, ap);
1086 * error/warning routines for external builtins
1089 ash_msg(const char *fmt, ...)
1099 * Return a string describing an error. The returned string may be a
1100 * pointer to a static buffer that will be overwritten on the next call.
1101 * Action describes the operation that got the error.
1104 errmsg(int e, const char *em)
1106 if (e == ENOENT || e == ENOTDIR) {
1113 /* ============ Memory allocation */
1116 * It appears that grabstackstr() will barf with such alignments
1117 * because stalloc() will return a string allocated in a new stackblock.
1119 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1121 /* Most machines require the value returned from malloc to be aligned
1122 * in some way. The following macro will get this right
1123 * on many machines. */
1124 SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,
1125 /* Minimum size of a block */
1126 MINSIZE = SHELL_ALIGN(504),
1129 struct stack_block {
1130 struct stack_block *prev;
1131 char space[MINSIZE];
1135 struct stack_block *stackp;
1138 struct stackmark *marknext;
1142 struct globals_memstack {
1143 struct stack_block *g_stackp; // = &stackbase;
1144 struct stackmark *markp;
1145 char *g_stacknxt; // = stackbase.space;
1146 char *sstrend; // = stackbase.space + MINSIZE;
1147 size_t g_stacknleft; // = MINSIZE;
1148 int herefd; // = -1;
1149 struct stack_block stackbase;
1151 /* Make it reside in writable memory, yet make compiler understand that it is not going to change. */
1152 static struct globals_memstack *const ptr_to_globals_memstack __attribute__ ((section (".data")));
1153 #define G_memstack (*ptr_to_globals_memstack)
1154 #define g_stackp (G_memstack.g_stackp )
1155 #define markp (G_memstack.markp )
1156 #define g_stacknxt (G_memstack.g_stacknxt )
1157 #define sstrend (G_memstack.sstrend )
1158 #define g_stacknleft (G_memstack.g_stacknleft)
1159 #define herefd (G_memstack.herefd )
1160 #define stackbase (G_memstack.stackbase )
1161 #define INIT_G_memstack() do { \
1162 (*(struct globals_memstack**)&ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1163 g_stackp = &stackbase; \
1164 g_stacknxt = stackbase.space; \
1165 g_stacknleft = MINSIZE; \
1166 sstrend = stackbase.space + MINSIZE; \
1170 #define stackblock() ((void *)g_stacknxt)
1171 #define stackblocksize() g_stacknleft
1175 ckrealloc(void * p, size_t nbytes)
1177 p = realloc(p, nbytes);
1179 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1184 ckmalloc(size_t nbytes)
1186 return ckrealloc(NULL, nbytes);
1190 * Make a copy of a string in safe storage.
1193 ckstrdup(const char *s)
1195 char *p = strdup(s);
1197 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1202 * Parse trees for commands are allocated in lifo order, so we use a stack
1203 * to make this more efficient, and also to avoid all sorts of exception
1204 * handling code to handle interrupts in the middle of a parse.
1206 * The size 504 was chosen because the Ultrix malloc handles that size
1210 stalloc(size_t nbytes)
1215 aligned = SHELL_ALIGN(nbytes);
1216 if (aligned > g_stacknleft) {
1219 struct stack_block *sp;
1221 blocksize = aligned;
1222 if (blocksize < MINSIZE)
1223 blocksize = MINSIZE;
1224 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1225 if (len < blocksize)
1226 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1229 sp->prev = g_stackp;
1230 g_stacknxt = sp->space;
1231 g_stacknleft = blocksize;
1232 sstrend = g_stacknxt + blocksize;
1237 g_stacknxt += aligned;
1238 g_stacknleft -= aligned;
1246 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1247 write(2, "stunalloc\n", 10);
1251 g_stacknleft += g_stacknxt - (char *)p;
1256 * Like strdup but works with the ash stack.
1259 ststrdup(const char *p)
1261 size_t len = strlen(p) + 1;
1262 return memcpy(stalloc(len), p, len);
1266 setstackmark(struct stackmark *mark)
1268 mark->stackp = g_stackp;
1269 mark->stacknxt = g_stacknxt;
1270 mark->stacknleft = g_stacknleft;
1271 mark->marknext = markp;
1276 popstackmark(struct stackmark *mark)
1278 struct stack_block *sp;
1284 markp = mark->marknext;
1285 while (g_stackp != mark->stackp) {
1287 g_stackp = sp->prev;
1290 g_stacknxt = mark->stacknxt;
1291 g_stacknleft = mark->stacknleft;
1292 sstrend = mark->stacknxt + mark->stacknleft;
1297 * When the parser reads in a string, it wants to stick the string on the
1298 * stack and only adjust the stack pointer when it knows how big the
1299 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1300 * of space on top of the stack and stackblocklen returns the length of
1301 * this block. Growstackblock will grow this space by at least one byte,
1302 * possibly moving it (like realloc). Grabstackblock actually allocates the
1303 * part of the block that has been used.
1306 growstackblock(void)
1310 newlen = g_stacknleft * 2;
1311 if (newlen < g_stacknleft)
1312 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1316 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1317 struct stack_block *oldstackp;
1318 struct stackmark *xmark;
1319 struct stack_block *sp;
1320 struct stack_block *prevstackp;
1324 oldstackp = g_stackp;
1326 prevstackp = sp->prev;
1327 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1328 sp = ckrealloc(sp, grosslen);
1329 sp->prev = prevstackp;
1331 g_stacknxt = sp->space;
1332 g_stacknleft = newlen;
1333 sstrend = sp->space + newlen;
1336 * Stack marks pointing to the start of the old block
1337 * must be relocated to point to the new block
1340 while (xmark != NULL && xmark->stackp == oldstackp) {
1341 xmark->stackp = g_stackp;
1342 xmark->stacknxt = g_stacknxt;
1343 xmark->stacknleft = g_stacknleft;
1344 xmark = xmark->marknext;
1348 char *oldspace = g_stacknxt;
1349 int oldlen = g_stacknleft;
1350 char *p = stalloc(newlen);
1352 /* free the space we just allocated */
1353 g_stacknxt = memcpy(p, oldspace, oldlen);
1354 g_stacknleft += newlen;
1359 grabstackblock(size_t len)
1361 len = SHELL_ALIGN(len);
1363 g_stacknleft -= len;
1367 * The following routines are somewhat easier to use than the above.
1368 * The user declares a variable of type STACKSTR, which may be declared
1369 * to be a register. The macro STARTSTACKSTR initializes things. Then
1370 * the user uses the macro STPUTC to add characters to the string. In
1371 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1372 * grown as necessary. When the user is done, she can just leave the
1373 * string there and refer to it using stackblock(). Or she can allocate
1374 * the space for it using grabstackstr(). If it is necessary to allow
1375 * someone else to use the stack temporarily and then continue to grow
1376 * the string, the user should use grabstack to allocate the space, and
1377 * then call ungrabstr(p) to return to the previous mode of operation.
1379 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1380 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1381 * is space for at least one character.
1386 size_t len = stackblocksize();
1387 if (herefd >= 0 && len >= 1024) {
1388 full_write(herefd, stackblock(), len);
1389 return stackblock();
1392 return stackblock() + len;
1396 * Called from CHECKSTRSPACE.
1399 makestrspace(size_t newlen, char *p)
1401 size_t len = p - g_stacknxt;
1402 size_t size = stackblocksize();
1407 size = stackblocksize();
1409 if (nleft >= newlen)
1413 return stackblock() + len;
1417 stack_nputstr(const char *s, size_t n, char *p)
1419 p = makestrspace(n, p);
1420 p = memcpy(p, s, n) + n;
1425 stack_putstr(const char *s, char *p)
1427 return stack_nputstr(s, strlen(s), p);
1431 _STPUTC(int c, char *p)
1439 #define STARTSTACKSTR(p) ((p) = stackblock())
1440 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1441 #define CHECKSTRSPACE(n, p) \
1445 size_t m = sstrend - q; \
1447 (p) = makestrspace(l, q); \
1449 #define USTPUTC(c, p) (*p++ = (c))
1450 #define STACKSTRNUL(p) \
1452 if ((p) == sstrend) \
1453 p = growstackstr(); \
1456 #define STUNPUTC(p) (--p)
1457 #define STTOPC(p) (p[-1])
1458 #define STADJUST(amount, p) (p += (amount))
1460 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1461 #define ungrabstackstr(s, p) stunalloc((s))
1462 #define stackstrend() ((void *)sstrend)
1465 /* ============ String helpers */
1468 * prefix -- see if pfx is a prefix of string.
1471 prefix(const char *string, const char *pfx)
1474 if (*pfx++ != *string++)
1477 return (char *) string;
1481 * Check for a valid number. This should be elsewhere.
1484 is_number(const char *p)
1489 } while (*++p != '\0');
1494 * Convert a string of digits to an integer, printing an error message on
1498 number(const char *s)
1501 ash_msg_and_raise_error(illnum, s);
1506 * Produce a possibly single quoted string suitable as input to the shell.
1507 * The return string is allocated on the stack.
1510 single_quote(const char *s)
1520 len = strchrnul(s, '\'') - s;
1522 q = p = makestrspace(len + 3, p);
1525 q = memcpy(q, s, len) + len;
1531 len = strspn(s, "'");
1535 q = p = makestrspace(len + 3, p);
1538 q = memcpy(q, s, len) + len;
1547 return stackblock();
1551 /* ============ nextopt */
1553 static char **argptr; /* argument list for builtin commands */
1554 static char *optionarg; /* set by nextopt (like getopt) */
1555 static char *optptr; /* used by nextopt */
1558 * XXX - should get rid of. have all builtins use getopt(3). the
1559 * library getopt must have the BSD extension static variable "optreset"
1560 * otherwise it can't be used within the shell safely.
1562 * Standard option processing (a la getopt) for builtin routines. The
1563 * only argument that is passed to nextopt is the option string; the
1564 * other arguments are unnecessary. It return the character, or '\0' on
1568 nextopt(const char *optstring)
1575 if (p == NULL || *p == '\0') {
1577 if (p == NULL || *p != '-' || *++p == '\0')
1580 if (LONE_DASH(p)) /* check for "--" */
1584 for (q = optstring; *q != c; ) {
1586 ash_msg_and_raise_error("illegal option -%c", c);
1591 if (*p == '\0' && (p = *argptr++) == NULL)
1592 ash_msg_and_raise_error("no arg for -%c option", c);
1601 /* ============ Math support definitions */
1603 #if ENABLE_ASH_MATH_SUPPORT_64
1604 typedef int64_t arith_t;
1605 #define arith_t_type long long
1607 typedef long arith_t;
1608 #define arith_t_type long
1611 #if ENABLE_ASH_MATH_SUPPORT
1612 static arith_t dash_arith(const char *);
1613 static arith_t arith(const char *expr, int *perrcode);
1616 #if ENABLE_ASH_RANDOM_SUPPORT
1617 static unsigned long rseed;
1624 /* ============ Shell variables */
1627 * The parsefile structure pointed to by the global variable parsefile
1628 * contains information about the current file being read.
1631 struct redirtab *next;
1637 int nparam; /* # of positional parameters (without $0) */
1638 #if ENABLE_ASH_GETOPTS
1639 int optind; /* next parameter to be processed by getopts */
1640 int optoff; /* used by getopts */
1642 unsigned char malloced; /* if parameter list dynamically allocated */
1643 char **p; /* parameter list */
1647 * Free the list of positional parameters.
1650 freeparam(volatile struct shparam *param)
1654 if (param->malloced) {
1655 for (ap = param->p; *ap; ap++)
1661 #if ENABLE_ASH_GETOPTS
1662 static void getoptsreset(const char *value);
1666 struct var *next; /* next entry in hash list */
1667 int flags; /* flags are defined above */
1668 const char *text; /* name=value */
1669 void (*func)(const char *); /* function to be called when */
1670 /* the variable gets set/unset */
1674 struct localvar *next; /* next local variable in list */
1675 struct var *vp; /* the variable that was made local */
1676 int flags; /* saved flags */
1677 const char *text; /* saved text */
1681 #define VEXPORT 0x01 /* variable is exported */
1682 #define VREADONLY 0x02 /* variable cannot be modified */
1683 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1684 #define VTEXTFIXED 0x08 /* text is statically allocated */
1685 #define VSTACK 0x10 /* text is allocated on the stack */
1686 #define VUNSET 0x20 /* the variable is not set */
1687 #define VNOFUNC 0x40 /* don't call the callback function */
1688 #define VNOSET 0x80 /* do not set variable - just readonly test */
1689 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1691 # define VDYNAMIC 0x200 /* dynamic variable */
1697 static const char defifsvar[] ALIGN1 = "IFS= \t\n";
1698 #define defifs (defifsvar + 4)
1700 static const char defifs[] ALIGN1 = " \t\n";
1704 /* Need to be before varinit_data[] */
1705 #if ENABLE_LOCALE_SUPPORT
1707 change_lc_all(const char *value)
1709 if (value && *value != '\0')
1710 setlocale(LC_ALL, value);
1713 change_lc_ctype(const char *value)
1715 if (value && *value != '\0')
1716 setlocale(LC_CTYPE, value);
1720 static void chkmail(void);
1721 static void changemail(const char *);
1723 static void changepath(const char *);
1724 #if ENABLE_ASH_RANDOM_SUPPORT
1725 static void change_random(const char *);
1728 static const struct {
1731 void (*func)(const char *);
1732 } varinit_data[] = {
1734 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1736 { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL },
1739 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0" , changemail },
1740 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1742 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1743 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1744 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1745 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1746 #if ENABLE_ASH_GETOPTS
1747 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
1749 #if ENABLE_ASH_RANDOM_SUPPORT
1750 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1752 #if ENABLE_LOCALE_SUPPORT
1753 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL\0" , change_lc_all },
1754 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE\0", change_lc_ctype },
1756 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1757 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE\0", NULL },
1762 struct globals_var {
1763 struct shparam shellparam; /* $@ current positional parameters */
1764 struct redirtab *redirlist;
1766 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1767 struct var *vartab[VTABSIZE];
1768 struct var varinit[ARRAY_SIZE(varinit_data)];
1770 /* Make it reside in writable memory, yet make compiler understand that it is not going to change. */
1771 static struct globals_var *const ptr_to_globals_var __attribute__ ((section (".data")));
1772 #define G_var (*ptr_to_globals_var)
1773 #define shellparam (G_var.shellparam )
1774 #define redirlist (G_var.redirlist )
1775 #define g_nullredirs (G_var.g_nullredirs )
1776 #define preverrout_fd (G_var.preverrout_fd)
1777 #define vartab (G_var.vartab )
1778 #define varinit (G_var.varinit )
1779 #define INIT_G_var() do { \
1781 (*(struct globals_var**)&ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1782 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1783 varinit[i].flags = varinit_data[i].flags; \
1784 varinit[i].text = varinit_data[i].text; \
1785 varinit[i].func = varinit_data[i].func; \
1789 #define vifs varinit[0]
1791 #define vmail (&vifs)[1]
1792 #define vmpath (&vmail)[1]
1796 #define vpath (&vmpath)[1]
1797 #define vps1 (&vpath)[1]
1798 #define vps2 (&vps1)[1]
1799 #define vps4 (&vps2)[1]
1800 #define voptind (&vps4)[1]
1801 #if ENABLE_ASH_GETOPTS
1802 #define vrandom (&voptind)[1]
1804 #define vrandom (&vps4)[1]
1808 * The following macros access the values of the above variables.
1809 * They have to skip over the name. They return the null string
1810 * for unset variables.
1812 #define ifsval() (vifs.text + 4)
1813 #define ifsset() ((vifs.flags & VUNSET) == 0)
1814 #define mailval() (vmail.text + 5)
1815 #define mpathval() (vmpath.text + 9)
1816 #define pathval() (vpath.text + 5)
1817 #define ps1val() (vps1.text + 4)
1818 #define ps2val() (vps2.text + 4)
1819 #define ps4val() (vps4.text + 4)
1820 #define optindval() (voptind.text + 7)
1822 #define mpathset() ((vmpath.flags & VUNSET) == 0)
1825 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1826 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1828 #if ENABLE_ASH_GETOPTS
1830 getoptsreset(const char *value)
1832 shellparam.optind = number(value);
1833 shellparam.optoff = -1;
1838 * Return of a legal variable name (a letter or underscore followed by zero or
1839 * more letters, underscores, and digits).
1842 endofname(const char *name)
1850 if (!is_in_name(*p))
1857 * Compares two strings up to the first = or '\0'. The first
1858 * string must be terminated by '='; the second may be terminated by
1859 * either '=' or '\0'.
1862 varcmp(const char *p, const char *q)
1866 while ((c = *p) == (d = *q)) {
1881 varequal(const char *a, const char *b)
1883 return !varcmp(a, b);
1887 * Find the appropriate entry in the hash table from the name.
1889 static struct var **
1890 hashvar(const char *p)
1894 hashval = ((unsigned char) *p) << 4;
1895 while (*p && *p != '=')
1896 hashval += (unsigned char) *p++;
1897 return &vartab[hashval % VTABSIZE];
1901 vpcmp(const void *a, const void *b)
1903 return varcmp(*(const char **)a, *(const char **)b);
1907 * This routine initializes the builtin variables.
1917 * PS1 depends on uid
1919 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1920 vps1.text = "PS1=\\w \\$ ";
1923 vps1.text = "PS1=# ";
1926 end = vp + ARRAY_SIZE(varinit);
1928 vpp = hashvar(vp->text);
1931 } while (++vp < end);
1934 static struct var **
1935 findvar(struct var **vpp, const char *name)
1937 for (; *vpp; vpp = &(*vpp)->next) {
1938 if (varequal((*vpp)->text, name)) {
1946 * Find the value of a variable. Returns NULL if not set.
1949 lookupvar(const char *name)
1953 v = *findvar(hashvar(name), name);
1957 * Dynamic variables are implemented roughly the same way they are
1958 * in bash. Namely, they're "special" so long as they aren't unset.
1959 * As soon as they're unset, they're no longer dynamic, and dynamic
1960 * lookup will no longer happen at that point. -- PFM.
1962 if ((v->flags & VDYNAMIC))
1965 if (!(v->flags & VUNSET))
1966 return strchrnul(v->text, '=') + 1;
1972 * Search the environment of a builtin command.
1975 bltinlookup(const char *name)
1979 for (sp = cmdenviron; sp; sp = sp->next) {
1980 if (varequal(sp->text, name))
1981 return strchrnul(sp->text, '=') + 1;
1983 return lookupvar(name);
1987 * Same as setvar except that the variable and value are passed in
1988 * the first argument as name=value. Since the first argument will
1989 * be actually stored in the table, it should not be a string that
1991 * Called with interrupts off.
1994 setvareq(char *s, int flags)
1996 struct var *vp, **vpp;
1999 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2000 vp = *findvar(vpp, s);
2002 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2005 if (flags & VNOSAVE)
2008 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2014 if (vp->func && (flags & VNOFUNC) == 0)
2015 (*vp->func)(strchrnul(s, '=') + 1);
2017 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
2018 free((char*)vp->text);
2020 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2025 vp = ckmalloc(sizeof(*vp));
2030 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2037 * Set the value of a variable. The flags argument is ored with the
2038 * flags of the variable. If val is NULL, the variable is unset.
2041 setvar(const char *name, const char *val, int flags)
2048 q = endofname(name);
2049 p = strchrnul(q, '=');
2051 if (!namelen || p != q)
2052 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2057 vallen = strlen(val);
2060 nameeq = ckmalloc(namelen + vallen + 2);
2061 p = memcpy(nameeq, name, namelen) + namelen;
2064 p = memcpy(p, val, vallen) + vallen;
2067 setvareq(nameeq, flags | VNOSAVE);
2071 #if ENABLE_ASH_GETOPTS
2073 * Safe version of setvar, returns 1 on success 0 on failure.
2076 setvarsafe(const char *name, const char *val, int flags)
2079 volatile int saveint;
2080 struct jmploc *volatile savehandler = exception_handler;
2081 struct jmploc jmploc;
2084 if (setjmp(jmploc.loc))
2087 exception_handler = &jmploc;
2088 setvar(name, val, flags);
2091 exception_handler = savehandler;
2092 RESTORE_INT(saveint);
2098 * Unset the specified variable.
2101 unsetvar(const char *s)
2107 vpp = findvar(hashvar(s), s);
2111 int flags = vp->flags;
2114 if (flags & VREADONLY)
2117 vp->flags &= ~VDYNAMIC;
2121 if ((flags & VSTRFIXED) == 0) {
2123 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2124 free((char*)vp->text);
2130 vp->flags &= ~VEXPORT;
2140 * Process a linked list of variable assignments.
2143 listsetvar(struct strlist *list_set_var, int flags)
2145 struct strlist *lp = list_set_var;
2151 setvareq(lp->text, flags);
2158 * Generate a list of variables satisfying the given conditions.
2161 listvars(int on, int off, char ***end)
2172 for (vp = *vpp; vp; vp = vp->next) {
2173 if ((vp->flags & mask) == on) {
2174 if (ep == stackstrend())
2175 ep = growstackstr();
2176 *ep++ = (char *) vp->text;
2179 } while (++vpp < vartab + VTABSIZE);
2180 if (ep == stackstrend())
2181 ep = growstackstr();
2185 return grabstackstr(ep);
2189 /* ============ Path search helper
2191 * The variable path (passed by reference) should be set to the start
2192 * of the path before the first call; padvance will update
2193 * this value as it proceeds. Successive calls to padvance will return
2194 * the possible path expansions in sequence. If an option (indicated by
2195 * a percent sign) appears in the path entry then the global variable
2196 * pathopt will be set to point to it; otherwise pathopt will be set to
2199 static const char *pathopt; /* set by padvance */
2202 padvance(const char **path, const char *name)
2212 for (p = start; *p && *p != ':' && *p != '%'; p++);
2213 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2214 while (stackblocksize() < len)
2218 memcpy(q, start, p - start);
2226 while (*p && *p != ':') p++;
2232 return stalloc(len);
2236 /* ============ Prompt */
2238 static smallint doprompt; /* if set, prompt the user */
2239 static smallint needprompt; /* true if interactive and at start of line */
2241 #if ENABLE_FEATURE_EDITING
2242 static line_input_t *line_input_state;
2243 static const char *cmdedit_prompt;
2245 putprompt(const char *s)
2247 if (ENABLE_ASH_EXPAND_PRMT) {
2248 free((char*)cmdedit_prompt);
2249 cmdedit_prompt = ckstrdup(s);
2256 putprompt(const char *s)
2262 #if ENABLE_ASH_EXPAND_PRMT
2263 /* expandstr() needs parsing machinery, so it is far away ahead... */
2264 static const char *expandstr(const char *ps);
2266 #define expandstr(s) s
2270 setprompt(int whichprompt)
2273 #if ENABLE_ASH_EXPAND_PRMT
2274 struct stackmark smark;
2279 switch (whichprompt) {
2289 #if ENABLE_ASH_EXPAND_PRMT
2290 setstackmark(&smark);
2291 stalloc(stackblocksize());
2293 putprompt(expandstr(prompt));
2294 #if ENABLE_ASH_EXPAND_PRMT
2295 popstackmark(&smark);
2300 /* ============ The cd and pwd commands */
2302 #define CD_PHYSICAL 1
2305 static int docd(const char *, int);
2314 while ((i = nextopt("LP"))) {
2316 flags ^= CD_PHYSICAL;
2325 * Update curdir (the name of the current directory) in response to a
2329 updatepwd(const char *dir)
2336 cdcomppath = ststrdup(dir);
2339 if (curdir == nullstr)
2341 new = stack_putstr(curdir, new);
2343 new = makestrspace(strlen(dir) + 2, new);
2344 lim = stackblock() + 1;
2348 if (new > lim && *lim == '/')
2353 if (dir[1] == '/' && dir[2] != '/') {
2359 p = strtok(cdcomppath, "/");
2363 if (p[1] == '.' && p[2] == '\0') {
2375 new = stack_putstr(p, new);
2383 return stackblock();
2387 * Find out what the current directory is. If we already know the current
2388 * directory, this routine returns immediately.
2393 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2394 return dir ? dir : nullstr;
2398 setpwd(const char *val, int setold)
2402 oldcur = dir = curdir;
2405 setvar("OLDPWD", oldcur, VEXPORT);
2408 if (physdir != nullstr) {
2409 if (physdir != oldcur)
2413 if (oldcur == val || !val) {
2419 dir = ckstrdup(val);
2420 if (oldcur != dir && oldcur != nullstr) {
2425 setvar("PWD", dir, VEXPORT);
2428 static void hashcd(void);
2431 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2432 * know that the current directory has changed.
2435 docd(const char *dest, int flags)
2437 const char *dir = 0;
2440 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2443 if (!(flags & CD_PHYSICAL)) {
2444 dir = updatepwd(dest);
2459 cdcmd(int argc, char **argv)
2471 dest = bltinlookup(homestr);
2472 else if (LONE_DASH(dest)) {
2473 dest = bltinlookup("OLDPWD");
2495 path = bltinlookup("CDPATH");
2504 p = padvance(&path, dest);
2505 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2509 if (!docd(p, flags))
2514 ash_msg_and_raise_error("can't cd to %s", dest);
2517 if (flags & CD_PRINT)
2518 out1fmt(snlfmt, curdir);
2523 pwdcmd(int argc, char **argv)
2526 const char *dir = curdir;
2530 if (physdir == nullstr)
2534 out1fmt(snlfmt, dir);
2539 /* ============ ... */
2541 #define IBUFSIZ COMMON_BUFSIZE
2542 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */
2544 /* Syntax classes */
2545 #define CWORD 0 /* character is nothing special */
2546 #define CNL 1 /* newline character */
2547 #define CBACK 2 /* a backslash character */
2548 #define CSQUOTE 3 /* single quote */
2549 #define CDQUOTE 4 /* double quote */
2550 #define CENDQUOTE 5 /* a terminating quote */
2551 #define CBQUOTE 6 /* backwards single quote */
2552 #define CVAR 7 /* a dollar sign */
2553 #define CENDVAR 8 /* a '}' character */
2554 #define CLP 9 /* a left paren in arithmetic */
2555 #define CRP 10 /* a right paren in arithmetic */
2556 #define CENDFILE 11 /* end of file */
2557 #define CCTL 12 /* like CWORD, except it must be escaped */
2558 #define CSPCL 13 /* these terminate a word */
2559 #define CIGN 14 /* character should be ignored */
2561 #if ENABLE_ASH_ALIAS
2565 #define PEOA_OR_PEOF PEOA
2569 #define PEOA_OR_PEOF PEOF
2572 /* number syntax index */
2573 #define BASESYNTAX 0 /* not in quotes */
2574 #define DQSYNTAX 1 /* in double quotes */
2575 #define SQSYNTAX 2 /* in single quotes */
2576 #define ARISYNTAX 3 /* in arithmetic */
2577 #define PSSYNTAX 4 /* prompt */
2579 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
2580 #define USE_SIT_FUNCTION
2583 #if ENABLE_ASH_MATH_SUPPORT
2584 static const char S_I_T[][4] = {
2585 #if ENABLE_ASH_ALIAS
2586 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */
2588 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */
2589 { CNL, CNL, CNL, CNL }, /* 2, \n */
2590 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */
2591 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */
2592 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */
2593 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */
2594 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */
2595 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */
2596 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */
2597 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */
2598 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */
2599 #ifndef USE_SIT_FUNCTION
2600 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2601 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2602 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2606 static const char S_I_T[][3] = {
2607 #if ENABLE_ASH_ALIAS
2608 { CSPCL, CIGN, CIGN }, /* 0, PEOA */
2610 { CSPCL, CWORD, CWORD }, /* 1, ' ' */
2611 { CNL, CNL, CNL }, /* 2, \n */
2612 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */
2613 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */
2614 { CVAR, CVAR, CWORD }, /* 5, $ */
2615 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */
2616 { CSPCL, CWORD, CWORD }, /* 7, ( */
2617 { CSPCL, CWORD, CWORD }, /* 8, ) */
2618 { CBACK, CBACK, CCTL }, /* 9, \ */
2619 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */
2620 { CENDVAR, CENDVAR, CWORD }, /* 11, } */
2621 #ifndef USE_SIT_FUNCTION
2622 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2623 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2624 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2627 #endif /* ASH_MATH_SUPPORT */
2629 #ifdef USE_SIT_FUNCTION
2632 SIT(int c, int syntax)
2634 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2635 #if ENABLE_ASH_ALIAS
2636 static const char syntax_index_table[] ALIGN1 = {
2637 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2638 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2639 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2643 static const char syntax_index_table[] ALIGN1 = {
2644 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2645 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2646 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2653 if (c == PEOF) /* 2^8+2 */
2655 #if ENABLE_ASH_ALIAS
2656 if (c == PEOA) /* 2^8+1 */
2660 #define U_C(c) ((unsigned char)(c))
2662 if ((unsigned char)c >= (unsigned char)(CTLESC)
2663 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
2667 s = strchr(spec_symbls, c);
2668 if (s == NULL || *s == '\0')
2670 indx = syntax_index_table[(s - spec_symbls)];
2672 return S_I_T[indx][syntax];
2675 #else /* !USE_SIT_FUNCTION */
2677 #if ENABLE_ASH_ALIAS
2678 #define CSPCL_CIGN_CIGN_CIGN 0
2679 #define CSPCL_CWORD_CWORD_CWORD 1
2680 #define CNL_CNL_CNL_CNL 2
2681 #define CWORD_CCTL_CCTL_CWORD 3
2682 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
2683 #define CVAR_CVAR_CWORD_CVAR 5
2684 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
2685 #define CSPCL_CWORD_CWORD_CLP 7
2686 #define CSPCL_CWORD_CWORD_CRP 8
2687 #define CBACK_CBACK_CCTL_CBACK 9
2688 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
2689 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
2690 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
2691 #define CWORD_CWORD_CWORD_CWORD 13
2692 #define CCTL_CCTL_CCTL_CCTL 14
2694 #define CSPCL_CWORD_CWORD_CWORD 0
2695 #define CNL_CNL_CNL_CNL 1
2696 #define CWORD_CCTL_CCTL_CWORD 2
2697 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
2698 #define CVAR_CVAR_CWORD_CVAR 4
2699 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
2700 #define CSPCL_CWORD_CWORD_CLP 6
2701 #define CSPCL_CWORD_CWORD_CRP 7
2702 #define CBACK_CBACK_CCTL_CBACK 8
2703 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
2704 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
2705 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
2706 #define CWORD_CWORD_CWORD_CWORD 12
2707 #define CCTL_CCTL_CCTL_CCTL 13
2710 static const char syntax_index_table[258] = {
2711 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2712 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2713 #if ENABLE_ASH_ALIAS
2714 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
2716 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2717 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2718 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2719 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2720 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2721 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2722 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2723 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2724 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2725 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
2726 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
2727 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
2728 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
2729 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
2730 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
2731 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
2732 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
2733 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
2734 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
2735 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
2736 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
2737 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
2738 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
2739 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
2740 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
2741 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
2742 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
2743 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
2744 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
2745 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
2746 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
2747 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
2748 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
2749 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
2750 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
2751 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
2752 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
2753 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
2754 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
2755 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
2756 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
2757 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
2758 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
2759 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
2760 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
2761 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
2762 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
2763 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
2764 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
2765 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
2766 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
2767 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
2768 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
2769 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
2770 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
2771 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
2772 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
2773 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
2774 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
2775 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
2776 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
2777 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
2778 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
2779 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
2780 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
2781 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
2782 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
2783 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
2784 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
2785 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
2786 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
2787 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
2788 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
2789 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
2790 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
2791 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
2792 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
2793 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
2794 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
2795 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
2796 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
2797 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
2798 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
2799 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
2800 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
2801 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
2802 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
2803 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
2804 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
2805 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
2806 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
2807 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
2808 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
2809 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
2810 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
2811 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
2812 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
2813 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
2814 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
2815 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
2816 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
2817 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
2818 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
2819 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
2820 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
2821 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
2822 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
2823 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
2824 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
2825 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
2826 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
2827 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
2828 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
2829 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
2830 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
2831 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
2832 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
2833 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
2834 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
2835 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
2836 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
2837 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
2838 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
2839 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
2840 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
2841 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
2842 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
2843 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
2844 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
2845 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
2846 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
2847 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
2848 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
2853 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2854 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
2855 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2877 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2878 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2879 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2880 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2881 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2882 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2883 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2884 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2885 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2886 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2887 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2888 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
2889 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2890 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
2891 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2892 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2893 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2894 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2895 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2896 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2897 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2898 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2899 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2900 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2901 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2902 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2903 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2904 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2905 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2906 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2907 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2908 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2909 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2910 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2936 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2937 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2938 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2941 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2969 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2970 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2971 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
2974 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])
2976 #endif /* USE_SIT_FUNCTION */
2979 /* ============ Alias handling */
2981 #if ENABLE_ASH_ALIAS
2983 #define ALIASINUSE 1
2994 static struct alias **atab; // [ATABSIZE];
2995 #define INIT_G_alias() do { \
2996 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3000 static struct alias **
3001 __lookupalias(const char *name) {
3002 unsigned int hashval;
3009 ch = (unsigned char)*p;
3013 ch = (unsigned char)*++p;
3015 app = &atab[hashval % ATABSIZE];
3017 for (; *app; app = &(*app)->next) {
3018 if (strcmp(name, (*app)->name) == 0) {
3026 static struct alias *
3027 lookupalias(const char *name, int check)
3029 struct alias *ap = *__lookupalias(name);
3031 if (check && ap && (ap->flag & ALIASINUSE))
3036 static struct alias *
3037 freealias(struct alias *ap)
3041 if (ap->flag & ALIASINUSE) {
3042 ap->flag |= ALIASDEAD;
3054 setalias(const char *name, const char *val)
3056 struct alias *ap, **app;
3058 app = __lookupalias(name);
3062 if (!(ap->flag & ALIASINUSE)) {
3065 ap->val = ckstrdup(val);
3066 ap->flag &= ~ALIASDEAD;
3069 ap = ckmalloc(sizeof(struct alias));
3070 ap->name = ckstrdup(name);
3071 ap->val = ckstrdup(val);
3080 unalias(const char *name)
3084 app = __lookupalias(name);
3088 *app = freealias(*app);
3099 struct alias *ap, **app;
3103 for (i = 0; i < ATABSIZE; i++) {
3105 for (ap = *app; ap; ap = *app) {
3106 *app = freealias(*app);
3116 printalias(const struct alias *ap)
3118 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3122 * TODO - sort output
3125 aliascmd(int argc, char **argv)
3134 for (i = 0; i < ATABSIZE; i++)
3135 for (ap = atab[i]; ap; ap = ap->next) {
3140 while ((n = *++argv) != NULL) {
3141 v = strchr(n+1, '=');
3142 if (v == NULL) { /* n+1: funny ksh stuff */
3143 ap = *__lookupalias(n);
3145 fprintf(stderr, "%s: %s not found\n", "alias", n);
3159 unaliascmd(int argc, char **argv)
3163 while ((i = nextopt("a")) != '\0') {
3169 for (i = 0; *argptr; argptr++) {
3170 if (unalias(*argptr)) {
3171 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3179 #endif /* ASH_ALIAS */
3182 /* ============ jobs.c */
3184 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3187 #define FORK_NOJOB 2
3189 /* mode flags for showjob(s) */
3190 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
3191 #define SHOW_PID 0x04 /* include process pid */
3192 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
3195 * A job structure contains information about a job. A job is either a
3196 * single process or a set of processes contained in a pipeline. In the
3197 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3202 pid_t pid; /* process id */
3203 int status; /* last process status from wait() */
3204 char *cmd; /* text of command being run */
3208 struct procstat ps0; /* status of process */
3209 struct procstat *ps; /* status or processes when more than one */
3211 int stopstatus; /* status of a stopped job */
3214 nprocs: 16, /* number of processes */
3216 #define JOBRUNNING 0 /* at least one proc running */
3217 #define JOBSTOPPED 1 /* all procs are stopped */
3218 #define JOBDONE 2 /* all procs are completed */
3220 sigint: 1, /* job was killed by SIGINT */
3221 jobctl: 1, /* job running under job control */
3223 waited: 1, /* true if this entry has been waited for */
3224 used: 1, /* true if this entry is in used */
3225 changed: 1; /* true if status has changed */
3226 struct job *prev_job; /* previous job */
3229 static pid_t backgndpid; /* pid of last background process */
3230 static smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
3232 static struct job *makejob(union node *, int);
3233 static int forkshell(struct job *, union node *, int);
3234 static int waitforjob(struct job *);
3237 enum { jobctl = 0 };
3238 #define setjobctl(on) do {} while (0)
3240 static smallint jobctl; /* true if doing job control */
3241 static void setjobctl(int);
3245 * Set the signal handler for the specified signal. The routine figures
3246 * out what it should be set to.
3249 setsignal(int signo)
3253 struct sigaction act;
3259 else if (*t != '\0')
3261 if (rootshell && action == S_DFL) {
3264 if (iflag || minusc || sflag == 0)
3287 t = &sigmode[signo - 1];
3291 * current setting unknown
3293 if (sigaction(signo, NULL, &act) == -1) {
3295 * Pretend it worked; maybe we should give a warning
3296 * here, but other shells don't. We don't alter
3297 * sigmode, so that we retry every time.
3301 tsig = S_RESET; /* force to be set */
3302 if (act.sa_handler == SIG_IGN) {
3305 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3307 tsig = S_IGN; /* don't hard ignore these */
3311 if (tsig == S_HARD_IGN || tsig == action)
3313 act.sa_handler = SIG_DFL;
3316 act.sa_handler = onsig;
3319 act.sa_handler = SIG_IGN;
3324 sigfillset(&act.sa_mask);
3325 sigaction(signo, &act, NULL);
3328 /* mode flags for set_curjob */
3329 #define CUR_DELETE 2
3330 #define CUR_RUNNING 1
3331 #define CUR_STOPPED 0
3333 /* mode flags for dowait */
3334 #define DOWAIT_NONBLOCK WNOHANG
3335 #define DOWAIT_BLOCK 0
3338 /* pgrp of shell on invocation */
3339 static int initialpgrp;
3340 static int ttyfd = -1;
3343 static struct job *jobtab;
3345 static unsigned njobs;
3347 static struct job *curjob;
3348 /* number of presumed living untracked jobs */
3352 set_curjob(struct job *jp, unsigned mode)
3355 struct job **jpp, **curp;
3357 /* first remove from list */
3358 jpp = curp = &curjob;
3363 jpp = &jp1->prev_job;
3365 *jpp = jp1->prev_job;
3367 /* Then re-insert in correct position */
3375 /* job being deleted */
3378 /* newly created job or backgrounded job,
3379 put after all stopped jobs. */
3383 if (!jp1 || jp1->state != JOBSTOPPED)
3386 jpp = &jp1->prev_job;
3392 /* newly stopped job - becomes curjob */
3393 jp->prev_job = *jpp;
3401 jobno(const struct job *jp)
3403 return jp - jobtab + 1;
3408 * Convert a job name to a job structure.
3411 getjob(const char *name, int getctl)
3415 const char *err_msg = "No such job: %s";
3419 char *(*match)(const char *, const char *);
3434 if (c == '+' || c == '%') {
3436 err_msg = "No current job";
3442 err_msg = "No previous job";
3453 jp = jobtab + num - 1;
3470 if (match(jp->ps[0].cmd, p)) {
3474 err_msg = "%s: ambiguous";
3481 err_msg = "job %s not created under job control";
3482 if (getctl && jp->jobctl == 0)
3487 ash_msg_and_raise_error(err_msg, name);
3491 * Mark a job structure as unused.
3494 freejob(struct job *jp)
3496 struct procstat *ps;
3500 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3501 if (ps->cmd != nullstr)
3504 if (jp->ps != &jp->ps0)
3507 set_curjob(jp, CUR_DELETE);
3513 xtcsetpgrp(int fd, pid_t pgrp)
3515 if (tcsetpgrp(fd, pgrp))
3516 ash_msg_and_raise_error("cannot set tty process group (%m)");
3520 * Turn job control on and off.
3522 * Note: This code assumes that the third arg to ioctl is a character
3523 * pointer, which is true on Berkeley systems but not System V. Since
3524 * System V doesn't have job control yet, this isn't a problem now.
3526 * Called with interrupts off.
3534 if (on == jobctl || rootshell == 0)
3538 ofd = fd = open(_PATH_TTY, O_RDWR);
3540 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3541 * That sometimes helps to acquire controlling tty.
3542 * Obviously, a workaround for bugs when someone
3543 * failed to provide a controlling tty to bash! :) */
3549 fd = fcntl(fd, F_DUPFD, 10);
3554 /* fd is a tty at this point */
3555 close_on_exec_on(fd);
3556 do { /* while we are in the background */
3557 pgrp = tcgetpgrp(fd);
3560 ash_msg("can't access tty; job control turned off");
3564 if (pgrp == getpgrp())
3575 xtcsetpgrp(fd, pgrp);
3577 /* turning job control off */
3580 /* was xtcsetpgrp, but this can make exiting ash
3581 * loop forever if pty is already deleted */
3582 tcsetpgrp(fd, pgrp);
3597 killcmd(int argc, char **argv)
3599 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3602 if (argv[i][0] == '%') {
3603 struct job *jp = getjob(argv[i], 0);
3604 unsigned pid = jp->ps[0].pid;
3605 /* Enough space for ' -NNN<nul>' */
3606 argv[i] = alloca(sizeof(int)*3 + 3);
3607 /* kill_main has matching code to expect
3608 * leading space. Needed to not confuse
3609 * negative pids with "kill -SIGNAL_NO" syntax */
3610 sprintf(argv[i], " -%u", pid);
3612 } while (argv[++i]);
3614 return kill_main(argc, argv);
3618 showpipe(struct job *jp, FILE *out)
3620 struct procstat *sp;
3621 struct procstat *spend;
3623 spend = jp->ps + jp->nprocs;
3624 for (sp = jp->ps + 1; sp < spend; sp++)
3625 fprintf(out, " | %s", sp->cmd);
3626 outcslow('\n', out);
3627 flush_stdout_stderr();
3632 restartjob(struct job *jp, int mode)
3634 struct procstat *ps;
3640 if (jp->state == JOBDONE)
3642 jp->state = JOBRUNNING;
3644 if (mode == FORK_FG)
3645 xtcsetpgrp(ttyfd, pgid);
3646 killpg(pgid, SIGCONT);
3650 if (WIFSTOPPED(ps->status)) {
3656 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3662 fg_bgcmd(int argc, char **argv)
3669 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3674 jp = getjob(*argv, 1);
3675 if (mode == FORK_BG) {
3676 set_curjob(jp, CUR_RUNNING);
3677 fprintf(out, "[%d] ", jobno(jp));
3679 outstr(jp->ps->cmd, out);
3681 retval = restartjob(jp, mode);
3682 } while (*argv && *++argv);
3688 sprint_status(char *s, int status, int sigonly)
3694 if (!WIFEXITED(status)) {
3696 if (WIFSTOPPED(status))
3697 st = WSTOPSIG(status);
3700 st = WTERMSIG(status);
3702 if (st == SIGINT || st == SIGPIPE)
3705 if (WIFSTOPPED(status))
3710 col = fmtstr(s, 32, strsignal(st));
3711 if (WCOREDUMP(status)) {
3712 col += fmtstr(s + col, 16, " (core dumped)");
3714 } else if (!sigonly) {
3715 st = WEXITSTATUS(status);
3717 col = fmtstr(s, 16, "Done(%d)", st);
3719 col = fmtstr(s, 16, "Done");
3726 * Do a wait system call. If job control is compiled in, we accept
3727 * stopped processes. If block is zero, we return a value of zero
3728 * rather than blocking.
3730 * System V doesn't have a non-blocking wait system call. It does
3731 * have a SIGCLD signal that is sent to a process when one of it's
3732 * children dies. The obvious way to use SIGCLD would be to install
3733 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
3734 * was received, and have waitproc bump another counter when it got
3735 * the status of a process. Waitproc would then know that a wait
3736 * system call would not block if the two counters were different.
3737 * This approach doesn't work because if a process has children that
3738 * have not been waited for, System V will send it a SIGCLD when it
3739 * installs a signal handler for SIGCLD. What this means is that when
3740 * a child exits, the shell will be sent SIGCLD signals continuously
3741 * until is runs out of stack space, unless it does a wait call before
3742 * restoring the signal handler. The code below takes advantage of
3743 * this (mis)feature by installing a signal handler for SIGCLD and
3744 * then checking to see whether it was called. If there are any
3745 * children to be waited for, it will be.
3747 * If neither SYSV nor BSD is defined, we don't implement nonblocking
3748 * waits at all. In this case, the user will not be informed when
3749 * a background process until the next time she runs a real program
3750 * (as opposed to running a builtin command or just typing return),
3751 * and the jobs command may give out of date information.
3754 waitproc(int wait_flags, int *status)
3758 wait_flags |= WUNTRACED;
3760 /* NB: _not_ safe_waitpid, we need to detect EINTR */
3761 return waitpid(-1, status, wait_flags);
3765 * Wait for a process to terminate.
3768 dowait(int wait_flags, struct job *job)
3773 struct job *thisjob;
3776 TRACE(("dowait(%d) called\n", wait_flags));
3777 pid = waitproc(wait_flags, &status);
3778 TRACE(("wait returns pid=%d, status=%d\n", pid, status));
3780 /* If we were doing blocking wait and (probably) got EINTR,
3781 * check for pending sigs received while waiting.
3782 * (NB: can be moved into callers if needed) */
3783 if (wait_flags == DOWAIT_BLOCK && pendingsig)
3784 raise_exception(EXSIG);
3789 for (jp = curjob; jp; jp = jp->prev_job) {
3790 struct procstat *sp;
3791 struct procstat *spend;
3792 if (jp->state == JOBDONE)
3795 spend = jp->ps + jp->nprocs;
3798 if (sp->pid == pid) {
3799 TRACE(("Job %d: changing status of proc %d "
3800 "from 0x%x to 0x%x\n",
3801 jobno(jp), pid, sp->status, status));
3802 sp->status = status;
3805 if (sp->status == -1)
3808 if (state == JOBRUNNING)
3810 if (WIFSTOPPED(sp->status)) {
3811 jp->stopstatus = sp->status;
3815 } while (++sp < spend);
3820 if (!WIFSTOPPED(status))
3826 if (state != JOBRUNNING) {
3827 thisjob->changed = 1;
3829 if (thisjob->state != state) {
3830 TRACE(("Job %d: changing state from %d to %d\n",
3831 jobno(thisjob), thisjob->state, state));
3832 thisjob->state = state;
3834 if (state == JOBSTOPPED) {
3835 set_curjob(thisjob, CUR_STOPPED);
3844 if (thisjob && thisjob == job) {
3848 len = sprint_status(s, status, 1);
3860 showjob(FILE *out, struct job *jp, int mode)
3862 struct procstat *ps;
3863 struct procstat *psend;
3870 if (mode & SHOW_PGID) {
3871 /* just output process (group) id of pipeline */
3872 fprintf(out, "%d\n", ps->pid);
3876 col = fmtstr(s, 16, "[%d] ", jobno(jp));
3881 else if (curjob && jp == curjob->prev_job)
3884 if (mode & SHOW_PID)
3885 col += fmtstr(s + col, 16, "%d ", ps->pid);
3887 psend = ps + jp->nprocs;
3889 if (jp->state == JOBRUNNING) {
3890 strcpy(s + col, "Running");
3891 col += sizeof("Running") - 1;
3893 int status = psend[-1].status;
3894 if (jp->state == JOBSTOPPED)
3895 status = jp->stopstatus;
3896 col += sprint_status(s + col, status, 0);
3902 /* for each process */
3903 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
3905 fprintf(out, "%s%*c%s",
3906 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
3908 if (!(mode & SHOW_PID)) {
3912 if (++ps == psend) {
3913 outcslow('\n', out);
3920 if (jp->state == JOBDONE) {
3921 TRACE(("showjob: freeing job %d\n", jobno(jp)));
3927 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3928 * statuses have changed since the last call to showjobs.
3931 showjobs(FILE *out, int mode)
3935 TRACE(("showjobs(%x) called\n", mode));
3937 /* If not even one job changed, there is nothing to do */
3938 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3941 for (jp = curjob; jp; jp = jp->prev_job) {
3942 if (!(mode & SHOW_CHANGED) || jp->changed) {
3943 showjob(out, jp, mode);
3949 jobscmd(int argc, char **argv)
3954 while ((m = nextopt("lp"))) {
3964 showjob(stdout, getjob(*argv,0), mode);
3967 showjobs(stdout, mode);
3974 getstatus(struct job *job)
3979 status = job->ps[job->nprocs - 1].status;
3980 retval = WEXITSTATUS(status);
3981 if (!WIFEXITED(status)) {
3983 retval = WSTOPSIG(status);
3984 if (!WIFSTOPPED(status))
3987 /* XXX: limits number of signals */
3988 retval = WTERMSIG(status);
3990 if (retval == SIGINT)
3996 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
3997 jobno(job), job->nprocs, status, retval));
4002 waitcmd(int argc, char **argv)
4011 raise_exception(EXSIG);
4018 /* wait for all jobs */
4022 if (!jp) /* no running procs */
4024 if (jp->state == JOBRUNNING)
4029 dowait(DOWAIT_BLOCK, NULL);
4035 if (**argv != '%') {
4036 pid_t pid = number(*argv);
4041 if (job->ps[job->nprocs - 1].pid == pid)
4043 job = job->prev_job;
4046 job = getjob(*argv, 0);
4047 /* loop until process terminated or stopped */
4048 while (job->state == JOBRUNNING)
4049 dowait(DOWAIT_BLOCK, NULL);
4051 retval = getstatus(job);
4065 struct job *jp, *jq;
4067 len = njobs * sizeof(*jp);
4069 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4071 offset = (char *)jp - (char *)jq;
4073 /* Relocate pointers */
4076 jq = (struct job *)((char *)jq + l);
4080 #define joff(p) ((struct job *)((char *)(p) + l))
4081 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4082 if (joff(jp)->ps == &jq->ps0)
4083 jmove(joff(jp)->ps);
4084 if (joff(jp)->prev_job)
4085 jmove(joff(jp)->prev_job);
4095 jp = (struct job *)((char *)jp + len);
4099 } while (--jq >= jp);
4104 * Return a new job structure.
4105 * Called with interrupts off.
4108 makejob(union node *node, int nprocs)
4113 for (i = njobs, jp = jobtab; ; jp++) {
4120 if (jp->state != JOBDONE || !jp->waited)
4129 memset(jp, 0, sizeof(*jp));
4131 /* jp->jobctl is a bitfield.
4132 * "jp->jobctl |= jobctl" likely to give awful code */
4136 jp->prev_job = curjob;
4141 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4143 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
4150 * Return a string identifying a command (to be printed by the
4153 static char *cmdnextc;
4156 cmdputs(const char *s)
4158 const char *p, *str;
4159 char c, cc[2] = " ";
4163 static const char vstype[VSTYPE + 1][4] = {
4164 "", "}", "-", "+", "?", "=",
4165 "%", "%%", "#", "##"
4168 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4170 while ((c = *p++) != 0) {
4178 if ((subtype & VSTYPE) == VSLENGTH)
4182 if (!(subtype & VSQUOTE) == !(quoted & 1))
4188 str = "\"}" + !(quoted & 1);
4195 case CTLBACKQ+CTLQUOTE:
4198 #if ENABLE_ASH_MATH_SUPPORT
4213 if ((subtype & VSTYPE) != VSNORMAL)
4215 str = vstype[subtype & VSTYPE];
4216 if (subtype & VSNUL)
4225 /* These can only happen inside quotes */
4238 while ((c = *str++)) {
4243 USTPUTC('"', nextc);
4249 /* cmdtxt() and cmdlist() call each other */
4250 static void cmdtxt(union node *n);
4253 cmdlist(union node *np, int sep)
4255 for (; np; np = np->narg.next) {
4259 if (sep && np->narg.next)
4265 cmdtxt(union node *n)
4268 struct nodelist *lp;
4280 lp = n->npipe.cmdlist;
4298 cmdtxt(n->nbinary.ch1);
4314 cmdtxt(n->nif.test);
4317 if (n->nif.elsepart) {
4320 n = n->nif.elsepart;
4336 cmdtxt(n->nbinary.ch1);
4346 cmdputs(n->nfor.var);
4348 cmdlist(n->nfor.args, 1);
4353 cmdputs(n->narg.text);
4357 cmdlist(n->ncmd.args, 1);
4358 cmdlist(n->ncmd.redirect, 0);
4371 cmdputs(n->ncase.expr->narg.text);
4373 for (np = n->ncase.cases; np; np = np->nclist.next) {
4374 cmdtxt(np->nclist.pattern);
4376 cmdtxt(np->nclist.body);
4402 s[0] = n->nfile.fd + '0';
4406 if (n->type == NTOFD || n->type == NFROMFD) {
4407 s[0] = n->ndup.dupfd + '0';
4417 commandtext(union node *n)
4421 STARTSTACKSTR(cmdnextc);
4423 name = stackblock();
4424 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4425 name, cmdnextc, cmdnextc));
4426 return ckstrdup(name);
4431 * Fork off a subshell. If we are doing job control, give the subshell its
4432 * own process group. Jp is a job structure that the job is to be added to.
4433 * N is the command that will be evaluated by the child. Both jp and n may
4434 * be NULL. The mode parameter can be one of the following:
4435 * FORK_FG - Fork off a foreground process.
4436 * FORK_BG - Fork off a background process.
4437 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4438 * process group even if job control is on.
4440 * When job control is turned off, background processes have their standard
4441 * input redirected to /dev/null (except for the second and later processes
4444 * Called with interrupts off.
4447 * Clear traps on a fork.
4454 for (tp = trap; tp < &trap[NSIG]; tp++) {
4455 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4460 setsignal(tp - trap);
4466 /* Lives far away from here, needed for forkchild */
4467 static void closescript(void);
4469 /* Called after fork(), in child */
4471 forkchild(struct job *jp, union node *n, int mode)
4475 TRACE(("Child shell %d\n", getpid()));
4482 /* do job control only in root shell */
4484 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4487 if (jp->nprocs == 0)
4490 pgrp = jp->ps[0].pid;
4491 /* This can fail because we are doing it in the parent also */
4492 (void)setpgid(0, pgrp);
4493 if (mode == FORK_FG)
4494 xtcsetpgrp(ttyfd, pgrp);
4499 if (mode == FORK_BG) {
4502 if (jp->nprocs == 0) {
4504 if (open(bb_dev_null, O_RDONLY) != 0)
4505 ash_msg_and_raise_error("can't open %s", bb_dev_null);
4508 if (!oldlvl && iflag) {
4513 for (jp = curjob; jp; jp = jp->prev_job)
4518 /* Called after fork(), in parent */
4520 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4522 TRACE(("In parent shell: child = %d\n", pid));
4524 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4530 if (mode != FORK_NOJOB && jp->jobctl) {
4533 if (jp->nprocs == 0)
4536 pgrp = jp->ps[0].pid;
4537 /* This can fail because we are doing it in the child also */
4541 if (mode == FORK_BG) {
4542 backgndpid = pid; /* set $! */
4543 set_curjob(jp, CUR_RUNNING);
4546 struct procstat *ps = &jp->ps[jp->nprocs++];
4552 ps->cmd = commandtext(n);
4558 forkshell(struct job *jp, union node *n, int mode)
4562 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4565 TRACE(("Fork failed, errno=%d", errno));
4568 ash_msg_and_raise_error("cannot fork");
4571 forkchild(jp, n, mode);
4573 forkparent(jp, n, mode, pid);
4578 * Wait for job to finish.
4580 * Under job control we have the problem that while a child process is
4581 * running interrupts generated by the user are sent to the child but not
4582 * to the shell. This means that an infinite loop started by an inter-
4583 * active user may be hard to kill. With job control turned off, an
4584 * interactive user may place an interactive program inside a loop. If
4585 * the interactive program catches interrupts, the user doesn't want
4586 * these interrupts to also abort the loop. The approach we take here
4587 * is to have the shell ignore interrupt signals while waiting for a
4588 * foreground process to terminate, and then send itself an interrupt
4589 * signal if the child process was terminated by an interrupt signal.
4590 * Unfortunately, some programs want to do a bit of cleanup and then
4591 * exit on interrupt; unless these processes terminate themselves by
4592 * sending a signal to themselves (instead of calling exit) they will
4593 * confuse this approach.
4595 * Called with interrupts off.
4598 waitforjob(struct job *jp)
4602 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4603 while (jp->state == JOBRUNNING) {
4604 dowait(DOWAIT_BLOCK, jp);
4609 xtcsetpgrp(ttyfd, rootpid);
4611 * This is truly gross.
4612 * If we're doing job control, then we did a TIOCSPGRP which
4613 * caused us (the shell) to no longer be in the controlling
4614 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4615 * intuit from the subprocess exit status whether a SIGINT
4616 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4618 if (jp->sigint) /* TODO: do the same with all signals */
4619 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4621 if (jp->state == JOBDONE)
4628 * return 1 if there are stopped jobs, otherwise 0
4640 if (jp && jp->state == JOBSTOPPED) {
4641 out2str("You have stopped jobs.\n");
4650 /* ============ redir.c
4652 * Code for dealing with input/output redirection.
4655 #define EMPTY -2 /* marks an unused slot in redirtab */
4656 #define CLOSED -3 /* marks a slot of previously-closed fd */
4658 # define PIPESIZE 4096 /* amount of buffering in a pipe */
4660 # define PIPESIZE PIPE_BUF
4664 * Open a file in noclobber mode.
4665 * The code was copied from bash.
4668 noclobberopen(const char *fname)
4671 struct stat finfo, finfo2;
4674 * If the file exists and is a regular file, return an error
4677 r = stat(fname, &finfo);
4678 if (r == 0 && S_ISREG(finfo.st_mode)) {
4684 * If the file was not present (r != 0), make sure we open it
4685 * exclusively so that if it is created before we open it, our open
4686 * will fail. Make sure that we do not truncate an existing file.
4687 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4688 * file was not a regular file, we leave O_EXCL off.
4691 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4692 fd = open(fname, O_WRONLY|O_CREAT, 0666);
4694 /* If the open failed, return the file descriptor right away. */
4699 * OK, the open succeeded, but the file may have been changed from a
4700 * non-regular file to a regular file between the stat and the open.
4701 * We are assuming that the O_EXCL open handles the case where FILENAME
4702 * did not exist and is symlinked to an existing file between the stat
4707 * If we can open it and fstat the file descriptor, and neither check
4708 * revealed that it was a regular file, and the file has not been
4709 * replaced, return the file descriptor.
4711 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4712 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4715 /* The file has been replaced. badness. */
4722 * Handle here documents. Normally we fork off a process to write the
4723 * data to a pipe. If the document is short, we can stuff the data in
4724 * the pipe without forking.
4726 /* openhere needs this forward reference */
4727 static void expandhere(union node *arg, int fd);
4729 openhere(union node *redir)
4735 ash_msg_and_raise_error("pipe call failed");
4736 if (redir->type == NHERE) {
4737 len = strlen(redir->nhere.doc->narg.text);
4738 if (len <= PIPESIZE) {
4739 full_write(pip[1], redir->nhere.doc->narg.text, len);
4743 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4745 signal(SIGINT, SIG_IGN);
4746 signal(SIGQUIT, SIG_IGN);
4747 signal(SIGHUP, SIG_IGN);
4749 signal(SIGTSTP, SIG_IGN);
4751 signal(SIGPIPE, SIG_DFL);
4752 if (redir->type == NHERE)
4753 full_write(pip[1], redir->nhere.doc->narg.text, len);
4755 expandhere(redir->nhere.doc, pip[1]);
4764 openredirect(union node *redir)
4769 switch (redir->nfile.type) {
4771 fname = redir->nfile.expfname;
4772 f = open(fname, O_RDONLY);
4777 fname = redir->nfile.expfname;
4778 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
4783 /* Take care of noclobber mode. */
4785 fname = redir->nfile.expfname;
4786 f = noclobberopen(fname);
4793 fname = redir->nfile.expfname;
4794 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4799 fname = redir->nfile.expfname;
4800 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4808 /* Fall through to eliminate warning. */
4815 f = openhere(redir);
4821 ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4823 ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "no such file"));
4827 * Copy a file descriptor to be >= to. Returns -1
4828 * if the source file descriptor is closed, EMPTY if there are no unused
4829 * file descriptors left.
4832 copyfd(int from, int to)
4836 newfd = fcntl(from, F_DUPFD, to);
4838 if (errno == EMFILE)
4840 ash_msg_and_raise_error("%d: %m", from);
4846 dupredirect(union node *redir, int f)
4848 int fd = redir->nfile.fd;
4850 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
4851 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
4852 copyfd(redir->ndup.dupfd, fd);
4864 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
4865 * old file descriptors are stashed away so that the redirection can be
4866 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
4867 * standard output, and the standard error if it becomes a duplicate of
4868 * stdout, is saved in memory.
4870 /* flags passed to redirect */
4871 #define REDIR_PUSH 01 /* save previous values of file descriptors */
4872 #define REDIR_SAVEFD2 03 /* set preverrout */
4874 redirect(union node *redir, int flags)
4877 struct redirtab *sv;
4888 if (flags & REDIR_PUSH) {
4889 sv = ckmalloc(sizeof(*sv));
4890 sv->next = redirlist;
4892 sv->nullredirs = g_nullredirs - 1;
4893 for (i = 0; i < 10; i++)
4894 sv->renamed[i] = EMPTY;
4900 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD)
4901 && n->ndup.dupfd == fd)
4902 continue; /* redirect from/to same file descriptor */
4904 newfd = openredirect(n);
4906 /* Descriptor wasn't open before redirect.
4907 * Mark it for close in the future */
4908 if (sv && sv->renamed[fd] == EMPTY)
4909 sv->renamed[fd] = CLOSED;
4912 if (sv && sv->renamed[fd] == EMPTY) {
4913 i = fcntl(fd, F_DUPFD, 10);
4920 ash_msg_and_raise_error("%d: %m", fd);
4924 sv->renamed[fd] = i;
4930 dupredirect(n, newfd);
4931 } while ((n = n->nfile.next));
4933 if ((flags & REDIR_SAVEFD2) && sv && sv->renamed[2] >= 0)
4934 preverrout_fd = sv->renamed[2];
4938 * Undo the effects of the last redirection.
4943 struct redirtab *rp;
4946 if (--g_nullredirs >= 0)
4950 for (i = 0; i < 10; i++) {
4951 if (rp->renamed[i] == CLOSED) {
4956 if (rp->renamed[i] != EMPTY) {
4959 copyfd(rp->renamed[i], i);
4961 close(rp->renamed[i]);
4964 redirlist = rp->next;
4965 g_nullredirs = rp->nullredirs;
4971 * Undo all redirections. Called on error or interrupt.
4975 * Discard all saved file descriptors.
4978 clearredir(int drop)
4989 redirectsafe(union node *redir, int flags)
4992 volatile int saveint;
4993 struct jmploc *volatile savehandler = exception_handler;
4994 struct jmploc jmploc;
4997 err = setjmp(jmploc.loc) * 2;
4999 exception_handler = &jmploc;
5000 redirect(redir, flags);
5002 exception_handler = savehandler;
5003 if (err && exception != EXERROR)
5004 longjmp(exception_handler->loc, 1);
5005 RESTORE_INT(saveint);
5010 /* ============ Routines to expand arguments to commands
5012 * We have to deal with backquotes, shell variables, and file metacharacters.
5018 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5019 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5020 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5021 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5022 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5023 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5024 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5025 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5026 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5030 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5031 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5032 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5033 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5034 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5037 * Structure specifying which parts of the string should be searched
5038 * for IFS characters.
5041 struct ifsregion *next; /* next region in list */
5042 int begoff; /* offset of start of region */
5043 int endoff; /* offset of end of region */
5044 int nulonly; /* search for nul bytes only */
5048 struct strlist *list;
5049 struct strlist **lastp;
5052 /* output of current string */
5053 static char *expdest;
5054 /* list of back quote expressions */
5055 static struct nodelist *argbackq;
5056 /* first struct in list of ifs regions */
5057 static struct ifsregion ifsfirst;
5058 /* last struct in list */
5059 static struct ifsregion *ifslastp;
5060 /* holds expanded arg list */
5061 static struct arglist exparg;
5071 expdest = makestrspace(32, expdest);
5072 #if ENABLE_ASH_MATH_SUPPORT_64
5073 len = fmtstr(expdest, 32, "%lld", (long long) num);
5075 len = fmtstr(expdest, 32, "%ld", num);
5077 STADJUST(len, expdest);
5082 esclen(const char *start, const char *p)
5086 while (p > start && *--p == CTLESC) {
5093 * Remove any CTLESC characters from a string.
5096 _rmescapes(char *str, int flag)
5098 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5105 p = strpbrk(str, qchars);
5111 if (flag & RMESCAPE_ALLOC) {
5112 size_t len = p - str;
5113 size_t fulllen = len + strlen(p) + 1;
5115 if (flag & RMESCAPE_GROW) {
5116 r = makestrspace(fulllen, expdest);
5117 } else if (flag & RMESCAPE_HEAP) {
5118 r = ckmalloc(fulllen);
5120 r = stalloc(fulllen);
5124 q = memcpy(q, str, len) + len;
5127 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5128 globbing = flag & RMESCAPE_GLOB;
5129 notescaped = globbing;
5131 if (*p == CTLQUOTEMARK) {
5132 inquotes = ~inquotes;
5134 notescaped = globbing;
5138 /* naked back slash */
5144 if (notescaped && inquotes && *p != '/') {
5148 notescaped = globbing;
5153 if (flag & RMESCAPE_GROW) {
5155 STADJUST(q - r + 1, expdest);
5159 #define rmescapes(p) _rmescapes((p), 0)
5161 #define pmatch(a, b) !fnmatch((a), (b), 0)
5164 * Prepare a pattern for a expmeta (internal glob(3)) call.
5166 * Returns an stalloced string.
5169 preglob(const char *pattern, int quoted, int flag)
5171 flag |= RMESCAPE_GLOB;
5173 flag |= RMESCAPE_QUOTED;
5175 return _rmescapes((char *)pattern, flag);
5179 * Put a string on the stack.
5182 memtodest(const char *p, size_t len, int syntax, int quotes)
5186 q = makestrspace(len * 2, q);
5189 int c = signed_char2int(*p++);
5192 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5201 strtodest(const char *p, int syntax, int quotes)
5203 memtodest(p, strlen(p), syntax, quotes);
5207 * Record the fact that we have to scan this region of the
5208 * string for IFS characters.
5211 recordregion(int start, int end, int nulonly)
5213 struct ifsregion *ifsp;
5215 if (ifslastp == NULL) {
5219 ifsp = ckmalloc(sizeof(*ifsp));
5221 ifslastp->next = ifsp;
5225 ifslastp->begoff = start;
5226 ifslastp->endoff = end;
5227 ifslastp->nulonly = nulonly;
5231 removerecordregions(int endoff)
5233 if (ifslastp == NULL)
5236 if (ifsfirst.endoff > endoff) {
5237 while (ifsfirst.next != NULL) {
5238 struct ifsregion *ifsp;
5240 ifsp = ifsfirst.next->next;
5241 free(ifsfirst.next);
5242 ifsfirst.next = ifsp;
5245 if (ifsfirst.begoff > endoff)
5248 ifslastp = &ifsfirst;
5249 ifsfirst.endoff = endoff;
5254 ifslastp = &ifsfirst;
5255 while (ifslastp->next && ifslastp->next->begoff < endoff)
5256 ifslastp=ifslastp->next;
5257 while (ifslastp->next != NULL) {
5258 struct ifsregion *ifsp;
5260 ifsp = ifslastp->next->next;
5261 free(ifslastp->next);
5262 ifslastp->next = ifsp;
5265 if (ifslastp->endoff > endoff)
5266 ifslastp->endoff = endoff;
5270 exptilde(char *startp, char *p, int flag)
5276 int quotes = flag & (EXP_FULL | EXP_CASE);
5281 while ((c = *++p) != '\0') {
5288 if (flag & EXP_VARTILDE)
5298 if (*name == '\0') {
5299 home = lookupvar(homestr);
5301 pw = getpwnam(name);
5306 if (!home || !*home)
5309 startloc = expdest - (char *)stackblock();
5310 strtodest(home, SQSYNTAX, quotes);
5311 recordregion(startloc, expdest - (char *)stackblock(), 0);
5319 * Execute a command inside back quotes. If it's a builtin command, we
5320 * want to save its output in a block obtained from malloc. Otherwise
5321 * we fork off a subprocess and get the output of the command via a pipe.
5322 * Should be called with interrupts off.
5324 struct backcmd { /* result of evalbackcmd */
5325 int fd; /* file descriptor to read from */
5326 char *buf; /* buffer */
5327 int nleft; /* number of chars in buffer */
5328 struct job *jp; /* job structure for command */
5331 /* These forward decls are needed to use "eval" code for backticks handling: */
5332 static int back_exitstatus; /* exit status of backquoted command */
5333 #define EV_EXIT 01 /* exit after evaluating tree */
5334 static void evaltree(union node *, int);
5337 evalbackcmd(union node *n, struct backcmd *result)
5349 saveherefd = herefd;
5357 ash_msg_and_raise_error("pipe call failed");
5359 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5368 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5372 result->fd = pip[0];
5375 herefd = saveherefd;
5377 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5378 result->fd, result->buf, result->nleft, result->jp));
5382 * Expand stuff in backwards quotes.
5385 expbackq(union node *cmd, int quoted, int quotes)
5393 int syntax = quoted? DQSYNTAX : BASESYNTAX;
5394 struct stackmark smark;
5397 setstackmark(&smark);
5399 startloc = dest - (char *)stackblock();
5401 evalbackcmd(cmd, &in);
5402 popstackmark(&smark);
5409 memtodest(p, i, syntax, quotes);
5413 i = safe_read(in.fd, buf, sizeof(buf));
5414 TRACE(("expbackq: read returns %d\n", i));
5423 back_exitstatus = waitforjob(in.jp);
5427 /* Eat all trailing newlines */
5429 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5434 recordregion(startloc, dest - (char *)stackblock(), 0);
5435 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5436 (dest - (char *)stackblock()) - startloc,
5437 (dest - (char *)stackblock()) - startloc,
5438 stackblock() + startloc));
5441 #if ENABLE_ASH_MATH_SUPPORT
5443 * Expand arithmetic expression. Backup to start of expression,
5444 * evaluate, place result in (backed up) result, adjust string position.
5457 * This routine is slightly over-complicated for
5458 * efficiency. Next we scan backwards looking for the
5459 * start of arithmetic.
5461 start = stackblock();
5468 while (*p != CTLARI) {
5472 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5477 esc = esclen(start, p);
5487 removerecordregions(begoff);
5496 len = cvtnum(dash_arith(p + 2));
5499 recordregion(begoff, begoff + len, 0);
5503 /* argstr needs it */
5504 static char *evalvar(char *p, int flag);
5507 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5508 * characters to allow for further processing. Otherwise treat
5509 * $@ like $* since no splitting will be performed.
5512 argstr(char *p, int flag)
5514 static const char spclchars[] ALIGN1 = {
5522 CTLBACKQ | CTLQUOTE,
5523 #if ENABLE_ASH_MATH_SUPPORT
5528 const char *reject = spclchars;
5530 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
5531 int breakall = flag & EXP_WORD;
5536 if (!(flag & EXP_VARTILDE)) {
5538 } else if (flag & EXP_VARTILDE2) {
5543 if (flag & EXP_TILDE) {
5549 if (*q == CTLESC && (flag & EXP_QWORD))
5552 p = exptilde(p, q, flag);
5555 startloc = expdest - (char *)stackblock();
5557 length += strcspn(p + length, reject);
5559 if (c && (!(c & 0x80)
5560 #if ENABLE_ASH_MATH_SUPPORT
5564 /* c == '=' || c == ':' || c == CTLENDARI */
5569 expdest = stack_nputstr(p, length, expdest);
5570 newloc = expdest - (char *)stackblock();
5571 if (breakall && !inquotes && newloc > startloc) {
5572 recordregion(startloc, newloc, 0);
5583 if (flag & EXP_VARTILDE2) {
5587 flag |= EXP_VARTILDE2;
5592 * sort of a hack - expand tildes in variable
5593 * assignments (after the first '=' and after ':'s).
5602 case CTLENDVAR: /* ??? */
5605 /* "$@" syntax adherence hack */
5608 !memcmp(p, dolatstr, 4) &&
5609 (p[4] == CTLQUOTEMARK || (
5610 p[4] == CTLENDVAR &&
5611 p[5] == CTLQUOTEMARK
5614 p = evalvar(p + 1, flag) + 1;
5617 inquotes = !inquotes;
5630 p = evalvar(p, flag);
5634 case CTLBACKQ|CTLQUOTE:
5635 expbackq(argbackq->n, c, quotes);
5636 argbackq = argbackq->next;
5638 #if ENABLE_ASH_MATH_SUPPORT
5651 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5662 const char *s = loc2;
5668 match = pmatch(str, s);
5672 if (quotes && *loc == CTLESC)
5681 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5688 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5691 const char *s = loc2;
5696 match = pmatch(str, s);
5703 esc = esclen(startp, loc);
5714 static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN;
5716 varunset(const char *end, const char *var, const char *umsg, int varflags)
5722 msg = "parameter not set";
5724 if (*end == CTLENDVAR) {
5725 if (varflags & VSNUL)
5730 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5734 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5738 int saveherefd = herefd;
5739 struct nodelist *saveargbackq = argbackq;
5741 char *rmesc, *rmescend;
5743 char *(*scan)(char *, char *, char *, char *, int , int);
5746 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5747 STPUTC('\0', expdest);
5748 herefd = saveherefd;
5749 argbackq = saveargbackq;
5750 startp = stackblock() + startloc;
5754 setvar(str, startp, 0);
5755 amount = startp - expdest;
5756 STADJUST(amount, expdest);
5760 varunset(p, str, startp, varflags);
5764 subtype -= VSTRIMRIGHT;
5766 if (subtype < 0 || subtype > 3)
5771 rmescend = stackblock() + strloc;
5773 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5774 if (rmesc != startp) {
5776 startp = stackblock() + startloc;
5780 str = stackblock() + strloc;
5781 preglob(str, varflags & VSQUOTE, 0);
5783 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5784 zero = subtype >> 1;
5785 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5786 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5788 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5791 memmove(startp, loc, str - loc);
5792 loc = startp + (str - loc) - 1;
5795 amount = loc - expdest;
5796 STADJUST(amount, expdest);
5802 * Add the value of a specialized variable to the stack string.
5805 varvalue(char *name, int varflags, int flags)
5815 int quoted = varflags & VSQUOTE;
5816 int subtype = varflags & VSTYPE;
5817 int quotes = flags & (EXP_FULL | EXP_CASE);
5819 if (quoted && (flags & EXP_FULL))
5820 sep = 1 << CHAR_BIT;
5822 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5831 num = shellparam.nparam;
5841 p = makestrspace(NOPTS, expdest);
5842 for (i = NOPTS - 1; i >= 0; i--) {
5844 USTPUTC(optletters(i), p);
5855 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
5856 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5862 while ((p = *ap++)) {
5865 partlen = strlen(p);
5868 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5869 memtodest(p, partlen, syntax, quotes);
5875 if (subtype == VSPLUS || subtype == VSLENGTH) {
5897 if (num < 0 || num > shellparam.nparam)
5899 p = num ? shellparam.p[num - 1] : arg0;
5902 p = lookupvar(name);
5908 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5909 memtodest(p, len, syntax, quotes);
5913 if (subtype == VSPLUS || subtype == VSLENGTH)
5914 STADJUST(-len, expdest);
5919 * Expand a variable, and return a pointer to the next character in the
5923 evalvar(char *p, int flag)
5936 quotes = flag & (EXP_FULL | EXP_CASE);
5938 subtype = varflags & VSTYPE;
5939 quoted = varflags & VSQUOTE;
5941 easy = (!quoted || (*var == '@' && shellparam.nparam));
5942 startloc = expdest - (char *)stackblock();
5943 p = strchr(p, '=') + 1;
5946 varlen = varvalue(var, varflags, flag);
5947 if (varflags & VSNUL)
5950 if (subtype == VSPLUS) {
5951 varlen = -1 - varlen;
5955 if (subtype == VSMINUS) {
5959 p, flag | EXP_TILDE |
5960 (quoted ? EXP_QWORD : EXP_WORD)
5969 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5971 if (subevalvar(p, var, 0, subtype, startloc, varflags, 0)) {
5974 * Remove any recorded regions beyond
5977 removerecordregions(startloc);
5987 if (varlen < 0 && uflag)
5988 varunset(p, var, 0, 0);
5990 if (subtype == VSLENGTH) {
5991 cvtnum(varlen > 0 ? varlen : 0);
5995 if (subtype == VSNORMAL) {
5999 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6008 case VSTRIMRIGHTMAX:
6017 * Terminate the string and start recording the pattern
6020 STPUTC('\0', expdest);
6021 patloc = expdest - (char *)stackblock();
6022 if (subevalvar(p, NULL, patloc, subtype,
6023 startloc, varflags, quotes) == 0) {
6024 int amount = expdest - (
6025 (char *)stackblock() + patloc - 1
6027 STADJUST(-amount, expdest);
6029 /* Remove any recorded regions beyond start of variable */
6030 removerecordregions(startloc);
6035 if (subtype != VSNORMAL) { /* skip to end of alternative */
6041 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6043 argbackq = argbackq->next;
6044 } else if (c == CTLVAR) {
6045 if ((*p++ & VSTYPE) != VSNORMAL)
6047 } else if (c == CTLENDVAR) {
6057 * Break the argument string into pieces based upon IFS and add the
6058 * strings to the argument list. The regions of the string to be
6059 * searched for IFS characters have been stored by recordregion.
6062 ifsbreakup(char *string, struct arglist *arglist)
6064 struct ifsregion *ifsp;
6069 const char *ifs, *realifs;
6074 if (ifslastp != NULL) {
6077 realifs = ifsset() ? ifsval() : defifs;
6080 p = string + ifsp->begoff;
6081 nulonly = ifsp->nulonly;
6082 ifs = nulonly ? nullstr : realifs;
6084 while (p < string + ifsp->endoff) {
6088 if (!strchr(ifs, *p)) {
6093 ifsspc = (strchr(defifs, *p) != NULL);
6094 /* Ignore IFS whitespace at start */
6095 if (q == start && ifsspc) {
6101 sp = stalloc(sizeof(*sp));
6103 *arglist->lastp = sp;
6104 arglist->lastp = &sp->next;
6108 if (p >= string + ifsp->endoff) {
6114 if (strchr(ifs, *p) == NULL ) {
6117 } else if (strchr(defifs, *p) == NULL) {
6132 } while (ifsp != NULL);
6141 sp = stalloc(sizeof(*sp));
6143 *arglist->lastp = sp;
6144 arglist->lastp = &sp->next;
6150 struct ifsregion *p;
6155 struct ifsregion *ifsp;
6161 ifsfirst.next = NULL;
6166 * Add a file name to the list.
6169 addfname(const char *name)
6173 sp = stalloc(sizeof(*sp));
6174 sp->text = ststrdup(name);
6176 exparg.lastp = &sp->next;
6179 static char *expdir;
6182 * Do metacharacter (i.e. *, ?, [...]) expansion.
6185 expmeta(char *enddir, char *name)
6200 for (p = name; *p; p++) {
6201 if (*p == '*' || *p == '?')
6203 else if (*p == '[') {
6210 if (*q == '/' || *q == '\0')
6217 } else if (*p == '\\')
6219 else if (*p == '/') {
6226 if (metaflag == 0) { /* we've reached the end of the file name */
6227 if (enddir != expdir)
6235 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6246 } while (p < start);
6248 if (enddir == expdir) {
6250 } else if (enddir == expdir + 1 && *expdir == '/') {
6259 if (enddir != expdir)
6261 if (*endname == 0) {
6273 while (!intpending && (dp = readdir(dirp)) != NULL) {
6274 if (dp->d_name[0] == '.' && ! matchdot)
6276 if (pmatch(start, dp->d_name)) {
6278 strcpy(enddir, dp->d_name);
6281 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6284 expmeta(p, endname);
6293 static struct strlist *
6294 msort(struct strlist *list, int len)
6296 struct strlist *p, *q = NULL;
6297 struct strlist **lpp;
6305 for (n = half; --n >= 0; ) {
6309 q->next = NULL; /* terminate first half of list */
6310 q = msort(list, half); /* sort first half of list */
6311 p = msort(p, len - half); /* sort second half */
6314 #if ENABLE_LOCALE_SUPPORT
6315 if (strcoll(p->text, q->text) < 0)
6317 if (strcmp(p->text, q->text) < 0)
6341 * Sort the results of file name expansion. It calculates the number of
6342 * strings to sort and then calls msort (short for merge sort) to do the
6345 static struct strlist *
6346 expsort(struct strlist *str)
6352 for (sp = str; sp; sp = sp->next)
6354 return msort(str, len);
6358 expandmeta(struct strlist *str, int flag)
6360 static const char metachars[] ALIGN1 = {
6363 /* TODO - EXP_REDIR */
6366 struct strlist **savelastp;
6372 if (!strpbrk(str->text, metachars))
6374 savelastp = exparg.lastp;
6377 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
6379 int i = strlen(str->text);
6380 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
6388 if (exparg.lastp == savelastp) {
6393 *exparg.lastp = str;
6394 rmescapes(str->text);
6395 exparg.lastp = &str->next;
6397 *exparg.lastp = NULL;
6398 *savelastp = sp = expsort(*savelastp);
6399 while (sp->next != NULL)
6401 exparg.lastp = &sp->next;
6408 * Perform variable substitution and command substitution on an argument,
6409 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6410 * perform splitting and file name expansion. When arglist is NULL, perform
6411 * here document expansion.
6414 expandarg(union node *arg, struct arglist *arglist, int flag)
6419 argbackq = arg->narg.backquote;
6420 STARTSTACKSTR(expdest);
6421 ifsfirst.next = NULL;
6423 argstr(arg->narg.text, flag);
6424 p = _STPUTC('\0', expdest);
6426 if (arglist == NULL) {
6427 return; /* here document expanded */
6429 p = grabstackstr(p);
6430 exparg.lastp = &exparg.list;
6434 if (flag & EXP_FULL) {
6435 ifsbreakup(p, &exparg);
6436 *exparg.lastp = NULL;
6437 exparg.lastp = &exparg.list;
6438 expandmeta(exparg.list, flag);
6440 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
6442 sp = stalloc(sizeof(*sp));
6445 exparg.lastp = &sp->next;
6449 *exparg.lastp = NULL;
6451 *arglist->lastp = exparg.list;
6452 arglist->lastp = exparg.lastp;
6457 * Expand shell variables and backquotes inside a here document.
6460 expandhere(union node *arg, int fd)
6463 expandarg(arg, (struct arglist *)NULL, 0);
6464 full_write(fd, stackblock(), expdest - (char *)stackblock());
6468 * Returns true if the pattern matches the string.
6471 patmatch(char *pattern, const char *string)
6473 return pmatch(preglob(pattern, 0, 0), string);
6477 * See if a pattern matches in a case statement.
6480 casematch(union node *pattern, char *val)
6482 struct stackmark smark;
6485 setstackmark(&smark);
6486 argbackq = pattern->narg.backquote;
6487 STARTSTACKSTR(expdest);
6489 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
6490 STACKSTRNUL(expdest);
6491 result = patmatch(stackblock(), val);
6492 popstackmark(&smark);
6497 /* ============ find_command */
6501 int (*builtin)(int, char **);
6502 /* unsigned flags; */
6504 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
6505 /* "regular" builtins always take precedence over commands,
6506 * regardless of PATH=....%builtin... position */
6507 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
6508 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
6514 const struct builtincmd *cmd;
6515 struct funcnode *func;
6518 /* values of cmdtype */
6519 #define CMDUNKNOWN -1 /* no entry in table for command */
6520 #define CMDNORMAL 0 /* command is an executable program */
6521 #define CMDFUNCTION 1 /* command is a shell function */
6522 #define CMDBUILTIN 2 /* command is a shell builtin */
6524 /* action to find_command() */
6525 #define DO_ERR 0x01 /* prints errors */
6526 #define DO_ABS 0x02 /* checks absolute paths */
6527 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
6528 #define DO_ALTPATH 0x08 /* using alternate path */
6529 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
6531 static void find_command(char *, struct cmdentry *, int, const char *);
6534 /* ============ Hashing commands */
6537 * When commands are first encountered, they are entered in a hash table.
6538 * This ensures that a full path search will not have to be done for them
6539 * on each invocation.
6541 * We should investigate converting to a linear search, even though that
6542 * would make the command name "hash" a misnomer.
6545 #define ARB 1 /* actual size determined at run time */
6548 struct tblentry *next; /* next entry in hash chain */
6549 union param param; /* definition of builtin function */
6550 short cmdtype; /* index identifying command */
6551 char rehash; /* if set, cd done since entry created */
6552 char cmdname[ARB]; /* name of command */
6555 static struct tblentry **cmdtable;
6556 #define INIT_G_cmdtable() do { \
6557 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
6560 static int builtinloc = -1; /* index in path of %builtin, or -1 */
6564 tryexec(char *cmd, char **argv, char **envp)
6568 #if ENABLE_FEATURE_SH_STANDALONE
6569 if (strchr(cmd, '/') == NULL) {
6570 int a = find_applet_by_name(cmd);
6572 if (APPLET_IS_NOEXEC(a))
6573 run_applet_no_and_exit(a, argv);
6574 /* re-exec ourselves with the new arguments */
6575 execve(bb_busybox_exec_path, argv, envp);
6576 /* If they called chroot or otherwise made the binary no longer
6577 * executable, fall through */
6585 execve(cmd, argv, envp);
6586 } while (errno == EINTR);
6588 execve(cmd, argv, envp);
6592 } else if (errno == ENOEXEC) {
6596 for (ap = argv; *ap; ap++)
6598 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
6600 ap[0] = cmd = (char *)DEFAULT_SHELL;
6603 while ((*ap++ = *argv++))
6611 * Exec a program. Never returns. If you change this routine, you may
6612 * have to change the find_command routine as well.
6614 #define environment() listvars(VEXPORT, VUNSET, 0)
6615 static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
6617 shellexec(char **argv, const char *path, int idx)
6625 envp = environment();
6626 if (strchr(argv[0], '/')
6627 #if ENABLE_FEATURE_SH_STANDALONE
6628 || find_applet_by_name(argv[0]) >= 0
6631 tryexec(argv[0], argv, envp);
6635 while ((cmdname = padvance(&path, argv[0])) != NULL) {
6636 if (--idx < 0 && pathopt == NULL) {
6637 tryexec(cmdname, argv, envp);
6638 if (errno != ENOENT && errno != ENOTDIR)
6645 /* Map to POSIX errors */
6657 exitstatus = exerrno;
6658 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
6659 argv[0], e, suppressint ));
6660 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
6665 printentry(struct tblentry *cmdp)
6671 idx = cmdp->param.index;
6674 name = padvance(&path, cmdp->cmdname);
6676 } while (--idx >= 0);
6677 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
6681 * Clear out command entries. The argument specifies the first entry in
6682 * PATH which has changed.
6685 clearcmdentry(int firstchange)
6687 struct tblentry **tblp;
6688 struct tblentry **pp;
6689 struct tblentry *cmdp;
6692 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
6694 while ((cmdp = *pp) != NULL) {
6695 if ((cmdp->cmdtype == CMDNORMAL &&
6696 cmdp->param.index >= firstchange)
6697 || (cmdp->cmdtype == CMDBUILTIN &&
6698 builtinloc >= firstchange)
6711 * Locate a command in the command hash table. If "add" is nonzero,
6712 * add the command to the table if it is not already present. The
6713 * variable "lastcmdentry" is set to point to the address of the link
6714 * pointing to the entry, so that delete_cmd_entry can delete the
6717 * Interrupts must be off if called with add != 0.
6719 static struct tblentry **lastcmdentry;
6721 static struct tblentry *
6722 cmdlookup(const char *name, int add)
6724 unsigned int hashval;
6726 struct tblentry *cmdp;
6727 struct tblentry **pp;
6730 hashval = (unsigned char)*p << 4;
6732 hashval += (unsigned char)*p++;
6734 pp = &cmdtable[hashval % CMDTABLESIZE];
6735 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6736 if (strcmp(cmdp->cmdname, name) == 0)
6740 if (add && cmdp == NULL) {
6741 cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB
6742 + strlen(name) + 1);
6744 cmdp->cmdtype = CMDUNKNOWN;
6745 strcpy(cmdp->cmdname, name);
6752 * Delete the command entry returned on the last lookup.
6755 delete_cmd_entry(void)
6757 struct tblentry *cmdp;
6760 cmdp = *lastcmdentry;
6761 *lastcmdentry = cmdp->next;
6762 if (cmdp->cmdtype == CMDFUNCTION)
6763 freefunc(cmdp->param.func);
6769 * Add a new command entry, replacing any existing command entry for
6770 * the same name - except special builtins.
6773 addcmdentry(char *name, struct cmdentry *entry)
6775 struct tblentry *cmdp;
6777 cmdp = cmdlookup(name, 1);
6778 if (cmdp->cmdtype == CMDFUNCTION) {
6779 freefunc(cmdp->param.func);
6781 cmdp->cmdtype = entry->cmdtype;
6782 cmdp->param = entry->u;
6787 hashcmd(int argc, char **argv)
6789 struct tblentry **pp;
6790 struct tblentry *cmdp;
6792 struct cmdentry entry;
6795 if (nextopt("r") != '\0') {
6800 if (*argptr == NULL) {
6801 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
6802 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6803 if (cmdp->cmdtype == CMDNORMAL)
6811 while ((name = *argptr) != NULL) {
6812 cmdp = cmdlookup(name, 0);
6814 && (cmdp->cmdtype == CMDNORMAL
6815 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
6819 find_command(name, &entry, DO_ERR, pathval());
6820 if (entry.cmdtype == CMDUNKNOWN)
6828 * Called when a cd is done. Marks all commands so the next time they
6829 * are executed they will be rehashed.
6834 struct tblentry **pp;
6835 struct tblentry *cmdp;
6837 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
6838 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6839 if (cmdp->cmdtype == CMDNORMAL
6840 || (cmdp->cmdtype == CMDBUILTIN
6841 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
6851 * Fix command hash table when PATH changed.
6852 * Called before PATH is changed. The argument is the new value of PATH;
6853 * pathval() still returns the old value at this point.
6854 * Called with interrupts off.
6857 changepath(const char *new)
6865 firstchange = 9999; /* assume no change */
6871 if ((*old == '\0' && *new == ':')
6872 || (*old == ':' && *new == '\0'))
6874 old = new; /* ignore subsequent differences */
6878 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
6884 if (builtinloc < 0 && idx_bltin >= 0)
6885 builtinloc = idx_bltin; /* zap builtins */
6886 if (builtinloc >= 0 && idx_bltin < 0)
6888 clearcmdentry(firstchange);
6889 builtinloc = idx_bltin;
6904 #define TENDBQUOTE 12
6922 /* first char is indicating which tokens mark the end of a list */
6923 static const char *const tokname_array[] = {
6937 #define KWDOFFSET 13
6938 /* the following are keywords */
6960 static char buf[16];
6963 //if (tok < TSEMI) return tokname_array[tok] + 1;
6964 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
6969 sprintf(buf + (tok >= TSEMI), "%s%c",
6970 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
6974 /* Wrapper around strcmp for qsort/bsearch/... */
6976 pstrcmp(const void *a, const void *b)
6978 return strcmp((char*) a, (*(char**) b) + 1);
6981 static const char *const *
6982 findkwd(const char *s)
6984 return bsearch(s, tokname_array + KWDOFFSET,
6985 ARRAY_SIZE(tokname_array) - KWDOFFSET,
6986 sizeof(tokname_array[0]), pstrcmp);
6990 * Locate and print what a word is...
6993 describe_command(char *command, int describe_command_verbose)
6995 struct cmdentry entry;
6996 struct tblentry *cmdp;
6997 #if ENABLE_ASH_ALIAS
6998 const struct alias *ap;
7000 const char *path = pathval();
7002 if (describe_command_verbose) {
7006 /* First look at the keywords */
7007 if (findkwd(command)) {
7008 out1str(describe_command_verbose ? " is a shell keyword" : command);
7012 #if ENABLE_ASH_ALIAS
7013 /* Then look at the aliases */
7014 ap = lookupalias(command, 0);
7016 if (!describe_command_verbose) {
7021 out1fmt(" is an alias for %s", ap->val);
7025 /* Then check if it is a tracked alias */
7026 cmdp = cmdlookup(command, 0);
7028 entry.cmdtype = cmdp->cmdtype;
7029 entry.u = cmdp->param;
7031 /* Finally use brute force */
7032 find_command(command, &entry, DO_ABS, path);
7035 switch (entry.cmdtype) {
7037 int j = entry.u.index;
7043 p = padvance(&path, command);
7047 if (describe_command_verbose) {
7049 (cmdp ? " a tracked alias for" : nullstr), p
7058 if (describe_command_verbose) {
7059 out1str(" is a shell function");
7066 if (describe_command_verbose) {
7067 out1fmt(" is a %sshell builtin",
7068 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7069 "special " : nullstr
7077 if (describe_command_verbose) {
7078 out1str(": not found\n");
7083 outstr("\n", stdout);
7088 typecmd(int argc, char **argv)
7094 /* type -p ... ? (we don't bother checking for 'p') */
7095 if (argv[1] && argv[1][0] == '-') {
7100 err |= describe_command(argv[i++], verbose);
7105 #if ENABLE_ASH_CMDCMD
7107 commandcmd(int argc, char **argv)
7115 while ((c = nextopt("pvV")) != '\0')
7117 verify |= VERIFY_VERBOSE;
7119 verify |= VERIFY_BRIEF;
7125 return describe_command(*argptr, verify - VERIFY_BRIEF);
7132 /* ============ eval.c */
7134 static int funcblocksize; /* size of structures in function */
7135 static int funcstringsize; /* size of strings in node */
7136 static void *funcblock; /* block to allocate function from */
7137 static char *funcstring; /* block to allocate strings from */
7139 /* flags in argument to evaltree */
7140 #define EV_EXIT 01 /* exit after evaluating tree */
7141 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7142 #define EV_BACKCMD 04 /* command executing within back quotes */
7144 static const short nodesize[26] = {
7145 SHELL_ALIGN(sizeof(struct ncmd)),
7146 SHELL_ALIGN(sizeof(struct npipe)),
7147 SHELL_ALIGN(sizeof(struct nredir)),
7148 SHELL_ALIGN(sizeof(struct nredir)),
7149 SHELL_ALIGN(sizeof(struct nredir)),
7150 SHELL_ALIGN(sizeof(struct nbinary)),
7151 SHELL_ALIGN(sizeof(struct nbinary)),
7152 SHELL_ALIGN(sizeof(struct nbinary)),
7153 SHELL_ALIGN(sizeof(struct nif)),
7154 SHELL_ALIGN(sizeof(struct nbinary)),
7155 SHELL_ALIGN(sizeof(struct nbinary)),
7156 SHELL_ALIGN(sizeof(struct nfor)),
7157 SHELL_ALIGN(sizeof(struct ncase)),
7158 SHELL_ALIGN(sizeof(struct nclist)),
7159 SHELL_ALIGN(sizeof(struct narg)),
7160 SHELL_ALIGN(sizeof(struct narg)),
7161 SHELL_ALIGN(sizeof(struct nfile)),
7162 SHELL_ALIGN(sizeof(struct nfile)),
7163 SHELL_ALIGN(sizeof(struct nfile)),
7164 SHELL_ALIGN(sizeof(struct nfile)),
7165 SHELL_ALIGN(sizeof(struct nfile)),
7166 SHELL_ALIGN(sizeof(struct ndup)),
7167 SHELL_ALIGN(sizeof(struct ndup)),
7168 SHELL_ALIGN(sizeof(struct nhere)),
7169 SHELL_ALIGN(sizeof(struct nhere)),
7170 SHELL_ALIGN(sizeof(struct nnot)),
7173 static void calcsize(union node *n);
7176 sizenodelist(struct nodelist *lp)
7179 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7186 calcsize(union node *n)
7190 funcblocksize += nodesize[n->type];
7193 calcsize(n->ncmd.redirect);
7194 calcsize(n->ncmd.args);
7195 calcsize(n->ncmd.assign);
7198 sizenodelist(n->npipe.cmdlist);
7203 calcsize(n->nredir.redirect);
7204 calcsize(n->nredir.n);
7211 calcsize(n->nbinary.ch2);
7212 calcsize(n->nbinary.ch1);
7215 calcsize(n->nif.elsepart);
7216 calcsize(n->nif.ifpart);
7217 calcsize(n->nif.test);
7220 funcstringsize += strlen(n->nfor.var) + 1;
7221 calcsize(n->nfor.body);
7222 calcsize(n->nfor.args);
7225 calcsize(n->ncase.cases);
7226 calcsize(n->ncase.expr);
7229 calcsize(n->nclist.body);
7230 calcsize(n->nclist.pattern);
7231 calcsize(n->nclist.next);
7235 sizenodelist(n->narg.backquote);
7236 funcstringsize += strlen(n->narg.text) + 1;
7237 calcsize(n->narg.next);
7244 calcsize(n->nfile.fname);
7245 calcsize(n->nfile.next);
7249 calcsize(n->ndup.vname);
7250 calcsize(n->ndup.next);
7254 calcsize(n->nhere.doc);
7255 calcsize(n->nhere.next);
7258 calcsize(n->nnot.com);
7264 nodeckstrdup(char *s)
7266 char *rtn = funcstring;
7268 strcpy(funcstring, s);
7269 funcstring += strlen(s) + 1;
7273 static union node *copynode(union node *);
7275 static struct nodelist *
7276 copynodelist(struct nodelist *lp)
7278 struct nodelist *start;
7279 struct nodelist **lpp;
7284 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7285 (*lpp)->n = copynode(lp->n);
7287 lpp = &(*lpp)->next;
7294 copynode(union node *n)
7301 funcblock = (char *) funcblock + nodesize[n->type];
7305 new->ncmd.redirect = copynode(n->ncmd.redirect);
7306 new->ncmd.args = copynode(n->ncmd.args);
7307 new->ncmd.assign = copynode(n->ncmd.assign);
7310 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7311 new->npipe.backgnd = n->npipe.backgnd;
7316 new->nredir.redirect = copynode(n->nredir.redirect);
7317 new->nredir.n = copynode(n->nredir.n);
7324 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7325 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7328 new->nif.elsepart = copynode(n->nif.elsepart);
7329 new->nif.ifpart = copynode(n->nif.ifpart);
7330 new->nif.test = copynode(n->nif.test);
7333 new->nfor.var = nodeckstrdup(n->nfor.var);
7334 new->nfor.body = copynode(n->nfor.body);
7335 new->nfor.args = copynode(n->nfor.args);
7338 new->ncase.cases = copynode(n->ncase.cases);
7339 new->ncase.expr = copynode(n->ncase.expr);
7342 new->nclist.body = copynode(n->nclist.body);
7343 new->nclist.pattern = copynode(n->nclist.pattern);
7344 new->nclist.next = copynode(n->nclist.next);
7348 new->narg.backquote = copynodelist(n->narg.backquote);
7349 new->narg.text = nodeckstrdup(n->narg.text);
7350 new->narg.next = copynode(n->narg.next);
7357 new->nfile.fname = copynode(n->nfile.fname);
7358 new->nfile.fd = n->nfile.fd;
7359 new->nfile.next = copynode(n->nfile.next);
7363 new->ndup.vname = copynode(n->ndup.vname);
7364 new->ndup.dupfd = n->ndup.dupfd;
7365 new->ndup.fd = n->ndup.fd;
7366 new->ndup.next = copynode(n->ndup.next);
7370 new->nhere.doc = copynode(n->nhere.doc);
7371 new->nhere.fd = n->nhere.fd;
7372 new->nhere.next = copynode(n->nhere.next);
7375 new->nnot.com = copynode(n->nnot.com);
7378 new->type = n->type;
7383 * Make a copy of a parse tree.
7385 static struct funcnode *
7386 copyfunc(union node *n)
7391 funcblocksize = offsetof(struct funcnode, n);
7394 blocksize = funcblocksize;
7395 f = ckmalloc(blocksize + funcstringsize);
7396 funcblock = (char *) f + offsetof(struct funcnode, n);
7397 funcstring = (char *) f + blocksize;
7404 * Define a shell function.
7407 defun(char *name, union node *func)
7409 struct cmdentry entry;
7412 entry.cmdtype = CMDFUNCTION;
7413 entry.u.func = copyfunc(func);
7414 addcmdentry(name, &entry);
7418 static int evalskip; /* set if we are skipping commands */
7419 /* reasons for skipping commands (see comment on breakcmd routine) */
7420 #define SKIPBREAK (1 << 0)
7421 #define SKIPCONT (1 << 1)
7422 #define SKIPFUNC (1 << 2)
7423 #define SKIPFILE (1 << 3)
7424 #define SKIPEVAL (1 << 4)
7425 static int skipcount; /* number of levels to skip */
7426 static int funcnest; /* depth of function calls */
7428 /* forward decl way out to parsing code - dotrap needs it */
7429 static int evalstring(char *s, int mask);
7432 * Called to execute a trap. Perhaps we should avoid entering new trap
7433 * handlers while we are executing a trap handler.
7444 savestatus = exitstatus;
7448 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
7456 skip = evalstring(p, SKIPEVAL);
7457 exitstatus = savestatus;
7465 /* forward declarations - evaluation is fairly recursive business... */
7466 static void evalloop(union node *, int);
7467 static void evalfor(union node *, int);
7468 static void evalcase(union node *, int);
7469 static void evalsubshell(union node *, int);
7470 static void expredir(union node *);
7471 static void evalpipe(union node *, int);
7472 static void evalcommand(union node *, int);
7473 static int evalbltin(const struct builtincmd *, int, char **);
7474 static void prehash(union node *);
7477 * Evaluate a parse tree. The value is left in the global variable
7481 evaltree(union node *n, int flags)
7484 void (*evalfn)(union node *, int);
7488 TRACE(("evaltree(NULL) called\n"));
7491 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
7492 getpid(), n, n->type, flags));
7496 out1fmt("Node type = %d\n", n->type);
7501 evaltree(n->nnot.com, EV_TESTED);
7502 status = !exitstatus;
7505 expredir(n->nredir.redirect);
7506 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
7508 evaltree(n->nredir.n, flags & EV_TESTED);
7509 status = exitstatus;
7514 evalfn = evalcommand;
7516 if (eflag && !(flags & EV_TESTED))
7528 evalfn = evalsubshell;
7540 #error NAND + 1 != NOR
7542 #if NOR + 1 != NSEMI
7543 #error NOR + 1 != NSEMI
7545 isor = n->type - NAND;
7548 (flags | ((isor >> 1) - 1)) & EV_TESTED
7550 if (!exitstatus == isor)
7562 evaltree(n->nif.test, EV_TESTED);
7565 if (exitstatus == 0) {
7568 } else if (n->nif.elsepart) {
7569 n = n->nif.elsepart;
7574 defun(n->narg.text, n->narg.next);
7578 exitstatus = status;
7582 if ((checkexit & exitstatus))
7583 evalskip |= SKIPEVAL;
7584 else if (pendingsig && dotrap())
7587 if (flags & EV_EXIT) {
7589 raise_exception(EXEXIT);
7593 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
7596 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
7598 static int loopnest; /* current loop nesting level */
7601 evalloop(union node *n, int flags)
7611 evaltree(n->nbinary.ch1, EV_TESTED);
7614 if (evalskip == SKIPCONT && --skipcount <= 0) {
7618 if (evalskip == SKIPBREAK && --skipcount <= 0)
7623 if (n->type != NWHILE)
7627 evaltree(n->nbinary.ch2, flags);
7628 status = exitstatus;
7633 exitstatus = status;
7637 evalfor(union node *n, int flags)
7639 struct arglist arglist;
7642 struct stackmark smark;
7644 setstackmark(&smark);
7645 arglist.lastp = &arglist.list;
7646 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
7647 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
7652 *arglist.lastp = NULL;
7657 for (sp = arglist.list; sp; sp = sp->next) {
7658 setvar(n->nfor.var, sp->text, 0);
7659 evaltree(n->nfor.body, flags);
7661 if (evalskip == SKIPCONT && --skipcount <= 0) {
7665 if (evalskip == SKIPBREAK && --skipcount <= 0)
7672 popstackmark(&smark);
7676 evalcase(union node *n, int flags)
7680 struct arglist arglist;
7681 struct stackmark smark;
7683 setstackmark(&smark);
7684 arglist.lastp = &arglist.list;
7685 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
7687 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
7688 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
7689 if (casematch(patp, arglist.list->text)) {
7690 if (evalskip == 0) {
7691 evaltree(cp->nclist.body, flags);
7698 popstackmark(&smark);
7702 * Kick off a subshell to evaluate a tree.
7705 evalsubshell(union node *n, int flags)
7708 int backgnd = (n->type == NBACKGND);
7711 expredir(n->nredir.redirect);
7712 if (!backgnd && flags & EV_EXIT && !trap[0])
7716 if (forkshell(jp, n, backgnd) == 0) {
7720 flags &=~ EV_TESTED;
7722 redirect(n->nredir.redirect, 0);
7723 evaltreenr(n->nredir.n, flags);
7728 status = waitforjob(jp);
7729 exitstatus = status;
7734 * Compute the names of the files in a redirection list.
7736 static void fixredir(union node *, const char *, int);
7738 expredir(union node *n)
7742 for (redir = n; redir; redir = redir->nfile.next) {
7745 memset(&fn, 0, sizeof(fn));
7746 fn.lastp = &fn.list;
7747 switch (redir->type) {
7753 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
7754 redir->nfile.expfname = fn.list->text;
7758 if (redir->ndup.vname) {
7759 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
7760 if (fn.list == NULL)
7761 ash_msg_and_raise_error("redir error");
7762 fixredir(redir, fn.list->text, 1);
7770 * Evaluate a pipeline. All the processes in the pipeline are children
7771 * of the process creating the pipeline. (This differs from some versions
7772 * of the shell, which make the last process in a pipeline the parent
7776 evalpipe(union node *n, int flags)
7779 struct nodelist *lp;
7784 TRACE(("evalpipe(0x%lx) called\n", (long)n));
7786 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
7790 jp = makejob(n, pipelen);
7792 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
7796 if (pipe(pip) < 0) {
7798 ash_msg_and_raise_error("pipe call failed");
7801 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
7814 evaltreenr(lp->n, flags);
7822 if (n->npipe.backgnd == 0) {
7823 exitstatus = waitforjob(jp);
7824 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
7830 * Controls whether the shell is interactive or not.
7833 setinteractive(int on)
7835 static int is_interactive;
7837 if (++on == is_interactive)
7839 is_interactive = on;
7843 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
7844 if (is_interactive > 1) {
7845 /* Looks like they want an interactive shell */
7846 static smallint did_banner;
7851 "%s built-in shell (ash)\n"
7852 "Enter 'help' for a list of built-in commands."
7861 #if ENABLE_FEATURE_EDITING_VI
7862 #define setvimode(on) do { \
7863 if (on) line_input_state->flags |= VI_MODE; \
7864 else line_input_state->flags &= ~VI_MODE; \
7867 #define setvimode(on) viflag = 0 /* forcibly keep the option off */
7876 setinteractive(iflag);
7881 static struct localvar *localvars;
7884 * Called after a function returns.
7885 * Interrupts must be off.
7890 struct localvar *lvp;
7893 while ((lvp = localvars) != NULL) {
7894 localvars = lvp->next;
7896 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
7897 if (vp == NULL) { /* $- saved */
7898 memcpy(optlist, lvp->text, sizeof(optlist));
7899 free((char*)lvp->text);
7901 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
7905 (*vp->func)(strchrnul(lvp->text, '=') + 1);
7906 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
7907 free((char*)vp->text);
7908 vp->flags = lvp->flags;
7909 vp->text = lvp->text;
7916 evalfun(struct funcnode *func, int argc, char **argv, int flags)
7918 volatile struct shparam saveparam;
7919 struct localvar *volatile savelocalvars;
7920 struct jmploc *volatile savehandler;
7921 struct jmploc jmploc;
7924 saveparam = shellparam;
7925 savelocalvars = localvars;
7926 e = setjmp(jmploc.loc);
7931 savehandler = exception_handler;
7932 exception_handler = &jmploc;
7934 shellparam.malloced = 0;
7938 shellparam.nparam = argc - 1;
7939 shellparam.p = argv + 1;
7940 #if ENABLE_ASH_GETOPTS
7941 shellparam.optind = 1;
7942 shellparam.optoff = -1;
7944 evaltree(&func->n, flags & EV_TESTED);
7950 localvars = savelocalvars;
7951 freeparam(&shellparam);
7952 shellparam = saveparam;
7953 exception_handler = savehandler;
7955 evalskip &= ~SKIPFUNC;
7959 #if ENABLE_ASH_CMDCMD
7961 parse_command_args(char **argv, const char **path)
7974 if (c == '-' && !*cp) {
7981 *path = bb_default_path;
7984 /* run 'typecmd' for other options */
7995 * Make a variable a local variable. When a variable is made local, it's
7996 * value and flags are saved in a localvar structure. The saved values
7997 * will be restored when the shell function returns. We handle the name
7998 * "-" as a special case.
8003 struct localvar *lvp;
8008 lvp = ckmalloc(sizeof(struct localvar));
8009 if (LONE_DASH(name)) {
8011 p = ckmalloc(sizeof(optlist));
8012 lvp->text = memcpy(p, optlist, sizeof(optlist));
8017 vpp = hashvar(name);
8018 vp = *findvar(vpp, name);
8019 eq = strchr(name, '=');
8022 setvareq(name, VSTRFIXED);
8024 setvar(name, NULL, VSTRFIXED);
8025 vp = *vpp; /* the new variable */
8026 lvp->flags = VUNSET;
8028 lvp->text = vp->text;
8029 lvp->flags = vp->flags;
8030 vp->flags |= VSTRFIXED|VTEXTFIXED;
8036 lvp->next = localvars;
8042 * The "local" command.
8045 localcmd(int argc, char **argv)
8050 while ((name = *argv++) != NULL) {
8057 falsecmd(int argc, char **argv)
8063 truecmd(int argc, char **argv)
8069 execcmd(int argc, char **argv)
8072 iflag = 0; /* exit on error */
8075 shellexec(argv + 1, pathval(), 0);
8081 * The return command.
8084 returncmd(int argc, char **argv)
8087 * If called outside a function, do what ksh does;
8088 * skip the rest of the file.
8090 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8091 return argv[1] ? number(argv[1]) : exitstatus;
8094 /* Forward declarations for builtintab[] */
8095 static int breakcmd(int, char **);
8096 static int dotcmd(int, char **);
8097 static int evalcmd(int, char **);
8098 #if ENABLE_ASH_BUILTIN_ECHO
8099 static int echocmd(int, char **);
8101 #if ENABLE_ASH_BUILTIN_TEST
8102 static int testcmd(int, char **);
8104 static int exitcmd(int, char **);
8105 static int exportcmd(int, char **);
8106 #if ENABLE_ASH_GETOPTS
8107 static int getoptscmd(int, char **);
8109 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8110 static int helpcmd(int argc, char **argv);
8112 #if ENABLE_ASH_MATH_SUPPORT
8113 static int letcmd(int, char **);
8115 static int readcmd(int, char **);
8116 static int setcmd(int, char **);
8117 static int shiftcmd(int, char **);
8118 static int timescmd(int, char **);
8119 static int trapcmd(int, char **);
8120 static int umaskcmd(int, char **);
8121 static int unsetcmd(int, char **);
8122 static int ulimitcmd(int, char **);
8124 #define BUILTIN_NOSPEC "0"
8125 #define BUILTIN_SPECIAL "1"
8126 #define BUILTIN_REGULAR "2"
8127 #define BUILTIN_SPEC_REG "3"
8128 #define BUILTIN_ASSIGN "4"
8129 #define BUILTIN_SPEC_ASSG "5"
8130 #define BUILTIN_REG_ASSG "6"
8131 #define BUILTIN_SPEC_REG_ASSG "7"
8133 /* make sure to keep these in proper order since it is searched via bsearch() */
8134 static const struct builtincmd builtintab[] = {
8135 { BUILTIN_SPEC_REG ".", dotcmd },
8136 { BUILTIN_SPEC_REG ":", truecmd },
8137 #if ENABLE_ASH_BUILTIN_TEST
8138 { BUILTIN_REGULAR "[", testcmd },
8139 { BUILTIN_REGULAR "[[", testcmd },
8141 #if ENABLE_ASH_ALIAS
8142 { BUILTIN_REG_ASSG "alias", aliascmd },
8145 { BUILTIN_REGULAR "bg", fg_bgcmd },
8147 { BUILTIN_SPEC_REG "break", breakcmd },
8148 { BUILTIN_REGULAR "cd", cdcmd },
8149 { BUILTIN_NOSPEC "chdir", cdcmd },
8150 #if ENABLE_ASH_CMDCMD
8151 { BUILTIN_REGULAR "command", commandcmd },
8153 { BUILTIN_SPEC_REG "continue", breakcmd },
8154 #if ENABLE_ASH_BUILTIN_ECHO
8155 { BUILTIN_REGULAR "echo", echocmd },
8157 { BUILTIN_SPEC_REG "eval", evalcmd },
8158 { BUILTIN_SPEC_REG "exec", execcmd },
8159 { BUILTIN_SPEC_REG "exit", exitcmd },
8160 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8161 { BUILTIN_REGULAR "false", falsecmd },
8163 { BUILTIN_REGULAR "fg", fg_bgcmd },
8165 #if ENABLE_ASH_GETOPTS
8166 { BUILTIN_REGULAR "getopts", getoptscmd },
8168 { BUILTIN_NOSPEC "hash", hashcmd },
8169 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8170 { BUILTIN_NOSPEC "help", helpcmd },
8173 { BUILTIN_REGULAR "jobs", jobscmd },
8174 { BUILTIN_REGULAR "kill", killcmd },
8176 #if ENABLE_ASH_MATH_SUPPORT
8177 { BUILTIN_NOSPEC "let", letcmd },
8179 { BUILTIN_ASSIGN "local", localcmd },
8180 { BUILTIN_NOSPEC "pwd", pwdcmd },
8181 { BUILTIN_REGULAR "read", readcmd },
8182 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8183 { BUILTIN_SPEC_REG "return", returncmd },
8184 { BUILTIN_SPEC_REG "set", setcmd },
8185 { BUILTIN_SPEC_REG "shift", shiftcmd },
8186 { BUILTIN_SPEC_REG "source", dotcmd },
8187 #if ENABLE_ASH_BUILTIN_TEST
8188 { BUILTIN_REGULAR "test", testcmd },
8190 { BUILTIN_SPEC_REG "times", timescmd },
8191 { BUILTIN_SPEC_REG "trap", trapcmd },
8192 { BUILTIN_REGULAR "true", truecmd },
8193 { BUILTIN_NOSPEC "type", typecmd },
8194 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
8195 { BUILTIN_REGULAR "umask", umaskcmd },
8196 #if ENABLE_ASH_ALIAS
8197 { BUILTIN_REGULAR "unalias", unaliascmd },
8199 { BUILTIN_SPEC_REG "unset", unsetcmd },
8200 { BUILTIN_REGULAR "wait", waitcmd },
8204 #define COMMANDCMD (builtintab + 5 + \
8205 2 * ENABLE_ASH_BUILTIN_TEST + \
8206 ENABLE_ASH_ALIAS + \
8207 ENABLE_ASH_JOB_CONTROL)
8208 #define EXECCMD (builtintab + 7 + \
8209 2 * ENABLE_ASH_BUILTIN_TEST + \
8210 ENABLE_ASH_ALIAS + \
8211 ENABLE_ASH_JOB_CONTROL + \
8212 ENABLE_ASH_CMDCMD + \
8213 ENABLE_ASH_BUILTIN_ECHO)
8216 * Search the table of builtin commands.
8218 static struct builtincmd *
8219 find_builtin(const char *name)
8221 struct builtincmd *bp;
8224 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8231 * Execute a simple command.
8233 static int back_exitstatus; /* exit status of backquoted command */
8235 isassignment(const char *p)
8237 const char *q = endofname(p);
8243 bltincmd(int argc, char **argv)
8245 /* Preserve exitstatus of a previous possible redirection
8246 * as POSIX mandates */
8247 return back_exitstatus;
8250 evalcommand(union node *cmd, int flags)
8252 static const struct builtincmd bltin = {
8255 struct stackmark smark;
8257 struct arglist arglist;
8258 struct arglist varlist;
8261 const struct strlist *sp;
8262 struct cmdentry cmdentry;
8270 struct builtincmd *bcmd;
8271 int pseudovarflag = 0;
8273 /* First expand the arguments. */
8274 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8275 setstackmark(&smark);
8276 back_exitstatus = 0;
8278 cmdentry.cmdtype = CMDBUILTIN;
8279 cmdentry.u.cmd = &bltin;
8280 varlist.lastp = &varlist.list;
8281 *varlist.lastp = NULL;
8282 arglist.lastp = &arglist.list;
8283 *arglist.lastp = NULL;
8286 if (cmd->ncmd.args) {
8287 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8288 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8291 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8292 struct strlist **spp;
8294 spp = arglist.lastp;
8295 if (pseudovarflag && isassignment(argp->narg.text))
8296 expandarg(argp, &arglist, EXP_VARTILDE);
8298 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8300 for (sp = *spp; sp; sp = sp->next)
8304 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8305 for (sp = arglist.list; sp; sp = sp->next) {
8306 TRACE(("evalcommand arg: %s\n", sp->text));
8307 *nargv++ = sp->text;
8312 if (iflag && funcnest == 0 && argc > 0)
8313 lastarg = nargv[-1];
8316 expredir(cmd->ncmd.redirect);
8317 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8320 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8321 struct strlist **spp;
8324 spp = varlist.lastp;
8325 expandarg(argp, &varlist, EXP_VARTILDE);
8328 * Modify the command lookup path, if a PATH= assignment
8332 if (varequal(p, path))
8336 /* Print the command if xflag is set. */
8339 const char *p = " %s";
8342 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8345 for (n = 0; n < 2; n++) {
8347 fdprintf(preverrout_fd, p, sp->text);
8355 full_write(preverrout_fd, "\n", 1);
8361 /* Now locate the command. */
8363 const char *oldpath;
8364 int cmd_flag = DO_ERR;
8369 find_command(argv[0], &cmdentry, cmd_flag, path);
8370 if (cmdentry.cmdtype == CMDUNKNOWN) {
8376 /* implement bltin and command here */
8377 if (cmdentry.cmdtype != CMDBUILTIN)
8380 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8381 if (cmdentry.u.cmd == EXECCMD)
8383 #if ENABLE_ASH_CMDCMD
8384 if (cmdentry.u.cmd == COMMANDCMD) {
8386 nargv = parse_command_args(argv, &path);
8389 argc -= nargv - argv;
8391 cmd_flag |= DO_NOFUNC;
8399 /* We have a redirection error. */
8401 raise_exception(EXERROR);
8403 exitstatus = status;
8407 /* Execute the command. */
8408 switch (cmdentry.cmdtype) {
8410 /* Fork off a child process if necessary. */
8411 if (!(flags & EV_EXIT) || trap[0]) {
8413 jp = makejob(cmd, 1);
8414 if (forkshell(jp, cmd, FORK_FG) != 0) {
8415 exitstatus = waitforjob(jp);
8421 listsetvar(varlist.list, VEXPORT|VSTACK);
8422 shellexec(argv, path, cmdentry.u.index);
8426 cmdenviron = varlist.list;
8428 struct strlist *list = cmdenviron;
8430 if (spclbltin > 0 || argc == 0) {
8432 if (cmd_is_exec && argc > 1)
8435 listsetvar(list, i);
8437 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
8444 exit_status = 128 + SIGINT;
8446 exit_status = 128 + pendingsig;
8447 exitstatus = exit_status;
8448 if (i == EXINT || spclbltin > 0) {
8450 longjmp(exception_handler->loc, 1);
8457 listsetvar(varlist.list, 0);
8458 if (evalfun(cmdentry.u.func, argc, argv, flags))
8464 popredir(cmd_is_exec);
8466 /* dsl: I think this is intended to be used to support
8467 * '_' in 'vi' command mode during line editing...
8468 * However I implemented that within libedit itself.
8470 setvar("_", lastarg, 0);
8471 popstackmark(&smark);
8475 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
8477 char *volatile savecmdname;
8478 struct jmploc *volatile savehandler;
8479 struct jmploc jmploc;
8482 savecmdname = commandname;
8483 i = setjmp(jmploc.loc);
8486 savehandler = exception_handler;
8487 exception_handler = &jmploc;
8488 commandname = argv[0];
8490 optptr = NULL; /* initialize nextopt */
8491 exitstatus = (*cmd->builtin)(argc, argv);
8492 flush_stdout_stderr();
8494 exitstatus |= ferror(stdout);
8496 commandname = savecmdname;
8498 exception_handler = savehandler;
8504 goodname(const char *p)
8506 return !*endofname(p);
8511 * Search for a command. This is called before we fork so that the
8512 * location of the command will be available in the parent as well as
8513 * the child. The check for "goodname" is an overly conservative
8514 * check that the name will not be subject to expansion.
8517 prehash(union node *n)
8519 struct cmdentry entry;
8521 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
8522 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
8526 /* ============ Builtin commands
8528 * Builtin commands whose functions are closely tied to evaluation
8529 * are implemented here.
8533 * Handle break and continue commands. Break, continue, and return are
8534 * all handled by setting the evalskip flag. The evaluation routines
8535 * above all check this flag, and if it is set they start skipping
8536 * commands rather than executing them. The variable skipcount is
8537 * the number of loops to break/continue, or the number of function
8538 * levels to return. (The latter is always 1.) It should probably
8539 * be an error to break out of more loops than exist, but it isn't
8540 * in the standard shell so we don't make it one here.
8543 breakcmd(int argc, char **argv)
8545 int n = argc > 1 ? number(argv[1]) : 1;
8548 ash_msg_and_raise_error(illnum, argv[1]);
8552 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
8559 /* ============ input.c
8561 * This implements the input routines used by the parser.
8564 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
8567 INPUT_PUSH_FILE = 1,
8568 INPUT_NOFILE_OK = 2,
8571 static int plinno = 1; /* input line number */
8572 /* number of characters left in input buffer */
8573 static int parsenleft; /* copy of parsefile->nleft */
8574 static int parselleft; /* copy of parsefile->lleft */
8575 /* next character in input buffer */
8576 static char *parsenextc; /* copy of parsefile->nextc */
8578 static int checkkwd;
8579 /* values of checkkwd variable */
8580 #define CHKALIAS 0x1
8587 struct strpush *sp = parsefile->strpush;
8590 #if ENABLE_ASH_ALIAS
8592 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
8593 checkkwd |= CHKALIAS;
8595 if (sp->string != sp->ap->val) {
8598 sp->ap->flag &= ~ALIASINUSE;
8599 if (sp->ap->flag & ALIASDEAD) {
8600 unalias(sp->ap->name);
8604 parsenextc = sp->prevstring;
8605 parsenleft = sp->prevnleft;
8606 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
8607 parsefile->strpush = sp->prev;
8608 if (sp != &(parsefile->basestrpush))
8617 char *buf = parsefile->buf;
8621 #if ENABLE_FEATURE_EDITING
8622 if (!iflag || parsefile->fd)
8623 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
8625 #if ENABLE_FEATURE_TAB_COMPLETION
8626 line_input_state->path_lookup = pathval();
8628 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
8630 /* Ctrl+C pressed */
8639 if (nr < 0 && errno == 0) {
8640 /* Ctrl+D pressed */
8645 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
8649 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
8650 int flags = fcntl(0, F_GETFL);
8651 if (flags >= 0 && (flags & O_NONBLOCK)) {
8652 flags &= ~O_NONBLOCK;
8653 if (fcntl(0, F_SETFL, flags) >= 0) {
8654 out2str("sh: turning off NDELAY mode\n");
8664 * Refill the input buffer and return the next input character:
8666 * 1) If a string was pushed back on the input, pop it;
8667 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
8668 * from a string so we can't refill the buffer, return EOF.
8669 * 3) If the is more stuff in this buffer, use it else call read to fill it.
8670 * 4) Process input up to the next newline, deleting nul characters.
8679 while (parsefile->strpush) {
8680 #if ENABLE_ASH_ALIAS
8681 if (parsenleft == -1 && parsefile->strpush->ap &&
8682 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
8687 if (--parsenleft >= 0)
8688 return signed_char2int(*parsenextc++);
8690 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
8692 flush_stdout_stderr();
8699 parselleft = parsenleft = EOF_NLEFT;
8706 /* delete nul characters */
8714 memmove(q, q + 1, more);
8718 parsenleft = q - parsenextc - 1;
8724 parsenleft = q - parsenextc - 1;
8736 out2str(parsenextc);
8741 return signed_char2int(*parsenextc++);
8744 #define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer())
8748 return pgetc_as_macro();
8751 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
8752 #define pgetc_macro() pgetc()
8754 #define pgetc_macro() pgetc_as_macro()
8758 * Same as pgetc(), but ignores PEOA.
8760 #if ENABLE_ASH_ALIAS
8768 } while (c == PEOA);
8775 return pgetc_macro();
8780 * Read a line from the script.
8783 pfgets(char *line, int len)
8789 while (--nleft > 0) {
8805 * Undo the last call to pgetc. Only one character may be pushed back.
8806 * PEOF may be pushed back.
8816 * Push a string back onto the input at this current parsefile level.
8817 * We handle aliases this way.
8820 pushstring(char *s, void *ap)
8827 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
8828 if (parsefile->strpush) {
8829 sp = ckmalloc(sizeof(struct strpush));
8830 sp->prev = parsefile->strpush;
8831 parsefile->strpush = sp;
8833 sp = parsefile->strpush = &(parsefile->basestrpush);
8834 sp->prevstring = parsenextc;
8835 sp->prevnleft = parsenleft;
8836 #if ENABLE_ASH_ALIAS
8837 sp->ap = (struct alias *)ap;
8839 ((struct alias *)ap)->flag |= ALIASINUSE;
8849 * To handle the "." command, a stack of input files is used. Pushfile
8850 * adds a new entry to the stack and popfile restores the previous level.
8855 struct parsefile *pf;
8857 parsefile->nleft = parsenleft;
8858 parsefile->lleft = parselleft;
8859 parsefile->nextc = parsenextc;
8860 parsefile->linno = plinno;
8861 pf = ckmalloc(sizeof(*pf));
8862 pf->prev = parsefile;
8865 pf->basestrpush.prev = NULL;
8872 struct parsefile *pf = parsefile;
8880 parsefile = pf->prev;
8882 parsenleft = parsefile->nleft;
8883 parselleft = parsefile->lleft;
8884 parsenextc = parsefile->nextc;
8885 plinno = parsefile->linno;
8890 * Return to top level.
8895 while (parsefile != &basepf)
8900 * Close the file(s) that the shell is reading commands from. Called
8901 * after a fork is done.
8907 if (parsefile->fd > 0) {
8908 close(parsefile->fd);
8914 * Like setinputfile, but takes an open file descriptor. Call this with
8918 setinputfd(int fd, int push)
8920 close_on_exec_on(fd);
8926 if (parsefile->buf == NULL)
8927 parsefile->buf = ckmalloc(IBUFSIZ);
8928 parselleft = parsenleft = 0;
8933 * Set the input to take input from a file. If push is set, push the
8934 * old input onto the stack first.
8937 setinputfile(const char *fname, int flags)
8943 fd = open(fname, O_RDONLY);
8945 if (flags & INPUT_NOFILE_OK)
8947 ash_msg_and_raise_error("can't open %s", fname);
8950 fd2 = copyfd(fd, 10);
8953 ash_msg_and_raise_error("out of file descriptors");
8956 setinputfd(fd, flags & INPUT_PUSH_FILE);
8963 * Like setinputfile, but takes input from a string.
8966 setinputstring(char *string)
8970 parsenextc = string;
8971 parsenleft = strlen(string);
8972 parsefile->buf = NULL;
8978 /* ============ mail.c
8980 * Routines to check for mail.
8985 #define MAXMBOXES 10
8987 /* times of mailboxes */
8988 static time_t mailtime[MAXMBOXES];
8989 /* Set if MAIL or MAILPATH is changed. */
8990 static smallint mail_var_path_changed;
8993 * Print appropriate message(s) if mail has arrived.
8994 * If mail_var_path_changed is set,
8995 * then the value of MAIL has mail_var_path_changed,
8996 * so we just update the values.
9005 struct stackmark smark;
9008 setstackmark(&smark);
9009 mpath = mpathset() ? mpathval() : mailval();
9010 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9011 p = padvance(&mpath, nullstr);
9016 for (q = p; *q; q++);
9021 q[-1] = '\0'; /* delete trailing '/' */
9022 if (stat(p, &statb) < 0) {
9026 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9029 pathopt ? pathopt : "you have mail"
9032 *mtp = statb.st_mtime;
9034 mail_var_path_changed = 0;
9035 popstackmark(&smark);
9039 changemail(const char *val)
9041 mail_var_path_changed = 1;
9044 #endif /* ASH_MAIL */
9047 /* ============ ??? */
9050 * Set the shell parameters.
9053 setparam(char **argv)
9059 for (nparam = 0; argv[nparam]; nparam++);
9060 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9062 *ap++ = ckstrdup(*argv++);
9065 freeparam(&shellparam);
9066 shellparam.malloced = 1;
9067 shellparam.nparam = nparam;
9068 shellparam.p = newparam;
9069 #if ENABLE_ASH_GETOPTS
9070 shellparam.optind = 1;
9071 shellparam.optoff = -1;
9076 * Process shell options. The global variable argptr contains a pointer
9077 * to the argument list; we advance it past the options.
9080 minus_o(char *name, int val)
9085 for (i = 0; i < NOPTS; i++) {
9086 if (strcmp(name, optnames(i)) == 0) {
9091 ash_msg_and_raise_error("illegal option -o %s", name);
9093 out1str("Current option settings\n");
9094 for (i = 0; i < NOPTS; i++)
9095 out1fmt("%-16s%s\n", optnames(i),
9096 optlist[i] ? "on" : "off");
9099 setoption(int flag, int val)
9103 for (i = 0; i < NOPTS; i++) {
9104 if (optletters(i) == flag) {
9109 ash_msg_and_raise_error("illegal option -%c", flag);
9113 options(int cmdline)
9121 while ((p = *argptr) != NULL) {
9123 if (c != '-' && c != '+')
9126 val = 0; /* val = 0 if c == '+' */
9129 if (p[0] == '\0' || LONE_DASH(p)) {
9131 /* "-" means turn off -x and -v */
9134 /* "--" means reset params */
9135 else if (*argptr == NULL)
9138 break; /* "-" or "--" terminates options */
9141 /* first char was + or - */
9142 while ((c = *p++) != '\0') {
9143 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9144 if (c == 'c' && cmdline) {
9145 minusc = p; /* command is after shell args */
9146 } else if (c == 'o') {
9147 minus_o(*argptr, val);
9150 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9152 /* bash does not accept +-login, we also won't */
9153 } else if (cmdline && val && (c == '-')) { /* long options */
9154 if (strcmp(p, "login") == 0)
9165 * The shift builtin command.
9168 shiftcmd(int argc, char **argv)
9175 n = number(argv[1]);
9176 if (n > shellparam.nparam)
9177 ash_msg_and_raise_error("can't shift that many");
9179 shellparam.nparam -= n;
9180 for (ap1 = shellparam.p; --n >= 0; ap1++) {
9181 if (shellparam.malloced)
9185 while ((*ap2++ = *ap1++) != NULL);
9186 #if ENABLE_ASH_GETOPTS
9187 shellparam.optind = 1;
9188 shellparam.optoff = -1;
9195 * POSIX requires that 'set' (but not export or readonly) output the
9196 * variables in lexicographic order - by the locale's collating order (sigh).
9197 * Maybe we could keep them in an ordered balanced binary tree
9198 * instead of hashed lists.
9199 * For now just roll 'em through qsort for printing...
9202 showvars(const char *sep_prefix, int on, int off)
9207 ep = listvars(on, off, &epend);
9208 qsort(ep, epend - ep, sizeof(char *), vpcmp);
9210 sep = *sep_prefix ? " " : sep_prefix;
9212 for (; ep < epend; ep++) {
9216 p = strchrnul(*ep, '=');
9219 q = single_quote(++p);
9220 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9226 * The set command builtin.
9229 setcmd(int argc, char **argv)
9232 return showvars(nullstr, 0, VUNSET);
9236 if (*argptr != NULL) {
9243 #if ENABLE_ASH_RANDOM_SUPPORT
9244 /* Roughly copied from bash.. */
9246 change_random(const char *value)
9248 if (value == NULL) {
9249 /* "get", generate */
9252 rseed = rseed * 1103515245 + 12345;
9253 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9254 /* set without recursion */
9255 setvar(vrandom.text, buf, VNOFUNC);
9256 vrandom.flags &= ~VNOFUNC;
9259 rseed = strtoul(value, (char **)NULL, 10);
9264 #if ENABLE_ASH_GETOPTS
9266 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9275 if (*param_optind < 1)
9277 optnext = optfirst + *param_optind - 1;
9279 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9282 p = optnext[-1] + *optoff;
9283 if (p == NULL || *p == '\0') {
9284 /* Current word is done, advance */
9286 if (p == NULL || *p != '-' || *++p == '\0') {
9293 if (LONE_DASH(p)) /* check for "--" */
9298 for (q = optstr; *q != c; ) {
9300 if (optstr[0] == ':') {
9303 err |= setvarsafe("OPTARG", s, 0);
9305 fprintf(stderr, "Illegal option -%c\n", c);
9316 if (*p == '\0' && (p = *optnext) == NULL) {
9317 if (optstr[0] == ':') {
9320 err |= setvarsafe("OPTARG", s, 0);
9323 fprintf(stderr, "No arg for -%c option\n", c);
9332 err |= setvarsafe("OPTARG", p, 0);
9335 err |= setvarsafe("OPTARG", nullstr, 0);
9337 *optoff = p ? p - *(optnext - 1) : -1;
9338 *param_optind = optnext - optfirst + 1;
9339 fmtstr(s, sizeof(s), "%d", *param_optind);
9340 err |= setvarsafe("OPTIND", s, VNOFUNC);
9343 err |= setvarsafe(optvar, s, 0);
9347 flush_stdout_stderr();
9348 raise_exception(EXERROR);
9354 * The getopts builtin. Shellparam.optnext points to the next argument
9355 * to be processed. Shellparam.optptr points to the next character to
9356 * be processed in the current argument. If shellparam.optnext is NULL,
9357 * then it's the first time getopts has been called.
9360 getoptscmd(int argc, char **argv)
9365 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
9367 optbase = shellparam.p;
9368 if (shellparam.optind > shellparam.nparam + 1) {
9369 shellparam.optind = 1;
9370 shellparam.optoff = -1;
9374 if (shellparam.optind > argc - 2) {
9375 shellparam.optind = 1;
9376 shellparam.optoff = -1;
9380 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9381 &shellparam.optoff);
9383 #endif /* ASH_GETOPTS */
9386 /* ============ Shell parser */
9389 * NEOF is returned by parsecmd when it encounters an end of file. It
9390 * must be distinct from NULL, so we use the address of a variable that
9391 * happens to be handy.
9393 static smallint tokpushback; /* last token pushed back */
9394 #define NEOF ((union node *)&tokpushback)
9395 static smallint parsebackquote; /* nonzero if we are inside backquotes */
9396 static int lasttoken; /* last token read */
9397 static char *wordtext; /* text of last word returned by readtoken */
9398 static struct nodelist *backquotelist;
9399 static union node *redirnode;
9400 static struct heredoc *heredoc;
9401 static smallint quoteflag; /* set if (part of) last token was quoted */
9403 static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN;
9405 raise_error_syntax(const char *msg)
9407 ash_msg_and_raise_error("syntax error: %s", msg);
9412 * Called when an unexpected token is read during the parse. The argument
9413 * is the token that is expected, or -1 if more than one type of token can
9414 * occur at this point.
9416 static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN;
9418 raise_error_unexpected_syntax(int token)
9423 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
9425 sprintf(msg + l, " (expecting %s)", tokname(token));
9426 raise_error_syntax(msg);
9430 #define EOFMARKLEN 79
9433 struct heredoc *next; /* next here document in list */
9434 union node *here; /* redirection node */
9435 char *eofmark; /* string indicating end of input */
9436 int striptabs; /* if set, strip leading tabs */
9439 static struct heredoc *heredoclist; /* list of here documents to read */
9441 /* parsing is heavily cross-recursive, need these forward decls */
9442 static union node *andor(void);
9443 static union node *pipeline(void);
9444 static union node *parse_command(void);
9445 static void parseheredoc(void);
9446 static char peektoken(void);
9447 static int readtoken(void);
9452 union node *n1, *n2, *n3;
9455 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9456 if (nlflag == 2 && peektoken())
9462 if (tok == TBACKGND) {
9463 if (n2->type == NPIPE) {
9464 n2->npipe.backgnd = 1;
9466 if (n2->type != NREDIR) {
9467 n3 = stalloc(sizeof(struct nredir));
9469 n3->nredir.redirect = NULL;
9472 n2->type = NBACKGND;
9478 n3 = stalloc(sizeof(struct nbinary));
9480 n3->nbinary.ch1 = n1;
9481 n3->nbinary.ch2 = n2;
9497 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9505 pungetc(); /* push back EOF on input */
9509 raise_error_unexpected_syntax(-1);
9519 union node *n1, *n2, *n3;
9527 } else if (t == TOR) {
9533 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9535 n3 = stalloc(sizeof(struct nbinary));
9537 n3->nbinary.ch1 = n1;
9538 n3->nbinary.ch2 = n2;
9546 union node *n1, *n2, *pipenode;
9547 struct nodelist *lp, *prev;
9551 TRACE(("pipeline: entered\n"));
9552 if (readtoken() == TNOT) {
9554 checkkwd = CHKKWD | CHKALIAS;
9557 n1 = parse_command();
9558 if (readtoken() == TPIPE) {
9559 pipenode = stalloc(sizeof(struct npipe));
9560 pipenode->type = NPIPE;
9561 pipenode->npipe.backgnd = 0;
9562 lp = stalloc(sizeof(struct nodelist));
9563 pipenode->npipe.cmdlist = lp;
9567 lp = stalloc(sizeof(struct nodelist));
9568 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9569 lp->n = parse_command();
9571 } while (readtoken() == TPIPE);
9577 n2 = stalloc(sizeof(struct nnot));
9590 n = stalloc(sizeof(struct narg));
9592 n->narg.next = NULL;
9593 n->narg.text = wordtext;
9594 n->narg.backquote = backquotelist;
9599 fixredir(union node *n, const char *text, int err)
9601 TRACE(("Fix redir %s %d\n", text, err));
9603 n->ndup.vname = NULL;
9605 if (isdigit(text[0]) && text[1] == '\0')
9606 n->ndup.dupfd = text[0] - '0';
9607 else if (LONE_DASH(text))
9611 raise_error_syntax("Bad fd number");
9612 n->ndup.vname = makename();
9617 * Returns true if the text contains nothing to expand (no dollar signs
9621 noexpand(char *text)
9627 while ((c = *p++) != '\0') {
9628 if (c == CTLQUOTEMARK)
9632 else if (SIT(c, BASESYNTAX) == CCTL)
9641 union node *n = redirnode;
9643 if (readtoken() != TWORD)
9644 raise_error_unexpected_syntax(-1);
9645 if (n->type == NHERE) {
9646 struct heredoc *here = heredoc;
9652 TRACE(("Here document %d\n", n->type));
9653 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9654 raise_error_syntax("Illegal eof marker for << redirection");
9655 rmescapes(wordtext);
9656 here->eofmark = wordtext;
9658 if (heredoclist == NULL)
9661 for (p = heredoclist; p->next; p = p->next);
9664 } else if (n->type == NTOFD || n->type == NFROMFD) {
9665 fixredir(n, wordtext, 0);
9667 n->nfile.fname = makename();
9674 union node *args, **app;
9675 union node *n = NULL;
9676 union node *vars, **vpp;
9677 union node **rpp, *redir;
9687 savecheckkwd = CHKALIAS;
9689 checkkwd = savecheckkwd;
9690 switch (readtoken()) {
9692 n = stalloc(sizeof(struct narg));
9694 n->narg.text = wordtext;
9695 n->narg.backquote = backquotelist;
9696 if (savecheckkwd && isassignment(wordtext)) {
9698 vpp = &n->narg.next;
9701 app = &n->narg.next;
9706 *rpp = n = redirnode;
9707 rpp = &n->nfile.next;
9708 parsefname(); /* read name of redirection file */
9711 if (args && app == &args->narg.next
9714 struct builtincmd *bcmd;
9717 /* We have a function */
9718 if (readtoken() != TRP)
9719 raise_error_unexpected_syntax(TRP);
9720 name = n->narg.text;
9722 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
9724 raise_error_syntax("Bad function name");
9727 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9728 n->narg.next = parse_command();
9741 n = stalloc(sizeof(struct ncmd));
9743 n->ncmd.args = args;
9744 n->ncmd.assign = vars;
9745 n->ncmd.redirect = redir;
9752 union node *n1, *n2;
9753 union node *ap, **app;
9754 union node *cp, **cpp;
9755 union node *redir, **rpp;
9762 switch (readtoken()) {
9764 raise_error_unexpected_syntax(-1);
9767 n1 = stalloc(sizeof(struct nif));
9769 n1->nif.test = list(0);
9770 if (readtoken() != TTHEN)
9771 raise_error_unexpected_syntax(TTHEN);
9772 n1->nif.ifpart = list(0);
9774 while (readtoken() == TELIF) {
9775 n2->nif.elsepart = stalloc(sizeof(struct nif));
9776 n2 = n2->nif.elsepart;
9778 n2->nif.test = list(0);
9779 if (readtoken() != TTHEN)
9780 raise_error_unexpected_syntax(TTHEN);
9781 n2->nif.ifpart = list(0);
9783 if (lasttoken == TELSE)
9784 n2->nif.elsepart = list(0);
9786 n2->nif.elsepart = NULL;
9794 n1 = stalloc(sizeof(struct nbinary));
9795 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
9796 n1->nbinary.ch1 = list(0);
9799 TRACE(("expecting DO got %s %s\n", tokname(got),
9800 got == TWORD ? wordtext : ""));
9801 raise_error_unexpected_syntax(TDO);
9803 n1->nbinary.ch2 = list(0);
9808 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9809 raise_error_syntax("Bad for loop variable");
9810 n1 = stalloc(sizeof(struct nfor));
9812 n1->nfor.var = wordtext;
9813 checkkwd = CHKKWD | CHKALIAS;
9814 if (readtoken() == TIN) {
9816 while (readtoken() == TWORD) {
9817 n2 = stalloc(sizeof(struct narg));
9819 n2->narg.text = wordtext;
9820 n2->narg.backquote = backquotelist;
9822 app = &n2->narg.next;
9826 if (lasttoken != TNL && lasttoken != TSEMI)
9827 raise_error_unexpected_syntax(-1);
9829 n2 = stalloc(sizeof(struct narg));
9831 n2->narg.text = (char *)dolatstr;
9832 n2->narg.backquote = NULL;
9833 n2->narg.next = NULL;
9836 * Newline or semicolon here is optional (but note
9837 * that the original Bourne shell only allowed NL).
9839 if (lasttoken != TNL && lasttoken != TSEMI)
9842 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9843 if (readtoken() != TDO)
9844 raise_error_unexpected_syntax(TDO);
9845 n1->nfor.body = list(0);
9849 n1 = stalloc(sizeof(struct ncase));
9851 if (readtoken() != TWORD)
9852 raise_error_unexpected_syntax(TWORD);
9853 n1->ncase.expr = n2 = stalloc(sizeof(struct narg));
9855 n2->narg.text = wordtext;
9856 n2->narg.backquote = backquotelist;
9857 n2->narg.next = NULL;
9859 checkkwd = CHKKWD | CHKALIAS;
9860 } while (readtoken() == TNL);
9861 if (lasttoken != TIN)
9862 raise_error_unexpected_syntax(TIN);
9863 cpp = &n1->ncase.cases;
9865 checkkwd = CHKNL | CHKKWD;
9867 while (t != TESAC) {
9868 if (lasttoken == TLP)
9870 *cpp = cp = stalloc(sizeof(struct nclist));
9872 app = &cp->nclist.pattern;
9874 *app = ap = stalloc(sizeof(struct narg));
9876 ap->narg.text = wordtext;
9877 ap->narg.backquote = backquotelist;
9878 if (readtoken() != TPIPE)
9880 app = &ap->narg.next;
9883 ap->narg.next = NULL;
9884 if (lasttoken != TRP)
9885 raise_error_unexpected_syntax(TRP);
9886 cp->nclist.body = list(2);
9888 cpp = &cp->nclist.next;
9890 checkkwd = CHKNL | CHKKWD;
9894 raise_error_unexpected_syntax(TENDCASE);
9901 n1 = stalloc(sizeof(struct nredir));
9902 n1->type = NSUBSHELL;
9903 n1->nredir.n = list(0);
9904 n1->nredir.redirect = NULL;
9917 if (readtoken() != t)
9918 raise_error_unexpected_syntax(t);
9921 /* Now check for redirection which may follow command */
9922 checkkwd = CHKKWD | CHKALIAS;
9924 while (readtoken() == TREDIR) {
9925 *rpp = n2 = redirnode;
9926 rpp = &n2->nfile.next;
9932 if (n1->type != NSUBSHELL) {
9933 n2 = stalloc(sizeof(struct nredir));
9938 n1->nredir.redirect = redir;
9944 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
9945 * is not NULL, read a here document. In the latter case, eofmark is the
9946 * word which marks the end of the document and striptabs is true if
9947 * leading tabs should be stripped from the document. The argument firstc
9948 * is the first character of the input token or document.
9950 * Because C does not have internal subroutines, I have simulated them
9951 * using goto's to implement the subroutine linkage. The following macros
9952 * will run code that appears at the end of readtoken1.
9955 #define CHECKEND() {goto checkend; checkend_return:;}
9956 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
9957 #define PARSESUB() {goto parsesub; parsesub_return:;}
9958 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
9959 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
9960 #define PARSEARITH() {goto parsearith; parsearith_return:;}
9963 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
9965 /* NB: syntax parameter fits into smallint */
9969 char line[EOFMARKLEN + 1];
9970 struct nodelist *bqlist;
9974 smallint prevsyntax; /* syntax before arithmetic */
9975 #if ENABLE_ASH_EXPAND_PRMT
9976 smallint pssyntax; /* we are expanding a prompt string */
9978 int varnest; /* levels of variables expansion */
9979 int arinest; /* levels of arithmetic expansion */
9980 int parenlevel; /* levels of parens in arithmetic */
9981 int dqvarnest; /* levels of variables expansion within double quotes */
9984 /* Avoid longjmp clobbering */
9996 startlinno = plinno;
10001 #if ENABLE_ASH_EXPAND_PRMT
10002 pssyntax = (syntax == PSSYNTAX);
10006 dblquote = (syntax == DQSYNTAX);
10012 STARTSTACKSTR(out);
10013 loop: { /* for each line, until end of word */
10014 CHECKEND(); /* set c to PEOF if at end of here document */
10015 for (;;) { /* until end of line or end of word */
10016 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10017 switch (SIT(c, syntax)) {
10018 case CNL: /* '\n' */
10019 if (syntax == BASESYNTAX)
10020 goto endword; /* exit outer loop */
10026 goto loop; /* continue outer loop */
10031 if (eofmark == NULL || dblquote)
10032 USTPUTC(CTLESC, out);
10035 case CBACK: /* backslash */
10038 USTPUTC(CTLESC, out);
10039 USTPUTC('\\', out);
10041 } else if (c == '\n') {
10045 #if ENABLE_ASH_EXPAND_PRMT
10046 if (c == '$' && pssyntax) {
10047 USTPUTC(CTLESC, out);
10048 USTPUTC('\\', out);
10052 c != '\\' && c != '`' &&
10057 USTPUTC(CTLESC, out);
10058 USTPUTC('\\', out);
10060 if (SIT(c, SQSYNTAX) == CCTL)
10061 USTPUTC(CTLESC, out);
10069 if (eofmark == NULL) {
10070 USTPUTC(CTLQUOTEMARK, out);
10078 if (eofmark != NULL && arinest == 0
10083 if (dqvarnest == 0) {
10084 syntax = BASESYNTAX;
10091 case CVAR: /* '$' */
10092 PARSESUB(); /* parse substitution */
10094 case CENDVAR: /* '}' */
10097 if (dqvarnest > 0) {
10100 USTPUTC(CTLENDVAR, out);
10105 #if ENABLE_ASH_MATH_SUPPORT
10106 case CLP: /* '(' in arithmetic */
10110 case CRP: /* ')' in arithmetic */
10111 if (parenlevel > 0) {
10115 if (pgetc() == ')') {
10116 if (--arinest == 0) {
10117 USTPUTC(CTLENDARI, out);
10118 syntax = prevsyntax;
10119 dblquote = (syntax == DQSYNTAX);
10124 * unbalanced parens
10125 * (don't 2nd guess - no error)
10133 case CBQUOTE: /* '`' */
10137 goto endword; /* exit outer loop */
10142 goto endword; /* exit outer loop */
10143 #if ENABLE_ASH_ALIAS
10153 #if ENABLE_ASH_MATH_SUPPORT
10154 if (syntax == ARISYNTAX)
10155 raise_error_syntax("Missing '))'");
10157 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10158 raise_error_syntax("Unterminated quoted string");
10159 if (varnest != 0) {
10160 startlinno = plinno;
10162 raise_error_syntax("Missing '}'");
10164 USTPUTC('\0', out);
10165 len = out - (char *)stackblock();
10166 out = stackblock();
10167 if (eofmark == NULL) {
10168 if ((c == '>' || c == '<')
10171 && (*out == '\0' || isdigit(*out))) {
10173 return lasttoken = TREDIR;
10178 quoteflag = quotef;
10179 backquotelist = bqlist;
10180 grabstackblock(len);
10184 /* end of readtoken routine */
10187 * Check to see whether we are at the end of the here document. When this
10188 * is called, c is set to the first character of the next input line. If
10189 * we are at the end of the here document, this routine sets the c to PEOF.
10193 #if ENABLE_ASH_ALIAS
10199 while (c == '\t') {
10203 if (c == *eofmark) {
10204 if (pfgets(line, sizeof(line)) != NULL) {
10208 for (q = eofmark + 1; *q && *p == *q; p++, q++);
10209 if (*p == '\n' && *q == '\0') {
10212 needprompt = doprompt;
10214 pushstring(line, NULL);
10219 goto checkend_return;
10223 * Parse a redirection operator. The variable "out" points to a string
10224 * specifying the fd to be redirected. The variable "c" contains the
10225 * first character of the redirection operator.
10231 np = stalloc(sizeof(struct nfile));
10236 np->type = NAPPEND;
10238 np->type = NCLOBBER;
10245 } else { /* c == '<' */
10250 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10251 np = stalloc(sizeof(struct nhere));
10255 heredoc = stalloc(sizeof(struct heredoc));
10256 heredoc->here = np;
10259 heredoc->striptabs = 1;
10261 heredoc->striptabs = 0;
10267 np->type = NFROMFD;
10271 np->type = NFROMTO;
10281 np->nfile.fd = fd - '0';
10283 goto parseredir_return;
10287 * Parse a substitution. At this point, we have read the dollar sign
10288 * and nothing else.
10291 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
10292 * (assuming ascii char codes, as the original implementation did) */
10293 #define is_special(c) \
10294 ((((unsigned int)c) - 33 < 32) \
10295 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
10301 static const char types[] ALIGN1 = "}-+?=";
10305 c <= PEOA_OR_PEOF ||
10306 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10310 } else if (c == '(') { /* $(command) or $((arith)) */
10311 if (pgetc() == '(') {
10312 #if ENABLE_ASH_MATH_SUPPORT
10315 raise_error_syntax("We unsupport $((arith))");
10322 USTPUTC(CTLVAR, out);
10323 typeloc = out - (char *)stackblock();
10324 USTPUTC(VSNORMAL, out);
10325 subtype = VSNORMAL;
10333 subtype = VSLENGTH;
10337 if (c > PEOA_OR_PEOF && is_name(c)) {
10341 } while (c > PEOA_OR_PEOF && is_in_name(c));
10342 } else if (isdigit(c)) {
10346 } while (isdigit(c));
10347 } else if (is_special(c)) {
10351 badsub: raise_error_syntax("Bad substitution");
10355 if (subtype == 0) {
10362 p = strchr(types, c);
10365 subtype = p - types + VSNORMAL;
10371 subtype = c == '#' ? VSTRIMLEFT :
10384 if (dblquote || arinest)
10386 *((char *)stackblock() + typeloc) = subtype | flags;
10387 if (subtype != VSNORMAL) {
10389 if (dblquote || arinest) {
10394 goto parsesub_return;
10398 * Called to parse command substitutions. Newstyle is set if the command
10399 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10400 * list of commands (passed by reference), and savelen is the number of
10401 * characters on the top of the stack which must be preserved.
10404 struct nodelist **nlpp;
10407 char *volatile str;
10408 struct jmploc jmploc;
10409 struct jmploc *volatile savehandler;
10411 smallint saveprompt = 0;
10414 (void) &saveprompt;
10416 savepbq = parsebackquote;
10417 if (setjmp(jmploc.loc)) {
10419 parsebackquote = 0;
10420 exception_handler = savehandler;
10421 longjmp(exception_handler->loc, 1);
10425 savelen = out - (char *)stackblock();
10427 str = ckmalloc(savelen);
10428 memcpy(str, stackblock(), savelen);
10430 savehandler = exception_handler;
10431 exception_handler = &jmploc;
10434 /* We must read until the closing backquote, giving special
10435 treatment to some slashes, and then push the string and
10436 reread it as input, interpreting it normally. */
10443 STARTSTACKSTR(pout);
10460 * If eating a newline, avoid putting
10461 * the newline into the new character
10462 * stream (via the STPUTC after the
10467 if (pc != '\\' && pc != '`' && pc != '$'
10468 && (!dblquote || pc != '"'))
10469 STPUTC('\\', pout);
10470 if (pc > PEOA_OR_PEOF) {
10476 #if ENABLE_ASH_ALIAS
10479 startlinno = plinno;
10480 raise_error_syntax("EOF in backquote substitution");
10484 needprompt = doprompt;
10493 STPUTC('\0', pout);
10494 psavelen = pout - (char *)stackblock();
10495 if (psavelen > 0) {
10496 pstr = grabstackstr(pout);
10497 setinputstring(pstr);
10502 nlpp = &(*nlpp)->next;
10503 *nlpp = stalloc(sizeof(**nlpp));
10504 (*nlpp)->next = NULL;
10505 parsebackquote = oldstyle;
10508 saveprompt = doprompt;
10515 doprompt = saveprompt;
10516 else if (readtoken() != TRP)
10517 raise_error_unexpected_syntax(TRP);
10522 * Start reading from old file again, ignoring any pushed back
10523 * tokens left from the backquote parsing
10528 while (stackblocksize() <= savelen)
10530 STARTSTACKSTR(out);
10532 memcpy(out, str, savelen);
10533 STADJUST(savelen, out);
10539 parsebackquote = savepbq;
10540 exception_handler = savehandler;
10541 if (arinest || dblquote)
10542 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10544 USTPUTC(CTLBACKQ, out);
10546 goto parsebackq_oldreturn;
10547 goto parsebackq_newreturn;
10550 #if ENABLE_ASH_MATH_SUPPORT
10552 * Parse an arithmetic expansion (indicate start of one and set state)
10555 if (++arinest == 1) {
10556 prevsyntax = syntax;
10557 syntax = ARISYNTAX;
10558 USTPUTC(CTLARI, out);
10565 * we collapse embedded arithmetic expansion to
10566 * parenthesis, which should be equivalent
10570 goto parsearith_return;
10574 } /* end of readtoken */
10577 * Read the next input token.
10578 * If the token is a word, we set backquotelist to the list of cmds in
10579 * backquotes. We set quoteflag to true if any part of the word was
10581 * If the token is TREDIR, then we set redirnode to a structure containing
10583 * In all cases, the variable startlinno is set to the number of the line
10584 * on which the token starts.
10586 * [Change comment: here documents and internal procedures]
10587 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10588 * word parsing code into a separate routine. In this case, readtoken
10589 * doesn't need to have any internal procedures, but parseword does.
10590 * We could also make parseoperator in essence the main routine, and
10591 * have parseword (readtoken1?) handle both words and redirection.]
10593 #define NEW_xxreadtoken
10594 #ifdef NEW_xxreadtoken
10595 /* singles must be first! */
10596 static const char xxreadtoken_chars[7] ALIGN1 = {
10597 '\n', '(', ')', '&', '|', ';', 0
10600 static const char xxreadtoken_tokens[] ALIGN1 = {
10601 TNL, TLP, TRP, /* only single occurrence allowed */
10602 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10603 TEOF, /* corresponds to trailing nul */
10604 TAND, TOR, TENDCASE /* if double occurrence */
10607 #define xxreadtoken_doubles \
10608 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10609 #define xxreadtoken_singles \
10610 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10624 startlinno = plinno;
10625 for (;;) { /* until token or start of word found */
10628 if ((c != ' ') && (c != '\t')
10629 #if ENABLE_ASH_ALIAS
10634 while ((c = pgetc()) != '\n' && c != PEOF);
10636 } else if (c == '\\') {
10637 if (pgetc() != '\n') {
10641 startlinno = ++plinno;
10646 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10651 needprompt = doprompt;
10654 p = strchr(xxreadtoken_chars, c);
10657 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10660 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10661 if (pgetc() == *p) { /* double occurrence? */
10662 p += xxreadtoken_doubles + 1;
10668 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10674 #define RETURN(token) return lasttoken = token
10687 startlinno = plinno;
10688 for (;;) { /* until token or start of word found */
10691 case ' ': case '\t':
10692 #if ENABLE_ASH_ALIAS
10697 while ((c = pgetc()) != '\n' && c != PEOF);
10701 if (pgetc() == '\n') {
10702 startlinno = ++plinno;
10711 needprompt = doprompt;
10716 if (pgetc() == '&')
10721 if (pgetc() == '|')
10726 if (pgetc() == ';')
10739 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10742 #endif /* NEW_xxreadtoken */
10749 smallint alreadyseen = tokpushback;
10752 #if ENABLE_ASH_ALIAS
10761 if (checkkwd & CHKNL) {
10768 if (t != TWORD || quoteflag) {
10773 * check for keywords
10775 if (checkkwd & CHKKWD) {
10776 const char *const *pp;
10778 pp = findkwd(wordtext);
10780 lasttoken = t = pp - tokname_array;
10781 TRACE(("keyword %s recognized\n", tokname(t)));
10786 if (checkkwd & CHKALIAS) {
10787 #if ENABLE_ASH_ALIAS
10789 ap = lookupalias(wordtext, 1);
10792 pushstring(ap->val, ap);
10802 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
10804 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
10816 return tokname_array[t][0];
10820 * Read and parse a command. Returns NEOF on end of file. (NULL is a
10821 * valid parse tree indicating a blank line.)
10823 static union node *
10824 parsecmd(int interact)
10829 doprompt = interact;
10831 setprompt(doprompt);
10843 * Input any here documents.
10848 struct heredoc *here;
10851 here = heredoclist;
10858 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10859 here->eofmark, here->striptabs);
10860 n = stalloc(sizeof(struct narg));
10861 n->narg.type = NARG;
10862 n->narg.next = NULL;
10863 n->narg.text = wordtext;
10864 n->narg.backquote = backquotelist;
10865 here->here->nhere.doc = n;
10872 * called by editline -- any expansions to the prompt should be added here.
10874 #if ENABLE_ASH_EXPAND_PRMT
10875 static const char *
10876 expandstr(const char *ps)
10880 /* XXX Fix (char *) cast. */
10881 setinputstring((char *)ps);
10882 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
10885 n.narg.type = NARG;
10886 n.narg.next = NULL;
10887 n.narg.text = wordtext;
10888 n.narg.backquote = backquotelist;
10890 expandarg(&n, NULL, 0);
10891 return stackblock();
10896 * Execute a command or commands contained in a string.
10899 evalstring(char *s, int mask)
10902 struct stackmark smark;
10906 setstackmark(&smark);
10909 while ((n = parsecmd(0)) != NEOF) {
10911 popstackmark(&smark);
10924 * The eval command.
10927 evalcmd(int argc, char **argv)
10936 STARTSTACKSTR(concat);
10939 concat = stack_putstr(p, concat);
10943 STPUTC(' ', concat);
10945 STPUTC('\0', concat);
10946 p = grabstackstr(concat);
10948 evalstring(p, ~SKIPEVAL);
10955 * Read and execute commands. "Top" is nonzero for the top level command
10956 * loop; it turns on prompting if the shell is interactive.
10962 struct stackmark smark;
10966 TRACE(("cmdloop(%d) called\n", top));
10970 setstackmark(&smark);
10973 showjobs(stderr, SHOW_CHANGED);
10976 if (iflag && top) {
10978 #if ENABLE_ASH_MAIL
10982 n = parsecmd(inter);
10983 /* showtree(n); DEBUG */
10985 if (!top || numeof >= 50)
10987 if (!stoppedjobs()) {
10990 out2str("\nUse \"exit\" to leave shell.\n");
10993 } else if (nflag == 0) {
10994 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
10999 popstackmark(&smark);
11004 return skip & SKIPEVAL;
11011 * Take commands from a file. To be compatible we should do a path
11012 * search for the file, which is necessary to find sub-commands.
11015 find_dot_file(char *name)
11018 const char *path = pathval();
11021 /* don't try this for absolute or relative paths */
11022 if (strchr(name, '/'))
11025 while ((fullname = padvance(&path, name)) != NULL) {
11026 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11028 * Don't bother freeing here, since it will
11029 * be freed by the caller.
11033 stunalloc(fullname);
11036 /* not found in the PATH */
11037 ash_msg_and_raise_error("%s: not found", name);
11042 dotcmd(int argc, char **argv)
11044 struct strlist *sp;
11045 volatile struct shparam saveparam;
11048 for (sp = cmdenviron; sp; sp = sp->next)
11049 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11051 if (argc >= 2) { /* That's what SVR2 does */
11054 fullname = find_dot_file(argv[1]);
11057 saveparam = shellparam;
11058 shellparam.malloced = 0;
11059 shellparam.nparam = argc - 2;
11060 shellparam.p = argv + 2;
11063 setinputfile(fullname, INPUT_PUSH_FILE);
11064 commandname = fullname;
11069 freeparam(&shellparam);
11070 shellparam = saveparam;
11072 status = exitstatus;
11078 exitcmd(int argc, char **argv)
11083 exitstatus = number(argv[1]);
11084 raise_exception(EXEXIT);
11088 #if ENABLE_ASH_BUILTIN_ECHO
11090 echocmd(int argc, char **argv)
11092 return echo_main(argc, argv);
11096 #if ENABLE_ASH_BUILTIN_TEST
11098 testcmd(int argc, char **argv)
11100 return test_main(argc, argv);
11105 * Read a file containing shell functions.
11108 readcmdfile(char *name)
11110 setinputfile(name, INPUT_PUSH_FILE);
11116 /* ============ find_command inplementation */
11119 * Resolve a command name. If you change this routine, you may have to
11120 * change the shellexec routine as well.
11123 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11125 struct tblentry *cmdp;
11132 struct builtincmd *bcmd;
11134 /* If name contains a slash, don't use PATH or hash table */
11135 if (strchr(name, '/') != NULL) {
11136 entry->u.index = -1;
11137 if (act & DO_ABS) {
11138 while (stat(name, &statb) < 0) {
11140 if (errno == EINTR)
11143 entry->cmdtype = CMDUNKNOWN;
11147 entry->cmdtype = CMDNORMAL;
11151 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11153 updatetbl = (path == pathval());
11156 if (strstr(path, "%builtin") != NULL)
11157 act |= DO_ALTBLTIN;
11160 /* If name is in the table, check answer will be ok */
11161 cmdp = cmdlookup(name, 0);
11162 if (cmdp != NULL) {
11165 switch (cmdp->cmdtype) {
11183 } else if (cmdp->rehash == 0)
11184 /* if not invalidated by cd, we're done */
11188 /* If %builtin not in path, check for builtin next */
11189 bcmd = find_builtin(name);
11191 if (IS_BUILTIN_REGULAR(bcmd))
11192 goto builtin_success;
11193 if (act & DO_ALTPATH) {
11194 if (!(act & DO_ALTBLTIN))
11195 goto builtin_success;
11196 } else if (builtinloc <= 0) {
11197 goto builtin_success;
11201 #if ENABLE_FEATURE_SH_STANDALONE
11202 if (find_applet_by_name(name) >= 0) {
11203 entry->cmdtype = CMDNORMAL;
11204 entry->u.index = -1;
11209 /* We have to search path. */
11210 prev = -1; /* where to start */
11211 if (cmdp && cmdp->rehash) { /* doing a rehash */
11212 if (cmdp->cmdtype == CMDBUILTIN)
11215 prev = cmdp->param.index;
11221 while ((fullname = padvance(&path, name)) != NULL) {
11222 stunalloc(fullname);
11223 /* NB: code below will still use fullname
11224 * despite it being "unallocated" */
11227 if (prefix(pathopt, "builtin")) {
11229 goto builtin_success;
11231 } else if (!(act & DO_NOFUNC)
11232 && prefix(pathopt, "func")) {
11233 /* handled below */
11235 /* ignore unimplemented options */
11239 /* if rehash, don't redo absolute path names */
11240 if (fullname[0] == '/' && idx <= prev) {
11243 TRACE(("searchexec \"%s\": no change\n", name));
11246 while (stat(fullname, &statb) < 0) {
11248 if (errno == EINTR)
11251 if (errno != ENOENT && errno != ENOTDIR)
11255 e = EACCES; /* if we fail, this will be the error */
11256 if (!S_ISREG(statb.st_mode))
11258 if (pathopt) { /* this is a %func directory */
11259 stalloc(strlen(fullname) + 1);
11260 /* NB: stalloc will return space pointed by fullname
11261 * (because we don't have any intervening allocations
11262 * between stunalloc above and this stalloc) */
11263 readcmdfile(fullname);
11264 cmdp = cmdlookup(name, 0);
11265 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
11266 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
11267 stunalloc(fullname);
11270 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
11272 entry->cmdtype = CMDNORMAL;
11273 entry->u.index = idx;
11277 cmdp = cmdlookup(name, 1);
11278 cmdp->cmdtype = CMDNORMAL;
11279 cmdp->param.index = idx;
11284 /* We failed. If there was an entry for this command, delete it */
11285 if (cmdp && updatetbl)
11286 delete_cmd_entry();
11288 ash_msg("%s: %s", name, errmsg(e, "not found"));
11289 entry->cmdtype = CMDUNKNOWN;
11294 entry->cmdtype = CMDBUILTIN;
11295 entry->u.cmd = bcmd;
11299 cmdp = cmdlookup(name, 1);
11300 cmdp->cmdtype = CMDBUILTIN;
11301 cmdp->param.cmd = bcmd;
11305 entry->cmdtype = cmdp->cmdtype;
11306 entry->u = cmdp->param;
11310 /* ============ trap.c */
11313 * The trap builtin.
11316 trapcmd(int argc, char **argv)
11325 for (signo = 0; signo < NSIG; signo++) {
11326 if (trap[signo] != NULL) {
11329 sn = get_signame(signo);
11330 out1fmt("trap -- %s %s\n",
11331 single_quote(trap[signo]), sn);
11341 signo = get_signum(*ap);
11343 ash_msg_and_raise_error("%s: bad trap", *ap);
11346 if (LONE_DASH(action))
11349 action = ckstrdup(action);
11352 trap[signo] = action;
11362 /* ============ Builtins */
11364 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
11366 * Lists available builtins
11369 helpcmd(int argc, char **argv)
11373 out1fmt("\nBuilt-in commands:\n-------------------\n");
11374 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
11375 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11376 builtintab[i].name + 1);
11382 #if ENABLE_FEATURE_SH_STANDALONE
11384 const char *a = applet_names;
11386 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
11391 a += strlen(a) + 1;
11396 return EXIT_SUCCESS;
11398 #endif /* FEATURE_SH_EXTRA_QUIET */
11401 * The export and readonly commands.
11404 exportcmd(int argc, char **argv)
11410 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
11412 if (nextopt("p") != 'p') {
11417 p = strchr(name, '=');
11421 vp = *findvar(hashvar(name), name);
11427 setvar(name, p, flag);
11428 } while ((name = *++aptr) != NULL);
11432 showvars(argv[0], flag, 0);
11437 * Delete a function if it exists.
11440 unsetfunc(const char *name)
11442 struct tblentry *cmdp;
11444 cmdp = cmdlookup(name, 0);
11445 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
11446 delete_cmd_entry();
11450 * The unset builtin command. We unset the function before we unset the
11451 * variable to allow a function to be unset when there is a readonly variable
11452 * with the same name.
11455 unsetcmd(int argc, char **argv)
11462 while ((i = nextopt("vf")) != '\0') {
11466 for (ap = argptr; *ap; ap++) {
11482 #include <sys/times.h>
11484 static const unsigned char timescmd_str[] ALIGN1 = {
11485 ' ', offsetof(struct tms, tms_utime),
11486 '\n', offsetof(struct tms, tms_stime),
11487 ' ', offsetof(struct tms, tms_cutime),
11488 '\n', offsetof(struct tms, tms_cstime),
11493 timescmd(int ac, char **av)
11495 long clk_tck, s, t;
11496 const unsigned char *p;
11499 clk_tck = sysconf(_SC_CLK_TCK);
11504 t = *(clock_t *)(((char *) &buf) + p[1]);
11506 out1fmt("%ldm%ld.%.3lds%c",
11508 ((t - s * clk_tck) * 1000) / clk_tck,
11510 } while (*(p += 2));
11515 #if ENABLE_ASH_MATH_SUPPORT
11517 dash_arith(const char *s)
11523 result = arith(s, &errcode);
11526 ash_msg_and_raise_error("exponent less than 0");
11528 ash_msg_and_raise_error("divide by zero");
11530 ash_msg_and_raise_error("expression recursion loop detected");
11531 raise_error_syntax(s);
11539 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
11540 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
11542 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
11545 letcmd(int argc, char **argv)
11552 ash_msg_and_raise_error("expression expected");
11553 for (ap = argv + 1; *ap; ap++) {
11554 i = dash_arith(*ap);
11559 #endif /* ASH_MATH_SUPPORT */
11562 /* ============ miscbltin.c
11564 * Miscellaneous builtins.
11569 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
11570 typedef enum __rlimit_resource rlim_t;
11574 * The read builtin. The -e option causes backslashes to escape the
11575 * following character.
11577 * This uses unbuffered input, which may be avoidable in some cases.
11580 readcmd(int argc, char **argv)
11592 #if ENABLE_ASH_READ_NCHARS
11596 struct termios tty, old_tty;
11598 #if ENABLE_ASH_READ_TIMEOUT
11602 ts.tv_sec = ts.tv_usec = 0;
11607 #if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT
11608 while ((i = nextopt("p:rt:n:s")) != '\0')
11609 #elif ENABLE_ASH_READ_NCHARS
11610 while ((i = nextopt("p:rn:s")) != '\0')
11611 #elif ENABLE_ASH_READ_TIMEOUT
11612 while ((i = nextopt("p:rt:")) != '\0')
11614 while ((i = nextopt("p:r")) != '\0')
11619 prompt = optionarg;
11621 #if ENABLE_ASH_READ_NCHARS
11623 nchars = bb_strtou(optionarg, NULL, 10);
11624 if (nchars < 0 || errno)
11625 ash_msg_and_raise_error("invalid count");
11626 n_flag = nchars; /* just a flag "nchars is nonzero" */
11632 #if ENABLE_ASH_READ_TIMEOUT
11634 ts.tv_sec = bb_strtou(optionarg, &p, 10);
11636 /* EINVAL means number is ok, but not terminated by NUL */
11637 if (*p == '.' && errno == EINVAL) {
11641 ts.tv_usec = bb_strtou(p, &p2, 10);
11643 ash_msg_and_raise_error("invalid timeout");
11645 /* normalize to usec */
11647 ash_msg_and_raise_error("invalid timeout");
11648 while (scale++ < 6)
11651 } else if (ts.tv_sec < 0 || errno) {
11652 ash_msg_and_raise_error("invalid timeout");
11654 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
11655 ash_msg_and_raise_error("invalid timeout");
11666 if (prompt && isatty(0)) {
11671 ash_msg_and_raise_error("arg count");
11672 ifs = bltinlookup("IFS");
11675 #if ENABLE_ASH_READ_NCHARS
11676 if (n_flag || silent) {
11677 if (tcgetattr(0, &tty) != 0) {
11684 tty.c_lflag &= ~ICANON;
11685 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
11688 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
11690 tcsetattr(0, TCSANOW, &tty);
11694 #if ENABLE_ASH_READ_TIMEOUT
11695 if (ts.tv_sec || ts.tv_usec) {
11699 /* poll-based wait produces bigger code, using select */
11700 i = select(1, &set, NULL, NULL, &ts);
11701 if (!i) { /* timed out! */
11702 #if ENABLE_ASH_READ_NCHARS
11704 tcsetattr(0, TCSANOW, &old_tty);
11715 if (read(0, &c, 1) != 1) {
11727 if (!rflag && c == '\\') {
11733 if (startword && *ifs == ' ' && strchr(ifs, c)) {
11737 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
11739 setvar(*ap, stackblock(), 0);
11748 /* end of do {} while: */
11749 #if ENABLE_ASH_READ_NCHARS
11750 while (!n_flag || --nchars);
11755 #if ENABLE_ASH_READ_NCHARS
11756 if (n_flag || silent)
11757 tcsetattr(0, TCSANOW, &old_tty);
11761 /* Remove trailing blanks */
11762 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
11764 setvar(*ap, stackblock(), 0);
11765 while (*++ap != NULL)
11766 setvar(*ap, nullstr, 0);
11771 umaskcmd(int argc, char **argv)
11773 static const char permuser[3] ALIGN1 = "ugo";
11774 static const char permmode[3] ALIGN1 = "rwx";
11775 static const short permmask[] ALIGN2 = {
11776 S_IRUSR, S_IWUSR, S_IXUSR,
11777 S_IRGRP, S_IWGRP, S_IXGRP,
11778 S_IROTH, S_IWOTH, S_IXOTH
11784 int symbolic_mode = 0;
11786 while (nextopt("S") != '\0') {
11797 if (symbolic_mode) {
11801 for (i = 0; i < 3; i++) {
11804 *p++ = permuser[i];
11806 for (j = 0; j < 3; j++) {
11807 if ((mask & permmask[3 * i + j]) == 0) {
11808 *p++ = permmode[j];
11816 out1fmt("%.4o\n", mask);
11819 if (isdigit((unsigned char) *ap)) {
11822 if (*ap >= '8' || *ap < '0')
11823 ash_msg_and_raise_error(illnum, argv[1]);
11824 mask = (mask << 3) + (*ap - '0');
11825 } while (*++ap != '\0');
11828 mask = ~mask & 0777;
11829 if (!bb_parse_mode(ap, &mask)) {
11830 ash_msg_and_raise_error("illegal mode: %s", ap);
11832 umask(~mask & 0777);
11841 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
11842 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
11843 * ash by J.T. Conklin.
11849 uint8_t cmd; /* RLIMIT_xxx fit into it */
11850 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
11854 static const struct limits limits_tbl[] = {
11856 { RLIMIT_CPU, 0, 't' },
11858 #ifdef RLIMIT_FSIZE
11859 { RLIMIT_FSIZE, 9, 'f' },
11862 { RLIMIT_DATA, 10, 'd' },
11864 #ifdef RLIMIT_STACK
11865 { RLIMIT_STACK, 10, 's' },
11868 { RLIMIT_CORE, 9, 'c' },
11871 { RLIMIT_RSS, 10, 'm' },
11873 #ifdef RLIMIT_MEMLOCK
11874 { RLIMIT_MEMLOCK, 10, 'l' },
11876 #ifdef RLIMIT_NPROC
11877 { RLIMIT_NPROC, 0, 'p' },
11879 #ifdef RLIMIT_NOFILE
11880 { RLIMIT_NOFILE, 0, 'n' },
11883 { RLIMIT_AS, 10, 'v' },
11885 #ifdef RLIMIT_LOCKS
11886 { RLIMIT_LOCKS, 0, 'w' },
11889 static const char limits_name[] =
11891 "time(seconds)" "\0"
11893 #ifdef RLIMIT_FSIZE
11894 "file(blocks)" "\0"
11899 #ifdef RLIMIT_STACK
11903 "coredump(blocks)" "\0"
11908 #ifdef RLIMIT_MEMLOCK
11909 "locked memory(kb)" "\0"
11911 #ifdef RLIMIT_NPROC
11914 #ifdef RLIMIT_NOFILE
11920 #ifdef RLIMIT_LOCKS
11925 enum limtype { SOFT = 0x1, HARD = 0x2 };
11928 printlim(enum limtype how, const struct rlimit *limit,
11929 const struct limits *l)
11933 val = limit->rlim_max;
11935 val = limit->rlim_cur;
11937 if (val == RLIM_INFINITY)
11938 out1fmt("unlimited\n");
11940 val >>= l->factor_shift;
11941 out1fmt("%lld\n", (long long) val);
11946 ulimitcmd(int argc, char **argv)
11950 enum limtype how = SOFT | HARD;
11951 const struct limits *l;
11954 struct rlimit limit;
11957 while ((optc = nextopt("HSa"
11961 #ifdef RLIMIT_FSIZE
11967 #ifdef RLIMIT_STACK
11976 #ifdef RLIMIT_MEMLOCK
11979 #ifdef RLIMIT_NPROC
11982 #ifdef RLIMIT_NOFILE
11988 #ifdef RLIMIT_LOCKS
12006 for (l = limits_tbl; l->option != what; l++)
12009 set = *argptr ? 1 : 0;
12013 if (all || argptr[1])
12014 ash_msg_and_raise_error("too many arguments");
12015 if (strncmp(p, "unlimited\n", 9) == 0)
12016 val = RLIM_INFINITY;
12020 while ((c = *p++) >= '0' && c <= '9') {
12021 val = (val * 10) + (long)(c - '0');
12022 if (val < (rlim_t) 0)
12026 ash_msg_and_raise_error("bad number");
12027 val <<= l->factor_shift;
12031 const char *lname = limits_name;
12032 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12033 getrlimit(l->cmd, &limit);
12034 out1fmt("%-20s ", lname);
12035 lname += strlen(lname) + 1;
12036 printlim(how, &limit, l);
12041 getrlimit(l->cmd, &limit);
12044 limit.rlim_max = val;
12046 limit.rlim_cur = val;
12047 if (setrlimit(l->cmd, &limit) < 0)
12048 ash_msg_and_raise_error("error setting limit (%m)");
12050 printlim(how, &limit, l);
12056 /* ============ Math support */
12058 #if ENABLE_ASH_MATH_SUPPORT
12060 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12062 Permission is hereby granted, free of charge, to any person obtaining
12063 a copy of this software and associated documentation files (the
12064 "Software"), to deal in the Software without restriction, including
12065 without limitation the rights to use, copy, modify, merge, publish,
12066 distribute, sublicense, and/or sell copies of the Software, and to
12067 permit persons to whom the Software is furnished to do so, subject to
12068 the following conditions:
12070 The above copyright notice and this permission notice shall be
12071 included in all copies or substantial portions of the Software.
12073 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12074 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12075 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12076 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12077 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12078 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12079 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12082 /* This is my infix parser/evaluator. It is optimized for size, intended
12083 * as a replacement for yacc-based parsers. However, it may well be faster
12084 * than a comparable parser written in yacc. The supported operators are
12085 * listed in #defines below. Parens, order of operations, and error handling
12086 * are supported. This code is thread safe. The exact expression format should
12087 * be that which POSIX specifies for shells. */
12089 /* The code uses a simple two-stack algorithm. See
12090 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12091 * for a detailed explanation of the infix-to-postfix algorithm on which
12092 * this is based (this code differs in that it applies operators immediately
12093 * to the stack instead of adding them to a queue to end up with an
12096 /* To use the routine, call it with an expression string and error return
12100 * Aug 24, 2001 Manuel Novoa III
12102 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12104 * 1) In arith_apply():
12105 * a) Cached values of *numptr and &(numptr[-1]).
12106 * b) Removed redundant test for zero denominator.
12109 * a) Eliminated redundant code for processing operator tokens by moving
12110 * to a table-based implementation. Also folded handling of parens
12112 * b) Combined all 3 loops which called arith_apply to reduce generated
12113 * code size at the cost of speed.
12115 * 3) The following expressions were treated as valid by the original code:
12116 * 1() , 0! , 1 ( *3 ) .
12117 * These bugs have been fixed by internally enclosing the expression in
12118 * parens and then checking that all binary ops and right parens are
12119 * preceded by a valid expression (NUM_TOKEN).
12121 * Note: It may be desirable to replace Aaron's test for whitespace with
12122 * ctype's isspace() if it is used by another busybox applet or if additional
12123 * whitespace chars should be considered. Look below the "#include"s for a
12124 * precompiler test.
12128 * Aug 26, 2001 Manuel Novoa III
12130 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12132 * Merge in Aaron's comments previously posted to the busybox list,
12133 * modified slightly to take account of my changes to the code.
12138 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12140 * - allow access to variable,
12141 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12142 * - realize assign syntax (VAR=expr, +=, *= etc)
12143 * - realize exponentiation (** operator)
12144 * - realize comma separated - expr, expr
12145 * - realise ++expr --expr expr++ expr--
12146 * - realise expr ? expr : expr (but, second expr calculate always)
12147 * - allow hexadecimal and octal numbers
12148 * - was restored loses XOR operator
12149 * - remove one goto label, added three ;-)
12150 * - protect $((num num)) as true zero expr (Manuel`s error)
12151 * - always use special isspace(), see comment from bash ;-)
12154 #define arith_isspace(arithval) \
12155 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12157 typedef unsigned char operator;
12159 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12160 * precedence, and 3 high bits are an ID unique across operators of that
12161 * precedence. The ID portion is so that multiple operators can have the
12162 * same precedence, ensuring that the leftmost one is evaluated first.
12163 * Consider * and /. */
12165 #define tok_decl(prec,id) (((id)<<5)|(prec))
12166 #define PREC(op) ((op) & 0x1F)
12168 #define TOK_LPAREN tok_decl(0,0)
12170 #define TOK_COMMA tok_decl(1,0)
12172 #define TOK_ASSIGN tok_decl(2,0)
12173 #define TOK_AND_ASSIGN tok_decl(2,1)
12174 #define TOK_OR_ASSIGN tok_decl(2,2)
12175 #define TOK_XOR_ASSIGN tok_decl(2,3)
12176 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12177 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12178 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12179 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12181 #define TOK_MUL_ASSIGN tok_decl(3,0)
12182 #define TOK_DIV_ASSIGN tok_decl(3,1)
12183 #define TOK_REM_ASSIGN tok_decl(3,2)
12185 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12186 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12188 /* conditional is right associativity too */
12189 #define TOK_CONDITIONAL tok_decl(4,0)
12190 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12192 #define TOK_OR tok_decl(5,0)
12194 #define TOK_AND tok_decl(6,0)
12196 #define TOK_BOR tok_decl(7,0)
12198 #define TOK_BXOR tok_decl(8,0)
12200 #define TOK_BAND tok_decl(9,0)
12202 #define TOK_EQ tok_decl(10,0)
12203 #define TOK_NE tok_decl(10,1)
12205 #define TOK_LT tok_decl(11,0)
12206 #define TOK_GT tok_decl(11,1)
12207 #define TOK_GE tok_decl(11,2)
12208 #define TOK_LE tok_decl(11,3)
12210 #define TOK_LSHIFT tok_decl(12,0)
12211 #define TOK_RSHIFT tok_decl(12,1)
12213 #define TOK_ADD tok_decl(13,0)
12214 #define TOK_SUB tok_decl(13,1)
12216 #define TOK_MUL tok_decl(14,0)
12217 #define TOK_DIV tok_decl(14,1)
12218 #define TOK_REM tok_decl(14,2)
12220 /* exponent is right associativity */
12221 #define TOK_EXPONENT tok_decl(15,1)
12223 /* For now unary operators. */
12224 #define UNARYPREC 16
12225 #define TOK_BNOT tok_decl(UNARYPREC,0)
12226 #define TOK_NOT tok_decl(UNARYPREC,1)
12228 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12229 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12231 #define PREC_PRE (UNARYPREC+2)
12233 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12234 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12236 #define PREC_POST (UNARYPREC+3)
12238 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12239 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12241 #define SPEC_PREC (UNARYPREC+4)
12243 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12244 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12246 #define NUMPTR (*numstackptr)
12249 tok_have_assign(operator op)
12251 operator prec = PREC(op);
12253 convert_prec_is_assing(prec);
12254 return (prec == PREC(TOK_ASSIGN) ||
12255 prec == PREC_PRE || prec == PREC_POST);
12259 is_right_associativity(operator prec)
12261 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
12262 || prec == PREC(TOK_CONDITIONAL));
12265 typedef struct ARITCH_VAR_NUM {
12267 arith_t contidional_second_val;
12268 char contidional_second_val_initialized;
12269 char *var; /* if NULL then is regular number,
12270 else is variable name */
12273 typedef struct CHK_VAR_RECURSIVE_LOOPED {
12275 struct CHK_VAR_RECURSIVE_LOOPED *next;
12276 } chk_var_recursive_looped_t;
12278 static chk_var_recursive_looped_t *prev_chk_var_recursive;
12281 arith_lookup_val(v_n_t *t)
12284 const char * p = lookupvar(t->var);
12289 /* recursive try as expression */
12290 chk_var_recursive_looped_t *cur;
12291 chk_var_recursive_looped_t cur_save;
12293 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
12294 if (strcmp(cur->var, t->var) == 0) {
12295 /* expression recursion loop detected */
12299 /* save current lookuped var name */
12300 cur = prev_chk_var_recursive;
12301 cur_save.var = t->var;
12302 cur_save.next = cur;
12303 prev_chk_var_recursive = &cur_save;
12305 t->val = arith (p, &errcode);
12306 /* restore previous ptr after recursiving */
12307 prev_chk_var_recursive = cur;
12310 /* allow undefined var as 0 */
12316 /* "applying" a token means performing it on the top elements on the integer
12317 * stack. For a unary operator it will only change the top element, but a
12318 * binary operator will pop two arguments and push a result */
12320 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
12323 arith_t numptr_val, rez;
12324 int ret_arith_lookup_val;
12326 /* There is no operator that can work without arguments */
12327 if (NUMPTR == numstack) goto err;
12328 numptr_m1 = NUMPTR - 1;
12330 /* check operand is var with noninteger value */
12331 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12332 if (ret_arith_lookup_val)
12333 return ret_arith_lookup_val;
12335 rez = numptr_m1->val;
12336 if (op == TOK_UMINUS)
12338 else if (op == TOK_NOT)
12340 else if (op == TOK_BNOT)
12342 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
12344 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
12346 else if (op != TOK_UPLUS) {
12347 /* Binary operators */
12349 /* check and binary operators need two arguments */
12350 if (numptr_m1 == numstack) goto err;
12352 /* ... and they pop one */
12355 if (op == TOK_CONDITIONAL) {
12356 if (! numptr_m1->contidional_second_val_initialized) {
12357 /* protect $((expr1 ? expr2)) without ": expr" */
12360 rez = numptr_m1->contidional_second_val;
12361 } else if (numptr_m1->contidional_second_val_initialized) {
12362 /* protect $((expr1 : expr2)) without "expr ? " */
12365 numptr_m1 = NUMPTR - 1;
12366 if (op != TOK_ASSIGN) {
12367 /* check operand is var with noninteger value for not '=' */
12368 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12369 if (ret_arith_lookup_val)
12370 return ret_arith_lookup_val;
12372 if (op == TOK_CONDITIONAL) {
12373 numptr_m1->contidional_second_val = rez;
12375 rez = numptr_m1->val;
12376 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
12378 else if (op == TOK_OR)
12379 rez = numptr_val || rez;
12380 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
12382 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
12384 else if (op == TOK_AND)
12385 rez = rez && numptr_val;
12386 else if (op == TOK_EQ)
12387 rez = (rez == numptr_val);
12388 else if (op == TOK_NE)
12389 rez = (rez != numptr_val);
12390 else if (op == TOK_GE)
12391 rez = (rez >= numptr_val);
12392 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
12393 rez >>= numptr_val;
12394 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
12395 rez <<= numptr_val;
12396 else if (op == TOK_GT)
12397 rez = (rez > numptr_val);
12398 else if (op == TOK_LT)
12399 rez = (rez < numptr_val);
12400 else if (op == TOK_LE)
12401 rez = (rez <= numptr_val);
12402 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
12404 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
12406 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
12408 else if (op == TOK_ASSIGN || op == TOK_COMMA)
12410 else if (op == TOK_CONDITIONAL_SEP) {
12411 if (numptr_m1 == numstack) {
12412 /* protect $((expr : expr)) without "expr ? " */
12415 numptr_m1->contidional_second_val_initialized = op;
12416 numptr_m1->contidional_second_val = numptr_val;
12417 } else if (op == TOK_CONDITIONAL) {
12419 numptr_val : numptr_m1->contidional_second_val;
12420 } else if (op == TOK_EXPONENT) {
12421 if (numptr_val < 0)
12422 return -3; /* exponent less than 0 */
12427 while (numptr_val--)
12431 } else if (numptr_val==0) /* zero divisor check */
12433 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
12435 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
12438 if (tok_have_assign(op)) {
12439 char buf[sizeof(arith_t_type)*3 + 2];
12441 if (numptr_m1->var == NULL) {
12445 /* save to shell variable */
12446 #if ENABLE_ASH_MATH_SUPPORT_64
12447 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
12449 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
12451 setvar(numptr_m1->var, buf, 0);
12452 /* after saving, make previous value for v++ or v-- */
12453 if (op == TOK_POST_INC)
12455 else if (op == TOK_POST_DEC)
12458 numptr_m1->val = rez;
12459 /* protect geting var value, is number now */
12460 numptr_m1->var = NULL;
12466 /* longest must be first */
12467 static const char op_tokens[] ALIGN1 = {
12468 '<','<','=',0, TOK_LSHIFT_ASSIGN,
12469 '>','>','=',0, TOK_RSHIFT_ASSIGN,
12470 '<','<', 0, TOK_LSHIFT,
12471 '>','>', 0, TOK_RSHIFT,
12472 '|','|', 0, TOK_OR,
12473 '&','&', 0, TOK_AND,
12474 '!','=', 0, TOK_NE,
12475 '<','=', 0, TOK_LE,
12476 '>','=', 0, TOK_GE,
12477 '=','=', 0, TOK_EQ,
12478 '|','=', 0, TOK_OR_ASSIGN,
12479 '&','=', 0, TOK_AND_ASSIGN,
12480 '*','=', 0, TOK_MUL_ASSIGN,
12481 '/','=', 0, TOK_DIV_ASSIGN,
12482 '%','=', 0, TOK_REM_ASSIGN,
12483 '+','=', 0, TOK_PLUS_ASSIGN,
12484 '-','=', 0, TOK_MINUS_ASSIGN,
12485 '-','-', 0, TOK_POST_DEC,
12486 '^','=', 0, TOK_XOR_ASSIGN,
12487 '+','+', 0, TOK_POST_INC,
12488 '*','*', 0, TOK_EXPONENT,
12492 '=', 0, TOK_ASSIGN,
12504 '?', 0, TOK_CONDITIONAL,
12505 ':', 0, TOK_CONDITIONAL_SEP,
12506 ')', 0, TOK_RPAREN,
12507 '(', 0, TOK_LPAREN,
12511 #define endexpression &op_tokens[sizeof(op_tokens)-7]
12514 arith(const char *expr, int *perrcode)
12516 char arithval; /* Current character under analysis */
12517 operator lasttok, op;
12520 const char *p = endexpression;
12523 size_t datasizes = strlen(expr) + 2;
12525 /* Stack of integers */
12526 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
12527 * in any given correct or incorrect expression is left as an exercise to
12529 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
12530 *numstackptr = numstack;
12531 /* Stack of operator tokens */
12532 operator *stack = alloca((datasizes) * sizeof(operator)),
12535 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
12536 *perrcode = errcode = 0;
12540 if (arithval == 0) {
12541 if (p == endexpression) {
12542 /* Null expression. */
12546 /* This is only reached after all tokens have been extracted from the
12547 * input stream. If there are still tokens on the operator stack, they
12548 * are to be applied in order. At the end, there should be a final
12549 * result on the integer stack */
12551 if (expr != endexpression + 1) {
12552 /* If we haven't done so already, */
12553 /* append a closing right paren */
12554 expr = endexpression;
12555 /* and let the loop process it. */
12558 /* At this point, we're done with the expression. */
12559 if (numstackptr != numstack+1) {
12560 /* ... but if there isn't, it's bad */
12562 return (*perrcode = -1);
12564 if (numstack->var) {
12565 /* expression is $((var)) only, lookup now */
12566 errcode = arith_lookup_val(numstack);
12569 *perrcode = errcode;
12570 return numstack->val;
12573 /* Continue processing the expression. */
12574 if (arith_isspace(arithval)) {
12575 /* Skip whitespace */
12578 p = endofname(expr);
12580 size_t var_name_size = (p-expr) + 1; /* trailing zero */
12582 numstackptr->var = alloca(var_name_size);
12583 safe_strncpy(numstackptr->var, expr, var_name_size);
12586 numstackptr->contidional_second_val_initialized = 0;
12591 if (isdigit(arithval)) {
12592 numstackptr->var = NULL;
12593 #if ENABLE_ASH_MATH_SUPPORT_64
12594 numstackptr->val = strtoll(expr, (char **) &expr, 0);
12596 numstackptr->val = strtol(expr, (char **) &expr, 0);
12600 for (p = op_tokens; ; p++) {
12604 /* strange operator not found */
12607 for (o = expr; *p && *o == *p; p++)
12614 /* skip tail uncompared token */
12617 /* skip zero delim */
12622 /* post grammar: a++ reduce to num */
12623 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
12626 /* Plus and minus are binary (not unary) _only_ if the last
12627 * token was as number, or a right paren (which pretends to be
12628 * a number, since it evaluates to one). Think about it.
12629 * It makes sense. */
12630 if (lasttok != TOK_NUM) {
12646 /* We don't want a unary operator to cause recursive descent on the
12647 * stack, because there can be many in a row and it could cause an
12648 * operator to be evaluated before its argument is pushed onto the
12649 * integer stack. */
12650 /* But for binary operators, "apply" everything on the operator
12651 * stack until we find an operator with a lesser priority than the
12652 * one we have just extracted. */
12653 /* Left paren is given the lowest priority so it will never be
12654 * "applied" in this way.
12655 * if associativity is right and priority eq, applied also skip
12658 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
12659 /* not left paren or unary */
12660 if (lasttok != TOK_NUM) {
12661 /* binary op must be preceded by a num */
12664 while (stackptr != stack) {
12665 if (op == TOK_RPAREN) {
12666 /* The algorithm employed here is simple: while we don't
12667 * hit an open paren nor the bottom of the stack, pop
12668 * tokens and apply them */
12669 if (stackptr[-1] == TOK_LPAREN) {
12671 /* Any operator directly after a */
12673 /* close paren should consider itself binary */
12677 operator prev_prec = PREC(stackptr[-1]);
12679 convert_prec_is_assing(prec);
12680 convert_prec_is_assing(prev_prec);
12681 if (prev_prec < prec)
12683 /* check right assoc */
12684 if (prev_prec == prec && is_right_associativity(prec))
12687 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
12688 if (errcode) goto ret;
12690 if (op == TOK_RPAREN) {
12695 /* Push this operator to the stack and remember it. */
12696 *stackptr++ = lasttok = op;
12701 #endif /* ASH_MATH_SUPPORT */
12704 /* ============ main() and helpers */
12707 * Called to exit the shell.
12709 static void exitshell(void) ATTRIBUTE_NORETURN;
12717 status = exitstatus;
12718 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12719 if (setjmp(loc.loc)) {
12720 if (exception == EXEXIT)
12721 /* dash bug: it just does _exit(exitstatus) here
12722 * but we have to do setjobctl(0) first!
12723 * (bug is still not fixed in dash-0.5.3 - if you run dash
12724 * under Midnight Commander, on exit from dash MC is backgrounded) */
12725 status = exitstatus;
12728 exception_handler = &loc;
12734 flush_stdout_stderr();
12744 /* from input.c: */
12745 basepf.nextc = basepf.buf = basebuf;
12748 signal(SIGCHLD, SIG_DFL);
12753 char ppid[sizeof(int)*3 + 1];
12755 struct stat st1, st2;
12758 for (envp = environ; envp && *envp; envp++) {
12759 if (strchr(*envp, '=')) {
12760 setvareq(*envp, VEXPORT|VTEXTFIXED);
12764 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
12765 setvar("PPID", ppid, 0);
12767 p = lookupvar("PWD");
12769 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
12770 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
12777 * Process the shell command line arguments.
12780 procargs(int argc, char **argv)
12783 const char *xminusc;
12790 for (i = 0; i < NOPTS; i++)
12796 if (*xargv == NULL) {
12798 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
12801 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
12805 for (i = 0; i < NOPTS; i++)
12806 if (optlist[i] == 2)
12811 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
12816 } else if (!sflag) {
12817 setinputfile(*xargv, 0);
12820 commandname = arg0;
12823 shellparam.p = xargv;
12824 #if ENABLE_ASH_GETOPTS
12825 shellparam.optind = 1;
12826 shellparam.optoff = -1;
12828 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
12830 shellparam.nparam++;
12837 * Read /etc/profile or .profile.
12840 read_profile(const char *name)
12844 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
12853 * This routine is called when an error or an interrupt occurs in an
12854 * interactive shell and control is returned to the main command loop.
12862 /* from input.c: */
12863 parselleft = parsenleft = 0; /* clear input buffer */
12865 /* from parser.c: */
12868 /* from redir.c: */
12873 static short profile_buf[16384];
12874 extern int etext();
12878 * Main routine. We initialize things, parse the arguments, execute
12879 * profiles if we're a login shell, and then call cmdloop to execute
12880 * commands. The setjmp call sets up the location to jump to when an
12881 * exception occurs. When an exception occurs the variable "state"
12882 * is used to figure out how far we had gotten.
12884 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
12885 int ash_main(int argc, char **argv)
12888 volatile int state;
12889 struct jmploc jmploc;
12890 struct stackmark smark;
12892 /* Initialize global data */
12896 #if ENABLE_ASH_ALIAS
12902 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
12905 #if ENABLE_FEATURE_EDITING
12906 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
12909 if (setjmp(jmploc.loc)) {
12919 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
12923 outcslow('\n', stderr);
12925 popstackmark(&smark);
12926 FORCE_INT_ON; /* enable interrupts */
12935 exception_handler = &jmploc;
12938 trace_puts("Shell args: ");
12939 trace_puts_args(argv);
12941 rootpid = getpid();
12943 #if ENABLE_ASH_RANDOM_SUPPORT
12944 rseed = rootpid + time(NULL);
12947 setstackmark(&smark);
12948 procargs(argc, argv);
12949 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
12951 const char *hp = lookupvar("HISTFILE");
12954 hp = lookupvar("HOME");
12956 char *defhp = concat_path_file(hp, ".ash_history");
12957 setvar("HISTFILE", defhp, 0);
12963 if (argv[0] && argv[0][0] == '-')
12967 read_profile("/etc/profile");
12970 read_profile(".profile");
12976 getuid() == geteuid() && getgid() == getegid() &&
12980 shinit = lookupvar("ENV");
12981 if (shinit != NULL && *shinit != '\0') {
12982 read_profile(shinit);
12988 evalstring(minusc, 0);
12990 if (sflag || minusc == NULL) {
12991 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
12993 const char *hp = lookupvar("HISTFILE");
12996 line_input_state->hist_file = hp;
12999 state4: /* XXX ??? - why isn't this before the "if" statement */
13007 extern void _mcleanup(void);
13016 const char *applet_name = "debug stuff usage";
13017 int main(int argc, char **argv)
13019 return ash_main(argc, argv);
13025 * Copyright (c) 1989, 1991, 1993, 1994
13026 * The Regents of the University of California. All rights reserved.
13028 * This code is derived from software contributed to Berkeley by
13029 * Kenneth Almquist.
13031 * Redistribution and use in source and binary forms, with or without
13032 * modification, are permitted provided that the following conditions
13034 * 1. Redistributions of source code must retain the above copyright
13035 * notice, this list of conditions and the following disclaimer.
13036 * 2. Redistributions in binary form must reproduce the above copyright
13037 * notice, this list of conditions and the following disclaimer in the
13038 * documentation and/or other materials provided with the distribution.
13039 * 3. Neither the name of the University nor the names of its contributors
13040 * may be used to endorse or promote products derived from this software
13041 * without specific prior written permission.
13043 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13044 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13045 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13046 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13047 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13048 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13049 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13050 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13051 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13052 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF