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) };
114 /* ============ Misc data */
116 static const char homestr[] ALIGN1 = "HOME";
117 static const char snlfmt[] ALIGN1 = "%s\n";
118 static const char illnum[] ALIGN1 = "Illegal number: %s";
121 * We enclose jmp_buf in a structure so that we can declare pointers to
122 * jump locations. The global variable handler contains the location to
123 * jump to when an exception occurs, and the global variable exception
124 * contains a code identifying the exception. To implement nested
125 * exception handlers, the user should save the value of handler on entry
126 * to an inner scope, set handler to point to a jmploc structure for the
127 * inner scope, and restore handler on exit from the scope.
133 struct globals_misc {
134 /* pid of main shell */
136 /* shell level: 0 for the main shell, 1 for its children, and so on */
138 #define rootshell (!shlvl)
139 char *minusc; /* argument to -c option */
141 char *curdir; // = nullstr; /* current working directory */
142 char *physdir; // = nullstr; /* physical working directory */
144 char *arg0; /* value of $0 */
146 struct jmploc *exception_handler;
148 // disabled by vda: cannot understand how it was supposed to work -
149 // cannot fix bugs. That's why you have to explain your non-trivial designs!
150 // /* do we generate EXSIG events */
151 // int exsig; /* counter */
152 volatile int suppressint; /* counter */
153 volatile /*sig_atomic_t*/ smallint intpending; /* 1 = got SIGINT */
154 /* last pending signal */
155 volatile /*sig_atomic_t*/ smallint pendingsig;
156 smallint exception; /* kind of exception (0..5) */
158 #define EXINT 0 /* SIGINT received */
159 #define EXERROR 1 /* a generic error */
160 #define EXSHELLPROC 2 /* execute a shell procedure */
161 #define EXEXEC 3 /* command execution failed */
162 #define EXEXIT 4 /* exit the shell */
163 #define EXSIG 5 /* trapped signal in wait(1) */
166 char nullstr[1]; /* zero length string */
169 #define eflag optlist[0]
170 #define fflag optlist[1]
171 #define Iflag optlist[2]
172 #define iflag optlist[3]
173 #define mflag optlist[4]
174 #define nflag optlist[5]
175 #define sflag optlist[6]
176 #define xflag optlist[7]
177 #define vflag optlist[8]
178 #define Cflag optlist[9]
179 #define aflag optlist[10]
180 #define bflag optlist[11]
181 #define uflag optlist[12]
182 #define viflag optlist[13]
184 #define nolog optlist[14]
185 #define debug optlist[15]
188 /* trap handler commands */
190 * Sigmode records the current value of the signal handlers for the various
191 * modes. A value of zero means that the current handler is not known.
192 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
194 char sigmode[NSIG - 1];
195 #define S_DFL 1 /* default signal handling (SIG_DFL) */
196 #define S_CATCH 2 /* signal is caught */
197 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
198 #define S_HARD_IGN 4 /* signal is ignored permenantly */
199 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
201 /* indicates specified signal received */
202 char gotsig[NSIG - 1];
205 /* Rarely referenced stuff */
206 #if ENABLE_ASH_RANDOM_SUPPORT
207 /* Random number generators */
208 int32_t random_galois_LFSR; /* Galois LFSR (fast but weak). signed! */
209 uint32_t random_LCG; /* LCG (fast but weak) */
211 pid_t backgndpid; /* pid of last background process */
212 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
214 extern struct globals_misc *const ash_ptr_to_globals_misc;
215 #define G_misc (*ash_ptr_to_globals_misc)
216 #define rootpid (G_misc.rootpid )
217 #define shlvl (G_misc.shlvl )
218 #define minusc (G_misc.minusc )
219 #define curdir (G_misc.curdir )
220 #define physdir (G_misc.physdir )
221 #define arg0 (G_misc.arg0 )
222 #define exception_handler (G_misc.exception_handler)
223 #define exception (G_misc.exception )
224 #define suppressint (G_misc.suppressint )
225 #define intpending (G_misc.intpending )
226 //#define exsig (G_misc.exsig )
227 #define pendingsig (G_misc.pendingsig )
228 #define isloginsh (G_misc.isloginsh )
229 #define nullstr (G_misc.nullstr )
230 #define optlist (G_misc.optlist )
231 #define sigmode (G_misc.sigmode )
232 #define gotsig (G_misc.gotsig )
233 #define trap (G_misc.trap )
234 #define random_galois_LFSR (G_misc.random_galois_LFSR)
235 #define random_LCG (G_misc.random_LCG )
236 #define backgndpid (G_misc.backgndpid )
237 #define job_warning (G_misc.job_warning)
238 #define INIT_G_misc() do { \
239 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
246 /* ============ Interrupts / exceptions */
249 * These macros allow the user to suspend the handling of interrupt signals
250 * over a period of time. This is similar to SIGHOLD or to sigblock, but
251 * much more efficient and portable. (But hacking the kernel is so much
252 * more fun than worrying about efficiency and portability. :-))
254 #define INT_OFF do { \
260 * Called to raise an exception. Since C doesn't include exceptions, we
261 * just do a longjmp to the exception handler. The type of exception is
262 * stored in the global variable "exception".
264 static void raise_exception(int) NORETURN;
266 raise_exception(int e)
269 if (exception_handler == NULL)
274 longjmp(exception_handler->loc, 1);
278 * Called from trap.c when a SIGINT is received. (If the user specifies
279 * that SIGINT is to be trapped or ignored using the trap builtin, then
280 * this routine is not called.) Suppressint is nonzero when interrupts
281 * are held using the INT_OFF macro. (The test for iflag is just
282 * defensive programming.)
284 static void raise_interrupt(void) NORETURN;
286 raise_interrupt(void)
291 /* Signal is not automatically unmasked after it is raised,
292 * do it ourself - unmask all signals */
293 sigprocmask_allsigs(SIG_UNBLOCK);
294 /* pendingsig = 0; - now done in onsig() */
297 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
298 if (!(rootshell && iflag)) {
299 /* Kill ourself with SIGINT */
300 signal(SIGINT, SIG_DFL);
309 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
313 if (--suppressint == 0 && intpending) {
317 #define INT_ON int_on()
325 #define FORCE_INT_ON force_int_on()
327 #define INT_ON do { \
329 if (--suppressint == 0 && intpending) \
332 #define FORCE_INT_ON do { \
338 #endif /* ASH_OPTIMIZE_FOR_SIZE */
340 #define SAVE_INT(v) ((v) = suppressint)
342 #define RESTORE_INT(v) do { \
345 if (suppressint == 0 && intpending) \
350 * Ignore a signal. Only one usage site - in forkchild()
355 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
356 signal(signo, SIG_IGN);
358 sigmode[signo - 1] = S_HARD_IGN;
362 * Signal handler. Only one usage site - in setsignal()
367 gotsig[signo - 1] = 1;
370 if (/* exsig || */ (signo == SIGINT && !trap[SIGINT])) {
373 raise_interrupt(); /* does not return */
380 /* ============ Stdout/stderr output */
383 outstr(const char *p, FILE *file)
391 flush_stdout_stderr(void)
408 outcslow(int c, FILE *dest)
416 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
418 out1fmt(const char *fmt, ...)
425 r = vprintf(fmt, ap);
431 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
433 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
440 ret = vsnprintf(outbuf, length, fmt, ap);
447 out1str(const char *p)
453 out2str(const char *p)
460 /* ============ Parser structures */
462 /* control characters in argument strings */
463 #define CTLESC '\201' /* escape next character */
464 #define CTLVAR '\202' /* variable defn */
465 #define CTLENDVAR '\203'
466 #define CTLBACKQ '\204'
467 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
468 /* CTLBACKQ | CTLQUOTE == '\205' */
469 #define CTLARI '\206' /* arithmetic expression */
470 #define CTLENDARI '\207'
471 #define CTLQUOTEMARK '\210'
473 /* variable substitution byte (follows CTLVAR) */
474 #define VSTYPE 0x0f /* type of variable substitution */
475 #define VSNUL 0x10 /* colon--treat the empty string as unset */
476 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
478 /* values of VSTYPE field */
479 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
480 #define VSMINUS 0x2 /* ${var-text} */
481 #define VSPLUS 0x3 /* ${var+text} */
482 #define VSQUESTION 0x4 /* ${var?message} */
483 #define VSASSIGN 0x5 /* ${var=text} */
484 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
485 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
486 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
487 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
488 #define VSLENGTH 0xa /* ${#var} */
489 #if ENABLE_ASH_BASH_COMPAT
490 #define VSSUBSTR 0xc /* ${var:position:length} */
491 #define VSREPLACE 0xd /* ${var/pattern/replacement} */
492 #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
495 static const char dolatstr[] ALIGN1 = {
496 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
529 smallint type; /* Nxxxx */
532 union node *redirect;
537 smallint pipe_backgnd;
538 struct nodelist *cmdlist;
544 union node *redirect;
557 union node *elsepart;
584 struct nodelist *backquote;
619 struct nredir nredir;
620 struct nbinary nbinary;
624 struct nclist nclist;
633 struct nodelist *next;
646 freefunc(struct funcnode *f)
648 if (f && --f->count < 0)
653 /* ============ Debugging output */
657 static FILE *tracefile;
660 trace_printf(const char *fmt, ...)
667 vfprintf(tracefile, fmt, va);
672 trace_vprintf(const char *fmt, va_list va)
676 vfprintf(tracefile, fmt, va);
680 trace_puts(const char *s)
688 trace_puts_quoted(char *s)
695 putc('"', tracefile);
696 for (p = s; *p; p++) {
698 case '\n': c = 'n'; goto backslash;
699 case '\t': c = 't'; goto backslash;
700 case '\r': c = 'r'; goto backslash;
701 case '"': c = '"'; goto backslash;
702 case '\\': c = '\\'; goto backslash;
703 case CTLESC: c = 'e'; goto backslash;
704 case CTLVAR: c = 'v'; goto backslash;
705 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
706 case CTLBACKQ: c = 'q'; goto backslash;
707 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
709 putc('\\', tracefile);
713 if (*p >= ' ' && *p <= '~')
716 putc('\\', tracefile);
717 putc(*p >> 6 & 03, tracefile);
718 putc(*p >> 3 & 07, tracefile);
719 putc(*p & 07, tracefile);
724 putc('"', tracefile);
728 trace_puts_args(char **ap)
735 trace_puts_quoted(*ap);
737 putc('\n', tracefile);
740 putc(' ', tracefile);
755 /* leave open because libedit might be using it */
758 strcpy(s, "./trace");
760 if (!freopen(s, "a", tracefile)) {
761 fprintf(stderr, "Can't re-open %s\n", s);
766 tracefile = fopen(s, "a");
767 if (tracefile == NULL) {
768 fprintf(stderr, "Can't open %s\n", s);
774 flags = fcntl(fileno(tracefile), F_GETFL);
776 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
778 setlinebuf(tracefile);
779 fputs("\nTracing started.\n", tracefile);
783 indent(int amount, char *pfx, FILE *fp)
787 for (i = 0; i < amount; i++) {
788 if (pfx && i == amount - 1)
794 /* little circular references here... */
795 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
798 sharg(union node *arg, FILE *fp)
801 struct nodelist *bqlist;
804 if (arg->type != NARG) {
805 out1fmt("<node type %d>\n", arg->type);
808 bqlist = arg->narg.backquote;
809 for (p = arg->narg.text; *p; p++) {
818 if (subtype == VSLENGTH)
827 switch (subtype & VSTYPE) {
860 out1fmt("<subtype %d>", subtype);
867 case CTLBACKQ|CTLQUOTE:
870 shtree(bqlist->n, -1, NULL, fp);
881 shcmd(union node *cmd, FILE *fp)
889 for (np = cmd->ncmd.args; np; np = np->narg.next) {
895 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
899 switch (np->nfile.type) {
900 case NTO: s = ">>"+1; dftfd = 1; break;
901 case NCLOBBER: s = ">|"; dftfd = 1; break;
902 case NAPPEND: s = ">>"; dftfd = 1; break;
903 case NTOFD: s = ">&"; dftfd = 1; break;
904 case NFROM: s = "<"; break;
905 case NFROMFD: s = "<&"; break;
906 case NFROMTO: s = "<>"; break;
907 default: s = "*error*"; break;
909 if (np->nfile.fd != dftfd)
910 fprintf(fp, "%d", np->nfile.fd);
912 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
913 fprintf(fp, "%d", np->ndup.dupfd);
915 sharg(np->nfile.fname, fp);
922 shtree(union node *n, int ind, char *pfx, FILE *fp)
930 indent(ind, pfx, fp);
941 shtree(n->nbinary.ch1, ind, NULL, fp);
944 shtree(n->nbinary.ch2, ind, NULL, fp);
952 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
957 if (n->npipe.pipe_backgnd)
963 fprintf(fp, "<node type %d>", n->type);
971 showtree(union node *n)
973 trace_puts("showtree called\n");
974 shtree(n, 1, NULL, stdout);
977 #define TRACE(param) trace_printf param
978 #define TRACEV(param) trace_vprintf param
983 #define TRACEV(param)
988 /* ============ Parser data */
991 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
994 struct strlist *next;
1001 struct strpush *prev; /* preceding string on stack */
1004 #if ENABLE_ASH_ALIAS
1005 struct alias *ap; /* if push was associated with an alias */
1007 char *string; /* remember the string since it may change */
1011 struct parsefile *prev; /* preceding file on stack */
1012 int linno; /* current line */
1013 int fd; /* file descriptor (or -1 if string) */
1014 int nleft; /* number of chars left in this line */
1015 int lleft; /* number of chars left in this buffer */
1016 char *nextc; /* next char in buffer */
1017 char *buf; /* input buffer */
1018 struct strpush *strpush; /* for pushing strings at this level */
1019 struct strpush basestrpush; /* so pushing one is fast */
1022 static struct parsefile basepf; /* top level input file */
1023 static struct parsefile *g_parsefile = &basepf; /* current input file */
1024 static int startlinno; /* line # where last token started */
1025 static char *commandname; /* currently executing command */
1026 static struct strlist *cmdenviron; /* environment for builtin command */
1027 static uint8_t exitstatus; /* exit status of last command */
1030 /* ============ Message printing */
1033 ash_vmsg(const char *msg, va_list ap)
1035 fprintf(stderr, "%s: ", arg0);
1037 if (strcmp(arg0, commandname))
1038 fprintf(stderr, "%s: ", commandname);
1039 if (!iflag || g_parsefile->fd)
1040 fprintf(stderr, "line %d: ", startlinno);
1042 vfprintf(stderr, msg, ap);
1043 outcslow('\n', stderr);
1047 * Exverror is called to raise the error exception. If the second argument
1048 * is not NULL then error prints an error message using printf style
1049 * formatting. It then raises the error exception.
1051 static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1053 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1057 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1059 TRACE(("\") pid=%d\n", getpid()));
1061 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1066 flush_stdout_stderr();
1067 raise_exception(cond);
1071 static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1073 ash_msg_and_raise_error(const char *msg, ...)
1078 ash_vmsg_and_raise(EXERROR, msg, ap);
1083 static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1085 ash_msg_and_raise(int cond, const char *msg, ...)
1090 ash_vmsg_and_raise(cond, msg, ap);
1096 * error/warning routines for external builtins
1099 ash_msg(const char *fmt, ...)
1109 * Return a string describing an error. The returned string may be a
1110 * pointer to a static buffer that will be overwritten on the next call.
1111 * Action describes the operation that got the error.
1114 errmsg(int e, const char *em)
1116 if (e == ENOENT || e == ENOTDIR) {
1123 /* ============ Memory allocation */
1126 * It appears that grabstackstr() will barf with such alignments
1127 * because stalloc() will return a string allocated in a new stackblock.
1129 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1131 /* Most machines require the value returned from malloc to be aligned
1132 * in some way. The following macro will get this right
1133 * on many machines. */
1134 SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,
1135 /* Minimum size of a block */
1136 MINSIZE = SHELL_ALIGN(504),
1139 struct stack_block {
1140 struct stack_block *prev;
1141 char space[MINSIZE];
1145 struct stack_block *stackp;
1148 struct stackmark *marknext;
1152 struct globals_memstack {
1153 struct stack_block *g_stackp; // = &stackbase;
1154 struct stackmark *markp;
1155 char *g_stacknxt; // = stackbase.space;
1156 char *sstrend; // = stackbase.space + MINSIZE;
1157 size_t g_stacknleft; // = MINSIZE;
1158 int herefd; // = -1;
1159 struct stack_block stackbase;
1161 extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1162 #define G_memstack (*ash_ptr_to_globals_memstack)
1163 #define g_stackp (G_memstack.g_stackp )
1164 #define markp (G_memstack.markp )
1165 #define g_stacknxt (G_memstack.g_stacknxt )
1166 #define sstrend (G_memstack.sstrend )
1167 #define g_stacknleft (G_memstack.g_stacknleft)
1168 #define herefd (G_memstack.herefd )
1169 #define stackbase (G_memstack.stackbase )
1170 #define INIT_G_memstack() do { \
1171 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1173 g_stackp = &stackbase; \
1174 g_stacknxt = stackbase.space; \
1175 g_stacknleft = MINSIZE; \
1176 sstrend = stackbase.space + MINSIZE; \
1180 #define stackblock() ((void *)g_stacknxt)
1181 #define stackblocksize() g_stacknleft
1185 ckrealloc(void * p, size_t nbytes)
1187 p = realloc(p, nbytes);
1189 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1194 ckmalloc(size_t nbytes)
1196 return ckrealloc(NULL, nbytes);
1200 ckzalloc(size_t nbytes)
1202 return memset(ckmalloc(nbytes), 0, nbytes);
1206 * Make a copy of a string in safe storage.
1209 ckstrdup(const char *s)
1211 char *p = strdup(s);
1213 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1218 * Parse trees for commands are allocated in lifo order, so we use a stack
1219 * to make this more efficient, and also to avoid all sorts of exception
1220 * handling code to handle interrupts in the middle of a parse.
1222 * The size 504 was chosen because the Ultrix malloc handles that size
1226 stalloc(size_t nbytes)
1231 aligned = SHELL_ALIGN(nbytes);
1232 if (aligned > g_stacknleft) {
1235 struct stack_block *sp;
1237 blocksize = aligned;
1238 if (blocksize < MINSIZE)
1239 blocksize = MINSIZE;
1240 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1241 if (len < blocksize)
1242 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1245 sp->prev = g_stackp;
1246 g_stacknxt = sp->space;
1247 g_stacknleft = blocksize;
1248 sstrend = g_stacknxt + blocksize;
1253 g_stacknxt += aligned;
1254 g_stacknleft -= aligned;
1259 stzalloc(size_t nbytes)
1261 return memset(stalloc(nbytes), 0, nbytes);
1268 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1269 write(STDERR_FILENO, "stunalloc\n", 10);
1273 g_stacknleft += g_stacknxt - (char *)p;
1278 * Like strdup but works with the ash stack.
1281 ststrdup(const char *p)
1283 size_t len = strlen(p) + 1;
1284 return memcpy(stalloc(len), p, len);
1288 setstackmark(struct stackmark *mark)
1290 mark->stackp = g_stackp;
1291 mark->stacknxt = g_stacknxt;
1292 mark->stacknleft = g_stacknleft;
1293 mark->marknext = markp;
1298 popstackmark(struct stackmark *mark)
1300 struct stack_block *sp;
1306 markp = mark->marknext;
1307 while (g_stackp != mark->stackp) {
1309 g_stackp = sp->prev;
1312 g_stacknxt = mark->stacknxt;
1313 g_stacknleft = mark->stacknleft;
1314 sstrend = mark->stacknxt + mark->stacknleft;
1319 * When the parser reads in a string, it wants to stick the string on the
1320 * stack and only adjust the stack pointer when it knows how big the
1321 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1322 * of space on top of the stack and stackblocklen returns the length of
1323 * this block. Growstackblock will grow this space by at least one byte,
1324 * possibly moving it (like realloc). Grabstackblock actually allocates the
1325 * part of the block that has been used.
1328 growstackblock(void)
1332 newlen = g_stacknleft * 2;
1333 if (newlen < g_stacknleft)
1334 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1338 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1339 struct stack_block *oldstackp;
1340 struct stackmark *xmark;
1341 struct stack_block *sp;
1342 struct stack_block *prevstackp;
1346 oldstackp = g_stackp;
1348 prevstackp = sp->prev;
1349 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1350 sp = ckrealloc(sp, grosslen);
1351 sp->prev = prevstackp;
1353 g_stacknxt = sp->space;
1354 g_stacknleft = newlen;
1355 sstrend = sp->space + newlen;
1358 * Stack marks pointing to the start of the old block
1359 * must be relocated to point to the new block
1362 while (xmark != NULL && xmark->stackp == oldstackp) {
1363 xmark->stackp = g_stackp;
1364 xmark->stacknxt = g_stacknxt;
1365 xmark->stacknleft = g_stacknleft;
1366 xmark = xmark->marknext;
1370 char *oldspace = g_stacknxt;
1371 size_t oldlen = g_stacknleft;
1372 char *p = stalloc(newlen);
1374 /* free the space we just allocated */
1375 g_stacknxt = memcpy(p, oldspace, oldlen);
1376 g_stacknleft += newlen;
1381 grabstackblock(size_t len)
1383 len = SHELL_ALIGN(len);
1385 g_stacknleft -= len;
1389 * The following routines are somewhat easier to use than the above.
1390 * The user declares a variable of type STACKSTR, which may be declared
1391 * to be a register. The macro STARTSTACKSTR initializes things. Then
1392 * the user uses the macro STPUTC to add characters to the string. In
1393 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1394 * grown as necessary. When the user is done, she can just leave the
1395 * string there and refer to it using stackblock(). Or she can allocate
1396 * the space for it using grabstackstr(). If it is necessary to allow
1397 * someone else to use the stack temporarily and then continue to grow
1398 * the string, the user should use grabstack to allocate the space, and
1399 * then call ungrabstr(p) to return to the previous mode of operation.
1401 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1402 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1403 * is space for at least one character.
1408 size_t len = stackblocksize();
1409 if (herefd >= 0 && len >= 1024) {
1410 full_write(herefd, stackblock(), len);
1411 return stackblock();
1414 return (char *)stackblock() + len;
1418 * Called from CHECKSTRSPACE.
1421 makestrspace(size_t newlen, char *p)
1423 size_t len = p - g_stacknxt;
1424 size_t size = stackblocksize();
1429 size = stackblocksize();
1431 if (nleft >= newlen)
1435 return (char *)stackblock() + len;
1439 stack_nputstr(const char *s, size_t n, char *p)
1441 p = makestrspace(n, p);
1442 p = (char *)memcpy(p, s, n) + n;
1447 stack_putstr(const char *s, char *p)
1449 return stack_nputstr(s, strlen(s), p);
1453 _STPUTC(int c, char *p)
1461 #define STARTSTACKSTR(p) ((p) = stackblock())
1462 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1463 #define CHECKSTRSPACE(n, p) do { \
1466 size_t m = sstrend - q; \
1468 (p) = makestrspace(l, q); \
1470 #define USTPUTC(c, p) (*(p)++ = (c))
1471 #define STACKSTRNUL(p) do { \
1472 if ((p) == sstrend) \
1473 (p) = growstackstr(); \
1476 #define STUNPUTC(p) (--(p))
1477 #define STTOPC(p) ((p)[-1])
1478 #define STADJUST(amount, p) ((p) += (amount))
1480 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1481 #define ungrabstackstr(s, p) stunalloc(s)
1482 #define stackstrend() ((void *)sstrend)
1485 /* ============ String helpers */
1488 * prefix -- see if pfx is a prefix of string.
1491 prefix(const char *string, const char *pfx)
1494 if (*pfx++ != *string++)
1497 return (char *) string;
1501 * Check for a valid number. This should be elsewhere.
1504 is_number(const char *p)
1509 } while (*++p != '\0');
1514 * Convert a string of digits to an integer, printing an error message on
1518 number(const char *s)
1521 ash_msg_and_raise_error(illnum, s);
1526 * Produce a possibly single quoted string suitable as input to the shell.
1527 * The return string is allocated on the stack.
1530 single_quote(const char *s)
1540 len = strchrnul(s, '\'') - s;
1542 q = p = makestrspace(len + 3, p);
1545 q = (char *)memcpy(q, s, len) + len;
1551 len = strspn(s, "'");
1555 q = p = makestrspace(len + 3, p);
1558 q = (char *)memcpy(q, s, len) + len;
1567 return stackblock();
1571 /* ============ nextopt */
1573 static char **argptr; /* argument list for builtin commands */
1574 static char *optionarg; /* set by nextopt (like getopt) */
1575 static char *optptr; /* used by nextopt */
1578 * XXX - should get rid of. Have all builtins use getopt(3).
1579 * The library getopt must have the BSD extension static variable
1580 * "optreset", otherwise it can't be used within the shell safely.
1582 * Standard option processing (a la getopt) for builtin routines.
1583 * The only argument that is passed to nextopt is the option string;
1584 * the other arguments are unnecessary. It returns the character,
1585 * or '\0' on end of input.
1588 nextopt(const char *optstring)
1595 if (p == NULL || *p == '\0') {
1596 /* We ate entire "-param", take next one */
1602 if (*++p == '\0') /* just "-" ? */
1605 if (LONE_DASH(p)) /* "--" ? */
1607 /* p => next "-param" */
1609 /* p => some option char in the middle of a "-param" */
1611 for (q = optstring; *q != c;) {
1613 ash_msg_and_raise_error("illegal option -%c", c);
1621 ash_msg_and_raise_error("no arg for -%c option", c);
1631 /* ============ Shell variables */
1634 * The parsefile structure pointed to by the global variable parsefile
1635 * contains information about the current file being read.
1638 struct redirtab *next;
1644 int nparam; /* # of positional parameters (without $0) */
1645 #if ENABLE_ASH_GETOPTS
1646 int optind; /* next parameter to be processed by getopts */
1647 int optoff; /* used by getopts */
1649 unsigned char malloced; /* if parameter list dynamically allocated */
1650 char **p; /* parameter list */
1654 * Free the list of positional parameters.
1657 freeparam(volatile struct shparam *param)
1659 if (param->malloced) {
1661 ap = ap1 = param->p;
1668 #if ENABLE_ASH_GETOPTS
1669 static void getoptsreset(const char *value);
1673 struct var *next; /* next entry in hash list */
1674 int flags; /* flags are defined above */
1675 const char *text; /* name=value */
1676 void (*func)(const char *); /* function to be called when */
1677 /* the variable gets set/unset */
1681 struct localvar *next; /* next local variable in list */
1682 struct var *vp; /* the variable that was made local */
1683 int flags; /* saved flags */
1684 const char *text; /* saved text */
1688 #define VEXPORT 0x01 /* variable is exported */
1689 #define VREADONLY 0x02 /* variable cannot be modified */
1690 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1691 #define VTEXTFIXED 0x08 /* text is statically allocated */
1692 #define VSTACK 0x10 /* text is allocated on the stack */
1693 #define VUNSET 0x20 /* the variable is not set */
1694 #define VNOFUNC 0x40 /* don't call the callback function */
1695 #define VNOSET 0x80 /* do not set variable - just readonly test */
1696 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1697 #if ENABLE_ASH_RANDOM_SUPPORT
1698 # define VDYNAMIC 0x200 /* dynamic variable */
1704 static const char defifsvar[] ALIGN1 = "IFS= \t\n";
1705 #define defifs (defifsvar + 4)
1707 static const char defifs[] ALIGN1 = " \t\n";
1711 /* Need to be before varinit_data[] */
1712 #if ENABLE_LOCALE_SUPPORT
1714 change_lc_all(const char *value)
1716 if (value && *value != '\0')
1717 setlocale(LC_ALL, value);
1720 change_lc_ctype(const char *value)
1722 if (value && *value != '\0')
1723 setlocale(LC_CTYPE, value);
1727 static void chkmail(void);
1728 static void changemail(const char *);
1730 static void changepath(const char *);
1731 #if ENABLE_ASH_RANDOM_SUPPORT
1732 static void change_random(const char *);
1735 static const struct {
1738 void (*func)(const char *);
1739 } varinit_data[] = {
1741 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1743 { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL },
1746 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0" , changemail },
1747 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1749 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1750 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1751 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1752 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1753 #if ENABLE_ASH_GETOPTS
1754 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
1756 #if ENABLE_ASH_RANDOM_SUPPORT
1757 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1759 #if ENABLE_LOCALE_SUPPORT
1760 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL\0" , change_lc_all },
1761 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE\0", change_lc_ctype },
1763 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1764 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE\0", NULL },
1769 struct globals_var {
1770 struct shparam shellparam; /* $@ current positional parameters */
1771 struct redirtab *redirlist;
1773 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1774 struct var *vartab[VTABSIZE];
1775 struct var varinit[ARRAY_SIZE(varinit_data)];
1777 extern struct globals_var *const ash_ptr_to_globals_var;
1778 #define G_var (*ash_ptr_to_globals_var)
1779 #define shellparam (G_var.shellparam )
1780 #define redirlist (G_var.redirlist )
1781 #define g_nullredirs (G_var.g_nullredirs )
1782 #define preverrout_fd (G_var.preverrout_fd)
1783 #define vartab (G_var.vartab )
1784 #define varinit (G_var.varinit )
1785 #define INIT_G_var() do { \
1787 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1789 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1790 varinit[i].flags = varinit_data[i].flags; \
1791 varinit[i].text = varinit_data[i].text; \
1792 varinit[i].func = varinit_data[i].func; \
1796 #define vifs varinit[0]
1798 # define vmail (&vifs)[1]
1799 # define vmpath (&vmail)[1]
1800 # define vpath (&vmpath)[1]
1802 # define vpath (&vifs)[1]
1804 #define vps1 (&vpath)[1]
1805 #define vps2 (&vps1)[1]
1806 #define vps4 (&vps2)[1]
1807 #if ENABLE_ASH_GETOPTS
1808 # define voptind (&vps4)[1]
1809 # if ENABLE_ASH_RANDOM_SUPPORT
1810 # define vrandom (&voptind)[1]
1813 # if ENABLE_ASH_RANDOM_SUPPORT
1814 # define vrandom (&vps4)[1]
1819 * The following macros access the values of the above variables.
1820 * They have to skip over the name. They return the null string
1821 * for unset variables.
1823 #define ifsval() (vifs.text + 4)
1824 #define ifsset() ((vifs.flags & VUNSET) == 0)
1826 # define mailval() (vmail.text + 5)
1827 # define mpathval() (vmpath.text + 9)
1828 # define mpathset() ((vmpath.flags & VUNSET) == 0)
1830 #define pathval() (vpath.text + 5)
1831 #define ps1val() (vps1.text + 4)
1832 #define ps2val() (vps2.text + 4)
1833 #define ps4val() (vps4.text + 4)
1834 #if ENABLE_ASH_GETOPTS
1835 # define optindval() (voptind.text + 7)
1839 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1840 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1842 #if ENABLE_ASH_GETOPTS
1844 getoptsreset(const char *value)
1846 shellparam.optind = number(value);
1847 shellparam.optoff = -1;
1852 * Return of a legal variable name (a letter or underscore followed by zero or
1853 * more letters, underscores, and digits).
1856 endofname(const char *name)
1864 if (!is_in_name(*p))
1871 * Compares two strings up to the first = or '\0'. The first
1872 * string must be terminated by '='; the second may be terminated by
1873 * either '=' or '\0'.
1876 varcmp(const char *p, const char *q)
1880 while ((c = *p) == (d = *q)) {
1895 varequal(const char *a, const char *b)
1897 return !varcmp(a, b);
1901 * Find the appropriate entry in the hash table from the name.
1903 static struct var **
1904 hashvar(const char *p)
1908 hashval = ((unsigned char) *p) << 4;
1909 while (*p && *p != '=')
1910 hashval += (unsigned char) *p++;
1911 return &vartab[hashval % VTABSIZE];
1915 vpcmp(const void *a, const void *b)
1917 return varcmp(*(const char **)a, *(const char **)b);
1921 * This routine initializes the builtin variables.
1931 * PS1 depends on uid
1933 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1934 vps1.text = "PS1=\\w \\$ ";
1937 vps1.text = "PS1=# ";
1940 end = vp + ARRAY_SIZE(varinit);
1942 vpp = hashvar(vp->text);
1945 } while (++vp < end);
1948 static struct var **
1949 findvar(struct var **vpp, const char *name)
1951 for (; *vpp; vpp = &(*vpp)->next) {
1952 if (varequal((*vpp)->text, name)) {
1960 * Find the value of a variable. Returns NULL if not set.
1963 lookupvar(const char *name)
1967 v = *findvar(hashvar(name), name);
1969 #if ENABLE_ASH_RANDOM_SUPPORT
1971 * Dynamic variables are implemented roughly the same way they are
1972 * in bash. Namely, they're "special" so long as they aren't unset.
1973 * As soon as they're unset, they're no longer dynamic, and dynamic
1974 * lookup will no longer happen at that point. -- PFM.
1976 if ((v->flags & VDYNAMIC))
1979 if (!(v->flags & VUNSET))
1980 return strchrnul(v->text, '=') + 1;
1986 * Search the environment of a builtin command.
1989 bltinlookup(const char *name)
1993 for (sp = cmdenviron; sp; sp = sp->next) {
1994 if (varequal(sp->text, name))
1995 return strchrnul(sp->text, '=') + 1;
1997 return lookupvar(name);
2001 * Same as setvar except that the variable and value are passed in
2002 * the first argument as name=value. Since the first argument will
2003 * be actually stored in the table, it should not be a string that
2005 * Called with interrupts off.
2008 setvareq(char *s, int flags)
2010 struct var *vp, **vpp;
2013 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2014 vp = *findvar(vpp, s);
2016 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2019 if (flags & VNOSAVE)
2022 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2028 if (vp->func && (flags & VNOFUNC) == 0)
2029 (*vp->func)(strchrnul(s, '=') + 1);
2031 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
2032 free((char*)vp->text);
2034 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2039 vp = ckzalloc(sizeof(*vp));
2041 /*vp->func = NULL; - ckzalloc did it */
2044 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2051 * Set the value of a variable. The flags argument is ored with the
2052 * flags of the variable. If val is NULL, the variable is unset.
2055 setvar(const char *name, const char *val, int flags)
2062 q = endofname(name);
2063 p = strchrnul(q, '=');
2065 if (!namelen || p != q)
2066 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2071 vallen = strlen(val);
2074 nameeq = ckmalloc(namelen + vallen + 2);
2075 p = (char *)memcpy(nameeq, name, namelen) + namelen;
2078 p = (char *)memcpy(p, val, vallen) + vallen;
2081 setvareq(nameeq, flags | VNOSAVE);
2085 #if ENABLE_ASH_GETOPTS
2087 * Safe version of setvar, returns 1 on success 0 on failure.
2090 setvarsafe(const char *name, const char *val, int flags)
2093 volatile int saveint;
2094 struct jmploc *volatile savehandler = exception_handler;
2095 struct jmploc jmploc;
2098 if (setjmp(jmploc.loc))
2101 exception_handler = &jmploc;
2102 setvar(name, val, flags);
2105 exception_handler = savehandler;
2106 RESTORE_INT(saveint);
2112 * Unset the specified variable.
2115 unsetvar(const char *s)
2121 vpp = findvar(hashvar(s), s);
2125 int flags = vp->flags;
2128 if (flags & VREADONLY)
2130 #if ENABLE_ASH_RANDOM_SUPPORT
2131 vp->flags &= ~VDYNAMIC;
2135 if ((flags & VSTRFIXED) == 0) {
2137 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2138 free((char*)vp->text);
2144 vp->flags &= ~VEXPORT;
2154 * Process a linked list of variable assignments.
2157 listsetvar(struct strlist *list_set_var, int flags)
2159 struct strlist *lp = list_set_var;
2165 setvareq(lp->text, flags);
2172 * Generate a list of variables satisfying the given conditions.
2175 listvars(int on, int off, char ***end)
2186 for (vp = *vpp; vp; vp = vp->next) {
2187 if ((vp->flags & mask) == on) {
2188 if (ep == stackstrend())
2189 ep = growstackstr();
2190 *ep++ = (char *) vp->text;
2193 } while (++vpp < vartab + VTABSIZE);
2194 if (ep == stackstrend())
2195 ep = growstackstr();
2199 return grabstackstr(ep);
2203 /* ============ Path search helper
2205 * The variable path (passed by reference) should be set to the start
2206 * of the path before the first call; padvance will update
2207 * this value as it proceeds. Successive calls to padvance will return
2208 * the possible path expansions in sequence. If an option (indicated by
2209 * a percent sign) appears in the path entry then the global variable
2210 * pathopt will be set to point to it; otherwise pathopt will be set to
2213 static const char *pathopt; /* set by padvance */
2216 padvance(const char **path, const char *name)
2226 for (p = start; *p && *p != ':' && *p != '%'; p++)
2228 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2229 while (stackblocksize() < len)
2233 memcpy(q, start, p - start);
2241 while (*p && *p != ':')
2248 return stalloc(len);
2252 /* ============ Prompt */
2254 static smallint doprompt; /* if set, prompt the user */
2255 static smallint needprompt; /* true if interactive and at start of line */
2257 #if ENABLE_FEATURE_EDITING
2258 static line_input_t *line_input_state;
2259 static const char *cmdedit_prompt;
2261 putprompt(const char *s)
2263 if (ENABLE_ASH_EXPAND_PRMT) {
2264 free((char*)cmdedit_prompt);
2265 cmdedit_prompt = ckstrdup(s);
2272 putprompt(const char *s)
2278 #if ENABLE_ASH_EXPAND_PRMT
2279 /* expandstr() needs parsing machinery, so it is far away ahead... */
2280 static const char *expandstr(const char *ps);
2282 #define expandstr(s) s
2286 setprompt(int whichprompt)
2289 #if ENABLE_ASH_EXPAND_PRMT
2290 struct stackmark smark;
2295 switch (whichprompt) {
2305 #if ENABLE_ASH_EXPAND_PRMT
2306 setstackmark(&smark);
2307 stalloc(stackblocksize());
2309 putprompt(expandstr(prompt));
2310 #if ENABLE_ASH_EXPAND_PRMT
2311 popstackmark(&smark);
2316 /* ============ The cd and pwd commands */
2318 #define CD_PHYSICAL 1
2321 static int docd(const char *, int);
2330 while ((i = nextopt("LP"))) {
2332 flags ^= CD_PHYSICAL;
2341 * Update curdir (the name of the current directory) in response to a
2345 updatepwd(const char *dir)
2352 cdcomppath = ststrdup(dir);
2355 if (curdir == nullstr)
2357 new = stack_putstr(curdir, new);
2359 new = makestrspace(strlen(dir) + 2, new);
2360 lim = (char *)stackblock() + 1;
2364 if (new > lim && *lim == '/')
2369 if (dir[1] == '/' && dir[2] != '/') {
2375 p = strtok(cdcomppath, "/");
2379 if (p[1] == '.' && p[2] == '\0') {
2391 new = stack_putstr(p, new);
2399 return stackblock();
2403 * Find out what the current directory is. If we already know the current
2404 * directory, this routine returns immediately.
2409 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2410 return dir ? dir : nullstr;
2414 setpwd(const char *val, int setold)
2418 oldcur = dir = curdir;
2421 setvar("OLDPWD", oldcur, VEXPORT);
2424 if (physdir != nullstr) {
2425 if (physdir != oldcur)
2429 if (oldcur == val || !val) {
2435 dir = ckstrdup(val);
2436 if (oldcur != dir && oldcur != nullstr) {
2441 setvar("PWD", dir, VEXPORT);
2444 static void hashcd(void);
2447 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2448 * know that the current directory has changed.
2451 docd(const char *dest, int flags)
2453 const char *dir = 0;
2456 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2459 if (!(flags & CD_PHYSICAL)) {
2460 dir = updatepwd(dest);
2475 cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2487 dest = bltinlookup(homestr);
2488 else if (LONE_DASH(dest)) {
2489 dest = bltinlookup("OLDPWD");
2511 path = bltinlookup("CDPATH");
2520 p = padvance(&path, dest);
2521 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2525 if (!docd(p, flags))
2530 ash_msg_and_raise_error("can't cd to %s", dest);
2533 if (flags & CD_PRINT)
2534 out1fmt(snlfmt, curdir);
2539 pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2542 const char *dir = curdir;
2546 if (physdir == nullstr)
2550 out1fmt(snlfmt, dir);
2555 /* ============ ... */
2557 #define IBUFSIZ COMMON_BUFSIZE
2558 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */
2560 /* Syntax classes */
2561 #define CWORD 0 /* character is nothing special */
2562 #define CNL 1 /* newline character */
2563 #define CBACK 2 /* a backslash character */
2564 #define CSQUOTE 3 /* single quote */
2565 #define CDQUOTE 4 /* double quote */
2566 #define CENDQUOTE 5 /* a terminating quote */
2567 #define CBQUOTE 6 /* backwards single quote */
2568 #define CVAR 7 /* a dollar sign */
2569 #define CENDVAR 8 /* a '}' character */
2570 #define CLP 9 /* a left paren in arithmetic */
2571 #define CRP 10 /* a right paren in arithmetic */
2572 #define CENDFILE 11 /* end of file */
2573 #define CCTL 12 /* like CWORD, except it must be escaped */
2574 #define CSPCL 13 /* these terminate a word */
2575 #define CIGN 14 /* character should be ignored */
2577 #if ENABLE_ASH_ALIAS
2581 #define PEOA_OR_PEOF PEOA
2585 #define PEOA_OR_PEOF PEOF
2588 /* number syntax index */
2589 #define BASESYNTAX 0 /* not in quotes */
2590 #define DQSYNTAX 1 /* in double quotes */
2591 #define SQSYNTAX 2 /* in single quotes */
2592 #define ARISYNTAX 3 /* in arithmetic */
2593 #define PSSYNTAX 4 /* prompt */
2595 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
2596 #define USE_SIT_FUNCTION
2599 #if ENABLE_ASH_MATH_SUPPORT
2600 static const char S_I_T[][4] = {
2601 #if ENABLE_ASH_ALIAS
2602 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */
2604 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */
2605 { CNL, CNL, CNL, CNL }, /* 2, \n */
2606 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */
2607 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */
2608 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */
2609 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */
2610 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */
2611 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */
2612 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */
2613 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */
2614 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */
2615 #ifndef USE_SIT_FUNCTION
2616 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2617 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2618 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2622 static const char S_I_T[][3] = {
2623 #if ENABLE_ASH_ALIAS
2624 { CSPCL, CIGN, CIGN }, /* 0, PEOA */
2626 { CSPCL, CWORD, CWORD }, /* 1, ' ' */
2627 { CNL, CNL, CNL }, /* 2, \n */
2628 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */
2629 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */
2630 { CVAR, CVAR, CWORD }, /* 5, $ */
2631 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */
2632 { CSPCL, CWORD, CWORD }, /* 7, ( */
2633 { CSPCL, CWORD, CWORD }, /* 8, ) */
2634 { CBACK, CBACK, CCTL }, /* 9, \ */
2635 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */
2636 { CENDVAR, CENDVAR, CWORD }, /* 11, } */
2637 #ifndef USE_SIT_FUNCTION
2638 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2639 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2640 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2643 #endif /* ASH_MATH_SUPPORT */
2645 #ifdef USE_SIT_FUNCTION
2648 SIT(int c, int syntax)
2650 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2651 #if ENABLE_ASH_ALIAS
2652 static const char syntax_index_table[] ALIGN1 = {
2653 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2654 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2655 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2659 static const char syntax_index_table[] ALIGN1 = {
2660 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2661 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2662 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2669 if (c == PEOF) /* 2^8+2 */
2671 #if ENABLE_ASH_ALIAS
2672 if (c == PEOA) /* 2^8+1 */
2676 #define U_C(c) ((unsigned char)(c))
2678 if ((unsigned char)c >= (unsigned char)(CTLESC)
2679 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
2683 s = strchrnul(spec_symbls, c);
2686 indx = syntax_index_table[s - spec_symbls];
2688 return S_I_T[indx][syntax];
2691 #else /* !USE_SIT_FUNCTION */
2693 #if ENABLE_ASH_ALIAS
2694 #define CSPCL_CIGN_CIGN_CIGN 0
2695 #define CSPCL_CWORD_CWORD_CWORD 1
2696 #define CNL_CNL_CNL_CNL 2
2697 #define CWORD_CCTL_CCTL_CWORD 3
2698 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
2699 #define CVAR_CVAR_CWORD_CVAR 5
2700 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
2701 #define CSPCL_CWORD_CWORD_CLP 7
2702 #define CSPCL_CWORD_CWORD_CRP 8
2703 #define CBACK_CBACK_CCTL_CBACK 9
2704 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
2705 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
2706 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
2707 #define CWORD_CWORD_CWORD_CWORD 13
2708 #define CCTL_CCTL_CCTL_CCTL 14
2710 #define CSPCL_CWORD_CWORD_CWORD 0
2711 #define CNL_CNL_CNL_CNL 1
2712 #define CWORD_CCTL_CCTL_CWORD 2
2713 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
2714 #define CVAR_CVAR_CWORD_CVAR 4
2715 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
2716 #define CSPCL_CWORD_CWORD_CLP 6
2717 #define CSPCL_CWORD_CWORD_CRP 7
2718 #define CBACK_CBACK_CCTL_CBACK 8
2719 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
2720 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
2721 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
2722 #define CWORD_CWORD_CWORD_CWORD 12
2723 #define CCTL_CCTL_CCTL_CCTL 13
2726 static const char syntax_index_table[258] = {
2727 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2728 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2729 #if ENABLE_ASH_ALIAS
2730 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
2732 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2733 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2734 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2735 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2736 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2737 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2738 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2739 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2740 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2741 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
2742 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
2743 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
2744 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
2745 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
2746 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
2747 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
2748 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
2749 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
2750 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
2751 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
2752 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
2753 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
2754 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
2755 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
2756 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
2757 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
2758 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
2759 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
2760 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
2761 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
2762 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
2763 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
2764 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
2765 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
2766 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
2767 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
2768 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
2769 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
2770 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
2771 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
2772 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
2773 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
2774 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
2775 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
2776 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
2777 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
2778 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
2779 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
2780 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
2781 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
2782 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
2783 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
2784 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
2785 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
2786 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
2787 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
2788 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
2789 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
2790 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
2791 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
2792 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
2793 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
2794 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
2795 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
2796 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
2797 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
2798 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
2799 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
2800 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
2801 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
2802 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
2803 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
2804 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
2805 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
2806 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
2807 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
2808 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
2809 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
2810 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
2811 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
2812 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
2813 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
2814 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
2815 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
2816 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
2817 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
2818 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
2819 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
2820 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
2821 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
2822 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
2823 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
2824 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
2825 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
2826 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
2827 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
2828 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
2829 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
2830 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
2831 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
2832 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
2833 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
2834 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
2835 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
2836 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
2837 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
2838 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
2839 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
2840 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
2841 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
2842 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
2843 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
2844 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
2845 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
2846 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
2847 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
2848 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
2853 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
2854 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2870 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
2871 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2893 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2894 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2895 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2896 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2897 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2898 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2899 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2900 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2901 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2902 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2903 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2904 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
2905 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2906 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
2907 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2908 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2909 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2910 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2919 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2920 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2921 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2922 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2923 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2924 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2952 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2953 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2954 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2957 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2985 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2986 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2987 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
2990 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])
2992 #endif /* USE_SIT_FUNCTION */
2995 /* ============ Alias handling */
2997 #if ENABLE_ASH_ALIAS
2999 #define ALIASINUSE 1
3010 static struct alias **atab; // [ATABSIZE];
3011 #define INIT_G_alias() do { \
3012 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3016 static struct alias **
3017 __lookupalias(const char *name) {
3018 unsigned int hashval;
3025 ch = (unsigned char)*p;
3029 ch = (unsigned char)*++p;
3031 app = &atab[hashval % ATABSIZE];
3033 for (; *app; app = &(*app)->next) {
3034 if (strcmp(name, (*app)->name) == 0) {
3042 static struct alias *
3043 lookupalias(const char *name, int check)
3045 struct alias *ap = *__lookupalias(name);
3047 if (check && ap && (ap->flag & ALIASINUSE))
3052 static struct alias *
3053 freealias(struct alias *ap)
3057 if (ap->flag & ALIASINUSE) {
3058 ap->flag |= ALIASDEAD;
3070 setalias(const char *name, const char *val)
3072 struct alias *ap, **app;
3074 app = __lookupalias(name);
3078 if (!(ap->flag & ALIASINUSE)) {
3081 ap->val = ckstrdup(val);
3082 ap->flag &= ~ALIASDEAD;
3085 ap = ckzalloc(sizeof(struct alias));
3086 ap->name = ckstrdup(name);
3087 ap->val = ckstrdup(val);
3088 /*ap->flag = 0; - ckzalloc did it */
3089 /*ap->next = NULL;*/
3096 unalias(const char *name)
3100 app = __lookupalias(name);
3104 *app = freealias(*app);
3115 struct alias *ap, **app;
3119 for (i = 0; i < ATABSIZE; i++) {
3121 for (ap = *app; ap; ap = *app) {
3122 *app = freealias(*app);
3132 printalias(const struct alias *ap)
3134 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3138 * TODO - sort output
3141 aliascmd(int argc UNUSED_PARAM, char **argv)
3150 for (i = 0; i < ATABSIZE; i++) {
3151 for (ap = atab[i]; ap; ap = ap->next) {
3157 while ((n = *++argv) != NULL) {
3158 v = strchr(n+1, '=');
3159 if (v == NULL) { /* n+1: funny ksh stuff */
3160 ap = *__lookupalias(n);
3162 fprintf(stderr, "%s: %s not found\n", "alias", n);
3176 unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3180 while ((i = nextopt("a")) != '\0') {
3186 for (i = 0; *argptr; argptr++) {
3187 if (unalias(*argptr)) {
3188 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3196 #endif /* ASH_ALIAS */
3199 /* ============ jobs.c */
3201 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3204 #define FORK_NOJOB 2
3206 /* mode flags for showjob(s) */
3207 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
3208 #define SHOW_PID 0x04 /* include process pid */
3209 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
3212 * A job structure contains information about a job. A job is either a
3213 * single process or a set of processes contained in a pipeline. In the
3214 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3219 pid_t pid; /* process id */
3220 int status; /* last process status from wait() */
3221 char *cmd; /* text of command being run */
3225 struct procstat ps0; /* status of process */
3226 struct procstat *ps; /* status or processes when more than one */
3228 int stopstatus; /* status of a stopped job */
3231 nprocs: 16, /* number of processes */
3233 #define JOBRUNNING 0 /* at least one proc running */
3234 #define JOBSTOPPED 1 /* all procs are stopped */
3235 #define JOBDONE 2 /* all procs are completed */
3237 sigint: 1, /* job was killed by SIGINT */
3238 jobctl: 1, /* job running under job control */
3240 waited: 1, /* true if this entry has been waited for */
3241 used: 1, /* true if this entry is in used */
3242 changed: 1; /* true if status has changed */
3243 struct job *prev_job; /* previous job */
3246 static struct job *makejob(/*union node *,*/ int);
3248 #define forkshell(job, node, mode) forkshell(job, mode)
3250 static int forkshell(struct job *, union node *, int);
3251 static int waitforjob(struct job *);
3254 enum { doing_jobctl = 0 };
3255 #define setjobctl(on) do {} while (0)
3257 static smallint doing_jobctl; //references:8
3258 static void setjobctl(int);
3262 * Set the signal handler for the specified signal. The routine figures
3263 * out what it should be set to.
3266 setsignal(int signo)
3270 struct sigaction act;
3276 else if (*t != '\0')
3278 if (rootshell && action == S_DFL) {
3281 if (iflag || minusc || sflag == 0)
3304 t = &sigmode[signo - 1];
3308 * current setting unknown
3310 if (sigaction(signo, NULL, &act) == -1) {
3312 * Pretend it worked; maybe we should give a warning
3313 * here, but other shells don't. We don't alter
3314 * sigmode, so that we retry every time.
3318 tsig = S_RESET; /* force to be set */
3319 if (act.sa_handler == SIG_IGN) {
3322 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3324 tsig = S_IGN; /* don't hard ignore these */
3328 if (tsig == S_HARD_IGN || tsig == action)
3330 act.sa_handler = SIG_DFL;
3333 act.sa_handler = onsig;
3336 act.sa_handler = SIG_IGN;
3341 sigfillset(&act.sa_mask);
3342 sigaction_set(signo, &act);
3345 /* mode flags for set_curjob */
3346 #define CUR_DELETE 2
3347 #define CUR_RUNNING 1
3348 #define CUR_STOPPED 0
3350 /* mode flags for dowait */
3351 #define DOWAIT_NONBLOCK WNOHANG
3352 #define DOWAIT_BLOCK 0
3355 /* pgrp of shell on invocation */
3356 static int initialpgrp; //references:2
3357 static int ttyfd = -1; //5
3360 static struct job *jobtab; //5
3362 static unsigned njobs; //4
3364 static struct job *curjob; //lots
3365 /* number of presumed living untracked jobs */
3366 static int jobless; //4
3369 set_curjob(struct job *jp, unsigned mode)
3372 struct job **jpp, **curp;
3374 /* first remove from list */
3375 jpp = curp = &curjob;
3380 jpp = &jp1->prev_job;
3382 *jpp = jp1->prev_job;
3384 /* Then re-insert in correct position */
3392 /* job being deleted */
3395 /* newly created job or backgrounded job,
3396 put after all stopped jobs. */
3400 if (!jp1 || jp1->state != JOBSTOPPED)
3403 jpp = &jp1->prev_job;
3409 /* newly stopped job - becomes curjob */
3410 jp->prev_job = *jpp;
3418 jobno(const struct job *jp)
3420 return jp - jobtab + 1;
3425 * Convert a job name to a job structure.
3428 #define getjob(name, getctl) getjob(name)
3431 getjob(const char *name, int getctl)
3435 const char *err_msg = "No such job: %s";
3439 char *(*match)(const char *, const char *);
3454 if (c == '+' || c == '%') {
3456 err_msg = "No current job";
3462 err_msg = "No previous job";
3471 // TODO: number() instead? It does error checking...
3474 jp = jobtab + num - 1;
3491 if (match(jp->ps[0].cmd, p)) {
3495 err_msg = "%s: ambiguous";
3502 err_msg = "job %s not created under job control";
3503 if (getctl && jp->jobctl == 0)
3508 ash_msg_and_raise_error(err_msg, name);
3512 * Mark a job structure as unused.
3515 freejob(struct job *jp)
3517 struct procstat *ps;
3521 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3522 if (ps->cmd != nullstr)
3525 if (jp->ps != &jp->ps0)
3528 set_curjob(jp, CUR_DELETE);
3534 xtcsetpgrp(int fd, pid_t pgrp)
3536 if (tcsetpgrp(fd, pgrp))
3537 ash_msg_and_raise_error("can't set tty process group (%m)");
3541 * Turn job control on and off.
3543 * Note: This code assumes that the third arg to ioctl is a character
3544 * pointer, which is true on Berkeley systems but not System V. Since
3545 * System V doesn't have job control yet, this isn't a problem now.
3547 * Called with interrupts off.
3555 if (on == doing_jobctl || rootshell == 0)
3559 ofd = fd = open(_PATH_TTY, O_RDWR);
3561 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3562 * That sometimes helps to acquire controlling tty.
3563 * Obviously, a workaround for bugs when someone
3564 * failed to provide a controlling tty to bash! :) */
3570 fd = fcntl(fd, F_DUPFD, 10);
3575 /* fd is a tty at this point */
3576 close_on_exec_on(fd);
3577 do { /* while we are in the background */
3578 pgrp = tcgetpgrp(fd);
3581 ash_msg("can't access tty; job control turned off");
3585 if (pgrp == getpgrp())
3596 xtcsetpgrp(fd, pgrp);
3598 /* turning job control off */
3601 /* was xtcsetpgrp, but this can make exiting ash
3602 * loop forever if pty is already deleted */
3603 tcsetpgrp(fd, pgrp);
3618 killcmd(int argc, char **argv)
3621 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3623 if (argv[i][0] == '%') {
3624 struct job *jp = getjob(argv[i], 0);
3625 unsigned pid = jp->ps[0].pid;
3626 /* Enough space for ' -NNN<nul>' */
3627 argv[i] = alloca(sizeof(int)*3 + 3);
3628 /* kill_main has matching code to expect
3629 * leading space. Needed to not confuse
3630 * negative pids with "kill -SIGNAL_NO" syntax */
3631 sprintf(argv[i], " -%u", pid);
3633 } while (argv[++i]);
3635 return kill_main(argc, argv);
3639 showpipe(struct job *jp, FILE *out)
3641 struct procstat *sp;
3642 struct procstat *spend;
3644 spend = jp->ps + jp->nprocs;
3645 for (sp = jp->ps + 1; sp < spend; sp++)
3646 fprintf(out, " | %s", sp->cmd);
3647 outcslow('\n', out);
3648 flush_stdout_stderr();
3653 restartjob(struct job *jp, int mode)
3655 struct procstat *ps;
3661 if (jp->state == JOBDONE)
3663 jp->state = JOBRUNNING;
3665 if (mode == FORK_FG)
3666 xtcsetpgrp(ttyfd, pgid);
3667 killpg(pgid, SIGCONT);
3671 if (WIFSTOPPED(ps->status)) {
3677 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3683 fg_bgcmd(int argc UNUSED_PARAM, char **argv)
3690 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3695 jp = getjob(*argv, 1);
3696 if (mode == FORK_BG) {
3697 set_curjob(jp, CUR_RUNNING);
3698 fprintf(out, "[%d] ", jobno(jp));
3700 outstr(jp->ps->cmd, out);
3702 retval = restartjob(jp, mode);
3703 } while (*argv && *++argv);
3709 sprint_status(char *s, int status, int sigonly)
3715 if (!WIFEXITED(status)) {
3717 if (WIFSTOPPED(status))
3718 st = WSTOPSIG(status);
3721 st = WTERMSIG(status);
3723 if (st == SIGINT || st == SIGPIPE)
3726 if (WIFSTOPPED(status))
3731 col = fmtstr(s, 32, strsignal(st));
3732 if (WCOREDUMP(status)) {
3733 col += fmtstr(s + col, 16, " (core dumped)");
3735 } else if (!sigonly) {
3736 st = WEXITSTATUS(status);
3738 col = fmtstr(s, 16, "Done(%d)", st);
3740 col = fmtstr(s, 16, "Done");
3747 * Do a wait system call. If job control is compiled in, we accept
3748 * stopped processes. If block is zero, we return a value of zero
3749 * rather than blocking.
3751 * System V doesn't have a non-blocking wait system call. It does
3752 * have a SIGCLD signal that is sent to a process when one of it's
3753 * children dies. The obvious way to use SIGCLD would be to install
3754 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
3755 * was received, and have waitproc bump another counter when it got
3756 * the status of a process. Waitproc would then know that a wait
3757 * system call would not block if the two counters were different.
3758 * This approach doesn't work because if a process has children that
3759 * have not been waited for, System V will send it a SIGCLD when it
3760 * installs a signal handler for SIGCLD. What this means is that when
3761 * a child exits, the shell will be sent SIGCLD signals continuously
3762 * until is runs out of stack space, unless it does a wait call before
3763 * restoring the signal handler. The code below takes advantage of
3764 * this (mis)feature by installing a signal handler for SIGCLD and
3765 * then checking to see whether it was called. If there are any
3766 * children to be waited for, it will be.
3768 * If neither SYSV nor BSD is defined, we don't implement nonblocking
3769 * waits at all. In this case, the user will not be informed when
3770 * a background process until the next time she runs a real program
3771 * (as opposed to running a builtin command or just typing return),
3772 * and the jobs command may give out of date information.
3775 waitproc(int wait_flags, int *status)
3779 wait_flags |= WUNTRACED;
3781 /* NB: _not_ safe_waitpid, we need to detect EINTR */
3782 return waitpid(-1, status, wait_flags);
3786 * Wait for a process to terminate.
3789 dowait(int wait_flags, struct job *job)
3794 struct job *thisjob;
3797 TRACE(("dowait(%d) called\n", wait_flags));
3798 pid = waitproc(wait_flags, &status);
3799 TRACE(("wait returns pid=%d, status=%d\n", pid, status));
3801 /* If we were doing blocking wait and (probably) got EINTR,
3802 * check for pending sigs received while waiting.
3803 * (NB: can be moved into callers if needed) */
3804 if (wait_flags == DOWAIT_BLOCK && pendingsig)
3805 raise_exception(EXSIG);
3810 for (jp = curjob; jp; jp = jp->prev_job) {
3811 struct procstat *sp;
3812 struct procstat *spend;
3813 if (jp->state == JOBDONE)
3816 spend = jp->ps + jp->nprocs;
3819 if (sp->pid == pid) {
3820 TRACE(("Job %d: changing status of proc %d "
3821 "from 0x%x to 0x%x\n",
3822 jobno(jp), pid, sp->status, status));
3823 sp->status = status;
3826 if (sp->status == -1)
3829 if (state == JOBRUNNING)
3831 if (WIFSTOPPED(sp->status)) {
3832 jp->stopstatus = sp->status;
3836 } while (++sp < spend);
3841 if (!WIFSTOPPED(status))
3847 if (state != JOBRUNNING) {
3848 thisjob->changed = 1;
3850 if (thisjob->state != state) {
3851 TRACE(("Job %d: changing state from %d to %d\n",
3852 jobno(thisjob), thisjob->state, state));
3853 thisjob->state = state;
3855 if (state == JOBSTOPPED) {
3856 set_curjob(thisjob, CUR_STOPPED);
3865 if (thisjob && thisjob == job) {
3869 len = sprint_status(s, status, 1);
3881 showjob(FILE *out, struct job *jp, int mode)
3883 struct procstat *ps;
3884 struct procstat *psend;
3891 if (mode & SHOW_PGID) {
3892 /* just output process (group) id of pipeline */
3893 fprintf(out, "%d\n", ps->pid);
3897 col = fmtstr(s, 16, "[%d] ", jobno(jp));
3902 else if (curjob && jp == curjob->prev_job)
3905 if (mode & SHOW_PID)
3906 col += fmtstr(s + col, 16, "%d ", ps->pid);
3908 psend = ps + jp->nprocs;
3910 if (jp->state == JOBRUNNING) {
3911 strcpy(s + col, "Running");
3912 col += sizeof("Running") - 1;
3914 int status = psend[-1].status;
3915 if (jp->state == JOBSTOPPED)
3916 status = jp->stopstatus;
3917 col += sprint_status(s + col, status, 0);
3923 /* for each process */
3924 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
3926 fprintf(out, "%s%*c%s",
3927 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
3929 if (!(mode & SHOW_PID)) {
3933 if (++ps == psend) {
3934 outcslow('\n', out);
3941 if (jp->state == JOBDONE) {
3942 TRACE(("showjob: freeing job %d\n", jobno(jp)));
3948 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3949 * statuses have changed since the last call to showjobs.
3952 showjobs(FILE *out, int mode)
3956 TRACE(("showjobs(%x) called\n", mode));
3958 /* If not even one job changed, there is nothing to do */
3959 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3962 for (jp = curjob; jp; jp = jp->prev_job) {
3963 if (!(mode & SHOW_CHANGED) || jp->changed) {
3964 showjob(out, jp, mode);
3970 jobscmd(int argc UNUSED_PARAM, char **argv)
3975 while ((m = nextopt("lp"))) {
3985 showjob(stdout, getjob(*argv,0), mode);
3988 showjobs(stdout, mode);
3995 getstatus(struct job *job)
4000 status = job->ps[job->nprocs - 1].status;
4001 retval = WEXITSTATUS(status);
4002 if (!WIFEXITED(status)) {
4004 retval = WSTOPSIG(status);
4005 if (!WIFSTOPPED(status))
4008 /* XXX: limits number of signals */
4009 retval = WTERMSIG(status);
4011 if (retval == SIGINT)
4017 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
4018 jobno(job), job->nprocs, status, retval));
4023 waitcmd(int argc UNUSED_PARAM, char **argv)
4032 raise_exception(EXSIG);
4039 /* wait for all jobs */
4043 if (!jp) /* no running procs */
4045 if (jp->state == JOBRUNNING)
4050 dowait(DOWAIT_BLOCK, NULL);
4056 if (**argv != '%') {
4057 pid_t pid = number(*argv);
4062 if (job->ps[job->nprocs - 1].pid == pid)
4064 job = job->prev_job;
4067 job = getjob(*argv, 0);
4068 /* loop until process terminated or stopped */
4069 while (job->state == JOBRUNNING)
4070 dowait(DOWAIT_BLOCK, NULL);
4072 retval = getstatus(job);
4086 struct job *jp, *jq;
4088 len = njobs * sizeof(*jp);
4090 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4092 offset = (char *)jp - (char *)jq;
4094 /* Relocate pointers */
4097 jq = (struct job *)((char *)jq + l);
4101 #define joff(p) ((struct job *)((char *)(p) + l))
4102 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4103 if (joff(jp)->ps == &jq->ps0)
4104 jmove(joff(jp)->ps);
4105 if (joff(jp)->prev_job)
4106 jmove(joff(jp)->prev_job);
4116 jp = (struct job *)((char *)jp + len);
4120 } while (--jq >= jp);
4125 * Return a new job structure.
4126 * Called with interrupts off.
4129 makejob(/*union node *node,*/ int nprocs)
4134 for (i = njobs, jp = jobtab; ; jp++) {
4141 if (jp->state != JOBDONE || !jp->waited)
4150 memset(jp, 0, sizeof(*jp));
4152 /* jp->jobctl is a bitfield.
4153 * "jp->jobctl |= jobctl" likely to give awful code */
4157 jp->prev_job = curjob;
4162 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4164 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4171 * Return a string identifying a command (to be printed by the
4174 static char *cmdnextc;
4177 cmdputs(const char *s)
4179 static const char vstype[VSTYPE + 1][3] = {
4180 "", "}", "-", "+", "?", "=",
4181 "%", "%%", "#", "##"
4182 USE_ASH_BASH_COMPAT(, ":", "/", "//")
4185 const char *p, *str;
4186 char c, cc[2] = " ";
4191 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4193 while ((c = *p++) != 0) {
4201 if ((subtype & VSTYPE) == VSLENGTH)
4205 if (!(subtype & VSQUOTE) == !(quoted & 1))
4211 str = "\"}" + !(quoted & 1);
4218 case CTLBACKQ+CTLQUOTE:
4221 #if ENABLE_ASH_MATH_SUPPORT
4236 if ((subtype & VSTYPE) != VSNORMAL)
4238 str = vstype[subtype & VSTYPE];
4239 if (subtype & VSNUL)
4248 /* These can only happen inside quotes */
4261 while ((c = *str++)) {
4266 USTPUTC('"', nextc);
4272 /* cmdtxt() and cmdlist() call each other */
4273 static void cmdtxt(union node *n);
4276 cmdlist(union node *np, int sep)
4278 for (; np; np = np->narg.next) {
4282 if (sep && np->narg.next)
4288 cmdtxt(union node *n)
4291 struct nodelist *lp;
4303 lp = n->npipe.cmdlist;
4321 cmdtxt(n->nbinary.ch1);
4337 cmdtxt(n->nif.test);
4340 if (n->nif.elsepart) {
4343 n = n->nif.elsepart;
4359 cmdtxt(n->nbinary.ch1);
4369 cmdputs(n->nfor.var);
4371 cmdlist(n->nfor.args, 1);
4376 cmdputs(n->narg.text);
4380 cmdlist(n->ncmd.args, 1);
4381 cmdlist(n->ncmd.redirect, 0);
4394 cmdputs(n->ncase.expr->narg.text);
4396 for (np = n->ncase.cases; np; np = np->nclist.next) {
4397 cmdtxt(np->nclist.pattern);
4399 cmdtxt(np->nclist.body);
4425 s[0] = n->nfile.fd + '0';
4429 if (n->type == NTOFD || n->type == NFROMFD) {
4430 s[0] = n->ndup.dupfd + '0';
4440 commandtext(union node *n)
4444 STARTSTACKSTR(cmdnextc);
4446 name = stackblock();
4447 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4448 name, cmdnextc, cmdnextc));
4449 return ckstrdup(name);
4454 * Fork off a subshell. If we are doing job control, give the subshell its
4455 * own process group. Jp is a job structure that the job is to be added to.
4456 * N is the command that will be evaluated by the child. Both jp and n may
4457 * be NULL. The mode parameter can be one of the following:
4458 * FORK_FG - Fork off a foreground process.
4459 * FORK_BG - Fork off a background process.
4460 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4461 * process group even if job control is on.
4463 * When job control is turned off, background processes have their standard
4464 * input redirected to /dev/null (except for the second and later processes
4467 * Called with interrupts off.
4470 * Clear traps on a fork.
4477 for (tp = trap; tp < &trap[NSIG]; tp++) {
4478 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4483 setsignal(tp - trap);
4489 /* Lives far away from here, needed for forkchild */
4490 static void closescript(void);
4492 /* Called after fork(), in child */
4494 forkchild(struct job *jp, /*union node *n,*/ int mode)
4498 TRACE(("Child shell %d\n", getpid()));
4505 /* do job control only in root shell */
4507 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4510 if (jp->nprocs == 0)
4513 pgrp = jp->ps[0].pid;
4514 /* This can fail because we are doing it in the parent also */
4515 (void)setpgid(0, pgrp);
4516 if (mode == FORK_FG)
4517 xtcsetpgrp(ttyfd, pgrp);
4522 if (mode == FORK_BG) {
4525 if (jp->nprocs == 0) {
4527 if (open(bb_dev_null, O_RDONLY) != 0)
4528 ash_msg_and_raise_error("can't open %s", bb_dev_null);
4531 if (!oldlvl && iflag) {
4536 for (jp = curjob; jp; jp = jp->prev_job)
4541 /* Called after fork(), in parent */
4543 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4546 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4548 TRACE(("In parent shell: child = %d\n", pid));
4550 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4556 if (mode != FORK_NOJOB && jp->jobctl) {
4559 if (jp->nprocs == 0)
4562 pgrp = jp->ps[0].pid;
4563 /* This can fail because we are doing it in the child also */
4567 if (mode == FORK_BG) {
4568 backgndpid = pid; /* set $! */
4569 set_curjob(jp, CUR_RUNNING);
4572 struct procstat *ps = &jp->ps[jp->nprocs++];
4577 if (doing_jobctl && n)
4578 ps->cmd = commandtext(n);
4584 forkshell(struct job *jp, union node *n, int mode)
4588 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4591 TRACE(("Fork failed, errno=%d", errno));
4594 ash_msg_and_raise_error("can't fork");
4597 forkchild(jp, /*n,*/ mode);
4599 forkparent(jp, n, mode, pid);
4604 * Wait for job to finish.
4606 * Under job control we have the problem that while a child process is
4607 * running interrupts generated by the user are sent to the child but not
4608 * to the shell. This means that an infinite loop started by an inter-
4609 * active user may be hard to kill. With job control turned off, an
4610 * interactive user may place an interactive program inside a loop. If
4611 * the interactive program catches interrupts, the user doesn't want
4612 * these interrupts to also abort the loop. The approach we take here
4613 * is to have the shell ignore interrupt signals while waiting for a
4614 * foreground process to terminate, and then send itself an interrupt
4615 * signal if the child process was terminated by an interrupt signal.
4616 * Unfortunately, some programs want to do a bit of cleanup and then
4617 * exit on interrupt; unless these processes terminate themselves by
4618 * sending a signal to themselves (instead of calling exit) they will
4619 * confuse this approach.
4621 * Called with interrupts off.
4624 waitforjob(struct job *jp)
4628 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4629 while (jp->state == JOBRUNNING) {
4630 dowait(DOWAIT_BLOCK, jp);
4635 xtcsetpgrp(ttyfd, rootpid);
4637 * This is truly gross.
4638 * If we're doing job control, then we did a TIOCSPGRP which
4639 * caused us (the shell) to no longer be in the controlling
4640 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4641 * intuit from the subprocess exit status whether a SIGINT
4642 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4644 if (jp->sigint) /* TODO: do the same with all signals */
4645 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4647 if (jp->state == JOBDONE)
4654 * return 1 if there are stopped jobs, otherwise 0
4666 if (jp && jp->state == JOBSTOPPED) {
4667 out2str("You have stopped jobs.\n");
4676 /* ============ redir.c
4678 * Code for dealing with input/output redirection.
4681 #define EMPTY -2 /* marks an unused slot in redirtab */
4682 #define CLOSED -3 /* marks a slot of previously-closed fd */
4684 # define PIPESIZE 4096 /* amount of buffering in a pipe */
4686 # define PIPESIZE PIPE_BUF
4690 * Open a file in noclobber mode.
4691 * The code was copied from bash.
4694 noclobberopen(const char *fname)
4697 struct stat finfo, finfo2;
4700 * If the file exists and is a regular file, return an error
4703 r = stat(fname, &finfo);
4704 if (r == 0 && S_ISREG(finfo.st_mode)) {
4710 * If the file was not present (r != 0), make sure we open it
4711 * exclusively so that if it is created before we open it, our open
4712 * will fail. Make sure that we do not truncate an existing file.
4713 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4714 * file was not a regular file, we leave O_EXCL off.
4717 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4718 fd = open(fname, O_WRONLY|O_CREAT, 0666);
4720 /* If the open failed, return the file descriptor right away. */
4725 * OK, the open succeeded, but the file may have been changed from a
4726 * non-regular file to a regular file between the stat and the open.
4727 * We are assuming that the O_EXCL open handles the case where FILENAME
4728 * did not exist and is symlinked to an existing file between the stat
4733 * If we can open it and fstat the file descriptor, and neither check
4734 * revealed that it was a regular file, and the file has not been
4735 * replaced, return the file descriptor.
4737 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4738 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4741 /* The file has been replaced. badness. */
4748 * Handle here documents. Normally we fork off a process to write the
4749 * data to a pipe. If the document is short, we can stuff the data in
4750 * the pipe without forking.
4752 /* openhere needs this forward reference */
4753 static void expandhere(union node *arg, int fd);
4755 openhere(union node *redir)
4761 ash_msg_and_raise_error("pipe call failed");
4762 if (redir->type == NHERE) {
4763 len = strlen(redir->nhere.doc->narg.text);
4764 if (len <= PIPESIZE) {
4765 full_write(pip[1], redir->nhere.doc->narg.text, len);
4769 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4771 signal(SIGINT, SIG_IGN);
4772 signal(SIGQUIT, SIG_IGN);
4773 signal(SIGHUP, SIG_IGN);
4775 signal(SIGTSTP, SIG_IGN);
4777 signal(SIGPIPE, SIG_DFL);
4778 if (redir->type == NHERE)
4779 full_write(pip[1], redir->nhere.doc->narg.text, len);
4781 expandhere(redir->nhere.doc, pip[1]);
4782 _exit(EXIT_SUCCESS);
4790 openredirect(union node *redir)
4795 switch (redir->nfile.type) {
4797 fname = redir->nfile.expfname;
4798 f = open(fname, O_RDONLY);
4803 fname = redir->nfile.expfname;
4804 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
4809 /* Take care of noclobber mode. */
4811 fname = redir->nfile.expfname;
4812 f = noclobberopen(fname);
4819 fname = redir->nfile.expfname;
4820 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4825 fname = redir->nfile.expfname;
4826 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4834 /* Fall through to eliminate warning. */
4841 f = openhere(redir);
4847 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4849 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
4853 * Copy a file descriptor to be >= to. Returns -1
4854 * if the source file descriptor is closed, EMPTY if there are no unused
4855 * file descriptors left.
4858 copyfd(int from, int to)
4862 newfd = fcntl(from, F_DUPFD, to);
4864 if (errno == EMFILE)
4866 ash_msg_and_raise_error("%d: %m", from);
4872 dupredirect(union node *redir, int f)
4874 int fd = redir->nfile.fd;
4876 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
4877 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
4878 copyfd(redir->ndup.dupfd, fd);
4890 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
4891 * old file descriptors are stashed away so that the redirection can be
4892 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
4893 * standard output, and the standard error if it becomes a duplicate of
4894 * stdout, is saved in memory.
4896 /* flags passed to redirect */
4897 #define REDIR_PUSH 01 /* save previous values of file descriptors */
4898 #define REDIR_SAVEFD2 03 /* set preverrout */
4900 redirect(union node *redir, int flags)
4902 struct redirtab *sv;
4913 if (flags & REDIR_PUSH) {
4914 sv = ckmalloc(sizeof(*sv));
4915 sv->next = redirlist;
4917 sv->nullredirs = g_nullredirs - 1;
4918 for (i = 0; i < 10; i++)
4919 sv->renamed[i] = EMPTY;
4923 fd = redir->nfile.fd;
4924 if ((redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD)
4925 && redir->ndup.dupfd == fd)
4926 continue; /* redirect from/to same file descriptor */
4928 newfd = openredirect(redir);
4930 /* Descriptor wasn't open before redirect.
4931 * Mark it for close in the future */
4932 if (sv && sv->renamed[fd] == EMPTY)
4933 sv->renamed[fd] = CLOSED;
4936 if (sv && sv->renamed[fd] == EMPTY) {
4937 i = fcntl(fd, F_DUPFD, 10);
4944 ash_msg_and_raise_error("%d: %m", fd);
4948 sv->renamed[fd] = i;
4954 dupredirect(redir, newfd);
4955 } while ((redir = redir->nfile.next) != NULL);
4957 if ((flags & REDIR_SAVEFD2) && sv && sv->renamed[2] >= 0)
4958 preverrout_fd = sv->renamed[2];
4962 * Undo the effects of the last redirection.
4967 struct redirtab *rp;
4970 if (--g_nullredirs >= 0)
4974 for (i = 0; i < 10; i++) {
4975 if (rp->renamed[i] == CLOSED) {
4980 if (rp->renamed[i] != EMPTY) {
4983 copyfd(rp->renamed[i], i);
4985 close(rp->renamed[i]);
4988 redirlist = rp->next;
4989 g_nullredirs = rp->nullredirs;
4995 * Undo all redirections. Called on error or interrupt.
4999 * Discard all saved file descriptors.
5002 clearredir(int drop)
5013 redirectsafe(union node *redir, int flags)
5016 volatile int saveint;
5017 struct jmploc *volatile savehandler = exception_handler;
5018 struct jmploc jmploc;
5021 err = setjmp(jmploc.loc) * 2;
5023 exception_handler = &jmploc;
5024 redirect(redir, flags);
5026 exception_handler = savehandler;
5027 if (err && exception != EXERROR)
5028 longjmp(exception_handler->loc, 1);
5029 RESTORE_INT(saveint);
5034 /* ============ Routines to expand arguments to commands
5036 * We have to deal with backquotes, shell variables, and file metacharacters.
5039 #if ENABLE_ASH_MATH_SUPPORT_64
5040 typedef int64_t arith_t;
5041 #define arith_t_type long long
5043 typedef long arith_t;
5044 #define arith_t_type long
5047 #if ENABLE_ASH_MATH_SUPPORT
5048 static arith_t dash_arith(const char *);
5049 static arith_t arith(const char *expr, int *perrcode);
5055 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5056 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5057 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5058 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5059 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5060 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5061 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5062 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5063 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5067 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5068 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5069 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5070 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5071 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5074 * Structure specifying which parts of the string should be searched
5075 * for IFS characters.
5078 struct ifsregion *next; /* next region in list */
5079 int begoff; /* offset of start of region */
5080 int endoff; /* offset of end of region */
5081 int nulonly; /* search for nul bytes only */
5085 struct strlist *list;
5086 struct strlist **lastp;
5089 /* output of current string */
5090 static char *expdest;
5091 /* list of back quote expressions */
5092 static struct nodelist *argbackq;
5093 /* first struct in list of ifs regions */
5094 static struct ifsregion ifsfirst;
5095 /* last struct in list */
5096 static struct ifsregion *ifslastp;
5097 /* holds expanded arg list */
5098 static struct arglist exparg;
5108 expdest = makestrspace(32, expdest);
5109 #if ENABLE_ASH_MATH_SUPPORT_64
5110 len = fmtstr(expdest, 32, "%lld", (long long) num);
5112 len = fmtstr(expdest, 32, "%ld", num);
5114 STADJUST(len, expdest);
5119 esclen(const char *start, const char *p)
5123 while (p > start && *--p == CTLESC) {
5130 * Remove any CTLESC characters from a string.
5133 _rmescapes(char *str, int flag)
5135 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5142 p = strpbrk(str, qchars);
5148 if (flag & RMESCAPE_ALLOC) {
5149 size_t len = p - str;
5150 size_t fulllen = len + strlen(p) + 1;
5152 if (flag & RMESCAPE_GROW) {
5153 r = makestrspace(fulllen, expdest);
5154 } else if (flag & RMESCAPE_HEAP) {
5155 r = ckmalloc(fulllen);
5157 r = stalloc(fulllen);
5161 q = (char *)memcpy(q, str, len) + len;
5164 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5165 globbing = flag & RMESCAPE_GLOB;
5166 notescaped = globbing;
5168 if (*p == CTLQUOTEMARK) {
5169 inquotes = ~inquotes;
5171 notescaped = globbing;
5175 /* naked back slash */
5181 if (notescaped && inquotes && *p != '/') {
5185 notescaped = globbing;
5190 if (flag & RMESCAPE_GROW) {
5192 STADJUST(q - r + 1, expdest);
5196 #define rmescapes(p) _rmescapes((p), 0)
5198 #define pmatch(a, b) !fnmatch((a), (b), 0)
5201 * Prepare a pattern for a expmeta (internal glob(3)) call.
5203 * Returns an stalloced string.
5206 preglob(const char *pattern, int quoted, int flag)
5208 flag |= RMESCAPE_GLOB;
5210 flag |= RMESCAPE_QUOTED;
5212 return _rmescapes((char *)pattern, flag);
5216 * Put a string on the stack.
5219 memtodest(const char *p, size_t len, int syntax, int quotes)
5223 q = makestrspace(len * 2, q);
5226 int c = signed_char2int(*p++);
5229 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5238 strtodest(const char *p, int syntax, int quotes)
5240 memtodest(p, strlen(p), syntax, quotes);
5244 * Record the fact that we have to scan this region of the
5245 * string for IFS characters.
5248 recordregion(int start, int end, int nulonly)
5250 struct ifsregion *ifsp;
5252 if (ifslastp == NULL) {
5256 ifsp = ckzalloc(sizeof(*ifsp));
5257 /*ifsp->next = NULL; - ckzalloc did it */
5258 ifslastp->next = ifsp;
5262 ifslastp->begoff = start;
5263 ifslastp->endoff = end;
5264 ifslastp->nulonly = nulonly;
5268 removerecordregions(int endoff)
5270 if (ifslastp == NULL)
5273 if (ifsfirst.endoff > endoff) {
5274 while (ifsfirst.next != NULL) {
5275 struct ifsregion *ifsp;
5277 ifsp = ifsfirst.next->next;
5278 free(ifsfirst.next);
5279 ifsfirst.next = ifsp;
5282 if (ifsfirst.begoff > endoff)
5285 ifslastp = &ifsfirst;
5286 ifsfirst.endoff = endoff;
5291 ifslastp = &ifsfirst;
5292 while (ifslastp->next && ifslastp->next->begoff < endoff)
5293 ifslastp=ifslastp->next;
5294 while (ifslastp->next != NULL) {
5295 struct ifsregion *ifsp;
5297 ifsp = ifslastp->next->next;
5298 free(ifslastp->next);
5299 ifslastp->next = ifsp;
5302 if (ifslastp->endoff > endoff)
5303 ifslastp->endoff = endoff;
5307 exptilde(char *startp, char *p, int flag)
5313 int quotes = flag & (EXP_FULL | EXP_CASE);
5318 while ((c = *++p) != '\0') {
5325 if (flag & EXP_VARTILDE)
5335 if (*name == '\0') {
5336 home = lookupvar(homestr);
5338 pw = getpwnam(name);
5343 if (!home || !*home)
5346 startloc = expdest - (char *)stackblock();
5347 strtodest(home, SQSYNTAX, quotes);
5348 recordregion(startloc, expdest - (char *)stackblock(), 0);
5356 * Execute a command inside back quotes. If it's a builtin command, we
5357 * want to save its output in a block obtained from malloc. Otherwise
5358 * we fork off a subprocess and get the output of the command via a pipe.
5359 * Should be called with interrupts off.
5361 struct backcmd { /* result of evalbackcmd */
5362 int fd; /* file descriptor to read from */
5363 int nleft; /* number of chars in buffer */
5364 char *buf; /* buffer */
5365 struct job *jp; /* job structure for command */
5368 /* These forward decls are needed to use "eval" code for backticks handling: */
5369 static uint8_t back_exitstatus; /* exit status of backquoted command */
5370 #define EV_EXIT 01 /* exit after evaluating tree */
5371 static void evaltree(union node *, int);
5374 evalbackcmd(union node *n, struct backcmd *result)
5386 saveherefd = herefd;
5394 ash_msg_and_raise_error("pipe call failed");
5395 jp = makejob(/*n,*/ 1);
5396 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5405 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5409 result->fd = pip[0];
5412 herefd = saveherefd;
5414 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5415 result->fd, result->buf, result->nleft, result->jp));
5419 * Expand stuff in backwards quotes.
5422 expbackq(union node *cmd, int quoted, int quotes)
5430 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
5431 struct stackmark smark;
5434 setstackmark(&smark);
5436 startloc = dest - (char *)stackblock();
5438 evalbackcmd(cmd, &in);
5439 popstackmark(&smark);
5446 memtodest(p, i, syntax, quotes);
5450 i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5451 TRACE(("expbackq: read returns %d\n", i));
5460 back_exitstatus = waitforjob(in.jp);
5464 /* Eat all trailing newlines */
5466 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5471 recordregion(startloc, dest - (char *)stackblock(), 0);
5472 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5473 (dest - (char *)stackblock()) - startloc,
5474 (dest - (char *)stackblock()) - startloc,
5475 stackblock() + startloc));
5478 #if ENABLE_ASH_MATH_SUPPORT
5480 * Expand arithmetic expression. Backup to start of expression,
5481 * evaluate, place result in (backed up) result, adjust string position.
5494 * This routine is slightly over-complicated for
5495 * efficiency. Next we scan backwards looking for the
5496 * start of arithmetic.
5498 start = stackblock();
5505 while (*p != CTLARI) {
5509 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5514 esc = esclen(start, p);
5524 removerecordregions(begoff);
5533 len = cvtnum(dash_arith(p + 2));
5536 recordregion(begoff, begoff + len, 0);
5540 /* argstr needs it */
5541 static char *evalvar(char *p, int flag, struct strlist *var_str_list);
5544 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5545 * characters to allow for further processing. Otherwise treat
5546 * $@ like $* since no splitting will be performed.
5548 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5549 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5550 * for correct expansion of "B=$A" word.
5553 argstr(char *p, int flag, struct strlist *var_str_list)
5555 static const char spclchars[] ALIGN1 = {
5563 CTLBACKQ | CTLQUOTE,
5564 #if ENABLE_ASH_MATH_SUPPORT
5569 const char *reject = spclchars;
5571 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
5572 int breakall = flag & EXP_WORD;
5577 if (!(flag & EXP_VARTILDE)) {
5579 } else if (flag & EXP_VARTILDE2) {
5584 if (flag & EXP_TILDE) {
5590 if (*q == CTLESC && (flag & EXP_QWORD))
5593 p = exptilde(p, q, flag);
5596 startloc = expdest - (char *)stackblock();
5598 length += strcspn(p + length, reject);
5600 if (c && (!(c & 0x80)
5601 #if ENABLE_ASH_MATH_SUPPORT
5605 /* c == '=' || c == ':' || c == CTLENDARI */
5610 expdest = stack_nputstr(p, length, expdest);
5611 newloc = expdest - (char *)stackblock();
5612 if (breakall && !inquotes && newloc > startloc) {
5613 recordregion(startloc, newloc, 0);
5624 if (flag & EXP_VARTILDE2) {
5628 flag |= EXP_VARTILDE2;
5633 * sort of a hack - expand tildes in variable
5634 * assignments (after the first '=' and after ':'s).
5643 case CTLENDVAR: /* ??? */
5646 /* "$@" syntax adherence hack */
5649 !memcmp(p, dolatstr, 4) &&
5650 (p[4] == CTLQUOTEMARK || (
5651 p[4] == CTLENDVAR &&
5652 p[5] == CTLQUOTEMARK
5655 p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;
5658 inquotes = !inquotes;
5671 p = evalvar(p, flag, var_str_list);
5675 case CTLBACKQ|CTLQUOTE:
5676 expbackq(argbackq->n, c, quotes);
5677 argbackq = argbackq->next;
5679 #if ENABLE_ASH_MATH_SUPPORT
5692 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int quotes,
5695 // This commented out code was added by James Simmons <jsimmons@infradead.org>
5696 // as part of a larger change when he added support for ${var/a/b}.
5697 // However, it broke # and % operators:
5701 //echo ${var#ab} abcdcd abcdcd
5702 //echo ${var##ab} abcdcd abcdcd
5703 //echo ${var#a*b} abcdcd ababcdcd (!)
5704 //echo ${var##a*b} cdcd cdcd
5705 //echo ${var#?} babcdcd ababcdcd (!)
5706 //echo ${var##?} babcdcd babcdcd
5707 //echo ${var#*} ababcdcd babcdcd (!)
5709 //echo ${var%cd} ababcd ababcd
5710 //echo ${var%%cd} ababcd abab (!)
5711 //echo ${var%c*d} ababcd ababcd
5712 //echo ${var%%c*d} abab ababcdcd (!)
5713 //echo ${var%?} ababcdc ababcdc
5714 //echo ${var%%?} ababcdc ababcdcd (!)
5715 //echo ${var%*} ababcdcd ababcdcd
5718 // Commenting it back out helped. Remove it completely if it really
5721 char *loc, *loc2; //, *full;
5727 int match; // = strlen(str);
5728 const char *s = loc2;
5735 match = pmatch(str, s); // this line was deleted
5737 // // chop off end if its '*'
5738 // full = strrchr(str, '*');
5739 // if (full && full != str)
5742 // // If str starts with '*' replace with s.
5743 // if ((*str == '*') && strlen(s) >= match) {
5744 // full = xstrdup(s);
5745 // strncpy(full+strlen(s)-match+1, str+1, match-1);
5747 // full = xstrndup(str, match);
5748 // match = strncmp(s, full, strlen(full));
5752 if (match) // if (!match)
5754 if (quotes && *loc == CTLESC)
5763 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5770 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5773 const char *s = loc2;
5778 match = pmatch(str, s);
5785 esc = esclen(startp, loc);
5796 static void varunset(const char *, const char *, const char *, int) NORETURN;
5798 varunset(const char *end, const char *var, const char *umsg, int varflags)
5804 msg = "parameter not set";
5806 if (*end == CTLENDVAR) {
5807 if (varflags & VSNUL)
5812 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5815 #if ENABLE_ASH_BASH_COMPAT
5817 parse_sub_pattern(char *arg, int inquotes)
5819 char *idx, *repl = NULL;
5828 /* Only the first '/' seen is our separator */
5835 if (!inquotes && c == '\\' && arg[1] == '\\')
5836 arg++; /* skip both \\, not just first one */
5843 #endif /* ENABLE_ASH_BASH_COMPAT */
5846 subevalvar(char *p, char *str, int strloc, int subtype,
5847 int startloc, int varflags, int quotes, struct strlist *var_str_list)
5849 struct nodelist *saveargbackq = argbackq;
5852 char *rmesc, *rmescend;
5853 USE_ASH_BASH_COMPAT(char *repl = NULL;)
5854 USE_ASH_BASH_COMPAT(char null = '\0';)
5855 USE_ASH_BASH_COMPAT(int pos, len, orig_len;)
5856 int saveherefd = herefd;
5857 int amount, workloc, resetloc;
5859 char *(*scan)(char*, char*, char*, char*, int, int);
5862 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
5864 STPUTC('\0', expdest);
5865 herefd = saveherefd;
5866 argbackq = saveargbackq;
5867 startp = (char *)stackblock() + startloc;
5871 setvar(str, startp, 0);
5872 amount = startp - expdest;
5873 STADJUST(amount, expdest);
5876 #if ENABLE_ASH_BASH_COMPAT
5878 loc = str = stackblock() + strloc;
5879 // TODO: number() instead? It does error checking...
5881 len = str - startp - 1;
5883 /* *loc != '\0', guaranteed by parser */
5887 /* We must adjust the length by the number of escapes we find. */
5888 for (ptr = startp; ptr < (str - 1); ptr++) {
5889 if(*ptr == CTLESC) {
5897 if (*loc++ == ':') {
5898 // TODO: number() instead? It does error checking...
5902 while (*loc && *loc != ':')
5905 // TODO: number() instead? It does error checking...
5908 if (pos >= orig_len) {
5912 if (len > (orig_len - pos))
5913 len = orig_len - pos;
5915 for (str = startp; pos; str++, pos--) {
5916 if (quotes && *str == CTLESC)
5919 for (loc = startp; len; len--) {
5920 if (quotes && *str == CTLESC)
5925 amount = loc - expdest;
5926 STADJUST(amount, expdest);
5931 varunset(p, str, startp, varflags);
5934 resetloc = expdest - (char *)stackblock();
5936 /* We'll comeback here if we grow the stack while handling
5937 * a VSREPLACE or VSREPLACEALL, since our pointers into the
5938 * stack will need rebasing, and we'll need to remove our work
5941 USE_ASH_BASH_COMPAT(restart:)
5943 amount = expdest - ((char *)stackblock() + resetloc);
5944 STADJUST(-amount, expdest);
5945 startp = (char *)stackblock() + startloc;
5948 rmescend = (char *)stackblock() + strloc;
5950 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5951 if (rmesc != startp) {
5953 startp = (char *)stackblock() + startloc;
5957 str = (char *)stackblock() + strloc;
5958 preglob(str, varflags & VSQUOTE, 0);
5959 workloc = expdest - (char *)stackblock();
5961 #if ENABLE_ASH_BASH_COMPAT
5962 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
5963 char *idx, *end, *restart_detect;
5966 repl = parse_sub_pattern(str, varflags & VSQUOTE);
5971 /* If there's no pattern to match, return the expansion unmolested */
5979 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
5981 /* No match, advance */
5982 restart_detect = stackblock();
5983 STPUTC(*idx, expdest);
5984 if (quotes && *idx == CTLESC) {
5987 STPUTC(*idx, expdest);
5989 if (stackblock() != restart_detect)
5997 if (subtype == VSREPLACEALL) {
5999 if (quotes && *idx == CTLESC)
6007 for (loc = repl; *loc; loc++) {
6008 restart_detect = stackblock();
6009 STPUTC(*loc, expdest);
6010 if (stackblock() != restart_detect)
6015 if (subtype == VSREPLACE) {
6017 restart_detect = stackblock();
6018 STPUTC(*idx, expdest);
6019 if (stackblock() != restart_detect)
6028 /* We've put the replaced text into a buffer at workloc, now
6029 * move it to the right place and adjust the stack.
6031 startp = stackblock() + startloc;
6032 STPUTC('\0', expdest);
6033 memmove(startp, stackblock() + workloc, len);
6034 startp[len++] = '\0';
6035 amount = expdest - ((char *)stackblock() + startloc + len - 1);
6036 STADJUST(-amount, expdest);
6039 #endif /* ENABLE_ASH_BASH_COMPAT */
6041 subtype -= VSTRIMRIGHT;
6043 if (subtype < 0 || subtype > 7)
6046 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
6047 zero = subtype >> 1;
6048 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6049 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6051 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6054 memmove(startp, loc, str - loc);
6055 loc = startp + (str - loc) - 1;
6058 amount = loc - expdest;
6059 STADJUST(amount, expdest);
6065 * Add the value of a specialized variable to the stack string.
6068 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6078 int quoted = varflags & VSQUOTE;
6079 int subtype = varflags & VSTYPE;
6080 int quotes = flags & (EXP_FULL | EXP_CASE);
6082 if (quoted && (flags & EXP_FULL))
6083 sep = 1 << CHAR_BIT;
6085 syntax = quoted ? DQSYNTAX : BASESYNTAX;
6094 num = shellparam.nparam;
6104 p = makestrspace(NOPTS, expdest);
6105 for (i = NOPTS - 1; i >= 0; i--) {
6107 USTPUTC(optletters(i), p);
6118 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
6119 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
6125 while ((p = *ap++)) {
6128 partlen = strlen(p);
6131 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6132 memtodest(p, partlen, syntax, quotes);
6138 if (subtype == VSPLUS || subtype == VSLENGTH) {
6159 // TODO: number() instead? It does error checking...
6161 if (num < 0 || num > shellparam.nparam)
6163 p = num ? shellparam.p[num - 1] : arg0;
6166 /* NB: name has form "VAR=..." */
6168 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6169 * which should be considered before we check variables. */
6171 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6175 str = var_str_list->text;
6176 eq = strchr(str, '=');
6177 if (!eq) /* stop at first non-assignment */
6180 if (name_len == (unsigned)(eq - str)
6181 && strncmp(str, name, name_len) == 0) {
6183 /* goto value; - WRONG! */
6184 /* think "A=1 A=2 B=$A" */
6186 var_str_list = var_str_list->next;
6187 } while (var_str_list);
6191 p = lookupvar(name);
6197 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6198 memtodest(p, len, syntax, quotes);
6202 if (subtype == VSPLUS || subtype == VSLENGTH)
6203 STADJUST(-len, expdest);
6208 * Expand a variable, and return a pointer to the next character in the
6212 evalvar(char *p, int flag, struct strlist *var_str_list)
6224 subtype = varflags & VSTYPE;
6225 quoted = varflags & VSQUOTE;
6227 easy = (!quoted || (*var == '@' && shellparam.nparam));
6228 startloc = expdest - (char *)stackblock();
6229 p = strchr(p, '=') + 1;
6232 varlen = varvalue(var, varflags, flag, var_str_list);
6233 if (varflags & VSNUL)
6236 if (subtype == VSPLUS) {
6237 varlen = -1 - varlen;
6241 if (subtype == VSMINUS) {
6245 p, flag | EXP_TILDE |
6246 (quoted ? EXP_QWORD : EXP_WORD),
6256 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6258 if (subevalvar(p, var, /* strloc: */ 0,
6259 subtype, startloc, varflags,
6265 * Remove any recorded regions beyond
6268 removerecordregions(startloc);
6278 if (varlen < 0 && uflag)
6279 varunset(p, var, 0, 0);
6281 if (subtype == VSLENGTH) {
6282 cvtnum(varlen > 0 ? varlen : 0);
6286 if (subtype == VSNORMAL) {
6297 case VSTRIMRIGHTMAX:
6298 #if ENABLE_ASH_BASH_COMPAT
6311 * Terminate the string and start recording the pattern
6314 STPUTC('\0', expdest);
6315 patloc = expdest - (char *)stackblock();
6316 if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6318 /* quotes: */ flag & (EXP_FULL | EXP_CASE),
6321 int amount = expdest - (
6322 (char *)stackblock() + patloc - 1
6324 STADJUST(-amount, expdest);
6326 /* Remove any recorded regions beyond start of variable */
6327 removerecordregions(startloc);
6329 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6333 if (subtype != VSNORMAL) { /* skip to end of alternative */
6339 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6341 argbackq = argbackq->next;
6342 } else if (c == CTLVAR) {
6343 if ((*p++ & VSTYPE) != VSNORMAL)
6345 } else if (c == CTLENDVAR) {
6355 * Break the argument string into pieces based upon IFS and add the
6356 * strings to the argument list. The regions of the string to be
6357 * searched for IFS characters have been stored by recordregion.
6360 ifsbreakup(char *string, struct arglist *arglist)
6362 struct ifsregion *ifsp;
6367 const char *ifs, *realifs;
6372 if (ifslastp != NULL) {
6375 realifs = ifsset() ? ifsval() : defifs;
6378 p = string + ifsp->begoff;
6379 nulonly = ifsp->nulonly;
6380 ifs = nulonly ? nullstr : realifs;
6382 while (p < string + ifsp->endoff) {
6386 if (!strchr(ifs, *p)) {
6391 ifsspc = (strchr(defifs, *p) != NULL);
6392 /* Ignore IFS whitespace at start */
6393 if (q == start && ifsspc) {
6399 sp = stzalloc(sizeof(*sp));
6401 *arglist->lastp = sp;
6402 arglist->lastp = &sp->next;
6406 if (p >= string + ifsp->endoff) {
6412 if (strchr(ifs, *p) == NULL) {
6416 if (strchr(defifs, *p) == NULL) {
6431 } while (ifsp != NULL);
6440 sp = stzalloc(sizeof(*sp));
6442 *arglist->lastp = sp;
6443 arglist->lastp = &sp->next;
6449 struct ifsregion *p;
6454 struct ifsregion *ifsp;
6460 ifsfirst.next = NULL;
6465 * Add a file name to the list.
6468 addfname(const char *name)
6472 sp = stzalloc(sizeof(*sp));
6473 sp->text = ststrdup(name);
6475 exparg.lastp = &sp->next;
6478 static char *expdir;
6481 * Do metacharacter (i.e. *, ?, [...]) expansion.
6484 expmeta(char *enddir, char *name)
6499 for (p = name; *p; p++) {
6500 if (*p == '*' || *p == '?')
6502 else if (*p == '[') {
6509 if (*q == '/' || *q == '\0')
6516 } else if (*p == '\\')
6518 else if (*p == '/') {
6525 if (metaflag == 0) { /* we've reached the end of the file name */
6526 if (enddir != expdir)
6534 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6545 } while (p < start);
6547 if (enddir == expdir) {
6549 } else if (enddir == expdir + 1 && *expdir == '/') {
6558 if (enddir != expdir)
6560 if (*endname == 0) {
6572 while (!intpending && (dp = readdir(dirp)) != NULL) {
6573 if (dp->d_name[0] == '.' && !matchdot)
6575 if (pmatch(start, dp->d_name)) {
6577 strcpy(enddir, dp->d_name);
6580 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6583 expmeta(p, endname);
6592 static struct strlist *
6593 msort(struct strlist *list, int len)
6595 struct strlist *p, *q = NULL;
6596 struct strlist **lpp;
6604 for (n = half; --n >= 0;) {
6608 q->next = NULL; /* terminate first half of list */
6609 q = msort(list, half); /* sort first half of list */
6610 p = msort(p, len - half); /* sort second half */
6613 #if ENABLE_LOCALE_SUPPORT
6614 if (strcoll(p->text, q->text) < 0)
6616 if (strcmp(p->text, q->text) < 0)
6640 * Sort the results of file name expansion. It calculates the number of
6641 * strings to sort and then calls msort (short for merge sort) to do the
6644 static struct strlist *
6645 expsort(struct strlist *str)
6651 for (sp = str; sp; sp = sp->next)
6653 return msort(str, len);
6657 expandmeta(struct strlist *str /*, int flag*/)
6659 static const char metachars[] ALIGN1 = {
6662 /* TODO - EXP_REDIR */
6665 struct strlist **savelastp;
6671 if (!strpbrk(str->text, metachars))
6673 savelastp = exparg.lastp;
6676 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
6678 int i = strlen(str->text);
6679 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
6687 if (exparg.lastp == savelastp) {
6692 *exparg.lastp = str;
6693 rmescapes(str->text);
6694 exparg.lastp = &str->next;
6696 *exparg.lastp = NULL;
6697 *savelastp = sp = expsort(*savelastp);
6698 while (sp->next != NULL)
6700 exparg.lastp = &sp->next;
6707 * Perform variable substitution and command substitution on an argument,
6708 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6709 * perform splitting and file name expansion. When arglist is NULL, perform
6710 * here document expansion.
6713 expandarg(union node *arg, struct arglist *arglist, int flag)
6718 argbackq = arg->narg.backquote;
6719 STARTSTACKSTR(expdest);
6720 ifsfirst.next = NULL;
6722 argstr(arg->narg.text, flag,
6723 /* var_str_list: */ arglist ? arglist->list : NULL);
6724 p = _STPUTC('\0', expdest);
6726 if (arglist == NULL) {
6727 return; /* here document expanded */
6729 p = grabstackstr(p);
6730 exparg.lastp = &exparg.list;
6734 if (flag & EXP_FULL) {
6735 ifsbreakup(p, &exparg);
6736 *exparg.lastp = NULL;
6737 exparg.lastp = &exparg.list;
6738 expandmeta(exparg.list /*, flag*/);
6740 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
6742 sp = stzalloc(sizeof(*sp));
6745 exparg.lastp = &sp->next;
6749 *exparg.lastp = NULL;
6751 *arglist->lastp = exparg.list;
6752 arglist->lastp = exparg.lastp;
6757 * Expand shell variables and backquotes inside a here document.
6760 expandhere(union node *arg, int fd)
6763 expandarg(arg, (struct arglist *)NULL, 0);
6764 full_write(fd, stackblock(), expdest - (char *)stackblock());
6768 * Returns true if the pattern matches the string.
6771 patmatch(char *pattern, const char *string)
6773 return pmatch(preglob(pattern, 0, 0), string);
6777 * See if a pattern matches in a case statement.
6780 casematch(union node *pattern, char *val)
6782 struct stackmark smark;
6785 setstackmark(&smark);
6786 argbackq = pattern->narg.backquote;
6787 STARTSTACKSTR(expdest);
6789 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
6790 /* var_str_list: */ NULL);
6791 STACKSTRNUL(expdest);
6792 result = patmatch(stackblock(), val);
6793 popstackmark(&smark);
6798 /* ============ find_command */
6802 int (*builtin)(int, char **);
6803 /* unsigned flags; */
6805 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
6806 /* "regular" builtins always take precedence over commands,
6807 * regardless of PATH=....%builtin... position */
6808 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
6809 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
6812 smallint cmdtype; /* CMDxxx */
6815 /* index >= 0 for commands without path (slashes) */
6816 /* (TODO: what exactly does the value mean? PATH position?) */
6817 /* index == -1 for commands with slashes */
6818 /* index == (-2 - applet_no) for NOFORK applets */
6819 const struct builtincmd *cmd;
6820 struct funcnode *func;
6823 /* values of cmdtype */
6824 #define CMDUNKNOWN -1 /* no entry in table for command */
6825 #define CMDNORMAL 0 /* command is an executable program */
6826 #define CMDFUNCTION 1 /* command is a shell function */
6827 #define CMDBUILTIN 2 /* command is a shell builtin */
6829 /* action to find_command() */
6830 #define DO_ERR 0x01 /* prints errors */
6831 #define DO_ABS 0x02 /* checks absolute paths */
6832 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
6833 #define DO_ALTPATH 0x08 /* using alternate path */
6834 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
6836 static void find_command(char *, struct cmdentry *, int, const char *);
6839 /* ============ Hashing commands */
6842 * When commands are first encountered, they are entered in a hash table.
6843 * This ensures that a full path search will not have to be done for them
6844 * on each invocation.
6846 * We should investigate converting to a linear search, even though that
6847 * would make the command name "hash" a misnomer.
6851 struct tblentry *next; /* next entry in hash chain */
6852 union param param; /* definition of builtin function */
6853 smallint cmdtype; /* CMDxxx */
6854 char rehash; /* if set, cd done since entry created */
6855 char cmdname[1]; /* name of command */
6858 static struct tblentry **cmdtable;
6859 #define INIT_G_cmdtable() do { \
6860 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
6863 static int builtinloc = -1; /* index in path of %builtin, or -1 */
6867 tryexec(USE_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
6871 #if ENABLE_FEATURE_SH_STANDALONE
6872 if (applet_no >= 0) {
6873 if (APPLET_IS_NOEXEC(applet_no))
6874 run_applet_no_and_exit(applet_no, argv);
6875 /* re-exec ourselves with the new arguments */
6876 execve(bb_busybox_exec_path, argv, envp);
6877 /* If they called chroot or otherwise made the binary no longer
6878 * executable, fall through */
6885 execve(cmd, argv, envp);
6886 } while (errno == EINTR);
6888 execve(cmd, argv, envp);
6894 if (errno == ENOEXEC) {
6898 for (ap = argv; *ap; ap++)
6900 ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0]));
6902 ap[0] = cmd = (char *)DEFAULT_SHELL;
6905 while ((*ap++ = *argv++) != NULL)
6914 * Exec a program. Never returns. If you change this routine, you may
6915 * have to change the find_command routine as well.
6917 static void shellexec(char **, const char *, int) NORETURN;
6919 shellexec(char **argv, const char *path, int idx)
6925 #if ENABLE_FEATURE_SH_STANDALONE
6930 envp = listvars(VEXPORT, VUNSET, 0);
6931 if (strchr(argv[0], '/') != NULL
6932 #if ENABLE_FEATURE_SH_STANDALONE
6933 || (applet_no = find_applet_by_name(argv[0])) >= 0
6936 tryexec(USE_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
6940 while ((cmdname = padvance(&path, argv[0])) != NULL) {
6941 if (--idx < 0 && pathopt == NULL) {
6942 tryexec(USE_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
6943 if (errno != ENOENT && errno != ENOTDIR)
6950 /* Map to POSIX errors */
6962 exitstatus = exerrno;
6963 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
6964 argv[0], e, suppressint));
6965 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
6970 printentry(struct tblentry *cmdp)
6976 idx = cmdp->param.index;
6979 name = padvance(&path, cmdp->cmdname);
6981 } while (--idx >= 0);
6982 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
6986 * Clear out command entries. The argument specifies the first entry in
6987 * PATH which has changed.
6990 clearcmdentry(int firstchange)
6992 struct tblentry **tblp;
6993 struct tblentry **pp;
6994 struct tblentry *cmdp;
6997 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
6999 while ((cmdp = *pp) != NULL) {
7000 if ((cmdp->cmdtype == CMDNORMAL &&
7001 cmdp->param.index >= firstchange)
7002 || (cmdp->cmdtype == CMDBUILTIN &&
7003 builtinloc >= firstchange)
7016 * Locate a command in the command hash table. If "add" is nonzero,
7017 * add the command to the table if it is not already present. The
7018 * variable "lastcmdentry" is set to point to the address of the link
7019 * pointing to the entry, so that delete_cmd_entry can delete the
7022 * Interrupts must be off if called with add != 0.
7024 static struct tblentry **lastcmdentry;
7026 static struct tblentry *
7027 cmdlookup(const char *name, int add)
7029 unsigned int hashval;
7031 struct tblentry *cmdp;
7032 struct tblentry **pp;
7035 hashval = (unsigned char)*p << 4;
7037 hashval += (unsigned char)*p++;
7039 pp = &cmdtable[hashval % CMDTABLESIZE];
7040 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7041 if (strcmp(cmdp->cmdname, name) == 0)
7045 if (add && cmdp == NULL) {
7046 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7048 /* + 1 - already done because
7049 * tblentry::cmdname is char[1] */);
7050 /*cmdp->next = NULL; - ckzalloc did it */
7051 cmdp->cmdtype = CMDUNKNOWN;
7052 strcpy(cmdp->cmdname, name);
7059 * Delete the command entry returned on the last lookup.
7062 delete_cmd_entry(void)
7064 struct tblentry *cmdp;
7067 cmdp = *lastcmdentry;
7068 *lastcmdentry = cmdp->next;
7069 if (cmdp->cmdtype == CMDFUNCTION)
7070 freefunc(cmdp->param.func);
7076 * Add a new command entry, replacing any existing command entry for
7077 * the same name - except special builtins.
7080 addcmdentry(char *name, struct cmdentry *entry)
7082 struct tblentry *cmdp;
7084 cmdp = cmdlookup(name, 1);
7085 if (cmdp->cmdtype == CMDFUNCTION) {
7086 freefunc(cmdp->param.func);
7088 cmdp->cmdtype = entry->cmdtype;
7089 cmdp->param = entry->u;
7094 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7096 struct tblentry **pp;
7097 struct tblentry *cmdp;
7099 struct cmdentry entry;
7102 if (nextopt("r") != '\0') {
7107 if (*argptr == NULL) {
7108 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7109 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7110 if (cmdp->cmdtype == CMDNORMAL)
7118 while ((name = *argptr) != NULL) {
7119 cmdp = cmdlookup(name, 0);
7121 && (cmdp->cmdtype == CMDNORMAL
7122 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7126 find_command(name, &entry, DO_ERR, pathval());
7127 if (entry.cmdtype == CMDUNKNOWN)
7135 * Called when a cd is done. Marks all commands so the next time they
7136 * are executed they will be rehashed.
7141 struct tblentry **pp;
7142 struct tblentry *cmdp;
7144 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7145 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7146 if (cmdp->cmdtype == CMDNORMAL
7147 || (cmdp->cmdtype == CMDBUILTIN
7148 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7158 * Fix command hash table when PATH changed.
7159 * Called before PATH is changed. The argument is the new value of PATH;
7160 * pathval() still returns the old value at this point.
7161 * Called with interrupts off.
7164 changepath(const char *new)
7172 firstchange = 9999; /* assume no change */
7178 if ((*old == '\0' && *new == ':')
7179 || (*old == ':' && *new == '\0'))
7181 old = new; /* ignore subsequent differences */
7185 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7191 if (builtinloc < 0 && idx_bltin >= 0)
7192 builtinloc = idx_bltin; /* zap builtins */
7193 if (builtinloc >= 0 && idx_bltin < 0)
7195 clearcmdentry(firstchange);
7196 builtinloc = idx_bltin;
7211 #define TENDBQUOTE 12
7228 typedef smallint token_id_t;
7230 /* first char is indicating which tokens mark the end of a list */
7231 static const char *const tokname_array[] = {
7245 #define KWDOFFSET 13
7246 /* the following are keywords */
7268 static char buf[16];
7271 //if (tok < TSEMI) return tokname_array[tok] + 1;
7272 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
7277 sprintf(buf + (tok >= TSEMI), "%s%c",
7278 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
7282 /* Wrapper around strcmp for qsort/bsearch/... */
7284 pstrcmp(const void *a, const void *b)
7286 return strcmp((char*) a, (*(char**) b) + 1);
7289 static const char *const *
7290 findkwd(const char *s)
7292 return bsearch(s, tokname_array + KWDOFFSET,
7293 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7294 sizeof(tokname_array[0]), pstrcmp);
7298 * Locate and print what a word is...
7301 describe_command(char *command, int describe_command_verbose)
7303 struct cmdentry entry;
7304 struct tblentry *cmdp;
7305 #if ENABLE_ASH_ALIAS
7306 const struct alias *ap;
7308 const char *path = pathval();
7310 if (describe_command_verbose) {
7314 /* First look at the keywords */
7315 if (findkwd(command)) {
7316 out1str(describe_command_verbose ? " is a shell keyword" : command);
7320 #if ENABLE_ASH_ALIAS
7321 /* Then look at the aliases */
7322 ap = lookupalias(command, 0);
7324 if (!describe_command_verbose) {
7329 out1fmt(" is an alias for %s", ap->val);
7333 /* Then check if it is a tracked alias */
7334 cmdp = cmdlookup(command, 0);
7336 entry.cmdtype = cmdp->cmdtype;
7337 entry.u = cmdp->param;
7339 /* Finally use brute force */
7340 find_command(command, &entry, DO_ABS, path);
7343 switch (entry.cmdtype) {
7345 int j = entry.u.index;
7351 p = padvance(&path, command);
7355 if (describe_command_verbose) {
7357 (cmdp ? " a tracked alias for" : nullstr), p
7366 if (describe_command_verbose) {
7367 out1str(" is a shell function");
7374 if (describe_command_verbose) {
7375 out1fmt(" is a %sshell builtin",
7376 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7377 "special " : nullstr
7385 if (describe_command_verbose) {
7386 out1str(": not found\n");
7391 outstr("\n", stdout);
7396 typecmd(int argc UNUSED_PARAM, char **argv)
7402 /* type -p ... ? (we don't bother checking for 'p') */
7403 if (argv[1] && argv[1][0] == '-') {
7408 err |= describe_command(argv[i++], verbose);
7413 #if ENABLE_ASH_CMDCMD
7415 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7423 while ((c = nextopt("pvV")) != '\0')
7425 verify |= VERIFY_VERBOSE;
7427 verify |= VERIFY_BRIEF;
7432 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7433 if (verify && (*argptr != NULL)) {
7434 return describe_command(*argptr, verify - VERIFY_BRIEF);
7442 /* ============ eval.c */
7444 static int funcblocksize; /* size of structures in function */
7445 static int funcstringsize; /* size of strings in node */
7446 static void *funcblock; /* block to allocate function from */
7447 static char *funcstring; /* block to allocate strings from */
7449 /* flags in argument to evaltree */
7450 #define EV_EXIT 01 /* exit after evaluating tree */
7451 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7452 #define EV_BACKCMD 04 /* command executing within back quotes */
7454 static const short nodesize[26] = {
7455 SHELL_ALIGN(sizeof(struct ncmd)),
7456 SHELL_ALIGN(sizeof(struct npipe)),
7457 SHELL_ALIGN(sizeof(struct nredir)),
7458 SHELL_ALIGN(sizeof(struct nredir)),
7459 SHELL_ALIGN(sizeof(struct nredir)),
7460 SHELL_ALIGN(sizeof(struct nbinary)),
7461 SHELL_ALIGN(sizeof(struct nbinary)),
7462 SHELL_ALIGN(sizeof(struct nbinary)),
7463 SHELL_ALIGN(sizeof(struct nif)),
7464 SHELL_ALIGN(sizeof(struct nbinary)),
7465 SHELL_ALIGN(sizeof(struct nbinary)),
7466 SHELL_ALIGN(sizeof(struct nfor)),
7467 SHELL_ALIGN(sizeof(struct ncase)),
7468 SHELL_ALIGN(sizeof(struct nclist)),
7469 SHELL_ALIGN(sizeof(struct narg)),
7470 SHELL_ALIGN(sizeof(struct narg)),
7471 SHELL_ALIGN(sizeof(struct nfile)),
7472 SHELL_ALIGN(sizeof(struct nfile)),
7473 SHELL_ALIGN(sizeof(struct nfile)),
7474 SHELL_ALIGN(sizeof(struct nfile)),
7475 SHELL_ALIGN(sizeof(struct nfile)),
7476 SHELL_ALIGN(sizeof(struct ndup)),
7477 SHELL_ALIGN(sizeof(struct ndup)),
7478 SHELL_ALIGN(sizeof(struct nhere)),
7479 SHELL_ALIGN(sizeof(struct nhere)),
7480 SHELL_ALIGN(sizeof(struct nnot)),
7483 static void calcsize(union node *n);
7486 sizenodelist(struct nodelist *lp)
7489 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7496 calcsize(union node *n)
7500 funcblocksize += nodesize[n->type];
7503 calcsize(n->ncmd.redirect);
7504 calcsize(n->ncmd.args);
7505 calcsize(n->ncmd.assign);
7508 sizenodelist(n->npipe.cmdlist);
7513 calcsize(n->nredir.redirect);
7514 calcsize(n->nredir.n);
7521 calcsize(n->nbinary.ch2);
7522 calcsize(n->nbinary.ch1);
7525 calcsize(n->nif.elsepart);
7526 calcsize(n->nif.ifpart);
7527 calcsize(n->nif.test);
7530 funcstringsize += strlen(n->nfor.var) + 1;
7531 calcsize(n->nfor.body);
7532 calcsize(n->nfor.args);
7535 calcsize(n->ncase.cases);
7536 calcsize(n->ncase.expr);
7539 calcsize(n->nclist.body);
7540 calcsize(n->nclist.pattern);
7541 calcsize(n->nclist.next);
7545 sizenodelist(n->narg.backquote);
7546 funcstringsize += strlen(n->narg.text) + 1;
7547 calcsize(n->narg.next);
7554 calcsize(n->nfile.fname);
7555 calcsize(n->nfile.next);
7559 calcsize(n->ndup.vname);
7560 calcsize(n->ndup.next);
7564 calcsize(n->nhere.doc);
7565 calcsize(n->nhere.next);
7568 calcsize(n->nnot.com);
7574 nodeckstrdup(char *s)
7576 char *rtn = funcstring;
7578 strcpy(funcstring, s);
7579 funcstring += strlen(s) + 1;
7583 static union node *copynode(union node *);
7585 static struct nodelist *
7586 copynodelist(struct nodelist *lp)
7588 struct nodelist *start;
7589 struct nodelist **lpp;
7594 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7595 (*lpp)->n = copynode(lp->n);
7597 lpp = &(*lpp)->next;
7604 copynode(union node *n)
7611 funcblock = (char *) funcblock + nodesize[n->type];
7615 new->ncmd.redirect = copynode(n->ncmd.redirect);
7616 new->ncmd.args = copynode(n->ncmd.args);
7617 new->ncmd.assign = copynode(n->ncmd.assign);
7620 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7621 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
7626 new->nredir.redirect = copynode(n->nredir.redirect);
7627 new->nredir.n = copynode(n->nredir.n);
7634 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7635 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7638 new->nif.elsepart = copynode(n->nif.elsepart);
7639 new->nif.ifpart = copynode(n->nif.ifpart);
7640 new->nif.test = copynode(n->nif.test);
7643 new->nfor.var = nodeckstrdup(n->nfor.var);
7644 new->nfor.body = copynode(n->nfor.body);
7645 new->nfor.args = copynode(n->nfor.args);
7648 new->ncase.cases = copynode(n->ncase.cases);
7649 new->ncase.expr = copynode(n->ncase.expr);
7652 new->nclist.body = copynode(n->nclist.body);
7653 new->nclist.pattern = copynode(n->nclist.pattern);
7654 new->nclist.next = copynode(n->nclist.next);
7658 new->narg.backquote = copynodelist(n->narg.backquote);
7659 new->narg.text = nodeckstrdup(n->narg.text);
7660 new->narg.next = copynode(n->narg.next);
7667 new->nfile.fname = copynode(n->nfile.fname);
7668 new->nfile.fd = n->nfile.fd;
7669 new->nfile.next = copynode(n->nfile.next);
7673 new->ndup.vname = copynode(n->ndup.vname);
7674 new->ndup.dupfd = n->ndup.dupfd;
7675 new->ndup.fd = n->ndup.fd;
7676 new->ndup.next = copynode(n->ndup.next);
7680 new->nhere.doc = copynode(n->nhere.doc);
7681 new->nhere.fd = n->nhere.fd;
7682 new->nhere.next = copynode(n->nhere.next);
7685 new->nnot.com = copynode(n->nnot.com);
7688 new->type = n->type;
7693 * Make a copy of a parse tree.
7695 static struct funcnode *
7696 copyfunc(union node *n)
7701 funcblocksize = offsetof(struct funcnode, n);
7704 blocksize = funcblocksize;
7705 f = ckmalloc(blocksize + funcstringsize);
7706 funcblock = (char *) f + offsetof(struct funcnode, n);
7707 funcstring = (char *) f + blocksize;
7714 * Define a shell function.
7717 defun(char *name, union node *func)
7719 struct cmdentry entry;
7722 entry.cmdtype = CMDFUNCTION;
7723 entry.u.func = copyfunc(func);
7724 addcmdentry(name, &entry);
7728 static int evalskip; /* set if we are skipping commands */
7729 /* reasons for skipping commands (see comment on breakcmd routine) */
7730 #define SKIPBREAK (1 << 0)
7731 #define SKIPCONT (1 << 1)
7732 #define SKIPFUNC (1 << 2)
7733 #define SKIPFILE (1 << 3)
7734 #define SKIPEVAL (1 << 4)
7735 static int skipcount; /* number of levels to skip */
7736 static int funcnest; /* depth of function calls */
7737 static int loopnest; /* current loop nesting level */
7739 /* forward decl way out to parsing code - dotrap needs it */
7740 static int evalstring(char *s, int mask);
7743 * Called to execute a trap. Perhaps we should avoid entering new trap
7744 * handlers while we are executing a trap handler.
7755 savestatus = exitstatus;
7759 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
7767 skip = evalstring(p, SKIPEVAL);
7768 exitstatus = savestatus;
7776 /* forward declarations - evaluation is fairly recursive business... */
7777 static void evalloop(union node *, int);
7778 static void evalfor(union node *, int);
7779 static void evalcase(union node *, int);
7780 static void evalsubshell(union node *, int);
7781 static void expredir(union node *);
7782 static void evalpipe(union node *, int);
7783 static void evalcommand(union node *, int);
7784 static int evalbltin(const struct builtincmd *, int, char **);
7785 static void prehash(union node *);
7788 * Evaluate a parse tree. The value is left in the global variable
7792 evaltree(union node *n, int flags)
7795 void (*evalfn)(union node *, int);
7799 TRACE(("evaltree(NULL) called\n"));
7802 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
7803 getpid(), n, n->type, flags));
7807 out1fmt("Node type = %d\n", n->type);
7812 evaltree(n->nnot.com, EV_TESTED);
7813 status = !exitstatus;
7816 expredir(n->nredir.redirect);
7817 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
7819 evaltree(n->nredir.n, flags & EV_TESTED);
7820 status = exitstatus;
7825 evalfn = evalcommand;
7827 if (eflag && !(flags & EV_TESTED))
7839 evalfn = evalsubshell;
7851 #error NAND + 1 != NOR
7853 #if NOR + 1 != NSEMI
7854 #error NOR + 1 != NSEMI
7856 isor = n->type - NAND;
7859 (flags | ((isor >> 1) - 1)) & EV_TESTED
7861 if (!exitstatus == isor)
7873 evaltree(n->nif.test, EV_TESTED);
7876 if (exitstatus == 0) {
7879 } else if (n->nif.elsepart) {
7880 n = n->nif.elsepart;
7885 defun(n->narg.text, n->narg.next);
7889 exitstatus = status;
7893 if ((checkexit & exitstatus))
7894 evalskip |= SKIPEVAL;
7895 else if (pendingsig && dotrap())
7898 if (flags & EV_EXIT) {
7900 raise_exception(EXEXIT);
7904 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
7907 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
7910 evalloop(union node *n, int flags)
7920 evaltree(n->nbinary.ch1, EV_TESTED);
7923 if (evalskip == SKIPCONT && --skipcount <= 0) {
7927 if (evalskip == SKIPBREAK && --skipcount <= 0)
7932 if (n->type != NWHILE)
7936 evaltree(n->nbinary.ch2, flags);
7937 status = exitstatus;
7942 exitstatus = status;
7946 evalfor(union node *n, int flags)
7948 struct arglist arglist;
7951 struct stackmark smark;
7953 setstackmark(&smark);
7954 arglist.list = NULL;
7955 arglist.lastp = &arglist.list;
7956 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
7957 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
7962 *arglist.lastp = NULL;
7967 for (sp = arglist.list; sp; sp = sp->next) {
7968 setvar(n->nfor.var, sp->text, 0);
7969 evaltree(n->nfor.body, flags);
7971 if (evalskip == SKIPCONT && --skipcount <= 0) {
7975 if (evalskip == SKIPBREAK && --skipcount <= 0)
7982 popstackmark(&smark);
7986 evalcase(union node *n, int flags)
7990 struct arglist arglist;
7991 struct stackmark smark;
7993 setstackmark(&smark);
7994 arglist.list = NULL;
7995 arglist.lastp = &arglist.list;
7996 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
7998 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
7999 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8000 if (casematch(patp, arglist.list->text)) {
8001 if (evalskip == 0) {
8002 evaltree(cp->nclist.body, flags);
8009 popstackmark(&smark);
8013 * Kick off a subshell to evaluate a tree.
8016 evalsubshell(union node *n, int flags)
8019 int backgnd = (n->type == NBACKGND);
8022 expredir(n->nredir.redirect);
8023 if (!backgnd && flags & EV_EXIT && !trap[0])
8026 jp = makejob(/*n,*/ 1);
8027 if (forkshell(jp, n, backgnd) == 0) {
8031 flags &=~ EV_TESTED;
8033 redirect(n->nredir.redirect, 0);
8034 evaltreenr(n->nredir.n, flags);
8039 status = waitforjob(jp);
8040 exitstatus = status;
8045 * Compute the names of the files in a redirection list.
8047 static void fixredir(union node *, const char *, int);
8049 expredir(union node *n)
8053 for (redir = n; redir; redir = redir->nfile.next) {
8057 fn.lastp = &fn.list;
8058 switch (redir->type) {
8064 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8065 redir->nfile.expfname = fn.list->text;
8069 if (redir->ndup.vname) {
8070 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8071 if (fn.list == NULL)
8072 ash_msg_and_raise_error("redir error");
8073 fixredir(redir, fn.list->text, 1);
8081 * Evaluate a pipeline. All the processes in the pipeline are children
8082 * of the process creating the pipeline. (This differs from some versions
8083 * of the shell, which make the last process in a pipeline the parent
8087 evalpipe(union node *n, int flags)
8090 struct nodelist *lp;
8095 TRACE(("evalpipe(0x%lx) called\n", (long)n));
8097 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8101 jp = makejob(/*n,*/ pipelen);
8103 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8107 if (pipe(pip) < 0) {
8109 ash_msg_and_raise_error("pipe call failed");
8112 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8125 evaltreenr(lp->n, flags);
8133 if (n->npipe.pipe_backgnd == 0) {
8134 exitstatus = waitforjob(jp);
8135 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
8141 * Controls whether the shell is interactive or not.
8144 setinteractive(int on)
8146 static smallint is_interactive;
8148 if (++on == is_interactive)
8150 is_interactive = on;
8154 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8155 if (is_interactive > 1) {
8156 /* Looks like they want an interactive shell */
8157 static smallint did_banner;
8162 "%s built-in shell (ash)\n"
8163 "Enter 'help' for a list of built-in commands."
8178 setinteractive(iflag);
8180 #if ENABLE_FEATURE_EDITING_VI
8182 line_input_state->flags |= VI_MODE;
8184 line_input_state->flags &= ~VI_MODE;
8186 viflag = 0; /* forcibly keep the option off */
8190 static struct localvar *localvars;
8193 * Called after a function returns.
8194 * Interrupts must be off.
8199 struct localvar *lvp;
8202 while ((lvp = localvars) != NULL) {
8203 localvars = lvp->next;
8205 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
8206 if (vp == NULL) { /* $- saved */
8207 memcpy(optlist, lvp->text, sizeof(optlist));
8208 free((char*)lvp->text);
8210 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8214 (*vp->func)(strchrnul(lvp->text, '=') + 1);
8215 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8216 free((char*)vp->text);
8217 vp->flags = lvp->flags;
8218 vp->text = lvp->text;
8225 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8227 volatile struct shparam saveparam;
8228 struct localvar *volatile savelocalvars;
8229 struct jmploc *volatile savehandler;
8230 struct jmploc jmploc;
8233 saveparam = shellparam;
8234 savelocalvars = localvars;
8235 e = setjmp(jmploc.loc);
8240 savehandler = exception_handler;
8241 exception_handler = &jmploc;
8243 shellparam.malloced = 0;
8247 shellparam.nparam = argc - 1;
8248 shellparam.p = argv + 1;
8249 #if ENABLE_ASH_GETOPTS
8250 shellparam.optind = 1;
8251 shellparam.optoff = -1;
8253 evaltree(&func->n, flags & EV_TESTED);
8259 localvars = savelocalvars;
8260 freeparam(&shellparam);
8261 shellparam = saveparam;
8262 exception_handler = savehandler;
8264 evalskip &= ~SKIPFUNC;
8268 #if ENABLE_ASH_CMDCMD
8270 parse_command_args(char **argv, const char **path)
8283 if (c == '-' && !*cp) {
8290 *path = bb_default_path;
8293 /* run 'typecmd' for other options */
8304 * Make a variable a local variable. When a variable is made local, it's
8305 * value and flags are saved in a localvar structure. The saved values
8306 * will be restored when the shell function returns. We handle the name
8307 * "-" as a special case.
8312 struct localvar *lvp;
8317 lvp = ckzalloc(sizeof(struct localvar));
8318 if (LONE_DASH(name)) {
8320 p = ckmalloc(sizeof(optlist));
8321 lvp->text = memcpy(p, optlist, sizeof(optlist));
8326 vpp = hashvar(name);
8327 vp = *findvar(vpp, name);
8328 eq = strchr(name, '=');
8331 setvareq(name, VSTRFIXED);
8333 setvar(name, NULL, VSTRFIXED);
8334 vp = *vpp; /* the new variable */
8335 lvp->flags = VUNSET;
8337 lvp->text = vp->text;
8338 lvp->flags = vp->flags;
8339 vp->flags |= VSTRFIXED|VTEXTFIXED;
8345 lvp->next = localvars;
8351 * The "local" command.
8354 localcmd(int argc UNUSED_PARAM, char **argv)
8359 while ((name = *argv++) != NULL) {
8366 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8372 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8378 execcmd(int argc UNUSED_PARAM, char **argv)
8381 iflag = 0; /* exit on error */
8384 shellexec(argv + 1, pathval(), 0);
8390 * The return command.
8393 returncmd(int argc UNUSED_PARAM, char **argv)
8396 * If called outside a function, do what ksh does;
8397 * skip the rest of the file.
8399 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8400 return argv[1] ? number(argv[1]) : exitstatus;
8403 /* Forward declarations for builtintab[] */
8404 static int breakcmd(int, char **);
8405 static int dotcmd(int, char **);
8406 static int evalcmd(int, char **);
8407 static int exitcmd(int, char **);
8408 static int exportcmd(int, char **);
8409 #if ENABLE_ASH_GETOPTS
8410 static int getoptscmd(int, char **);
8412 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8413 static int helpcmd(int, char **);
8415 #if ENABLE_ASH_MATH_SUPPORT
8416 static int letcmd(int, char **);
8418 static int readcmd(int, char **);
8419 static int setcmd(int, char **);
8420 static int shiftcmd(int, char **);
8421 static int timescmd(int, char **);
8422 static int trapcmd(int, char **);
8423 static int umaskcmd(int, char **);
8424 static int unsetcmd(int, char **);
8425 static int ulimitcmd(int, char **);
8427 #define BUILTIN_NOSPEC "0"
8428 #define BUILTIN_SPECIAL "1"
8429 #define BUILTIN_REGULAR "2"
8430 #define BUILTIN_SPEC_REG "3"
8431 #define BUILTIN_ASSIGN "4"
8432 #define BUILTIN_SPEC_ASSG "5"
8433 #define BUILTIN_REG_ASSG "6"
8434 #define BUILTIN_SPEC_REG_ASSG "7"
8436 /* We do not handle [[ expr ]] bashism bash-compatibly,
8437 * we make it a synonym of [ expr ].
8438 * Basically, word splitting and pathname expansion should NOT be performed
8440 * no word splitting: a="a b"; [[ $a = "a b" ]]; echo $? should print "0"
8441 * no pathname expansion: [[ /bin/m* = "/bin/m*" ]]; echo $? should print "0"
8442 * Additional operators:
8443 * || and && should work as -o and -a
8445 * Apart from the above, [[ expr ]] should work as [ expr ]
8448 #define echocmd echo_main
8449 #define printfcmd printf_main
8450 #define testcmd test_main
8452 /* Keep these in proper order since it is searched via bsearch() */
8453 static const struct builtincmd builtintab[] = {
8454 { BUILTIN_SPEC_REG ".", dotcmd },
8455 { BUILTIN_SPEC_REG ":", truecmd },
8456 #if ENABLE_ASH_BUILTIN_TEST
8457 { BUILTIN_REGULAR "[", testcmd },
8458 #if ENABLE_ASH_BASH_COMPAT
8459 { BUILTIN_REGULAR "[[", testcmd },
8462 #if ENABLE_ASH_ALIAS
8463 { BUILTIN_REG_ASSG "alias", aliascmd },
8466 { BUILTIN_REGULAR "bg", fg_bgcmd },
8468 { BUILTIN_SPEC_REG "break", breakcmd },
8469 { BUILTIN_REGULAR "cd", cdcmd },
8470 { BUILTIN_NOSPEC "chdir", cdcmd },
8471 #if ENABLE_ASH_CMDCMD
8472 { BUILTIN_REGULAR "command", commandcmd },
8474 { BUILTIN_SPEC_REG "continue", breakcmd },
8475 #if ENABLE_ASH_BUILTIN_ECHO
8476 { BUILTIN_REGULAR "echo", echocmd },
8478 { BUILTIN_SPEC_REG "eval", evalcmd },
8479 { BUILTIN_SPEC_REG "exec", execcmd },
8480 { BUILTIN_SPEC_REG "exit", exitcmd },
8481 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8482 { BUILTIN_REGULAR "false", falsecmd },
8484 { BUILTIN_REGULAR "fg", fg_bgcmd },
8486 #if ENABLE_ASH_GETOPTS
8487 { BUILTIN_REGULAR "getopts", getoptscmd },
8489 { BUILTIN_NOSPEC "hash", hashcmd },
8490 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8491 { BUILTIN_NOSPEC "help", helpcmd },
8494 { BUILTIN_REGULAR "jobs", jobscmd },
8495 { BUILTIN_REGULAR "kill", killcmd },
8497 #if ENABLE_ASH_MATH_SUPPORT
8498 { BUILTIN_NOSPEC "let", letcmd },
8500 { BUILTIN_ASSIGN "local", localcmd },
8501 #if ENABLE_ASH_BUILTIN_PRINTF
8502 { BUILTIN_REGULAR "printf", printfcmd },
8504 { BUILTIN_NOSPEC "pwd", pwdcmd },
8505 { BUILTIN_REGULAR "read", readcmd },
8506 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8507 { BUILTIN_SPEC_REG "return", returncmd },
8508 { BUILTIN_SPEC_REG "set", setcmd },
8509 { BUILTIN_SPEC_REG "shift", shiftcmd },
8510 { BUILTIN_SPEC_REG "source", dotcmd },
8511 #if ENABLE_ASH_BUILTIN_TEST
8512 { BUILTIN_REGULAR "test", testcmd },
8514 { BUILTIN_SPEC_REG "times", timescmd },
8515 { BUILTIN_SPEC_REG "trap", trapcmd },
8516 { BUILTIN_REGULAR "true", truecmd },
8517 { BUILTIN_NOSPEC "type", typecmd },
8518 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
8519 { BUILTIN_REGULAR "umask", umaskcmd },
8520 #if ENABLE_ASH_ALIAS
8521 { BUILTIN_REGULAR "unalias", unaliascmd },
8523 { BUILTIN_SPEC_REG "unset", unsetcmd },
8524 { BUILTIN_REGULAR "wait", waitcmd },
8527 /* Should match the above table! */
8528 #define COMMANDCMD (builtintab + \
8530 1 * ENABLE_ASH_BUILTIN_TEST + \
8531 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8532 1 * ENABLE_ASH_ALIAS + \
8533 1 * ENABLE_ASH_JOB_CONTROL + \
8535 #define EXECCMD (builtintab + \
8537 1 * ENABLE_ASH_BUILTIN_TEST + \
8538 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8539 1 * ENABLE_ASH_ALIAS + \
8540 1 * ENABLE_ASH_JOB_CONTROL + \
8542 1 * ENABLE_ASH_CMDCMD + \
8544 ENABLE_ASH_BUILTIN_ECHO + \
8548 * Search the table of builtin commands.
8550 static struct builtincmd *
8551 find_builtin(const char *name)
8553 struct builtincmd *bp;
8556 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8563 * Execute a simple command.
8566 isassignment(const char *p)
8568 const char *q = endofname(p);
8574 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8576 /* Preserve exitstatus of a previous possible redirection
8577 * as POSIX mandates */
8578 return back_exitstatus;
8581 evalcommand(union node *cmd, int flags)
8583 static const struct builtincmd null_bltin = {
8584 "\0\0", bltincmd /* why three NULs? */
8586 struct stackmark smark;
8588 struct arglist arglist;
8589 struct arglist varlist;
8592 const struct strlist *sp;
8593 struct cmdentry cmdentry;
8601 struct builtincmd *bcmd;
8602 int pseudovarflag = 0;
8604 /* First expand the arguments. */
8605 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8606 setstackmark(&smark);
8607 back_exitstatus = 0;
8609 cmdentry.cmdtype = CMDBUILTIN;
8610 cmdentry.u.cmd = &null_bltin;
8611 varlist.lastp = &varlist.list;
8612 *varlist.lastp = NULL;
8613 arglist.lastp = &arglist.list;
8614 *arglist.lastp = NULL;
8617 if (cmd->ncmd.args) {
8618 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8619 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8622 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8623 struct strlist **spp;
8625 spp = arglist.lastp;
8626 if (pseudovarflag && isassignment(argp->narg.text))
8627 expandarg(argp, &arglist, EXP_VARTILDE);
8629 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8631 for (sp = *spp; sp; sp = sp->next)
8635 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8636 for (sp = arglist.list; sp; sp = sp->next) {
8637 TRACE(("evalcommand arg: %s\n", sp->text));
8638 *nargv++ = sp->text;
8643 if (iflag && funcnest == 0 && argc > 0)
8644 lastarg = nargv[-1];
8647 expredir(cmd->ncmd.redirect);
8648 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8651 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8652 struct strlist **spp;
8655 spp = varlist.lastp;
8656 expandarg(argp, &varlist, EXP_VARTILDE);
8659 * Modify the command lookup path, if a PATH= assignment
8663 if (varequal(p, path))
8667 /* Print the command if xflag is set. */
8670 const char *p = " %s";
8673 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8676 for (n = 0; n < 2; n++) {
8678 fdprintf(preverrout_fd, p, sp->text);
8686 safe_write(preverrout_fd, "\n", 1);
8692 /* Now locate the command. */
8694 const char *oldpath;
8695 int cmd_flag = DO_ERR;
8700 find_command(argv[0], &cmdentry, cmd_flag, path);
8701 if (cmdentry.cmdtype == CMDUNKNOWN) {
8707 /* implement bltin and command here */
8708 if (cmdentry.cmdtype != CMDBUILTIN)
8711 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8712 if (cmdentry.u.cmd == EXECCMD)
8714 #if ENABLE_ASH_CMDCMD
8715 if (cmdentry.u.cmd == COMMANDCMD) {
8717 nargv = parse_command_args(argv, &path);
8720 argc -= nargv - argv;
8722 cmd_flag |= DO_NOFUNC;
8730 /* We have a redirection error. */
8732 raise_exception(EXERROR);
8734 exitstatus = status;
8738 /* Execute the command. */
8739 switch (cmdentry.cmdtype) {
8741 #if ENABLE_FEATURE_SH_NOFORK
8743 /* find_command() encodes applet_no as (-2 - applet_no) */
8744 int applet_no = (- cmdentry.u.index - 2);
8745 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
8746 listsetvar(varlist.list, VEXPORT|VSTACK);
8747 /* run <applet>_main() */
8748 exitstatus = run_nofork_applet(applet_no, argv);
8754 /* Fork off a child process if necessary. */
8755 if (!(flags & EV_EXIT) || trap[0]) {
8757 jp = makejob(/*cmd,*/ 1);
8758 if (forkshell(jp, cmd, FORK_FG) != 0) {
8759 exitstatus = waitforjob(jp);
8765 listsetvar(varlist.list, VEXPORT|VSTACK);
8766 shellexec(argv, path, cmdentry.u.index);
8770 cmdenviron = varlist.list;
8772 struct strlist *list = cmdenviron;
8774 if (spclbltin > 0 || argc == 0) {
8776 if (cmd_is_exec && argc > 1)
8779 listsetvar(list, i);
8781 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
8788 exit_status = 128 + SIGINT;
8790 exit_status = 128 + pendingsig;
8791 exitstatus = exit_status;
8792 if (i == EXINT || spclbltin > 0) {
8794 longjmp(exception_handler->loc, 1);
8801 listsetvar(varlist.list, 0);
8802 if (evalfun(cmdentry.u.func, argc, argv, flags))
8808 popredir(cmd_is_exec);
8810 /* dsl: I think this is intended to be used to support
8811 * '_' in 'vi' command mode during line editing...
8812 * However I implemented that within libedit itself.
8814 setvar("_", lastarg, 0);
8815 popstackmark(&smark);
8819 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
8821 char *volatile savecmdname;
8822 struct jmploc *volatile savehandler;
8823 struct jmploc jmploc;
8826 savecmdname = commandname;
8827 i = setjmp(jmploc.loc);
8830 savehandler = exception_handler;
8831 exception_handler = &jmploc;
8832 commandname = argv[0];
8834 optptr = NULL; /* initialize nextopt */
8835 exitstatus = (*cmd->builtin)(argc, argv);
8836 flush_stdout_stderr();
8838 exitstatus |= ferror(stdout);
8840 commandname = savecmdname;
8842 exception_handler = savehandler;
8848 goodname(const char *p)
8850 return !*endofname(p);
8855 * Search for a command. This is called before we fork so that the
8856 * location of the command will be available in the parent as well as
8857 * the child. The check for "goodname" is an overly conservative
8858 * check that the name will not be subject to expansion.
8861 prehash(union node *n)
8863 struct cmdentry entry;
8865 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
8866 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
8870 /* ============ Builtin commands
8872 * Builtin commands whose functions are closely tied to evaluation
8873 * are implemented here.
8877 * Handle break and continue commands. Break, continue, and return are
8878 * all handled by setting the evalskip flag. The evaluation routines
8879 * above all check this flag, and if it is set they start skipping
8880 * commands rather than executing them. The variable skipcount is
8881 * the number of loops to break/continue, or the number of function
8882 * levels to return. (The latter is always 1.) It should probably
8883 * be an error to break out of more loops than exist, but it isn't
8884 * in the standard shell so we don't make it one here.
8887 breakcmd(int argc UNUSED_PARAM, char **argv)
8889 int n = argv[1] ? number(argv[1]) : 1;
8892 ash_msg_and_raise_error(illnum, argv[1]);
8896 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
8903 /* ============ input.c
8905 * This implements the input routines used by the parser.
8908 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
8911 INPUT_PUSH_FILE = 1,
8912 INPUT_NOFILE_OK = 2,
8915 static int plinno = 1; /* input line number */
8916 /* number of characters left in input buffer */
8917 static int parsenleft; /* copy of parsefile->nleft */
8918 static int parselleft; /* copy of parsefile->lleft */
8919 /* next character in input buffer */
8920 static char *parsenextc; /* copy of parsefile->nextc */
8922 static smallint checkkwd;
8923 /* values of checkkwd variable */
8924 #define CHKALIAS 0x1
8931 struct strpush *sp = g_parsefile->strpush;
8934 #if ENABLE_ASH_ALIAS
8936 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
8937 checkkwd |= CHKALIAS;
8939 if (sp->string != sp->ap->val) {
8942 sp->ap->flag &= ~ALIASINUSE;
8943 if (sp->ap->flag & ALIASDEAD) {
8944 unalias(sp->ap->name);
8948 parsenextc = sp->prevstring;
8949 parsenleft = sp->prevnleft;
8950 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
8951 g_parsefile->strpush = sp->prev;
8952 if (sp != &(g_parsefile->basestrpush))
8961 char *buf = g_parsefile->buf;
8964 #if ENABLE_FEATURE_EDITING
8966 if (!iflag || g_parsefile->fd)
8967 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
8969 #if ENABLE_FEATURE_TAB_COMPLETION
8970 line_input_state->path_lookup = pathval();
8972 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
8974 /* Ctrl+C pressed */
8983 if (nr < 0 && errno == 0) {
8984 /* Ctrl+D pressed */
8989 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
8993 /* nonblock_safe_read() handles this problem */
8995 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
8996 int flags = fcntl(0, F_GETFL);
8997 if (flags >= 0 && (flags & O_NONBLOCK)) {
8998 flags &= ~O_NONBLOCK;
8999 if (fcntl(0, F_SETFL, flags) >= 0) {
9000 out2str("sh: turning off NDELAY mode\n");
9011 * Refill the input buffer and return the next input character:
9013 * 1) If a string was pushed back on the input, pop it;
9014 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
9015 * from a string so we can't refill the buffer, return EOF.
9016 * 3) If the is more stuff in this buffer, use it else call read to fill it.
9017 * 4) Process input up to the next newline, deleting nul characters.
9026 while (g_parsefile->strpush) {
9027 #if ENABLE_ASH_ALIAS
9028 if (parsenleft == -1 && g_parsefile->strpush->ap &&
9029 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
9034 if (--parsenleft >= 0)
9035 return signed_char2int(*parsenextc++);
9037 if (parsenleft == EOF_NLEFT || g_parsefile->buf == NULL)
9039 flush_stdout_stderr();
9046 parselleft = parsenleft = EOF_NLEFT;
9053 /* delete nul characters */
9061 memmove(q, q + 1, more);
9065 parsenleft = q - parsenextc - 1;
9071 parsenleft = q - parsenextc - 1;
9083 out2str(parsenextc);
9088 return signed_char2int(*parsenextc++);
9091 #define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer())
9095 return pgetc_as_macro();
9098 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9099 #define pgetc_macro() pgetc()
9101 #define pgetc_macro() pgetc_as_macro()
9105 * Same as pgetc(), but ignores PEOA.
9107 #if ENABLE_ASH_ALIAS
9115 } while (c == PEOA);
9122 return pgetc_macro();
9127 * Read a line from the script.
9130 pfgets(char *line, int len)
9136 while (--nleft > 0) {
9152 * Undo the last call to pgetc. Only one character may be pushed back.
9153 * PEOF may be pushed back.
9163 * Push a string back onto the input at this current parsefile level.
9164 * We handle aliases this way.
9166 #if !ENABLE_ASH_ALIAS
9167 #define pushstring(s, ap) pushstring(s)
9170 pushstring(char *s, struct alias *ap)
9177 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
9178 if (g_parsefile->strpush) {
9179 sp = ckzalloc(sizeof(struct strpush));
9180 sp->prev = g_parsefile->strpush;
9181 g_parsefile->strpush = sp;
9183 sp = g_parsefile->strpush = &(g_parsefile->basestrpush);
9184 sp->prevstring = parsenextc;
9185 sp->prevnleft = parsenleft;
9186 #if ENABLE_ASH_ALIAS
9189 ap->flag |= ALIASINUSE;
9199 * To handle the "." command, a stack of input files is used. Pushfile
9200 * adds a new entry to the stack and popfile restores the previous level.
9205 struct parsefile *pf;
9207 g_parsefile->nleft = parsenleft;
9208 g_parsefile->lleft = parselleft;
9209 g_parsefile->nextc = parsenextc;
9210 g_parsefile->linno = plinno;
9211 pf = ckzalloc(sizeof(*pf));
9212 pf->prev = g_parsefile;
9214 /*pf->strpush = NULL; - ckzalloc did it */
9215 /*pf->basestrpush.prev = NULL;*/
9222 struct parsefile *pf = g_parsefile;
9230 g_parsefile = pf->prev;
9232 parsenleft = g_parsefile->nleft;
9233 parselleft = g_parsefile->lleft;
9234 parsenextc = g_parsefile->nextc;
9235 plinno = g_parsefile->linno;
9240 * Return to top level.
9245 while (g_parsefile != &basepf)
9250 * Close the file(s) that the shell is reading commands from. Called
9251 * after a fork is done.
9257 if (g_parsefile->fd > 0) {
9258 close(g_parsefile->fd);
9259 g_parsefile->fd = 0;
9264 * Like setinputfile, but takes an open file descriptor. Call this with
9268 setinputfd(int fd, int push)
9270 close_on_exec_on(fd);
9273 g_parsefile->buf = 0;
9275 g_parsefile->fd = fd;
9276 if (g_parsefile->buf == NULL)
9277 g_parsefile->buf = ckmalloc(IBUFSIZ);
9278 parselleft = parsenleft = 0;
9283 * Set the input to take input from a file. If push is set, push the
9284 * old input onto the stack first.
9287 setinputfile(const char *fname, int flags)
9293 fd = open(fname, O_RDONLY);
9295 if (flags & INPUT_NOFILE_OK)
9297 ash_msg_and_raise_error("can't open %s", fname);
9300 fd2 = copyfd(fd, 10);
9303 ash_msg_and_raise_error("out of file descriptors");
9306 setinputfd(fd, flags & INPUT_PUSH_FILE);
9313 * Like setinputfile, but takes input from a string.
9316 setinputstring(char *string)
9320 parsenextc = string;
9321 parsenleft = strlen(string);
9322 g_parsefile->buf = NULL;
9328 /* ============ mail.c
9330 * Routines to check for mail.
9335 #define MAXMBOXES 10
9337 /* times of mailboxes */
9338 static time_t mailtime[MAXMBOXES];
9339 /* Set if MAIL or MAILPATH is changed. */
9340 static smallint mail_var_path_changed;
9343 * Print appropriate message(s) if mail has arrived.
9344 * If mail_var_path_changed is set,
9345 * then the value of MAIL has mail_var_path_changed,
9346 * so we just update the values.
9355 struct stackmark smark;
9358 setstackmark(&smark);
9359 mpath = mpathset() ? mpathval() : mailval();
9360 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9361 p = padvance(&mpath, nullstr);
9366 for (q = p; *q; q++)
9372 q[-1] = '\0'; /* delete trailing '/' */
9373 if (stat(p, &statb) < 0) {
9377 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9380 pathopt ? pathopt : "you have mail"
9383 *mtp = statb.st_mtime;
9385 mail_var_path_changed = 0;
9386 popstackmark(&smark);
9390 changemail(const char *val UNUSED_PARAM)
9392 mail_var_path_changed = 1;
9395 #endif /* ASH_MAIL */
9398 /* ============ ??? */
9401 * Set the shell parameters.
9404 setparam(char **argv)
9410 for (nparam = 0; argv[nparam]; nparam++)
9412 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9414 *ap++ = ckstrdup(*argv++);
9417 freeparam(&shellparam);
9418 shellparam.malloced = 1;
9419 shellparam.nparam = nparam;
9420 shellparam.p = newparam;
9421 #if ENABLE_ASH_GETOPTS
9422 shellparam.optind = 1;
9423 shellparam.optoff = -1;
9428 * Process shell options. The global variable argptr contains a pointer
9429 * to the argument list; we advance it past the options.
9431 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9432 * For a non-interactive shell, an error condition encountered
9433 * by a special built-in ... shall cause the shell to write a diagnostic message
9434 * to standard error and exit as shown in the following table:
9435 * Error Special Built-In
9437 * Utility syntax error (option or operand error) Shall exit
9439 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9440 * we see that bash does not do that (set "finishes" with error code 1 instead,
9441 * and shell continues), and people rely on this behavior!
9443 * set -o barfoo 2>/dev/null
9446 * Oh well. Let's mimic that.
9449 plus_minus_o(char *name, int val)
9454 for (i = 0; i < NOPTS; i++) {
9455 if (strcmp(name, optnames(i)) == 0) {
9460 ash_msg("illegal option %co %s", val ? '-' : '+', name);
9463 for (i = 0; i < NOPTS; i++) {
9465 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
9467 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
9473 setoption(int flag, int val)
9477 for (i = 0; i < NOPTS; i++) {
9478 if (optletters(i) == flag) {
9483 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
9487 options(int cmdline)
9495 while ((p = *argptr) != NULL) {
9497 if (c != '-' && c != '+')
9500 val = 0; /* val = 0 if c == '+' */
9503 if (p[0] == '\0' || LONE_DASH(p)) {
9505 /* "-" means turn off -x and -v */
9508 /* "--" means reset params */
9509 else if (*argptr == NULL)
9512 break; /* "-" or "--" terminates options */
9515 /* first char was + or - */
9516 while ((c = *p++) != '\0') {
9517 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9518 if (c == 'c' && cmdline) {
9519 minusc = p; /* command is after shell args */
9520 } else if (c == 'o') {
9521 if (plus_minus_o(*argptr, val)) {
9522 /* it already printed err message */
9523 return 1; /* error */
9527 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9529 /* bash does not accept +-login, we also won't */
9530 } else if (cmdline && val && (c == '-')) { /* long options */
9531 if (strcmp(p, "login") == 0)
9543 * The shift builtin command.
9546 shiftcmd(int argc UNUSED_PARAM, char **argv)
9553 n = number(argv[1]);
9554 if (n > shellparam.nparam)
9555 n = shellparam.nparam;
9557 shellparam.nparam -= n;
9558 for (ap1 = shellparam.p; --n >= 0; ap1++) {
9559 if (shellparam.malloced)
9563 while ((*ap2++ = *ap1++) != NULL)
9565 #if ENABLE_ASH_GETOPTS
9566 shellparam.optind = 1;
9567 shellparam.optoff = -1;
9574 * POSIX requires that 'set' (but not export or readonly) output the
9575 * variables in lexicographic order - by the locale's collating order (sigh).
9576 * Maybe we could keep them in an ordered balanced binary tree
9577 * instead of hashed lists.
9578 * For now just roll 'em through qsort for printing...
9581 showvars(const char *sep_prefix, int on, int off)
9586 ep = listvars(on, off, &epend);
9587 qsort(ep, epend - ep, sizeof(char *), vpcmp);
9589 sep = *sep_prefix ? " " : sep_prefix;
9591 for (; ep < epend; ep++) {
9595 p = strchrnul(*ep, '=');
9598 q = single_quote(++p);
9599 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9605 * The set command builtin.
9608 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9613 return showvars(nullstr, 0, VUNSET);
9616 if (!options(0)) { /* if no parse error... */
9619 if (*argptr != NULL) {
9627 #if ENABLE_ASH_RANDOM_SUPPORT
9629 change_random(const char *value)
9631 /* Galois LFSR parameter */
9632 /* Taps at 32 31 29 1: */
9633 enum { MASK = 0x8000000b };
9634 /* Another example - taps at 32 31 30 10: */
9635 /* MASK = 0x00400007 */
9637 if (value == NULL) {
9638 /* "get", generate */
9641 /* LCG has period of 2^32 and alternating lowest bit */
9642 random_LCG = 1664525 * random_LCG + 1013904223;
9643 /* Galois LFSR has period of 2^32-1 = 3 * 5 * 17 * 257 * 65537 */
9644 t = (random_galois_LFSR << 1);
9645 if (random_galois_LFSR < 0) /* if we just shifted 1 out of msb... */
9647 random_galois_LFSR = t;
9648 /* Both are weak, combining them gives better randomness
9649 * and ~2^64 period. & 0x7fff is probably bash compat
9650 * for $RANDOM range. Combining with subtraction is
9651 * just for fun. + and ^ would work equally well. */
9652 t = (t - random_LCG) & 0x7fff;
9653 /* set without recursion */
9654 setvar(vrandom.text, utoa(t), VNOFUNC);
9655 vrandom.flags &= ~VNOFUNC;
9658 random_galois_LFSR = random_LCG = strtoul(value, (char **)NULL, 10);
9663 #if ENABLE_ASH_GETOPTS
9665 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9674 if (*param_optind < 1)
9676 optnext = optfirst + *param_optind - 1;
9678 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
9681 p = optnext[-1] + *optoff;
9682 if (p == NULL || *p == '\0') {
9683 /* Current word is done, advance */
9685 if (p == NULL || *p != '-' || *++p == '\0') {
9692 if (LONE_DASH(p)) /* check for "--" */
9697 for (q = optstr; *q != c;) {
9699 if (optstr[0] == ':') {
9702 err |= setvarsafe("OPTARG", s, 0);
9704 fprintf(stderr, "Illegal option -%c\n", c);
9715 if (*p == '\0' && (p = *optnext) == NULL) {
9716 if (optstr[0] == ':') {
9719 err |= setvarsafe("OPTARG", s, 0);
9722 fprintf(stderr, "No arg for -%c option\n", c);
9731 err |= setvarsafe("OPTARG", p, 0);
9734 err |= setvarsafe("OPTARG", nullstr, 0);
9736 *optoff = p ? p - *(optnext - 1) : -1;
9737 *param_optind = optnext - optfirst + 1;
9738 fmtstr(s, sizeof(s), "%d", *param_optind);
9739 err |= setvarsafe("OPTIND", s, VNOFUNC);
9742 err |= setvarsafe(optvar, s, 0);
9746 flush_stdout_stderr();
9747 raise_exception(EXERROR);
9753 * The getopts builtin. Shellparam.optnext points to the next argument
9754 * to be processed. Shellparam.optptr points to the next character to
9755 * be processed in the current argument. If shellparam.optnext is NULL,
9756 * then it's the first time getopts has been called.
9759 getoptscmd(int argc, char **argv)
9764 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
9766 optbase = shellparam.p;
9767 if (shellparam.optind > shellparam.nparam + 1) {
9768 shellparam.optind = 1;
9769 shellparam.optoff = -1;
9773 if (shellparam.optind > argc - 2) {
9774 shellparam.optind = 1;
9775 shellparam.optoff = -1;
9779 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9780 &shellparam.optoff);
9782 #endif /* ASH_GETOPTS */
9785 /* ============ Shell parser */
9788 struct heredoc *next; /* next here document in list */
9789 union node *here; /* redirection node */
9790 char *eofmark; /* string indicating end of input */
9791 smallint striptabs; /* if set, strip leading tabs */
9794 static smallint tokpushback; /* last token pushed back */
9795 static smallint parsebackquote; /* nonzero if we are inside backquotes */
9796 static smallint quoteflag; /* set if (part of) last token was quoted */
9797 static token_id_t lasttoken; /* last token read (integer id Txxx) */
9798 static struct heredoc *heredoclist; /* list of here documents to read */
9799 static char *wordtext; /* text of last word returned by readtoken */
9800 static struct nodelist *backquotelist;
9801 static union node *redirnode;
9802 static struct heredoc *heredoc;
9804 * NEOF is returned by parsecmd when it encounters an end of file. It
9805 * must be distinct from NULL, so we use the address of a variable that
9806 * happens to be handy.
9808 #define NEOF ((union node *)&tokpushback)
9810 static void raise_error_syntax(const char *) NORETURN;
9812 raise_error_syntax(const char *msg)
9814 ash_msg_and_raise_error("syntax error: %s", msg);
9819 * Called when an unexpected token is read during the parse. The argument
9820 * is the token that is expected, or -1 if more than one type of token can
9821 * occur at this point.
9823 static void raise_error_unexpected_syntax(int) NORETURN;
9825 raise_error_unexpected_syntax(int token)
9830 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
9832 sprintf(msg + l, " (expecting %s)", tokname(token));
9833 raise_error_syntax(msg);
9837 #define EOFMARKLEN 79
9839 /* parsing is heavily cross-recursive, need these forward decls */
9840 static union node *andor(void);
9841 static union node *pipeline(void);
9842 static union node *parse_command(void);
9843 static void parseheredoc(void);
9844 static char peektoken(void);
9845 static int readtoken(void);
9850 union node *n1, *n2, *n3;
9853 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9854 if (nlflag == 2 && peektoken())
9860 if (tok == TBACKGND) {
9861 if (n2->type == NPIPE) {
9862 n2->npipe.pipe_backgnd = 1;
9864 if (n2->type != NREDIR) {
9865 n3 = stzalloc(sizeof(struct nredir));
9867 /*n3->nredir.redirect = NULL; - stzalloc did it */
9870 n2->type = NBACKGND;
9876 n3 = stzalloc(sizeof(struct nbinary));
9878 n3->nbinary.ch1 = n1;
9879 n3->nbinary.ch2 = n2;
9895 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9903 pungetc(); /* push back EOF on input */
9907 raise_error_unexpected_syntax(-1);
9917 union node *n1, *n2, *n3;
9925 } else if (t == TOR) {
9931 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9933 n3 = stzalloc(sizeof(struct nbinary));
9935 n3->nbinary.ch1 = n1;
9936 n3->nbinary.ch2 = n2;
9944 union node *n1, *n2, *pipenode;
9945 struct nodelist *lp, *prev;
9949 TRACE(("pipeline: entered\n"));
9950 if (readtoken() == TNOT) {
9952 checkkwd = CHKKWD | CHKALIAS;
9955 n1 = parse_command();
9956 if (readtoken() == TPIPE) {
9957 pipenode = stzalloc(sizeof(struct npipe));
9958 pipenode->type = NPIPE;
9959 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
9960 lp = stzalloc(sizeof(struct nodelist));
9961 pipenode->npipe.cmdlist = lp;
9965 lp = stzalloc(sizeof(struct nodelist));
9966 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9967 lp->n = parse_command();
9969 } while (readtoken() == TPIPE);
9975 n2 = stzalloc(sizeof(struct nnot));
9988 n = stzalloc(sizeof(struct narg));
9990 /*n->narg.next = NULL; - stzalloc did it */
9991 n->narg.text = wordtext;
9992 n->narg.backquote = backquotelist;
9997 fixredir(union node *n, const char *text, int err)
9999 TRACE(("Fix redir %s %d\n", text, err));
10001 n->ndup.vname = NULL;
10003 if (isdigit(text[0]) && text[1] == '\0')
10004 n->ndup.dupfd = text[0] - '0';
10005 else if (LONE_DASH(text))
10006 n->ndup.dupfd = -1;
10009 raise_error_syntax("Bad fd number");
10010 n->ndup.vname = makename();
10015 * Returns true if the text contains nothing to expand (no dollar signs
10019 noexpand(char *text)
10025 while ((c = *p++) != '\0') {
10026 if (c == CTLQUOTEMARK)
10030 else if (SIT(c, BASESYNTAX) == CCTL)
10039 union node *n = redirnode;
10041 if (readtoken() != TWORD)
10042 raise_error_unexpected_syntax(-1);
10043 if (n->type == NHERE) {
10044 struct heredoc *here = heredoc;
10048 if (quoteflag == 0)
10050 TRACE(("Here document %d\n", n->type));
10051 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10052 raise_error_syntax("Illegal eof marker for << redirection");
10053 rmescapes(wordtext);
10054 here->eofmark = wordtext;
10056 if (heredoclist == NULL)
10057 heredoclist = here;
10059 for (p = heredoclist; p->next; p = p->next)
10063 } else if (n->type == NTOFD || n->type == NFROMFD) {
10064 fixredir(n, wordtext, 0);
10066 n->nfile.fname = makename();
10070 static union node *
10073 union node *args, **app;
10074 union node *n = NULL;
10075 union node *vars, **vpp;
10076 union node **rpp, *redir;
10078 #if ENABLE_ASH_BASH_COMPAT
10079 smallint double_brackets_flag = 0;
10089 savecheckkwd = CHKALIAS;
10092 checkkwd = savecheckkwd;
10095 #if ENABLE_ASH_BASH_COMPAT
10096 case TAND: /* "&&" */
10097 case TOR: /* "||" */
10098 if (!double_brackets_flag) {
10102 wordtext = (char *) (t == TAND ? "-a" : "-o");
10105 n = stzalloc(sizeof(struct narg));
10107 /*n->narg.next = NULL; - stzalloc did it */
10108 n->narg.text = wordtext;
10109 #if ENABLE_ASH_BASH_COMPAT
10110 if (strcmp("[[", wordtext) == 0)
10111 double_brackets_flag = 1;
10112 else if (strcmp("]]", wordtext) == 0)
10113 double_brackets_flag = 0;
10115 n->narg.backquote = backquotelist;
10116 if (savecheckkwd && isassignment(wordtext)) {
10118 vpp = &n->narg.next;
10121 app = &n->narg.next;
10126 *rpp = n = redirnode;
10127 rpp = &n->nfile.next;
10128 parsefname(); /* read name of redirection file */
10131 if (args && app == &args->narg.next
10134 struct builtincmd *bcmd;
10137 /* We have a function */
10138 if (readtoken() != TRP)
10139 raise_error_unexpected_syntax(TRP);
10140 name = n->narg.text;
10141 if (!goodname(name)
10142 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10144 raise_error_syntax("Bad function name");
10147 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10148 n->narg.next = parse_command();
10161 n = stzalloc(sizeof(struct ncmd));
10163 n->ncmd.args = args;
10164 n->ncmd.assign = vars;
10165 n->ncmd.redirect = redir;
10169 static union node *
10170 parse_command(void)
10172 union node *n1, *n2;
10173 union node *ap, **app;
10174 union node *cp, **cpp;
10175 union node *redir, **rpp;
10182 switch (readtoken()) {
10184 raise_error_unexpected_syntax(-1);
10187 n1 = stzalloc(sizeof(struct nif));
10189 n1->nif.test = list(0);
10190 if (readtoken() != TTHEN)
10191 raise_error_unexpected_syntax(TTHEN);
10192 n1->nif.ifpart = list(0);
10194 while (readtoken() == TELIF) {
10195 n2->nif.elsepart = stzalloc(sizeof(struct nif));
10196 n2 = n2->nif.elsepart;
10198 n2->nif.test = list(0);
10199 if (readtoken() != TTHEN)
10200 raise_error_unexpected_syntax(TTHEN);
10201 n2->nif.ifpart = list(0);
10203 if (lasttoken == TELSE)
10204 n2->nif.elsepart = list(0);
10206 n2->nif.elsepart = NULL;
10214 n1 = stzalloc(sizeof(struct nbinary));
10215 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10216 n1->nbinary.ch1 = list(0);
10219 TRACE(("expecting DO got %s %s\n", tokname(got),
10220 got == TWORD ? wordtext : ""));
10221 raise_error_unexpected_syntax(TDO);
10223 n1->nbinary.ch2 = list(0);
10228 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10229 raise_error_syntax("Bad for loop variable");
10230 n1 = stzalloc(sizeof(struct nfor));
10232 n1->nfor.var = wordtext;
10233 checkkwd = CHKKWD | CHKALIAS;
10234 if (readtoken() == TIN) {
10236 while (readtoken() == TWORD) {
10237 n2 = stzalloc(sizeof(struct narg));
10239 /*n2->narg.next = NULL; - stzalloc did it */
10240 n2->narg.text = wordtext;
10241 n2->narg.backquote = backquotelist;
10243 app = &n2->narg.next;
10246 n1->nfor.args = ap;
10247 if (lasttoken != TNL && lasttoken != TSEMI)
10248 raise_error_unexpected_syntax(-1);
10250 n2 = stzalloc(sizeof(struct narg));
10252 /*n2->narg.next = NULL; - stzalloc did it */
10253 n2->narg.text = (char *)dolatstr;
10254 /*n2->narg.backquote = NULL;*/
10255 n1->nfor.args = n2;
10257 * Newline or semicolon here is optional (but note
10258 * that the original Bourne shell only allowed NL).
10260 if (lasttoken != TNL && lasttoken != TSEMI)
10263 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10264 if (readtoken() != TDO)
10265 raise_error_unexpected_syntax(TDO);
10266 n1->nfor.body = list(0);
10270 n1 = stzalloc(sizeof(struct ncase));
10272 if (readtoken() != TWORD)
10273 raise_error_unexpected_syntax(TWORD);
10274 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10276 /*n2->narg.next = NULL; - stzalloc did it */
10277 n2->narg.text = wordtext;
10278 n2->narg.backquote = backquotelist;
10280 checkkwd = CHKKWD | CHKALIAS;
10281 } while (readtoken() == TNL);
10282 if (lasttoken != TIN)
10283 raise_error_unexpected_syntax(TIN);
10284 cpp = &n1->ncase.cases;
10286 checkkwd = CHKNL | CHKKWD;
10288 while (t != TESAC) {
10289 if (lasttoken == TLP)
10291 *cpp = cp = stzalloc(sizeof(struct nclist));
10293 app = &cp->nclist.pattern;
10295 *app = ap = stzalloc(sizeof(struct narg));
10297 /*ap->narg.next = NULL; - stzalloc did it */
10298 ap->narg.text = wordtext;
10299 ap->narg.backquote = backquotelist;
10300 if (readtoken() != TPIPE)
10302 app = &ap->narg.next;
10305 //ap->narg.next = NULL;
10306 if (lasttoken != TRP)
10307 raise_error_unexpected_syntax(TRP);
10308 cp->nclist.body = list(2);
10310 cpp = &cp->nclist.next;
10312 checkkwd = CHKNL | CHKKWD;
10316 raise_error_unexpected_syntax(TENDCASE);
10323 n1 = stzalloc(sizeof(struct nredir));
10324 n1->type = NSUBSHELL;
10325 n1->nredir.n = list(0);
10326 /*n1->nredir.redirect = NULL; - stzalloc did it */
10336 return simplecmd();
10339 if (readtoken() != t)
10340 raise_error_unexpected_syntax(t);
10343 /* Now check for redirection which may follow command */
10344 checkkwd = CHKKWD | CHKALIAS;
10346 while (readtoken() == TREDIR) {
10347 *rpp = n2 = redirnode;
10348 rpp = &n2->nfile.next;
10354 if (n1->type != NSUBSHELL) {
10355 n2 = stzalloc(sizeof(struct nredir));
10360 n1->nredir.redirect = redir;
10365 #if ENABLE_ASH_BASH_COMPAT
10366 static int decode_dollar_squote(void)
10368 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
10374 p = strchr(C_escapes, c);
10379 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
10383 } while ((unsigned char)(c - '0') <= 7 && --cnt);
10385 } else if (c == 'x') { /* \xHH */
10389 } while (isxdigit(c) && --cnt);
10391 if (cnt == 3) { /* \x but next char is "bad" */
10395 } else { /* simple seq like \\ or \t */
10400 c = bb_process_escape_sequence((void*)&p);
10401 } else { /* unrecognized "\z": print both chars unless ' or " */
10402 if (c != '\'' && c != '"') {
10404 c |= 0x100; /* "please encode \, then me" */
10412 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10413 * is not NULL, read a here document. In the latter case, eofmark is the
10414 * word which marks the end of the document and striptabs is true if
10415 * leading tabs should be stripped from the document. The argument firstc
10416 * is the first character of the input token or document.
10418 * Because C does not have internal subroutines, I have simulated them
10419 * using goto's to implement the subroutine linkage. The following macros
10420 * will run code that appears at the end of readtoken1.
10422 #define CHECKEND() {goto checkend; checkend_return:;}
10423 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10424 #define PARSESUB() {goto parsesub; parsesub_return:;}
10425 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10426 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10427 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10429 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10431 /* NB: syntax parameter fits into smallint */
10435 char line[EOFMARKLEN + 1];
10436 struct nodelist *bqlist;
10440 smallint prevsyntax; /* syntax before arithmetic */
10441 #if ENABLE_ASH_EXPAND_PRMT
10442 smallint pssyntax; /* we are expanding a prompt string */
10444 int varnest; /* levels of variables expansion */
10445 int arinest; /* levels of arithmetic expansion */
10446 int parenlevel; /* levels of parens in arithmetic */
10447 int dqvarnest; /* levels of variables expansion within double quotes */
10449 USE_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
10452 /* Avoid longjmp clobbering */
10458 (void) &parenlevel;
10461 (void) &prevsyntax;
10464 startlinno = plinno;
10469 #if ENABLE_ASH_EXPAND_PRMT
10470 pssyntax = (syntax == PSSYNTAX);
10474 dblquote = (syntax == DQSYNTAX);
10480 STARTSTACKSTR(out);
10481 loop: { /* for each line, until end of word */
10482 CHECKEND(); /* set c to PEOF if at end of here document */
10483 for (;;) { /* until end of line or end of word */
10484 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10485 switch (SIT(c, syntax)) {
10486 case CNL: /* '\n' */
10487 if (syntax == BASESYNTAX)
10488 goto endword; /* exit outer loop */
10494 goto loop; /* continue outer loop */
10499 if (eofmark == NULL || dblquote)
10500 USTPUTC(CTLESC, out);
10501 #if ENABLE_ASH_BASH_COMPAT
10502 if (c == '\\' && bash_dollar_squote) {
10503 c = decode_dollar_squote();
10505 USTPUTC('\\', out);
10506 c = (unsigned char)c;
10512 case CBACK: /* backslash */
10515 USTPUTC(CTLESC, out);
10516 USTPUTC('\\', out);
10518 } else if (c == '\n') {
10522 #if ENABLE_ASH_EXPAND_PRMT
10523 if (c == '$' && pssyntax) {
10524 USTPUTC(CTLESC, out);
10525 USTPUTC('\\', out);
10528 if (dblquote && c != '\\'
10529 && c != '`' && c != '$'
10530 && (c != '"' || eofmark != NULL)
10532 USTPUTC(CTLESC, out);
10533 USTPUTC('\\', out);
10535 if (SIT(c, SQSYNTAX) == CCTL)
10536 USTPUTC(CTLESC, out);
10544 if (eofmark == NULL) {
10545 USTPUTC(CTLQUOTEMARK, out);
10553 USE_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
10554 if (eofmark != NULL && arinest == 0
10559 if (dqvarnest == 0) {
10560 syntax = BASESYNTAX;
10567 case CVAR: /* '$' */
10568 PARSESUB(); /* parse substitution */
10570 case CENDVAR: /* '}' */
10573 if (dqvarnest > 0) {
10576 USTPUTC(CTLENDVAR, out);
10581 #if ENABLE_ASH_MATH_SUPPORT
10582 case CLP: /* '(' in arithmetic */
10586 case CRP: /* ')' in arithmetic */
10587 if (parenlevel > 0) {
10591 if (pgetc() == ')') {
10592 if (--arinest == 0) {
10593 USTPUTC(CTLENDARI, out);
10594 syntax = prevsyntax;
10595 dblquote = (syntax == DQSYNTAX);
10600 * unbalanced parens
10601 * (don't 2nd guess - no error)
10609 case CBQUOTE: /* '`' */
10613 goto endword; /* exit outer loop */
10618 goto endword; /* exit outer loop */
10619 #if ENABLE_ASH_ALIAS
10629 #if ENABLE_ASH_MATH_SUPPORT
10630 if (syntax == ARISYNTAX)
10631 raise_error_syntax("Missing '))'");
10633 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10634 raise_error_syntax("Unterminated quoted string");
10635 if (varnest != 0) {
10636 startlinno = plinno;
10638 raise_error_syntax("Missing '}'");
10640 USTPUTC('\0', out);
10641 len = out - (char *)stackblock();
10642 out = stackblock();
10643 if (eofmark == NULL) {
10644 if ((c == '>' || c == '<')
10647 && (*out == '\0' || isdigit(*out))
10650 lasttoken = TREDIR;
10655 quoteflag = quotef;
10656 backquotelist = bqlist;
10657 grabstackblock(len);
10661 /* end of readtoken routine */
10664 * Check to see whether we are at the end of the here document. When this
10665 * is called, c is set to the first character of the next input line. If
10666 * we are at the end of the here document, this routine sets the c to PEOF.
10670 #if ENABLE_ASH_ALIAS
10676 while (c == '\t') {
10680 if (c == *eofmark) {
10681 if (pfgets(line, sizeof(line)) != NULL) {
10685 for (q = eofmark + 1; *q && *p == *q; p++, q++)
10687 if (*p == '\n' && *q == '\0') {
10690 needprompt = doprompt;
10692 pushstring(line, NULL);
10697 goto checkend_return;
10701 * Parse a redirection operator. The variable "out" points to a string
10702 * specifying the fd to be redirected. The variable "c" contains the
10703 * first character of the redirection operator.
10709 np = stzalloc(sizeof(struct nfile));
10714 np->type = NAPPEND;
10716 np->type = NCLOBBER;
10723 } else { /* c == '<' */
10724 /*np->nfile.fd = 0; - stzalloc did it */
10728 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10729 np = stzalloc(sizeof(struct nhere));
10730 /*np->nfile.fd = 0; - stzalloc did it */
10733 heredoc = stzalloc(sizeof(struct heredoc));
10734 heredoc->here = np;
10737 heredoc->striptabs = 1;
10739 /*heredoc->striptabs = 0; - stzalloc did it */
10745 np->type = NFROMFD;
10749 np->type = NFROMTO;
10759 np->nfile.fd = fd - '0';
10761 goto parseredir_return;
10765 * Parse a substitution. At this point, we have read the dollar sign
10766 * and nothing else.
10769 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
10770 * (assuming ascii char codes, as the original implementation did) */
10771 #define is_special(c) \
10772 (((unsigned)(c) - 33 < 32) \
10773 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
10779 static const char types[] ALIGN1 = "}-+?=";
10782 if (c <= PEOA_OR_PEOF
10783 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10785 #if ENABLE_ASH_BASH_COMPAT
10787 bash_dollar_squote = 1;
10792 } else if (c == '(') { /* $(command) or $((arith)) */
10793 if (pgetc() == '(') {
10794 #if ENABLE_ASH_MATH_SUPPORT
10797 raise_error_syntax("you disabled math support for $((arith)) syntax");
10804 USTPUTC(CTLVAR, out);
10805 typeloc = out - (char *)stackblock();
10806 USTPUTC(VSNORMAL, out);
10807 subtype = VSNORMAL;
10815 subtype = VSLENGTH;
10819 if (c > PEOA_OR_PEOF && is_name(c)) {
10823 } while (c > PEOA_OR_PEOF && is_in_name(c));
10824 } else if (isdigit(c)) {
10828 } while (isdigit(c));
10829 } else if (is_special(c)) {
10833 badsub: raise_error_syntax("Bad substitution");
10837 if (subtype == 0) {
10841 #if ENABLE_ASH_BASH_COMPAT
10842 if (c == ':' || c == '$' || isdigit(c)) {
10844 subtype = VSSUBSTR;
10851 p = strchr(types, c);
10854 subtype = p - types + VSNORMAL;
10859 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
10867 #if ENABLE_ASH_BASH_COMPAT
10869 subtype = VSREPLACE;
10872 subtype++; /* VSREPLACEALL */
10881 if (dblquote || arinest)
10883 *((char *)stackblock() + typeloc) = subtype | flags;
10884 if (subtype != VSNORMAL) {
10886 if (dblquote || arinest) {
10891 goto parsesub_return;
10895 * Called to parse command substitutions. Newstyle is set if the command
10896 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10897 * list of commands (passed by reference), and savelen is the number of
10898 * characters on the top of the stack which must be preserved.
10901 struct nodelist **nlpp;
10904 char *volatile str;
10905 struct jmploc jmploc;
10906 struct jmploc *volatile savehandler;
10908 smallint saveprompt = 0;
10911 (void) &saveprompt;
10913 savepbq = parsebackquote;
10914 if (setjmp(jmploc.loc)) {
10916 parsebackquote = 0;
10917 exception_handler = savehandler;
10918 longjmp(exception_handler->loc, 1);
10922 savelen = out - (char *)stackblock();
10924 str = ckmalloc(savelen);
10925 memcpy(str, stackblock(), savelen);
10927 savehandler = exception_handler;
10928 exception_handler = &jmploc;
10931 /* We must read until the closing backquote, giving special
10932 treatment to some slashes, and then push the string and
10933 reread it as input, interpreting it normally. */
10940 STARTSTACKSTR(pout);
10957 * If eating a newline, avoid putting
10958 * the newline into the new character
10959 * stream (via the STPUTC after the
10964 if (pc != '\\' && pc != '`' && pc != '$'
10965 && (!dblquote || pc != '"'))
10966 STPUTC('\\', pout);
10967 if (pc > PEOA_OR_PEOF) {
10973 #if ENABLE_ASH_ALIAS
10976 startlinno = plinno;
10977 raise_error_syntax("EOF in backquote substitution");
10981 needprompt = doprompt;
10990 STPUTC('\0', pout);
10991 psavelen = pout - (char *)stackblock();
10992 if (psavelen > 0) {
10993 pstr = grabstackstr(pout);
10994 setinputstring(pstr);
10999 nlpp = &(*nlpp)->next;
11000 *nlpp = stzalloc(sizeof(**nlpp));
11001 /* (*nlpp)->next = NULL; - stzalloc did it */
11002 parsebackquote = oldstyle;
11005 saveprompt = doprompt;
11012 doprompt = saveprompt;
11013 else if (readtoken() != TRP)
11014 raise_error_unexpected_syntax(TRP);
11019 * Start reading from old file again, ignoring any pushed back
11020 * tokens left from the backquote parsing
11025 while (stackblocksize() <= savelen)
11027 STARTSTACKSTR(out);
11029 memcpy(out, str, savelen);
11030 STADJUST(savelen, out);
11036 parsebackquote = savepbq;
11037 exception_handler = savehandler;
11038 if (arinest || dblquote)
11039 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11041 USTPUTC(CTLBACKQ, out);
11043 goto parsebackq_oldreturn;
11044 goto parsebackq_newreturn;
11047 #if ENABLE_ASH_MATH_SUPPORT
11049 * Parse an arithmetic expansion (indicate start of one and set state)
11052 if (++arinest == 1) {
11053 prevsyntax = syntax;
11054 syntax = ARISYNTAX;
11055 USTPUTC(CTLARI, out);
11062 * we collapse embedded arithmetic expansion to
11063 * parenthesis, which should be equivalent
11067 goto parsearith_return;
11071 } /* end of readtoken */
11074 * Read the next input token.
11075 * If the token is a word, we set backquotelist to the list of cmds in
11076 * backquotes. We set quoteflag to true if any part of the word was
11078 * If the token is TREDIR, then we set redirnode to a structure containing
11080 * In all cases, the variable startlinno is set to the number of the line
11081 * on which the token starts.
11083 * [Change comment: here documents and internal procedures]
11084 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11085 * word parsing code into a separate routine. In this case, readtoken
11086 * doesn't need to have any internal procedures, but parseword does.
11087 * We could also make parseoperator in essence the main routine, and
11088 * have parseword (readtoken1?) handle both words and redirection.]
11090 #define NEW_xxreadtoken
11091 #ifdef NEW_xxreadtoken
11092 /* singles must be first! */
11093 static const char xxreadtoken_chars[7] ALIGN1 = {
11094 '\n', '(', ')', '&', '|', ';', 0
11097 static const char xxreadtoken_tokens[] ALIGN1 = {
11098 TNL, TLP, TRP, /* only single occurrence allowed */
11099 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11100 TEOF, /* corresponds to trailing nul */
11101 TAND, TOR, TENDCASE /* if double occurrence */
11104 #define xxreadtoken_doubles \
11105 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
11106 #define xxreadtoken_singles \
11107 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
11121 startlinno = plinno;
11122 for (;;) { /* until token or start of word found */
11125 if ((c != ' ') && (c != '\t')
11126 #if ENABLE_ASH_ALIAS
11131 while ((c = pgetc()) != '\n' && c != PEOF)
11134 } else if (c == '\\') {
11135 if (pgetc() != '\n') {
11139 startlinno = ++plinno;
11144 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11149 needprompt = doprompt;
11152 p = strchr(xxreadtoken_chars, c);
11155 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11158 if ((size_t)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11159 if (pgetc() == *p) { /* double occurrence? */
11160 p += xxreadtoken_doubles + 1;
11166 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11173 #define RETURN(token) return lasttoken = token
11186 startlinno = plinno;
11187 for (;;) { /* until token or start of word found */
11190 case ' ': case '\t':
11191 #if ENABLE_ASH_ALIAS
11196 while ((c = pgetc()) != '\n' && c != PEOF)
11201 if (pgetc() == '\n') {
11202 startlinno = ++plinno;
11211 needprompt = doprompt;
11216 if (pgetc() == '&')
11221 if (pgetc() == '|')
11226 if (pgetc() == ';')
11239 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11242 #endif /* NEW_xxreadtoken */
11249 smallint alreadyseen = tokpushback;
11252 #if ENABLE_ASH_ALIAS
11261 if (checkkwd & CHKNL) {
11268 if (t != TWORD || quoteflag) {
11273 * check for keywords
11275 if (checkkwd & CHKKWD) {
11276 const char *const *pp;
11278 pp = findkwd(wordtext);
11280 lasttoken = t = pp - tokname_array;
11281 TRACE(("keyword %s recognized\n", tokname(t)));
11286 if (checkkwd & CHKALIAS) {
11287 #if ENABLE_ASH_ALIAS
11289 ap = lookupalias(wordtext, 1);
11292 pushstring(ap->val, ap);
11302 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11304 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11316 return tokname_array[t][0];
11320 * Read and parse a command. Returns NEOF on end of file. (NULL is a
11321 * valid parse tree indicating a blank line.)
11323 static union node *
11324 parsecmd(int interact)
11329 doprompt = interact;
11331 setprompt(doprompt);
11343 * Input any here documents.
11348 struct heredoc *here;
11351 here = heredoclist;
11352 heredoclist = NULL;
11358 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
11359 here->eofmark, here->striptabs);
11360 n = stzalloc(sizeof(struct narg));
11361 n->narg.type = NARG;
11362 /*n->narg.next = NULL; - stzalloc did it */
11363 n->narg.text = wordtext;
11364 n->narg.backquote = backquotelist;
11365 here->here->nhere.doc = n;
11372 * called by editline -- any expansions to the prompt should be added here.
11374 #if ENABLE_ASH_EXPAND_PRMT
11375 static const char *
11376 expandstr(const char *ps)
11380 /* XXX Fix (char *) cast. */
11381 setinputstring((char *)ps);
11382 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
11385 n.narg.type = NARG;
11386 n.narg.next = NULL;
11387 n.narg.text = wordtext;
11388 n.narg.backquote = backquotelist;
11390 expandarg(&n, NULL, 0);
11391 return stackblock();
11396 * Execute a command or commands contained in a string.
11399 evalstring(char *s, int mask)
11402 struct stackmark smark;
11406 setstackmark(&smark);
11409 while ((n = parsecmd(0)) != NEOF) {
11411 popstackmark(&smark);
11424 * The eval command.
11427 evalcmd(int argc UNUSED_PARAM, char **argv)
11436 STARTSTACKSTR(concat);
11438 concat = stack_putstr(p, concat);
11442 STPUTC(' ', concat);
11444 STPUTC('\0', concat);
11445 p = grabstackstr(concat);
11447 evalstring(p, ~SKIPEVAL);
11454 * Read and execute commands. "Top" is nonzero for the top level command
11455 * loop; it turns on prompting if the shell is interactive.
11461 struct stackmark smark;
11465 TRACE(("cmdloop(%d) called\n", top));
11469 setstackmark(&smark);
11472 showjobs(stderr, SHOW_CHANGED);
11475 if (iflag && top) {
11477 #if ENABLE_ASH_MAIL
11481 n = parsecmd(inter);
11482 /* showtree(n); DEBUG */
11484 if (!top || numeof >= 50)
11486 if (!stoppedjobs()) {
11489 out2str("\nUse \"exit\" to leave shell.\n");
11492 } else if (nflag == 0) {
11493 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11498 popstackmark(&smark);
11503 return skip & SKIPEVAL;
11510 * Take commands from a file. To be compatible we should do a path
11511 * search for the file, which is necessary to find sub-commands.
11514 find_dot_file(char *name)
11517 const char *path = pathval();
11520 /* don't try this for absolute or relative paths */
11521 if (strchr(name, '/'))
11524 while ((fullname = padvance(&path, name)) != NULL) {
11525 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11527 * Don't bother freeing here, since it will
11528 * be freed by the caller.
11532 stunalloc(fullname);
11535 /* not found in the PATH */
11536 ash_msg_and_raise_error("%s: not found", name);
11541 dotcmd(int argc, char **argv)
11543 struct strlist *sp;
11544 volatile struct shparam saveparam;
11547 for (sp = cmdenviron; sp; sp = sp->next)
11548 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11550 if (argv[1]) { /* That's what SVR2 does */
11551 char *fullname = find_dot_file(argv[1]);
11554 if (argc) { /* argc > 0, argv[0] != NULL */
11555 saveparam = shellparam;
11556 shellparam.malloced = 0;
11557 shellparam.nparam = argc;
11558 shellparam.p = argv;
11561 setinputfile(fullname, INPUT_PUSH_FILE);
11562 commandname = fullname;
11567 freeparam(&shellparam);
11568 shellparam = saveparam;
11570 status = exitstatus;
11576 exitcmd(int argc UNUSED_PARAM, char **argv)
11581 exitstatus = number(argv[1]);
11582 raise_exception(EXEXIT);
11587 * Read a file containing shell functions.
11590 readcmdfile(char *name)
11592 setinputfile(name, INPUT_PUSH_FILE);
11598 /* ============ find_command inplementation */
11601 * Resolve a command name. If you change this routine, you may have to
11602 * change the shellexec routine as well.
11605 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11607 struct tblentry *cmdp;
11614 struct builtincmd *bcmd;
11616 /* If name contains a slash, don't use PATH or hash table */
11617 if (strchr(name, '/') != NULL) {
11618 entry->u.index = -1;
11619 if (act & DO_ABS) {
11620 while (stat(name, &statb) < 0) {
11622 if (errno == EINTR)
11625 entry->cmdtype = CMDUNKNOWN;
11629 entry->cmdtype = CMDNORMAL;
11633 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11635 updatetbl = (path == pathval());
11638 if (strstr(path, "%builtin") != NULL)
11639 act |= DO_ALTBLTIN;
11642 /* If name is in the table, check answer will be ok */
11643 cmdp = cmdlookup(name, 0);
11644 if (cmdp != NULL) {
11647 switch (cmdp->cmdtype) {
11665 } else if (cmdp->rehash == 0)
11666 /* if not invalidated by cd, we're done */
11670 /* If %builtin not in path, check for builtin next */
11671 bcmd = find_builtin(name);
11673 if (IS_BUILTIN_REGULAR(bcmd))
11674 goto builtin_success;
11675 if (act & DO_ALTPATH) {
11676 if (!(act & DO_ALTBLTIN))
11677 goto builtin_success;
11678 } else if (builtinloc <= 0) {
11679 goto builtin_success;
11683 #if ENABLE_FEATURE_SH_STANDALONE
11685 int applet_no = find_applet_by_name(name);
11686 if (applet_no >= 0) {
11687 entry->cmdtype = CMDNORMAL;
11688 entry->u.index = -2 - applet_no;
11694 /* We have to search path. */
11695 prev = -1; /* where to start */
11696 if (cmdp && cmdp->rehash) { /* doing a rehash */
11697 if (cmdp->cmdtype == CMDBUILTIN)
11700 prev = cmdp->param.index;
11706 while ((fullname = padvance(&path, name)) != NULL) {
11707 stunalloc(fullname);
11708 /* NB: code below will still use fullname
11709 * despite it being "unallocated" */
11712 if (prefix(pathopt, "builtin")) {
11714 goto builtin_success;
11717 if ((act & DO_NOFUNC)
11718 || !prefix(pathopt, "func")
11719 ) { /* ignore unimplemented options */
11723 /* if rehash, don't redo absolute path names */
11724 if (fullname[0] == '/' && idx <= prev) {
11727 TRACE(("searchexec \"%s\": no change\n", name));
11730 while (stat(fullname, &statb) < 0) {
11732 if (errno == EINTR)
11735 if (errno != ENOENT && errno != ENOTDIR)
11739 e = EACCES; /* if we fail, this will be the error */
11740 if (!S_ISREG(statb.st_mode))
11742 if (pathopt) { /* this is a %func directory */
11743 stalloc(strlen(fullname) + 1);
11744 /* NB: stalloc will return space pointed by fullname
11745 * (because we don't have any intervening allocations
11746 * between stunalloc above and this stalloc) */
11747 readcmdfile(fullname);
11748 cmdp = cmdlookup(name, 0);
11749 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
11750 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
11751 stunalloc(fullname);
11754 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
11756 entry->cmdtype = CMDNORMAL;
11757 entry->u.index = idx;
11761 cmdp = cmdlookup(name, 1);
11762 cmdp->cmdtype = CMDNORMAL;
11763 cmdp->param.index = idx;
11768 /* We failed. If there was an entry for this command, delete it */
11769 if (cmdp && updatetbl)
11770 delete_cmd_entry();
11772 ash_msg("%s: %s", name, errmsg(e, "not found"));
11773 entry->cmdtype = CMDUNKNOWN;
11778 entry->cmdtype = CMDBUILTIN;
11779 entry->u.cmd = bcmd;
11783 cmdp = cmdlookup(name, 1);
11784 cmdp->cmdtype = CMDBUILTIN;
11785 cmdp->param.cmd = bcmd;
11789 entry->cmdtype = cmdp->cmdtype;
11790 entry->u = cmdp->param;
11794 /* ============ trap.c */
11797 * The trap builtin.
11800 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11809 for (signo = 0; signo < NSIG; signo++) {
11810 if (trap[signo] != NULL) {
11813 sn = get_signame(signo);
11814 out1fmt("trap -- %s %s\n",
11815 single_quote(trap[signo]), sn);
11825 signo = get_signum(*ap);
11827 ash_msg_and_raise_error("%s: bad trap", *ap);
11830 if (LONE_DASH(action))
11833 action = ckstrdup(action);
11836 trap[signo] = action;
11846 /* ============ Builtins */
11848 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
11850 * Lists available builtins
11853 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11858 out1fmt("\nBuilt-in commands:\n-------------------\n");
11859 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
11860 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11861 builtintab[i].name + 1);
11867 #if ENABLE_FEATURE_SH_STANDALONE
11869 const char *a = applet_names;
11871 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
11876 a += strlen(a) + 1;
11881 return EXIT_SUCCESS;
11883 #endif /* FEATURE_SH_EXTRA_QUIET */
11886 * The export and readonly commands.
11889 exportcmd(int argc UNUSED_PARAM, char **argv)
11895 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
11897 if (nextopt("p") != 'p') {
11902 p = strchr(name, '=');
11906 vp = *findvar(hashvar(name), name);
11912 setvar(name, p, flag);
11913 } while ((name = *++aptr) != NULL);
11917 showvars(argv[0], flag, 0);
11922 * Delete a function if it exists.
11925 unsetfunc(const char *name)
11927 struct tblentry *cmdp;
11929 cmdp = cmdlookup(name, 0);
11930 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
11931 delete_cmd_entry();
11935 * The unset builtin command. We unset the function before we unset the
11936 * variable to allow a function to be unset when there is a readonly variable
11937 * with the same name.
11940 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11947 while ((i = nextopt("vf")) != '\0') {
11951 for (ap = argptr; *ap; ap++) {
11967 #include <sys/times.h>
11969 static const unsigned char timescmd_str[] ALIGN1 = {
11970 ' ', offsetof(struct tms, tms_utime),
11971 '\n', offsetof(struct tms, tms_stime),
11972 ' ', offsetof(struct tms, tms_cutime),
11973 '\n', offsetof(struct tms, tms_cstime),
11978 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11980 long clk_tck, s, t;
11981 const unsigned char *p;
11984 clk_tck = sysconf(_SC_CLK_TCK);
11989 t = *(clock_t *)(((char *) &buf) + p[1]);
11991 out1fmt("%ldm%ld.%.3lds%c",
11993 ((t - s * clk_tck) * 1000) / clk_tck,
11995 } while (*(p += 2));
12000 #if ENABLE_ASH_MATH_SUPPORT
12002 dash_arith(const char *s)
12008 result = arith(s, &errcode);
12011 ash_msg_and_raise_error("exponent less than 0");
12013 ash_msg_and_raise_error("divide by zero");
12015 ash_msg_and_raise_error("expression recursion loop detected");
12016 raise_error_syntax(s);
12024 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12025 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12027 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12030 letcmd(int argc UNUSED_PARAM, char **argv)
12036 ash_msg_and_raise_error("expression expected");
12038 i = dash_arith(*argv);
12043 #endif /* ASH_MATH_SUPPORT */
12046 /* ============ miscbltin.c
12048 * Miscellaneous builtins.
12053 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12054 typedef enum __rlimit_resource rlim_t;
12058 * The read builtin. Options:
12059 * -r Do not interpret '\' specially
12060 * -s Turn off echo (tty only)
12061 * -n NCHARS Read NCHARS max
12062 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12063 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12064 * -u FD Read from given FD instead of fd 0
12065 * This uses unbuffered input, which may be avoidable in some cases.
12066 * TODO: bash also has:
12067 * -a ARRAY Read into array[0],[1],etc
12068 * -d DELIM End on DELIM char, not newline
12069 * -e Use line editing (tty only)
12072 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12074 static const char *const arg_REPLY[] = { "REPLY", NULL };
12087 #if ENABLE_ASH_READ_NCHARS
12088 int nchars = 0; /* if != 0, -n is in effect */
12090 struct termios tty, old_tty;
12092 #if ENABLE_ASH_READ_TIMEOUT
12093 unsigned end_ms = 0;
12094 unsigned timeout = 0;
12099 while ((i = nextopt("p:u:r"
12100 USE_ASH_READ_TIMEOUT("t:")
12101 USE_ASH_READ_NCHARS("n:s")
12105 prompt = optionarg;
12107 #if ENABLE_ASH_READ_NCHARS
12109 nchars = bb_strtou(optionarg, NULL, 10);
12110 if (nchars < 0 || errno)
12111 ash_msg_and_raise_error("invalid count");
12112 /* nchars == 0: off (bash 3.2 does this too) */
12118 #if ENABLE_ASH_READ_TIMEOUT
12120 timeout = bb_strtou(optionarg, NULL, 10);
12121 if (errno || timeout > UINT_MAX / 2048)
12122 ash_msg_and_raise_error("invalid timeout");
12124 #if 0 /* even bash have no -t N.NNN support */
12125 ts.tv_sec = bb_strtou(optionarg, &p, 10);
12127 /* EINVAL means number is ok, but not terminated by NUL */
12128 if (*p == '.' && errno == EINVAL) {
12132 ts.tv_usec = bb_strtou(p, &p2, 10);
12134 ash_msg_and_raise_error("invalid timeout");
12136 /* normalize to usec */
12138 ash_msg_and_raise_error("invalid timeout");
12139 while (scale++ < 6)
12142 } else if (ts.tv_sec < 0 || errno) {
12143 ash_msg_and_raise_error("invalid timeout");
12145 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
12146 ash_msg_and_raise_error("invalid timeout");
12155 fd = bb_strtou(optionarg, NULL, 10);
12156 if (fd < 0 || errno)
12157 ash_msg_and_raise_error("invalid file descriptor");
12163 if (prompt && isatty(fd)) {
12168 ap = (char**)arg_REPLY;
12169 ifs = bltinlookup("IFS");
12172 #if ENABLE_ASH_READ_NCHARS
12173 tcgetattr(fd, &tty);
12175 if (nchars || silent) {
12177 tty.c_lflag &= ~ICANON;
12178 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
12181 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
12183 /* if tcgetattr failed, tcsetattr will fail too.
12184 * Ignoring, it's harmless. */
12185 tcsetattr(fd, TCSANOW, &tty);
12192 #if ENABLE_ASH_READ_TIMEOUT
12193 if (timeout) /* NB: ensuring end_ms is nonzero */
12194 end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1;
12198 #if ENABLE_ASH_READ_TIMEOUT
12200 struct pollfd pfd[1];
12202 pfd[0].events = POLLIN;
12203 timeout = end_ms - (unsigned)(monotonic_us() / 1000);
12204 if ((int)timeout <= 0 /* already late? */
12205 || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
12206 ) { /* timed out! */
12207 #if ENABLE_ASH_READ_NCHARS
12208 tcsetattr(fd, TCSANOW, &old_tty);
12214 if (nonblock_safe_read(fd, &c, 1) != 1) {
12226 if (!rflag && c == '\\') {
12232 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12236 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12238 setvar(*ap, stackblock(), 0);
12247 /* end of do {} while: */
12248 #if ENABLE_ASH_READ_NCHARS
12254 #if ENABLE_ASH_READ_NCHARS
12255 tcsetattr(fd, TCSANOW, &old_tty);
12259 /* Remove trailing blanks */
12260 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12262 setvar(*ap, stackblock(), 0);
12263 while (*++ap != NULL)
12264 setvar(*ap, nullstr, 0);
12269 umaskcmd(int argc UNUSED_PARAM, char **argv)
12271 static const char permuser[3] ALIGN1 = "ugo";
12272 static const char permmode[3] ALIGN1 = "rwx";
12273 static const short permmask[] ALIGN2 = {
12274 S_IRUSR, S_IWUSR, S_IXUSR,
12275 S_IRGRP, S_IWGRP, S_IXGRP,
12276 S_IROTH, S_IWOTH, S_IXOTH
12282 int symbolic_mode = 0;
12284 while (nextopt("S") != '\0') {
12295 if (symbolic_mode) {
12299 for (i = 0; i < 3; i++) {
12302 *p++ = permuser[i];
12304 for (j = 0; j < 3; j++) {
12305 if ((mask & permmask[3 * i + j]) == 0) {
12306 *p++ = permmode[j];
12314 out1fmt("%.4o\n", mask);
12317 if (isdigit((unsigned char) *ap)) {
12320 if (*ap >= '8' || *ap < '0')
12321 ash_msg_and_raise_error(illnum, argv[1]);
12322 mask = (mask << 3) + (*ap - '0');
12323 } while (*++ap != '\0');
12326 mask = ~mask & 0777;
12327 if (!bb_parse_mode(ap, &mask)) {
12328 ash_msg_and_raise_error("illegal mode: %s", ap);
12330 umask(~mask & 0777);
12339 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12340 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12341 * ash by J.T. Conklin.
12347 uint8_t cmd; /* RLIMIT_xxx fit into it */
12348 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
12352 static const struct limits limits_tbl[] = {
12354 { RLIMIT_CPU, 0, 't' },
12356 #ifdef RLIMIT_FSIZE
12357 { RLIMIT_FSIZE, 9, 'f' },
12360 { RLIMIT_DATA, 10, 'd' },
12362 #ifdef RLIMIT_STACK
12363 { RLIMIT_STACK, 10, 's' },
12366 { RLIMIT_CORE, 9, 'c' },
12369 { RLIMIT_RSS, 10, 'm' },
12371 #ifdef RLIMIT_MEMLOCK
12372 { RLIMIT_MEMLOCK, 10, 'l' },
12374 #ifdef RLIMIT_NPROC
12375 { RLIMIT_NPROC, 0, 'p' },
12377 #ifdef RLIMIT_NOFILE
12378 { RLIMIT_NOFILE, 0, 'n' },
12381 { RLIMIT_AS, 10, 'v' },
12383 #ifdef RLIMIT_LOCKS
12384 { RLIMIT_LOCKS, 0, 'w' },
12387 static const char limits_name[] =
12389 "time(seconds)" "\0"
12391 #ifdef RLIMIT_FSIZE
12392 "file(blocks)" "\0"
12397 #ifdef RLIMIT_STACK
12401 "coredump(blocks)" "\0"
12406 #ifdef RLIMIT_MEMLOCK
12407 "locked memory(kb)" "\0"
12409 #ifdef RLIMIT_NPROC
12412 #ifdef RLIMIT_NOFILE
12418 #ifdef RLIMIT_LOCKS
12423 enum limtype { SOFT = 0x1, HARD = 0x2 };
12426 printlim(enum limtype how, const struct rlimit *limit,
12427 const struct limits *l)
12431 val = limit->rlim_max;
12433 val = limit->rlim_cur;
12435 if (val == RLIM_INFINITY)
12436 out1fmt("unlimited\n");
12438 val >>= l->factor_shift;
12439 out1fmt("%lld\n", (long long) val);
12444 ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12448 enum limtype how = SOFT | HARD;
12449 const struct limits *l;
12452 struct rlimit limit;
12455 while ((optc = nextopt("HSa"
12459 #ifdef RLIMIT_FSIZE
12465 #ifdef RLIMIT_STACK
12474 #ifdef RLIMIT_MEMLOCK
12477 #ifdef RLIMIT_NPROC
12480 #ifdef RLIMIT_NOFILE
12486 #ifdef RLIMIT_LOCKS
12504 for (l = limits_tbl; l->option != what; l++)
12507 set = *argptr ? 1 : 0;
12511 if (all || argptr[1])
12512 ash_msg_and_raise_error("too many arguments");
12513 if (strncmp(p, "unlimited\n", 9) == 0)
12514 val = RLIM_INFINITY;
12518 while ((c = *p++) >= '0' && c <= '9') {
12519 val = (val * 10) + (long)(c - '0');
12520 // val is actually 'unsigned long int' and can't get < 0
12521 if (val < (rlim_t) 0)
12525 ash_msg_and_raise_error("bad number");
12526 val <<= l->factor_shift;
12530 const char *lname = limits_name;
12531 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12532 getrlimit(l->cmd, &limit);
12533 out1fmt("%-20s ", lname);
12534 lname += strlen(lname) + 1;
12535 printlim(how, &limit, l);
12540 getrlimit(l->cmd, &limit);
12543 limit.rlim_max = val;
12545 limit.rlim_cur = val;
12546 if (setrlimit(l->cmd, &limit) < 0)
12547 ash_msg_and_raise_error("error setting limit (%m)");
12549 printlim(how, &limit, l);
12555 /* ============ Math support */
12557 #if ENABLE_ASH_MATH_SUPPORT
12559 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12561 Permission is hereby granted, free of charge, to any person obtaining
12562 a copy of this software and associated documentation files (the
12563 "Software"), to deal in the Software without restriction, including
12564 without limitation the rights to use, copy, modify, merge, publish,
12565 distribute, sublicense, and/or sell copies of the Software, and to
12566 permit persons to whom the Software is furnished to do so, subject to
12567 the following conditions:
12569 The above copyright notice and this permission notice shall be
12570 included in all copies or substantial portions of the Software.
12572 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12573 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12574 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12575 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12576 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12577 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12578 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12581 /* This is my infix parser/evaluator. It is optimized for size, intended
12582 * as a replacement for yacc-based parsers. However, it may well be faster
12583 * than a comparable parser written in yacc. The supported operators are
12584 * listed in #defines below. Parens, order of operations, and error handling
12585 * are supported. This code is thread safe. The exact expression format should
12586 * be that which POSIX specifies for shells. */
12588 /* The code uses a simple two-stack algorithm. See
12589 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12590 * for a detailed explanation of the infix-to-postfix algorithm on which
12591 * this is based (this code differs in that it applies operators immediately
12592 * to the stack instead of adding them to a queue to end up with an
12595 /* To use the routine, call it with an expression string and error return
12599 * Aug 24, 2001 Manuel Novoa III
12601 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12603 * 1) In arith_apply():
12604 * a) Cached values of *numptr and &(numptr[-1]).
12605 * b) Removed redundant test for zero denominator.
12608 * a) Eliminated redundant code for processing operator tokens by moving
12609 * to a table-based implementation. Also folded handling of parens
12611 * b) Combined all 3 loops which called arith_apply to reduce generated
12612 * code size at the cost of speed.
12614 * 3) The following expressions were treated as valid by the original code:
12615 * 1() , 0! , 1 ( *3 ) .
12616 * These bugs have been fixed by internally enclosing the expression in
12617 * parens and then checking that all binary ops and right parens are
12618 * preceded by a valid expression (NUM_TOKEN).
12620 * Note: It may be desirable to replace Aaron's test for whitespace with
12621 * ctype's isspace() if it is used by another busybox applet or if additional
12622 * whitespace chars should be considered. Look below the "#include"s for a
12623 * precompiler test.
12627 * Aug 26, 2001 Manuel Novoa III
12629 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12631 * Merge in Aaron's comments previously posted to the busybox list,
12632 * modified slightly to take account of my changes to the code.
12637 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12639 * - allow access to variable,
12640 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12641 * - realize assign syntax (VAR=expr, +=, *= etc)
12642 * - realize exponentiation (** operator)
12643 * - realize comma separated - expr, expr
12644 * - realise ++expr --expr expr++ expr--
12645 * - realise expr ? expr : expr (but, second expr calculate always)
12646 * - allow hexadecimal and octal numbers
12647 * - was restored loses XOR operator
12648 * - remove one goto label, added three ;-)
12649 * - protect $((num num)) as true zero expr (Manuel`s error)
12650 * - always use special isspace(), see comment from bash ;-)
12653 #define arith_isspace(arithval) \
12654 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12656 typedef unsigned char operator;
12658 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12659 * precedence, and 3 high bits are an ID unique across operators of that
12660 * precedence. The ID portion is so that multiple operators can have the
12661 * same precedence, ensuring that the leftmost one is evaluated first.
12662 * Consider * and /. */
12664 #define tok_decl(prec,id) (((id)<<5)|(prec))
12665 #define PREC(op) ((op) & 0x1F)
12667 #define TOK_LPAREN tok_decl(0,0)
12669 #define TOK_COMMA tok_decl(1,0)
12671 #define TOK_ASSIGN tok_decl(2,0)
12672 #define TOK_AND_ASSIGN tok_decl(2,1)
12673 #define TOK_OR_ASSIGN tok_decl(2,2)
12674 #define TOK_XOR_ASSIGN tok_decl(2,3)
12675 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12676 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12677 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12678 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12680 #define TOK_MUL_ASSIGN tok_decl(3,0)
12681 #define TOK_DIV_ASSIGN tok_decl(3,1)
12682 #define TOK_REM_ASSIGN tok_decl(3,2)
12684 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12685 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12687 /* conditional is right associativity too */
12688 #define TOK_CONDITIONAL tok_decl(4,0)
12689 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12691 #define TOK_OR tok_decl(5,0)
12693 #define TOK_AND tok_decl(6,0)
12695 #define TOK_BOR tok_decl(7,0)
12697 #define TOK_BXOR tok_decl(8,0)
12699 #define TOK_BAND tok_decl(9,0)
12701 #define TOK_EQ tok_decl(10,0)
12702 #define TOK_NE tok_decl(10,1)
12704 #define TOK_LT tok_decl(11,0)
12705 #define TOK_GT tok_decl(11,1)
12706 #define TOK_GE tok_decl(11,2)
12707 #define TOK_LE tok_decl(11,3)
12709 #define TOK_LSHIFT tok_decl(12,0)
12710 #define TOK_RSHIFT tok_decl(12,1)
12712 #define TOK_ADD tok_decl(13,0)
12713 #define TOK_SUB tok_decl(13,1)
12715 #define TOK_MUL tok_decl(14,0)
12716 #define TOK_DIV tok_decl(14,1)
12717 #define TOK_REM tok_decl(14,2)
12719 /* exponent is right associativity */
12720 #define TOK_EXPONENT tok_decl(15,1)
12722 /* For now unary operators. */
12723 #define UNARYPREC 16
12724 #define TOK_BNOT tok_decl(UNARYPREC,0)
12725 #define TOK_NOT tok_decl(UNARYPREC,1)
12727 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12728 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12730 #define PREC_PRE (UNARYPREC+2)
12732 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12733 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12735 #define PREC_POST (UNARYPREC+3)
12737 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12738 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12740 #define SPEC_PREC (UNARYPREC+4)
12742 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12743 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12745 #define NUMPTR (*numstackptr)
12748 tok_have_assign(operator op)
12750 operator prec = PREC(op);
12752 convert_prec_is_assing(prec);
12753 return (prec == PREC(TOK_ASSIGN) ||
12754 prec == PREC_PRE || prec == PREC_POST);
12758 is_right_associativity(operator prec)
12760 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
12761 || prec == PREC(TOK_CONDITIONAL));
12766 arith_t contidional_second_val;
12767 char contidional_second_val_initialized;
12768 char *var; /* if NULL then is regular number,
12769 else is variable name */
12772 typedef struct chk_var_recursive_looped_t {
12774 struct chk_var_recursive_looped_t *next;
12775 } chk_var_recursive_looped_t;
12777 static chk_var_recursive_looped_t *prev_chk_var_recursive;
12780 arith_lookup_val(v_n_t *t)
12783 const char * p = lookupvar(t->var);
12788 /* recursive try as expression */
12789 chk_var_recursive_looped_t *cur;
12790 chk_var_recursive_looped_t cur_save;
12792 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
12793 if (strcmp(cur->var, t->var) == 0) {
12794 /* expression recursion loop detected */
12798 /* save current lookuped var name */
12799 cur = prev_chk_var_recursive;
12800 cur_save.var = t->var;
12801 cur_save.next = cur;
12802 prev_chk_var_recursive = &cur_save;
12804 t->val = arith (p, &errcode);
12805 /* restore previous ptr after recursiving */
12806 prev_chk_var_recursive = cur;
12809 /* allow undefined var as 0 */
12815 /* "applying" a token means performing it on the top elements on the integer
12816 * stack. For a unary operator it will only change the top element, but a
12817 * binary operator will pop two arguments and push a result */
12819 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
12822 arith_t numptr_val, rez;
12823 int ret_arith_lookup_val;
12825 /* There is no operator that can work without arguments */
12826 if (NUMPTR == numstack) goto err;
12827 numptr_m1 = NUMPTR - 1;
12829 /* check operand is var with noninteger value */
12830 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12831 if (ret_arith_lookup_val)
12832 return ret_arith_lookup_val;
12834 rez = numptr_m1->val;
12835 if (op == TOK_UMINUS)
12837 else if (op == TOK_NOT)
12839 else if (op == TOK_BNOT)
12841 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
12843 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
12845 else if (op != TOK_UPLUS) {
12846 /* Binary operators */
12848 /* check and binary operators need two arguments */
12849 if (numptr_m1 == numstack) goto err;
12851 /* ... and they pop one */
12854 if (op == TOK_CONDITIONAL) {
12855 if (!numptr_m1->contidional_second_val_initialized) {
12856 /* protect $((expr1 ? expr2)) without ": expr" */
12859 rez = numptr_m1->contidional_second_val;
12860 } else if (numptr_m1->contidional_second_val_initialized) {
12861 /* protect $((expr1 : expr2)) without "expr ? " */
12864 numptr_m1 = NUMPTR - 1;
12865 if (op != TOK_ASSIGN) {
12866 /* check operand is var with noninteger value for not '=' */
12867 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12868 if (ret_arith_lookup_val)
12869 return ret_arith_lookup_val;
12871 if (op == TOK_CONDITIONAL) {
12872 numptr_m1->contidional_second_val = rez;
12874 rez = numptr_m1->val;
12875 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
12877 else if (op == TOK_OR)
12878 rez = numptr_val || rez;
12879 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
12881 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
12883 else if (op == TOK_AND)
12884 rez = rez && numptr_val;
12885 else if (op == TOK_EQ)
12886 rez = (rez == numptr_val);
12887 else if (op == TOK_NE)
12888 rez = (rez != numptr_val);
12889 else if (op == TOK_GE)
12890 rez = (rez >= numptr_val);
12891 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
12892 rez >>= numptr_val;
12893 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
12894 rez <<= numptr_val;
12895 else if (op == TOK_GT)
12896 rez = (rez > numptr_val);
12897 else if (op == TOK_LT)
12898 rez = (rez < numptr_val);
12899 else if (op == TOK_LE)
12900 rez = (rez <= numptr_val);
12901 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
12903 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
12905 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
12907 else if (op == TOK_ASSIGN || op == TOK_COMMA)
12909 else if (op == TOK_CONDITIONAL_SEP) {
12910 if (numptr_m1 == numstack) {
12911 /* protect $((expr : expr)) without "expr ? " */
12914 numptr_m1->contidional_second_val_initialized = op;
12915 numptr_m1->contidional_second_val = numptr_val;
12916 } else if (op == TOK_CONDITIONAL) {
12918 numptr_val : numptr_m1->contidional_second_val;
12919 } else if (op == TOK_EXPONENT) {
12920 if (numptr_val < 0)
12921 return -3; /* exponent less than 0 */
12926 while (numptr_val--)
12930 } else if (numptr_val==0) /* zero divisor check */
12932 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
12934 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
12937 if (tok_have_assign(op)) {
12938 char buf[sizeof(arith_t_type)*3 + 2];
12940 if (numptr_m1->var == NULL) {
12944 /* save to shell variable */
12945 #if ENABLE_ASH_MATH_SUPPORT_64
12946 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
12948 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
12950 setvar(numptr_m1->var, buf, 0);
12951 /* after saving, make previous value for v++ or v-- */
12952 if (op == TOK_POST_INC)
12954 else if (op == TOK_POST_DEC)
12957 numptr_m1->val = rez;
12958 /* protect geting var value, is number now */
12959 numptr_m1->var = NULL;
12965 /* longest must be first */
12966 static const char op_tokens[] ALIGN1 = {
12967 '<','<','=',0, TOK_LSHIFT_ASSIGN,
12968 '>','>','=',0, TOK_RSHIFT_ASSIGN,
12969 '<','<', 0, TOK_LSHIFT,
12970 '>','>', 0, TOK_RSHIFT,
12971 '|','|', 0, TOK_OR,
12972 '&','&', 0, TOK_AND,
12973 '!','=', 0, TOK_NE,
12974 '<','=', 0, TOK_LE,
12975 '>','=', 0, TOK_GE,
12976 '=','=', 0, TOK_EQ,
12977 '|','=', 0, TOK_OR_ASSIGN,
12978 '&','=', 0, TOK_AND_ASSIGN,
12979 '*','=', 0, TOK_MUL_ASSIGN,
12980 '/','=', 0, TOK_DIV_ASSIGN,
12981 '%','=', 0, TOK_REM_ASSIGN,
12982 '+','=', 0, TOK_PLUS_ASSIGN,
12983 '-','=', 0, TOK_MINUS_ASSIGN,
12984 '-','-', 0, TOK_POST_DEC,
12985 '^','=', 0, TOK_XOR_ASSIGN,
12986 '+','+', 0, TOK_POST_INC,
12987 '*','*', 0, TOK_EXPONENT,
12991 '=', 0, TOK_ASSIGN,
13003 '?', 0, TOK_CONDITIONAL,
13004 ':', 0, TOK_CONDITIONAL_SEP,
13005 ')', 0, TOK_RPAREN,
13006 '(', 0, TOK_LPAREN,
13010 #define endexpression (&op_tokens[sizeof(op_tokens)-7])
13013 arith(const char *expr, int *perrcode)
13015 char arithval; /* Current character under analysis */
13016 operator lasttok, op;
13018 operator *stack, *stackptr;
13019 const char *p = endexpression;
13021 v_n_t *numstack, *numstackptr;
13022 unsigned datasizes = strlen(expr) + 2;
13024 /* Stack of integers */
13025 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13026 * in any given correct or incorrect expression is left as an exercise to
13028 numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0]));
13029 /* Stack of operator tokens */
13030 stackptr = stack = alloca(datasizes * sizeof(stack[0]));
13032 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13033 *perrcode = errcode = 0;
13037 if (arithval == 0) {
13038 if (p == endexpression) {
13039 /* Null expression. */
13043 /* This is only reached after all tokens have been extracted from the
13044 * input stream. If there are still tokens on the operator stack, they
13045 * are to be applied in order. At the end, there should be a final
13046 * result on the integer stack */
13048 if (expr != endexpression + 1) {
13049 /* If we haven't done so already, */
13050 /* append a closing right paren */
13051 expr = endexpression;
13052 /* and let the loop process it. */
13055 /* At this point, we're done with the expression. */
13056 if (numstackptr != numstack+1) {
13057 /* ... but if there isn't, it's bad */
13062 if (numstack->var) {
13063 /* expression is $((var)) only, lookup now */
13064 errcode = arith_lookup_val(numstack);
13067 *perrcode = errcode;
13068 return numstack->val;
13071 /* Continue processing the expression. */
13072 if (arith_isspace(arithval)) {
13073 /* Skip whitespace */
13076 p = endofname(expr);
13078 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13080 numstackptr->var = alloca(var_name_size);
13081 safe_strncpy(numstackptr->var, expr, var_name_size);
13084 numstackptr->contidional_second_val_initialized = 0;
13089 if (isdigit(arithval)) {
13090 numstackptr->var = NULL;
13091 #if ENABLE_ASH_MATH_SUPPORT_64
13092 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13094 numstackptr->val = strtol(expr, (char **) &expr, 0);
13098 for (p = op_tokens; ; p++) {
13102 /* strange operator not found */
13105 for (o = expr; *p && *o == *p; p++)
13112 /* skip tail uncompared token */
13115 /* skip zero delim */
13120 /* post grammar: a++ reduce to num */
13121 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13124 /* Plus and minus are binary (not unary) _only_ if the last
13125 * token was as number, or a right paren (which pretends to be
13126 * a number, since it evaluates to one). Think about it.
13127 * It makes sense. */
13128 if (lasttok != TOK_NUM) {
13144 /* We don't want a unary operator to cause recursive descent on the
13145 * stack, because there can be many in a row and it could cause an
13146 * operator to be evaluated before its argument is pushed onto the
13147 * integer stack. */
13148 /* But for binary operators, "apply" everything on the operator
13149 * stack until we find an operator with a lesser priority than the
13150 * one we have just extracted. */
13151 /* Left paren is given the lowest priority so it will never be
13152 * "applied" in this way.
13153 * if associativity is right and priority eq, applied also skip
13156 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13157 /* not left paren or unary */
13158 if (lasttok != TOK_NUM) {
13159 /* binary op must be preceded by a num */
13162 while (stackptr != stack) {
13163 if (op == TOK_RPAREN) {
13164 /* The algorithm employed here is simple: while we don't
13165 * hit an open paren nor the bottom of the stack, pop
13166 * tokens and apply them */
13167 if (stackptr[-1] == TOK_LPAREN) {
13169 /* Any operator directly after a */
13171 /* close paren should consider itself binary */
13175 operator prev_prec = PREC(stackptr[-1]);
13177 convert_prec_is_assing(prec);
13178 convert_prec_is_assing(prev_prec);
13179 if (prev_prec < prec)
13181 /* check right assoc */
13182 if (prev_prec == prec && is_right_associativity(prec))
13185 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13186 if (errcode) goto ret;
13188 if (op == TOK_RPAREN) {
13193 /* Push this operator to the stack and remember it. */
13194 *stackptr++ = lasttok = op;
13199 #endif /* ASH_MATH_SUPPORT */
13202 /* ============ main() and helpers */
13205 * Called to exit the shell.
13207 static void exitshell(void) NORETURN;
13215 status = exitstatus;
13216 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13217 if (setjmp(loc.loc)) {
13218 if (exception == EXEXIT)
13219 /* dash bug: it just does _exit(exitstatus) here
13220 * but we have to do setjobctl(0) first!
13221 * (bug is still not fixed in dash-0.5.3 - if you run dash
13222 * under Midnight Commander, on exit from dash MC is backgrounded) */
13223 status = exitstatus;
13226 exception_handler = &loc;
13232 flush_stdout_stderr();
13242 /* from input.c: */
13243 basepf.nextc = basepf.buf = basebuf;
13246 signal(SIGCHLD, SIG_DFL);
13251 char ppid[sizeof(int)*3 + 1];
13253 struct stat st1, st2;
13256 for (envp = environ; envp && *envp; envp++) {
13257 if (strchr(*envp, '=')) {
13258 setvareq(*envp, VEXPORT|VTEXTFIXED);
13262 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
13263 setvar("PPID", ppid, 0);
13265 p = lookupvar("PWD");
13267 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
13268 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
13275 * Process the shell command line arguments.
13278 procargs(char **argv)
13281 const char *xminusc;
13286 /* if (xargv[0]) - mmm, this is always true! */
13288 for (i = 0; i < NOPTS; i++)
13292 /* it already printed err message */
13293 raise_exception(EXERROR);
13297 if (*xargv == NULL) {
13299 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13302 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13306 for (i = 0; i < NOPTS; i++)
13307 if (optlist[i] == 2)
13312 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13317 } else if (!sflag) {
13318 setinputfile(*xargv, 0);
13321 commandname = arg0;
13324 shellparam.p = xargv;
13325 #if ENABLE_ASH_GETOPTS
13326 shellparam.optind = 1;
13327 shellparam.optoff = -1;
13329 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13331 shellparam.nparam++;
13338 * Read /etc/profile or .profile.
13341 read_profile(const char *name)
13345 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13354 * This routine is called when an error or an interrupt occurs in an
13355 * interactive shell and control is returned to the main command loop.
13363 /* from input.c: */
13364 parselleft = parsenleft = 0; /* clear input buffer */
13366 /* from parser.c: */
13369 /* from redir.c: */
13374 static short profile_buf[16384];
13375 extern int etext();
13379 * Main routine. We initialize things, parse the arguments, execute
13380 * profiles if we're a login shell, and then call cmdloop to execute
13381 * commands. The setjmp call sets up the location to jump to when an
13382 * exception occurs. When an exception occurs the variable "state"
13383 * is used to figure out how far we had gotten.
13385 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13386 int ash_main(int argc UNUSED_PARAM, char **argv)
13389 volatile int state;
13390 struct jmploc jmploc;
13391 struct stackmark smark;
13393 /* Initialize global data */
13397 #if ENABLE_ASH_ALIAS
13403 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13406 #if ENABLE_FEATURE_EDITING
13407 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13410 if (setjmp(jmploc.loc)) {
13420 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13424 outcslow('\n', stderr);
13426 popstackmark(&smark);
13427 FORCE_INT_ON; /* enable interrupts */
13436 exception_handler = &jmploc;
13439 trace_puts("Shell args: ");
13440 trace_puts_args(argv);
13442 rootpid = getpid();
13444 #if ENABLE_ASH_RANDOM_SUPPORT
13445 /* Can use monotonic_ns() for better randomness but for now it is
13446 * not used anywhere else in busybox... so avoid bloat */
13447 random_galois_LFSR = random_LCG = rootpid + monotonic_us();
13450 setstackmark(&smark);
13453 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13455 const char *hp = lookupvar("HISTFILE");
13458 hp = lookupvar("HOME");
13460 char *defhp = concat_path_file(hp, ".ash_history");
13461 setvar("HISTFILE", defhp, 0);
13467 if (argv[0] && argv[0][0] == '-')
13471 read_profile("/etc/profile");
13474 read_profile(".profile");
13480 getuid() == geteuid() && getgid() == getegid() &&
13484 shinit = lookupvar("ENV");
13485 if (shinit != NULL && *shinit != '\0') {
13486 read_profile(shinit);
13492 evalstring(minusc, 0);
13494 if (sflag || minusc == NULL) {
13495 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13497 const char *hp = lookupvar("HISTFILE");
13500 line_input_state->hist_file = hp;
13503 state4: /* XXX ??? - why isn't this before the "if" statement */
13511 extern void _mcleanup(void);
13520 const char *applet_name = "debug stuff usage";
13521 int main(int argc, char **argv)
13523 return ash_main(argc, argv);
13529 * Copyright (c) 1989, 1991, 1993, 1994
13530 * The Regents of the University of California. All rights reserved.
13532 * This code is derived from software contributed to Berkeley by
13533 * Kenneth Almquist.
13535 * Redistribution and use in source and binary forms, with or without
13536 * modification, are permitted provided that the following conditions
13538 * 1. Redistributions of source code must retain the above copyright
13539 * notice, this list of conditions and the following disclaimer.
13540 * 2. Redistributions in binary form must reproduce the above copyright
13541 * notice, this list of conditions and the following disclaimer in the
13542 * documentation and/or other materials provided with the distribution.
13543 * 3. Neither the name of the University nor the names of its contributors
13544 * may be used to endorse or promote products derived from this software
13545 * without specific prior written permission.
13547 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13548 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13549 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13550 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13551 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13552 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13553 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13554 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13555 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13556 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF