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.
49 #define JOBS ENABLE_ASH_JOB_CONTROL
57 #include "busybox.h" /* for applet_names */
61 #if JOBS || ENABLE_ASH_READ_NCHARS
65 #if defined(__uClinux__)
66 #error "Do not even bother, ash will not run on uClinux"
70 /* ============ Hash table sizes. Configurable. */
74 #define CMDTABLESIZE 31 /* should be prime */
77 /* ============ Misc helpers */
79 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
81 /* C99 say: "char" declaration may be signed or unsigned default */
82 #define signed_char2int(sc) ((int)((signed char)sc))
85 /* ============ Shell options */
87 static const char *const optletters_optnames[] = {
108 #define optletters(n) optletters_optnames[(n)][0]
109 #define optnames(n) (&optletters_optnames[(n)][1])
111 enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
113 static char optlist[NOPTS] ALIGN1;
115 #define eflag optlist[0]
116 #define fflag optlist[1]
117 #define Iflag optlist[2]
118 #define iflag optlist[3]
119 #define mflag optlist[4]
120 #define nflag optlist[5]
121 #define sflag optlist[6]
122 #define xflag optlist[7]
123 #define vflag optlist[8]
124 #define Cflag optlist[9]
125 #define aflag optlist[10]
126 #define bflag optlist[11]
127 #define uflag optlist[12]
128 #define viflag optlist[13]
130 #define nolog optlist[14]
131 #define debug optlist[15]
135 /* ============ Misc data */
137 static const char homestr[] ALIGN1 = "HOME";
138 static const char snlfmt[] ALIGN1 = "%s\n";
139 static const char illnum[] ALIGN1 = "Illegal number: %s";
142 * We enclose jmp_buf in a structure so that we can declare pointers to
143 * jump locations. The global variable handler contains the location to
144 * jump to when an exception occurs, and the global variable exception
145 * contains a code identifying the exception. To implement nested
146 * exception handlers, the user should save the value of handler on entry
147 * to an inner scope, set handler to point to a jmploc structure for the
148 * inner scope, and restore handler on exit from the scope.
154 struct globals_misc {
155 /* pid of main shell */
157 /* shell level: 0 for the main shell, 1 for its children, and so on */
159 #define rootshell (!shlvl)
160 char *minusc; /* argument to -c option */
162 char *curdir; // = nullstr; /* current working directory */
163 char *physdir; // = nullstr; /* physical working directory */
165 char *arg0; /* value of $0 */
167 struct jmploc *exception_handler;
169 // disabled by vda: cannot understand how it was supposed to work -
170 // cannot fix bugs. That's why you have to explain your non-trivial designs!
171 // /* do we generate EXSIG events */
172 // int exsig; /* counter */
173 volatile int suppressint; /* counter */
174 volatile /*sig_atomic_t*/ smallint intpending; /* 1 = got SIGINT */
175 /* last pending signal */
176 volatile /*sig_atomic_t*/ smallint pendingsig;
177 smallint exception; /* kind of exception (0..5) */
179 #define EXINT 0 /* SIGINT received */
180 #define EXERROR 1 /* a generic error */
181 #define EXSHELLPROC 2 /* execute a shell procedure */
182 #define EXEXEC 3 /* command execution failed */
183 #define EXEXIT 4 /* exit the shell */
184 #define EXSIG 5 /* trapped signal in wait(1) */
186 /* trap handler commands */
189 char nullstr[1]; /* zero length string */
191 * Sigmode records the current value of the signal handlers for the various
192 * modes. A value of zero means that the current handler is not known.
193 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
195 char sigmode[NSIG - 1];
196 #define S_DFL 1 /* default signal handling (SIG_DFL) */
197 #define S_CATCH 2 /* signal is caught */
198 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
199 #define S_HARD_IGN 4 /* signal is ignored permenantly */
200 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
202 /* indicates specified signal received */
203 char gotsig[NSIG - 1];
205 extern struct globals_misc *const ash_ptr_to_globals_misc;
206 #define G_misc (*ash_ptr_to_globals_misc)
207 #define rootpid (G_misc.rootpid )
208 #define shlvl (G_misc.shlvl )
209 #define minusc (G_misc.minusc )
210 #define curdir (G_misc.curdir )
211 #define physdir (G_misc.physdir )
212 #define arg0 (G_misc.arg0 )
213 #define exception_handler (G_misc.exception_handler)
214 #define exception (G_misc.exception )
215 #define suppressint (G_misc.suppressint )
216 #define intpending (G_misc.intpending )
217 //#define exsig (G_misc.exsig )
218 #define pendingsig (G_misc.pendingsig )
219 #define isloginsh (G_misc.isloginsh)
220 #define trap (G_misc.trap )
221 #define nullstr (G_misc.nullstr )
222 #define sigmode (G_misc.sigmode )
223 #define gotsig (G_misc.gotsig )
224 #define INIT_G_misc() do { \
225 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
232 /* ============ Interrupts / exceptions */
235 * These macros allow the user to suspend the handling of interrupt signals
236 * over a period of time. This is similar to SIGHOLD or to sigblock, but
237 * much more efficient and portable. (But hacking the kernel is so much
238 * more fun than worrying about efficiency and portability. :-))
247 * Called to raise an exception. Since C doesn't include exceptions, we
248 * just do a longjmp to the exception handler. The type of exception is
249 * stored in the global variable "exception".
251 static void raise_exception(int) ATTRIBUTE_NORETURN;
253 raise_exception(int e)
256 if (exception_handler == NULL)
261 longjmp(exception_handler->loc, 1);
265 * Called from trap.c when a SIGINT is received. (If the user specifies
266 * that SIGINT is to be trapped or ignored using the trap builtin, then
267 * this routine is not called.) Suppressint is nonzero when interrupts
268 * are held using the INT_OFF macro. (The test for iflag is just
269 * defensive programming.)
271 static void raise_interrupt(void) ATTRIBUTE_NORETURN;
273 raise_interrupt(void)
278 /* Signal is not automatically unmasked after it is raised,
279 * do it ourself - unmask all signals */
280 sigprocmask_allsigs(SIG_UNBLOCK);
281 /* pendingsig = 0; - now done in onsig() */
284 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
285 if (!(rootshell && iflag)) {
286 /* Kill ourself with SIGINT */
287 signal(SIGINT, SIG_DFL);
296 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
300 if (--suppressint == 0 && intpending) {
304 #define INT_ON int_on()
312 #define FORCE_INT_ON force_int_on()
317 if (--suppressint == 0 && intpending) \
320 #define FORCE_INT_ON \
327 #endif /* ASH_OPTIMIZE_FOR_SIZE */
329 #define SAVE_INT(v) ((v) = suppressint)
331 #define RESTORE_INT(v) \
335 if (suppressint == 0 && intpending) \
340 * Ignore a signal. Only one usage site - in forkchild()
345 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
346 signal(signo, SIG_IGN);
348 sigmode[signo - 1] = S_HARD_IGN;
352 * Signal handler. Only one usage site - in setsignal()
357 gotsig[signo - 1] = 1;
360 if ( /* exsig || */ (signo == SIGINT && !trap[SIGINT])) {
363 raise_interrupt(); /* does not return */
370 /* ============ Stdout/stderr output */
373 outstr(const char *p, FILE *file)
381 flush_stdout_stderr(void)
398 outcslow(int c, FILE *dest)
406 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
408 out1fmt(const char *fmt, ...)
415 r = vprintf(fmt, ap);
421 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
423 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
430 ret = vsnprintf(outbuf, length, fmt, ap);
437 out1str(const char *p)
443 out2str(const char *p)
450 /* ============ Parser structures */
452 /* control characters in argument strings */
453 #define CTLESC '\201' /* escape next character */
454 #define CTLVAR '\202' /* variable defn */
455 #define CTLENDVAR '\203'
456 #define CTLBACKQ '\204'
457 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
458 /* CTLBACKQ | CTLQUOTE == '\205' */
459 #define CTLARI '\206' /* arithmetic expression */
460 #define CTLENDARI '\207'
461 #define CTLQUOTEMARK '\210'
463 /* variable substitution byte (follows CTLVAR) */
464 #define VSTYPE 0x0f /* type of variable substitution */
465 #define VSNUL 0x10 /* colon--treat the empty string as unset */
466 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
468 /* values of VSTYPE field */
469 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
470 #define VSMINUS 0x2 /* ${var-text} */
471 #define VSPLUS 0x3 /* ${var+text} */
472 #define VSQUESTION 0x4 /* ${var?message} */
473 #define VSASSIGN 0x5 /* ${var=text} */
474 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
475 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
476 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
477 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
478 #define VSLENGTH 0xa /* ${#var} */
479 #if ENABLE_ASH_BASH_COMPAT
480 #define VSSUBSTR 0xc /* ${var:position:length} */
481 #define VSREPLACE 0xd /* ${var/pattern/replacement} */
482 #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
485 static const char dolatstr[] ALIGN1 = {
486 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
522 union node *redirect;
528 struct nodelist *cmdlist;
534 union node *redirect;
547 union node *elsepart;
574 struct nodelist *backquote;
609 struct nredir nredir;
610 struct nbinary nbinary;
614 struct nclist nclist;
623 struct nodelist *next;
636 freefunc(struct funcnode *f)
638 if (f && --f->count < 0)
643 /* ============ Debugging output */
647 static FILE *tracefile;
650 trace_printf(const char *fmt, ...)
657 vfprintf(tracefile, fmt, va);
662 trace_vprintf(const char *fmt, va_list va)
666 vfprintf(tracefile, fmt, va);
670 trace_puts(const char *s)
678 trace_puts_quoted(char *s)
685 putc('"', tracefile);
686 for (p = s; *p; p++) {
688 case '\n': c = 'n'; goto backslash;
689 case '\t': c = 't'; goto backslash;
690 case '\r': c = 'r'; goto backslash;
691 case '"': c = '"'; goto backslash;
692 case '\\': c = '\\'; goto backslash;
693 case CTLESC: c = 'e'; goto backslash;
694 case CTLVAR: c = 'v'; goto backslash;
695 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
696 case CTLBACKQ: c = 'q'; goto backslash;
697 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
699 putc('\\', tracefile);
703 if (*p >= ' ' && *p <= '~')
706 putc('\\', tracefile);
707 putc(*p >> 6 & 03, tracefile);
708 putc(*p >> 3 & 07, tracefile);
709 putc(*p & 07, tracefile);
714 putc('"', tracefile);
718 trace_puts_args(char **ap)
725 trace_puts_quoted(*ap);
727 putc('\n', tracefile);
730 putc(' ', tracefile);
745 /* leave open because libedit might be using it */
748 strcpy(s, "./trace");
750 if (!freopen(s, "a", tracefile)) {
751 fprintf(stderr, "Can't re-open %s\n", s);
756 tracefile = fopen(s, "a");
757 if (tracefile == NULL) {
758 fprintf(stderr, "Can't open %s\n", s);
764 flags = fcntl(fileno(tracefile), F_GETFL);
766 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
768 setlinebuf(tracefile);
769 fputs("\nTracing started.\n", tracefile);
773 indent(int amount, char *pfx, FILE *fp)
777 for (i = 0; i < amount; i++) {
778 if (pfx && i == amount - 1)
784 /* little circular references here... */
785 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
788 sharg(union node *arg, FILE *fp)
791 struct nodelist *bqlist;
794 if (arg->type != NARG) {
795 out1fmt("<node type %d>\n", arg->type);
798 bqlist = arg->narg.backquote;
799 for (p = arg->narg.text; *p; p++) {
808 if (subtype == VSLENGTH)
817 switch (subtype & VSTYPE) {
850 out1fmt("<subtype %d>", subtype);
857 case CTLBACKQ|CTLQUOTE:
860 shtree(bqlist->n, -1, NULL, fp);
871 shcmd(union node *cmd, FILE *fp)
879 for (np = cmd->ncmd.args; np; np = np->narg.next) {
885 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
889 switch (np->nfile.type) {
890 case NTO: s = ">>"+1; dftfd = 1; break;
891 case NCLOBBER: s = ">|"; dftfd = 1; break;
892 case NAPPEND: s = ">>"; dftfd = 1; break;
893 case NTOFD: s = ">&"; dftfd = 1; break;
894 case NFROM: s = "<"; break;
895 case NFROMFD: s = "<&"; break;
896 case NFROMTO: s = "<>"; break;
897 default: s = "*error*"; break;
899 if (np->nfile.fd != dftfd)
900 fprintf(fp, "%d", np->nfile.fd);
902 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
903 fprintf(fp, "%d", np->ndup.dupfd);
905 sharg(np->nfile.fname, fp);
912 shtree(union node *n, int ind, char *pfx, FILE *fp)
920 indent(ind, pfx, fp);
931 shtree(n->nbinary.ch1, ind, NULL, fp);
934 shtree(n->nbinary.ch2, ind, NULL, fp);
942 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
947 if (n->npipe.backgnd)
953 fprintf(fp, "<node type %d>", n->type);
961 showtree(union node *n)
963 trace_puts("showtree called\n");
964 shtree(n, 1, NULL, stdout);
967 #define TRACE(param) trace_printf param
968 #define TRACEV(param) trace_vprintf param
973 #define TRACEV(param)
978 /* ============ Parser data */
981 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
984 struct strlist *next;
993 struct strpush *prev; /* preceding string on stack */
997 struct alias *ap; /* if push was associated with an alias */
999 char *string; /* remember the string since it may change */
1003 struct parsefile *prev; /* preceding file on stack */
1004 int linno; /* current line */
1005 int fd; /* file descriptor (or -1 if string) */
1006 int nleft; /* number of chars left in this line */
1007 int lleft; /* number of chars left in this buffer */
1008 char *nextc; /* next char in buffer */
1009 char *buf; /* input buffer */
1010 struct strpush *strpush; /* for pushing strings at this level */
1011 struct strpush basestrpush; /* so pushing one is fast */
1014 static struct parsefile basepf; /* top level input file */
1015 static struct parsefile *g_parsefile = &basepf; /* current input file */
1016 static int startlinno; /* line # where last token started */
1017 static char *commandname; /* currently executing command */
1018 static struct strlist *cmdenviron; /* environment for builtin command */
1019 static int exitstatus; /* exit status of last command */
1022 /* ============ Message printing */
1025 ash_vmsg(const char *msg, va_list ap)
1027 fprintf(stderr, "%s: ", arg0);
1029 if (strcmp(arg0, commandname))
1030 fprintf(stderr, "%s: ", commandname);
1031 if (!iflag || g_parsefile->fd)
1032 fprintf(stderr, "line %d: ", startlinno);
1034 vfprintf(stderr, msg, ap);
1035 outcslow('\n', stderr);
1039 * Exverror is called to raise the error exception. If the second argument
1040 * is not NULL then error prints an error message using printf style
1041 * formatting. It then raises the error exception.
1043 static void ash_vmsg_and_raise(int, const char *, va_list) ATTRIBUTE_NORETURN;
1045 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1049 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1051 TRACE(("\") pid=%d\n", getpid()));
1053 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1058 flush_stdout_stderr();
1059 raise_exception(cond);
1063 static void ash_msg_and_raise_error(const char *, ...) ATTRIBUTE_NORETURN;
1065 ash_msg_and_raise_error(const char *msg, ...)
1070 ash_vmsg_and_raise(EXERROR, msg, ap);
1075 static void ash_msg_and_raise(int, const char *, ...) ATTRIBUTE_NORETURN;
1077 ash_msg_and_raise(int cond, const char *msg, ...)
1082 ash_vmsg_and_raise(cond, msg, ap);
1088 * error/warning routines for external builtins
1091 ash_msg(const char *fmt, ...)
1101 * Return a string describing an error. The returned string may be a
1102 * pointer to a static buffer that will be overwritten on the next call.
1103 * Action describes the operation that got the error.
1106 errmsg(int e, const char *em)
1108 if (e == ENOENT || e == ENOTDIR) {
1115 /* ============ Memory allocation */
1118 * It appears that grabstackstr() will barf with such alignments
1119 * because stalloc() will return a string allocated in a new stackblock.
1121 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1123 /* Most machines require the value returned from malloc to be aligned
1124 * in some way. The following macro will get this right
1125 * on many machines. */
1126 SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,
1127 /* Minimum size of a block */
1128 MINSIZE = SHELL_ALIGN(504),
1131 struct stack_block {
1132 struct stack_block *prev;
1133 char space[MINSIZE];
1137 struct stack_block *stackp;
1140 struct stackmark *marknext;
1144 struct globals_memstack {
1145 struct stack_block *g_stackp; // = &stackbase;
1146 struct stackmark *markp;
1147 char *g_stacknxt; // = stackbase.space;
1148 char *sstrend; // = stackbase.space + MINSIZE;
1149 size_t g_stacknleft; // = MINSIZE;
1150 int herefd; // = -1;
1151 struct stack_block stackbase;
1153 extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1154 #define G_memstack (*ash_ptr_to_globals_memstack)
1155 #define g_stackp (G_memstack.g_stackp )
1156 #define markp (G_memstack.markp )
1157 #define g_stacknxt (G_memstack.g_stacknxt )
1158 #define sstrend (G_memstack.sstrend )
1159 #define g_stacknleft (G_memstack.g_stacknleft)
1160 #define herefd (G_memstack.herefd )
1161 #define stackbase (G_memstack.stackbase )
1162 #define INIT_G_memstack() do { \
1163 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1165 g_stackp = &stackbase; \
1166 g_stacknxt = stackbase.space; \
1167 g_stacknleft = MINSIZE; \
1168 sstrend = stackbase.space + MINSIZE; \
1172 #define stackblock() ((void *)g_stacknxt)
1173 #define stackblocksize() g_stacknleft
1177 ckrealloc(void * p, size_t nbytes)
1179 p = realloc(p, nbytes);
1181 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1186 ckmalloc(size_t nbytes)
1188 return ckrealloc(NULL, nbytes);
1192 ckzalloc(size_t nbytes)
1194 return memset(ckmalloc(nbytes), 0, nbytes);
1198 * Make a copy of a string in safe storage.
1201 ckstrdup(const char *s)
1203 char *p = strdup(s);
1205 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1210 * Parse trees for commands are allocated in lifo order, so we use a stack
1211 * to make this more efficient, and also to avoid all sorts of exception
1212 * handling code to handle interrupts in the middle of a parse.
1214 * The size 504 was chosen because the Ultrix malloc handles that size
1218 stalloc(size_t nbytes)
1223 aligned = SHELL_ALIGN(nbytes);
1224 if (aligned > g_stacknleft) {
1227 struct stack_block *sp;
1229 blocksize = aligned;
1230 if (blocksize < MINSIZE)
1231 blocksize = MINSIZE;
1232 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1233 if (len < blocksize)
1234 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1237 sp->prev = g_stackp;
1238 g_stacknxt = sp->space;
1239 g_stacknleft = blocksize;
1240 sstrend = g_stacknxt + blocksize;
1245 g_stacknxt += aligned;
1246 g_stacknleft -= aligned;
1251 stzalloc(size_t nbytes)
1253 return memset(stalloc(nbytes), 0, nbytes);
1260 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1261 write(STDERR_FILENO, "stunalloc\n", 10);
1265 g_stacknleft += g_stacknxt - (char *)p;
1270 * Like strdup but works with the ash stack.
1273 ststrdup(const char *p)
1275 size_t len = strlen(p) + 1;
1276 return memcpy(stalloc(len), p, len);
1280 setstackmark(struct stackmark *mark)
1282 mark->stackp = g_stackp;
1283 mark->stacknxt = g_stacknxt;
1284 mark->stacknleft = g_stacknleft;
1285 mark->marknext = markp;
1290 popstackmark(struct stackmark *mark)
1292 struct stack_block *sp;
1298 markp = mark->marknext;
1299 while (g_stackp != mark->stackp) {
1301 g_stackp = sp->prev;
1304 g_stacknxt = mark->stacknxt;
1305 g_stacknleft = mark->stacknleft;
1306 sstrend = mark->stacknxt + mark->stacknleft;
1311 * When the parser reads in a string, it wants to stick the string on the
1312 * stack and only adjust the stack pointer when it knows how big the
1313 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1314 * of space on top of the stack and stackblocklen returns the length of
1315 * this block. Growstackblock will grow this space by at least one byte,
1316 * possibly moving it (like realloc). Grabstackblock actually allocates the
1317 * part of the block that has been used.
1320 growstackblock(void)
1324 newlen = g_stacknleft * 2;
1325 if (newlen < g_stacknleft)
1326 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1330 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1331 struct stack_block *oldstackp;
1332 struct stackmark *xmark;
1333 struct stack_block *sp;
1334 struct stack_block *prevstackp;
1338 oldstackp = g_stackp;
1340 prevstackp = sp->prev;
1341 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1342 sp = ckrealloc(sp, grosslen);
1343 sp->prev = prevstackp;
1345 g_stacknxt = sp->space;
1346 g_stacknleft = newlen;
1347 sstrend = sp->space + newlen;
1350 * Stack marks pointing to the start of the old block
1351 * must be relocated to point to the new block
1354 while (xmark != NULL && xmark->stackp == oldstackp) {
1355 xmark->stackp = g_stackp;
1356 xmark->stacknxt = g_stacknxt;
1357 xmark->stacknleft = g_stacknleft;
1358 xmark = xmark->marknext;
1362 char *oldspace = g_stacknxt;
1363 size_t oldlen = g_stacknleft;
1364 char *p = stalloc(newlen);
1366 /* free the space we just allocated */
1367 g_stacknxt = memcpy(p, oldspace, oldlen);
1368 g_stacknleft += newlen;
1373 grabstackblock(size_t len)
1375 len = SHELL_ALIGN(len);
1377 g_stacknleft -= len;
1381 * The following routines are somewhat easier to use than the above.
1382 * The user declares a variable of type STACKSTR, which may be declared
1383 * to be a register. The macro STARTSTACKSTR initializes things. Then
1384 * the user uses the macro STPUTC to add characters to the string. In
1385 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1386 * grown as necessary. When the user is done, she can just leave the
1387 * string there and refer to it using stackblock(). Or she can allocate
1388 * the space for it using grabstackstr(). If it is necessary to allow
1389 * someone else to use the stack temporarily and then continue to grow
1390 * the string, the user should use grabstack to allocate the space, and
1391 * then call ungrabstr(p) to return to the previous mode of operation.
1393 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1394 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1395 * is space for at least one character.
1400 size_t len = stackblocksize();
1401 if (herefd >= 0 && len >= 1024) {
1402 full_write(herefd, stackblock(), len);
1403 return stackblock();
1406 return (char *)stackblock() + len;
1410 * Called from CHECKSTRSPACE.
1413 makestrspace(size_t newlen, char *p)
1415 size_t len = p - g_stacknxt;
1416 size_t size = stackblocksize();
1421 size = stackblocksize();
1423 if (nleft >= newlen)
1427 return (char *)stackblock() + len;
1431 stack_nputstr(const char *s, size_t n, char *p)
1433 p = makestrspace(n, p);
1434 p = (char *)memcpy(p, s, n) + n;
1439 stack_putstr(const char *s, char *p)
1441 return stack_nputstr(s, strlen(s), p);
1445 _STPUTC(int c, char *p)
1453 #define STARTSTACKSTR(p) ((p) = stackblock())
1454 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1455 #define CHECKSTRSPACE(n, p) \
1459 size_t m = sstrend - q; \
1461 (p) = makestrspace(l, q); \
1463 #define USTPUTC(c, p) (*(p)++ = (c))
1464 #define STACKSTRNUL(p) \
1466 if ((p) == sstrend) \
1467 (p) = growstackstr(); \
1470 #define STUNPUTC(p) (--(p))
1471 #define STTOPC(p) ((p)[-1])
1472 #define STADJUST(amount, p) ((p) += (amount))
1474 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1475 #define ungrabstackstr(s, p) stunalloc(s)
1476 #define stackstrend() ((void *)sstrend)
1479 /* ============ String helpers */
1482 * prefix -- see if pfx is a prefix of string.
1485 prefix(const char *string, const char *pfx)
1488 if (*pfx++ != *string++)
1491 return (char *) string;
1495 * Check for a valid number. This should be elsewhere.
1498 is_number(const char *p)
1503 } while (*++p != '\0');
1508 * Convert a string of digits to an integer, printing an error message on
1512 number(const char *s)
1515 ash_msg_and_raise_error(illnum, s);
1520 * Produce a possibly single quoted string suitable as input to the shell.
1521 * The return string is allocated on the stack.
1524 single_quote(const char *s)
1534 len = strchrnul(s, '\'') - s;
1536 q = p = makestrspace(len + 3, p);
1539 q = (char *)memcpy(q, s, len) + len;
1545 len = strspn(s, "'");
1549 q = p = makestrspace(len + 3, p);
1552 q = (char *)memcpy(q, s, len) + len;
1561 return stackblock();
1565 /* ============ nextopt */
1567 static char **argptr; /* argument list for builtin commands */
1568 static char *optionarg; /* set by nextopt (like getopt) */
1569 static char *optptr; /* used by nextopt */
1572 * XXX - should get rid of. have all builtins use getopt(3). the
1573 * library getopt must have the BSD extension static variable "optreset"
1574 * otherwise it can't be used within the shell safely.
1576 * Standard option processing (a la getopt) for builtin routines. The
1577 * only argument that is passed to nextopt is the option string; the
1578 * other arguments are unnecessary. It return the character, or '\0' on
1582 nextopt(const char *optstring)
1589 if (p == NULL || *p == '\0') {
1591 if (p == NULL || *p != '-' || *++p == '\0')
1594 if (LONE_DASH(p)) /* check for "--" */
1598 for (q = optstring; *q != c; ) {
1600 ash_msg_and_raise_error("illegal option -%c", c);
1605 if (*p == '\0' && (p = *argptr++) == NULL)
1606 ash_msg_and_raise_error("no arg for -%c option", c);
1615 /* ============ Math support definitions */
1617 #if ENABLE_ASH_MATH_SUPPORT_64
1618 typedef int64_t arith_t;
1619 #define arith_t_type long long
1621 typedef long arith_t;
1622 #define arith_t_type long
1625 #if ENABLE_ASH_MATH_SUPPORT
1626 static arith_t dash_arith(const char *);
1627 static arith_t arith(const char *expr, int *perrcode);
1630 #if ENABLE_ASH_RANDOM_SUPPORT
1631 static unsigned long rseed;
1638 /* ============ Shell variables */
1641 * The parsefile structure pointed to by the global variable parsefile
1642 * contains information about the current file being read.
1645 struct redirtab *next;
1651 int nparam; /* # of positional parameters (without $0) */
1652 #if ENABLE_ASH_GETOPTS
1653 int optind; /* next parameter to be processed by getopts */
1654 int optoff; /* used by getopts */
1656 unsigned char malloced; /* if parameter list dynamically allocated */
1657 char **p; /* parameter list */
1661 * Free the list of positional parameters.
1664 freeparam(volatile struct shparam *param)
1668 if (param->malloced) {
1669 for (ap = param->p; *ap; ap++)
1675 #if ENABLE_ASH_GETOPTS
1676 static void getoptsreset(const char *value);
1680 struct var *next; /* next entry in hash list */
1681 int flags; /* flags are defined above */
1682 const char *text; /* name=value */
1683 void (*func)(const char *); /* function to be called when */
1684 /* the variable gets set/unset */
1688 struct localvar *next; /* next local variable in list */
1689 struct var *vp; /* the variable that was made local */
1690 int flags; /* saved flags */
1691 const char *text; /* saved text */
1695 #define VEXPORT 0x01 /* variable is exported */
1696 #define VREADONLY 0x02 /* variable cannot be modified */
1697 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1698 #define VTEXTFIXED 0x08 /* text is statically allocated */
1699 #define VSTACK 0x10 /* text is allocated on the stack */
1700 #define VUNSET 0x20 /* the variable is not set */
1701 #define VNOFUNC 0x40 /* don't call the callback function */
1702 #define VNOSET 0x80 /* do not set variable - just readonly test */
1703 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1705 # define VDYNAMIC 0x200 /* dynamic variable */
1711 static const char defifsvar[] ALIGN1 = "IFS= \t\n";
1712 #define defifs (defifsvar + 4)
1714 static const char defifs[] ALIGN1 = " \t\n";
1718 /* Need to be before varinit_data[] */
1719 #if ENABLE_LOCALE_SUPPORT
1721 change_lc_all(const char *value)
1723 if (value && *value != '\0')
1724 setlocale(LC_ALL, value);
1727 change_lc_ctype(const char *value)
1729 if (value && *value != '\0')
1730 setlocale(LC_CTYPE, value);
1734 static void chkmail(void);
1735 static void changemail(const char *);
1737 static void changepath(const char *);
1738 #if ENABLE_ASH_RANDOM_SUPPORT
1739 static void change_random(const char *);
1742 static const struct {
1745 void (*func)(const char *);
1746 } varinit_data[] = {
1748 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1750 { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL },
1753 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0" , changemail },
1754 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1756 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1757 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1758 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1759 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1760 #if ENABLE_ASH_GETOPTS
1761 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
1763 #if ENABLE_ASH_RANDOM_SUPPORT
1764 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1766 #if ENABLE_LOCALE_SUPPORT
1767 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL\0" , change_lc_all },
1768 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE\0", change_lc_ctype },
1770 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1771 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE\0", NULL },
1776 struct globals_var {
1777 struct shparam shellparam; /* $@ current positional parameters */
1778 struct redirtab *redirlist;
1780 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1781 struct var *vartab[VTABSIZE];
1782 struct var varinit[ARRAY_SIZE(varinit_data)];
1784 extern struct globals_var *const ash_ptr_to_globals_var;
1785 #define G_var (*ash_ptr_to_globals_var)
1786 #define shellparam (G_var.shellparam )
1787 #define redirlist (G_var.redirlist )
1788 #define g_nullredirs (G_var.g_nullredirs )
1789 #define preverrout_fd (G_var.preverrout_fd)
1790 #define vartab (G_var.vartab )
1791 #define varinit (G_var.varinit )
1792 #define INIT_G_var() do { \
1794 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1796 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1797 varinit[i].flags = varinit_data[i].flags; \
1798 varinit[i].text = varinit_data[i].text; \
1799 varinit[i].func = varinit_data[i].func; \
1803 #define vifs varinit[0]
1805 # define vmail (&vifs)[1]
1806 # define vmpath (&vmail)[1]
1807 # define vpath (&vmpath)[1]
1809 # define vpath (&vifs)[1]
1811 #define vps1 (&vpath)[1]
1812 #define vps2 (&vps1)[1]
1813 #define vps4 (&vps2)[1]
1814 #if ENABLE_ASH_GETOPTS
1815 # define voptind (&vps4)[1]
1816 # if ENABLE_ASH_RANDOM_SUPPORT
1817 # define vrandom (&voptind)[1]
1820 # if ENABLE_ASH_RANDOM_SUPPORT
1821 # define vrandom (&vps4)[1]
1826 * The following macros access the values of the above variables.
1827 * They have to skip over the name. They return the null string
1828 * for unset variables.
1830 #define ifsval() (vifs.text + 4)
1831 #define ifsset() ((vifs.flags & VUNSET) == 0)
1833 # define mailval() (vmail.text + 5)
1834 # define mpathval() (vmpath.text + 9)
1835 # define mpathset() ((vmpath.flags & VUNSET) == 0)
1837 #define pathval() (vpath.text + 5)
1838 #define ps1val() (vps1.text + 4)
1839 #define ps2val() (vps2.text + 4)
1840 #define ps4val() (vps4.text + 4)
1841 #if ENABLE_ASH_GETOPTS
1842 # define optindval() (voptind.text + 7)
1846 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1847 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1849 #if ENABLE_ASH_GETOPTS
1851 getoptsreset(const char *value)
1853 shellparam.optind = number(value);
1854 shellparam.optoff = -1;
1859 * Return of a legal variable name (a letter or underscore followed by zero or
1860 * more letters, underscores, and digits).
1863 endofname(const char *name)
1871 if (!is_in_name(*p))
1878 * Compares two strings up to the first = or '\0'. The first
1879 * string must be terminated by '='; the second may be terminated by
1880 * either '=' or '\0'.
1883 varcmp(const char *p, const char *q)
1887 while ((c = *p) == (d = *q)) {
1902 varequal(const char *a, const char *b)
1904 return !varcmp(a, b);
1908 * Find the appropriate entry in the hash table from the name.
1910 static struct var **
1911 hashvar(const char *p)
1915 hashval = ((unsigned char) *p) << 4;
1916 while (*p && *p != '=')
1917 hashval += (unsigned char) *p++;
1918 return &vartab[hashval % VTABSIZE];
1922 vpcmp(const void *a, const void *b)
1924 return varcmp(*(const char **)a, *(const char **)b);
1928 * This routine initializes the builtin variables.
1938 * PS1 depends on uid
1940 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1941 vps1.text = "PS1=\\w \\$ ";
1944 vps1.text = "PS1=# ";
1947 end = vp + ARRAY_SIZE(varinit);
1949 vpp = hashvar(vp->text);
1952 } while (++vp < end);
1955 static struct var **
1956 findvar(struct var **vpp, const char *name)
1958 for (; *vpp; vpp = &(*vpp)->next) {
1959 if (varequal((*vpp)->text, name)) {
1967 * Find the value of a variable. Returns NULL if not set.
1970 lookupvar(const char *name)
1974 v = *findvar(hashvar(name), name);
1978 * Dynamic variables are implemented roughly the same way they are
1979 * in bash. Namely, they're "special" so long as they aren't unset.
1980 * As soon as they're unset, they're no longer dynamic, and dynamic
1981 * lookup will no longer happen at that point. -- PFM.
1983 if ((v->flags & VDYNAMIC))
1986 if (!(v->flags & VUNSET))
1987 return strchrnul(v->text, '=') + 1;
1993 * Search the environment of a builtin command.
1996 bltinlookup(const char *name)
2000 for (sp = cmdenviron; sp; sp = sp->next) {
2001 if (varequal(sp->text, name))
2002 return strchrnul(sp->text, '=') + 1;
2004 return lookupvar(name);
2008 * Same as setvar except that the variable and value are passed in
2009 * the first argument as name=value. Since the first argument will
2010 * be actually stored in the table, it should not be a string that
2012 * Called with interrupts off.
2015 setvareq(char *s, int flags)
2017 struct var *vp, **vpp;
2020 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2021 vp = *findvar(vpp, s);
2023 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2026 if (flags & VNOSAVE)
2029 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2035 if (vp->func && (flags & VNOFUNC) == 0)
2036 (*vp->func)(strchrnul(s, '=') + 1);
2038 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
2039 free((char*)vp->text);
2041 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2046 vp = ckzalloc(sizeof(*vp));
2048 /*vp->func = NULL; - ckzalloc did it */
2051 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2058 * Set the value of a variable. The flags argument is ored with the
2059 * flags of the variable. If val is NULL, the variable is unset.
2062 setvar(const char *name, const char *val, int flags)
2069 q = endofname(name);
2070 p = strchrnul(q, '=');
2072 if (!namelen || p != q)
2073 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2078 vallen = strlen(val);
2081 nameeq = ckmalloc(namelen + vallen + 2);
2082 p = (char *)memcpy(nameeq, name, namelen) + namelen;
2085 p = (char *)memcpy(p, val, vallen) + vallen;
2088 setvareq(nameeq, flags | VNOSAVE);
2092 #if ENABLE_ASH_GETOPTS
2094 * Safe version of setvar, returns 1 on success 0 on failure.
2097 setvarsafe(const char *name, const char *val, int flags)
2100 volatile int saveint;
2101 struct jmploc *volatile savehandler = exception_handler;
2102 struct jmploc jmploc;
2105 if (setjmp(jmploc.loc))
2108 exception_handler = &jmploc;
2109 setvar(name, val, flags);
2112 exception_handler = savehandler;
2113 RESTORE_INT(saveint);
2119 * Unset the specified variable.
2122 unsetvar(const char *s)
2128 vpp = findvar(hashvar(s), s);
2132 int flags = vp->flags;
2135 if (flags & VREADONLY)
2138 vp->flags &= ~VDYNAMIC;
2142 if ((flags & VSTRFIXED) == 0) {
2144 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2145 free((char*)vp->text);
2151 vp->flags &= ~VEXPORT;
2161 * Process a linked list of variable assignments.
2164 listsetvar(struct strlist *list_set_var, int flags)
2166 struct strlist *lp = list_set_var;
2172 setvareq(lp->text, flags);
2179 * Generate a list of variables satisfying the given conditions.
2182 listvars(int on, int off, char ***end)
2193 for (vp = *vpp; vp; vp = vp->next) {
2194 if ((vp->flags & mask) == on) {
2195 if (ep == stackstrend())
2196 ep = growstackstr();
2197 *ep++ = (char *) vp->text;
2200 } while (++vpp < vartab + VTABSIZE);
2201 if (ep == stackstrend())
2202 ep = growstackstr();
2206 return grabstackstr(ep);
2210 /* ============ Path search helper
2212 * The variable path (passed by reference) should be set to the start
2213 * of the path before the first call; padvance will update
2214 * this value as it proceeds. Successive calls to padvance will return
2215 * the possible path expansions in sequence. If an option (indicated by
2216 * a percent sign) appears in the path entry then the global variable
2217 * pathopt will be set to point to it; otherwise pathopt will be set to
2220 static const char *pathopt; /* set by padvance */
2223 padvance(const char **path, const char *name)
2233 for (p = start; *p && *p != ':' && *p != '%'; p++)
2235 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2236 while (stackblocksize() < len)
2240 memcpy(q, start, p - start);
2248 while (*p && *p != ':')
2255 return stalloc(len);
2259 /* ============ Prompt */
2261 static smallint doprompt; /* if set, prompt the user */
2262 static smallint needprompt; /* true if interactive and at start of line */
2264 #if ENABLE_FEATURE_EDITING
2265 static line_input_t *line_input_state;
2266 static const char *cmdedit_prompt;
2268 putprompt(const char *s)
2270 if (ENABLE_ASH_EXPAND_PRMT) {
2271 free((char*)cmdedit_prompt);
2272 cmdedit_prompt = ckstrdup(s);
2279 putprompt(const char *s)
2285 #if ENABLE_ASH_EXPAND_PRMT
2286 /* expandstr() needs parsing machinery, so it is far away ahead... */
2287 static const char *expandstr(const char *ps);
2289 #define expandstr(s) s
2293 setprompt(int whichprompt)
2296 #if ENABLE_ASH_EXPAND_PRMT
2297 struct stackmark smark;
2302 switch (whichprompt) {
2312 #if ENABLE_ASH_EXPAND_PRMT
2313 setstackmark(&smark);
2314 stalloc(stackblocksize());
2316 putprompt(expandstr(prompt));
2317 #if ENABLE_ASH_EXPAND_PRMT
2318 popstackmark(&smark);
2323 /* ============ The cd and pwd commands */
2325 #define CD_PHYSICAL 1
2328 static int docd(const char *, int);
2337 while ((i = nextopt("LP"))) {
2339 flags ^= CD_PHYSICAL;
2348 * Update curdir (the name of the current directory) in response to a
2352 updatepwd(const char *dir)
2359 cdcomppath = ststrdup(dir);
2362 if (curdir == nullstr)
2364 new = stack_putstr(curdir, new);
2366 new = makestrspace(strlen(dir) + 2, new);
2367 lim = (char *)stackblock() + 1;
2371 if (new > lim && *lim == '/')
2376 if (dir[1] == '/' && dir[2] != '/') {
2382 p = strtok(cdcomppath, "/");
2386 if (p[1] == '.' && p[2] == '\0') {
2398 new = stack_putstr(p, new);
2406 return stackblock();
2410 * Find out what the current directory is. If we already know the current
2411 * directory, this routine returns immediately.
2416 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2417 return dir ? dir : nullstr;
2421 setpwd(const char *val, int setold)
2425 oldcur = dir = curdir;
2428 setvar("OLDPWD", oldcur, VEXPORT);
2431 if (physdir != nullstr) {
2432 if (physdir != oldcur)
2436 if (oldcur == val || !val) {
2442 dir = ckstrdup(val);
2443 if (oldcur != dir && oldcur != nullstr) {
2448 setvar("PWD", dir, VEXPORT);
2451 static void hashcd(void);
2454 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2455 * know that the current directory has changed.
2458 docd(const char *dest, int flags)
2460 const char *dir = 0;
2463 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2466 if (!(flags & CD_PHYSICAL)) {
2467 dir = updatepwd(dest);
2482 cdcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
2494 dest = bltinlookup(homestr);
2495 else if (LONE_DASH(dest)) {
2496 dest = bltinlookup("OLDPWD");
2518 path = bltinlookup("CDPATH");
2527 p = padvance(&path, dest);
2528 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2532 if (!docd(p, flags))
2537 ash_msg_and_raise_error("can't cd to %s", dest);
2540 if (flags & CD_PRINT)
2541 out1fmt(snlfmt, curdir);
2546 pwdcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
2549 const char *dir = curdir;
2553 if (physdir == nullstr)
2557 out1fmt(snlfmt, dir);
2562 /* ============ ... */
2564 #define IBUFSIZ COMMON_BUFSIZE
2565 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */
2567 /* Syntax classes */
2568 #define CWORD 0 /* character is nothing special */
2569 #define CNL 1 /* newline character */
2570 #define CBACK 2 /* a backslash character */
2571 #define CSQUOTE 3 /* single quote */
2572 #define CDQUOTE 4 /* double quote */
2573 #define CENDQUOTE 5 /* a terminating quote */
2574 #define CBQUOTE 6 /* backwards single quote */
2575 #define CVAR 7 /* a dollar sign */
2576 #define CENDVAR 8 /* a '}' character */
2577 #define CLP 9 /* a left paren in arithmetic */
2578 #define CRP 10 /* a right paren in arithmetic */
2579 #define CENDFILE 11 /* end of file */
2580 #define CCTL 12 /* like CWORD, except it must be escaped */
2581 #define CSPCL 13 /* these terminate a word */
2582 #define CIGN 14 /* character should be ignored */
2584 #if ENABLE_ASH_ALIAS
2588 #define PEOA_OR_PEOF PEOA
2592 #define PEOA_OR_PEOF PEOF
2595 /* number syntax index */
2596 #define BASESYNTAX 0 /* not in quotes */
2597 #define DQSYNTAX 1 /* in double quotes */
2598 #define SQSYNTAX 2 /* in single quotes */
2599 #define ARISYNTAX 3 /* in arithmetic */
2600 #define PSSYNTAX 4 /* prompt */
2602 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
2603 #define USE_SIT_FUNCTION
2606 #if ENABLE_ASH_MATH_SUPPORT
2607 static const char S_I_T[][4] = {
2608 #if ENABLE_ASH_ALIAS
2609 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */
2611 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */
2612 { CNL, CNL, CNL, CNL }, /* 2, \n */
2613 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */
2614 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */
2615 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */
2616 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */
2617 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */
2618 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */
2619 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */
2620 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */
2621 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */
2622 #ifndef USE_SIT_FUNCTION
2623 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2624 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2625 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2629 static const char S_I_T[][3] = {
2630 #if ENABLE_ASH_ALIAS
2631 { CSPCL, CIGN, CIGN }, /* 0, PEOA */
2633 { CSPCL, CWORD, CWORD }, /* 1, ' ' */
2634 { CNL, CNL, CNL }, /* 2, \n */
2635 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */
2636 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */
2637 { CVAR, CVAR, CWORD }, /* 5, $ */
2638 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */
2639 { CSPCL, CWORD, CWORD }, /* 7, ( */
2640 { CSPCL, CWORD, CWORD }, /* 8, ) */
2641 { CBACK, CBACK, CCTL }, /* 9, \ */
2642 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */
2643 { CENDVAR, CENDVAR, CWORD }, /* 11, } */
2644 #ifndef USE_SIT_FUNCTION
2645 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2646 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2647 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2650 #endif /* ASH_MATH_SUPPORT */
2652 #ifdef USE_SIT_FUNCTION
2655 SIT(int c, int syntax)
2657 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2658 #if ENABLE_ASH_ALIAS
2659 static const char syntax_index_table[] ALIGN1 = {
2660 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2661 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2662 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2666 static const char syntax_index_table[] ALIGN1 = {
2667 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2668 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2669 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2676 if (c == PEOF) /* 2^8+2 */
2678 #if ENABLE_ASH_ALIAS
2679 if (c == PEOA) /* 2^8+1 */
2683 #define U_C(c) ((unsigned char)(c))
2685 if ((unsigned char)c >= (unsigned char)(CTLESC)
2686 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
2690 s = strchrnul(spec_symbls, c);
2693 indx = syntax_index_table[s - spec_symbls];
2695 return S_I_T[indx][syntax];
2698 #else /* !USE_SIT_FUNCTION */
2700 #if ENABLE_ASH_ALIAS
2701 #define CSPCL_CIGN_CIGN_CIGN 0
2702 #define CSPCL_CWORD_CWORD_CWORD 1
2703 #define CNL_CNL_CNL_CNL 2
2704 #define CWORD_CCTL_CCTL_CWORD 3
2705 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
2706 #define CVAR_CVAR_CWORD_CVAR 5
2707 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
2708 #define CSPCL_CWORD_CWORD_CLP 7
2709 #define CSPCL_CWORD_CWORD_CRP 8
2710 #define CBACK_CBACK_CCTL_CBACK 9
2711 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
2712 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
2713 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
2714 #define CWORD_CWORD_CWORD_CWORD 13
2715 #define CCTL_CCTL_CCTL_CCTL 14
2717 #define CSPCL_CWORD_CWORD_CWORD 0
2718 #define CNL_CNL_CNL_CNL 1
2719 #define CWORD_CCTL_CCTL_CWORD 2
2720 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
2721 #define CVAR_CVAR_CWORD_CVAR 4
2722 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
2723 #define CSPCL_CWORD_CWORD_CLP 6
2724 #define CSPCL_CWORD_CWORD_CRP 7
2725 #define CBACK_CBACK_CCTL_CBACK 8
2726 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
2727 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
2728 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
2729 #define CWORD_CWORD_CWORD_CWORD 12
2730 #define CCTL_CCTL_CCTL_CCTL 13
2733 static const char syntax_index_table[258] = {
2734 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2735 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2736 #if ENABLE_ASH_ALIAS
2737 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
2739 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2740 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2741 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2742 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2743 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2744 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2745 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2746 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2747 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2748 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
2749 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
2750 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
2751 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
2752 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
2753 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
2754 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
2755 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
2756 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
2757 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
2758 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
2759 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
2760 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
2761 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
2762 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
2763 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
2764 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
2765 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
2766 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
2767 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
2768 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
2769 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
2770 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
2771 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
2772 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
2773 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
2774 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
2775 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
2776 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
2777 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
2778 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
2779 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
2780 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
2781 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
2782 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
2783 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
2784 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
2785 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
2786 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
2787 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
2788 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
2789 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
2790 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
2791 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
2792 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
2793 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
2794 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
2795 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
2796 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
2797 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
2798 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
2799 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
2800 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
2801 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
2802 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
2803 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
2804 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
2805 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
2806 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
2807 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
2808 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
2809 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
2810 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
2811 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
2812 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
2813 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
2814 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
2815 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
2816 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
2817 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
2818 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
2819 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
2820 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
2821 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
2822 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
2823 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
2824 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
2825 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
2826 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
2827 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
2828 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
2829 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
2830 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
2831 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
2832 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
2833 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
2834 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
2835 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
2836 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
2837 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
2838 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
2839 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
2840 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
2841 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
2842 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
2843 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
2844 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
2845 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
2846 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
2847 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
2848 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
2853 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
2854 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2877 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
2878 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
2898 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
2899 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2900 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2901 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2902 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2903 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2904 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2905 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2906 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2907 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2908 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2909 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2910 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
2912 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2913 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
2914 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2915 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2926 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2927 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2928 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2929 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2930 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2931 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2959 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2960 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2961 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2964 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2992 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2993 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2994 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
2997 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])
2999 #endif /* USE_SIT_FUNCTION */
3002 /* ============ Alias handling */
3004 #if ENABLE_ASH_ALIAS
3006 #define ALIASINUSE 1
3017 static struct alias **atab; // [ATABSIZE];
3018 #define INIT_G_alias() do { \
3019 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3023 static struct alias **
3024 __lookupalias(const char *name) {
3025 unsigned int hashval;
3032 ch = (unsigned char)*p;
3036 ch = (unsigned char)*++p;
3038 app = &atab[hashval % ATABSIZE];
3040 for (; *app; app = &(*app)->next) {
3041 if (strcmp(name, (*app)->name) == 0) {
3049 static struct alias *
3050 lookupalias(const char *name, int check)
3052 struct alias *ap = *__lookupalias(name);
3054 if (check && ap && (ap->flag & ALIASINUSE))
3059 static struct alias *
3060 freealias(struct alias *ap)
3064 if (ap->flag & ALIASINUSE) {
3065 ap->flag |= ALIASDEAD;
3077 setalias(const char *name, const char *val)
3079 struct alias *ap, **app;
3081 app = __lookupalias(name);
3085 if (!(ap->flag & ALIASINUSE)) {
3088 ap->val = ckstrdup(val);
3089 ap->flag &= ~ALIASDEAD;
3092 ap = ckzalloc(sizeof(struct alias));
3093 ap->name = ckstrdup(name);
3094 ap->val = ckstrdup(val);
3095 /*ap->flag = 0; - ckzalloc did it */
3096 /*ap->next = NULL;*/
3103 unalias(const char *name)
3107 app = __lookupalias(name);
3111 *app = freealias(*app);
3122 struct alias *ap, **app;
3126 for (i = 0; i < ATABSIZE; i++) {
3128 for (ap = *app; ap; ap = *app) {
3129 *app = freealias(*app);
3139 printalias(const struct alias *ap)
3141 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3145 * TODO - sort output
3148 aliascmd(int argc ATTRIBUTE_UNUSED, char **argv)
3157 for (i = 0; i < ATABSIZE; i++) {
3158 for (ap = atab[i]; ap; ap = ap->next) {
3164 while ((n = *++argv) != NULL) {
3165 v = strchr(n+1, '=');
3166 if (v == NULL) { /* n+1: funny ksh stuff */
3167 ap = *__lookupalias(n);
3169 fprintf(stderr, "%s: %s not found\n", "alias", n);
3183 unaliascmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
3187 while ((i = nextopt("a")) != '\0') {
3193 for (i = 0; *argptr; argptr++) {
3194 if (unalias(*argptr)) {
3195 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3203 #endif /* ASH_ALIAS */
3206 /* ============ jobs.c */
3208 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3211 #define FORK_NOJOB 2
3213 /* mode flags for showjob(s) */
3214 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
3215 #define SHOW_PID 0x04 /* include process pid */
3216 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
3219 * A job structure contains information about a job. A job is either a
3220 * single process or a set of processes contained in a pipeline. In the
3221 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3226 pid_t pid; /* process id */
3227 int status; /* last process status from wait() */
3228 char *cmd; /* text of command being run */
3232 struct procstat ps0; /* status of process */
3233 struct procstat *ps; /* status or processes when more than one */
3235 int stopstatus; /* status of a stopped job */
3238 nprocs: 16, /* number of processes */
3240 #define JOBRUNNING 0 /* at least one proc running */
3241 #define JOBSTOPPED 1 /* all procs are stopped */
3242 #define JOBDONE 2 /* all procs are completed */
3244 sigint: 1, /* job was killed by SIGINT */
3245 jobctl: 1, /* job running under job control */
3247 waited: 1, /* true if this entry has been waited for */
3248 used: 1, /* true if this entry is in used */
3249 changed: 1; /* true if status has changed */
3250 struct job *prev_job; /* previous job */
3253 static pid_t backgndpid; /* pid of last background process */
3254 static smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
3256 static struct job *makejob(/*union node *,*/ int);
3258 #define forkshell(job, node, mode) forkshell(job, mode)
3260 static int forkshell(struct job *, union node *, int);
3261 static int waitforjob(struct job *);
3264 enum { doing_jobctl = 0 };
3265 #define setjobctl(on) do {} while (0)
3267 static smallint doing_jobctl;
3268 static void setjobctl(int);
3272 * Set the signal handler for the specified signal. The routine figures
3273 * out what it should be set to.
3276 setsignal(int signo)
3280 struct sigaction act;
3286 else if (*t != '\0')
3288 if (rootshell && action == S_DFL) {
3291 if (iflag || minusc || sflag == 0)
3314 t = &sigmode[signo - 1];
3318 * current setting unknown
3320 if (sigaction(signo, NULL, &act) == -1) {
3322 * Pretend it worked; maybe we should give a warning
3323 * here, but other shells don't. We don't alter
3324 * sigmode, so that we retry every time.
3328 tsig = S_RESET; /* force to be set */
3329 if (act.sa_handler == SIG_IGN) {
3332 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3334 tsig = S_IGN; /* don't hard ignore these */
3338 if (tsig == S_HARD_IGN || tsig == action)
3340 act.sa_handler = SIG_DFL;
3343 act.sa_handler = onsig;
3346 act.sa_handler = SIG_IGN;
3351 sigfillset(&act.sa_mask);
3352 sigaction_set(signo, &act);
3355 /* mode flags for set_curjob */
3356 #define CUR_DELETE 2
3357 #define CUR_RUNNING 1
3358 #define CUR_STOPPED 0
3360 /* mode flags for dowait */
3361 #define DOWAIT_NONBLOCK WNOHANG
3362 #define DOWAIT_BLOCK 0
3365 /* pgrp of shell on invocation */
3366 static int initialpgrp;
3367 static int ttyfd = -1;
3370 static struct job *jobtab;
3372 static unsigned njobs;
3374 static struct job *curjob;
3375 /* number of presumed living untracked jobs */
3379 set_curjob(struct job *jp, unsigned mode)
3382 struct job **jpp, **curp;
3384 /* first remove from list */
3385 jpp = curp = &curjob;
3390 jpp = &jp1->prev_job;
3392 *jpp = jp1->prev_job;
3394 /* Then re-insert in correct position */
3402 /* job being deleted */
3405 /* newly created job or backgrounded job,
3406 put after all stopped jobs. */
3410 if (!jp1 || jp1->state != JOBSTOPPED)
3413 jpp = &jp1->prev_job;
3419 /* newly stopped job - becomes curjob */
3420 jp->prev_job = *jpp;
3428 jobno(const struct job *jp)
3430 return jp - jobtab + 1;
3435 * Convert a job name to a job structure.
3438 #define getjob(name, getctl) getjob(name)
3441 getjob(const char *name, int getctl)
3445 const char *err_msg = "No such job: %s";
3449 char *(*match)(const char *, const char *);
3464 if (c == '+' || c == '%') {
3466 err_msg = "No current job";
3472 err_msg = "No previous job";
3481 // TODO: number() instead? It does error checking...
3484 jp = jobtab + num - 1;
3501 if (match(jp->ps[0].cmd, p)) {
3505 err_msg = "%s: ambiguous";
3512 err_msg = "job %s not created under job control";
3513 if (getctl && jp->jobctl == 0)
3518 ash_msg_and_raise_error(err_msg, name);
3522 * Mark a job structure as unused.
3525 freejob(struct job *jp)
3527 struct procstat *ps;
3531 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3532 if (ps->cmd != nullstr)
3535 if (jp->ps != &jp->ps0)
3538 set_curjob(jp, CUR_DELETE);
3544 xtcsetpgrp(int fd, pid_t pgrp)
3546 if (tcsetpgrp(fd, pgrp))
3547 ash_msg_and_raise_error("cannot set tty process group (%m)");
3551 * Turn job control on and off.
3553 * Note: This code assumes that the third arg to ioctl is a character
3554 * pointer, which is true on Berkeley systems but not System V. Since
3555 * System V doesn't have job control yet, this isn't a problem now.
3557 * Called with interrupts off.
3565 if (on == doing_jobctl || rootshell == 0)
3569 ofd = fd = open(_PATH_TTY, O_RDWR);
3571 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3572 * That sometimes helps to acquire controlling tty.
3573 * Obviously, a workaround for bugs when someone
3574 * failed to provide a controlling tty to bash! :) */
3580 fd = fcntl(fd, F_DUPFD, 10);
3585 /* fd is a tty at this point */
3586 close_on_exec_on(fd);
3587 do { /* while we are in the background */
3588 pgrp = tcgetpgrp(fd);
3591 ash_msg("can't access tty; job control turned off");
3595 if (pgrp == getpgrp())
3606 xtcsetpgrp(fd, pgrp);
3608 /* turning job control off */
3611 /* was xtcsetpgrp, but this can make exiting ash
3612 * loop forever if pty is already deleted */
3613 tcsetpgrp(fd, pgrp);
3628 killcmd(int argc, char **argv)
3631 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3633 if (argv[i][0] == '%') {
3634 struct job *jp = getjob(argv[i], 0);
3635 unsigned pid = jp->ps[0].pid;
3636 /* Enough space for ' -NNN<nul>' */
3637 argv[i] = alloca(sizeof(int)*3 + 3);
3638 /* kill_main has matching code to expect
3639 * leading space. Needed to not confuse
3640 * negative pids with "kill -SIGNAL_NO" syntax */
3641 sprintf(argv[i], " -%u", pid);
3643 } while (argv[++i]);
3645 return kill_main(argc, argv);
3649 showpipe(struct job *jp, FILE *out)
3651 struct procstat *sp;
3652 struct procstat *spend;
3654 spend = jp->ps + jp->nprocs;
3655 for (sp = jp->ps + 1; sp < spend; sp++)
3656 fprintf(out, " | %s", sp->cmd);
3657 outcslow('\n', out);
3658 flush_stdout_stderr();
3663 restartjob(struct job *jp, int mode)
3665 struct procstat *ps;
3671 if (jp->state == JOBDONE)
3673 jp->state = JOBRUNNING;
3675 if (mode == FORK_FG)
3676 xtcsetpgrp(ttyfd, pgid);
3677 killpg(pgid, SIGCONT);
3681 if (WIFSTOPPED(ps->status)) {
3687 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3693 fg_bgcmd(int argc ATTRIBUTE_UNUSED, char **argv)
3700 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3705 jp = getjob(*argv, 1);
3706 if (mode == FORK_BG) {
3707 set_curjob(jp, CUR_RUNNING);
3708 fprintf(out, "[%d] ", jobno(jp));
3710 outstr(jp->ps->cmd, out);
3712 retval = restartjob(jp, mode);
3713 } while (*argv && *++argv);
3719 sprint_status(char *s, int status, int sigonly)
3725 if (!WIFEXITED(status)) {
3727 if (WIFSTOPPED(status))
3728 st = WSTOPSIG(status);
3731 st = WTERMSIG(status);
3733 if (st == SIGINT || st == SIGPIPE)
3736 if (WIFSTOPPED(status))
3741 col = fmtstr(s, 32, strsignal(st));
3742 if (WCOREDUMP(status)) {
3743 col += fmtstr(s + col, 16, " (core dumped)");
3745 } else if (!sigonly) {
3746 st = WEXITSTATUS(status);
3748 col = fmtstr(s, 16, "Done(%d)", st);
3750 col = fmtstr(s, 16, "Done");
3757 * Do a wait system call. If job control is compiled in, we accept
3758 * stopped processes. If block is zero, we return a value of zero
3759 * rather than blocking.
3761 * System V doesn't have a non-blocking wait system call. It does
3762 * have a SIGCLD signal that is sent to a process when one of it's
3763 * children dies. The obvious way to use SIGCLD would be to install
3764 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
3765 * was received, and have waitproc bump another counter when it got
3766 * the status of a process. Waitproc would then know that a wait
3767 * system call would not block if the two counters were different.
3768 * This approach doesn't work because if a process has children that
3769 * have not been waited for, System V will send it a SIGCLD when it
3770 * installs a signal handler for SIGCLD. What this means is that when
3771 * a child exits, the shell will be sent SIGCLD signals continuously
3772 * until is runs out of stack space, unless it does a wait call before
3773 * restoring the signal handler. The code below takes advantage of
3774 * this (mis)feature by installing a signal handler for SIGCLD and
3775 * then checking to see whether it was called. If there are any
3776 * children to be waited for, it will be.
3778 * If neither SYSV nor BSD is defined, we don't implement nonblocking
3779 * waits at all. In this case, the user will not be informed when
3780 * a background process until the next time she runs a real program
3781 * (as opposed to running a builtin command or just typing return),
3782 * and the jobs command may give out of date information.
3785 waitproc(int wait_flags, int *status)
3789 wait_flags |= WUNTRACED;
3791 /* NB: _not_ safe_waitpid, we need to detect EINTR */
3792 return waitpid(-1, status, wait_flags);
3796 * Wait for a process to terminate.
3799 dowait(int wait_flags, struct job *job)
3804 struct job *thisjob;
3807 TRACE(("dowait(%d) called\n", wait_flags));
3808 pid = waitproc(wait_flags, &status);
3809 TRACE(("wait returns pid=%d, status=%d\n", pid, status));
3811 /* If we were doing blocking wait and (probably) got EINTR,
3812 * check for pending sigs received while waiting.
3813 * (NB: can be moved into callers if needed) */
3814 if (wait_flags == DOWAIT_BLOCK && pendingsig)
3815 raise_exception(EXSIG);
3820 for (jp = curjob; jp; jp = jp->prev_job) {
3821 struct procstat *sp;
3822 struct procstat *spend;
3823 if (jp->state == JOBDONE)
3826 spend = jp->ps + jp->nprocs;
3829 if (sp->pid == pid) {
3830 TRACE(("Job %d: changing status of proc %d "
3831 "from 0x%x to 0x%x\n",
3832 jobno(jp), pid, sp->status, status));
3833 sp->status = status;
3836 if (sp->status == -1)
3839 if (state == JOBRUNNING)
3841 if (WIFSTOPPED(sp->status)) {
3842 jp->stopstatus = sp->status;
3846 } while (++sp < spend);
3851 if (!WIFSTOPPED(status))
3857 if (state != JOBRUNNING) {
3858 thisjob->changed = 1;
3860 if (thisjob->state != state) {
3861 TRACE(("Job %d: changing state from %d to %d\n",
3862 jobno(thisjob), thisjob->state, state));
3863 thisjob->state = state;
3865 if (state == JOBSTOPPED) {
3866 set_curjob(thisjob, CUR_STOPPED);
3875 if (thisjob && thisjob == job) {
3879 len = sprint_status(s, status, 1);
3891 showjob(FILE *out, struct job *jp, int mode)
3893 struct procstat *ps;
3894 struct procstat *psend;
3901 if (mode & SHOW_PGID) {
3902 /* just output process (group) id of pipeline */
3903 fprintf(out, "%d\n", ps->pid);
3907 col = fmtstr(s, 16, "[%d] ", jobno(jp));
3912 else if (curjob && jp == curjob->prev_job)
3915 if (mode & SHOW_PID)
3916 col += fmtstr(s + col, 16, "%d ", ps->pid);
3918 psend = ps + jp->nprocs;
3920 if (jp->state == JOBRUNNING) {
3921 strcpy(s + col, "Running");
3922 col += sizeof("Running") - 1;
3924 int status = psend[-1].status;
3925 if (jp->state == JOBSTOPPED)
3926 status = jp->stopstatus;
3927 col += sprint_status(s + col, status, 0);
3933 /* for each process */
3934 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
3936 fprintf(out, "%s%*c%s",
3937 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
3939 if (!(mode & SHOW_PID)) {
3943 if (++ps == psend) {
3944 outcslow('\n', out);
3951 if (jp->state == JOBDONE) {
3952 TRACE(("showjob: freeing job %d\n", jobno(jp)));
3958 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3959 * statuses have changed since the last call to showjobs.
3962 showjobs(FILE *out, int mode)
3966 TRACE(("showjobs(%x) called\n", mode));
3968 /* If not even one job changed, there is nothing to do */
3969 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3972 for (jp = curjob; jp; jp = jp->prev_job) {
3973 if (!(mode & SHOW_CHANGED) || jp->changed) {
3974 showjob(out, jp, mode);
3980 jobscmd(int argc ATTRIBUTE_UNUSED, char **argv)
3985 while ((m = nextopt("lp"))) {
3995 showjob(stdout, getjob(*argv,0), mode);
3998 showjobs(stdout, mode);
4005 getstatus(struct job *job)
4010 status = job->ps[job->nprocs - 1].status;
4011 retval = WEXITSTATUS(status);
4012 if (!WIFEXITED(status)) {
4014 retval = WSTOPSIG(status);
4015 if (!WIFSTOPPED(status))
4018 /* XXX: limits number of signals */
4019 retval = WTERMSIG(status);
4021 if (retval == SIGINT)
4027 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
4028 jobno(job), job->nprocs, status, retval));
4033 waitcmd(int argc ATTRIBUTE_UNUSED, char **argv)
4042 raise_exception(EXSIG);
4049 /* wait for all jobs */
4053 if (!jp) /* no running procs */
4055 if (jp->state == JOBRUNNING)
4060 dowait(DOWAIT_BLOCK, NULL);
4066 if (**argv != '%') {
4067 pid_t pid = number(*argv);
4072 if (job->ps[job->nprocs - 1].pid == pid)
4074 job = job->prev_job;
4077 job = getjob(*argv, 0);
4078 /* loop until process terminated or stopped */
4079 while (job->state == JOBRUNNING)
4080 dowait(DOWAIT_BLOCK, NULL);
4082 retval = getstatus(job);
4096 struct job *jp, *jq;
4098 len = njobs * sizeof(*jp);
4100 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4102 offset = (char *)jp - (char *)jq;
4104 /* Relocate pointers */
4107 jq = (struct job *)((char *)jq + l);
4111 #define joff(p) ((struct job *)((char *)(p) + l))
4112 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4113 if (joff(jp)->ps == &jq->ps0)
4114 jmove(joff(jp)->ps);
4115 if (joff(jp)->prev_job)
4116 jmove(joff(jp)->prev_job);
4126 jp = (struct job *)((char *)jp + len);
4130 } while (--jq >= jp);
4135 * Return a new job structure.
4136 * Called with interrupts off.
4139 makejob(/*union node *node,*/ int nprocs)
4144 for (i = njobs, jp = jobtab; ; jp++) {
4151 if (jp->state != JOBDONE || !jp->waited)
4160 memset(jp, 0, sizeof(*jp));
4162 /* jp->jobctl is a bitfield.
4163 * "jp->jobctl |= jobctl" likely to give awful code */
4167 jp->prev_job = curjob;
4172 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4174 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4181 * Return a string identifying a command (to be printed by the
4184 static char *cmdnextc;
4187 cmdputs(const char *s)
4189 static const char vstype[VSTYPE + 1][3] = {
4190 "", "}", "-", "+", "?", "=",
4191 "%", "%%", "#", "##"
4192 USE_ASH_BASH_COMPAT(, ":", "/", "//")
4195 const char *p, *str;
4196 char c, cc[2] = " ";
4201 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4203 while ((c = *p++) != 0) {
4211 if ((subtype & VSTYPE) == VSLENGTH)
4215 if (!(subtype & VSQUOTE) == !(quoted & 1))
4221 str = "\"}" + !(quoted & 1);
4228 case CTLBACKQ+CTLQUOTE:
4231 #if ENABLE_ASH_MATH_SUPPORT
4246 if ((subtype & VSTYPE) != VSNORMAL)
4248 str = vstype[subtype & VSTYPE];
4249 if (subtype & VSNUL)
4258 /* These can only happen inside quotes */
4271 while ((c = *str++)) {
4276 USTPUTC('"', nextc);
4282 /* cmdtxt() and cmdlist() call each other */
4283 static void cmdtxt(union node *n);
4286 cmdlist(union node *np, int sep)
4288 for (; np; np = np->narg.next) {
4292 if (sep && np->narg.next)
4298 cmdtxt(union node *n)
4301 struct nodelist *lp;
4313 lp = n->npipe.cmdlist;
4331 cmdtxt(n->nbinary.ch1);
4347 cmdtxt(n->nif.test);
4350 if (n->nif.elsepart) {
4353 n = n->nif.elsepart;
4369 cmdtxt(n->nbinary.ch1);
4379 cmdputs(n->nfor.var);
4381 cmdlist(n->nfor.args, 1);
4386 cmdputs(n->narg.text);
4390 cmdlist(n->ncmd.args, 1);
4391 cmdlist(n->ncmd.redirect, 0);
4404 cmdputs(n->ncase.expr->narg.text);
4406 for (np = n->ncase.cases; np; np = np->nclist.next) {
4407 cmdtxt(np->nclist.pattern);
4409 cmdtxt(np->nclist.body);
4435 s[0] = n->nfile.fd + '0';
4439 if (n->type == NTOFD || n->type == NFROMFD) {
4440 s[0] = n->ndup.dupfd + '0';
4450 commandtext(union node *n)
4454 STARTSTACKSTR(cmdnextc);
4456 name = stackblock();
4457 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4458 name, cmdnextc, cmdnextc));
4459 return ckstrdup(name);
4464 * Fork off a subshell. If we are doing job control, give the subshell its
4465 * own process group. Jp is a job structure that the job is to be added to.
4466 * N is the command that will be evaluated by the child. Both jp and n may
4467 * be NULL. The mode parameter can be one of the following:
4468 * FORK_FG - Fork off a foreground process.
4469 * FORK_BG - Fork off a background process.
4470 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4471 * process group even if job control is on.
4473 * When job control is turned off, background processes have their standard
4474 * input redirected to /dev/null (except for the second and later processes
4477 * Called with interrupts off.
4480 * Clear traps on a fork.
4487 for (tp = trap; tp < &trap[NSIG]; tp++) {
4488 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4493 setsignal(tp - trap);
4499 /* Lives far away from here, needed for forkchild */
4500 static void closescript(void);
4502 /* Called after fork(), in child */
4504 forkchild(struct job *jp, /*union node *n,*/ int mode)
4508 TRACE(("Child shell %d\n", getpid()));
4515 /* do job control only in root shell */
4517 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4520 if (jp->nprocs == 0)
4523 pgrp = jp->ps[0].pid;
4524 /* This can fail because we are doing it in the parent also */
4525 (void)setpgid(0, pgrp);
4526 if (mode == FORK_FG)
4527 xtcsetpgrp(ttyfd, pgrp);
4532 if (mode == FORK_BG) {
4535 if (jp->nprocs == 0) {
4537 if (open(bb_dev_null, O_RDONLY) != 0)
4538 ash_msg_and_raise_error("can't open %s", bb_dev_null);
4541 if (!oldlvl && iflag) {
4546 for (jp = curjob; jp; jp = jp->prev_job)
4551 /* Called after fork(), in parent */
4553 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4556 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4558 TRACE(("In parent shell: child = %d\n", pid));
4560 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4566 if (mode != FORK_NOJOB && jp->jobctl) {
4569 if (jp->nprocs == 0)
4572 pgrp = jp->ps[0].pid;
4573 /* This can fail because we are doing it in the child also */
4577 if (mode == FORK_BG) {
4578 backgndpid = pid; /* set $! */
4579 set_curjob(jp, CUR_RUNNING);
4582 struct procstat *ps = &jp->ps[jp->nprocs++];
4587 if (doing_jobctl && n)
4588 ps->cmd = commandtext(n);
4594 forkshell(struct job *jp, union node *n, int mode)
4598 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4601 TRACE(("Fork failed, errno=%d", errno));
4604 ash_msg_and_raise_error("cannot fork");
4607 forkchild(jp, /*n,*/ mode);
4609 forkparent(jp, n, mode, pid);
4614 * Wait for job to finish.
4616 * Under job control we have the problem that while a child process is
4617 * running interrupts generated by the user are sent to the child but not
4618 * to the shell. This means that an infinite loop started by an inter-
4619 * active user may be hard to kill. With job control turned off, an
4620 * interactive user may place an interactive program inside a loop. If
4621 * the interactive program catches interrupts, the user doesn't want
4622 * these interrupts to also abort the loop. The approach we take here
4623 * is to have the shell ignore interrupt signals while waiting for a
4624 * foreground process to terminate, and then send itself an interrupt
4625 * signal if the child process was terminated by an interrupt signal.
4626 * Unfortunately, some programs want to do a bit of cleanup and then
4627 * exit on interrupt; unless these processes terminate themselves by
4628 * sending a signal to themselves (instead of calling exit) they will
4629 * confuse this approach.
4631 * Called with interrupts off.
4634 waitforjob(struct job *jp)
4638 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4639 while (jp->state == JOBRUNNING) {
4640 dowait(DOWAIT_BLOCK, jp);
4645 xtcsetpgrp(ttyfd, rootpid);
4647 * This is truly gross.
4648 * If we're doing job control, then we did a TIOCSPGRP which
4649 * caused us (the shell) to no longer be in the controlling
4650 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4651 * intuit from the subprocess exit status whether a SIGINT
4652 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4654 if (jp->sigint) /* TODO: do the same with all signals */
4655 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4657 if (jp->state == JOBDONE)
4664 * return 1 if there are stopped jobs, otherwise 0
4676 if (jp && jp->state == JOBSTOPPED) {
4677 out2str("You have stopped jobs.\n");
4686 /* ============ redir.c
4688 * Code for dealing with input/output redirection.
4691 #define EMPTY -2 /* marks an unused slot in redirtab */
4692 #define CLOSED -3 /* marks a slot of previously-closed fd */
4694 # define PIPESIZE 4096 /* amount of buffering in a pipe */
4696 # define PIPESIZE PIPE_BUF
4700 * Open a file in noclobber mode.
4701 * The code was copied from bash.
4704 noclobberopen(const char *fname)
4707 struct stat finfo, finfo2;
4710 * If the file exists and is a regular file, return an error
4713 r = stat(fname, &finfo);
4714 if (r == 0 && S_ISREG(finfo.st_mode)) {
4720 * If the file was not present (r != 0), make sure we open it
4721 * exclusively so that if it is created before we open it, our open
4722 * will fail. Make sure that we do not truncate an existing file.
4723 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4724 * file was not a regular file, we leave O_EXCL off.
4727 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4728 fd = open(fname, O_WRONLY|O_CREAT, 0666);
4730 /* If the open failed, return the file descriptor right away. */
4735 * OK, the open succeeded, but the file may have been changed from a
4736 * non-regular file to a regular file between the stat and the open.
4737 * We are assuming that the O_EXCL open handles the case where FILENAME
4738 * did not exist and is symlinked to an existing file between the stat
4743 * If we can open it and fstat the file descriptor, and neither check
4744 * revealed that it was a regular file, and the file has not been
4745 * replaced, return the file descriptor.
4747 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4748 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4751 /* The file has been replaced. badness. */
4758 * Handle here documents. Normally we fork off a process to write the
4759 * data to a pipe. If the document is short, we can stuff the data in
4760 * the pipe without forking.
4762 /* openhere needs this forward reference */
4763 static void expandhere(union node *arg, int fd);
4765 openhere(union node *redir)
4771 ash_msg_and_raise_error("pipe call failed");
4772 if (redir->type == NHERE) {
4773 len = strlen(redir->nhere.doc->narg.text);
4774 if (len <= PIPESIZE) {
4775 full_write(pip[1], redir->nhere.doc->narg.text, len);
4779 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4781 signal(SIGINT, SIG_IGN);
4782 signal(SIGQUIT, SIG_IGN);
4783 signal(SIGHUP, SIG_IGN);
4785 signal(SIGTSTP, SIG_IGN);
4787 signal(SIGPIPE, SIG_DFL);
4788 if (redir->type == NHERE)
4789 full_write(pip[1], redir->nhere.doc->narg.text, len);
4791 expandhere(redir->nhere.doc, pip[1]);
4792 _exit(EXIT_SUCCESS);
4800 openredirect(union node *redir)
4805 switch (redir->nfile.type) {
4807 fname = redir->nfile.expfname;
4808 f = open(fname, O_RDONLY);
4813 fname = redir->nfile.expfname;
4814 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
4819 /* Take care of noclobber mode. */
4821 fname = redir->nfile.expfname;
4822 f = noclobberopen(fname);
4829 fname = redir->nfile.expfname;
4830 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4835 fname = redir->nfile.expfname;
4836 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4844 /* Fall through to eliminate warning. */
4851 f = openhere(redir);
4857 ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4859 ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "no such file"));
4863 * Copy a file descriptor to be >= to. Returns -1
4864 * if the source file descriptor is closed, EMPTY if there are no unused
4865 * file descriptors left.
4868 copyfd(int from, int to)
4872 newfd = fcntl(from, F_DUPFD, to);
4874 if (errno == EMFILE)
4876 ash_msg_and_raise_error("%d: %m", from);
4882 dupredirect(union node *redir, int f)
4884 int fd = redir->nfile.fd;
4886 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
4887 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
4888 copyfd(redir->ndup.dupfd, fd);
4900 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
4901 * old file descriptors are stashed away so that the redirection can be
4902 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
4903 * standard output, and the standard error if it becomes a duplicate of
4904 * stdout, is saved in memory.
4906 /* flags passed to redirect */
4907 #define REDIR_PUSH 01 /* save previous values of file descriptors */
4908 #define REDIR_SAVEFD2 03 /* set preverrout */
4910 redirect(union node *redir, int flags)
4913 struct redirtab *sv;
4924 if (flags & REDIR_PUSH) {
4925 sv = ckmalloc(sizeof(*sv));
4926 sv->next = redirlist;
4928 sv->nullredirs = g_nullredirs - 1;
4929 for (i = 0; i < 10; i++)
4930 sv->renamed[i] = EMPTY;
4936 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD)
4937 && n->ndup.dupfd == fd)
4938 continue; /* redirect from/to same file descriptor */
4940 newfd = openredirect(n);
4942 /* Descriptor wasn't open before redirect.
4943 * Mark it for close in the future */
4944 if (sv && sv->renamed[fd] == EMPTY)
4945 sv->renamed[fd] = CLOSED;
4948 if (sv && sv->renamed[fd] == EMPTY) {
4949 i = fcntl(fd, F_DUPFD, 10);
4956 ash_msg_and_raise_error("%d: %m", fd);
4960 sv->renamed[fd] = i;
4966 dupredirect(n, newfd);
4967 } while ((n = n->nfile.next));
4969 if ((flags & REDIR_SAVEFD2) && sv && sv->renamed[2] >= 0)
4970 preverrout_fd = sv->renamed[2];
4974 * Undo the effects of the last redirection.
4979 struct redirtab *rp;
4982 if (--g_nullredirs >= 0)
4986 for (i = 0; i < 10; i++) {
4987 if (rp->renamed[i] == CLOSED) {
4992 if (rp->renamed[i] != EMPTY) {
4995 copyfd(rp->renamed[i], i);
4997 close(rp->renamed[i]);
5000 redirlist = rp->next;
5001 g_nullredirs = rp->nullredirs;
5007 * Undo all redirections. Called on error or interrupt.
5011 * Discard all saved file descriptors.
5014 clearredir(int drop)
5025 redirectsafe(union node *redir, int flags)
5028 volatile int saveint;
5029 struct jmploc *volatile savehandler = exception_handler;
5030 struct jmploc jmploc;
5033 err = setjmp(jmploc.loc) * 2;
5035 exception_handler = &jmploc;
5036 redirect(redir, flags);
5038 exception_handler = savehandler;
5039 if (err && exception != EXERROR)
5040 longjmp(exception_handler->loc, 1);
5041 RESTORE_INT(saveint);
5046 /* ============ Routines to expand arguments to commands
5048 * We have to deal with backquotes, shell variables, and file metacharacters.
5054 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5055 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5056 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5057 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5058 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5059 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5060 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5061 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5062 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5066 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5067 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5068 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5069 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5070 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5073 * Structure specifying which parts of the string should be searched
5074 * for IFS characters.
5077 struct ifsregion *next; /* next region in list */
5078 int begoff; /* offset of start of region */
5079 int endoff; /* offset of end of region */
5080 int nulonly; /* search for nul bytes only */
5084 struct strlist *list;
5085 struct strlist **lastp;
5088 /* output of current string */
5089 static char *expdest;
5090 /* list of back quote expressions */
5091 static struct nodelist *argbackq;
5092 /* first struct in list of ifs regions */
5093 static struct ifsregion ifsfirst;
5094 /* last struct in list */
5095 static struct ifsregion *ifslastp;
5096 /* holds expanded arg list */
5097 static struct arglist exparg;
5107 expdest = makestrspace(32, expdest);
5108 #if ENABLE_ASH_MATH_SUPPORT_64
5109 len = fmtstr(expdest, 32, "%lld", (long long) num);
5111 len = fmtstr(expdest, 32, "%ld", num);
5113 STADJUST(len, expdest);
5118 esclen(const char *start, const char *p)
5122 while (p > start && *--p == CTLESC) {
5129 * Remove any CTLESC characters from a string.
5132 _rmescapes(char *str, int flag)
5134 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5141 p = strpbrk(str, qchars);
5147 if (flag & RMESCAPE_ALLOC) {
5148 size_t len = p - str;
5149 size_t fulllen = len + strlen(p) + 1;
5151 if (flag & RMESCAPE_GROW) {
5152 r = makestrspace(fulllen, expdest);
5153 } else if (flag & RMESCAPE_HEAP) {
5154 r = ckmalloc(fulllen);
5156 r = stalloc(fulllen);
5160 q = (char *)memcpy(q, str, len) + len;
5163 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5164 globbing = flag & RMESCAPE_GLOB;
5165 notescaped = globbing;
5167 if (*p == CTLQUOTEMARK) {
5168 inquotes = ~inquotes;
5170 notescaped = globbing;
5174 /* naked back slash */
5180 if (notescaped && inquotes && *p != '/') {
5184 notescaped = globbing;
5189 if (flag & RMESCAPE_GROW) {
5191 STADJUST(q - r + 1, expdest);
5195 #define rmescapes(p) _rmescapes((p), 0)
5197 #define pmatch(a, b) !fnmatch((a), (b), 0)
5200 * Prepare a pattern for a expmeta (internal glob(3)) call.
5202 * Returns an stalloced string.
5205 preglob(const char *pattern, int quoted, int flag)
5207 flag |= RMESCAPE_GLOB;
5209 flag |= RMESCAPE_QUOTED;
5211 return _rmescapes((char *)pattern, flag);
5215 * Put a string on the stack.
5218 memtodest(const char *p, size_t len, int syntax, int quotes)
5222 q = makestrspace(len * 2, q);
5225 int c = signed_char2int(*p++);
5228 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5237 strtodest(const char *p, int syntax, int quotes)
5239 memtodest(p, strlen(p), syntax, quotes);
5243 * Record the fact that we have to scan this region of the
5244 * string for IFS characters.
5247 recordregion(int start, int end, int nulonly)
5249 struct ifsregion *ifsp;
5251 if (ifslastp == NULL) {
5255 ifsp = ckzalloc(sizeof(*ifsp));
5256 /*ifsp->next = NULL; - ckzalloc did it */
5257 ifslastp->next = ifsp;
5261 ifslastp->begoff = start;
5262 ifslastp->endoff = end;
5263 ifslastp->nulonly = nulonly;
5267 removerecordregions(int endoff)
5269 if (ifslastp == NULL)
5272 if (ifsfirst.endoff > endoff) {
5273 while (ifsfirst.next != NULL) {
5274 struct ifsregion *ifsp;
5276 ifsp = ifsfirst.next->next;
5277 free(ifsfirst.next);
5278 ifsfirst.next = ifsp;
5281 if (ifsfirst.begoff > endoff)
5284 ifslastp = &ifsfirst;
5285 ifsfirst.endoff = endoff;
5290 ifslastp = &ifsfirst;
5291 while (ifslastp->next && ifslastp->next->begoff < endoff)
5292 ifslastp=ifslastp->next;
5293 while (ifslastp->next != NULL) {
5294 struct ifsregion *ifsp;
5296 ifsp = ifslastp->next->next;
5297 free(ifslastp->next);
5298 ifslastp->next = ifsp;
5301 if (ifslastp->endoff > endoff)
5302 ifslastp->endoff = endoff;
5306 exptilde(char *startp, char *p, int flag)
5312 int quotes = flag & (EXP_FULL | EXP_CASE);
5317 while ((c = *++p) != '\0') {
5324 if (flag & EXP_VARTILDE)
5334 if (*name == '\0') {
5335 home = lookupvar(homestr);
5337 pw = getpwnam(name);
5342 if (!home || !*home)
5345 startloc = expdest - (char *)stackblock();
5346 strtodest(home, SQSYNTAX, quotes);
5347 recordregion(startloc, expdest - (char *)stackblock(), 0);
5355 * Execute a command inside back quotes. If it's a builtin command, we
5356 * want to save its output in a block obtained from malloc. Otherwise
5357 * we fork off a subprocess and get the output of the command via a pipe.
5358 * Should be called with interrupts off.
5360 struct backcmd { /* result of evalbackcmd */
5361 int fd; /* file descriptor to read from */
5362 int nleft; /* number of chars in buffer */
5363 char *buf; /* buffer */
5364 struct job *jp; /* job structure for command */
5367 /* These forward decls are needed to use "eval" code for backticks handling: */
5368 static smalluint back_exitstatus; /* exit status of backquoted command */
5369 #define EV_EXIT 01 /* exit after evaluating tree */
5370 static void evaltree(union node *, int);
5373 evalbackcmd(union node *n, struct backcmd *result)
5385 saveherefd = herefd;
5393 ash_msg_and_raise_error("pipe call failed");
5394 jp = makejob(/*n,*/ 1);
5395 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5404 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5408 result->fd = pip[0];
5411 herefd = saveherefd;
5413 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5414 result->fd, result->buf, result->nleft, result->jp));
5418 * Expand stuff in backwards quotes.
5421 expbackq(union node *cmd, int quoted, int quotes)
5429 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
5430 struct stackmark smark;
5433 setstackmark(&smark);
5435 startloc = dest - (char *)stackblock();
5437 evalbackcmd(cmd, &in);
5438 popstackmark(&smark);
5445 memtodest(p, i, syntax, quotes);
5449 i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5450 TRACE(("expbackq: read returns %d\n", i));
5459 back_exitstatus = waitforjob(in.jp);
5463 /* Eat all trailing newlines */
5465 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5470 recordregion(startloc, dest - (char *)stackblock(), 0);
5471 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5472 (dest - (char *)stackblock()) - startloc,
5473 (dest - (char *)stackblock()) - startloc,
5474 stackblock() + startloc));
5477 #if ENABLE_ASH_MATH_SUPPORT
5479 * Expand arithmetic expression. Backup to start of expression,
5480 * evaluate, place result in (backed up) result, adjust string position.
5493 * This routine is slightly over-complicated for
5494 * efficiency. Next we scan backwards looking for the
5495 * start of arithmetic.
5497 start = stackblock();
5504 while (*p != CTLARI) {
5508 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5513 esc = esclen(start, p);
5523 removerecordregions(begoff);
5532 len = cvtnum(dash_arith(p + 2));
5535 recordregion(begoff, begoff + len, 0);
5539 /* argstr needs it */
5540 static char *evalvar(char *p, int flag, struct strlist *var_str_list);
5543 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5544 * characters to allow for further processing. Otherwise treat
5545 * $@ like $* since no splitting will be performed.
5547 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5548 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5549 * for correct expansion of "B=$A" word.
5552 argstr(char *p, int flag, struct strlist *var_str_list)
5554 static const char spclchars[] ALIGN1 = {
5562 CTLBACKQ | CTLQUOTE,
5563 #if ENABLE_ASH_MATH_SUPPORT
5568 const char *reject = spclchars;
5570 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
5571 int breakall = flag & EXP_WORD;
5576 if (!(flag & EXP_VARTILDE)) {
5578 } else if (flag & EXP_VARTILDE2) {
5583 if (flag & EXP_TILDE) {
5589 if (*q == CTLESC && (flag & EXP_QWORD))
5592 p = exptilde(p, q, flag);
5595 startloc = expdest - (char *)stackblock();
5597 length += strcspn(p + length, reject);
5599 if (c && (!(c & 0x80)
5600 #if ENABLE_ASH_MATH_SUPPORT
5604 /* c == '=' || c == ':' || c == CTLENDARI */
5609 expdest = stack_nputstr(p, length, expdest);
5610 newloc = expdest - (char *)stackblock();
5611 if (breakall && !inquotes && newloc > startloc) {
5612 recordregion(startloc, newloc, 0);
5623 if (flag & EXP_VARTILDE2) {
5627 flag |= EXP_VARTILDE2;
5632 * sort of a hack - expand tildes in variable
5633 * assignments (after the first '=' and after ':'s).
5642 case CTLENDVAR: /* ??? */
5645 /* "$@" syntax adherence hack */
5648 !memcmp(p, dolatstr, 4) &&
5649 (p[4] == CTLQUOTEMARK || (
5650 p[4] == CTLENDVAR &&
5651 p[5] == CTLQUOTEMARK
5654 p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;
5657 inquotes = !inquotes;
5670 p = evalvar(p, flag, var_str_list);
5674 case CTLBACKQ|CTLQUOTE:
5675 expbackq(argbackq->n, c, quotes);
5676 argbackq = argbackq->next;
5678 #if ENABLE_ASH_MATH_SUPPORT
5691 scanleft(char *startp, char *rmesc, char *rmescend ATTRIBUTE_UNUSED, char *str, int quotes,
5694 // This commented out code was added by James Simmons <jsimmons@infradead.org>
5695 // as part of a larger change when he added support for ${var/a/b}.
5696 // However, it broke # and % operators:
5700 //echo ${var#ab} abcdcd abcdcd
5701 //echo ${var##ab} abcdcd abcdcd
5702 //echo ${var#a*b} abcdcd ababcdcd (!)
5703 //echo ${var##a*b} cdcd cdcd
5704 //echo ${var#?} babcdcd ababcdcd (!)
5705 //echo ${var##?} babcdcd babcdcd
5706 //echo ${var#*} ababcdcd babcdcd (!)
5708 //echo ${var%cd} ababcd ababcd
5709 //echo ${var%%cd} ababcd abab (!)
5710 //echo ${var%c*d} ababcd ababcd
5711 //echo ${var%%c*d} abab ababcdcd (!)
5712 //echo ${var%?} ababcdc ababcdc
5713 //echo ${var%%?} ababcdc ababcdcd (!)
5714 //echo ${var%*} ababcdcd ababcdcd
5717 // Commenting it back out helped. Remove it completely if it really
5720 char *loc, *loc2; //, *full;
5726 int match; // = strlen(str);
5727 const char *s = loc2;
5734 match = pmatch(str, s); // this line was deleted
5736 // // chop off end if its '*'
5737 // full = strrchr(str, '*');
5738 // if (full && full != str)
5741 // // If str starts with '*' replace with s.
5742 // if ((*str == '*') && strlen(s) >= match) {
5743 // full = xstrdup(s);
5744 // strncpy(full+strlen(s)-match+1, str+1, match-1);
5746 // full = xstrndup(str, match);
5747 // match = strncmp(s, full, strlen(full));
5751 if (match) // if (!match)
5753 if (quotes && *loc == CTLESC)
5762 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5769 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5772 const char *s = loc2;
5777 match = pmatch(str, s);
5784 esc = esclen(startp, loc);
5795 static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN;
5797 varunset(const char *end, const char *var, const char *umsg, int varflags)
5803 msg = "parameter not set";
5805 if (*end == CTLENDVAR) {
5806 if (varflags & VSNUL)
5811 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5814 #if ENABLE_ASH_BASH_COMPAT
5816 parse_sub_pattern(char *arg, int inquotes)
5818 char *idx, *repl = NULL;
5827 /* Only the first '/' seen is our separator */
5834 if (!inquotes && c == '\\' && arg[1] == '\\')
5835 arg++; /* skip both \\, not just first one */
5842 #endif /* ENABLE_ASH_BASH_COMPAT */
5845 subevalvar(char *p, char *str, int strloc, int subtype,
5846 int startloc, int varflags, int quotes, struct strlist *var_str_list)
5848 struct nodelist *saveargbackq = argbackq;
5851 char *rmesc, *rmescend;
5852 USE_ASH_BASH_COMPAT(char *repl = NULL;)
5853 USE_ASH_BASH_COMPAT(char null = '\0';)
5854 USE_ASH_BASH_COMPAT(int pos, len, orig_len;)
5855 int saveherefd = herefd;
5856 int amount, workloc, resetloc;
5858 char *(*scan)(char*, char*, char*, char*, int, int);
5861 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
5863 STPUTC('\0', expdest);
5864 herefd = saveherefd;
5865 argbackq = saveargbackq;
5866 startp = (char *)stackblock() + startloc;
5870 setvar(str, startp, 0);
5871 amount = startp - expdest;
5872 STADJUST(amount, expdest);
5875 #if ENABLE_ASH_BASH_COMPAT
5877 loc = str = stackblock() + strloc;
5878 // TODO: number() instead? It does error checking...
5880 len = str - startp - 1;
5882 /* *loc != '\0', guaranteed by parser */
5886 /* We must adjust the length by the number of escapes we find. */
5887 for (ptr = startp; ptr < (str - 1); ptr++) {
5888 if(*ptr == CTLESC) {
5896 if (*loc++ == ':') {
5897 // TODO: number() instead? It does error checking...
5901 while (*loc && *loc != ':')
5904 // TODO: number() instead? It does error checking...
5907 if (pos >= orig_len) {
5911 if (len > (orig_len - pos))
5912 len = orig_len - pos;
5914 for (str = startp; pos; str++, pos--) {
5915 if (quotes && *str == CTLESC)
5918 for (loc = startp; len; len--) {
5919 if (quotes && *str == CTLESC)
5924 amount = loc - expdest;
5925 STADJUST(amount, expdest);
5930 varunset(p, str, startp, varflags);
5933 resetloc = expdest - (char *)stackblock();
5935 /* We'll comeback here if we grow the stack while handling
5936 * a VSREPLACE or VSREPLACEALL, since our pointers into the
5937 * stack will need rebasing, and we'll need to remove our work
5940 USE_ASH_BASH_COMPAT(restart:)
5942 amount = expdest - ((char *)stackblock() + resetloc);
5943 STADJUST(-amount, expdest);
5944 startp = (char *)stackblock() + startloc;
5947 rmescend = (char *)stackblock() + strloc;
5949 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5950 if (rmesc != startp) {
5952 startp = (char *)stackblock() + startloc;
5956 str = (char *)stackblock() + strloc;
5957 preglob(str, varflags & VSQUOTE, 0);
5958 workloc = expdest - (char *)stackblock();
5960 #if ENABLE_ASH_BASH_COMPAT
5961 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
5962 char *idx, *end, *restart_detect;
5965 repl = parse_sub_pattern(str, varflags & VSQUOTE);
5970 /* If there's no pattern to match, return the expansion unmolested */
5978 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
5980 /* No match, advance */
5981 restart_detect = stackblock();
5982 STPUTC(*idx, expdest);
5983 if (quotes && *idx == CTLESC) {
5986 STPUTC(*idx, expdest);
5988 if (stackblock() != restart_detect)
5996 if (subtype == VSREPLACEALL) {
5998 if (quotes && *idx == CTLESC)
6006 for (loc = repl; *loc; loc++) {
6007 restart_detect = stackblock();
6008 STPUTC(*loc, expdest);
6009 if (stackblock() != restart_detect)
6014 if (subtype == VSREPLACE) {
6016 restart_detect = stackblock();
6017 STPUTC(*idx, expdest);
6018 if (stackblock() != restart_detect)
6027 /* We've put the replaced text into a buffer at workloc, now
6028 * move it to the right place and adjust the stack.
6030 startp = stackblock() + startloc;
6031 STPUTC('\0', expdest);
6032 memmove(startp, stackblock() + workloc, len);
6033 startp[len++] = '\0';
6034 amount = expdest - ((char *)stackblock() + startloc + len - 1);
6035 STADJUST(-amount, expdest);
6038 #endif /* ENABLE_ASH_BASH_COMPAT */
6040 subtype -= VSTRIMRIGHT;
6042 if (subtype < 0 || subtype > 7)
6045 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
6046 zero = subtype >> 1;
6047 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6048 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6050 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6053 memmove(startp, loc, str - loc);
6054 loc = startp + (str - loc) - 1;
6057 amount = loc - expdest;
6058 STADJUST(amount, expdest);
6064 * Add the value of a specialized variable to the stack string.
6067 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6077 int quoted = varflags & VSQUOTE;
6078 int subtype = varflags & VSTYPE;
6079 int quotes = flags & (EXP_FULL | EXP_CASE);
6081 if (quoted && (flags & EXP_FULL))
6082 sep = 1 << CHAR_BIT;
6084 syntax = quoted ? DQSYNTAX : BASESYNTAX;
6093 num = shellparam.nparam;
6103 p = makestrspace(NOPTS, expdest);
6104 for (i = NOPTS - 1; i >= 0; i--) {
6106 USTPUTC(optletters(i), p);
6117 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
6118 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
6124 while ((p = *ap++)) {
6127 partlen = strlen(p);
6130 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6131 memtodest(p, partlen, syntax, quotes);
6137 if (subtype == VSPLUS || subtype == VSLENGTH) {
6158 // TODO: number() instead? It does error checking...
6160 if (num < 0 || num > shellparam.nparam)
6162 p = num ? shellparam.p[num - 1] : arg0;
6165 /* NB: name has form "VAR=..." */
6167 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6168 * which should be considered before we check variables. */
6170 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6174 str = var_str_list->text;
6175 eq = strchr(str, '=');
6176 if (!eq) /* stop at first non-assignment */
6179 if (name_len == (unsigned)(eq - str)
6180 && strncmp(str, name, name_len) == 0) {
6182 /* goto value; - WRONG! */
6183 /* think "A=1 A=2 B=$A" */
6185 var_str_list = var_str_list->next;
6186 } while (var_str_list);
6190 p = lookupvar(name);
6196 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6197 memtodest(p, len, syntax, quotes);
6201 if (subtype == VSPLUS || subtype == VSLENGTH)
6202 STADJUST(-len, expdest);
6207 * Expand a variable, and return a pointer to the next character in the
6211 evalvar(char *p, int flag, struct strlist *var_str_list)
6223 subtype = varflags & VSTYPE;
6224 quoted = varflags & VSQUOTE;
6226 easy = (!quoted || (*var == '@' && shellparam.nparam));
6227 startloc = expdest - (char *)stackblock();
6228 p = strchr(p, '=') + 1;
6231 varlen = varvalue(var, varflags, flag, var_str_list);
6232 if (varflags & VSNUL)
6235 if (subtype == VSPLUS) {
6236 varlen = -1 - varlen;
6240 if (subtype == VSMINUS) {
6244 p, flag | EXP_TILDE |
6245 (quoted ? EXP_QWORD : EXP_WORD),
6255 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6257 if (subevalvar(p, var, /* strloc: */ 0,
6258 subtype, startloc, varflags,
6264 * Remove any recorded regions beyond
6267 removerecordregions(startloc);
6277 if (varlen < 0 && uflag)
6278 varunset(p, var, 0, 0);
6280 if (subtype == VSLENGTH) {
6281 cvtnum(varlen > 0 ? varlen : 0);
6285 if (subtype == VSNORMAL) {
6296 case VSTRIMRIGHTMAX:
6297 #if ENABLE_ASH_BASH_COMPAT
6310 * Terminate the string and start recording the pattern
6313 STPUTC('\0', expdest);
6314 patloc = expdest - (char *)stackblock();
6315 if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6317 /* quotes: */ flag & (EXP_FULL | EXP_CASE),
6320 int amount = expdest - (
6321 (char *)stackblock() + patloc - 1
6323 STADJUST(-amount, expdest);
6325 /* Remove any recorded regions beyond start of variable */
6326 removerecordregions(startloc);
6328 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6332 if (subtype != VSNORMAL) { /* skip to end of alternative */
6338 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6340 argbackq = argbackq->next;
6341 } else if (c == CTLVAR) {
6342 if ((*p++ & VSTYPE) != VSNORMAL)
6344 } else if (c == CTLENDVAR) {
6354 * Break the argument string into pieces based upon IFS and add the
6355 * strings to the argument list. The regions of the string to be
6356 * searched for IFS characters have been stored by recordregion.
6359 ifsbreakup(char *string, struct arglist *arglist)
6361 struct ifsregion *ifsp;
6366 const char *ifs, *realifs;
6371 if (ifslastp != NULL) {
6374 realifs = ifsset() ? ifsval() : defifs;
6377 p = string + ifsp->begoff;
6378 nulonly = ifsp->nulonly;
6379 ifs = nulonly ? nullstr : realifs;
6381 while (p < string + ifsp->endoff) {
6385 if (!strchr(ifs, *p)) {
6390 ifsspc = (strchr(defifs, *p) != NULL);
6391 /* Ignore IFS whitespace at start */
6392 if (q == start && ifsspc) {
6398 sp = stzalloc(sizeof(*sp));
6400 *arglist->lastp = sp;
6401 arglist->lastp = &sp->next;
6405 if (p >= string + ifsp->endoff) {
6411 if (strchr(ifs, *p) == NULL ) {
6415 if (strchr(defifs, *p) == NULL) {
6430 } while (ifsp != NULL);
6439 sp = stzalloc(sizeof(*sp));
6441 *arglist->lastp = sp;
6442 arglist->lastp = &sp->next;
6448 struct ifsregion *p;
6453 struct ifsregion *ifsp;
6459 ifsfirst.next = NULL;
6464 * Add a file name to the list.
6467 addfname(const char *name)
6471 sp = stzalloc(sizeof(*sp));
6472 sp->text = ststrdup(name);
6474 exparg.lastp = &sp->next;
6477 static char *expdir;
6480 * Do metacharacter (i.e. *, ?, [...]) expansion.
6483 expmeta(char *enddir, char *name)
6498 for (p = name; *p; p++) {
6499 if (*p == '*' || *p == '?')
6501 else if (*p == '[') {
6508 if (*q == '/' || *q == '\0')
6515 } else if (*p == '\\')
6517 else if (*p == '/') {
6524 if (metaflag == 0) { /* we've reached the end of the file name */
6525 if (enddir != expdir)
6533 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6544 } while (p < start);
6546 if (enddir == expdir) {
6548 } else if (enddir == expdir + 1 && *expdir == '/') {
6557 if (enddir != expdir)
6559 if (*endname == 0) {
6571 while (!intpending && (dp = readdir(dirp)) != NULL) {
6572 if (dp->d_name[0] == '.' && ! matchdot)
6574 if (pmatch(start, dp->d_name)) {
6576 strcpy(enddir, dp->d_name);
6579 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6582 expmeta(p, endname);
6591 static struct strlist *
6592 msort(struct strlist *list, int len)
6594 struct strlist *p, *q = NULL;
6595 struct strlist **lpp;
6603 for (n = half; --n >= 0; ) {
6607 q->next = NULL; /* terminate first half of list */
6608 q = msort(list, half); /* sort first half of list */
6609 p = msort(p, len - half); /* sort second half */
6612 #if ENABLE_LOCALE_SUPPORT
6613 if (strcoll(p->text, q->text) < 0)
6615 if (strcmp(p->text, q->text) < 0)
6639 * Sort the results of file name expansion. It calculates the number of
6640 * strings to sort and then calls msort (short for merge sort) to do the
6643 static struct strlist *
6644 expsort(struct strlist *str)
6650 for (sp = str; sp; sp = sp->next)
6652 return msort(str, len);
6656 expandmeta(struct strlist *str /*, int flag*/)
6658 static const char metachars[] ALIGN1 = {
6661 /* TODO - EXP_REDIR */
6664 struct strlist **savelastp;
6670 if (!strpbrk(str->text, metachars))
6672 savelastp = exparg.lastp;
6675 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
6677 int i = strlen(str->text);
6678 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
6686 if (exparg.lastp == savelastp) {
6691 *exparg.lastp = str;
6692 rmescapes(str->text);
6693 exparg.lastp = &str->next;
6695 *exparg.lastp = NULL;
6696 *savelastp = sp = expsort(*savelastp);
6697 while (sp->next != NULL)
6699 exparg.lastp = &sp->next;
6706 * Perform variable substitution and command substitution on an argument,
6707 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6708 * perform splitting and file name expansion. When arglist is NULL, perform
6709 * here document expansion.
6712 expandarg(union node *arg, struct arglist *arglist, int flag)
6717 argbackq = arg->narg.backquote;
6718 STARTSTACKSTR(expdest);
6719 ifsfirst.next = NULL;
6721 argstr(arg->narg.text, flag,
6722 /* var_str_list: */ arglist ? arglist->list : NULL);
6723 p = _STPUTC('\0', expdest);
6725 if (arglist == NULL) {
6726 return; /* here document expanded */
6728 p = grabstackstr(p);
6729 exparg.lastp = &exparg.list;
6733 if (flag & EXP_FULL) {
6734 ifsbreakup(p, &exparg);
6735 *exparg.lastp = NULL;
6736 exparg.lastp = &exparg.list;
6737 expandmeta(exparg.list /*, flag*/);
6739 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
6741 sp = stzalloc(sizeof(*sp));
6744 exparg.lastp = &sp->next;
6748 *exparg.lastp = NULL;
6750 *arglist->lastp = exparg.list;
6751 arglist->lastp = exparg.lastp;
6756 * Expand shell variables and backquotes inside a here document.
6759 expandhere(union node *arg, int fd)
6762 expandarg(arg, (struct arglist *)NULL, 0);
6763 full_write(fd, stackblock(), expdest - (char *)stackblock());
6767 * Returns true if the pattern matches the string.
6770 patmatch(char *pattern, const char *string)
6772 return pmatch(preglob(pattern, 0, 0), string);
6776 * See if a pattern matches in a case statement.
6779 casematch(union node *pattern, char *val)
6781 struct stackmark smark;
6784 setstackmark(&smark);
6785 argbackq = pattern->narg.backquote;
6786 STARTSTACKSTR(expdest);
6788 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
6789 /* var_str_list: */ NULL);
6790 STACKSTRNUL(expdest);
6791 result = patmatch(stackblock(), val);
6792 popstackmark(&smark);
6797 /* ============ find_command */
6801 int (*builtin)(int, char **);
6802 /* unsigned flags; */
6804 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
6805 /* "regular" builtins always take precedence over commands,
6806 * regardless of PATH=....%builtin... position */
6807 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
6808 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
6811 smallint cmdtype; /* CMDxxx */
6814 /* index >= 0 for commands without path (slashes) */
6815 /* (TODO: what exactly does the value mean? PATH position?) */
6816 /* index == -1 for commands with slashes */
6817 /* index == (-2 - applet_no) for NOFORK applets */
6818 const struct builtincmd *cmd;
6819 struct funcnode *func;
6822 /* values of cmdtype */
6823 #define CMDUNKNOWN -1 /* no entry in table for command */
6824 #define CMDNORMAL 0 /* command is an executable program */
6825 #define CMDFUNCTION 1 /* command is a shell function */
6826 #define CMDBUILTIN 2 /* command is a shell builtin */
6828 /* action to find_command() */
6829 #define DO_ERR 0x01 /* prints errors */
6830 #define DO_ABS 0x02 /* checks absolute paths */
6831 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
6832 #define DO_ALTPATH 0x08 /* using alternate path */
6833 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
6835 static void find_command(char *, struct cmdentry *, int, const char *);
6838 /* ============ Hashing commands */
6841 * When commands are first encountered, they are entered in a hash table.
6842 * This ensures that a full path search will not have to be done for them
6843 * on each invocation.
6845 * We should investigate converting to a linear search, even though that
6846 * would make the command name "hash" a misnomer.
6850 struct tblentry *next; /* next entry in hash chain */
6851 union param param; /* definition of builtin function */
6852 smallint cmdtype; /* CMDxxx */
6853 char rehash; /* if set, cd done since entry created */
6854 char cmdname[1]; /* name of command */
6857 static struct tblentry **cmdtable;
6858 #define INIT_G_cmdtable() do { \
6859 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
6862 static int builtinloc = -1; /* index in path of %builtin, or -1 */
6866 tryexec(USE_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
6870 #if ENABLE_FEATURE_SH_STANDALONE
6871 if (applet_no >= 0) {
6872 if (APPLET_IS_NOEXEC(applet_no))
6873 run_applet_no_and_exit(applet_no, argv);
6874 /* re-exec ourselves with the new arguments */
6875 execve(bb_busybox_exec_path, argv, envp);
6876 /* If they called chroot or otherwise made the binary no longer
6877 * executable, fall through */
6884 execve(cmd, argv, envp);
6885 } while (errno == EINTR);
6887 execve(cmd, argv, envp);
6893 if (errno == ENOEXEC) {
6897 for (ap = argv; *ap; ap++)
6899 ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0]));
6901 ap[0] = cmd = (char *)DEFAULT_SHELL;
6904 while ((*ap++ = *argv++) != NULL)
6913 * Exec a program. Never returns. If you change this routine, you may
6914 * have to change the find_command routine as well.
6916 static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
6918 shellexec(char **argv, const char *path, int idx)
6924 #if ENABLE_FEATURE_SH_STANDALONE
6929 envp = listvars(VEXPORT, VUNSET, 0);
6930 if (strchr(argv[0], '/') != NULL
6931 #if ENABLE_FEATURE_SH_STANDALONE
6932 || (applet_no = find_applet_by_name(argv[0])) >= 0
6935 tryexec(USE_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
6939 while ((cmdname = padvance(&path, argv[0])) != NULL) {
6940 if (--idx < 0 && pathopt == NULL) {
6941 tryexec(USE_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
6942 if (errno != ENOENT && errno != ENOTDIR)
6949 /* Map to POSIX errors */
6961 exitstatus = exerrno;
6962 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
6963 argv[0], e, suppressint ));
6964 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
6969 printentry(struct tblentry *cmdp)
6975 idx = cmdp->param.index;
6978 name = padvance(&path, cmdp->cmdname);
6980 } while (--idx >= 0);
6981 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
6985 * Clear out command entries. The argument specifies the first entry in
6986 * PATH which has changed.
6989 clearcmdentry(int firstchange)
6991 struct tblentry **tblp;
6992 struct tblentry **pp;
6993 struct tblentry *cmdp;
6996 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
6998 while ((cmdp = *pp) != NULL) {
6999 if ((cmdp->cmdtype == CMDNORMAL &&
7000 cmdp->param.index >= firstchange)
7001 || (cmdp->cmdtype == CMDBUILTIN &&
7002 builtinloc >= firstchange)
7015 * Locate a command in the command hash table. If "add" is nonzero,
7016 * add the command to the table if it is not already present. The
7017 * variable "lastcmdentry" is set to point to the address of the link
7018 * pointing to the entry, so that delete_cmd_entry can delete the
7021 * Interrupts must be off if called with add != 0.
7023 static struct tblentry **lastcmdentry;
7025 static struct tblentry *
7026 cmdlookup(const char *name, int add)
7028 unsigned int hashval;
7030 struct tblentry *cmdp;
7031 struct tblentry **pp;
7034 hashval = (unsigned char)*p << 4;
7036 hashval += (unsigned char)*p++;
7038 pp = &cmdtable[hashval % CMDTABLESIZE];
7039 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7040 if (strcmp(cmdp->cmdname, name) == 0)
7044 if (add && cmdp == NULL) {
7045 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7047 /* + 1 - already done because
7048 * tblentry::cmdname is char[1] */);
7049 /*cmdp->next = NULL; - ckzalloc did it */
7050 cmdp->cmdtype = CMDUNKNOWN;
7051 strcpy(cmdp->cmdname, name);
7058 * Delete the command entry returned on the last lookup.
7061 delete_cmd_entry(void)
7063 struct tblentry *cmdp;
7066 cmdp = *lastcmdentry;
7067 *lastcmdentry = cmdp->next;
7068 if (cmdp->cmdtype == CMDFUNCTION)
7069 freefunc(cmdp->param.func);
7075 * Add a new command entry, replacing any existing command entry for
7076 * the same name - except special builtins.
7079 addcmdentry(char *name, struct cmdentry *entry)
7081 struct tblentry *cmdp;
7083 cmdp = cmdlookup(name, 1);
7084 if (cmdp->cmdtype == CMDFUNCTION) {
7085 freefunc(cmdp->param.func);
7087 cmdp->cmdtype = entry->cmdtype;
7088 cmdp->param = entry->u;
7093 hashcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
7095 struct tblentry **pp;
7096 struct tblentry *cmdp;
7098 struct cmdentry entry;
7101 if (nextopt("r") != '\0') {
7106 if (*argptr == NULL) {
7107 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7108 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7109 if (cmdp->cmdtype == CMDNORMAL)
7117 while ((name = *argptr) != NULL) {
7118 cmdp = cmdlookup(name, 0);
7120 && (cmdp->cmdtype == CMDNORMAL
7121 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7125 find_command(name, &entry, DO_ERR, pathval());
7126 if (entry.cmdtype == CMDUNKNOWN)
7134 * Called when a cd is done. Marks all commands so the next time they
7135 * are executed they will be rehashed.
7140 struct tblentry **pp;
7141 struct tblentry *cmdp;
7143 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7144 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7145 if (cmdp->cmdtype == CMDNORMAL
7146 || (cmdp->cmdtype == CMDBUILTIN
7147 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7157 * Fix command hash table when PATH changed.
7158 * Called before PATH is changed. The argument is the new value of PATH;
7159 * pathval() still returns the old value at this point.
7160 * Called with interrupts off.
7163 changepath(const char *new)
7171 firstchange = 9999; /* assume no change */
7177 if ((*old == '\0' && *new == ':')
7178 || (*old == ':' && *new == '\0'))
7180 old = new; /* ignore subsequent differences */
7184 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7190 if (builtinloc < 0 && idx_bltin >= 0)
7191 builtinloc = idx_bltin; /* zap builtins */
7192 if (builtinloc >= 0 && idx_bltin < 0)
7194 clearcmdentry(firstchange);
7195 builtinloc = idx_bltin;
7210 #define TENDBQUOTE 12
7227 typedef smallint token_id_t;
7229 /* first char is indicating which tokens mark the end of a list */
7230 static const char *const tokname_array[] = {
7244 #define KWDOFFSET 13
7245 /* the following are keywords */
7267 static char buf[16];
7270 //if (tok < TSEMI) return tokname_array[tok] + 1;
7271 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
7276 sprintf(buf + (tok >= TSEMI), "%s%c",
7277 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
7281 /* Wrapper around strcmp for qsort/bsearch/... */
7283 pstrcmp(const void *a, const void *b)
7285 return strcmp((char*) a, (*(char**) b) + 1);
7288 static const char *const *
7289 findkwd(const char *s)
7291 return bsearch(s, tokname_array + KWDOFFSET,
7292 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7293 sizeof(tokname_array[0]), pstrcmp);
7297 * Locate and print what a word is...
7300 describe_command(char *command, int describe_command_verbose)
7302 struct cmdentry entry;
7303 struct tblentry *cmdp;
7304 #if ENABLE_ASH_ALIAS
7305 const struct alias *ap;
7307 const char *path = pathval();
7309 if (describe_command_verbose) {
7313 /* First look at the keywords */
7314 if (findkwd(command)) {
7315 out1str(describe_command_verbose ? " is a shell keyword" : command);
7319 #if ENABLE_ASH_ALIAS
7320 /* Then look at the aliases */
7321 ap = lookupalias(command, 0);
7323 if (!describe_command_verbose) {
7328 out1fmt(" is an alias for %s", ap->val);
7332 /* Then check if it is a tracked alias */
7333 cmdp = cmdlookup(command, 0);
7335 entry.cmdtype = cmdp->cmdtype;
7336 entry.u = cmdp->param;
7338 /* Finally use brute force */
7339 find_command(command, &entry, DO_ABS, path);
7342 switch (entry.cmdtype) {
7344 int j = entry.u.index;
7350 p = padvance(&path, command);
7354 if (describe_command_verbose) {
7356 (cmdp ? " a tracked alias for" : nullstr), p
7365 if (describe_command_verbose) {
7366 out1str(" is a shell function");
7373 if (describe_command_verbose) {
7374 out1fmt(" is a %sshell builtin",
7375 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7376 "special " : nullstr
7384 if (describe_command_verbose) {
7385 out1str(": not found\n");
7390 outstr("\n", stdout);
7395 typecmd(int argc ATTRIBUTE_UNUSED, char **argv)
7401 /* type -p ... ? (we don't bother checking for 'p') */
7402 if (argv[1] && argv[1][0] == '-') {
7407 err |= describe_command(argv[i++], verbose);
7412 #if ENABLE_ASH_CMDCMD
7414 commandcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
7422 while ((c = nextopt("pvV")) != '\0')
7424 verify |= VERIFY_VERBOSE;
7426 verify |= VERIFY_BRIEF;
7432 return describe_command(*argptr, verify - VERIFY_BRIEF);
7439 /* ============ eval.c */
7441 static int funcblocksize; /* size of structures in function */
7442 static int funcstringsize; /* size of strings in node */
7443 static void *funcblock; /* block to allocate function from */
7444 static char *funcstring; /* block to allocate strings from */
7446 /* flags in argument to evaltree */
7447 #define EV_EXIT 01 /* exit after evaluating tree */
7448 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7449 #define EV_BACKCMD 04 /* command executing within back quotes */
7451 static const short nodesize[26] = {
7452 SHELL_ALIGN(sizeof(struct ncmd)),
7453 SHELL_ALIGN(sizeof(struct npipe)),
7454 SHELL_ALIGN(sizeof(struct nredir)),
7455 SHELL_ALIGN(sizeof(struct nredir)),
7456 SHELL_ALIGN(sizeof(struct nredir)),
7457 SHELL_ALIGN(sizeof(struct nbinary)),
7458 SHELL_ALIGN(sizeof(struct nbinary)),
7459 SHELL_ALIGN(sizeof(struct nbinary)),
7460 SHELL_ALIGN(sizeof(struct nif)),
7461 SHELL_ALIGN(sizeof(struct nbinary)),
7462 SHELL_ALIGN(sizeof(struct nbinary)),
7463 SHELL_ALIGN(sizeof(struct nfor)),
7464 SHELL_ALIGN(sizeof(struct ncase)),
7465 SHELL_ALIGN(sizeof(struct nclist)),
7466 SHELL_ALIGN(sizeof(struct narg)),
7467 SHELL_ALIGN(sizeof(struct narg)),
7468 SHELL_ALIGN(sizeof(struct nfile)),
7469 SHELL_ALIGN(sizeof(struct nfile)),
7470 SHELL_ALIGN(sizeof(struct nfile)),
7471 SHELL_ALIGN(sizeof(struct nfile)),
7472 SHELL_ALIGN(sizeof(struct nfile)),
7473 SHELL_ALIGN(sizeof(struct ndup)),
7474 SHELL_ALIGN(sizeof(struct ndup)),
7475 SHELL_ALIGN(sizeof(struct nhere)),
7476 SHELL_ALIGN(sizeof(struct nhere)),
7477 SHELL_ALIGN(sizeof(struct nnot)),
7480 static void calcsize(union node *n);
7483 sizenodelist(struct nodelist *lp)
7486 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7493 calcsize(union node *n)
7497 funcblocksize += nodesize[n->type];
7500 calcsize(n->ncmd.redirect);
7501 calcsize(n->ncmd.args);
7502 calcsize(n->ncmd.assign);
7505 sizenodelist(n->npipe.cmdlist);
7510 calcsize(n->nredir.redirect);
7511 calcsize(n->nredir.n);
7518 calcsize(n->nbinary.ch2);
7519 calcsize(n->nbinary.ch1);
7522 calcsize(n->nif.elsepart);
7523 calcsize(n->nif.ifpart);
7524 calcsize(n->nif.test);
7527 funcstringsize += strlen(n->nfor.var) + 1;
7528 calcsize(n->nfor.body);
7529 calcsize(n->nfor.args);
7532 calcsize(n->ncase.cases);
7533 calcsize(n->ncase.expr);
7536 calcsize(n->nclist.body);
7537 calcsize(n->nclist.pattern);
7538 calcsize(n->nclist.next);
7542 sizenodelist(n->narg.backquote);
7543 funcstringsize += strlen(n->narg.text) + 1;
7544 calcsize(n->narg.next);
7551 calcsize(n->nfile.fname);
7552 calcsize(n->nfile.next);
7556 calcsize(n->ndup.vname);
7557 calcsize(n->ndup.next);
7561 calcsize(n->nhere.doc);
7562 calcsize(n->nhere.next);
7565 calcsize(n->nnot.com);
7571 nodeckstrdup(char *s)
7573 char *rtn = funcstring;
7575 strcpy(funcstring, s);
7576 funcstring += strlen(s) + 1;
7580 static union node *copynode(union node *);
7582 static struct nodelist *
7583 copynodelist(struct nodelist *lp)
7585 struct nodelist *start;
7586 struct nodelist **lpp;
7591 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7592 (*lpp)->n = copynode(lp->n);
7594 lpp = &(*lpp)->next;
7601 copynode(union node *n)
7608 funcblock = (char *) funcblock + nodesize[n->type];
7612 new->ncmd.redirect = copynode(n->ncmd.redirect);
7613 new->ncmd.args = copynode(n->ncmd.args);
7614 new->ncmd.assign = copynode(n->ncmd.assign);
7617 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7618 new->npipe.backgnd = n->npipe.backgnd;
7623 new->nredir.redirect = copynode(n->nredir.redirect);
7624 new->nredir.n = copynode(n->nredir.n);
7631 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7632 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7635 new->nif.elsepart = copynode(n->nif.elsepart);
7636 new->nif.ifpart = copynode(n->nif.ifpart);
7637 new->nif.test = copynode(n->nif.test);
7640 new->nfor.var = nodeckstrdup(n->nfor.var);
7641 new->nfor.body = copynode(n->nfor.body);
7642 new->nfor.args = copynode(n->nfor.args);
7645 new->ncase.cases = copynode(n->ncase.cases);
7646 new->ncase.expr = copynode(n->ncase.expr);
7649 new->nclist.body = copynode(n->nclist.body);
7650 new->nclist.pattern = copynode(n->nclist.pattern);
7651 new->nclist.next = copynode(n->nclist.next);
7655 new->narg.backquote = copynodelist(n->narg.backquote);
7656 new->narg.text = nodeckstrdup(n->narg.text);
7657 new->narg.next = copynode(n->narg.next);
7664 new->nfile.fname = copynode(n->nfile.fname);
7665 new->nfile.fd = n->nfile.fd;
7666 new->nfile.next = copynode(n->nfile.next);
7670 new->ndup.vname = copynode(n->ndup.vname);
7671 new->ndup.dupfd = n->ndup.dupfd;
7672 new->ndup.fd = n->ndup.fd;
7673 new->ndup.next = copynode(n->ndup.next);
7677 new->nhere.doc = copynode(n->nhere.doc);
7678 new->nhere.fd = n->nhere.fd;
7679 new->nhere.next = copynode(n->nhere.next);
7682 new->nnot.com = copynode(n->nnot.com);
7685 new->type = n->type;
7690 * Make a copy of a parse tree.
7692 static struct funcnode *
7693 copyfunc(union node *n)
7698 funcblocksize = offsetof(struct funcnode, n);
7701 blocksize = funcblocksize;
7702 f = ckmalloc(blocksize + funcstringsize);
7703 funcblock = (char *) f + offsetof(struct funcnode, n);
7704 funcstring = (char *) f + blocksize;
7711 * Define a shell function.
7714 defun(char *name, union node *func)
7716 struct cmdentry entry;
7719 entry.cmdtype = CMDFUNCTION;
7720 entry.u.func = copyfunc(func);
7721 addcmdentry(name, &entry);
7725 static int evalskip; /* set if we are skipping commands */
7726 /* reasons for skipping commands (see comment on breakcmd routine) */
7727 #define SKIPBREAK (1 << 0)
7728 #define SKIPCONT (1 << 1)
7729 #define SKIPFUNC (1 << 2)
7730 #define SKIPFILE (1 << 3)
7731 #define SKIPEVAL (1 << 4)
7732 static int skipcount; /* number of levels to skip */
7733 static int funcnest; /* depth of function calls */
7735 /* forward decl way out to parsing code - dotrap needs it */
7736 static int evalstring(char *s, int mask);
7739 * Called to execute a trap. Perhaps we should avoid entering new trap
7740 * handlers while we are executing a trap handler.
7751 savestatus = exitstatus;
7755 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
7763 skip = evalstring(p, SKIPEVAL);
7764 exitstatus = savestatus;
7772 /* forward declarations - evaluation is fairly recursive business... */
7773 static void evalloop(union node *, int);
7774 static void evalfor(union node *, int);
7775 static void evalcase(union node *, int);
7776 static void evalsubshell(union node *, int);
7777 static void expredir(union node *);
7778 static void evalpipe(union node *, int);
7779 static void evalcommand(union node *, int);
7780 static int evalbltin(const struct builtincmd *, int, char **);
7781 static void prehash(union node *);
7784 * Evaluate a parse tree. The value is left in the global variable
7788 evaltree(union node *n, int flags)
7791 void (*evalfn)(union node *, int);
7795 TRACE(("evaltree(NULL) called\n"));
7798 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
7799 getpid(), n, n->type, flags));
7803 out1fmt("Node type = %d\n", n->type);
7808 evaltree(n->nnot.com, EV_TESTED);
7809 status = !exitstatus;
7812 expredir(n->nredir.redirect);
7813 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
7815 evaltree(n->nredir.n, flags & EV_TESTED);
7816 status = exitstatus;
7821 evalfn = evalcommand;
7823 if (eflag && !(flags & EV_TESTED))
7835 evalfn = evalsubshell;
7847 #error NAND + 1 != NOR
7849 #if NOR + 1 != NSEMI
7850 #error NOR + 1 != NSEMI
7852 isor = n->type - NAND;
7855 (flags | ((isor >> 1) - 1)) & EV_TESTED
7857 if (!exitstatus == isor)
7869 evaltree(n->nif.test, EV_TESTED);
7872 if (exitstatus == 0) {
7875 } else if (n->nif.elsepart) {
7876 n = n->nif.elsepart;
7881 defun(n->narg.text, n->narg.next);
7885 exitstatus = status;
7889 if ((checkexit & exitstatus))
7890 evalskip |= SKIPEVAL;
7891 else if (pendingsig && dotrap())
7894 if (flags & EV_EXIT) {
7896 raise_exception(EXEXIT);
7900 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
7903 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
7905 static int loopnest; /* current loop nesting level */
7908 evalloop(union node *n, int flags)
7918 evaltree(n->nbinary.ch1, EV_TESTED);
7921 if (evalskip == SKIPCONT && --skipcount <= 0) {
7925 if (evalskip == SKIPBREAK && --skipcount <= 0)
7930 if (n->type != NWHILE)
7934 evaltree(n->nbinary.ch2, flags);
7935 status = exitstatus;
7940 exitstatus = status;
7944 evalfor(union node *n, int flags)
7946 struct arglist arglist;
7949 struct stackmark smark;
7951 setstackmark(&smark);
7952 arglist.list = NULL;
7953 arglist.lastp = &arglist.list;
7954 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
7955 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
7960 *arglist.lastp = NULL;
7965 for (sp = arglist.list; sp; sp = sp->next) {
7966 setvar(n->nfor.var, sp->text, 0);
7967 evaltree(n->nfor.body, flags);
7969 if (evalskip == SKIPCONT && --skipcount <= 0) {
7973 if (evalskip == SKIPBREAK && --skipcount <= 0)
7980 popstackmark(&smark);
7984 evalcase(union node *n, int flags)
7988 struct arglist arglist;
7989 struct stackmark smark;
7991 setstackmark(&smark);
7992 arglist.list = NULL;
7993 arglist.lastp = &arglist.list;
7994 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
7996 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
7997 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
7998 if (casematch(patp, arglist.list->text)) {
7999 if (evalskip == 0) {
8000 evaltree(cp->nclist.body, flags);
8007 popstackmark(&smark);
8011 * Kick off a subshell to evaluate a tree.
8014 evalsubshell(union node *n, int flags)
8017 int backgnd = (n->type == NBACKGND);
8020 expredir(n->nredir.redirect);
8021 if (!backgnd && flags & EV_EXIT && !trap[0])
8024 jp = makejob(/*n,*/ 1);
8025 if (forkshell(jp, n, backgnd) == 0) {
8029 flags &=~ EV_TESTED;
8031 redirect(n->nredir.redirect, 0);
8032 evaltreenr(n->nredir.n, flags);
8037 status = waitforjob(jp);
8038 exitstatus = status;
8043 * Compute the names of the files in a redirection list.
8045 static void fixredir(union node *, const char *, int);
8047 expredir(union node *n)
8051 for (redir = n; redir; redir = redir->nfile.next) {
8055 fn.lastp = &fn.list;
8056 switch (redir->type) {
8062 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8063 redir->nfile.expfname = fn.list->text;
8067 if (redir->ndup.vname) {
8068 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8069 if (fn.list == NULL)
8070 ash_msg_and_raise_error("redir error");
8071 fixredir(redir, fn.list->text, 1);
8079 * Evaluate a pipeline. All the processes in the pipeline are children
8080 * of the process creating the pipeline. (This differs from some versions
8081 * of the shell, which make the last process in a pipeline the parent
8085 evalpipe(union node *n, int flags)
8088 struct nodelist *lp;
8093 TRACE(("evalpipe(0x%lx) called\n", (long)n));
8095 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8099 jp = makejob(/*n,*/ pipelen);
8101 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8105 if (pipe(pip) < 0) {
8107 ash_msg_and_raise_error("pipe call failed");
8110 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
8123 evaltreenr(lp->n, flags);
8131 if (n->npipe.backgnd == 0) {
8132 exitstatus = waitforjob(jp);
8133 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
8139 * Controls whether the shell is interactive or not.
8142 setinteractive(int on)
8144 static smallint is_interactive;
8146 if (++on == is_interactive)
8148 is_interactive = on;
8152 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8153 if (is_interactive > 1) {
8154 /* Looks like they want an interactive shell */
8155 static smallint did_banner;
8160 "%s built-in shell (ash)\n"
8161 "Enter 'help' for a list of built-in commands."
8176 setinteractive(iflag);
8178 #if ENABLE_FEATURE_EDITING_VI
8180 line_input_state->flags |= VI_MODE;
8182 line_input_state->flags &= ~VI_MODE;
8184 viflag = 0; /* forcibly keep the option off */
8188 static struct localvar *localvars;
8191 * Called after a function returns.
8192 * Interrupts must be off.
8197 struct localvar *lvp;
8200 while ((lvp = localvars) != NULL) {
8201 localvars = lvp->next;
8203 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
8204 if (vp == NULL) { /* $- saved */
8205 memcpy(optlist, lvp->text, sizeof(optlist));
8206 free((char*)lvp->text);
8208 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8212 (*vp->func)(strchrnul(lvp->text, '=') + 1);
8213 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8214 free((char*)vp->text);
8215 vp->flags = lvp->flags;
8216 vp->text = lvp->text;
8223 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8225 volatile struct shparam saveparam;
8226 struct localvar *volatile savelocalvars;
8227 struct jmploc *volatile savehandler;
8228 struct jmploc jmploc;
8231 saveparam = shellparam;
8232 savelocalvars = localvars;
8233 e = setjmp(jmploc.loc);
8238 savehandler = exception_handler;
8239 exception_handler = &jmploc;
8241 shellparam.malloced = 0;
8245 shellparam.nparam = argc - 1;
8246 shellparam.p = argv + 1;
8247 #if ENABLE_ASH_GETOPTS
8248 shellparam.optind = 1;
8249 shellparam.optoff = -1;
8251 evaltree(&func->n, flags & EV_TESTED);
8257 localvars = savelocalvars;
8258 freeparam(&shellparam);
8259 shellparam = saveparam;
8260 exception_handler = savehandler;
8262 evalskip &= ~SKIPFUNC;
8266 #if ENABLE_ASH_CMDCMD
8268 parse_command_args(char **argv, const char **path)
8281 if (c == '-' && !*cp) {
8288 *path = bb_default_path;
8291 /* run 'typecmd' for other options */
8302 * Make a variable a local variable. When a variable is made local, it's
8303 * value and flags are saved in a localvar structure. The saved values
8304 * will be restored when the shell function returns. We handle the name
8305 * "-" as a special case.
8310 struct localvar *lvp;
8315 lvp = ckzalloc(sizeof(struct localvar));
8316 if (LONE_DASH(name)) {
8318 p = ckmalloc(sizeof(optlist));
8319 lvp->text = memcpy(p, optlist, sizeof(optlist));
8324 vpp = hashvar(name);
8325 vp = *findvar(vpp, name);
8326 eq = strchr(name, '=');
8329 setvareq(name, VSTRFIXED);
8331 setvar(name, NULL, VSTRFIXED);
8332 vp = *vpp; /* the new variable */
8333 lvp->flags = VUNSET;
8335 lvp->text = vp->text;
8336 lvp->flags = vp->flags;
8337 vp->flags |= VSTRFIXED|VTEXTFIXED;
8343 lvp->next = localvars;
8349 * The "local" command.
8352 localcmd(int argc ATTRIBUTE_UNUSED, char **argv)
8357 while ((name = *argv++) != NULL) {
8364 falsecmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
8370 truecmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
8376 execcmd(int argc ATTRIBUTE_UNUSED, char **argv)
8379 iflag = 0; /* exit on error */
8382 shellexec(argv + 1, pathval(), 0);
8388 * The return command.
8391 returncmd(int argc ATTRIBUTE_UNUSED, char **argv)
8394 * If called outside a function, do what ksh does;
8395 * skip the rest of the file.
8397 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8398 return argv[1] ? number(argv[1]) : exitstatus;
8401 /* Forward declarations for builtintab[] */
8402 static int breakcmd(int, char **);
8403 static int dotcmd(int, char **);
8404 static int evalcmd(int, char **);
8405 static int exitcmd(int, char **);
8406 static int exportcmd(int, char **);
8407 #if ENABLE_ASH_GETOPTS
8408 static int getoptscmd(int, char **);
8410 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8411 static int helpcmd(int, char **);
8413 #if ENABLE_ASH_MATH_SUPPORT
8414 static int letcmd(int, char **);
8416 static int readcmd(int, char **);
8417 static int setcmd(int, char **);
8418 static int shiftcmd(int, char **);
8419 static int timescmd(int, char **);
8420 static int trapcmd(int, char **);
8421 static int umaskcmd(int, char **);
8422 static int unsetcmd(int, char **);
8423 static int ulimitcmd(int, char **);
8425 #define BUILTIN_NOSPEC "0"
8426 #define BUILTIN_SPECIAL "1"
8427 #define BUILTIN_REGULAR "2"
8428 #define BUILTIN_SPEC_REG "3"
8429 #define BUILTIN_ASSIGN "4"
8430 #define BUILTIN_SPEC_ASSG "5"
8431 #define BUILTIN_REG_ASSG "6"
8432 #define BUILTIN_SPEC_REG_ASSG "7"
8434 /* We do not handle [[ expr ]] bashism bash-compatibly,
8435 * we make it a synonym of [ expr ].
8436 * Basically, word splitting and pathname expansion should NOT be performed
8438 * no word splitting: a="a b"; [[ $a = "a b" ]]; echo $? should print "0"
8439 * no pathname expansion: [[ /bin/m* = "/bin/m*" ]]; echo $? should print "0"
8440 * Additional operators:
8441 * || and && should work as -o and -a
8443 * Apart from the above, [[ expr ]] should work as [ expr ]
8446 #define echocmd echo_main
8447 #define printfcmd printf_main
8448 #define testcmd test_main
8450 /* Keep these in proper order since it is searched via bsearch() */
8451 static const struct builtincmd builtintab[] = {
8452 { BUILTIN_SPEC_REG ".", dotcmd },
8453 { BUILTIN_SPEC_REG ":", truecmd },
8454 #if ENABLE_ASH_BUILTIN_TEST
8455 { BUILTIN_REGULAR "[", testcmd },
8456 #if ENABLE_ASH_BASH_COMPAT
8457 { BUILTIN_REGULAR "[[", testcmd },
8460 #if ENABLE_ASH_ALIAS
8461 { BUILTIN_REG_ASSG "alias", aliascmd },
8464 { BUILTIN_REGULAR "bg", fg_bgcmd },
8466 { BUILTIN_SPEC_REG "break", breakcmd },
8467 { BUILTIN_REGULAR "cd", cdcmd },
8468 { BUILTIN_NOSPEC "chdir", cdcmd },
8469 #if ENABLE_ASH_CMDCMD
8470 { BUILTIN_REGULAR "command", commandcmd },
8472 { BUILTIN_SPEC_REG "continue", breakcmd },
8473 #if ENABLE_ASH_BUILTIN_ECHO
8474 { BUILTIN_REGULAR "echo", echocmd },
8476 { BUILTIN_SPEC_REG "eval", evalcmd },
8477 { BUILTIN_SPEC_REG "exec", execcmd },
8478 { BUILTIN_SPEC_REG "exit", exitcmd },
8479 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8480 { BUILTIN_REGULAR "false", falsecmd },
8482 { BUILTIN_REGULAR "fg", fg_bgcmd },
8484 #if ENABLE_ASH_GETOPTS
8485 { BUILTIN_REGULAR "getopts", getoptscmd },
8487 { BUILTIN_NOSPEC "hash", hashcmd },
8488 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8489 { BUILTIN_NOSPEC "help", helpcmd },
8492 { BUILTIN_REGULAR "jobs", jobscmd },
8493 { BUILTIN_REGULAR "kill", killcmd },
8495 #if ENABLE_ASH_MATH_SUPPORT
8496 { BUILTIN_NOSPEC "let", letcmd },
8498 { BUILTIN_ASSIGN "local", localcmd },
8499 #if ENABLE_ASH_BUILTIN_PRINTF
8500 { BUILTIN_REGULAR "printf", printfcmd },
8502 { BUILTIN_NOSPEC "pwd", pwdcmd },
8503 { BUILTIN_REGULAR "read", readcmd },
8504 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8505 { BUILTIN_SPEC_REG "return", returncmd },
8506 { BUILTIN_SPEC_REG "set", setcmd },
8507 { BUILTIN_SPEC_REG "shift", shiftcmd },
8508 { BUILTIN_SPEC_REG "source", dotcmd },
8509 #if ENABLE_ASH_BUILTIN_TEST
8510 { BUILTIN_REGULAR "test", testcmd },
8512 { BUILTIN_SPEC_REG "times", timescmd },
8513 { BUILTIN_SPEC_REG "trap", trapcmd },
8514 { BUILTIN_REGULAR "true", truecmd },
8515 { BUILTIN_NOSPEC "type", typecmd },
8516 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
8517 { BUILTIN_REGULAR "umask", umaskcmd },
8518 #if ENABLE_ASH_ALIAS
8519 { BUILTIN_REGULAR "unalias", unaliascmd },
8521 { BUILTIN_SPEC_REG "unset", unsetcmd },
8522 { BUILTIN_REGULAR "wait", waitcmd },
8525 /* Should match the above table! */
8526 #define COMMANDCMD (builtintab + \
8528 1 * ENABLE_ASH_BUILTIN_TEST + \
8529 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8530 1 * ENABLE_ASH_ALIAS + \
8531 1 * ENABLE_ASH_JOB_CONTROL + \
8533 #define EXECCMD (builtintab + \
8535 1 * ENABLE_ASH_BUILTIN_TEST + \
8536 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8537 1 * ENABLE_ASH_ALIAS + \
8538 1 * ENABLE_ASH_JOB_CONTROL + \
8540 1 * ENABLE_ASH_CMDCMD + \
8542 ENABLE_ASH_BUILTIN_ECHO + \
8546 * Search the table of builtin commands.
8548 static struct builtincmd *
8549 find_builtin(const char *name)
8551 struct builtincmd *bp;
8554 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8561 * Execute a simple command.
8564 isassignment(const char *p)
8566 const char *q = endofname(p);
8572 bltincmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
8574 /* Preserve exitstatus of a previous possible redirection
8575 * as POSIX mandates */
8576 return back_exitstatus;
8579 evalcommand(union node *cmd, int flags)
8581 static const struct builtincmd null_bltin = {
8582 "\0\0", bltincmd /* why three NULs? */
8584 struct stackmark smark;
8586 struct arglist arglist;
8587 struct arglist varlist;
8590 const struct strlist *sp;
8591 struct cmdentry cmdentry;
8599 struct builtincmd *bcmd;
8600 int pseudovarflag = 0;
8602 /* First expand the arguments. */
8603 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8604 setstackmark(&smark);
8605 back_exitstatus = 0;
8607 cmdentry.cmdtype = CMDBUILTIN;
8608 cmdentry.u.cmd = &null_bltin;
8609 varlist.lastp = &varlist.list;
8610 *varlist.lastp = NULL;
8611 arglist.lastp = &arglist.list;
8612 *arglist.lastp = NULL;
8615 if (cmd->ncmd.args) {
8616 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8617 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8620 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8621 struct strlist **spp;
8623 spp = arglist.lastp;
8624 if (pseudovarflag && isassignment(argp->narg.text))
8625 expandarg(argp, &arglist, EXP_VARTILDE);
8627 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8629 for (sp = *spp; sp; sp = sp->next)
8633 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8634 for (sp = arglist.list; sp; sp = sp->next) {
8635 TRACE(("evalcommand arg: %s\n", sp->text));
8636 *nargv++ = sp->text;
8641 if (iflag && funcnest == 0 && argc > 0)
8642 lastarg = nargv[-1];
8645 expredir(cmd->ncmd.redirect);
8646 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8649 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8650 struct strlist **spp;
8653 spp = varlist.lastp;
8654 expandarg(argp, &varlist, EXP_VARTILDE);
8657 * Modify the command lookup path, if a PATH= assignment
8661 if (varequal(p, path))
8665 /* Print the command if xflag is set. */
8668 const char *p = " %s";
8671 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8674 for (n = 0; n < 2; n++) {
8676 fdprintf(preverrout_fd, p, sp->text);
8684 safe_write(preverrout_fd, "\n", 1);
8690 /* Now locate the command. */
8692 const char *oldpath;
8693 int cmd_flag = DO_ERR;
8698 find_command(argv[0], &cmdentry, cmd_flag, path);
8699 if (cmdentry.cmdtype == CMDUNKNOWN) {
8705 /* implement bltin and command here */
8706 if (cmdentry.cmdtype != CMDBUILTIN)
8709 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8710 if (cmdentry.u.cmd == EXECCMD)
8712 #if ENABLE_ASH_CMDCMD
8713 if (cmdentry.u.cmd == COMMANDCMD) {
8715 nargv = parse_command_args(argv, &path);
8718 argc -= nargv - argv;
8720 cmd_flag |= DO_NOFUNC;
8728 /* We have a redirection error. */
8730 raise_exception(EXERROR);
8732 exitstatus = status;
8736 /* Execute the command. */
8737 switch (cmdentry.cmdtype) {
8739 #if ENABLE_FEATURE_SH_NOFORK
8741 /* find_command() encodes applet_no as (-2 - applet_no) */
8742 int applet_no = (- cmdentry.u.index - 2);
8743 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
8744 listsetvar(varlist.list, VEXPORT|VSTACK);
8745 /* run <applet>_main() */
8746 exitstatus = run_nofork_applet(applet_no, argv);
8752 /* Fork off a child process if necessary. */
8753 if (!(flags & EV_EXIT) || trap[0]) {
8755 jp = makejob(/*cmd,*/ 1);
8756 if (forkshell(jp, cmd, FORK_FG) != 0) {
8757 exitstatus = waitforjob(jp);
8763 listsetvar(varlist.list, VEXPORT|VSTACK);
8764 shellexec(argv, path, cmdentry.u.index);
8768 cmdenviron = varlist.list;
8770 struct strlist *list = cmdenviron;
8772 if (spclbltin > 0 || argc == 0) {
8774 if (cmd_is_exec && argc > 1)
8777 listsetvar(list, i);
8779 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
8786 exit_status = 128 + SIGINT;
8788 exit_status = 128 + pendingsig;
8789 exitstatus = exit_status;
8790 if (i == EXINT || spclbltin > 0) {
8792 longjmp(exception_handler->loc, 1);
8799 listsetvar(varlist.list, 0);
8800 if (evalfun(cmdentry.u.func, argc, argv, flags))
8806 popredir(cmd_is_exec);
8808 /* dsl: I think this is intended to be used to support
8809 * '_' in 'vi' command mode during line editing...
8810 * However I implemented that within libedit itself.
8812 setvar("_", lastarg, 0);
8813 popstackmark(&smark);
8817 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
8819 char *volatile savecmdname;
8820 struct jmploc *volatile savehandler;
8821 struct jmploc jmploc;
8824 savecmdname = commandname;
8825 i = setjmp(jmploc.loc);
8828 savehandler = exception_handler;
8829 exception_handler = &jmploc;
8830 commandname = argv[0];
8832 optptr = NULL; /* initialize nextopt */
8833 exitstatus = (*cmd->builtin)(argc, argv);
8834 flush_stdout_stderr();
8836 exitstatus |= ferror(stdout);
8838 commandname = savecmdname;
8840 exception_handler = savehandler;
8846 goodname(const char *p)
8848 return !*endofname(p);
8853 * Search for a command. This is called before we fork so that the
8854 * location of the command will be available in the parent as well as
8855 * the child. The check for "goodname" is an overly conservative
8856 * check that the name will not be subject to expansion.
8859 prehash(union node *n)
8861 struct cmdentry entry;
8863 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
8864 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
8868 /* ============ Builtin commands
8870 * Builtin commands whose functions are closely tied to evaluation
8871 * are implemented here.
8875 * Handle break and continue commands. Break, continue, and return are
8876 * all handled by setting the evalskip flag. The evaluation routines
8877 * above all check this flag, and if it is set they start skipping
8878 * commands rather than executing them. The variable skipcount is
8879 * the number of loops to break/continue, or the number of function
8880 * levels to return. (The latter is always 1.) It should probably
8881 * be an error to break out of more loops than exist, but it isn't
8882 * in the standard shell so we don't make it one here.
8885 breakcmd(int argc ATTRIBUTE_UNUSED, char **argv)
8887 int n = argv[1] ? number(argv[1]) : 1;
8890 ash_msg_and_raise_error(illnum, argv[1]);
8894 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
8901 /* ============ input.c
8903 * This implements the input routines used by the parser.
8906 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
8909 INPUT_PUSH_FILE = 1,
8910 INPUT_NOFILE_OK = 2,
8913 static int plinno = 1; /* input line number */
8914 /* number of characters left in input buffer */
8915 static int parsenleft; /* copy of parsefile->nleft */
8916 static int parselleft; /* copy of parsefile->lleft */
8917 /* next character in input buffer */
8918 static char *parsenextc; /* copy of parsefile->nextc */
8920 static smallint checkkwd;
8921 /* values of checkkwd variable */
8922 #define CHKALIAS 0x1
8929 struct strpush *sp = g_parsefile->strpush;
8932 #if ENABLE_ASH_ALIAS
8934 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
8935 checkkwd |= CHKALIAS;
8937 if (sp->string != sp->ap->val) {
8940 sp->ap->flag &= ~ALIASINUSE;
8941 if (sp->ap->flag & ALIASDEAD) {
8942 unalias(sp->ap->name);
8946 parsenextc = sp->prevstring;
8947 parsenleft = sp->prevnleft;
8948 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
8949 g_parsefile->strpush = sp->prev;
8950 if (sp != &(g_parsefile->basestrpush))
8959 char *buf = g_parsefile->buf;
8962 #if ENABLE_FEATURE_EDITING
8964 if (!iflag || g_parsefile->fd)
8965 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
8967 #if ENABLE_FEATURE_TAB_COMPLETION
8968 line_input_state->path_lookup = pathval();
8970 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
8972 /* Ctrl+C pressed */
8981 if (nr < 0 && errno == 0) {
8982 /* Ctrl+D pressed */
8987 nr = nonblock_safe_read(parsefile->fd, buf, BUFSIZ - 1);
8991 /* nonblock_safe_read() handles this problem */
8993 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
8994 int flags = fcntl(0, F_GETFL);
8995 if (flags >= 0 && (flags & O_NONBLOCK)) {
8996 flags &= ~O_NONBLOCK;
8997 if (fcntl(0, F_SETFL, flags) >= 0) {
8998 out2str("sh: turning off NDELAY mode\n");
9009 * Refill the input buffer and return the next input character:
9011 * 1) If a string was pushed back on the input, pop it;
9012 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
9013 * from a string so we can't refill the buffer, return EOF.
9014 * 3) If the is more stuff in this buffer, use it else call read to fill it.
9015 * 4) Process input up to the next newline, deleting nul characters.
9024 while (g_parsefile->strpush) {
9025 #if ENABLE_ASH_ALIAS
9026 if (parsenleft == -1 && g_parsefile->strpush->ap &&
9027 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
9032 if (--parsenleft >= 0)
9033 return signed_char2int(*parsenextc++);
9035 if (parsenleft == EOF_NLEFT || g_parsefile->buf == NULL)
9037 flush_stdout_stderr();
9044 parselleft = parsenleft = EOF_NLEFT;
9051 /* delete nul characters */
9059 memmove(q, q + 1, more);
9063 parsenleft = q - parsenextc - 1;
9069 parsenleft = q - parsenextc - 1;
9081 out2str(parsenextc);
9086 return signed_char2int(*parsenextc++);
9089 #define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer())
9093 return pgetc_as_macro();
9096 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9097 #define pgetc_macro() pgetc()
9099 #define pgetc_macro() pgetc_as_macro()
9103 * Same as pgetc(), but ignores PEOA.
9105 #if ENABLE_ASH_ALIAS
9113 } while (c == PEOA);
9120 return pgetc_macro();
9125 * Read a line from the script.
9128 pfgets(char *line, int len)
9134 while (--nleft > 0) {
9150 * Undo the last call to pgetc. Only one character may be pushed back.
9151 * PEOF may be pushed back.
9161 * Push a string back onto the input at this current parsefile level.
9162 * We handle aliases this way.
9164 #if !ENABLE_ASH_ALIAS
9165 #define pushstring(s, ap) pushstring(s)
9168 pushstring(char *s, struct alias *ap)
9175 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
9176 if (g_parsefile->strpush) {
9177 sp = ckzalloc(sizeof(struct strpush));
9178 sp->prev = g_parsefile->strpush;
9179 g_parsefile->strpush = sp;
9181 sp = g_parsefile->strpush = &(g_parsefile->basestrpush);
9182 sp->prevstring = parsenextc;
9183 sp->prevnleft = parsenleft;
9184 #if ENABLE_ASH_ALIAS
9187 ap->flag |= ALIASINUSE;
9197 * To handle the "." command, a stack of input files is used. Pushfile
9198 * adds a new entry to the stack and popfile restores the previous level.
9203 struct parsefile *pf;
9205 g_parsefile->nleft = parsenleft;
9206 g_parsefile->lleft = parselleft;
9207 g_parsefile->nextc = parsenextc;
9208 g_parsefile->linno = plinno;
9209 pf = ckzalloc(sizeof(*pf));
9210 pf->prev = g_parsefile;
9212 /*pf->strpush = NULL; - ckzalloc did it */
9213 /*pf->basestrpush.prev = NULL;*/
9220 struct parsefile *pf = g_parsefile;
9228 g_parsefile = pf->prev;
9230 parsenleft = g_parsefile->nleft;
9231 parselleft = g_parsefile->lleft;
9232 parsenextc = g_parsefile->nextc;
9233 plinno = g_parsefile->linno;
9238 * Return to top level.
9243 while (g_parsefile != &basepf)
9248 * Close the file(s) that the shell is reading commands from. Called
9249 * after a fork is done.
9255 if (g_parsefile->fd > 0) {
9256 close(g_parsefile->fd);
9257 g_parsefile->fd = 0;
9262 * Like setinputfile, but takes an open file descriptor. Call this with
9266 setinputfd(int fd, int push)
9268 close_on_exec_on(fd);
9271 g_parsefile->buf = 0;
9273 g_parsefile->fd = fd;
9274 if (g_parsefile->buf == NULL)
9275 g_parsefile->buf = ckmalloc(IBUFSIZ);
9276 parselleft = parsenleft = 0;
9281 * Set the input to take input from a file. If push is set, push the
9282 * old input onto the stack first.
9285 setinputfile(const char *fname, int flags)
9291 fd = open(fname, O_RDONLY);
9293 if (flags & INPUT_NOFILE_OK)
9295 ash_msg_and_raise_error("can't open %s", fname);
9298 fd2 = copyfd(fd, 10);
9301 ash_msg_and_raise_error("out of file descriptors");
9304 setinputfd(fd, flags & INPUT_PUSH_FILE);
9311 * Like setinputfile, but takes input from a string.
9314 setinputstring(char *string)
9318 parsenextc = string;
9319 parsenleft = strlen(string);
9320 g_parsefile->buf = NULL;
9326 /* ============ mail.c
9328 * Routines to check for mail.
9333 #define MAXMBOXES 10
9335 /* times of mailboxes */
9336 static time_t mailtime[MAXMBOXES];
9337 /* Set if MAIL or MAILPATH is changed. */
9338 static smallint mail_var_path_changed;
9341 * Print appropriate message(s) if mail has arrived.
9342 * If mail_var_path_changed is set,
9343 * then the value of MAIL has mail_var_path_changed,
9344 * so we just update the values.
9353 struct stackmark smark;
9356 setstackmark(&smark);
9357 mpath = mpathset() ? mpathval() : mailval();
9358 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9359 p = padvance(&mpath, nullstr);
9364 for (q = p; *q; q++)
9370 q[-1] = '\0'; /* delete trailing '/' */
9371 if (stat(p, &statb) < 0) {
9375 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9378 pathopt ? pathopt : "you have mail"
9381 *mtp = statb.st_mtime;
9383 mail_var_path_changed = 0;
9384 popstackmark(&smark);
9388 changemail(const char *val ATTRIBUTE_UNUSED)
9390 mail_var_path_changed = 1;
9393 #endif /* ASH_MAIL */
9396 /* ============ ??? */
9399 * Set the shell parameters.
9402 setparam(char **argv)
9408 for (nparam = 0; argv[nparam]; nparam++)
9410 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9412 *ap++ = ckstrdup(*argv++);
9415 freeparam(&shellparam);
9416 shellparam.malloced = 1;
9417 shellparam.nparam = nparam;
9418 shellparam.p = newparam;
9419 #if ENABLE_ASH_GETOPTS
9420 shellparam.optind = 1;
9421 shellparam.optoff = -1;
9426 * Process shell options. The global variable argptr contains a pointer
9427 * to the argument list; we advance it past the options.
9429 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9430 * For a non-interactive shell, an error condition encountered
9431 * by a special built-in ... shall cause the shell to write a diagnostic message
9432 * to standard error and exit as shown in the following table:
9433 * Error Special Built-In
9435 * Utility syntax error (option or operand error) Shall exit
9437 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9438 * we see that bash does not do that (set "finishes" with error code 1 instead,
9439 * and shell continues), and people rely on this behavior!
9441 * set -o barfoo 2>/dev/null
9444 * Oh well. Let's mimic that.
9447 plus_minus_o(char *name, int val)
9452 for (i = 0; i < NOPTS; i++) {
9453 if (strcmp(name, optnames(i)) == 0) {
9458 ash_msg("illegal option %co %s", val ? '-' : '+', name);
9461 for (i = 0; i < NOPTS; i++) {
9463 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
9465 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
9471 setoption(int flag, int val)
9475 for (i = 0; i < NOPTS; i++) {
9476 if (optletters(i) == flag) {
9481 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
9485 options(int cmdline)
9493 while ((p = *argptr) != NULL) {
9495 if (c != '-' && c != '+')
9498 val = 0; /* val = 0 if c == '+' */
9501 if (p[0] == '\0' || LONE_DASH(p)) {
9503 /* "-" means turn off -x and -v */
9506 /* "--" means reset params */
9507 else if (*argptr == NULL)
9510 break; /* "-" or "--" terminates options */
9513 /* first char was + or - */
9514 while ((c = *p++) != '\0') {
9515 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9516 if (c == 'c' && cmdline) {
9517 minusc = p; /* command is after shell args */
9518 } else if (c == 'o') {
9519 if (plus_minus_o(*argptr, val)) {
9520 /* it already printed err message */
9521 return 1; /* error */
9525 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9527 /* bash does not accept +-login, we also won't */
9528 } else if (cmdline && val && (c == '-')) { /* long options */
9529 if (strcmp(p, "login") == 0)
9541 * The shift builtin command.
9544 shiftcmd(int argc ATTRIBUTE_UNUSED, char **argv)
9551 n = number(argv[1]);
9552 if (n > shellparam.nparam)
9553 n = shellparam.nparam;
9555 shellparam.nparam -= n;
9556 for (ap1 = shellparam.p; --n >= 0; ap1++) {
9557 if (shellparam.malloced)
9561 while ((*ap2++ = *ap1++) != NULL)
9563 #if ENABLE_ASH_GETOPTS
9564 shellparam.optind = 1;
9565 shellparam.optoff = -1;
9572 * POSIX requires that 'set' (but not export or readonly) output the
9573 * variables in lexicographic order - by the locale's collating order (sigh).
9574 * Maybe we could keep them in an ordered balanced binary tree
9575 * instead of hashed lists.
9576 * For now just roll 'em through qsort for printing...
9579 showvars(const char *sep_prefix, int on, int off)
9584 ep = listvars(on, off, &epend);
9585 qsort(ep, epend - ep, sizeof(char *), vpcmp);
9587 sep = *sep_prefix ? " " : sep_prefix;
9589 for (; ep < epend; ep++) {
9593 p = strchrnul(*ep, '=');
9596 q = single_quote(++p);
9597 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9603 * The set command builtin.
9606 setcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
9611 return showvars(nullstr, 0, VUNSET);
9614 if (!options(0)) { /* if no parse error... */
9617 if (*argptr != NULL) {
9625 #if ENABLE_ASH_RANDOM_SUPPORT
9626 /* Roughly copied from bash.. */
9628 change_random(const char *value)
9630 if (value == NULL) {
9631 /* "get", generate */
9634 rseed = rseed * 1103515245 + 12345;
9635 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9636 /* set without recursion */
9637 setvar(vrandom.text, buf, VNOFUNC);
9638 vrandom.flags &= ~VNOFUNC;
9641 rseed = strtoul(value, (char **)NULL, 10);
9646 #if ENABLE_ASH_GETOPTS
9648 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9657 if (*param_optind < 1)
9659 optnext = optfirst + *param_optind - 1;
9661 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
9664 p = optnext[-1] + *optoff;
9665 if (p == NULL || *p == '\0') {
9666 /* Current word is done, advance */
9668 if (p == NULL || *p != '-' || *++p == '\0') {
9675 if (LONE_DASH(p)) /* check for "--" */
9680 for (q = optstr; *q != c; ) {
9682 if (optstr[0] == ':') {
9685 err |= setvarsafe("OPTARG", s, 0);
9687 fprintf(stderr, "Illegal option -%c\n", c);
9698 if (*p == '\0' && (p = *optnext) == NULL) {
9699 if (optstr[0] == ':') {
9702 err |= setvarsafe("OPTARG", s, 0);
9705 fprintf(stderr, "No arg for -%c option\n", c);
9714 err |= setvarsafe("OPTARG", p, 0);
9717 err |= setvarsafe("OPTARG", nullstr, 0);
9719 *optoff = p ? p - *(optnext - 1) : -1;
9720 *param_optind = optnext - optfirst + 1;
9721 fmtstr(s, sizeof(s), "%d", *param_optind);
9722 err |= setvarsafe("OPTIND", s, VNOFUNC);
9725 err |= setvarsafe(optvar, s, 0);
9729 flush_stdout_stderr();
9730 raise_exception(EXERROR);
9736 * The getopts builtin. Shellparam.optnext points to the next argument
9737 * to be processed. Shellparam.optptr points to the next character to
9738 * be processed in the current argument. If shellparam.optnext is NULL,
9739 * then it's the first time getopts has been called.
9742 getoptscmd(int argc, char **argv)
9747 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
9749 optbase = shellparam.p;
9750 if (shellparam.optind > shellparam.nparam + 1) {
9751 shellparam.optind = 1;
9752 shellparam.optoff = -1;
9756 if (shellparam.optind > argc - 2) {
9757 shellparam.optind = 1;
9758 shellparam.optoff = -1;
9762 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9763 &shellparam.optoff);
9765 #endif /* ASH_GETOPTS */
9768 /* ============ Shell parser */
9771 struct heredoc *next; /* next here document in list */
9772 union node *here; /* redirection node */
9773 char *eofmark; /* string indicating end of input */
9774 smallint striptabs; /* if set, strip leading tabs */
9777 static smallint tokpushback; /* last token pushed back */
9778 static smallint parsebackquote; /* nonzero if we are inside backquotes */
9779 static smallint quoteflag; /* set if (part of) last token was quoted */
9780 static token_id_t lasttoken; /* last token read (integer id Txxx) */
9781 static struct heredoc *heredoclist; /* list of here documents to read */
9782 static char *wordtext; /* text of last word returned by readtoken */
9783 static struct nodelist *backquotelist;
9784 static union node *redirnode;
9785 static struct heredoc *heredoc;
9787 * NEOF is returned by parsecmd when it encounters an end of file. It
9788 * must be distinct from NULL, so we use the address of a variable that
9789 * happens to be handy.
9791 #define NEOF ((union node *)&tokpushback)
9793 static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN;
9795 raise_error_syntax(const char *msg)
9797 ash_msg_and_raise_error("syntax error: %s", msg);
9802 * Called when an unexpected token is read during the parse. The argument
9803 * is the token that is expected, or -1 if more than one type of token can
9804 * occur at this point.
9806 static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN;
9808 raise_error_unexpected_syntax(int token)
9813 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
9815 sprintf(msg + l, " (expecting %s)", tokname(token));
9816 raise_error_syntax(msg);
9820 #define EOFMARKLEN 79
9822 /* parsing is heavily cross-recursive, need these forward decls */
9823 static union node *andor(void);
9824 static union node *pipeline(void);
9825 static union node *parse_command(void);
9826 static void parseheredoc(void);
9827 static char peektoken(void);
9828 static int readtoken(void);
9833 union node *n1, *n2, *n3;
9836 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9837 if (nlflag == 2 && peektoken())
9843 if (tok == TBACKGND) {
9844 if (n2->type == NPIPE) {
9845 n2->npipe.backgnd = 1;
9847 if (n2->type != NREDIR) {
9848 n3 = stzalloc(sizeof(struct nredir));
9850 /*n3->nredir.redirect = NULL; - stzalloc did it */
9853 n2->type = NBACKGND;
9859 n3 = stzalloc(sizeof(struct nbinary));
9861 n3->nbinary.ch1 = n1;
9862 n3->nbinary.ch2 = n2;
9878 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9886 pungetc(); /* push back EOF on input */
9890 raise_error_unexpected_syntax(-1);
9900 union node *n1, *n2, *n3;
9908 } else if (t == TOR) {
9914 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9916 n3 = stzalloc(sizeof(struct nbinary));
9918 n3->nbinary.ch1 = n1;
9919 n3->nbinary.ch2 = n2;
9927 union node *n1, *n2, *pipenode;
9928 struct nodelist *lp, *prev;
9932 TRACE(("pipeline: entered\n"));
9933 if (readtoken() == TNOT) {
9935 checkkwd = CHKKWD | CHKALIAS;
9938 n1 = parse_command();
9939 if (readtoken() == TPIPE) {
9940 pipenode = stzalloc(sizeof(struct npipe));
9941 pipenode->type = NPIPE;
9942 /*pipenode->npipe.backgnd = 0; - stzalloc did it */
9943 lp = stzalloc(sizeof(struct nodelist));
9944 pipenode->npipe.cmdlist = lp;
9948 lp = stzalloc(sizeof(struct nodelist));
9949 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9950 lp->n = parse_command();
9952 } while (readtoken() == TPIPE);
9958 n2 = stzalloc(sizeof(struct nnot));
9971 n = stzalloc(sizeof(struct narg));
9973 /*n->narg.next = NULL; - stzalloc did it */
9974 n->narg.text = wordtext;
9975 n->narg.backquote = backquotelist;
9980 fixredir(union node *n, const char *text, int err)
9982 TRACE(("Fix redir %s %d\n", text, err));
9984 n->ndup.vname = NULL;
9986 if (isdigit(text[0]) && text[1] == '\0')
9987 n->ndup.dupfd = text[0] - '0';
9988 else if (LONE_DASH(text))
9992 raise_error_syntax("Bad fd number");
9993 n->ndup.vname = makename();
9998 * Returns true if the text contains nothing to expand (no dollar signs
10002 noexpand(char *text)
10008 while ((c = *p++) != '\0') {
10009 if (c == CTLQUOTEMARK)
10013 else if (SIT(c, BASESYNTAX) == CCTL)
10022 union node *n = redirnode;
10024 if (readtoken() != TWORD)
10025 raise_error_unexpected_syntax(-1);
10026 if (n->type == NHERE) {
10027 struct heredoc *here = heredoc;
10031 if (quoteflag == 0)
10033 TRACE(("Here document %d\n", n->type));
10034 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10035 raise_error_syntax("Illegal eof marker for << redirection");
10036 rmescapes(wordtext);
10037 here->eofmark = wordtext;
10039 if (heredoclist == NULL)
10040 heredoclist = here;
10042 for (p = heredoclist; p->next; p = p->next)
10046 } else if (n->type == NTOFD || n->type == NFROMFD) {
10047 fixredir(n, wordtext, 0);
10049 n->nfile.fname = makename();
10053 static union node *
10056 union node *args, **app;
10057 union node *n = NULL;
10058 union node *vars, **vpp;
10059 union node **rpp, *redir;
10061 #if ENABLE_ASH_BASH_COMPAT
10062 smallint double_brackets_flag = 0;
10072 savecheckkwd = CHKALIAS;
10075 checkkwd = savecheckkwd;
10078 #if ENABLE_ASH_BASH_COMPAT
10079 case TAND: /* "&&" */
10080 case TOR: /* "||" */
10081 if (!double_brackets_flag) {
10085 wordtext = (char *) (t == TAND ? "-a" : "-o");
10088 n = stzalloc(sizeof(struct narg));
10090 /*n->narg.next = NULL; - stzalloc did it */
10091 n->narg.text = wordtext;
10092 #if ENABLE_ASH_BASH_COMPAT
10093 if (strcmp("[[", wordtext) == 0)
10094 double_brackets_flag = 1;
10095 else if (strcmp("]]", wordtext) == 0)
10096 double_brackets_flag = 0;
10098 n->narg.backquote = backquotelist;
10099 if (savecheckkwd && isassignment(wordtext)) {
10101 vpp = &n->narg.next;
10104 app = &n->narg.next;
10109 *rpp = n = redirnode;
10110 rpp = &n->nfile.next;
10111 parsefname(); /* read name of redirection file */
10114 if (args && app == &args->narg.next
10117 struct builtincmd *bcmd;
10120 /* We have a function */
10121 if (readtoken() != TRP)
10122 raise_error_unexpected_syntax(TRP);
10123 name = n->narg.text;
10124 if (!goodname(name)
10125 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10127 raise_error_syntax("Bad function name");
10130 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10131 n->narg.next = parse_command();
10144 n = stzalloc(sizeof(struct ncmd));
10146 n->ncmd.args = args;
10147 n->ncmd.assign = vars;
10148 n->ncmd.redirect = redir;
10152 static union node *
10153 parse_command(void)
10155 union node *n1, *n2;
10156 union node *ap, **app;
10157 union node *cp, **cpp;
10158 union node *redir, **rpp;
10165 switch (readtoken()) {
10167 raise_error_unexpected_syntax(-1);
10170 n1 = stzalloc(sizeof(struct nif));
10172 n1->nif.test = list(0);
10173 if (readtoken() != TTHEN)
10174 raise_error_unexpected_syntax(TTHEN);
10175 n1->nif.ifpart = list(0);
10177 while (readtoken() == TELIF) {
10178 n2->nif.elsepart = stzalloc(sizeof(struct nif));
10179 n2 = n2->nif.elsepart;
10181 n2->nif.test = list(0);
10182 if (readtoken() != TTHEN)
10183 raise_error_unexpected_syntax(TTHEN);
10184 n2->nif.ifpart = list(0);
10186 if (lasttoken == TELSE)
10187 n2->nif.elsepart = list(0);
10189 n2->nif.elsepart = NULL;
10197 n1 = stzalloc(sizeof(struct nbinary));
10198 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10199 n1->nbinary.ch1 = list(0);
10202 TRACE(("expecting DO got %s %s\n", tokname(got),
10203 got == TWORD ? wordtext : ""));
10204 raise_error_unexpected_syntax(TDO);
10206 n1->nbinary.ch2 = list(0);
10211 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
10212 raise_error_syntax("Bad for loop variable");
10213 n1 = stzalloc(sizeof(struct nfor));
10215 n1->nfor.var = wordtext;
10216 checkkwd = CHKKWD | CHKALIAS;
10217 if (readtoken() == TIN) {
10219 while (readtoken() == TWORD) {
10220 n2 = stzalloc(sizeof(struct narg));
10222 /*n2->narg.next = NULL; - stzalloc did it */
10223 n2->narg.text = wordtext;
10224 n2->narg.backquote = backquotelist;
10226 app = &n2->narg.next;
10229 n1->nfor.args = ap;
10230 if (lasttoken != TNL && lasttoken != TSEMI)
10231 raise_error_unexpected_syntax(-1);
10233 n2 = stzalloc(sizeof(struct narg));
10235 /*n2->narg.next = NULL; - stzalloc did it */
10236 n2->narg.text = (char *)dolatstr;
10237 /*n2->narg.backquote = NULL;*/
10238 n1->nfor.args = n2;
10240 * Newline or semicolon here is optional (but note
10241 * that the original Bourne shell only allowed NL).
10243 if (lasttoken != TNL && lasttoken != TSEMI)
10246 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10247 if (readtoken() != TDO)
10248 raise_error_unexpected_syntax(TDO);
10249 n1->nfor.body = list(0);
10253 n1 = stzalloc(sizeof(struct ncase));
10255 if (readtoken() != TWORD)
10256 raise_error_unexpected_syntax(TWORD);
10257 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10259 /*n2->narg.next = NULL; - stzalloc did it */
10260 n2->narg.text = wordtext;
10261 n2->narg.backquote = backquotelist;
10263 checkkwd = CHKKWD | CHKALIAS;
10264 } while (readtoken() == TNL);
10265 if (lasttoken != TIN)
10266 raise_error_unexpected_syntax(TIN);
10267 cpp = &n1->ncase.cases;
10269 checkkwd = CHKNL | CHKKWD;
10271 while (t != TESAC) {
10272 if (lasttoken == TLP)
10274 *cpp = cp = stzalloc(sizeof(struct nclist));
10276 app = &cp->nclist.pattern;
10278 *app = ap = stzalloc(sizeof(struct narg));
10280 /*ap->narg.next = NULL; - stzalloc did it */
10281 ap->narg.text = wordtext;
10282 ap->narg.backquote = backquotelist;
10283 if (readtoken() != TPIPE)
10285 app = &ap->narg.next;
10288 //ap->narg.next = NULL;
10289 if (lasttoken != TRP)
10290 raise_error_unexpected_syntax(TRP);
10291 cp->nclist.body = list(2);
10293 cpp = &cp->nclist.next;
10295 checkkwd = CHKNL | CHKKWD;
10299 raise_error_unexpected_syntax(TENDCASE);
10306 n1 = stzalloc(sizeof(struct nredir));
10307 n1->type = NSUBSHELL;
10308 n1->nredir.n = list(0);
10309 /*n1->nredir.redirect = NULL; - stzalloc did it */
10319 return simplecmd();
10322 if (readtoken() != t)
10323 raise_error_unexpected_syntax(t);
10326 /* Now check for redirection which may follow command */
10327 checkkwd = CHKKWD | CHKALIAS;
10329 while (readtoken() == TREDIR) {
10330 *rpp = n2 = redirnode;
10331 rpp = &n2->nfile.next;
10337 if (n1->type != NSUBSHELL) {
10338 n2 = stzalloc(sizeof(struct nredir));
10343 n1->nredir.redirect = redir;
10348 #if ENABLE_ASH_BASH_COMPAT
10349 static int decode_dollar_squote(void)
10351 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
10357 p = strchr(C_escapes, c);
10362 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
10366 } while ((unsigned char)(c - '0') <= 7 && --cnt);
10368 } else if (c == 'x') { /* \xHH */
10372 } while (isxdigit(c) && --cnt);
10374 if (cnt == 3) { /* \x but next char is "bad" */
10378 } else { /* simple seq like \\ or \t */
10383 c = bb_process_escape_sequence((void*)&p);
10384 } else { /* unrecognized "\z": print both chars unless ' or " */
10385 if (c != '\'' && c != '"') {
10387 c |= 0x100; /* "please encode \, then me" */
10395 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10396 * is not NULL, read a here document. In the latter case, eofmark is the
10397 * word which marks the end of the document and striptabs is true if
10398 * leading tabs should be stripped from the document. The argument firstc
10399 * is the first character of the input token or document.
10401 * Because C does not have internal subroutines, I have simulated them
10402 * using goto's to implement the subroutine linkage. The following macros
10403 * will run code that appears at the end of readtoken1.
10405 #define CHECKEND() {goto checkend; checkend_return:;}
10406 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10407 #define PARSESUB() {goto parsesub; parsesub_return:;}
10408 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10409 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10410 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10412 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10414 /* NB: syntax parameter fits into smallint */
10418 char line[EOFMARKLEN + 1];
10419 struct nodelist *bqlist;
10423 smallint prevsyntax; /* syntax before arithmetic */
10424 #if ENABLE_ASH_EXPAND_PRMT
10425 smallint pssyntax; /* we are expanding a prompt string */
10427 int varnest; /* levels of variables expansion */
10428 int arinest; /* levels of arithmetic expansion */
10429 int parenlevel; /* levels of parens in arithmetic */
10430 int dqvarnest; /* levels of variables expansion within double quotes */
10432 USE_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
10435 /* Avoid longjmp clobbering */
10441 (void) &parenlevel;
10444 (void) &prevsyntax;
10447 startlinno = plinno;
10452 #if ENABLE_ASH_EXPAND_PRMT
10453 pssyntax = (syntax == PSSYNTAX);
10457 dblquote = (syntax == DQSYNTAX);
10463 STARTSTACKSTR(out);
10464 loop: { /* for each line, until end of word */
10465 CHECKEND(); /* set c to PEOF if at end of here document */
10466 for (;;) { /* until end of line or end of word */
10467 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10468 switch (SIT(c, syntax)) {
10469 case CNL: /* '\n' */
10470 if (syntax == BASESYNTAX)
10471 goto endword; /* exit outer loop */
10477 goto loop; /* continue outer loop */
10482 if (eofmark == NULL || dblquote)
10483 USTPUTC(CTLESC, out);
10484 #if ENABLE_ASH_BASH_COMPAT
10485 if (c == '\\' && bash_dollar_squote) {
10486 c = decode_dollar_squote();
10488 USTPUTC('\\', out);
10489 c = (unsigned char)c;
10495 case CBACK: /* backslash */
10498 USTPUTC(CTLESC, out);
10499 USTPUTC('\\', out);
10501 } else if (c == '\n') {
10505 #if ENABLE_ASH_EXPAND_PRMT
10506 if (c == '$' && pssyntax) {
10507 USTPUTC(CTLESC, out);
10508 USTPUTC('\\', out);
10511 if (dblquote && c != '\\'
10512 && c != '`' && c != '$'
10513 && (c != '"' || eofmark != NULL)
10515 USTPUTC(CTLESC, out);
10516 USTPUTC('\\', out);
10518 if (SIT(c, SQSYNTAX) == CCTL)
10519 USTPUTC(CTLESC, out);
10527 if (eofmark == NULL) {
10528 USTPUTC(CTLQUOTEMARK, out);
10536 USE_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
10537 if (eofmark != NULL && arinest == 0
10542 if (dqvarnest == 0) {
10543 syntax = BASESYNTAX;
10550 case CVAR: /* '$' */
10551 PARSESUB(); /* parse substitution */
10553 case CENDVAR: /* '}' */
10556 if (dqvarnest > 0) {
10559 USTPUTC(CTLENDVAR, out);
10564 #if ENABLE_ASH_MATH_SUPPORT
10565 case CLP: /* '(' in arithmetic */
10569 case CRP: /* ')' in arithmetic */
10570 if (parenlevel > 0) {
10574 if (pgetc() == ')') {
10575 if (--arinest == 0) {
10576 USTPUTC(CTLENDARI, out);
10577 syntax = prevsyntax;
10578 dblquote = (syntax == DQSYNTAX);
10583 * unbalanced parens
10584 * (don't 2nd guess - no error)
10592 case CBQUOTE: /* '`' */
10596 goto endword; /* exit outer loop */
10601 goto endword; /* exit outer loop */
10602 #if ENABLE_ASH_ALIAS
10612 #if ENABLE_ASH_MATH_SUPPORT
10613 if (syntax == ARISYNTAX)
10614 raise_error_syntax("Missing '))'");
10616 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10617 raise_error_syntax("Unterminated quoted string");
10618 if (varnest != 0) {
10619 startlinno = plinno;
10621 raise_error_syntax("Missing '}'");
10623 USTPUTC('\0', out);
10624 len = out - (char *)stackblock();
10625 out = stackblock();
10626 if (eofmark == NULL) {
10627 if ((c == '>' || c == '<')
10630 && (*out == '\0' || isdigit(*out))
10633 lasttoken = TREDIR;
10638 quoteflag = quotef;
10639 backquotelist = bqlist;
10640 grabstackblock(len);
10644 /* end of readtoken routine */
10647 * Check to see whether we are at the end of the here document. When this
10648 * is called, c is set to the first character of the next input line. If
10649 * we are at the end of the here document, this routine sets the c to PEOF.
10653 #if ENABLE_ASH_ALIAS
10659 while (c == '\t') {
10663 if (c == *eofmark) {
10664 if (pfgets(line, sizeof(line)) != NULL) {
10668 for (q = eofmark + 1; *q && *p == *q; p++, q++)
10670 if (*p == '\n' && *q == '\0') {
10673 needprompt = doprompt;
10675 pushstring(line, NULL);
10680 goto checkend_return;
10684 * Parse a redirection operator. The variable "out" points to a string
10685 * specifying the fd to be redirected. The variable "c" contains the
10686 * first character of the redirection operator.
10692 np = stzalloc(sizeof(struct nfile));
10697 np->type = NAPPEND;
10699 np->type = NCLOBBER;
10706 } else { /* c == '<' */
10707 /*np->nfile.fd = 0; - stzalloc did it */
10711 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10712 np = stzalloc(sizeof(struct nhere));
10713 /*np->nfile.fd = 0; - stzalloc did it */
10716 heredoc = stzalloc(sizeof(struct heredoc));
10717 heredoc->here = np;
10720 heredoc->striptabs = 1;
10722 /*heredoc->striptabs = 0; - stzalloc did it */
10728 np->type = NFROMFD;
10732 np->type = NFROMTO;
10742 np->nfile.fd = fd - '0';
10744 goto parseredir_return;
10748 * Parse a substitution. At this point, we have read the dollar sign
10749 * and nothing else.
10752 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
10753 * (assuming ascii char codes, as the original implementation did) */
10754 #define is_special(c) \
10755 (((unsigned)(c) - 33 < 32) \
10756 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
10762 static const char types[] ALIGN1 = "}-+?=";
10765 if (c <= PEOA_OR_PEOF
10766 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10768 #if ENABLE_ASH_BASH_COMPAT
10770 bash_dollar_squote = 1;
10775 } else if (c == '(') { /* $(command) or $((arith)) */
10776 if (pgetc() == '(') {
10777 #if ENABLE_ASH_MATH_SUPPORT
10780 raise_error_syntax("you disabled math support for $((arith)) syntax");
10787 USTPUTC(CTLVAR, out);
10788 typeloc = out - (char *)stackblock();
10789 USTPUTC(VSNORMAL, out);
10790 subtype = VSNORMAL;
10798 subtype = VSLENGTH;
10802 if (c > PEOA_OR_PEOF && is_name(c)) {
10806 } while (c > PEOA_OR_PEOF && is_in_name(c));
10807 } else if (isdigit(c)) {
10811 } while (isdigit(c));
10812 } else if (is_special(c)) {
10816 badsub: raise_error_syntax("Bad substitution");
10820 if (subtype == 0) {
10824 #if ENABLE_ASH_BASH_COMPAT
10825 if (c == ':' || c == '$' || isdigit(c)) {
10827 subtype = VSSUBSTR;
10834 p = strchr(types, c);
10837 subtype = p - types + VSNORMAL;
10842 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
10850 #if ENABLE_ASH_BASH_COMPAT
10852 subtype = VSREPLACE;
10855 subtype++; /* VSREPLACEALL */
10864 if (dblquote || arinest)
10866 *((char *)stackblock() + typeloc) = subtype | flags;
10867 if (subtype != VSNORMAL) {
10869 if (dblquote || arinest) {
10874 goto parsesub_return;
10878 * Called to parse command substitutions. Newstyle is set if the command
10879 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10880 * list of commands (passed by reference), and savelen is the number of
10881 * characters on the top of the stack which must be preserved.
10884 struct nodelist **nlpp;
10887 char *volatile str;
10888 struct jmploc jmploc;
10889 struct jmploc *volatile savehandler;
10891 smallint saveprompt = 0;
10894 (void) &saveprompt;
10896 savepbq = parsebackquote;
10897 if (setjmp(jmploc.loc)) {
10899 parsebackquote = 0;
10900 exception_handler = savehandler;
10901 longjmp(exception_handler->loc, 1);
10905 savelen = out - (char *)stackblock();
10907 str = ckmalloc(savelen);
10908 memcpy(str, stackblock(), savelen);
10910 savehandler = exception_handler;
10911 exception_handler = &jmploc;
10914 /* We must read until the closing backquote, giving special
10915 treatment to some slashes, and then push the string and
10916 reread it as input, interpreting it normally. */
10923 STARTSTACKSTR(pout);
10940 * If eating a newline, avoid putting
10941 * the newline into the new character
10942 * stream (via the STPUTC after the
10947 if (pc != '\\' && pc != '`' && pc != '$'
10948 && (!dblquote || pc != '"'))
10949 STPUTC('\\', pout);
10950 if (pc > PEOA_OR_PEOF) {
10956 #if ENABLE_ASH_ALIAS
10959 startlinno = plinno;
10960 raise_error_syntax("EOF in backquote substitution");
10964 needprompt = doprompt;
10973 STPUTC('\0', pout);
10974 psavelen = pout - (char *)stackblock();
10975 if (psavelen > 0) {
10976 pstr = grabstackstr(pout);
10977 setinputstring(pstr);
10982 nlpp = &(*nlpp)->next;
10983 *nlpp = stzalloc(sizeof(**nlpp));
10984 /* (*nlpp)->next = NULL; - stzalloc did it */
10985 parsebackquote = oldstyle;
10988 saveprompt = doprompt;
10995 doprompt = saveprompt;
10996 else if (readtoken() != TRP)
10997 raise_error_unexpected_syntax(TRP);
11002 * Start reading from old file again, ignoring any pushed back
11003 * tokens left from the backquote parsing
11008 while (stackblocksize() <= savelen)
11010 STARTSTACKSTR(out);
11012 memcpy(out, str, savelen);
11013 STADJUST(savelen, out);
11019 parsebackquote = savepbq;
11020 exception_handler = savehandler;
11021 if (arinest || dblquote)
11022 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11024 USTPUTC(CTLBACKQ, out);
11026 goto parsebackq_oldreturn;
11027 goto parsebackq_newreturn;
11030 #if ENABLE_ASH_MATH_SUPPORT
11032 * Parse an arithmetic expansion (indicate start of one and set state)
11035 if (++arinest == 1) {
11036 prevsyntax = syntax;
11037 syntax = ARISYNTAX;
11038 USTPUTC(CTLARI, out);
11045 * we collapse embedded arithmetic expansion to
11046 * parenthesis, which should be equivalent
11050 goto parsearith_return;
11054 } /* end of readtoken */
11057 * Read the next input token.
11058 * If the token is a word, we set backquotelist to the list of cmds in
11059 * backquotes. We set quoteflag to true if any part of the word was
11061 * If the token is TREDIR, then we set redirnode to a structure containing
11063 * In all cases, the variable startlinno is set to the number of the line
11064 * on which the token starts.
11066 * [Change comment: here documents and internal procedures]
11067 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11068 * word parsing code into a separate routine. In this case, readtoken
11069 * doesn't need to have any internal procedures, but parseword does.
11070 * We could also make parseoperator in essence the main routine, and
11071 * have parseword (readtoken1?) handle both words and redirection.]
11073 #define NEW_xxreadtoken
11074 #ifdef NEW_xxreadtoken
11075 /* singles must be first! */
11076 static const char xxreadtoken_chars[7] ALIGN1 = {
11077 '\n', '(', ')', '&', '|', ';', 0
11080 static const char xxreadtoken_tokens[] ALIGN1 = {
11081 TNL, TLP, TRP, /* only single occurrence allowed */
11082 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11083 TEOF, /* corresponds to trailing nul */
11084 TAND, TOR, TENDCASE /* if double occurrence */
11087 #define xxreadtoken_doubles \
11088 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
11089 #define xxreadtoken_singles \
11090 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
11104 startlinno = plinno;
11105 for (;;) { /* until token or start of word found */
11108 if ((c != ' ') && (c != '\t')
11109 #if ENABLE_ASH_ALIAS
11114 while ((c = pgetc()) != '\n' && c != PEOF)
11117 } else if (c == '\\') {
11118 if (pgetc() != '\n') {
11122 startlinno = ++plinno;
11127 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11132 needprompt = doprompt;
11135 p = strchr(xxreadtoken_chars, c);
11138 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11141 if ((size_t)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11142 if (pgetc() == *p) { /* double occurrence? */
11143 p += xxreadtoken_doubles + 1;
11149 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11156 #define RETURN(token) return lasttoken = token
11169 startlinno = plinno;
11170 for (;;) { /* until token or start of word found */
11173 case ' ': case '\t':
11174 #if ENABLE_ASH_ALIAS
11179 while ((c = pgetc()) != '\n' && c != PEOF)
11184 if (pgetc() == '\n') {
11185 startlinno = ++plinno;
11194 needprompt = doprompt;
11199 if (pgetc() == '&')
11204 if (pgetc() == '|')
11209 if (pgetc() == ';')
11222 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11225 #endif /* NEW_xxreadtoken */
11232 smallint alreadyseen = tokpushback;
11235 #if ENABLE_ASH_ALIAS
11244 if (checkkwd & CHKNL) {
11251 if (t != TWORD || quoteflag) {
11256 * check for keywords
11258 if (checkkwd & CHKKWD) {
11259 const char *const *pp;
11261 pp = findkwd(wordtext);
11263 lasttoken = t = pp - tokname_array;
11264 TRACE(("keyword %s recognized\n", tokname(t)));
11269 if (checkkwd & CHKALIAS) {
11270 #if ENABLE_ASH_ALIAS
11272 ap = lookupalias(wordtext, 1);
11275 pushstring(ap->val, ap);
11285 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11287 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11299 return tokname_array[t][0];
11303 * Read and parse a command. Returns NEOF on end of file. (NULL is a
11304 * valid parse tree indicating a blank line.)
11306 static union node *
11307 parsecmd(int interact)
11312 doprompt = interact;
11314 setprompt(doprompt);
11326 * Input any here documents.
11331 struct heredoc *here;
11334 here = heredoclist;
11335 heredoclist = NULL;
11341 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
11342 here->eofmark, here->striptabs);
11343 n = stzalloc(sizeof(struct narg));
11344 n->narg.type = NARG;
11345 /*n->narg.next = NULL; - stzalloc did it */
11346 n->narg.text = wordtext;
11347 n->narg.backquote = backquotelist;
11348 here->here->nhere.doc = n;
11355 * called by editline -- any expansions to the prompt should be added here.
11357 #if ENABLE_ASH_EXPAND_PRMT
11358 static const char *
11359 expandstr(const char *ps)
11363 /* XXX Fix (char *) cast. */
11364 setinputstring((char *)ps);
11365 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
11368 n.narg.type = NARG;
11369 n.narg.next = NULL;
11370 n.narg.text = wordtext;
11371 n.narg.backquote = backquotelist;
11373 expandarg(&n, NULL, 0);
11374 return stackblock();
11379 * Execute a command or commands contained in a string.
11382 evalstring(char *s, int mask)
11385 struct stackmark smark;
11389 setstackmark(&smark);
11392 while ((n = parsecmd(0)) != NEOF) {
11394 popstackmark(&smark);
11407 * The eval command.
11410 evalcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11419 STARTSTACKSTR(concat);
11421 concat = stack_putstr(p, concat);
11425 STPUTC(' ', concat);
11427 STPUTC('\0', concat);
11428 p = grabstackstr(concat);
11430 evalstring(p, ~SKIPEVAL);
11437 * Read and execute commands. "Top" is nonzero for the top level command
11438 * loop; it turns on prompting if the shell is interactive.
11444 struct stackmark smark;
11448 TRACE(("cmdloop(%d) called\n", top));
11452 setstackmark(&smark);
11455 showjobs(stderr, SHOW_CHANGED);
11458 if (iflag && top) {
11460 #if ENABLE_ASH_MAIL
11464 n = parsecmd(inter);
11465 /* showtree(n); DEBUG */
11467 if (!top || numeof >= 50)
11469 if (!stoppedjobs()) {
11472 out2str("\nUse \"exit\" to leave shell.\n");
11475 } else if (nflag == 0) {
11476 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11481 popstackmark(&smark);
11486 return skip & SKIPEVAL;
11493 * Take commands from a file. To be compatible we should do a path
11494 * search for the file, which is necessary to find sub-commands.
11497 find_dot_file(char *name)
11500 const char *path = pathval();
11503 /* don't try this for absolute or relative paths */
11504 if (strchr(name, '/'))
11507 while ((fullname = padvance(&path, name)) != NULL) {
11508 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11510 * Don't bother freeing here, since it will
11511 * be freed by the caller.
11515 stunalloc(fullname);
11518 /* not found in the PATH */
11519 ash_msg_and_raise_error("%s: not found", name);
11524 dotcmd(int argc, char **argv)
11526 struct strlist *sp;
11527 volatile struct shparam saveparam;
11530 for (sp = cmdenviron; sp; sp = sp->next)
11531 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11533 if (argv[1]) { /* That's what SVR2 does */
11534 char *fullname = find_dot_file(argv[1]);
11537 if (argc) { /* argc > 0, argv[0] != NULL */
11538 saveparam = shellparam;
11539 shellparam.malloced = 0;
11540 shellparam.nparam = argc;
11541 shellparam.p = argv;
11544 setinputfile(fullname, INPUT_PUSH_FILE);
11545 commandname = fullname;
11550 freeparam(&shellparam);
11551 shellparam = saveparam;
11553 status = exitstatus;
11559 exitcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11564 exitstatus = number(argv[1]);
11565 raise_exception(EXEXIT);
11570 * Read a file containing shell functions.
11573 readcmdfile(char *name)
11575 setinputfile(name, INPUT_PUSH_FILE);
11581 /* ============ find_command inplementation */
11584 * Resolve a command name. If you change this routine, you may have to
11585 * change the shellexec routine as well.
11588 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11590 struct tblentry *cmdp;
11597 struct builtincmd *bcmd;
11599 /* If name contains a slash, don't use PATH or hash table */
11600 if (strchr(name, '/') != NULL) {
11601 entry->u.index = -1;
11602 if (act & DO_ABS) {
11603 while (stat(name, &statb) < 0) {
11605 if (errno == EINTR)
11608 entry->cmdtype = CMDUNKNOWN;
11612 entry->cmdtype = CMDNORMAL;
11616 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11618 updatetbl = (path == pathval());
11621 if (strstr(path, "%builtin") != NULL)
11622 act |= DO_ALTBLTIN;
11625 /* If name is in the table, check answer will be ok */
11626 cmdp = cmdlookup(name, 0);
11627 if (cmdp != NULL) {
11630 switch (cmdp->cmdtype) {
11648 } else if (cmdp->rehash == 0)
11649 /* if not invalidated by cd, we're done */
11653 /* If %builtin not in path, check for builtin next */
11654 bcmd = find_builtin(name);
11656 if (IS_BUILTIN_REGULAR(bcmd))
11657 goto builtin_success;
11658 if (act & DO_ALTPATH) {
11659 if (!(act & DO_ALTBLTIN))
11660 goto builtin_success;
11661 } else if (builtinloc <= 0) {
11662 goto builtin_success;
11666 #if ENABLE_FEATURE_SH_STANDALONE
11668 int applet_no = find_applet_by_name(name);
11669 if (applet_no >= 0) {
11670 entry->cmdtype = CMDNORMAL;
11671 entry->u.index = -2 - applet_no;
11677 /* We have to search path. */
11678 prev = -1; /* where to start */
11679 if (cmdp && cmdp->rehash) { /* doing a rehash */
11680 if (cmdp->cmdtype == CMDBUILTIN)
11683 prev = cmdp->param.index;
11689 while ((fullname = padvance(&path, name)) != NULL) {
11690 stunalloc(fullname);
11691 /* NB: code below will still use fullname
11692 * despite it being "unallocated" */
11695 if (prefix(pathopt, "builtin")) {
11697 goto builtin_success;
11700 if ((act & DO_NOFUNC)
11701 || !prefix(pathopt, "func")
11702 ) { /* ignore unimplemented options */
11706 /* if rehash, don't redo absolute path names */
11707 if (fullname[0] == '/' && idx <= prev) {
11710 TRACE(("searchexec \"%s\": no change\n", name));
11713 while (stat(fullname, &statb) < 0) {
11715 if (errno == EINTR)
11718 if (errno != ENOENT && errno != ENOTDIR)
11722 e = EACCES; /* if we fail, this will be the error */
11723 if (!S_ISREG(statb.st_mode))
11725 if (pathopt) { /* this is a %func directory */
11726 stalloc(strlen(fullname) + 1);
11727 /* NB: stalloc will return space pointed by fullname
11728 * (because we don't have any intervening allocations
11729 * between stunalloc above and this stalloc) */
11730 readcmdfile(fullname);
11731 cmdp = cmdlookup(name, 0);
11732 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
11733 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
11734 stunalloc(fullname);
11737 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
11739 entry->cmdtype = CMDNORMAL;
11740 entry->u.index = idx;
11744 cmdp = cmdlookup(name, 1);
11745 cmdp->cmdtype = CMDNORMAL;
11746 cmdp->param.index = idx;
11751 /* We failed. If there was an entry for this command, delete it */
11752 if (cmdp && updatetbl)
11753 delete_cmd_entry();
11755 ash_msg("%s: %s", name, errmsg(e, "not found"));
11756 entry->cmdtype = CMDUNKNOWN;
11761 entry->cmdtype = CMDBUILTIN;
11762 entry->u.cmd = bcmd;
11766 cmdp = cmdlookup(name, 1);
11767 cmdp->cmdtype = CMDBUILTIN;
11768 cmdp->param.cmd = bcmd;
11772 entry->cmdtype = cmdp->cmdtype;
11773 entry->u = cmdp->param;
11777 /* ============ trap.c */
11780 * The trap builtin.
11783 trapcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11792 for (signo = 0; signo < NSIG; signo++) {
11793 if (trap[signo] != NULL) {
11796 sn = get_signame(signo);
11797 out1fmt("trap -- %s %s\n",
11798 single_quote(trap[signo]), sn);
11808 signo = get_signum(*ap);
11810 ash_msg_and_raise_error("%s: bad trap", *ap);
11813 if (LONE_DASH(action))
11816 action = ckstrdup(action);
11819 trap[signo] = action;
11829 /* ============ Builtins */
11831 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
11833 * Lists available builtins
11836 helpcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11841 out1fmt("\nBuilt-in commands:\n-------------------\n");
11842 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
11843 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11844 builtintab[i].name + 1);
11850 #if ENABLE_FEATURE_SH_STANDALONE
11852 const char *a = applet_names;
11854 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
11859 a += strlen(a) + 1;
11864 return EXIT_SUCCESS;
11866 #endif /* FEATURE_SH_EXTRA_QUIET */
11869 * The export and readonly commands.
11872 exportcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11878 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
11880 if (nextopt("p") != 'p') {
11885 p = strchr(name, '=');
11889 vp = *findvar(hashvar(name), name);
11895 setvar(name, p, flag);
11896 } while ((name = *++aptr) != NULL);
11900 showvars(argv[0], flag, 0);
11905 * Delete a function if it exists.
11908 unsetfunc(const char *name)
11910 struct tblentry *cmdp;
11912 cmdp = cmdlookup(name, 0);
11913 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
11914 delete_cmd_entry();
11918 * The unset builtin command. We unset the function before we unset the
11919 * variable to allow a function to be unset when there is a readonly variable
11920 * with the same name.
11923 unsetcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11930 while ((i = nextopt("vf")) != '\0') {
11934 for (ap = argptr; *ap; ap++) {
11950 #include <sys/times.h>
11952 static const unsigned char timescmd_str[] ALIGN1 = {
11953 ' ', offsetof(struct tms, tms_utime),
11954 '\n', offsetof(struct tms, tms_stime),
11955 ' ', offsetof(struct tms, tms_cutime),
11956 '\n', offsetof(struct tms, tms_cstime),
11961 timescmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11963 long clk_tck, s, t;
11964 const unsigned char *p;
11967 clk_tck = sysconf(_SC_CLK_TCK);
11972 t = *(clock_t *)(((char *) &buf) + p[1]);
11974 out1fmt("%ldm%ld.%.3lds%c",
11976 ((t - s * clk_tck) * 1000) / clk_tck,
11978 } while (*(p += 2));
11983 #if ENABLE_ASH_MATH_SUPPORT
11985 dash_arith(const char *s)
11991 result = arith(s, &errcode);
11994 ash_msg_and_raise_error("exponent less than 0");
11996 ash_msg_and_raise_error("divide by zero");
11998 ash_msg_and_raise_error("expression recursion loop detected");
11999 raise_error_syntax(s);
12007 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12008 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12010 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12013 letcmd(int argc ATTRIBUTE_UNUSED, char **argv)
12019 ash_msg_and_raise_error("expression expected");
12021 i = dash_arith(*argv);
12026 #endif /* ASH_MATH_SUPPORT */
12029 /* ============ miscbltin.c
12031 * Miscellaneous builtins.
12036 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12037 typedef enum __rlimit_resource rlim_t;
12041 * The read builtin. Options:
12042 * -r Do not interpret '\' specially
12043 * -s Turn off echo (tty only)
12044 * -n NCHARS Read NCHARS max
12045 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12046 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12047 * -u FD Read from given FD instead of fd 0
12048 * This uses unbuffered input, which may be avoidable in some cases.
12049 * TODO: bash also has:
12050 * -a ARRAY Read into array[0],[1],etc
12051 * -d DELIM End on DELIM char, not newline
12052 * -e Use line editing (tty only)
12055 readcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
12057 static const char *const arg_REPLY[] = { "REPLY", NULL };
12070 #if ENABLE_ASH_READ_NCHARS
12071 int nchars = 0; /* if != 0, -n is in effect */
12073 struct termios tty, old_tty;
12075 #if ENABLE_ASH_READ_TIMEOUT
12076 unsigned end_ms = 0;
12077 unsigned timeout = 0;
12082 while ((i = nextopt("p:u:r"
12083 USE_ASH_READ_TIMEOUT("t:")
12084 USE_ASH_READ_NCHARS("n:s")
12088 prompt = optionarg;
12090 #if ENABLE_ASH_READ_NCHARS
12092 nchars = bb_strtou(optionarg, NULL, 10);
12093 if (nchars < 0 || errno)
12094 ash_msg_and_raise_error("invalid count");
12095 /* nchars == 0: off (bash 3.2 does this too) */
12101 #if ENABLE_ASH_READ_TIMEOUT
12103 timeout = bb_strtou(optionarg, NULL, 10);
12104 if (errno || timeout > UINT_MAX / 2048)
12105 ash_msg_and_raise_error("invalid timeout");
12107 #if 0 /* even bash have no -t N.NNN support */
12108 ts.tv_sec = bb_strtou(optionarg, &p, 10);
12110 /* EINVAL means number is ok, but not terminated by NUL */
12111 if (*p == '.' && errno == EINVAL) {
12115 ts.tv_usec = bb_strtou(p, &p2, 10);
12117 ash_msg_and_raise_error("invalid timeout");
12119 /* normalize to usec */
12121 ash_msg_and_raise_error("invalid timeout");
12122 while (scale++ < 6)
12125 } else if (ts.tv_sec < 0 || errno) {
12126 ash_msg_and_raise_error("invalid timeout");
12128 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
12129 ash_msg_and_raise_error("invalid timeout");
12138 fd = bb_strtou(optionarg, NULL, 10);
12139 if (fd < 0 || errno)
12140 ash_msg_and_raise_error("invalid file descriptor");
12146 if (prompt && isatty(fd)) {
12151 ap = (char**)arg_REPLY;
12152 ifs = bltinlookup("IFS");
12155 #if ENABLE_ASH_READ_NCHARS
12156 tcgetattr(fd, &tty);
12158 if (nchars || silent) {
12160 tty.c_lflag &= ~ICANON;
12161 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
12164 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
12166 /* if tcgetattr failed, tcsetattr will fail too.
12167 * Ignoring, it's harmless. */
12168 tcsetattr(fd, TCSANOW, &tty);
12175 #if ENABLE_ASH_READ_TIMEOUT
12176 if (timeout) /* NB: ensuring end_ms is nonzero */
12177 end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1;
12181 #if ENABLE_ASH_READ_TIMEOUT
12183 struct pollfd pfd[1];
12185 pfd[0].events = POLLIN;
12186 timeout = end_ms - (unsigned)(monotonic_us() / 1000);
12187 if ((int)timeout <= 0 /* already late? */
12188 || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
12189 ) { /* timed out! */
12190 #if ENABLE_ASH_READ_NCHARS
12191 tcsetattr(fd, TCSANOW, &old_tty);
12197 if (nonblock_safe_read(fd, &c, 1) != 1) {
12209 if (!rflag && c == '\\') {
12215 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12219 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12221 setvar(*ap, stackblock(), 0);
12230 /* end of do {} while: */
12231 #if ENABLE_ASH_READ_NCHARS
12237 #if ENABLE_ASH_READ_NCHARS
12238 tcsetattr(fd, TCSANOW, &old_tty);
12242 /* Remove trailing blanks */
12243 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12245 setvar(*ap, stackblock(), 0);
12246 while (*++ap != NULL)
12247 setvar(*ap, nullstr, 0);
12252 umaskcmd(int argc ATTRIBUTE_UNUSED, char **argv)
12254 static const char permuser[3] ALIGN1 = "ugo";
12255 static const char permmode[3] ALIGN1 = "rwx";
12256 static const short permmask[] ALIGN2 = {
12257 S_IRUSR, S_IWUSR, S_IXUSR,
12258 S_IRGRP, S_IWGRP, S_IXGRP,
12259 S_IROTH, S_IWOTH, S_IXOTH
12265 int symbolic_mode = 0;
12267 while (nextopt("S") != '\0') {
12278 if (symbolic_mode) {
12282 for (i = 0; i < 3; i++) {
12285 *p++ = permuser[i];
12287 for (j = 0; j < 3; j++) {
12288 if ((mask & permmask[3 * i + j]) == 0) {
12289 *p++ = permmode[j];
12297 out1fmt("%.4o\n", mask);
12300 if (isdigit((unsigned char) *ap)) {
12303 if (*ap >= '8' || *ap < '0')
12304 ash_msg_and_raise_error(illnum, argv[1]);
12305 mask = (mask << 3) + (*ap - '0');
12306 } while (*++ap != '\0');
12309 mask = ~mask & 0777;
12310 if (!bb_parse_mode(ap, &mask)) {
12311 ash_msg_and_raise_error("illegal mode: %s", ap);
12313 umask(~mask & 0777);
12322 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12323 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12324 * ash by J.T. Conklin.
12330 uint8_t cmd; /* RLIMIT_xxx fit into it */
12331 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
12335 static const struct limits limits_tbl[] = {
12337 { RLIMIT_CPU, 0, 't' },
12339 #ifdef RLIMIT_FSIZE
12340 { RLIMIT_FSIZE, 9, 'f' },
12343 { RLIMIT_DATA, 10, 'd' },
12345 #ifdef RLIMIT_STACK
12346 { RLIMIT_STACK, 10, 's' },
12349 { RLIMIT_CORE, 9, 'c' },
12352 { RLIMIT_RSS, 10, 'm' },
12354 #ifdef RLIMIT_MEMLOCK
12355 { RLIMIT_MEMLOCK, 10, 'l' },
12357 #ifdef RLIMIT_NPROC
12358 { RLIMIT_NPROC, 0, 'p' },
12360 #ifdef RLIMIT_NOFILE
12361 { RLIMIT_NOFILE, 0, 'n' },
12364 { RLIMIT_AS, 10, 'v' },
12366 #ifdef RLIMIT_LOCKS
12367 { RLIMIT_LOCKS, 0, 'w' },
12370 static const char limits_name[] =
12372 "time(seconds)" "\0"
12374 #ifdef RLIMIT_FSIZE
12375 "file(blocks)" "\0"
12380 #ifdef RLIMIT_STACK
12384 "coredump(blocks)" "\0"
12389 #ifdef RLIMIT_MEMLOCK
12390 "locked memory(kb)" "\0"
12392 #ifdef RLIMIT_NPROC
12395 #ifdef RLIMIT_NOFILE
12401 #ifdef RLIMIT_LOCKS
12406 enum limtype { SOFT = 0x1, HARD = 0x2 };
12409 printlim(enum limtype how, const struct rlimit *limit,
12410 const struct limits *l)
12414 val = limit->rlim_max;
12416 val = limit->rlim_cur;
12418 if (val == RLIM_INFINITY)
12419 out1fmt("unlimited\n");
12421 val >>= l->factor_shift;
12422 out1fmt("%lld\n", (long long) val);
12427 ulimitcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
12431 enum limtype how = SOFT | HARD;
12432 const struct limits *l;
12435 struct rlimit limit;
12438 while ((optc = nextopt("HSa"
12442 #ifdef RLIMIT_FSIZE
12448 #ifdef RLIMIT_STACK
12457 #ifdef RLIMIT_MEMLOCK
12460 #ifdef RLIMIT_NPROC
12463 #ifdef RLIMIT_NOFILE
12469 #ifdef RLIMIT_LOCKS
12487 for (l = limits_tbl; l->option != what; l++)
12490 set = *argptr ? 1 : 0;
12494 if (all || argptr[1])
12495 ash_msg_and_raise_error("too many arguments");
12496 if (strncmp(p, "unlimited\n", 9) == 0)
12497 val = RLIM_INFINITY;
12501 while ((c = *p++) >= '0' && c <= '9') {
12502 val = (val * 10) + (long)(c - '0');
12503 // val is actually 'unsigned long int' and can't get < 0
12504 if (val < (rlim_t) 0)
12508 ash_msg_and_raise_error("bad number");
12509 val <<= l->factor_shift;
12513 const char *lname = limits_name;
12514 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12515 getrlimit(l->cmd, &limit);
12516 out1fmt("%-20s ", lname);
12517 lname += strlen(lname) + 1;
12518 printlim(how, &limit, l);
12523 getrlimit(l->cmd, &limit);
12526 limit.rlim_max = val;
12528 limit.rlim_cur = val;
12529 if (setrlimit(l->cmd, &limit) < 0)
12530 ash_msg_and_raise_error("error setting limit (%m)");
12532 printlim(how, &limit, l);
12538 /* ============ Math support */
12540 #if ENABLE_ASH_MATH_SUPPORT
12542 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12544 Permission is hereby granted, free of charge, to any person obtaining
12545 a copy of this software and associated documentation files (the
12546 "Software"), to deal in the Software without restriction, including
12547 without limitation the rights to use, copy, modify, merge, publish,
12548 distribute, sublicense, and/or sell copies of the Software, and to
12549 permit persons to whom the Software is furnished to do so, subject to
12550 the following conditions:
12552 The above copyright notice and this permission notice shall be
12553 included in all copies or substantial portions of the Software.
12555 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12556 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12557 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12558 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12559 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12560 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12561 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12564 /* This is my infix parser/evaluator. It is optimized for size, intended
12565 * as a replacement for yacc-based parsers. However, it may well be faster
12566 * than a comparable parser written in yacc. The supported operators are
12567 * listed in #defines below. Parens, order of operations, and error handling
12568 * are supported. This code is thread safe. The exact expression format should
12569 * be that which POSIX specifies for shells. */
12571 /* The code uses a simple two-stack algorithm. See
12572 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12573 * for a detailed explanation of the infix-to-postfix algorithm on which
12574 * this is based (this code differs in that it applies operators immediately
12575 * to the stack instead of adding them to a queue to end up with an
12578 /* To use the routine, call it with an expression string and error return
12582 * Aug 24, 2001 Manuel Novoa III
12584 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12586 * 1) In arith_apply():
12587 * a) Cached values of *numptr and &(numptr[-1]).
12588 * b) Removed redundant test for zero denominator.
12591 * a) Eliminated redundant code for processing operator tokens by moving
12592 * to a table-based implementation. Also folded handling of parens
12594 * b) Combined all 3 loops which called arith_apply to reduce generated
12595 * code size at the cost of speed.
12597 * 3) The following expressions were treated as valid by the original code:
12598 * 1() , 0! , 1 ( *3 ) .
12599 * These bugs have been fixed by internally enclosing the expression in
12600 * parens and then checking that all binary ops and right parens are
12601 * preceded by a valid expression (NUM_TOKEN).
12603 * Note: It may be desirable to replace Aaron's test for whitespace with
12604 * ctype's isspace() if it is used by another busybox applet or if additional
12605 * whitespace chars should be considered. Look below the "#include"s for a
12606 * precompiler test.
12610 * Aug 26, 2001 Manuel Novoa III
12612 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12614 * Merge in Aaron's comments previously posted to the busybox list,
12615 * modified slightly to take account of my changes to the code.
12620 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12622 * - allow access to variable,
12623 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12624 * - realize assign syntax (VAR=expr, +=, *= etc)
12625 * - realize exponentiation (** operator)
12626 * - realize comma separated - expr, expr
12627 * - realise ++expr --expr expr++ expr--
12628 * - realise expr ? expr : expr (but, second expr calculate always)
12629 * - allow hexadecimal and octal numbers
12630 * - was restored loses XOR operator
12631 * - remove one goto label, added three ;-)
12632 * - protect $((num num)) as true zero expr (Manuel`s error)
12633 * - always use special isspace(), see comment from bash ;-)
12636 #define arith_isspace(arithval) \
12637 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12639 typedef unsigned char operator;
12641 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12642 * precedence, and 3 high bits are an ID unique across operators of that
12643 * precedence. The ID portion is so that multiple operators can have the
12644 * same precedence, ensuring that the leftmost one is evaluated first.
12645 * Consider * and /. */
12647 #define tok_decl(prec,id) (((id)<<5)|(prec))
12648 #define PREC(op) ((op) & 0x1F)
12650 #define TOK_LPAREN tok_decl(0,0)
12652 #define TOK_COMMA tok_decl(1,0)
12654 #define TOK_ASSIGN tok_decl(2,0)
12655 #define TOK_AND_ASSIGN tok_decl(2,1)
12656 #define TOK_OR_ASSIGN tok_decl(2,2)
12657 #define TOK_XOR_ASSIGN tok_decl(2,3)
12658 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12659 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12660 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12661 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12663 #define TOK_MUL_ASSIGN tok_decl(3,0)
12664 #define TOK_DIV_ASSIGN tok_decl(3,1)
12665 #define TOK_REM_ASSIGN tok_decl(3,2)
12667 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12668 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12670 /* conditional is right associativity too */
12671 #define TOK_CONDITIONAL tok_decl(4,0)
12672 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12674 #define TOK_OR tok_decl(5,0)
12676 #define TOK_AND tok_decl(6,0)
12678 #define TOK_BOR tok_decl(7,0)
12680 #define TOK_BXOR tok_decl(8,0)
12682 #define TOK_BAND tok_decl(9,0)
12684 #define TOK_EQ tok_decl(10,0)
12685 #define TOK_NE tok_decl(10,1)
12687 #define TOK_LT tok_decl(11,0)
12688 #define TOK_GT tok_decl(11,1)
12689 #define TOK_GE tok_decl(11,2)
12690 #define TOK_LE tok_decl(11,3)
12692 #define TOK_LSHIFT tok_decl(12,0)
12693 #define TOK_RSHIFT tok_decl(12,1)
12695 #define TOK_ADD tok_decl(13,0)
12696 #define TOK_SUB tok_decl(13,1)
12698 #define TOK_MUL tok_decl(14,0)
12699 #define TOK_DIV tok_decl(14,1)
12700 #define TOK_REM tok_decl(14,2)
12702 /* exponent is right associativity */
12703 #define TOK_EXPONENT tok_decl(15,1)
12705 /* For now unary operators. */
12706 #define UNARYPREC 16
12707 #define TOK_BNOT tok_decl(UNARYPREC,0)
12708 #define TOK_NOT tok_decl(UNARYPREC,1)
12710 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12711 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12713 #define PREC_PRE (UNARYPREC+2)
12715 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12716 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12718 #define PREC_POST (UNARYPREC+3)
12720 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12721 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12723 #define SPEC_PREC (UNARYPREC+4)
12725 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12726 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12728 #define NUMPTR (*numstackptr)
12731 tok_have_assign(operator op)
12733 operator prec = PREC(op);
12735 convert_prec_is_assing(prec);
12736 return (prec == PREC(TOK_ASSIGN) ||
12737 prec == PREC_PRE || prec == PREC_POST);
12741 is_right_associativity(operator prec)
12743 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
12744 || prec == PREC(TOK_CONDITIONAL));
12749 arith_t contidional_second_val;
12750 char contidional_second_val_initialized;
12751 char *var; /* if NULL then is regular number,
12752 else is variable name */
12755 typedef struct chk_var_recursive_looped_t {
12757 struct chk_var_recursive_looped_t *next;
12758 } chk_var_recursive_looped_t;
12760 static chk_var_recursive_looped_t *prev_chk_var_recursive;
12763 arith_lookup_val(v_n_t *t)
12766 const char * p = lookupvar(t->var);
12771 /* recursive try as expression */
12772 chk_var_recursive_looped_t *cur;
12773 chk_var_recursive_looped_t cur_save;
12775 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
12776 if (strcmp(cur->var, t->var) == 0) {
12777 /* expression recursion loop detected */
12781 /* save current lookuped var name */
12782 cur = prev_chk_var_recursive;
12783 cur_save.var = t->var;
12784 cur_save.next = cur;
12785 prev_chk_var_recursive = &cur_save;
12787 t->val = arith (p, &errcode);
12788 /* restore previous ptr after recursiving */
12789 prev_chk_var_recursive = cur;
12792 /* allow undefined var as 0 */
12798 /* "applying" a token means performing it on the top elements on the integer
12799 * stack. For a unary operator it will only change the top element, but a
12800 * binary operator will pop two arguments and push a result */
12802 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
12805 arith_t numptr_val, rez;
12806 int ret_arith_lookup_val;
12808 /* There is no operator that can work without arguments */
12809 if (NUMPTR == numstack) goto err;
12810 numptr_m1 = NUMPTR - 1;
12812 /* check operand is var with noninteger value */
12813 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12814 if (ret_arith_lookup_val)
12815 return ret_arith_lookup_val;
12817 rez = numptr_m1->val;
12818 if (op == TOK_UMINUS)
12820 else if (op == TOK_NOT)
12822 else if (op == TOK_BNOT)
12824 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
12826 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
12828 else if (op != TOK_UPLUS) {
12829 /* Binary operators */
12831 /* check and binary operators need two arguments */
12832 if (numptr_m1 == numstack) goto err;
12834 /* ... and they pop one */
12837 if (op == TOK_CONDITIONAL) {
12838 if (! numptr_m1->contidional_second_val_initialized) {
12839 /* protect $((expr1 ? expr2)) without ": expr" */
12842 rez = numptr_m1->contidional_second_val;
12843 } else if (numptr_m1->contidional_second_val_initialized) {
12844 /* protect $((expr1 : expr2)) without "expr ? " */
12847 numptr_m1 = NUMPTR - 1;
12848 if (op != TOK_ASSIGN) {
12849 /* check operand is var with noninteger value for not '=' */
12850 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12851 if (ret_arith_lookup_val)
12852 return ret_arith_lookup_val;
12854 if (op == TOK_CONDITIONAL) {
12855 numptr_m1->contidional_second_val = rez;
12857 rez = numptr_m1->val;
12858 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
12860 else if (op == TOK_OR)
12861 rez = numptr_val || rez;
12862 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
12864 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
12866 else if (op == TOK_AND)
12867 rez = rez && numptr_val;
12868 else if (op == TOK_EQ)
12869 rez = (rez == numptr_val);
12870 else if (op == TOK_NE)
12871 rez = (rez != numptr_val);
12872 else if (op == TOK_GE)
12873 rez = (rez >= numptr_val);
12874 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
12875 rez >>= numptr_val;
12876 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
12877 rez <<= numptr_val;
12878 else if (op == TOK_GT)
12879 rez = (rez > numptr_val);
12880 else if (op == TOK_LT)
12881 rez = (rez < numptr_val);
12882 else if (op == TOK_LE)
12883 rez = (rez <= numptr_val);
12884 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
12886 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
12888 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
12890 else if (op == TOK_ASSIGN || op == TOK_COMMA)
12892 else if (op == TOK_CONDITIONAL_SEP) {
12893 if (numptr_m1 == numstack) {
12894 /* protect $((expr : expr)) without "expr ? " */
12897 numptr_m1->contidional_second_val_initialized = op;
12898 numptr_m1->contidional_second_val = numptr_val;
12899 } else if (op == TOK_CONDITIONAL) {
12901 numptr_val : numptr_m1->contidional_second_val;
12902 } else if (op == TOK_EXPONENT) {
12903 if (numptr_val < 0)
12904 return -3; /* exponent less than 0 */
12909 while (numptr_val--)
12913 } else if (numptr_val==0) /* zero divisor check */
12915 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
12917 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
12920 if (tok_have_assign(op)) {
12921 char buf[sizeof(arith_t_type)*3 + 2];
12923 if (numptr_m1->var == NULL) {
12927 /* save to shell variable */
12928 #if ENABLE_ASH_MATH_SUPPORT_64
12929 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
12931 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
12933 setvar(numptr_m1->var, buf, 0);
12934 /* after saving, make previous value for v++ or v-- */
12935 if (op == TOK_POST_INC)
12937 else if (op == TOK_POST_DEC)
12940 numptr_m1->val = rez;
12941 /* protect geting var value, is number now */
12942 numptr_m1->var = NULL;
12948 /* longest must be first */
12949 static const char op_tokens[] ALIGN1 = {
12950 '<','<','=',0, TOK_LSHIFT_ASSIGN,
12951 '>','>','=',0, TOK_RSHIFT_ASSIGN,
12952 '<','<', 0, TOK_LSHIFT,
12953 '>','>', 0, TOK_RSHIFT,
12954 '|','|', 0, TOK_OR,
12955 '&','&', 0, TOK_AND,
12956 '!','=', 0, TOK_NE,
12957 '<','=', 0, TOK_LE,
12958 '>','=', 0, TOK_GE,
12959 '=','=', 0, TOK_EQ,
12960 '|','=', 0, TOK_OR_ASSIGN,
12961 '&','=', 0, TOK_AND_ASSIGN,
12962 '*','=', 0, TOK_MUL_ASSIGN,
12963 '/','=', 0, TOK_DIV_ASSIGN,
12964 '%','=', 0, TOK_REM_ASSIGN,
12965 '+','=', 0, TOK_PLUS_ASSIGN,
12966 '-','=', 0, TOK_MINUS_ASSIGN,
12967 '-','-', 0, TOK_POST_DEC,
12968 '^','=', 0, TOK_XOR_ASSIGN,
12969 '+','+', 0, TOK_POST_INC,
12970 '*','*', 0, TOK_EXPONENT,
12974 '=', 0, TOK_ASSIGN,
12986 '?', 0, TOK_CONDITIONAL,
12987 ':', 0, TOK_CONDITIONAL_SEP,
12988 ')', 0, TOK_RPAREN,
12989 '(', 0, TOK_LPAREN,
12993 #define endexpression (&op_tokens[sizeof(op_tokens)-7])
12996 arith(const char *expr, int *perrcode)
12998 char arithval; /* Current character under analysis */
12999 operator lasttok, op;
13001 operator *stack, *stackptr;
13002 const char *p = endexpression;
13004 v_n_t *numstack, *numstackptr;
13005 unsigned datasizes = strlen(expr) + 2;
13007 /* Stack of integers */
13008 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13009 * in any given correct or incorrect expression is left as an exercise to
13011 numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0]));
13012 /* Stack of operator tokens */
13013 stackptr = stack = alloca(datasizes * sizeof(stack[0]));
13015 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13016 *perrcode = errcode = 0;
13020 if (arithval == 0) {
13021 if (p == endexpression) {
13022 /* Null expression. */
13026 /* This is only reached after all tokens have been extracted from the
13027 * input stream. If there are still tokens on the operator stack, they
13028 * are to be applied in order. At the end, there should be a final
13029 * result on the integer stack */
13031 if (expr != endexpression + 1) {
13032 /* If we haven't done so already, */
13033 /* append a closing right paren */
13034 expr = endexpression;
13035 /* and let the loop process it. */
13038 /* At this point, we're done with the expression. */
13039 if (numstackptr != numstack+1) {
13040 /* ... but if there isn't, it's bad */
13045 if (numstack->var) {
13046 /* expression is $((var)) only, lookup now */
13047 errcode = arith_lookup_val(numstack);
13050 *perrcode = errcode;
13051 return numstack->val;
13054 /* Continue processing the expression. */
13055 if (arith_isspace(arithval)) {
13056 /* Skip whitespace */
13059 p = endofname(expr);
13061 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13063 numstackptr->var = alloca(var_name_size);
13064 safe_strncpy(numstackptr->var, expr, var_name_size);
13067 numstackptr->contidional_second_val_initialized = 0;
13072 if (isdigit(arithval)) {
13073 numstackptr->var = NULL;
13074 #if ENABLE_ASH_MATH_SUPPORT_64
13075 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13077 numstackptr->val = strtol(expr, (char **) &expr, 0);
13081 for (p = op_tokens; ; p++) {
13085 /* strange operator not found */
13088 for (o = expr; *p && *o == *p; p++)
13095 /* skip tail uncompared token */
13098 /* skip zero delim */
13103 /* post grammar: a++ reduce to num */
13104 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13107 /* Plus and minus are binary (not unary) _only_ if the last
13108 * token was as number, or a right paren (which pretends to be
13109 * a number, since it evaluates to one). Think about it.
13110 * It makes sense. */
13111 if (lasttok != TOK_NUM) {
13127 /* We don't want a unary operator to cause recursive descent on the
13128 * stack, because there can be many in a row and it could cause an
13129 * operator to be evaluated before its argument is pushed onto the
13130 * integer stack. */
13131 /* But for binary operators, "apply" everything on the operator
13132 * stack until we find an operator with a lesser priority than the
13133 * one we have just extracted. */
13134 /* Left paren is given the lowest priority so it will never be
13135 * "applied" in this way.
13136 * if associativity is right and priority eq, applied also skip
13139 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13140 /* not left paren or unary */
13141 if (lasttok != TOK_NUM) {
13142 /* binary op must be preceded by a num */
13145 while (stackptr != stack) {
13146 if (op == TOK_RPAREN) {
13147 /* The algorithm employed here is simple: while we don't
13148 * hit an open paren nor the bottom of the stack, pop
13149 * tokens and apply them */
13150 if (stackptr[-1] == TOK_LPAREN) {
13152 /* Any operator directly after a */
13154 /* close paren should consider itself binary */
13158 operator prev_prec = PREC(stackptr[-1]);
13160 convert_prec_is_assing(prec);
13161 convert_prec_is_assing(prev_prec);
13162 if (prev_prec < prec)
13164 /* check right assoc */
13165 if (prev_prec == prec && is_right_associativity(prec))
13168 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13169 if (errcode) goto ret;
13171 if (op == TOK_RPAREN) {
13176 /* Push this operator to the stack and remember it. */
13177 *stackptr++ = lasttok = op;
13182 #endif /* ASH_MATH_SUPPORT */
13185 /* ============ main() and helpers */
13188 * Called to exit the shell.
13190 static void exitshell(void) ATTRIBUTE_NORETURN;
13198 status = exitstatus;
13199 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13200 if (setjmp(loc.loc)) {
13201 if (exception == EXEXIT)
13202 /* dash bug: it just does _exit(exitstatus) here
13203 * but we have to do setjobctl(0) first!
13204 * (bug is still not fixed in dash-0.5.3 - if you run dash
13205 * under Midnight Commander, on exit from dash MC is backgrounded) */
13206 status = exitstatus;
13209 exception_handler = &loc;
13215 flush_stdout_stderr();
13225 /* from input.c: */
13226 basepf.nextc = basepf.buf = basebuf;
13229 signal(SIGCHLD, SIG_DFL);
13234 char ppid[sizeof(int)*3 + 1];
13236 struct stat st1, st2;
13239 for (envp = environ; envp && *envp; envp++) {
13240 if (strchr(*envp, '=')) {
13241 setvareq(*envp, VEXPORT|VTEXTFIXED);
13245 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
13246 setvar("PPID", ppid, 0);
13248 p = lookupvar("PWD");
13250 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
13251 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
13258 * Process the shell command line arguments.
13261 procargs(char **argv)
13264 const char *xminusc;
13269 /* if (xargv[0]) - mmm, this is always true! */
13271 for (i = 0; i < NOPTS; i++)
13275 /* it already printed err message */
13276 raise_exception(EXERROR);
13280 if (*xargv == NULL) {
13282 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13285 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13289 for (i = 0; i < NOPTS; i++)
13290 if (optlist[i] == 2)
13295 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13300 } else if (!sflag) {
13301 setinputfile(*xargv, 0);
13304 commandname = arg0;
13307 shellparam.p = xargv;
13308 #if ENABLE_ASH_GETOPTS
13309 shellparam.optind = 1;
13310 shellparam.optoff = -1;
13312 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13314 shellparam.nparam++;
13321 * Read /etc/profile or .profile.
13324 read_profile(const char *name)
13328 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13337 * This routine is called when an error or an interrupt occurs in an
13338 * interactive shell and control is returned to the main command loop.
13346 /* from input.c: */
13347 parselleft = parsenleft = 0; /* clear input buffer */
13349 /* from parser.c: */
13352 /* from redir.c: */
13357 static short profile_buf[16384];
13358 extern int etext();
13362 * Main routine. We initialize things, parse the arguments, execute
13363 * profiles if we're a login shell, and then call cmdloop to execute
13364 * commands. The setjmp call sets up the location to jump to when an
13365 * exception occurs. When an exception occurs the variable "state"
13366 * is used to figure out how far we had gotten.
13368 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13369 int ash_main(int argc ATTRIBUTE_UNUSED, char **argv)
13372 volatile int state;
13373 struct jmploc jmploc;
13374 struct stackmark smark;
13376 /* Initialize global data */
13380 #if ENABLE_ASH_ALIAS
13386 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13389 #if ENABLE_FEATURE_EDITING
13390 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13393 if (setjmp(jmploc.loc)) {
13403 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13407 outcslow('\n', stderr);
13409 popstackmark(&smark);
13410 FORCE_INT_ON; /* enable interrupts */
13419 exception_handler = &jmploc;
13422 trace_puts("Shell args: ");
13423 trace_puts_args(argv);
13425 rootpid = getpid();
13427 #if ENABLE_ASH_RANDOM_SUPPORT
13428 rseed = rootpid + time(NULL);
13431 setstackmark(&smark);
13434 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13436 const char *hp = lookupvar("HISTFILE");
13439 hp = lookupvar("HOME");
13441 char *defhp = concat_path_file(hp, ".ash_history");
13442 setvar("HISTFILE", defhp, 0);
13448 if (argv[0] && argv[0][0] == '-')
13452 read_profile("/etc/profile");
13455 read_profile(".profile");
13461 getuid() == geteuid() && getgid() == getegid() &&
13465 shinit = lookupvar("ENV");
13466 if (shinit != NULL && *shinit != '\0') {
13467 read_profile(shinit);
13473 evalstring(minusc, 0);
13475 if (sflag || minusc == NULL) {
13476 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13478 const char *hp = lookupvar("HISTFILE");
13481 line_input_state->hist_file = hp;
13484 state4: /* XXX ??? - why isn't this before the "if" statement */
13492 extern void _mcleanup(void);
13501 const char *applet_name = "debug stuff usage";
13502 int main(int argc, char **argv)
13504 return ash_main(argc, argv);
13510 * Copyright (c) 1989, 1991, 1993, 1994
13511 * The Regents of the University of California. All rights reserved.
13513 * This code is derived from software contributed to Berkeley by
13514 * Kenneth Almquist.
13516 * Redistribution and use in source and binary forms, with or without
13517 * modification, are permitted provided that the following conditions
13519 * 1. Redistributions of source code must retain the above copyright
13520 * notice, this list of conditions and the following disclaimer.
13521 * 2. Redistributions in binary form must reproduce the above copyright
13522 * notice, this list of conditions and the following disclaimer in the
13523 * documentation and/or other materials provided with the distribution.
13524 * 3. Neither the name of the University nor the names of its contributors
13525 * may be used to endorse or promote products derived from this software
13526 * without specific prior written permission.
13528 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13529 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13530 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13531 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13532 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13533 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13534 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13535 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13536 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13537 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF