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);
3251 #define forkshell(job, node, mode) forkshell(job, mode)
3253 static int forkshell(struct job *, union node *, int);
3254 static int waitforjob(struct job *);
3257 enum { jobctl = 0 };
3258 #define setjobctl(on) do {} while (0)
3260 static smallint jobctl; /* true if doing job control */
3261 static void setjobctl(int);
3265 * Set the signal handler for the specified signal. The routine figures
3266 * out what it should be set to.
3269 setsignal(int signo)
3273 struct sigaction act;
3279 else if (*t != '\0')
3281 if (rootshell && action == S_DFL) {
3284 if (iflag || minusc || sflag == 0)
3307 t = &sigmode[signo - 1];
3311 * current setting unknown
3313 if (sigaction(signo, NULL, &act) == -1) {
3315 * Pretend it worked; maybe we should give a warning
3316 * here, but other shells don't. We don't alter
3317 * sigmode, so that we retry every time.
3321 tsig = S_RESET; /* force to be set */
3322 if (act.sa_handler == SIG_IGN) {
3325 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3327 tsig = S_IGN; /* don't hard ignore these */
3331 if (tsig == S_HARD_IGN || tsig == action)
3333 act.sa_handler = SIG_DFL;
3336 act.sa_handler = onsig;
3339 act.sa_handler = SIG_IGN;
3344 sigfillset(&act.sa_mask);
3345 sigaction_set(signo, &act);
3348 /* mode flags for set_curjob */
3349 #define CUR_DELETE 2
3350 #define CUR_RUNNING 1
3351 #define CUR_STOPPED 0
3353 /* mode flags for dowait */
3354 #define DOWAIT_NONBLOCK WNOHANG
3355 #define DOWAIT_BLOCK 0
3358 /* pgrp of shell on invocation */
3359 static int initialpgrp;
3360 static int ttyfd = -1;
3363 static struct job *jobtab;
3365 static unsigned njobs;
3367 static struct job *curjob;
3368 /* number of presumed living untracked jobs */
3372 set_curjob(struct job *jp, unsigned mode)
3375 struct job **jpp, **curp;
3377 /* first remove from list */
3378 jpp = curp = &curjob;
3383 jpp = &jp1->prev_job;
3385 *jpp = jp1->prev_job;
3387 /* Then re-insert in correct position */
3395 /* job being deleted */
3398 /* newly created job or backgrounded job,
3399 put after all stopped jobs. */
3403 if (!jp1 || jp1->state != JOBSTOPPED)
3406 jpp = &jp1->prev_job;
3412 /* newly stopped job - becomes curjob */
3413 jp->prev_job = *jpp;
3421 jobno(const struct job *jp)
3423 return jp - jobtab + 1;
3428 * Convert a job name to a job structure.
3431 #define getjob(name, getctl) getjob(name)
3434 getjob(const char *name, int getctl)
3438 const char *err_msg = "No such job: %s";
3442 char *(*match)(const char *, const char *);
3457 if (c == '+' || c == '%') {
3459 err_msg = "No current job";
3465 err_msg = "No previous job";
3476 jp = jobtab + num - 1;
3493 if (match(jp->ps[0].cmd, p)) {
3497 err_msg = "%s: ambiguous";
3504 err_msg = "job %s not created under job control";
3505 if (getctl && jp->jobctl == 0)
3510 ash_msg_and_raise_error(err_msg, name);
3514 * Mark a job structure as unused.
3517 freejob(struct job *jp)
3519 struct procstat *ps;
3523 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3524 if (ps->cmd != nullstr)
3527 if (jp->ps != &jp->ps0)
3530 set_curjob(jp, CUR_DELETE);
3536 xtcsetpgrp(int fd, pid_t pgrp)
3538 if (tcsetpgrp(fd, pgrp))
3539 ash_msg_and_raise_error("cannot set tty process group (%m)");
3543 * Turn job control on and off.
3545 * Note: This code assumes that the third arg to ioctl is a character
3546 * pointer, which is true on Berkeley systems but not System V. Since
3547 * System V doesn't have job control yet, this isn't a problem now.
3549 * Called with interrupts off.
3557 if (on == jobctl || rootshell == 0)
3561 ofd = fd = open(_PATH_TTY, O_RDWR);
3563 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3564 * That sometimes helps to acquire controlling tty.
3565 * Obviously, a workaround for bugs when someone
3566 * failed to provide a controlling tty to bash! :) */
3572 fd = fcntl(fd, F_DUPFD, 10);
3577 /* fd is a tty at this point */
3578 close_on_exec_on(fd);
3579 do { /* while we are in the background */
3580 pgrp = tcgetpgrp(fd);
3583 ash_msg("can't access tty; job control turned off");
3587 if (pgrp == getpgrp())
3598 xtcsetpgrp(fd, pgrp);
3600 /* turning job control off */
3603 /* was xtcsetpgrp, but this can make exiting ash
3604 * loop forever if pty is already deleted */
3605 tcsetpgrp(fd, pgrp);
3620 killcmd(int argc, char **argv)
3623 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3625 if (argv[i][0] == '%') {
3626 struct job *jp = getjob(argv[i], 0);
3627 unsigned pid = jp->ps[0].pid;
3628 /* Enough space for ' -NNN<nul>' */
3629 argv[i] = alloca(sizeof(int)*3 + 3);
3630 /* kill_main has matching code to expect
3631 * leading space. Needed to not confuse
3632 * negative pids with "kill -SIGNAL_NO" syntax */
3633 sprintf(argv[i], " -%u", pid);
3635 } while (argv[++i]);
3637 return kill_main(argc, argv);
3641 showpipe(struct job *jp, FILE *out)
3643 struct procstat *sp;
3644 struct procstat *spend;
3646 spend = jp->ps + jp->nprocs;
3647 for (sp = jp->ps + 1; sp < spend; sp++)
3648 fprintf(out, " | %s", sp->cmd);
3649 outcslow('\n', out);
3650 flush_stdout_stderr();
3655 restartjob(struct job *jp, int mode)
3657 struct procstat *ps;
3663 if (jp->state == JOBDONE)
3665 jp->state = JOBRUNNING;
3667 if (mode == FORK_FG)
3668 xtcsetpgrp(ttyfd, pgid);
3669 killpg(pgid, SIGCONT);
3673 if (WIFSTOPPED(ps->status)) {
3679 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3685 fg_bgcmd(int argc ATTRIBUTE_UNUSED, char **argv)
3692 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3697 jp = getjob(*argv, 1);
3698 if (mode == FORK_BG) {
3699 set_curjob(jp, CUR_RUNNING);
3700 fprintf(out, "[%d] ", jobno(jp));
3702 outstr(jp->ps->cmd, out);
3704 retval = restartjob(jp, mode);
3705 } while (*argv && *++argv);
3711 sprint_status(char *s, int status, int sigonly)
3717 if (!WIFEXITED(status)) {
3719 if (WIFSTOPPED(status))
3720 st = WSTOPSIG(status);
3723 st = WTERMSIG(status);
3725 if (st == SIGINT || st == SIGPIPE)
3728 if (WIFSTOPPED(status))
3733 col = fmtstr(s, 32, strsignal(st));
3734 if (WCOREDUMP(status)) {
3735 col += fmtstr(s + col, 16, " (core dumped)");
3737 } else if (!sigonly) {
3738 st = WEXITSTATUS(status);
3740 col = fmtstr(s, 16, "Done(%d)", st);
3742 col = fmtstr(s, 16, "Done");
3749 * Do a wait system call. If job control is compiled in, we accept
3750 * stopped processes. If block is zero, we return a value of zero
3751 * rather than blocking.
3753 * System V doesn't have a non-blocking wait system call. It does
3754 * have a SIGCLD signal that is sent to a process when one of it's
3755 * children dies. The obvious way to use SIGCLD would be to install
3756 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
3757 * was received, and have waitproc bump another counter when it got
3758 * the status of a process. Waitproc would then know that a wait
3759 * system call would not block if the two counters were different.
3760 * This approach doesn't work because if a process has children that
3761 * have not been waited for, System V will send it a SIGCLD when it
3762 * installs a signal handler for SIGCLD. What this means is that when
3763 * a child exits, the shell will be sent SIGCLD signals continuously
3764 * until is runs out of stack space, unless it does a wait call before
3765 * restoring the signal handler. The code below takes advantage of
3766 * this (mis)feature by installing a signal handler for SIGCLD and
3767 * then checking to see whether it was called. If there are any
3768 * children to be waited for, it will be.
3770 * If neither SYSV nor BSD is defined, we don't implement nonblocking
3771 * waits at all. In this case, the user will not be informed when
3772 * a background process until the next time she runs a real program
3773 * (as opposed to running a builtin command or just typing return),
3774 * and the jobs command may give out of date information.
3777 waitproc(int wait_flags, int *status)
3781 wait_flags |= WUNTRACED;
3783 /* NB: _not_ safe_waitpid, we need to detect EINTR */
3784 return waitpid(-1, status, wait_flags);
3788 * Wait for a process to terminate.
3791 dowait(int wait_flags, struct job *job)
3796 struct job *thisjob;
3799 TRACE(("dowait(%d) called\n", wait_flags));
3800 pid = waitproc(wait_flags, &status);
3801 TRACE(("wait returns pid=%d, status=%d\n", pid, status));
3803 /* If we were doing blocking wait and (probably) got EINTR,
3804 * check for pending sigs received while waiting.
3805 * (NB: can be moved into callers if needed) */
3806 if (wait_flags == DOWAIT_BLOCK && pendingsig)
3807 raise_exception(EXSIG);
3812 for (jp = curjob; jp; jp = jp->prev_job) {
3813 struct procstat *sp;
3814 struct procstat *spend;
3815 if (jp->state == JOBDONE)
3818 spend = jp->ps + jp->nprocs;
3821 if (sp->pid == pid) {
3822 TRACE(("Job %d: changing status of proc %d "
3823 "from 0x%x to 0x%x\n",
3824 jobno(jp), pid, sp->status, status));
3825 sp->status = status;
3828 if (sp->status == -1)
3831 if (state == JOBRUNNING)
3833 if (WIFSTOPPED(sp->status)) {
3834 jp->stopstatus = sp->status;
3838 } while (++sp < spend);
3843 if (!WIFSTOPPED(status))
3849 if (state != JOBRUNNING) {
3850 thisjob->changed = 1;
3852 if (thisjob->state != state) {
3853 TRACE(("Job %d: changing state from %d to %d\n",
3854 jobno(thisjob), thisjob->state, state));
3855 thisjob->state = state;
3857 if (state == JOBSTOPPED) {
3858 set_curjob(thisjob, CUR_STOPPED);
3867 if (thisjob && thisjob == job) {
3871 len = sprint_status(s, status, 1);
3883 showjob(FILE *out, struct job *jp, int mode)
3885 struct procstat *ps;
3886 struct procstat *psend;
3893 if (mode & SHOW_PGID) {
3894 /* just output process (group) id of pipeline */
3895 fprintf(out, "%d\n", ps->pid);
3899 col = fmtstr(s, 16, "[%d] ", jobno(jp));
3904 else if (curjob && jp == curjob->prev_job)
3907 if (mode & SHOW_PID)
3908 col += fmtstr(s + col, 16, "%d ", ps->pid);
3910 psend = ps + jp->nprocs;
3912 if (jp->state == JOBRUNNING) {
3913 strcpy(s + col, "Running");
3914 col += sizeof("Running") - 1;
3916 int status = psend[-1].status;
3917 if (jp->state == JOBSTOPPED)
3918 status = jp->stopstatus;
3919 col += sprint_status(s + col, status, 0);
3925 /* for each process */
3926 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
3928 fprintf(out, "%s%*c%s",
3929 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
3931 if (!(mode & SHOW_PID)) {
3935 if (++ps == psend) {
3936 outcslow('\n', out);
3943 if (jp->state == JOBDONE) {
3944 TRACE(("showjob: freeing job %d\n", jobno(jp)));
3950 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3951 * statuses have changed since the last call to showjobs.
3954 showjobs(FILE *out, int mode)
3958 TRACE(("showjobs(%x) called\n", mode));
3960 /* If not even one job changed, there is nothing to do */
3961 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3964 for (jp = curjob; jp; jp = jp->prev_job) {
3965 if (!(mode & SHOW_CHANGED) || jp->changed) {
3966 showjob(out, jp, mode);
3972 jobscmd(int argc ATTRIBUTE_UNUSED, char **argv)
3977 while ((m = nextopt("lp"))) {
3987 showjob(stdout, getjob(*argv,0), mode);
3990 showjobs(stdout, mode);
3997 getstatus(struct job *job)
4002 status = job->ps[job->nprocs - 1].status;
4003 retval = WEXITSTATUS(status);
4004 if (!WIFEXITED(status)) {
4006 retval = WSTOPSIG(status);
4007 if (!WIFSTOPPED(status))
4010 /* XXX: limits number of signals */
4011 retval = WTERMSIG(status);
4013 if (retval == SIGINT)
4019 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
4020 jobno(job), job->nprocs, status, retval));
4025 waitcmd(int argc ATTRIBUTE_UNUSED, char **argv)
4034 raise_exception(EXSIG);
4041 /* wait for all jobs */
4045 if (!jp) /* no running procs */
4047 if (jp->state == JOBRUNNING)
4052 dowait(DOWAIT_BLOCK, NULL);
4058 if (**argv != '%') {
4059 pid_t pid = number(*argv);
4064 if (job->ps[job->nprocs - 1].pid == pid)
4066 job = job->prev_job;
4069 job = getjob(*argv, 0);
4070 /* loop until process terminated or stopped */
4071 while (job->state == JOBRUNNING)
4072 dowait(DOWAIT_BLOCK, NULL);
4074 retval = getstatus(job);
4088 struct job *jp, *jq;
4090 len = njobs * sizeof(*jp);
4092 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4094 offset = (char *)jp - (char *)jq;
4096 /* Relocate pointers */
4099 jq = (struct job *)((char *)jq + l);
4103 #define joff(p) ((struct job *)((char *)(p) + l))
4104 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4105 if (joff(jp)->ps == &jq->ps0)
4106 jmove(joff(jp)->ps);
4107 if (joff(jp)->prev_job)
4108 jmove(joff(jp)->prev_job);
4118 jp = (struct job *)((char *)jp + len);
4122 } while (--jq >= jp);
4127 * Return a new job structure.
4128 * Called with interrupts off.
4131 makejob(/*union node *node,*/ int nprocs)
4136 for (i = njobs, jp = jobtab; ; jp++) {
4143 if (jp->state != JOBDONE || !jp->waited)
4152 memset(jp, 0, sizeof(*jp));
4154 /* jp->jobctl is a bitfield.
4155 * "jp->jobctl |= jobctl" likely to give awful code */
4159 jp->prev_job = curjob;
4164 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4166 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4173 * Return a string identifying a command (to be printed by the
4176 static char *cmdnextc;
4179 cmdputs(const char *s)
4181 const char *p, *str;
4182 char c, cc[2] = " ";
4186 static const char vstype[VSTYPE + 1][4] = {
4187 "", "}", "-", "+", "?", "=",
4188 "%", "%%", "#", "##"
4191 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4193 while ((c = *p++) != 0) {
4201 if ((subtype & VSTYPE) == VSLENGTH)
4205 if (!(subtype & VSQUOTE) == !(quoted & 1))
4211 str = "\"}" + !(quoted & 1);
4218 case CTLBACKQ+CTLQUOTE:
4221 #if ENABLE_ASH_MATH_SUPPORT
4236 if ((subtype & VSTYPE) != VSNORMAL)
4238 str = vstype[subtype & VSTYPE];
4239 if (subtype & VSNUL)
4248 /* These can only happen inside quotes */
4261 while ((c = *str++)) {
4266 USTPUTC('"', nextc);
4272 /* cmdtxt() and cmdlist() call each other */
4273 static void cmdtxt(union node *n);
4276 cmdlist(union node *np, int sep)
4278 for (; np; np = np->narg.next) {
4282 if (sep && np->narg.next)
4288 cmdtxt(union node *n)
4291 struct nodelist *lp;
4303 lp = n->npipe.cmdlist;
4321 cmdtxt(n->nbinary.ch1);
4337 cmdtxt(n->nif.test);
4340 if (n->nif.elsepart) {
4343 n = n->nif.elsepart;
4359 cmdtxt(n->nbinary.ch1);
4369 cmdputs(n->nfor.var);
4371 cmdlist(n->nfor.args, 1);
4376 cmdputs(n->narg.text);
4380 cmdlist(n->ncmd.args, 1);
4381 cmdlist(n->ncmd.redirect, 0);
4394 cmdputs(n->ncase.expr->narg.text);
4396 for (np = n->ncase.cases; np; np = np->nclist.next) {
4397 cmdtxt(np->nclist.pattern);
4399 cmdtxt(np->nclist.body);
4425 s[0] = n->nfile.fd + '0';
4429 if (n->type == NTOFD || n->type == NFROMFD) {
4430 s[0] = n->ndup.dupfd + '0';
4440 commandtext(union node *n)
4444 STARTSTACKSTR(cmdnextc);
4446 name = stackblock();
4447 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4448 name, cmdnextc, cmdnextc));
4449 return ckstrdup(name);
4454 * Fork off a subshell. If we are doing job control, give the subshell its
4455 * own process group. Jp is a job structure that the job is to be added to.
4456 * N is the command that will be evaluated by the child. Both jp and n may
4457 * be NULL. The mode parameter can be one of the following:
4458 * FORK_FG - Fork off a foreground process.
4459 * FORK_BG - Fork off a background process.
4460 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4461 * process group even if job control is on.
4463 * When job control is turned off, background processes have their standard
4464 * input redirected to /dev/null (except for the second and later processes
4467 * Called with interrupts off.
4470 * Clear traps on a fork.
4477 for (tp = trap; tp < &trap[NSIG]; tp++) {
4478 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4483 setsignal(tp - trap);
4489 /* Lives far away from here, needed for forkchild */
4490 static void closescript(void);
4492 /* Called after fork(), in child */
4494 forkchild(struct job *jp, /*union node *n,*/ int mode)
4498 TRACE(("Child shell %d\n", getpid()));
4505 /* do job control only in root shell */
4507 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4510 if (jp->nprocs == 0)
4513 pgrp = jp->ps[0].pid;
4514 /* This can fail because we are doing it in the parent also */
4515 (void)setpgid(0, pgrp);
4516 if (mode == FORK_FG)
4517 xtcsetpgrp(ttyfd, pgrp);
4522 if (mode == FORK_BG) {
4525 if (jp->nprocs == 0) {
4527 if (open(bb_dev_null, O_RDONLY) != 0)
4528 ash_msg_and_raise_error("can't open %s", bb_dev_null);
4531 if (!oldlvl && iflag) {
4536 for (jp = curjob; jp; jp = jp->prev_job)
4541 /* Called after fork(), in parent */
4543 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4546 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4548 TRACE(("In parent shell: child = %d\n", pid));
4550 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4556 if (mode != FORK_NOJOB && jp->jobctl) {
4559 if (jp->nprocs == 0)
4562 pgrp = jp->ps[0].pid;
4563 /* This can fail because we are doing it in the child also */
4567 if (mode == FORK_BG) {
4568 backgndpid = pid; /* set $! */
4569 set_curjob(jp, CUR_RUNNING);
4572 struct procstat *ps = &jp->ps[jp->nprocs++];
4578 ps->cmd = commandtext(n);
4584 forkshell(struct job *jp, union node *n, int mode)
4588 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4591 TRACE(("Fork failed, errno=%d", errno));
4594 ash_msg_and_raise_error("cannot fork");
4597 forkchild(jp, /*n,*/ mode);
4599 forkparent(jp, n, mode, pid);
4604 * Wait for job to finish.
4606 * Under job control we have the problem that while a child process is
4607 * running interrupts generated by the user are sent to the child but not
4608 * to the shell. This means that an infinite loop started by an inter-
4609 * active user may be hard to kill. With job control turned off, an
4610 * interactive user may place an interactive program inside a loop. If
4611 * the interactive program catches interrupts, the user doesn't want
4612 * these interrupts to also abort the loop. The approach we take here
4613 * is to have the shell ignore interrupt signals while waiting for a
4614 * foreground process to terminate, and then send itself an interrupt
4615 * signal if the child process was terminated by an interrupt signal.
4616 * Unfortunately, some programs want to do a bit of cleanup and then
4617 * exit on interrupt; unless these processes terminate themselves by
4618 * sending a signal to themselves (instead of calling exit) they will
4619 * confuse this approach.
4621 * Called with interrupts off.
4624 waitforjob(struct job *jp)
4628 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4629 while (jp->state == JOBRUNNING) {
4630 dowait(DOWAIT_BLOCK, jp);
4635 xtcsetpgrp(ttyfd, rootpid);
4637 * This is truly gross.
4638 * If we're doing job control, then we did a TIOCSPGRP which
4639 * caused us (the shell) to no longer be in the controlling
4640 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4641 * intuit from the subprocess exit status whether a SIGINT
4642 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4644 if (jp->sigint) /* TODO: do the same with all signals */
4645 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4647 if (jp->state == JOBDONE)
4654 * return 1 if there are stopped jobs, otherwise 0
4666 if (jp && jp->state == JOBSTOPPED) {
4667 out2str("You have stopped jobs.\n");
4676 /* ============ redir.c
4678 * Code for dealing with input/output redirection.
4681 #define EMPTY -2 /* marks an unused slot in redirtab */
4682 #define CLOSED -3 /* marks a slot of previously-closed fd */
4684 # define PIPESIZE 4096 /* amount of buffering in a pipe */
4686 # define PIPESIZE PIPE_BUF
4690 * Open a file in noclobber mode.
4691 * The code was copied from bash.
4694 noclobberopen(const char *fname)
4697 struct stat finfo, finfo2;
4700 * If the file exists and is a regular file, return an error
4703 r = stat(fname, &finfo);
4704 if (r == 0 && S_ISREG(finfo.st_mode)) {
4710 * If the file was not present (r != 0), make sure we open it
4711 * exclusively so that if it is created before we open it, our open
4712 * will fail. Make sure that we do not truncate an existing file.
4713 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4714 * file was not a regular file, we leave O_EXCL off.
4717 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4718 fd = open(fname, O_WRONLY|O_CREAT, 0666);
4720 /* If the open failed, return the file descriptor right away. */
4725 * OK, the open succeeded, but the file may have been changed from a
4726 * non-regular file to a regular file between the stat and the open.
4727 * We are assuming that the O_EXCL open handles the case where FILENAME
4728 * did not exist and is symlinked to an existing file between the stat
4733 * If we can open it and fstat the file descriptor, and neither check
4734 * revealed that it was a regular file, and the file has not been
4735 * replaced, return the file descriptor.
4737 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4738 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4741 /* The file has been replaced. badness. */
4748 * Handle here documents. Normally we fork off a process to write the
4749 * data to a pipe. If the document is short, we can stuff the data in
4750 * the pipe without forking.
4752 /* openhere needs this forward reference */
4753 static void expandhere(union node *arg, int fd);
4755 openhere(union node *redir)
4761 ash_msg_and_raise_error("pipe call failed");
4762 if (redir->type == NHERE) {
4763 len = strlen(redir->nhere.doc->narg.text);
4764 if (len <= PIPESIZE) {
4765 full_write(pip[1], redir->nhere.doc->narg.text, len);
4769 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4771 signal(SIGINT, SIG_IGN);
4772 signal(SIGQUIT, SIG_IGN);
4773 signal(SIGHUP, SIG_IGN);
4775 signal(SIGTSTP, SIG_IGN);
4777 signal(SIGPIPE, SIG_DFL);
4778 if (redir->type == NHERE)
4779 full_write(pip[1], redir->nhere.doc->narg.text, len);
4781 expandhere(redir->nhere.doc, pip[1]);
4790 openredirect(union node *redir)
4795 switch (redir->nfile.type) {
4797 fname = redir->nfile.expfname;
4798 f = open(fname, O_RDONLY);
4803 fname = redir->nfile.expfname;
4804 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
4809 /* Take care of noclobber mode. */
4811 fname = redir->nfile.expfname;
4812 f = noclobberopen(fname);
4819 fname = redir->nfile.expfname;
4820 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4825 fname = redir->nfile.expfname;
4826 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4834 /* Fall through to eliminate warning. */
4841 f = openhere(redir);
4847 ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4849 ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "no such file"));
4853 * Copy a file descriptor to be >= to. Returns -1
4854 * if the source file descriptor is closed, EMPTY if there are no unused
4855 * file descriptors left.
4858 copyfd(int from, int to)
4862 newfd = fcntl(from, F_DUPFD, to);
4864 if (errno == EMFILE)
4866 ash_msg_and_raise_error("%d: %m", from);
4872 dupredirect(union node *redir, int f)
4874 int fd = redir->nfile.fd;
4876 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
4877 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
4878 copyfd(redir->ndup.dupfd, fd);
4890 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
4891 * old file descriptors are stashed away so that the redirection can be
4892 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
4893 * standard output, and the standard error if it becomes a duplicate of
4894 * stdout, is saved in memory.
4896 /* flags passed to redirect */
4897 #define REDIR_PUSH 01 /* save previous values of file descriptors */
4898 #define REDIR_SAVEFD2 03 /* set preverrout */
4900 redirect(union node *redir, int flags)
4903 struct redirtab *sv;
4914 if (flags & REDIR_PUSH) {
4915 sv = ckmalloc(sizeof(*sv));
4916 sv->next = redirlist;
4918 sv->nullredirs = g_nullredirs - 1;
4919 for (i = 0; i < 10; i++)
4920 sv->renamed[i] = EMPTY;
4926 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD)
4927 && n->ndup.dupfd == fd)
4928 continue; /* redirect from/to same file descriptor */
4930 newfd = openredirect(n);
4932 /* Descriptor wasn't open before redirect.
4933 * Mark it for close in the future */
4934 if (sv && sv->renamed[fd] == EMPTY)
4935 sv->renamed[fd] = CLOSED;
4938 if (sv && sv->renamed[fd] == EMPTY) {
4939 i = fcntl(fd, F_DUPFD, 10);
4946 ash_msg_and_raise_error("%d: %m", fd);
4950 sv->renamed[fd] = i;
4956 dupredirect(n, newfd);
4957 } while ((n = n->nfile.next));
4959 if ((flags & REDIR_SAVEFD2) && sv && sv->renamed[2] >= 0)
4960 preverrout_fd = sv->renamed[2];
4964 * Undo the effects of the last redirection.
4969 struct redirtab *rp;
4972 if (--g_nullredirs >= 0)
4976 for (i = 0; i < 10; i++) {
4977 if (rp->renamed[i] == CLOSED) {
4982 if (rp->renamed[i] != EMPTY) {
4985 copyfd(rp->renamed[i], i);
4987 close(rp->renamed[i]);
4990 redirlist = rp->next;
4991 g_nullredirs = rp->nullredirs;
4997 * Undo all redirections. Called on error or interrupt.
5001 * Discard all saved file descriptors.
5004 clearredir(int drop)
5015 redirectsafe(union node *redir, int flags)
5018 volatile int saveint;
5019 struct jmploc *volatile savehandler = exception_handler;
5020 struct jmploc jmploc;
5023 err = setjmp(jmploc.loc) * 2;
5025 exception_handler = &jmploc;
5026 redirect(redir, flags);
5028 exception_handler = savehandler;
5029 if (err && exception != EXERROR)
5030 longjmp(exception_handler->loc, 1);
5031 RESTORE_INT(saveint);
5036 /* ============ Routines to expand arguments to commands
5038 * We have to deal with backquotes, shell variables, and file metacharacters.
5044 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5045 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5046 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5047 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5048 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5049 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5050 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5051 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5052 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5056 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5057 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5058 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5059 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5060 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5063 * Structure specifying which parts of the string should be searched
5064 * for IFS characters.
5067 struct ifsregion *next; /* next region in list */
5068 int begoff; /* offset of start of region */
5069 int endoff; /* offset of end of region */
5070 int nulonly; /* search for nul bytes only */
5074 struct strlist *list;
5075 struct strlist **lastp;
5078 /* output of current string */
5079 static char *expdest;
5080 /* list of back quote expressions */
5081 static struct nodelist *argbackq;
5082 /* first struct in list of ifs regions */
5083 static struct ifsregion ifsfirst;
5084 /* last struct in list */
5085 static struct ifsregion *ifslastp;
5086 /* holds expanded arg list */
5087 static struct arglist exparg;
5097 expdest = makestrspace(32, expdest);
5098 #if ENABLE_ASH_MATH_SUPPORT_64
5099 len = fmtstr(expdest, 32, "%lld", (long long) num);
5101 len = fmtstr(expdest, 32, "%ld", num);
5103 STADJUST(len, expdest);
5108 esclen(const char *start, const char *p)
5112 while (p > start && *--p == CTLESC) {
5119 * Remove any CTLESC characters from a string.
5122 _rmescapes(char *str, int flag)
5124 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5131 p = strpbrk(str, qchars);
5137 if (flag & RMESCAPE_ALLOC) {
5138 size_t len = p - str;
5139 size_t fulllen = len + strlen(p) + 1;
5141 if (flag & RMESCAPE_GROW) {
5142 r = makestrspace(fulllen, expdest);
5143 } else if (flag & RMESCAPE_HEAP) {
5144 r = ckmalloc(fulllen);
5146 r = stalloc(fulllen);
5150 q = memcpy(q, str, len) + len;
5153 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5154 globbing = flag & RMESCAPE_GLOB;
5155 notescaped = globbing;
5157 if (*p == CTLQUOTEMARK) {
5158 inquotes = ~inquotes;
5160 notescaped = globbing;
5164 /* naked back slash */
5170 if (notescaped && inquotes && *p != '/') {
5174 notescaped = globbing;
5179 if (flag & RMESCAPE_GROW) {
5181 STADJUST(q - r + 1, expdest);
5185 #define rmescapes(p) _rmescapes((p), 0)
5187 #define pmatch(a, b) !fnmatch((a), (b), 0)
5190 * Prepare a pattern for a expmeta (internal glob(3)) call.
5192 * Returns an stalloced string.
5195 preglob(const char *pattern, int quoted, int flag)
5197 flag |= RMESCAPE_GLOB;
5199 flag |= RMESCAPE_QUOTED;
5201 return _rmescapes((char *)pattern, flag);
5205 * Put a string on the stack.
5208 memtodest(const char *p, size_t len, int syntax, int quotes)
5212 q = makestrspace(len * 2, q);
5215 int c = signed_char2int(*p++);
5218 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5227 strtodest(const char *p, int syntax, int quotes)
5229 memtodest(p, strlen(p), syntax, quotes);
5233 * Record the fact that we have to scan this region of the
5234 * string for IFS characters.
5237 recordregion(int start, int end, int nulonly)
5239 struct ifsregion *ifsp;
5241 if (ifslastp == NULL) {
5245 ifsp = ckzalloc(sizeof(*ifsp));
5246 /*ifsp->next = NULL; - ckzalloc did it */
5247 ifslastp->next = ifsp;
5251 ifslastp->begoff = start;
5252 ifslastp->endoff = end;
5253 ifslastp->nulonly = nulonly;
5257 removerecordregions(int endoff)
5259 if (ifslastp == NULL)
5262 if (ifsfirst.endoff > endoff) {
5263 while (ifsfirst.next != NULL) {
5264 struct ifsregion *ifsp;
5266 ifsp = ifsfirst.next->next;
5267 free(ifsfirst.next);
5268 ifsfirst.next = ifsp;
5271 if (ifsfirst.begoff > endoff)
5274 ifslastp = &ifsfirst;
5275 ifsfirst.endoff = endoff;
5280 ifslastp = &ifsfirst;
5281 while (ifslastp->next && ifslastp->next->begoff < endoff)
5282 ifslastp=ifslastp->next;
5283 while (ifslastp->next != NULL) {
5284 struct ifsregion *ifsp;
5286 ifsp = ifslastp->next->next;
5287 free(ifslastp->next);
5288 ifslastp->next = ifsp;
5291 if (ifslastp->endoff > endoff)
5292 ifslastp->endoff = endoff;
5296 exptilde(char *startp, char *p, int flag)
5302 int quotes = flag & (EXP_FULL | EXP_CASE);
5307 while ((c = *++p) != '\0') {
5314 if (flag & EXP_VARTILDE)
5324 if (*name == '\0') {
5325 home = lookupvar(homestr);
5327 pw = getpwnam(name);
5332 if (!home || !*home)
5335 startloc = expdest - (char *)stackblock();
5336 strtodest(home, SQSYNTAX, quotes);
5337 recordregion(startloc, expdest - (char *)stackblock(), 0);
5345 * Execute a command inside back quotes. If it's a builtin command, we
5346 * want to save its output in a block obtained from malloc. Otherwise
5347 * we fork off a subprocess and get the output of the command via a pipe.
5348 * Should be called with interrupts off.
5350 struct backcmd { /* result of evalbackcmd */
5351 int fd; /* file descriptor to read from */
5352 char *buf; /* buffer */
5353 int nleft; /* number of chars in buffer */
5354 struct job *jp; /* job structure for command */
5357 /* These forward decls are needed to use "eval" code for backticks handling: */
5358 static int back_exitstatus; /* exit status of backquoted command */
5359 #define EV_EXIT 01 /* exit after evaluating tree */
5360 static void evaltree(union node *, int);
5363 evalbackcmd(union node *n, struct backcmd *result)
5375 saveherefd = herefd;
5383 ash_msg_and_raise_error("pipe call failed");
5384 jp = makejob(/*n,*/ 1);
5385 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5394 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5398 result->fd = pip[0];
5401 herefd = saveherefd;
5403 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5404 result->fd, result->buf, result->nleft, result->jp));
5408 * Expand stuff in backwards quotes.
5411 expbackq(union node *cmd, int quoted, int quotes)
5419 int syntax = quoted? DQSYNTAX : BASESYNTAX;
5420 struct stackmark smark;
5423 setstackmark(&smark);
5425 startloc = dest - (char *)stackblock();
5427 evalbackcmd(cmd, &in);
5428 popstackmark(&smark);
5435 memtodest(p, i, syntax, quotes);
5439 i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5440 TRACE(("expbackq: read returns %d\n", i));
5449 back_exitstatus = waitforjob(in.jp);
5453 /* Eat all trailing newlines */
5455 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5460 recordregion(startloc, dest - (char *)stackblock(), 0);
5461 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5462 (dest - (char *)stackblock()) - startloc,
5463 (dest - (char *)stackblock()) - startloc,
5464 stackblock() + startloc));
5467 #if ENABLE_ASH_MATH_SUPPORT
5469 * Expand arithmetic expression. Backup to start of expression,
5470 * evaluate, place result in (backed up) result, adjust string position.
5483 * This routine is slightly over-complicated for
5484 * efficiency. Next we scan backwards looking for the
5485 * start of arithmetic.
5487 start = stackblock();
5494 while (*p != CTLARI) {
5498 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5503 esc = esclen(start, p);
5513 removerecordregions(begoff);
5522 len = cvtnum(dash_arith(p + 2));
5525 recordregion(begoff, begoff + len, 0);
5529 /* argstr needs it */
5530 static char *evalvar(char *p, int flag, struct strlist *var_str_list);
5533 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5534 * characters to allow for further processing. Otherwise treat
5535 * $@ like $* since no splitting will be performed.
5537 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5538 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5539 * for correct expansion of "B=$A" word.
5542 argstr(char *p, int flag, struct strlist *var_str_list)
5544 static const char spclchars[] ALIGN1 = {
5552 CTLBACKQ | CTLQUOTE,
5553 #if ENABLE_ASH_MATH_SUPPORT
5558 const char *reject = spclchars;
5560 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
5561 int breakall = flag & EXP_WORD;
5566 if (!(flag & EXP_VARTILDE)) {
5568 } else if (flag & EXP_VARTILDE2) {
5573 if (flag & EXP_TILDE) {
5579 if (*q == CTLESC && (flag & EXP_QWORD))
5582 p = exptilde(p, q, flag);
5585 startloc = expdest - (char *)stackblock();
5587 length += strcspn(p + length, reject);
5589 if (c && (!(c & 0x80)
5590 #if ENABLE_ASH_MATH_SUPPORT
5594 /* c == '=' || c == ':' || c == CTLENDARI */
5599 expdest = stack_nputstr(p, length, expdest);
5600 newloc = expdest - (char *)stackblock();
5601 if (breakall && !inquotes && newloc > startloc) {
5602 recordregion(startloc, newloc, 0);
5613 if (flag & EXP_VARTILDE2) {
5617 flag |= EXP_VARTILDE2;
5622 * sort of a hack - expand tildes in variable
5623 * assignments (after the first '=' and after ':'s).
5632 case CTLENDVAR: /* ??? */
5635 /* "$@" syntax adherence hack */
5638 !memcmp(p, dolatstr, 4) &&
5639 (p[4] == CTLQUOTEMARK || (
5640 p[4] == CTLENDVAR &&
5641 p[5] == CTLQUOTEMARK
5644 p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;
5647 inquotes = !inquotes;
5660 p = evalvar(p, flag, var_str_list);
5664 case CTLBACKQ|CTLQUOTE:
5665 expbackq(argbackq->n, c, quotes);
5666 argbackq = argbackq->next;
5668 #if ENABLE_ASH_MATH_SUPPORT
5681 scanleft(char *startp, char *rmesc, char *rmescend ATTRIBUTE_UNUSED, char *str, int quotes,
5692 const char *s = loc2;
5698 match = pmatch(str, s);
5702 if (quotes && *loc == CTLESC)
5711 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5718 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5721 const char *s = loc2;
5726 match = pmatch(str, s);
5733 esc = esclen(startp, loc);
5744 static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN;
5746 varunset(const char *end, const char *var, const char *umsg, int varflags)
5752 msg = "parameter not set";
5754 if (*end == CTLENDVAR) {
5755 if (varflags & VSNUL)
5760 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5764 subevalvar(char *p, char *str, int strloc, int subtype,
5765 int startloc, int varflags, int quotes, struct strlist *var_str_list)
5769 int saveherefd = herefd;
5770 struct nodelist *saveargbackq = argbackq;
5772 char *rmesc, *rmescend;
5774 char *(*scan)(char *, char *, char *, char *, int , int);
5777 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
5779 STPUTC('\0', expdest);
5780 herefd = saveherefd;
5781 argbackq = saveargbackq;
5782 startp = stackblock() + startloc;
5786 setvar(str, startp, 0);
5787 amount = startp - expdest;
5788 STADJUST(amount, expdest);
5792 varunset(p, str, startp, varflags);
5796 subtype -= VSTRIMRIGHT;
5798 if (subtype < 0 || subtype > 3)
5803 rmescend = stackblock() + strloc;
5805 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5806 if (rmesc != startp) {
5808 startp = stackblock() + startloc;
5812 str = stackblock() + strloc;
5813 preglob(str, varflags & VSQUOTE, 0);
5815 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5816 zero = subtype >> 1;
5817 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5818 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5820 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5823 memmove(startp, loc, str - loc);
5824 loc = startp + (str - loc) - 1;
5827 amount = loc - expdest;
5828 STADJUST(amount, expdest);
5834 * Add the value of a specialized variable to the stack string.
5837 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
5847 int quoted = varflags & VSQUOTE;
5848 int subtype = varflags & VSTYPE;
5849 int quotes = flags & (EXP_FULL | EXP_CASE);
5851 if (quoted && (flags & EXP_FULL))
5852 sep = 1 << CHAR_BIT;
5854 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5863 num = shellparam.nparam;
5873 p = makestrspace(NOPTS, expdest);
5874 for (i = NOPTS - 1; i >= 0; i--) {
5876 USTPUTC(optletters(i), p);
5887 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
5888 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5894 while ((p = *ap++)) {
5897 partlen = strlen(p);
5900 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5901 memtodest(p, partlen, syntax, quotes);
5907 if (subtype == VSPLUS || subtype == VSLENGTH) {
5929 if (num < 0 || num > shellparam.nparam)
5931 p = num ? shellparam.p[num - 1] : arg0;
5934 /* NB: name has form "VAR=..." */
5936 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
5937 * which should be considered before we check variables. */
5939 unsigned name_len = (strchrnul(name, '=') - name) + 1;
5943 str = var_str_list->text;
5944 eq = strchr(str, '=');
5945 if (!eq) /* stop at first non-assignment */
5948 if (name_len == (eq - str)
5949 && strncmp(str, name, name_len) == 0) {
5951 /* goto value; - WRONG! */
5952 /* think "A=1 A=2 B=$A" */
5954 var_str_list = var_str_list->next;
5955 } while (var_str_list);
5959 p = lookupvar(name);
5965 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5966 memtodest(p, len, syntax, quotes);
5970 if (subtype == VSPLUS || subtype == VSLENGTH)
5971 STADJUST(-len, expdest);
5976 * Expand a variable, and return a pointer to the next character in the
5980 evalvar(char *p, int flag, struct strlist *var_str_list)
5992 subtype = varflags & VSTYPE;
5993 quoted = varflags & VSQUOTE;
5995 easy = (!quoted || (*var == '@' && shellparam.nparam));
5996 startloc = expdest - (char *)stackblock();
5997 p = strchr(p, '=') + 1;
6000 varlen = varvalue(var, varflags, flag, var_str_list);
6001 if (varflags & VSNUL)
6004 if (subtype == VSPLUS) {
6005 varlen = -1 - varlen;
6009 if (subtype == VSMINUS) {
6013 p, flag | EXP_TILDE |
6014 (quoted ? EXP_QWORD : EXP_WORD),
6024 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6026 if (subevalvar(p, var, /* strloc: */ 0,
6027 subtype, startloc, varflags,
6033 * Remove any recorded regions beyond
6036 removerecordregions(startloc);
6046 if (varlen < 0 && uflag)
6047 varunset(p, var, 0, 0);
6049 if (subtype == VSLENGTH) {
6050 cvtnum(varlen > 0 ? varlen : 0);
6054 if (subtype == VSNORMAL) {
6065 case VSTRIMRIGHTMAX:
6074 * Terminate the string and start recording the pattern
6077 STPUTC('\0', expdest);
6078 patloc = expdest - (char *)stackblock();
6079 if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6081 /* quotes: */ flag & (EXP_FULL | EXP_CASE),
6084 int amount = expdest - (
6085 (char *)stackblock() + patloc - 1
6087 STADJUST(-amount, expdest);
6089 /* Remove any recorded regions beyond start of variable */
6090 removerecordregions(startloc);
6092 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6096 if (subtype != VSNORMAL) { /* skip to end of alternative */
6102 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6104 argbackq = argbackq->next;
6105 } else if (c == CTLVAR) {
6106 if ((*p++ & VSTYPE) != VSNORMAL)
6108 } else if (c == CTLENDVAR) {
6118 * Break the argument string into pieces based upon IFS and add the
6119 * strings to the argument list. The regions of the string to be
6120 * searched for IFS characters have been stored by recordregion.
6123 ifsbreakup(char *string, struct arglist *arglist)
6125 struct ifsregion *ifsp;
6130 const char *ifs, *realifs;
6135 if (ifslastp != NULL) {
6138 realifs = ifsset() ? ifsval() : defifs;
6141 p = string + ifsp->begoff;
6142 nulonly = ifsp->nulonly;
6143 ifs = nulonly ? nullstr : realifs;
6145 while (p < string + ifsp->endoff) {
6149 if (!strchr(ifs, *p)) {
6154 ifsspc = (strchr(defifs, *p) != NULL);
6155 /* Ignore IFS whitespace at start */
6156 if (q == start && ifsspc) {
6162 sp = stzalloc(sizeof(*sp));
6164 *arglist->lastp = sp;
6165 arglist->lastp = &sp->next;
6169 if (p >= string + ifsp->endoff) {
6175 if (strchr(ifs, *p) == NULL ) {
6179 if (strchr(defifs, *p) == NULL) {
6194 } while (ifsp != NULL);
6203 sp = stzalloc(sizeof(*sp));
6205 *arglist->lastp = sp;
6206 arglist->lastp = &sp->next;
6212 struct ifsregion *p;
6217 struct ifsregion *ifsp;
6223 ifsfirst.next = NULL;
6228 * Add a file name to the list.
6231 addfname(const char *name)
6235 sp = stzalloc(sizeof(*sp));
6236 sp->text = ststrdup(name);
6238 exparg.lastp = &sp->next;
6241 static char *expdir;
6244 * Do metacharacter (i.e. *, ?, [...]) expansion.
6247 expmeta(char *enddir, char *name)
6262 for (p = name; *p; p++) {
6263 if (*p == '*' || *p == '?')
6265 else if (*p == '[') {
6272 if (*q == '/' || *q == '\0')
6279 } else if (*p == '\\')
6281 else if (*p == '/') {
6288 if (metaflag == 0) { /* we've reached the end of the file name */
6289 if (enddir != expdir)
6297 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6308 } while (p < start);
6310 if (enddir == expdir) {
6312 } else if (enddir == expdir + 1 && *expdir == '/') {
6321 if (enddir != expdir)
6323 if (*endname == 0) {
6335 while (!intpending && (dp = readdir(dirp)) != NULL) {
6336 if (dp->d_name[0] == '.' && ! matchdot)
6338 if (pmatch(start, dp->d_name)) {
6340 strcpy(enddir, dp->d_name);
6343 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6346 expmeta(p, endname);
6355 static struct strlist *
6356 msort(struct strlist *list, int len)
6358 struct strlist *p, *q = NULL;
6359 struct strlist **lpp;
6367 for (n = half; --n >= 0; ) {
6371 q->next = NULL; /* terminate first half of list */
6372 q = msort(list, half); /* sort first half of list */
6373 p = msort(p, len - half); /* sort second half */
6376 #if ENABLE_LOCALE_SUPPORT
6377 if (strcoll(p->text, q->text) < 0)
6379 if (strcmp(p->text, q->text) < 0)
6403 * Sort the results of file name expansion. It calculates the number of
6404 * strings to sort and then calls msort (short for merge sort) to do the
6407 static struct strlist *
6408 expsort(struct strlist *str)
6414 for (sp = str; sp; sp = sp->next)
6416 return msort(str, len);
6420 expandmeta(struct strlist *str /*, int flag*/)
6422 static const char metachars[] ALIGN1 = {
6425 /* TODO - EXP_REDIR */
6428 struct strlist **savelastp;
6434 if (!strpbrk(str->text, metachars))
6436 savelastp = exparg.lastp;
6439 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
6441 int i = strlen(str->text);
6442 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
6450 if (exparg.lastp == savelastp) {
6455 *exparg.lastp = str;
6456 rmescapes(str->text);
6457 exparg.lastp = &str->next;
6459 *exparg.lastp = NULL;
6460 *savelastp = sp = expsort(*savelastp);
6461 while (sp->next != NULL)
6463 exparg.lastp = &sp->next;
6470 * Perform variable substitution and command substitution on an argument,
6471 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6472 * perform splitting and file name expansion. When arglist is NULL, perform
6473 * here document expansion.
6476 expandarg(union node *arg, struct arglist *arglist, int flag)
6481 argbackq = arg->narg.backquote;
6482 STARTSTACKSTR(expdest);
6483 ifsfirst.next = NULL;
6485 argstr(arg->narg.text, flag,
6486 /* var_str_list: */ arglist ? arglist->list : NULL);
6487 p = _STPUTC('\0', expdest);
6489 if (arglist == NULL) {
6490 return; /* here document expanded */
6492 p = grabstackstr(p);
6493 exparg.lastp = &exparg.list;
6497 if (flag & EXP_FULL) {
6498 ifsbreakup(p, &exparg);
6499 *exparg.lastp = NULL;
6500 exparg.lastp = &exparg.list;
6501 expandmeta(exparg.list /*, flag*/);
6503 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
6505 sp = stzalloc(sizeof(*sp));
6508 exparg.lastp = &sp->next;
6512 *exparg.lastp = NULL;
6514 *arglist->lastp = exparg.list;
6515 arglist->lastp = exparg.lastp;
6520 * Expand shell variables and backquotes inside a here document.
6523 expandhere(union node *arg, int fd)
6526 expandarg(arg, (struct arglist *)NULL, 0);
6527 full_write(fd, stackblock(), expdest - (char *)stackblock());
6531 * Returns true if the pattern matches the string.
6534 patmatch(char *pattern, const char *string)
6536 return pmatch(preglob(pattern, 0, 0), string);
6540 * See if a pattern matches in a case statement.
6543 casematch(union node *pattern, char *val)
6545 struct stackmark smark;
6548 setstackmark(&smark);
6549 argbackq = pattern->narg.backquote;
6550 STARTSTACKSTR(expdest);
6552 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
6553 /* var_str_list: */ NULL);
6554 STACKSTRNUL(expdest);
6555 result = patmatch(stackblock(), val);
6556 popstackmark(&smark);
6561 /* ============ find_command */
6565 int (*builtin)(int, char **);
6566 /* unsigned flags; */
6568 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
6569 /* "regular" builtins always take precedence over commands,
6570 * regardless of PATH=....%builtin... position */
6571 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
6572 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
6578 const struct builtincmd *cmd;
6579 struct funcnode *func;
6582 /* values of cmdtype */
6583 #define CMDUNKNOWN -1 /* no entry in table for command */
6584 #define CMDNORMAL 0 /* command is an executable program */
6585 #define CMDFUNCTION 1 /* command is a shell function */
6586 #define CMDBUILTIN 2 /* command is a shell builtin */
6588 /* action to find_command() */
6589 #define DO_ERR 0x01 /* prints errors */
6590 #define DO_ABS 0x02 /* checks absolute paths */
6591 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
6592 #define DO_ALTPATH 0x08 /* using alternate path */
6593 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
6595 static void find_command(char *, struct cmdentry *, int, const char *);
6598 /* ============ Hashing commands */
6601 * When commands are first encountered, they are entered in a hash table.
6602 * This ensures that a full path search will not have to be done for them
6603 * on each invocation.
6605 * We should investigate converting to a linear search, even though that
6606 * would make the command name "hash" a misnomer.
6609 #define ARB 1 /* actual size determined at run time */
6612 struct tblentry *next; /* next entry in hash chain */
6613 union param param; /* definition of builtin function */
6614 short cmdtype; /* index identifying command */
6615 char rehash; /* if set, cd done since entry created */
6616 char cmdname[ARB]; /* name of command */
6619 static struct tblentry **cmdtable;
6620 #define INIT_G_cmdtable() do { \
6621 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
6624 static int builtinloc = -1; /* index in path of %builtin, or -1 */
6628 tryexec(char *cmd, char **argv, char **envp)
6632 #if ENABLE_FEATURE_SH_STANDALONE
6633 if (strchr(cmd, '/') == NULL) {
6634 int a = find_applet_by_name(cmd);
6636 if (APPLET_IS_NOEXEC(a))
6637 run_applet_no_and_exit(a, argv);
6638 /* re-exec ourselves with the new arguments */
6639 execve(bb_busybox_exec_path, argv, envp);
6640 /* If they called chroot or otherwise made the binary no longer
6641 * executable, fall through */
6649 execve(cmd, argv, envp);
6650 } while (errno == EINTR);
6652 execve(cmd, argv, envp);
6656 } else if (errno == ENOEXEC) {
6660 for (ap = argv; *ap; ap++)
6662 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
6664 ap[0] = cmd = (char *)DEFAULT_SHELL;
6667 while ((*ap++ = *argv++))
6675 * Exec a program. Never returns. If you change this routine, you may
6676 * have to change the find_command routine as well.
6678 #define environment() listvars(VEXPORT, VUNSET, 0)
6679 static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
6681 shellexec(char **argv, const char *path, int idx)
6689 envp = environment();
6690 if (strchr(argv[0], '/')
6691 #if ENABLE_FEATURE_SH_STANDALONE
6692 || find_applet_by_name(argv[0]) >= 0
6695 tryexec(argv[0], argv, envp);
6699 while ((cmdname = padvance(&path, argv[0])) != NULL) {
6700 if (--idx < 0 && pathopt == NULL) {
6701 tryexec(cmdname, argv, envp);
6702 if (errno != ENOENT && errno != ENOTDIR)
6709 /* Map to POSIX errors */
6721 exitstatus = exerrno;
6722 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
6723 argv[0], e, suppressint ));
6724 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
6729 printentry(struct tblentry *cmdp)
6735 idx = cmdp->param.index;
6738 name = padvance(&path, cmdp->cmdname);
6740 } while (--idx >= 0);
6741 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
6745 * Clear out command entries. The argument specifies the first entry in
6746 * PATH which has changed.
6749 clearcmdentry(int firstchange)
6751 struct tblentry **tblp;
6752 struct tblentry **pp;
6753 struct tblentry *cmdp;
6756 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
6758 while ((cmdp = *pp) != NULL) {
6759 if ((cmdp->cmdtype == CMDNORMAL &&
6760 cmdp->param.index >= firstchange)
6761 || (cmdp->cmdtype == CMDBUILTIN &&
6762 builtinloc >= firstchange)
6775 * Locate a command in the command hash table. If "add" is nonzero,
6776 * add the command to the table if it is not already present. The
6777 * variable "lastcmdentry" is set to point to the address of the link
6778 * pointing to the entry, so that delete_cmd_entry can delete the
6781 * Interrupts must be off if called with add != 0.
6783 static struct tblentry **lastcmdentry;
6785 static struct tblentry *
6786 cmdlookup(const char *name, int add)
6788 unsigned int hashval;
6790 struct tblentry *cmdp;
6791 struct tblentry **pp;
6794 hashval = (unsigned char)*p << 4;
6796 hashval += (unsigned char)*p++;
6798 pp = &cmdtable[hashval % CMDTABLESIZE];
6799 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6800 if (strcmp(cmdp->cmdname, name) == 0)
6804 if (add && cmdp == NULL) {
6805 cmdp = *pp = ckzalloc(sizeof(struct tblentry) - ARB
6806 + strlen(name) + 1);
6807 /*cmdp->next = NULL; - ckzalloc did it */
6808 cmdp->cmdtype = CMDUNKNOWN;
6809 strcpy(cmdp->cmdname, name);
6816 * Delete the command entry returned on the last lookup.
6819 delete_cmd_entry(void)
6821 struct tblentry *cmdp;
6824 cmdp = *lastcmdentry;
6825 *lastcmdentry = cmdp->next;
6826 if (cmdp->cmdtype == CMDFUNCTION)
6827 freefunc(cmdp->param.func);
6833 * Add a new command entry, replacing any existing command entry for
6834 * the same name - except special builtins.
6837 addcmdentry(char *name, struct cmdentry *entry)
6839 struct tblentry *cmdp;
6841 cmdp = cmdlookup(name, 1);
6842 if (cmdp->cmdtype == CMDFUNCTION) {
6843 freefunc(cmdp->param.func);
6845 cmdp->cmdtype = entry->cmdtype;
6846 cmdp->param = entry->u;
6851 hashcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
6853 struct tblentry **pp;
6854 struct tblentry *cmdp;
6856 struct cmdentry entry;
6859 if (nextopt("r") != '\0') {
6864 if (*argptr == NULL) {
6865 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
6866 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6867 if (cmdp->cmdtype == CMDNORMAL)
6875 while ((name = *argptr) != NULL) {
6876 cmdp = cmdlookup(name, 0);
6878 && (cmdp->cmdtype == CMDNORMAL
6879 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
6883 find_command(name, &entry, DO_ERR, pathval());
6884 if (entry.cmdtype == CMDUNKNOWN)
6892 * Called when a cd is done. Marks all commands so the next time they
6893 * are executed they will be rehashed.
6898 struct tblentry **pp;
6899 struct tblentry *cmdp;
6901 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
6902 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6903 if (cmdp->cmdtype == CMDNORMAL
6904 || (cmdp->cmdtype == CMDBUILTIN
6905 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
6915 * Fix command hash table when PATH changed.
6916 * Called before PATH is changed. The argument is the new value of PATH;
6917 * pathval() still returns the old value at this point.
6918 * Called with interrupts off.
6921 changepath(const char *new)
6929 firstchange = 9999; /* assume no change */
6935 if ((*old == '\0' && *new == ':')
6936 || (*old == ':' && *new == '\0'))
6938 old = new; /* ignore subsequent differences */
6942 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
6948 if (builtinloc < 0 && idx_bltin >= 0)
6949 builtinloc = idx_bltin; /* zap builtins */
6950 if (builtinloc >= 0 && idx_bltin < 0)
6952 clearcmdentry(firstchange);
6953 builtinloc = idx_bltin;
6968 #define TENDBQUOTE 12
6986 /* first char is indicating which tokens mark the end of a list */
6987 static const char *const tokname_array[] = {
7001 #define KWDOFFSET 13
7002 /* the following are keywords */
7024 static char buf[16];
7027 //if (tok < TSEMI) return tokname_array[tok] + 1;
7028 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
7033 sprintf(buf + (tok >= TSEMI), "%s%c",
7034 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
7038 /* Wrapper around strcmp for qsort/bsearch/... */
7040 pstrcmp(const void *a, const void *b)
7042 return strcmp((char*) a, (*(char**) b) + 1);
7045 static const char *const *
7046 findkwd(const char *s)
7048 return bsearch(s, tokname_array + KWDOFFSET,
7049 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7050 sizeof(tokname_array[0]), pstrcmp);
7054 * Locate and print what a word is...
7057 describe_command(char *command, int describe_command_verbose)
7059 struct cmdentry entry;
7060 struct tblentry *cmdp;
7061 #if ENABLE_ASH_ALIAS
7062 const struct alias *ap;
7064 const char *path = pathval();
7066 if (describe_command_verbose) {
7070 /* First look at the keywords */
7071 if (findkwd(command)) {
7072 out1str(describe_command_verbose ? " is a shell keyword" : command);
7076 #if ENABLE_ASH_ALIAS
7077 /* Then look at the aliases */
7078 ap = lookupalias(command, 0);
7080 if (!describe_command_verbose) {
7085 out1fmt(" is an alias for %s", ap->val);
7089 /* Then check if it is a tracked alias */
7090 cmdp = cmdlookup(command, 0);
7092 entry.cmdtype = cmdp->cmdtype;
7093 entry.u = cmdp->param;
7095 /* Finally use brute force */
7096 find_command(command, &entry, DO_ABS, path);
7099 switch (entry.cmdtype) {
7101 int j = entry.u.index;
7107 p = padvance(&path, command);
7111 if (describe_command_verbose) {
7113 (cmdp ? " a tracked alias for" : nullstr), p
7122 if (describe_command_verbose) {
7123 out1str(" is a shell function");
7130 if (describe_command_verbose) {
7131 out1fmt(" is a %sshell builtin",
7132 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7133 "special " : nullstr
7141 if (describe_command_verbose) {
7142 out1str(": not found\n");
7147 outstr("\n", stdout);
7152 typecmd(int argc ATTRIBUTE_UNUSED, char **argv)
7158 /* type -p ... ? (we don't bother checking for 'p') */
7159 if (argv[1] && argv[1][0] == '-') {
7164 err |= describe_command(argv[i++], verbose);
7169 #if ENABLE_ASH_CMDCMD
7171 commandcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
7179 while ((c = nextopt("pvV")) != '\0')
7181 verify |= VERIFY_VERBOSE;
7183 verify |= VERIFY_BRIEF;
7189 return describe_command(*argptr, verify - VERIFY_BRIEF);
7196 /* ============ eval.c */
7198 static int funcblocksize; /* size of structures in function */
7199 static int funcstringsize; /* size of strings in node */
7200 static void *funcblock; /* block to allocate function from */
7201 static char *funcstring; /* block to allocate strings from */
7203 /* flags in argument to evaltree */
7204 #define EV_EXIT 01 /* exit after evaluating tree */
7205 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7206 #define EV_BACKCMD 04 /* command executing within back quotes */
7208 static const short nodesize[26] = {
7209 SHELL_ALIGN(sizeof(struct ncmd)),
7210 SHELL_ALIGN(sizeof(struct npipe)),
7211 SHELL_ALIGN(sizeof(struct nredir)),
7212 SHELL_ALIGN(sizeof(struct nredir)),
7213 SHELL_ALIGN(sizeof(struct nredir)),
7214 SHELL_ALIGN(sizeof(struct nbinary)),
7215 SHELL_ALIGN(sizeof(struct nbinary)),
7216 SHELL_ALIGN(sizeof(struct nbinary)),
7217 SHELL_ALIGN(sizeof(struct nif)),
7218 SHELL_ALIGN(sizeof(struct nbinary)),
7219 SHELL_ALIGN(sizeof(struct nbinary)),
7220 SHELL_ALIGN(sizeof(struct nfor)),
7221 SHELL_ALIGN(sizeof(struct ncase)),
7222 SHELL_ALIGN(sizeof(struct nclist)),
7223 SHELL_ALIGN(sizeof(struct narg)),
7224 SHELL_ALIGN(sizeof(struct narg)),
7225 SHELL_ALIGN(sizeof(struct nfile)),
7226 SHELL_ALIGN(sizeof(struct nfile)),
7227 SHELL_ALIGN(sizeof(struct nfile)),
7228 SHELL_ALIGN(sizeof(struct nfile)),
7229 SHELL_ALIGN(sizeof(struct nfile)),
7230 SHELL_ALIGN(sizeof(struct ndup)),
7231 SHELL_ALIGN(sizeof(struct ndup)),
7232 SHELL_ALIGN(sizeof(struct nhere)),
7233 SHELL_ALIGN(sizeof(struct nhere)),
7234 SHELL_ALIGN(sizeof(struct nnot)),
7237 static void calcsize(union node *n);
7240 sizenodelist(struct nodelist *lp)
7243 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7250 calcsize(union node *n)
7254 funcblocksize += nodesize[n->type];
7257 calcsize(n->ncmd.redirect);
7258 calcsize(n->ncmd.args);
7259 calcsize(n->ncmd.assign);
7262 sizenodelist(n->npipe.cmdlist);
7267 calcsize(n->nredir.redirect);
7268 calcsize(n->nredir.n);
7275 calcsize(n->nbinary.ch2);
7276 calcsize(n->nbinary.ch1);
7279 calcsize(n->nif.elsepart);
7280 calcsize(n->nif.ifpart);
7281 calcsize(n->nif.test);
7284 funcstringsize += strlen(n->nfor.var) + 1;
7285 calcsize(n->nfor.body);
7286 calcsize(n->nfor.args);
7289 calcsize(n->ncase.cases);
7290 calcsize(n->ncase.expr);
7293 calcsize(n->nclist.body);
7294 calcsize(n->nclist.pattern);
7295 calcsize(n->nclist.next);
7299 sizenodelist(n->narg.backquote);
7300 funcstringsize += strlen(n->narg.text) + 1;
7301 calcsize(n->narg.next);
7308 calcsize(n->nfile.fname);
7309 calcsize(n->nfile.next);
7313 calcsize(n->ndup.vname);
7314 calcsize(n->ndup.next);
7318 calcsize(n->nhere.doc);
7319 calcsize(n->nhere.next);
7322 calcsize(n->nnot.com);
7328 nodeckstrdup(char *s)
7330 char *rtn = funcstring;
7332 strcpy(funcstring, s);
7333 funcstring += strlen(s) + 1;
7337 static union node *copynode(union node *);
7339 static struct nodelist *
7340 copynodelist(struct nodelist *lp)
7342 struct nodelist *start;
7343 struct nodelist **lpp;
7348 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7349 (*lpp)->n = copynode(lp->n);
7351 lpp = &(*lpp)->next;
7358 copynode(union node *n)
7365 funcblock = (char *) funcblock + nodesize[n->type];
7369 new->ncmd.redirect = copynode(n->ncmd.redirect);
7370 new->ncmd.args = copynode(n->ncmd.args);
7371 new->ncmd.assign = copynode(n->ncmd.assign);
7374 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7375 new->npipe.backgnd = n->npipe.backgnd;
7380 new->nredir.redirect = copynode(n->nredir.redirect);
7381 new->nredir.n = copynode(n->nredir.n);
7388 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7389 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7392 new->nif.elsepart = copynode(n->nif.elsepart);
7393 new->nif.ifpart = copynode(n->nif.ifpart);
7394 new->nif.test = copynode(n->nif.test);
7397 new->nfor.var = nodeckstrdup(n->nfor.var);
7398 new->nfor.body = copynode(n->nfor.body);
7399 new->nfor.args = copynode(n->nfor.args);
7402 new->ncase.cases = copynode(n->ncase.cases);
7403 new->ncase.expr = copynode(n->ncase.expr);
7406 new->nclist.body = copynode(n->nclist.body);
7407 new->nclist.pattern = copynode(n->nclist.pattern);
7408 new->nclist.next = copynode(n->nclist.next);
7412 new->narg.backquote = copynodelist(n->narg.backquote);
7413 new->narg.text = nodeckstrdup(n->narg.text);
7414 new->narg.next = copynode(n->narg.next);
7421 new->nfile.fname = copynode(n->nfile.fname);
7422 new->nfile.fd = n->nfile.fd;
7423 new->nfile.next = copynode(n->nfile.next);
7427 new->ndup.vname = copynode(n->ndup.vname);
7428 new->ndup.dupfd = n->ndup.dupfd;
7429 new->ndup.fd = n->ndup.fd;
7430 new->ndup.next = copynode(n->ndup.next);
7434 new->nhere.doc = copynode(n->nhere.doc);
7435 new->nhere.fd = n->nhere.fd;
7436 new->nhere.next = copynode(n->nhere.next);
7439 new->nnot.com = copynode(n->nnot.com);
7442 new->type = n->type;
7447 * Make a copy of a parse tree.
7449 static struct funcnode *
7450 copyfunc(union node *n)
7455 funcblocksize = offsetof(struct funcnode, n);
7458 blocksize = funcblocksize;
7459 f = ckmalloc(blocksize + funcstringsize);
7460 funcblock = (char *) f + offsetof(struct funcnode, n);
7461 funcstring = (char *) f + blocksize;
7468 * Define a shell function.
7471 defun(char *name, union node *func)
7473 struct cmdentry entry;
7476 entry.cmdtype = CMDFUNCTION;
7477 entry.u.func = copyfunc(func);
7478 addcmdentry(name, &entry);
7482 static int evalskip; /* set if we are skipping commands */
7483 /* reasons for skipping commands (see comment on breakcmd routine) */
7484 #define SKIPBREAK (1 << 0)
7485 #define SKIPCONT (1 << 1)
7486 #define SKIPFUNC (1 << 2)
7487 #define SKIPFILE (1 << 3)
7488 #define SKIPEVAL (1 << 4)
7489 static int skipcount; /* number of levels to skip */
7490 static int funcnest; /* depth of function calls */
7492 /* forward decl way out to parsing code - dotrap needs it */
7493 static int evalstring(char *s, int mask);
7496 * Called to execute a trap. Perhaps we should avoid entering new trap
7497 * handlers while we are executing a trap handler.
7508 savestatus = exitstatus;
7512 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
7520 skip = evalstring(p, SKIPEVAL);
7521 exitstatus = savestatus;
7529 /* forward declarations - evaluation is fairly recursive business... */
7530 static void evalloop(union node *, int);
7531 static void evalfor(union node *, int);
7532 static void evalcase(union node *, int);
7533 static void evalsubshell(union node *, int);
7534 static void expredir(union node *);
7535 static void evalpipe(union node *, int);
7536 static void evalcommand(union node *, int);
7537 static int evalbltin(const struct builtincmd *, int, char **);
7538 static void prehash(union node *);
7541 * Evaluate a parse tree. The value is left in the global variable
7545 evaltree(union node *n, int flags)
7548 void (*evalfn)(union node *, int);
7552 TRACE(("evaltree(NULL) called\n"));
7555 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
7556 getpid(), n, n->type, flags));
7560 out1fmt("Node type = %d\n", n->type);
7565 evaltree(n->nnot.com, EV_TESTED);
7566 status = !exitstatus;
7569 expredir(n->nredir.redirect);
7570 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
7572 evaltree(n->nredir.n, flags & EV_TESTED);
7573 status = exitstatus;
7578 evalfn = evalcommand;
7580 if (eflag && !(flags & EV_TESTED))
7592 evalfn = evalsubshell;
7604 #error NAND + 1 != NOR
7606 #if NOR + 1 != NSEMI
7607 #error NOR + 1 != NSEMI
7609 isor = n->type - NAND;
7612 (flags | ((isor >> 1) - 1)) & EV_TESTED
7614 if (!exitstatus == isor)
7626 evaltree(n->nif.test, EV_TESTED);
7629 if (exitstatus == 0) {
7632 } else if (n->nif.elsepart) {
7633 n = n->nif.elsepart;
7638 defun(n->narg.text, n->narg.next);
7642 exitstatus = status;
7646 if ((checkexit & exitstatus))
7647 evalskip |= SKIPEVAL;
7648 else if (pendingsig && dotrap())
7651 if (flags & EV_EXIT) {
7653 raise_exception(EXEXIT);
7657 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
7660 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
7662 static int loopnest; /* current loop nesting level */
7665 evalloop(union node *n, int flags)
7675 evaltree(n->nbinary.ch1, EV_TESTED);
7678 if (evalskip == SKIPCONT && --skipcount <= 0) {
7682 if (evalskip == SKIPBREAK && --skipcount <= 0)
7687 if (n->type != NWHILE)
7691 evaltree(n->nbinary.ch2, flags);
7692 status = exitstatus;
7697 exitstatus = status;
7701 evalfor(union node *n, int flags)
7703 struct arglist arglist;
7706 struct stackmark smark;
7708 setstackmark(&smark);
7709 arglist.list = NULL;
7710 arglist.lastp = &arglist.list;
7711 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
7712 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
7717 *arglist.lastp = NULL;
7722 for (sp = arglist.list; sp; sp = sp->next) {
7723 setvar(n->nfor.var, sp->text, 0);
7724 evaltree(n->nfor.body, flags);
7726 if (evalskip == SKIPCONT && --skipcount <= 0) {
7730 if (evalskip == SKIPBREAK && --skipcount <= 0)
7737 popstackmark(&smark);
7741 evalcase(union node *n, int flags)
7745 struct arglist arglist;
7746 struct stackmark smark;
7748 setstackmark(&smark);
7749 arglist.list = NULL;
7750 arglist.lastp = &arglist.list;
7751 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
7753 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
7754 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
7755 if (casematch(patp, arglist.list->text)) {
7756 if (evalskip == 0) {
7757 evaltree(cp->nclist.body, flags);
7764 popstackmark(&smark);
7768 * Kick off a subshell to evaluate a tree.
7771 evalsubshell(union node *n, int flags)
7774 int backgnd = (n->type == NBACKGND);
7777 expredir(n->nredir.redirect);
7778 if (!backgnd && flags & EV_EXIT && !trap[0])
7781 jp = makejob(/*n,*/ 1);
7782 if (forkshell(jp, n, backgnd) == 0) {
7786 flags &=~ EV_TESTED;
7788 redirect(n->nredir.redirect, 0);
7789 evaltreenr(n->nredir.n, flags);
7794 status = waitforjob(jp);
7795 exitstatus = status;
7800 * Compute the names of the files in a redirection list.
7802 static void fixredir(union node *, const char *, int);
7804 expredir(union node *n)
7808 for (redir = n; redir; redir = redir->nfile.next) {
7812 fn.lastp = &fn.list;
7813 switch (redir->type) {
7819 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
7820 redir->nfile.expfname = fn.list->text;
7824 if (redir->ndup.vname) {
7825 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
7826 if (fn.list == NULL)
7827 ash_msg_and_raise_error("redir error");
7828 fixredir(redir, fn.list->text, 1);
7836 * Evaluate a pipeline. All the processes in the pipeline are children
7837 * of the process creating the pipeline. (This differs from some versions
7838 * of the shell, which make the last process in a pipeline the parent
7842 evalpipe(union node *n, int flags)
7845 struct nodelist *lp;
7850 TRACE(("evalpipe(0x%lx) called\n", (long)n));
7852 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
7856 jp = makejob(/*n,*/ pipelen);
7858 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
7862 if (pipe(pip) < 0) {
7864 ash_msg_and_raise_error("pipe call failed");
7867 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
7880 evaltreenr(lp->n, flags);
7888 if (n->npipe.backgnd == 0) {
7889 exitstatus = waitforjob(jp);
7890 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
7896 * Controls whether the shell is interactive or not.
7899 setinteractive(int on)
7901 static int is_interactive;
7903 if (++on == is_interactive)
7905 is_interactive = on;
7909 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
7910 if (is_interactive > 1) {
7911 /* Looks like they want an interactive shell */
7912 static smallint did_banner;
7917 "%s built-in shell (ash)\n"
7918 "Enter 'help' for a list of built-in commands."
7927 #if ENABLE_FEATURE_EDITING_VI
7928 #define setvimode(on) do { \
7929 if (on) line_input_state->flags |= VI_MODE; \
7930 else line_input_state->flags &= ~VI_MODE; \
7933 #define setvimode(on) viflag = 0 /* forcibly keep the option off */
7942 setinteractive(iflag);
7947 static struct localvar *localvars;
7950 * Called after a function returns.
7951 * Interrupts must be off.
7956 struct localvar *lvp;
7959 while ((lvp = localvars) != NULL) {
7960 localvars = lvp->next;
7962 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
7963 if (vp == NULL) { /* $- saved */
7964 memcpy(optlist, lvp->text, sizeof(optlist));
7965 free((char*)lvp->text);
7967 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
7971 (*vp->func)(strchrnul(lvp->text, '=') + 1);
7972 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
7973 free((char*)vp->text);
7974 vp->flags = lvp->flags;
7975 vp->text = lvp->text;
7982 evalfun(struct funcnode *func, int argc, char **argv, int flags)
7984 volatile struct shparam saveparam;
7985 struct localvar *volatile savelocalvars;
7986 struct jmploc *volatile savehandler;
7987 struct jmploc jmploc;
7990 saveparam = shellparam;
7991 savelocalvars = localvars;
7992 e = setjmp(jmploc.loc);
7997 savehandler = exception_handler;
7998 exception_handler = &jmploc;
8000 shellparam.malloced = 0;
8004 shellparam.nparam = argc - 1;
8005 shellparam.p = argv + 1;
8006 #if ENABLE_ASH_GETOPTS
8007 shellparam.optind = 1;
8008 shellparam.optoff = -1;
8010 evaltree(&func->n, flags & EV_TESTED);
8016 localvars = savelocalvars;
8017 freeparam(&shellparam);
8018 shellparam = saveparam;
8019 exception_handler = savehandler;
8021 evalskip &= ~SKIPFUNC;
8025 #if ENABLE_ASH_CMDCMD
8027 parse_command_args(char **argv, const char **path)
8040 if (c == '-' && !*cp) {
8047 *path = bb_default_path;
8050 /* run 'typecmd' for other options */
8061 * Make a variable a local variable. When a variable is made local, it's
8062 * value and flags are saved in a localvar structure. The saved values
8063 * will be restored when the shell function returns. We handle the name
8064 * "-" as a special case.
8069 struct localvar *lvp;
8074 lvp = ckzalloc(sizeof(struct localvar));
8075 if (LONE_DASH(name)) {
8077 p = ckmalloc(sizeof(optlist));
8078 lvp->text = memcpy(p, optlist, sizeof(optlist));
8083 vpp = hashvar(name);
8084 vp = *findvar(vpp, name);
8085 eq = strchr(name, '=');
8088 setvareq(name, VSTRFIXED);
8090 setvar(name, NULL, VSTRFIXED);
8091 vp = *vpp; /* the new variable */
8092 lvp->flags = VUNSET;
8094 lvp->text = vp->text;
8095 lvp->flags = vp->flags;
8096 vp->flags |= VSTRFIXED|VTEXTFIXED;
8102 lvp->next = localvars;
8108 * The "local" command.
8111 localcmd(int argc ATTRIBUTE_UNUSED, char **argv)
8116 while ((name = *argv++) != NULL) {
8123 falsecmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
8129 truecmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
8135 execcmd(int argc ATTRIBUTE_UNUSED, char **argv)
8138 iflag = 0; /* exit on error */
8141 shellexec(argv + 1, pathval(), 0);
8147 * The return command.
8150 returncmd(int argc ATTRIBUTE_UNUSED, char **argv)
8153 * If called outside a function, do what ksh does;
8154 * skip the rest of the file.
8156 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8157 return argv[1] ? number(argv[1]) : exitstatus;
8160 /* Forward declarations for builtintab[] */
8161 static int breakcmd(int, char **);
8162 static int dotcmd(int, char **);
8163 static int evalcmd(int, char **);
8164 #if ENABLE_ASH_BUILTIN_ECHO
8165 static int echocmd(int, char **);
8167 #if ENABLE_ASH_BUILTIN_TEST
8168 static int testcmd(int, char **);
8170 static int exitcmd(int, char **);
8171 static int exportcmd(int, char **);
8172 #if ENABLE_ASH_GETOPTS
8173 static int getoptscmd(int, char **);
8175 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8176 static int helpcmd(int argc, char **argv);
8178 #if ENABLE_ASH_MATH_SUPPORT
8179 static int letcmd(int, char **);
8181 static int readcmd(int, char **);
8182 static int setcmd(int, char **);
8183 static int shiftcmd(int, char **);
8184 static int timescmd(int, char **);
8185 static int trapcmd(int, char **);
8186 static int umaskcmd(int, char **);
8187 static int unsetcmd(int, char **);
8188 static int ulimitcmd(int, char **);
8190 #define BUILTIN_NOSPEC "0"
8191 #define BUILTIN_SPECIAL "1"
8192 #define BUILTIN_REGULAR "2"
8193 #define BUILTIN_SPEC_REG "3"
8194 #define BUILTIN_ASSIGN "4"
8195 #define BUILTIN_SPEC_ASSG "5"
8196 #define BUILTIN_REG_ASSG "6"
8197 #define BUILTIN_SPEC_REG_ASSG "7"
8199 /* make sure to keep these in proper order since it is searched via bsearch() */
8200 static const struct builtincmd builtintab[] = {
8201 { BUILTIN_SPEC_REG ".", dotcmd },
8202 { BUILTIN_SPEC_REG ":", truecmd },
8203 #if ENABLE_ASH_BUILTIN_TEST
8204 { BUILTIN_REGULAR "[", testcmd },
8205 { BUILTIN_REGULAR "[[", testcmd },
8207 #if ENABLE_ASH_ALIAS
8208 { BUILTIN_REG_ASSG "alias", aliascmd },
8211 { BUILTIN_REGULAR "bg", fg_bgcmd },
8213 { BUILTIN_SPEC_REG "break", breakcmd },
8214 { BUILTIN_REGULAR "cd", cdcmd },
8215 { BUILTIN_NOSPEC "chdir", cdcmd },
8216 #if ENABLE_ASH_CMDCMD
8217 { BUILTIN_REGULAR "command", commandcmd },
8219 { BUILTIN_SPEC_REG "continue", breakcmd },
8220 #if ENABLE_ASH_BUILTIN_ECHO
8221 { BUILTIN_REGULAR "echo", echocmd },
8223 { BUILTIN_SPEC_REG "eval", evalcmd },
8224 { BUILTIN_SPEC_REG "exec", execcmd },
8225 { BUILTIN_SPEC_REG "exit", exitcmd },
8226 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8227 { BUILTIN_REGULAR "false", falsecmd },
8229 { BUILTIN_REGULAR "fg", fg_bgcmd },
8231 #if ENABLE_ASH_GETOPTS
8232 { BUILTIN_REGULAR "getopts", getoptscmd },
8234 { BUILTIN_NOSPEC "hash", hashcmd },
8235 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8236 { BUILTIN_NOSPEC "help", helpcmd },
8239 { BUILTIN_REGULAR "jobs", jobscmd },
8240 { BUILTIN_REGULAR "kill", killcmd },
8242 #if ENABLE_ASH_MATH_SUPPORT
8243 { BUILTIN_NOSPEC "let", letcmd },
8245 { BUILTIN_ASSIGN "local", localcmd },
8246 { BUILTIN_NOSPEC "pwd", pwdcmd },
8247 { BUILTIN_REGULAR "read", readcmd },
8248 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8249 { BUILTIN_SPEC_REG "return", returncmd },
8250 { BUILTIN_SPEC_REG "set", setcmd },
8251 { BUILTIN_SPEC_REG "shift", shiftcmd },
8252 { BUILTIN_SPEC_REG "source", dotcmd },
8253 #if ENABLE_ASH_BUILTIN_TEST
8254 { BUILTIN_REGULAR "test", testcmd },
8256 { BUILTIN_SPEC_REG "times", timescmd },
8257 { BUILTIN_SPEC_REG "trap", trapcmd },
8258 { BUILTIN_REGULAR "true", truecmd },
8259 { BUILTIN_NOSPEC "type", typecmd },
8260 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
8261 { BUILTIN_REGULAR "umask", umaskcmd },
8262 #if ENABLE_ASH_ALIAS
8263 { BUILTIN_REGULAR "unalias", unaliascmd },
8265 { BUILTIN_SPEC_REG "unset", unsetcmd },
8266 { BUILTIN_REGULAR "wait", waitcmd },
8270 #define COMMANDCMD (builtintab + 5 + \
8271 2 * ENABLE_ASH_BUILTIN_TEST + \
8272 ENABLE_ASH_ALIAS + \
8273 ENABLE_ASH_JOB_CONTROL)
8274 #define EXECCMD (builtintab + 7 + \
8275 2 * ENABLE_ASH_BUILTIN_TEST + \
8276 ENABLE_ASH_ALIAS + \
8277 ENABLE_ASH_JOB_CONTROL + \
8278 ENABLE_ASH_CMDCMD + \
8279 ENABLE_ASH_BUILTIN_ECHO)
8282 * Search the table of builtin commands.
8284 static struct builtincmd *
8285 find_builtin(const char *name)
8287 struct builtincmd *bp;
8290 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8297 * Execute a simple command.
8299 static int back_exitstatus; /* exit status of backquoted command */
8301 isassignment(const char *p)
8303 const char *q = endofname(p);
8309 bltincmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
8311 /* Preserve exitstatus of a previous possible redirection
8312 * as POSIX mandates */
8313 return back_exitstatus;
8316 evalcommand(union node *cmd, int flags)
8318 static const struct builtincmd null_bltin = {
8319 "\0\0", bltincmd /* why three NULs? */
8321 struct stackmark smark;
8323 struct arglist arglist;
8324 struct arglist varlist;
8327 const struct strlist *sp;
8328 struct cmdentry cmdentry;
8336 struct builtincmd *bcmd;
8337 int pseudovarflag = 0;
8339 /* First expand the arguments. */
8340 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8341 setstackmark(&smark);
8342 back_exitstatus = 0;
8344 cmdentry.cmdtype = CMDBUILTIN;
8345 cmdentry.u.cmd = &null_bltin;
8346 varlist.lastp = &varlist.list;
8347 *varlist.lastp = NULL;
8348 arglist.lastp = &arglist.list;
8349 *arglist.lastp = NULL;
8352 if (cmd->ncmd.args) {
8353 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8354 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8357 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8358 struct strlist **spp;
8360 spp = arglist.lastp;
8361 if (pseudovarflag && isassignment(argp->narg.text))
8362 expandarg(argp, &arglist, EXP_VARTILDE);
8364 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8366 for (sp = *spp; sp; sp = sp->next)
8370 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8371 for (sp = arglist.list; sp; sp = sp->next) {
8372 TRACE(("evalcommand arg: %s\n", sp->text));
8373 *nargv++ = sp->text;
8378 if (iflag && funcnest == 0 && argc > 0)
8379 lastarg = nargv[-1];
8382 expredir(cmd->ncmd.redirect);
8383 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8386 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8387 struct strlist **spp;
8390 spp = varlist.lastp;
8391 expandarg(argp, &varlist, EXP_VARTILDE);
8394 * Modify the command lookup path, if a PATH= assignment
8398 if (varequal(p, path))
8402 /* Print the command if xflag is set. */
8405 const char *p = " %s";
8408 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8411 for (n = 0; n < 2; n++) {
8413 fdprintf(preverrout_fd, p, sp->text);
8421 safe_write(preverrout_fd, "\n", 1);
8427 /* Now locate the command. */
8429 const char *oldpath;
8430 int cmd_flag = DO_ERR;
8435 find_command(argv[0], &cmdentry, cmd_flag, path);
8436 if (cmdentry.cmdtype == CMDUNKNOWN) {
8442 /* implement bltin and command here */
8443 if (cmdentry.cmdtype != CMDBUILTIN)
8446 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8447 if (cmdentry.u.cmd == EXECCMD)
8449 #if ENABLE_ASH_CMDCMD
8450 if (cmdentry.u.cmd == COMMANDCMD) {
8452 nargv = parse_command_args(argv, &path);
8455 argc -= nargv - argv;
8457 cmd_flag |= DO_NOFUNC;
8465 /* We have a redirection error. */
8467 raise_exception(EXERROR);
8469 exitstatus = status;
8473 /* Execute the command. */
8474 switch (cmdentry.cmdtype) {
8476 /* Fork off a child process if necessary. */
8477 if (!(flags & EV_EXIT) || trap[0]) {
8479 jp = makejob(/*cmd,*/ 1);
8480 if (forkshell(jp, cmd, FORK_FG) != 0) {
8481 exitstatus = waitforjob(jp);
8487 listsetvar(varlist.list, VEXPORT|VSTACK);
8488 shellexec(argv, path, cmdentry.u.index);
8492 cmdenviron = varlist.list;
8494 struct strlist *list = cmdenviron;
8496 if (spclbltin > 0 || argc == 0) {
8498 if (cmd_is_exec && argc > 1)
8501 listsetvar(list, i);
8503 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
8510 exit_status = 128 + SIGINT;
8512 exit_status = 128 + pendingsig;
8513 exitstatus = exit_status;
8514 if (i == EXINT || spclbltin > 0) {
8516 longjmp(exception_handler->loc, 1);
8523 listsetvar(varlist.list, 0);
8524 if (evalfun(cmdentry.u.func, argc, argv, flags))
8530 popredir(cmd_is_exec);
8532 /* dsl: I think this is intended to be used to support
8533 * '_' in 'vi' command mode during line editing...
8534 * However I implemented that within libedit itself.
8536 setvar("_", lastarg, 0);
8537 popstackmark(&smark);
8541 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
8543 char *volatile savecmdname;
8544 struct jmploc *volatile savehandler;
8545 struct jmploc jmploc;
8548 savecmdname = commandname;
8549 i = setjmp(jmploc.loc);
8552 savehandler = exception_handler;
8553 exception_handler = &jmploc;
8554 commandname = argv[0];
8556 optptr = NULL; /* initialize nextopt */
8557 exitstatus = (*cmd->builtin)(argc, argv);
8558 flush_stdout_stderr();
8560 exitstatus |= ferror(stdout);
8562 commandname = savecmdname;
8564 exception_handler = savehandler;
8570 goodname(const char *p)
8572 return !*endofname(p);
8577 * Search for a command. This is called before we fork so that the
8578 * location of the command will be available in the parent as well as
8579 * the child. The check for "goodname" is an overly conservative
8580 * check that the name will not be subject to expansion.
8583 prehash(union node *n)
8585 struct cmdentry entry;
8587 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
8588 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
8592 /* ============ Builtin commands
8594 * Builtin commands whose functions are closely tied to evaluation
8595 * are implemented here.
8599 * Handle break and continue commands. Break, continue, and return are
8600 * all handled by setting the evalskip flag. The evaluation routines
8601 * above all check this flag, and if it is set they start skipping
8602 * commands rather than executing them. The variable skipcount is
8603 * the number of loops to break/continue, or the number of function
8604 * levels to return. (The latter is always 1.) It should probably
8605 * be an error to break out of more loops than exist, but it isn't
8606 * in the standard shell so we don't make it one here.
8609 breakcmd(int argc ATTRIBUTE_UNUSED, char **argv)
8611 int n = argv[1] ? number(argv[1]) : 1;
8614 ash_msg_and_raise_error(illnum, argv[1]);
8618 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
8625 /* ============ input.c
8627 * This implements the input routines used by the parser.
8630 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
8633 INPUT_PUSH_FILE = 1,
8634 INPUT_NOFILE_OK = 2,
8637 static int plinno = 1; /* input line number */
8638 /* number of characters left in input buffer */
8639 static int parsenleft; /* copy of parsefile->nleft */
8640 static int parselleft; /* copy of parsefile->lleft */
8641 /* next character in input buffer */
8642 static char *parsenextc; /* copy of parsefile->nextc */
8644 static int checkkwd;
8645 /* values of checkkwd variable */
8646 #define CHKALIAS 0x1
8653 struct strpush *sp = parsefile->strpush;
8656 #if ENABLE_ASH_ALIAS
8658 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
8659 checkkwd |= CHKALIAS;
8661 if (sp->string != sp->ap->val) {
8664 sp->ap->flag &= ~ALIASINUSE;
8665 if (sp->ap->flag & ALIASDEAD) {
8666 unalias(sp->ap->name);
8670 parsenextc = sp->prevstring;
8671 parsenleft = sp->prevnleft;
8672 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
8673 parsefile->strpush = sp->prev;
8674 if (sp != &(parsefile->basestrpush))
8683 char *buf = parsefile->buf;
8686 #if ENABLE_FEATURE_EDITING
8688 if (!iflag || parsefile->fd)
8689 nr = nonblock_safe_read(parsefile->fd, buf, BUFSIZ - 1);
8691 #if ENABLE_FEATURE_TAB_COMPLETION
8692 line_input_state->path_lookup = pathval();
8694 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
8696 /* Ctrl+C pressed */
8705 if (nr < 0 && errno == 0) {
8706 /* Ctrl+D pressed */
8711 nr = nonblock_safe_read(parsefile->fd, buf, BUFSIZ - 1);
8715 /* nonblock_safe_read() handles this problem */
8717 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
8718 int flags = fcntl(0, F_GETFL);
8719 if (flags >= 0 && (flags & O_NONBLOCK)) {
8720 flags &= ~O_NONBLOCK;
8721 if (fcntl(0, F_SETFL, flags) >= 0) {
8722 out2str("sh: turning off NDELAY mode\n");
8733 * Refill the input buffer and return the next input character:
8735 * 1) If a string was pushed back on the input, pop it;
8736 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
8737 * from a string so we can't refill the buffer, return EOF.
8738 * 3) If the is more stuff in this buffer, use it else call read to fill it.
8739 * 4) Process input up to the next newline, deleting nul characters.
8748 while (parsefile->strpush) {
8749 #if ENABLE_ASH_ALIAS
8750 if (parsenleft == -1 && parsefile->strpush->ap &&
8751 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
8756 if (--parsenleft >= 0)
8757 return signed_char2int(*parsenextc++);
8759 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
8761 flush_stdout_stderr();
8768 parselleft = parsenleft = EOF_NLEFT;
8775 /* delete nul characters */
8783 memmove(q, q + 1, more);
8787 parsenleft = q - parsenextc - 1;
8793 parsenleft = q - parsenextc - 1;
8805 out2str(parsenextc);
8810 return signed_char2int(*parsenextc++);
8813 #define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer())
8817 return pgetc_as_macro();
8820 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
8821 #define pgetc_macro() pgetc()
8823 #define pgetc_macro() pgetc_as_macro()
8827 * Same as pgetc(), but ignores PEOA.
8829 #if ENABLE_ASH_ALIAS
8837 } while (c == PEOA);
8844 return pgetc_macro();
8849 * Read a line from the script.
8852 pfgets(char *line, int len)
8858 while (--nleft > 0) {
8874 * Undo the last call to pgetc. Only one character may be pushed back.
8875 * PEOF may be pushed back.
8885 * Push a string back onto the input at this current parsefile level.
8886 * We handle aliases this way.
8888 #if !ENABLE_ASH_ALIAS
8889 #define pushstring(s, ap) pushstring(s)
8892 pushstring(char *s, struct alias *ap)
8899 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
8900 if (parsefile->strpush) {
8901 sp = ckzalloc(sizeof(struct strpush));
8902 sp->prev = parsefile->strpush;
8903 parsefile->strpush = sp;
8905 sp = parsefile->strpush = &(parsefile->basestrpush);
8906 sp->prevstring = parsenextc;
8907 sp->prevnleft = parsenleft;
8908 #if ENABLE_ASH_ALIAS
8911 ap->flag |= ALIASINUSE;
8921 * To handle the "." command, a stack of input files is used. Pushfile
8922 * adds a new entry to the stack and popfile restores the previous level.
8927 struct parsefile *pf;
8929 parsefile->nleft = parsenleft;
8930 parsefile->lleft = parselleft;
8931 parsefile->nextc = parsenextc;
8932 parsefile->linno = plinno;
8933 pf = ckzalloc(sizeof(*pf));
8934 pf->prev = parsefile;
8936 /*pf->strpush = NULL; - ckzalloc did it */
8937 /*pf->basestrpush.prev = NULL;*/
8944 struct parsefile *pf = parsefile;
8952 parsefile = pf->prev;
8954 parsenleft = parsefile->nleft;
8955 parselleft = parsefile->lleft;
8956 parsenextc = parsefile->nextc;
8957 plinno = parsefile->linno;
8962 * Return to top level.
8967 while (parsefile != &basepf)
8972 * Close the file(s) that the shell is reading commands from. Called
8973 * after a fork is done.
8979 if (parsefile->fd > 0) {
8980 close(parsefile->fd);
8986 * Like setinputfile, but takes an open file descriptor. Call this with
8990 setinputfd(int fd, int push)
8992 close_on_exec_on(fd);
8998 if (parsefile->buf == NULL)
8999 parsefile->buf = ckmalloc(IBUFSIZ);
9000 parselleft = parsenleft = 0;
9005 * Set the input to take input from a file. If push is set, push the
9006 * old input onto the stack first.
9009 setinputfile(const char *fname, int flags)
9015 fd = open(fname, O_RDONLY);
9017 if (flags & INPUT_NOFILE_OK)
9019 ash_msg_and_raise_error("can't open %s", fname);
9022 fd2 = copyfd(fd, 10);
9025 ash_msg_and_raise_error("out of file descriptors");
9028 setinputfd(fd, flags & INPUT_PUSH_FILE);
9035 * Like setinputfile, but takes input from a string.
9038 setinputstring(char *string)
9042 parsenextc = string;
9043 parsenleft = strlen(string);
9044 parsefile->buf = NULL;
9050 /* ============ mail.c
9052 * Routines to check for mail.
9057 #define MAXMBOXES 10
9059 /* times of mailboxes */
9060 static time_t mailtime[MAXMBOXES];
9061 /* Set if MAIL or MAILPATH is changed. */
9062 static smallint mail_var_path_changed;
9065 * Print appropriate message(s) if mail has arrived.
9066 * If mail_var_path_changed is set,
9067 * then the value of MAIL has mail_var_path_changed,
9068 * so we just update the values.
9077 struct stackmark smark;
9080 setstackmark(&smark);
9081 mpath = mpathset() ? mpathval() : mailval();
9082 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9083 p = padvance(&mpath, nullstr);
9088 for (q = p; *q; q++);
9093 q[-1] = '\0'; /* delete trailing '/' */
9094 if (stat(p, &statb) < 0) {
9098 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9101 pathopt ? pathopt : "you have mail"
9104 *mtp = statb.st_mtime;
9106 mail_var_path_changed = 0;
9107 popstackmark(&smark);
9111 changemail(const char *val ATTRIBUTE_UNUSED)
9113 mail_var_path_changed = 1;
9116 #endif /* ASH_MAIL */
9119 /* ============ ??? */
9122 * Set the shell parameters.
9125 setparam(char **argv)
9131 for (nparam = 0; argv[nparam]; nparam++);
9132 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9134 *ap++ = ckstrdup(*argv++);
9137 freeparam(&shellparam);
9138 shellparam.malloced = 1;
9139 shellparam.nparam = nparam;
9140 shellparam.p = newparam;
9141 #if ENABLE_ASH_GETOPTS
9142 shellparam.optind = 1;
9143 shellparam.optoff = -1;
9148 * Process shell options. The global variable argptr contains a pointer
9149 * to the argument list; we advance it past the options.
9151 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9152 * For a non-interactive shell, an error condition encountered
9153 * by a special built-in ... shall cause the shell to write a diagnostic message
9154 * to standard error and exit as shown in the following table:
9155 * Error Special Built-In
9157 * Utility syntax error (option or operand error) Shall exit
9159 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9160 * we see that bash does not do that (set "finishes" with error code 1 instead,
9161 * and shell continues), and people rely on this behavior!
9163 * set -o barfoo 2>/dev/null
9166 * Oh well. Let's mimic that.
9169 minus_o(char *name, int val)
9174 for (i = 0; i < NOPTS; i++) {
9175 if (strcmp(name, optnames(i)) == 0) {
9180 ash_msg("illegal option -o %s", name);
9183 out1str("Current option settings\n");
9184 for (i = 0; i < NOPTS; i++)
9185 out1fmt("%-16s%s\n", optnames(i),
9186 optlist[i] ? "on" : "off");
9190 setoption(int flag, int val)
9194 for (i = 0; i < NOPTS; i++) {
9195 if (optletters(i) == flag) {
9200 ash_msg_and_raise_error("illegal option -%c", flag);
9204 options(int cmdline)
9212 while ((p = *argptr) != NULL) {
9214 if (c != '-' && c != '+')
9217 val = 0; /* val = 0 if c == '+' */
9220 if (p[0] == '\0' || LONE_DASH(p)) {
9222 /* "-" means turn off -x and -v */
9225 /* "--" means reset params */
9226 else if (*argptr == NULL)
9229 break; /* "-" or "--" terminates options */
9232 /* first char was + or - */
9233 while ((c = *p++) != '\0') {
9234 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9235 if (c == 'c' && cmdline) {
9236 minusc = p; /* command is after shell args */
9237 } else if (c == 'o') {
9238 if (minus_o(*argptr, val)) {
9239 /* it already printed err message */
9240 return 1; /* error */
9244 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9246 /* bash does not accept +-login, we also won't */
9247 } else if (cmdline && val && (c == '-')) { /* long options */
9248 if (strcmp(p, "login") == 0)
9260 * The shift builtin command.
9263 shiftcmd(int argc ATTRIBUTE_UNUSED, char **argv)
9270 n = number(argv[1]);
9271 if (n > shellparam.nparam)
9272 ash_msg_and_raise_error("can't shift that many");
9274 shellparam.nparam -= n;
9275 for (ap1 = shellparam.p; --n >= 0; ap1++) {
9276 if (shellparam.malloced)
9280 while ((*ap2++ = *ap1++) != NULL);
9281 #if ENABLE_ASH_GETOPTS
9282 shellparam.optind = 1;
9283 shellparam.optoff = -1;
9290 * POSIX requires that 'set' (but not export or readonly) output the
9291 * variables in lexicographic order - by the locale's collating order (sigh).
9292 * Maybe we could keep them in an ordered balanced binary tree
9293 * instead of hashed lists.
9294 * For now just roll 'em through qsort for printing...
9297 showvars(const char *sep_prefix, int on, int off)
9302 ep = listvars(on, off, &epend);
9303 qsort(ep, epend - ep, sizeof(char *), vpcmp);
9305 sep = *sep_prefix ? " " : sep_prefix;
9307 for (; ep < epend; ep++) {
9311 p = strchrnul(*ep, '=');
9314 q = single_quote(++p);
9315 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9321 * The set command builtin.
9324 setcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
9329 return showvars(nullstr, 0, VUNSET);
9332 if (!options(0)) { /* if no parse error... */
9335 if (*argptr != NULL) {
9343 #if ENABLE_ASH_RANDOM_SUPPORT
9344 /* Roughly copied from bash.. */
9346 change_random(const char *value)
9348 if (value == NULL) {
9349 /* "get", generate */
9352 rseed = rseed * 1103515245 + 12345;
9353 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9354 /* set without recursion */
9355 setvar(vrandom.text, buf, VNOFUNC);
9356 vrandom.flags &= ~VNOFUNC;
9359 rseed = strtoul(value, (char **)NULL, 10);
9364 #if ENABLE_ASH_GETOPTS
9366 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9375 if (*param_optind < 1)
9377 optnext = optfirst + *param_optind - 1;
9379 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9382 p = optnext[-1] + *optoff;
9383 if (p == NULL || *p == '\0') {
9384 /* Current word is done, advance */
9386 if (p == NULL || *p != '-' || *++p == '\0') {
9393 if (LONE_DASH(p)) /* check for "--" */
9398 for (q = optstr; *q != c; ) {
9400 if (optstr[0] == ':') {
9403 err |= setvarsafe("OPTARG", s, 0);
9405 fprintf(stderr, "Illegal option -%c\n", c);
9416 if (*p == '\0' && (p = *optnext) == NULL) {
9417 if (optstr[0] == ':') {
9420 err |= setvarsafe("OPTARG", s, 0);
9423 fprintf(stderr, "No arg for -%c option\n", c);
9432 err |= setvarsafe("OPTARG", p, 0);
9435 err |= setvarsafe("OPTARG", nullstr, 0);
9437 *optoff = p ? p - *(optnext - 1) : -1;
9438 *param_optind = optnext - optfirst + 1;
9439 fmtstr(s, sizeof(s), "%d", *param_optind);
9440 err |= setvarsafe("OPTIND", s, VNOFUNC);
9443 err |= setvarsafe(optvar, s, 0);
9447 flush_stdout_stderr();
9448 raise_exception(EXERROR);
9454 * The getopts builtin. Shellparam.optnext points to the next argument
9455 * to be processed. Shellparam.optptr points to the next character to
9456 * be processed in the current argument. If shellparam.optnext is NULL,
9457 * then it's the first time getopts has been called.
9460 getoptscmd(int argc, char **argv)
9465 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
9467 optbase = shellparam.p;
9468 if (shellparam.optind > shellparam.nparam + 1) {
9469 shellparam.optind = 1;
9470 shellparam.optoff = -1;
9474 if (shellparam.optind > argc - 2) {
9475 shellparam.optind = 1;
9476 shellparam.optoff = -1;
9480 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9481 &shellparam.optoff);
9483 #endif /* ASH_GETOPTS */
9486 /* ============ Shell parser */
9489 * NEOF is returned by parsecmd when it encounters an end of file. It
9490 * must be distinct from NULL, so we use the address of a variable that
9491 * happens to be handy.
9493 static smallint tokpushback; /* last token pushed back */
9494 #define NEOF ((union node *)&tokpushback)
9495 static smallint parsebackquote; /* nonzero if we are inside backquotes */
9496 static int lasttoken; /* last token read */
9497 static char *wordtext; /* text of last word returned by readtoken */
9498 static struct nodelist *backquotelist;
9499 static union node *redirnode;
9500 static struct heredoc *heredoc;
9501 static smallint quoteflag; /* set if (part of) last token was quoted */
9503 static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN;
9505 raise_error_syntax(const char *msg)
9507 ash_msg_and_raise_error("syntax error: %s", msg);
9512 * Called when an unexpected token is read during the parse. The argument
9513 * is the token that is expected, or -1 if more than one type of token can
9514 * occur at this point.
9516 static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN;
9518 raise_error_unexpected_syntax(int token)
9523 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
9525 sprintf(msg + l, " (expecting %s)", tokname(token));
9526 raise_error_syntax(msg);
9530 #define EOFMARKLEN 79
9533 struct heredoc *next; /* next here document in list */
9534 union node *here; /* redirection node */
9535 char *eofmark; /* string indicating end of input */
9536 int striptabs; /* if set, strip leading tabs */
9539 static struct heredoc *heredoclist; /* list of here documents to read */
9541 /* parsing is heavily cross-recursive, need these forward decls */
9542 static union node *andor(void);
9543 static union node *pipeline(void);
9544 static union node *parse_command(void);
9545 static void parseheredoc(void);
9546 static char peektoken(void);
9547 static int readtoken(void);
9552 union node *n1, *n2, *n3;
9555 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9556 if (nlflag == 2 && peektoken())
9562 if (tok == TBACKGND) {
9563 if (n2->type == NPIPE) {
9564 n2->npipe.backgnd = 1;
9566 if (n2->type != NREDIR) {
9567 n3 = stzalloc(sizeof(struct nredir));
9569 /*n3->nredir.redirect = NULL; - stzalloc did it */
9572 n2->type = NBACKGND;
9578 n3 = stzalloc(sizeof(struct nbinary));
9580 n3->nbinary.ch1 = n1;
9581 n3->nbinary.ch2 = n2;
9597 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9605 pungetc(); /* push back EOF on input */
9609 raise_error_unexpected_syntax(-1);
9619 union node *n1, *n2, *n3;
9627 } else if (t == TOR) {
9633 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9635 n3 = stzalloc(sizeof(struct nbinary));
9637 n3->nbinary.ch1 = n1;
9638 n3->nbinary.ch2 = n2;
9646 union node *n1, *n2, *pipenode;
9647 struct nodelist *lp, *prev;
9651 TRACE(("pipeline: entered\n"));
9652 if (readtoken() == TNOT) {
9654 checkkwd = CHKKWD | CHKALIAS;
9657 n1 = parse_command();
9658 if (readtoken() == TPIPE) {
9659 pipenode = stzalloc(sizeof(struct npipe));
9660 pipenode->type = NPIPE;
9661 /*pipenode->npipe.backgnd = 0; - stzalloc did it */
9662 lp = stzalloc(sizeof(struct nodelist));
9663 pipenode->npipe.cmdlist = lp;
9667 lp = stzalloc(sizeof(struct nodelist));
9668 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9669 lp->n = parse_command();
9671 } while (readtoken() == TPIPE);
9677 n2 = stzalloc(sizeof(struct nnot));
9690 n = stzalloc(sizeof(struct narg));
9692 /*n->narg.next = NULL; - stzalloc did it */
9693 n->narg.text = wordtext;
9694 n->narg.backquote = backquotelist;
9699 fixredir(union node *n, const char *text, int err)
9701 TRACE(("Fix redir %s %d\n", text, err));
9703 n->ndup.vname = NULL;
9705 if (isdigit(text[0]) && text[1] == '\0')
9706 n->ndup.dupfd = text[0] - '0';
9707 else if (LONE_DASH(text))
9711 raise_error_syntax("Bad fd number");
9712 n->ndup.vname = makename();
9717 * Returns true if the text contains nothing to expand (no dollar signs
9721 noexpand(char *text)
9727 while ((c = *p++) != '\0') {
9728 if (c == CTLQUOTEMARK)
9732 else if (SIT(c, BASESYNTAX) == CCTL)
9741 union node *n = redirnode;
9743 if (readtoken() != TWORD)
9744 raise_error_unexpected_syntax(-1);
9745 if (n->type == NHERE) {
9746 struct heredoc *here = heredoc;
9752 TRACE(("Here document %d\n", n->type));
9753 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9754 raise_error_syntax("Illegal eof marker for << redirection");
9755 rmescapes(wordtext);
9756 here->eofmark = wordtext;
9758 if (heredoclist == NULL)
9761 for (p = heredoclist; p->next; p = p->next)
9765 } else if (n->type == NTOFD || n->type == NFROMFD) {
9766 fixredir(n, wordtext, 0);
9768 n->nfile.fname = makename();
9775 union node *args, **app;
9776 union node *n = NULL;
9777 union node *vars, **vpp;
9778 union node **rpp, *redir;
9788 savecheckkwd = CHKALIAS;
9790 checkkwd = savecheckkwd;
9791 switch (readtoken()) {
9793 n = stzalloc(sizeof(struct narg));
9795 /*n->narg.next = NULL; - stzalloc did it */
9796 n->narg.text = wordtext;
9797 n->narg.backquote = backquotelist;
9798 if (savecheckkwd && isassignment(wordtext)) {
9800 vpp = &n->narg.next;
9803 app = &n->narg.next;
9808 *rpp = n = redirnode;
9809 rpp = &n->nfile.next;
9810 parsefname(); /* read name of redirection file */
9813 if (args && app == &args->narg.next
9816 struct builtincmd *bcmd;
9819 /* We have a function */
9820 if (readtoken() != TRP)
9821 raise_error_unexpected_syntax(TRP);
9822 name = n->narg.text;
9824 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
9826 raise_error_syntax("Bad function name");
9829 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9830 n->narg.next = parse_command();
9843 n = stzalloc(sizeof(struct ncmd));
9845 n->ncmd.args = args;
9846 n->ncmd.assign = vars;
9847 n->ncmd.redirect = redir;
9854 union node *n1, *n2;
9855 union node *ap, **app;
9856 union node *cp, **cpp;
9857 union node *redir, **rpp;
9864 switch (readtoken()) {
9866 raise_error_unexpected_syntax(-1);
9869 n1 = stzalloc(sizeof(struct nif));
9871 n1->nif.test = list(0);
9872 if (readtoken() != TTHEN)
9873 raise_error_unexpected_syntax(TTHEN);
9874 n1->nif.ifpart = list(0);
9876 while (readtoken() == TELIF) {
9877 n2->nif.elsepart = stzalloc(sizeof(struct nif));
9878 n2 = n2->nif.elsepart;
9880 n2->nif.test = list(0);
9881 if (readtoken() != TTHEN)
9882 raise_error_unexpected_syntax(TTHEN);
9883 n2->nif.ifpart = list(0);
9885 if (lasttoken == TELSE)
9886 n2->nif.elsepart = list(0);
9888 n2->nif.elsepart = NULL;
9896 n1 = stzalloc(sizeof(struct nbinary));
9897 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
9898 n1->nbinary.ch1 = list(0);
9901 TRACE(("expecting DO got %s %s\n", tokname(got),
9902 got == TWORD ? wordtext : ""));
9903 raise_error_unexpected_syntax(TDO);
9905 n1->nbinary.ch2 = list(0);
9910 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9911 raise_error_syntax("Bad for loop variable");
9912 n1 = stzalloc(sizeof(struct nfor));
9914 n1->nfor.var = wordtext;
9915 checkkwd = CHKKWD | CHKALIAS;
9916 if (readtoken() == TIN) {
9918 while (readtoken() == TWORD) {
9919 n2 = stzalloc(sizeof(struct narg));
9921 /*n2->narg.next = NULL; - stzalloc did it */
9922 n2->narg.text = wordtext;
9923 n2->narg.backquote = backquotelist;
9925 app = &n2->narg.next;
9929 if (lasttoken != TNL && lasttoken != TSEMI)
9930 raise_error_unexpected_syntax(-1);
9932 n2 = stzalloc(sizeof(struct narg));
9934 /*n2->narg.next = NULL; - stzalloc did it */
9935 n2->narg.text = (char *)dolatstr;
9936 /*n2->narg.backquote = NULL;*/
9939 * Newline or semicolon here is optional (but note
9940 * that the original Bourne shell only allowed NL).
9942 if (lasttoken != TNL && lasttoken != TSEMI)
9945 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9946 if (readtoken() != TDO)
9947 raise_error_unexpected_syntax(TDO);
9948 n1->nfor.body = list(0);
9952 n1 = stzalloc(sizeof(struct ncase));
9954 if (readtoken() != TWORD)
9955 raise_error_unexpected_syntax(TWORD);
9956 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
9958 /*n2->narg.next = NULL; - stzalloc did it */
9959 n2->narg.text = wordtext;
9960 n2->narg.backquote = backquotelist;
9962 checkkwd = CHKKWD | CHKALIAS;
9963 } while (readtoken() == TNL);
9964 if (lasttoken != TIN)
9965 raise_error_unexpected_syntax(TIN);
9966 cpp = &n1->ncase.cases;
9968 checkkwd = CHKNL | CHKKWD;
9970 while (t != TESAC) {
9971 if (lasttoken == TLP)
9973 *cpp = cp = stzalloc(sizeof(struct nclist));
9975 app = &cp->nclist.pattern;
9977 *app = ap = stzalloc(sizeof(struct narg));
9979 /*ap->narg.next = NULL; - stzalloc did it */
9980 ap->narg.text = wordtext;
9981 ap->narg.backquote = backquotelist;
9982 if (readtoken() != TPIPE)
9984 app = &ap->narg.next;
9987 //ap->narg.next = NULL;
9988 if (lasttoken != TRP)
9989 raise_error_unexpected_syntax(TRP);
9990 cp->nclist.body = list(2);
9992 cpp = &cp->nclist.next;
9994 checkkwd = CHKNL | CHKKWD;
9998 raise_error_unexpected_syntax(TENDCASE);
10005 n1 = stzalloc(sizeof(struct nredir));
10006 n1->type = NSUBSHELL;
10007 n1->nredir.n = list(0);
10008 /*n1->nredir.redirect = NULL; - stzalloc did it */
10018 return simplecmd();
10021 if (readtoken() != t)
10022 raise_error_unexpected_syntax(t);
10025 /* Now check for redirection which may follow command */
10026 checkkwd = CHKKWD | CHKALIAS;
10028 while (readtoken() == TREDIR) {
10029 *rpp = n2 = redirnode;
10030 rpp = &n2->nfile.next;
10036 if (n1->type != NSUBSHELL) {
10037 n2 = stzalloc(sizeof(struct nredir));
10042 n1->nredir.redirect = redir;
10048 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10049 * is not NULL, read a here document. In the latter case, eofmark is the
10050 * word which marks the end of the document and striptabs is true if
10051 * leading tabs should be stripped from the document. The argument firstc
10052 * is the first character of the input token or document.
10054 * Because C does not have internal subroutines, I have simulated them
10055 * using goto's to implement the subroutine linkage. The following macros
10056 * will run code that appears at the end of readtoken1.
10059 #define CHECKEND() {goto checkend; checkend_return:;}
10060 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10061 #define PARSESUB() {goto parsesub; parsesub_return:;}
10062 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10063 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10064 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10067 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10069 /* NB: syntax parameter fits into smallint */
10073 char line[EOFMARKLEN + 1];
10074 struct nodelist *bqlist;
10078 smallint prevsyntax; /* syntax before arithmetic */
10079 #if ENABLE_ASH_EXPAND_PRMT
10080 smallint pssyntax; /* we are expanding a prompt string */
10082 int varnest; /* levels of variables expansion */
10083 int arinest; /* levels of arithmetic expansion */
10084 int parenlevel; /* levels of parens in arithmetic */
10085 int dqvarnest; /* levels of variables expansion within double quotes */
10088 /* Avoid longjmp clobbering */
10094 (void) &parenlevel;
10097 (void) &prevsyntax;
10100 startlinno = plinno;
10105 #if ENABLE_ASH_EXPAND_PRMT
10106 pssyntax = (syntax == PSSYNTAX);
10110 dblquote = (syntax == DQSYNTAX);
10116 STARTSTACKSTR(out);
10117 loop: { /* for each line, until end of word */
10118 CHECKEND(); /* set c to PEOF if at end of here document */
10119 for (;;) { /* until end of line or end of word */
10120 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10121 switch (SIT(c, syntax)) {
10122 case CNL: /* '\n' */
10123 if (syntax == BASESYNTAX)
10124 goto endword; /* exit outer loop */
10130 goto loop; /* continue outer loop */
10135 if (eofmark == NULL || dblquote)
10136 USTPUTC(CTLESC, out);
10139 case CBACK: /* backslash */
10142 USTPUTC(CTLESC, out);
10143 USTPUTC('\\', out);
10145 } else if (c == '\n') {
10149 #if ENABLE_ASH_EXPAND_PRMT
10150 if (c == '$' && pssyntax) {
10151 USTPUTC(CTLESC, out);
10152 USTPUTC('\\', out);
10156 c != '\\' && c != '`' &&
10161 USTPUTC(CTLESC, out);
10162 USTPUTC('\\', out);
10164 if (SIT(c, SQSYNTAX) == CCTL)
10165 USTPUTC(CTLESC, out);
10173 if (eofmark == NULL) {
10174 USTPUTC(CTLQUOTEMARK, out);
10182 if (eofmark != NULL && arinest == 0
10187 if (dqvarnest == 0) {
10188 syntax = BASESYNTAX;
10195 case CVAR: /* '$' */
10196 PARSESUB(); /* parse substitution */
10198 case CENDVAR: /* '}' */
10201 if (dqvarnest > 0) {
10204 USTPUTC(CTLENDVAR, out);
10209 #if ENABLE_ASH_MATH_SUPPORT
10210 case CLP: /* '(' in arithmetic */
10214 case CRP: /* ')' in arithmetic */
10215 if (parenlevel > 0) {
10219 if (pgetc() == ')') {
10220 if (--arinest == 0) {
10221 USTPUTC(CTLENDARI, out);
10222 syntax = prevsyntax;
10223 dblquote = (syntax == DQSYNTAX);
10228 * unbalanced parens
10229 * (don't 2nd guess - no error)
10237 case CBQUOTE: /* '`' */
10241 goto endword; /* exit outer loop */
10246 goto endword; /* exit outer loop */
10247 #if ENABLE_ASH_ALIAS
10257 #if ENABLE_ASH_MATH_SUPPORT
10258 if (syntax == ARISYNTAX)
10259 raise_error_syntax("Missing '))'");
10261 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10262 raise_error_syntax("Unterminated quoted string");
10263 if (varnest != 0) {
10264 startlinno = plinno;
10266 raise_error_syntax("Missing '}'");
10268 USTPUTC('\0', out);
10269 len = out - (char *)stackblock();
10270 out = stackblock();
10271 if (eofmark == NULL) {
10272 if ((c == '>' || c == '<')
10275 && (*out == '\0' || isdigit(*out))) {
10277 return lasttoken = TREDIR;
10282 quoteflag = quotef;
10283 backquotelist = bqlist;
10284 grabstackblock(len);
10288 /* end of readtoken routine */
10291 * Check to see whether we are at the end of the here document. When this
10292 * is called, c is set to the first character of the next input line. If
10293 * we are at the end of the here document, this routine sets the c to PEOF.
10297 #if ENABLE_ASH_ALIAS
10303 while (c == '\t') {
10307 if (c == *eofmark) {
10308 if (pfgets(line, sizeof(line)) != NULL) {
10312 for (q = eofmark + 1; *q && *p == *q; p++, q++);
10313 if (*p == '\n' && *q == '\0') {
10316 needprompt = doprompt;
10318 pushstring(line, NULL);
10323 goto checkend_return;
10327 * Parse a redirection operator. The variable "out" points to a string
10328 * specifying the fd to be redirected. The variable "c" contains the
10329 * first character of the redirection operator.
10335 np = stzalloc(sizeof(struct nfile));
10340 np->type = NAPPEND;
10342 np->type = NCLOBBER;
10349 } else { /* c == '<' */
10350 /*np->nfile.fd = 0; - stzalloc did it */
10354 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10355 np = stzalloc(sizeof(struct nhere));
10356 /*np->nfile.fd = 0; - stzalloc did it */
10359 heredoc = stzalloc(sizeof(struct heredoc));
10360 heredoc->here = np;
10363 heredoc->striptabs = 1;
10365 /*heredoc->striptabs = 0; - stzalloc did it */
10371 np->type = NFROMFD;
10375 np->type = NFROMTO;
10385 np->nfile.fd = fd - '0';
10387 goto parseredir_return;
10391 * Parse a substitution. At this point, we have read the dollar sign
10392 * and nothing else.
10395 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
10396 * (assuming ascii char codes, as the original implementation did) */
10397 #define is_special(c) \
10398 ((((unsigned int)c) - 33 < 32) \
10399 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
10405 static const char types[] ALIGN1 = "}-+?=";
10409 c <= PEOA_OR_PEOF ||
10410 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10414 } else if (c == '(') { /* $(command) or $((arith)) */
10415 if (pgetc() == '(') {
10416 #if ENABLE_ASH_MATH_SUPPORT
10419 raise_error_syntax("We unsupport $((arith))");
10426 USTPUTC(CTLVAR, out);
10427 typeloc = out - (char *)stackblock();
10428 USTPUTC(VSNORMAL, out);
10429 subtype = VSNORMAL;
10437 subtype = VSLENGTH;
10441 if (c > PEOA_OR_PEOF && is_name(c)) {
10445 } while (c > PEOA_OR_PEOF && is_in_name(c));
10446 } else if (isdigit(c)) {
10450 } while (isdigit(c));
10451 } else if (is_special(c)) {
10455 badsub: raise_error_syntax("Bad substitution");
10459 if (subtype == 0) {
10466 p = strchr(types, c);
10469 subtype = p - types + VSNORMAL;
10475 subtype = c == '#' ? VSTRIMLEFT :
10488 if (dblquote || arinest)
10490 *((char *)stackblock() + typeloc) = subtype | flags;
10491 if (subtype != VSNORMAL) {
10493 if (dblquote || arinest) {
10498 goto parsesub_return;
10502 * Called to parse command substitutions. Newstyle is set if the command
10503 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10504 * list of commands (passed by reference), and savelen is the number of
10505 * characters on the top of the stack which must be preserved.
10508 struct nodelist **nlpp;
10511 char *volatile str;
10512 struct jmploc jmploc;
10513 struct jmploc *volatile savehandler;
10515 smallint saveprompt = 0;
10518 (void) &saveprompt;
10520 savepbq = parsebackquote;
10521 if (setjmp(jmploc.loc)) {
10523 parsebackquote = 0;
10524 exception_handler = savehandler;
10525 longjmp(exception_handler->loc, 1);
10529 savelen = out - (char *)stackblock();
10531 str = ckmalloc(savelen);
10532 memcpy(str, stackblock(), savelen);
10534 savehandler = exception_handler;
10535 exception_handler = &jmploc;
10538 /* We must read until the closing backquote, giving special
10539 treatment to some slashes, and then push the string and
10540 reread it as input, interpreting it normally. */
10547 STARTSTACKSTR(pout);
10564 * If eating a newline, avoid putting
10565 * the newline into the new character
10566 * stream (via the STPUTC after the
10571 if (pc != '\\' && pc != '`' && pc != '$'
10572 && (!dblquote || pc != '"'))
10573 STPUTC('\\', pout);
10574 if (pc > PEOA_OR_PEOF) {
10580 #if ENABLE_ASH_ALIAS
10583 startlinno = plinno;
10584 raise_error_syntax("EOF in backquote substitution");
10588 needprompt = doprompt;
10597 STPUTC('\0', pout);
10598 psavelen = pout - (char *)stackblock();
10599 if (psavelen > 0) {
10600 pstr = grabstackstr(pout);
10601 setinputstring(pstr);
10606 nlpp = &(*nlpp)->next;
10607 *nlpp = stzalloc(sizeof(**nlpp));
10608 /* (*nlpp)->next = NULL; - stzalloc did it */
10609 parsebackquote = oldstyle;
10612 saveprompt = doprompt;
10619 doprompt = saveprompt;
10620 else if (readtoken() != TRP)
10621 raise_error_unexpected_syntax(TRP);
10626 * Start reading from old file again, ignoring any pushed back
10627 * tokens left from the backquote parsing
10632 while (stackblocksize() <= savelen)
10634 STARTSTACKSTR(out);
10636 memcpy(out, str, savelen);
10637 STADJUST(savelen, out);
10643 parsebackquote = savepbq;
10644 exception_handler = savehandler;
10645 if (arinest || dblquote)
10646 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10648 USTPUTC(CTLBACKQ, out);
10650 goto parsebackq_oldreturn;
10651 goto parsebackq_newreturn;
10654 #if ENABLE_ASH_MATH_SUPPORT
10656 * Parse an arithmetic expansion (indicate start of one and set state)
10659 if (++arinest == 1) {
10660 prevsyntax = syntax;
10661 syntax = ARISYNTAX;
10662 USTPUTC(CTLARI, out);
10669 * we collapse embedded arithmetic expansion to
10670 * parenthesis, which should be equivalent
10674 goto parsearith_return;
10678 } /* end of readtoken */
10681 * Read the next input token.
10682 * If the token is a word, we set backquotelist to the list of cmds in
10683 * backquotes. We set quoteflag to true if any part of the word was
10685 * If the token is TREDIR, then we set redirnode to a structure containing
10687 * In all cases, the variable startlinno is set to the number of the line
10688 * on which the token starts.
10690 * [Change comment: here documents and internal procedures]
10691 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10692 * word parsing code into a separate routine. In this case, readtoken
10693 * doesn't need to have any internal procedures, but parseword does.
10694 * We could also make parseoperator in essence the main routine, and
10695 * have parseword (readtoken1?) handle both words and redirection.]
10697 #define NEW_xxreadtoken
10698 #ifdef NEW_xxreadtoken
10699 /* singles must be first! */
10700 static const char xxreadtoken_chars[7] ALIGN1 = {
10701 '\n', '(', ')', '&', '|', ';', 0
10704 static const char xxreadtoken_tokens[] ALIGN1 = {
10705 TNL, TLP, TRP, /* only single occurrence allowed */
10706 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10707 TEOF, /* corresponds to trailing nul */
10708 TAND, TOR, TENDCASE /* if double occurrence */
10711 #define xxreadtoken_doubles \
10712 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10713 #define xxreadtoken_singles \
10714 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10728 startlinno = plinno;
10729 for (;;) { /* until token or start of word found */
10732 if ((c != ' ') && (c != '\t')
10733 #if ENABLE_ASH_ALIAS
10738 while ((c = pgetc()) != '\n' && c != PEOF);
10740 } else if (c == '\\') {
10741 if (pgetc() != '\n') {
10745 startlinno = ++plinno;
10750 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10755 needprompt = doprompt;
10758 p = strchr(xxreadtoken_chars, c);
10761 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10764 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10765 if (pgetc() == *p) { /* double occurrence? */
10766 p += xxreadtoken_doubles + 1;
10772 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10778 #define RETURN(token) return lasttoken = token
10791 startlinno = plinno;
10792 for (;;) { /* until token or start of word found */
10795 case ' ': case '\t':
10796 #if ENABLE_ASH_ALIAS
10801 while ((c = pgetc()) != '\n' && c != PEOF);
10805 if (pgetc() == '\n') {
10806 startlinno = ++plinno;
10815 needprompt = doprompt;
10820 if (pgetc() == '&')
10825 if (pgetc() == '|')
10830 if (pgetc() == ';')
10843 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10846 #endif /* NEW_xxreadtoken */
10853 smallint alreadyseen = tokpushback;
10856 #if ENABLE_ASH_ALIAS
10865 if (checkkwd & CHKNL) {
10872 if (t != TWORD || quoteflag) {
10877 * check for keywords
10879 if (checkkwd & CHKKWD) {
10880 const char *const *pp;
10882 pp = findkwd(wordtext);
10884 lasttoken = t = pp - tokname_array;
10885 TRACE(("keyword %s recognized\n", tokname(t)));
10890 if (checkkwd & CHKALIAS) {
10891 #if ENABLE_ASH_ALIAS
10893 ap = lookupalias(wordtext, 1);
10896 pushstring(ap->val, ap);
10906 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
10908 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
10920 return tokname_array[t][0];
10924 * Read and parse a command. Returns NEOF on end of file. (NULL is a
10925 * valid parse tree indicating a blank line.)
10927 static union node *
10928 parsecmd(int interact)
10933 doprompt = interact;
10935 setprompt(doprompt);
10947 * Input any here documents.
10952 struct heredoc *here;
10955 here = heredoclist;
10956 heredoclist = NULL;
10962 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10963 here->eofmark, here->striptabs);
10964 n = stzalloc(sizeof(struct narg));
10965 n->narg.type = NARG;
10966 /*n->narg.next = NULL; - stzalloc did it */
10967 n->narg.text = wordtext;
10968 n->narg.backquote = backquotelist;
10969 here->here->nhere.doc = n;
10976 * called by editline -- any expansions to the prompt should be added here.
10978 #if ENABLE_ASH_EXPAND_PRMT
10979 static const char *
10980 expandstr(const char *ps)
10984 /* XXX Fix (char *) cast. */
10985 setinputstring((char *)ps);
10986 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
10989 n.narg.type = NARG;
10990 n.narg.next = NULL;
10991 n.narg.text = wordtext;
10992 n.narg.backquote = backquotelist;
10994 expandarg(&n, NULL, 0);
10995 return stackblock();
11000 * Execute a command or commands contained in a string.
11003 evalstring(char *s, int mask)
11006 struct stackmark smark;
11010 setstackmark(&smark);
11013 while ((n = parsecmd(0)) != NEOF) {
11015 popstackmark(&smark);
11028 * The eval command.
11031 evalcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11040 STARTSTACKSTR(concat);
11042 concat = stack_putstr(p, concat);
11046 STPUTC(' ', concat);
11048 STPUTC('\0', concat);
11049 p = grabstackstr(concat);
11051 evalstring(p, ~SKIPEVAL);
11058 * Read and execute commands. "Top" is nonzero for the top level command
11059 * loop; it turns on prompting if the shell is interactive.
11065 struct stackmark smark;
11069 TRACE(("cmdloop(%d) called\n", top));
11073 setstackmark(&smark);
11076 showjobs(stderr, SHOW_CHANGED);
11079 if (iflag && top) {
11081 #if ENABLE_ASH_MAIL
11085 n = parsecmd(inter);
11086 /* showtree(n); DEBUG */
11088 if (!top || numeof >= 50)
11090 if (!stoppedjobs()) {
11093 out2str("\nUse \"exit\" to leave shell.\n");
11096 } else if (nflag == 0) {
11097 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11102 popstackmark(&smark);
11107 return skip & SKIPEVAL;
11114 * Take commands from a file. To be compatible we should do a path
11115 * search for the file, which is necessary to find sub-commands.
11118 find_dot_file(char *name)
11121 const char *path = pathval();
11124 /* don't try this for absolute or relative paths */
11125 if (strchr(name, '/'))
11128 while ((fullname = padvance(&path, name)) != NULL) {
11129 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11131 * Don't bother freeing here, since it will
11132 * be freed by the caller.
11136 stunalloc(fullname);
11139 /* not found in the PATH */
11140 ash_msg_and_raise_error("%s: not found", name);
11145 dotcmd(int argc, char **argv)
11147 struct strlist *sp;
11148 volatile struct shparam saveparam;
11151 for (sp = cmdenviron; sp; sp = sp->next)
11152 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11154 if (argv[1]) { /* That's what SVR2 does */
11155 char *fullname = find_dot_file(argv[1]);
11158 if (argc) { /* argc > 0, argv[0] != NULL */
11159 saveparam = shellparam;
11160 shellparam.malloced = 0;
11161 shellparam.nparam = argc;
11162 shellparam.p = argv;
11165 setinputfile(fullname, INPUT_PUSH_FILE);
11166 commandname = fullname;
11171 freeparam(&shellparam);
11172 shellparam = saveparam;
11174 status = exitstatus;
11180 exitcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11185 exitstatus = number(argv[1]);
11186 raise_exception(EXEXIT);
11190 #if ENABLE_ASH_BUILTIN_ECHO
11192 echocmd(int argc, char **argv)
11194 return echo_main(argc, argv);
11198 #if ENABLE_ASH_BUILTIN_TEST
11200 testcmd(int argc, char **argv)
11202 return test_main(argc, argv);
11207 * Read a file containing shell functions.
11210 readcmdfile(char *name)
11212 setinputfile(name, INPUT_PUSH_FILE);
11218 /* ============ find_command inplementation */
11221 * Resolve a command name. If you change this routine, you may have to
11222 * change the shellexec routine as well.
11225 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11227 struct tblentry *cmdp;
11234 struct builtincmd *bcmd;
11236 /* If name contains a slash, don't use PATH or hash table */
11237 if (strchr(name, '/') != NULL) {
11238 entry->u.index = -1;
11239 if (act & DO_ABS) {
11240 while (stat(name, &statb) < 0) {
11242 if (errno == EINTR)
11245 entry->cmdtype = CMDUNKNOWN;
11249 entry->cmdtype = CMDNORMAL;
11253 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11255 updatetbl = (path == pathval());
11258 if (strstr(path, "%builtin") != NULL)
11259 act |= DO_ALTBLTIN;
11262 /* If name is in the table, check answer will be ok */
11263 cmdp = cmdlookup(name, 0);
11264 if (cmdp != NULL) {
11267 switch (cmdp->cmdtype) {
11285 } else if (cmdp->rehash == 0)
11286 /* if not invalidated by cd, we're done */
11290 /* If %builtin not in path, check for builtin next */
11291 bcmd = find_builtin(name);
11293 if (IS_BUILTIN_REGULAR(bcmd))
11294 goto builtin_success;
11295 if (act & DO_ALTPATH) {
11296 if (!(act & DO_ALTBLTIN))
11297 goto builtin_success;
11298 } else if (builtinloc <= 0) {
11299 goto builtin_success;
11303 #if ENABLE_FEATURE_SH_STANDALONE
11304 if (find_applet_by_name(name) >= 0) {
11305 entry->cmdtype = CMDNORMAL;
11306 entry->u.index = -1;
11311 /* We have to search path. */
11312 prev = -1; /* where to start */
11313 if (cmdp && cmdp->rehash) { /* doing a rehash */
11314 if (cmdp->cmdtype == CMDBUILTIN)
11317 prev = cmdp->param.index;
11323 while ((fullname = padvance(&path, name)) != NULL) {
11324 stunalloc(fullname);
11325 /* NB: code below will still use fullname
11326 * despite it being "unallocated" */
11329 if (prefix(pathopt, "builtin")) {
11331 goto builtin_success;
11333 } else if (!(act & DO_NOFUNC)
11334 && prefix(pathopt, "func")) {
11335 /* handled below */
11337 /* ignore unimplemented options */
11341 /* if rehash, don't redo absolute path names */
11342 if (fullname[0] == '/' && idx <= prev) {
11345 TRACE(("searchexec \"%s\": no change\n", name));
11348 while (stat(fullname, &statb) < 0) {
11350 if (errno == EINTR)
11353 if (errno != ENOENT && errno != ENOTDIR)
11357 e = EACCES; /* if we fail, this will be the error */
11358 if (!S_ISREG(statb.st_mode))
11360 if (pathopt) { /* this is a %func directory */
11361 stalloc(strlen(fullname) + 1);
11362 /* NB: stalloc will return space pointed by fullname
11363 * (because we don't have any intervening allocations
11364 * between stunalloc above and this stalloc) */
11365 readcmdfile(fullname);
11366 cmdp = cmdlookup(name, 0);
11367 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
11368 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
11369 stunalloc(fullname);
11372 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
11374 entry->cmdtype = CMDNORMAL;
11375 entry->u.index = idx;
11379 cmdp = cmdlookup(name, 1);
11380 cmdp->cmdtype = CMDNORMAL;
11381 cmdp->param.index = idx;
11386 /* We failed. If there was an entry for this command, delete it */
11387 if (cmdp && updatetbl)
11388 delete_cmd_entry();
11390 ash_msg("%s: %s", name, errmsg(e, "not found"));
11391 entry->cmdtype = CMDUNKNOWN;
11396 entry->cmdtype = CMDBUILTIN;
11397 entry->u.cmd = bcmd;
11401 cmdp = cmdlookup(name, 1);
11402 cmdp->cmdtype = CMDBUILTIN;
11403 cmdp->param.cmd = bcmd;
11407 entry->cmdtype = cmdp->cmdtype;
11408 entry->u = cmdp->param;
11412 /* ============ trap.c */
11415 * The trap builtin.
11418 trapcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11427 for (signo = 0; signo < NSIG; signo++) {
11428 if (trap[signo] != NULL) {
11431 sn = get_signame(signo);
11432 out1fmt("trap -- %s %s\n",
11433 single_quote(trap[signo]), sn);
11443 signo = get_signum(*ap);
11445 ash_msg_and_raise_error("%s: bad trap", *ap);
11448 if (LONE_DASH(action))
11451 action = ckstrdup(action);
11454 trap[signo] = action;
11464 /* ============ Builtins */
11466 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
11468 * Lists available builtins
11471 helpcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11475 out1fmt("\nBuilt-in commands:\n-------------------\n");
11476 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
11477 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11478 builtintab[i].name + 1);
11484 #if ENABLE_FEATURE_SH_STANDALONE
11486 const char *a = applet_names;
11488 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
11493 a += strlen(a) + 1;
11498 return EXIT_SUCCESS;
11500 #endif /* FEATURE_SH_EXTRA_QUIET */
11503 * The export and readonly commands.
11506 exportcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11512 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
11514 if (nextopt("p") != 'p') {
11519 p = strchr(name, '=');
11523 vp = *findvar(hashvar(name), name);
11529 setvar(name, p, flag);
11530 } while ((name = *++aptr) != NULL);
11534 showvars(argv[0], flag, 0);
11539 * Delete a function if it exists.
11542 unsetfunc(const char *name)
11544 struct tblentry *cmdp;
11546 cmdp = cmdlookup(name, 0);
11547 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
11548 delete_cmd_entry();
11552 * The unset builtin command. We unset the function before we unset the
11553 * variable to allow a function to be unset when there is a readonly variable
11554 * with the same name.
11557 unsetcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11564 while ((i = nextopt("vf")) != '\0') {
11568 for (ap = argptr; *ap; ap++) {
11584 #include <sys/times.h>
11586 static const unsigned char timescmd_str[] ALIGN1 = {
11587 ' ', offsetof(struct tms, tms_utime),
11588 '\n', offsetof(struct tms, tms_stime),
11589 ' ', offsetof(struct tms, tms_cutime),
11590 '\n', offsetof(struct tms, tms_cstime),
11595 timescmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11597 long clk_tck, s, t;
11598 const unsigned char *p;
11601 clk_tck = sysconf(_SC_CLK_TCK);
11606 t = *(clock_t *)(((char *) &buf) + p[1]);
11608 out1fmt("%ldm%ld.%.3lds%c",
11610 ((t - s * clk_tck) * 1000) / clk_tck,
11612 } while (*(p += 2));
11617 #if ENABLE_ASH_MATH_SUPPORT
11619 dash_arith(const char *s)
11625 result = arith(s, &errcode);
11628 ash_msg_and_raise_error("exponent less than 0");
11630 ash_msg_and_raise_error("divide by zero");
11632 ash_msg_and_raise_error("expression recursion loop detected");
11633 raise_error_syntax(s);
11641 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
11642 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
11644 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
11647 letcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11653 ash_msg_and_raise_error("expression expected");
11655 i = dash_arith(*argv);
11660 #endif /* ASH_MATH_SUPPORT */
11663 /* ============ miscbltin.c
11665 * Miscellaneous builtins.
11670 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
11671 typedef enum __rlimit_resource rlim_t;
11675 * The read builtin. Options:
11676 * -r Do not interpret '\' specially
11677 * -s Turn off echo (tty only)
11678 * -n NCHARS Read NCHARS max
11679 * -p PROMPT Display PROMPT on stderr (if input is from tty)
11680 * -t SECONDS Timeout after SECONDS (tty or pipe only)
11681 * -u FD Read from given FD instead of fd 0
11682 * This uses unbuffered input, which may be avoidable in some cases.
11683 * TODO: bash also has:
11684 * -a ARRAY Read into array[0],[1],etc
11685 * -d DELIM End on DELIM char, not newline
11686 * -e Use line editing (tty only)
11689 readcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11702 #if ENABLE_ASH_READ_NCHARS
11703 int nchars = 0; /* if != 0, -n is in effect */
11705 struct termios tty, old_tty;
11707 #if ENABLE_ASH_READ_TIMEOUT
11708 unsigned end_ms = 0;
11709 unsigned timeout = 0;
11714 while ((i = nextopt("p:u:r"
11715 USE_ASH_READ_TIMEOUT("t:")
11716 USE_ASH_READ_NCHARS("n:s")
11720 prompt = optionarg;
11722 #if ENABLE_ASH_READ_NCHARS
11724 nchars = bb_strtou(optionarg, NULL, 10);
11725 if (nchars < 0 || errno)
11726 ash_msg_and_raise_error("invalid count");
11727 /* nchars == 0: off (bash 3.2 does this too) */
11733 #if ENABLE_ASH_READ_TIMEOUT
11735 timeout = bb_strtou(optionarg, NULL, 10);
11736 if (errno || timeout > UINT_MAX / 2048)
11737 ash_msg_and_raise_error("invalid timeout");
11739 #if 0 /* even bash have no -t N.NNN support */
11740 ts.tv_sec = bb_strtou(optionarg, &p, 10);
11742 /* EINVAL means number is ok, but not terminated by NUL */
11743 if (*p == '.' && errno == EINVAL) {
11747 ts.tv_usec = bb_strtou(p, &p2, 10);
11749 ash_msg_and_raise_error("invalid timeout");
11751 /* normalize to usec */
11753 ash_msg_and_raise_error("invalid timeout");
11754 while (scale++ < 6)
11757 } else if (ts.tv_sec < 0 || errno) {
11758 ash_msg_and_raise_error("invalid timeout");
11760 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
11761 ash_msg_and_raise_error("invalid timeout");
11770 fd = bb_strtou(optionarg, NULL, 10);
11771 if (fd < 0 || errno)
11772 ash_msg_and_raise_error("invalid file descriptor");
11778 if (prompt && isatty(fd)) {
11783 ash_msg_and_raise_error("arg count");
11784 ifs = bltinlookup("IFS");
11787 #if ENABLE_ASH_READ_NCHARS
11788 tcgetattr(fd, &tty);
11790 if (nchars || silent) {
11792 tty.c_lflag &= ~ICANON;
11793 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
11796 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
11798 /* if tcgetattr failed, tcsetattr will fail too.
11799 * Ignoring, it's harmless. */
11800 tcsetattr(fd, TCSANOW, &tty);
11807 #if ENABLE_ASH_READ_TIMEOUT
11808 if (timeout) /* NB: ensuring end_ms is nonzero */
11809 end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1;
11813 #if ENABLE_ASH_READ_TIMEOUT
11815 struct pollfd pfd[1];
11817 pfd[0].events = POLLIN;
11818 timeout = end_ms - (unsigned)(monotonic_us() / 1000);
11819 if ((int)timeout <= 0 /* already late? */
11820 || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
11821 ) { /* timed out! */
11822 #if ENABLE_ASH_READ_NCHARS
11823 tcsetattr(fd, TCSANOW, &old_tty);
11829 if (nonblock_safe_read(fd, &c, 1) != 1) {
11841 if (!rflag && c == '\\') {
11847 if (startword && *ifs == ' ' && strchr(ifs, c)) {
11851 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
11853 setvar(*ap, stackblock(), 0);
11862 /* end of do {} while: */
11863 #if ENABLE_ASH_READ_NCHARS
11869 #if ENABLE_ASH_READ_NCHARS
11870 tcsetattr(fd, TCSANOW, &old_tty);
11874 /* Remove trailing blanks */
11875 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
11877 setvar(*ap, stackblock(), 0);
11878 while (*++ap != NULL)
11879 setvar(*ap, nullstr, 0);
11884 umaskcmd(int argc ATTRIBUTE_UNUSED, char **argv)
11886 static const char permuser[3] ALIGN1 = "ugo";
11887 static const char permmode[3] ALIGN1 = "rwx";
11888 static const short permmask[] ALIGN2 = {
11889 S_IRUSR, S_IWUSR, S_IXUSR,
11890 S_IRGRP, S_IWGRP, S_IXGRP,
11891 S_IROTH, S_IWOTH, S_IXOTH
11897 int symbolic_mode = 0;
11899 while (nextopt("S") != '\0') {
11910 if (symbolic_mode) {
11914 for (i = 0; i < 3; i++) {
11917 *p++ = permuser[i];
11919 for (j = 0; j < 3; j++) {
11920 if ((mask & permmask[3 * i + j]) == 0) {
11921 *p++ = permmode[j];
11929 out1fmt("%.4o\n", mask);
11932 if (isdigit((unsigned char) *ap)) {
11935 if (*ap >= '8' || *ap < '0')
11936 ash_msg_and_raise_error(illnum, argv[1]);
11937 mask = (mask << 3) + (*ap - '0');
11938 } while (*++ap != '\0');
11941 mask = ~mask & 0777;
11942 if (!bb_parse_mode(ap, &mask)) {
11943 ash_msg_and_raise_error("illegal mode: %s", ap);
11945 umask(~mask & 0777);
11954 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
11955 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
11956 * ash by J.T. Conklin.
11962 uint8_t cmd; /* RLIMIT_xxx fit into it */
11963 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
11967 static const struct limits limits_tbl[] = {
11969 { RLIMIT_CPU, 0, 't' },
11971 #ifdef RLIMIT_FSIZE
11972 { RLIMIT_FSIZE, 9, 'f' },
11975 { RLIMIT_DATA, 10, 'd' },
11977 #ifdef RLIMIT_STACK
11978 { RLIMIT_STACK, 10, 's' },
11981 { RLIMIT_CORE, 9, 'c' },
11984 { RLIMIT_RSS, 10, 'm' },
11986 #ifdef RLIMIT_MEMLOCK
11987 { RLIMIT_MEMLOCK, 10, 'l' },
11989 #ifdef RLIMIT_NPROC
11990 { RLIMIT_NPROC, 0, 'p' },
11992 #ifdef RLIMIT_NOFILE
11993 { RLIMIT_NOFILE, 0, 'n' },
11996 { RLIMIT_AS, 10, 'v' },
11998 #ifdef RLIMIT_LOCKS
11999 { RLIMIT_LOCKS, 0, 'w' },
12002 static const char limits_name[] =
12004 "time(seconds)" "\0"
12006 #ifdef RLIMIT_FSIZE
12007 "file(blocks)" "\0"
12012 #ifdef RLIMIT_STACK
12016 "coredump(blocks)" "\0"
12021 #ifdef RLIMIT_MEMLOCK
12022 "locked memory(kb)" "\0"
12024 #ifdef RLIMIT_NPROC
12027 #ifdef RLIMIT_NOFILE
12033 #ifdef RLIMIT_LOCKS
12038 enum limtype { SOFT = 0x1, HARD = 0x2 };
12041 printlim(enum limtype how, const struct rlimit *limit,
12042 const struct limits *l)
12046 val = limit->rlim_max;
12048 val = limit->rlim_cur;
12050 if (val == RLIM_INFINITY)
12051 out1fmt("unlimited\n");
12053 val >>= l->factor_shift;
12054 out1fmt("%lld\n", (long long) val);
12059 ulimitcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
12063 enum limtype how = SOFT | HARD;
12064 const struct limits *l;
12067 struct rlimit limit;
12070 while ((optc = nextopt("HSa"
12074 #ifdef RLIMIT_FSIZE
12080 #ifdef RLIMIT_STACK
12089 #ifdef RLIMIT_MEMLOCK
12092 #ifdef RLIMIT_NPROC
12095 #ifdef RLIMIT_NOFILE
12101 #ifdef RLIMIT_LOCKS
12119 for (l = limits_tbl; l->option != what; l++)
12122 set = *argptr ? 1 : 0;
12126 if (all || argptr[1])
12127 ash_msg_and_raise_error("too many arguments");
12128 if (strncmp(p, "unlimited\n", 9) == 0)
12129 val = RLIM_INFINITY;
12133 while ((c = *p++) >= '0' && c <= '9') {
12134 val = (val * 10) + (long)(c - '0');
12135 if (val < (rlim_t) 0)
12139 ash_msg_and_raise_error("bad number");
12140 val <<= l->factor_shift;
12144 const char *lname = limits_name;
12145 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12146 getrlimit(l->cmd, &limit);
12147 out1fmt("%-20s ", lname);
12148 lname += strlen(lname) + 1;
12149 printlim(how, &limit, l);
12154 getrlimit(l->cmd, &limit);
12157 limit.rlim_max = val;
12159 limit.rlim_cur = val;
12160 if (setrlimit(l->cmd, &limit) < 0)
12161 ash_msg_and_raise_error("error setting limit (%m)");
12163 printlim(how, &limit, l);
12169 /* ============ Math support */
12171 #if ENABLE_ASH_MATH_SUPPORT
12173 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12175 Permission is hereby granted, free of charge, to any person obtaining
12176 a copy of this software and associated documentation files (the
12177 "Software"), to deal in the Software without restriction, including
12178 without limitation the rights to use, copy, modify, merge, publish,
12179 distribute, sublicense, and/or sell copies of the Software, and to
12180 permit persons to whom the Software is furnished to do so, subject to
12181 the following conditions:
12183 The above copyright notice and this permission notice shall be
12184 included in all copies or substantial portions of the Software.
12186 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12187 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12188 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12189 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12190 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12191 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12192 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12195 /* This is my infix parser/evaluator. It is optimized for size, intended
12196 * as a replacement for yacc-based parsers. However, it may well be faster
12197 * than a comparable parser written in yacc. The supported operators are
12198 * listed in #defines below. Parens, order of operations, and error handling
12199 * are supported. This code is thread safe. The exact expression format should
12200 * be that which POSIX specifies for shells. */
12202 /* The code uses a simple two-stack algorithm. See
12203 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12204 * for a detailed explanation of the infix-to-postfix algorithm on which
12205 * this is based (this code differs in that it applies operators immediately
12206 * to the stack instead of adding them to a queue to end up with an
12209 /* To use the routine, call it with an expression string and error return
12213 * Aug 24, 2001 Manuel Novoa III
12215 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12217 * 1) In arith_apply():
12218 * a) Cached values of *numptr and &(numptr[-1]).
12219 * b) Removed redundant test for zero denominator.
12222 * a) Eliminated redundant code for processing operator tokens by moving
12223 * to a table-based implementation. Also folded handling of parens
12225 * b) Combined all 3 loops which called arith_apply to reduce generated
12226 * code size at the cost of speed.
12228 * 3) The following expressions were treated as valid by the original code:
12229 * 1() , 0! , 1 ( *3 ) .
12230 * These bugs have been fixed by internally enclosing the expression in
12231 * parens and then checking that all binary ops and right parens are
12232 * preceded by a valid expression (NUM_TOKEN).
12234 * Note: It may be desirable to replace Aaron's test for whitespace with
12235 * ctype's isspace() if it is used by another busybox applet or if additional
12236 * whitespace chars should be considered. Look below the "#include"s for a
12237 * precompiler test.
12241 * Aug 26, 2001 Manuel Novoa III
12243 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12245 * Merge in Aaron's comments previously posted to the busybox list,
12246 * modified slightly to take account of my changes to the code.
12251 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12253 * - allow access to variable,
12254 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12255 * - realize assign syntax (VAR=expr, +=, *= etc)
12256 * - realize exponentiation (** operator)
12257 * - realize comma separated - expr, expr
12258 * - realise ++expr --expr expr++ expr--
12259 * - realise expr ? expr : expr (but, second expr calculate always)
12260 * - allow hexadecimal and octal numbers
12261 * - was restored loses XOR operator
12262 * - remove one goto label, added three ;-)
12263 * - protect $((num num)) as true zero expr (Manuel`s error)
12264 * - always use special isspace(), see comment from bash ;-)
12267 #define arith_isspace(arithval) \
12268 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12270 typedef unsigned char operator;
12272 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12273 * precedence, and 3 high bits are an ID unique across operators of that
12274 * precedence. The ID portion is so that multiple operators can have the
12275 * same precedence, ensuring that the leftmost one is evaluated first.
12276 * Consider * and /. */
12278 #define tok_decl(prec,id) (((id)<<5)|(prec))
12279 #define PREC(op) ((op) & 0x1F)
12281 #define TOK_LPAREN tok_decl(0,0)
12283 #define TOK_COMMA tok_decl(1,0)
12285 #define TOK_ASSIGN tok_decl(2,0)
12286 #define TOK_AND_ASSIGN tok_decl(2,1)
12287 #define TOK_OR_ASSIGN tok_decl(2,2)
12288 #define TOK_XOR_ASSIGN tok_decl(2,3)
12289 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12290 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12291 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12292 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12294 #define TOK_MUL_ASSIGN tok_decl(3,0)
12295 #define TOK_DIV_ASSIGN tok_decl(3,1)
12296 #define TOK_REM_ASSIGN tok_decl(3,2)
12298 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12299 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12301 /* conditional is right associativity too */
12302 #define TOK_CONDITIONAL tok_decl(4,0)
12303 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12305 #define TOK_OR tok_decl(5,0)
12307 #define TOK_AND tok_decl(6,0)
12309 #define TOK_BOR tok_decl(7,0)
12311 #define TOK_BXOR tok_decl(8,0)
12313 #define TOK_BAND tok_decl(9,0)
12315 #define TOK_EQ tok_decl(10,0)
12316 #define TOK_NE tok_decl(10,1)
12318 #define TOK_LT tok_decl(11,0)
12319 #define TOK_GT tok_decl(11,1)
12320 #define TOK_GE tok_decl(11,2)
12321 #define TOK_LE tok_decl(11,3)
12323 #define TOK_LSHIFT tok_decl(12,0)
12324 #define TOK_RSHIFT tok_decl(12,1)
12326 #define TOK_ADD tok_decl(13,0)
12327 #define TOK_SUB tok_decl(13,1)
12329 #define TOK_MUL tok_decl(14,0)
12330 #define TOK_DIV tok_decl(14,1)
12331 #define TOK_REM tok_decl(14,2)
12333 /* exponent is right associativity */
12334 #define TOK_EXPONENT tok_decl(15,1)
12336 /* For now unary operators. */
12337 #define UNARYPREC 16
12338 #define TOK_BNOT tok_decl(UNARYPREC,0)
12339 #define TOK_NOT tok_decl(UNARYPREC,1)
12341 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12342 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12344 #define PREC_PRE (UNARYPREC+2)
12346 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12347 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12349 #define PREC_POST (UNARYPREC+3)
12351 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12352 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12354 #define SPEC_PREC (UNARYPREC+4)
12356 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12357 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12359 #define NUMPTR (*numstackptr)
12362 tok_have_assign(operator op)
12364 operator prec = PREC(op);
12366 convert_prec_is_assing(prec);
12367 return (prec == PREC(TOK_ASSIGN) ||
12368 prec == PREC_PRE || prec == PREC_POST);
12372 is_right_associativity(operator prec)
12374 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
12375 || prec == PREC(TOK_CONDITIONAL));
12378 typedef struct ARITCH_VAR_NUM {
12380 arith_t contidional_second_val;
12381 char contidional_second_val_initialized;
12382 char *var; /* if NULL then is regular number,
12383 else is variable name */
12386 typedef struct CHK_VAR_RECURSIVE_LOOPED {
12388 struct CHK_VAR_RECURSIVE_LOOPED *next;
12389 } chk_var_recursive_looped_t;
12391 static chk_var_recursive_looped_t *prev_chk_var_recursive;
12394 arith_lookup_val(v_n_t *t)
12397 const char * p = lookupvar(t->var);
12402 /* recursive try as expression */
12403 chk_var_recursive_looped_t *cur;
12404 chk_var_recursive_looped_t cur_save;
12406 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
12407 if (strcmp(cur->var, t->var) == 0) {
12408 /* expression recursion loop detected */
12412 /* save current lookuped var name */
12413 cur = prev_chk_var_recursive;
12414 cur_save.var = t->var;
12415 cur_save.next = cur;
12416 prev_chk_var_recursive = &cur_save;
12418 t->val = arith (p, &errcode);
12419 /* restore previous ptr after recursiving */
12420 prev_chk_var_recursive = cur;
12423 /* allow undefined var as 0 */
12429 /* "applying" a token means performing it on the top elements on the integer
12430 * stack. For a unary operator it will only change the top element, but a
12431 * binary operator will pop two arguments and push a result */
12433 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
12436 arith_t numptr_val, rez;
12437 int ret_arith_lookup_val;
12439 /* There is no operator that can work without arguments */
12440 if (NUMPTR == numstack) goto err;
12441 numptr_m1 = NUMPTR - 1;
12443 /* check operand is var with noninteger value */
12444 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12445 if (ret_arith_lookup_val)
12446 return ret_arith_lookup_val;
12448 rez = numptr_m1->val;
12449 if (op == TOK_UMINUS)
12451 else if (op == TOK_NOT)
12453 else if (op == TOK_BNOT)
12455 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
12457 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
12459 else if (op != TOK_UPLUS) {
12460 /* Binary operators */
12462 /* check and binary operators need two arguments */
12463 if (numptr_m1 == numstack) goto err;
12465 /* ... and they pop one */
12468 if (op == TOK_CONDITIONAL) {
12469 if (! numptr_m1->contidional_second_val_initialized) {
12470 /* protect $((expr1 ? expr2)) without ": expr" */
12473 rez = numptr_m1->contidional_second_val;
12474 } else if (numptr_m1->contidional_second_val_initialized) {
12475 /* protect $((expr1 : expr2)) without "expr ? " */
12478 numptr_m1 = NUMPTR - 1;
12479 if (op != TOK_ASSIGN) {
12480 /* check operand is var with noninteger value for not '=' */
12481 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12482 if (ret_arith_lookup_val)
12483 return ret_arith_lookup_val;
12485 if (op == TOK_CONDITIONAL) {
12486 numptr_m1->contidional_second_val = rez;
12488 rez = numptr_m1->val;
12489 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
12491 else if (op == TOK_OR)
12492 rez = numptr_val || rez;
12493 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
12495 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
12497 else if (op == TOK_AND)
12498 rez = rez && numptr_val;
12499 else if (op == TOK_EQ)
12500 rez = (rez == numptr_val);
12501 else if (op == TOK_NE)
12502 rez = (rez != numptr_val);
12503 else if (op == TOK_GE)
12504 rez = (rez >= numptr_val);
12505 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
12506 rez >>= numptr_val;
12507 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
12508 rez <<= numptr_val;
12509 else if (op == TOK_GT)
12510 rez = (rez > numptr_val);
12511 else if (op == TOK_LT)
12512 rez = (rez < numptr_val);
12513 else if (op == TOK_LE)
12514 rez = (rez <= numptr_val);
12515 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
12517 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
12519 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
12521 else if (op == TOK_ASSIGN || op == TOK_COMMA)
12523 else if (op == TOK_CONDITIONAL_SEP) {
12524 if (numptr_m1 == numstack) {
12525 /* protect $((expr : expr)) without "expr ? " */
12528 numptr_m1->contidional_second_val_initialized = op;
12529 numptr_m1->contidional_second_val = numptr_val;
12530 } else if (op == TOK_CONDITIONAL) {
12532 numptr_val : numptr_m1->contidional_second_val;
12533 } else if (op == TOK_EXPONENT) {
12534 if (numptr_val < 0)
12535 return -3; /* exponent less than 0 */
12540 while (numptr_val--)
12544 } else if (numptr_val==0) /* zero divisor check */
12546 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
12548 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
12551 if (tok_have_assign(op)) {
12552 char buf[sizeof(arith_t_type)*3 + 2];
12554 if (numptr_m1->var == NULL) {
12558 /* save to shell variable */
12559 #if ENABLE_ASH_MATH_SUPPORT_64
12560 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
12562 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
12564 setvar(numptr_m1->var, buf, 0);
12565 /* after saving, make previous value for v++ or v-- */
12566 if (op == TOK_POST_INC)
12568 else if (op == TOK_POST_DEC)
12571 numptr_m1->val = rez;
12572 /* protect geting var value, is number now */
12573 numptr_m1->var = NULL;
12579 /* longest must be first */
12580 static const char op_tokens[] ALIGN1 = {
12581 '<','<','=',0, TOK_LSHIFT_ASSIGN,
12582 '>','>','=',0, TOK_RSHIFT_ASSIGN,
12583 '<','<', 0, TOK_LSHIFT,
12584 '>','>', 0, TOK_RSHIFT,
12585 '|','|', 0, TOK_OR,
12586 '&','&', 0, TOK_AND,
12587 '!','=', 0, TOK_NE,
12588 '<','=', 0, TOK_LE,
12589 '>','=', 0, TOK_GE,
12590 '=','=', 0, TOK_EQ,
12591 '|','=', 0, TOK_OR_ASSIGN,
12592 '&','=', 0, TOK_AND_ASSIGN,
12593 '*','=', 0, TOK_MUL_ASSIGN,
12594 '/','=', 0, TOK_DIV_ASSIGN,
12595 '%','=', 0, TOK_REM_ASSIGN,
12596 '+','=', 0, TOK_PLUS_ASSIGN,
12597 '-','=', 0, TOK_MINUS_ASSIGN,
12598 '-','-', 0, TOK_POST_DEC,
12599 '^','=', 0, TOK_XOR_ASSIGN,
12600 '+','+', 0, TOK_POST_INC,
12601 '*','*', 0, TOK_EXPONENT,
12605 '=', 0, TOK_ASSIGN,
12617 '?', 0, TOK_CONDITIONAL,
12618 ':', 0, TOK_CONDITIONAL_SEP,
12619 ')', 0, TOK_RPAREN,
12620 '(', 0, TOK_LPAREN,
12624 #define endexpression &op_tokens[sizeof(op_tokens)-7]
12627 arith(const char *expr, int *perrcode)
12629 char arithval; /* Current character under analysis */
12630 operator lasttok, op;
12633 const char *p = endexpression;
12636 size_t datasizes = strlen(expr) + 2;
12638 /* Stack of integers */
12639 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
12640 * in any given correct or incorrect expression is left as an exercise to
12642 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
12643 *numstackptr = numstack;
12644 /* Stack of operator tokens */
12645 operator *stack = alloca((datasizes) * sizeof(operator)),
12648 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
12649 *perrcode = errcode = 0;
12653 if (arithval == 0) {
12654 if (p == endexpression) {
12655 /* Null expression. */
12659 /* This is only reached after all tokens have been extracted from the
12660 * input stream. If there are still tokens on the operator stack, they
12661 * are to be applied in order. At the end, there should be a final
12662 * result on the integer stack */
12664 if (expr != endexpression + 1) {
12665 /* If we haven't done so already, */
12666 /* append a closing right paren */
12667 expr = endexpression;
12668 /* and let the loop process it. */
12671 /* At this point, we're done with the expression. */
12672 if (numstackptr != numstack+1) {
12673 /* ... but if there isn't, it's bad */
12675 return (*perrcode = -1);
12677 if (numstack->var) {
12678 /* expression is $((var)) only, lookup now */
12679 errcode = arith_lookup_val(numstack);
12682 *perrcode = errcode;
12683 return numstack->val;
12686 /* Continue processing the expression. */
12687 if (arith_isspace(arithval)) {
12688 /* Skip whitespace */
12691 p = endofname(expr);
12693 size_t var_name_size = (p-expr) + 1; /* trailing zero */
12695 numstackptr->var = alloca(var_name_size);
12696 safe_strncpy(numstackptr->var, expr, var_name_size);
12699 numstackptr->contidional_second_val_initialized = 0;
12704 if (isdigit(arithval)) {
12705 numstackptr->var = NULL;
12706 #if ENABLE_ASH_MATH_SUPPORT_64
12707 numstackptr->val = strtoll(expr, (char **) &expr, 0);
12709 numstackptr->val = strtol(expr, (char **) &expr, 0);
12713 for (p = op_tokens; ; p++) {
12717 /* strange operator not found */
12720 for (o = expr; *p && *o == *p; p++)
12727 /* skip tail uncompared token */
12730 /* skip zero delim */
12735 /* post grammar: a++ reduce to num */
12736 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
12739 /* Plus and minus are binary (not unary) _only_ if the last
12740 * token was as number, or a right paren (which pretends to be
12741 * a number, since it evaluates to one). Think about it.
12742 * It makes sense. */
12743 if (lasttok != TOK_NUM) {
12759 /* We don't want a unary operator to cause recursive descent on the
12760 * stack, because there can be many in a row and it could cause an
12761 * operator to be evaluated before its argument is pushed onto the
12762 * integer stack. */
12763 /* But for binary operators, "apply" everything on the operator
12764 * stack until we find an operator with a lesser priority than the
12765 * one we have just extracted. */
12766 /* Left paren is given the lowest priority so it will never be
12767 * "applied" in this way.
12768 * if associativity is right and priority eq, applied also skip
12771 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
12772 /* not left paren or unary */
12773 if (lasttok != TOK_NUM) {
12774 /* binary op must be preceded by a num */
12777 while (stackptr != stack) {
12778 if (op == TOK_RPAREN) {
12779 /* The algorithm employed here is simple: while we don't
12780 * hit an open paren nor the bottom of the stack, pop
12781 * tokens and apply them */
12782 if (stackptr[-1] == TOK_LPAREN) {
12784 /* Any operator directly after a */
12786 /* close paren should consider itself binary */
12790 operator prev_prec = PREC(stackptr[-1]);
12792 convert_prec_is_assing(prec);
12793 convert_prec_is_assing(prev_prec);
12794 if (prev_prec < prec)
12796 /* check right assoc */
12797 if (prev_prec == prec && is_right_associativity(prec))
12800 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
12801 if (errcode) goto ret;
12803 if (op == TOK_RPAREN) {
12808 /* Push this operator to the stack and remember it. */
12809 *stackptr++ = lasttok = op;
12814 #endif /* ASH_MATH_SUPPORT */
12817 /* ============ main() and helpers */
12820 * Called to exit the shell.
12822 static void exitshell(void) ATTRIBUTE_NORETURN;
12830 status = exitstatus;
12831 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12832 if (setjmp(loc.loc)) {
12833 if (exception == EXEXIT)
12834 /* dash bug: it just does _exit(exitstatus) here
12835 * but we have to do setjobctl(0) first!
12836 * (bug is still not fixed in dash-0.5.3 - if you run dash
12837 * under Midnight Commander, on exit from dash MC is backgrounded) */
12838 status = exitstatus;
12841 exception_handler = &loc;
12847 flush_stdout_stderr();
12857 /* from input.c: */
12858 basepf.nextc = basepf.buf = basebuf;
12861 signal(SIGCHLD, SIG_DFL);
12866 char ppid[sizeof(int)*3 + 1];
12868 struct stat st1, st2;
12871 for (envp = environ; envp && *envp; envp++) {
12872 if (strchr(*envp, '=')) {
12873 setvareq(*envp, VEXPORT|VTEXTFIXED);
12877 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
12878 setvar("PPID", ppid, 0);
12880 p = lookupvar("PWD");
12882 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
12883 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
12890 * Process the shell command line arguments.
12893 procargs(char **argv)
12896 const char *xminusc;
12901 /* if (xargv[0]) - mmm, this is always true! */
12903 for (i = 0; i < NOPTS; i++)
12907 /* it already printed err message */
12908 raise_exception(EXERROR);
12912 if (*xargv == NULL) {
12914 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
12917 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
12921 for (i = 0; i < NOPTS; i++)
12922 if (optlist[i] == 2)
12927 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
12932 } else if (!sflag) {
12933 setinputfile(*xargv, 0);
12936 commandname = arg0;
12939 shellparam.p = xargv;
12940 #if ENABLE_ASH_GETOPTS
12941 shellparam.optind = 1;
12942 shellparam.optoff = -1;
12944 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
12946 shellparam.nparam++;
12953 * Read /etc/profile or .profile.
12956 read_profile(const char *name)
12960 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
12969 * This routine is called when an error or an interrupt occurs in an
12970 * interactive shell and control is returned to the main command loop.
12978 /* from input.c: */
12979 parselleft = parsenleft = 0; /* clear input buffer */
12981 /* from parser.c: */
12984 /* from redir.c: */
12989 static short profile_buf[16384];
12990 extern int etext();
12994 * Main routine. We initialize things, parse the arguments, execute
12995 * profiles if we're a login shell, and then call cmdloop to execute
12996 * commands. The setjmp call sets up the location to jump to when an
12997 * exception occurs. When an exception occurs the variable "state"
12998 * is used to figure out how far we had gotten.
13000 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13001 int ash_main(int argc ATTRIBUTE_UNUSED, char **argv)
13004 volatile int state;
13005 struct jmploc jmploc;
13006 struct stackmark smark;
13008 /* Initialize global data */
13012 #if ENABLE_ASH_ALIAS
13018 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13021 #if ENABLE_FEATURE_EDITING
13022 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13025 if (setjmp(jmploc.loc)) {
13035 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13039 outcslow('\n', stderr);
13041 popstackmark(&smark);
13042 FORCE_INT_ON; /* enable interrupts */
13051 exception_handler = &jmploc;
13054 trace_puts("Shell args: ");
13055 trace_puts_args(argv);
13057 rootpid = getpid();
13059 #if ENABLE_ASH_RANDOM_SUPPORT
13060 rseed = rootpid + time(NULL);
13063 setstackmark(&smark);
13066 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13068 const char *hp = lookupvar("HISTFILE");
13071 hp = lookupvar("HOME");
13073 char *defhp = concat_path_file(hp, ".ash_history");
13074 setvar("HISTFILE", defhp, 0);
13080 if (argv[0] && argv[0][0] == '-')
13084 read_profile("/etc/profile");
13087 read_profile(".profile");
13093 getuid() == geteuid() && getgid() == getegid() &&
13097 shinit = lookupvar("ENV");
13098 if (shinit != NULL && *shinit != '\0') {
13099 read_profile(shinit);
13105 evalstring(minusc, 0);
13107 if (sflag || minusc == NULL) {
13108 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13110 const char *hp = lookupvar("HISTFILE");
13113 line_input_state->hist_file = hp;
13116 state4: /* XXX ??? - why isn't this before the "if" statement */
13124 extern void _mcleanup(void);
13133 const char *applet_name = "debug stuff usage";
13134 int main(int argc, char **argv)
13136 return ash_main(argc, argv);
13142 * Copyright (c) 1989, 1991, 1993, 1994
13143 * The Regents of the University of California. All rights reserved.
13145 * This code is derived from software contributed to Berkeley by
13146 * Kenneth Almquist.
13148 * Redistribution and use in source and binary forms, with or without
13149 * modification, are permitted provided that the following conditions
13151 * 1. Redistributions of source code must retain the above copyright
13152 * notice, this list of conditions and the following disclaimer.
13153 * 2. Redistributions in binary form must reproduce the above copyright
13154 * notice, this list of conditions and the following disclaimer in the
13155 * documentation and/or other materials provided with the distribution.
13156 * 3. Neither the name of the University nor the names of its contributors
13157 * may be used to endorse or promote products derived from this software
13158 * without specific prior written permission.
13160 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13161 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13162 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13163 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13164 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13165 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13166 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13167 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13168 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13169 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF