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} */
480 static const char dolatstr[] ALIGN1 = {
481 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
517 union node *redirect;
523 struct nodelist *cmdlist;
529 union node *redirect;
542 union node *elsepart;
569 struct nodelist *backquote;
604 struct nredir nredir;
605 struct nbinary nbinary;
609 struct nclist nclist;
618 struct nodelist *next;
631 freefunc(struct funcnode *f)
633 if (f && --f->count < 0)
638 /* ============ Debugging output */
642 static FILE *tracefile;
645 trace_printf(const char *fmt, ...)
652 vfprintf(tracefile, fmt, va);
657 trace_vprintf(const char *fmt, va_list va)
661 vfprintf(tracefile, fmt, va);
665 trace_puts(const char *s)
673 trace_puts_quoted(char *s)
680 putc('"', tracefile);
681 for (p = s; *p; p++) {
683 case '\n': c = 'n'; goto backslash;
684 case '\t': c = 't'; goto backslash;
685 case '\r': c = 'r'; goto backslash;
686 case '"': c = '"'; goto backslash;
687 case '\\': c = '\\'; goto backslash;
688 case CTLESC: c = 'e'; goto backslash;
689 case CTLVAR: c = 'v'; goto backslash;
690 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
691 case CTLBACKQ: c = 'q'; goto backslash;
692 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
694 putc('\\', tracefile);
698 if (*p >= ' ' && *p <= '~')
701 putc('\\', tracefile);
702 putc(*p >> 6 & 03, tracefile);
703 putc(*p >> 3 & 07, tracefile);
704 putc(*p & 07, tracefile);
709 putc('"', tracefile);
713 trace_puts_args(char **ap)
720 trace_puts_quoted(*ap);
722 putc('\n', tracefile);
725 putc(' ', tracefile);
740 /* leave open because libedit might be using it */
743 strcpy(s, "./trace");
745 if (!freopen(s, "a", tracefile)) {
746 fprintf(stderr, "Can't re-open %s\n", s);
751 tracefile = fopen(s, "a");
752 if (tracefile == NULL) {
753 fprintf(stderr, "Can't open %s\n", s);
759 flags = fcntl(fileno(tracefile), F_GETFL);
761 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
763 setlinebuf(tracefile);
764 fputs("\nTracing started.\n", tracefile);
768 indent(int amount, char *pfx, FILE *fp)
772 for (i = 0; i < amount; i++) {
773 if (pfx && i == amount - 1)
779 /* little circular references here... */
780 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
783 sharg(union node *arg, FILE *fp)
786 struct nodelist *bqlist;
789 if (arg->type != NARG) {
790 out1fmt("<node type %d>\n", arg->type);
793 bqlist = arg->narg.backquote;
794 for (p = arg->narg.text; *p; p++) {
803 if (subtype == VSLENGTH)
812 switch (subtype & VSTYPE) {
845 out1fmt("<subtype %d>", subtype);
852 case CTLBACKQ|CTLQUOTE:
855 shtree(bqlist->n, -1, NULL, fp);
866 shcmd(union node *cmd, FILE *fp)
874 for (np = cmd->ncmd.args; np; np = np->narg.next) {
880 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
884 switch (np->nfile.type) {
885 case NTO: s = ">>"+1; dftfd = 1; break;
886 case NCLOBBER: s = ">|"; dftfd = 1; break;
887 case NAPPEND: s = ">>"; dftfd = 1; break;
888 case NTOFD: s = ">&"; dftfd = 1; break;
889 case NFROM: s = "<"; break;
890 case NFROMFD: s = "<&"; break;
891 case NFROMTO: s = "<>"; break;
892 default: s = "*error*"; break;
894 if (np->nfile.fd != dftfd)
895 fprintf(fp, "%d", np->nfile.fd);
897 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
898 fprintf(fp, "%d", np->ndup.dupfd);
900 sharg(np->nfile.fname, fp);
907 shtree(union node *n, int ind, char *pfx, FILE *fp)
915 indent(ind, pfx, fp);
926 shtree(n->nbinary.ch1, ind, NULL, fp);
929 shtree(n->nbinary.ch2, ind, NULL, fp);
937 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
942 if (n->npipe.backgnd)
948 fprintf(fp, "<node type %d>", n->type);
956 showtree(union node *n)
958 trace_puts("showtree called\n");
959 shtree(n, 1, NULL, stdout);
962 #define TRACE(param) trace_printf param
963 #define TRACEV(param) trace_vprintf param
968 #define TRACEV(param)
973 /* ============ Parser data */
976 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
979 struct strlist *next;
988 struct strpush *prev; /* preceding string on stack */
992 struct alias *ap; /* if push was associated with an alias */
994 char *string; /* remember the string since it may change */
998 struct parsefile *prev; /* preceding file on stack */
999 int linno; /* current line */
1000 int fd; /* file descriptor (or -1 if string) */
1001 int nleft; /* number of chars left in this line */
1002 int lleft; /* number of chars left in this buffer */
1003 char *nextc; /* next char in buffer */
1004 char *buf; /* input buffer */
1005 struct strpush *strpush; /* for pushing strings at this level */
1006 struct strpush basestrpush; /* so pushing one is fast */
1009 static struct parsefile basepf; /* top level input file */
1010 static struct parsefile *parsefile = &basepf; /* current input file */
1011 static int startlinno; /* line # where last token started */
1012 static char *commandname; /* currently executing command */
1013 static struct strlist *cmdenviron; /* environment for builtin command */
1014 static int exitstatus; /* exit status of last command */
1017 /* ============ Message printing */
1020 ash_vmsg(const char *msg, va_list ap)
1022 fprintf(stderr, "%s: ", arg0);
1024 if (strcmp(arg0, commandname))
1025 fprintf(stderr, "%s: ", commandname);
1026 if (!iflag || parsefile->fd)
1027 fprintf(stderr, "line %d: ", startlinno);
1029 vfprintf(stderr, msg, ap);
1030 outcslow('\n', stderr);
1034 * Exverror is called to raise the error exception. If the second argument
1035 * is not NULL then error prints an error message using printf style
1036 * formatting. It then raises the error exception.
1038 static void ash_vmsg_and_raise(int, const char *, va_list) ATTRIBUTE_NORETURN;
1040 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1044 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1046 TRACE(("\") pid=%d\n", getpid()));
1048 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1053 flush_stdout_stderr();
1054 raise_exception(cond);
1058 static void ash_msg_and_raise_error(const char *, ...) ATTRIBUTE_NORETURN;
1060 ash_msg_and_raise_error(const char *msg, ...)
1065 ash_vmsg_and_raise(EXERROR, msg, ap);
1070 static void ash_msg_and_raise(int, const char *, ...) ATTRIBUTE_NORETURN;
1072 ash_msg_and_raise(int cond, const char *msg, ...)
1077 ash_vmsg_and_raise(cond, msg, ap);
1083 * error/warning routines for external builtins
1086 ash_msg(const char *fmt, ...)
1096 * Return a string describing an error. The returned string may be a
1097 * pointer to a static buffer that will be overwritten on the next call.
1098 * Action describes the operation that got the error.
1101 errmsg(int e, const char *em)
1103 if (e == ENOENT || e == ENOTDIR) {
1110 /* ============ Memory allocation */
1113 * It appears that grabstackstr() will barf with such alignments
1114 * because stalloc() will return a string allocated in a new stackblock.
1116 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1118 /* Most machines require the value returned from malloc to be aligned
1119 * in some way. The following macro will get this right
1120 * on many machines. */
1121 SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,
1122 /* Minimum size of a block */
1123 MINSIZE = SHELL_ALIGN(504),
1126 struct stack_block {
1127 struct stack_block *prev;
1128 char space[MINSIZE];
1132 struct stack_block *stackp;
1135 struct stackmark *marknext;
1139 struct globals_memstack {
1140 struct stack_block *g_stackp; // = &stackbase;
1141 struct stackmark *markp;
1142 char *g_stacknxt; // = stackbase.space;
1143 char *sstrend; // = stackbase.space + MINSIZE;
1144 size_t g_stacknleft; // = MINSIZE;
1145 int herefd; // = -1;
1146 struct stack_block stackbase;
1148 extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1149 #define G_memstack (*ash_ptr_to_globals_memstack)
1150 #define g_stackp (G_memstack.g_stackp )
1151 #define markp (G_memstack.markp )
1152 #define g_stacknxt (G_memstack.g_stacknxt )
1153 #define sstrend (G_memstack.sstrend )
1154 #define g_stacknleft (G_memstack.g_stacknleft)
1155 #define herefd (G_memstack.herefd )
1156 #define stackbase (G_memstack.stackbase )
1157 #define INIT_G_memstack() do { \
1158 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1160 g_stackp = &stackbase; \
1161 g_stacknxt = stackbase.space; \
1162 g_stacknleft = MINSIZE; \
1163 sstrend = stackbase.space + MINSIZE; \
1167 #define stackblock() ((void *)g_stacknxt)
1168 #define stackblocksize() g_stacknleft
1172 ckrealloc(void * p, size_t nbytes)
1174 p = realloc(p, nbytes);
1176 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1181 ckmalloc(size_t nbytes)
1183 return ckrealloc(NULL, nbytes);
1187 ckzalloc(size_t nbytes)
1189 return memset(ckmalloc(nbytes), 0, nbytes);
1193 * Make a copy of a string in safe storage.
1196 ckstrdup(const char *s)
1198 char *p = strdup(s);
1200 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1205 * Parse trees for commands are allocated in lifo order, so we use a stack
1206 * to make this more efficient, and also to avoid all sorts of exception
1207 * handling code to handle interrupts in the middle of a parse.
1209 * The size 504 was chosen because the Ultrix malloc handles that size
1213 stalloc(size_t nbytes)
1218 aligned = SHELL_ALIGN(nbytes);
1219 if (aligned > g_stacknleft) {
1222 struct stack_block *sp;
1224 blocksize = aligned;
1225 if (blocksize < MINSIZE)
1226 blocksize = MINSIZE;
1227 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1228 if (len < blocksize)
1229 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1232 sp->prev = g_stackp;
1233 g_stacknxt = sp->space;
1234 g_stacknleft = blocksize;
1235 sstrend = g_stacknxt + blocksize;
1240 g_stacknxt += aligned;
1241 g_stacknleft -= aligned;
1246 stzalloc(size_t nbytes)
1248 return memset(stalloc(nbytes), 0, nbytes);
1255 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1256 write(2, "stunalloc\n", 10);
1260 g_stacknleft += g_stacknxt - (char *)p;
1265 * Like strdup but works with the ash stack.
1268 ststrdup(const char *p)
1270 size_t len = strlen(p) + 1;
1271 return memcpy(stalloc(len), p, len);
1275 setstackmark(struct stackmark *mark)
1277 mark->stackp = g_stackp;
1278 mark->stacknxt = g_stacknxt;
1279 mark->stacknleft = g_stacknleft;
1280 mark->marknext = markp;
1285 popstackmark(struct stackmark *mark)
1287 struct stack_block *sp;
1293 markp = mark->marknext;
1294 while (g_stackp != mark->stackp) {
1296 g_stackp = sp->prev;
1299 g_stacknxt = mark->stacknxt;
1300 g_stacknleft = mark->stacknleft;
1301 sstrend = mark->stacknxt + mark->stacknleft;
1306 * When the parser reads in a string, it wants to stick the string on the
1307 * stack and only adjust the stack pointer when it knows how big the
1308 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1309 * of space on top of the stack and stackblocklen returns the length of
1310 * this block. Growstackblock will grow this space by at least one byte,
1311 * possibly moving it (like realloc). Grabstackblock actually allocates the
1312 * part of the block that has been used.
1315 growstackblock(void)
1319 newlen = g_stacknleft * 2;
1320 if (newlen < g_stacknleft)
1321 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1325 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1326 struct stack_block *oldstackp;
1327 struct stackmark *xmark;
1328 struct stack_block *sp;
1329 struct stack_block *prevstackp;
1333 oldstackp = g_stackp;
1335 prevstackp = sp->prev;
1336 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1337 sp = ckrealloc(sp, grosslen);
1338 sp->prev = prevstackp;
1340 g_stacknxt = sp->space;
1341 g_stacknleft = newlen;
1342 sstrend = sp->space + newlen;
1345 * Stack marks pointing to the start of the old block
1346 * must be relocated to point to the new block
1349 while (xmark != NULL && xmark->stackp == oldstackp) {
1350 xmark->stackp = g_stackp;
1351 xmark->stacknxt = g_stacknxt;
1352 xmark->stacknleft = g_stacknleft;
1353 xmark = xmark->marknext;
1357 char *oldspace = g_stacknxt;
1358 int oldlen = g_stacknleft;
1359 char *p = stalloc(newlen);
1361 /* free the space we just allocated */
1362 g_stacknxt = memcpy(p, oldspace, oldlen);
1363 g_stacknleft += newlen;
1368 grabstackblock(size_t len)
1370 len = SHELL_ALIGN(len);
1372 g_stacknleft -= len;
1376 * The following routines are somewhat easier to use than the above.
1377 * The user declares a variable of type STACKSTR, which may be declared
1378 * to be a register. The macro STARTSTACKSTR initializes things. Then
1379 * the user uses the macro STPUTC to add characters to the string. In
1380 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1381 * grown as necessary. When the user is done, she can just leave the
1382 * string there and refer to it using stackblock(). Or she can allocate
1383 * the space for it using grabstackstr(). If it is necessary to allow
1384 * someone else to use the stack temporarily and then continue to grow
1385 * the string, the user should use grabstack to allocate the space, and
1386 * then call ungrabstr(p) to return to the previous mode of operation.
1388 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1389 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1390 * is space for at least one character.
1395 size_t len = stackblocksize();
1396 if (herefd >= 0 && len >= 1024) {
1397 full_write(herefd, stackblock(), len);
1398 return stackblock();
1401 return stackblock() + len;
1405 * Called from CHECKSTRSPACE.
1408 makestrspace(size_t newlen, char *p)
1410 size_t len = p - g_stacknxt;
1411 size_t size = stackblocksize();
1416 size = stackblocksize();
1418 if (nleft >= newlen)
1422 return stackblock() + len;
1426 stack_nputstr(const char *s, size_t n, char *p)
1428 p = makestrspace(n, p);
1429 p = memcpy(p, s, n) + n;
1434 stack_putstr(const char *s, char *p)
1436 return stack_nputstr(s, strlen(s), p);
1440 _STPUTC(int c, char *p)
1448 #define STARTSTACKSTR(p) ((p) = stackblock())
1449 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1450 #define CHECKSTRSPACE(n, p) \
1454 size_t m = sstrend - q; \
1456 (p) = makestrspace(l, q); \
1458 #define USTPUTC(c, p) (*p++ = (c))
1459 #define STACKSTRNUL(p) \
1461 if ((p) == sstrend) \
1462 p = growstackstr(); \
1465 #define STUNPUTC(p) (--p)
1466 #define STTOPC(p) (p[-1])
1467 #define STADJUST(amount, p) (p += (amount))
1469 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1470 #define ungrabstackstr(s, p) stunalloc((s))
1471 #define stackstrend() ((void *)sstrend)
1474 /* ============ String helpers */
1477 * prefix -- see if pfx is a prefix of string.
1480 prefix(const char *string, const char *pfx)
1483 if (*pfx++ != *string++)
1486 return (char *) string;
1490 * Check for a valid number. This should be elsewhere.
1493 is_number(const char *p)
1498 } while (*++p != '\0');
1503 * Convert a string of digits to an integer, printing an error message on
1507 number(const char *s)
1510 ash_msg_and_raise_error(illnum, s);
1515 * Produce a possibly single quoted string suitable as input to the shell.
1516 * The return string is allocated on the stack.
1519 single_quote(const char *s)
1529 len = strchrnul(s, '\'') - s;
1531 q = p = makestrspace(len + 3, p);
1534 q = memcpy(q, s, len) + len;
1540 len = strspn(s, "'");
1544 q = p = makestrspace(len + 3, p);
1547 q = memcpy(q, s, len) + len;
1556 return stackblock();
1560 /* ============ nextopt */
1562 static char **argptr; /* argument list for builtin commands */
1563 static char *optionarg; /* set by nextopt (like getopt) */
1564 static char *optptr; /* used by nextopt */
1567 * XXX - should get rid of. have all builtins use getopt(3). the
1568 * library getopt must have the BSD extension static variable "optreset"
1569 * otherwise it can't be used within the shell safely.
1571 * Standard option processing (a la getopt) for builtin routines. The
1572 * only argument that is passed to nextopt is the option string; the
1573 * other arguments are unnecessary. It return the character, or '\0' on
1577 nextopt(const char *optstring)
1584 if (p == NULL || *p == '\0') {
1586 if (p == NULL || *p != '-' || *++p == '\0')
1589 if (LONE_DASH(p)) /* check for "--" */
1593 for (q = optstring; *q != c; ) {
1595 ash_msg_and_raise_error("illegal option -%c", c);
1600 if (*p == '\0' && (p = *argptr++) == NULL)
1601 ash_msg_and_raise_error("no arg for -%c option", c);
1610 /* ============ Math support definitions */
1612 #if ENABLE_ASH_MATH_SUPPORT_64
1613 typedef int64_t arith_t;
1614 #define arith_t_type long long
1616 typedef long arith_t;
1617 #define arith_t_type long
1620 #if ENABLE_ASH_MATH_SUPPORT
1621 static arith_t dash_arith(const char *);
1622 static arith_t arith(const char *expr, int *perrcode);
1625 #if ENABLE_ASH_RANDOM_SUPPORT
1626 static unsigned long rseed;
1633 /* ============ Shell variables */
1636 * The parsefile structure pointed to by the global variable parsefile
1637 * contains information about the current file being read.
1640 struct redirtab *next;
1646 int nparam; /* # of positional parameters (without $0) */
1647 #if ENABLE_ASH_GETOPTS
1648 int optind; /* next parameter to be processed by getopts */
1649 int optoff; /* used by getopts */
1651 unsigned char malloced; /* if parameter list dynamically allocated */
1652 char **p; /* parameter list */
1656 * Free the list of positional parameters.
1659 freeparam(volatile struct shparam *param)
1663 if (param->malloced) {
1664 for (ap = param->p; *ap; ap++)
1670 #if ENABLE_ASH_GETOPTS
1671 static void getoptsreset(const char *value);
1675 struct var *next; /* next entry in hash list */
1676 int flags; /* flags are defined above */
1677 const char *text; /* name=value */
1678 void (*func)(const char *); /* function to be called when */
1679 /* the variable gets set/unset */
1683 struct localvar *next; /* next local variable in list */
1684 struct var *vp; /* the variable that was made local */
1685 int flags; /* saved flags */
1686 const char *text; /* saved text */
1690 #define VEXPORT 0x01 /* variable is exported */
1691 #define VREADONLY 0x02 /* variable cannot be modified */
1692 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1693 #define VTEXTFIXED 0x08 /* text is statically allocated */
1694 #define VSTACK 0x10 /* text is allocated on the stack */
1695 #define VUNSET 0x20 /* the variable is not set */
1696 #define VNOFUNC 0x40 /* don't call the callback function */
1697 #define VNOSET 0x80 /* do not set variable - just readonly test */
1698 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1700 # define VDYNAMIC 0x200 /* dynamic variable */
1706 static const char defifsvar[] ALIGN1 = "IFS= \t\n";
1707 #define defifs (defifsvar + 4)
1709 static const char defifs[] ALIGN1 = " \t\n";
1713 /* Need to be before varinit_data[] */
1714 #if ENABLE_LOCALE_SUPPORT
1716 change_lc_all(const char *value)
1718 if (value && *value != '\0')
1719 setlocale(LC_ALL, value);
1722 change_lc_ctype(const char *value)
1724 if (value && *value != '\0')
1725 setlocale(LC_CTYPE, value);
1729 static void chkmail(void);
1730 static void changemail(const char *);
1732 static void changepath(const char *);
1733 #if ENABLE_ASH_RANDOM_SUPPORT
1734 static void change_random(const char *);
1737 static const struct {
1740 void (*func)(const char *);
1741 } varinit_data[] = {
1743 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1745 { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL },
1748 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0" , changemail },
1749 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1751 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1752 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1753 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1754 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1755 #if ENABLE_ASH_GETOPTS
1756 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
1758 #if ENABLE_ASH_RANDOM_SUPPORT
1759 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1761 #if ENABLE_LOCALE_SUPPORT
1762 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL\0" , change_lc_all },
1763 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE\0", change_lc_ctype },
1765 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1766 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE\0", NULL },
1771 struct globals_var {
1772 struct shparam shellparam; /* $@ current positional parameters */
1773 struct redirtab *redirlist;
1775 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1776 struct var *vartab[VTABSIZE];
1777 struct var varinit[ARRAY_SIZE(varinit_data)];
1779 extern struct globals_var *const ash_ptr_to_globals_var;
1780 #define G_var (*ash_ptr_to_globals_var)
1781 #define shellparam (G_var.shellparam )
1782 #define redirlist (G_var.redirlist )
1783 #define g_nullredirs (G_var.g_nullredirs )
1784 #define preverrout_fd (G_var.preverrout_fd)
1785 #define vartab (G_var.vartab )
1786 #define varinit (G_var.varinit )
1787 #define INIT_G_var() do { \
1789 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1791 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1792 varinit[i].flags = varinit_data[i].flags; \
1793 varinit[i].text = varinit_data[i].text; \
1794 varinit[i].func = varinit_data[i].func; \
1798 #define vifs varinit[0]
1800 # define vmail (&vifs)[1]
1801 # define vmpath (&vmail)[1]
1802 # define vpath (&vmpath)[1]
1804 # define vpath (&vifs)[1]
1806 #define vps1 (&vpath)[1]
1807 #define vps2 (&vps1)[1]
1808 #define vps4 (&vps2)[1]
1809 #if ENABLE_ASH_GETOPTS
1810 # define voptind (&vps4)[1]
1811 # if ENABLE_ASH_RANDOM_SUPPORT
1812 # define vrandom (&voptind)[1]
1815 # if ENABLE_ASH_RANDOM_SUPPORT
1816 # define vrandom (&vps4)[1]
1821 * The following macros access the values of the above variables.
1822 * They have to skip over the name. They return the null string
1823 * for unset variables.
1825 #define ifsval() (vifs.text + 4)
1826 #define ifsset() ((vifs.flags & VUNSET) == 0)
1828 # define mailval() (vmail.text + 5)
1829 # define mpathval() (vmpath.text + 9)
1830 # define mpathset() ((vmpath.flags & VUNSET) == 0)
1832 #define pathval() (vpath.text + 5)
1833 #define ps1val() (vps1.text + 4)
1834 #define ps2val() (vps2.text + 4)
1835 #define ps4val() (vps4.text + 4)
1836 #if ENABLE_ASH_GETOPTS
1837 # define optindval() (voptind.text + 7)
1841 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1842 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1844 #if ENABLE_ASH_GETOPTS
1846 getoptsreset(const char *value)
1848 shellparam.optind = number(value);
1849 shellparam.optoff = -1;
1854 * Return of a legal variable name (a letter or underscore followed by zero or
1855 * more letters, underscores, and digits).
1858 endofname(const char *name)
1866 if (!is_in_name(*p))
1873 * Compares two strings up to the first = or '\0'. The first
1874 * string must be terminated by '='; the second may be terminated by
1875 * either '=' or '\0'.
1878 varcmp(const char *p, const char *q)
1882 while ((c = *p) == (d = *q)) {
1897 varequal(const char *a, const char *b)
1899 return !varcmp(a, b);
1903 * Find the appropriate entry in the hash table from the name.
1905 static struct var **
1906 hashvar(const char *p)
1910 hashval = ((unsigned char) *p) << 4;
1911 while (*p && *p != '=')
1912 hashval += (unsigned char) *p++;
1913 return &vartab[hashval % VTABSIZE];
1917 vpcmp(const void *a, const void *b)
1919 return varcmp(*(const char **)a, *(const char **)b);
1923 * This routine initializes the builtin variables.
1933 * PS1 depends on uid
1935 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1936 vps1.text = "PS1=\\w \\$ ";
1939 vps1.text = "PS1=# ";
1942 end = vp + ARRAY_SIZE(varinit);
1944 vpp = hashvar(vp->text);
1947 } while (++vp < end);
1950 static struct var **
1951 findvar(struct var **vpp, const char *name)
1953 for (; *vpp; vpp = &(*vpp)->next) {
1954 if (varequal((*vpp)->text, name)) {
1962 * Find the value of a variable. Returns NULL if not set.
1965 lookupvar(const char *name)
1969 v = *findvar(hashvar(name), name);
1973 * Dynamic variables are implemented roughly the same way they are
1974 * in bash. Namely, they're "special" so long as they aren't unset.
1975 * As soon as they're unset, they're no longer dynamic, and dynamic
1976 * lookup will no longer happen at that point. -- PFM.
1978 if ((v->flags & VDYNAMIC))
1981 if (!(v->flags & VUNSET))
1982 return strchrnul(v->text, '=') + 1;
1988 * Search the environment of a builtin command.
1991 bltinlookup(const char *name)
1995 for (sp = cmdenviron; sp; sp = sp->next) {
1996 if (varequal(sp->text, name))
1997 return strchrnul(sp->text, '=') + 1;
1999 return lookupvar(name);
2003 * Same as setvar except that the variable and value are passed in
2004 * the first argument as name=value. Since the first argument will
2005 * be actually stored in the table, it should not be a string that
2007 * Called with interrupts off.
2010 setvareq(char *s, int flags)
2012 struct var *vp, **vpp;
2015 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2016 vp = *findvar(vpp, s);
2018 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2021 if (flags & VNOSAVE)
2024 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2030 if (vp->func && (flags & VNOFUNC) == 0)
2031 (*vp->func)(strchrnul(s, '=') + 1);
2033 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
2034 free((char*)vp->text);
2036 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2041 vp = ckzalloc(sizeof(*vp));
2043 /*vp->func = NULL; - ckzalloc did it */
2046 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2053 * Set the value of a variable. The flags argument is ored with the
2054 * flags of the variable. If val is NULL, the variable is unset.
2057 setvar(const char *name, const char *val, int flags)
2064 q = endofname(name);
2065 p = strchrnul(q, '=');
2067 if (!namelen || p != q)
2068 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2073 vallen = strlen(val);
2076 nameeq = ckmalloc(namelen + vallen + 2);
2077 p = memcpy(nameeq, name, namelen) + namelen;
2080 p = memcpy(p, val, vallen) + vallen;
2083 setvareq(nameeq, flags | VNOSAVE);
2087 #if ENABLE_ASH_GETOPTS
2089 * Safe version of setvar, returns 1 on success 0 on failure.
2092 setvarsafe(const char *name, const char *val, int flags)
2095 volatile int saveint;
2096 struct jmploc *volatile savehandler = exception_handler;
2097 struct jmploc jmploc;
2100 if (setjmp(jmploc.loc))
2103 exception_handler = &jmploc;
2104 setvar(name, val, flags);
2107 exception_handler = savehandler;
2108 RESTORE_INT(saveint);
2114 * Unset the specified variable.
2117 unsetvar(const char *s)
2123 vpp = findvar(hashvar(s), s);
2127 int flags = vp->flags;
2130 if (flags & VREADONLY)
2133 vp->flags &= ~VDYNAMIC;
2137 if ((flags & VSTRFIXED) == 0) {
2139 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2140 free((char*)vp->text);
2146 vp->flags &= ~VEXPORT;
2156 * Process a linked list of variable assignments.
2159 listsetvar(struct strlist *list_set_var, int flags)
2161 struct strlist *lp = list_set_var;
2167 setvareq(lp->text, flags);
2174 * Generate a list of variables satisfying the given conditions.
2177 listvars(int on, int off, char ***end)
2188 for (vp = *vpp; vp; vp = vp->next) {
2189 if ((vp->flags & mask) == on) {
2190 if (ep == stackstrend())
2191 ep = growstackstr();
2192 *ep++ = (char *) vp->text;
2195 } while (++vpp < vartab + VTABSIZE);
2196 if (ep == stackstrend())
2197 ep = growstackstr();
2201 return grabstackstr(ep);
2205 /* ============ Path search helper
2207 * The variable path (passed by reference) should be set to the start
2208 * of the path before the first call; padvance will update
2209 * this value as it proceeds. Successive calls to padvance will return
2210 * the possible path expansions in sequence. If an option (indicated by
2211 * a percent sign) appears in the path entry then the global variable
2212 * pathopt will be set to point to it; otherwise pathopt will be set to
2215 static const char *pathopt; /* set by padvance */
2218 padvance(const char **path, const char *name)
2228 for (p = start; *p && *p != ':' && *p != '%'; p++);
2229 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2230 while (stackblocksize() < len)
2234 memcpy(q, start, p - start);
2242 while (*p && *p != ':') p++;
2248 return stalloc(len);
2252 /* ============ Prompt */
2254 static smallint doprompt; /* if set, prompt the user */
2255 static smallint needprompt; /* true if interactive and at start of line */
2257 #if ENABLE_FEATURE_EDITING
2258 static line_input_t *line_input_state;
2259 static const char *cmdedit_prompt;
2261 putprompt(const char *s)
2263 if (ENABLE_ASH_EXPAND_PRMT) {
2264 free((char*)cmdedit_prompt);
2265 cmdedit_prompt = ckstrdup(s);
2272 putprompt(const char *s)
2278 #if ENABLE_ASH_EXPAND_PRMT
2279 /* expandstr() needs parsing machinery, so it is far away ahead... */
2280 static const char *expandstr(const char *ps);
2282 #define expandstr(s) s
2286 setprompt(int whichprompt)
2289 #if ENABLE_ASH_EXPAND_PRMT
2290 struct stackmark smark;
2295 switch (whichprompt) {
2305 #if ENABLE_ASH_EXPAND_PRMT
2306 setstackmark(&smark);
2307 stalloc(stackblocksize());
2309 putprompt(expandstr(prompt));
2310 #if ENABLE_ASH_EXPAND_PRMT
2311 popstackmark(&smark);
2316 /* ============ The cd and pwd commands */
2318 #define CD_PHYSICAL 1
2321 static int docd(const char *, int);
2330 while ((i = nextopt("LP"))) {
2332 flags ^= CD_PHYSICAL;
2341 * Update curdir (the name of the current directory) in response to a
2345 updatepwd(const char *dir)
2352 cdcomppath = ststrdup(dir);
2355 if (curdir == nullstr)
2357 new = stack_putstr(curdir, new);
2359 new = makestrspace(strlen(dir) + 2, new);
2360 lim = stackblock() + 1;
2364 if (new > lim && *lim == '/')
2369 if (dir[1] == '/' && dir[2] != '/') {
2375 p = strtok(cdcomppath, "/");
2379 if (p[1] == '.' && p[2] == '\0') {
2391 new = stack_putstr(p, new);
2399 return stackblock();
2403 * Find out what the current directory is. If we already know the current
2404 * directory, this routine returns immediately.
2409 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2410 return dir ? dir : nullstr;
2414 setpwd(const char *val, int setold)
2418 oldcur = dir = curdir;
2421 setvar("OLDPWD", oldcur, VEXPORT);
2424 if (physdir != nullstr) {
2425 if (physdir != oldcur)
2429 if (oldcur == val || !val) {
2435 dir = ckstrdup(val);
2436 if (oldcur != dir && oldcur != nullstr) {
2441 setvar("PWD", dir, VEXPORT);
2444 static void hashcd(void);
2447 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2448 * know that the current directory has changed.
2451 docd(const char *dest, int flags)
2453 const char *dir = 0;
2456 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2459 if (!(flags & CD_PHYSICAL)) {
2460 dir = updatepwd(dest);
2475 cdcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
2487 dest = bltinlookup(homestr);
2488 else if (LONE_DASH(dest)) {
2489 dest = bltinlookup("OLDPWD");
2511 path = bltinlookup("CDPATH");
2520 p = padvance(&path, dest);
2521 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2525 if (!docd(p, flags))
2530 ash_msg_and_raise_error("can't cd to %s", dest);
2533 if (flags & CD_PRINT)
2534 out1fmt(snlfmt, curdir);
2539 pwdcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
2542 const char *dir = curdir;
2546 if (physdir == nullstr)
2550 out1fmt(snlfmt, dir);
2555 /* ============ ... */
2557 #define IBUFSIZ COMMON_BUFSIZE
2558 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */
2560 /* Syntax classes */
2561 #define CWORD 0 /* character is nothing special */
2562 #define CNL 1 /* newline character */
2563 #define CBACK 2 /* a backslash character */
2564 #define CSQUOTE 3 /* single quote */
2565 #define CDQUOTE 4 /* double quote */
2566 #define CENDQUOTE 5 /* a terminating quote */
2567 #define CBQUOTE 6 /* backwards single quote */
2568 #define CVAR 7 /* a dollar sign */
2569 #define CENDVAR 8 /* a '}' character */
2570 #define CLP 9 /* a left paren in arithmetic */
2571 #define CRP 10 /* a right paren in arithmetic */
2572 #define CENDFILE 11 /* end of file */
2573 #define CCTL 12 /* like CWORD, except it must be escaped */
2574 #define CSPCL 13 /* these terminate a word */
2575 #define CIGN 14 /* character should be ignored */
2577 #if ENABLE_ASH_ALIAS
2581 #define PEOA_OR_PEOF PEOA
2585 #define PEOA_OR_PEOF PEOF
2588 /* number syntax index */
2589 #define BASESYNTAX 0 /* not in quotes */
2590 #define DQSYNTAX 1 /* in double quotes */
2591 #define SQSYNTAX 2 /* in single quotes */
2592 #define ARISYNTAX 3 /* in arithmetic */
2593 #define PSSYNTAX 4 /* prompt */
2595 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
2596 #define USE_SIT_FUNCTION
2599 #if ENABLE_ASH_MATH_SUPPORT
2600 static const char S_I_T[][4] = {
2601 #if ENABLE_ASH_ALIAS
2602 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */
2604 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */
2605 { CNL, CNL, CNL, CNL }, /* 2, \n */
2606 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */
2607 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */
2608 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */
2609 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */
2610 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */
2611 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */
2612 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */
2613 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */
2614 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */
2615 #ifndef USE_SIT_FUNCTION
2616 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2617 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2618 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2622 static const char S_I_T[][3] = {
2623 #if ENABLE_ASH_ALIAS
2624 { CSPCL, CIGN, CIGN }, /* 0, PEOA */
2626 { CSPCL, CWORD, CWORD }, /* 1, ' ' */
2627 { CNL, CNL, CNL }, /* 2, \n */
2628 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */
2629 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */
2630 { CVAR, CVAR, CWORD }, /* 5, $ */
2631 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */
2632 { CSPCL, CWORD, CWORD }, /* 7, ( */
2633 { CSPCL, CWORD, CWORD }, /* 8, ) */
2634 { CBACK, CBACK, CCTL }, /* 9, \ */
2635 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */
2636 { CENDVAR, CENDVAR, CWORD }, /* 11, } */
2637 #ifndef USE_SIT_FUNCTION
2638 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2639 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2640 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2643 #endif /* ASH_MATH_SUPPORT */
2645 #ifdef USE_SIT_FUNCTION
2648 SIT(int c, int syntax)
2650 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2651 #if ENABLE_ASH_ALIAS
2652 static const char syntax_index_table[] ALIGN1 = {
2653 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2654 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2655 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2659 static const char syntax_index_table[] ALIGN1 = {
2660 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2661 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2662 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2669 if (c == PEOF) /* 2^8+2 */
2671 #if ENABLE_ASH_ALIAS
2672 if (c == PEOA) /* 2^8+1 */
2676 #define U_C(c) ((unsigned char)(c))
2678 if ((unsigned char)c >= (unsigned char)(CTLESC)
2679 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
2683 s = strchr(spec_symbls, c);
2684 if (s == NULL || *s == '\0')
2686 indx = syntax_index_table[(s - spec_symbls)];
2688 return S_I_T[indx][syntax];
2691 #else /* !USE_SIT_FUNCTION */
2693 #if ENABLE_ASH_ALIAS
2694 #define CSPCL_CIGN_CIGN_CIGN 0
2695 #define CSPCL_CWORD_CWORD_CWORD 1
2696 #define CNL_CNL_CNL_CNL 2
2697 #define CWORD_CCTL_CCTL_CWORD 3
2698 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
2699 #define CVAR_CVAR_CWORD_CVAR 5
2700 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
2701 #define CSPCL_CWORD_CWORD_CLP 7
2702 #define CSPCL_CWORD_CWORD_CRP 8
2703 #define CBACK_CBACK_CCTL_CBACK 9
2704 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
2705 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
2706 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
2707 #define CWORD_CWORD_CWORD_CWORD 13
2708 #define CCTL_CCTL_CCTL_CCTL 14
2710 #define CSPCL_CWORD_CWORD_CWORD 0
2711 #define CNL_CNL_CNL_CNL 1
2712 #define CWORD_CCTL_CCTL_CWORD 2
2713 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
2714 #define CVAR_CVAR_CWORD_CVAR 4
2715 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
2716 #define CSPCL_CWORD_CWORD_CLP 6
2717 #define CSPCL_CWORD_CWORD_CRP 7
2718 #define CBACK_CBACK_CCTL_CBACK 8
2719 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
2720 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
2721 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
2722 #define CWORD_CWORD_CWORD_CWORD 12
2723 #define CCTL_CCTL_CCTL_CCTL 13
2726 static const char syntax_index_table[258] = {
2727 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2728 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2729 #if ENABLE_ASH_ALIAS
2730 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
2732 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2733 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2734 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2735 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2736 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2737 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2738 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2739 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2740 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2741 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
2742 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
2743 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
2744 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
2745 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
2746 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
2747 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
2748 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
2749 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
2750 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
2751 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
2752 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
2753 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
2754 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
2755 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
2756 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
2757 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
2758 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
2759 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
2760 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
2761 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
2762 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
2763 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
2764 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
2765 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
2766 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
2767 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
2768 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
2769 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
2770 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
2771 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
2772 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
2773 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
2774 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
2775 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
2776 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
2777 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
2778 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
2779 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
2780 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
2781 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
2782 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
2783 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
2784 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
2785 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
2786 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
2787 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
2788 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
2789 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
2790 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
2791 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
2792 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
2793 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
2794 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
2795 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
2796 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
2797 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
2798 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
2799 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
2800 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
2801 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
2802 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
2803 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
2804 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
2805 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
2806 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
2807 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
2808 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
2809 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
2810 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
2811 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
2812 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
2813 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
2814 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
2815 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
2816 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
2817 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
2818 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
2819 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
2820 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
2821 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
2822 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
2823 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
2824 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
2825 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
2826 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
2827 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
2828 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
2829 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
2830 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
2831 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
2832 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
2833 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
2834 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
2835 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
2836 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
2837 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
2838 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
2839 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
2840 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
2841 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
2842 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
2843 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
2844 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
2845 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
2846 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
2847 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
2848 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
2853 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
2854 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2870 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
2871 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2893 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2894 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2895 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2896 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2897 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2898 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2899 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2900 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2901 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2902 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2903 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2904 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
2905 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2906 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
2907 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2908 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2909 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2910 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2919 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2920 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2921 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2922 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2923 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2924 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2952 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2953 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2954 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2957 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2985 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2986 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2987 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
2990 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])
2992 #endif /* USE_SIT_FUNCTION */
2995 /* ============ Alias handling */
2997 #if ENABLE_ASH_ALIAS
2999 #define ALIASINUSE 1
3010 static struct alias **atab; // [ATABSIZE];
3011 #define INIT_G_alias() do { \
3012 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3016 static struct alias **
3017 __lookupalias(const char *name) {
3018 unsigned int hashval;
3025 ch = (unsigned char)*p;
3029 ch = (unsigned char)*++p;
3031 app = &atab[hashval % ATABSIZE];
3033 for (; *app; app = &(*app)->next) {
3034 if (strcmp(name, (*app)->name) == 0) {
3042 static struct alias *
3043 lookupalias(const char *name, int check)
3045 struct alias *ap = *__lookupalias(name);
3047 if (check && ap && (ap->flag & ALIASINUSE))
3052 static struct alias *
3053 freealias(struct alias *ap)
3057 if (ap->flag & ALIASINUSE) {
3058 ap->flag |= ALIASDEAD;
3070 setalias(const char *name, const char *val)
3072 struct alias *ap, **app;
3074 app = __lookupalias(name);
3078 if (!(ap->flag & ALIASINUSE)) {
3081 ap->val = ckstrdup(val);
3082 ap->flag &= ~ALIASDEAD;
3085 ap = ckzalloc(sizeof(struct alias));
3086 ap->name = ckstrdup(name);
3087 ap->val = ckstrdup(val);
3088 /*ap->flag = 0; - ckzalloc did it */
3089 /*ap->next = NULL;*/
3096 unalias(const char *name)
3100 app = __lookupalias(name);
3104 *app = freealias(*app);
3115 struct alias *ap, **app;
3119 for (i = 0; i < ATABSIZE; i++) {
3121 for (ap = *app; ap; ap = *app) {
3122 *app = freealias(*app);
3132 printalias(const struct alias *ap)
3134 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3138 * TODO - sort output
3141 aliascmd(int argc ATTRIBUTE_UNUSED, char **argv)
3150 for (i = 0; i < ATABSIZE; i++) {
3151 for (ap = atab[i]; ap; ap = ap->next) {
3157 while ((n = *++argv) != NULL) {
3158 v = strchr(n+1, '=');
3159 if (v == NULL) { /* n+1: funny ksh stuff */
3160 ap = *__lookupalias(n);
3162 fprintf(stderr, "%s: %s not found\n", "alias", n);
3176 unaliascmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
3180 while ((i = nextopt("a")) != '\0') {
3186 for (i = 0; *argptr; argptr++) {
3187 if (unalias(*argptr)) {
3188 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3196 #endif /* ASH_ALIAS */
3199 /* ============ jobs.c */
3201 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3204 #define FORK_NOJOB 2
3206 /* mode flags for showjob(s) */
3207 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
3208 #define SHOW_PID 0x04 /* include process pid */
3209 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
3212 * A job structure contains information about a job. A job is either a
3213 * single process or a set of processes contained in a pipeline. In the
3214 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3219 pid_t pid; /* process id */
3220 int status; /* last process status from wait() */
3221 char *cmd; /* text of command being run */
3225 struct procstat ps0; /* status of process */
3226 struct procstat *ps; /* status or processes when more than one */
3228 int stopstatus; /* status of a stopped job */
3231 nprocs: 16, /* number of processes */
3233 #define JOBRUNNING 0 /* at least one proc running */
3234 #define JOBSTOPPED 1 /* all procs are stopped */
3235 #define JOBDONE 2 /* all procs are completed */
3237 sigint: 1, /* job was killed by SIGINT */
3238 jobctl: 1, /* job running under job control */
3240 waited: 1, /* true if this entry has been waited for */
3241 used: 1, /* true if this entry is in used */
3242 changed: 1; /* true if status has changed */
3243 struct job *prev_job; /* previous job */
3246 static pid_t backgndpid; /* pid of last background process */
3247 static smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
3249 static struct job *makejob(/*union node *,*/ int);
3250 static int forkshell(struct job *, union node *, int);
3251 static int waitforjob(struct job *);
3254 enum { jobctl = 0 };
3255 #define setjobctl(on) do {} while (0)
3257 static smallint jobctl; /* true if doing job control */
3258 static void setjobctl(int);
3262 * Set the signal handler for the specified signal. The routine figures
3263 * out what it should be set to.
3266 setsignal(int signo)
3270 struct sigaction act;
3276 else if (*t != '\0')
3278 if (rootshell && action == S_DFL) {
3281 if (iflag || minusc || sflag == 0)
3304 t = &sigmode[signo - 1];
3308 * current setting unknown
3310 if (sigaction(signo, NULL, &act) == -1) {
3312 * Pretend it worked; maybe we should give a warning
3313 * here, but other shells don't. We don't alter
3314 * sigmode, so that we retry every time.
3318 tsig = S_RESET; /* force to be set */
3319 if (act.sa_handler == SIG_IGN) {
3322 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3324 tsig = S_IGN; /* don't hard ignore these */
3328 if (tsig == S_HARD_IGN || tsig == action)
3330 act.sa_handler = SIG_DFL;
3333 act.sa_handler = onsig;
3336 act.sa_handler = SIG_IGN;
3341 sigfillset(&act.sa_mask);
3342 sigaction_set(signo, &act);
3345 /* mode flags for set_curjob */
3346 #define CUR_DELETE 2
3347 #define CUR_RUNNING 1
3348 #define CUR_STOPPED 0
3350 /* mode flags for dowait */
3351 #define DOWAIT_NONBLOCK WNOHANG
3352 #define DOWAIT_BLOCK 0
3355 /* pgrp of shell on invocation */
3356 static int initialpgrp;
3357 static int ttyfd = -1;
3360 static struct job *jobtab;
3362 static unsigned njobs;
3364 static struct job *curjob;
3365 /* number of presumed living untracked jobs */
3369 set_curjob(struct job *jp, unsigned mode)
3372 struct job **jpp, **curp;
3374 /* first remove from list */
3375 jpp = curp = &curjob;
3380 jpp = &jp1->prev_job;
3382 *jpp = jp1->prev_job;
3384 /* Then re-insert in correct position */
3392 /* job being deleted */
3395 /* newly created job or backgrounded job,
3396 put after all stopped jobs. */
3400 if (!jp1 || jp1->state != JOBSTOPPED)
3403 jpp = &jp1->prev_job;
3409 /* newly stopped job - becomes curjob */
3410 jp->prev_job = *jpp;
3418 jobno(const struct job *jp)
3420 return jp - jobtab + 1;
3425 * Convert a job name to a job structure.
3428 getjob(const char *name, int getctl)
3432 const char *err_msg = "No such job: %s";
3436 char *(*match)(const char *, const char *);
3451 if (c == '+' || c == '%') {
3453 err_msg = "No current job";
3459 err_msg = "No previous job";
3470 jp = jobtab + num - 1;
3487 if (match(jp->ps[0].cmd, p)) {
3491 err_msg = "%s: ambiguous";
3498 err_msg = "job %s not created under job control";
3499 if (getctl && jp->jobctl == 0)
3504 ash_msg_and_raise_error(err_msg, name);
3508 * Mark a job structure as unused.
3511 freejob(struct job *jp)
3513 struct procstat *ps;
3517 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3518 if (ps->cmd != nullstr)
3521 if (jp->ps != &jp->ps0)
3524 set_curjob(jp, CUR_DELETE);
3530 xtcsetpgrp(int fd, pid_t pgrp)
3532 if (tcsetpgrp(fd, pgrp))
3533 ash_msg_and_raise_error("cannot set tty process group (%m)");
3537 * Turn job control on and off.
3539 * Note: This code assumes that the third arg to ioctl is a character
3540 * pointer, which is true on Berkeley systems but not System V. Since
3541 * System V doesn't have job control yet, this isn't a problem now.
3543 * Called with interrupts off.
3551 if (on == jobctl || rootshell == 0)
3555 ofd = fd = open(_PATH_TTY, O_RDWR);
3557 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3558 * That sometimes helps to acquire controlling tty.
3559 * Obviously, a workaround for bugs when someone
3560 * failed to provide a controlling tty to bash! :) */
3566 fd = fcntl(fd, F_DUPFD, 10);
3571 /* fd is a tty at this point */
3572 close_on_exec_on(fd);
3573 do { /* while we are in the background */
3574 pgrp = tcgetpgrp(fd);
3577 ash_msg("can't access tty; job control turned off");
3581 if (pgrp == getpgrp())
3592 xtcsetpgrp(fd, pgrp);
3594 /* turning job control off */
3597 /* was xtcsetpgrp, but this can make exiting ash
3598 * loop forever if pty is already deleted */
3599 tcsetpgrp(fd, pgrp);
3614 killcmd(int argc, char **argv)
3617 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3619 if (argv[i][0] == '%') {
3620 struct job *jp = getjob(argv[i], 0);
3621 unsigned pid = jp->ps[0].pid;
3622 /* Enough space for ' -NNN<nul>' */
3623 argv[i] = alloca(sizeof(int)*3 + 3);
3624 /* kill_main has matching code to expect
3625 * leading space. Needed to not confuse
3626 * negative pids with "kill -SIGNAL_NO" syntax */
3627 sprintf(argv[i], " -%u", pid);
3629 } while (argv[++i]);
3631 return kill_main(argc, argv);
3635 showpipe(struct job *jp, FILE *out)
3637 struct procstat *sp;
3638 struct procstat *spend;
3640 spend = jp->ps + jp->nprocs;
3641 for (sp = jp->ps + 1; sp < spend; sp++)
3642 fprintf(out, " | %s", sp->cmd);
3643 outcslow('\n', out);
3644 flush_stdout_stderr();
3649 restartjob(struct job *jp, int mode)
3651 struct procstat *ps;
3657 if (jp->state == JOBDONE)
3659 jp->state = JOBRUNNING;
3661 if (mode == FORK_FG)
3662 xtcsetpgrp(ttyfd, pgid);
3663 killpg(pgid, SIGCONT);
3667 if (WIFSTOPPED(ps->status)) {
3673 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3679 fg_bgcmd(int argc ATTRIBUTE_UNUSED, char **argv)
3686 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3691 jp = getjob(*argv, 1);
3692 if (mode == FORK_BG) {
3693 set_curjob(jp, CUR_RUNNING);
3694 fprintf(out, "[%d] ", jobno(jp));
3696 outstr(jp->ps->cmd, out);
3698 retval = restartjob(jp, mode);
3699 } while (*argv && *++argv);
3705 sprint_status(char *s, int status, int sigonly)
3711 if (!WIFEXITED(status)) {
3713 if (WIFSTOPPED(status))
3714 st = WSTOPSIG(status);
3717 st = WTERMSIG(status);
3719 if (st == SIGINT || st == SIGPIPE)
3722 if (WIFSTOPPED(status))
3727 col = fmtstr(s, 32, strsignal(st));
3728 if (WCOREDUMP(status)) {
3729 col += fmtstr(s + col, 16, " (core dumped)");
3731 } else if (!sigonly) {
3732 st = WEXITSTATUS(status);
3734 col = fmtstr(s, 16, "Done(%d)", st);
3736 col = fmtstr(s, 16, "Done");
3743 * Do a wait system call. If job control is compiled in, we accept
3744 * stopped processes. If block is zero, we return a value of zero
3745 * rather than blocking.
3747 * System V doesn't have a non-blocking wait system call. It does
3748 * have a SIGCLD signal that is sent to a process when one of it's
3749 * children dies. The obvious way to use SIGCLD would be to install
3750 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
3751 * was received, and have waitproc bump another counter when it got
3752 * the status of a process. Waitproc would then know that a wait
3753 * system call would not block if the two counters were different.
3754 * This approach doesn't work because if a process has children that
3755 * have not been waited for, System V will send it a SIGCLD when it
3756 * installs a signal handler for SIGCLD. What this means is that when
3757 * a child exits, the shell will be sent SIGCLD signals continuously
3758 * until is runs out of stack space, unless it does a wait call before
3759 * restoring the signal handler. The code below takes advantage of
3760 * this (mis)feature by installing a signal handler for SIGCLD and
3761 * then checking to see whether it was called. If there are any
3762 * children to be waited for, it will be.
3764 * If neither SYSV nor BSD is defined, we don't implement nonblocking
3765 * waits at all. In this case, the user will not be informed when
3766 * a background process until the next time she runs a real program
3767 * (as opposed to running a builtin command or just typing return),
3768 * and the jobs command may give out of date information.
3771 waitproc(int wait_flags, int *status)
3775 wait_flags |= WUNTRACED;
3777 /* NB: _not_ safe_waitpid, we need to detect EINTR */
3778 return waitpid(-1, status, wait_flags);
3782 * Wait for a process to terminate.
3785 dowait(int wait_flags, struct job *job)
3790 struct job *thisjob;
3793 TRACE(("dowait(%d) called\n", wait_flags));
3794 pid = waitproc(wait_flags, &status);
3795 TRACE(("wait returns pid=%d, status=%d\n", pid, status));
3797 /* If we were doing blocking wait and (probably) got EINTR,
3798 * check for pending sigs received while waiting.
3799 * (NB: can be moved into callers if needed) */
3800 if (wait_flags == DOWAIT_BLOCK && pendingsig)
3801 raise_exception(EXSIG);
3806 for (jp = curjob; jp; jp = jp->prev_job) {
3807 struct procstat *sp;
3808 struct procstat *spend;
3809 if (jp->state == JOBDONE)
3812 spend = jp->ps + jp->nprocs;
3815 if (sp->pid == pid) {
3816 TRACE(("Job %d: changing status of proc %d "
3817 "from 0x%x to 0x%x\n",
3818 jobno(jp), pid, sp->status, status));
3819 sp->status = status;
3822 if (sp->status == -1)
3825 if (state == JOBRUNNING)
3827 if (WIFSTOPPED(sp->status)) {
3828 jp->stopstatus = sp->status;
3832 } while (++sp < spend);
3837 if (!WIFSTOPPED(status))
3843 if (state != JOBRUNNING) {
3844 thisjob->changed = 1;
3846 if (thisjob->state != state) {
3847 TRACE(("Job %d: changing state from %d to %d\n",
3848 jobno(thisjob), thisjob->state, state));
3849 thisjob->state = state;
3851 if (state == JOBSTOPPED) {
3852 set_curjob(thisjob, CUR_STOPPED);
3861 if (thisjob && thisjob == job) {
3865 len = sprint_status(s, status, 1);
3877 showjob(FILE *out, struct job *jp, int mode)
3879 struct procstat *ps;
3880 struct procstat *psend;
3887 if (mode & SHOW_PGID) {
3888 /* just output process (group) id of pipeline */
3889 fprintf(out, "%d\n", ps->pid);
3893 col = fmtstr(s, 16, "[%d] ", jobno(jp));
3898 else if (curjob && jp == curjob->prev_job)
3901 if (mode & SHOW_PID)
3902 col += fmtstr(s + col, 16, "%d ", ps->pid);
3904 psend = ps + jp->nprocs;
3906 if (jp->state == JOBRUNNING) {
3907 strcpy(s + col, "Running");
3908 col += sizeof("Running") - 1;
3910 int status = psend[-1].status;
3911 if (jp->state == JOBSTOPPED)
3912 status = jp->stopstatus;
3913 col += sprint_status(s + col, status, 0);
3919 /* for each process */
3920 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
3922 fprintf(out, "%s%*c%s",
3923 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
3925 if (!(mode & SHOW_PID)) {
3929 if (++ps == psend) {
3930 outcslow('\n', out);
3937 if (jp->state == JOBDONE) {
3938 TRACE(("showjob: freeing job %d\n", jobno(jp)));
3944 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3945 * statuses have changed since the last call to showjobs.
3948 showjobs(FILE *out, int mode)
3952 TRACE(("showjobs(%x) called\n", mode));
3954 /* If not even one job changed, there is nothing to do */
3955 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3958 for (jp = curjob; jp; jp = jp->prev_job) {
3959 if (!(mode & SHOW_CHANGED) || jp->changed) {
3960 showjob(out, jp, mode);
3966 jobscmd(int argc ATTRIBUTE_UNUSED, char **argv)
3971 while ((m = nextopt("lp"))) {
3981 showjob(stdout, getjob(*argv,0), mode);
3984 showjobs(stdout, mode);
3991 getstatus(struct job *job)
3996 status = job->ps[job->nprocs - 1].status;
3997 retval = WEXITSTATUS(status);
3998 if (!WIFEXITED(status)) {
4000 retval = WSTOPSIG(status);
4001 if (!WIFSTOPPED(status))
4004 /* XXX: limits number of signals */
4005 retval = WTERMSIG(status);
4007 if (retval == SIGINT)
4013 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
4014 jobno(job), job->nprocs, status, retval));
4019 waitcmd(int argc ATTRIBUTE_UNUSED, char **argv)
4028 raise_exception(EXSIG);
4035 /* wait for all jobs */
4039 if (!jp) /* no running procs */
4041 if (jp->state == JOBRUNNING)
4046 dowait(DOWAIT_BLOCK, NULL);
4052 if (**argv != '%') {
4053 pid_t pid = number(*argv);
4058 if (job->ps[job->nprocs - 1].pid == pid)
4060 job = job->prev_job;
4063 job = getjob(*argv, 0);
4064 /* loop until process terminated or stopped */
4065 while (job->state == JOBRUNNING)
4066 dowait(DOWAIT_BLOCK, NULL);
4068 retval = getstatus(job);
4082 struct job *jp, *jq;
4084 len = njobs * sizeof(*jp);
4086 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4088 offset = (char *)jp - (char *)jq;
4090 /* Relocate pointers */
4093 jq = (struct job *)((char *)jq + l);
4097 #define joff(p) ((struct job *)((char *)(p) + l))
4098 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4099 if (joff(jp)->ps == &jq->ps0)
4100 jmove(joff(jp)->ps);
4101 if (joff(jp)->prev_job)
4102 jmove(joff(jp)->prev_job);
4112 jp = (struct job *)((char *)jp + len);
4116 } while (--jq >= jp);
4121 * Return a new job structure.
4122 * Called with interrupts off.
4125 makejob(/*union node *node,*/ int nprocs)
4130 for (i = njobs, jp = jobtab; ; jp++) {
4137 if (jp->state != JOBDONE || !jp->waited)
4146 memset(jp, 0, sizeof(*jp));
4148 /* jp->jobctl is a bitfield.
4149 * "jp->jobctl |= jobctl" likely to give awful code */
4153 jp->prev_job = curjob;
4158 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4160 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4167 * Return a string identifying a command (to be printed by the
4170 static char *cmdnextc;
4173 cmdputs(const char *s)
4175 const char *p, *str;
4176 char c, cc[2] = " ";
4180 static const char vstype[VSTYPE + 1][4] = {
4181 "", "}", "-", "+", "?", "=",
4182 "%", "%%", "#", "##"
4185 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4187 while ((c = *p++) != 0) {
4195 if ((subtype & VSTYPE) == VSLENGTH)
4199 if (!(subtype & VSQUOTE) == !(quoted & 1))
4205 str = "\"}" + !(quoted & 1);
4212 case CTLBACKQ+CTLQUOTE:
4215 #if ENABLE_ASH_MATH_SUPPORT
4230 if ((subtype & VSTYPE) != VSNORMAL)
4232 str = vstype[subtype & VSTYPE];
4233 if (subtype & VSNUL)
4242 /* These can only happen inside quotes */
4255 while ((c = *str++)) {
4260 USTPUTC('"', nextc);
4266 /* cmdtxt() and cmdlist() call each other */
4267 static void cmdtxt(union node *n);
4270 cmdlist(union node *np, int sep)
4272 for (; np; np = np->narg.next) {
4276 if (sep && np->narg.next)
4282 cmdtxt(union node *n)
4285 struct nodelist *lp;
4297 lp = n->npipe.cmdlist;
4315 cmdtxt(n->nbinary.ch1);
4331 cmdtxt(n->nif.test);
4334 if (n->nif.elsepart) {
4337 n = n->nif.elsepart;
4353 cmdtxt(n->nbinary.ch1);
4363 cmdputs(n->nfor.var);
4365 cmdlist(n->nfor.args, 1);
4370 cmdputs(n->narg.text);
4374 cmdlist(n->ncmd.args, 1);
4375 cmdlist(n->ncmd.redirect, 0);
4388 cmdputs(n->ncase.expr->narg.text);
4390 for (np = n->ncase.cases; np; np = np->nclist.next) {
4391 cmdtxt(np->nclist.pattern);
4393 cmdtxt(np->nclist.body);
4419 s[0] = n->nfile.fd + '0';
4423 if (n->type == NTOFD || n->type == NFROMFD) {
4424 s[0] = n->ndup.dupfd + '0';
4434 commandtext(union node *n)
4438 STARTSTACKSTR(cmdnextc);
4440 name = stackblock();
4441 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4442 name, cmdnextc, cmdnextc));
4443 return ckstrdup(name);
4448 * Fork off a subshell. If we are doing job control, give the subshell its
4449 * own process group. Jp is a job structure that the job is to be added to.
4450 * N is the command that will be evaluated by the child. Both jp and n may
4451 * be NULL. The mode parameter can be one of the following:
4452 * FORK_FG - Fork off a foreground process.
4453 * FORK_BG - Fork off a background process.
4454 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4455 * process group even if job control is on.
4457 * When job control is turned off, background processes have their standard
4458 * input redirected to /dev/null (except for the second and later processes
4461 * Called with interrupts off.
4464 * Clear traps on a fork.
4471 for (tp = trap; tp < &trap[NSIG]; tp++) {
4472 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4477 setsignal(tp - trap);
4483 /* Lives far away from here, needed for forkchild */
4484 static void closescript(void);
4486 /* Called after fork(), in child */
4488 forkchild(struct job *jp, /*union node *n,*/ int mode)
4492 TRACE(("Child shell %d\n", getpid()));
4499 /* do job control only in root shell */
4501 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4504 if (jp->nprocs == 0)
4507 pgrp = jp->ps[0].pid;
4508 /* This can fail because we are doing it in the parent also */
4509 (void)setpgid(0, pgrp);
4510 if (mode == FORK_FG)
4511 xtcsetpgrp(ttyfd, pgrp);
4516 if (mode == FORK_BG) {
4519 if (jp->nprocs == 0) {
4521 if (open(bb_dev_null, O_RDONLY) != 0)
4522 ash_msg_and_raise_error("can't open %s", bb_dev_null);
4525 if (!oldlvl && iflag) {
4530 for (jp = curjob; jp; jp = jp->prev_job)
4535 /* Called after fork(), in parent */
4537 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4539 TRACE(("In parent shell: child = %d\n", pid));
4541 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4547 if (mode != FORK_NOJOB && jp->jobctl) {
4550 if (jp->nprocs == 0)
4553 pgrp = jp->ps[0].pid;
4554 /* This can fail because we are doing it in the child also */
4558 if (mode == FORK_BG) {
4559 backgndpid = pid; /* set $! */
4560 set_curjob(jp, CUR_RUNNING);
4563 struct procstat *ps = &jp->ps[jp->nprocs++];
4569 ps->cmd = commandtext(n);
4575 forkshell(struct job *jp, union node *n, int mode)
4579 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4582 TRACE(("Fork failed, errno=%d", errno));
4585 ash_msg_and_raise_error("cannot fork");
4588 forkchild(jp, /*n,*/ mode);
4590 forkparent(jp, n, mode, pid);
4595 * Wait for job to finish.
4597 * Under job control we have the problem that while a child process is
4598 * running interrupts generated by the user are sent to the child but not
4599 * to the shell. This means that an infinite loop started by an inter-
4600 * active user may be hard to kill. With job control turned off, an
4601 * interactive user may place an interactive program inside a loop. If
4602 * the interactive program catches interrupts, the user doesn't want
4603 * these interrupts to also abort the loop. The approach we take here
4604 * is to have the shell ignore interrupt signals while waiting for a
4605 * foreground process to terminate, and then send itself an interrupt
4606 * signal if the child process was terminated by an interrupt signal.
4607 * Unfortunately, some programs want to do a bit of cleanup and then
4608 * exit on interrupt; unless these processes terminate themselves by
4609 * sending a signal to themselves (instead of calling exit) they will
4610 * confuse this approach.
4612 * Called with interrupts off.
4615 waitforjob(struct job *jp)
4619 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4620 while (jp->state == JOBRUNNING) {
4621 dowait(DOWAIT_BLOCK, jp);
4626 xtcsetpgrp(ttyfd, rootpid);
4628 * This is truly gross.
4629 * If we're doing job control, then we did a TIOCSPGRP which
4630 * caused us (the shell) to no longer be in the controlling
4631 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4632 * intuit from the subprocess exit status whether a SIGINT
4633 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4635 if (jp->sigint) /* TODO: do the same with all signals */
4636 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4638 if (jp->state == JOBDONE)
4645 * return 1 if there are stopped jobs, otherwise 0
4657 if (jp && jp->state == JOBSTOPPED) {
4658 out2str("You have stopped jobs.\n");
4667 /* ============ redir.c
4669 * Code for dealing with input/output redirection.
4672 #define EMPTY -2 /* marks an unused slot in redirtab */
4673 #define CLOSED -3 /* marks a slot of previously-closed fd */
4675 # define PIPESIZE 4096 /* amount of buffering in a pipe */
4677 # define PIPESIZE PIPE_BUF
4681 * Open a file in noclobber mode.
4682 * The code was copied from bash.
4685 noclobberopen(const char *fname)
4688 struct stat finfo, finfo2;
4691 * If the file exists and is a regular file, return an error
4694 r = stat(fname, &finfo);
4695 if (r == 0 && S_ISREG(finfo.st_mode)) {
4701 * If the file was not present (r != 0), make sure we open it
4702 * exclusively so that if it is created before we open it, our open
4703 * will fail. Make sure that we do not truncate an existing file.
4704 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4705 * file was not a regular file, we leave O_EXCL off.
4708 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4709 fd = open(fname, O_WRONLY|O_CREAT, 0666);
4711 /* If the open failed, return the file descriptor right away. */
4716 * OK, the open succeeded, but the file may have been changed from a
4717 * non-regular file to a regular file between the stat and the open.
4718 * We are assuming that the O_EXCL open handles the case where FILENAME
4719 * did not exist and is symlinked to an existing file between the stat
4724 * If we can open it and fstat the file descriptor, and neither check
4725 * revealed that it was a regular file, and the file has not been
4726 * replaced, return the file descriptor.
4728 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4729 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4732 /* The file has been replaced. badness. */
4739 * Handle here documents. Normally we fork off a process to write the
4740 * data to a pipe. If the document is short, we can stuff the data in
4741 * the pipe without forking.
4743 /* openhere needs this forward reference */
4744 static void expandhere(union node *arg, int fd);
4746 openhere(union node *redir)
4752 ash_msg_and_raise_error("pipe call failed");
4753 if (redir->type == NHERE) {
4754 len = strlen(redir->nhere.doc->narg.text);
4755 if (len <= PIPESIZE) {
4756 full_write(pip[1], redir->nhere.doc->narg.text, len);
4760 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4762 signal(SIGINT, SIG_IGN);
4763 signal(SIGQUIT, SIG_IGN);
4764 signal(SIGHUP, SIG_IGN);
4766 signal(SIGTSTP, SIG_IGN);
4768 signal(SIGPIPE, SIG_DFL);
4769 if (redir->type == NHERE)
4770 full_write(pip[1], redir->nhere.doc->narg.text, len);
4772 expandhere(redir->nhere.doc, pip[1]);
4781 openredirect(union node *redir)
4786 switch (redir->nfile.type) {
4788 fname = redir->nfile.expfname;
4789 f = open(fname, O_RDONLY);
4794 fname = redir->nfile.expfname;
4795 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
4800 /* Take care of noclobber mode. */
4802 fname = redir->nfile.expfname;
4803 f = noclobberopen(fname);
4810 fname = redir->nfile.expfname;
4811 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4816 fname = redir->nfile.expfname;
4817 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4825 /* Fall through to eliminate warning. */
4832 f = openhere(redir);
4838 ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4840 ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "no such file"));
4844 * Copy a file descriptor to be >= to. Returns -1
4845 * if the source file descriptor is closed, EMPTY if there are no unused
4846 * file descriptors left.
4849 copyfd(int from, int to)
4853 newfd = fcntl(from, F_DUPFD, to);
4855 if (errno == EMFILE)
4857 ash_msg_and_raise_error("%d: %m", from);
4863 dupredirect(union node *redir, int f)
4865 int fd = redir->nfile.fd;
4867 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
4868 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
4869 copyfd(redir->ndup.dupfd, fd);
4881 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
4882 * old file descriptors are stashed away so that the redirection can be
4883 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
4884 * standard output, and the standard error if it becomes a duplicate of
4885 * stdout, is saved in memory.
4887 /* flags passed to redirect */
4888 #define REDIR_PUSH 01 /* save previous values of file descriptors */
4889 #define REDIR_SAVEFD2 03 /* set preverrout */
4891 redirect(union node *redir, int flags)
4894 struct redirtab *sv;
4905 if (flags & REDIR_PUSH) {
4906 sv = ckmalloc(sizeof(*sv));
4907 sv->next = redirlist;
4909 sv->nullredirs = g_nullredirs - 1;
4910 for (i = 0; i < 10; i++)
4911 sv->renamed[i] = EMPTY;
4917 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD)
4918 && n->ndup.dupfd == fd)
4919 continue; /* redirect from/to same file descriptor */
4921 newfd = openredirect(n);
4923 /* Descriptor wasn't open before redirect.
4924 * Mark it for close in the future */
4925 if (sv && sv->renamed[fd] == EMPTY)
4926 sv->renamed[fd] = CLOSED;
4929 if (sv && sv->renamed[fd] == EMPTY) {
4930 i = fcntl(fd, F_DUPFD, 10);
4937 ash_msg_and_raise_error("%d: %m", fd);
4941 sv->renamed[fd] = i;
4947 dupredirect(n, newfd);
4948 } while ((n = n->nfile.next));
4950 if ((flags & REDIR_SAVEFD2) && sv && sv->renamed[2] >= 0)
4951 preverrout_fd = sv->renamed[2];
4955 * Undo the effects of the last redirection.
4960 struct redirtab *rp;
4963 if (--g_nullredirs >= 0)
4967 for (i = 0; i < 10; i++) {
4968 if (rp->renamed[i] == CLOSED) {
4973 if (rp->renamed[i] != EMPTY) {
4976 copyfd(rp->renamed[i], i);
4978 close(rp->renamed[i]);
4981 redirlist = rp->next;
4982 g_nullredirs = rp->nullredirs;
4988 * Undo all redirections. Called on error or interrupt.
4992 * Discard all saved file descriptors.
4995 clearredir(int drop)
5006 redirectsafe(union node *redir, int flags)
5009 volatile int saveint;
5010 struct jmploc *volatile savehandler = exception_handler;
5011 struct jmploc jmploc;
5014 err = setjmp(jmploc.loc) * 2;
5016 exception_handler = &jmploc;
5017 redirect(redir, flags);
5019 exception_handler = savehandler;
5020 if (err && exception != EXERROR)
5021 longjmp(exception_handler->loc, 1);
5022 RESTORE_INT(saveint);
5027 /* ============ Routines to expand arguments to commands
5029 * We have to deal with backquotes, shell variables, and file metacharacters.
5035 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5036 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5037 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5038 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5039 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5040 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5041 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5042 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5043 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5047 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5048 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5049 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5050 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5051 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5054 * Structure specifying which parts of the string should be searched
5055 * for IFS characters.
5058 struct ifsregion *next; /* next region in list */
5059 int begoff; /* offset of start of region */
5060 int endoff; /* offset of end of region */
5061 int nulonly; /* search for nul bytes only */
5065 struct strlist *list;
5066 struct strlist **lastp;
5069 /* output of current string */
5070 static char *expdest;
5071 /* list of back quote expressions */
5072 static struct nodelist *argbackq;
5073 /* first struct in list of ifs regions */
5074 static struct ifsregion ifsfirst;
5075 /* last struct in list */
5076 static struct ifsregion *ifslastp;
5077 /* holds expanded arg list */
5078 static struct arglist exparg;
5088 expdest = makestrspace(32, expdest);
5089 #if ENABLE_ASH_MATH_SUPPORT_64
5090 len = fmtstr(expdest, 32, "%lld", (long long) num);
5092 len = fmtstr(expdest, 32, "%ld", num);
5094 STADJUST(len, expdest);
5099 esclen(const char *start, const char *p)
5103 while (p > start && *--p == CTLESC) {
5110 * Remove any CTLESC characters from a string.
5113 _rmescapes(char *str, int flag)
5115 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5122 p = strpbrk(str, qchars);
5128 if (flag & RMESCAPE_ALLOC) {
5129 size_t len = p - str;
5130 size_t fulllen = len + strlen(p) + 1;
5132 if (flag & RMESCAPE_GROW) {
5133 r = makestrspace(fulllen, expdest);
5134 } else if (flag & RMESCAPE_HEAP) {
5135 r = ckmalloc(fulllen);
5137 r = stalloc(fulllen);
5141 q = memcpy(q, str, len) + len;
5144 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5145 globbing = flag & RMESCAPE_GLOB;
5146 notescaped = globbing;
5148 if (*p == CTLQUOTEMARK) {
5149 inquotes = ~inquotes;
5151 notescaped = globbing;
5155 /* naked back slash */
5161 if (notescaped && inquotes && *p != '/') {
5165 notescaped = globbing;
5170 if (flag & RMESCAPE_GROW) {
5172 STADJUST(q - r + 1, expdest);
5176 #define rmescapes(p) _rmescapes((p), 0)
5178 #define pmatch(a, b) !fnmatch((a), (b), 0)
5181 * Prepare a pattern for a expmeta (internal glob(3)) call.
5183 * Returns an stalloced string.
5186 preglob(const char *pattern, int quoted, int flag)
5188 flag |= RMESCAPE_GLOB;
5190 flag |= RMESCAPE_QUOTED;
5192 return _rmescapes((char *)pattern, flag);
5196 * Put a string on the stack.
5199 memtodest(const char *p, size_t len, int syntax, int quotes)
5203 q = makestrspace(len * 2, q);
5206 int c = signed_char2int(*p++);
5209 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5218 strtodest(const char *p, int syntax, int quotes)
5220 memtodest(p, strlen(p), syntax, quotes);
5224 * Record the fact that we have to scan this region of the
5225 * string for IFS characters.
5228 recordregion(int start, int end, int nulonly)
5230 struct ifsregion *ifsp;
5232 if (ifslastp == NULL) {
5236 ifsp = ckzalloc(sizeof(*ifsp));
5237 /*ifsp->next = NULL; - ckzalloc did it */
5238 ifslastp->next = ifsp;
5242 ifslastp->begoff = start;
5243 ifslastp->endoff = end;
5244 ifslastp->nulonly = nulonly;
5248 removerecordregions(int endoff)
5250 if (ifslastp == NULL)
5253 if (ifsfirst.endoff > endoff) {
5254 while (ifsfirst.next != NULL) {
5255 struct ifsregion *ifsp;
5257 ifsp = ifsfirst.next->next;
5258 free(ifsfirst.next);
5259 ifsfirst.next = ifsp;
5262 if (ifsfirst.begoff > endoff)
5265 ifslastp = &ifsfirst;
5266 ifsfirst.endoff = endoff;
5271 ifslastp = &ifsfirst;
5272 while (ifslastp->next && ifslastp->next->begoff < endoff)
5273 ifslastp=ifslastp->next;
5274 while (ifslastp->next != NULL) {
5275 struct ifsregion *ifsp;
5277 ifsp = ifslastp->next->next;
5278 free(ifslastp->next);
5279 ifslastp->next = ifsp;
5282 if (ifslastp->endoff > endoff)
5283 ifslastp->endoff = endoff;
5287 exptilde(char *startp, char *p, int flag)
5293 int quotes = flag & (EXP_FULL | EXP_CASE);
5298 while ((c = *++p) != '\0') {
5305 if (flag & EXP_VARTILDE)
5315 if (*name == '\0') {
5316 home = lookupvar(homestr);
5318 pw = getpwnam(name);
5323 if (!home || !*home)
5326 startloc = expdest - (char *)stackblock();
5327 strtodest(home, SQSYNTAX, quotes);
5328 recordregion(startloc, expdest - (char *)stackblock(), 0);
5336 * Execute a command inside back quotes. If it's a builtin command, we
5337 * want to save its output in a block obtained from malloc. Otherwise
5338 * we fork off a subprocess and get the output of the command via a pipe.
5339 * Should be called with interrupts off.
5341 struct backcmd { /* result of evalbackcmd */
5342 int fd; /* file descriptor to read from */
5343 char *buf; /* buffer */
5344 int nleft; /* number of chars in buffer */
5345 struct job *jp; /* job structure for command */
5348 /* These forward decls are needed to use "eval" code for backticks handling: */
5349 static int back_exitstatus; /* exit status of backquoted command */
5350 #define EV_EXIT 01 /* exit after evaluating tree */
5351 static void evaltree(union node *, int);
5354 evalbackcmd(union node *n, struct backcmd *result)
5366 saveherefd = herefd;
5374 ash_msg_and_raise_error("pipe call failed");
5375 jp = makejob(/*n,*/ 1);
5376 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5385 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5389 result->fd = pip[0];
5392 herefd = saveherefd;
5394 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5395 result->fd, result->buf, result->nleft, result->jp));
5399 * Expand stuff in backwards quotes.
5402 expbackq(union node *cmd, int quoted, int quotes)
5410 int syntax = quoted? DQSYNTAX : BASESYNTAX;
5411 struct stackmark smark;
5414 setstackmark(&smark);
5416 startloc = dest - (char *)stackblock();
5418 evalbackcmd(cmd, &in);
5419 popstackmark(&smark);
5426 memtodest(p, i, syntax, quotes);
5430 i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5431 TRACE(("expbackq: read returns %d\n", i));
5440 back_exitstatus = waitforjob(in.jp);
5444 /* Eat all trailing newlines */
5446 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5451 recordregion(startloc, dest - (char *)stackblock(), 0);
5452 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5453 (dest - (char *)stackblock()) - startloc,
5454 (dest - (char *)stackblock()) - startloc,
5455 stackblock() + startloc));
5458 #if ENABLE_ASH_MATH_SUPPORT
5460 * Expand arithmetic expression. Backup to start of expression,
5461 * evaluate, place result in (backed up) result, adjust string position.
5474 * This routine is slightly over-complicated for
5475 * efficiency. Next we scan backwards looking for the
5476 * start of arithmetic.
5478 start = stackblock();
5485 while (*p != CTLARI) {
5489 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5494 esc = esclen(start, p);
5504 removerecordregions(begoff);
5513 len = cvtnum(dash_arith(p + 2));
5516 recordregion(begoff, begoff + len, 0);
5520 /* argstr needs it */
5521 static char *evalvar(char *p, int flag, struct strlist *var_str_list);
5524 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5525 * characters to allow for further processing. Otherwise treat
5526 * $@ like $* since no splitting will be performed.
5528 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5529 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5530 * for correct expansion of "B=$A" word.
5533 argstr(char *p, int flag, struct strlist *var_str_list)
5535 static const char spclchars[] ALIGN1 = {
5543 CTLBACKQ | CTLQUOTE,
5544 #if ENABLE_ASH_MATH_SUPPORT
5549 const char *reject = spclchars;
5551 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
5552 int breakall = flag & EXP_WORD;
5557 if (!(flag & EXP_VARTILDE)) {
5559 } else if (flag & EXP_VARTILDE2) {
5564 if (flag & EXP_TILDE) {
5570 if (*q == CTLESC && (flag & EXP_QWORD))
5573 p = exptilde(p, q, flag);
5576 startloc = expdest - (char *)stackblock();
5578 length += strcspn(p + length, reject);
5580 if (c && (!(c & 0x80)
5581 #if ENABLE_ASH_MATH_SUPPORT
5585 /* c == '=' || c == ':' || c == CTLENDARI */
5590 expdest = stack_nputstr(p, length, expdest);
5591 newloc = expdest - (char *)stackblock();
5592 if (breakall && !inquotes && newloc > startloc) {
5593 recordregion(startloc, newloc, 0);
5604 if (flag & EXP_VARTILDE2) {
5608 flag |= EXP_VARTILDE2;
5613 * sort of a hack - expand tildes in variable
5614 * assignments (after the first '=' and after ':'s).
5623 case CTLENDVAR: /* ??? */
5626 /* "$@" syntax adherence hack */
5629 !memcmp(p, dolatstr, 4) &&
5630 (p[4] == CTLQUOTEMARK || (
5631 p[4] == CTLENDVAR &&
5632 p[5] == CTLQUOTEMARK
5635 p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;
5638 inquotes = !inquotes;
5651 p = evalvar(p, flag, var_str_list);
5655 case CTLBACKQ|CTLQUOTE:
5656 expbackq(argbackq->n, c, quotes);
5657 argbackq = argbackq->next;
5659 #if ENABLE_ASH_MATH_SUPPORT
5672 scanleft(char *startp, char *rmesc, char *rmescend ATTRIBUTE_UNUSED, char *str, int quotes,
5683 const char *s = loc2;
5689 match = pmatch(str, s);
5693 if (quotes && *loc == CTLESC)
5702 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5709 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5712 const char *s = loc2;
5717 match = pmatch(str, s);
5724 esc = esclen(startp, loc);
5735 static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN;
5737 varunset(const char *end, const char *var, const char *umsg, int varflags)
5743 msg = "parameter not set";
5745 if (*end == CTLENDVAR) {
5746 if (varflags & VSNUL)
5751 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5755 subevalvar(char *p, char *str, int strloc, int subtype,
5756 int startloc, int varflags, int quotes, struct strlist *var_str_list)
5760 int saveherefd = herefd;
5761 struct nodelist *saveargbackq = argbackq;
5763 char *rmesc, *rmescend;
5765 char *(*scan)(char *, char *, char *, char *, int , int);
5768 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
5770 STPUTC('\0', expdest);
5771 herefd = saveherefd;
5772 argbackq = saveargbackq;
5773 startp = stackblock() + startloc;
5777 setvar(str, startp, 0);
5778 amount = startp - expdest;
5779 STADJUST(amount, expdest);
5783 varunset(p, str, startp, varflags);
5787 subtype -= VSTRIMRIGHT;
5789 if (subtype < 0 || subtype > 3)
5794 rmescend = stackblock() + strloc;
5796 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5797 if (rmesc != startp) {
5799 startp = stackblock() + startloc;
5803 str = stackblock() + strloc;
5804 preglob(str, varflags & VSQUOTE, 0);
5806 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5807 zero = subtype >> 1;
5808 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5809 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5811 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5814 memmove(startp, loc, str - loc);
5815 loc = startp + (str - loc) - 1;
5818 amount = loc - expdest;
5819 STADJUST(amount, expdest);
5825 * Add the value of a specialized variable to the stack string.
5828 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
5838 int quoted = varflags & VSQUOTE;
5839 int subtype = varflags & VSTYPE;
5840 int quotes = flags & (EXP_FULL | EXP_CASE);
5842 if (quoted && (flags & EXP_FULL))
5843 sep = 1 << CHAR_BIT;
5845 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5854 num = shellparam.nparam;
5864 p = makestrspace(NOPTS, expdest);
5865 for (i = NOPTS - 1; i >= 0; i--) {
5867 USTPUTC(optletters(i), p);
5878 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
5879 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5885 while ((p = *ap++)) {
5888 partlen = strlen(p);
5891 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5892 memtodest(p, partlen, syntax, quotes);
5898 if (subtype == VSPLUS || subtype == VSLENGTH) {
5920 if (num < 0 || num > shellparam.nparam)
5922 p = num ? shellparam.p[num - 1] : arg0;
5925 /* NB: name has form "VAR=..." */
5927 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
5928 * which should be considered before we check variables. */
5930 unsigned name_len = (strchrnul(name, '=') - name) + 1;
5934 str = var_str_list->text;
5935 eq = strchr(str, '=');
5936 if (!eq) /* stop at first non-assignment */
5939 if (name_len == (eq - str)
5940 && strncmp(str, name, name_len) == 0) {
5942 /* goto value; - WRONG! */
5943 /* think "A=1 A=2 B=$A" */
5945 var_str_list = var_str_list->next;
5946 } while (var_str_list);
5950 p = lookupvar(name);
5956 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5957 memtodest(p, len, syntax, quotes);
5961 if (subtype == VSPLUS || subtype == VSLENGTH)
5962 STADJUST(-len, expdest);
5967 * Expand a variable, and return a pointer to the next character in the
5971 evalvar(char *p, int flag, struct strlist *var_str_list)
5983 subtype = varflags & VSTYPE;
5984 quoted = varflags & VSQUOTE;
5986 easy = (!quoted || (*var == '@' && shellparam.nparam));
5987 startloc = expdest - (char *)stackblock();
5988 p = strchr(p, '=') + 1;
5991 varlen = varvalue(var, varflags, flag, var_str_list);
5992 if (varflags & VSNUL)
5995 if (subtype == VSPLUS) {
5996 varlen = -1 - varlen;
6000 if (subtype == VSMINUS) {
6004 p, flag | EXP_TILDE |
6005 (quoted ? EXP_QWORD : EXP_WORD),
6015 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6017 if (subevalvar(p, var, /* strloc: */ 0,
6018 subtype, startloc, varflags,
6024 * Remove any recorded regions beyond
6027 removerecordregions(startloc);
6037 if (varlen < 0 && uflag)
6038 varunset(p, var, 0, 0);
6040 if (subtype == VSLENGTH) {
6041 cvtnum(varlen > 0 ? varlen : 0);
6045 if (subtype == VSNORMAL) {
6056 case VSTRIMRIGHTMAX:
6065 * Terminate the string and start recording the pattern
6068 STPUTC('\0', expdest);
6069 patloc = expdest - (char *)stackblock();
6070 if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6072 /* quotes: */ flag & (EXP_FULL | EXP_CASE),
6075 int amount = expdest - (
6076 (char *)stackblock() + patloc - 1
6078 STADJUST(-amount, expdest);
6080 /* Remove any recorded regions beyond start of variable */
6081 removerecordregions(startloc);
6083 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6087 if (subtype != VSNORMAL) { /* skip to end of alternative */
6093 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6095 argbackq = argbackq->next;
6096 } else if (c == CTLVAR) {
6097 if ((*p++ & VSTYPE) != VSNORMAL)
6099 } else if (c == CTLENDVAR) {
6109 * Break the argument string into pieces based upon IFS and add the
6110 * strings to the argument list. The regions of the string to be
6111 * searched for IFS characters have been stored by recordregion.
6114 ifsbreakup(char *string, struct arglist *arglist)
6116 struct ifsregion *ifsp;
6121 const char *ifs, *realifs;
6126 if (ifslastp != NULL) {
6129 realifs = ifsset() ? ifsval() : defifs;
6132 p = string + ifsp->begoff;
6133 nulonly = ifsp->nulonly;
6134 ifs = nulonly ? nullstr : realifs;
6136 while (p < string + ifsp->endoff) {
6140 if (!strchr(ifs, *p)) {
6145 ifsspc = (strchr(defifs, *p) != NULL);
6146 /* Ignore IFS whitespace at start */
6147 if (q == start && ifsspc) {
6153 sp = stzalloc(sizeof(*sp));
6155 *arglist->lastp = sp;
6156 arglist->lastp = &sp->next;
6160 if (p >= string + ifsp->endoff) {
6166 if (strchr(ifs, *p) == NULL ) {
6170 if (strchr(defifs, *p) == NULL) {
6185 } while (ifsp != NULL);
6194 sp = stzalloc(sizeof(*sp));
6196 *arglist->lastp = sp;
6197 arglist->lastp = &sp->next;
6203 struct ifsregion *p;
6208 struct ifsregion *ifsp;
6214 ifsfirst.next = NULL;
6219 * Add a file name to the list.
6222 addfname(const char *name)
6226 sp = stzalloc(sizeof(*sp));
6227 sp->text = ststrdup(name);
6229 exparg.lastp = &sp->next;
6232 static char *expdir;
6235 * Do metacharacter (i.e. *, ?, [...]) expansion.
6238 expmeta(char *enddir, char *name)
6253 for (p = name; *p; p++) {
6254 if (*p == '*' || *p == '?')
6256 else if (*p == '[') {
6263 if (*q == '/' || *q == '\0')
6270 } else if (*p == '\\')
6272 else if (*p == '/') {
6279 if (metaflag == 0) { /* we've reached the end of the file name */
6280 if (enddir != expdir)
6288 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6299 } while (p < start);
6301 if (enddir == expdir) {
6303 } else if (enddir == expdir + 1 && *expdir == '/') {
6312 if (enddir != expdir)
6314 if (*endname == 0) {
6326 while (!intpending && (dp = readdir(dirp)) != NULL) {
6327 if (dp->d_name[0] == '.' && ! matchdot)
6329 if (pmatch(start, dp->d_name)) {
6331 strcpy(enddir, dp->d_name);
6334 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6337 expmeta(p, endname);
6346 static struct strlist *
6347 msort(struct strlist *list, int len)
6349 struct strlist *p, *q = NULL;
6350 struct strlist **lpp;
6358 for (n = half; --n >= 0; ) {
6362 q->next = NULL; /* terminate first half of list */
6363 q = msort(list, half); /* sort first half of list */
6364 p = msort(p, len - half); /* sort second half */
6367 #if ENABLE_LOCALE_SUPPORT
6368 if (strcoll(p->text, q->text) < 0)
6370 if (strcmp(p->text, q->text) < 0)
6394 * Sort the results of file name expansion. It calculates the number of
6395 * strings to sort and then calls msort (short for merge sort) to do the
6398 static struct strlist *
6399 expsort(struct strlist *str)
6405 for (sp = str; sp; sp = sp->next)
6407 return msort(str, len);
6411 expandmeta(struct strlist *str /*, int flag*/)
6413 static const char metachars[] ALIGN1 = {
6416 /* TODO - EXP_REDIR */
6419 struct strlist **savelastp;
6425 if (!strpbrk(str->text, metachars))
6427 savelastp = exparg.lastp;
6430 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
6432 int i = strlen(str->text);
6433 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
6441 if (exparg.lastp == savelastp) {
6446 *exparg.lastp = str;
6447 rmescapes(str->text);
6448 exparg.lastp = &str->next;
6450 *exparg.lastp = NULL;
6451 *savelastp = sp = expsort(*savelastp);
6452 while (sp->next != NULL)
6454 exparg.lastp = &sp->next;
6461 * Perform variable substitution and command substitution on an argument,
6462 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6463 * perform splitting and file name expansion. When arglist is NULL, perform
6464 * here document expansion.
6467 expandarg(union node *arg, struct arglist *arglist, int flag)
6472 argbackq = arg->narg.backquote;
6473 STARTSTACKSTR(expdest);
6474 ifsfirst.next = NULL;
6476 argstr(arg->narg.text, flag,
6477 /* var_str_list: */ arglist ? arglist->list : NULL);
6478 p = _STPUTC('\0', expdest);
6480 if (arglist == NULL) {
6481 return; /* here document expanded */
6483 p = grabstackstr(p);
6484 exparg.lastp = &exparg.list;
6488 if (flag & EXP_FULL) {
6489 ifsbreakup(p, &exparg);
6490 *exparg.lastp = NULL;
6491 exparg.lastp = &exparg.list;
6492 expandmeta(exparg.list /*, flag*/);
6494 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
6496 sp = stzalloc(sizeof(*sp));
6499 exparg.lastp = &sp->next;
6503 *exparg.lastp = NULL;
6505 *arglist->lastp = exparg.list;
6506 arglist->lastp = exparg.lastp;
6511 * Expand shell variables and backquotes inside a here document.
6514 expandhere(union node *arg, int fd)
6517 expandarg(arg, (struct arglist *)NULL, 0);
6518 full_write(fd, stackblock(), expdest - (char *)stackblock());
6522 * Returns true if the pattern matches the string.
6525 patmatch(char *pattern, const char *string)
6527 return pmatch(preglob(pattern, 0, 0), string);
6531 * See if a pattern matches in a case statement.
6534 casematch(union node *pattern, char *val)
6536 struct stackmark smark;
6539 setstackmark(&smark);
6540 argbackq = pattern->narg.backquote;
6541 STARTSTACKSTR(expdest);
6543 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
6544 /* var_str_list: */ NULL);
6545 STACKSTRNUL(expdest);
6546 result = patmatch(stackblock(), val);
6547 popstackmark(&smark);
6552 /* ============ find_command */
6556 int (*builtin)(int, char **);
6557 /* unsigned flags; */
6559 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
6560 /* "regular" builtins always take precedence over commands,
6561 * regardless of PATH=....%builtin... position */
6562 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
6563 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
6569 const struct builtincmd *cmd;
6570 struct funcnode *func;
6573 /* values of cmdtype */
6574 #define CMDUNKNOWN -1 /* no entry in table for command */
6575 #define CMDNORMAL 0 /* command is an executable program */
6576 #define CMDFUNCTION 1 /* command is a shell function */
6577 #define CMDBUILTIN 2 /* command is a shell builtin */
6579 /* action to find_command() */
6580 #define DO_ERR 0x01 /* prints errors */
6581 #define DO_ABS 0x02 /* checks absolute paths */
6582 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
6583 #define DO_ALTPATH 0x08 /* using alternate path */
6584 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
6586 static void find_command(char *, struct cmdentry *, int, const char *);
6589 /* ============ Hashing commands */
6592 * When commands are first encountered, they are entered in a hash table.
6593 * This ensures that a full path search will not have to be done for them
6594 * on each invocation.
6596 * We should investigate converting to a linear search, even though that
6597 * would make the command name "hash" a misnomer.
6600 #define ARB 1 /* actual size determined at run time */
6603 struct tblentry *next; /* next entry in hash chain */
6604 union param param; /* definition of builtin function */
6605 short cmdtype; /* index identifying command */
6606 char rehash; /* if set, cd done since entry created */
6607 char cmdname[ARB]; /* name of command */
6610 static struct tblentry **cmdtable;
6611 #define INIT_G_cmdtable() do { \
6612 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
6615 static int builtinloc = -1; /* index in path of %builtin, or -1 */
6619 tryexec(char *cmd, char **argv, char **envp)
6623 #if ENABLE_FEATURE_SH_STANDALONE
6624 if (strchr(cmd, '/') == NULL) {
6625 int a = find_applet_by_name(cmd);
6627 if (APPLET_IS_NOEXEC(a))
6628 run_applet_no_and_exit(a, argv);
6629 /* re-exec ourselves with the new arguments */
6630 execve(bb_busybox_exec_path, argv, envp);
6631 /* If they called chroot or otherwise made the binary no longer
6632 * executable, fall through */
6640 execve(cmd, argv, envp);
6641 } while (errno == EINTR);
6643 execve(cmd, argv, envp);
6647 } else if (errno == ENOEXEC) {
6651 for (ap = argv; *ap; ap++)
6653 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
6655 ap[0] = cmd = (char *)DEFAULT_SHELL;
6658 while ((*ap++ = *argv++))
6666 * Exec a program. Never returns. If you change this routine, you may
6667 * have to change the find_command routine as well.
6669 #define environment() listvars(VEXPORT, VUNSET, 0)
6670 static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
6672 shellexec(char **argv, const char *path, int idx)
6680 envp = environment();
6681 if (strchr(argv[0], '/')
6682 #if ENABLE_FEATURE_SH_STANDALONE
6683 || find_applet_by_name(argv[0]) >= 0
6686 tryexec(argv[0], argv, envp);
6690 while ((cmdname = padvance(&path, argv[0])) != NULL) {
6691 if (--idx < 0 && pathopt == NULL) {
6692 tryexec(cmdname, argv, envp);
6693 if (errno != ENOENT && errno != ENOTDIR)
6700 /* Map to POSIX errors */
6712 exitstatus = exerrno;
6713 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
6714 argv[0], e, suppressint ));
6715 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
6720 printentry(struct tblentry *cmdp)
6726 idx = cmdp->param.index;
6729 name = padvance(&path, cmdp->cmdname);
6731 } while (--idx >= 0);
6732 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
6736 * Clear out command entries. The argument specifies the first entry in
6737 * PATH which has changed.
6740 clearcmdentry(int firstchange)
6742 struct tblentry **tblp;
6743 struct tblentry **pp;
6744 struct tblentry *cmdp;
6747 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
6749 while ((cmdp = *pp) != NULL) {
6750 if ((cmdp->cmdtype == CMDNORMAL &&
6751 cmdp->param.index >= firstchange)
6752 || (cmdp->cmdtype == CMDBUILTIN &&
6753 builtinloc >= firstchange)
6766 * Locate a command in the command hash table. If "add" is nonzero,
6767 * add the command to the table if it is not already present. The
6768 * variable "lastcmdentry" is set to point to the address of the link
6769 * pointing to the entry, so that delete_cmd_entry can delete the
6772 * Interrupts must be off if called with add != 0.
6774 static struct tblentry **lastcmdentry;
6776 static struct tblentry *
6777 cmdlookup(const char *name, int add)
6779 unsigned int hashval;
6781 struct tblentry *cmdp;
6782 struct tblentry **pp;
6785 hashval = (unsigned char)*p << 4;
6787 hashval += (unsigned char)*p++;
6789 pp = &cmdtable[hashval % CMDTABLESIZE];
6790 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6791 if (strcmp(cmdp->cmdname, name) == 0)
6795 if (add && cmdp == NULL) {
6796 cmdp = *pp = ckzalloc(sizeof(struct tblentry) - ARB
6797 + strlen(name) + 1);
6798 /*cmdp->next = NULL; - ckzalloc did it */
6799 cmdp->cmdtype = CMDUNKNOWN;
6800 strcpy(cmdp->cmdname, name);
6807 * Delete the command entry returned on the last lookup.
6810 delete_cmd_entry(void)
6812 struct tblentry *cmdp;
6815 cmdp = *lastcmdentry;
6816 *lastcmdentry = cmdp->next;
6817 if (cmdp->cmdtype == CMDFUNCTION)
6818 freefunc(cmdp->param.func);
6824 * Add a new command entry, replacing any existing command entry for
6825 * the same name - except special builtins.
6828 addcmdentry(char *name, struct cmdentry *entry)
6830 struct tblentry *cmdp;
6832 cmdp = cmdlookup(name, 1);
6833 if (cmdp->cmdtype == CMDFUNCTION) {
6834 freefunc(cmdp->param.func);
6836 cmdp->cmdtype = entry->cmdtype;
6837 cmdp->param = entry->u;
6842 hashcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
6844 struct tblentry **pp;
6845 struct tblentry *cmdp;
6847 struct cmdentry entry;
6850 if (nextopt("r") != '\0') {
6855 if (*argptr == NULL) {
6856 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
6857 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6858 if (cmdp->cmdtype == CMDNORMAL)
6866 while ((name = *argptr) != NULL) {
6867 cmdp = cmdlookup(name, 0);
6869 && (cmdp->cmdtype == CMDNORMAL
6870 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
6874 find_command(name, &entry, DO_ERR, pathval());
6875 if (entry.cmdtype == CMDUNKNOWN)
6883 * Called when a cd is done. Marks all commands so the next time they
6884 * are executed they will be rehashed.
6889 struct tblentry **pp;
6890 struct tblentry *cmdp;
6892 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
6893 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6894 if (cmdp->cmdtype == CMDNORMAL
6895 || (cmdp->cmdtype == CMDBUILTIN
6896 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
6906 * Fix command hash table when PATH changed.
6907 * Called before PATH is changed. The argument is the new value of PATH;
6908 * pathval() still returns the old value at this point.
6909 * Called with interrupts off.
6912 changepath(const char *new)
6920 firstchange = 9999; /* assume no change */
6926 if ((*old == '\0' && *new == ':')
6927 || (*old == ':' && *new == '\0'))
6929 old = new; /* ignore subsequent differences */
6933 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
6939 if (builtinloc < 0 && idx_bltin >= 0)
6940 builtinloc = idx_bltin; /* zap builtins */
6941 if (builtinloc >= 0 && idx_bltin < 0)
6943 clearcmdentry(firstchange);
6944 builtinloc = idx_bltin;
6959 #define TENDBQUOTE 12
6977 /* first char is indicating which tokens mark the end of a list */
6978 static const char *const tokname_array[] = {
6992 #define KWDOFFSET 13
6993 /* the following are keywords */
7015 static char buf[16];
7018 //if (tok < TSEMI) return tokname_array[tok] + 1;
7019 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
7024 sprintf(buf + (tok >= TSEMI), "%s%c",
7025 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
7029 /* Wrapper around strcmp for qsort/bsearch/... */
7031 pstrcmp(const void *a, const void *b)
7033 return strcmp((char*) a, (*(char**) b) + 1);
7036 static const char *const *
7037 findkwd(const char *s)
7039 return bsearch(s, tokname_array + KWDOFFSET,
7040 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7041 sizeof(tokname_array[0]), pstrcmp);
7045 * Locate and print what a word is...
7048 describe_command(char *command, int describe_command_verbose)
7050 struct cmdentry entry;
7051 struct tblentry *cmdp;
7052 #if ENABLE_ASH_ALIAS
7053 const struct alias *ap;
7055 const char *path = pathval();
7057 if (describe_command_verbose) {
7061 /* First look at the keywords */
7062 if (findkwd(command)) {
7063 out1str(describe_command_verbose ? " is a shell keyword" : command);
7067 #if ENABLE_ASH_ALIAS
7068 /* Then look at the aliases */
7069 ap = lookupalias(command, 0);
7071 if (!describe_command_verbose) {
7076 out1fmt(" is an alias for %s", ap->val);
7080 /* Then check if it is a tracked alias */
7081 cmdp = cmdlookup(command, 0);
7083 entry.cmdtype = cmdp->cmdtype;
7084 entry.u = cmdp->param;
7086 /* Finally use brute force */
7087 find_command(command, &entry, DO_ABS, path);
7090 switch (entry.cmdtype) {
7092 int j = entry.u.index;
7098 p = padvance(&path, command);
7102 if (describe_command_verbose) {
7104 (cmdp ? " a tracked alias for" : nullstr), p
7113 if (describe_command_verbose) {
7114 out1str(" is a shell function");
7121 if (describe_command_verbose) {
7122 out1fmt(" is a %sshell builtin",
7123 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7124 "special " : nullstr
7132 if (describe_command_verbose) {
7133 out1str(": not found\n");
7138 outstr("\n", stdout);
7143 typecmd(int argc ATTRIBUTE_UNUSED, char **argv)
7149 /* type -p ... ? (we don't bother checking for 'p') */
7150 if (argv[1] && argv[1][0] == '-') {
7155 err |= describe_command(argv[i++], verbose);
7160 #if ENABLE_ASH_CMDCMD
7162 commandcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
7170 while ((c = nextopt("pvV")) != '\0')
7172 verify |= VERIFY_VERBOSE;
7174 verify |= VERIFY_BRIEF;
7180 return describe_command(*argptr, verify - VERIFY_BRIEF);
7187 /* ============ eval.c */
7189 static int funcblocksize; /* size of structures in function */
7190 static int funcstringsize; /* size of strings in node */
7191 static void *funcblock; /* block to allocate function from */
7192 static char *funcstring; /* block to allocate strings from */
7194 /* flags in argument to evaltree */
7195 #define EV_EXIT 01 /* exit after evaluating tree */
7196 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7197 #define EV_BACKCMD 04 /* command executing within back quotes */
7199 static const short nodesize[26] = {
7200 SHELL_ALIGN(sizeof(struct ncmd)),
7201 SHELL_ALIGN(sizeof(struct npipe)),
7202 SHELL_ALIGN(sizeof(struct nredir)),
7203 SHELL_ALIGN(sizeof(struct nredir)),
7204 SHELL_ALIGN(sizeof(struct nredir)),
7205 SHELL_ALIGN(sizeof(struct nbinary)),
7206 SHELL_ALIGN(sizeof(struct nbinary)),
7207 SHELL_ALIGN(sizeof(struct nbinary)),
7208 SHELL_ALIGN(sizeof(struct nif)),
7209 SHELL_ALIGN(sizeof(struct nbinary)),
7210 SHELL_ALIGN(sizeof(struct nbinary)),
7211 SHELL_ALIGN(sizeof(struct nfor)),
7212 SHELL_ALIGN(sizeof(struct ncase)),
7213 SHELL_ALIGN(sizeof(struct nclist)),
7214 SHELL_ALIGN(sizeof(struct narg)),
7215 SHELL_ALIGN(sizeof(struct narg)),
7216 SHELL_ALIGN(sizeof(struct nfile)),
7217 SHELL_ALIGN(sizeof(struct nfile)),
7218 SHELL_ALIGN(sizeof(struct nfile)),
7219 SHELL_ALIGN(sizeof(struct nfile)),
7220 SHELL_ALIGN(sizeof(struct nfile)),
7221 SHELL_ALIGN(sizeof(struct ndup)),
7222 SHELL_ALIGN(sizeof(struct ndup)),
7223 SHELL_ALIGN(sizeof(struct nhere)),
7224 SHELL_ALIGN(sizeof(struct nhere)),
7225 SHELL_ALIGN(sizeof(struct nnot)),
7228 static void calcsize(union node *n);
7231 sizenodelist(struct nodelist *lp)
7234 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7241 calcsize(union node *n)
7245 funcblocksize += nodesize[n->type];
7248 calcsize(n->ncmd.redirect);
7249 calcsize(n->ncmd.args);
7250 calcsize(n->ncmd.assign);
7253 sizenodelist(n->npipe.cmdlist);
7258 calcsize(n->nredir.redirect);
7259 calcsize(n->nredir.n);
7266 calcsize(n->nbinary.ch2);
7267 calcsize(n->nbinary.ch1);
7270 calcsize(n->nif.elsepart);
7271 calcsize(n->nif.ifpart);
7272 calcsize(n->nif.test);
7275 funcstringsize += strlen(n->nfor.var) + 1;
7276 calcsize(n->nfor.body);
7277 calcsize(n->nfor.args);
7280 calcsize(n->ncase.cases);
7281 calcsize(n->ncase.expr);
7284 calcsize(n->nclist.body);
7285 calcsize(n->nclist.pattern);
7286 calcsize(n->nclist.next);
7290 sizenodelist(n->narg.backquote);
7291 funcstringsize += strlen(n->narg.text) + 1;
7292 calcsize(n->narg.next);
7299 calcsize(n->nfile.fname);
7300 calcsize(n->nfile.next);
7304 calcsize(n->ndup.vname);
7305 calcsize(n->ndup.next);
7309 calcsize(n->nhere.doc);
7310 calcsize(n->nhere.next);
7313 calcsize(n->nnot.com);
7319 nodeckstrdup(char *s)
7321 char *rtn = funcstring;
7323 strcpy(funcstring, s);
7324 funcstring += strlen(s) + 1;
7328 static union node *copynode(union node *);
7330 static struct nodelist *
7331 copynodelist(struct nodelist *lp)
7333 struct nodelist *start;
7334 struct nodelist **lpp;
7339 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7340 (*lpp)->n = copynode(lp->n);
7342 lpp = &(*lpp)->next;
7349 copynode(union node *n)
7356 funcblock = (char *) funcblock + nodesize[n->type];
7360 new->ncmd.redirect = copynode(n->ncmd.redirect);
7361 new->ncmd.args = copynode(n->ncmd.args);
7362 new->ncmd.assign = copynode(n->ncmd.assign);
7365 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7366 new->npipe.backgnd = n->npipe.backgnd;
7371 new->nredir.redirect = copynode(n->nredir.redirect);
7372 new->nredir.n = copynode(n->nredir.n);
7379 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7380 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7383 new->nif.elsepart = copynode(n->nif.elsepart);
7384 new->nif.ifpart = copynode(n->nif.ifpart);
7385 new->nif.test = copynode(n->nif.test);
7388 new->nfor.var = nodeckstrdup(n->nfor.var);
7389 new->nfor.body = copynode(n->nfor.body);
7390 new->nfor.args = copynode(n->nfor.args);
7393 new->ncase.cases = copynode(n->ncase.cases);
7394 new->ncase.expr = copynode(n->ncase.expr);
7397 new->nclist.body = copynode(n->nclist.body);
7398 new->nclist.pattern = copynode(n->nclist.pattern);
7399 new->nclist.next = copynode(n->nclist.next);
7403 new->narg.backquote = copynodelist(n->narg.backquote);
7404 new->narg.text = nodeckstrdup(n->narg.text);
7405 new->narg.next = copynode(n->narg.next);
7412 new->nfile.fname = copynode(n->nfile.fname);
7413 new->nfile.fd = n->nfile.fd;
7414 new->nfile.next = copynode(n->nfile.next);
7418 new->ndup.vname = copynode(n->ndup.vname);
7419 new->ndup.dupfd = n->ndup.dupfd;
7420 new->ndup.fd = n->ndup.fd;
7421 new->ndup.next = copynode(n->ndup.next);
7425 new->nhere.doc = copynode(n->nhere.doc);
7426 new->nhere.fd = n->nhere.fd;
7427 new->nhere.next = copynode(n->nhere.next);
7430 new->nnot.com = copynode(n->nnot.com);
7433 new->type = n->type;
7438 * Make a copy of a parse tree.
7440 static struct funcnode *
7441 copyfunc(union node *n)
7446 funcblocksize = offsetof(struct funcnode, n);
7449 blocksize = funcblocksize;
7450 f = ckmalloc(blocksize + funcstringsize);
7451 funcblock = (char *) f + offsetof(struct funcnode, n);
7452 funcstring = (char *) f + blocksize;
7459 * Define a shell function.
7462 defun(char *name, union node *func)
7464 struct cmdentry entry;
7467 entry.cmdtype = CMDFUNCTION;
7468 entry.u.func = copyfunc(func);
7469 addcmdentry(name, &entry);
7473 static int evalskip; /* set if we are skipping commands */
7474 /* reasons for skipping commands (see comment on breakcmd routine) */
7475 #define SKIPBREAK (1 << 0)
7476 #define SKIPCONT (1 << 1)
7477 #define SKIPFUNC (1 << 2)
7478 #define SKIPFILE (1 << 3)
7479 #define SKIPEVAL (1 << 4)
7480 static int skipcount; /* number of levels to skip */
7481 static int funcnest; /* depth of function calls */
7483 /* forward decl way out to parsing code - dotrap needs it */
7484 static int evalstring(char *s, int mask);
7487 * Called to execute a trap. Perhaps we should avoid entering new trap
7488 * handlers while we are executing a trap handler.
7499 savestatus = exitstatus;
7503 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
7511 skip = evalstring(p, SKIPEVAL);
7512 exitstatus = savestatus;
7520 /* forward declarations - evaluation is fairly recursive business... */
7521 static void evalloop(union node *, int);
7522 static void evalfor(union node *, int);
7523 static void evalcase(union node *, int);
7524 static void evalsubshell(union node *, int);
7525 static void expredir(union node *);
7526 static void evalpipe(union node *, int);
7527 static void evalcommand(union node *, int);
7528 static int evalbltin(const struct builtincmd *, int, char **);
7529 static void prehash(union node *);
7532 * Evaluate a parse tree. The value is left in the global variable
7536 evaltree(union node *n, int flags)
7539 void (*evalfn)(union node *, int);
7543 TRACE(("evaltree(NULL) called\n"));
7546 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
7547 getpid(), n, n->type, flags));
7551 out1fmt("Node type = %d\n", n->type);
7556 evaltree(n->nnot.com, EV_TESTED);
7557 status = !exitstatus;
7560 expredir(n->nredir.redirect);
7561 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
7563 evaltree(n->nredir.n, flags & EV_TESTED);
7564 status = exitstatus;
7569 evalfn = evalcommand;
7571 if (eflag && !(flags & EV_TESTED))
7583 evalfn = evalsubshell;
7595 #error NAND + 1 != NOR
7597 #if NOR + 1 != NSEMI
7598 #error NOR + 1 != NSEMI
7600 isor = n->type - NAND;
7603 (flags | ((isor >> 1) - 1)) & EV_TESTED
7605 if (!exitstatus == isor)
7617 evaltree(n->nif.test, EV_TESTED);
7620 if (exitstatus == 0) {
7623 } else if (n->nif.elsepart) {
7624 n = n->nif.elsepart;
7629 defun(n->narg.text, n->narg.next);
7633 exitstatus = status;
7637 if ((checkexit & exitstatus))
7638 evalskip |= SKIPEVAL;
7639 else if (pendingsig && dotrap())
7642 if (flags & EV_EXIT) {
7644 raise_exception(EXEXIT);
7648 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
7651 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
7653 static int loopnest; /* current loop nesting level */
7656 evalloop(union node *n, int flags)
7666 evaltree(n->nbinary.ch1, EV_TESTED);
7669 if (evalskip == SKIPCONT && --skipcount <= 0) {
7673 if (evalskip == SKIPBREAK && --skipcount <= 0)
7678 if (n->type != NWHILE)
7682 evaltree(n->nbinary.ch2, flags);
7683 status = exitstatus;
7688 exitstatus = status;
7692 evalfor(union node *n, int flags)
7694 struct arglist arglist;
7697 struct stackmark smark;
7699 setstackmark(&smark);
7700 arglist.list = NULL;
7701 arglist.lastp = &arglist.list;
7702 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
7703 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
7708 *arglist.lastp = NULL;
7713 for (sp = arglist.list; sp; sp = sp->next) {
7714 setvar(n->nfor.var, sp->text, 0);
7715 evaltree(n->nfor.body, flags);
7717 if (evalskip == SKIPCONT && --skipcount <= 0) {
7721 if (evalskip == SKIPBREAK && --skipcount <= 0)
7728 popstackmark(&smark);
7732 evalcase(union node *n, int flags)
7736 struct arglist arglist;
7737 struct stackmark smark;
7739 setstackmark(&smark);
7740 arglist.list = NULL;
7741 arglist.lastp = &arglist.list;
7742 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
7744 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
7745 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
7746 if (casematch(patp, arglist.list->text)) {
7747 if (evalskip == 0) {
7748 evaltree(cp->nclist.body, flags);
7755 popstackmark(&smark);
7759 * Kick off a subshell to evaluate a tree.
7762 evalsubshell(union node *n, int flags)
7765 int backgnd = (n->type == NBACKGND);
7768 expredir(n->nredir.redirect);
7769 if (!backgnd && flags & EV_EXIT && !trap[0])
7772 jp = makejob(/*n,*/ 1);
7773 if (forkshell(jp, n, backgnd) == 0) {
7777 flags &=~ EV_TESTED;
7779 redirect(n->nredir.redirect, 0);
7780 evaltreenr(n->nredir.n, flags);
7785 status = waitforjob(jp);
7786 exitstatus = status;
7791 * Compute the names of the files in a redirection list.
7793 static void fixredir(union node *, const char *, int);
7795 expredir(union node *n)
7799 for (redir = n; redir; redir = redir->nfile.next) {
7803 fn.lastp = &fn.list;
7804 switch (redir->type) {
7810 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
7811 redir->nfile.expfname = fn.list->text;
7815 if (redir->ndup.vname) {
7816 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
7817 if (fn.list == NULL)
7818 ash_msg_and_raise_error("redir error");
7819 fixredir(redir, fn.list->text, 1);
7827 * Evaluate a pipeline. All the processes in the pipeline are children
7828 * of the process creating the pipeline. (This differs from some versions
7829 * of the shell, which make the last process in a pipeline the parent
7833 evalpipe(union node *n, int flags)
7836 struct nodelist *lp;
7841 TRACE(("evalpipe(0x%lx) called\n", (long)n));
7843 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
7847 jp = makejob(/*n,*/ pipelen);
7849 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
7853 if (pipe(pip) < 0) {
7855 ash_msg_and_raise_error("pipe call failed");
7858 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
7871 evaltreenr(lp->n, flags);
7879 if (n->npipe.backgnd == 0) {
7880 exitstatus = waitforjob(jp);
7881 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
7887 * Controls whether the shell is interactive or not.
7890 setinteractive(int on)
7892 static int is_interactive;
7894 if (++on == is_interactive)
7896 is_interactive = on;
7900 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
7901 if (is_interactive > 1) {
7902 /* Looks like they want an interactive shell */
7903 static smallint did_banner;
7908 "%s built-in shell (ash)\n"
7909 "Enter 'help' for a list of built-in commands."
7918 #if ENABLE_FEATURE_EDITING_VI
7919 #define setvimode(on) do { \
7920 if (on) line_input_state->flags |= VI_MODE; \
7921 else line_input_state->flags &= ~VI_MODE; \
7924 #define setvimode(on) viflag = 0 /* forcibly keep the option off */
7933 setinteractive(iflag);
7938 static struct localvar *localvars;
7941 * Called after a function returns.
7942 * Interrupts must be off.
7947 struct localvar *lvp;
7950 while ((lvp = localvars) != NULL) {
7951 localvars = lvp->next;
7953 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
7954 if (vp == NULL) { /* $- saved */
7955 memcpy(optlist, lvp->text, sizeof(optlist));
7956 free((char*)lvp->text);
7958 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
7962 (*vp->func)(strchrnul(lvp->text, '=') + 1);
7963 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
7964 free((char*)vp->text);
7965 vp->flags = lvp->flags;
7966 vp->text = lvp->text;
7973 evalfun(struct funcnode *func, int argc, char **argv, int flags)
7975 volatile struct shparam saveparam;
7976 struct localvar *volatile savelocalvars;
7977 struct jmploc *volatile savehandler;
7978 struct jmploc jmploc;
7981 saveparam = shellparam;
7982 savelocalvars = localvars;
7983 e = setjmp(jmploc.loc);
7988 savehandler = exception_handler;
7989 exception_handler = &jmploc;
7991 shellparam.malloced = 0;
7995 shellparam.nparam = argc - 1;
7996 shellparam.p = argv + 1;
7997 #if ENABLE_ASH_GETOPTS
7998 shellparam.optind = 1;
7999 shellparam.optoff = -1;
8001 evaltree(&func->n, flags & EV_TESTED);
8007 localvars = savelocalvars;
8008 freeparam(&shellparam);
8009 shellparam = saveparam;
8010 exception_handler = savehandler;
8012 evalskip &= ~SKIPFUNC;
8016 #if ENABLE_ASH_CMDCMD
8018 parse_command_args(char **argv, const char **path)
8031 if (c == '-' && !*cp) {
8038 *path = bb_default_path;
8041 /* run 'typecmd' for other options */
8052 * Make a variable a local variable. When a variable is made local, it's
8053 * value and flags are saved in a localvar structure. The saved values
8054 * will be restored when the shell function returns. We handle the name
8055 * "-" as a special case.
8060 struct localvar *lvp;
8065 lvp = ckzalloc(sizeof(struct localvar));
8066 if (LONE_DASH(name)) {
8068 p = ckmalloc(sizeof(optlist));
8069 lvp->text = memcpy(p, optlist, sizeof(optlist));
8074 vpp = hashvar(name);
8075 vp = *findvar(vpp, name);
8076 eq = strchr(name, '=');
8079 setvareq(name, VSTRFIXED);
8081 setvar(name, NULL, VSTRFIXED);
8082 vp = *vpp; /* the new variable */
8083 lvp->flags = VUNSET;
8085 lvp->text = vp->text;
8086 lvp->flags = vp->flags;
8087 vp->flags |= VSTRFIXED|VTEXTFIXED;
8093 lvp->next = localvars;
8099 * The "local" command.
8102 localcmd(int argc ATTRIBUTE_UNUSED, char **argv)
8107 while ((name = *argv++) != NULL) {
8114 falsecmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
8120 truecmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
8126 execcmd(int argc ATTRIBUTE_UNUSED, char **argv)
8129 iflag = 0; /* exit on error */
8132 shellexec(argv + 1, pathval(), 0);
8138 * The return command.
8141 returncmd(int argc ATTRIBUTE_UNUSED, char **argv)
8144 * If called outside a function, do what ksh does;
8145 * skip the rest of the file.
8147 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8148 return argv[1] ? number(argv[1]) : exitstatus;
8151 /* Forward declarations for builtintab[] */
8152 static int breakcmd(int, char **);
8153 static int dotcmd(int, char **);
8154 static int evalcmd(int, char **);
8155 #if ENABLE_ASH_BUILTIN_ECHO
8156 static int echocmd(int, char **);
8158 #if ENABLE_ASH_BUILTIN_TEST
8159 static int testcmd(int, char **);
8161 static int exitcmd(int, char **);
8162 static int exportcmd(int, char **);
8163 #if ENABLE_ASH_GETOPTS
8164 static int getoptscmd(int, char **);
8166 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8167 static int helpcmd(int argc, char **argv);
8169 #if ENABLE_ASH_MATH_SUPPORT
8170 static int letcmd(int, char **);
8172 static int readcmd(int, char **);
8173 static int setcmd(int, char **);
8174 static int shiftcmd(int, char **);
8175 static int timescmd(int, char **);
8176 static int trapcmd(int, char **);
8177 static int umaskcmd(int, char **);
8178 static int unsetcmd(int, char **);
8179 static int ulimitcmd(int, char **);
8181 #define BUILTIN_NOSPEC "0"
8182 #define BUILTIN_SPECIAL "1"
8183 #define BUILTIN_REGULAR "2"
8184 #define BUILTIN_SPEC_REG "3"
8185 #define BUILTIN_ASSIGN "4"
8186 #define BUILTIN_SPEC_ASSG "5"
8187 #define BUILTIN_REG_ASSG "6"
8188 #define BUILTIN_SPEC_REG_ASSG "7"
8190 /* make sure to keep these in proper order since it is searched via bsearch() */
8191 static const struct builtincmd builtintab[] = {
8192 { BUILTIN_SPEC_REG ".", dotcmd },
8193 { BUILTIN_SPEC_REG ":", truecmd },
8194 #if ENABLE_ASH_BUILTIN_TEST
8195 { BUILTIN_REGULAR "[", testcmd },
8196 { BUILTIN_REGULAR "[[", testcmd },
8198 #if ENABLE_ASH_ALIAS
8199 { BUILTIN_REG_ASSG "alias", aliascmd },
8202 { BUILTIN_REGULAR "bg", fg_bgcmd },
8204 { BUILTIN_SPEC_REG "break", breakcmd },
8205 { BUILTIN_REGULAR "cd", cdcmd },
8206 { BUILTIN_NOSPEC "chdir", cdcmd },
8207 #if ENABLE_ASH_CMDCMD
8208 { BUILTIN_REGULAR "command", commandcmd },
8210 { BUILTIN_SPEC_REG "continue", breakcmd },
8211 #if ENABLE_ASH_BUILTIN_ECHO
8212 { BUILTIN_REGULAR "echo", echocmd },
8214 { BUILTIN_SPEC_REG "eval", evalcmd },
8215 { BUILTIN_SPEC_REG "exec", execcmd },
8216 { BUILTIN_SPEC_REG "exit", exitcmd },
8217 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8218 { BUILTIN_REGULAR "false", falsecmd },
8220 { BUILTIN_REGULAR "fg", fg_bgcmd },
8222 #if ENABLE_ASH_GETOPTS
8223 { BUILTIN_REGULAR "getopts", getoptscmd },
8225 { BUILTIN_NOSPEC "hash", hashcmd },
8226 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8227 { BUILTIN_NOSPEC "help", helpcmd },
8230 { BUILTIN_REGULAR "jobs", jobscmd },
8231 { BUILTIN_REGULAR "kill", killcmd },
8233 #if ENABLE_ASH_MATH_SUPPORT
8234 { BUILTIN_NOSPEC "let", letcmd },
8236 { BUILTIN_ASSIGN "local", localcmd },
8237 { BUILTIN_NOSPEC "pwd", pwdcmd },
8238 { BUILTIN_REGULAR "read", readcmd },
8239 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8240 { BUILTIN_SPEC_REG "return", returncmd },
8241 { BUILTIN_SPEC_REG "set", setcmd },
8242 { BUILTIN_SPEC_REG "shift", shiftcmd },
8243 { BUILTIN_SPEC_REG "source", dotcmd },
8244 #if ENABLE_ASH_BUILTIN_TEST
8245 { BUILTIN_REGULAR "test", testcmd },
8247 { BUILTIN_SPEC_REG "times", timescmd },
8248 { BUILTIN_SPEC_REG "trap", trapcmd },
8249 { BUILTIN_REGULAR "true", truecmd },
8250 { BUILTIN_NOSPEC "type", typecmd },
8251 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
8252 { BUILTIN_REGULAR "umask", umaskcmd },
8253 #if ENABLE_ASH_ALIAS
8254 { BUILTIN_REGULAR "unalias", unaliascmd },
8256 { BUILTIN_SPEC_REG "unset", unsetcmd },
8257 { BUILTIN_REGULAR "wait", waitcmd },
8261 #define COMMANDCMD (builtintab + 5 + \
8262 2 * ENABLE_ASH_BUILTIN_TEST + \
8263 ENABLE_ASH_ALIAS + \
8264 ENABLE_ASH_JOB_CONTROL)
8265 #define EXECCMD (builtintab + 7 + \
8266 2 * ENABLE_ASH_BUILTIN_TEST + \
8267 ENABLE_ASH_ALIAS + \
8268 ENABLE_ASH_JOB_CONTROL + \
8269 ENABLE_ASH_CMDCMD + \
8270 ENABLE_ASH_BUILTIN_ECHO)
8273 * Search the table of builtin commands.
8275 static struct builtincmd *
8276 find_builtin(const char *name)
8278 struct builtincmd *bp;
8281 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8288 * Execute a simple command.
8290 static int back_exitstatus; /* exit status of backquoted command */
8292 isassignment(const char *p)
8294 const char *q = endofname(p);
8300 bltincmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
8302 /* Preserve exitstatus of a previous possible redirection
8303 * as POSIX mandates */
8304 return back_exitstatus;
8307 evalcommand(union node *cmd, int flags)
8309 static const struct builtincmd null_bltin = {
8310 "\0\0", bltincmd /* why three NULs? */
8312 struct stackmark smark;
8314 struct arglist arglist;
8315 struct arglist varlist;
8318 const struct strlist *sp;
8319 struct cmdentry cmdentry;
8327 struct builtincmd *bcmd;
8328 int pseudovarflag = 0;
8330 /* First expand the arguments. */
8331 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8332 setstackmark(&smark);
8333 back_exitstatus = 0;
8335 cmdentry.cmdtype = CMDBUILTIN;
8336 cmdentry.u.cmd = &null_bltin;
8337 varlist.lastp = &varlist.list;
8338 *varlist.lastp = NULL;
8339 arglist.lastp = &arglist.list;
8340 *arglist.lastp = NULL;
8343 if (cmd->ncmd.args) {
8344 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8345 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8348 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8349 struct strlist **spp;
8351 spp = arglist.lastp;
8352 if (pseudovarflag && isassignment(argp->narg.text))
8353 expandarg(argp, &arglist, EXP_VARTILDE);
8355 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8357 for (sp = *spp; sp; sp = sp->next)
8361 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8362 for (sp = arglist.list; sp; sp = sp->next) {
8363 TRACE(("evalcommand arg: %s\n", sp->text));
8364 *nargv++ = sp->text;
8369 if (iflag && funcnest == 0 && argc > 0)
8370 lastarg = nargv[-1];
8373 expredir(cmd->ncmd.redirect);
8374 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8377 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8378 struct strlist **spp;
8381 spp = varlist.lastp;
8382 expandarg(argp, &varlist, EXP_VARTILDE);
8385 * Modify the command lookup path, if a PATH= assignment
8389 if (varequal(p, path))
8393 /* Print the command if xflag is set. */
8396 const char *p = " %s";
8399 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8402 for (n = 0; n < 2; n++) {
8404 fdprintf(preverrout_fd, p, sp->text);
8412 safe_write(preverrout_fd, "\n", 1);
8418 /* Now locate the command. */
8420 const char *oldpath;
8421 int cmd_flag = DO_ERR;
8426 find_command(argv[0], &cmdentry, cmd_flag, path);
8427 if (cmdentry.cmdtype == CMDUNKNOWN) {
8433 /* implement bltin and command here */
8434 if (cmdentry.cmdtype != CMDBUILTIN)
8437 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8438 if (cmdentry.u.cmd == EXECCMD)
8440 #if ENABLE_ASH_CMDCMD
8441 if (cmdentry.u.cmd == COMMANDCMD) {
8443 nargv = parse_command_args(argv, &path);
8446 argc -= nargv - argv;
8448 cmd_flag |= DO_NOFUNC;
8456 /* We have a redirection error. */
8458 raise_exception(EXERROR);
8460 exitstatus = status;
8464 /* Execute the command. */
8465 switch (cmdentry.cmdtype) {
8467 /* Fork off a child process if necessary. */
8468 if (!(flags & EV_EXIT) || trap[0]) {
8470 jp = makejob(/*cmd,*/ 1);
8471 if (forkshell(jp, cmd, FORK_FG) != 0) {
8472 exitstatus = waitforjob(jp);
8478 listsetvar(varlist.list, VEXPORT|VSTACK);
8479 shellexec(argv, path, cmdentry.u.index);
8483 cmdenviron = varlist.list;
8485 struct strlist *list = cmdenviron;
8487 if (spclbltin > 0 || argc == 0) {
8489 if (cmd_is_exec && argc > 1)
8492 listsetvar(list, i);
8494 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
8501 exit_status = 128 + SIGINT;
8503 exit_status = 128 + pendingsig;
8504 exitstatus = exit_status;
8505 if (i == EXINT || spclbltin > 0) {
8507 longjmp(exception_handler->loc, 1);
8514 listsetvar(varlist.list, 0);
8515 if (evalfun(cmdentry.u.func, argc, argv, flags))
8521 popredir(cmd_is_exec);
8523 /* dsl: I think this is intended to be used to support
8524 * '_' in 'vi' command mode during line editing...
8525 * However I implemented that within libedit itself.
8527 setvar("_", lastarg, 0);
8528 popstackmark(&smark);
8532 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
8534 char *volatile savecmdname;
8535 struct jmploc *volatile savehandler;
8536 struct jmploc jmploc;
8539 savecmdname = commandname;
8540 i = setjmp(jmploc.loc);
8543 savehandler = exception_handler;
8544 exception_handler = &jmploc;
8545 commandname = argv[0];
8547 optptr = NULL; /* initialize nextopt */
8548 exitstatus = (*cmd->builtin)(argc, argv);
8549 flush_stdout_stderr();
8551 exitstatus |= ferror(stdout);
8553 commandname = savecmdname;
8555 exception_handler = savehandler;
8561 goodname(const char *p)
8563 return !*endofname(p);
8568 * Search for a command. This is called before we fork so that the
8569 * location of the command will be available in the parent as well as
8570 * the child. The check for "goodname" is an overly conservative
8571 * check that the name will not be subject to expansion.
8574 prehash(union node *n)
8576 struct cmdentry entry;
8578 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
8579 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
8583 /* ============ Builtin commands
8585 * Builtin commands whose functions are closely tied to evaluation
8586 * are implemented here.
8590 * Handle break and continue commands. Break, continue, and return are
8591 * all handled by setting the evalskip flag. The evaluation routines
8592 * above all check this flag, and if it is set they start skipping
8593 * commands rather than executing them. The variable skipcount is
8594 * the number of loops to break/continue, or the number of function
8595 * levels to return. (The latter is always 1.) It should probably
8596 * be an error to break out of more loops than exist, but it isn't
8597 * in the standard shell so we don't make it one here.
8600 breakcmd(int argc ATTRIBUTE_UNUSED, char **argv)
8602 int n = argv[1] ? number(argv[1]) : 1;
8605 ash_msg_and_raise_error(illnum, argv[1]);
8609 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
8616 /* ============ input.c
8618 * This implements the input routines used by the parser.
8621 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
8624 INPUT_PUSH_FILE = 1,
8625 INPUT_NOFILE_OK = 2,
8628 static int plinno = 1; /* input line number */
8629 /* number of characters left in input buffer */
8630 static int parsenleft; /* copy of parsefile->nleft */
8631 static int parselleft; /* copy of parsefile->lleft */
8632 /* next character in input buffer */
8633 static char *parsenextc; /* copy of parsefile->nextc */
8635 static int checkkwd;
8636 /* values of checkkwd variable */
8637 #define CHKALIAS 0x1
8644 struct strpush *sp = parsefile->strpush;
8647 #if ENABLE_ASH_ALIAS
8649 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
8650 checkkwd |= CHKALIAS;
8652 if (sp->string != sp->ap->val) {
8655 sp->ap->flag &= ~ALIASINUSE;
8656 if (sp->ap->flag & ALIASDEAD) {
8657 unalias(sp->ap->name);
8661 parsenextc = sp->prevstring;
8662 parsenleft = sp->prevnleft;
8663 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
8664 parsefile->strpush = sp->prev;
8665 if (sp != &(parsefile->basestrpush))
8674 char *buf = parsefile->buf;
8678 #if ENABLE_FEATURE_EDITING
8679 if (!iflag || parsefile->fd)
8680 nr = nonblock_safe_read(parsefile->fd, buf, BUFSIZ - 1);
8682 #if ENABLE_FEATURE_TAB_COMPLETION
8683 line_input_state->path_lookup = pathval();
8685 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
8687 /* Ctrl+C pressed */
8696 if (nr < 0 && errno == 0) {
8697 /* Ctrl+D pressed */
8702 nr = nonblock_safe_read(parsefile->fd, buf, BUFSIZ - 1);
8706 /* nonblock_safe_read() handles this problem */
8708 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
8709 int flags = fcntl(0, F_GETFL);
8710 if (flags >= 0 && (flags & O_NONBLOCK)) {
8711 flags &= ~O_NONBLOCK;
8712 if (fcntl(0, F_SETFL, flags) >= 0) {
8713 out2str("sh: turning off NDELAY mode\n");
8724 * Refill the input buffer and return the next input character:
8726 * 1) If a string was pushed back on the input, pop it;
8727 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
8728 * from a string so we can't refill the buffer, return EOF.
8729 * 3) If the is more stuff in this buffer, use it else call read to fill it.
8730 * 4) Process input up to the next newline, deleting nul characters.
8739 while (parsefile->strpush) {
8740 #if ENABLE_ASH_ALIAS
8741 if (parsenleft == -1 && parsefile->strpush->ap &&
8742 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
8747 if (--parsenleft >= 0)
8748 return signed_char2int(*parsenextc++);
8750 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
8752 flush_stdout_stderr();
8759 parselleft = parsenleft = EOF_NLEFT;
8766 /* delete nul characters */
8774 memmove(q, q + 1, more);
8778 parsenleft = q - parsenextc - 1;
8784 parsenleft = q - parsenextc - 1;
8796 out2str(parsenextc);
8801 return signed_char2int(*parsenextc++);
8804 #define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer())
8808 return pgetc_as_macro();
8811 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
8812 #define pgetc_macro() pgetc()
8814 #define pgetc_macro() pgetc_as_macro()
8818 * Same as pgetc(), but ignores PEOA.
8820 #if ENABLE_ASH_ALIAS
8828 } while (c == PEOA);
8835 return pgetc_macro();
8840 * Read a line from the script.
8843 pfgets(char *line, int len)
8849 while (--nleft > 0) {
8865 * Undo the last call to pgetc. Only one character may be pushed back.
8866 * PEOF may be pushed back.
8876 * Push a string back onto the input at this current parsefile level.
8877 * We handle aliases this way.
8880 pushstring(char *s, void *ap)
8887 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
8888 if (parsefile->strpush) {
8889 sp = ckzalloc(sizeof(struct strpush));
8890 sp->prev = parsefile->strpush;
8891 parsefile->strpush = sp;
8893 sp = parsefile->strpush = &(parsefile->basestrpush);
8894 sp->prevstring = parsenextc;
8895 sp->prevnleft = parsenleft;
8896 #if ENABLE_ASH_ALIAS
8897 sp->ap = (struct alias *)ap;
8899 ((struct alias *)ap)->flag |= ALIASINUSE;
8909 * To handle the "." command, a stack of input files is used. Pushfile
8910 * adds a new entry to the stack and popfile restores the previous level.
8915 struct parsefile *pf;
8917 parsefile->nleft = parsenleft;
8918 parsefile->lleft = parselleft;
8919 parsefile->nextc = parsenextc;
8920 parsefile->linno = plinno;
8921 pf = ckzalloc(sizeof(*pf));
8922 pf->prev = parsefile;
8924 /*pf->strpush = NULL; - ckzalloc did it */
8925 /*pf->basestrpush.prev = NULL;*/
8932 struct parsefile *pf = parsefile;
8940 parsefile = pf->prev;
8942 parsenleft = parsefile->nleft;
8943 parselleft = parsefile->lleft;
8944 parsenextc = parsefile->nextc;
8945 plinno = parsefile->linno;
8950 * Return to top level.
8955 while (parsefile != &basepf)
8960 * Close the file(s) that the shell is reading commands from. Called
8961 * after a fork is done.
8967 if (parsefile->fd > 0) {
8968 close(parsefile->fd);
8974 * Like setinputfile, but takes an open file descriptor. Call this with
8978 setinputfd(int fd, int push)
8980 close_on_exec_on(fd);
8986 if (parsefile->buf == NULL)
8987 parsefile->buf = ckmalloc(IBUFSIZ);
8988 parselleft = parsenleft = 0;
8993 * Set the input to take input from a file. If push is set, push the
8994 * old input onto the stack first.
8997 setinputfile(const char *fname, int flags)
9003 fd = open(fname, O_RDONLY);
9005 if (flags & INPUT_NOFILE_OK)
9007 ash_msg_and_raise_error("can't open %s", fname);
9010 fd2 = copyfd(fd, 10);
9013 ash_msg_and_raise_error("out of file descriptors");
9016 setinputfd(fd, flags & INPUT_PUSH_FILE);
9023 * Like setinputfile, but takes input from a string.
9026 setinputstring(char *string)
9030 parsenextc = string;
9031 parsenleft = strlen(string);
9032 parsefile->buf = NULL;
9038 /* ============ mail.c
9040 * Routines to check for mail.
9045 #define MAXMBOXES 10
9047 /* times of mailboxes */
9048 static time_t mailtime[MAXMBOXES];
9049 /* Set if MAIL or MAILPATH is changed. */
9050 static smallint mail_var_path_changed;
9053 * Print appropriate message(s) if mail has arrived.
9054 * If mail_var_path_changed is set,
9055 * then the value of MAIL has mail_var_path_changed,
9056 * so we just update the values.
9065 struct stackmark smark;
9068 setstackmark(&smark);
9069 mpath = mpathset() ? mpathval() : mailval();
9070 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9071 p = padvance(&mpath, nullstr);
9076 for (q = p; *q; q++);
9081 q[-1] = '\0'; /* delete trailing '/' */
9082 if (stat(p, &statb) < 0) {
9086 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9089 pathopt ? pathopt : "you have mail"
9092 *mtp = statb.st_mtime;
9094 mail_var_path_changed = 0;
9095 popstackmark(&smark);
9099 changemail(const char *val ATTRIBUTE_UNUSED)
9101 mail_var_path_changed = 1;
9104 #endif /* ASH_MAIL */
9107 /* ============ ??? */
9110 * Set the shell parameters.
9113 setparam(char **argv)
9119 for (nparam = 0; argv[nparam]; nparam++);
9120 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9122 *ap++ = ckstrdup(*argv++);
9125 freeparam(&shellparam);
9126 shellparam.malloced = 1;
9127 shellparam.nparam = nparam;
9128 shellparam.p = newparam;
9129 #if ENABLE_ASH_GETOPTS
9130 shellparam.optind = 1;
9131 shellparam.optoff = -1;
9136 * Process shell options. The global variable argptr contains a pointer
9137 * to the argument list; we advance it past the options.
9139 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9140 * For a non-interactive shell, an error condition encountered
9141 * by a special built-in ... shall cause the shell to write a diagnostic message
9142 * to standard error and exit as shown in the following table:
9143 * Error Special Built-In
9145 * Utility syntax error (option or operand error) Shall exit
9147 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9148 * we see that bash does not do that (set "finishes" with error code 1 instead,
9149 * and shell continues), and people rely on this behavior!
9151 * set -o barfoo 2>/dev/null
9154 * Oh well. Let's mimic that.
9157 minus_o(char *name, int val)
9162 for (i = 0; i < NOPTS; i++) {
9163 if (strcmp(name, optnames(i)) == 0) {
9168 ash_msg("illegal option -o %s", name);
9171 out1str("Current option settings\n");
9172 for (i = 0; i < NOPTS; i++)
9173 out1fmt("%-16s%s\n", optnames(i),
9174 optlist[i] ? "on" : "off");
9178 setoption(int flag, int val)
9182 for (i = 0; i < NOPTS; i++) {
9183 if (optletters(i) == flag) {
9188 ash_msg_and_raise_error("illegal option -%c", flag);
9192 options(int cmdline)
9200 while ((p = *argptr) != NULL) {
9202 if (c != '-' && c != '+')
9205 val = 0; /* val = 0 if c == '+' */
9208 if (p[0] == '\0' || LONE_DASH(p)) {
9210 /* "-" means turn off -x and -v */
9213 /* "--" means reset params */
9214 else if (*argptr == NULL)
9217 break; /* "-" or "--" terminates options */
9220 /* first char was + or - */
9221 while ((c = *p++) != '\0') {
9222 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9223 if (c == 'c' && cmdline) {
9224 minusc = p; /* command is after shell args */
9225 } else if (c == 'o') {
9226 if (minus_o(*argptr, val)) {
9227 /* it already printed err message */
9228 return 1; /* error */
9232 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9234 /* bash does not accept +-login, we also won't */
9235 } else if (cmdline && val && (c == '-')) { /* long options */
9236 if (strcmp(p, "login") == 0)
9248 * The shift builtin command.
9251 shiftcmd(int argc ATTRIBUTE_UNUSED, char **argv)
9258 n = number(argv[1]);
9259 if (n > shellparam.nparam)
9260 ash_msg_and_raise_error("can't shift that many");
9262 shellparam.nparam -= n;
9263 for (ap1 = shellparam.p; --n >= 0; ap1++) {
9264 if (shellparam.malloced)
9268 while ((*ap2++ = *ap1++) != NULL);
9269 #if ENABLE_ASH_GETOPTS
9270 shellparam.optind = 1;
9271 shellparam.optoff = -1;
9278 * POSIX requires that 'set' (but not export or readonly) output the
9279 * variables in lexicographic order - by the locale's collating order (sigh).
9280 * Maybe we could keep them in an ordered balanced binary tree
9281 * instead of hashed lists.
9282 * For now just roll 'em through qsort for printing...
9285 showvars(const char *sep_prefix, int on, int off)
9290 ep = listvars(on, off, &epend);
9291 qsort(ep, epend - ep, sizeof(char *), vpcmp);
9293 sep = *sep_prefix ? " " : sep_prefix;
9295 for (; ep < epend; ep++) {
9299 p = strchrnul(*ep, '=');
9302 q = single_quote(++p);
9303 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9309 * The set command builtin.
9312 setcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
9317 return showvars(nullstr, 0, VUNSET);
9320 if (!options(0)) { /* if no parse error... */
9323 if (*argptr != NULL) {
9331 #if ENABLE_ASH_RANDOM_SUPPORT
9332 /* Roughly copied from bash.. */
9334 change_random(const char *value)
9336 if (value == NULL) {
9337 /* "get", generate */
9340 rseed = rseed * 1103515245 + 12345;
9341 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9342 /* set without recursion */
9343 setvar(vrandom.text, buf, VNOFUNC);
9344 vrandom.flags &= ~VNOFUNC;
9347 rseed = strtoul(value, (char **)NULL, 10);
9352 #if ENABLE_ASH_GETOPTS
9354 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9363 if (*param_optind < 1)
9365 optnext = optfirst + *param_optind - 1;
9367 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9370 p = optnext[-1] + *optoff;
9371 if (p == NULL || *p == '\0') {
9372 /* Current word is done, advance */
9374 if (p == NULL || *p != '-' || *++p == '\0') {
9381 if (LONE_DASH(p)) /* check for "--" */
9386 for (q = optstr; *q != c; ) {
9388 if (optstr[0] == ':') {
9391 err |= setvarsafe("OPTARG", s, 0);
9393 fprintf(stderr, "Illegal option -%c\n", c);
9404 if (*p == '\0' && (p = *optnext) == NULL) {
9405 if (optstr[0] == ':') {
9408 err |= setvarsafe("OPTARG", s, 0);
9411 fprintf(stderr, "No arg for -%c option\n", c);
9420 err |= setvarsafe("OPTARG", p, 0);
9423 err |= setvarsafe("OPTARG", nullstr, 0);
9425 *optoff = p ? p - *(optnext - 1) : -1;
9426 *param_optind = optnext - optfirst + 1;
9427 fmtstr(s, sizeof(s), "%d", *param_optind);
9428 err |= setvarsafe("OPTIND", s, VNOFUNC);
9431 err |= setvarsafe(optvar, s, 0);
9435 flush_stdout_stderr();
9436 raise_exception(EXERROR);
9442 * The getopts builtin. Shellparam.optnext points to the next argument
9443 * to be processed. Shellparam.optptr points to the next character to
9444 * be processed in the current argument. If shellparam.optnext is NULL,
9445 * then it's the first time getopts has been called.
9448 getoptscmd(int argc, char **argv)
9453 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
9455 optbase = shellparam.p;
9456 if (shellparam.optind > shellparam.nparam + 1) {
9457 shellparam.optind = 1;
9458 shellparam.optoff = -1;
9462 if (shellparam.optind > argc - 2) {
9463 shellparam.optind = 1;
9464 shellparam.optoff = -1;
9468 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9469 &shellparam.optoff);
9471 #endif /* ASH_GETOPTS */
9474 /* ============ Shell parser */
9477 * NEOF is returned by parsecmd when it encounters an end of file. It
9478 * must be distinct from NULL, so we use the address of a variable that
9479 * happens to be handy.
9481 static smallint tokpushback; /* last token pushed back */
9482 #define NEOF ((union node *)&tokpushback)
9483 static smallint parsebackquote; /* nonzero if we are inside backquotes */
9484 static int lasttoken; /* last token read */
9485 static char *wordtext; /* text of last word returned by readtoken */
9486 static struct nodelist *backquotelist;
9487 static union node *redirnode;
9488 static struct heredoc *heredoc;
9489 static smallint quoteflag; /* set if (part of) last token was quoted */
9491 static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN;
9493 raise_error_syntax(const char *msg)
9495 ash_msg_and_raise_error("syntax error: %s", msg);
9500 * Called when an unexpected token is read during the parse. The argument
9501 * is the token that is expected, or -1 if more than one type of token can
9502 * occur at this point.
9504 static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN;
9506 raise_error_unexpected_syntax(int token)
9511 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
9513 sprintf(msg + l, " (expecting %s)", tokname(token));
9514 raise_error_syntax(msg);
9518 #define EOFMARKLEN 79
9521 struct heredoc *next; /* next here document in list */
9522 union node *here; /* redirection node */
9523 char *eofmark; /* string indicating end of input */
9524 int striptabs; /* if set, strip leading tabs */
9527 static struct heredoc *heredoclist; /* list of here documents to read */
9529 /* parsing is heavily cross-recursive, need these forward decls */
9530 static union node *andor(void);
9531 static union node *pipeline(void);
9532 static union node *parse_command(void);
9533 static void parseheredoc(void);
9534 static char peektoken(void);
9535 static int readtoken(void);
9540 union node *n1, *n2, *n3;
9543 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9544 if (nlflag == 2 && peektoken())
9550 if (tok == TBACKGND) {
9551 if (n2->type == NPIPE) {
9552 n2->npipe.backgnd = 1;
9554 if (n2->type != NREDIR) {
9555 n3 = stzalloc(sizeof(struct nredir));
9557 /*n3->nredir.redirect = NULL; - stzalloc did it */
9560 n2->type = NBACKGND;
9566 n3 = stzalloc(sizeof(struct nbinary));
9568 n3->nbinary.ch1 = n1;
9569 n3->nbinary.ch2 = n2;
9585 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9593 pungetc(); /* push back EOF on input */
9597 raise_error_unexpected_syntax(-1);
9607 union node *n1, *n2, *n3;
9615 } else if (t == TOR) {
9621 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9623 n3 = stzalloc(sizeof(struct nbinary));
9625 n3->nbinary.ch1 = n1;
9626 n3->nbinary.ch2 = n2;
9634 union node *n1, *n2, *pipenode;
9635 struct nodelist *lp, *prev;
9639 TRACE(("pipeline: entered\n"));
9640 if (readtoken() == TNOT) {
9642 checkkwd = CHKKWD | CHKALIAS;
9645 n1 = parse_command();
9646 if (readtoken() == TPIPE) {
9647 pipenode = stzalloc(sizeof(struct npipe));
9648 pipenode->type = NPIPE;
9649 /*pipenode->npipe.backgnd = 0; - stzalloc did it */
9650 lp = stzalloc(sizeof(struct nodelist));
9651 pipenode->npipe.cmdlist = lp;
9655 lp = stzalloc(sizeof(struct nodelist));
9656 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9657 lp->n = parse_command();
9659 } while (readtoken() == TPIPE);
9665 n2 = stzalloc(sizeof(struct nnot));
9678 n = stzalloc(sizeof(struct narg));
9680 /*n->narg.next = NULL; - stzalloc did it */
9681 n->narg.text = wordtext;
9682 n->narg.backquote = backquotelist;
9687 fixredir(union node *n, const char *text, int err)
9689 TRACE(("Fix redir %s %d\n", text, err));
9691 n->ndup.vname = NULL;
9693 if (isdigit(text[0]) && text[1] == '\0')
9694 n->ndup.dupfd = text[0] - '0';
9695 else if (LONE_DASH(text))
9699 raise_error_syntax("Bad fd number");
9700 n->ndup.vname = makename();
9705 * Returns true if the text contains nothing to expand (no dollar signs
9709 noexpand(char *text)
9715 while ((c = *p++) != '\0') {
9716 if (c == CTLQUOTEMARK)
9720 else if (SIT(c, BASESYNTAX) == CCTL)
9729 union node *n = redirnode;
9731 if (readtoken() != TWORD)
9732 raise_error_unexpected_syntax(-1);
9733 if (n->type == NHERE) {
9734 struct heredoc *here = heredoc;
9740 TRACE(("Here document %d\n", n->type));
9741 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9742 raise_error_syntax("Illegal eof marker for << redirection");
9743 rmescapes(wordtext);
9744 here->eofmark = wordtext;
9746 if (heredoclist == NULL)
9749 for (p = heredoclist; p->next; p = p->next)
9753 } else if (n->type == NTOFD || n->type == NFROMFD) {
9754 fixredir(n, wordtext, 0);
9756 n->nfile.fname = makename();
9763 union node *args, **app;
9764 union node *n = NULL;
9765 union node *vars, **vpp;
9766 union node **rpp, *redir;
9776 savecheckkwd = CHKALIAS;
9778 checkkwd = savecheckkwd;
9779 switch (readtoken()) {
9781 n = stzalloc(sizeof(struct narg));
9783 /*n->narg.next = NULL; - stzalloc did it */
9784 n->narg.text = wordtext;
9785 n->narg.backquote = backquotelist;
9786 if (savecheckkwd && isassignment(wordtext)) {
9788 vpp = &n->narg.next;
9791 app = &n->narg.next;
9796 *rpp = n = redirnode;
9797 rpp = &n->nfile.next;
9798 parsefname(); /* read name of redirection file */
9801 if (args && app == &args->narg.next
9804 struct builtincmd *bcmd;
9807 /* We have a function */
9808 if (readtoken() != TRP)
9809 raise_error_unexpected_syntax(TRP);
9810 name = n->narg.text;
9812 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
9814 raise_error_syntax("Bad function name");
9817 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9818 n->narg.next = parse_command();
9831 n = stzalloc(sizeof(struct ncmd));
9833 n->ncmd.args = args;
9834 n->ncmd.assign = vars;
9835 n->ncmd.redirect = redir;
9842 union node *n1, *n2;
9843 union node *ap, **app;
9844 union node *cp, **cpp;
9845 union node *redir, **rpp;
9852 switch (readtoken()) {
9854 raise_error_unexpected_syntax(-1);
9857 n1 = stzalloc(sizeof(struct nif));
9859 n1->nif.test = list(0);
9860 if (readtoken() != TTHEN)
9861 raise_error_unexpected_syntax(TTHEN);
9862 n1->nif.ifpart = list(0);
9864 while (readtoken() == TELIF) {
9865 n2->nif.elsepart = stzalloc(sizeof(struct nif));
9866 n2 = n2->nif.elsepart;
9868 n2->nif.test = list(0);
9869 if (readtoken() != TTHEN)
9870 raise_error_unexpected_syntax(TTHEN);
9871 n2->nif.ifpart = list(0);
9873 if (lasttoken == TELSE)
9874 n2->nif.elsepart = list(0);
9876 n2->nif.elsepart = NULL;
9884 n1 = stzalloc(sizeof(struct nbinary));
9885 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
9886 n1->nbinary.ch1 = list(0);
9889 TRACE(("expecting DO got %s %s\n", tokname(got),
9890 got == TWORD ? wordtext : ""));
9891 raise_error_unexpected_syntax(TDO);
9893 n1->nbinary.ch2 = list(0);
9898 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9899 raise_error_syntax("Bad for loop variable");
9900 n1 = stzalloc(sizeof(struct nfor));
9902 n1->nfor.var = wordtext;
9903 checkkwd = CHKKWD | CHKALIAS;
9904 if (readtoken() == TIN) {
9906 while (readtoken() == TWORD) {
9907 n2 = stzalloc(sizeof(struct narg));
9909 /*n2->narg.next = NULL; - stzalloc did it */
9910 n2->narg.text = wordtext;
9911 n2->narg.backquote = backquotelist;
9913 app = &n2->narg.next;
9917 if (lasttoken != TNL && lasttoken != TSEMI)
9918 raise_error_unexpected_syntax(-1);
9920 n2 = stzalloc(sizeof(struct narg));
9922 /*n2->narg.next = NULL; - stzalloc did it */
9923 n2->narg.text = (char *)dolatstr;
9924 /*n2->narg.backquote = NULL;*/
9927 * Newline or semicolon here is optional (but note
9928 * that the original Bourne shell only allowed NL).
9930 if (lasttoken != TNL && lasttoken != TSEMI)
9933 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9934 if (readtoken() != TDO)
9935 raise_error_unexpected_syntax(TDO);
9936 n1->nfor.body = list(0);
9940 n1 = stzalloc(sizeof(struct ncase));
9942 if (readtoken() != TWORD)
9943 raise_error_unexpected_syntax(TWORD);
9944 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
9946 /*n2->narg.next = NULL; - stzalloc did it */
9947 n2->narg.text = wordtext;
9948 n2->narg.backquote = backquotelist;
9950 checkkwd = CHKKWD | CHKALIAS;
9951 } while (readtoken() == TNL);
9952 if (lasttoken != TIN)
9953 raise_error_unexpected_syntax(TIN);
9954 cpp = &n1->ncase.cases;
9956 checkkwd = CHKNL | CHKKWD;
9958 while (t != TESAC) {
9959 if (lasttoken == TLP)
9961 *cpp = cp = stzalloc(sizeof(struct nclist));
9963 app = &cp->nclist.pattern;
9965 *app = ap = stzalloc(sizeof(struct narg));
9967 /*ap->narg.next = NULL; - stzalloc did it */
9968 ap->narg.text = wordtext;
9969 ap->narg.backquote = backquotelist;
9970 if (readtoken() != TPIPE)
9972 app = &ap->narg.next;
9975 //ap->narg.next = NULL;
9976 if (lasttoken != TRP)
9977 raise_error_unexpected_syntax(TRP);
9978 cp->nclist.body = list(2);
9980 cpp = &cp->nclist.next;
9982 checkkwd = CHKNL | CHKKWD;
9986 raise_error_unexpected_syntax(TENDCASE);
9993 n1 = stzalloc(sizeof(struct nredir));
9994 n1->type = NSUBSHELL;
9995 n1->nredir.n = list(0);
9996 /*n1->nredir.redirect = NULL; - stzalloc did it */
10006 return simplecmd();
10009 if (readtoken() != t)
10010 raise_error_unexpected_syntax(t);
10013 /* Now check for redirection which may follow command */
10014 checkkwd = CHKKWD | CHKALIAS;
10016 while (readtoken() == TREDIR) {
10017 *rpp = n2 = redirnode;
10018 rpp = &n2->nfile.next;
10024 if (n1->type != NSUBSHELL) {
10025 n2 = stzalloc(sizeof(struct nredir));
10030 n1->nredir.redirect = redir;
10036 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10037 * is not NULL, read a here document. In the latter case, eofmark is the
10038 * word which marks the end of the document and striptabs is true if
10039 * leading tabs should be stripped from the document. The argument firstc
10040 * is the first character of the input token or document.
10042 * Because C does not have internal subroutines, I have simulated them
10043 * using goto's to implement the subroutine linkage. The following macros
10044 * will run code that appears at the end of readtoken1.
10047 #define CHECKEND() {goto checkend; checkend_return:;}
10048 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10049 #define PARSESUB() {goto parsesub; parsesub_return:;}
10050 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10051 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10052 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10055 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10057 /* NB: syntax parameter fits into smallint */
10061 char line[EOFMARKLEN + 1];
10062 struct nodelist *bqlist;
10066 smallint prevsyntax; /* syntax before arithmetic */
10067 #if ENABLE_ASH_EXPAND_PRMT
10068 smallint pssyntax; /* we are expanding a prompt string */
10070 int varnest; /* levels of variables expansion */
10071 int arinest; /* levels of arithmetic expansion */
10072 int parenlevel; /* levels of parens in arithmetic */
10073 int dqvarnest; /* levels of variables expansion within double quotes */
10076 /* Avoid longjmp clobbering */
10082 (void) &parenlevel;
10085 (void) &prevsyntax;
10088 startlinno = plinno;
10093 #if ENABLE_ASH_EXPAND_PRMT
10094 pssyntax = (syntax == PSSYNTAX);
10098 dblquote = (syntax == DQSYNTAX);
10104 STARTSTACKSTR(out);
10105 loop: { /* for each line, until end of word */
10106 CHECKEND(); /* set c to PEOF if at end of here document */
10107 for (;;) { /* until end of line or end of word */
10108 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10109 switch (SIT(c, syntax)) {
10110 case CNL: /* '\n' */
10111 if (syntax == BASESYNTAX)
10112 goto endword; /* exit outer loop */
10118 goto loop; /* continue outer loop */
10123 if (eofmark == NULL || dblquote)
10124 USTPUTC(CTLESC, out);
10127 case CBACK: /* backslash */
10130 USTPUTC(CTLESC, out);
10131 USTPUTC('\\', out);
10133 } else if (c == '\n') {
10137 #if ENABLE_ASH_EXPAND_PRMT
10138 if (c == '$' && pssyntax) {
10139 USTPUTC(CTLESC, out);
10140 USTPUTC('\\', out);
10144 c != '\\' && c != '`' &&
10149 USTPUTC(CTLESC, out);
10150 USTPUTC('\\', out);
10152 if (SIT(c, SQSYNTAX) == CCTL)
10153 USTPUTC(CTLESC, out);
10161 if (eofmark == NULL) {
10162 USTPUTC(CTLQUOTEMARK, out);
10170 if (eofmark != NULL && arinest == 0
10175 if (dqvarnest == 0) {
10176 syntax = BASESYNTAX;
10183 case CVAR: /* '$' */
10184 PARSESUB(); /* parse substitution */
10186 case CENDVAR: /* '}' */
10189 if (dqvarnest > 0) {
10192 USTPUTC(CTLENDVAR, out);
10197 #if ENABLE_ASH_MATH_SUPPORT
10198 case CLP: /* '(' in arithmetic */
10202 case CRP: /* ')' in arithmetic */
10203 if (parenlevel > 0) {
10207 if (pgetc() == ')') {
10208 if (--arinest == 0) {
10209 USTPUTC(CTLENDARI, out);
10210 syntax = prevsyntax;
10211 dblquote = (syntax == DQSYNTAX);
10216 * unbalanced parens
10217 * (don't 2nd guess - no error)
10225 case CBQUOTE: /* '`' */
10229 goto endword; /* exit outer loop */
10234 goto endword; /* exit outer loop */
10235 #if ENABLE_ASH_ALIAS
10245 #if ENABLE_ASH_MATH_SUPPORT
10246 if (syntax == ARISYNTAX)
10247 raise_error_syntax("Missing '))'");
10249 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10250 raise_error_syntax("Unterminated quoted string");
10251 if (varnest != 0) {
10252 startlinno = plinno;
10254 raise_error_syntax("Missing '}'");
10256 USTPUTC('\0', out);
10257 len = out - (char *)stackblock();
10258 out = stackblock();
10259 if (eofmark == NULL) {
10260 if ((c == '>' || c == '<')
10263 && (*out == '\0' || isdigit(*out))) {
10265 return lasttoken = TREDIR;
10270 quoteflag = quotef;
10271 backquotelist = bqlist;
10272 grabstackblock(len);
10276 /* end of readtoken routine */
10279 * Check to see whether we are at the end of the here document. When this
10280 * is called, c is set to the first character of the next input line. If
10281 * we are at the end of the here document, this routine sets the c to PEOF.
10285 #if ENABLE_ASH_ALIAS
10291 while (c == '\t') {
10295 if (c == *eofmark) {
10296 if (pfgets(line, sizeof(line)) != NULL) {
10300 for (q = eofmark + 1; *q && *p == *q; p++, q++);
10301 if (*p == '\n' && *q == '\0') {
10304 needprompt = doprompt;
10306 pushstring(line, NULL);
10311 goto checkend_return;
10315 * Parse a redirection operator. The variable "out" points to a string
10316 * specifying the fd to be redirected. The variable "c" contains the
10317 * first character of the redirection operator.
10323 np = stzalloc(sizeof(struct nfile));
10328 np->type = NAPPEND;
10330 np->type = NCLOBBER;
10337 } else { /* c == '<' */
10338 /*np->nfile.fd = 0; - stzalloc did it */
10342 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10343 np = stzalloc(sizeof(struct nhere));
10344 /*np->nfile.fd = 0; - stzalloc did it */
10347 heredoc = stzalloc(sizeof(struct heredoc));
10348 heredoc->here = np;
10351 heredoc->striptabs = 1;
10353 /*heredoc->striptabs = 0; - stzalloc did it */
10359 np->type = NFROMFD;
10363 np->type = NFROMTO;
10373 np->nfile.fd = fd - '0';
10375 goto parseredir_return;
10379 * Parse a substitution. At this point, we have read the dollar sign
10380 * and nothing else.
10383 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
10384 * (assuming ascii char codes, as the original implementation did) */
10385 #define is_special(c) \
10386 ((((unsigned int)c) - 33 < 32) \
10387 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
10393 static const char types[] ALIGN1 = "}-+?=";
10397 c <= PEOA_OR_PEOF ||
10398 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10402 } else if (c == '(') { /* $(command) or $((arith)) */
10403 if (pgetc() == '(') {
10404 #if ENABLE_ASH_MATH_SUPPORT
10407 raise_error_syntax("We unsupport $((arith))");
10414 USTPUTC(CTLVAR, out);
10415 typeloc = out - (char *)stackblock();
10416 USTPUTC(VSNORMAL, out);
10417 subtype = VSNORMAL;
10425 subtype = VSLENGTH;
10429 if (c > PEOA_OR_PEOF && is_name(c)) {
10433 } while (c > PEOA_OR_PEOF && is_in_name(c));
10434 } else if (isdigit(c)) {
10438 } while (isdigit(c));
10439 } else if (is_special(c)) {
10443 badsub: raise_error_syntax("Bad substitution");
10447 if (subtype == 0) {
10454 p = strchr(types, c);
10457 subtype = p - types + VSNORMAL;
10463 subtype = c == '#' ? VSTRIMLEFT :
10476 if (dblquote || arinest)
10478 *((char *)stackblock() + typeloc) = subtype | flags;
10479 if (subtype != VSNORMAL) {
10481 if (dblquote || arinest) {
10486 goto parsesub_return;
10490 * Called to parse command substitutions. Newstyle is set if the command
10491 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10492 * list of commands (passed by reference), and savelen is the number of
10493 * characters on the top of the stack which must be preserved.
10496 struct nodelist **nlpp;
10499 char *volatile str;
10500 struct jmploc jmploc;
10501 struct jmploc *volatile savehandler;
10503 smallint saveprompt = 0;
10506 (void) &saveprompt;
10508 savepbq = parsebackquote;
10509 if (setjmp(jmploc.loc)) {
10511 parsebackquote = 0;
10512 exception_handler = savehandler;
10513 longjmp(exception_handler->loc, 1);
10517 savelen = out - (char *)stackblock();
10519 str = ckmalloc(savelen);
10520 memcpy(str, stackblock(), savelen);
10522 savehandler = exception_handler;
10523 exception_handler = &jmploc;
10526 /* We must read until the closing backquote, giving special
10527 treatment to some slashes, and then push the string and
10528 reread it as input, interpreting it normally. */
10535 STARTSTACKSTR(pout);
10552 * If eating a newline, avoid putting
10553 * the newline into the new character
10554 * stream (via the STPUTC after the
10559 if (pc != '\\' && pc != '`' && pc != '$'
10560 && (!dblquote || pc != '"'))
10561 STPUTC('\\', pout);
10562 if (pc > PEOA_OR_PEOF) {
10568 #if ENABLE_ASH_ALIAS
10571 startlinno = plinno;
10572 raise_error_syntax("EOF in backquote substitution");
10576 needprompt = doprompt;
10585 STPUTC('\0', pout);
10586 psavelen = pout - (char *)stackblock();
10587 if (psavelen > 0) {
10588 pstr = grabstackstr(pout);
10589 setinputstring(pstr);
10594 nlpp = &(*nlpp)->next;
10595 *nlpp = stzalloc(sizeof(**nlpp));
10596 /* (*nlpp)->next = NULL; - stzalloc did it */
10597 parsebackquote = oldstyle;
10600 saveprompt = doprompt;
10607 doprompt = saveprompt;
10608 else if (readtoken() != TRP)
10609 raise_error_unexpected_syntax(TRP);
10614 * Start reading from old file again, ignoring any pushed back
10615 * tokens left from the backquote parsing
10620 while (stackblocksize() <= savelen)
10622 STARTSTACKSTR(out);
10624 memcpy(out, str, savelen);
10625 STADJUST(savelen, out);
10631 parsebackquote = savepbq;
10632 exception_handler = savehandler;
10633 if (arinest || dblquote)
10634 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10636 USTPUTC(CTLBACKQ, out);
10638 goto parsebackq_oldreturn;
10639 goto parsebackq_newreturn;
10642 #if ENABLE_ASH_MATH_SUPPORT
10644 * Parse an arithmetic expansion (indicate start of one and set state)
10647 if (++arinest == 1) {
10648 prevsyntax = syntax;
10649 syntax = ARISYNTAX;
10650 USTPUTC(CTLARI, out);
10657 * we collapse embedded arithmetic expansion to
10658 * parenthesis, which should be equivalent
10662 goto parsearith_return;
10666 } /* end of readtoken */
10669 * Read the next input token.
10670 * If the token is a word, we set backquotelist to the list of cmds in
10671 * backquotes. We set quoteflag to true if any part of the word was
10673 * If the token is TREDIR, then we set redirnode to a structure containing
10675 * In all cases, the variable startlinno is set to the number of the line
10676 * on which the token starts.
10678 * [Change comment: here documents and internal procedures]
10679 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10680 * word parsing code into a separate routine. In this case, readtoken
10681 * doesn't need to have any internal procedures, but parseword does.
10682 * We could also make parseoperator in essence the main routine, and
10683 * have parseword (readtoken1?) handle both words and redirection.]
10685 #define NEW_xxreadtoken
10686 #ifdef NEW_xxreadtoken
10687 /* singles must be first! */
10688 static const char xxreadtoken_chars[7] ALIGN1 = {
10689 '\n', '(', ')', '&', '|', ';', 0
10692 static const char xxreadtoken_tokens[] ALIGN1 = {
10693 TNL, TLP, TRP, /* only single occurrence allowed */
10694 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10695 TEOF, /* corresponds to trailing nul */
10696 TAND, TOR, TENDCASE /* if double occurrence */
10699 #define xxreadtoken_doubles \
10700 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10701 #define xxreadtoken_singles \
10702 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10716 startlinno = plinno;
10717 for (;;) { /* until token or start of word found */
10720 if ((c != ' ') && (c != '\t')
10721 #if ENABLE_ASH_ALIAS
10726 while ((c = pgetc()) != '\n' && c != PEOF);
10728 } else if (c == '\\') {
10729 if (pgetc() != '\n') {
10733 startlinno = ++plinno;
10738 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10743 needprompt = doprompt;
10746 p = strchr(xxreadtoken_chars, c);
10749 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10752 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10753 if (pgetc() == *p) { /* double occurrence? */
10754 p += xxreadtoken_doubles + 1;
10760 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10766 #define RETURN(token) return lasttoken = token
10779 startlinno = plinno;
10780 for (;;) { /* until token or start of word found */
10783 case ' ': case '\t':
10784 #if ENABLE_ASH_ALIAS
10789 while ((c = pgetc()) != '\n' && c != PEOF);
10793 if (pgetc() == '\n') {
10794 startlinno = ++plinno;
10803 needprompt = doprompt;
10808 if (pgetc() == '&')
10813 if (pgetc() == '|')
10818 if (pgetc() == ';')
10831 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10834 #endif /* NEW_xxreadtoken */
10841 smallint alreadyseen = tokpushback;
10844 #if ENABLE_ASH_ALIAS
10853 if (checkkwd & CHKNL) {
10860 if (t != TWORD || quoteflag) {
10865 * check for keywords
10867 if (checkkwd & CHKKWD) {
10868 const char *const *pp;
10870 pp = findkwd(wordtext);
10872 lasttoken = t = pp - tokname_array;
10873 TRACE(("keyword %s recognized\n", tokname(t)));
10878 if (checkkwd & CHKALIAS) {
10879 #if ENABLE_ASH_ALIAS
10881 ap = lookupalias(wordtext, 1);
10884 pushstring(ap->val, ap);
10894 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
10896 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
10908 return tokname_array[t][0];
10912 * Read and parse a command. Returns NEOF on end of file. (NULL is a
10913 * valid parse tree indicating a blank line.)
10915 static union node *
10916 parsecmd(int interact)
10921 doprompt = interact;
10923 setprompt(doprompt);
10935 * Input any here documents.
10940 struct heredoc *here;
10943 here = heredoclist;
10944 heredoclist = NULL;
10950 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10951 here->eofmark, here->striptabs);
10952 n = stzalloc(sizeof(struct narg));
10953 n->narg.type = NARG;
10954 /*n->narg.next = NULL; - stzalloc did it */
10955 n->narg.text = wordtext;
10956 n->narg.backquote = backquotelist;
10957 here->here->nhere.doc = n;
10964 * called by editline -- any expansions to the prompt should be added here.
10966 #if ENABLE_ASH_EXPAND_PRMT
10967 static const char *
10968 expandstr(const char *ps)
10972 /* XXX Fix (char *) cast. */
10973 setinputstring((char *)ps);
10974 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
10977 n.narg.type = NARG;
10978 n.narg.next = NULL;
10979 n.narg.text = wordtext;
10980 n.narg.backquote = backquotelist;
10982 expandarg(&n, NULL, 0);
10983 return stackblock();
10988 * Execute a command or commands contained in a string.
10991 evalstring(char *s, int mask)
10994 struct stackmark smark;
10998 setstackmark(&smark);
11001 while ((n = parsecmd(0)) != NEOF) {
11003 popstackmark(&smark);
11016 * The eval command.
11019 evalcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11028 STARTSTACKSTR(concat);
11030 concat = stack_putstr(p, concat);
11034 STPUTC(' ', concat);
11036 STPUTC('\0', concat);
11037 p = grabstackstr(concat);
11039 evalstring(p, ~SKIPEVAL);
11046 * Read and execute commands. "Top" is nonzero for the top level command
11047 * loop; it turns on prompting if the shell is interactive.
11053 struct stackmark smark;
11057 TRACE(("cmdloop(%d) called\n", top));
11061 setstackmark(&smark);
11064 showjobs(stderr, SHOW_CHANGED);
11067 if (iflag && top) {
11069 #if ENABLE_ASH_MAIL
11073 n = parsecmd(inter);
11074 /* showtree(n); DEBUG */
11076 if (!top || numeof >= 50)
11078 if (!stoppedjobs()) {
11081 out2str("\nUse \"exit\" to leave shell.\n");
11084 } else if (nflag == 0) {
11085 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11090 popstackmark(&smark);
11095 return skip & SKIPEVAL;
11102 * Take commands from a file. To be compatible we should do a path
11103 * search for the file, which is necessary to find sub-commands.
11106 find_dot_file(char *name)
11109 const char *path = pathval();
11112 /* don't try this for absolute or relative paths */
11113 if (strchr(name, '/'))
11116 while ((fullname = padvance(&path, name)) != NULL) {
11117 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11119 * Don't bother freeing here, since it will
11120 * be freed by the caller.
11124 stunalloc(fullname);
11127 /* not found in the PATH */
11128 ash_msg_and_raise_error("%s: not found", name);
11133 dotcmd(int argc, char **argv)
11135 struct strlist *sp;
11136 volatile struct shparam saveparam;
11139 for (sp = cmdenviron; sp; sp = sp->next)
11140 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11142 if (argv[1]) { /* That's what SVR2 does */
11143 char *fullname = find_dot_file(argv[1]);
11146 if (argc) { /* argc > 0, argv[0] != NULL */
11147 saveparam = shellparam;
11148 shellparam.malloced = 0;
11149 shellparam.nparam = argc;
11150 shellparam.p = argv;
11153 setinputfile(fullname, INPUT_PUSH_FILE);
11154 commandname = fullname;
11159 freeparam(&shellparam);
11160 shellparam = saveparam;
11162 status = exitstatus;
11168 exitcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11173 exitstatus = number(argv[1]);
11174 raise_exception(EXEXIT);
11178 #if ENABLE_ASH_BUILTIN_ECHO
11180 echocmd(int argc, char **argv)
11182 return echo_main(argc, argv);
11186 #if ENABLE_ASH_BUILTIN_TEST
11188 testcmd(int argc, char **argv)
11190 return test_main(argc, argv);
11195 * Read a file containing shell functions.
11198 readcmdfile(char *name)
11200 setinputfile(name, INPUT_PUSH_FILE);
11206 /* ============ find_command inplementation */
11209 * Resolve a command name. If you change this routine, you may have to
11210 * change the shellexec routine as well.
11213 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11215 struct tblentry *cmdp;
11222 struct builtincmd *bcmd;
11224 /* If name contains a slash, don't use PATH or hash table */
11225 if (strchr(name, '/') != NULL) {
11226 entry->u.index = -1;
11227 if (act & DO_ABS) {
11228 while (stat(name, &statb) < 0) {
11230 if (errno == EINTR)
11233 entry->cmdtype = CMDUNKNOWN;
11237 entry->cmdtype = CMDNORMAL;
11241 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11243 updatetbl = (path == pathval());
11246 if (strstr(path, "%builtin") != NULL)
11247 act |= DO_ALTBLTIN;
11250 /* If name is in the table, check answer will be ok */
11251 cmdp = cmdlookup(name, 0);
11252 if (cmdp != NULL) {
11255 switch (cmdp->cmdtype) {
11273 } else if (cmdp->rehash == 0)
11274 /* if not invalidated by cd, we're done */
11278 /* If %builtin not in path, check for builtin next */
11279 bcmd = find_builtin(name);
11281 if (IS_BUILTIN_REGULAR(bcmd))
11282 goto builtin_success;
11283 if (act & DO_ALTPATH) {
11284 if (!(act & DO_ALTBLTIN))
11285 goto builtin_success;
11286 } else if (builtinloc <= 0) {
11287 goto builtin_success;
11291 #if ENABLE_FEATURE_SH_STANDALONE
11292 if (find_applet_by_name(name) >= 0) {
11293 entry->cmdtype = CMDNORMAL;
11294 entry->u.index = -1;
11299 /* We have to search path. */
11300 prev = -1; /* where to start */
11301 if (cmdp && cmdp->rehash) { /* doing a rehash */
11302 if (cmdp->cmdtype == CMDBUILTIN)
11305 prev = cmdp->param.index;
11311 while ((fullname = padvance(&path, name)) != NULL) {
11312 stunalloc(fullname);
11313 /* NB: code below will still use fullname
11314 * despite it being "unallocated" */
11317 if (prefix(pathopt, "builtin")) {
11319 goto builtin_success;
11321 } else if (!(act & DO_NOFUNC)
11322 && prefix(pathopt, "func")) {
11323 /* handled below */
11325 /* ignore unimplemented options */
11329 /* if rehash, don't redo absolute path names */
11330 if (fullname[0] == '/' && idx <= prev) {
11333 TRACE(("searchexec \"%s\": no change\n", name));
11336 while (stat(fullname, &statb) < 0) {
11338 if (errno == EINTR)
11341 if (errno != ENOENT && errno != ENOTDIR)
11345 e = EACCES; /* if we fail, this will be the error */
11346 if (!S_ISREG(statb.st_mode))
11348 if (pathopt) { /* this is a %func directory */
11349 stalloc(strlen(fullname) + 1);
11350 /* NB: stalloc will return space pointed by fullname
11351 * (because we don't have any intervening allocations
11352 * between stunalloc above and this stalloc) */
11353 readcmdfile(fullname);
11354 cmdp = cmdlookup(name, 0);
11355 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
11356 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
11357 stunalloc(fullname);
11360 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
11362 entry->cmdtype = CMDNORMAL;
11363 entry->u.index = idx;
11367 cmdp = cmdlookup(name, 1);
11368 cmdp->cmdtype = CMDNORMAL;
11369 cmdp->param.index = idx;
11374 /* We failed. If there was an entry for this command, delete it */
11375 if (cmdp && updatetbl)
11376 delete_cmd_entry();
11378 ash_msg("%s: %s", name, errmsg(e, "not found"));
11379 entry->cmdtype = CMDUNKNOWN;
11384 entry->cmdtype = CMDBUILTIN;
11385 entry->u.cmd = bcmd;
11389 cmdp = cmdlookup(name, 1);
11390 cmdp->cmdtype = CMDBUILTIN;
11391 cmdp->param.cmd = bcmd;
11395 entry->cmdtype = cmdp->cmdtype;
11396 entry->u = cmdp->param;
11400 /* ============ trap.c */
11403 * The trap builtin.
11406 trapcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11415 for (signo = 0; signo < NSIG; signo++) {
11416 if (trap[signo] != NULL) {
11419 sn = get_signame(signo);
11420 out1fmt("trap -- %s %s\n",
11421 single_quote(trap[signo]), sn);
11431 signo = get_signum(*ap);
11433 ash_msg_and_raise_error("%s: bad trap", *ap);
11436 if (LONE_DASH(action))
11439 action = ckstrdup(action);
11442 trap[signo] = action;
11452 /* ============ Builtins */
11454 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
11456 * Lists available builtins
11459 helpcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11463 out1fmt("\nBuilt-in commands:\n-------------------\n");
11464 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
11465 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11466 builtintab[i].name + 1);
11472 #if ENABLE_FEATURE_SH_STANDALONE
11474 const char *a = applet_names;
11476 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
11481 a += strlen(a) + 1;
11486 return EXIT_SUCCESS;
11488 #endif /* FEATURE_SH_EXTRA_QUIET */
11491 * The export and readonly commands.
11494 exportcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11500 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
11502 if (nextopt("p") != 'p') {
11507 p = strchr(name, '=');
11511 vp = *findvar(hashvar(name), name);
11517 setvar(name, p, flag);
11518 } while ((name = *++aptr) != NULL);
11522 showvars(argv[0], flag, 0);
11527 * Delete a function if it exists.
11530 unsetfunc(const char *name)
11532 struct tblentry *cmdp;
11534 cmdp = cmdlookup(name, 0);
11535 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
11536 delete_cmd_entry();
11540 * The unset builtin command. We unset the function before we unset the
11541 * variable to allow a function to be unset when there is a readonly variable
11542 * with the same name.
11545 unsetcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11552 while ((i = nextopt("vf")) != '\0') {
11556 for (ap = argptr; *ap; ap++) {
11572 #include <sys/times.h>
11574 static const unsigned char timescmd_str[] ALIGN1 = {
11575 ' ', offsetof(struct tms, tms_utime),
11576 '\n', offsetof(struct tms, tms_stime),
11577 ' ', offsetof(struct tms, tms_cutime),
11578 '\n', offsetof(struct tms, tms_cstime),
11583 timescmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11585 long clk_tck, s, t;
11586 const unsigned char *p;
11589 clk_tck = sysconf(_SC_CLK_TCK);
11594 t = *(clock_t *)(((char *) &buf) + p[1]);
11596 out1fmt("%ldm%ld.%.3lds%c",
11598 ((t - s * clk_tck) * 1000) / clk_tck,
11600 } while (*(p += 2));
11605 #if ENABLE_ASH_MATH_SUPPORT
11607 dash_arith(const char *s)
11613 result = arith(s, &errcode);
11616 ash_msg_and_raise_error("exponent less than 0");
11618 ash_msg_and_raise_error("divide by zero");
11620 ash_msg_and_raise_error("expression recursion loop detected");
11621 raise_error_syntax(s);
11629 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
11630 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
11632 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
11635 letcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11641 ash_msg_and_raise_error("expression expected");
11643 i = dash_arith(*argv);
11648 #endif /* ASH_MATH_SUPPORT */
11651 /* ============ miscbltin.c
11653 * Miscellaneous builtins.
11658 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
11659 typedef enum __rlimit_resource rlim_t;
11663 * The read builtin. The -e option causes backslashes to escape the
11664 * following character.
11666 * This uses unbuffered input, which may be avoidable in some cases.
11669 readcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11681 #if ENABLE_ASH_READ_NCHARS
11685 struct termios tty, old_tty;
11687 #if ENABLE_ASH_READ_TIMEOUT
11691 ts.tv_sec = ts.tv_usec = 0;
11696 #if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT
11697 while ((i = nextopt("p:rt:n:s")) != '\0')
11698 #elif ENABLE_ASH_READ_NCHARS
11699 while ((i = nextopt("p:rn:s")) != '\0')
11700 #elif ENABLE_ASH_READ_TIMEOUT
11701 while ((i = nextopt("p:rt:")) != '\0')
11703 while ((i = nextopt("p:r")) != '\0')
11708 prompt = optionarg;
11710 #if ENABLE_ASH_READ_NCHARS
11712 nchars = bb_strtou(optionarg, NULL, 10);
11713 if (nchars < 0 || errno)
11714 ash_msg_and_raise_error("invalid count");
11715 n_flag = nchars; /* just a flag "nchars is nonzero" */
11721 #if ENABLE_ASH_READ_TIMEOUT
11723 ts.tv_sec = bb_strtou(optionarg, &p, 10);
11725 /* EINVAL means number is ok, but not terminated by NUL */
11726 if (*p == '.' && errno == EINVAL) {
11730 ts.tv_usec = bb_strtou(p, &p2, 10);
11732 ash_msg_and_raise_error("invalid timeout");
11734 /* normalize to usec */
11736 ash_msg_and_raise_error("invalid timeout");
11737 while (scale++ < 6)
11740 } else if (ts.tv_sec < 0 || errno) {
11741 ash_msg_and_raise_error("invalid timeout");
11743 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
11744 ash_msg_and_raise_error("invalid timeout");
11755 if (prompt && isatty(0)) {
11760 ash_msg_and_raise_error("arg count");
11761 ifs = bltinlookup("IFS");
11764 #if ENABLE_ASH_READ_NCHARS
11765 if (n_flag || silent) {
11766 if (tcgetattr(0, &tty) != 0) {
11773 tty.c_lflag &= ~ICANON;
11774 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
11777 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
11779 tcsetattr(0, TCSANOW, &tty);
11783 #if ENABLE_ASH_READ_TIMEOUT
11784 if (ts.tv_sec || ts.tv_usec) {
11788 /* poll-based wait produces bigger code, using select */
11789 i = select(1, &set, NULL, NULL, &ts);
11790 if (!i) { /* timed out! */
11791 #if ENABLE_ASH_READ_NCHARS
11793 tcsetattr(0, TCSANOW, &old_tty);
11804 if (nonblock_safe_read(0, &c, 1) != 1) {
11816 if (!rflag && c == '\\') {
11822 if (startword && *ifs == ' ' && strchr(ifs, c)) {
11826 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
11828 setvar(*ap, stackblock(), 0);
11837 /* end of do {} while: */
11838 #if ENABLE_ASH_READ_NCHARS
11839 while (!n_flag || --nchars);
11844 #if ENABLE_ASH_READ_NCHARS
11845 if (n_flag || silent)
11846 tcsetattr(0, TCSANOW, &old_tty);
11850 /* Remove trailing blanks */
11851 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
11853 setvar(*ap, stackblock(), 0);
11854 while (*++ap != NULL)
11855 setvar(*ap, nullstr, 0);
11860 umaskcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11862 static const char permuser[3] ALIGN1 = "ugo";
11863 static const char permmode[3] ALIGN1 = "rwx";
11864 static const short permmask[] ALIGN2 = {
11865 S_IRUSR, S_IWUSR, S_IXUSR,
11866 S_IRGRP, S_IWGRP, S_IXGRP,
11867 S_IROTH, S_IWOTH, S_IXOTH
11873 int symbolic_mode = 0;
11875 while (nextopt("S") != '\0') {
11886 if (symbolic_mode) {
11890 for (i = 0; i < 3; i++) {
11893 *p++ = permuser[i];
11895 for (j = 0; j < 3; j++) {
11896 if ((mask & permmask[3 * i + j]) == 0) {
11897 *p++ = permmode[j];
11905 out1fmt("%.4o\n", mask);
11908 if (isdigit((unsigned char) *ap)) {
11911 if (*ap >= '8' || *ap < '0')
11912 ash_msg_and_raise_error(illnum, argv[1]);
11913 mask = (mask << 3) + (*ap - '0');
11914 } while (*++ap != '\0');
11917 mask = ~mask & 0777;
11918 if (!bb_parse_mode(ap, &mask)) {
11919 ash_msg_and_raise_error("illegal mode: %s", ap);
11921 umask(~mask & 0777);
11930 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
11931 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
11932 * ash by J.T. Conklin.
11938 uint8_t cmd; /* RLIMIT_xxx fit into it */
11939 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
11943 static const struct limits limits_tbl[] = {
11945 { RLIMIT_CPU, 0, 't' },
11947 #ifdef RLIMIT_FSIZE
11948 { RLIMIT_FSIZE, 9, 'f' },
11951 { RLIMIT_DATA, 10, 'd' },
11953 #ifdef RLIMIT_STACK
11954 { RLIMIT_STACK, 10, 's' },
11957 { RLIMIT_CORE, 9, 'c' },
11960 { RLIMIT_RSS, 10, 'm' },
11962 #ifdef RLIMIT_MEMLOCK
11963 { RLIMIT_MEMLOCK, 10, 'l' },
11965 #ifdef RLIMIT_NPROC
11966 { RLIMIT_NPROC, 0, 'p' },
11968 #ifdef RLIMIT_NOFILE
11969 { RLIMIT_NOFILE, 0, 'n' },
11972 { RLIMIT_AS, 10, 'v' },
11974 #ifdef RLIMIT_LOCKS
11975 { RLIMIT_LOCKS, 0, 'w' },
11978 static const char limits_name[] =
11980 "time(seconds)" "\0"
11982 #ifdef RLIMIT_FSIZE
11983 "file(blocks)" "\0"
11988 #ifdef RLIMIT_STACK
11992 "coredump(blocks)" "\0"
11997 #ifdef RLIMIT_MEMLOCK
11998 "locked memory(kb)" "\0"
12000 #ifdef RLIMIT_NPROC
12003 #ifdef RLIMIT_NOFILE
12009 #ifdef RLIMIT_LOCKS
12014 enum limtype { SOFT = 0x1, HARD = 0x2 };
12017 printlim(enum limtype how, const struct rlimit *limit,
12018 const struct limits *l)
12022 val = limit->rlim_max;
12024 val = limit->rlim_cur;
12026 if (val == RLIM_INFINITY)
12027 out1fmt("unlimited\n");
12029 val >>= l->factor_shift;
12030 out1fmt("%lld\n", (long long) val);
12035 ulimitcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
12039 enum limtype how = SOFT | HARD;
12040 const struct limits *l;
12043 struct rlimit limit;
12046 while ((optc = nextopt("HSa"
12050 #ifdef RLIMIT_FSIZE
12056 #ifdef RLIMIT_STACK
12065 #ifdef RLIMIT_MEMLOCK
12068 #ifdef RLIMIT_NPROC
12071 #ifdef RLIMIT_NOFILE
12077 #ifdef RLIMIT_LOCKS
12095 for (l = limits_tbl; l->option != what; l++)
12098 set = *argptr ? 1 : 0;
12102 if (all || argptr[1])
12103 ash_msg_and_raise_error("too many arguments");
12104 if (strncmp(p, "unlimited\n", 9) == 0)
12105 val = RLIM_INFINITY;
12109 while ((c = *p++) >= '0' && c <= '9') {
12110 val = (val * 10) + (long)(c - '0');
12111 if (val < (rlim_t) 0)
12115 ash_msg_and_raise_error("bad number");
12116 val <<= l->factor_shift;
12120 const char *lname = limits_name;
12121 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12122 getrlimit(l->cmd, &limit);
12123 out1fmt("%-20s ", lname);
12124 lname += strlen(lname) + 1;
12125 printlim(how, &limit, l);
12130 getrlimit(l->cmd, &limit);
12133 limit.rlim_max = val;
12135 limit.rlim_cur = val;
12136 if (setrlimit(l->cmd, &limit) < 0)
12137 ash_msg_and_raise_error("error setting limit (%m)");
12139 printlim(how, &limit, l);
12145 /* ============ Math support */
12147 #if ENABLE_ASH_MATH_SUPPORT
12149 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12151 Permission is hereby granted, free of charge, to any person obtaining
12152 a copy of this software and associated documentation files (the
12153 "Software"), to deal in the Software without restriction, including
12154 without limitation the rights to use, copy, modify, merge, publish,
12155 distribute, sublicense, and/or sell copies of the Software, and to
12156 permit persons to whom the Software is furnished to do so, subject to
12157 the following conditions:
12159 The above copyright notice and this permission notice shall be
12160 included in all copies or substantial portions of the Software.
12162 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12163 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12164 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12165 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12166 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12167 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12168 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12171 /* This is my infix parser/evaluator. It is optimized for size, intended
12172 * as a replacement for yacc-based parsers. However, it may well be faster
12173 * than a comparable parser written in yacc. The supported operators are
12174 * listed in #defines below. Parens, order of operations, and error handling
12175 * are supported. This code is thread safe. The exact expression format should
12176 * be that which POSIX specifies for shells. */
12178 /* The code uses a simple two-stack algorithm. See
12179 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12180 * for a detailed explanation of the infix-to-postfix algorithm on which
12181 * this is based (this code differs in that it applies operators immediately
12182 * to the stack instead of adding them to a queue to end up with an
12185 /* To use the routine, call it with an expression string and error return
12189 * Aug 24, 2001 Manuel Novoa III
12191 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12193 * 1) In arith_apply():
12194 * a) Cached values of *numptr and &(numptr[-1]).
12195 * b) Removed redundant test for zero denominator.
12198 * a) Eliminated redundant code for processing operator tokens by moving
12199 * to a table-based implementation. Also folded handling of parens
12201 * b) Combined all 3 loops which called arith_apply to reduce generated
12202 * code size at the cost of speed.
12204 * 3) The following expressions were treated as valid by the original code:
12205 * 1() , 0! , 1 ( *3 ) .
12206 * These bugs have been fixed by internally enclosing the expression in
12207 * parens and then checking that all binary ops and right parens are
12208 * preceded by a valid expression (NUM_TOKEN).
12210 * Note: It may be desirable to replace Aaron's test for whitespace with
12211 * ctype's isspace() if it is used by another busybox applet or if additional
12212 * whitespace chars should be considered. Look below the "#include"s for a
12213 * precompiler test.
12217 * Aug 26, 2001 Manuel Novoa III
12219 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12221 * Merge in Aaron's comments previously posted to the busybox list,
12222 * modified slightly to take account of my changes to the code.
12227 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12229 * - allow access to variable,
12230 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12231 * - realize assign syntax (VAR=expr, +=, *= etc)
12232 * - realize exponentiation (** operator)
12233 * - realize comma separated - expr, expr
12234 * - realise ++expr --expr expr++ expr--
12235 * - realise expr ? expr : expr (but, second expr calculate always)
12236 * - allow hexadecimal and octal numbers
12237 * - was restored loses XOR operator
12238 * - remove one goto label, added three ;-)
12239 * - protect $((num num)) as true zero expr (Manuel`s error)
12240 * - always use special isspace(), see comment from bash ;-)
12243 #define arith_isspace(arithval) \
12244 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12246 typedef unsigned char operator;
12248 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12249 * precedence, and 3 high bits are an ID unique across operators of that
12250 * precedence. The ID portion is so that multiple operators can have the
12251 * same precedence, ensuring that the leftmost one is evaluated first.
12252 * Consider * and /. */
12254 #define tok_decl(prec,id) (((id)<<5)|(prec))
12255 #define PREC(op) ((op) & 0x1F)
12257 #define TOK_LPAREN tok_decl(0,0)
12259 #define TOK_COMMA tok_decl(1,0)
12261 #define TOK_ASSIGN tok_decl(2,0)
12262 #define TOK_AND_ASSIGN tok_decl(2,1)
12263 #define TOK_OR_ASSIGN tok_decl(2,2)
12264 #define TOK_XOR_ASSIGN tok_decl(2,3)
12265 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12266 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12267 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12268 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12270 #define TOK_MUL_ASSIGN tok_decl(3,0)
12271 #define TOK_DIV_ASSIGN tok_decl(3,1)
12272 #define TOK_REM_ASSIGN tok_decl(3,2)
12274 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12275 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12277 /* conditional is right associativity too */
12278 #define TOK_CONDITIONAL tok_decl(4,0)
12279 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12281 #define TOK_OR tok_decl(5,0)
12283 #define TOK_AND tok_decl(6,0)
12285 #define TOK_BOR tok_decl(7,0)
12287 #define TOK_BXOR tok_decl(8,0)
12289 #define TOK_BAND tok_decl(9,0)
12291 #define TOK_EQ tok_decl(10,0)
12292 #define TOK_NE tok_decl(10,1)
12294 #define TOK_LT tok_decl(11,0)
12295 #define TOK_GT tok_decl(11,1)
12296 #define TOK_GE tok_decl(11,2)
12297 #define TOK_LE tok_decl(11,3)
12299 #define TOK_LSHIFT tok_decl(12,0)
12300 #define TOK_RSHIFT tok_decl(12,1)
12302 #define TOK_ADD tok_decl(13,0)
12303 #define TOK_SUB tok_decl(13,1)
12305 #define TOK_MUL tok_decl(14,0)
12306 #define TOK_DIV tok_decl(14,1)
12307 #define TOK_REM tok_decl(14,2)
12309 /* exponent is right associativity */
12310 #define TOK_EXPONENT tok_decl(15,1)
12312 /* For now unary operators. */
12313 #define UNARYPREC 16
12314 #define TOK_BNOT tok_decl(UNARYPREC,0)
12315 #define TOK_NOT tok_decl(UNARYPREC,1)
12317 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12318 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12320 #define PREC_PRE (UNARYPREC+2)
12322 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12323 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12325 #define PREC_POST (UNARYPREC+3)
12327 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12328 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12330 #define SPEC_PREC (UNARYPREC+4)
12332 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12333 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12335 #define NUMPTR (*numstackptr)
12338 tok_have_assign(operator op)
12340 operator prec = PREC(op);
12342 convert_prec_is_assing(prec);
12343 return (prec == PREC(TOK_ASSIGN) ||
12344 prec == PREC_PRE || prec == PREC_POST);
12348 is_right_associativity(operator prec)
12350 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
12351 || prec == PREC(TOK_CONDITIONAL));
12354 typedef struct ARITCH_VAR_NUM {
12356 arith_t contidional_second_val;
12357 char contidional_second_val_initialized;
12358 char *var; /* if NULL then is regular number,
12359 else is variable name */
12362 typedef struct CHK_VAR_RECURSIVE_LOOPED {
12364 struct CHK_VAR_RECURSIVE_LOOPED *next;
12365 } chk_var_recursive_looped_t;
12367 static chk_var_recursive_looped_t *prev_chk_var_recursive;
12370 arith_lookup_val(v_n_t *t)
12373 const char * p = lookupvar(t->var);
12378 /* recursive try as expression */
12379 chk_var_recursive_looped_t *cur;
12380 chk_var_recursive_looped_t cur_save;
12382 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
12383 if (strcmp(cur->var, t->var) == 0) {
12384 /* expression recursion loop detected */
12388 /* save current lookuped var name */
12389 cur = prev_chk_var_recursive;
12390 cur_save.var = t->var;
12391 cur_save.next = cur;
12392 prev_chk_var_recursive = &cur_save;
12394 t->val = arith (p, &errcode);
12395 /* restore previous ptr after recursiving */
12396 prev_chk_var_recursive = cur;
12399 /* allow undefined var as 0 */
12405 /* "applying" a token means performing it on the top elements on the integer
12406 * stack. For a unary operator it will only change the top element, but a
12407 * binary operator will pop two arguments and push a result */
12409 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
12412 arith_t numptr_val, rez;
12413 int ret_arith_lookup_val;
12415 /* There is no operator that can work without arguments */
12416 if (NUMPTR == numstack) goto err;
12417 numptr_m1 = NUMPTR - 1;
12419 /* check operand is var with noninteger value */
12420 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12421 if (ret_arith_lookup_val)
12422 return ret_arith_lookup_val;
12424 rez = numptr_m1->val;
12425 if (op == TOK_UMINUS)
12427 else if (op == TOK_NOT)
12429 else if (op == TOK_BNOT)
12431 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
12433 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
12435 else if (op != TOK_UPLUS) {
12436 /* Binary operators */
12438 /* check and binary operators need two arguments */
12439 if (numptr_m1 == numstack) goto err;
12441 /* ... and they pop one */
12444 if (op == TOK_CONDITIONAL) {
12445 if (! numptr_m1->contidional_second_val_initialized) {
12446 /* protect $((expr1 ? expr2)) without ": expr" */
12449 rez = numptr_m1->contidional_second_val;
12450 } else if (numptr_m1->contidional_second_val_initialized) {
12451 /* protect $((expr1 : expr2)) without "expr ? " */
12454 numptr_m1 = NUMPTR - 1;
12455 if (op != TOK_ASSIGN) {
12456 /* check operand is var with noninteger value for not '=' */
12457 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12458 if (ret_arith_lookup_val)
12459 return ret_arith_lookup_val;
12461 if (op == TOK_CONDITIONAL) {
12462 numptr_m1->contidional_second_val = rez;
12464 rez = numptr_m1->val;
12465 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
12467 else if (op == TOK_OR)
12468 rez = numptr_val || rez;
12469 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
12471 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
12473 else if (op == TOK_AND)
12474 rez = rez && numptr_val;
12475 else if (op == TOK_EQ)
12476 rez = (rez == numptr_val);
12477 else if (op == TOK_NE)
12478 rez = (rez != numptr_val);
12479 else if (op == TOK_GE)
12480 rez = (rez >= numptr_val);
12481 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
12482 rez >>= numptr_val;
12483 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
12484 rez <<= numptr_val;
12485 else if (op == TOK_GT)
12486 rez = (rez > numptr_val);
12487 else if (op == TOK_LT)
12488 rez = (rez < numptr_val);
12489 else if (op == TOK_LE)
12490 rez = (rez <= numptr_val);
12491 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
12493 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
12495 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
12497 else if (op == TOK_ASSIGN || op == TOK_COMMA)
12499 else if (op == TOK_CONDITIONAL_SEP) {
12500 if (numptr_m1 == numstack) {
12501 /* protect $((expr : expr)) without "expr ? " */
12504 numptr_m1->contidional_second_val_initialized = op;
12505 numptr_m1->contidional_second_val = numptr_val;
12506 } else if (op == TOK_CONDITIONAL) {
12508 numptr_val : numptr_m1->contidional_second_val;
12509 } else if (op == TOK_EXPONENT) {
12510 if (numptr_val < 0)
12511 return -3; /* exponent less than 0 */
12516 while (numptr_val--)
12520 } else if (numptr_val==0) /* zero divisor check */
12522 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
12524 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
12527 if (tok_have_assign(op)) {
12528 char buf[sizeof(arith_t_type)*3 + 2];
12530 if (numptr_m1->var == NULL) {
12534 /* save to shell variable */
12535 #if ENABLE_ASH_MATH_SUPPORT_64
12536 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
12538 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
12540 setvar(numptr_m1->var, buf, 0);
12541 /* after saving, make previous value for v++ or v-- */
12542 if (op == TOK_POST_INC)
12544 else if (op == TOK_POST_DEC)
12547 numptr_m1->val = rez;
12548 /* protect geting var value, is number now */
12549 numptr_m1->var = NULL;
12555 /* longest must be first */
12556 static const char op_tokens[] ALIGN1 = {
12557 '<','<','=',0, TOK_LSHIFT_ASSIGN,
12558 '>','>','=',0, TOK_RSHIFT_ASSIGN,
12559 '<','<', 0, TOK_LSHIFT,
12560 '>','>', 0, TOK_RSHIFT,
12561 '|','|', 0, TOK_OR,
12562 '&','&', 0, TOK_AND,
12563 '!','=', 0, TOK_NE,
12564 '<','=', 0, TOK_LE,
12565 '>','=', 0, TOK_GE,
12566 '=','=', 0, TOK_EQ,
12567 '|','=', 0, TOK_OR_ASSIGN,
12568 '&','=', 0, TOK_AND_ASSIGN,
12569 '*','=', 0, TOK_MUL_ASSIGN,
12570 '/','=', 0, TOK_DIV_ASSIGN,
12571 '%','=', 0, TOK_REM_ASSIGN,
12572 '+','=', 0, TOK_PLUS_ASSIGN,
12573 '-','=', 0, TOK_MINUS_ASSIGN,
12574 '-','-', 0, TOK_POST_DEC,
12575 '^','=', 0, TOK_XOR_ASSIGN,
12576 '+','+', 0, TOK_POST_INC,
12577 '*','*', 0, TOK_EXPONENT,
12581 '=', 0, TOK_ASSIGN,
12593 '?', 0, TOK_CONDITIONAL,
12594 ':', 0, TOK_CONDITIONAL_SEP,
12595 ')', 0, TOK_RPAREN,
12596 '(', 0, TOK_LPAREN,
12600 #define endexpression &op_tokens[sizeof(op_tokens)-7]
12603 arith(const char *expr, int *perrcode)
12605 char arithval; /* Current character under analysis */
12606 operator lasttok, op;
12609 const char *p = endexpression;
12612 size_t datasizes = strlen(expr) + 2;
12614 /* Stack of integers */
12615 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
12616 * in any given correct or incorrect expression is left as an exercise to
12618 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
12619 *numstackptr = numstack;
12620 /* Stack of operator tokens */
12621 operator *stack = alloca((datasizes) * sizeof(operator)),
12624 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
12625 *perrcode = errcode = 0;
12629 if (arithval == 0) {
12630 if (p == endexpression) {
12631 /* Null expression. */
12635 /* This is only reached after all tokens have been extracted from the
12636 * input stream. If there are still tokens on the operator stack, they
12637 * are to be applied in order. At the end, there should be a final
12638 * result on the integer stack */
12640 if (expr != endexpression + 1) {
12641 /* If we haven't done so already, */
12642 /* append a closing right paren */
12643 expr = endexpression;
12644 /* and let the loop process it. */
12647 /* At this point, we're done with the expression. */
12648 if (numstackptr != numstack+1) {
12649 /* ... but if there isn't, it's bad */
12651 return (*perrcode = -1);
12653 if (numstack->var) {
12654 /* expression is $((var)) only, lookup now */
12655 errcode = arith_lookup_val(numstack);
12658 *perrcode = errcode;
12659 return numstack->val;
12662 /* Continue processing the expression. */
12663 if (arith_isspace(arithval)) {
12664 /* Skip whitespace */
12667 p = endofname(expr);
12669 size_t var_name_size = (p-expr) + 1; /* trailing zero */
12671 numstackptr->var = alloca(var_name_size);
12672 safe_strncpy(numstackptr->var, expr, var_name_size);
12675 numstackptr->contidional_second_val_initialized = 0;
12680 if (isdigit(arithval)) {
12681 numstackptr->var = NULL;
12682 #if ENABLE_ASH_MATH_SUPPORT_64
12683 numstackptr->val = strtoll(expr, (char **) &expr, 0);
12685 numstackptr->val = strtol(expr, (char **) &expr, 0);
12689 for (p = op_tokens; ; p++) {
12693 /* strange operator not found */
12696 for (o = expr; *p && *o == *p; p++)
12703 /* skip tail uncompared token */
12706 /* skip zero delim */
12711 /* post grammar: a++ reduce to num */
12712 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
12715 /* Plus and minus are binary (not unary) _only_ if the last
12716 * token was as number, or a right paren (which pretends to be
12717 * a number, since it evaluates to one). Think about it.
12718 * It makes sense. */
12719 if (lasttok != TOK_NUM) {
12735 /* We don't want a unary operator to cause recursive descent on the
12736 * stack, because there can be many in a row and it could cause an
12737 * operator to be evaluated before its argument is pushed onto the
12738 * integer stack. */
12739 /* But for binary operators, "apply" everything on the operator
12740 * stack until we find an operator with a lesser priority than the
12741 * one we have just extracted. */
12742 /* Left paren is given the lowest priority so it will never be
12743 * "applied" in this way.
12744 * if associativity is right and priority eq, applied also skip
12747 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
12748 /* not left paren or unary */
12749 if (lasttok != TOK_NUM) {
12750 /* binary op must be preceded by a num */
12753 while (stackptr != stack) {
12754 if (op == TOK_RPAREN) {
12755 /* The algorithm employed here is simple: while we don't
12756 * hit an open paren nor the bottom of the stack, pop
12757 * tokens and apply them */
12758 if (stackptr[-1] == TOK_LPAREN) {
12760 /* Any operator directly after a */
12762 /* close paren should consider itself binary */
12766 operator prev_prec = PREC(stackptr[-1]);
12768 convert_prec_is_assing(prec);
12769 convert_prec_is_assing(prev_prec);
12770 if (prev_prec < prec)
12772 /* check right assoc */
12773 if (prev_prec == prec && is_right_associativity(prec))
12776 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
12777 if (errcode) goto ret;
12779 if (op == TOK_RPAREN) {
12784 /* Push this operator to the stack and remember it. */
12785 *stackptr++ = lasttok = op;
12790 #endif /* ASH_MATH_SUPPORT */
12793 /* ============ main() and helpers */
12796 * Called to exit the shell.
12798 static void exitshell(void) ATTRIBUTE_NORETURN;
12806 status = exitstatus;
12807 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12808 if (setjmp(loc.loc)) {
12809 if (exception == EXEXIT)
12810 /* dash bug: it just does _exit(exitstatus) here
12811 * but we have to do setjobctl(0) first!
12812 * (bug is still not fixed in dash-0.5.3 - if you run dash
12813 * under Midnight Commander, on exit from dash MC is backgrounded) */
12814 status = exitstatus;
12817 exception_handler = &loc;
12823 flush_stdout_stderr();
12833 /* from input.c: */
12834 basepf.nextc = basepf.buf = basebuf;
12837 signal(SIGCHLD, SIG_DFL);
12842 char ppid[sizeof(int)*3 + 1];
12844 struct stat st1, st2;
12847 for (envp = environ; envp && *envp; envp++) {
12848 if (strchr(*envp, '=')) {
12849 setvareq(*envp, VEXPORT|VTEXTFIXED);
12853 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
12854 setvar("PPID", ppid, 0);
12856 p = lookupvar("PWD");
12858 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
12859 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
12866 * Process the shell command line arguments.
12869 procargs(char **argv)
12872 const char *xminusc;
12877 /* if (xargv[0]) - mmm, this is always true! */
12879 for (i = 0; i < NOPTS; i++)
12883 /* it already printed err message */
12884 raise_exception(EXERROR);
12888 if (*xargv == NULL) {
12890 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
12893 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
12897 for (i = 0; i < NOPTS; i++)
12898 if (optlist[i] == 2)
12903 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
12908 } else if (!sflag) {
12909 setinputfile(*xargv, 0);
12912 commandname = arg0;
12915 shellparam.p = xargv;
12916 #if ENABLE_ASH_GETOPTS
12917 shellparam.optind = 1;
12918 shellparam.optoff = -1;
12920 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
12922 shellparam.nparam++;
12929 * Read /etc/profile or .profile.
12932 read_profile(const char *name)
12936 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
12945 * This routine is called when an error or an interrupt occurs in an
12946 * interactive shell and control is returned to the main command loop.
12954 /* from input.c: */
12955 parselleft = parsenleft = 0; /* clear input buffer */
12957 /* from parser.c: */
12960 /* from redir.c: */
12965 static short profile_buf[16384];
12966 extern int etext();
12970 * Main routine. We initialize things, parse the arguments, execute
12971 * profiles if we're a login shell, and then call cmdloop to execute
12972 * commands. The setjmp call sets up the location to jump to when an
12973 * exception occurs. When an exception occurs the variable "state"
12974 * is used to figure out how far we had gotten.
12976 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
12977 int ash_main(int argc ATTRIBUTE_UNUSED, char **argv)
12980 volatile int state;
12981 struct jmploc jmploc;
12982 struct stackmark smark;
12984 /* Initialize global data */
12988 #if ENABLE_ASH_ALIAS
12994 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
12997 #if ENABLE_FEATURE_EDITING
12998 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13001 if (setjmp(jmploc.loc)) {
13011 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13015 outcslow('\n', stderr);
13017 popstackmark(&smark);
13018 FORCE_INT_ON; /* enable interrupts */
13027 exception_handler = &jmploc;
13030 trace_puts("Shell args: ");
13031 trace_puts_args(argv);
13033 rootpid = getpid();
13035 #if ENABLE_ASH_RANDOM_SUPPORT
13036 rseed = rootpid + time(NULL);
13039 setstackmark(&smark);
13042 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13044 const char *hp = lookupvar("HISTFILE");
13047 hp = lookupvar("HOME");
13049 char *defhp = concat_path_file(hp, ".ash_history");
13050 setvar("HISTFILE", defhp, 0);
13056 if (argv[0] && argv[0][0] == '-')
13060 read_profile("/etc/profile");
13063 read_profile(".profile");
13069 getuid() == geteuid() && getgid() == getegid() &&
13073 shinit = lookupvar("ENV");
13074 if (shinit != NULL && *shinit != '\0') {
13075 read_profile(shinit);
13081 evalstring(minusc, 0);
13083 if (sflag || minusc == NULL) {
13084 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13086 const char *hp = lookupvar("HISTFILE");
13089 line_input_state->hist_file = hp;
13092 state4: /* XXX ??? - why isn't this before the "if" statement */
13100 extern void _mcleanup(void);
13109 const char *applet_name = "debug stuff usage";
13110 int main(int argc, char **argv)
13112 return ash_main(argc, argv);
13118 * Copyright (c) 1989, 1991, 1993, 1994
13119 * The Regents of the University of California. All rights reserved.
13121 * This code is derived from software contributed to Berkeley by
13122 * Kenneth Almquist.
13124 * Redistribution and use in source and binary forms, with or without
13125 * modification, are permitted provided that the following conditions
13127 * 1. Redistributions of source code must retain the above copyright
13128 * notice, this list of conditions and the following disclaimer.
13129 * 2. Redistributions in binary form must reproduce the above copyright
13130 * notice, this list of conditions and the following disclaimer in the
13131 * documentation and/or other materials provided with the distribution.
13132 * 3. Neither the name of the University nor the names of its contributors
13133 * may be used to endorse or promote products derived from this software
13134 * without specific prior written permission.
13136 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13137 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13138 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13139 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13140 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13141 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13142 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13143 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13144 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13145 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF