1 /* vi: set sw=4 ts=4: */
3 * ash shell port for busybox
5 * Copyright (c) 1989, 1991, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
8 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
9 * was re-ported from NetBSD and debianized.
12 * This code is derived from software contributed to Berkeley by
15 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
17 * Original BSD copyright notice is retained at the end of this file.
21 * rewrite arith.y to micro stack based cryptic algorithm by
22 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
24 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
27 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be
28 * used in busybox and size optimizations,
29 * rewrote arith (see notes to this), added locale support,
30 * rewrote dynamic variables.
35 * The follow should be set to reflect the type of system you have:
36 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
37 * define SYSV if you are running under System V.
38 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
39 * define DEBUG=2 to compile in and turn on debugging.
41 * When debugging is on, debugging info will be written to ./trace and
42 * a quit signal will generate a core dump.
49 #define JOBS ENABLE_ASH_JOB_CONTROL
57 #include "busybox.h" /* for applet_names */
61 #if JOBS || ENABLE_ASH_READ_NCHARS
65 #if defined(__uClinux__)
66 #error "Do not even bother, ash will not run on uClinux"
70 /* ============ Hash table sizes. Configurable. */
74 #define CMDTABLESIZE 31 /* should be prime */
77 /* ============ Misc helpers */
79 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
81 /* C99 say: "char" declaration may be signed or unsigned default */
82 #define signed_char2int(sc) ((int)((signed char)sc))
85 /* ============ Shell options */
87 static const char *const optletters_optnames[] = {
108 #define optletters(n) optletters_optnames[(n)][0]
109 #define optnames(n) (&optletters_optnames[(n)][1])
111 enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
113 static char optlist[NOPTS] ALIGN1;
115 #define eflag optlist[0]
116 #define fflag optlist[1]
117 #define Iflag optlist[2]
118 #define iflag optlist[3]
119 #define mflag optlist[4]
120 #define nflag optlist[5]
121 #define sflag optlist[6]
122 #define xflag optlist[7]
123 #define vflag optlist[8]
124 #define Cflag optlist[9]
125 #define aflag optlist[10]
126 #define bflag optlist[11]
127 #define uflag optlist[12]
128 #define viflag optlist[13]
130 #define nolog optlist[14]
131 #define debug optlist[15]
135 /* ============ Misc data */
137 static const char homestr[] ALIGN1 = "HOME";
138 static const char snlfmt[] ALIGN1 = "%s\n";
139 static const char illnum[] ALIGN1 = "Illegal number: %s";
142 * We enclose jmp_buf in a structure so that we can declare pointers to
143 * jump locations. The global variable handler contains the location to
144 * jump to when an exception occurs, and the global variable exception
145 * contains a code identifying the exception. To implement nested
146 * exception handlers, the user should save the value of handler on entry
147 * to an inner scope, set handler to point to a jmploc structure for the
148 * inner scope, and restore handler on exit from the scope.
154 struct globals_misc {
155 /* pid of main shell */
157 /* shell level: 0 for the main shell, 1 for its children, and so on */
159 #define rootshell (!shlvl)
160 char *minusc; /* argument to -c option */
162 char *curdir; // = nullstr; /* current working directory */
163 char *physdir; // = nullstr; /* physical working directory */
165 char *arg0; /* value of $0 */
167 struct jmploc *exception_handler;
169 // disabled by vda: cannot understand how it was supposed to work -
170 // cannot fix bugs. That's why you have to explain your non-trivial designs!
171 // /* do we generate EXSIG events */
172 // int exsig; /* counter */
173 volatile int suppressint; /* counter */
174 volatile /*sig_atomic_t*/ smallint intpending; /* 1 = got SIGINT */
175 /* last pending signal */
176 volatile /*sig_atomic_t*/ smallint pendingsig;
177 smallint exception; /* kind of exception (0..5) */
179 #define EXINT 0 /* SIGINT received */
180 #define EXERROR 1 /* a generic error */
181 #define EXSHELLPROC 2 /* execute a shell procedure */
182 #define EXEXEC 3 /* command execution failed */
183 #define EXEXIT 4 /* exit the shell */
184 #define EXSIG 5 /* trapped signal in wait(1) */
186 /* trap handler commands */
189 char nullstr[1]; /* zero length string */
191 * Sigmode records the current value of the signal handlers for the various
192 * modes. A value of zero means that the current handler is not known.
193 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
195 char sigmode[NSIG - 1];
196 #define S_DFL 1 /* default signal handling (SIG_DFL) */
197 #define S_CATCH 2 /* signal is caught */
198 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
199 #define S_HARD_IGN 4 /* signal is ignored permenantly */
200 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
202 /* indicates specified signal received */
203 char gotsig[NSIG - 1];
205 extern struct globals_misc *const ash_ptr_to_globals_misc;
206 #define G_misc (*ash_ptr_to_globals_misc)
207 #define rootpid (G_misc.rootpid )
208 #define shlvl (G_misc.shlvl )
209 #define minusc (G_misc.minusc )
210 #define curdir (G_misc.curdir )
211 #define physdir (G_misc.physdir )
212 #define arg0 (G_misc.arg0 )
213 #define exception_handler (G_misc.exception_handler)
214 #define exception (G_misc.exception )
215 #define suppressint (G_misc.suppressint )
216 #define intpending (G_misc.intpending )
217 //#define exsig (G_misc.exsig )
218 #define pendingsig (G_misc.pendingsig )
219 #define trap (G_misc.trap )
220 #define isloginsh (G_misc.isloginsh)
221 #define nullstr (G_misc.nullstr )
222 #define sigmode (G_misc.sigmode )
223 #define gotsig (G_misc.gotsig )
224 #define INIT_G_misc() do { \
225 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
232 /* ============ Interrupts / exceptions */
235 * These macros allow the user to suspend the handling of interrupt signals
236 * over a period of time. This is similar to SIGHOLD or to sigblock, but
237 * much more efficient and portable. (But hacking the kernel is so much
238 * more fun than worrying about efficiency and portability. :-))
247 * Called to raise an exception. Since C doesn't include exceptions, we
248 * just do a longjmp to the exception handler. The type of exception is
249 * stored in the global variable "exception".
251 static void raise_exception(int) ATTRIBUTE_NORETURN;
253 raise_exception(int e)
256 if (exception_handler == NULL)
261 longjmp(exception_handler->loc, 1);
265 * Called from trap.c when a SIGINT is received. (If the user specifies
266 * that SIGINT is to be trapped or ignored using the trap builtin, then
267 * this routine is not called.) Suppressint is nonzero when interrupts
268 * are held using the INT_OFF macro. (The test for iflag is just
269 * defensive programming.)
271 static void raise_interrupt(void) ATTRIBUTE_NORETURN;
273 raise_interrupt(void)
278 /* Signal is not automatically unmasked after it is raised,
279 * do it ourself - unmask all signals */
280 sigprocmask_allsigs(SIG_UNBLOCK);
281 /* pendingsig = 0; - now done in onsig() */
284 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
285 if (!(rootshell && iflag)) {
286 /* Kill ourself with SIGINT */
287 signal(SIGINT, SIG_DFL);
296 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
300 if (--suppressint == 0 && intpending) {
304 #define INT_ON int_on()
312 #define FORCE_INT_ON force_int_on()
317 if (--suppressint == 0 && intpending) \
320 #define FORCE_INT_ON \
327 #endif /* ASH_OPTIMIZE_FOR_SIZE */
329 #define SAVE_INT(v) ((v) = suppressint)
331 #define RESTORE_INT(v) \
335 if (suppressint == 0 && intpending) \
340 * Ignore a signal. Only one usage site - in forkchild()
345 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
346 signal(signo, SIG_IGN);
348 sigmode[signo - 1] = S_HARD_IGN;
352 * Signal handler. Only one usage site - in setsignal()
357 gotsig[signo - 1] = 1;
360 if ( /* exsig || */ (signo == SIGINT && !trap[SIGINT])) {
363 raise_interrupt(); /* does not return */
370 /* ============ Stdout/stderr output */
373 outstr(const char *p, FILE *file)
381 flush_stdout_stderr(void)
398 outcslow(int c, FILE *dest)
406 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
408 out1fmt(const char *fmt, ...)
415 r = vprintf(fmt, ap);
421 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
423 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
430 ret = vsnprintf(outbuf, length, fmt, ap);
437 out1str(const char *p)
443 out2str(const char *p)
450 /* ============ Parser structures */
452 /* control characters in argument strings */
453 #define CTLESC '\201' /* escape next character */
454 #define CTLVAR '\202' /* variable defn */
455 #define CTLENDVAR '\203'
456 #define CTLBACKQ '\204'
457 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
458 /* CTLBACKQ | CTLQUOTE == '\205' */
459 #define CTLARI '\206' /* arithmetic expression */
460 #define CTLENDARI '\207'
461 #define CTLQUOTEMARK '\210'
463 /* variable substitution byte (follows CTLVAR) */
464 #define VSTYPE 0x0f /* type of variable substitution */
465 #define VSNUL 0x10 /* colon--treat the empty string as unset */
466 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
468 /* values of VSTYPE field */
469 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
470 #define VSMINUS 0x2 /* ${var-text} */
471 #define VSPLUS 0x3 /* ${var+text} */
472 #define VSQUESTION 0x4 /* ${var?message} */
473 #define VSASSIGN 0x5 /* ${var=text} */
474 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
475 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
476 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
477 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
478 #define VSLENGTH 0xa /* ${#var} */
479 #if ENABLE_ASH_BASH_COMPAT
480 #define VSSUBSTR 0xc /* ${var:position:length} */
481 #define VSREPLACE 0xd /* ${var/pattern/replacement} */
482 #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
485 static const char dolatstr[] ALIGN1 = {
486 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
522 union node *redirect;
528 struct nodelist *cmdlist;
534 union node *redirect;
547 union node *elsepart;
574 struct nodelist *backquote;
609 struct nredir nredir;
610 struct nbinary nbinary;
614 struct nclist nclist;
623 struct nodelist *next;
636 freefunc(struct funcnode *f)
638 if (f && --f->count < 0)
643 /* ============ Debugging output */
647 static FILE *tracefile;
650 trace_printf(const char *fmt, ...)
657 vfprintf(tracefile, fmt, va);
662 trace_vprintf(const char *fmt, va_list va)
666 vfprintf(tracefile, fmt, va);
670 trace_puts(const char *s)
678 trace_puts_quoted(char *s)
685 putc('"', tracefile);
686 for (p = s; *p; p++) {
688 case '\n': c = 'n'; goto backslash;
689 case '\t': c = 't'; goto backslash;
690 case '\r': c = 'r'; goto backslash;
691 case '"': c = '"'; goto backslash;
692 case '\\': c = '\\'; goto backslash;
693 case CTLESC: c = 'e'; goto backslash;
694 case CTLVAR: c = 'v'; goto backslash;
695 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
696 case CTLBACKQ: c = 'q'; goto backslash;
697 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
699 putc('\\', tracefile);
703 if (*p >= ' ' && *p <= '~')
706 putc('\\', tracefile);
707 putc(*p >> 6 & 03, tracefile);
708 putc(*p >> 3 & 07, tracefile);
709 putc(*p & 07, tracefile);
714 putc('"', tracefile);
718 trace_puts_args(char **ap)
725 trace_puts_quoted(*ap);
727 putc('\n', tracefile);
730 putc(' ', tracefile);
745 /* leave open because libedit might be using it */
748 strcpy(s, "./trace");
750 if (!freopen(s, "a", tracefile)) {
751 fprintf(stderr, "Can't re-open %s\n", s);
756 tracefile = fopen(s, "a");
757 if (tracefile == NULL) {
758 fprintf(stderr, "Can't open %s\n", s);
764 flags = fcntl(fileno(tracefile), F_GETFL);
766 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
768 setlinebuf(tracefile);
769 fputs("\nTracing started.\n", tracefile);
773 indent(int amount, char *pfx, FILE *fp)
777 for (i = 0; i < amount; i++) {
778 if (pfx && i == amount - 1)
784 /* little circular references here... */
785 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
788 sharg(union node *arg, FILE *fp)
791 struct nodelist *bqlist;
794 if (arg->type != NARG) {
795 out1fmt("<node type %d>\n", arg->type);
798 bqlist = arg->narg.backquote;
799 for (p = arg->narg.text; *p; p++) {
808 if (subtype == VSLENGTH)
817 switch (subtype & VSTYPE) {
850 out1fmt("<subtype %d>", subtype);
857 case CTLBACKQ|CTLQUOTE:
860 shtree(bqlist->n, -1, NULL, fp);
871 shcmd(union node *cmd, FILE *fp)
879 for (np = cmd->ncmd.args; np; np = np->narg.next) {
885 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
889 switch (np->nfile.type) {
890 case NTO: s = ">>"+1; dftfd = 1; break;
891 case NCLOBBER: s = ">|"; dftfd = 1; break;
892 case NAPPEND: s = ">>"; dftfd = 1; break;
893 case NTOFD: s = ">&"; dftfd = 1; break;
894 case NFROM: s = "<"; break;
895 case NFROMFD: s = "<&"; break;
896 case NFROMTO: s = "<>"; break;
897 default: s = "*error*"; break;
899 if (np->nfile.fd != dftfd)
900 fprintf(fp, "%d", np->nfile.fd);
902 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
903 fprintf(fp, "%d", np->ndup.dupfd);
905 sharg(np->nfile.fname, fp);
912 shtree(union node *n, int ind, char *pfx, FILE *fp)
920 indent(ind, pfx, fp);
931 shtree(n->nbinary.ch1, ind, NULL, fp);
934 shtree(n->nbinary.ch2, ind, NULL, fp);
942 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
947 if (n->npipe.backgnd)
953 fprintf(fp, "<node type %d>", n->type);
961 showtree(union node *n)
963 trace_puts("showtree called\n");
964 shtree(n, 1, NULL, stdout);
967 #define TRACE(param) trace_printf param
968 #define TRACEV(param) trace_vprintf param
973 #define TRACEV(param)
978 /* ============ Parser data */
981 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
984 struct strlist *next;
993 struct strpush *prev; /* preceding string on stack */
997 struct alias *ap; /* if push was associated with an alias */
999 char *string; /* remember the string since it may change */
1003 struct parsefile *prev; /* preceding file on stack */
1004 int linno; /* current line */
1005 int fd; /* file descriptor (or -1 if string) */
1006 int nleft; /* number of chars left in this line */
1007 int lleft; /* number of chars left in this buffer */
1008 char *nextc; /* next char in buffer */
1009 char *buf; /* input buffer */
1010 struct strpush *strpush; /* for pushing strings at this level */
1011 struct strpush basestrpush; /* so pushing one is fast */
1014 static struct parsefile basepf; /* top level input file */
1015 static struct parsefile *parsefile = &basepf; /* current input file */
1016 static int startlinno; /* line # where last token started */
1017 static char *commandname; /* currently executing command */
1018 static struct strlist *cmdenviron; /* environment for builtin command */
1019 static int exitstatus; /* exit status of last command */
1022 /* ============ Message printing */
1025 ash_vmsg(const char *msg, va_list ap)
1027 fprintf(stderr, "%s: ", arg0);
1029 if (strcmp(arg0, commandname))
1030 fprintf(stderr, "%s: ", commandname);
1031 if (!iflag || parsefile->fd)
1032 fprintf(stderr, "line %d: ", startlinno);
1034 vfprintf(stderr, msg, ap);
1035 outcslow('\n', stderr);
1039 * Exverror is called to raise the error exception. If the second argument
1040 * is not NULL then error prints an error message using printf style
1041 * formatting. It then raises the error exception.
1043 static void ash_vmsg_and_raise(int, const char *, va_list) ATTRIBUTE_NORETURN;
1045 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1049 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1051 TRACE(("\") pid=%d\n", getpid()));
1053 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1058 flush_stdout_stderr();
1059 raise_exception(cond);
1063 static void ash_msg_and_raise_error(const char *, ...) ATTRIBUTE_NORETURN;
1065 ash_msg_and_raise_error(const char *msg, ...)
1070 ash_vmsg_and_raise(EXERROR, msg, ap);
1075 static void ash_msg_and_raise(int, const char *, ...) ATTRIBUTE_NORETURN;
1077 ash_msg_and_raise(int cond, const char *msg, ...)
1082 ash_vmsg_and_raise(cond, msg, ap);
1088 * error/warning routines for external builtins
1091 ash_msg(const char *fmt, ...)
1101 * Return a string describing an error. The returned string may be a
1102 * pointer to a static buffer that will be overwritten on the next call.
1103 * Action describes the operation that got the error.
1106 errmsg(int e, const char *em)
1108 if (e == ENOENT || e == ENOTDIR) {
1115 /* ============ Memory allocation */
1118 * It appears that grabstackstr() will barf with such alignments
1119 * because stalloc() will return a string allocated in a new stackblock.
1121 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1123 /* Most machines require the value returned from malloc to be aligned
1124 * in some way. The following macro will get this right
1125 * on many machines. */
1126 SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,
1127 /* Minimum size of a block */
1128 MINSIZE = SHELL_ALIGN(504),
1131 struct stack_block {
1132 struct stack_block *prev;
1133 char space[MINSIZE];
1137 struct stack_block *stackp;
1140 struct stackmark *marknext;
1144 struct globals_memstack {
1145 struct stack_block *g_stackp; // = &stackbase;
1146 struct stackmark *markp;
1147 char *g_stacknxt; // = stackbase.space;
1148 char *sstrend; // = stackbase.space + MINSIZE;
1149 size_t g_stacknleft; // = MINSIZE;
1150 int herefd; // = -1;
1151 struct stack_block stackbase;
1153 extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1154 #define G_memstack (*ash_ptr_to_globals_memstack)
1155 #define g_stackp (G_memstack.g_stackp )
1156 #define markp (G_memstack.markp )
1157 #define g_stacknxt (G_memstack.g_stacknxt )
1158 #define sstrend (G_memstack.sstrend )
1159 #define g_stacknleft (G_memstack.g_stacknleft)
1160 #define herefd (G_memstack.herefd )
1161 #define stackbase (G_memstack.stackbase )
1162 #define INIT_G_memstack() do { \
1163 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1165 g_stackp = &stackbase; \
1166 g_stacknxt = stackbase.space; \
1167 g_stacknleft = MINSIZE; \
1168 sstrend = stackbase.space + MINSIZE; \
1172 #define stackblock() ((void *)g_stacknxt)
1173 #define stackblocksize() g_stacknleft
1177 ckrealloc(void * p, size_t nbytes)
1179 p = realloc(p, nbytes);
1181 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1186 ckmalloc(size_t nbytes)
1188 return ckrealloc(NULL, nbytes);
1192 ckzalloc(size_t nbytes)
1194 return memset(ckmalloc(nbytes), 0, nbytes);
1198 * Make a copy of a string in safe storage.
1201 ckstrdup(const char *s)
1203 char *p = strdup(s);
1205 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1210 * Parse trees for commands are allocated in lifo order, so we use a stack
1211 * to make this more efficient, and also to avoid all sorts of exception
1212 * handling code to handle interrupts in the middle of a parse.
1214 * The size 504 was chosen because the Ultrix malloc handles that size
1218 stalloc(size_t nbytes)
1223 aligned = SHELL_ALIGN(nbytes);
1224 if (aligned > g_stacknleft) {
1227 struct stack_block *sp;
1229 blocksize = aligned;
1230 if (blocksize < MINSIZE)
1231 blocksize = MINSIZE;
1232 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1233 if (len < blocksize)
1234 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1237 sp->prev = g_stackp;
1238 g_stacknxt = sp->space;
1239 g_stacknleft = blocksize;
1240 sstrend = g_stacknxt + blocksize;
1245 g_stacknxt += aligned;
1246 g_stacknleft -= aligned;
1251 stzalloc(size_t nbytes)
1253 return memset(stalloc(nbytes), 0, nbytes);
1260 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1261 write(2, "stunalloc\n", 10);
1265 g_stacknleft += g_stacknxt - (char *)p;
1270 * Like strdup but works with the ash stack.
1273 ststrdup(const char *p)
1275 size_t len = strlen(p) + 1;
1276 return memcpy(stalloc(len), p, len);
1280 setstackmark(struct stackmark *mark)
1282 mark->stackp = g_stackp;
1283 mark->stacknxt = g_stacknxt;
1284 mark->stacknleft = g_stacknleft;
1285 mark->marknext = markp;
1290 popstackmark(struct stackmark *mark)
1292 struct stack_block *sp;
1298 markp = mark->marknext;
1299 while (g_stackp != mark->stackp) {
1301 g_stackp = sp->prev;
1304 g_stacknxt = mark->stacknxt;
1305 g_stacknleft = mark->stacknleft;
1306 sstrend = mark->stacknxt + mark->stacknleft;
1311 * When the parser reads in a string, it wants to stick the string on the
1312 * stack and only adjust the stack pointer when it knows how big the
1313 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1314 * of space on top of the stack and stackblocklen returns the length of
1315 * this block. Growstackblock will grow this space by at least one byte,
1316 * possibly moving it (like realloc). Grabstackblock actually allocates the
1317 * part of the block that has been used.
1320 growstackblock(void)
1324 newlen = g_stacknleft * 2;
1325 if (newlen < g_stacknleft)
1326 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1330 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1331 struct stack_block *oldstackp;
1332 struct stackmark *xmark;
1333 struct stack_block *sp;
1334 struct stack_block *prevstackp;
1338 oldstackp = g_stackp;
1340 prevstackp = sp->prev;
1341 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1342 sp = ckrealloc(sp, grosslen);
1343 sp->prev = prevstackp;
1345 g_stacknxt = sp->space;
1346 g_stacknleft = newlen;
1347 sstrend = sp->space + newlen;
1350 * Stack marks pointing to the start of the old block
1351 * must be relocated to point to the new block
1354 while (xmark != NULL && xmark->stackp == oldstackp) {
1355 xmark->stackp = g_stackp;
1356 xmark->stacknxt = g_stacknxt;
1357 xmark->stacknleft = g_stacknleft;
1358 xmark = xmark->marknext;
1362 char *oldspace = g_stacknxt;
1363 int oldlen = g_stacknleft;
1364 char *p = stalloc(newlen);
1366 /* free the space we just allocated */
1367 g_stacknxt = memcpy(p, oldspace, oldlen);
1368 g_stacknleft += newlen;
1373 grabstackblock(size_t len)
1375 len = SHELL_ALIGN(len);
1377 g_stacknleft -= len;
1381 * The following routines are somewhat easier to use than the above.
1382 * The user declares a variable of type STACKSTR, which may be declared
1383 * to be a register. The macro STARTSTACKSTR initializes things. Then
1384 * the user uses the macro STPUTC to add characters to the string. In
1385 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1386 * grown as necessary. When the user is done, she can just leave the
1387 * string there and refer to it using stackblock(). Or she can allocate
1388 * the space for it using grabstackstr(). If it is necessary to allow
1389 * someone else to use the stack temporarily and then continue to grow
1390 * the string, the user should use grabstack to allocate the space, and
1391 * then call ungrabstr(p) to return to the previous mode of operation.
1393 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1394 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1395 * is space for at least one character.
1400 size_t len = stackblocksize();
1401 if (herefd >= 0 && len >= 1024) {
1402 full_write(herefd, stackblock(), len);
1403 return stackblock();
1406 return stackblock() + len;
1410 * Called from CHECKSTRSPACE.
1413 makestrspace(size_t newlen, char *p)
1415 size_t len = p - g_stacknxt;
1416 size_t size = stackblocksize();
1421 size = stackblocksize();
1423 if (nleft >= newlen)
1427 return stackblock() + len;
1431 stack_nputstr(const char *s, size_t n, char *p)
1433 p = makestrspace(n, p);
1434 p = memcpy(p, s, n) + n;
1439 stack_putstr(const char *s, char *p)
1441 return stack_nputstr(s, strlen(s), p);
1445 _STPUTC(int c, char *p)
1453 #define STARTSTACKSTR(p) ((p) = stackblock())
1454 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1455 #define CHECKSTRSPACE(n, p) \
1459 size_t m = sstrend - q; \
1461 (p) = makestrspace(l, q); \
1463 #define USTPUTC(c, p) (*p++ = (c))
1464 #define STACKSTRNUL(p) \
1466 if ((p) == sstrend) \
1467 p = growstackstr(); \
1470 #define STUNPUTC(p) (--p)
1471 #define STTOPC(p) (p[-1])
1472 #define STADJUST(amount, p) (p += (amount))
1474 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1475 #define ungrabstackstr(s, p) stunalloc((s))
1476 #define stackstrend() ((void *)sstrend)
1479 /* ============ String helpers */
1482 * prefix -- see if pfx is a prefix of string.
1485 prefix(const char *string, const char *pfx)
1488 if (*pfx++ != *string++)
1491 return (char *) string;
1495 * Check for a valid number. This should be elsewhere.
1498 is_number(const char *p)
1503 } while (*++p != '\0');
1508 * Convert a string of digits to an integer, printing an error message on
1512 number(const char *s)
1515 ash_msg_and_raise_error(illnum, s);
1520 * Produce a possibly single quoted string suitable as input to the shell.
1521 * The return string is allocated on the stack.
1524 single_quote(const char *s)
1534 len = strchrnul(s, '\'') - s;
1536 q = p = makestrspace(len + 3, p);
1539 q = memcpy(q, s, len) + len;
1545 len = strspn(s, "'");
1549 q = p = makestrspace(len + 3, p);
1552 q = memcpy(q, s, len) + len;
1561 return stackblock();
1565 /* ============ nextopt */
1567 static char **argptr; /* argument list for builtin commands */
1568 static char *optionarg; /* set by nextopt (like getopt) */
1569 static char *optptr; /* used by nextopt */
1572 * XXX - should get rid of. have all builtins use getopt(3). the
1573 * library getopt must have the BSD extension static variable "optreset"
1574 * otherwise it can't be used within the shell safely.
1576 * Standard option processing (a la getopt) for builtin routines. The
1577 * only argument that is passed to nextopt is the option string; the
1578 * other arguments are unnecessary. It return the character, or '\0' on
1582 nextopt(const char *optstring)
1589 if (p == NULL || *p == '\0') {
1591 if (p == NULL || *p != '-' || *++p == '\0')
1594 if (LONE_DASH(p)) /* check for "--" */
1598 for (q = optstring; *q != c; ) {
1600 ash_msg_and_raise_error("illegal option -%c", c);
1605 if (*p == '\0' && (p = *argptr++) == NULL)
1606 ash_msg_and_raise_error("no arg for -%c option", c);
1615 /* ============ Math support definitions */
1617 #if ENABLE_ASH_MATH_SUPPORT_64
1618 typedef int64_t arith_t;
1619 #define arith_t_type long long
1621 typedef long arith_t;
1622 #define arith_t_type long
1625 #if ENABLE_ASH_MATH_SUPPORT
1626 static arith_t dash_arith(const char *);
1627 static arith_t arith(const char *expr, int *perrcode);
1630 #if ENABLE_ASH_RANDOM_SUPPORT
1631 static unsigned long rseed;
1638 /* ============ Shell variables */
1641 * The parsefile structure pointed to by the global variable parsefile
1642 * contains information about the current file being read.
1645 struct redirtab *next;
1651 int nparam; /* # of positional parameters (without $0) */
1652 #if ENABLE_ASH_GETOPTS
1653 int optind; /* next parameter to be processed by getopts */
1654 int optoff; /* used by getopts */
1656 unsigned char malloced; /* if parameter list dynamically allocated */
1657 char **p; /* parameter list */
1661 * Free the list of positional parameters.
1664 freeparam(volatile struct shparam *param)
1668 if (param->malloced) {
1669 for (ap = param->p; *ap; ap++)
1675 #if ENABLE_ASH_GETOPTS
1676 static void getoptsreset(const char *value);
1680 struct var *next; /* next entry in hash list */
1681 int flags; /* flags are defined above */
1682 const char *text; /* name=value */
1683 void (*func)(const char *); /* function to be called when */
1684 /* the variable gets set/unset */
1688 struct localvar *next; /* next local variable in list */
1689 struct var *vp; /* the variable that was made local */
1690 int flags; /* saved flags */
1691 const char *text; /* saved text */
1695 #define VEXPORT 0x01 /* variable is exported */
1696 #define VREADONLY 0x02 /* variable cannot be modified */
1697 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1698 #define VTEXTFIXED 0x08 /* text is statically allocated */
1699 #define VSTACK 0x10 /* text is allocated on the stack */
1700 #define VUNSET 0x20 /* the variable is not set */
1701 #define VNOFUNC 0x40 /* don't call the callback function */
1702 #define VNOSET 0x80 /* do not set variable - just readonly test */
1703 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1705 # define VDYNAMIC 0x200 /* dynamic variable */
1711 static const char defifsvar[] ALIGN1 = "IFS= \t\n";
1712 #define defifs (defifsvar + 4)
1714 static const char defifs[] ALIGN1 = " \t\n";
1718 /* Need to be before varinit_data[] */
1719 #if ENABLE_LOCALE_SUPPORT
1721 change_lc_all(const char *value)
1723 if (value && *value != '\0')
1724 setlocale(LC_ALL, value);
1727 change_lc_ctype(const char *value)
1729 if (value && *value != '\0')
1730 setlocale(LC_CTYPE, value);
1734 static void chkmail(void);
1735 static void changemail(const char *);
1737 static void changepath(const char *);
1738 #if ENABLE_ASH_RANDOM_SUPPORT
1739 static void change_random(const char *);
1742 static const struct {
1745 void (*func)(const char *);
1746 } varinit_data[] = {
1748 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1750 { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL },
1753 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0" , changemail },
1754 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1756 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1757 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1758 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1759 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1760 #if ENABLE_ASH_GETOPTS
1761 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
1763 #if ENABLE_ASH_RANDOM_SUPPORT
1764 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1766 #if ENABLE_LOCALE_SUPPORT
1767 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL\0" , change_lc_all },
1768 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE\0", change_lc_ctype },
1770 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1771 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE\0", NULL },
1776 struct globals_var {
1777 struct shparam shellparam; /* $@ current positional parameters */
1778 struct redirtab *redirlist;
1780 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1781 struct var *vartab[VTABSIZE];
1782 struct var varinit[ARRAY_SIZE(varinit_data)];
1784 extern struct globals_var *const ash_ptr_to_globals_var;
1785 #define G_var (*ash_ptr_to_globals_var)
1786 #define shellparam (G_var.shellparam )
1787 #define redirlist (G_var.redirlist )
1788 #define g_nullredirs (G_var.g_nullredirs )
1789 #define preverrout_fd (G_var.preverrout_fd)
1790 #define vartab (G_var.vartab )
1791 #define varinit (G_var.varinit )
1792 #define INIT_G_var() do { \
1794 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1796 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1797 varinit[i].flags = varinit_data[i].flags; \
1798 varinit[i].text = varinit_data[i].text; \
1799 varinit[i].func = varinit_data[i].func; \
1803 #define vifs varinit[0]
1805 # define vmail (&vifs)[1]
1806 # define vmpath (&vmail)[1]
1807 # define vpath (&vmpath)[1]
1809 # define vpath (&vifs)[1]
1811 #define vps1 (&vpath)[1]
1812 #define vps2 (&vps1)[1]
1813 #define vps4 (&vps2)[1]
1814 #if ENABLE_ASH_GETOPTS
1815 # define voptind (&vps4)[1]
1816 # if ENABLE_ASH_RANDOM_SUPPORT
1817 # define vrandom (&voptind)[1]
1820 # if ENABLE_ASH_RANDOM_SUPPORT
1821 # define vrandom (&vps4)[1]
1826 * The following macros access the values of the above variables.
1827 * They have to skip over the name. They return the null string
1828 * for unset variables.
1830 #define ifsval() (vifs.text + 4)
1831 #define ifsset() ((vifs.flags & VUNSET) == 0)
1833 # define mailval() (vmail.text + 5)
1834 # define mpathval() (vmpath.text + 9)
1835 # define mpathset() ((vmpath.flags & VUNSET) == 0)
1837 #define pathval() (vpath.text + 5)
1838 #define ps1val() (vps1.text + 4)
1839 #define ps2val() (vps2.text + 4)
1840 #define ps4val() (vps4.text + 4)
1841 #if ENABLE_ASH_GETOPTS
1842 # define optindval() (voptind.text + 7)
1846 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1847 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1849 #if ENABLE_ASH_GETOPTS
1851 getoptsreset(const char *value)
1853 shellparam.optind = number(value);
1854 shellparam.optoff = -1;
1859 * Return of a legal variable name (a letter or underscore followed by zero or
1860 * more letters, underscores, and digits).
1863 endofname(const char *name)
1871 if (!is_in_name(*p))
1878 * Compares two strings up to the first = or '\0'. The first
1879 * string must be terminated by '='; the second may be terminated by
1880 * either '=' or '\0'.
1883 varcmp(const char *p, const char *q)
1887 while ((c = *p) == (d = *q)) {
1902 varequal(const char *a, const char *b)
1904 return !varcmp(a, b);
1908 * Find the appropriate entry in the hash table from the name.
1910 static struct var **
1911 hashvar(const char *p)
1915 hashval = ((unsigned char) *p) << 4;
1916 while (*p && *p != '=')
1917 hashval += (unsigned char) *p++;
1918 return &vartab[hashval % VTABSIZE];
1922 vpcmp(const void *a, const void *b)
1924 return varcmp(*(const char **)a, *(const char **)b);
1928 * This routine initializes the builtin variables.
1938 * PS1 depends on uid
1940 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1941 vps1.text = "PS1=\\w \\$ ";
1944 vps1.text = "PS1=# ";
1947 end = vp + ARRAY_SIZE(varinit);
1949 vpp = hashvar(vp->text);
1952 } while (++vp < end);
1955 static struct var **
1956 findvar(struct var **vpp, const char *name)
1958 for (; *vpp; vpp = &(*vpp)->next) {
1959 if (varequal((*vpp)->text, name)) {
1967 * Find the value of a variable. Returns NULL if not set.
1970 lookupvar(const char *name)
1974 v = *findvar(hashvar(name), name);
1978 * Dynamic variables are implemented roughly the same way they are
1979 * in bash. Namely, they're "special" so long as they aren't unset.
1980 * As soon as they're unset, they're no longer dynamic, and dynamic
1981 * lookup will no longer happen at that point. -- PFM.
1983 if ((v->flags & VDYNAMIC))
1986 if (!(v->flags & VUNSET))
1987 return strchrnul(v->text, '=') + 1;
1993 * Search the environment of a builtin command.
1996 bltinlookup(const char *name)
2000 for (sp = cmdenviron; sp; sp = sp->next) {
2001 if (varequal(sp->text, name))
2002 return strchrnul(sp->text, '=') + 1;
2004 return lookupvar(name);
2008 * Same as setvar except that the variable and value are passed in
2009 * the first argument as name=value. Since the first argument will
2010 * be actually stored in the table, it should not be a string that
2012 * Called with interrupts off.
2015 setvareq(char *s, int flags)
2017 struct var *vp, **vpp;
2020 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2021 vp = *findvar(vpp, s);
2023 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2026 if (flags & VNOSAVE)
2029 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2035 if (vp->func && (flags & VNOFUNC) == 0)
2036 (*vp->func)(strchrnul(s, '=') + 1);
2038 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
2039 free((char*)vp->text);
2041 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2046 vp = ckzalloc(sizeof(*vp));
2048 /*vp->func = NULL; - ckzalloc did it */
2051 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2058 * Set the value of a variable. The flags argument is ored with the
2059 * flags of the variable. If val is NULL, the variable is unset.
2062 setvar(const char *name, const char *val, int flags)
2069 q = endofname(name);
2070 p = strchrnul(q, '=');
2072 if (!namelen || p != q)
2073 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2078 vallen = strlen(val);
2081 nameeq = ckmalloc(namelen + vallen + 2);
2082 p = memcpy(nameeq, name, namelen) + namelen;
2085 p = memcpy(p, val, vallen) + vallen;
2088 setvareq(nameeq, flags | VNOSAVE);
2092 #if ENABLE_ASH_GETOPTS
2094 * Safe version of setvar, returns 1 on success 0 on failure.
2097 setvarsafe(const char *name, const char *val, int flags)
2100 volatile int saveint;
2101 struct jmploc *volatile savehandler = exception_handler;
2102 struct jmploc jmploc;
2105 if (setjmp(jmploc.loc))
2108 exception_handler = &jmploc;
2109 setvar(name, val, flags);
2112 exception_handler = savehandler;
2113 RESTORE_INT(saveint);
2119 * Unset the specified variable.
2122 unsetvar(const char *s)
2128 vpp = findvar(hashvar(s), s);
2132 int flags = vp->flags;
2135 if (flags & VREADONLY)
2138 vp->flags &= ~VDYNAMIC;
2142 if ((flags & VSTRFIXED) == 0) {
2144 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2145 free((char*)vp->text);
2151 vp->flags &= ~VEXPORT;
2161 * Process a linked list of variable assignments.
2164 listsetvar(struct strlist *list_set_var, int flags)
2166 struct strlist *lp = list_set_var;
2172 setvareq(lp->text, flags);
2179 * Generate a list of variables satisfying the given conditions.
2182 listvars(int on, int off, char ***end)
2193 for (vp = *vpp; vp; vp = vp->next) {
2194 if ((vp->flags & mask) == on) {
2195 if (ep == stackstrend())
2196 ep = growstackstr();
2197 *ep++ = (char *) vp->text;
2200 } while (++vpp < vartab + VTABSIZE);
2201 if (ep == stackstrend())
2202 ep = growstackstr();
2206 return grabstackstr(ep);
2210 /* ============ Path search helper
2212 * The variable path (passed by reference) should be set to the start
2213 * of the path before the first call; padvance will update
2214 * this value as it proceeds. Successive calls to padvance will return
2215 * the possible path expansions in sequence. If an option (indicated by
2216 * a percent sign) appears in the path entry then the global variable
2217 * pathopt will be set to point to it; otherwise pathopt will be set to
2220 static const char *pathopt; /* set by padvance */
2223 padvance(const char **path, const char *name)
2233 for (p = start; *p && *p != ':' && *p != '%'; p++);
2234 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2235 while (stackblocksize() < len)
2239 memcpy(q, start, p - start);
2247 while (*p && *p != ':') p++;
2253 return stalloc(len);
2257 /* ============ Prompt */
2259 static smallint doprompt; /* if set, prompt the user */
2260 static smallint needprompt; /* true if interactive and at start of line */
2262 #if ENABLE_FEATURE_EDITING
2263 static line_input_t *line_input_state;
2264 static const char *cmdedit_prompt;
2266 putprompt(const char *s)
2268 if (ENABLE_ASH_EXPAND_PRMT) {
2269 free((char*)cmdedit_prompt);
2270 cmdedit_prompt = ckstrdup(s);
2277 putprompt(const char *s)
2283 #if ENABLE_ASH_EXPAND_PRMT
2284 /* expandstr() needs parsing machinery, so it is far away ahead... */
2285 static const char *expandstr(const char *ps);
2287 #define expandstr(s) s
2291 setprompt(int whichprompt)
2294 #if ENABLE_ASH_EXPAND_PRMT
2295 struct stackmark smark;
2300 switch (whichprompt) {
2310 #if ENABLE_ASH_EXPAND_PRMT
2311 setstackmark(&smark);
2312 stalloc(stackblocksize());
2314 putprompt(expandstr(prompt));
2315 #if ENABLE_ASH_EXPAND_PRMT
2316 popstackmark(&smark);
2321 /* ============ The cd and pwd commands */
2323 #define CD_PHYSICAL 1
2326 static int docd(const char *, int);
2335 while ((i = nextopt("LP"))) {
2337 flags ^= CD_PHYSICAL;
2346 * Update curdir (the name of the current directory) in response to a
2350 updatepwd(const char *dir)
2357 cdcomppath = ststrdup(dir);
2360 if (curdir == nullstr)
2362 new = stack_putstr(curdir, new);
2364 new = makestrspace(strlen(dir) + 2, new);
2365 lim = stackblock() + 1;
2369 if (new > lim && *lim == '/')
2374 if (dir[1] == '/' && dir[2] != '/') {
2380 p = strtok(cdcomppath, "/");
2384 if (p[1] == '.' && p[2] == '\0') {
2396 new = stack_putstr(p, new);
2404 return stackblock();
2408 * Find out what the current directory is. If we already know the current
2409 * directory, this routine returns immediately.
2414 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2415 return dir ? dir : nullstr;
2419 setpwd(const char *val, int setold)
2423 oldcur = dir = curdir;
2426 setvar("OLDPWD", oldcur, VEXPORT);
2429 if (physdir != nullstr) {
2430 if (physdir != oldcur)
2434 if (oldcur == val || !val) {
2440 dir = ckstrdup(val);
2441 if (oldcur != dir && oldcur != nullstr) {
2446 setvar("PWD", dir, VEXPORT);
2449 static void hashcd(void);
2452 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2453 * know that the current directory has changed.
2456 docd(const char *dest, int flags)
2458 const char *dir = 0;
2461 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2464 if (!(flags & CD_PHYSICAL)) {
2465 dir = updatepwd(dest);
2480 cdcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
2492 dest = bltinlookup(homestr);
2493 else if (LONE_DASH(dest)) {
2494 dest = bltinlookup("OLDPWD");
2516 path = bltinlookup("CDPATH");
2525 p = padvance(&path, dest);
2526 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2530 if (!docd(p, flags))
2535 ash_msg_and_raise_error("can't cd to %s", dest);
2538 if (flags & CD_PRINT)
2539 out1fmt(snlfmt, curdir);
2544 pwdcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
2547 const char *dir = curdir;
2551 if (physdir == nullstr)
2555 out1fmt(snlfmt, dir);
2560 /* ============ ... */
2562 #define IBUFSIZ COMMON_BUFSIZE
2563 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */
2565 /* Syntax classes */
2566 #define CWORD 0 /* character is nothing special */
2567 #define CNL 1 /* newline character */
2568 #define CBACK 2 /* a backslash character */
2569 #define CSQUOTE 3 /* single quote */
2570 #define CDQUOTE 4 /* double quote */
2571 #define CENDQUOTE 5 /* a terminating quote */
2572 #define CBQUOTE 6 /* backwards single quote */
2573 #define CVAR 7 /* a dollar sign */
2574 #define CENDVAR 8 /* a '}' character */
2575 #define CLP 9 /* a left paren in arithmetic */
2576 #define CRP 10 /* a right paren in arithmetic */
2577 #define CENDFILE 11 /* end of file */
2578 #define CCTL 12 /* like CWORD, except it must be escaped */
2579 #define CSPCL 13 /* these terminate a word */
2580 #define CIGN 14 /* character should be ignored */
2582 #if ENABLE_ASH_ALIAS
2586 #define PEOA_OR_PEOF PEOA
2590 #define PEOA_OR_PEOF PEOF
2593 /* number syntax index */
2594 #define BASESYNTAX 0 /* not in quotes */
2595 #define DQSYNTAX 1 /* in double quotes */
2596 #define SQSYNTAX 2 /* in single quotes */
2597 #define ARISYNTAX 3 /* in arithmetic */
2598 #define PSSYNTAX 4 /* prompt */
2600 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
2601 #define USE_SIT_FUNCTION
2604 #if ENABLE_ASH_MATH_SUPPORT
2605 static const char S_I_T[][4] = {
2606 #if ENABLE_ASH_ALIAS
2607 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */
2609 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */
2610 { CNL, CNL, CNL, CNL }, /* 2, \n */
2611 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */
2612 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */
2613 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */
2614 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */
2615 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */
2616 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */
2617 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */
2618 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */
2619 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */
2620 #ifndef USE_SIT_FUNCTION
2621 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2622 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2623 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2627 static const char S_I_T[][3] = {
2628 #if ENABLE_ASH_ALIAS
2629 { CSPCL, CIGN, CIGN }, /* 0, PEOA */
2631 { CSPCL, CWORD, CWORD }, /* 1, ' ' */
2632 { CNL, CNL, CNL }, /* 2, \n */
2633 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */
2634 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */
2635 { CVAR, CVAR, CWORD }, /* 5, $ */
2636 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */
2637 { CSPCL, CWORD, CWORD }, /* 7, ( */
2638 { CSPCL, CWORD, CWORD }, /* 8, ) */
2639 { CBACK, CBACK, CCTL }, /* 9, \ */
2640 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */
2641 { CENDVAR, CENDVAR, CWORD }, /* 11, } */
2642 #ifndef USE_SIT_FUNCTION
2643 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2644 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2645 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2648 #endif /* ASH_MATH_SUPPORT */
2650 #ifdef USE_SIT_FUNCTION
2653 SIT(int c, int syntax)
2655 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2656 #if ENABLE_ASH_ALIAS
2657 static const char syntax_index_table[] ALIGN1 = {
2658 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2659 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2660 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2664 static const char syntax_index_table[] ALIGN1 = {
2665 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2666 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2667 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2674 if (c == PEOF) /* 2^8+2 */
2676 #if ENABLE_ASH_ALIAS
2677 if (c == PEOA) /* 2^8+1 */
2681 #define U_C(c) ((unsigned char)(c))
2683 if ((unsigned char)c >= (unsigned char)(CTLESC)
2684 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
2688 s = strchr(spec_symbls, c);
2689 if (s == NULL || *s == '\0')
2691 indx = syntax_index_table[(s - spec_symbls)];
2693 return S_I_T[indx][syntax];
2696 #else /* !USE_SIT_FUNCTION */
2698 #if ENABLE_ASH_ALIAS
2699 #define CSPCL_CIGN_CIGN_CIGN 0
2700 #define CSPCL_CWORD_CWORD_CWORD 1
2701 #define CNL_CNL_CNL_CNL 2
2702 #define CWORD_CCTL_CCTL_CWORD 3
2703 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
2704 #define CVAR_CVAR_CWORD_CVAR 5
2705 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
2706 #define CSPCL_CWORD_CWORD_CLP 7
2707 #define CSPCL_CWORD_CWORD_CRP 8
2708 #define CBACK_CBACK_CCTL_CBACK 9
2709 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
2710 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
2711 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
2712 #define CWORD_CWORD_CWORD_CWORD 13
2713 #define CCTL_CCTL_CCTL_CCTL 14
2715 #define CSPCL_CWORD_CWORD_CWORD 0
2716 #define CNL_CNL_CNL_CNL 1
2717 #define CWORD_CCTL_CCTL_CWORD 2
2718 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
2719 #define CVAR_CVAR_CWORD_CVAR 4
2720 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
2721 #define CSPCL_CWORD_CWORD_CLP 6
2722 #define CSPCL_CWORD_CWORD_CRP 7
2723 #define CBACK_CBACK_CCTL_CBACK 8
2724 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
2725 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
2726 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
2727 #define CWORD_CWORD_CWORD_CWORD 12
2728 #define CCTL_CCTL_CCTL_CCTL 13
2731 static const char syntax_index_table[258] = {
2732 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2733 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2734 #if ENABLE_ASH_ALIAS
2735 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
2737 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2738 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2739 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2740 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2741 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2742 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2743 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2744 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2745 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2746 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
2747 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
2748 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
2749 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
2750 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
2751 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
2752 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
2753 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
2754 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
2755 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
2756 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
2757 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
2758 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
2759 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
2760 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
2761 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
2762 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
2763 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
2764 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
2765 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
2766 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
2767 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
2768 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
2769 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
2770 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
2771 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
2772 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
2773 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
2774 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
2775 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
2776 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
2777 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
2778 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
2779 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
2780 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
2781 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
2782 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
2783 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
2784 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
2785 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
2786 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
2787 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
2788 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
2789 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
2790 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
2791 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
2792 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
2793 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
2794 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
2795 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
2796 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
2797 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
2798 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
2799 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
2800 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
2801 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
2802 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
2803 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
2804 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
2805 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
2806 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
2807 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
2808 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
2809 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
2810 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
2811 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
2812 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
2813 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
2814 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
2815 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
2816 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
2817 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
2818 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
2819 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
2820 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
2821 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
2822 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
2823 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
2824 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
2825 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
2826 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
2827 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
2828 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
2829 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
2830 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
2831 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
2832 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
2833 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
2834 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
2835 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
2836 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
2837 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
2838 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
2839 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
2840 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
2841 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
2842 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
2843 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
2844 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
2845 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
2846 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
2847 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
2848 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
2853 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
2854 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2875 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
2876 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2898 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2899 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2900 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2901 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2902 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2903 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2904 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2905 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2906 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2907 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2908 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2909 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
2910 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2911 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
2912 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2913 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2924 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2925 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2926 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2927 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2928 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2929 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2957 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2958 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2959 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2962 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2990 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2991 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2992 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
2995 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])
2997 #endif /* USE_SIT_FUNCTION */
3000 /* ============ Alias handling */
3002 #if ENABLE_ASH_ALIAS
3004 #define ALIASINUSE 1
3015 static struct alias **atab; // [ATABSIZE];
3016 #define INIT_G_alias() do { \
3017 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3021 static struct alias **
3022 __lookupalias(const char *name) {
3023 unsigned int hashval;
3030 ch = (unsigned char)*p;
3034 ch = (unsigned char)*++p;
3036 app = &atab[hashval % ATABSIZE];
3038 for (; *app; app = &(*app)->next) {
3039 if (strcmp(name, (*app)->name) == 0) {
3047 static struct alias *
3048 lookupalias(const char *name, int check)
3050 struct alias *ap = *__lookupalias(name);
3052 if (check && ap && (ap->flag & ALIASINUSE))
3057 static struct alias *
3058 freealias(struct alias *ap)
3062 if (ap->flag & ALIASINUSE) {
3063 ap->flag |= ALIASDEAD;
3075 setalias(const char *name, const char *val)
3077 struct alias *ap, **app;
3079 app = __lookupalias(name);
3083 if (!(ap->flag & ALIASINUSE)) {
3086 ap->val = ckstrdup(val);
3087 ap->flag &= ~ALIASDEAD;
3090 ap = ckzalloc(sizeof(struct alias));
3091 ap->name = ckstrdup(name);
3092 ap->val = ckstrdup(val);
3093 /*ap->flag = 0; - ckzalloc did it */
3094 /*ap->next = NULL;*/
3101 unalias(const char *name)
3105 app = __lookupalias(name);
3109 *app = freealias(*app);
3120 struct alias *ap, **app;
3124 for (i = 0; i < ATABSIZE; i++) {
3126 for (ap = *app; ap; ap = *app) {
3127 *app = freealias(*app);
3137 printalias(const struct alias *ap)
3139 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3143 * TODO - sort output
3146 aliascmd(int argc ATTRIBUTE_UNUSED, char **argv)
3155 for (i = 0; i < ATABSIZE; i++) {
3156 for (ap = atab[i]; ap; ap = ap->next) {
3162 while ((n = *++argv) != NULL) {
3163 v = strchr(n+1, '=');
3164 if (v == NULL) { /* n+1: funny ksh stuff */
3165 ap = *__lookupalias(n);
3167 fprintf(stderr, "%s: %s not found\n", "alias", n);
3181 unaliascmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
3185 while ((i = nextopt("a")) != '\0') {
3191 for (i = 0; *argptr; argptr++) {
3192 if (unalias(*argptr)) {
3193 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3201 #endif /* ASH_ALIAS */
3204 /* ============ jobs.c */
3206 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3209 #define FORK_NOJOB 2
3211 /* mode flags for showjob(s) */
3212 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
3213 #define SHOW_PID 0x04 /* include process pid */
3214 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
3217 * A job structure contains information about a job. A job is either a
3218 * single process or a set of processes contained in a pipeline. In the
3219 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3224 pid_t pid; /* process id */
3225 int status; /* last process status from wait() */
3226 char *cmd; /* text of command being run */
3230 struct procstat ps0; /* status of process */
3231 struct procstat *ps; /* status or processes when more than one */
3233 int stopstatus; /* status of a stopped job */
3236 nprocs: 16, /* number of processes */
3238 #define JOBRUNNING 0 /* at least one proc running */
3239 #define JOBSTOPPED 1 /* all procs are stopped */
3240 #define JOBDONE 2 /* all procs are completed */
3242 sigint: 1, /* job was killed by SIGINT */
3243 jobctl: 1, /* job running under job control */
3245 waited: 1, /* true if this entry has been waited for */
3246 used: 1, /* true if this entry is in used */
3247 changed: 1; /* true if status has changed */
3248 struct job *prev_job; /* previous job */
3251 static pid_t backgndpid; /* pid of last background process */
3252 static smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
3254 static struct job *makejob(/*union node *,*/ int);
3256 #define forkshell(job, node, mode) forkshell(job, mode)
3258 static int forkshell(struct job *, union node *, int);
3259 static int waitforjob(struct job *);
3262 enum { jobctl = 0 };
3263 #define setjobctl(on) do {} while (0)
3265 static smallint jobctl; /* true if doing job control */
3266 static void setjobctl(int);
3270 * Set the signal handler for the specified signal. The routine figures
3271 * out what it should be set to.
3274 setsignal(int signo)
3278 struct sigaction act;
3284 else if (*t != '\0')
3286 if (rootshell && action == S_DFL) {
3289 if (iflag || minusc || sflag == 0)
3312 t = &sigmode[signo - 1];
3316 * current setting unknown
3318 if (sigaction(signo, NULL, &act) == -1) {
3320 * Pretend it worked; maybe we should give a warning
3321 * here, but other shells don't. We don't alter
3322 * sigmode, so that we retry every time.
3326 tsig = S_RESET; /* force to be set */
3327 if (act.sa_handler == SIG_IGN) {
3330 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3332 tsig = S_IGN; /* don't hard ignore these */
3336 if (tsig == S_HARD_IGN || tsig == action)
3338 act.sa_handler = SIG_DFL;
3341 act.sa_handler = onsig;
3344 act.sa_handler = SIG_IGN;
3349 sigfillset(&act.sa_mask);
3350 sigaction_set(signo, &act);
3353 /* mode flags for set_curjob */
3354 #define CUR_DELETE 2
3355 #define CUR_RUNNING 1
3356 #define CUR_STOPPED 0
3358 /* mode flags for dowait */
3359 #define DOWAIT_NONBLOCK WNOHANG
3360 #define DOWAIT_BLOCK 0
3363 /* pgrp of shell on invocation */
3364 static int initialpgrp;
3365 static int ttyfd = -1;
3368 static struct job *jobtab;
3370 static unsigned njobs;
3372 static struct job *curjob;
3373 /* number of presumed living untracked jobs */
3377 set_curjob(struct job *jp, unsigned mode)
3380 struct job **jpp, **curp;
3382 /* first remove from list */
3383 jpp = curp = &curjob;
3388 jpp = &jp1->prev_job;
3390 *jpp = jp1->prev_job;
3392 /* Then re-insert in correct position */
3400 /* job being deleted */
3403 /* newly created job or backgrounded job,
3404 put after all stopped jobs. */
3408 if (!jp1 || jp1->state != JOBSTOPPED)
3411 jpp = &jp1->prev_job;
3417 /* newly stopped job - becomes curjob */
3418 jp->prev_job = *jpp;
3426 jobno(const struct job *jp)
3428 return jp - jobtab + 1;
3433 * Convert a job name to a job structure.
3436 #define getjob(name, getctl) getjob(name)
3439 getjob(const char *name, int getctl)
3443 const char *err_msg = "No such job: %s";
3447 char *(*match)(const char *, const char *);
3462 if (c == '+' || c == '%') {
3464 err_msg = "No current job";
3470 err_msg = "No previous job";
3479 // TODO: number() instead? It does error checking...
3482 jp = jobtab + num - 1;
3499 if (match(jp->ps[0].cmd, p)) {
3503 err_msg = "%s: ambiguous";
3510 err_msg = "job %s not created under job control";
3511 if (getctl && jp->jobctl == 0)
3516 ash_msg_and_raise_error(err_msg, name);
3520 * Mark a job structure as unused.
3523 freejob(struct job *jp)
3525 struct procstat *ps;
3529 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3530 if (ps->cmd != nullstr)
3533 if (jp->ps != &jp->ps0)
3536 set_curjob(jp, CUR_DELETE);
3542 xtcsetpgrp(int fd, pid_t pgrp)
3544 if (tcsetpgrp(fd, pgrp))
3545 ash_msg_and_raise_error("cannot set tty process group (%m)");
3549 * Turn job control on and off.
3551 * Note: This code assumes that the third arg to ioctl is a character
3552 * pointer, which is true on Berkeley systems but not System V. Since
3553 * System V doesn't have job control yet, this isn't a problem now.
3555 * Called with interrupts off.
3563 if (on == jobctl || rootshell == 0)
3567 ofd = fd = open(_PATH_TTY, O_RDWR);
3569 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3570 * That sometimes helps to acquire controlling tty.
3571 * Obviously, a workaround for bugs when someone
3572 * failed to provide a controlling tty to bash! :) */
3578 fd = fcntl(fd, F_DUPFD, 10);
3583 /* fd is a tty at this point */
3584 close_on_exec_on(fd);
3585 do { /* while we are in the background */
3586 pgrp = tcgetpgrp(fd);
3589 ash_msg("can't access tty; job control turned off");
3593 if (pgrp == getpgrp())
3604 xtcsetpgrp(fd, pgrp);
3606 /* turning job control off */
3609 /* was xtcsetpgrp, but this can make exiting ash
3610 * loop forever if pty is already deleted */
3611 tcsetpgrp(fd, pgrp);
3626 killcmd(int argc, char **argv)
3629 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3631 if (argv[i][0] == '%') {
3632 struct job *jp = getjob(argv[i], 0);
3633 unsigned pid = jp->ps[0].pid;
3634 /* Enough space for ' -NNN<nul>' */
3635 argv[i] = alloca(sizeof(int)*3 + 3);
3636 /* kill_main has matching code to expect
3637 * leading space. Needed to not confuse
3638 * negative pids with "kill -SIGNAL_NO" syntax */
3639 sprintf(argv[i], " -%u", pid);
3641 } while (argv[++i]);
3643 return kill_main(argc, argv);
3647 showpipe(struct job *jp, FILE *out)
3649 struct procstat *sp;
3650 struct procstat *spend;
3652 spend = jp->ps + jp->nprocs;
3653 for (sp = jp->ps + 1; sp < spend; sp++)
3654 fprintf(out, " | %s", sp->cmd);
3655 outcslow('\n', out);
3656 flush_stdout_stderr();
3661 restartjob(struct job *jp, int mode)
3663 struct procstat *ps;
3669 if (jp->state == JOBDONE)
3671 jp->state = JOBRUNNING;
3673 if (mode == FORK_FG)
3674 xtcsetpgrp(ttyfd, pgid);
3675 killpg(pgid, SIGCONT);
3679 if (WIFSTOPPED(ps->status)) {
3685 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3691 fg_bgcmd(int argc ATTRIBUTE_UNUSED, char **argv)
3698 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3703 jp = getjob(*argv, 1);
3704 if (mode == FORK_BG) {
3705 set_curjob(jp, CUR_RUNNING);
3706 fprintf(out, "[%d] ", jobno(jp));
3708 outstr(jp->ps->cmd, out);
3710 retval = restartjob(jp, mode);
3711 } while (*argv && *++argv);
3717 sprint_status(char *s, int status, int sigonly)
3723 if (!WIFEXITED(status)) {
3725 if (WIFSTOPPED(status))
3726 st = WSTOPSIG(status);
3729 st = WTERMSIG(status);
3731 if (st == SIGINT || st == SIGPIPE)
3734 if (WIFSTOPPED(status))
3739 col = fmtstr(s, 32, strsignal(st));
3740 if (WCOREDUMP(status)) {
3741 col += fmtstr(s + col, 16, " (core dumped)");
3743 } else if (!sigonly) {
3744 st = WEXITSTATUS(status);
3746 col = fmtstr(s, 16, "Done(%d)", st);
3748 col = fmtstr(s, 16, "Done");
3755 * Do a wait system call. If job control is compiled in, we accept
3756 * stopped processes. If block is zero, we return a value of zero
3757 * rather than blocking.
3759 * System V doesn't have a non-blocking wait system call. It does
3760 * have a SIGCLD signal that is sent to a process when one of it's
3761 * children dies. The obvious way to use SIGCLD would be to install
3762 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
3763 * was received, and have waitproc bump another counter when it got
3764 * the status of a process. Waitproc would then know that a wait
3765 * system call would not block if the two counters were different.
3766 * This approach doesn't work because if a process has children that
3767 * have not been waited for, System V will send it a SIGCLD when it
3768 * installs a signal handler for SIGCLD. What this means is that when
3769 * a child exits, the shell will be sent SIGCLD signals continuously
3770 * until is runs out of stack space, unless it does a wait call before
3771 * restoring the signal handler. The code below takes advantage of
3772 * this (mis)feature by installing a signal handler for SIGCLD and
3773 * then checking to see whether it was called. If there are any
3774 * children to be waited for, it will be.
3776 * If neither SYSV nor BSD is defined, we don't implement nonblocking
3777 * waits at all. In this case, the user will not be informed when
3778 * a background process until the next time she runs a real program
3779 * (as opposed to running a builtin command or just typing return),
3780 * and the jobs command may give out of date information.
3783 waitproc(int wait_flags, int *status)
3787 wait_flags |= WUNTRACED;
3789 /* NB: _not_ safe_waitpid, we need to detect EINTR */
3790 return waitpid(-1, status, wait_flags);
3794 * Wait for a process to terminate.
3797 dowait(int wait_flags, struct job *job)
3802 struct job *thisjob;
3805 TRACE(("dowait(%d) called\n", wait_flags));
3806 pid = waitproc(wait_flags, &status);
3807 TRACE(("wait returns pid=%d, status=%d\n", pid, status));
3809 /* If we were doing blocking wait and (probably) got EINTR,
3810 * check for pending sigs received while waiting.
3811 * (NB: can be moved into callers if needed) */
3812 if (wait_flags == DOWAIT_BLOCK && pendingsig)
3813 raise_exception(EXSIG);
3818 for (jp = curjob; jp; jp = jp->prev_job) {
3819 struct procstat *sp;
3820 struct procstat *spend;
3821 if (jp->state == JOBDONE)
3824 spend = jp->ps + jp->nprocs;
3827 if (sp->pid == pid) {
3828 TRACE(("Job %d: changing status of proc %d "
3829 "from 0x%x to 0x%x\n",
3830 jobno(jp), pid, sp->status, status));
3831 sp->status = status;
3834 if (sp->status == -1)
3837 if (state == JOBRUNNING)
3839 if (WIFSTOPPED(sp->status)) {
3840 jp->stopstatus = sp->status;
3844 } while (++sp < spend);
3849 if (!WIFSTOPPED(status))
3855 if (state != JOBRUNNING) {
3856 thisjob->changed = 1;
3858 if (thisjob->state != state) {
3859 TRACE(("Job %d: changing state from %d to %d\n",
3860 jobno(thisjob), thisjob->state, state));
3861 thisjob->state = state;
3863 if (state == JOBSTOPPED) {
3864 set_curjob(thisjob, CUR_STOPPED);
3873 if (thisjob && thisjob == job) {
3877 len = sprint_status(s, status, 1);
3889 showjob(FILE *out, struct job *jp, int mode)
3891 struct procstat *ps;
3892 struct procstat *psend;
3899 if (mode & SHOW_PGID) {
3900 /* just output process (group) id of pipeline */
3901 fprintf(out, "%d\n", ps->pid);
3905 col = fmtstr(s, 16, "[%d] ", jobno(jp));
3910 else if (curjob && jp == curjob->prev_job)
3913 if (mode & SHOW_PID)
3914 col += fmtstr(s + col, 16, "%d ", ps->pid);
3916 psend = ps + jp->nprocs;
3918 if (jp->state == JOBRUNNING) {
3919 strcpy(s + col, "Running");
3920 col += sizeof("Running") - 1;
3922 int status = psend[-1].status;
3923 if (jp->state == JOBSTOPPED)
3924 status = jp->stopstatus;
3925 col += sprint_status(s + col, status, 0);
3931 /* for each process */
3932 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
3934 fprintf(out, "%s%*c%s",
3935 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
3937 if (!(mode & SHOW_PID)) {
3941 if (++ps == psend) {
3942 outcslow('\n', out);
3949 if (jp->state == JOBDONE) {
3950 TRACE(("showjob: freeing job %d\n", jobno(jp)));
3956 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3957 * statuses have changed since the last call to showjobs.
3960 showjobs(FILE *out, int mode)
3964 TRACE(("showjobs(%x) called\n", mode));
3966 /* If not even one job changed, there is nothing to do */
3967 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3970 for (jp = curjob; jp; jp = jp->prev_job) {
3971 if (!(mode & SHOW_CHANGED) || jp->changed) {
3972 showjob(out, jp, mode);
3978 jobscmd(int argc ATTRIBUTE_UNUSED, char **argv)
3983 while ((m = nextopt("lp"))) {
3993 showjob(stdout, getjob(*argv,0), mode);
3996 showjobs(stdout, mode);
4003 getstatus(struct job *job)
4008 status = job->ps[job->nprocs - 1].status;
4009 retval = WEXITSTATUS(status);
4010 if (!WIFEXITED(status)) {
4012 retval = WSTOPSIG(status);
4013 if (!WIFSTOPPED(status))
4016 /* XXX: limits number of signals */
4017 retval = WTERMSIG(status);
4019 if (retval == SIGINT)
4025 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
4026 jobno(job), job->nprocs, status, retval));
4031 waitcmd(int argc ATTRIBUTE_UNUSED, char **argv)
4040 raise_exception(EXSIG);
4047 /* wait for all jobs */
4051 if (!jp) /* no running procs */
4053 if (jp->state == JOBRUNNING)
4058 dowait(DOWAIT_BLOCK, NULL);
4064 if (**argv != '%') {
4065 pid_t pid = number(*argv);
4070 if (job->ps[job->nprocs - 1].pid == pid)
4072 job = job->prev_job;
4075 job = getjob(*argv, 0);
4076 /* loop until process terminated or stopped */
4077 while (job->state == JOBRUNNING)
4078 dowait(DOWAIT_BLOCK, NULL);
4080 retval = getstatus(job);
4094 struct job *jp, *jq;
4096 len = njobs * sizeof(*jp);
4098 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4100 offset = (char *)jp - (char *)jq;
4102 /* Relocate pointers */
4105 jq = (struct job *)((char *)jq + l);
4109 #define joff(p) ((struct job *)((char *)(p) + l))
4110 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4111 if (joff(jp)->ps == &jq->ps0)
4112 jmove(joff(jp)->ps);
4113 if (joff(jp)->prev_job)
4114 jmove(joff(jp)->prev_job);
4124 jp = (struct job *)((char *)jp + len);
4128 } while (--jq >= jp);
4133 * Return a new job structure.
4134 * Called with interrupts off.
4137 makejob(/*union node *node,*/ int nprocs)
4142 for (i = njobs, jp = jobtab; ; jp++) {
4149 if (jp->state != JOBDONE || !jp->waited)
4158 memset(jp, 0, sizeof(*jp));
4160 /* jp->jobctl is a bitfield.
4161 * "jp->jobctl |= jobctl" likely to give awful code */
4165 jp->prev_job = curjob;
4170 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4172 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4179 * Return a string identifying a command (to be printed by the
4182 static char *cmdnextc;
4185 cmdputs(const char *s)
4187 static const char vstype[VSTYPE + 1][3] = {
4188 "", "}", "-", "+", "?", "=",
4189 "%", "%%", "#", "##"
4190 USE_ASH_BASH_COMPAT(, ":", "/", "//")
4193 const char *p, *str;
4194 char c, cc[2] = " ";
4199 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4201 while ((c = *p++) != 0) {
4209 if ((subtype & VSTYPE) == VSLENGTH)
4213 if (!(subtype & VSQUOTE) == !(quoted & 1))
4219 str = "\"}" + !(quoted & 1);
4226 case CTLBACKQ+CTLQUOTE:
4229 #if ENABLE_ASH_MATH_SUPPORT
4244 if ((subtype & VSTYPE) != VSNORMAL)
4246 str = vstype[subtype & VSTYPE];
4247 if (subtype & VSNUL)
4256 /* These can only happen inside quotes */
4269 while ((c = *str++)) {
4274 USTPUTC('"', nextc);
4280 /* cmdtxt() and cmdlist() call each other */
4281 static void cmdtxt(union node *n);
4284 cmdlist(union node *np, int sep)
4286 for (; np; np = np->narg.next) {
4290 if (sep && np->narg.next)
4296 cmdtxt(union node *n)
4299 struct nodelist *lp;
4311 lp = n->npipe.cmdlist;
4329 cmdtxt(n->nbinary.ch1);
4345 cmdtxt(n->nif.test);
4348 if (n->nif.elsepart) {
4351 n = n->nif.elsepart;
4367 cmdtxt(n->nbinary.ch1);
4377 cmdputs(n->nfor.var);
4379 cmdlist(n->nfor.args, 1);
4384 cmdputs(n->narg.text);
4388 cmdlist(n->ncmd.args, 1);
4389 cmdlist(n->ncmd.redirect, 0);
4402 cmdputs(n->ncase.expr->narg.text);
4404 for (np = n->ncase.cases; np; np = np->nclist.next) {
4405 cmdtxt(np->nclist.pattern);
4407 cmdtxt(np->nclist.body);
4433 s[0] = n->nfile.fd + '0';
4437 if (n->type == NTOFD || n->type == NFROMFD) {
4438 s[0] = n->ndup.dupfd + '0';
4448 commandtext(union node *n)
4452 STARTSTACKSTR(cmdnextc);
4454 name = stackblock();
4455 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4456 name, cmdnextc, cmdnextc));
4457 return ckstrdup(name);
4462 * Fork off a subshell. If we are doing job control, give the subshell its
4463 * own process group. Jp is a job structure that the job is to be added to.
4464 * N is the command that will be evaluated by the child. Both jp and n may
4465 * be NULL. The mode parameter can be one of the following:
4466 * FORK_FG - Fork off a foreground process.
4467 * FORK_BG - Fork off a background process.
4468 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4469 * process group even if job control is on.
4471 * When job control is turned off, background processes have their standard
4472 * input redirected to /dev/null (except for the second and later processes
4475 * Called with interrupts off.
4478 * Clear traps on a fork.
4485 for (tp = trap; tp < &trap[NSIG]; tp++) {
4486 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4491 setsignal(tp - trap);
4497 /* Lives far away from here, needed for forkchild */
4498 static void closescript(void);
4500 /* Called after fork(), in child */
4502 forkchild(struct job *jp, /*union node *n,*/ int mode)
4506 TRACE(("Child shell %d\n", getpid()));
4513 /* do job control only in root shell */
4515 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4518 if (jp->nprocs == 0)
4521 pgrp = jp->ps[0].pid;
4522 /* This can fail because we are doing it in the parent also */
4523 (void)setpgid(0, pgrp);
4524 if (mode == FORK_FG)
4525 xtcsetpgrp(ttyfd, pgrp);
4530 if (mode == FORK_BG) {
4533 if (jp->nprocs == 0) {
4535 if (open(bb_dev_null, O_RDONLY) != 0)
4536 ash_msg_and_raise_error("can't open %s", bb_dev_null);
4539 if (!oldlvl && iflag) {
4544 for (jp = curjob; jp; jp = jp->prev_job)
4549 /* Called after fork(), in parent */
4551 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4554 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4556 TRACE(("In parent shell: child = %d\n", pid));
4558 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4564 if (mode != FORK_NOJOB && jp->jobctl) {
4567 if (jp->nprocs == 0)
4570 pgrp = jp->ps[0].pid;
4571 /* This can fail because we are doing it in the child also */
4575 if (mode == FORK_BG) {
4576 backgndpid = pid; /* set $! */
4577 set_curjob(jp, CUR_RUNNING);
4580 struct procstat *ps = &jp->ps[jp->nprocs++];
4586 ps->cmd = commandtext(n);
4592 forkshell(struct job *jp, union node *n, int mode)
4596 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4599 TRACE(("Fork failed, errno=%d", errno));
4602 ash_msg_and_raise_error("cannot fork");
4605 forkchild(jp, /*n,*/ mode);
4607 forkparent(jp, n, mode, pid);
4612 * Wait for job to finish.
4614 * Under job control we have the problem that while a child process is
4615 * running interrupts generated by the user are sent to the child but not
4616 * to the shell. This means that an infinite loop started by an inter-
4617 * active user may be hard to kill. With job control turned off, an
4618 * interactive user may place an interactive program inside a loop. If
4619 * the interactive program catches interrupts, the user doesn't want
4620 * these interrupts to also abort the loop. The approach we take here
4621 * is to have the shell ignore interrupt signals while waiting for a
4622 * foreground process to terminate, and then send itself an interrupt
4623 * signal if the child process was terminated by an interrupt signal.
4624 * Unfortunately, some programs want to do a bit of cleanup and then
4625 * exit on interrupt; unless these processes terminate themselves by
4626 * sending a signal to themselves (instead of calling exit) they will
4627 * confuse this approach.
4629 * Called with interrupts off.
4632 waitforjob(struct job *jp)
4636 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4637 while (jp->state == JOBRUNNING) {
4638 dowait(DOWAIT_BLOCK, jp);
4643 xtcsetpgrp(ttyfd, rootpid);
4645 * This is truly gross.
4646 * If we're doing job control, then we did a TIOCSPGRP which
4647 * caused us (the shell) to no longer be in the controlling
4648 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4649 * intuit from the subprocess exit status whether a SIGINT
4650 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4652 if (jp->sigint) /* TODO: do the same with all signals */
4653 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4655 if (jp->state == JOBDONE)
4662 * return 1 if there are stopped jobs, otherwise 0
4674 if (jp && jp->state == JOBSTOPPED) {
4675 out2str("You have stopped jobs.\n");
4684 /* ============ redir.c
4686 * Code for dealing with input/output redirection.
4689 #define EMPTY -2 /* marks an unused slot in redirtab */
4690 #define CLOSED -3 /* marks a slot of previously-closed fd */
4692 # define PIPESIZE 4096 /* amount of buffering in a pipe */
4694 # define PIPESIZE PIPE_BUF
4698 * Open a file in noclobber mode.
4699 * The code was copied from bash.
4702 noclobberopen(const char *fname)
4705 struct stat finfo, finfo2;
4708 * If the file exists and is a regular file, return an error
4711 r = stat(fname, &finfo);
4712 if (r == 0 && S_ISREG(finfo.st_mode)) {
4718 * If the file was not present (r != 0), make sure we open it
4719 * exclusively so that if it is created before we open it, our open
4720 * will fail. Make sure that we do not truncate an existing file.
4721 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4722 * file was not a regular file, we leave O_EXCL off.
4725 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4726 fd = open(fname, O_WRONLY|O_CREAT, 0666);
4728 /* If the open failed, return the file descriptor right away. */
4733 * OK, the open succeeded, but the file may have been changed from a
4734 * non-regular file to a regular file between the stat and the open.
4735 * We are assuming that the O_EXCL open handles the case where FILENAME
4736 * did not exist and is symlinked to an existing file between the stat
4741 * If we can open it and fstat the file descriptor, and neither check
4742 * revealed that it was a regular file, and the file has not been
4743 * replaced, return the file descriptor.
4745 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4746 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4749 /* The file has been replaced. badness. */
4756 * Handle here documents. Normally we fork off a process to write the
4757 * data to a pipe. If the document is short, we can stuff the data in
4758 * the pipe without forking.
4760 /* openhere needs this forward reference */
4761 static void expandhere(union node *arg, int fd);
4763 openhere(union node *redir)
4769 ash_msg_and_raise_error("pipe call failed");
4770 if (redir->type == NHERE) {
4771 len = strlen(redir->nhere.doc->narg.text);
4772 if (len <= PIPESIZE) {
4773 full_write(pip[1], redir->nhere.doc->narg.text, len);
4777 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4779 signal(SIGINT, SIG_IGN);
4780 signal(SIGQUIT, SIG_IGN);
4781 signal(SIGHUP, SIG_IGN);
4783 signal(SIGTSTP, SIG_IGN);
4785 signal(SIGPIPE, SIG_DFL);
4786 if (redir->type == NHERE)
4787 full_write(pip[1], redir->nhere.doc->narg.text, len);
4789 expandhere(redir->nhere.doc, pip[1]);
4798 openredirect(union node *redir)
4803 switch (redir->nfile.type) {
4805 fname = redir->nfile.expfname;
4806 f = open(fname, O_RDONLY);
4811 fname = redir->nfile.expfname;
4812 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
4817 /* Take care of noclobber mode. */
4819 fname = redir->nfile.expfname;
4820 f = noclobberopen(fname);
4827 fname = redir->nfile.expfname;
4828 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4833 fname = redir->nfile.expfname;
4834 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4842 /* Fall through to eliminate warning. */
4849 f = openhere(redir);
4855 ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4857 ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "no such file"));
4861 * Copy a file descriptor to be >= to. Returns -1
4862 * if the source file descriptor is closed, EMPTY if there are no unused
4863 * file descriptors left.
4866 copyfd(int from, int to)
4870 newfd = fcntl(from, F_DUPFD, to);
4872 if (errno == EMFILE)
4874 ash_msg_and_raise_error("%d: %m", from);
4880 dupredirect(union node *redir, int f)
4882 int fd = redir->nfile.fd;
4884 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
4885 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
4886 copyfd(redir->ndup.dupfd, fd);
4898 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
4899 * old file descriptors are stashed away so that the redirection can be
4900 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
4901 * standard output, and the standard error if it becomes a duplicate of
4902 * stdout, is saved in memory.
4904 /* flags passed to redirect */
4905 #define REDIR_PUSH 01 /* save previous values of file descriptors */
4906 #define REDIR_SAVEFD2 03 /* set preverrout */
4908 redirect(union node *redir, int flags)
4911 struct redirtab *sv;
4922 if (flags & REDIR_PUSH) {
4923 sv = ckmalloc(sizeof(*sv));
4924 sv->next = redirlist;
4926 sv->nullredirs = g_nullredirs - 1;
4927 for (i = 0; i < 10; i++)
4928 sv->renamed[i] = EMPTY;
4934 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD)
4935 && n->ndup.dupfd == fd)
4936 continue; /* redirect from/to same file descriptor */
4938 newfd = openredirect(n);
4940 /* Descriptor wasn't open before redirect.
4941 * Mark it for close in the future */
4942 if (sv && sv->renamed[fd] == EMPTY)
4943 sv->renamed[fd] = CLOSED;
4946 if (sv && sv->renamed[fd] == EMPTY) {
4947 i = fcntl(fd, F_DUPFD, 10);
4954 ash_msg_and_raise_error("%d: %m", fd);
4958 sv->renamed[fd] = i;
4964 dupredirect(n, newfd);
4965 } while ((n = n->nfile.next));
4967 if ((flags & REDIR_SAVEFD2) && sv && sv->renamed[2] >= 0)
4968 preverrout_fd = sv->renamed[2];
4972 * Undo the effects of the last redirection.
4977 struct redirtab *rp;
4980 if (--g_nullredirs >= 0)
4984 for (i = 0; i < 10; i++) {
4985 if (rp->renamed[i] == CLOSED) {
4990 if (rp->renamed[i] != EMPTY) {
4993 copyfd(rp->renamed[i], i);
4995 close(rp->renamed[i]);
4998 redirlist = rp->next;
4999 g_nullredirs = rp->nullredirs;
5005 * Undo all redirections. Called on error or interrupt.
5009 * Discard all saved file descriptors.
5012 clearredir(int drop)
5023 redirectsafe(union node *redir, int flags)
5026 volatile int saveint;
5027 struct jmploc *volatile savehandler = exception_handler;
5028 struct jmploc jmploc;
5031 err = setjmp(jmploc.loc) * 2;
5033 exception_handler = &jmploc;
5034 redirect(redir, flags);
5036 exception_handler = savehandler;
5037 if (err && exception != EXERROR)
5038 longjmp(exception_handler->loc, 1);
5039 RESTORE_INT(saveint);
5044 /* ============ Routines to expand arguments to commands
5046 * We have to deal with backquotes, shell variables, and file metacharacters.
5052 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5053 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5054 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5055 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5056 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5057 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5058 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5059 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5060 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5064 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5065 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5066 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5067 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5068 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5071 * Structure specifying which parts of the string should be searched
5072 * for IFS characters.
5075 struct ifsregion *next; /* next region in list */
5076 int begoff; /* offset of start of region */
5077 int endoff; /* offset of end of region */
5078 int nulonly; /* search for nul bytes only */
5082 struct strlist *list;
5083 struct strlist **lastp;
5086 /* output of current string */
5087 static char *expdest;
5088 /* list of back quote expressions */
5089 static struct nodelist *argbackq;
5090 /* first struct in list of ifs regions */
5091 static struct ifsregion ifsfirst;
5092 /* last struct in list */
5093 static struct ifsregion *ifslastp;
5094 /* holds expanded arg list */
5095 static struct arglist exparg;
5105 expdest = makestrspace(32, expdest);
5106 #if ENABLE_ASH_MATH_SUPPORT_64
5107 len = fmtstr(expdest, 32, "%lld", (long long) num);
5109 len = fmtstr(expdest, 32, "%ld", num);
5111 STADJUST(len, expdest);
5116 esclen(const char *start, const char *p)
5120 while (p > start && *--p == CTLESC) {
5127 * Remove any CTLESC characters from a string.
5130 _rmescapes(char *str, int flag)
5132 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5139 p = strpbrk(str, qchars);
5145 if (flag & RMESCAPE_ALLOC) {
5146 size_t len = p - str;
5147 size_t fulllen = len + strlen(p) + 1;
5149 if (flag & RMESCAPE_GROW) {
5150 r = makestrspace(fulllen, expdest);
5151 } else if (flag & RMESCAPE_HEAP) {
5152 r = ckmalloc(fulllen);
5154 r = stalloc(fulllen);
5158 q = memcpy(q, str, len) + len;
5161 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5162 globbing = flag & RMESCAPE_GLOB;
5163 notescaped = globbing;
5165 if (*p == CTLQUOTEMARK) {
5166 inquotes = ~inquotes;
5168 notescaped = globbing;
5172 /* naked back slash */
5178 if (notescaped && inquotes && *p != '/') {
5182 notescaped = globbing;
5187 if (flag & RMESCAPE_GROW) {
5189 STADJUST(q - r + 1, expdest);
5193 #define rmescapes(p) _rmescapes((p), 0)
5195 #define pmatch(a, b) !fnmatch((a), (b), 0)
5198 * Prepare a pattern for a expmeta (internal glob(3)) call.
5200 * Returns an stalloced string.
5203 preglob(const char *pattern, int quoted, int flag)
5205 flag |= RMESCAPE_GLOB;
5207 flag |= RMESCAPE_QUOTED;
5209 return _rmescapes((char *)pattern, flag);
5213 * Put a string on the stack.
5216 memtodest(const char *p, size_t len, int syntax, int quotes)
5220 q = makestrspace(len * 2, q);
5223 int c = signed_char2int(*p++);
5226 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5235 strtodest(const char *p, int syntax, int quotes)
5237 memtodest(p, strlen(p), syntax, quotes);
5241 * Record the fact that we have to scan this region of the
5242 * string for IFS characters.
5245 recordregion(int start, int end, int nulonly)
5247 struct ifsregion *ifsp;
5249 if (ifslastp == NULL) {
5253 ifsp = ckzalloc(sizeof(*ifsp));
5254 /*ifsp->next = NULL; - ckzalloc did it */
5255 ifslastp->next = ifsp;
5259 ifslastp->begoff = start;
5260 ifslastp->endoff = end;
5261 ifslastp->nulonly = nulonly;
5265 removerecordregions(int endoff)
5267 if (ifslastp == NULL)
5270 if (ifsfirst.endoff > endoff) {
5271 while (ifsfirst.next != NULL) {
5272 struct ifsregion *ifsp;
5274 ifsp = ifsfirst.next->next;
5275 free(ifsfirst.next);
5276 ifsfirst.next = ifsp;
5279 if (ifsfirst.begoff > endoff)
5282 ifslastp = &ifsfirst;
5283 ifsfirst.endoff = endoff;
5288 ifslastp = &ifsfirst;
5289 while (ifslastp->next && ifslastp->next->begoff < endoff)
5290 ifslastp=ifslastp->next;
5291 while (ifslastp->next != NULL) {
5292 struct ifsregion *ifsp;
5294 ifsp = ifslastp->next->next;
5295 free(ifslastp->next);
5296 ifslastp->next = ifsp;
5299 if (ifslastp->endoff > endoff)
5300 ifslastp->endoff = endoff;
5304 exptilde(char *startp, char *p, int flag)
5310 int quotes = flag & (EXP_FULL | EXP_CASE);
5315 while ((c = *++p) != '\0') {
5322 if (flag & EXP_VARTILDE)
5332 if (*name == '\0') {
5333 home = lookupvar(homestr);
5335 pw = getpwnam(name);
5340 if (!home || !*home)
5343 startloc = expdest - (char *)stackblock();
5344 strtodest(home, SQSYNTAX, quotes);
5345 recordregion(startloc, expdest - (char *)stackblock(), 0);
5353 * Execute a command inside back quotes. If it's a builtin command, we
5354 * want to save its output in a block obtained from malloc. Otherwise
5355 * we fork off a subprocess and get the output of the command via a pipe.
5356 * Should be called with interrupts off.
5358 struct backcmd { /* result of evalbackcmd */
5359 int fd; /* file descriptor to read from */
5360 char *buf; /* buffer */
5361 int nleft; /* number of chars in buffer */
5362 struct job *jp; /* job structure for command */
5365 /* These forward decls are needed to use "eval" code for backticks handling: */
5366 static int back_exitstatus; /* exit status of backquoted command */
5367 #define EV_EXIT 01 /* exit after evaluating tree */
5368 static void evaltree(union node *, int);
5371 evalbackcmd(union node *n, struct backcmd *result)
5383 saveherefd = herefd;
5391 ash_msg_and_raise_error("pipe call failed");
5392 jp = makejob(/*n,*/ 1);
5393 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5402 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5406 result->fd = pip[0];
5409 herefd = saveherefd;
5411 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5412 result->fd, result->buf, result->nleft, result->jp));
5416 * Expand stuff in backwards quotes.
5419 expbackq(union node *cmd, int quoted, int quotes)
5427 int syntax = quoted? DQSYNTAX : BASESYNTAX;
5428 struct stackmark smark;
5431 setstackmark(&smark);
5433 startloc = dest - (char *)stackblock();
5435 evalbackcmd(cmd, &in);
5436 popstackmark(&smark);
5443 memtodest(p, i, syntax, quotes);
5447 i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5448 TRACE(("expbackq: read returns %d\n", i));
5457 back_exitstatus = waitforjob(in.jp);
5461 /* Eat all trailing newlines */
5463 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5468 recordregion(startloc, dest - (char *)stackblock(), 0);
5469 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5470 (dest - (char *)stackblock()) - startloc,
5471 (dest - (char *)stackblock()) - startloc,
5472 stackblock() + startloc));
5475 #if ENABLE_ASH_MATH_SUPPORT
5477 * Expand arithmetic expression. Backup to start of expression,
5478 * evaluate, place result in (backed up) result, adjust string position.
5491 * This routine is slightly over-complicated for
5492 * efficiency. Next we scan backwards looking for the
5493 * start of arithmetic.
5495 start = stackblock();
5502 while (*p != CTLARI) {
5506 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5511 esc = esclen(start, p);
5521 removerecordregions(begoff);
5530 len = cvtnum(dash_arith(p + 2));
5533 recordregion(begoff, begoff + len, 0);
5537 /* argstr needs it */
5538 static char *evalvar(char *p, int flag, struct strlist *var_str_list);
5541 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5542 * characters to allow for further processing. Otherwise treat
5543 * $@ like $* since no splitting will be performed.
5545 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5546 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5547 * for correct expansion of "B=$A" word.
5550 argstr(char *p, int flag, struct strlist *var_str_list)
5552 static const char spclchars[] ALIGN1 = {
5560 CTLBACKQ | CTLQUOTE,
5561 #if ENABLE_ASH_MATH_SUPPORT
5566 const char *reject = spclchars;
5568 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
5569 int breakall = flag & EXP_WORD;
5574 if (!(flag & EXP_VARTILDE)) {
5576 } else if (flag & EXP_VARTILDE2) {
5581 if (flag & EXP_TILDE) {
5587 if (*q == CTLESC && (flag & EXP_QWORD))
5590 p = exptilde(p, q, flag);
5593 startloc = expdest - (char *)stackblock();
5595 length += strcspn(p + length, reject);
5597 if (c && (!(c & 0x80)
5598 #if ENABLE_ASH_MATH_SUPPORT
5602 /* c == '=' || c == ':' || c == CTLENDARI */
5607 expdest = stack_nputstr(p, length, expdest);
5608 newloc = expdest - (char *)stackblock();
5609 if (breakall && !inquotes && newloc > startloc) {
5610 recordregion(startloc, newloc, 0);
5621 if (flag & EXP_VARTILDE2) {
5625 flag |= EXP_VARTILDE2;
5630 * sort of a hack - expand tildes in variable
5631 * assignments (after the first '=' and after ':'s).
5640 case CTLENDVAR: /* ??? */
5643 /* "$@" syntax adherence hack */
5646 !memcmp(p, dolatstr, 4) &&
5647 (p[4] == CTLQUOTEMARK || (
5648 p[4] == CTLENDVAR &&
5649 p[5] == CTLQUOTEMARK
5652 p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;
5655 inquotes = !inquotes;
5668 p = evalvar(p, flag, var_str_list);
5672 case CTLBACKQ|CTLQUOTE:
5673 expbackq(argbackq->n, c, quotes);
5674 argbackq = argbackq->next;
5676 #if ENABLE_ASH_MATH_SUPPORT
5689 scanleft(char *startp, char *rmesc, char *rmescend ATTRIBUTE_UNUSED, char *str, int quotes,
5692 char *loc, *loc2, *full;
5698 int match = strlen(str);
5699 const char *s = loc2;
5707 // chop off end if its '*'
5708 full = strrchr(str, '*');
5709 if (full && full != str)
5712 // If str starts with '*' replace with s.
5713 if ((*str == '*') && strlen(s) >= match) {
5715 strncpy(full+strlen(s)-match+1, str+1, match-1);
5717 full = xstrndup(str, match);
5718 match = strncmp(s, full, strlen(full));
5724 if (quotes && *loc == CTLESC)
5733 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5740 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5743 const char *s = loc2;
5748 match = pmatch(str, s);
5755 esc = esclen(startp, loc);
5766 static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN;
5768 varunset(const char *end, const char *var, const char *umsg, int varflags)
5774 msg = "parameter not set";
5776 if (*end == CTLENDVAR) {
5777 if (varflags & VSNUL)
5782 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5785 #if ENABLE_ASH_BASH_COMPAT
5787 parse_sub_pattern(char *arg, int inquotes)
5789 char *idx, *repl = NULL;
5792 for (idx = arg; *arg; arg++) {
5794 /* Only the first '/' seen is our seperator */
5800 } else if (*arg != '\\') {
5806 if (*(arg + 1) != '\\')
5807 goto single_backslash;
5812 case 'n': c = '\n'; break;
5813 case 'r': c = '\r'; break;
5814 case 't': c = '\t'; break;
5815 case 'v': c = '\v'; break;
5816 case 'f': c = '\f'; break;
5817 case 'b': c = '\b'; break;
5818 case 'a': c = '\a'; break;
5820 if (*(arg + 1) != '\\' && !inquotes)
5821 goto single_backslash;
5825 /* Trailing backslash, just stuff one in the buffer
5826 * and backup arg so the loop will exit.
5835 /* It's an octal number, parse it. */
5839 for (i = 0; *arg && i < 3; arg++, i++) {
5840 if (*arg >= '8' || *arg < '0')
5841 ash_msg_and_raise_error("Invalid octal char in pattern");
5842 // TODO: number() instead? It does error checking...
5843 c = (c << 3) + atoi(arg);
5845 /* back off one (so outer loop can do it) */
5857 ash_msg_and_raise_error("single backslash unexpected");
5860 #endif /* ENABLE_ASH_BASH_COMPAT */
5863 subevalvar(char *p, char *str, int strloc, int subtype,
5864 int startloc, int varflags, int quotes, struct strlist *var_str_list)
5866 struct nodelist *saveargbackq = argbackq;
5869 char *rmesc, *rmescend;
5870 USE_ASH_BASH_COMPAT(char *repl = NULL;)
5871 USE_ASH_BASH_COMPAT(char null = '\0';)
5872 USE_ASH_BASH_COMPAT(int pos, len, orig_len;)
5873 int saveherefd = herefd;
5874 int amount, workloc, resetloc;
5876 char *(*scan)(char*, char*, char*, char*, int, int);
5879 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
5881 STPUTC('\0', expdest);
5882 herefd = saveherefd;
5883 argbackq = saveargbackq;
5884 startp = stackblock() + startloc;
5888 setvar(str, startp, 0);
5889 amount = startp - expdest;
5890 STADJUST(amount, expdest);
5893 #if ENABLE_ASH_BASH_COMPAT
5895 loc = str = stackblock() + strloc;
5896 // TODO: number() instead? It does error checking...
5898 len = str - startp - 1;
5900 /* *loc != '\0', guaranteed by parser */
5904 /* We must adjust the length by the number of escapes we find. */
5905 for (ptr = startp; ptr < (str - 1); ptr++) {
5906 if(*ptr == CTLESC) {
5914 if (*loc++ == ':') {
5915 // TODO: number() instead? It does error checking...
5919 while (*loc && *loc != ':')
5922 // TODO: number() instead? It does error checking...
5925 if (pos >= orig_len) {
5929 if (len > (orig_len - pos))
5930 len = orig_len - pos;
5932 for (str = startp; pos; str++, pos--) {
5933 if (quotes && *str == CTLESC)
5936 for (loc = startp; len; len--) {
5937 if (quotes && *str == CTLESC)
5942 amount = loc - expdest;
5943 STADJUST(amount, expdest);
5948 varunset(p, str, startp, varflags);
5951 resetloc = expdest - (char *)stackblock();
5953 /* We'll comeback here if we grow the stack while handling
5954 * a VSREPLACE or VSREPLACEALL, since our pointers into the
5955 * stack will need rebasing, and we'll need to remove our work
5958 USE_ASH_BASH_COMPAT(restart:)
5960 amount = expdest - ((char *)stackblock() + resetloc);
5961 STADJUST(-amount, expdest);
5962 startp = stackblock() + startloc;
5965 rmescend = stackblock() + strloc;
5967 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5968 if (rmesc != startp) {
5970 startp = stackblock() + startloc;
5974 str = stackblock() + strloc;
5975 preglob(str, varflags & VSQUOTE, 0);
5976 workloc = expdest - (char *)stackblock();
5978 #if ENABLE_ASH_BASH_COMPAT
5979 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
5980 char *idx, *end, *restart_detect;
5983 repl = parse_sub_pattern(str, varflags & VSQUOTE);
5988 /* If there's no pattern to match, return the expansion unmolested */
5996 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
5998 /* No match, advance */
5999 restart_detect = stackblock();
6000 STPUTC(*idx, expdest);
6001 if (quotes && *idx == CTLESC) {
6004 STPUTC(*idx, expdest);
6006 if (stackblock() != restart_detect)
6014 if (subtype == VSREPLACEALL) {
6016 if (quotes && *idx == CTLESC)
6024 for (loc = repl; *loc; loc++) {
6025 restart_detect = stackblock();
6026 STPUTC(*loc, expdest);
6027 if (stackblock() != restart_detect)
6032 if (subtype == VSREPLACE) {
6034 restart_detect = stackblock();
6035 STPUTC(*idx, expdest);
6036 if (stackblock() != restart_detect)
6045 /* We've put the replaced text into a buffer at workloc, now
6046 * move it to the right place and adjust the stack.
6048 startp = stackblock() + startloc;
6049 STPUTC('\0', expdest);
6050 memmove(startp, stackblock() + workloc, len);
6051 startp[len++] = '\0';
6052 amount = expdest - ((char *)stackblock() + startloc + len - 1);
6053 STADJUST(-amount, expdest);
6056 #endif /* ENABLE_ASH_BASH_COMPAT */
6058 subtype -= VSTRIMRIGHT;
6060 if (subtype < 0 || subtype > 7)
6063 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
6064 zero = subtype >> 1;
6065 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6066 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6068 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6071 memmove(startp, loc, str - loc);
6072 loc = startp + (str - loc) - 1;
6075 amount = loc - expdest;
6076 STADJUST(amount, expdest);
6082 * Add the value of a specialized variable to the stack string.
6085 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6095 int quoted = varflags & VSQUOTE;
6096 int subtype = varflags & VSTYPE;
6097 int quotes = flags & (EXP_FULL | EXP_CASE);
6099 if (quoted && (flags & EXP_FULL))
6100 sep = 1 << CHAR_BIT;
6102 syntax = quoted ? DQSYNTAX : BASESYNTAX;
6111 num = shellparam.nparam;
6121 p = makestrspace(NOPTS, expdest);
6122 for (i = NOPTS - 1; i >= 0; i--) {
6124 USTPUTC(optletters(i), p);
6135 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
6136 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
6142 while ((p = *ap++)) {
6145 partlen = strlen(p);
6148 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6149 memtodest(p, partlen, syntax, quotes);
6155 if (subtype == VSPLUS || subtype == VSLENGTH) {
6176 // TODO: number() instead? It does error checking...
6178 if (num < 0 || num > shellparam.nparam)
6180 p = num ? shellparam.p[num - 1] : arg0;
6183 /* NB: name has form "VAR=..." */
6185 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6186 * which should be considered before we check variables. */
6188 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6192 str = var_str_list->text;
6193 eq = strchr(str, '=');
6194 if (!eq) /* stop at first non-assignment */
6197 if (name_len == (eq - str)
6198 && strncmp(str, name, name_len) == 0) {
6200 /* goto value; - WRONG! */
6201 /* think "A=1 A=2 B=$A" */
6203 var_str_list = var_str_list->next;
6204 } while (var_str_list);
6208 p = lookupvar(name);
6214 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6215 memtodest(p, len, syntax, quotes);
6219 if (subtype == VSPLUS || subtype == VSLENGTH)
6220 STADJUST(-len, expdest);
6225 * Expand a variable, and return a pointer to the next character in the
6229 evalvar(char *p, int flag, struct strlist *var_str_list)
6241 subtype = varflags & VSTYPE;
6242 quoted = varflags & VSQUOTE;
6244 easy = (!quoted || (*var == '@' && shellparam.nparam));
6245 startloc = expdest - (char *)stackblock();
6246 p = strchr(p, '=') + 1;
6249 varlen = varvalue(var, varflags, flag, var_str_list);
6250 if (varflags & VSNUL)
6253 if (subtype == VSPLUS) {
6254 varlen = -1 - varlen;
6258 if (subtype == VSMINUS) {
6262 p, flag | EXP_TILDE |
6263 (quoted ? EXP_QWORD : EXP_WORD),
6273 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6275 if (subevalvar(p, var, /* strloc: */ 0,
6276 subtype, startloc, varflags,
6282 * Remove any recorded regions beyond
6285 removerecordregions(startloc);
6295 if (varlen < 0 && uflag)
6296 varunset(p, var, 0, 0);
6298 if (subtype == VSLENGTH) {
6299 cvtnum(varlen > 0 ? varlen : 0);
6303 if (subtype == VSNORMAL) {
6314 case VSTRIMRIGHTMAX:
6315 #if ENABLE_ASH_BASH_COMPAT
6328 * Terminate the string and start recording the pattern
6331 STPUTC('\0', expdest);
6332 patloc = expdest - (char *)stackblock();
6333 if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6335 /* quotes: */ flag & (EXP_FULL | EXP_CASE),
6338 int amount = expdest - (
6339 (char *)stackblock() + patloc - 1
6341 STADJUST(-amount, expdest);
6343 /* Remove any recorded regions beyond start of variable */
6344 removerecordregions(startloc);
6346 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6350 if (subtype != VSNORMAL) { /* skip to end of alternative */
6356 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6358 argbackq = argbackq->next;
6359 } else if (c == CTLVAR) {
6360 if ((*p++ & VSTYPE) != VSNORMAL)
6362 } else if (c == CTLENDVAR) {
6372 * Break the argument string into pieces based upon IFS and add the
6373 * strings to the argument list. The regions of the string to be
6374 * searched for IFS characters have been stored by recordregion.
6377 ifsbreakup(char *string, struct arglist *arglist)
6379 struct ifsregion *ifsp;
6384 const char *ifs, *realifs;
6389 if (ifslastp != NULL) {
6392 realifs = ifsset() ? ifsval() : defifs;
6395 p = string + ifsp->begoff;
6396 nulonly = ifsp->nulonly;
6397 ifs = nulonly ? nullstr : realifs;
6399 while (p < string + ifsp->endoff) {
6403 if (!strchr(ifs, *p)) {
6408 ifsspc = (strchr(defifs, *p) != NULL);
6409 /* Ignore IFS whitespace at start */
6410 if (q == start && ifsspc) {
6416 sp = stzalloc(sizeof(*sp));
6418 *arglist->lastp = sp;
6419 arglist->lastp = &sp->next;
6423 if (p >= string + ifsp->endoff) {
6429 if (strchr(ifs, *p) == NULL ) {
6433 if (strchr(defifs, *p) == NULL) {
6448 } while (ifsp != NULL);
6457 sp = stzalloc(sizeof(*sp));
6459 *arglist->lastp = sp;
6460 arglist->lastp = &sp->next;
6466 struct ifsregion *p;
6471 struct ifsregion *ifsp;
6477 ifsfirst.next = NULL;
6482 * Add a file name to the list.
6485 addfname(const char *name)
6489 sp = stzalloc(sizeof(*sp));
6490 sp->text = ststrdup(name);
6492 exparg.lastp = &sp->next;
6495 static char *expdir;
6498 * Do metacharacter (i.e. *, ?, [...]) expansion.
6501 expmeta(char *enddir, char *name)
6516 for (p = name; *p; p++) {
6517 if (*p == '*' || *p == '?')
6519 else if (*p == '[') {
6526 if (*q == '/' || *q == '\0')
6533 } else if (*p == '\\')
6535 else if (*p == '/') {
6542 if (metaflag == 0) { /* we've reached the end of the file name */
6543 if (enddir != expdir)
6551 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6562 } while (p < start);
6564 if (enddir == expdir) {
6566 } else if (enddir == expdir + 1 && *expdir == '/') {
6575 if (enddir != expdir)
6577 if (*endname == 0) {
6589 while (!intpending && (dp = readdir(dirp)) != NULL) {
6590 if (dp->d_name[0] == '.' && ! matchdot)
6592 if (pmatch(start, dp->d_name)) {
6594 strcpy(enddir, dp->d_name);
6597 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6600 expmeta(p, endname);
6609 static struct strlist *
6610 msort(struct strlist *list, int len)
6612 struct strlist *p, *q = NULL;
6613 struct strlist **lpp;
6621 for (n = half; --n >= 0; ) {
6625 q->next = NULL; /* terminate first half of list */
6626 q = msort(list, half); /* sort first half of list */
6627 p = msort(p, len - half); /* sort second half */
6630 #if ENABLE_LOCALE_SUPPORT
6631 if (strcoll(p->text, q->text) < 0)
6633 if (strcmp(p->text, q->text) < 0)
6657 * Sort the results of file name expansion. It calculates the number of
6658 * strings to sort and then calls msort (short for merge sort) to do the
6661 static struct strlist *
6662 expsort(struct strlist *str)
6668 for (sp = str; sp; sp = sp->next)
6670 return msort(str, len);
6674 expandmeta(struct strlist *str /*, int flag*/)
6676 static const char metachars[] ALIGN1 = {
6679 /* TODO - EXP_REDIR */
6682 struct strlist **savelastp;
6688 if (!strpbrk(str->text, metachars))
6690 savelastp = exparg.lastp;
6693 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
6695 int i = strlen(str->text);
6696 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
6704 if (exparg.lastp == savelastp) {
6709 *exparg.lastp = str;
6710 rmescapes(str->text);
6711 exparg.lastp = &str->next;
6713 *exparg.lastp = NULL;
6714 *savelastp = sp = expsort(*savelastp);
6715 while (sp->next != NULL)
6717 exparg.lastp = &sp->next;
6724 * Perform variable substitution and command substitution on an argument,
6725 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6726 * perform splitting and file name expansion. When arglist is NULL, perform
6727 * here document expansion.
6730 expandarg(union node *arg, struct arglist *arglist, int flag)
6735 argbackq = arg->narg.backquote;
6736 STARTSTACKSTR(expdest);
6737 ifsfirst.next = NULL;
6739 argstr(arg->narg.text, flag,
6740 /* var_str_list: */ arglist ? arglist->list : NULL);
6741 p = _STPUTC('\0', expdest);
6743 if (arglist == NULL) {
6744 return; /* here document expanded */
6746 p = grabstackstr(p);
6747 exparg.lastp = &exparg.list;
6751 if (flag & EXP_FULL) {
6752 ifsbreakup(p, &exparg);
6753 *exparg.lastp = NULL;
6754 exparg.lastp = &exparg.list;
6755 expandmeta(exparg.list /*, flag*/);
6757 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
6759 sp = stzalloc(sizeof(*sp));
6762 exparg.lastp = &sp->next;
6766 *exparg.lastp = NULL;
6768 *arglist->lastp = exparg.list;
6769 arglist->lastp = exparg.lastp;
6774 * Expand shell variables and backquotes inside a here document.
6777 expandhere(union node *arg, int fd)
6780 expandarg(arg, (struct arglist *)NULL, 0);
6781 full_write(fd, stackblock(), expdest - (char *)stackblock());
6785 * Returns true if the pattern matches the string.
6788 patmatch(char *pattern, const char *string)
6790 return pmatch(preglob(pattern, 0, 0), string);
6794 * See if a pattern matches in a case statement.
6797 casematch(union node *pattern, char *val)
6799 struct stackmark smark;
6802 setstackmark(&smark);
6803 argbackq = pattern->narg.backquote;
6804 STARTSTACKSTR(expdest);
6806 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
6807 /* var_str_list: */ NULL);
6808 STACKSTRNUL(expdest);
6809 result = patmatch(stackblock(), val);
6810 popstackmark(&smark);
6815 /* ============ find_command */
6819 int (*builtin)(int, char **);
6820 /* unsigned flags; */
6822 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
6823 /* "regular" builtins always take precedence over commands,
6824 * regardless of PATH=....%builtin... position */
6825 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
6826 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
6832 const struct builtincmd *cmd;
6833 struct funcnode *func;
6836 /* values of cmdtype */
6837 #define CMDUNKNOWN -1 /* no entry in table for command */
6838 #define CMDNORMAL 0 /* command is an executable program */
6839 #define CMDFUNCTION 1 /* command is a shell function */
6840 #define CMDBUILTIN 2 /* command is a shell builtin */
6842 /* action to find_command() */
6843 #define DO_ERR 0x01 /* prints errors */
6844 #define DO_ABS 0x02 /* checks absolute paths */
6845 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
6846 #define DO_ALTPATH 0x08 /* using alternate path */
6847 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
6849 static void find_command(char *, struct cmdentry *, int, const char *);
6852 /* ============ Hashing commands */
6855 * When commands are first encountered, they are entered in a hash table.
6856 * This ensures that a full path search will not have to be done for them
6857 * on each invocation.
6859 * We should investigate converting to a linear search, even though that
6860 * would make the command name "hash" a misnomer.
6863 #define ARB 1 /* actual size determined at run time */
6866 struct tblentry *next; /* next entry in hash chain */
6867 union param param; /* definition of builtin function */
6868 short cmdtype; /* index identifying command */
6869 char rehash; /* if set, cd done since entry created */
6870 char cmdname[ARB]; /* name of command */
6873 static struct tblentry **cmdtable;
6874 #define INIT_G_cmdtable() do { \
6875 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
6878 static int builtinloc = -1; /* index in path of %builtin, or -1 */
6882 tryexec(char *cmd, char **argv, char **envp)
6886 #if ENABLE_FEATURE_SH_STANDALONE
6887 if (strchr(cmd, '/') == NULL) {
6888 int a = find_applet_by_name(cmd);
6890 if (APPLET_IS_NOEXEC(a))
6891 run_applet_no_and_exit(a, argv);
6892 /* re-exec ourselves with the new arguments */
6893 execve(bb_busybox_exec_path, argv, envp);
6894 /* If they called chroot or otherwise made the binary no longer
6895 * executable, fall through */
6903 execve(cmd, argv, envp);
6904 } while (errno == EINTR);
6906 execve(cmd, argv, envp);
6910 } else if (errno == ENOEXEC) {
6914 for (ap = argv; *ap; ap++)
6916 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
6918 ap[0] = cmd = (char *)DEFAULT_SHELL;
6921 while ((*ap++ = *argv++))
6929 * Exec a program. Never returns. If you change this routine, you may
6930 * have to change the find_command routine as well.
6932 #define environment() listvars(VEXPORT, VUNSET, 0)
6933 static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
6935 shellexec(char **argv, const char *path, int idx)
6943 envp = environment();
6944 if (strchr(argv[0], '/')
6945 #if ENABLE_FEATURE_SH_STANDALONE
6946 || find_applet_by_name(argv[0]) >= 0
6949 tryexec(argv[0], argv, envp);
6953 while ((cmdname = padvance(&path, argv[0])) != NULL) {
6954 if (--idx < 0 && pathopt == NULL) {
6955 tryexec(cmdname, argv, envp);
6956 if (errno != ENOENT && errno != ENOTDIR)
6963 /* Map to POSIX errors */
6975 exitstatus = exerrno;
6976 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
6977 argv[0], e, suppressint ));
6978 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
6983 printentry(struct tblentry *cmdp)
6989 idx = cmdp->param.index;
6992 name = padvance(&path, cmdp->cmdname);
6994 } while (--idx >= 0);
6995 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
6999 * Clear out command entries. The argument specifies the first entry in
7000 * PATH which has changed.
7003 clearcmdentry(int firstchange)
7005 struct tblentry **tblp;
7006 struct tblentry **pp;
7007 struct tblentry *cmdp;
7010 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7012 while ((cmdp = *pp) != NULL) {
7013 if ((cmdp->cmdtype == CMDNORMAL &&
7014 cmdp->param.index >= firstchange)
7015 || (cmdp->cmdtype == CMDBUILTIN &&
7016 builtinloc >= firstchange)
7029 * Locate a command in the command hash table. If "add" is nonzero,
7030 * add the command to the table if it is not already present. The
7031 * variable "lastcmdentry" is set to point to the address of the link
7032 * pointing to the entry, so that delete_cmd_entry can delete the
7035 * Interrupts must be off if called with add != 0.
7037 static struct tblentry **lastcmdentry;
7039 static struct tblentry *
7040 cmdlookup(const char *name, int add)
7042 unsigned int hashval;
7044 struct tblentry *cmdp;
7045 struct tblentry **pp;
7048 hashval = (unsigned char)*p << 4;
7050 hashval += (unsigned char)*p++;
7052 pp = &cmdtable[hashval % CMDTABLESIZE];
7053 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7054 if (strcmp(cmdp->cmdname, name) == 0)
7058 if (add && cmdp == NULL) {
7059 cmdp = *pp = ckzalloc(sizeof(struct tblentry) - ARB
7060 + strlen(name) + 1);
7061 /*cmdp->next = NULL; - ckzalloc did it */
7062 cmdp->cmdtype = CMDUNKNOWN;
7063 strcpy(cmdp->cmdname, name);
7070 * Delete the command entry returned on the last lookup.
7073 delete_cmd_entry(void)
7075 struct tblentry *cmdp;
7078 cmdp = *lastcmdentry;
7079 *lastcmdentry = cmdp->next;
7080 if (cmdp->cmdtype == CMDFUNCTION)
7081 freefunc(cmdp->param.func);
7087 * Add a new command entry, replacing any existing command entry for
7088 * the same name - except special builtins.
7091 addcmdentry(char *name, struct cmdentry *entry)
7093 struct tblentry *cmdp;
7095 cmdp = cmdlookup(name, 1);
7096 if (cmdp->cmdtype == CMDFUNCTION) {
7097 freefunc(cmdp->param.func);
7099 cmdp->cmdtype = entry->cmdtype;
7100 cmdp->param = entry->u;
7105 hashcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
7107 struct tblentry **pp;
7108 struct tblentry *cmdp;
7110 struct cmdentry entry;
7113 if (nextopt("r") != '\0') {
7118 if (*argptr == NULL) {
7119 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7120 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7121 if (cmdp->cmdtype == CMDNORMAL)
7129 while ((name = *argptr) != NULL) {
7130 cmdp = cmdlookup(name, 0);
7132 && (cmdp->cmdtype == CMDNORMAL
7133 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7137 find_command(name, &entry, DO_ERR, pathval());
7138 if (entry.cmdtype == CMDUNKNOWN)
7146 * Called when a cd is done. Marks all commands so the next time they
7147 * are executed they will be rehashed.
7152 struct tblentry **pp;
7153 struct tblentry *cmdp;
7155 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7156 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7157 if (cmdp->cmdtype == CMDNORMAL
7158 || (cmdp->cmdtype == CMDBUILTIN
7159 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7169 * Fix command hash table when PATH changed.
7170 * Called before PATH is changed. The argument is the new value of PATH;
7171 * pathval() still returns the old value at this point.
7172 * Called with interrupts off.
7175 changepath(const char *new)
7183 firstchange = 9999; /* assume no change */
7189 if ((*old == '\0' && *new == ':')
7190 || (*old == ':' && *new == '\0'))
7192 old = new; /* ignore subsequent differences */
7196 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7202 if (builtinloc < 0 && idx_bltin >= 0)
7203 builtinloc = idx_bltin; /* zap builtins */
7204 if (builtinloc >= 0 && idx_bltin < 0)
7206 clearcmdentry(firstchange);
7207 builtinloc = idx_bltin;
7222 #define TENDBQUOTE 12
7240 /* first char is indicating which tokens mark the end of a list */
7241 static const char *const tokname_array[] = {
7255 #define KWDOFFSET 13
7256 /* the following are keywords */
7278 static char buf[16];
7281 //if (tok < TSEMI) return tokname_array[tok] + 1;
7282 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
7287 sprintf(buf + (tok >= TSEMI), "%s%c",
7288 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
7292 /* Wrapper around strcmp for qsort/bsearch/... */
7294 pstrcmp(const void *a, const void *b)
7296 return strcmp((char*) a, (*(char**) b) + 1);
7299 static const char *const *
7300 findkwd(const char *s)
7302 return bsearch(s, tokname_array + KWDOFFSET,
7303 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7304 sizeof(tokname_array[0]), pstrcmp);
7308 * Locate and print what a word is...
7311 describe_command(char *command, int describe_command_verbose)
7313 struct cmdentry entry;
7314 struct tblentry *cmdp;
7315 #if ENABLE_ASH_ALIAS
7316 const struct alias *ap;
7318 const char *path = pathval();
7320 if (describe_command_verbose) {
7324 /* First look at the keywords */
7325 if (findkwd(command)) {
7326 out1str(describe_command_verbose ? " is a shell keyword" : command);
7330 #if ENABLE_ASH_ALIAS
7331 /* Then look at the aliases */
7332 ap = lookupalias(command, 0);
7334 if (!describe_command_verbose) {
7339 out1fmt(" is an alias for %s", ap->val);
7343 /* Then check if it is a tracked alias */
7344 cmdp = cmdlookup(command, 0);
7346 entry.cmdtype = cmdp->cmdtype;
7347 entry.u = cmdp->param;
7349 /* Finally use brute force */
7350 find_command(command, &entry, DO_ABS, path);
7353 switch (entry.cmdtype) {
7355 int j = entry.u.index;
7361 p = padvance(&path, command);
7365 if (describe_command_verbose) {
7367 (cmdp ? " a tracked alias for" : nullstr), p
7376 if (describe_command_verbose) {
7377 out1str(" is a shell function");
7384 if (describe_command_verbose) {
7385 out1fmt(" is a %sshell builtin",
7386 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7387 "special " : nullstr
7395 if (describe_command_verbose) {
7396 out1str(": not found\n");
7401 outstr("\n", stdout);
7406 typecmd(int argc ATTRIBUTE_UNUSED, char **argv)
7412 /* type -p ... ? (we don't bother checking for 'p') */
7413 if (argv[1] && argv[1][0] == '-') {
7418 err |= describe_command(argv[i++], verbose);
7423 #if ENABLE_ASH_CMDCMD
7425 commandcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
7433 while ((c = nextopt("pvV")) != '\0')
7435 verify |= VERIFY_VERBOSE;
7437 verify |= VERIFY_BRIEF;
7443 return describe_command(*argptr, verify - VERIFY_BRIEF);
7450 /* ============ eval.c */
7452 static int funcblocksize; /* size of structures in function */
7453 static int funcstringsize; /* size of strings in node */
7454 static void *funcblock; /* block to allocate function from */
7455 static char *funcstring; /* block to allocate strings from */
7457 /* flags in argument to evaltree */
7458 #define EV_EXIT 01 /* exit after evaluating tree */
7459 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7460 #define EV_BACKCMD 04 /* command executing within back quotes */
7462 static const short nodesize[26] = {
7463 SHELL_ALIGN(sizeof(struct ncmd)),
7464 SHELL_ALIGN(sizeof(struct npipe)),
7465 SHELL_ALIGN(sizeof(struct nredir)),
7466 SHELL_ALIGN(sizeof(struct nredir)),
7467 SHELL_ALIGN(sizeof(struct nredir)),
7468 SHELL_ALIGN(sizeof(struct nbinary)),
7469 SHELL_ALIGN(sizeof(struct nbinary)),
7470 SHELL_ALIGN(sizeof(struct nbinary)),
7471 SHELL_ALIGN(sizeof(struct nif)),
7472 SHELL_ALIGN(sizeof(struct nbinary)),
7473 SHELL_ALIGN(sizeof(struct nbinary)),
7474 SHELL_ALIGN(sizeof(struct nfor)),
7475 SHELL_ALIGN(sizeof(struct ncase)),
7476 SHELL_ALIGN(sizeof(struct nclist)),
7477 SHELL_ALIGN(sizeof(struct narg)),
7478 SHELL_ALIGN(sizeof(struct narg)),
7479 SHELL_ALIGN(sizeof(struct nfile)),
7480 SHELL_ALIGN(sizeof(struct nfile)),
7481 SHELL_ALIGN(sizeof(struct nfile)),
7482 SHELL_ALIGN(sizeof(struct nfile)),
7483 SHELL_ALIGN(sizeof(struct nfile)),
7484 SHELL_ALIGN(sizeof(struct ndup)),
7485 SHELL_ALIGN(sizeof(struct ndup)),
7486 SHELL_ALIGN(sizeof(struct nhere)),
7487 SHELL_ALIGN(sizeof(struct nhere)),
7488 SHELL_ALIGN(sizeof(struct nnot)),
7491 static void calcsize(union node *n);
7494 sizenodelist(struct nodelist *lp)
7497 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7504 calcsize(union node *n)
7508 funcblocksize += nodesize[n->type];
7511 calcsize(n->ncmd.redirect);
7512 calcsize(n->ncmd.args);
7513 calcsize(n->ncmd.assign);
7516 sizenodelist(n->npipe.cmdlist);
7521 calcsize(n->nredir.redirect);
7522 calcsize(n->nredir.n);
7529 calcsize(n->nbinary.ch2);
7530 calcsize(n->nbinary.ch1);
7533 calcsize(n->nif.elsepart);
7534 calcsize(n->nif.ifpart);
7535 calcsize(n->nif.test);
7538 funcstringsize += strlen(n->nfor.var) + 1;
7539 calcsize(n->nfor.body);
7540 calcsize(n->nfor.args);
7543 calcsize(n->ncase.cases);
7544 calcsize(n->ncase.expr);
7547 calcsize(n->nclist.body);
7548 calcsize(n->nclist.pattern);
7549 calcsize(n->nclist.next);
7553 sizenodelist(n->narg.backquote);
7554 funcstringsize += strlen(n->narg.text) + 1;
7555 calcsize(n->narg.next);
7562 calcsize(n->nfile.fname);
7563 calcsize(n->nfile.next);
7567 calcsize(n->ndup.vname);
7568 calcsize(n->ndup.next);
7572 calcsize(n->nhere.doc);
7573 calcsize(n->nhere.next);
7576 calcsize(n->nnot.com);
7582 nodeckstrdup(char *s)
7584 char *rtn = funcstring;
7586 strcpy(funcstring, s);
7587 funcstring += strlen(s) + 1;
7591 static union node *copynode(union node *);
7593 static struct nodelist *
7594 copynodelist(struct nodelist *lp)
7596 struct nodelist *start;
7597 struct nodelist **lpp;
7602 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7603 (*lpp)->n = copynode(lp->n);
7605 lpp = &(*lpp)->next;
7612 copynode(union node *n)
7619 funcblock = (char *) funcblock + nodesize[n->type];
7623 new->ncmd.redirect = copynode(n->ncmd.redirect);
7624 new->ncmd.args = copynode(n->ncmd.args);
7625 new->ncmd.assign = copynode(n->ncmd.assign);
7628 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7629 new->npipe.backgnd = n->npipe.backgnd;
7634 new->nredir.redirect = copynode(n->nredir.redirect);
7635 new->nredir.n = copynode(n->nredir.n);
7642 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7643 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7646 new->nif.elsepart = copynode(n->nif.elsepart);
7647 new->nif.ifpart = copynode(n->nif.ifpart);
7648 new->nif.test = copynode(n->nif.test);
7651 new->nfor.var = nodeckstrdup(n->nfor.var);
7652 new->nfor.body = copynode(n->nfor.body);
7653 new->nfor.args = copynode(n->nfor.args);
7656 new->ncase.cases = copynode(n->ncase.cases);
7657 new->ncase.expr = copynode(n->ncase.expr);
7660 new->nclist.body = copynode(n->nclist.body);
7661 new->nclist.pattern = copynode(n->nclist.pattern);
7662 new->nclist.next = copynode(n->nclist.next);
7666 new->narg.backquote = copynodelist(n->narg.backquote);
7667 new->narg.text = nodeckstrdup(n->narg.text);
7668 new->narg.next = copynode(n->narg.next);
7675 new->nfile.fname = copynode(n->nfile.fname);
7676 new->nfile.fd = n->nfile.fd;
7677 new->nfile.next = copynode(n->nfile.next);
7681 new->ndup.vname = copynode(n->ndup.vname);
7682 new->ndup.dupfd = n->ndup.dupfd;
7683 new->ndup.fd = n->ndup.fd;
7684 new->ndup.next = copynode(n->ndup.next);
7688 new->nhere.doc = copynode(n->nhere.doc);
7689 new->nhere.fd = n->nhere.fd;
7690 new->nhere.next = copynode(n->nhere.next);
7693 new->nnot.com = copynode(n->nnot.com);
7696 new->type = n->type;
7701 * Make a copy of a parse tree.
7703 static struct funcnode *
7704 copyfunc(union node *n)
7709 funcblocksize = offsetof(struct funcnode, n);
7712 blocksize = funcblocksize;
7713 f = ckmalloc(blocksize + funcstringsize);
7714 funcblock = (char *) f + offsetof(struct funcnode, n);
7715 funcstring = (char *) f + blocksize;
7722 * Define a shell function.
7725 defun(char *name, union node *func)
7727 struct cmdentry entry;
7730 entry.cmdtype = CMDFUNCTION;
7731 entry.u.func = copyfunc(func);
7732 addcmdentry(name, &entry);
7736 static int evalskip; /* set if we are skipping commands */
7737 /* reasons for skipping commands (see comment on breakcmd routine) */
7738 #define SKIPBREAK (1 << 0)
7739 #define SKIPCONT (1 << 1)
7740 #define SKIPFUNC (1 << 2)
7741 #define SKIPFILE (1 << 3)
7742 #define SKIPEVAL (1 << 4)
7743 static int skipcount; /* number of levels to skip */
7744 static int funcnest; /* depth of function calls */
7746 /* forward decl way out to parsing code - dotrap needs it */
7747 static int evalstring(char *s, int mask);
7750 * Called to execute a trap. Perhaps we should avoid entering new trap
7751 * handlers while we are executing a trap handler.
7762 savestatus = exitstatus;
7766 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
7774 skip = evalstring(p, SKIPEVAL);
7775 exitstatus = savestatus;
7783 /* forward declarations - evaluation is fairly recursive business... */
7784 static void evalloop(union node *, int);
7785 static void evalfor(union node *, int);
7786 static void evalcase(union node *, int);
7787 static void evalsubshell(union node *, int);
7788 static void expredir(union node *);
7789 static void evalpipe(union node *, int);
7790 static void evalcommand(union node *, int);
7791 static int evalbltin(const struct builtincmd *, int, char **);
7792 static void prehash(union node *);
7795 * Evaluate a parse tree. The value is left in the global variable
7799 evaltree(union node *n, int flags)
7802 void (*evalfn)(union node *, int);
7806 TRACE(("evaltree(NULL) called\n"));
7809 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
7810 getpid(), n, n->type, flags));
7814 out1fmt("Node type = %d\n", n->type);
7819 evaltree(n->nnot.com, EV_TESTED);
7820 status = !exitstatus;
7823 expredir(n->nredir.redirect);
7824 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
7826 evaltree(n->nredir.n, flags & EV_TESTED);
7827 status = exitstatus;
7832 evalfn = evalcommand;
7834 if (eflag && !(flags & EV_TESTED))
7846 evalfn = evalsubshell;
7858 #error NAND + 1 != NOR
7860 #if NOR + 1 != NSEMI
7861 #error NOR + 1 != NSEMI
7863 isor = n->type - NAND;
7866 (flags | ((isor >> 1) - 1)) & EV_TESTED
7868 if (!exitstatus == isor)
7880 evaltree(n->nif.test, EV_TESTED);
7883 if (exitstatus == 0) {
7886 } else if (n->nif.elsepart) {
7887 n = n->nif.elsepart;
7892 defun(n->narg.text, n->narg.next);
7896 exitstatus = status;
7900 if ((checkexit & exitstatus))
7901 evalskip |= SKIPEVAL;
7902 else if (pendingsig && dotrap())
7905 if (flags & EV_EXIT) {
7907 raise_exception(EXEXIT);
7911 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
7914 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
7916 static int loopnest; /* current loop nesting level */
7919 evalloop(union node *n, int flags)
7929 evaltree(n->nbinary.ch1, EV_TESTED);
7932 if (evalskip == SKIPCONT && --skipcount <= 0) {
7936 if (evalskip == SKIPBREAK && --skipcount <= 0)
7941 if (n->type != NWHILE)
7945 evaltree(n->nbinary.ch2, flags);
7946 status = exitstatus;
7951 exitstatus = status;
7955 evalfor(union node *n, int flags)
7957 struct arglist arglist;
7960 struct stackmark smark;
7962 setstackmark(&smark);
7963 arglist.list = NULL;
7964 arglist.lastp = &arglist.list;
7965 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
7966 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
7971 *arglist.lastp = NULL;
7976 for (sp = arglist.list; sp; sp = sp->next) {
7977 setvar(n->nfor.var, sp->text, 0);
7978 evaltree(n->nfor.body, flags);
7980 if (evalskip == SKIPCONT && --skipcount <= 0) {
7984 if (evalskip == SKIPBREAK && --skipcount <= 0)
7991 popstackmark(&smark);
7995 evalcase(union node *n, int flags)
7999 struct arglist arglist;
8000 struct stackmark smark;
8002 setstackmark(&smark);
8003 arglist.list = NULL;
8004 arglist.lastp = &arglist.list;
8005 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8007 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8008 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8009 if (casematch(patp, arglist.list->text)) {
8010 if (evalskip == 0) {
8011 evaltree(cp->nclist.body, flags);
8018 popstackmark(&smark);
8022 * Kick off a subshell to evaluate a tree.
8025 evalsubshell(union node *n, int flags)
8028 int backgnd = (n->type == NBACKGND);
8031 expredir(n->nredir.redirect);
8032 if (!backgnd && flags & EV_EXIT && !trap[0])
8035 jp = makejob(/*n,*/ 1);
8036 if (forkshell(jp, n, backgnd) == 0) {
8040 flags &=~ EV_TESTED;
8042 redirect(n->nredir.redirect, 0);
8043 evaltreenr(n->nredir.n, flags);
8048 status = waitforjob(jp);
8049 exitstatus = status;
8054 * Compute the names of the files in a redirection list.
8056 static void fixredir(union node *, const char *, int);
8058 expredir(union node *n)
8062 for (redir = n; redir; redir = redir->nfile.next) {
8066 fn.lastp = &fn.list;
8067 switch (redir->type) {
8073 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8074 redir->nfile.expfname = fn.list->text;
8078 if (redir->ndup.vname) {
8079 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8080 if (fn.list == NULL)
8081 ash_msg_and_raise_error("redir error");
8082 fixredir(redir, fn.list->text, 1);
8090 * Evaluate a pipeline. All the processes in the pipeline are children
8091 * of the process creating the pipeline. (This differs from some versions
8092 * of the shell, which make the last process in a pipeline the parent
8096 evalpipe(union node *n, int flags)
8099 struct nodelist *lp;
8104 TRACE(("evalpipe(0x%lx) called\n", (long)n));
8106 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8110 jp = makejob(/*n,*/ pipelen);
8112 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8116 if (pipe(pip) < 0) {
8118 ash_msg_and_raise_error("pipe call failed");
8121 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
8134 evaltreenr(lp->n, flags);
8142 if (n->npipe.backgnd == 0) {
8143 exitstatus = waitforjob(jp);
8144 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
8150 * Controls whether the shell is interactive or not.
8153 setinteractive(int on)
8155 static int is_interactive;
8157 if (++on == is_interactive)
8159 is_interactive = on;
8163 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8164 if (is_interactive > 1) {
8165 /* Looks like they want an interactive shell */
8166 static smallint did_banner;
8171 "%s built-in shell (ash)\n"
8172 "Enter 'help' for a list of built-in commands."
8181 #if ENABLE_FEATURE_EDITING_VI
8182 #define setvimode(on) do { \
8183 if (on) line_input_state->flags |= VI_MODE; \
8184 else line_input_state->flags &= ~VI_MODE; \
8187 #define setvimode(on) viflag = 0 /* forcibly keep the option off */
8196 setinteractive(iflag);
8201 static struct localvar *localvars;
8204 * Called after a function returns.
8205 * Interrupts must be off.
8210 struct localvar *lvp;
8213 while ((lvp = localvars) != NULL) {
8214 localvars = lvp->next;
8216 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
8217 if (vp == NULL) { /* $- saved */
8218 memcpy(optlist, lvp->text, sizeof(optlist));
8219 free((char*)lvp->text);
8221 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8225 (*vp->func)(strchrnul(lvp->text, '=') + 1);
8226 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8227 free((char*)vp->text);
8228 vp->flags = lvp->flags;
8229 vp->text = lvp->text;
8236 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8238 volatile struct shparam saveparam;
8239 struct localvar *volatile savelocalvars;
8240 struct jmploc *volatile savehandler;
8241 struct jmploc jmploc;
8244 saveparam = shellparam;
8245 savelocalvars = localvars;
8246 e = setjmp(jmploc.loc);
8251 savehandler = exception_handler;
8252 exception_handler = &jmploc;
8254 shellparam.malloced = 0;
8258 shellparam.nparam = argc - 1;
8259 shellparam.p = argv + 1;
8260 #if ENABLE_ASH_GETOPTS
8261 shellparam.optind = 1;
8262 shellparam.optoff = -1;
8264 evaltree(&func->n, flags & EV_TESTED);
8270 localvars = savelocalvars;
8271 freeparam(&shellparam);
8272 shellparam = saveparam;
8273 exception_handler = savehandler;
8275 evalskip &= ~SKIPFUNC;
8279 #if ENABLE_ASH_CMDCMD
8281 parse_command_args(char **argv, const char **path)
8294 if (c == '-' && !*cp) {
8301 *path = bb_default_path;
8304 /* run 'typecmd' for other options */
8315 * Make a variable a local variable. When a variable is made local, it's
8316 * value and flags are saved in a localvar structure. The saved values
8317 * will be restored when the shell function returns. We handle the name
8318 * "-" as a special case.
8323 struct localvar *lvp;
8328 lvp = ckzalloc(sizeof(struct localvar));
8329 if (LONE_DASH(name)) {
8331 p = ckmalloc(sizeof(optlist));
8332 lvp->text = memcpy(p, optlist, sizeof(optlist));
8337 vpp = hashvar(name);
8338 vp = *findvar(vpp, name);
8339 eq = strchr(name, '=');
8342 setvareq(name, VSTRFIXED);
8344 setvar(name, NULL, VSTRFIXED);
8345 vp = *vpp; /* the new variable */
8346 lvp->flags = VUNSET;
8348 lvp->text = vp->text;
8349 lvp->flags = vp->flags;
8350 vp->flags |= VSTRFIXED|VTEXTFIXED;
8356 lvp->next = localvars;
8362 * The "local" command.
8365 localcmd(int argc ATTRIBUTE_UNUSED, char **argv)
8370 while ((name = *argv++) != NULL) {
8377 falsecmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
8383 truecmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
8389 execcmd(int argc ATTRIBUTE_UNUSED, char **argv)
8392 iflag = 0; /* exit on error */
8395 shellexec(argv + 1, pathval(), 0);
8401 * The return command.
8404 returncmd(int argc ATTRIBUTE_UNUSED, char **argv)
8407 * If called outside a function, do what ksh does;
8408 * skip the rest of the file.
8410 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8411 return argv[1] ? number(argv[1]) : exitstatus;
8414 /* Forward declarations for builtintab[] */
8415 static int breakcmd(int, char **);
8416 static int dotcmd(int, char **);
8417 static int evalcmd(int, char **);
8418 #if ENABLE_ASH_BUILTIN_ECHO
8419 static int echocmd(int, char **);
8421 #if ENABLE_ASH_BUILTIN_TEST
8422 static int testcmd(int, char **);
8424 static int exitcmd(int, char **);
8425 static int exportcmd(int, char **);
8426 #if ENABLE_ASH_GETOPTS
8427 static int getoptscmd(int, char **);
8429 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8430 static int helpcmd(int argc, char **argv);
8432 #if ENABLE_ASH_MATH_SUPPORT
8433 static int letcmd(int, char **);
8435 static int readcmd(int, char **);
8436 static int setcmd(int, char **);
8437 static int shiftcmd(int, char **);
8438 static int timescmd(int, char **);
8439 static int trapcmd(int, char **);
8440 static int umaskcmd(int, char **);
8441 static int unsetcmd(int, char **);
8442 static int ulimitcmd(int, char **);
8444 #define BUILTIN_NOSPEC "0"
8445 #define BUILTIN_SPECIAL "1"
8446 #define BUILTIN_REGULAR "2"
8447 #define BUILTIN_SPEC_REG "3"
8448 #define BUILTIN_ASSIGN "4"
8449 #define BUILTIN_SPEC_ASSG "5"
8450 #define BUILTIN_REG_ASSG "6"
8451 #define BUILTIN_SPEC_REG_ASSG "7"
8453 /* make sure to keep these in proper order since it is searched via bsearch() */
8454 static const struct builtincmd builtintab[] = {
8455 { BUILTIN_SPEC_REG ".", dotcmd },
8456 { BUILTIN_SPEC_REG ":", truecmd },
8457 #if ENABLE_ASH_BUILTIN_TEST
8458 { BUILTIN_REGULAR "[", testcmd },
8459 { BUILTIN_REGULAR "[[", testcmd },
8461 #if ENABLE_ASH_ALIAS
8462 { BUILTIN_REG_ASSG "alias", aliascmd },
8465 { BUILTIN_REGULAR "bg", fg_bgcmd },
8467 { BUILTIN_SPEC_REG "break", breakcmd },
8468 { BUILTIN_REGULAR "cd", cdcmd },
8469 { BUILTIN_NOSPEC "chdir", cdcmd },
8470 #if ENABLE_ASH_CMDCMD
8471 { BUILTIN_REGULAR "command", commandcmd },
8473 { BUILTIN_SPEC_REG "continue", breakcmd },
8474 #if ENABLE_ASH_BUILTIN_ECHO
8475 { BUILTIN_REGULAR "echo", echocmd },
8477 { BUILTIN_SPEC_REG "eval", evalcmd },
8478 { BUILTIN_SPEC_REG "exec", execcmd },
8479 { BUILTIN_SPEC_REG "exit", exitcmd },
8480 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8481 { BUILTIN_REGULAR "false", falsecmd },
8483 { BUILTIN_REGULAR "fg", fg_bgcmd },
8485 #if ENABLE_ASH_GETOPTS
8486 { BUILTIN_REGULAR "getopts", getoptscmd },
8488 { BUILTIN_NOSPEC "hash", hashcmd },
8489 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8490 { BUILTIN_NOSPEC "help", helpcmd },
8493 { BUILTIN_REGULAR "jobs", jobscmd },
8494 { BUILTIN_REGULAR "kill", killcmd },
8496 #if ENABLE_ASH_MATH_SUPPORT
8497 { BUILTIN_NOSPEC "let", letcmd },
8499 { BUILTIN_ASSIGN "local", localcmd },
8500 { BUILTIN_NOSPEC "pwd", pwdcmd },
8501 { BUILTIN_REGULAR "read", readcmd },
8502 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8503 { BUILTIN_SPEC_REG "return", returncmd },
8504 { BUILTIN_SPEC_REG "set", setcmd },
8505 { BUILTIN_SPEC_REG "shift", shiftcmd },
8506 { BUILTIN_SPEC_REG "source", dotcmd },
8507 #if ENABLE_ASH_BUILTIN_TEST
8508 { BUILTIN_REGULAR "test", testcmd },
8510 { BUILTIN_SPEC_REG "times", timescmd },
8511 { BUILTIN_SPEC_REG "trap", trapcmd },
8512 { BUILTIN_REGULAR "true", truecmd },
8513 { BUILTIN_NOSPEC "type", typecmd },
8514 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
8515 { BUILTIN_REGULAR "umask", umaskcmd },
8516 #if ENABLE_ASH_ALIAS
8517 { BUILTIN_REGULAR "unalias", unaliascmd },
8519 { BUILTIN_SPEC_REG "unset", unsetcmd },
8520 { BUILTIN_REGULAR "wait", waitcmd },
8524 #define COMMANDCMD (builtintab + 5 + \
8525 2 * ENABLE_ASH_BUILTIN_TEST + \
8526 ENABLE_ASH_ALIAS + \
8527 ENABLE_ASH_JOB_CONTROL)
8528 #define EXECCMD (builtintab + 7 + \
8529 2 * ENABLE_ASH_BUILTIN_TEST + \
8530 ENABLE_ASH_ALIAS + \
8531 ENABLE_ASH_JOB_CONTROL + \
8532 ENABLE_ASH_CMDCMD + \
8533 ENABLE_ASH_BUILTIN_ECHO)
8536 * Search the table of builtin commands.
8538 static struct builtincmd *
8539 find_builtin(const char *name)
8541 struct builtincmd *bp;
8544 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8551 * Execute a simple command.
8553 static int back_exitstatus; /* exit status of backquoted command */
8555 isassignment(const char *p)
8557 const char *q = endofname(p);
8563 bltincmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
8565 /* Preserve exitstatus of a previous possible redirection
8566 * as POSIX mandates */
8567 return back_exitstatus;
8570 evalcommand(union node *cmd, int flags)
8572 static const struct builtincmd null_bltin = {
8573 "\0\0", bltincmd /* why three NULs? */
8575 struct stackmark smark;
8577 struct arglist arglist;
8578 struct arglist varlist;
8581 const struct strlist *sp;
8582 struct cmdentry cmdentry;
8590 struct builtincmd *bcmd;
8591 int pseudovarflag = 0;
8593 /* First expand the arguments. */
8594 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8595 setstackmark(&smark);
8596 back_exitstatus = 0;
8598 cmdentry.cmdtype = CMDBUILTIN;
8599 cmdentry.u.cmd = &null_bltin;
8600 varlist.lastp = &varlist.list;
8601 *varlist.lastp = NULL;
8602 arglist.lastp = &arglist.list;
8603 *arglist.lastp = NULL;
8606 if (cmd->ncmd.args) {
8607 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8608 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8611 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8612 struct strlist **spp;
8614 spp = arglist.lastp;
8615 if (pseudovarflag && isassignment(argp->narg.text))
8616 expandarg(argp, &arglist, EXP_VARTILDE);
8618 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8620 for (sp = *spp; sp; sp = sp->next)
8624 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8625 for (sp = arglist.list; sp; sp = sp->next) {
8626 TRACE(("evalcommand arg: %s\n", sp->text));
8627 *nargv++ = sp->text;
8632 if (iflag && funcnest == 0 && argc > 0)
8633 lastarg = nargv[-1];
8636 expredir(cmd->ncmd.redirect);
8637 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8640 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8641 struct strlist **spp;
8644 spp = varlist.lastp;
8645 expandarg(argp, &varlist, EXP_VARTILDE);
8648 * Modify the command lookup path, if a PATH= assignment
8652 if (varequal(p, path))
8656 /* Print the command if xflag is set. */
8659 const char *p = " %s";
8662 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8665 for (n = 0; n < 2; n++) {
8667 fdprintf(preverrout_fd, p, sp->text);
8675 safe_write(preverrout_fd, "\n", 1);
8681 /* Now locate the command. */
8683 const char *oldpath;
8684 int cmd_flag = DO_ERR;
8689 find_command(argv[0], &cmdentry, cmd_flag, path);
8690 if (cmdentry.cmdtype == CMDUNKNOWN) {
8696 /* implement bltin and command here */
8697 if (cmdentry.cmdtype != CMDBUILTIN)
8700 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8701 if (cmdentry.u.cmd == EXECCMD)
8703 #if ENABLE_ASH_CMDCMD
8704 if (cmdentry.u.cmd == COMMANDCMD) {
8706 nargv = parse_command_args(argv, &path);
8709 argc -= nargv - argv;
8711 cmd_flag |= DO_NOFUNC;
8719 /* We have a redirection error. */
8721 raise_exception(EXERROR);
8723 exitstatus = status;
8727 /* Execute the command. */
8728 switch (cmdentry.cmdtype) {
8730 /* Fork off a child process if necessary. */
8731 if (!(flags & EV_EXIT) || trap[0]) {
8733 jp = makejob(/*cmd,*/ 1);
8734 if (forkshell(jp, cmd, FORK_FG) != 0) {
8735 exitstatus = waitforjob(jp);
8741 listsetvar(varlist.list, VEXPORT|VSTACK);
8742 shellexec(argv, path, cmdentry.u.index);
8746 cmdenviron = varlist.list;
8748 struct strlist *list = cmdenviron;
8750 if (spclbltin > 0 || argc == 0) {
8752 if (cmd_is_exec && argc > 1)
8755 listsetvar(list, i);
8757 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
8764 exit_status = 128 + SIGINT;
8766 exit_status = 128 + pendingsig;
8767 exitstatus = exit_status;
8768 if (i == EXINT || spclbltin > 0) {
8770 longjmp(exception_handler->loc, 1);
8777 listsetvar(varlist.list, 0);
8778 if (evalfun(cmdentry.u.func, argc, argv, flags))
8784 popredir(cmd_is_exec);
8786 /* dsl: I think this is intended to be used to support
8787 * '_' in 'vi' command mode during line editing...
8788 * However I implemented that within libedit itself.
8790 setvar("_", lastarg, 0);
8791 popstackmark(&smark);
8795 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
8797 char *volatile savecmdname;
8798 struct jmploc *volatile savehandler;
8799 struct jmploc jmploc;
8802 savecmdname = commandname;
8803 i = setjmp(jmploc.loc);
8806 savehandler = exception_handler;
8807 exception_handler = &jmploc;
8808 commandname = argv[0];
8810 optptr = NULL; /* initialize nextopt */
8811 exitstatus = (*cmd->builtin)(argc, argv);
8812 flush_stdout_stderr();
8814 exitstatus |= ferror(stdout);
8816 commandname = savecmdname;
8818 exception_handler = savehandler;
8824 goodname(const char *p)
8826 return !*endofname(p);
8831 * Search for a command. This is called before we fork so that the
8832 * location of the command will be available in the parent as well as
8833 * the child. The check for "goodname" is an overly conservative
8834 * check that the name will not be subject to expansion.
8837 prehash(union node *n)
8839 struct cmdentry entry;
8841 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
8842 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
8846 /* ============ Builtin commands
8848 * Builtin commands whose functions are closely tied to evaluation
8849 * are implemented here.
8853 * Handle break and continue commands. Break, continue, and return are
8854 * all handled by setting the evalskip flag. The evaluation routines
8855 * above all check this flag, and if it is set they start skipping
8856 * commands rather than executing them. The variable skipcount is
8857 * the number of loops to break/continue, or the number of function
8858 * levels to return. (The latter is always 1.) It should probably
8859 * be an error to break out of more loops than exist, but it isn't
8860 * in the standard shell so we don't make it one here.
8863 breakcmd(int argc ATTRIBUTE_UNUSED, char **argv)
8865 int n = argv[1] ? number(argv[1]) : 1;
8868 ash_msg_and_raise_error(illnum, argv[1]);
8872 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
8879 /* ============ input.c
8881 * This implements the input routines used by the parser.
8884 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
8887 INPUT_PUSH_FILE = 1,
8888 INPUT_NOFILE_OK = 2,
8891 static int plinno = 1; /* input line number */
8892 /* number of characters left in input buffer */
8893 static int parsenleft; /* copy of parsefile->nleft */
8894 static int parselleft; /* copy of parsefile->lleft */
8895 /* next character in input buffer */
8896 static char *parsenextc; /* copy of parsefile->nextc */
8898 static int checkkwd;
8899 /* values of checkkwd variable */
8900 #define CHKALIAS 0x1
8907 struct strpush *sp = parsefile->strpush;
8910 #if ENABLE_ASH_ALIAS
8912 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
8913 checkkwd |= CHKALIAS;
8915 if (sp->string != sp->ap->val) {
8918 sp->ap->flag &= ~ALIASINUSE;
8919 if (sp->ap->flag & ALIASDEAD) {
8920 unalias(sp->ap->name);
8924 parsenextc = sp->prevstring;
8925 parsenleft = sp->prevnleft;
8926 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
8927 parsefile->strpush = sp->prev;
8928 if (sp != &(parsefile->basestrpush))
8937 char *buf = parsefile->buf;
8940 #if ENABLE_FEATURE_EDITING
8942 if (!iflag || parsefile->fd)
8943 nr = nonblock_safe_read(parsefile->fd, buf, BUFSIZ - 1);
8945 #if ENABLE_FEATURE_TAB_COMPLETION
8946 line_input_state->path_lookup = pathval();
8948 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
8950 /* Ctrl+C pressed */
8959 if (nr < 0 && errno == 0) {
8960 /* Ctrl+D pressed */
8965 nr = nonblock_safe_read(parsefile->fd, buf, BUFSIZ - 1);
8969 /* nonblock_safe_read() handles this problem */
8971 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
8972 int flags = fcntl(0, F_GETFL);
8973 if (flags >= 0 && (flags & O_NONBLOCK)) {
8974 flags &= ~O_NONBLOCK;
8975 if (fcntl(0, F_SETFL, flags) >= 0) {
8976 out2str("sh: turning off NDELAY mode\n");
8987 * Refill the input buffer and return the next input character:
8989 * 1) If a string was pushed back on the input, pop it;
8990 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
8991 * from a string so we can't refill the buffer, return EOF.
8992 * 3) If the is more stuff in this buffer, use it else call read to fill it.
8993 * 4) Process input up to the next newline, deleting nul characters.
9002 while (parsefile->strpush) {
9003 #if ENABLE_ASH_ALIAS
9004 if (parsenleft == -1 && parsefile->strpush->ap &&
9005 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
9010 if (--parsenleft >= 0)
9011 return signed_char2int(*parsenextc++);
9013 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
9015 flush_stdout_stderr();
9022 parselleft = parsenleft = EOF_NLEFT;
9029 /* delete nul characters */
9037 memmove(q, q + 1, more);
9041 parsenleft = q - parsenextc - 1;
9047 parsenleft = q - parsenextc - 1;
9059 out2str(parsenextc);
9064 return signed_char2int(*parsenextc++);
9067 #define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer())
9071 return pgetc_as_macro();
9074 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9075 #define pgetc_macro() pgetc()
9077 #define pgetc_macro() pgetc_as_macro()
9081 * Same as pgetc(), but ignores PEOA.
9083 #if ENABLE_ASH_ALIAS
9091 } while (c == PEOA);
9098 return pgetc_macro();
9103 * Read a line from the script.
9106 pfgets(char *line, int len)
9112 while (--nleft > 0) {
9128 * Undo the last call to pgetc. Only one character may be pushed back.
9129 * PEOF may be pushed back.
9139 * Push a string back onto the input at this current parsefile level.
9140 * We handle aliases this way.
9142 #if !ENABLE_ASH_ALIAS
9143 #define pushstring(s, ap) pushstring(s)
9146 pushstring(char *s, struct alias *ap)
9153 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
9154 if (parsefile->strpush) {
9155 sp = ckzalloc(sizeof(struct strpush));
9156 sp->prev = parsefile->strpush;
9157 parsefile->strpush = sp;
9159 sp = parsefile->strpush = &(parsefile->basestrpush);
9160 sp->prevstring = parsenextc;
9161 sp->prevnleft = parsenleft;
9162 #if ENABLE_ASH_ALIAS
9165 ap->flag |= ALIASINUSE;
9175 * To handle the "." command, a stack of input files is used. Pushfile
9176 * adds a new entry to the stack and popfile restores the previous level.
9181 struct parsefile *pf;
9183 parsefile->nleft = parsenleft;
9184 parsefile->lleft = parselleft;
9185 parsefile->nextc = parsenextc;
9186 parsefile->linno = plinno;
9187 pf = ckzalloc(sizeof(*pf));
9188 pf->prev = parsefile;
9190 /*pf->strpush = NULL; - ckzalloc did it */
9191 /*pf->basestrpush.prev = NULL;*/
9198 struct parsefile *pf = parsefile;
9206 parsefile = pf->prev;
9208 parsenleft = parsefile->nleft;
9209 parselleft = parsefile->lleft;
9210 parsenextc = parsefile->nextc;
9211 plinno = parsefile->linno;
9216 * Return to top level.
9221 while (parsefile != &basepf)
9226 * Close the file(s) that the shell is reading commands from. Called
9227 * after a fork is done.
9233 if (parsefile->fd > 0) {
9234 close(parsefile->fd);
9240 * Like setinputfile, but takes an open file descriptor. Call this with
9244 setinputfd(int fd, int push)
9246 close_on_exec_on(fd);
9252 if (parsefile->buf == NULL)
9253 parsefile->buf = ckmalloc(IBUFSIZ);
9254 parselleft = parsenleft = 0;
9259 * Set the input to take input from a file. If push is set, push the
9260 * old input onto the stack first.
9263 setinputfile(const char *fname, int flags)
9269 fd = open(fname, O_RDONLY);
9271 if (flags & INPUT_NOFILE_OK)
9273 ash_msg_and_raise_error("can't open %s", fname);
9276 fd2 = copyfd(fd, 10);
9279 ash_msg_and_raise_error("out of file descriptors");
9282 setinputfd(fd, flags & INPUT_PUSH_FILE);
9289 * Like setinputfile, but takes input from a string.
9292 setinputstring(char *string)
9296 parsenextc = string;
9297 parsenleft = strlen(string);
9298 parsefile->buf = NULL;
9304 /* ============ mail.c
9306 * Routines to check for mail.
9311 #define MAXMBOXES 10
9313 /* times of mailboxes */
9314 static time_t mailtime[MAXMBOXES];
9315 /* Set if MAIL or MAILPATH is changed. */
9316 static smallint mail_var_path_changed;
9319 * Print appropriate message(s) if mail has arrived.
9320 * If mail_var_path_changed is set,
9321 * then the value of MAIL has mail_var_path_changed,
9322 * so we just update the values.
9331 struct stackmark smark;
9334 setstackmark(&smark);
9335 mpath = mpathset() ? mpathval() : mailval();
9336 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9337 p = padvance(&mpath, nullstr);
9342 for (q = p; *q; q++);
9347 q[-1] = '\0'; /* delete trailing '/' */
9348 if (stat(p, &statb) < 0) {
9352 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9355 pathopt ? pathopt : "you have mail"
9358 *mtp = statb.st_mtime;
9360 mail_var_path_changed = 0;
9361 popstackmark(&smark);
9365 changemail(const char *val ATTRIBUTE_UNUSED)
9367 mail_var_path_changed = 1;
9370 #endif /* ASH_MAIL */
9373 /* ============ ??? */
9376 * Set the shell parameters.
9379 setparam(char **argv)
9385 for (nparam = 0; argv[nparam]; nparam++);
9386 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9388 *ap++ = ckstrdup(*argv++);
9391 freeparam(&shellparam);
9392 shellparam.malloced = 1;
9393 shellparam.nparam = nparam;
9394 shellparam.p = newparam;
9395 #if ENABLE_ASH_GETOPTS
9396 shellparam.optind = 1;
9397 shellparam.optoff = -1;
9402 * Process shell options. The global variable argptr contains a pointer
9403 * to the argument list; we advance it past the options.
9405 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9406 * For a non-interactive shell, an error condition encountered
9407 * by a special built-in ... shall cause the shell to write a diagnostic message
9408 * to standard error and exit as shown in the following table:
9409 * Error Special Built-In
9411 * Utility syntax error (option or operand error) Shall exit
9413 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9414 * we see that bash does not do that (set "finishes" with error code 1 instead,
9415 * and shell continues), and people rely on this behavior!
9417 * set -o barfoo 2>/dev/null
9420 * Oh well. Let's mimic that.
9423 minus_o(char *name, int val)
9428 for (i = 0; i < NOPTS; i++) {
9429 if (strcmp(name, optnames(i)) == 0) {
9434 ash_msg("illegal option -o %s", name);
9437 out1str("Current option settings\n");
9438 for (i = 0; i < NOPTS; i++)
9439 out1fmt("%-16s%s\n", optnames(i),
9440 optlist[i] ? "on" : "off");
9444 setoption(int flag, int val)
9448 for (i = 0; i < NOPTS; i++) {
9449 if (optletters(i) == flag) {
9454 ash_msg_and_raise_error("illegal option -%c", flag);
9458 options(int cmdline)
9466 while ((p = *argptr) != NULL) {
9468 if (c != '-' && c != '+')
9471 val = 0; /* val = 0 if c == '+' */
9474 if (p[0] == '\0' || LONE_DASH(p)) {
9476 /* "-" means turn off -x and -v */
9479 /* "--" means reset params */
9480 else if (*argptr == NULL)
9483 break; /* "-" or "--" terminates options */
9486 /* first char was + or - */
9487 while ((c = *p++) != '\0') {
9488 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9489 if (c == 'c' && cmdline) {
9490 minusc = p; /* command is after shell args */
9491 } else if (c == 'o') {
9492 if (minus_o(*argptr, val)) {
9493 /* it already printed err message */
9494 return 1; /* error */
9498 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9500 /* bash does not accept +-login, we also won't */
9501 } else if (cmdline && val && (c == '-')) { /* long options */
9502 if (strcmp(p, "login") == 0)
9514 * The shift builtin command.
9517 shiftcmd(int argc ATTRIBUTE_UNUSED, char **argv)
9524 n = number(argv[1]);
9525 if (n > shellparam.nparam)
9526 ash_msg_and_raise_error("can't shift that many");
9528 shellparam.nparam -= n;
9529 for (ap1 = shellparam.p; --n >= 0; ap1++) {
9530 if (shellparam.malloced)
9534 while ((*ap2++ = *ap1++) != NULL);
9535 #if ENABLE_ASH_GETOPTS
9536 shellparam.optind = 1;
9537 shellparam.optoff = -1;
9544 * POSIX requires that 'set' (but not export or readonly) output the
9545 * variables in lexicographic order - by the locale's collating order (sigh).
9546 * Maybe we could keep them in an ordered balanced binary tree
9547 * instead of hashed lists.
9548 * For now just roll 'em through qsort for printing...
9551 showvars(const char *sep_prefix, int on, int off)
9556 ep = listvars(on, off, &epend);
9557 qsort(ep, epend - ep, sizeof(char *), vpcmp);
9559 sep = *sep_prefix ? " " : sep_prefix;
9561 for (; ep < epend; ep++) {
9565 p = strchrnul(*ep, '=');
9568 q = single_quote(++p);
9569 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9575 * The set command builtin.
9578 setcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
9583 return showvars(nullstr, 0, VUNSET);
9586 if (!options(0)) { /* if no parse error... */
9589 if (*argptr != NULL) {
9597 #if ENABLE_ASH_RANDOM_SUPPORT
9598 /* Roughly copied from bash.. */
9600 change_random(const char *value)
9602 if (value == NULL) {
9603 /* "get", generate */
9606 rseed = rseed * 1103515245 + 12345;
9607 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9608 /* set without recursion */
9609 setvar(vrandom.text, buf, VNOFUNC);
9610 vrandom.flags &= ~VNOFUNC;
9613 rseed = strtoul(value, (char **)NULL, 10);
9618 #if ENABLE_ASH_GETOPTS
9620 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9629 if (*param_optind < 1)
9631 optnext = optfirst + *param_optind - 1;
9633 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9636 p = optnext[-1] + *optoff;
9637 if (p == NULL || *p == '\0') {
9638 /* Current word is done, advance */
9640 if (p == NULL || *p != '-' || *++p == '\0') {
9647 if (LONE_DASH(p)) /* check for "--" */
9652 for (q = optstr; *q != c; ) {
9654 if (optstr[0] == ':') {
9657 err |= setvarsafe("OPTARG", s, 0);
9659 fprintf(stderr, "Illegal option -%c\n", c);
9670 if (*p == '\0' && (p = *optnext) == NULL) {
9671 if (optstr[0] == ':') {
9674 err |= setvarsafe("OPTARG", s, 0);
9677 fprintf(stderr, "No arg for -%c option\n", c);
9686 err |= setvarsafe("OPTARG", p, 0);
9689 err |= setvarsafe("OPTARG", nullstr, 0);
9691 *optoff = p ? p - *(optnext - 1) : -1;
9692 *param_optind = optnext - optfirst + 1;
9693 fmtstr(s, sizeof(s), "%d", *param_optind);
9694 err |= setvarsafe("OPTIND", s, VNOFUNC);
9697 err |= setvarsafe(optvar, s, 0);
9701 flush_stdout_stderr();
9702 raise_exception(EXERROR);
9708 * The getopts builtin. Shellparam.optnext points to the next argument
9709 * to be processed. Shellparam.optptr points to the next character to
9710 * be processed in the current argument. If shellparam.optnext is NULL,
9711 * then it's the first time getopts has been called.
9714 getoptscmd(int argc, char **argv)
9719 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
9721 optbase = shellparam.p;
9722 if (shellparam.optind > shellparam.nparam + 1) {
9723 shellparam.optind = 1;
9724 shellparam.optoff = -1;
9728 if (shellparam.optind > argc - 2) {
9729 shellparam.optind = 1;
9730 shellparam.optoff = -1;
9734 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9735 &shellparam.optoff);
9737 #endif /* ASH_GETOPTS */
9740 /* ============ Shell parser */
9743 * NEOF is returned by parsecmd when it encounters an end of file. It
9744 * must be distinct from NULL, so we use the address of a variable that
9745 * happens to be handy.
9747 static smallint tokpushback; /* last token pushed back */
9748 #define NEOF ((union node *)&tokpushback)
9749 static smallint parsebackquote; /* nonzero if we are inside backquotes */
9750 static int lasttoken; /* last token read */
9751 static char *wordtext; /* text of last word returned by readtoken */
9752 static struct nodelist *backquotelist;
9753 static union node *redirnode;
9754 static struct heredoc *heredoc;
9755 static smallint quoteflag; /* set if (part of) last token was quoted */
9757 static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN;
9759 raise_error_syntax(const char *msg)
9761 ash_msg_and_raise_error("syntax error: %s", msg);
9766 * Called when an unexpected token is read during the parse. The argument
9767 * is the token that is expected, or -1 if more than one type of token can
9768 * occur at this point.
9770 static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN;
9772 raise_error_unexpected_syntax(int token)
9777 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
9779 sprintf(msg + l, " (expecting %s)", tokname(token));
9780 raise_error_syntax(msg);
9784 #define EOFMARKLEN 79
9787 struct heredoc *next; /* next here document in list */
9788 union node *here; /* redirection node */
9789 char *eofmark; /* string indicating end of input */
9790 int striptabs; /* if set, strip leading tabs */
9793 static struct heredoc *heredoclist; /* list of here documents to read */
9795 /* parsing is heavily cross-recursive, need these forward decls */
9796 static union node *andor(void);
9797 static union node *pipeline(void);
9798 static union node *parse_command(void);
9799 static void parseheredoc(void);
9800 static char peektoken(void);
9801 static int readtoken(void);
9806 union node *n1, *n2, *n3;
9809 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9810 if (nlflag == 2 && peektoken())
9816 if (tok == TBACKGND) {
9817 if (n2->type == NPIPE) {
9818 n2->npipe.backgnd = 1;
9820 if (n2->type != NREDIR) {
9821 n3 = stzalloc(sizeof(struct nredir));
9823 /*n3->nredir.redirect = NULL; - stzalloc did it */
9826 n2->type = NBACKGND;
9832 n3 = stzalloc(sizeof(struct nbinary));
9834 n3->nbinary.ch1 = n1;
9835 n3->nbinary.ch2 = n2;
9851 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9859 pungetc(); /* push back EOF on input */
9863 raise_error_unexpected_syntax(-1);
9873 union node *n1, *n2, *n3;
9881 } else if (t == TOR) {
9887 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9889 n3 = stzalloc(sizeof(struct nbinary));
9891 n3->nbinary.ch1 = n1;
9892 n3->nbinary.ch2 = n2;
9900 union node *n1, *n2, *pipenode;
9901 struct nodelist *lp, *prev;
9905 TRACE(("pipeline: entered\n"));
9906 if (readtoken() == TNOT) {
9908 checkkwd = CHKKWD | CHKALIAS;
9911 n1 = parse_command();
9912 if (readtoken() == TPIPE) {
9913 pipenode = stzalloc(sizeof(struct npipe));
9914 pipenode->type = NPIPE;
9915 /*pipenode->npipe.backgnd = 0; - stzalloc did it */
9916 lp = stzalloc(sizeof(struct nodelist));
9917 pipenode->npipe.cmdlist = lp;
9921 lp = stzalloc(sizeof(struct nodelist));
9922 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9923 lp->n = parse_command();
9925 } while (readtoken() == TPIPE);
9931 n2 = stzalloc(sizeof(struct nnot));
9944 n = stzalloc(sizeof(struct narg));
9946 /*n->narg.next = NULL; - stzalloc did it */
9947 n->narg.text = wordtext;
9948 n->narg.backquote = backquotelist;
9953 fixredir(union node *n, const char *text, int err)
9955 TRACE(("Fix redir %s %d\n", text, err));
9957 n->ndup.vname = NULL;
9959 if (isdigit(text[0]) && text[1] == '\0')
9960 n->ndup.dupfd = text[0] - '0';
9961 else if (LONE_DASH(text))
9965 raise_error_syntax("Bad fd number");
9966 n->ndup.vname = makename();
9971 * Returns true if the text contains nothing to expand (no dollar signs
9975 noexpand(char *text)
9981 while ((c = *p++) != '\0') {
9982 if (c == CTLQUOTEMARK)
9986 else if (SIT(c, BASESYNTAX) == CCTL)
9995 union node *n = redirnode;
9997 if (readtoken() != TWORD)
9998 raise_error_unexpected_syntax(-1);
9999 if (n->type == NHERE) {
10000 struct heredoc *here = heredoc;
10004 if (quoteflag == 0)
10006 TRACE(("Here document %d\n", n->type));
10007 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10008 raise_error_syntax("Illegal eof marker for << redirection");
10009 rmescapes(wordtext);
10010 here->eofmark = wordtext;
10012 if (heredoclist == NULL)
10013 heredoclist = here;
10015 for (p = heredoclist; p->next; p = p->next)
10019 } else if (n->type == NTOFD || n->type == NFROMFD) {
10020 fixredir(n, wordtext, 0);
10022 n->nfile.fname = makename();
10026 static union node *
10029 union node *args, **app;
10030 union node *n = NULL;
10031 union node *vars, **vpp;
10032 union node **rpp, *redir;
10042 savecheckkwd = CHKALIAS;
10044 checkkwd = savecheckkwd;
10045 switch (readtoken()) {
10047 n = stzalloc(sizeof(struct narg));
10049 /*n->narg.next = NULL; - stzalloc did it */
10050 n->narg.text = wordtext;
10051 n->narg.backquote = backquotelist;
10052 if (savecheckkwd && isassignment(wordtext)) {
10054 vpp = &n->narg.next;
10057 app = &n->narg.next;
10062 *rpp = n = redirnode;
10063 rpp = &n->nfile.next;
10064 parsefname(); /* read name of redirection file */
10067 if (args && app == &args->narg.next
10070 struct builtincmd *bcmd;
10073 /* We have a function */
10074 if (readtoken() != TRP)
10075 raise_error_unexpected_syntax(TRP);
10076 name = n->narg.text;
10077 if (!goodname(name)
10078 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10080 raise_error_syntax("Bad function name");
10083 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10084 n->narg.next = parse_command();
10097 n = stzalloc(sizeof(struct ncmd));
10099 n->ncmd.args = args;
10100 n->ncmd.assign = vars;
10101 n->ncmd.redirect = redir;
10105 static union node *
10106 parse_command(void)
10108 union node *n1, *n2;
10109 union node *ap, **app;
10110 union node *cp, **cpp;
10111 union node *redir, **rpp;
10118 switch (readtoken()) {
10120 raise_error_unexpected_syntax(-1);
10123 n1 = stzalloc(sizeof(struct nif));
10125 n1->nif.test = list(0);
10126 if (readtoken() != TTHEN)
10127 raise_error_unexpected_syntax(TTHEN);
10128 n1->nif.ifpart = list(0);
10130 while (readtoken() == TELIF) {
10131 n2->nif.elsepart = stzalloc(sizeof(struct nif));
10132 n2 = n2->nif.elsepart;
10134 n2->nif.test = list(0);
10135 if (readtoken() != TTHEN)
10136 raise_error_unexpected_syntax(TTHEN);
10137 n2->nif.ifpart = list(0);
10139 if (lasttoken == TELSE)
10140 n2->nif.elsepart = list(0);
10142 n2->nif.elsepart = NULL;
10150 n1 = stzalloc(sizeof(struct nbinary));
10151 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10152 n1->nbinary.ch1 = list(0);
10155 TRACE(("expecting DO got %s %s\n", tokname(got),
10156 got == TWORD ? wordtext : ""));
10157 raise_error_unexpected_syntax(TDO);
10159 n1->nbinary.ch2 = list(0);
10164 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
10165 raise_error_syntax("Bad for loop variable");
10166 n1 = stzalloc(sizeof(struct nfor));
10168 n1->nfor.var = wordtext;
10169 checkkwd = CHKKWD | CHKALIAS;
10170 if (readtoken() == TIN) {
10172 while (readtoken() == TWORD) {
10173 n2 = stzalloc(sizeof(struct narg));
10175 /*n2->narg.next = NULL; - stzalloc did it */
10176 n2->narg.text = wordtext;
10177 n2->narg.backquote = backquotelist;
10179 app = &n2->narg.next;
10182 n1->nfor.args = ap;
10183 if (lasttoken != TNL && lasttoken != TSEMI)
10184 raise_error_unexpected_syntax(-1);
10186 n2 = stzalloc(sizeof(struct narg));
10188 /*n2->narg.next = NULL; - stzalloc did it */
10189 n2->narg.text = (char *)dolatstr;
10190 /*n2->narg.backquote = NULL;*/
10191 n1->nfor.args = n2;
10193 * Newline or semicolon here is optional (but note
10194 * that the original Bourne shell only allowed NL).
10196 if (lasttoken != TNL && lasttoken != TSEMI)
10199 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10200 if (readtoken() != TDO)
10201 raise_error_unexpected_syntax(TDO);
10202 n1->nfor.body = list(0);
10206 n1 = stzalloc(sizeof(struct ncase));
10208 if (readtoken() != TWORD)
10209 raise_error_unexpected_syntax(TWORD);
10210 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10212 /*n2->narg.next = NULL; - stzalloc did it */
10213 n2->narg.text = wordtext;
10214 n2->narg.backquote = backquotelist;
10216 checkkwd = CHKKWD | CHKALIAS;
10217 } while (readtoken() == TNL);
10218 if (lasttoken != TIN)
10219 raise_error_unexpected_syntax(TIN);
10220 cpp = &n1->ncase.cases;
10222 checkkwd = CHKNL | CHKKWD;
10224 while (t != TESAC) {
10225 if (lasttoken == TLP)
10227 *cpp = cp = stzalloc(sizeof(struct nclist));
10229 app = &cp->nclist.pattern;
10231 *app = ap = stzalloc(sizeof(struct narg));
10233 /*ap->narg.next = NULL; - stzalloc did it */
10234 ap->narg.text = wordtext;
10235 ap->narg.backquote = backquotelist;
10236 if (readtoken() != TPIPE)
10238 app = &ap->narg.next;
10241 //ap->narg.next = NULL;
10242 if (lasttoken != TRP)
10243 raise_error_unexpected_syntax(TRP);
10244 cp->nclist.body = list(2);
10246 cpp = &cp->nclist.next;
10248 checkkwd = CHKNL | CHKKWD;
10252 raise_error_unexpected_syntax(TENDCASE);
10259 n1 = stzalloc(sizeof(struct nredir));
10260 n1->type = NSUBSHELL;
10261 n1->nredir.n = list(0);
10262 /*n1->nredir.redirect = NULL; - stzalloc did it */
10272 return simplecmd();
10275 if (readtoken() != t)
10276 raise_error_unexpected_syntax(t);
10279 /* Now check for redirection which may follow command */
10280 checkkwd = CHKKWD | CHKALIAS;
10282 while (readtoken() == TREDIR) {
10283 *rpp = n2 = redirnode;
10284 rpp = &n2->nfile.next;
10290 if (n1->type != NSUBSHELL) {
10291 n2 = stzalloc(sizeof(struct nredir));
10296 n1->nredir.redirect = redir;
10302 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10303 * is not NULL, read a here document. In the latter case, eofmark is the
10304 * word which marks the end of the document and striptabs is true if
10305 * leading tabs should be stripped from the document. The argument firstc
10306 * is the first character of the input token or document.
10308 * Because C does not have internal subroutines, I have simulated them
10309 * using goto's to implement the subroutine linkage. The following macros
10310 * will run code that appears at the end of readtoken1.
10313 #define CHECKEND() {goto checkend; checkend_return:;}
10314 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10315 #define PARSESUB() {goto parsesub; parsesub_return:;}
10316 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10317 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10318 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10321 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10323 /* NB: syntax parameter fits into smallint */
10327 char line[EOFMARKLEN + 1];
10328 struct nodelist *bqlist;
10332 smallint prevsyntax; /* syntax before arithmetic */
10333 #if ENABLE_ASH_EXPAND_PRMT
10334 smallint pssyntax; /* we are expanding a prompt string */
10336 int varnest; /* levels of variables expansion */
10337 int arinest; /* levels of arithmetic expansion */
10338 int parenlevel; /* levels of parens in arithmetic */
10339 int dqvarnest; /* levels of variables expansion within double quotes */
10342 /* Avoid longjmp clobbering */
10348 (void) &parenlevel;
10351 (void) &prevsyntax;
10354 startlinno = plinno;
10359 #if ENABLE_ASH_EXPAND_PRMT
10360 pssyntax = (syntax == PSSYNTAX);
10364 dblquote = (syntax == DQSYNTAX);
10370 STARTSTACKSTR(out);
10371 loop: { /* for each line, until end of word */
10372 CHECKEND(); /* set c to PEOF if at end of here document */
10373 for (;;) { /* until end of line or end of word */
10374 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10375 switch (SIT(c, syntax)) {
10376 case CNL: /* '\n' */
10377 if (syntax == BASESYNTAX)
10378 goto endword; /* exit outer loop */
10384 goto loop; /* continue outer loop */
10389 if (eofmark == NULL || dblquote)
10390 USTPUTC(CTLESC, out);
10393 case CBACK: /* backslash */
10396 USTPUTC(CTLESC, out);
10397 USTPUTC('\\', out);
10399 } else if (c == '\n') {
10403 #if ENABLE_ASH_EXPAND_PRMT
10404 if (c == '$' && pssyntax) {
10405 USTPUTC(CTLESC, out);
10406 USTPUTC('\\', out);
10410 c != '\\' && c != '`' &&
10415 USTPUTC(CTLESC, out);
10416 USTPUTC('\\', out);
10418 if (SIT(c, SQSYNTAX) == CCTL)
10419 USTPUTC(CTLESC, out);
10427 if (eofmark == NULL) {
10428 USTPUTC(CTLQUOTEMARK, out);
10436 if (eofmark != NULL && arinest == 0
10441 if (dqvarnest == 0) {
10442 syntax = BASESYNTAX;
10449 case CVAR: /* '$' */
10450 PARSESUB(); /* parse substitution */
10452 case CENDVAR: /* '}' */
10455 if (dqvarnest > 0) {
10458 USTPUTC(CTLENDVAR, out);
10463 #if ENABLE_ASH_MATH_SUPPORT
10464 case CLP: /* '(' in arithmetic */
10468 case CRP: /* ')' in arithmetic */
10469 if (parenlevel > 0) {
10473 if (pgetc() == ')') {
10474 if (--arinest == 0) {
10475 USTPUTC(CTLENDARI, out);
10476 syntax = prevsyntax;
10477 dblquote = (syntax == DQSYNTAX);
10482 * unbalanced parens
10483 * (don't 2nd guess - no error)
10491 case CBQUOTE: /* '`' */
10495 goto endword; /* exit outer loop */
10500 goto endword; /* exit outer loop */
10501 #if ENABLE_ASH_ALIAS
10511 #if ENABLE_ASH_MATH_SUPPORT
10512 if (syntax == ARISYNTAX)
10513 raise_error_syntax("Missing '))'");
10515 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10516 raise_error_syntax("Unterminated quoted string");
10517 if (varnest != 0) {
10518 startlinno = plinno;
10520 raise_error_syntax("Missing '}'");
10522 USTPUTC('\0', out);
10523 len = out - (char *)stackblock();
10524 out = stackblock();
10525 if (eofmark == NULL) {
10526 if ((c == '>' || c == '<')
10529 && (*out == '\0' || isdigit(*out))) {
10531 return lasttoken = TREDIR;
10536 quoteflag = quotef;
10537 backquotelist = bqlist;
10538 grabstackblock(len);
10542 /* end of readtoken routine */
10545 * Check to see whether we are at the end of the here document. When this
10546 * is called, c is set to the first character of the next input line. If
10547 * we are at the end of the here document, this routine sets the c to PEOF.
10551 #if ENABLE_ASH_ALIAS
10557 while (c == '\t') {
10561 if (c == *eofmark) {
10562 if (pfgets(line, sizeof(line)) != NULL) {
10566 for (q = eofmark + 1; *q && *p == *q; p++, q++);
10567 if (*p == '\n' && *q == '\0') {
10570 needprompt = doprompt;
10572 pushstring(line, NULL);
10577 goto checkend_return;
10581 * Parse a redirection operator. The variable "out" points to a string
10582 * specifying the fd to be redirected. The variable "c" contains the
10583 * first character of the redirection operator.
10589 np = stzalloc(sizeof(struct nfile));
10594 np->type = NAPPEND;
10596 np->type = NCLOBBER;
10603 } else { /* c == '<' */
10604 /*np->nfile.fd = 0; - stzalloc did it */
10608 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10609 np = stzalloc(sizeof(struct nhere));
10610 /*np->nfile.fd = 0; - stzalloc did it */
10613 heredoc = stzalloc(sizeof(struct heredoc));
10614 heredoc->here = np;
10617 heredoc->striptabs = 1;
10619 /*heredoc->striptabs = 0; - stzalloc did it */
10625 np->type = NFROMFD;
10629 np->type = NFROMTO;
10639 np->nfile.fd = fd - '0';
10641 goto parseredir_return;
10645 * Parse a substitution. At this point, we have read the dollar sign
10646 * and nothing else.
10649 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
10650 * (assuming ascii char codes, as the original implementation did) */
10651 #define is_special(c) \
10652 ((((unsigned int)c) - 33 < 32) \
10653 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
10659 static const char types[] ALIGN1 = "}-+?=";
10663 c <= PEOA_OR_PEOF ||
10664 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10668 } else if (c == '(') { /* $(command) or $((arith)) */
10669 if (pgetc() == '(') {
10670 #if ENABLE_ASH_MATH_SUPPORT
10673 raise_error_syntax("We unsupport $((arith))");
10680 USTPUTC(CTLVAR, out);
10681 typeloc = out - (char *)stackblock();
10682 USTPUTC(VSNORMAL, out);
10683 subtype = VSNORMAL;
10691 subtype = VSLENGTH;
10695 if (c > PEOA_OR_PEOF && is_name(c)) {
10699 } while (c > PEOA_OR_PEOF && is_in_name(c));
10700 } else if (isdigit(c)) {
10704 } while (isdigit(c));
10705 } else if (is_special(c)) {
10709 badsub: raise_error_syntax("Bad substitution");
10713 if (subtype == 0) {
10717 #if ENABLE_ASH_BASH_COMPAT
10718 if (c == ':' || c == '$' || isdigit(c)) {
10720 subtype = VSSUBSTR;
10727 p = strchr(types, c);
10730 subtype = p - types + VSNORMAL;
10735 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
10743 #if ENABLE_ASH_BASH_COMPAT
10745 subtype = VSREPLACE;
10748 subtype++; /* VSREPLACEALL */
10757 if (dblquote || arinest)
10759 *((char *)stackblock() + typeloc) = subtype | flags;
10760 if (subtype != VSNORMAL) {
10762 if (dblquote || arinest) {
10767 goto parsesub_return;
10771 * Called to parse command substitutions. Newstyle is set if the command
10772 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10773 * list of commands (passed by reference), and savelen is the number of
10774 * characters on the top of the stack which must be preserved.
10777 struct nodelist **nlpp;
10780 char *volatile str;
10781 struct jmploc jmploc;
10782 struct jmploc *volatile savehandler;
10784 smallint saveprompt = 0;
10787 (void) &saveprompt;
10789 savepbq = parsebackquote;
10790 if (setjmp(jmploc.loc)) {
10792 parsebackquote = 0;
10793 exception_handler = savehandler;
10794 longjmp(exception_handler->loc, 1);
10798 savelen = out - (char *)stackblock();
10800 str = ckmalloc(savelen);
10801 memcpy(str, stackblock(), savelen);
10803 savehandler = exception_handler;
10804 exception_handler = &jmploc;
10807 /* We must read until the closing backquote, giving special
10808 treatment to some slashes, and then push the string and
10809 reread it as input, interpreting it normally. */
10816 STARTSTACKSTR(pout);
10833 * If eating a newline, avoid putting
10834 * the newline into the new character
10835 * stream (via the STPUTC after the
10840 if (pc != '\\' && pc != '`' && pc != '$'
10841 && (!dblquote || pc != '"'))
10842 STPUTC('\\', pout);
10843 if (pc > PEOA_OR_PEOF) {
10849 #if ENABLE_ASH_ALIAS
10852 startlinno = plinno;
10853 raise_error_syntax("EOF in backquote substitution");
10857 needprompt = doprompt;
10866 STPUTC('\0', pout);
10867 psavelen = pout - (char *)stackblock();
10868 if (psavelen > 0) {
10869 pstr = grabstackstr(pout);
10870 setinputstring(pstr);
10875 nlpp = &(*nlpp)->next;
10876 *nlpp = stzalloc(sizeof(**nlpp));
10877 /* (*nlpp)->next = NULL; - stzalloc did it */
10878 parsebackquote = oldstyle;
10881 saveprompt = doprompt;
10888 doprompt = saveprompt;
10889 else if (readtoken() != TRP)
10890 raise_error_unexpected_syntax(TRP);
10895 * Start reading from old file again, ignoring any pushed back
10896 * tokens left from the backquote parsing
10901 while (stackblocksize() <= savelen)
10903 STARTSTACKSTR(out);
10905 memcpy(out, str, savelen);
10906 STADJUST(savelen, out);
10912 parsebackquote = savepbq;
10913 exception_handler = savehandler;
10914 if (arinest || dblquote)
10915 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10917 USTPUTC(CTLBACKQ, out);
10919 goto parsebackq_oldreturn;
10920 goto parsebackq_newreturn;
10923 #if ENABLE_ASH_MATH_SUPPORT
10925 * Parse an arithmetic expansion (indicate start of one and set state)
10928 if (++arinest == 1) {
10929 prevsyntax = syntax;
10930 syntax = ARISYNTAX;
10931 USTPUTC(CTLARI, out);
10938 * we collapse embedded arithmetic expansion to
10939 * parenthesis, which should be equivalent
10943 goto parsearith_return;
10947 } /* end of readtoken */
10950 * Read the next input token.
10951 * If the token is a word, we set backquotelist to the list of cmds in
10952 * backquotes. We set quoteflag to true if any part of the word was
10954 * If the token is TREDIR, then we set redirnode to a structure containing
10956 * In all cases, the variable startlinno is set to the number of the line
10957 * on which the token starts.
10959 * [Change comment: here documents and internal procedures]
10960 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10961 * word parsing code into a separate routine. In this case, readtoken
10962 * doesn't need to have any internal procedures, but parseword does.
10963 * We could also make parseoperator in essence the main routine, and
10964 * have parseword (readtoken1?) handle both words and redirection.]
10966 #define NEW_xxreadtoken
10967 #ifdef NEW_xxreadtoken
10968 /* singles must be first! */
10969 static const char xxreadtoken_chars[7] ALIGN1 = {
10970 '\n', '(', ')', '&', '|', ';', 0
10973 static const char xxreadtoken_tokens[] ALIGN1 = {
10974 TNL, TLP, TRP, /* only single occurrence allowed */
10975 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10976 TEOF, /* corresponds to trailing nul */
10977 TAND, TOR, TENDCASE /* if double occurrence */
10980 #define xxreadtoken_doubles \
10981 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10982 #define xxreadtoken_singles \
10983 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10997 startlinno = plinno;
10998 for (;;) { /* until token or start of word found */
11001 if ((c != ' ') && (c != '\t')
11002 #if ENABLE_ASH_ALIAS
11007 while ((c = pgetc()) != '\n' && c != PEOF);
11009 } else if (c == '\\') {
11010 if (pgetc() != '\n') {
11014 startlinno = ++plinno;
11019 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11024 needprompt = doprompt;
11027 p = strchr(xxreadtoken_chars, c);
11030 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11033 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
11034 if (pgetc() == *p) { /* double occurrence? */
11035 p += xxreadtoken_doubles + 1;
11041 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11047 #define RETURN(token) return lasttoken = token
11060 startlinno = plinno;
11061 for (;;) { /* until token or start of word found */
11064 case ' ': case '\t':
11065 #if ENABLE_ASH_ALIAS
11070 while ((c = pgetc()) != '\n' && c != PEOF);
11074 if (pgetc() == '\n') {
11075 startlinno = ++plinno;
11084 needprompt = doprompt;
11089 if (pgetc() == '&')
11094 if (pgetc() == '|')
11099 if (pgetc() == ';')
11112 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11115 #endif /* NEW_xxreadtoken */
11122 smallint alreadyseen = tokpushback;
11125 #if ENABLE_ASH_ALIAS
11134 if (checkkwd & CHKNL) {
11141 if (t != TWORD || quoteflag) {
11146 * check for keywords
11148 if (checkkwd & CHKKWD) {
11149 const char *const *pp;
11151 pp = findkwd(wordtext);
11153 lasttoken = t = pp - tokname_array;
11154 TRACE(("keyword %s recognized\n", tokname(t)));
11159 if (checkkwd & CHKALIAS) {
11160 #if ENABLE_ASH_ALIAS
11162 ap = lookupalias(wordtext, 1);
11165 pushstring(ap->val, ap);
11175 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11177 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11189 return tokname_array[t][0];
11193 * Read and parse a command. Returns NEOF on end of file. (NULL is a
11194 * valid parse tree indicating a blank line.)
11196 static union node *
11197 parsecmd(int interact)
11202 doprompt = interact;
11204 setprompt(doprompt);
11216 * Input any here documents.
11221 struct heredoc *here;
11224 here = heredoclist;
11225 heredoclist = NULL;
11231 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
11232 here->eofmark, here->striptabs);
11233 n = stzalloc(sizeof(struct narg));
11234 n->narg.type = NARG;
11235 /*n->narg.next = NULL; - stzalloc did it */
11236 n->narg.text = wordtext;
11237 n->narg.backquote = backquotelist;
11238 here->here->nhere.doc = n;
11245 * called by editline -- any expansions to the prompt should be added here.
11247 #if ENABLE_ASH_EXPAND_PRMT
11248 static const char *
11249 expandstr(const char *ps)
11253 /* XXX Fix (char *) cast. */
11254 setinputstring((char *)ps);
11255 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
11258 n.narg.type = NARG;
11259 n.narg.next = NULL;
11260 n.narg.text = wordtext;
11261 n.narg.backquote = backquotelist;
11263 expandarg(&n, NULL, 0);
11264 return stackblock();
11269 * Execute a command or commands contained in a string.
11272 evalstring(char *s, int mask)
11275 struct stackmark smark;
11279 setstackmark(&smark);
11282 while ((n = parsecmd(0)) != NEOF) {
11284 popstackmark(&smark);
11297 * The eval command.
11300 evalcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11309 STARTSTACKSTR(concat);
11311 concat = stack_putstr(p, concat);
11315 STPUTC(' ', concat);
11317 STPUTC('\0', concat);
11318 p = grabstackstr(concat);
11320 evalstring(p, ~SKIPEVAL);
11327 * Read and execute commands. "Top" is nonzero for the top level command
11328 * loop; it turns on prompting if the shell is interactive.
11334 struct stackmark smark;
11338 TRACE(("cmdloop(%d) called\n", top));
11342 setstackmark(&smark);
11345 showjobs(stderr, SHOW_CHANGED);
11348 if (iflag && top) {
11350 #if ENABLE_ASH_MAIL
11354 n = parsecmd(inter);
11355 /* showtree(n); DEBUG */
11357 if (!top || numeof >= 50)
11359 if (!stoppedjobs()) {
11362 out2str("\nUse \"exit\" to leave shell.\n");
11365 } else if (nflag == 0) {
11366 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11371 popstackmark(&smark);
11376 return skip & SKIPEVAL;
11383 * Take commands from a file. To be compatible we should do a path
11384 * search for the file, which is necessary to find sub-commands.
11387 find_dot_file(char *name)
11390 const char *path = pathval();
11393 /* don't try this for absolute or relative paths */
11394 if (strchr(name, '/'))
11397 while ((fullname = padvance(&path, name)) != NULL) {
11398 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11400 * Don't bother freeing here, since it will
11401 * be freed by the caller.
11405 stunalloc(fullname);
11408 /* not found in the PATH */
11409 ash_msg_and_raise_error("%s: not found", name);
11414 dotcmd(int argc, char **argv)
11416 struct strlist *sp;
11417 volatile struct shparam saveparam;
11420 for (sp = cmdenviron; sp; sp = sp->next)
11421 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11423 if (argv[1]) { /* That's what SVR2 does */
11424 char *fullname = find_dot_file(argv[1]);
11427 if (argc) { /* argc > 0, argv[0] != NULL */
11428 saveparam = shellparam;
11429 shellparam.malloced = 0;
11430 shellparam.nparam = argc;
11431 shellparam.p = argv;
11434 setinputfile(fullname, INPUT_PUSH_FILE);
11435 commandname = fullname;
11440 freeparam(&shellparam);
11441 shellparam = saveparam;
11443 status = exitstatus;
11449 exitcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11454 exitstatus = number(argv[1]);
11455 raise_exception(EXEXIT);
11459 #if ENABLE_ASH_BUILTIN_ECHO
11461 echocmd(int argc, char **argv)
11463 return echo_main(argc, argv);
11467 #if ENABLE_ASH_BUILTIN_TEST
11469 testcmd(int argc, char **argv)
11471 return test_main(argc, argv);
11476 * Read a file containing shell functions.
11479 readcmdfile(char *name)
11481 setinputfile(name, INPUT_PUSH_FILE);
11487 /* ============ find_command inplementation */
11490 * Resolve a command name. If you change this routine, you may have to
11491 * change the shellexec routine as well.
11494 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11496 struct tblentry *cmdp;
11503 struct builtincmd *bcmd;
11505 /* If name contains a slash, don't use PATH or hash table */
11506 if (strchr(name, '/') != NULL) {
11507 entry->u.index = -1;
11508 if (act & DO_ABS) {
11509 while (stat(name, &statb) < 0) {
11511 if (errno == EINTR)
11514 entry->cmdtype = CMDUNKNOWN;
11518 entry->cmdtype = CMDNORMAL;
11522 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11524 updatetbl = (path == pathval());
11527 if (strstr(path, "%builtin") != NULL)
11528 act |= DO_ALTBLTIN;
11531 /* If name is in the table, check answer will be ok */
11532 cmdp = cmdlookup(name, 0);
11533 if (cmdp != NULL) {
11536 switch (cmdp->cmdtype) {
11554 } else if (cmdp->rehash == 0)
11555 /* if not invalidated by cd, we're done */
11559 /* If %builtin not in path, check for builtin next */
11560 bcmd = find_builtin(name);
11562 if (IS_BUILTIN_REGULAR(bcmd))
11563 goto builtin_success;
11564 if (act & DO_ALTPATH) {
11565 if (!(act & DO_ALTBLTIN))
11566 goto builtin_success;
11567 } else if (builtinloc <= 0) {
11568 goto builtin_success;
11572 #if ENABLE_FEATURE_SH_STANDALONE
11573 if (find_applet_by_name(name) >= 0) {
11574 entry->cmdtype = CMDNORMAL;
11575 entry->u.index = -1;
11580 /* We have to search path. */
11581 prev = -1; /* where to start */
11582 if (cmdp && cmdp->rehash) { /* doing a rehash */
11583 if (cmdp->cmdtype == CMDBUILTIN)
11586 prev = cmdp->param.index;
11592 while ((fullname = padvance(&path, name)) != NULL) {
11593 stunalloc(fullname);
11594 /* NB: code below will still use fullname
11595 * despite it being "unallocated" */
11598 if (prefix(pathopt, "builtin")) {
11600 goto builtin_success;
11602 } else if (!(act & DO_NOFUNC)
11603 && prefix(pathopt, "func")) {
11604 /* handled below */
11606 /* ignore unimplemented options */
11610 /* if rehash, don't redo absolute path names */
11611 if (fullname[0] == '/' && idx <= prev) {
11614 TRACE(("searchexec \"%s\": no change\n", name));
11617 while (stat(fullname, &statb) < 0) {
11619 if (errno == EINTR)
11622 if (errno != ENOENT && errno != ENOTDIR)
11626 e = EACCES; /* if we fail, this will be the error */
11627 if (!S_ISREG(statb.st_mode))
11629 if (pathopt) { /* this is a %func directory */
11630 stalloc(strlen(fullname) + 1);
11631 /* NB: stalloc will return space pointed by fullname
11632 * (because we don't have any intervening allocations
11633 * between stunalloc above and this stalloc) */
11634 readcmdfile(fullname);
11635 cmdp = cmdlookup(name, 0);
11636 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
11637 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
11638 stunalloc(fullname);
11641 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
11643 entry->cmdtype = CMDNORMAL;
11644 entry->u.index = idx;
11648 cmdp = cmdlookup(name, 1);
11649 cmdp->cmdtype = CMDNORMAL;
11650 cmdp->param.index = idx;
11655 /* We failed. If there was an entry for this command, delete it */
11656 if (cmdp && updatetbl)
11657 delete_cmd_entry();
11659 ash_msg("%s: %s", name, errmsg(e, "not found"));
11660 entry->cmdtype = CMDUNKNOWN;
11665 entry->cmdtype = CMDBUILTIN;
11666 entry->u.cmd = bcmd;
11670 cmdp = cmdlookup(name, 1);
11671 cmdp->cmdtype = CMDBUILTIN;
11672 cmdp->param.cmd = bcmd;
11676 entry->cmdtype = cmdp->cmdtype;
11677 entry->u = cmdp->param;
11681 /* ============ trap.c */
11684 * The trap builtin.
11687 trapcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11696 for (signo = 0; signo < NSIG; signo++) {
11697 if (trap[signo] != NULL) {
11700 sn = get_signame(signo);
11701 out1fmt("trap -- %s %s\n",
11702 single_quote(trap[signo]), sn);
11712 signo = get_signum(*ap);
11714 ash_msg_and_raise_error("%s: bad trap", *ap);
11717 if (LONE_DASH(action))
11720 action = ckstrdup(action);
11723 trap[signo] = action;
11733 /* ============ Builtins */
11735 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
11737 * Lists available builtins
11740 helpcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11744 out1fmt("\nBuilt-in commands:\n-------------------\n");
11745 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
11746 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11747 builtintab[i].name + 1);
11753 #if ENABLE_FEATURE_SH_STANDALONE
11755 const char *a = applet_names;
11757 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
11762 a += strlen(a) + 1;
11767 return EXIT_SUCCESS;
11769 #endif /* FEATURE_SH_EXTRA_QUIET */
11772 * The export and readonly commands.
11775 exportcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11781 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
11783 if (nextopt("p") != 'p') {
11788 p = strchr(name, '=');
11792 vp = *findvar(hashvar(name), name);
11798 setvar(name, p, flag);
11799 } while ((name = *++aptr) != NULL);
11803 showvars(argv[0], flag, 0);
11808 * Delete a function if it exists.
11811 unsetfunc(const char *name)
11813 struct tblentry *cmdp;
11815 cmdp = cmdlookup(name, 0);
11816 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
11817 delete_cmd_entry();
11821 * The unset builtin command. We unset the function before we unset the
11822 * variable to allow a function to be unset when there is a readonly variable
11823 * with the same name.
11826 unsetcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11833 while ((i = nextopt("vf")) != '\0') {
11837 for (ap = argptr; *ap; ap++) {
11853 #include <sys/times.h>
11855 static const unsigned char timescmd_str[] ALIGN1 = {
11856 ' ', offsetof(struct tms, tms_utime),
11857 '\n', offsetof(struct tms, tms_stime),
11858 ' ', offsetof(struct tms, tms_cutime),
11859 '\n', offsetof(struct tms, tms_cstime),
11864 timescmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11866 long clk_tck, s, t;
11867 const unsigned char *p;
11870 clk_tck = sysconf(_SC_CLK_TCK);
11875 t = *(clock_t *)(((char *) &buf) + p[1]);
11877 out1fmt("%ldm%ld.%.3lds%c",
11879 ((t - s * clk_tck) * 1000) / clk_tck,
11881 } while (*(p += 2));
11886 #if ENABLE_ASH_MATH_SUPPORT
11888 dash_arith(const char *s)
11894 result = arith(s, &errcode);
11897 ash_msg_and_raise_error("exponent less than 0");
11899 ash_msg_and_raise_error("divide by zero");
11901 ash_msg_and_raise_error("expression recursion loop detected");
11902 raise_error_syntax(s);
11910 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
11911 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
11913 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
11916 letcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11922 ash_msg_and_raise_error("expression expected");
11924 i = dash_arith(*argv);
11929 #endif /* ASH_MATH_SUPPORT */
11932 /* ============ miscbltin.c
11934 * Miscellaneous builtins.
11939 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
11940 typedef enum __rlimit_resource rlim_t;
11944 * The read builtin. Options:
11945 * -r Do not interpret '\' specially
11946 * -s Turn off echo (tty only)
11947 * -n NCHARS Read NCHARS max
11948 * -p PROMPT Display PROMPT on stderr (if input is from tty)
11949 * -t SECONDS Timeout after SECONDS (tty or pipe only)
11950 * -u FD Read from given FD instead of fd 0
11951 * This uses unbuffered input, which may be avoidable in some cases.
11952 * TODO: bash also has:
11953 * -a ARRAY Read into array[0],[1],etc
11954 * -d DELIM End on DELIM char, not newline
11955 * -e Use line editing (tty only)
11958 readcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11971 #if ENABLE_ASH_READ_NCHARS
11972 int nchars = 0; /* if != 0, -n is in effect */
11974 struct termios tty, old_tty;
11976 #if ENABLE_ASH_READ_TIMEOUT
11977 unsigned end_ms = 0;
11978 unsigned timeout = 0;
11983 while ((i = nextopt("p:u:r"
11984 USE_ASH_READ_TIMEOUT("t:")
11985 USE_ASH_READ_NCHARS("n:s")
11989 prompt = optionarg;
11991 #if ENABLE_ASH_READ_NCHARS
11993 nchars = bb_strtou(optionarg, NULL, 10);
11994 if (nchars < 0 || errno)
11995 ash_msg_and_raise_error("invalid count");
11996 /* nchars == 0: off (bash 3.2 does this too) */
12002 #if ENABLE_ASH_READ_TIMEOUT
12004 timeout = bb_strtou(optionarg, NULL, 10);
12005 if (errno || timeout > UINT_MAX / 2048)
12006 ash_msg_and_raise_error("invalid timeout");
12008 #if 0 /* even bash have no -t N.NNN support */
12009 ts.tv_sec = bb_strtou(optionarg, &p, 10);
12011 /* EINVAL means number is ok, but not terminated by NUL */
12012 if (*p == '.' && errno == EINVAL) {
12016 ts.tv_usec = bb_strtou(p, &p2, 10);
12018 ash_msg_and_raise_error("invalid timeout");
12020 /* normalize to usec */
12022 ash_msg_and_raise_error("invalid timeout");
12023 while (scale++ < 6)
12026 } else if (ts.tv_sec < 0 || errno) {
12027 ash_msg_and_raise_error("invalid timeout");
12029 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
12030 ash_msg_and_raise_error("invalid timeout");
12039 fd = bb_strtou(optionarg, NULL, 10);
12040 if (fd < 0 || errno)
12041 ash_msg_and_raise_error("invalid file descriptor");
12047 if (prompt && isatty(fd)) {
12052 ash_msg_and_raise_error("arg count");
12053 ifs = bltinlookup("IFS");
12056 #if ENABLE_ASH_READ_NCHARS
12057 tcgetattr(fd, &tty);
12059 if (nchars || silent) {
12061 tty.c_lflag &= ~ICANON;
12062 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
12065 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
12067 /* if tcgetattr failed, tcsetattr will fail too.
12068 * Ignoring, it's harmless. */
12069 tcsetattr(fd, TCSANOW, &tty);
12076 #if ENABLE_ASH_READ_TIMEOUT
12077 if (timeout) /* NB: ensuring end_ms is nonzero */
12078 end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1;
12082 #if ENABLE_ASH_READ_TIMEOUT
12084 struct pollfd pfd[1];
12086 pfd[0].events = POLLIN;
12087 timeout = end_ms - (unsigned)(monotonic_us() / 1000);
12088 if ((int)timeout <= 0 /* already late? */
12089 || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
12090 ) { /* timed out! */
12091 #if ENABLE_ASH_READ_NCHARS
12092 tcsetattr(fd, TCSANOW, &old_tty);
12098 if (nonblock_safe_read(fd, &c, 1) != 1) {
12110 if (!rflag && c == '\\') {
12116 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12120 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12122 setvar(*ap, stackblock(), 0);
12131 /* end of do {} while: */
12132 #if ENABLE_ASH_READ_NCHARS
12138 #if ENABLE_ASH_READ_NCHARS
12139 tcsetattr(fd, TCSANOW, &old_tty);
12143 /* Remove trailing blanks */
12144 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12146 setvar(*ap, stackblock(), 0);
12147 while (*++ap != NULL)
12148 setvar(*ap, nullstr, 0);
12153 umaskcmd(int argc ATTRIBUTE_UNUSED, char **argv)
12155 static const char permuser[3] ALIGN1 = "ugo";
12156 static const char permmode[3] ALIGN1 = "rwx";
12157 static const short permmask[] ALIGN2 = {
12158 S_IRUSR, S_IWUSR, S_IXUSR,
12159 S_IRGRP, S_IWGRP, S_IXGRP,
12160 S_IROTH, S_IWOTH, S_IXOTH
12166 int symbolic_mode = 0;
12168 while (nextopt("S") != '\0') {
12179 if (symbolic_mode) {
12183 for (i = 0; i < 3; i++) {
12186 *p++ = permuser[i];
12188 for (j = 0; j < 3; j++) {
12189 if ((mask & permmask[3 * i + j]) == 0) {
12190 *p++ = permmode[j];
12198 out1fmt("%.4o\n", mask);
12201 if (isdigit((unsigned char) *ap)) {
12204 if (*ap >= '8' || *ap < '0')
12205 ash_msg_and_raise_error(illnum, argv[1]);
12206 mask = (mask << 3) + (*ap - '0');
12207 } while (*++ap != '\0');
12210 mask = ~mask & 0777;
12211 if (!bb_parse_mode(ap, &mask)) {
12212 ash_msg_and_raise_error("illegal mode: %s", ap);
12214 umask(~mask & 0777);
12223 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12224 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12225 * ash by J.T. Conklin.
12231 uint8_t cmd; /* RLIMIT_xxx fit into it */
12232 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
12236 static const struct limits limits_tbl[] = {
12238 { RLIMIT_CPU, 0, 't' },
12240 #ifdef RLIMIT_FSIZE
12241 { RLIMIT_FSIZE, 9, 'f' },
12244 { RLIMIT_DATA, 10, 'd' },
12246 #ifdef RLIMIT_STACK
12247 { RLIMIT_STACK, 10, 's' },
12250 { RLIMIT_CORE, 9, 'c' },
12253 { RLIMIT_RSS, 10, 'm' },
12255 #ifdef RLIMIT_MEMLOCK
12256 { RLIMIT_MEMLOCK, 10, 'l' },
12258 #ifdef RLIMIT_NPROC
12259 { RLIMIT_NPROC, 0, 'p' },
12261 #ifdef RLIMIT_NOFILE
12262 { RLIMIT_NOFILE, 0, 'n' },
12265 { RLIMIT_AS, 10, 'v' },
12267 #ifdef RLIMIT_LOCKS
12268 { RLIMIT_LOCKS, 0, 'w' },
12271 static const char limits_name[] =
12273 "time(seconds)" "\0"
12275 #ifdef RLIMIT_FSIZE
12276 "file(blocks)" "\0"
12281 #ifdef RLIMIT_STACK
12285 "coredump(blocks)" "\0"
12290 #ifdef RLIMIT_MEMLOCK
12291 "locked memory(kb)" "\0"
12293 #ifdef RLIMIT_NPROC
12296 #ifdef RLIMIT_NOFILE
12302 #ifdef RLIMIT_LOCKS
12307 enum limtype { SOFT = 0x1, HARD = 0x2 };
12310 printlim(enum limtype how, const struct rlimit *limit,
12311 const struct limits *l)
12315 val = limit->rlim_max;
12317 val = limit->rlim_cur;
12319 if (val == RLIM_INFINITY)
12320 out1fmt("unlimited\n");
12322 val >>= l->factor_shift;
12323 out1fmt("%lld\n", (long long) val);
12328 ulimitcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
12332 enum limtype how = SOFT | HARD;
12333 const struct limits *l;
12336 struct rlimit limit;
12339 while ((optc = nextopt("HSa"
12343 #ifdef RLIMIT_FSIZE
12349 #ifdef RLIMIT_STACK
12358 #ifdef RLIMIT_MEMLOCK
12361 #ifdef RLIMIT_NPROC
12364 #ifdef RLIMIT_NOFILE
12370 #ifdef RLIMIT_LOCKS
12388 for (l = limits_tbl; l->option != what; l++)
12391 set = *argptr ? 1 : 0;
12395 if (all || argptr[1])
12396 ash_msg_and_raise_error("too many arguments");
12397 if (strncmp(p, "unlimited\n", 9) == 0)
12398 val = RLIM_INFINITY;
12402 while ((c = *p++) >= '0' && c <= '9') {
12403 val = (val * 10) + (long)(c - '0');
12404 if (val < (rlim_t) 0)
12408 ash_msg_and_raise_error("bad number");
12409 val <<= l->factor_shift;
12413 const char *lname = limits_name;
12414 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12415 getrlimit(l->cmd, &limit);
12416 out1fmt("%-20s ", lname);
12417 lname += strlen(lname) + 1;
12418 printlim(how, &limit, l);
12423 getrlimit(l->cmd, &limit);
12426 limit.rlim_max = val;
12428 limit.rlim_cur = val;
12429 if (setrlimit(l->cmd, &limit) < 0)
12430 ash_msg_and_raise_error("error setting limit (%m)");
12432 printlim(how, &limit, l);
12438 /* ============ Math support */
12440 #if ENABLE_ASH_MATH_SUPPORT
12442 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12444 Permission is hereby granted, free of charge, to any person obtaining
12445 a copy of this software and associated documentation files (the
12446 "Software"), to deal in the Software without restriction, including
12447 without limitation the rights to use, copy, modify, merge, publish,
12448 distribute, sublicense, and/or sell copies of the Software, and to
12449 permit persons to whom the Software is furnished to do so, subject to
12450 the following conditions:
12452 The above copyright notice and this permission notice shall be
12453 included in all copies or substantial portions of the Software.
12455 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12456 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12457 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12458 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12459 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12460 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12461 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12464 /* This is my infix parser/evaluator. It is optimized for size, intended
12465 * as a replacement for yacc-based parsers. However, it may well be faster
12466 * than a comparable parser written in yacc. The supported operators are
12467 * listed in #defines below. Parens, order of operations, and error handling
12468 * are supported. This code is thread safe. The exact expression format should
12469 * be that which POSIX specifies for shells. */
12471 /* The code uses a simple two-stack algorithm. See
12472 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12473 * for a detailed explanation of the infix-to-postfix algorithm on which
12474 * this is based (this code differs in that it applies operators immediately
12475 * to the stack instead of adding them to a queue to end up with an
12478 /* To use the routine, call it with an expression string and error return
12482 * Aug 24, 2001 Manuel Novoa III
12484 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12486 * 1) In arith_apply():
12487 * a) Cached values of *numptr and &(numptr[-1]).
12488 * b) Removed redundant test for zero denominator.
12491 * a) Eliminated redundant code for processing operator tokens by moving
12492 * to a table-based implementation. Also folded handling of parens
12494 * b) Combined all 3 loops which called arith_apply to reduce generated
12495 * code size at the cost of speed.
12497 * 3) The following expressions were treated as valid by the original code:
12498 * 1() , 0! , 1 ( *3 ) .
12499 * These bugs have been fixed by internally enclosing the expression in
12500 * parens and then checking that all binary ops and right parens are
12501 * preceded by a valid expression (NUM_TOKEN).
12503 * Note: It may be desirable to replace Aaron's test for whitespace with
12504 * ctype's isspace() if it is used by another busybox applet or if additional
12505 * whitespace chars should be considered. Look below the "#include"s for a
12506 * precompiler test.
12510 * Aug 26, 2001 Manuel Novoa III
12512 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12514 * Merge in Aaron's comments previously posted to the busybox list,
12515 * modified slightly to take account of my changes to the code.
12520 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12522 * - allow access to variable,
12523 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12524 * - realize assign syntax (VAR=expr, +=, *= etc)
12525 * - realize exponentiation (** operator)
12526 * - realize comma separated - expr, expr
12527 * - realise ++expr --expr expr++ expr--
12528 * - realise expr ? expr : expr (but, second expr calculate always)
12529 * - allow hexadecimal and octal numbers
12530 * - was restored loses XOR operator
12531 * - remove one goto label, added three ;-)
12532 * - protect $((num num)) as true zero expr (Manuel`s error)
12533 * - always use special isspace(), see comment from bash ;-)
12536 #define arith_isspace(arithval) \
12537 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12539 typedef unsigned char operator;
12541 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12542 * precedence, and 3 high bits are an ID unique across operators of that
12543 * precedence. The ID portion is so that multiple operators can have the
12544 * same precedence, ensuring that the leftmost one is evaluated first.
12545 * Consider * and /. */
12547 #define tok_decl(prec,id) (((id)<<5)|(prec))
12548 #define PREC(op) ((op) & 0x1F)
12550 #define TOK_LPAREN tok_decl(0,0)
12552 #define TOK_COMMA tok_decl(1,0)
12554 #define TOK_ASSIGN tok_decl(2,0)
12555 #define TOK_AND_ASSIGN tok_decl(2,1)
12556 #define TOK_OR_ASSIGN tok_decl(2,2)
12557 #define TOK_XOR_ASSIGN tok_decl(2,3)
12558 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12559 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12560 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12561 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12563 #define TOK_MUL_ASSIGN tok_decl(3,0)
12564 #define TOK_DIV_ASSIGN tok_decl(3,1)
12565 #define TOK_REM_ASSIGN tok_decl(3,2)
12567 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12568 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12570 /* conditional is right associativity too */
12571 #define TOK_CONDITIONAL tok_decl(4,0)
12572 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12574 #define TOK_OR tok_decl(5,0)
12576 #define TOK_AND tok_decl(6,0)
12578 #define TOK_BOR tok_decl(7,0)
12580 #define TOK_BXOR tok_decl(8,0)
12582 #define TOK_BAND tok_decl(9,0)
12584 #define TOK_EQ tok_decl(10,0)
12585 #define TOK_NE tok_decl(10,1)
12587 #define TOK_LT tok_decl(11,0)
12588 #define TOK_GT tok_decl(11,1)
12589 #define TOK_GE tok_decl(11,2)
12590 #define TOK_LE tok_decl(11,3)
12592 #define TOK_LSHIFT tok_decl(12,0)
12593 #define TOK_RSHIFT tok_decl(12,1)
12595 #define TOK_ADD tok_decl(13,0)
12596 #define TOK_SUB tok_decl(13,1)
12598 #define TOK_MUL tok_decl(14,0)
12599 #define TOK_DIV tok_decl(14,1)
12600 #define TOK_REM tok_decl(14,2)
12602 /* exponent is right associativity */
12603 #define TOK_EXPONENT tok_decl(15,1)
12605 /* For now unary operators. */
12606 #define UNARYPREC 16
12607 #define TOK_BNOT tok_decl(UNARYPREC,0)
12608 #define TOK_NOT tok_decl(UNARYPREC,1)
12610 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12611 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12613 #define PREC_PRE (UNARYPREC+2)
12615 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12616 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12618 #define PREC_POST (UNARYPREC+3)
12620 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12621 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12623 #define SPEC_PREC (UNARYPREC+4)
12625 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12626 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12628 #define NUMPTR (*numstackptr)
12631 tok_have_assign(operator op)
12633 operator prec = PREC(op);
12635 convert_prec_is_assing(prec);
12636 return (prec == PREC(TOK_ASSIGN) ||
12637 prec == PREC_PRE || prec == PREC_POST);
12641 is_right_associativity(operator prec)
12643 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
12644 || prec == PREC(TOK_CONDITIONAL));
12647 typedef struct ARITCH_VAR_NUM {
12649 arith_t contidional_second_val;
12650 char contidional_second_val_initialized;
12651 char *var; /* if NULL then is regular number,
12652 else is variable name */
12655 typedef struct CHK_VAR_RECURSIVE_LOOPED {
12657 struct CHK_VAR_RECURSIVE_LOOPED *next;
12658 } chk_var_recursive_looped_t;
12660 static chk_var_recursive_looped_t *prev_chk_var_recursive;
12663 arith_lookup_val(v_n_t *t)
12666 const char * p = lookupvar(t->var);
12671 /* recursive try as expression */
12672 chk_var_recursive_looped_t *cur;
12673 chk_var_recursive_looped_t cur_save;
12675 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
12676 if (strcmp(cur->var, t->var) == 0) {
12677 /* expression recursion loop detected */
12681 /* save current lookuped var name */
12682 cur = prev_chk_var_recursive;
12683 cur_save.var = t->var;
12684 cur_save.next = cur;
12685 prev_chk_var_recursive = &cur_save;
12687 t->val = arith (p, &errcode);
12688 /* restore previous ptr after recursiving */
12689 prev_chk_var_recursive = cur;
12692 /* allow undefined var as 0 */
12698 /* "applying" a token means performing it on the top elements on the integer
12699 * stack. For a unary operator it will only change the top element, but a
12700 * binary operator will pop two arguments and push a result */
12702 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
12705 arith_t numptr_val, rez;
12706 int ret_arith_lookup_val;
12708 /* There is no operator that can work without arguments */
12709 if (NUMPTR == numstack) goto err;
12710 numptr_m1 = NUMPTR - 1;
12712 /* check operand is var with noninteger value */
12713 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12714 if (ret_arith_lookup_val)
12715 return ret_arith_lookup_val;
12717 rez = numptr_m1->val;
12718 if (op == TOK_UMINUS)
12720 else if (op == TOK_NOT)
12722 else if (op == TOK_BNOT)
12724 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
12726 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
12728 else if (op != TOK_UPLUS) {
12729 /* Binary operators */
12731 /* check and binary operators need two arguments */
12732 if (numptr_m1 == numstack) goto err;
12734 /* ... and they pop one */
12737 if (op == TOK_CONDITIONAL) {
12738 if (! numptr_m1->contidional_second_val_initialized) {
12739 /* protect $((expr1 ? expr2)) without ": expr" */
12742 rez = numptr_m1->contidional_second_val;
12743 } else if (numptr_m1->contidional_second_val_initialized) {
12744 /* protect $((expr1 : expr2)) without "expr ? " */
12747 numptr_m1 = NUMPTR - 1;
12748 if (op != TOK_ASSIGN) {
12749 /* check operand is var with noninteger value for not '=' */
12750 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12751 if (ret_arith_lookup_val)
12752 return ret_arith_lookup_val;
12754 if (op == TOK_CONDITIONAL) {
12755 numptr_m1->contidional_second_val = rez;
12757 rez = numptr_m1->val;
12758 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
12760 else if (op == TOK_OR)
12761 rez = numptr_val || rez;
12762 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
12764 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
12766 else if (op == TOK_AND)
12767 rez = rez && numptr_val;
12768 else if (op == TOK_EQ)
12769 rez = (rez == numptr_val);
12770 else if (op == TOK_NE)
12771 rez = (rez != numptr_val);
12772 else if (op == TOK_GE)
12773 rez = (rez >= numptr_val);
12774 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
12775 rez >>= numptr_val;
12776 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
12777 rez <<= numptr_val;
12778 else if (op == TOK_GT)
12779 rez = (rez > numptr_val);
12780 else if (op == TOK_LT)
12781 rez = (rez < numptr_val);
12782 else if (op == TOK_LE)
12783 rez = (rez <= numptr_val);
12784 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
12786 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
12788 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
12790 else if (op == TOK_ASSIGN || op == TOK_COMMA)
12792 else if (op == TOK_CONDITIONAL_SEP) {
12793 if (numptr_m1 == numstack) {
12794 /* protect $((expr : expr)) without "expr ? " */
12797 numptr_m1->contidional_second_val_initialized = op;
12798 numptr_m1->contidional_second_val = numptr_val;
12799 } else if (op == TOK_CONDITIONAL) {
12801 numptr_val : numptr_m1->contidional_second_val;
12802 } else if (op == TOK_EXPONENT) {
12803 if (numptr_val < 0)
12804 return -3; /* exponent less than 0 */
12809 while (numptr_val--)
12813 } else if (numptr_val==0) /* zero divisor check */
12815 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
12817 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
12820 if (tok_have_assign(op)) {
12821 char buf[sizeof(arith_t_type)*3 + 2];
12823 if (numptr_m1->var == NULL) {
12827 /* save to shell variable */
12828 #if ENABLE_ASH_MATH_SUPPORT_64
12829 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
12831 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
12833 setvar(numptr_m1->var, buf, 0);
12834 /* after saving, make previous value for v++ or v-- */
12835 if (op == TOK_POST_INC)
12837 else if (op == TOK_POST_DEC)
12840 numptr_m1->val = rez;
12841 /* protect geting var value, is number now */
12842 numptr_m1->var = NULL;
12848 /* longest must be first */
12849 static const char op_tokens[] ALIGN1 = {
12850 '<','<','=',0, TOK_LSHIFT_ASSIGN,
12851 '>','>','=',0, TOK_RSHIFT_ASSIGN,
12852 '<','<', 0, TOK_LSHIFT,
12853 '>','>', 0, TOK_RSHIFT,
12854 '|','|', 0, TOK_OR,
12855 '&','&', 0, TOK_AND,
12856 '!','=', 0, TOK_NE,
12857 '<','=', 0, TOK_LE,
12858 '>','=', 0, TOK_GE,
12859 '=','=', 0, TOK_EQ,
12860 '|','=', 0, TOK_OR_ASSIGN,
12861 '&','=', 0, TOK_AND_ASSIGN,
12862 '*','=', 0, TOK_MUL_ASSIGN,
12863 '/','=', 0, TOK_DIV_ASSIGN,
12864 '%','=', 0, TOK_REM_ASSIGN,
12865 '+','=', 0, TOK_PLUS_ASSIGN,
12866 '-','=', 0, TOK_MINUS_ASSIGN,
12867 '-','-', 0, TOK_POST_DEC,
12868 '^','=', 0, TOK_XOR_ASSIGN,
12869 '+','+', 0, TOK_POST_INC,
12870 '*','*', 0, TOK_EXPONENT,
12874 '=', 0, TOK_ASSIGN,
12886 '?', 0, TOK_CONDITIONAL,
12887 ':', 0, TOK_CONDITIONAL_SEP,
12888 ')', 0, TOK_RPAREN,
12889 '(', 0, TOK_LPAREN,
12893 #define endexpression (&op_tokens[sizeof(op_tokens)-7])
12896 arith(const char *expr, int *perrcode)
12898 char arithval; /* Current character under analysis */
12899 operator lasttok, op;
12902 const char *p = endexpression;
12905 size_t datasizes = strlen(expr) + 2;
12907 /* Stack of integers */
12908 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
12909 * in any given correct or incorrect expression is left as an exercise to
12911 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
12912 *numstackptr = numstack;
12913 /* Stack of operator tokens */
12914 operator *stack = alloca((datasizes) * sizeof(operator)),
12917 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
12918 *perrcode = errcode = 0;
12922 if (arithval == 0) {
12923 if (p == endexpression) {
12924 /* Null expression. */
12928 /* This is only reached after all tokens have been extracted from the
12929 * input stream. If there are still tokens on the operator stack, they
12930 * are to be applied in order. At the end, there should be a final
12931 * result on the integer stack */
12933 if (expr != endexpression + 1) {
12934 /* If we haven't done so already, */
12935 /* append a closing right paren */
12936 expr = endexpression;
12937 /* and let the loop process it. */
12940 /* At this point, we're done with the expression. */
12941 if (numstackptr != numstack+1) {
12942 /* ... but if there isn't, it's bad */
12944 return (*perrcode = -1);
12946 if (numstack->var) {
12947 /* expression is $((var)) only, lookup now */
12948 errcode = arith_lookup_val(numstack);
12951 *perrcode = errcode;
12952 return numstack->val;
12955 /* Continue processing the expression. */
12956 if (arith_isspace(arithval)) {
12957 /* Skip whitespace */
12960 p = endofname(expr);
12962 size_t var_name_size = (p-expr) + 1; /* trailing zero */
12964 numstackptr->var = alloca(var_name_size);
12965 safe_strncpy(numstackptr->var, expr, var_name_size);
12968 numstackptr->contidional_second_val_initialized = 0;
12973 if (isdigit(arithval)) {
12974 numstackptr->var = NULL;
12975 #if ENABLE_ASH_MATH_SUPPORT_64
12976 numstackptr->val = strtoll(expr, (char **) &expr, 0);
12978 numstackptr->val = strtol(expr, (char **) &expr, 0);
12982 for (p = op_tokens; ; p++) {
12986 /* strange operator not found */
12989 for (o = expr; *p && *o == *p; p++)
12996 /* skip tail uncompared token */
12999 /* skip zero delim */
13004 /* post grammar: a++ reduce to num */
13005 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13008 /* Plus and minus are binary (not unary) _only_ if the last
13009 * token was as number, or a right paren (which pretends to be
13010 * a number, since it evaluates to one). Think about it.
13011 * It makes sense. */
13012 if (lasttok != TOK_NUM) {
13028 /* We don't want a unary operator to cause recursive descent on the
13029 * stack, because there can be many in a row and it could cause an
13030 * operator to be evaluated before its argument is pushed onto the
13031 * integer stack. */
13032 /* But for binary operators, "apply" everything on the operator
13033 * stack until we find an operator with a lesser priority than the
13034 * one we have just extracted. */
13035 /* Left paren is given the lowest priority so it will never be
13036 * "applied" in this way.
13037 * if associativity is right and priority eq, applied also skip
13040 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13041 /* not left paren or unary */
13042 if (lasttok != TOK_NUM) {
13043 /* binary op must be preceded by a num */
13046 while (stackptr != stack) {
13047 if (op == TOK_RPAREN) {
13048 /* The algorithm employed here is simple: while we don't
13049 * hit an open paren nor the bottom of the stack, pop
13050 * tokens and apply them */
13051 if (stackptr[-1] == TOK_LPAREN) {
13053 /* Any operator directly after a */
13055 /* close paren should consider itself binary */
13059 operator prev_prec = PREC(stackptr[-1]);
13061 convert_prec_is_assing(prec);
13062 convert_prec_is_assing(prev_prec);
13063 if (prev_prec < prec)
13065 /* check right assoc */
13066 if (prev_prec == prec && is_right_associativity(prec))
13069 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13070 if (errcode) goto ret;
13072 if (op == TOK_RPAREN) {
13077 /* Push this operator to the stack and remember it. */
13078 *stackptr++ = lasttok = op;
13083 #endif /* ASH_MATH_SUPPORT */
13086 /* ============ main() and helpers */
13089 * Called to exit the shell.
13091 static void exitshell(void) ATTRIBUTE_NORETURN;
13099 status = exitstatus;
13100 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13101 if (setjmp(loc.loc)) {
13102 if (exception == EXEXIT)
13103 /* dash bug: it just does _exit(exitstatus) here
13104 * but we have to do setjobctl(0) first!
13105 * (bug is still not fixed in dash-0.5.3 - if you run dash
13106 * under Midnight Commander, on exit from dash MC is backgrounded) */
13107 status = exitstatus;
13110 exception_handler = &loc;
13116 flush_stdout_stderr();
13126 /* from input.c: */
13127 basepf.nextc = basepf.buf = basebuf;
13130 signal(SIGCHLD, SIG_DFL);
13135 char ppid[sizeof(int)*3 + 1];
13137 struct stat st1, st2;
13140 for (envp = environ; envp && *envp; envp++) {
13141 if (strchr(*envp, '=')) {
13142 setvareq(*envp, VEXPORT|VTEXTFIXED);
13146 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
13147 setvar("PPID", ppid, 0);
13149 p = lookupvar("PWD");
13151 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
13152 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
13159 * Process the shell command line arguments.
13162 procargs(char **argv)
13165 const char *xminusc;
13170 /* if (xargv[0]) - mmm, this is always true! */
13172 for (i = 0; i < NOPTS; i++)
13176 /* it already printed err message */
13177 raise_exception(EXERROR);
13181 if (*xargv == NULL) {
13183 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13186 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13190 for (i = 0; i < NOPTS; i++)
13191 if (optlist[i] == 2)
13196 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13201 } else if (!sflag) {
13202 setinputfile(*xargv, 0);
13205 commandname = arg0;
13208 shellparam.p = xargv;
13209 #if ENABLE_ASH_GETOPTS
13210 shellparam.optind = 1;
13211 shellparam.optoff = -1;
13213 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13215 shellparam.nparam++;
13222 * Read /etc/profile or .profile.
13225 read_profile(const char *name)
13229 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13238 * This routine is called when an error or an interrupt occurs in an
13239 * interactive shell and control is returned to the main command loop.
13247 /* from input.c: */
13248 parselleft = parsenleft = 0; /* clear input buffer */
13250 /* from parser.c: */
13253 /* from redir.c: */
13258 static short profile_buf[16384];
13259 extern int etext();
13263 * Main routine. We initialize things, parse the arguments, execute
13264 * profiles if we're a login shell, and then call cmdloop to execute
13265 * commands. The setjmp call sets up the location to jump to when an
13266 * exception occurs. When an exception occurs the variable "state"
13267 * is used to figure out how far we had gotten.
13269 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13270 int ash_main(int argc ATTRIBUTE_UNUSED, char **argv)
13273 volatile int state;
13274 struct jmploc jmploc;
13275 struct stackmark smark;
13277 /* Initialize global data */
13281 #if ENABLE_ASH_ALIAS
13287 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13290 #if ENABLE_FEATURE_EDITING
13291 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13294 if (setjmp(jmploc.loc)) {
13304 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13308 outcslow('\n', stderr);
13310 popstackmark(&smark);
13311 FORCE_INT_ON; /* enable interrupts */
13320 exception_handler = &jmploc;
13323 trace_puts("Shell args: ");
13324 trace_puts_args(argv);
13326 rootpid = getpid();
13328 #if ENABLE_ASH_RANDOM_SUPPORT
13329 rseed = rootpid + time(NULL);
13332 setstackmark(&smark);
13335 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13337 const char *hp = lookupvar("HISTFILE");
13340 hp = lookupvar("HOME");
13342 char *defhp = concat_path_file(hp, ".ash_history");
13343 setvar("HISTFILE", defhp, 0);
13349 if (argv[0] && argv[0][0] == '-')
13353 read_profile("/etc/profile");
13356 read_profile(".profile");
13362 getuid() == geteuid() && getgid() == getegid() &&
13366 shinit = lookupvar("ENV");
13367 if (shinit != NULL && *shinit != '\0') {
13368 read_profile(shinit);
13374 evalstring(minusc, 0);
13376 if (sflag || minusc == NULL) {
13377 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13379 const char *hp = lookupvar("HISTFILE");
13382 line_input_state->hist_file = hp;
13385 state4: /* XXX ??? - why isn't this before the "if" statement */
13393 extern void _mcleanup(void);
13402 const char *applet_name = "debug stuff usage";
13403 int main(int argc, char **argv)
13405 return ash_main(argc, argv);
13411 * Copyright (c) 1989, 1991, 1993, 1994
13412 * The Regents of the University of California. All rights reserved.
13414 * This code is derived from software contributed to Berkeley by
13415 * Kenneth Almquist.
13417 * Redistribution and use in source and binary forms, with or without
13418 * modification, are permitted provided that the following conditions
13420 * 1. Redistributions of source code must retain the above copyright
13421 * notice, this list of conditions and the following disclaimer.
13422 * 2. Redistributions in binary form must reproduce the above copyright
13423 * notice, this list of conditions and the following disclaimer in the
13424 * documentation and/or other materials provided with the distribution.
13425 * 3. Neither the name of the University nor the names of its contributors
13426 * may be used to endorse or promote products derived from this software
13427 * without specific prior written permission.
13429 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13430 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13431 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13432 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13433 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13434 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13435 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13436 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13437 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13438 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF