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 /* Make it reside in writable memory, yet make compiler understand that it is not going to change. */
206 static struct globals_misc *const ptr_to_globals_misc __attribute__ ((section (".data")));
207 #define G_misc (*ptr_to_globals_misc)
208 #define rootpid (G_misc.rootpid )
209 #define shlvl (G_misc.shlvl )
210 #define minusc (G_misc.minusc )
211 #define curdir (G_misc.curdir )
212 #define physdir (G_misc.physdir )
213 #define arg0 (G_misc.arg0 )
214 #define exception_handler (G_misc.exception_handler)
215 #define exception (G_misc.exception )
216 #define suppressint (G_misc.suppressint )
217 #define intpending (G_misc.intpending )
218 //#define exsig (G_misc.exsig )
219 #define pendingsig (G_misc.pendingsig )
220 #define trap (G_misc.trap )
221 #define isloginsh (G_misc.isloginsh)
222 #define nullstr (G_misc.nullstr )
223 #define sigmode (G_misc.sigmode )
224 #define gotsig (G_misc.gotsig )
225 #define INIT_G_misc() do { \
226 (*(struct globals_misc**)&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)
279 /* Signal is not automatically unmasked after it is raised,
280 * do it ourself - unmask all signals */
282 sigprocmask(SIG_SETMASK, &mask, NULL);
283 /* pendingsig = 0; - now done in onsig() */
286 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
287 if (!(rootshell && iflag)) {
288 /* Kill ourself with SIGINT */
289 signal(SIGINT, SIG_DFL);
298 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
302 if (--suppressint == 0 && intpending) {
306 #define INT_ON int_on()
314 #define FORCE_INT_ON force_int_on()
319 if (--suppressint == 0 && intpending) \
322 #define FORCE_INT_ON \
329 #endif /* ASH_OPTIMIZE_FOR_SIZE */
331 #define SAVE_INT(v) ((v) = suppressint)
333 #define RESTORE_INT(v) \
337 if (suppressint == 0 && intpending) \
342 * Ignore a signal. Only one usage site - in forkchild()
347 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
348 signal(signo, SIG_IGN);
350 sigmode[signo - 1] = S_HARD_IGN;
354 * Signal handler. Only one usage site - in setsignal()
359 gotsig[signo - 1] = 1;
362 if ( /* exsig || */ (signo == SIGINT && !trap[SIGINT])) {
365 raise_interrupt(); /* does not return */
372 /* ============ Stdout/stderr output */
375 outstr(const char *p, FILE *file)
383 flush_stdout_stderr(void)
400 outcslow(int c, FILE *dest)
408 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
410 out1fmt(const char *fmt, ...)
417 r = vprintf(fmt, ap);
423 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
425 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
432 ret = vsnprintf(outbuf, length, fmt, ap);
439 out1str(const char *p)
445 out2str(const char *p)
452 /* ============ Parser structures */
454 /* control characters in argument strings */
455 #define CTLESC '\201' /* escape next character */
456 #define CTLVAR '\202' /* variable defn */
457 #define CTLENDVAR '\203'
458 #define CTLBACKQ '\204'
459 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
460 /* CTLBACKQ | CTLQUOTE == '\205' */
461 #define CTLARI '\206' /* arithmetic expression */
462 #define CTLENDARI '\207'
463 #define CTLQUOTEMARK '\210'
465 /* variable substitution byte (follows CTLVAR) */
466 #define VSTYPE 0x0f /* type of variable substitution */
467 #define VSNUL 0x10 /* colon--treat the empty string as unset */
468 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
470 /* values of VSTYPE field */
471 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
472 #define VSMINUS 0x2 /* ${var-text} */
473 #define VSPLUS 0x3 /* ${var+text} */
474 #define VSQUESTION 0x4 /* ${var?message} */
475 #define VSASSIGN 0x5 /* ${var=text} */
476 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
477 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
478 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
479 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
480 #define VSLENGTH 0xa /* ${#var} */
482 static const char dolatstr[] ALIGN1 = {
483 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
519 union node *redirect;
525 struct nodelist *cmdlist;
531 union node *redirect;
544 union node *elsepart;
571 struct nodelist *backquote;
606 struct nredir nredir;
607 struct nbinary nbinary;
611 struct nclist nclist;
620 struct nodelist *next;
633 freefunc(struct funcnode *f)
635 if (f && --f->count < 0)
640 /* ============ Debugging output */
644 static FILE *tracefile;
647 trace_printf(const char *fmt, ...)
654 vfprintf(tracefile, fmt, va);
659 trace_vprintf(const char *fmt, va_list va)
663 vfprintf(tracefile, fmt, va);
667 trace_puts(const char *s)
675 trace_puts_quoted(char *s)
682 putc('"', tracefile);
683 for (p = s; *p; p++) {
685 case '\n': c = 'n'; goto backslash;
686 case '\t': c = 't'; goto backslash;
687 case '\r': c = 'r'; goto backslash;
688 case '"': c = '"'; goto backslash;
689 case '\\': c = '\\'; goto backslash;
690 case CTLESC: c = 'e'; goto backslash;
691 case CTLVAR: c = 'v'; goto backslash;
692 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
693 case CTLBACKQ: c = 'q'; goto backslash;
694 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
696 putc('\\', tracefile);
700 if (*p >= ' ' && *p <= '~')
703 putc('\\', tracefile);
704 putc(*p >> 6 & 03, tracefile);
705 putc(*p >> 3 & 07, tracefile);
706 putc(*p & 07, tracefile);
711 putc('"', tracefile);
715 trace_puts_args(char **ap)
722 trace_puts_quoted(*ap);
724 putc('\n', tracefile);
727 putc(' ', tracefile);
742 /* leave open because libedit might be using it */
745 strcpy(s, "./trace");
747 if (!freopen(s, "a", tracefile)) {
748 fprintf(stderr, "Can't re-open %s\n", s);
753 tracefile = fopen(s, "a");
754 if (tracefile == NULL) {
755 fprintf(stderr, "Can't open %s\n", s);
761 flags = fcntl(fileno(tracefile), F_GETFL);
763 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
765 setlinebuf(tracefile);
766 fputs("\nTracing started.\n", tracefile);
770 indent(int amount, char *pfx, FILE *fp)
774 for (i = 0; i < amount; i++) {
775 if (pfx && i == amount - 1)
781 /* little circular references here... */
782 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
785 sharg(union node *arg, FILE *fp)
788 struct nodelist *bqlist;
791 if (arg->type != NARG) {
792 out1fmt("<node type %d>\n", arg->type);
795 bqlist = arg->narg.backquote;
796 for (p = arg->narg.text; *p; p++) {
805 if (subtype == VSLENGTH)
814 switch (subtype & VSTYPE) {
847 out1fmt("<subtype %d>", subtype);
854 case CTLBACKQ|CTLQUOTE:
857 shtree(bqlist->n, -1, NULL, fp);
868 shcmd(union node *cmd, FILE *fp)
876 for (np = cmd->ncmd.args; np; np = np->narg.next) {
882 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
886 switch (np->nfile.type) {
887 case NTO: s = ">>"+1; dftfd = 1; break;
888 case NCLOBBER: s = ">|"; dftfd = 1; break;
889 case NAPPEND: s = ">>"; dftfd = 1; break;
890 case NTOFD: s = ">&"; dftfd = 1; break;
891 case NFROM: s = "<"; break;
892 case NFROMFD: s = "<&"; break;
893 case NFROMTO: s = "<>"; break;
894 default: s = "*error*"; break;
896 if (np->nfile.fd != dftfd)
897 fprintf(fp, "%d", np->nfile.fd);
899 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
900 fprintf(fp, "%d", np->ndup.dupfd);
902 sharg(np->nfile.fname, fp);
909 shtree(union node *n, int ind, char *pfx, FILE *fp)
917 indent(ind, pfx, fp);
928 shtree(n->nbinary.ch1, ind, NULL, fp);
931 shtree(n->nbinary.ch2, ind, NULL, fp);
939 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
944 if (n->npipe.backgnd)
950 fprintf(fp, "<node type %d>", n->type);
958 showtree(union node *n)
960 trace_puts("showtree called\n");
961 shtree(n, 1, NULL, stdout);
964 #define TRACE(param) trace_printf param
965 #define TRACEV(param) trace_vprintf param
970 #define TRACEV(param)
975 /* ============ Parser data */
978 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
981 struct strlist *next;
990 struct strpush *prev; /* preceding string on stack */
994 struct alias *ap; /* if push was associated with an alias */
996 char *string; /* remember the string since it may change */
1000 struct parsefile *prev; /* preceding file on stack */
1001 int linno; /* current line */
1002 int fd; /* file descriptor (or -1 if string) */
1003 int nleft; /* number of chars left in this line */
1004 int lleft; /* number of chars left in this buffer */
1005 char *nextc; /* next char in buffer */
1006 char *buf; /* input buffer */
1007 struct strpush *strpush; /* for pushing strings at this level */
1008 struct strpush basestrpush; /* so pushing one is fast */
1011 static struct parsefile basepf; /* top level input file */
1012 static struct parsefile *parsefile = &basepf; /* current input file */
1013 static int startlinno; /* line # where last token started */
1014 static char *commandname; /* currently executing command */
1015 static struct strlist *cmdenviron; /* environment for builtin command */
1016 static int exitstatus; /* exit status of last command */
1019 /* ============ Message printing */
1022 ash_vmsg(const char *msg, va_list ap)
1024 fprintf(stderr, "%s: ", arg0);
1026 if (strcmp(arg0, commandname))
1027 fprintf(stderr, "%s: ", commandname);
1028 if (!iflag || parsefile->fd)
1029 fprintf(stderr, "line %d: ", startlinno);
1031 vfprintf(stderr, msg, ap);
1032 outcslow('\n', stderr);
1036 * Exverror is called to raise the error exception. If the second argument
1037 * is not NULL then error prints an error message using printf style
1038 * formatting. It then raises the error exception.
1040 static void ash_vmsg_and_raise(int, const char *, va_list) ATTRIBUTE_NORETURN;
1042 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1046 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1048 TRACE(("\") pid=%d\n", getpid()));
1050 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1055 flush_stdout_stderr();
1056 raise_exception(cond);
1060 static void ash_msg_and_raise_error(const char *, ...) ATTRIBUTE_NORETURN;
1062 ash_msg_and_raise_error(const char *msg, ...)
1067 ash_vmsg_and_raise(EXERROR, msg, ap);
1072 static void ash_msg_and_raise(int, const char *, ...) ATTRIBUTE_NORETURN;
1074 ash_msg_and_raise(int cond, const char *msg, ...)
1079 ash_vmsg_and_raise(cond, msg, ap);
1085 * error/warning routines for external builtins
1088 ash_msg(const char *fmt, ...)
1098 * Return a string describing an error. The returned string may be a
1099 * pointer to a static buffer that will be overwritten on the next call.
1100 * Action describes the operation that got the error.
1103 errmsg(int e, const char *em)
1105 if (e == ENOENT || e == ENOTDIR) {
1112 /* ============ Memory allocation */
1115 * It appears that grabstackstr() will barf with such alignments
1116 * because stalloc() will return a string allocated in a new stackblock.
1118 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1120 /* Most machines require the value returned from malloc to be aligned
1121 * in some way. The following macro will get this right
1122 * on many machines. */
1123 SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,
1124 /* Minimum size of a block */
1125 MINSIZE = SHELL_ALIGN(504),
1128 struct stack_block {
1129 struct stack_block *prev;
1130 char space[MINSIZE];
1134 struct stack_block *stackp;
1137 struct stackmark *marknext;
1141 struct globals_memstack {
1142 struct stack_block *g_stackp; // = &stackbase;
1143 struct stackmark *markp;
1144 char *g_stacknxt; // = stackbase.space;
1145 char *sstrend; // = stackbase.space + MINSIZE;
1146 size_t g_stacknleft; // = MINSIZE;
1147 int herefd; // = -1;
1148 struct stack_block stackbase;
1150 /* Make it reside in writable memory, yet make compiler understand that it is not going to change. */
1151 static struct globals_memstack *const ptr_to_globals_memstack __attribute__ ((section (".data")));
1152 #define G_memstack (*ptr_to_globals_memstack)
1153 #define g_stackp (G_memstack.g_stackp )
1154 #define markp (G_memstack.markp )
1155 #define g_stacknxt (G_memstack.g_stacknxt )
1156 #define sstrend (G_memstack.sstrend )
1157 #define g_stacknleft (G_memstack.g_stacknleft)
1158 #define herefd (G_memstack.herefd )
1159 #define stackbase (G_memstack.stackbase )
1160 #define INIT_G_memstack() do { \
1161 (*(struct globals_memstack**)&ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1162 g_stackp = &stackbase; \
1163 g_stacknxt = stackbase.space; \
1164 g_stacknleft = MINSIZE; \
1165 sstrend = stackbase.space + MINSIZE; \
1169 #define stackblock() ((void *)g_stacknxt)
1170 #define stackblocksize() g_stacknleft
1174 ckrealloc(void * p, size_t nbytes)
1176 p = realloc(p, nbytes);
1178 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1183 ckmalloc(size_t nbytes)
1185 return ckrealloc(NULL, nbytes);
1189 ckzalloc(size_t nbytes)
1191 return memset(ckmalloc(nbytes), 0, nbytes);
1195 * Make a copy of a string in safe storage.
1198 ckstrdup(const char *s)
1200 char *p = strdup(s);
1202 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1207 * Parse trees for commands are allocated in lifo order, so we use a stack
1208 * to make this more efficient, and also to avoid all sorts of exception
1209 * handling code to handle interrupts in the middle of a parse.
1211 * The size 504 was chosen because the Ultrix malloc handles that size
1215 stalloc(size_t nbytes)
1220 aligned = SHELL_ALIGN(nbytes);
1221 if (aligned > g_stacknleft) {
1224 struct stack_block *sp;
1226 blocksize = aligned;
1227 if (blocksize < MINSIZE)
1228 blocksize = MINSIZE;
1229 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1230 if (len < blocksize)
1231 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1234 sp->prev = g_stackp;
1235 g_stacknxt = sp->space;
1236 g_stacknleft = blocksize;
1237 sstrend = g_stacknxt + blocksize;
1242 g_stacknxt += aligned;
1243 g_stacknleft -= aligned;
1248 stzalloc(size_t nbytes)
1250 return memset(stalloc(nbytes), 0, nbytes);
1257 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1258 write(2, "stunalloc\n", 10);
1262 g_stacknleft += g_stacknxt - (char *)p;
1267 * Like strdup but works with the ash stack.
1270 ststrdup(const char *p)
1272 size_t len = strlen(p) + 1;
1273 return memcpy(stalloc(len), p, len);
1277 setstackmark(struct stackmark *mark)
1279 mark->stackp = g_stackp;
1280 mark->stacknxt = g_stacknxt;
1281 mark->stacknleft = g_stacknleft;
1282 mark->marknext = markp;
1287 popstackmark(struct stackmark *mark)
1289 struct stack_block *sp;
1295 markp = mark->marknext;
1296 while (g_stackp != mark->stackp) {
1298 g_stackp = sp->prev;
1301 g_stacknxt = mark->stacknxt;
1302 g_stacknleft = mark->stacknleft;
1303 sstrend = mark->stacknxt + mark->stacknleft;
1308 * When the parser reads in a string, it wants to stick the string on the
1309 * stack and only adjust the stack pointer when it knows how big the
1310 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1311 * of space on top of the stack and stackblocklen returns the length of
1312 * this block. Growstackblock will grow this space by at least one byte,
1313 * possibly moving it (like realloc). Grabstackblock actually allocates the
1314 * part of the block that has been used.
1317 growstackblock(void)
1321 newlen = g_stacknleft * 2;
1322 if (newlen < g_stacknleft)
1323 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1327 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1328 struct stack_block *oldstackp;
1329 struct stackmark *xmark;
1330 struct stack_block *sp;
1331 struct stack_block *prevstackp;
1335 oldstackp = g_stackp;
1337 prevstackp = sp->prev;
1338 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1339 sp = ckrealloc(sp, grosslen);
1340 sp->prev = prevstackp;
1342 g_stacknxt = sp->space;
1343 g_stacknleft = newlen;
1344 sstrend = sp->space + newlen;
1347 * Stack marks pointing to the start of the old block
1348 * must be relocated to point to the new block
1351 while (xmark != NULL && xmark->stackp == oldstackp) {
1352 xmark->stackp = g_stackp;
1353 xmark->stacknxt = g_stacknxt;
1354 xmark->stacknleft = g_stacknleft;
1355 xmark = xmark->marknext;
1359 char *oldspace = g_stacknxt;
1360 int oldlen = g_stacknleft;
1361 char *p = stalloc(newlen);
1363 /* free the space we just allocated */
1364 g_stacknxt = memcpy(p, oldspace, oldlen);
1365 g_stacknleft += newlen;
1370 grabstackblock(size_t len)
1372 len = SHELL_ALIGN(len);
1374 g_stacknleft -= len;
1378 * The following routines are somewhat easier to use than the above.
1379 * The user declares a variable of type STACKSTR, which may be declared
1380 * to be a register. The macro STARTSTACKSTR initializes things. Then
1381 * the user uses the macro STPUTC to add characters to the string. In
1382 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1383 * grown as necessary. When the user is done, she can just leave the
1384 * string there and refer to it using stackblock(). Or she can allocate
1385 * the space for it using grabstackstr(). If it is necessary to allow
1386 * someone else to use the stack temporarily and then continue to grow
1387 * the string, the user should use grabstack to allocate the space, and
1388 * then call ungrabstr(p) to return to the previous mode of operation.
1390 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1391 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1392 * is space for at least one character.
1397 size_t len = stackblocksize();
1398 if (herefd >= 0 && len >= 1024) {
1399 full_write(herefd, stackblock(), len);
1400 return stackblock();
1403 return stackblock() + len;
1407 * Called from CHECKSTRSPACE.
1410 makestrspace(size_t newlen, char *p)
1412 size_t len = p - g_stacknxt;
1413 size_t size = stackblocksize();
1418 size = stackblocksize();
1420 if (nleft >= newlen)
1424 return stackblock() + len;
1428 stack_nputstr(const char *s, size_t n, char *p)
1430 p = makestrspace(n, p);
1431 p = memcpy(p, s, n) + n;
1436 stack_putstr(const char *s, char *p)
1438 return stack_nputstr(s, strlen(s), p);
1442 _STPUTC(int c, char *p)
1450 #define STARTSTACKSTR(p) ((p) = stackblock())
1451 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1452 #define CHECKSTRSPACE(n, p) \
1456 size_t m = sstrend - q; \
1458 (p) = makestrspace(l, q); \
1460 #define USTPUTC(c, p) (*p++ = (c))
1461 #define STACKSTRNUL(p) \
1463 if ((p) == sstrend) \
1464 p = growstackstr(); \
1467 #define STUNPUTC(p) (--p)
1468 #define STTOPC(p) (p[-1])
1469 #define STADJUST(amount, p) (p += (amount))
1471 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1472 #define ungrabstackstr(s, p) stunalloc((s))
1473 #define stackstrend() ((void *)sstrend)
1476 /* ============ String helpers */
1479 * prefix -- see if pfx is a prefix of string.
1482 prefix(const char *string, const char *pfx)
1485 if (*pfx++ != *string++)
1488 return (char *) string;
1492 * Check for a valid number. This should be elsewhere.
1495 is_number(const char *p)
1500 } while (*++p != '\0');
1505 * Convert a string of digits to an integer, printing an error message on
1509 number(const char *s)
1512 ash_msg_and_raise_error(illnum, s);
1517 * Produce a possibly single quoted string suitable as input to the shell.
1518 * The return string is allocated on the stack.
1521 single_quote(const char *s)
1531 len = strchrnul(s, '\'') - s;
1533 q = p = makestrspace(len + 3, p);
1536 q = memcpy(q, s, len) + len;
1542 len = strspn(s, "'");
1546 q = p = makestrspace(len + 3, p);
1549 q = memcpy(q, s, len) + len;
1558 return stackblock();
1562 /* ============ nextopt */
1564 static char **argptr; /* argument list for builtin commands */
1565 static char *optionarg; /* set by nextopt (like getopt) */
1566 static char *optptr; /* used by nextopt */
1569 * XXX - should get rid of. have all builtins use getopt(3). the
1570 * library getopt must have the BSD extension static variable "optreset"
1571 * otherwise it can't be used within the shell safely.
1573 * Standard option processing (a la getopt) for builtin routines. The
1574 * only argument that is passed to nextopt is the option string; the
1575 * other arguments are unnecessary. It return the character, or '\0' on
1579 nextopt(const char *optstring)
1586 if (p == NULL || *p == '\0') {
1588 if (p == NULL || *p != '-' || *++p == '\0')
1591 if (LONE_DASH(p)) /* check for "--" */
1595 for (q = optstring; *q != c; ) {
1597 ash_msg_and_raise_error("illegal option -%c", c);
1602 if (*p == '\0' && (p = *argptr++) == NULL)
1603 ash_msg_and_raise_error("no arg for -%c option", c);
1612 /* ============ Math support definitions */
1614 #if ENABLE_ASH_MATH_SUPPORT_64
1615 typedef int64_t arith_t;
1616 #define arith_t_type long long
1618 typedef long arith_t;
1619 #define arith_t_type long
1622 #if ENABLE_ASH_MATH_SUPPORT
1623 static arith_t dash_arith(const char *);
1624 static arith_t arith(const char *expr, int *perrcode);
1627 #if ENABLE_ASH_RANDOM_SUPPORT
1628 static unsigned long rseed;
1635 /* ============ Shell variables */
1638 * The parsefile structure pointed to by the global variable parsefile
1639 * contains information about the current file being read.
1642 struct redirtab *next;
1648 int nparam; /* # of positional parameters (without $0) */
1649 #if ENABLE_ASH_GETOPTS
1650 int optind; /* next parameter to be processed by getopts */
1651 int optoff; /* used by getopts */
1653 unsigned char malloced; /* if parameter list dynamically allocated */
1654 char **p; /* parameter list */
1658 * Free the list of positional parameters.
1661 freeparam(volatile struct shparam *param)
1665 if (param->malloced) {
1666 for (ap = param->p; *ap; ap++)
1672 #if ENABLE_ASH_GETOPTS
1673 static void getoptsreset(const char *value);
1677 struct var *next; /* next entry in hash list */
1678 int flags; /* flags are defined above */
1679 const char *text; /* name=value */
1680 void (*func)(const char *); /* function to be called when */
1681 /* the variable gets set/unset */
1685 struct localvar *next; /* next local variable in list */
1686 struct var *vp; /* the variable that was made local */
1687 int flags; /* saved flags */
1688 const char *text; /* saved text */
1692 #define VEXPORT 0x01 /* variable is exported */
1693 #define VREADONLY 0x02 /* variable cannot be modified */
1694 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1695 #define VTEXTFIXED 0x08 /* text is statically allocated */
1696 #define VSTACK 0x10 /* text is allocated on the stack */
1697 #define VUNSET 0x20 /* the variable is not set */
1698 #define VNOFUNC 0x40 /* don't call the callback function */
1699 #define VNOSET 0x80 /* do not set variable - just readonly test */
1700 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1702 # define VDYNAMIC 0x200 /* dynamic variable */
1708 static const char defifsvar[] ALIGN1 = "IFS= \t\n";
1709 #define defifs (defifsvar + 4)
1711 static const char defifs[] ALIGN1 = " \t\n";
1715 /* Need to be before varinit_data[] */
1716 #if ENABLE_LOCALE_SUPPORT
1718 change_lc_all(const char *value)
1720 if (value && *value != '\0')
1721 setlocale(LC_ALL, value);
1724 change_lc_ctype(const char *value)
1726 if (value && *value != '\0')
1727 setlocale(LC_CTYPE, value);
1731 static void chkmail(void);
1732 static void changemail(const char *);
1734 static void changepath(const char *);
1735 #if ENABLE_ASH_RANDOM_SUPPORT
1736 static void change_random(const char *);
1739 static const struct {
1742 void (*func)(const char *);
1743 } varinit_data[] = {
1745 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1747 { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL },
1750 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0" , changemail },
1751 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1753 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1754 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1755 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1756 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1757 #if ENABLE_ASH_GETOPTS
1758 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
1760 #if ENABLE_ASH_RANDOM_SUPPORT
1761 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1763 #if ENABLE_LOCALE_SUPPORT
1764 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL\0" , change_lc_all },
1765 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE\0", change_lc_ctype },
1767 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1768 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE\0", NULL },
1773 struct globals_var {
1774 struct shparam shellparam; /* $@ current positional parameters */
1775 struct redirtab *redirlist;
1777 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1778 struct var *vartab[VTABSIZE];
1779 struct var varinit[ARRAY_SIZE(varinit_data)];
1781 /* Make it reside in writable memory, yet make compiler understand that it is not going to change. */
1782 static struct globals_var *const ptr_to_globals_var __attribute__ ((section (".data")));
1783 #define G_var (*ptr_to_globals_var)
1784 #define shellparam (G_var.shellparam )
1785 #define redirlist (G_var.redirlist )
1786 #define g_nullredirs (G_var.g_nullredirs )
1787 #define preverrout_fd (G_var.preverrout_fd)
1788 #define vartab (G_var.vartab )
1789 #define varinit (G_var.varinit )
1790 #define INIT_G_var() do { \
1792 (*(struct globals_var**)&ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1793 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1794 varinit[i].flags = varinit_data[i].flags; \
1795 varinit[i].text = varinit_data[i].text; \
1796 varinit[i].func = varinit_data[i].func; \
1800 #define vifs varinit[0]
1802 # define vmail (&vifs)[1]
1803 # define vmpath (&vmail)[1]
1804 # define vpath (&vmpath)[1]
1806 # define vpath (&vifs)[1]
1808 #define vps1 (&vpath)[1]
1809 #define vps2 (&vps1)[1]
1810 #define vps4 (&vps2)[1]
1811 #if ENABLE_ASH_GETOPTS
1812 # define voptind (&vps4)[1]
1813 # if ENABLE_ASH_RANDOM_SUPPORT
1814 # define vrandom (&voptind)[1]
1817 # if ENABLE_ASH_RANDOM_SUPPORT
1818 # define vrandom (&vps4)[1]
1823 * The following macros access the values of the above variables.
1824 * They have to skip over the name. They return the null string
1825 * for unset variables.
1827 #define ifsval() (vifs.text + 4)
1828 #define ifsset() ((vifs.flags & VUNSET) == 0)
1830 # define mailval() (vmail.text + 5)
1831 # define mpathval() (vmpath.text + 9)
1832 # define mpathset() ((vmpath.flags & VUNSET) == 0)
1834 #define pathval() (vpath.text + 5)
1835 #define ps1val() (vps1.text + 4)
1836 #define ps2val() (vps2.text + 4)
1837 #define ps4val() (vps4.text + 4)
1838 #if ENABLE_ASH_GETOPTS
1839 # define optindval() (voptind.text + 7)
1843 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1844 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1846 #if ENABLE_ASH_GETOPTS
1848 getoptsreset(const char *value)
1850 shellparam.optind = number(value);
1851 shellparam.optoff = -1;
1856 * Return of a legal variable name (a letter or underscore followed by zero or
1857 * more letters, underscores, and digits).
1860 endofname(const char *name)
1868 if (!is_in_name(*p))
1875 * Compares two strings up to the first = or '\0'. The first
1876 * string must be terminated by '='; the second may be terminated by
1877 * either '=' or '\0'.
1880 varcmp(const char *p, const char *q)
1884 while ((c = *p) == (d = *q)) {
1899 varequal(const char *a, const char *b)
1901 return !varcmp(a, b);
1905 * Find the appropriate entry in the hash table from the name.
1907 static struct var **
1908 hashvar(const char *p)
1912 hashval = ((unsigned char) *p) << 4;
1913 while (*p && *p != '=')
1914 hashval += (unsigned char) *p++;
1915 return &vartab[hashval % VTABSIZE];
1919 vpcmp(const void *a, const void *b)
1921 return varcmp(*(const char **)a, *(const char **)b);
1925 * This routine initializes the builtin variables.
1935 * PS1 depends on uid
1937 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1938 vps1.text = "PS1=\\w \\$ ";
1941 vps1.text = "PS1=# ";
1944 end = vp + ARRAY_SIZE(varinit);
1946 vpp = hashvar(vp->text);
1949 } while (++vp < end);
1952 static struct var **
1953 findvar(struct var **vpp, const char *name)
1955 for (; *vpp; vpp = &(*vpp)->next) {
1956 if (varequal((*vpp)->text, name)) {
1964 * Find the value of a variable. Returns NULL if not set.
1967 lookupvar(const char *name)
1971 v = *findvar(hashvar(name), name);
1975 * Dynamic variables are implemented roughly the same way they are
1976 * in bash. Namely, they're "special" so long as they aren't unset.
1977 * As soon as they're unset, they're no longer dynamic, and dynamic
1978 * lookup will no longer happen at that point. -- PFM.
1980 if ((v->flags & VDYNAMIC))
1983 if (!(v->flags & VUNSET))
1984 return strchrnul(v->text, '=') + 1;
1990 * Search the environment of a builtin command.
1993 bltinlookup(const char *name)
1997 for (sp = cmdenviron; sp; sp = sp->next) {
1998 if (varequal(sp->text, name))
1999 return strchrnul(sp->text, '=') + 1;
2001 return lookupvar(name);
2005 * Same as setvar except that the variable and value are passed in
2006 * the first argument as name=value. Since the first argument will
2007 * be actually stored in the table, it should not be a string that
2009 * Called with interrupts off.
2012 setvareq(char *s, int flags)
2014 struct var *vp, **vpp;
2017 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2018 vp = *findvar(vpp, s);
2020 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2023 if (flags & VNOSAVE)
2026 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2032 if (vp->func && (flags & VNOFUNC) == 0)
2033 (*vp->func)(strchrnul(s, '=') + 1);
2035 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
2036 free((char*)vp->text);
2038 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2043 vp = ckzalloc(sizeof(*vp));
2045 /*vp->func = NULL; - ckzalloc did it */
2048 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2055 * Set the value of a variable. The flags argument is ored with the
2056 * flags of the variable. If val is NULL, the variable is unset.
2059 setvar(const char *name, const char *val, int flags)
2066 q = endofname(name);
2067 p = strchrnul(q, '=');
2069 if (!namelen || p != q)
2070 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2075 vallen = strlen(val);
2078 nameeq = ckmalloc(namelen + vallen + 2);
2079 p = memcpy(nameeq, name, namelen) + namelen;
2082 p = memcpy(p, val, vallen) + vallen;
2085 setvareq(nameeq, flags | VNOSAVE);
2089 #if ENABLE_ASH_GETOPTS
2091 * Safe version of setvar, returns 1 on success 0 on failure.
2094 setvarsafe(const char *name, const char *val, int flags)
2097 volatile int saveint;
2098 struct jmploc *volatile savehandler = exception_handler;
2099 struct jmploc jmploc;
2102 if (setjmp(jmploc.loc))
2105 exception_handler = &jmploc;
2106 setvar(name, val, flags);
2109 exception_handler = savehandler;
2110 RESTORE_INT(saveint);
2116 * Unset the specified variable.
2119 unsetvar(const char *s)
2125 vpp = findvar(hashvar(s), s);
2129 int flags = vp->flags;
2132 if (flags & VREADONLY)
2135 vp->flags &= ~VDYNAMIC;
2139 if ((flags & VSTRFIXED) == 0) {
2141 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2142 free((char*)vp->text);
2148 vp->flags &= ~VEXPORT;
2158 * Process a linked list of variable assignments.
2161 listsetvar(struct strlist *list_set_var, int flags)
2163 struct strlist *lp = list_set_var;
2169 setvareq(lp->text, flags);
2176 * Generate a list of variables satisfying the given conditions.
2179 listvars(int on, int off, char ***end)
2190 for (vp = *vpp; vp; vp = vp->next) {
2191 if ((vp->flags & mask) == on) {
2192 if (ep == stackstrend())
2193 ep = growstackstr();
2194 *ep++ = (char *) vp->text;
2197 } while (++vpp < vartab + VTABSIZE);
2198 if (ep == stackstrend())
2199 ep = growstackstr();
2203 return grabstackstr(ep);
2207 /* ============ Path search helper
2209 * The variable path (passed by reference) should be set to the start
2210 * of the path before the first call; padvance will update
2211 * this value as it proceeds. Successive calls to padvance will return
2212 * the possible path expansions in sequence. If an option (indicated by
2213 * a percent sign) appears in the path entry then the global variable
2214 * pathopt will be set to point to it; otherwise pathopt will be set to
2217 static const char *pathopt; /* set by padvance */
2220 padvance(const char **path, const char *name)
2230 for (p = start; *p && *p != ':' && *p != '%'; p++);
2231 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2232 while (stackblocksize() < len)
2236 memcpy(q, start, p - start);
2244 while (*p && *p != ':') p++;
2250 return stalloc(len);
2254 /* ============ Prompt */
2256 static smallint doprompt; /* if set, prompt the user */
2257 static smallint needprompt; /* true if interactive and at start of line */
2259 #if ENABLE_FEATURE_EDITING
2260 static line_input_t *line_input_state;
2261 static const char *cmdedit_prompt;
2263 putprompt(const char *s)
2265 if (ENABLE_ASH_EXPAND_PRMT) {
2266 free((char*)cmdedit_prompt);
2267 cmdedit_prompt = ckstrdup(s);
2274 putprompt(const char *s)
2280 #if ENABLE_ASH_EXPAND_PRMT
2281 /* expandstr() needs parsing machinery, so it is far away ahead... */
2282 static const char *expandstr(const char *ps);
2284 #define expandstr(s) s
2288 setprompt(int whichprompt)
2291 #if ENABLE_ASH_EXPAND_PRMT
2292 struct stackmark smark;
2297 switch (whichprompt) {
2307 #if ENABLE_ASH_EXPAND_PRMT
2308 setstackmark(&smark);
2309 stalloc(stackblocksize());
2311 putprompt(expandstr(prompt));
2312 #if ENABLE_ASH_EXPAND_PRMT
2313 popstackmark(&smark);
2318 /* ============ The cd and pwd commands */
2320 #define CD_PHYSICAL 1
2323 static int docd(const char *, int);
2332 while ((i = nextopt("LP"))) {
2334 flags ^= CD_PHYSICAL;
2343 * Update curdir (the name of the current directory) in response to a
2347 updatepwd(const char *dir)
2354 cdcomppath = ststrdup(dir);
2357 if (curdir == nullstr)
2359 new = stack_putstr(curdir, new);
2361 new = makestrspace(strlen(dir) + 2, new);
2362 lim = stackblock() + 1;
2366 if (new > lim && *lim == '/')
2371 if (dir[1] == '/' && dir[2] != '/') {
2377 p = strtok(cdcomppath, "/");
2381 if (p[1] == '.' && p[2] == '\0') {
2393 new = stack_putstr(p, new);
2401 return stackblock();
2405 * Find out what the current directory is. If we already know the current
2406 * directory, this routine returns immediately.
2411 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2412 return dir ? dir : nullstr;
2416 setpwd(const char *val, int setold)
2420 oldcur = dir = curdir;
2423 setvar("OLDPWD", oldcur, VEXPORT);
2426 if (physdir != nullstr) {
2427 if (physdir != oldcur)
2431 if (oldcur == val || !val) {
2437 dir = ckstrdup(val);
2438 if (oldcur != dir && oldcur != nullstr) {
2443 setvar("PWD", dir, VEXPORT);
2446 static void hashcd(void);
2449 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2450 * know that the current directory has changed.
2453 docd(const char *dest, int flags)
2455 const char *dir = 0;
2458 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2461 if (!(flags & CD_PHYSICAL)) {
2462 dir = updatepwd(dest);
2477 cdcmd(int argc, char **argv)
2489 dest = bltinlookup(homestr);
2490 else if (LONE_DASH(dest)) {
2491 dest = bltinlookup("OLDPWD");
2513 path = bltinlookup("CDPATH");
2522 p = padvance(&path, dest);
2523 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2527 if (!docd(p, flags))
2532 ash_msg_and_raise_error("can't cd to %s", dest);
2535 if (flags & CD_PRINT)
2536 out1fmt(snlfmt, curdir);
2541 pwdcmd(int argc, char **argv)
2544 const char *dir = curdir;
2548 if (physdir == nullstr)
2552 out1fmt(snlfmt, dir);
2557 /* ============ ... */
2559 #define IBUFSIZ COMMON_BUFSIZE
2560 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */
2562 /* Syntax classes */
2563 #define CWORD 0 /* character is nothing special */
2564 #define CNL 1 /* newline character */
2565 #define CBACK 2 /* a backslash character */
2566 #define CSQUOTE 3 /* single quote */
2567 #define CDQUOTE 4 /* double quote */
2568 #define CENDQUOTE 5 /* a terminating quote */
2569 #define CBQUOTE 6 /* backwards single quote */
2570 #define CVAR 7 /* a dollar sign */
2571 #define CENDVAR 8 /* a '}' character */
2572 #define CLP 9 /* a left paren in arithmetic */
2573 #define CRP 10 /* a right paren in arithmetic */
2574 #define CENDFILE 11 /* end of file */
2575 #define CCTL 12 /* like CWORD, except it must be escaped */
2576 #define CSPCL 13 /* these terminate a word */
2577 #define CIGN 14 /* character should be ignored */
2579 #if ENABLE_ASH_ALIAS
2583 #define PEOA_OR_PEOF PEOA
2587 #define PEOA_OR_PEOF PEOF
2590 /* number syntax index */
2591 #define BASESYNTAX 0 /* not in quotes */
2592 #define DQSYNTAX 1 /* in double quotes */
2593 #define SQSYNTAX 2 /* in single quotes */
2594 #define ARISYNTAX 3 /* in arithmetic */
2595 #define PSSYNTAX 4 /* prompt */
2597 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
2598 #define USE_SIT_FUNCTION
2601 #if ENABLE_ASH_MATH_SUPPORT
2602 static const char S_I_T[][4] = {
2603 #if ENABLE_ASH_ALIAS
2604 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */
2606 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */
2607 { CNL, CNL, CNL, CNL }, /* 2, \n */
2608 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */
2609 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */
2610 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */
2611 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */
2612 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */
2613 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */
2614 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */
2615 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */
2616 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */
2617 #ifndef USE_SIT_FUNCTION
2618 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2619 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2620 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2624 static const char S_I_T[][3] = {
2625 #if ENABLE_ASH_ALIAS
2626 { CSPCL, CIGN, CIGN }, /* 0, PEOA */
2628 { CSPCL, CWORD, CWORD }, /* 1, ' ' */
2629 { CNL, CNL, CNL }, /* 2, \n */
2630 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */
2631 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */
2632 { CVAR, CVAR, CWORD }, /* 5, $ */
2633 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */
2634 { CSPCL, CWORD, CWORD }, /* 7, ( */
2635 { CSPCL, CWORD, CWORD }, /* 8, ) */
2636 { CBACK, CBACK, CCTL }, /* 9, \ */
2637 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */
2638 { CENDVAR, CENDVAR, CWORD }, /* 11, } */
2639 #ifndef USE_SIT_FUNCTION
2640 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2641 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2642 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2645 #endif /* ASH_MATH_SUPPORT */
2647 #ifdef USE_SIT_FUNCTION
2650 SIT(int c, int syntax)
2652 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2653 #if ENABLE_ASH_ALIAS
2654 static const char syntax_index_table[] ALIGN1 = {
2655 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2656 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2657 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2661 static const char syntax_index_table[] ALIGN1 = {
2662 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2663 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2664 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2671 if (c == PEOF) /* 2^8+2 */
2673 #if ENABLE_ASH_ALIAS
2674 if (c == PEOA) /* 2^8+1 */
2678 #define U_C(c) ((unsigned char)(c))
2680 if ((unsigned char)c >= (unsigned char)(CTLESC)
2681 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
2685 s = strchr(spec_symbls, c);
2686 if (s == NULL || *s == '\0')
2688 indx = syntax_index_table[(s - spec_symbls)];
2690 return S_I_T[indx][syntax];
2693 #else /* !USE_SIT_FUNCTION */
2695 #if ENABLE_ASH_ALIAS
2696 #define CSPCL_CIGN_CIGN_CIGN 0
2697 #define CSPCL_CWORD_CWORD_CWORD 1
2698 #define CNL_CNL_CNL_CNL 2
2699 #define CWORD_CCTL_CCTL_CWORD 3
2700 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
2701 #define CVAR_CVAR_CWORD_CVAR 5
2702 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
2703 #define CSPCL_CWORD_CWORD_CLP 7
2704 #define CSPCL_CWORD_CWORD_CRP 8
2705 #define CBACK_CBACK_CCTL_CBACK 9
2706 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
2707 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
2708 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
2709 #define CWORD_CWORD_CWORD_CWORD 13
2710 #define CCTL_CCTL_CCTL_CCTL 14
2712 #define CSPCL_CWORD_CWORD_CWORD 0
2713 #define CNL_CNL_CNL_CNL 1
2714 #define CWORD_CCTL_CCTL_CWORD 2
2715 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
2716 #define CVAR_CVAR_CWORD_CVAR 4
2717 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
2718 #define CSPCL_CWORD_CWORD_CLP 6
2719 #define CSPCL_CWORD_CWORD_CRP 7
2720 #define CBACK_CBACK_CCTL_CBACK 8
2721 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
2722 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
2723 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
2724 #define CWORD_CWORD_CWORD_CWORD 12
2725 #define CCTL_CCTL_CCTL_CCTL 13
2728 static const char syntax_index_table[258] = {
2729 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2730 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2731 #if ENABLE_ASH_ALIAS
2732 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
2734 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2735 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2736 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2737 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2738 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2739 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2740 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2741 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2742 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2743 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
2744 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
2745 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
2746 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
2747 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
2748 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
2749 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
2750 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
2751 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
2752 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
2753 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
2754 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
2755 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
2756 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
2757 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
2758 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
2759 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
2760 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
2761 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
2762 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
2763 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
2764 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
2765 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
2766 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
2767 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
2768 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
2769 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
2770 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
2771 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
2772 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
2773 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
2774 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
2775 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
2776 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
2777 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
2778 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
2779 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
2780 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
2781 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
2782 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
2783 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
2784 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
2785 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
2786 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
2787 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
2788 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
2789 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
2790 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
2791 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
2792 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
2793 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
2794 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
2795 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
2796 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
2797 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
2798 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
2799 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
2800 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
2801 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
2802 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
2803 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
2804 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
2805 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
2806 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
2807 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
2808 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
2809 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
2810 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
2811 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
2812 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
2813 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
2814 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
2815 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
2816 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
2817 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
2818 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
2819 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
2820 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
2821 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
2822 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
2823 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
2824 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
2825 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
2826 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
2827 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
2828 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
2829 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
2830 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
2831 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
2832 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
2833 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
2834 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
2835 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
2836 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
2837 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
2838 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
2839 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
2840 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
2841 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
2842 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
2843 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
2844 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
2845 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
2846 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
2847 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
2848 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
2853 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
2854 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2872 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
2873 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2895 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2896 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2897 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2898 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2899 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2900 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2901 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2902 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2903 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2904 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2905 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2906 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
2907 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2908 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
2909 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2910 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2921 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2922 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2923 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2924 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2925 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2926 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2954 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2955 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2956 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2959 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2987 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2988 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2989 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
2992 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])
2994 #endif /* USE_SIT_FUNCTION */
2997 /* ============ Alias handling */
2999 #if ENABLE_ASH_ALIAS
3001 #define ALIASINUSE 1
3012 static struct alias **atab; // [ATABSIZE];
3013 #define INIT_G_alias() do { \
3014 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3018 static struct alias **
3019 __lookupalias(const char *name) {
3020 unsigned int hashval;
3027 ch = (unsigned char)*p;
3031 ch = (unsigned char)*++p;
3033 app = &atab[hashval % ATABSIZE];
3035 for (; *app; app = &(*app)->next) {
3036 if (strcmp(name, (*app)->name) == 0) {
3044 static struct alias *
3045 lookupalias(const char *name, int check)
3047 struct alias *ap = *__lookupalias(name);
3049 if (check && ap && (ap->flag & ALIASINUSE))
3054 static struct alias *
3055 freealias(struct alias *ap)
3059 if (ap->flag & ALIASINUSE) {
3060 ap->flag |= ALIASDEAD;
3072 setalias(const char *name, const char *val)
3074 struct alias *ap, **app;
3076 app = __lookupalias(name);
3080 if (!(ap->flag & ALIASINUSE)) {
3083 ap->val = ckstrdup(val);
3084 ap->flag &= ~ALIASDEAD;
3087 ap = ckzalloc(sizeof(struct alias));
3088 ap->name = ckstrdup(name);
3089 ap->val = ckstrdup(val);
3090 /*ap->flag = 0; - ckzalloc did it */
3091 /*ap->next = NULL;*/
3098 unalias(const char *name)
3102 app = __lookupalias(name);
3106 *app = freealias(*app);
3117 struct alias *ap, **app;
3121 for (i = 0; i < ATABSIZE; i++) {
3123 for (ap = *app; ap; ap = *app) {
3124 *app = freealias(*app);
3134 printalias(const struct alias *ap)
3136 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3140 * TODO - sort output
3143 aliascmd(int argc, char **argv)
3152 for (i = 0; i < ATABSIZE; i++)
3153 for (ap = atab[i]; ap; ap = ap->next) {
3158 while ((n = *++argv) != NULL) {
3159 v = strchr(n+1, '=');
3160 if (v == NULL) { /* n+1: funny ksh stuff */
3161 ap = *__lookupalias(n);
3163 fprintf(stderr, "%s: %s not found\n", "alias", n);
3177 unaliascmd(int argc, char **argv)
3181 while ((i = nextopt("a")) != '\0') {
3187 for (i = 0; *argptr; argptr++) {
3188 if (unalias(*argptr)) {
3189 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3197 #endif /* ASH_ALIAS */
3200 /* ============ jobs.c */
3202 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3205 #define FORK_NOJOB 2
3207 /* mode flags for showjob(s) */
3208 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
3209 #define SHOW_PID 0x04 /* include process pid */
3210 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
3213 * A job structure contains information about a job. A job is either a
3214 * single process or a set of processes contained in a pipeline. In the
3215 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3220 pid_t pid; /* process id */
3221 int status; /* last process status from wait() */
3222 char *cmd; /* text of command being run */
3226 struct procstat ps0; /* status of process */
3227 struct procstat *ps; /* status or processes when more than one */
3229 int stopstatus; /* status of a stopped job */
3232 nprocs: 16, /* number of processes */
3234 #define JOBRUNNING 0 /* at least one proc running */
3235 #define JOBSTOPPED 1 /* all procs are stopped */
3236 #define JOBDONE 2 /* all procs are completed */
3238 sigint: 1, /* job was killed by SIGINT */
3239 jobctl: 1, /* job running under job control */
3241 waited: 1, /* true if this entry has been waited for */
3242 used: 1, /* true if this entry is in used */
3243 changed: 1; /* true if status has changed */
3244 struct job *prev_job; /* previous job */
3247 static pid_t backgndpid; /* pid of last background process */
3248 static smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
3250 static struct job *makejob(union node *, int);
3251 static int forkshell(struct job *, union node *, int);
3252 static int waitforjob(struct job *);
3255 enum { jobctl = 0 };
3256 #define setjobctl(on) do {} while (0)
3258 static smallint jobctl; /* true if doing job control */
3259 static void setjobctl(int);
3263 * Set the signal handler for the specified signal. The routine figures
3264 * out what it should be set to.
3267 setsignal(int signo)
3271 struct sigaction act;
3277 else if (*t != '\0')
3279 if (rootshell && action == S_DFL) {
3282 if (iflag || minusc || sflag == 0)
3305 t = &sigmode[signo - 1];
3309 * current setting unknown
3311 if (sigaction(signo, NULL, &act) == -1) {
3313 * Pretend it worked; maybe we should give a warning
3314 * here, but other shells don't. We don't alter
3315 * sigmode, so that we retry every time.
3319 tsig = S_RESET; /* force to be set */
3320 if (act.sa_handler == SIG_IGN) {
3323 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3325 tsig = S_IGN; /* don't hard ignore these */
3329 if (tsig == S_HARD_IGN || tsig == action)
3331 act.sa_handler = SIG_DFL;
3334 act.sa_handler = onsig;
3337 act.sa_handler = SIG_IGN;
3342 sigfillset(&act.sa_mask);
3343 sigaction(signo, &act, NULL);
3346 /* mode flags for set_curjob */
3347 #define CUR_DELETE 2
3348 #define CUR_RUNNING 1
3349 #define CUR_STOPPED 0
3351 /* mode flags for dowait */
3352 #define DOWAIT_NONBLOCK WNOHANG
3353 #define DOWAIT_BLOCK 0
3356 /* pgrp of shell on invocation */
3357 static int initialpgrp;
3358 static int ttyfd = -1;
3361 static struct job *jobtab;
3363 static unsigned njobs;
3365 static struct job *curjob;
3366 /* number of presumed living untracked jobs */
3370 set_curjob(struct job *jp, unsigned mode)
3373 struct job **jpp, **curp;
3375 /* first remove from list */
3376 jpp = curp = &curjob;
3381 jpp = &jp1->prev_job;
3383 *jpp = jp1->prev_job;
3385 /* Then re-insert in correct position */
3393 /* job being deleted */
3396 /* newly created job or backgrounded job,
3397 put after all stopped jobs. */
3401 if (!jp1 || jp1->state != JOBSTOPPED)
3404 jpp = &jp1->prev_job;
3410 /* newly stopped job - becomes curjob */
3411 jp->prev_job = *jpp;
3419 jobno(const struct job *jp)
3421 return jp - jobtab + 1;
3426 * Convert a job name to a job structure.
3429 getjob(const char *name, int getctl)
3433 const char *err_msg = "No such job: %s";
3437 char *(*match)(const char *, const char *);
3452 if (c == '+' || c == '%') {
3454 err_msg = "No current job";
3460 err_msg = "No previous job";
3471 jp = jobtab + num - 1;
3488 if (match(jp->ps[0].cmd, p)) {
3492 err_msg = "%s: ambiguous";
3499 err_msg = "job %s not created under job control";
3500 if (getctl && jp->jobctl == 0)
3505 ash_msg_and_raise_error(err_msg, name);
3509 * Mark a job structure as unused.
3512 freejob(struct job *jp)
3514 struct procstat *ps;
3518 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3519 if (ps->cmd != nullstr)
3522 if (jp->ps != &jp->ps0)
3525 set_curjob(jp, CUR_DELETE);
3531 xtcsetpgrp(int fd, pid_t pgrp)
3533 if (tcsetpgrp(fd, pgrp))
3534 ash_msg_and_raise_error("cannot set tty process group (%m)");
3538 * Turn job control on and off.
3540 * Note: This code assumes that the third arg to ioctl is a character
3541 * pointer, which is true on Berkeley systems but not System V. Since
3542 * System V doesn't have job control yet, this isn't a problem now.
3544 * Called with interrupts off.
3552 if (on == jobctl || rootshell == 0)
3556 ofd = fd = open(_PATH_TTY, O_RDWR);
3558 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3559 * That sometimes helps to acquire controlling tty.
3560 * Obviously, a workaround for bugs when someone
3561 * failed to provide a controlling tty to bash! :) */
3567 fd = fcntl(fd, F_DUPFD, 10);
3572 /* fd is a tty at this point */
3573 close_on_exec_on(fd);
3574 do { /* while we are in the background */
3575 pgrp = tcgetpgrp(fd);
3578 ash_msg("can't access tty; job control turned off");
3582 if (pgrp == getpgrp())
3593 xtcsetpgrp(fd, pgrp);
3595 /* turning job control off */
3598 /* was xtcsetpgrp, but this can make exiting ash
3599 * loop forever if pty is already deleted */
3600 tcsetpgrp(fd, pgrp);
3615 killcmd(int argc, char **argv)
3617 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3620 if (argv[i][0] == '%') {
3621 struct job *jp = getjob(argv[i], 0);
3622 unsigned pid = jp->ps[0].pid;
3623 /* Enough space for ' -NNN<nul>' */
3624 argv[i] = alloca(sizeof(int)*3 + 3);
3625 /* kill_main has matching code to expect
3626 * leading space. Needed to not confuse
3627 * negative pids with "kill -SIGNAL_NO" syntax */
3628 sprintf(argv[i], " -%u", pid);
3630 } while (argv[++i]);
3632 return kill_main(argc, argv);
3636 showpipe(struct job *jp, FILE *out)
3638 struct procstat *sp;
3639 struct procstat *spend;
3641 spend = jp->ps + jp->nprocs;
3642 for (sp = jp->ps + 1; sp < spend; sp++)
3643 fprintf(out, " | %s", sp->cmd);
3644 outcslow('\n', out);
3645 flush_stdout_stderr();
3650 restartjob(struct job *jp, int mode)
3652 struct procstat *ps;
3658 if (jp->state == JOBDONE)
3660 jp->state = JOBRUNNING;
3662 if (mode == FORK_FG)
3663 xtcsetpgrp(ttyfd, pgid);
3664 killpg(pgid, SIGCONT);
3668 if (WIFSTOPPED(ps->status)) {
3674 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3680 fg_bgcmd(int argc, char **argv)
3687 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3692 jp = getjob(*argv, 1);
3693 if (mode == FORK_BG) {
3694 set_curjob(jp, CUR_RUNNING);
3695 fprintf(out, "[%d] ", jobno(jp));
3697 outstr(jp->ps->cmd, out);
3699 retval = restartjob(jp, mode);
3700 } while (*argv && *++argv);
3706 sprint_status(char *s, int status, int sigonly)
3712 if (!WIFEXITED(status)) {
3714 if (WIFSTOPPED(status))
3715 st = WSTOPSIG(status);
3718 st = WTERMSIG(status);
3720 if (st == SIGINT || st == SIGPIPE)
3723 if (WIFSTOPPED(status))
3728 col = fmtstr(s, 32, strsignal(st));
3729 if (WCOREDUMP(status)) {
3730 col += fmtstr(s + col, 16, " (core dumped)");
3732 } else if (!sigonly) {
3733 st = WEXITSTATUS(status);
3735 col = fmtstr(s, 16, "Done(%d)", st);
3737 col = fmtstr(s, 16, "Done");
3744 * Do a wait system call. If job control is compiled in, we accept
3745 * stopped processes. If block is zero, we return a value of zero
3746 * rather than blocking.
3748 * System V doesn't have a non-blocking wait system call. It does
3749 * have a SIGCLD signal that is sent to a process when one of it's
3750 * children dies. The obvious way to use SIGCLD would be to install
3751 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
3752 * was received, and have waitproc bump another counter when it got
3753 * the status of a process. Waitproc would then know that a wait
3754 * system call would not block if the two counters were different.
3755 * This approach doesn't work because if a process has children that
3756 * have not been waited for, System V will send it a SIGCLD when it
3757 * installs a signal handler for SIGCLD. What this means is that when
3758 * a child exits, the shell will be sent SIGCLD signals continuously
3759 * until is runs out of stack space, unless it does a wait call before
3760 * restoring the signal handler. The code below takes advantage of
3761 * this (mis)feature by installing a signal handler for SIGCLD and
3762 * then checking to see whether it was called. If there are any
3763 * children to be waited for, it will be.
3765 * If neither SYSV nor BSD is defined, we don't implement nonblocking
3766 * waits at all. In this case, the user will not be informed when
3767 * a background process until the next time she runs a real program
3768 * (as opposed to running a builtin command or just typing return),
3769 * and the jobs command may give out of date information.
3772 waitproc(int wait_flags, int *status)
3776 wait_flags |= WUNTRACED;
3778 /* NB: _not_ safe_waitpid, we need to detect EINTR */
3779 return waitpid(-1, status, wait_flags);
3783 * Wait for a process to terminate.
3786 dowait(int wait_flags, struct job *job)
3791 struct job *thisjob;
3794 TRACE(("dowait(%d) called\n", wait_flags));
3795 pid = waitproc(wait_flags, &status);
3796 TRACE(("wait returns pid=%d, status=%d\n", pid, status));
3798 /* If we were doing blocking wait and (probably) got EINTR,
3799 * check for pending sigs received while waiting.
3800 * (NB: can be moved into callers if needed) */
3801 if (wait_flags == DOWAIT_BLOCK && pendingsig)
3802 raise_exception(EXSIG);
3807 for (jp = curjob; jp; jp = jp->prev_job) {
3808 struct procstat *sp;
3809 struct procstat *spend;
3810 if (jp->state == JOBDONE)
3813 spend = jp->ps + jp->nprocs;
3816 if (sp->pid == pid) {
3817 TRACE(("Job %d: changing status of proc %d "
3818 "from 0x%x to 0x%x\n",
3819 jobno(jp), pid, sp->status, status));
3820 sp->status = status;
3823 if (sp->status == -1)
3826 if (state == JOBRUNNING)
3828 if (WIFSTOPPED(sp->status)) {
3829 jp->stopstatus = sp->status;
3833 } while (++sp < spend);
3838 if (!WIFSTOPPED(status))
3844 if (state != JOBRUNNING) {
3845 thisjob->changed = 1;
3847 if (thisjob->state != state) {
3848 TRACE(("Job %d: changing state from %d to %d\n",
3849 jobno(thisjob), thisjob->state, state));
3850 thisjob->state = state;
3852 if (state == JOBSTOPPED) {
3853 set_curjob(thisjob, CUR_STOPPED);
3862 if (thisjob && thisjob == job) {
3866 len = sprint_status(s, status, 1);
3878 showjob(FILE *out, struct job *jp, int mode)
3880 struct procstat *ps;
3881 struct procstat *psend;
3888 if (mode & SHOW_PGID) {
3889 /* just output process (group) id of pipeline */
3890 fprintf(out, "%d\n", ps->pid);
3894 col = fmtstr(s, 16, "[%d] ", jobno(jp));
3899 else if (curjob && jp == curjob->prev_job)
3902 if (mode & SHOW_PID)
3903 col += fmtstr(s + col, 16, "%d ", ps->pid);
3905 psend = ps + jp->nprocs;
3907 if (jp->state == JOBRUNNING) {
3908 strcpy(s + col, "Running");
3909 col += sizeof("Running") - 1;
3911 int status = psend[-1].status;
3912 if (jp->state == JOBSTOPPED)
3913 status = jp->stopstatus;
3914 col += sprint_status(s + col, status, 0);
3920 /* for each process */
3921 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
3923 fprintf(out, "%s%*c%s",
3924 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
3926 if (!(mode & SHOW_PID)) {
3930 if (++ps == psend) {
3931 outcslow('\n', out);
3938 if (jp->state == JOBDONE) {
3939 TRACE(("showjob: freeing job %d\n", jobno(jp)));
3945 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3946 * statuses have changed since the last call to showjobs.
3949 showjobs(FILE *out, int mode)
3953 TRACE(("showjobs(%x) called\n", mode));
3955 /* If not even one job changed, there is nothing to do */
3956 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3959 for (jp = curjob; jp; jp = jp->prev_job) {
3960 if (!(mode & SHOW_CHANGED) || jp->changed) {
3961 showjob(out, jp, mode);
3967 jobscmd(int argc, char **argv)
3972 while ((m = nextopt("lp"))) {
3982 showjob(stdout, getjob(*argv,0), mode);
3985 showjobs(stdout, mode);
3992 getstatus(struct job *job)
3997 status = job->ps[job->nprocs - 1].status;
3998 retval = WEXITSTATUS(status);
3999 if (!WIFEXITED(status)) {
4001 retval = WSTOPSIG(status);
4002 if (!WIFSTOPPED(status))
4005 /* XXX: limits number of signals */
4006 retval = WTERMSIG(status);
4008 if (retval == SIGINT)
4014 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
4015 jobno(job), job->nprocs, status, retval));
4020 waitcmd(int argc, char **argv)
4029 raise_exception(EXSIG);
4036 /* wait for all jobs */
4040 if (!jp) /* no running procs */
4042 if (jp->state == JOBRUNNING)
4047 dowait(DOWAIT_BLOCK, NULL);
4053 if (**argv != '%') {
4054 pid_t pid = number(*argv);
4059 if (job->ps[job->nprocs - 1].pid == pid)
4061 job = job->prev_job;
4064 job = getjob(*argv, 0);
4065 /* loop until process terminated or stopped */
4066 while (job->state == JOBRUNNING)
4067 dowait(DOWAIT_BLOCK, NULL);
4069 retval = getstatus(job);
4083 struct job *jp, *jq;
4085 len = njobs * sizeof(*jp);
4087 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4089 offset = (char *)jp - (char *)jq;
4091 /* Relocate pointers */
4094 jq = (struct job *)((char *)jq + l);
4098 #define joff(p) ((struct job *)((char *)(p) + l))
4099 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4100 if (joff(jp)->ps == &jq->ps0)
4101 jmove(joff(jp)->ps);
4102 if (joff(jp)->prev_job)
4103 jmove(joff(jp)->prev_job);
4113 jp = (struct job *)((char *)jp + len);
4117 } while (--jq >= jp);
4122 * Return a new job structure.
4123 * Called with interrupts off.
4126 makejob(union node *node, int nprocs)
4131 for (i = njobs, jp = jobtab; ; jp++) {
4138 if (jp->state != JOBDONE || !jp->waited)
4147 memset(jp, 0, sizeof(*jp));
4149 /* jp->jobctl is a bitfield.
4150 * "jp->jobctl |= jobctl" likely to give awful code */
4154 jp->prev_job = curjob;
4159 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4161 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
4168 * Return a string identifying a command (to be printed by the
4171 static char *cmdnextc;
4174 cmdputs(const char *s)
4176 const char *p, *str;
4177 char c, cc[2] = " ";
4181 static const char vstype[VSTYPE + 1][4] = {
4182 "", "}", "-", "+", "?", "=",
4183 "%", "%%", "#", "##"
4186 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4188 while ((c = *p++) != 0) {
4196 if ((subtype & VSTYPE) == VSLENGTH)
4200 if (!(subtype & VSQUOTE) == !(quoted & 1))
4206 str = "\"}" + !(quoted & 1);
4213 case CTLBACKQ+CTLQUOTE:
4216 #if ENABLE_ASH_MATH_SUPPORT
4231 if ((subtype & VSTYPE) != VSNORMAL)
4233 str = vstype[subtype & VSTYPE];
4234 if (subtype & VSNUL)
4243 /* These can only happen inside quotes */
4256 while ((c = *str++)) {
4261 USTPUTC('"', nextc);
4267 /* cmdtxt() and cmdlist() call each other */
4268 static void cmdtxt(union node *n);
4271 cmdlist(union node *np, int sep)
4273 for (; np; np = np->narg.next) {
4277 if (sep && np->narg.next)
4283 cmdtxt(union node *n)
4286 struct nodelist *lp;
4298 lp = n->npipe.cmdlist;
4316 cmdtxt(n->nbinary.ch1);
4332 cmdtxt(n->nif.test);
4335 if (n->nif.elsepart) {
4338 n = n->nif.elsepart;
4354 cmdtxt(n->nbinary.ch1);
4364 cmdputs(n->nfor.var);
4366 cmdlist(n->nfor.args, 1);
4371 cmdputs(n->narg.text);
4375 cmdlist(n->ncmd.args, 1);
4376 cmdlist(n->ncmd.redirect, 0);
4389 cmdputs(n->ncase.expr->narg.text);
4391 for (np = n->ncase.cases; np; np = np->nclist.next) {
4392 cmdtxt(np->nclist.pattern);
4394 cmdtxt(np->nclist.body);
4420 s[0] = n->nfile.fd + '0';
4424 if (n->type == NTOFD || n->type == NFROMFD) {
4425 s[0] = n->ndup.dupfd + '0';
4435 commandtext(union node *n)
4439 STARTSTACKSTR(cmdnextc);
4441 name = stackblock();
4442 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4443 name, cmdnextc, cmdnextc));
4444 return ckstrdup(name);
4449 * Fork off a subshell. If we are doing job control, give the subshell its
4450 * own process group. Jp is a job structure that the job is to be added to.
4451 * N is the command that will be evaluated by the child. Both jp and n may
4452 * be NULL. The mode parameter can be one of the following:
4453 * FORK_FG - Fork off a foreground process.
4454 * FORK_BG - Fork off a background process.
4455 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4456 * process group even if job control is on.
4458 * When job control is turned off, background processes have their standard
4459 * input redirected to /dev/null (except for the second and later processes
4462 * Called with interrupts off.
4465 * Clear traps on a fork.
4472 for (tp = trap; tp < &trap[NSIG]; tp++) {
4473 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4478 setsignal(tp - trap);
4484 /* Lives far away from here, needed for forkchild */
4485 static void closescript(void);
4487 /* Called after fork(), in child */
4489 forkchild(struct job *jp, union node *n, int mode)
4493 TRACE(("Child shell %d\n", getpid()));
4500 /* do job control only in root shell */
4502 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4505 if (jp->nprocs == 0)
4508 pgrp = jp->ps[0].pid;
4509 /* This can fail because we are doing it in the parent also */
4510 (void)setpgid(0, pgrp);
4511 if (mode == FORK_FG)
4512 xtcsetpgrp(ttyfd, pgrp);
4517 if (mode == FORK_BG) {
4520 if (jp->nprocs == 0) {
4522 if (open(bb_dev_null, O_RDONLY) != 0)
4523 ash_msg_and_raise_error("can't open %s", bb_dev_null);
4526 if (!oldlvl && iflag) {
4531 for (jp = curjob; jp; jp = jp->prev_job)
4536 /* Called after fork(), in parent */
4538 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4540 TRACE(("In parent shell: child = %d\n", pid));
4542 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4548 if (mode != FORK_NOJOB && jp->jobctl) {
4551 if (jp->nprocs == 0)
4554 pgrp = jp->ps[0].pid;
4555 /* This can fail because we are doing it in the child also */
4559 if (mode == FORK_BG) {
4560 backgndpid = pid; /* set $! */
4561 set_curjob(jp, CUR_RUNNING);
4564 struct procstat *ps = &jp->ps[jp->nprocs++];
4570 ps->cmd = commandtext(n);
4576 forkshell(struct job *jp, union node *n, int mode)
4580 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4583 TRACE(("Fork failed, errno=%d", errno));
4586 ash_msg_and_raise_error("cannot fork");
4589 forkchild(jp, n, mode);
4591 forkparent(jp, n, mode, pid);
4596 * Wait for job to finish.
4598 * Under job control we have the problem that while a child process is
4599 * running interrupts generated by the user are sent to the child but not
4600 * to the shell. This means that an infinite loop started by an inter-
4601 * active user may be hard to kill. With job control turned off, an
4602 * interactive user may place an interactive program inside a loop. If
4603 * the interactive program catches interrupts, the user doesn't want
4604 * these interrupts to also abort the loop. The approach we take here
4605 * is to have the shell ignore interrupt signals while waiting for a
4606 * foreground process to terminate, and then send itself an interrupt
4607 * signal if the child process was terminated by an interrupt signal.
4608 * Unfortunately, some programs want to do a bit of cleanup and then
4609 * exit on interrupt; unless these processes terminate themselves by
4610 * sending a signal to themselves (instead of calling exit) they will
4611 * confuse this approach.
4613 * Called with interrupts off.
4616 waitforjob(struct job *jp)
4620 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4621 while (jp->state == JOBRUNNING) {
4622 dowait(DOWAIT_BLOCK, jp);
4627 xtcsetpgrp(ttyfd, rootpid);
4629 * This is truly gross.
4630 * If we're doing job control, then we did a TIOCSPGRP which
4631 * caused us (the shell) to no longer be in the controlling
4632 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4633 * intuit from the subprocess exit status whether a SIGINT
4634 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4636 if (jp->sigint) /* TODO: do the same with all signals */
4637 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4639 if (jp->state == JOBDONE)
4646 * return 1 if there are stopped jobs, otherwise 0
4658 if (jp && jp->state == JOBSTOPPED) {
4659 out2str("You have stopped jobs.\n");
4668 /* ============ redir.c
4670 * Code for dealing with input/output redirection.
4673 #define EMPTY -2 /* marks an unused slot in redirtab */
4674 #define CLOSED -3 /* marks a slot of previously-closed fd */
4676 # define PIPESIZE 4096 /* amount of buffering in a pipe */
4678 # define PIPESIZE PIPE_BUF
4682 * Open a file in noclobber mode.
4683 * The code was copied from bash.
4686 noclobberopen(const char *fname)
4689 struct stat finfo, finfo2;
4692 * If the file exists and is a regular file, return an error
4695 r = stat(fname, &finfo);
4696 if (r == 0 && S_ISREG(finfo.st_mode)) {
4702 * If the file was not present (r != 0), make sure we open it
4703 * exclusively so that if it is created before we open it, our open
4704 * will fail. Make sure that we do not truncate an existing file.
4705 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4706 * file was not a regular file, we leave O_EXCL off.
4709 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4710 fd = open(fname, O_WRONLY|O_CREAT, 0666);
4712 /* If the open failed, return the file descriptor right away. */
4717 * OK, the open succeeded, but the file may have been changed from a
4718 * non-regular file to a regular file between the stat and the open.
4719 * We are assuming that the O_EXCL open handles the case where FILENAME
4720 * did not exist and is symlinked to an existing file between the stat
4725 * If we can open it and fstat the file descriptor, and neither check
4726 * revealed that it was a regular file, and the file has not been
4727 * replaced, return the file descriptor.
4729 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4730 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4733 /* The file has been replaced. badness. */
4740 * Handle here documents. Normally we fork off a process to write the
4741 * data to a pipe. If the document is short, we can stuff the data in
4742 * the pipe without forking.
4744 /* openhere needs this forward reference */
4745 static void expandhere(union node *arg, int fd);
4747 openhere(union node *redir)
4753 ash_msg_and_raise_error("pipe call failed");
4754 if (redir->type == NHERE) {
4755 len = strlen(redir->nhere.doc->narg.text);
4756 if (len <= PIPESIZE) {
4757 full_write(pip[1], redir->nhere.doc->narg.text, len);
4761 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4763 signal(SIGINT, SIG_IGN);
4764 signal(SIGQUIT, SIG_IGN);
4765 signal(SIGHUP, SIG_IGN);
4767 signal(SIGTSTP, SIG_IGN);
4769 signal(SIGPIPE, SIG_DFL);
4770 if (redir->type == NHERE)
4771 full_write(pip[1], redir->nhere.doc->narg.text, len);
4773 expandhere(redir->nhere.doc, pip[1]);
4782 openredirect(union node *redir)
4787 switch (redir->nfile.type) {
4789 fname = redir->nfile.expfname;
4790 f = open(fname, O_RDONLY);
4795 fname = redir->nfile.expfname;
4796 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
4801 /* Take care of noclobber mode. */
4803 fname = redir->nfile.expfname;
4804 f = noclobberopen(fname);
4811 fname = redir->nfile.expfname;
4812 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4817 fname = redir->nfile.expfname;
4818 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4826 /* Fall through to eliminate warning. */
4833 f = openhere(redir);
4839 ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4841 ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "no such file"));
4845 * Copy a file descriptor to be >= to. Returns -1
4846 * if the source file descriptor is closed, EMPTY if there are no unused
4847 * file descriptors left.
4850 copyfd(int from, int to)
4854 newfd = fcntl(from, F_DUPFD, to);
4856 if (errno == EMFILE)
4858 ash_msg_and_raise_error("%d: %m", from);
4864 dupredirect(union node *redir, int f)
4866 int fd = redir->nfile.fd;
4868 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
4869 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
4870 copyfd(redir->ndup.dupfd, fd);
4882 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
4883 * old file descriptors are stashed away so that the redirection can be
4884 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
4885 * standard output, and the standard error if it becomes a duplicate of
4886 * stdout, is saved in memory.
4888 /* flags passed to redirect */
4889 #define REDIR_PUSH 01 /* save previous values of file descriptors */
4890 #define REDIR_SAVEFD2 03 /* set preverrout */
4892 redirect(union node *redir, int flags)
4895 struct redirtab *sv;
4906 if (flags & REDIR_PUSH) {
4907 sv = ckmalloc(sizeof(*sv));
4908 sv->next = redirlist;
4910 sv->nullredirs = g_nullredirs - 1;
4911 for (i = 0; i < 10; i++)
4912 sv->renamed[i] = EMPTY;
4918 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD)
4919 && n->ndup.dupfd == fd)
4920 continue; /* redirect from/to same file descriptor */
4922 newfd = openredirect(n);
4924 /* Descriptor wasn't open before redirect.
4925 * Mark it for close in the future */
4926 if (sv && sv->renamed[fd] == EMPTY)
4927 sv->renamed[fd] = CLOSED;
4930 if (sv && sv->renamed[fd] == EMPTY) {
4931 i = fcntl(fd, F_DUPFD, 10);
4938 ash_msg_and_raise_error("%d: %m", fd);
4942 sv->renamed[fd] = i;
4948 dupredirect(n, newfd);
4949 } while ((n = n->nfile.next));
4951 if ((flags & REDIR_SAVEFD2) && sv && sv->renamed[2] >= 0)
4952 preverrout_fd = sv->renamed[2];
4956 * Undo the effects of the last redirection.
4961 struct redirtab *rp;
4964 if (--g_nullredirs >= 0)
4968 for (i = 0; i < 10; i++) {
4969 if (rp->renamed[i] == CLOSED) {
4974 if (rp->renamed[i] != EMPTY) {
4977 copyfd(rp->renamed[i], i);
4979 close(rp->renamed[i]);
4982 redirlist = rp->next;
4983 g_nullredirs = rp->nullredirs;
4989 * Undo all redirections. Called on error or interrupt.
4993 * Discard all saved file descriptors.
4996 clearredir(int drop)
5007 redirectsafe(union node *redir, int flags)
5010 volatile int saveint;
5011 struct jmploc *volatile savehandler = exception_handler;
5012 struct jmploc jmploc;
5015 err = setjmp(jmploc.loc) * 2;
5017 exception_handler = &jmploc;
5018 redirect(redir, flags);
5020 exception_handler = savehandler;
5021 if (err && exception != EXERROR)
5022 longjmp(exception_handler->loc, 1);
5023 RESTORE_INT(saveint);
5028 /* ============ Routines to expand arguments to commands
5030 * We have to deal with backquotes, shell variables, and file metacharacters.
5036 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5037 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5038 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5039 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5040 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5041 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5042 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5043 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5044 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5048 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5049 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5050 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5051 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5052 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5055 * Structure specifying which parts of the string should be searched
5056 * for IFS characters.
5059 struct ifsregion *next; /* next region in list */
5060 int begoff; /* offset of start of region */
5061 int endoff; /* offset of end of region */
5062 int nulonly; /* search for nul bytes only */
5066 struct strlist *list;
5067 struct strlist **lastp;
5070 /* output of current string */
5071 static char *expdest;
5072 /* list of back quote expressions */
5073 static struct nodelist *argbackq;
5074 /* first struct in list of ifs regions */
5075 static struct ifsregion ifsfirst;
5076 /* last struct in list */
5077 static struct ifsregion *ifslastp;
5078 /* holds expanded arg list */
5079 static struct arglist exparg;
5089 expdest = makestrspace(32, expdest);
5090 #if ENABLE_ASH_MATH_SUPPORT_64
5091 len = fmtstr(expdest, 32, "%lld", (long long) num);
5093 len = fmtstr(expdest, 32, "%ld", num);
5095 STADJUST(len, expdest);
5100 esclen(const char *start, const char *p)
5104 while (p > start && *--p == CTLESC) {
5111 * Remove any CTLESC characters from a string.
5114 _rmescapes(char *str, int flag)
5116 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5123 p = strpbrk(str, qchars);
5129 if (flag & RMESCAPE_ALLOC) {
5130 size_t len = p - str;
5131 size_t fulllen = len + strlen(p) + 1;
5133 if (flag & RMESCAPE_GROW) {
5134 r = makestrspace(fulllen, expdest);
5135 } else if (flag & RMESCAPE_HEAP) {
5136 r = ckmalloc(fulllen);
5138 r = stalloc(fulllen);
5142 q = memcpy(q, str, len) + len;
5145 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5146 globbing = flag & RMESCAPE_GLOB;
5147 notescaped = globbing;
5149 if (*p == CTLQUOTEMARK) {
5150 inquotes = ~inquotes;
5152 notescaped = globbing;
5156 /* naked back slash */
5162 if (notescaped && inquotes && *p != '/') {
5166 notescaped = globbing;
5171 if (flag & RMESCAPE_GROW) {
5173 STADJUST(q - r + 1, expdest);
5177 #define rmescapes(p) _rmescapes((p), 0)
5179 #define pmatch(a, b) !fnmatch((a), (b), 0)
5182 * Prepare a pattern for a expmeta (internal glob(3)) call.
5184 * Returns an stalloced string.
5187 preglob(const char *pattern, int quoted, int flag)
5189 flag |= RMESCAPE_GLOB;
5191 flag |= RMESCAPE_QUOTED;
5193 return _rmescapes((char *)pattern, flag);
5197 * Put a string on the stack.
5200 memtodest(const char *p, size_t len, int syntax, int quotes)
5204 q = makestrspace(len * 2, q);
5207 int c = signed_char2int(*p++);
5210 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5219 strtodest(const char *p, int syntax, int quotes)
5221 memtodest(p, strlen(p), syntax, quotes);
5225 * Record the fact that we have to scan this region of the
5226 * string for IFS characters.
5229 recordregion(int start, int end, int nulonly)
5231 struct ifsregion *ifsp;
5233 if (ifslastp == NULL) {
5237 ifsp = ckzalloc(sizeof(*ifsp));
5238 /*ifsp->next = NULL; - ckzalloc did it */
5239 ifslastp->next = ifsp;
5243 ifslastp->begoff = start;
5244 ifslastp->endoff = end;
5245 ifslastp->nulonly = nulonly;
5249 removerecordregions(int endoff)
5251 if (ifslastp == NULL)
5254 if (ifsfirst.endoff > endoff) {
5255 while (ifsfirst.next != NULL) {
5256 struct ifsregion *ifsp;
5258 ifsp = ifsfirst.next->next;
5259 free(ifsfirst.next);
5260 ifsfirst.next = ifsp;
5263 if (ifsfirst.begoff > endoff)
5266 ifslastp = &ifsfirst;
5267 ifsfirst.endoff = endoff;
5272 ifslastp = &ifsfirst;
5273 while (ifslastp->next && ifslastp->next->begoff < endoff)
5274 ifslastp=ifslastp->next;
5275 while (ifslastp->next != NULL) {
5276 struct ifsregion *ifsp;
5278 ifsp = ifslastp->next->next;
5279 free(ifslastp->next);
5280 ifslastp->next = ifsp;
5283 if (ifslastp->endoff > endoff)
5284 ifslastp->endoff = endoff;
5288 exptilde(char *startp, char *p, int flag)
5294 int quotes = flag & (EXP_FULL | EXP_CASE);
5299 while ((c = *++p) != '\0') {
5306 if (flag & EXP_VARTILDE)
5316 if (*name == '\0') {
5317 home = lookupvar(homestr);
5319 pw = getpwnam(name);
5324 if (!home || !*home)
5327 startloc = expdest - (char *)stackblock();
5328 strtodest(home, SQSYNTAX, quotes);
5329 recordregion(startloc, expdest - (char *)stackblock(), 0);
5337 * Execute a command inside back quotes. If it's a builtin command, we
5338 * want to save its output in a block obtained from malloc. Otherwise
5339 * we fork off a subprocess and get the output of the command via a pipe.
5340 * Should be called with interrupts off.
5342 struct backcmd { /* result of evalbackcmd */
5343 int fd; /* file descriptor to read from */
5344 char *buf; /* buffer */
5345 int nleft; /* number of chars in buffer */
5346 struct job *jp; /* job structure for command */
5349 /* These forward decls are needed to use "eval" code for backticks handling: */
5350 static int back_exitstatus; /* exit status of backquoted command */
5351 #define EV_EXIT 01 /* exit after evaluating tree */
5352 static void evaltree(union node *, int);
5355 evalbackcmd(union node *n, struct backcmd *result)
5367 saveherefd = herefd;
5375 ash_msg_and_raise_error("pipe call failed");
5377 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5386 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5390 result->fd = pip[0];
5393 herefd = saveherefd;
5395 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5396 result->fd, result->buf, result->nleft, result->jp));
5400 * Expand stuff in backwards quotes.
5403 expbackq(union node *cmd, int quoted, int quotes)
5411 int syntax = quoted? DQSYNTAX : BASESYNTAX;
5412 struct stackmark smark;
5415 setstackmark(&smark);
5417 startloc = dest - (char *)stackblock();
5419 evalbackcmd(cmd, &in);
5420 popstackmark(&smark);
5427 memtodest(p, i, syntax, quotes);
5431 i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5432 TRACE(("expbackq: read returns %d\n", i));
5441 back_exitstatus = waitforjob(in.jp);
5445 /* Eat all trailing newlines */
5447 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5452 recordregion(startloc, dest - (char *)stackblock(), 0);
5453 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5454 (dest - (char *)stackblock()) - startloc,
5455 (dest - (char *)stackblock()) - startloc,
5456 stackblock() + startloc));
5459 #if ENABLE_ASH_MATH_SUPPORT
5461 * Expand arithmetic expression. Backup to start of expression,
5462 * evaluate, place result in (backed up) result, adjust string position.
5475 * This routine is slightly over-complicated for
5476 * efficiency. Next we scan backwards looking for the
5477 * start of arithmetic.
5479 start = stackblock();
5486 while (*p != CTLARI) {
5490 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5495 esc = esclen(start, p);
5505 removerecordregions(begoff);
5514 len = cvtnum(dash_arith(p + 2));
5517 recordregion(begoff, begoff + len, 0);
5521 /* argstr needs it */
5522 static char *evalvar(char *p, int flag, struct strlist *var_str_list);
5525 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5526 * characters to allow for further processing. Otherwise treat
5527 * $@ like $* since no splitting will be performed.
5529 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5530 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5531 * for correct expansion of "B=$A" word.
5534 argstr(char *p, int flag, struct strlist *var_str_list)
5536 static const char spclchars[] ALIGN1 = {
5544 CTLBACKQ | CTLQUOTE,
5545 #if ENABLE_ASH_MATH_SUPPORT
5550 const char *reject = spclchars;
5552 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
5553 int breakall = flag & EXP_WORD;
5558 if (!(flag & EXP_VARTILDE)) {
5560 } else if (flag & EXP_VARTILDE2) {
5565 if (flag & EXP_TILDE) {
5571 if (*q == CTLESC && (flag & EXP_QWORD))
5574 p = exptilde(p, q, flag);
5577 startloc = expdest - (char *)stackblock();
5579 length += strcspn(p + length, reject);
5581 if (c && (!(c & 0x80)
5582 #if ENABLE_ASH_MATH_SUPPORT
5586 /* c == '=' || c == ':' || c == CTLENDARI */
5591 expdest = stack_nputstr(p, length, expdest);
5592 newloc = expdest - (char *)stackblock();
5593 if (breakall && !inquotes && newloc > startloc) {
5594 recordregion(startloc, newloc, 0);
5605 if (flag & EXP_VARTILDE2) {
5609 flag |= EXP_VARTILDE2;
5614 * sort of a hack - expand tildes in variable
5615 * assignments (after the first '=' and after ':'s).
5624 case CTLENDVAR: /* ??? */
5627 /* "$@" syntax adherence hack */
5630 !memcmp(p, dolatstr, 4) &&
5631 (p[4] == CTLQUOTEMARK || (
5632 p[4] == CTLENDVAR &&
5633 p[5] == CTLQUOTEMARK
5636 p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;
5639 inquotes = !inquotes;
5652 p = evalvar(p, flag, var_str_list);
5656 case CTLBACKQ|CTLQUOTE:
5657 expbackq(argbackq->n, c, quotes);
5658 argbackq = argbackq->next;
5660 #if ENABLE_ASH_MATH_SUPPORT
5673 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5684 const char *s = loc2;
5690 match = pmatch(str, s);
5694 if (quotes && *loc == CTLESC)
5703 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5710 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5713 const char *s = loc2;
5718 match = pmatch(str, s);
5725 esc = esclen(startp, loc);
5736 static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN;
5738 varunset(const char *end, const char *var, const char *umsg, int varflags)
5744 msg = "parameter not set";
5746 if (*end == CTLENDVAR) {
5747 if (varflags & VSNUL)
5752 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5756 subevalvar(char *p, char *str, int strloc, int subtype,
5757 int startloc, int varflags, int quotes, struct strlist *var_str_list)
5761 int saveherefd = herefd;
5762 struct nodelist *saveargbackq = argbackq;
5764 char *rmesc, *rmescend;
5766 char *(*scan)(char *, char *, char *, char *, int , int);
5769 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
5771 STPUTC('\0', expdest);
5772 herefd = saveherefd;
5773 argbackq = saveargbackq;
5774 startp = stackblock() + startloc;
5778 setvar(str, startp, 0);
5779 amount = startp - expdest;
5780 STADJUST(amount, expdest);
5784 varunset(p, str, startp, varflags);
5788 subtype -= VSTRIMRIGHT;
5790 if (subtype < 0 || subtype > 3)
5795 rmescend = stackblock() + strloc;
5797 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5798 if (rmesc != startp) {
5800 startp = stackblock() + startloc;
5804 str = stackblock() + strloc;
5805 preglob(str, varflags & VSQUOTE, 0);
5807 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5808 zero = subtype >> 1;
5809 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5810 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5812 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5815 memmove(startp, loc, str - loc);
5816 loc = startp + (str - loc) - 1;
5819 amount = loc - expdest;
5820 STADJUST(amount, expdest);
5826 * Add the value of a specialized variable to the stack string.
5829 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
5839 int quoted = varflags & VSQUOTE;
5840 int subtype = varflags & VSTYPE;
5841 int quotes = flags & (EXP_FULL | EXP_CASE);
5843 if (quoted && (flags & EXP_FULL))
5844 sep = 1 << CHAR_BIT;
5846 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5855 num = shellparam.nparam;
5865 p = makestrspace(NOPTS, expdest);
5866 for (i = NOPTS - 1; i >= 0; i--) {
5868 USTPUTC(optletters(i), p);
5879 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
5880 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5886 while ((p = *ap++)) {
5889 partlen = strlen(p);
5892 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5893 memtodest(p, partlen, syntax, quotes);
5899 if (subtype == VSPLUS || subtype == VSLENGTH) {
5921 if (num < 0 || num > shellparam.nparam)
5923 p = num ? shellparam.p[num - 1] : arg0;
5926 /* NB: name has form "VAR=..." */
5928 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
5929 * which should be considered before we check variables. */
5931 unsigned name_len = (strchrnul(name, '=') - name) + 1;
5935 str = var_str_list->text;
5936 eq = strchr(str, '=');
5937 if (!eq) /* stop at first non-assignment */
5940 if (name_len == (eq - str)
5941 && strncmp(str, name, name_len) == 0) {
5943 /* goto value; - WRONG! */
5944 /* think "A=1 A=2 B=$A" */
5946 var_str_list = var_str_list->next;
5947 } while (var_str_list);
5951 p = lookupvar(name);
5957 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5958 memtodest(p, len, syntax, quotes);
5962 if (subtype == VSPLUS || subtype == VSLENGTH)
5963 STADJUST(-len, expdest);
5968 * Expand a variable, and return a pointer to the next character in the
5972 evalvar(char *p, int flag, struct strlist *var_str_list)
5984 subtype = varflags & VSTYPE;
5985 quoted = varflags & VSQUOTE;
5987 easy = (!quoted || (*var == '@' && shellparam.nparam));
5988 startloc = expdest - (char *)stackblock();
5989 p = strchr(p, '=') + 1;
5992 varlen = varvalue(var, varflags, flag, var_str_list);
5993 if (varflags & VSNUL)
5996 if (subtype == VSPLUS) {
5997 varlen = -1 - varlen;
6001 if (subtype == VSMINUS) {
6005 p, flag | EXP_TILDE |
6006 (quoted ? EXP_QWORD : EXP_WORD),
6016 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6018 if (subevalvar(p, var, /* strloc: */ 0,
6019 subtype, startloc, varflags,
6025 * Remove any recorded regions beyond
6028 removerecordregions(startloc);
6038 if (varlen < 0 && uflag)
6039 varunset(p, var, 0, 0);
6041 if (subtype == VSLENGTH) {
6042 cvtnum(varlen > 0 ? varlen : 0);
6046 if (subtype == VSNORMAL) {
6057 case VSTRIMRIGHTMAX:
6066 * Terminate the string and start recording the pattern
6069 STPUTC('\0', expdest);
6070 patloc = expdest - (char *)stackblock();
6071 if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6073 /* quotes: */ flag & (EXP_FULL | EXP_CASE),
6076 int amount = expdest - (
6077 (char *)stackblock() + patloc - 1
6079 STADJUST(-amount, expdest);
6081 /* Remove any recorded regions beyond start of variable */
6082 removerecordregions(startloc);
6084 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6088 if (subtype != VSNORMAL) { /* skip to end of alternative */
6094 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6096 argbackq = argbackq->next;
6097 } else if (c == CTLVAR) {
6098 if ((*p++ & VSTYPE) != VSNORMAL)
6100 } else if (c == CTLENDVAR) {
6110 * Break the argument string into pieces based upon IFS and add the
6111 * strings to the argument list. The regions of the string to be
6112 * searched for IFS characters have been stored by recordregion.
6115 ifsbreakup(char *string, struct arglist *arglist)
6117 struct ifsregion *ifsp;
6122 const char *ifs, *realifs;
6127 if (ifslastp != NULL) {
6130 realifs = ifsset() ? ifsval() : defifs;
6133 p = string + ifsp->begoff;
6134 nulonly = ifsp->nulonly;
6135 ifs = nulonly ? nullstr : realifs;
6137 while (p < string + ifsp->endoff) {
6141 if (!strchr(ifs, *p)) {
6146 ifsspc = (strchr(defifs, *p) != NULL);
6147 /* Ignore IFS whitespace at start */
6148 if (q == start && ifsspc) {
6154 sp = stzalloc(sizeof(*sp));
6156 *arglist->lastp = sp;
6157 arglist->lastp = &sp->next;
6161 if (p >= string + ifsp->endoff) {
6167 if (strchr(ifs, *p) == NULL ) {
6171 if (strchr(defifs, *p) == NULL) {
6186 } while (ifsp != NULL);
6195 sp = stzalloc(sizeof(*sp));
6197 *arglist->lastp = sp;
6198 arglist->lastp = &sp->next;
6204 struct ifsregion *p;
6209 struct ifsregion *ifsp;
6215 ifsfirst.next = NULL;
6220 * Add a file name to the list.
6223 addfname(const char *name)
6227 sp = stzalloc(sizeof(*sp));
6228 sp->text = ststrdup(name);
6230 exparg.lastp = &sp->next;
6233 static char *expdir;
6236 * Do metacharacter (i.e. *, ?, [...]) expansion.
6239 expmeta(char *enddir, char *name)
6254 for (p = name; *p; p++) {
6255 if (*p == '*' || *p == '?')
6257 else if (*p == '[') {
6264 if (*q == '/' || *q == '\0')
6271 } else if (*p == '\\')
6273 else if (*p == '/') {
6280 if (metaflag == 0) { /* we've reached the end of the file name */
6281 if (enddir != expdir)
6289 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6300 } while (p < start);
6302 if (enddir == expdir) {
6304 } else if (enddir == expdir + 1 && *expdir == '/') {
6313 if (enddir != expdir)
6315 if (*endname == 0) {
6327 while (!intpending && (dp = readdir(dirp)) != NULL) {
6328 if (dp->d_name[0] == '.' && ! matchdot)
6330 if (pmatch(start, dp->d_name)) {
6332 strcpy(enddir, dp->d_name);
6335 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6338 expmeta(p, endname);
6347 static struct strlist *
6348 msort(struct strlist *list, int len)
6350 struct strlist *p, *q = NULL;
6351 struct strlist **lpp;
6359 for (n = half; --n >= 0; ) {
6363 q->next = NULL; /* terminate first half of list */
6364 q = msort(list, half); /* sort first half of list */
6365 p = msort(p, len - half); /* sort second half */
6368 #if ENABLE_LOCALE_SUPPORT
6369 if (strcoll(p->text, q->text) < 0)
6371 if (strcmp(p->text, q->text) < 0)
6395 * Sort the results of file name expansion. It calculates the number of
6396 * strings to sort and then calls msort (short for merge sort) to do the
6399 static struct strlist *
6400 expsort(struct strlist *str)
6406 for (sp = str; sp; sp = sp->next)
6408 return msort(str, len);
6412 expandmeta(struct strlist *str, int flag)
6414 static const char metachars[] ALIGN1 = {
6417 /* TODO - EXP_REDIR */
6420 struct strlist **savelastp;
6426 if (!strpbrk(str->text, metachars))
6428 savelastp = exparg.lastp;
6431 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
6433 int i = strlen(str->text);
6434 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
6442 if (exparg.lastp == savelastp) {
6447 *exparg.lastp = str;
6448 rmescapes(str->text);
6449 exparg.lastp = &str->next;
6451 *exparg.lastp = NULL;
6452 *savelastp = sp = expsort(*savelastp);
6453 while (sp->next != NULL)
6455 exparg.lastp = &sp->next;
6462 * Perform variable substitution and command substitution on an argument,
6463 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6464 * perform splitting and file name expansion. When arglist is NULL, perform
6465 * here document expansion.
6468 expandarg(union node *arg, struct arglist *arglist, int flag)
6473 argbackq = arg->narg.backquote;
6474 STARTSTACKSTR(expdest);
6475 ifsfirst.next = NULL;
6477 argstr(arg->narg.text, flag,
6478 /* var_str_list: */ arglist ? arglist->list : NULL);
6479 p = _STPUTC('\0', expdest);
6481 if (arglist == NULL) {
6482 return; /* here document expanded */
6484 p = grabstackstr(p);
6485 exparg.lastp = &exparg.list;
6489 if (flag & EXP_FULL) {
6490 ifsbreakup(p, &exparg);
6491 *exparg.lastp = NULL;
6492 exparg.lastp = &exparg.list;
6493 expandmeta(exparg.list, flag);
6495 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
6497 sp = stzalloc(sizeof(*sp));
6500 exparg.lastp = &sp->next;
6504 *exparg.lastp = NULL;
6506 *arglist->lastp = exparg.list;
6507 arglist->lastp = exparg.lastp;
6512 * Expand shell variables and backquotes inside a here document.
6515 expandhere(union node *arg, int fd)
6518 expandarg(arg, (struct arglist *)NULL, 0);
6519 full_write(fd, stackblock(), expdest - (char *)stackblock());
6523 * Returns true if the pattern matches the string.
6526 patmatch(char *pattern, const char *string)
6528 return pmatch(preglob(pattern, 0, 0), string);
6532 * See if a pattern matches in a case statement.
6535 casematch(union node *pattern, char *val)
6537 struct stackmark smark;
6540 setstackmark(&smark);
6541 argbackq = pattern->narg.backquote;
6542 STARTSTACKSTR(expdest);
6544 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
6545 /* var_str_list: */ NULL);
6546 STACKSTRNUL(expdest);
6547 result = patmatch(stackblock(), val);
6548 popstackmark(&smark);
6553 /* ============ find_command */
6557 int (*builtin)(int, char **);
6558 /* unsigned flags; */
6560 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
6561 /* "regular" builtins always take precedence over commands,
6562 * regardless of PATH=....%builtin... position */
6563 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
6564 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
6570 const struct builtincmd *cmd;
6571 struct funcnode *func;
6574 /* values of cmdtype */
6575 #define CMDUNKNOWN -1 /* no entry in table for command */
6576 #define CMDNORMAL 0 /* command is an executable program */
6577 #define CMDFUNCTION 1 /* command is a shell function */
6578 #define CMDBUILTIN 2 /* command is a shell builtin */
6580 /* action to find_command() */
6581 #define DO_ERR 0x01 /* prints errors */
6582 #define DO_ABS 0x02 /* checks absolute paths */
6583 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
6584 #define DO_ALTPATH 0x08 /* using alternate path */
6585 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
6587 static void find_command(char *, struct cmdentry *, int, const char *);
6590 /* ============ Hashing commands */
6593 * When commands are first encountered, they are entered in a hash table.
6594 * This ensures that a full path search will not have to be done for them
6595 * on each invocation.
6597 * We should investigate converting to a linear search, even though that
6598 * would make the command name "hash" a misnomer.
6601 #define ARB 1 /* actual size determined at run time */
6604 struct tblentry *next; /* next entry in hash chain */
6605 union param param; /* definition of builtin function */
6606 short cmdtype; /* index identifying command */
6607 char rehash; /* if set, cd done since entry created */
6608 char cmdname[ARB]; /* name of command */
6611 static struct tblentry **cmdtable;
6612 #define INIT_G_cmdtable() do { \
6613 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
6616 static int builtinloc = -1; /* index in path of %builtin, or -1 */
6620 tryexec(char *cmd, char **argv, char **envp)
6624 #if ENABLE_FEATURE_SH_STANDALONE
6625 if (strchr(cmd, '/') == NULL) {
6626 int a = find_applet_by_name(cmd);
6628 if (APPLET_IS_NOEXEC(a))
6629 run_applet_no_and_exit(a, argv);
6630 /* re-exec ourselves with the new arguments */
6631 execve(bb_busybox_exec_path, argv, envp);
6632 /* If they called chroot or otherwise made the binary no longer
6633 * executable, fall through */
6641 execve(cmd, argv, envp);
6642 } while (errno == EINTR);
6644 execve(cmd, argv, envp);
6648 } else if (errno == ENOEXEC) {
6652 for (ap = argv; *ap; ap++)
6654 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
6656 ap[0] = cmd = (char *)DEFAULT_SHELL;
6659 while ((*ap++ = *argv++))
6667 * Exec a program. Never returns. If you change this routine, you may
6668 * have to change the find_command routine as well.
6670 #define environment() listvars(VEXPORT, VUNSET, 0)
6671 static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
6673 shellexec(char **argv, const char *path, int idx)
6681 envp = environment();
6682 if (strchr(argv[0], '/')
6683 #if ENABLE_FEATURE_SH_STANDALONE
6684 || find_applet_by_name(argv[0]) >= 0
6687 tryexec(argv[0], argv, envp);
6691 while ((cmdname = padvance(&path, argv[0])) != NULL) {
6692 if (--idx < 0 && pathopt == NULL) {
6693 tryexec(cmdname, argv, envp);
6694 if (errno != ENOENT && errno != ENOTDIR)
6701 /* Map to POSIX errors */
6713 exitstatus = exerrno;
6714 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
6715 argv[0], e, suppressint ));
6716 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
6721 printentry(struct tblentry *cmdp)
6727 idx = cmdp->param.index;
6730 name = padvance(&path, cmdp->cmdname);
6732 } while (--idx >= 0);
6733 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
6737 * Clear out command entries. The argument specifies the first entry in
6738 * PATH which has changed.
6741 clearcmdentry(int firstchange)
6743 struct tblentry **tblp;
6744 struct tblentry **pp;
6745 struct tblentry *cmdp;
6748 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
6750 while ((cmdp = *pp) != NULL) {
6751 if ((cmdp->cmdtype == CMDNORMAL &&
6752 cmdp->param.index >= firstchange)
6753 || (cmdp->cmdtype == CMDBUILTIN &&
6754 builtinloc >= firstchange)
6767 * Locate a command in the command hash table. If "add" is nonzero,
6768 * add the command to the table if it is not already present. The
6769 * variable "lastcmdentry" is set to point to the address of the link
6770 * pointing to the entry, so that delete_cmd_entry can delete the
6773 * Interrupts must be off if called with add != 0.
6775 static struct tblentry **lastcmdentry;
6777 static struct tblentry *
6778 cmdlookup(const char *name, int add)
6780 unsigned int hashval;
6782 struct tblentry *cmdp;
6783 struct tblentry **pp;
6786 hashval = (unsigned char)*p << 4;
6788 hashval += (unsigned char)*p++;
6790 pp = &cmdtable[hashval % CMDTABLESIZE];
6791 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6792 if (strcmp(cmdp->cmdname, name) == 0)
6796 if (add && cmdp == NULL) {
6797 cmdp = *pp = ckzalloc(sizeof(struct tblentry) - ARB
6798 + strlen(name) + 1);
6799 /*cmdp->next = NULL; - ckzalloc did it */
6800 cmdp->cmdtype = CMDUNKNOWN;
6801 strcpy(cmdp->cmdname, name);
6808 * Delete the command entry returned on the last lookup.
6811 delete_cmd_entry(void)
6813 struct tblentry *cmdp;
6816 cmdp = *lastcmdentry;
6817 *lastcmdentry = cmdp->next;
6818 if (cmdp->cmdtype == CMDFUNCTION)
6819 freefunc(cmdp->param.func);
6825 * Add a new command entry, replacing any existing command entry for
6826 * the same name - except special builtins.
6829 addcmdentry(char *name, struct cmdentry *entry)
6831 struct tblentry *cmdp;
6833 cmdp = cmdlookup(name, 1);
6834 if (cmdp->cmdtype == CMDFUNCTION) {
6835 freefunc(cmdp->param.func);
6837 cmdp->cmdtype = entry->cmdtype;
6838 cmdp->param = entry->u;
6843 hashcmd(int argc, char **argv)
6845 struct tblentry **pp;
6846 struct tblentry *cmdp;
6848 struct cmdentry entry;
6851 if (nextopt("r") != '\0') {
6856 if (*argptr == NULL) {
6857 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
6858 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6859 if (cmdp->cmdtype == CMDNORMAL)
6867 while ((name = *argptr) != NULL) {
6868 cmdp = cmdlookup(name, 0);
6870 && (cmdp->cmdtype == CMDNORMAL
6871 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
6875 find_command(name, &entry, DO_ERR, pathval());
6876 if (entry.cmdtype == CMDUNKNOWN)
6884 * Called when a cd is done. Marks all commands so the next time they
6885 * are executed they will be rehashed.
6890 struct tblentry **pp;
6891 struct tblentry *cmdp;
6893 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
6894 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6895 if (cmdp->cmdtype == CMDNORMAL
6896 || (cmdp->cmdtype == CMDBUILTIN
6897 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
6907 * Fix command hash table when PATH changed.
6908 * Called before PATH is changed. The argument is the new value of PATH;
6909 * pathval() still returns the old value at this point.
6910 * Called with interrupts off.
6913 changepath(const char *new)
6921 firstchange = 9999; /* assume no change */
6927 if ((*old == '\0' && *new == ':')
6928 || (*old == ':' && *new == '\0'))
6930 old = new; /* ignore subsequent differences */
6934 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
6940 if (builtinloc < 0 && idx_bltin >= 0)
6941 builtinloc = idx_bltin; /* zap builtins */
6942 if (builtinloc >= 0 && idx_bltin < 0)
6944 clearcmdentry(firstchange);
6945 builtinloc = idx_bltin;
6960 #define TENDBQUOTE 12
6978 /* first char is indicating which tokens mark the end of a list */
6979 static const char *const tokname_array[] = {
6993 #define KWDOFFSET 13
6994 /* the following are keywords */
7016 static char buf[16];
7019 //if (tok < TSEMI) return tokname_array[tok] + 1;
7020 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
7025 sprintf(buf + (tok >= TSEMI), "%s%c",
7026 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
7030 /* Wrapper around strcmp for qsort/bsearch/... */
7032 pstrcmp(const void *a, const void *b)
7034 return strcmp((char*) a, (*(char**) b) + 1);
7037 static const char *const *
7038 findkwd(const char *s)
7040 return bsearch(s, tokname_array + KWDOFFSET,
7041 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7042 sizeof(tokname_array[0]), pstrcmp);
7046 * Locate and print what a word is...
7049 describe_command(char *command, int describe_command_verbose)
7051 struct cmdentry entry;
7052 struct tblentry *cmdp;
7053 #if ENABLE_ASH_ALIAS
7054 const struct alias *ap;
7056 const char *path = pathval();
7058 if (describe_command_verbose) {
7062 /* First look at the keywords */
7063 if (findkwd(command)) {
7064 out1str(describe_command_verbose ? " is a shell keyword" : command);
7068 #if ENABLE_ASH_ALIAS
7069 /* Then look at the aliases */
7070 ap = lookupalias(command, 0);
7072 if (!describe_command_verbose) {
7077 out1fmt(" is an alias for %s", ap->val);
7081 /* Then check if it is a tracked alias */
7082 cmdp = cmdlookup(command, 0);
7084 entry.cmdtype = cmdp->cmdtype;
7085 entry.u = cmdp->param;
7087 /* Finally use brute force */
7088 find_command(command, &entry, DO_ABS, path);
7091 switch (entry.cmdtype) {
7093 int j = entry.u.index;
7099 p = padvance(&path, command);
7103 if (describe_command_verbose) {
7105 (cmdp ? " a tracked alias for" : nullstr), p
7114 if (describe_command_verbose) {
7115 out1str(" is a shell function");
7122 if (describe_command_verbose) {
7123 out1fmt(" is a %sshell builtin",
7124 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7125 "special " : nullstr
7133 if (describe_command_verbose) {
7134 out1str(": not found\n");
7139 outstr("\n", stdout);
7144 typecmd(int argc, char **argv)
7150 /* type -p ... ? (we don't bother checking for 'p') */
7151 if (argv[1] && argv[1][0] == '-') {
7156 err |= describe_command(argv[i++], verbose);
7161 #if ENABLE_ASH_CMDCMD
7163 commandcmd(int argc, char **argv)
7171 while ((c = nextopt("pvV")) != '\0')
7173 verify |= VERIFY_VERBOSE;
7175 verify |= VERIFY_BRIEF;
7181 return describe_command(*argptr, verify - VERIFY_BRIEF);
7188 /* ============ eval.c */
7190 static int funcblocksize; /* size of structures in function */
7191 static int funcstringsize; /* size of strings in node */
7192 static void *funcblock; /* block to allocate function from */
7193 static char *funcstring; /* block to allocate strings from */
7195 /* flags in argument to evaltree */
7196 #define EV_EXIT 01 /* exit after evaluating tree */
7197 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7198 #define EV_BACKCMD 04 /* command executing within back quotes */
7200 static const short nodesize[26] = {
7201 SHELL_ALIGN(sizeof(struct ncmd)),
7202 SHELL_ALIGN(sizeof(struct npipe)),
7203 SHELL_ALIGN(sizeof(struct nredir)),
7204 SHELL_ALIGN(sizeof(struct nredir)),
7205 SHELL_ALIGN(sizeof(struct nredir)),
7206 SHELL_ALIGN(sizeof(struct nbinary)),
7207 SHELL_ALIGN(sizeof(struct nbinary)),
7208 SHELL_ALIGN(sizeof(struct nbinary)),
7209 SHELL_ALIGN(sizeof(struct nif)),
7210 SHELL_ALIGN(sizeof(struct nbinary)),
7211 SHELL_ALIGN(sizeof(struct nbinary)),
7212 SHELL_ALIGN(sizeof(struct nfor)),
7213 SHELL_ALIGN(sizeof(struct ncase)),
7214 SHELL_ALIGN(sizeof(struct nclist)),
7215 SHELL_ALIGN(sizeof(struct narg)),
7216 SHELL_ALIGN(sizeof(struct narg)),
7217 SHELL_ALIGN(sizeof(struct nfile)),
7218 SHELL_ALIGN(sizeof(struct nfile)),
7219 SHELL_ALIGN(sizeof(struct nfile)),
7220 SHELL_ALIGN(sizeof(struct nfile)),
7221 SHELL_ALIGN(sizeof(struct nfile)),
7222 SHELL_ALIGN(sizeof(struct ndup)),
7223 SHELL_ALIGN(sizeof(struct ndup)),
7224 SHELL_ALIGN(sizeof(struct nhere)),
7225 SHELL_ALIGN(sizeof(struct nhere)),
7226 SHELL_ALIGN(sizeof(struct nnot)),
7229 static void calcsize(union node *n);
7232 sizenodelist(struct nodelist *lp)
7235 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7242 calcsize(union node *n)
7246 funcblocksize += nodesize[n->type];
7249 calcsize(n->ncmd.redirect);
7250 calcsize(n->ncmd.args);
7251 calcsize(n->ncmd.assign);
7254 sizenodelist(n->npipe.cmdlist);
7259 calcsize(n->nredir.redirect);
7260 calcsize(n->nredir.n);
7267 calcsize(n->nbinary.ch2);
7268 calcsize(n->nbinary.ch1);
7271 calcsize(n->nif.elsepart);
7272 calcsize(n->nif.ifpart);
7273 calcsize(n->nif.test);
7276 funcstringsize += strlen(n->nfor.var) + 1;
7277 calcsize(n->nfor.body);
7278 calcsize(n->nfor.args);
7281 calcsize(n->ncase.cases);
7282 calcsize(n->ncase.expr);
7285 calcsize(n->nclist.body);
7286 calcsize(n->nclist.pattern);
7287 calcsize(n->nclist.next);
7291 sizenodelist(n->narg.backquote);
7292 funcstringsize += strlen(n->narg.text) + 1;
7293 calcsize(n->narg.next);
7300 calcsize(n->nfile.fname);
7301 calcsize(n->nfile.next);
7305 calcsize(n->ndup.vname);
7306 calcsize(n->ndup.next);
7310 calcsize(n->nhere.doc);
7311 calcsize(n->nhere.next);
7314 calcsize(n->nnot.com);
7320 nodeckstrdup(char *s)
7322 char *rtn = funcstring;
7324 strcpy(funcstring, s);
7325 funcstring += strlen(s) + 1;
7329 static union node *copynode(union node *);
7331 static struct nodelist *
7332 copynodelist(struct nodelist *lp)
7334 struct nodelist *start;
7335 struct nodelist **lpp;
7340 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7341 (*lpp)->n = copynode(lp->n);
7343 lpp = &(*lpp)->next;
7350 copynode(union node *n)
7357 funcblock = (char *) funcblock + nodesize[n->type];
7361 new->ncmd.redirect = copynode(n->ncmd.redirect);
7362 new->ncmd.args = copynode(n->ncmd.args);
7363 new->ncmd.assign = copynode(n->ncmd.assign);
7366 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7367 new->npipe.backgnd = n->npipe.backgnd;
7372 new->nredir.redirect = copynode(n->nredir.redirect);
7373 new->nredir.n = copynode(n->nredir.n);
7380 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7381 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7384 new->nif.elsepart = copynode(n->nif.elsepart);
7385 new->nif.ifpart = copynode(n->nif.ifpart);
7386 new->nif.test = copynode(n->nif.test);
7389 new->nfor.var = nodeckstrdup(n->nfor.var);
7390 new->nfor.body = copynode(n->nfor.body);
7391 new->nfor.args = copynode(n->nfor.args);
7394 new->ncase.cases = copynode(n->ncase.cases);
7395 new->ncase.expr = copynode(n->ncase.expr);
7398 new->nclist.body = copynode(n->nclist.body);
7399 new->nclist.pattern = copynode(n->nclist.pattern);
7400 new->nclist.next = copynode(n->nclist.next);
7404 new->narg.backquote = copynodelist(n->narg.backquote);
7405 new->narg.text = nodeckstrdup(n->narg.text);
7406 new->narg.next = copynode(n->narg.next);
7413 new->nfile.fname = copynode(n->nfile.fname);
7414 new->nfile.fd = n->nfile.fd;
7415 new->nfile.next = copynode(n->nfile.next);
7419 new->ndup.vname = copynode(n->ndup.vname);
7420 new->ndup.dupfd = n->ndup.dupfd;
7421 new->ndup.fd = n->ndup.fd;
7422 new->ndup.next = copynode(n->ndup.next);
7426 new->nhere.doc = copynode(n->nhere.doc);
7427 new->nhere.fd = n->nhere.fd;
7428 new->nhere.next = copynode(n->nhere.next);
7431 new->nnot.com = copynode(n->nnot.com);
7434 new->type = n->type;
7439 * Make a copy of a parse tree.
7441 static struct funcnode *
7442 copyfunc(union node *n)
7447 funcblocksize = offsetof(struct funcnode, n);
7450 blocksize = funcblocksize;
7451 f = ckmalloc(blocksize + funcstringsize);
7452 funcblock = (char *) f + offsetof(struct funcnode, n);
7453 funcstring = (char *) f + blocksize;
7460 * Define a shell function.
7463 defun(char *name, union node *func)
7465 struct cmdentry entry;
7468 entry.cmdtype = CMDFUNCTION;
7469 entry.u.func = copyfunc(func);
7470 addcmdentry(name, &entry);
7474 static int evalskip; /* set if we are skipping commands */
7475 /* reasons for skipping commands (see comment on breakcmd routine) */
7476 #define SKIPBREAK (1 << 0)
7477 #define SKIPCONT (1 << 1)
7478 #define SKIPFUNC (1 << 2)
7479 #define SKIPFILE (1 << 3)
7480 #define SKIPEVAL (1 << 4)
7481 static int skipcount; /* number of levels to skip */
7482 static int funcnest; /* depth of function calls */
7484 /* forward decl way out to parsing code - dotrap needs it */
7485 static int evalstring(char *s, int mask);
7488 * Called to execute a trap. Perhaps we should avoid entering new trap
7489 * handlers while we are executing a trap handler.
7500 savestatus = exitstatus;
7504 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
7512 skip = evalstring(p, SKIPEVAL);
7513 exitstatus = savestatus;
7521 /* forward declarations - evaluation is fairly recursive business... */
7522 static void evalloop(union node *, int);
7523 static void evalfor(union node *, int);
7524 static void evalcase(union node *, int);
7525 static void evalsubshell(union node *, int);
7526 static void expredir(union node *);
7527 static void evalpipe(union node *, int);
7528 static void evalcommand(union node *, int);
7529 static int evalbltin(const struct builtincmd *, int, char **);
7530 static void prehash(union node *);
7533 * Evaluate a parse tree. The value is left in the global variable
7537 evaltree(union node *n, int flags)
7540 void (*evalfn)(union node *, int);
7544 TRACE(("evaltree(NULL) called\n"));
7547 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
7548 getpid(), n, n->type, flags));
7552 out1fmt("Node type = %d\n", n->type);
7557 evaltree(n->nnot.com, EV_TESTED);
7558 status = !exitstatus;
7561 expredir(n->nredir.redirect);
7562 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
7564 evaltree(n->nredir.n, flags & EV_TESTED);
7565 status = exitstatus;
7570 evalfn = evalcommand;
7572 if (eflag && !(flags & EV_TESTED))
7584 evalfn = evalsubshell;
7596 #error NAND + 1 != NOR
7598 #if NOR + 1 != NSEMI
7599 #error NOR + 1 != NSEMI
7601 isor = n->type - NAND;
7604 (flags | ((isor >> 1) - 1)) & EV_TESTED
7606 if (!exitstatus == isor)
7618 evaltree(n->nif.test, EV_TESTED);
7621 if (exitstatus == 0) {
7624 } else if (n->nif.elsepart) {
7625 n = n->nif.elsepart;
7630 defun(n->narg.text, n->narg.next);
7634 exitstatus = status;
7638 if ((checkexit & exitstatus))
7639 evalskip |= SKIPEVAL;
7640 else if (pendingsig && dotrap())
7643 if (flags & EV_EXIT) {
7645 raise_exception(EXEXIT);
7649 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
7652 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
7654 static int loopnest; /* current loop nesting level */
7657 evalloop(union node *n, int flags)
7667 evaltree(n->nbinary.ch1, EV_TESTED);
7670 if (evalskip == SKIPCONT && --skipcount <= 0) {
7674 if (evalskip == SKIPBREAK && --skipcount <= 0)
7679 if (n->type != NWHILE)
7683 evaltree(n->nbinary.ch2, flags);
7684 status = exitstatus;
7689 exitstatus = status;
7693 evalfor(union node *n, int flags)
7695 struct arglist arglist;
7698 struct stackmark smark;
7700 setstackmark(&smark);
7701 arglist.list = NULL;
7702 arglist.lastp = &arglist.list;
7703 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
7704 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
7709 *arglist.lastp = NULL;
7714 for (sp = arglist.list; sp; sp = sp->next) {
7715 setvar(n->nfor.var, sp->text, 0);
7716 evaltree(n->nfor.body, flags);
7718 if (evalskip == SKIPCONT && --skipcount <= 0) {
7722 if (evalskip == SKIPBREAK && --skipcount <= 0)
7729 popstackmark(&smark);
7733 evalcase(union node *n, int flags)
7737 struct arglist arglist;
7738 struct stackmark smark;
7740 setstackmark(&smark);
7741 arglist.list = NULL;
7742 arglist.lastp = &arglist.list;
7743 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
7745 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
7746 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
7747 if (casematch(patp, arglist.list->text)) {
7748 if (evalskip == 0) {
7749 evaltree(cp->nclist.body, flags);
7756 popstackmark(&smark);
7760 * Kick off a subshell to evaluate a tree.
7763 evalsubshell(union node *n, int flags)
7766 int backgnd = (n->type == NBACKGND);
7769 expredir(n->nredir.redirect);
7770 if (!backgnd && flags & EV_EXIT && !trap[0])
7774 if (forkshell(jp, n, backgnd) == 0) {
7778 flags &=~ EV_TESTED;
7780 redirect(n->nredir.redirect, 0);
7781 evaltreenr(n->nredir.n, flags);
7786 status = waitforjob(jp);
7787 exitstatus = status;
7792 * Compute the names of the files in a redirection list.
7794 static void fixredir(union node *, const char *, int);
7796 expredir(union node *n)
7800 for (redir = n; redir; redir = redir->nfile.next) {
7804 fn.lastp = &fn.list;
7805 switch (redir->type) {
7811 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
7812 redir->nfile.expfname = fn.list->text;
7816 if (redir->ndup.vname) {
7817 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
7818 if (fn.list == NULL)
7819 ash_msg_and_raise_error("redir error");
7820 fixredir(redir, fn.list->text, 1);
7828 * Evaluate a pipeline. All the processes in the pipeline are children
7829 * of the process creating the pipeline. (This differs from some versions
7830 * of the shell, which make the last process in a pipeline the parent
7834 evalpipe(union node *n, int flags)
7837 struct nodelist *lp;
7842 TRACE(("evalpipe(0x%lx) called\n", (long)n));
7844 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
7848 jp = makejob(n, pipelen);
7850 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
7854 if (pipe(pip) < 0) {
7856 ash_msg_and_raise_error("pipe call failed");
7859 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
7872 evaltreenr(lp->n, flags);
7880 if (n->npipe.backgnd == 0) {
7881 exitstatus = waitforjob(jp);
7882 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
7888 * Controls whether the shell is interactive or not.
7891 setinteractive(int on)
7893 static int is_interactive;
7895 if (++on == is_interactive)
7897 is_interactive = on;
7901 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
7902 if (is_interactive > 1) {
7903 /* Looks like they want an interactive shell */
7904 static smallint did_banner;
7909 "%s built-in shell (ash)\n"
7910 "Enter 'help' for a list of built-in commands."
7919 #if ENABLE_FEATURE_EDITING_VI
7920 #define setvimode(on) do { \
7921 if (on) line_input_state->flags |= VI_MODE; \
7922 else line_input_state->flags &= ~VI_MODE; \
7925 #define setvimode(on) viflag = 0 /* forcibly keep the option off */
7934 setinteractive(iflag);
7939 static struct localvar *localvars;
7942 * Called after a function returns.
7943 * Interrupts must be off.
7948 struct localvar *lvp;
7951 while ((lvp = localvars) != NULL) {
7952 localvars = lvp->next;
7954 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
7955 if (vp == NULL) { /* $- saved */
7956 memcpy(optlist, lvp->text, sizeof(optlist));
7957 free((char*)lvp->text);
7959 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
7963 (*vp->func)(strchrnul(lvp->text, '=') + 1);
7964 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
7965 free((char*)vp->text);
7966 vp->flags = lvp->flags;
7967 vp->text = lvp->text;
7974 evalfun(struct funcnode *func, int argc, char **argv, int flags)
7976 volatile struct shparam saveparam;
7977 struct localvar *volatile savelocalvars;
7978 struct jmploc *volatile savehandler;
7979 struct jmploc jmploc;
7982 saveparam = shellparam;
7983 savelocalvars = localvars;
7984 e = setjmp(jmploc.loc);
7989 savehandler = exception_handler;
7990 exception_handler = &jmploc;
7992 shellparam.malloced = 0;
7996 shellparam.nparam = argc - 1;
7997 shellparam.p = argv + 1;
7998 #if ENABLE_ASH_GETOPTS
7999 shellparam.optind = 1;
8000 shellparam.optoff = -1;
8002 evaltree(&func->n, flags & EV_TESTED);
8008 localvars = savelocalvars;
8009 freeparam(&shellparam);
8010 shellparam = saveparam;
8011 exception_handler = savehandler;
8013 evalskip &= ~SKIPFUNC;
8017 #if ENABLE_ASH_CMDCMD
8019 parse_command_args(char **argv, const char **path)
8032 if (c == '-' && !*cp) {
8039 *path = bb_default_path;
8042 /* run 'typecmd' for other options */
8053 * Make a variable a local variable. When a variable is made local, it's
8054 * value and flags are saved in a localvar structure. The saved values
8055 * will be restored when the shell function returns. We handle the name
8056 * "-" as a special case.
8061 struct localvar *lvp;
8066 lvp = ckzalloc(sizeof(struct localvar));
8067 if (LONE_DASH(name)) {
8069 p = ckmalloc(sizeof(optlist));
8070 lvp->text = memcpy(p, optlist, sizeof(optlist));
8075 vpp = hashvar(name);
8076 vp = *findvar(vpp, name);
8077 eq = strchr(name, '=');
8080 setvareq(name, VSTRFIXED);
8082 setvar(name, NULL, VSTRFIXED);
8083 vp = *vpp; /* the new variable */
8084 lvp->flags = VUNSET;
8086 lvp->text = vp->text;
8087 lvp->flags = vp->flags;
8088 vp->flags |= VSTRFIXED|VTEXTFIXED;
8094 lvp->next = localvars;
8100 * The "local" command.
8103 localcmd(int argc, char **argv)
8108 while ((name = *argv++) != NULL) {
8115 falsecmd(int argc, char **argv)
8121 truecmd(int argc, char **argv)
8127 execcmd(int argc, char **argv)
8130 iflag = 0; /* exit on error */
8133 shellexec(argv + 1, pathval(), 0);
8139 * The return command.
8142 returncmd(int argc, char **argv)
8145 * If called outside a function, do what ksh does;
8146 * skip the rest of the file.
8148 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8149 return argv[1] ? number(argv[1]) : exitstatus;
8152 /* Forward declarations for builtintab[] */
8153 static int breakcmd(int, char **);
8154 static int dotcmd(int, char **);
8155 static int evalcmd(int, char **);
8156 #if ENABLE_ASH_BUILTIN_ECHO
8157 static int echocmd(int, char **);
8159 #if ENABLE_ASH_BUILTIN_TEST
8160 static int testcmd(int, char **);
8162 static int exitcmd(int, char **);
8163 static int exportcmd(int, char **);
8164 #if ENABLE_ASH_GETOPTS
8165 static int getoptscmd(int, char **);
8167 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8168 static int helpcmd(int argc, char **argv);
8170 #if ENABLE_ASH_MATH_SUPPORT
8171 static int letcmd(int, char **);
8173 static int readcmd(int, char **);
8174 static int setcmd(int, char **);
8175 static int shiftcmd(int, char **);
8176 static int timescmd(int, char **);
8177 static int trapcmd(int, char **);
8178 static int umaskcmd(int, char **);
8179 static int unsetcmd(int, char **);
8180 static int ulimitcmd(int, char **);
8182 #define BUILTIN_NOSPEC "0"
8183 #define BUILTIN_SPECIAL "1"
8184 #define BUILTIN_REGULAR "2"
8185 #define BUILTIN_SPEC_REG "3"
8186 #define BUILTIN_ASSIGN "4"
8187 #define BUILTIN_SPEC_ASSG "5"
8188 #define BUILTIN_REG_ASSG "6"
8189 #define BUILTIN_SPEC_REG_ASSG "7"
8191 /* make sure to keep these in proper order since it is searched via bsearch() */
8192 static const struct builtincmd builtintab[] = {
8193 { BUILTIN_SPEC_REG ".", dotcmd },
8194 { BUILTIN_SPEC_REG ":", truecmd },
8195 #if ENABLE_ASH_BUILTIN_TEST
8196 { BUILTIN_REGULAR "[", testcmd },
8197 { BUILTIN_REGULAR "[[", testcmd },
8199 #if ENABLE_ASH_ALIAS
8200 { BUILTIN_REG_ASSG "alias", aliascmd },
8203 { BUILTIN_REGULAR "bg", fg_bgcmd },
8205 { BUILTIN_SPEC_REG "break", breakcmd },
8206 { BUILTIN_REGULAR "cd", cdcmd },
8207 { BUILTIN_NOSPEC "chdir", cdcmd },
8208 #if ENABLE_ASH_CMDCMD
8209 { BUILTIN_REGULAR "command", commandcmd },
8211 { BUILTIN_SPEC_REG "continue", breakcmd },
8212 #if ENABLE_ASH_BUILTIN_ECHO
8213 { BUILTIN_REGULAR "echo", echocmd },
8215 { BUILTIN_SPEC_REG "eval", evalcmd },
8216 { BUILTIN_SPEC_REG "exec", execcmd },
8217 { BUILTIN_SPEC_REG "exit", exitcmd },
8218 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8219 { BUILTIN_REGULAR "false", falsecmd },
8221 { BUILTIN_REGULAR "fg", fg_bgcmd },
8223 #if ENABLE_ASH_GETOPTS
8224 { BUILTIN_REGULAR "getopts", getoptscmd },
8226 { BUILTIN_NOSPEC "hash", hashcmd },
8227 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8228 { BUILTIN_NOSPEC "help", helpcmd },
8231 { BUILTIN_REGULAR "jobs", jobscmd },
8232 { BUILTIN_REGULAR "kill", killcmd },
8234 #if ENABLE_ASH_MATH_SUPPORT
8235 { BUILTIN_NOSPEC "let", letcmd },
8237 { BUILTIN_ASSIGN "local", localcmd },
8238 { BUILTIN_NOSPEC "pwd", pwdcmd },
8239 { BUILTIN_REGULAR "read", readcmd },
8240 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8241 { BUILTIN_SPEC_REG "return", returncmd },
8242 { BUILTIN_SPEC_REG "set", setcmd },
8243 { BUILTIN_SPEC_REG "shift", shiftcmd },
8244 { BUILTIN_SPEC_REG "source", dotcmd },
8245 #if ENABLE_ASH_BUILTIN_TEST
8246 { BUILTIN_REGULAR "test", testcmd },
8248 { BUILTIN_SPEC_REG "times", timescmd },
8249 { BUILTIN_SPEC_REG "trap", trapcmd },
8250 { BUILTIN_REGULAR "true", truecmd },
8251 { BUILTIN_NOSPEC "type", typecmd },
8252 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
8253 { BUILTIN_REGULAR "umask", umaskcmd },
8254 #if ENABLE_ASH_ALIAS
8255 { BUILTIN_REGULAR "unalias", unaliascmd },
8257 { BUILTIN_SPEC_REG "unset", unsetcmd },
8258 { BUILTIN_REGULAR "wait", waitcmd },
8262 #define COMMANDCMD (builtintab + 5 + \
8263 2 * ENABLE_ASH_BUILTIN_TEST + \
8264 ENABLE_ASH_ALIAS + \
8265 ENABLE_ASH_JOB_CONTROL)
8266 #define EXECCMD (builtintab + 7 + \
8267 2 * ENABLE_ASH_BUILTIN_TEST + \
8268 ENABLE_ASH_ALIAS + \
8269 ENABLE_ASH_JOB_CONTROL + \
8270 ENABLE_ASH_CMDCMD + \
8271 ENABLE_ASH_BUILTIN_ECHO)
8274 * Search the table of builtin commands.
8276 static struct builtincmd *
8277 find_builtin(const char *name)
8279 struct builtincmd *bp;
8282 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8289 * Execute a simple command.
8291 static int back_exitstatus; /* exit status of backquoted command */
8293 isassignment(const char *p)
8295 const char *q = endofname(p);
8301 bltincmd(int argc, char **argv)
8303 /* Preserve exitstatus of a previous possible redirection
8304 * as POSIX mandates */
8305 return back_exitstatus;
8308 evalcommand(union node *cmd, int flags)
8310 static const struct builtincmd null_bltin = {
8311 "\0\0", bltincmd /* why three NULs? */
8313 struct stackmark smark;
8315 struct arglist arglist;
8316 struct arglist varlist;
8319 const struct strlist *sp;
8320 struct cmdentry cmdentry;
8328 struct builtincmd *bcmd;
8329 int pseudovarflag = 0;
8331 /* First expand the arguments. */
8332 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8333 setstackmark(&smark);
8334 back_exitstatus = 0;
8336 cmdentry.cmdtype = CMDBUILTIN;
8337 cmdentry.u.cmd = &null_bltin;
8338 varlist.lastp = &varlist.list;
8339 *varlist.lastp = NULL;
8340 arglist.lastp = &arglist.list;
8341 *arglist.lastp = NULL;
8344 if (cmd->ncmd.args) {
8345 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8346 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8349 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8350 struct strlist **spp;
8352 spp = arglist.lastp;
8353 if (pseudovarflag && isassignment(argp->narg.text))
8354 expandarg(argp, &arglist, EXP_VARTILDE);
8356 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8358 for (sp = *spp; sp; sp = sp->next)
8362 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8363 for (sp = arglist.list; sp; sp = sp->next) {
8364 TRACE(("evalcommand arg: %s\n", sp->text));
8365 *nargv++ = sp->text;
8370 if (iflag && funcnest == 0 && argc > 0)
8371 lastarg = nargv[-1];
8374 expredir(cmd->ncmd.redirect);
8375 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8378 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8379 struct strlist **spp;
8382 spp = varlist.lastp;
8383 expandarg(argp, &varlist, EXP_VARTILDE);
8386 * Modify the command lookup path, if a PATH= assignment
8390 if (varequal(p, path))
8394 /* Print the command if xflag is set. */
8397 const char *p = " %s";
8400 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8403 for (n = 0; n < 2; n++) {
8405 fdprintf(preverrout_fd, p, sp->text);
8413 safe_write(preverrout_fd, "\n", 1);
8419 /* Now locate the command. */
8421 const char *oldpath;
8422 int cmd_flag = DO_ERR;
8427 find_command(argv[0], &cmdentry, cmd_flag, path);
8428 if (cmdentry.cmdtype == CMDUNKNOWN) {
8434 /* implement bltin and command here */
8435 if (cmdentry.cmdtype != CMDBUILTIN)
8438 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8439 if (cmdentry.u.cmd == EXECCMD)
8441 #if ENABLE_ASH_CMDCMD
8442 if (cmdentry.u.cmd == COMMANDCMD) {
8444 nargv = parse_command_args(argv, &path);
8447 argc -= nargv - argv;
8449 cmd_flag |= DO_NOFUNC;
8457 /* We have a redirection error. */
8459 raise_exception(EXERROR);
8461 exitstatus = status;
8465 /* Execute the command. */
8466 switch (cmdentry.cmdtype) {
8468 /* Fork off a child process if necessary. */
8469 if (!(flags & EV_EXIT) || trap[0]) {
8471 jp = makejob(cmd, 1);
8472 if (forkshell(jp, cmd, FORK_FG) != 0) {
8473 exitstatus = waitforjob(jp);
8479 listsetvar(varlist.list, VEXPORT|VSTACK);
8480 shellexec(argv, path, cmdentry.u.index);
8484 cmdenviron = varlist.list;
8486 struct strlist *list = cmdenviron;
8488 if (spclbltin > 0 || argc == 0) {
8490 if (cmd_is_exec && argc > 1)
8493 listsetvar(list, i);
8495 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
8502 exit_status = 128 + SIGINT;
8504 exit_status = 128 + pendingsig;
8505 exitstatus = exit_status;
8506 if (i == EXINT || spclbltin > 0) {
8508 longjmp(exception_handler->loc, 1);
8515 listsetvar(varlist.list, 0);
8516 if (evalfun(cmdentry.u.func, argc, argv, flags))
8522 popredir(cmd_is_exec);
8524 /* dsl: I think this is intended to be used to support
8525 * '_' in 'vi' command mode during line editing...
8526 * However I implemented that within libedit itself.
8528 setvar("_", lastarg, 0);
8529 popstackmark(&smark);
8533 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
8535 char *volatile savecmdname;
8536 struct jmploc *volatile savehandler;
8537 struct jmploc jmploc;
8540 savecmdname = commandname;
8541 i = setjmp(jmploc.loc);
8544 savehandler = exception_handler;
8545 exception_handler = &jmploc;
8546 commandname = argv[0];
8548 optptr = NULL; /* initialize nextopt */
8549 exitstatus = (*cmd->builtin)(argc, argv);
8550 flush_stdout_stderr();
8552 exitstatus |= ferror(stdout);
8554 commandname = savecmdname;
8556 exception_handler = savehandler;
8562 goodname(const char *p)
8564 return !*endofname(p);
8569 * Search for a command. This is called before we fork so that the
8570 * location of the command will be available in the parent as well as
8571 * the child. The check for "goodname" is an overly conservative
8572 * check that the name will not be subject to expansion.
8575 prehash(union node *n)
8577 struct cmdentry entry;
8579 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
8580 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
8584 /* ============ Builtin commands
8586 * Builtin commands whose functions are closely tied to evaluation
8587 * are implemented here.
8591 * Handle break and continue commands. Break, continue, and return are
8592 * all handled by setting the evalskip flag. The evaluation routines
8593 * above all check this flag, and if it is set they start skipping
8594 * commands rather than executing them. The variable skipcount is
8595 * the number of loops to break/continue, or the number of function
8596 * levels to return. (The latter is always 1.) It should probably
8597 * be an error to break out of more loops than exist, but it isn't
8598 * in the standard shell so we don't make it one here.
8601 breakcmd(int argc, char **argv)
8603 int n = argc > 1 ? number(argv[1]) : 1;
8606 ash_msg_and_raise_error(illnum, argv[1]);
8610 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
8617 /* ============ input.c
8619 * This implements the input routines used by the parser.
8622 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
8625 INPUT_PUSH_FILE = 1,
8626 INPUT_NOFILE_OK = 2,
8629 static int plinno = 1; /* input line number */
8630 /* number of characters left in input buffer */
8631 static int parsenleft; /* copy of parsefile->nleft */
8632 static int parselleft; /* copy of parsefile->lleft */
8633 /* next character in input buffer */
8634 static char *parsenextc; /* copy of parsefile->nextc */
8636 static int checkkwd;
8637 /* values of checkkwd variable */
8638 #define CHKALIAS 0x1
8645 struct strpush *sp = parsefile->strpush;
8648 #if ENABLE_ASH_ALIAS
8650 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
8651 checkkwd |= CHKALIAS;
8653 if (sp->string != sp->ap->val) {
8656 sp->ap->flag &= ~ALIASINUSE;
8657 if (sp->ap->flag & ALIASDEAD) {
8658 unalias(sp->ap->name);
8662 parsenextc = sp->prevstring;
8663 parsenleft = sp->prevnleft;
8664 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
8665 parsefile->strpush = sp->prev;
8666 if (sp != &(parsefile->basestrpush))
8675 char *buf = parsefile->buf;
8679 #if ENABLE_FEATURE_EDITING
8680 if (!iflag || parsefile->fd)
8681 nr = nonblock_safe_read(parsefile->fd, buf, BUFSIZ - 1);
8683 #if ENABLE_FEATURE_TAB_COMPLETION
8684 line_input_state->path_lookup = pathval();
8686 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
8688 /* Ctrl+C pressed */
8697 if (nr < 0 && errno == 0) {
8698 /* Ctrl+D pressed */
8703 nr = nonblock_safe_read(parsefile->fd, buf, BUFSIZ - 1);
8707 /* nonblock_safe_read() handles this problem */
8709 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
8710 int flags = fcntl(0, F_GETFL);
8711 if (flags >= 0 && (flags & O_NONBLOCK)) {
8712 flags &= ~O_NONBLOCK;
8713 if (fcntl(0, F_SETFL, flags) >= 0) {
8714 out2str("sh: turning off NDELAY mode\n");
8725 * Refill the input buffer and return the next input character:
8727 * 1) If a string was pushed back on the input, pop it;
8728 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
8729 * from a string so we can't refill the buffer, return EOF.
8730 * 3) If the is more stuff in this buffer, use it else call read to fill it.
8731 * 4) Process input up to the next newline, deleting nul characters.
8740 while (parsefile->strpush) {
8741 #if ENABLE_ASH_ALIAS
8742 if (parsenleft == -1 && parsefile->strpush->ap &&
8743 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
8748 if (--parsenleft >= 0)
8749 return signed_char2int(*parsenextc++);
8751 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
8753 flush_stdout_stderr();
8760 parselleft = parsenleft = EOF_NLEFT;
8767 /* delete nul characters */
8775 memmove(q, q + 1, more);
8779 parsenleft = q - parsenextc - 1;
8785 parsenleft = q - parsenextc - 1;
8797 out2str(parsenextc);
8802 return signed_char2int(*parsenextc++);
8805 #define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer())
8809 return pgetc_as_macro();
8812 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
8813 #define pgetc_macro() pgetc()
8815 #define pgetc_macro() pgetc_as_macro()
8819 * Same as pgetc(), but ignores PEOA.
8821 #if ENABLE_ASH_ALIAS
8829 } while (c == PEOA);
8836 return pgetc_macro();
8841 * Read a line from the script.
8844 pfgets(char *line, int len)
8850 while (--nleft > 0) {
8866 * Undo the last call to pgetc. Only one character may be pushed back.
8867 * PEOF may be pushed back.
8877 * Push a string back onto the input at this current parsefile level.
8878 * We handle aliases this way.
8881 pushstring(char *s, void *ap)
8888 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
8889 if (parsefile->strpush) {
8890 sp = ckzmalloc(sizeof(struct strpush));
8891 sp->prev = parsefile->strpush;
8892 parsefile->strpush = sp;
8894 sp = parsefile->strpush = &(parsefile->basestrpush);
8895 sp->prevstring = parsenextc;
8896 sp->prevnleft = parsenleft;
8897 #if ENABLE_ASH_ALIAS
8898 sp->ap = (struct alias *)ap;
8900 ((struct alias *)ap)->flag |= ALIASINUSE;
8910 * To handle the "." command, a stack of input files is used. Pushfile
8911 * adds a new entry to the stack and popfile restores the previous level.
8916 struct parsefile *pf;
8918 parsefile->nleft = parsenleft;
8919 parsefile->lleft = parselleft;
8920 parsefile->nextc = parsenextc;
8921 parsefile->linno = plinno;
8922 pf = ckzalloc(sizeof(*pf));
8923 pf->prev = parsefile;
8925 /*pf->strpush = NULL; - ckzalloc did it */
8926 /*pf->basestrpush.prev = NULL;*/
8933 struct parsefile *pf = parsefile;
8941 parsefile = pf->prev;
8943 parsenleft = parsefile->nleft;
8944 parselleft = parsefile->lleft;
8945 parsenextc = parsefile->nextc;
8946 plinno = parsefile->linno;
8951 * Return to top level.
8956 while (parsefile != &basepf)
8961 * Close the file(s) that the shell is reading commands from. Called
8962 * after a fork is done.
8968 if (parsefile->fd > 0) {
8969 close(parsefile->fd);
8975 * Like setinputfile, but takes an open file descriptor. Call this with
8979 setinputfd(int fd, int push)
8981 close_on_exec_on(fd);
8987 if (parsefile->buf == NULL)
8988 parsefile->buf = ckmalloc(IBUFSIZ);
8989 parselleft = parsenleft = 0;
8994 * Set the input to take input from a file. If push is set, push the
8995 * old input onto the stack first.
8998 setinputfile(const char *fname, int flags)
9004 fd = open(fname, O_RDONLY);
9006 if (flags & INPUT_NOFILE_OK)
9008 ash_msg_and_raise_error("can't open %s", fname);
9011 fd2 = copyfd(fd, 10);
9014 ash_msg_and_raise_error("out of file descriptors");
9017 setinputfd(fd, flags & INPUT_PUSH_FILE);
9024 * Like setinputfile, but takes input from a string.
9027 setinputstring(char *string)
9031 parsenextc = string;
9032 parsenleft = strlen(string);
9033 parsefile->buf = NULL;
9039 /* ============ mail.c
9041 * Routines to check for mail.
9046 #define MAXMBOXES 10
9048 /* times of mailboxes */
9049 static time_t mailtime[MAXMBOXES];
9050 /* Set if MAIL or MAILPATH is changed. */
9051 static smallint mail_var_path_changed;
9054 * Print appropriate message(s) if mail has arrived.
9055 * If mail_var_path_changed is set,
9056 * then the value of MAIL has mail_var_path_changed,
9057 * so we just update the values.
9066 struct stackmark smark;
9069 setstackmark(&smark);
9070 mpath = mpathset() ? mpathval() : mailval();
9071 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9072 p = padvance(&mpath, nullstr);
9077 for (q = p; *q; q++);
9082 q[-1] = '\0'; /* delete trailing '/' */
9083 if (stat(p, &statb) < 0) {
9087 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9090 pathopt ? pathopt : "you have mail"
9093 *mtp = statb.st_mtime;
9095 mail_var_path_changed = 0;
9096 popstackmark(&smark);
9100 changemail(const char *val)
9102 mail_var_path_changed = 1;
9105 #endif /* ASH_MAIL */
9108 /* ============ ??? */
9111 * Set the shell parameters.
9114 setparam(char **argv)
9120 for (nparam = 0; argv[nparam]; nparam++);
9121 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9123 *ap++ = ckstrdup(*argv++);
9126 freeparam(&shellparam);
9127 shellparam.malloced = 1;
9128 shellparam.nparam = nparam;
9129 shellparam.p = newparam;
9130 #if ENABLE_ASH_GETOPTS
9131 shellparam.optind = 1;
9132 shellparam.optoff = -1;
9137 * Process shell options. The global variable argptr contains a pointer
9138 * to the argument list; we advance it past the options.
9140 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9141 * For a non-interactive shell, an error condition encountered
9142 * by a special built-in ... shall cause the shell to write a diagnostic message
9143 * to standard error and exit as shown in the following table:
9144 * Error Special Built-In
9146 * Utility syntax error (option or operand error) Shall exit
9148 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9149 * we see that bash does not do that (set "finishes" with error code 1 instead,
9150 * and shell continues), and people rely on this behavior!
9152 * set -o barfoo 2>/dev/null
9155 * Oh well. Let's mimic that.
9158 minus_o(char *name, int val)
9163 for (i = 0; i < NOPTS; i++) {
9164 if (strcmp(name, optnames(i)) == 0) {
9169 ash_msg("illegal option -o %s", name);
9172 out1str("Current option settings\n");
9173 for (i = 0; i < NOPTS; i++)
9174 out1fmt("%-16s%s\n", optnames(i),
9175 optlist[i] ? "on" : "off");
9179 setoption(int flag, int val)
9183 for (i = 0; i < NOPTS; i++) {
9184 if (optletters(i) == flag) {
9189 ash_msg_and_raise_error("illegal option -%c", flag);
9193 options(int cmdline)
9201 while ((p = *argptr) != NULL) {
9203 if (c != '-' && c != '+')
9206 val = 0; /* val = 0 if c == '+' */
9209 if (p[0] == '\0' || LONE_DASH(p)) {
9211 /* "-" means turn off -x and -v */
9214 /* "--" means reset params */
9215 else if (*argptr == NULL)
9218 break; /* "-" or "--" terminates options */
9221 /* first char was + or - */
9222 while ((c = *p++) != '\0') {
9223 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9224 if (c == 'c' && cmdline) {
9225 minusc = p; /* command is after shell args */
9226 } else if (c == 'o') {
9227 if (minus_o(*argptr, val)) {
9228 /* it already printed err message */
9229 return 1; /* error */
9233 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9235 /* bash does not accept +-login, we also won't */
9236 } else if (cmdline && val && (c == '-')) { /* long options */
9237 if (strcmp(p, "login") == 0)
9249 * The shift builtin command.
9252 shiftcmd(int argc, char **argv)
9259 n = number(argv[1]);
9260 if (n > shellparam.nparam)
9261 ash_msg_and_raise_error("can't shift that many");
9263 shellparam.nparam -= n;
9264 for (ap1 = shellparam.p; --n >= 0; ap1++) {
9265 if (shellparam.malloced)
9269 while ((*ap2++ = *ap1++) != NULL);
9270 #if ENABLE_ASH_GETOPTS
9271 shellparam.optind = 1;
9272 shellparam.optoff = -1;
9279 * POSIX requires that 'set' (but not export or readonly) output the
9280 * variables in lexicographic order - by the locale's collating order (sigh).
9281 * Maybe we could keep them in an ordered balanced binary tree
9282 * instead of hashed lists.
9283 * For now just roll 'em through qsort for printing...
9286 showvars(const char *sep_prefix, int on, int off)
9291 ep = listvars(on, off, &epend);
9292 qsort(ep, epend - ep, sizeof(char *), vpcmp);
9294 sep = *sep_prefix ? " " : sep_prefix;
9296 for (; ep < epend; ep++) {
9300 p = strchrnul(*ep, '=');
9303 q = single_quote(++p);
9304 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9310 * The set command builtin.
9313 setcmd(int argc, char **argv)
9318 return showvars(nullstr, 0, VUNSET);
9321 if (!options(0)) { /* if no parse error... */
9324 if (*argptr != NULL) {
9332 #if ENABLE_ASH_RANDOM_SUPPORT
9333 /* Roughly copied from bash.. */
9335 change_random(const char *value)
9337 if (value == NULL) {
9338 /* "get", generate */
9341 rseed = rseed * 1103515245 + 12345;
9342 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9343 /* set without recursion */
9344 setvar(vrandom.text, buf, VNOFUNC);
9345 vrandom.flags &= ~VNOFUNC;
9348 rseed = strtoul(value, (char **)NULL, 10);
9353 #if ENABLE_ASH_GETOPTS
9355 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9364 if (*param_optind < 1)
9366 optnext = optfirst + *param_optind - 1;
9368 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9371 p = optnext[-1] + *optoff;
9372 if (p == NULL || *p == '\0') {
9373 /* Current word is done, advance */
9375 if (p == NULL || *p != '-' || *++p == '\0') {
9382 if (LONE_DASH(p)) /* check for "--" */
9387 for (q = optstr; *q != c; ) {
9389 if (optstr[0] == ':') {
9392 err |= setvarsafe("OPTARG", s, 0);
9394 fprintf(stderr, "Illegal option -%c\n", c);
9405 if (*p == '\0' && (p = *optnext) == NULL) {
9406 if (optstr[0] == ':') {
9409 err |= setvarsafe("OPTARG", s, 0);
9412 fprintf(stderr, "No arg for -%c option\n", c);
9421 err |= setvarsafe("OPTARG", p, 0);
9424 err |= setvarsafe("OPTARG", nullstr, 0);
9426 *optoff = p ? p - *(optnext - 1) : -1;
9427 *param_optind = optnext - optfirst + 1;
9428 fmtstr(s, sizeof(s), "%d", *param_optind);
9429 err |= setvarsafe("OPTIND", s, VNOFUNC);
9432 err |= setvarsafe(optvar, s, 0);
9436 flush_stdout_stderr();
9437 raise_exception(EXERROR);
9443 * The getopts builtin. Shellparam.optnext points to the next argument
9444 * to be processed. Shellparam.optptr points to the next character to
9445 * be processed in the current argument. If shellparam.optnext is NULL,
9446 * then it's the first time getopts has been called.
9449 getoptscmd(int argc, char **argv)
9454 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
9456 optbase = shellparam.p;
9457 if (shellparam.optind > shellparam.nparam + 1) {
9458 shellparam.optind = 1;
9459 shellparam.optoff = -1;
9463 if (shellparam.optind > argc - 2) {
9464 shellparam.optind = 1;
9465 shellparam.optoff = -1;
9469 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9470 &shellparam.optoff);
9472 #endif /* ASH_GETOPTS */
9475 /* ============ Shell parser */
9478 * NEOF is returned by parsecmd when it encounters an end of file. It
9479 * must be distinct from NULL, so we use the address of a variable that
9480 * happens to be handy.
9482 static smallint tokpushback; /* last token pushed back */
9483 #define NEOF ((union node *)&tokpushback)
9484 static smallint parsebackquote; /* nonzero if we are inside backquotes */
9485 static int lasttoken; /* last token read */
9486 static char *wordtext; /* text of last word returned by readtoken */
9487 static struct nodelist *backquotelist;
9488 static union node *redirnode;
9489 static struct heredoc *heredoc;
9490 static smallint quoteflag; /* set if (part of) last token was quoted */
9492 static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN;
9494 raise_error_syntax(const char *msg)
9496 ash_msg_and_raise_error("syntax error: %s", msg);
9501 * Called when an unexpected token is read during the parse. The argument
9502 * is the token that is expected, or -1 if more than one type of token can
9503 * occur at this point.
9505 static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN;
9507 raise_error_unexpected_syntax(int token)
9512 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
9514 sprintf(msg + l, " (expecting %s)", tokname(token));
9515 raise_error_syntax(msg);
9519 #define EOFMARKLEN 79
9522 struct heredoc *next; /* next here document in list */
9523 union node *here; /* redirection node */
9524 char *eofmark; /* string indicating end of input */
9525 int striptabs; /* if set, strip leading tabs */
9528 static struct heredoc *heredoclist; /* list of here documents to read */
9530 /* parsing is heavily cross-recursive, need these forward decls */
9531 static union node *andor(void);
9532 static union node *pipeline(void);
9533 static union node *parse_command(void);
9534 static void parseheredoc(void);
9535 static char peektoken(void);
9536 static int readtoken(void);
9541 union node *n1, *n2, *n3;
9544 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9545 if (nlflag == 2 && peektoken())
9551 if (tok == TBACKGND) {
9552 if (n2->type == NPIPE) {
9553 n2->npipe.backgnd = 1;
9555 if (n2->type != NREDIR) {
9556 n3 = stzalloc(sizeof(struct nredir));
9558 /*n3->nredir.redirect = NULL; - stzalloc did it */
9561 n2->type = NBACKGND;
9567 n3 = stzalloc(sizeof(struct nbinary));
9569 n3->nbinary.ch1 = n1;
9570 n3->nbinary.ch2 = n2;
9586 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9594 pungetc(); /* push back EOF on input */
9598 raise_error_unexpected_syntax(-1);
9608 union node *n1, *n2, *n3;
9616 } else if (t == TOR) {
9622 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9624 n3 = stzalloc(sizeof(struct nbinary));
9626 n3->nbinary.ch1 = n1;
9627 n3->nbinary.ch2 = n2;
9635 union node *n1, *n2, *pipenode;
9636 struct nodelist *lp, *prev;
9640 TRACE(("pipeline: entered\n"));
9641 if (readtoken() == TNOT) {
9643 checkkwd = CHKKWD | CHKALIAS;
9646 n1 = parse_command();
9647 if (readtoken() == TPIPE) {
9648 pipenode = stzalloc(sizeof(struct npipe));
9649 pipenode->type = NPIPE;
9650 /*pipenode->npipe.backgnd = 0; - stzalloc did it */
9651 lp = stzalloc(sizeof(struct nodelist));
9652 pipenode->npipe.cmdlist = lp;
9656 lp = stzalloc(sizeof(struct nodelist));
9657 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9658 lp->n = parse_command();
9660 } while (readtoken() == TPIPE);
9666 n2 = stzalloc(sizeof(struct nnot));
9679 n = stzalloc(sizeof(struct narg));
9681 /*n->narg.next = NULL; - stzalloc did it */
9682 n->narg.text = wordtext;
9683 n->narg.backquote = backquotelist;
9688 fixredir(union node *n, const char *text, int err)
9690 TRACE(("Fix redir %s %d\n", text, err));
9692 n->ndup.vname = NULL;
9694 if (isdigit(text[0]) && text[1] == '\0')
9695 n->ndup.dupfd = text[0] - '0';
9696 else if (LONE_DASH(text))
9700 raise_error_syntax("Bad fd number");
9701 n->ndup.vname = makename();
9706 * Returns true if the text contains nothing to expand (no dollar signs
9710 noexpand(char *text)
9716 while ((c = *p++) != '\0') {
9717 if (c == CTLQUOTEMARK)
9721 else if (SIT(c, BASESYNTAX) == CCTL)
9730 union node *n = redirnode;
9732 if (readtoken() != TWORD)
9733 raise_error_unexpected_syntax(-1);
9734 if (n->type == NHERE) {
9735 struct heredoc *here = heredoc;
9741 TRACE(("Here document %d\n", n->type));
9742 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9743 raise_error_syntax("Illegal eof marker for << redirection");
9744 rmescapes(wordtext);
9745 here->eofmark = wordtext;
9747 if (heredoclist == NULL)
9750 for (p = heredoclist; p->next; p = p->next)
9754 } else if (n->type == NTOFD || n->type == NFROMFD) {
9755 fixredir(n, wordtext, 0);
9757 n->nfile.fname = makename();
9764 union node *args, **app;
9765 union node *n = NULL;
9766 union node *vars, **vpp;
9767 union node **rpp, *redir;
9777 savecheckkwd = CHKALIAS;
9779 checkkwd = savecheckkwd;
9780 switch (readtoken()) {
9782 n = stzalloc(sizeof(struct narg));
9784 /*n->narg.next = NULL; - stzalloc did it */
9785 n->narg.text = wordtext;
9786 n->narg.backquote = backquotelist;
9787 if (savecheckkwd && isassignment(wordtext)) {
9789 vpp = &n->narg.next;
9792 app = &n->narg.next;
9797 *rpp = n = redirnode;
9798 rpp = &n->nfile.next;
9799 parsefname(); /* read name of redirection file */
9802 if (args && app == &args->narg.next
9805 struct builtincmd *bcmd;
9808 /* We have a function */
9809 if (readtoken() != TRP)
9810 raise_error_unexpected_syntax(TRP);
9811 name = n->narg.text;
9813 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
9815 raise_error_syntax("Bad function name");
9818 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9819 n->narg.next = parse_command();
9832 n = stzalloc(sizeof(struct ncmd));
9834 n->ncmd.args = args;
9835 n->ncmd.assign = vars;
9836 n->ncmd.redirect = redir;
9843 union node *n1, *n2;
9844 union node *ap, **app;
9845 union node *cp, **cpp;
9846 union node *redir, **rpp;
9853 switch (readtoken()) {
9855 raise_error_unexpected_syntax(-1);
9858 n1 = stzalloc(sizeof(struct nif));
9860 n1->nif.test = list(0);
9861 if (readtoken() != TTHEN)
9862 raise_error_unexpected_syntax(TTHEN);
9863 n1->nif.ifpart = list(0);
9865 while (readtoken() == TELIF) {
9866 n2->nif.elsepart = stzalloc(sizeof(struct nif));
9867 n2 = n2->nif.elsepart;
9869 n2->nif.test = list(0);
9870 if (readtoken() != TTHEN)
9871 raise_error_unexpected_syntax(TTHEN);
9872 n2->nif.ifpart = list(0);
9874 if (lasttoken == TELSE)
9875 n2->nif.elsepart = list(0);
9877 n2->nif.elsepart = NULL;
9885 n1 = stzalloc(sizeof(struct nbinary));
9886 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
9887 n1->nbinary.ch1 = list(0);
9890 TRACE(("expecting DO got %s %s\n", tokname(got),
9891 got == TWORD ? wordtext : ""));
9892 raise_error_unexpected_syntax(TDO);
9894 n1->nbinary.ch2 = list(0);
9899 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9900 raise_error_syntax("Bad for loop variable");
9901 n1 = stzalloc(sizeof(struct nfor));
9903 n1->nfor.var = wordtext;
9904 checkkwd = CHKKWD | CHKALIAS;
9905 if (readtoken() == TIN) {
9907 while (readtoken() == TWORD) {
9908 n2 = stzalloc(sizeof(struct narg));
9910 /*n2->narg.next = NULL; - stzalloc did it */
9911 n2->narg.text = wordtext;
9912 n2->narg.backquote = backquotelist;
9914 app = &n2->narg.next;
9918 if (lasttoken != TNL && lasttoken != TSEMI)
9919 raise_error_unexpected_syntax(-1);
9921 n2 = stzalloc(sizeof(struct narg));
9923 /*n2->narg.next = NULL; - stzalloc did it */
9924 n2->narg.text = (char *)dolatstr;
9925 /*n2->narg.backquote = NULL;*/
9928 * Newline or semicolon here is optional (but note
9929 * that the original Bourne shell only allowed NL).
9931 if (lasttoken != TNL && lasttoken != TSEMI)
9934 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9935 if (readtoken() != TDO)
9936 raise_error_unexpected_syntax(TDO);
9937 n1->nfor.body = list(0);
9941 n1 = stzalloc(sizeof(struct ncase));
9943 if (readtoken() != TWORD)
9944 raise_error_unexpected_syntax(TWORD);
9945 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
9947 /*n2->narg.next = NULL; - stzalloc did it */
9948 n2->narg.text = wordtext;
9949 n2->narg.backquote = backquotelist;
9951 checkkwd = CHKKWD | CHKALIAS;
9952 } while (readtoken() == TNL);
9953 if (lasttoken != TIN)
9954 raise_error_unexpected_syntax(TIN);
9955 cpp = &n1->ncase.cases;
9957 checkkwd = CHKNL | CHKKWD;
9959 while (t != TESAC) {
9960 if (lasttoken == TLP)
9962 *cpp = cp = stzalloc(sizeof(struct nclist));
9964 app = &cp->nclist.pattern;
9966 *app = ap = stzalloc(sizeof(struct narg));
9968 /*ap->narg.next = NULL; - stzalloc did it */
9969 ap->narg.text = wordtext;
9970 ap->narg.backquote = backquotelist;
9971 if (readtoken() != TPIPE)
9973 app = &ap->narg.next;
9976 //ap->narg.next = NULL;
9977 if (lasttoken != TRP)
9978 raise_error_unexpected_syntax(TRP);
9979 cp->nclist.body = list(2);
9981 cpp = &cp->nclist.next;
9983 checkkwd = CHKNL | CHKKWD;
9987 raise_error_unexpected_syntax(TENDCASE);
9994 n1 = stzalloc(sizeof(struct nredir));
9995 n1->type = NSUBSHELL;
9996 n1->nredir.n = list(0);
9997 /*n1->nredir.redirect = NULL; - stzalloc did it */
10007 return simplecmd();
10010 if (readtoken() != t)
10011 raise_error_unexpected_syntax(t);
10014 /* Now check for redirection which may follow command */
10015 checkkwd = CHKKWD | CHKALIAS;
10017 while (readtoken() == TREDIR) {
10018 *rpp = n2 = redirnode;
10019 rpp = &n2->nfile.next;
10025 if (n1->type != NSUBSHELL) {
10026 n2 = stzalloc(sizeof(struct nredir));
10031 n1->nredir.redirect = redir;
10037 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10038 * is not NULL, read a here document. In the latter case, eofmark is the
10039 * word which marks the end of the document and striptabs is true if
10040 * leading tabs should be stripped from the document. The argument firstc
10041 * is the first character of the input token or document.
10043 * Because C does not have internal subroutines, I have simulated them
10044 * using goto's to implement the subroutine linkage. The following macros
10045 * will run code that appears at the end of readtoken1.
10048 #define CHECKEND() {goto checkend; checkend_return:;}
10049 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10050 #define PARSESUB() {goto parsesub; parsesub_return:;}
10051 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10052 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10053 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10056 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10058 /* NB: syntax parameter fits into smallint */
10062 char line[EOFMARKLEN + 1];
10063 struct nodelist *bqlist;
10067 smallint prevsyntax; /* syntax before arithmetic */
10068 #if ENABLE_ASH_EXPAND_PRMT
10069 smallint pssyntax; /* we are expanding a prompt string */
10071 int varnest; /* levels of variables expansion */
10072 int arinest; /* levels of arithmetic expansion */
10073 int parenlevel; /* levels of parens in arithmetic */
10074 int dqvarnest; /* levels of variables expansion within double quotes */
10077 /* Avoid longjmp clobbering */
10083 (void) &parenlevel;
10086 (void) &prevsyntax;
10089 startlinno = plinno;
10094 #if ENABLE_ASH_EXPAND_PRMT
10095 pssyntax = (syntax == PSSYNTAX);
10099 dblquote = (syntax == DQSYNTAX);
10105 STARTSTACKSTR(out);
10106 loop: { /* for each line, until end of word */
10107 CHECKEND(); /* set c to PEOF if at end of here document */
10108 for (;;) { /* until end of line or end of word */
10109 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10110 switch (SIT(c, syntax)) {
10111 case CNL: /* '\n' */
10112 if (syntax == BASESYNTAX)
10113 goto endword; /* exit outer loop */
10119 goto loop; /* continue outer loop */
10124 if (eofmark == NULL || dblquote)
10125 USTPUTC(CTLESC, out);
10128 case CBACK: /* backslash */
10131 USTPUTC(CTLESC, out);
10132 USTPUTC('\\', out);
10134 } else if (c == '\n') {
10138 #if ENABLE_ASH_EXPAND_PRMT
10139 if (c == '$' && pssyntax) {
10140 USTPUTC(CTLESC, out);
10141 USTPUTC('\\', out);
10145 c != '\\' && c != '`' &&
10150 USTPUTC(CTLESC, out);
10151 USTPUTC('\\', out);
10153 if (SIT(c, SQSYNTAX) == CCTL)
10154 USTPUTC(CTLESC, out);
10162 if (eofmark == NULL) {
10163 USTPUTC(CTLQUOTEMARK, out);
10171 if (eofmark != NULL && arinest == 0
10176 if (dqvarnest == 0) {
10177 syntax = BASESYNTAX;
10184 case CVAR: /* '$' */
10185 PARSESUB(); /* parse substitution */
10187 case CENDVAR: /* '}' */
10190 if (dqvarnest > 0) {
10193 USTPUTC(CTLENDVAR, out);
10198 #if ENABLE_ASH_MATH_SUPPORT
10199 case CLP: /* '(' in arithmetic */
10203 case CRP: /* ')' in arithmetic */
10204 if (parenlevel > 0) {
10208 if (pgetc() == ')') {
10209 if (--arinest == 0) {
10210 USTPUTC(CTLENDARI, out);
10211 syntax = prevsyntax;
10212 dblquote = (syntax == DQSYNTAX);
10217 * unbalanced parens
10218 * (don't 2nd guess - no error)
10226 case CBQUOTE: /* '`' */
10230 goto endword; /* exit outer loop */
10235 goto endword; /* exit outer loop */
10236 #if ENABLE_ASH_ALIAS
10246 #if ENABLE_ASH_MATH_SUPPORT
10247 if (syntax == ARISYNTAX)
10248 raise_error_syntax("Missing '))'");
10250 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10251 raise_error_syntax("Unterminated quoted string");
10252 if (varnest != 0) {
10253 startlinno = plinno;
10255 raise_error_syntax("Missing '}'");
10257 USTPUTC('\0', out);
10258 len = out - (char *)stackblock();
10259 out = stackblock();
10260 if (eofmark == NULL) {
10261 if ((c == '>' || c == '<')
10264 && (*out == '\0' || isdigit(*out))) {
10266 return lasttoken = TREDIR;
10271 quoteflag = quotef;
10272 backquotelist = bqlist;
10273 grabstackblock(len);
10277 /* end of readtoken routine */
10280 * Check to see whether we are at the end of the here document. When this
10281 * is called, c is set to the first character of the next input line. If
10282 * we are at the end of the here document, this routine sets the c to PEOF.
10286 #if ENABLE_ASH_ALIAS
10292 while (c == '\t') {
10296 if (c == *eofmark) {
10297 if (pfgets(line, sizeof(line)) != NULL) {
10301 for (q = eofmark + 1; *q && *p == *q; p++, q++);
10302 if (*p == '\n' && *q == '\0') {
10305 needprompt = doprompt;
10307 pushstring(line, NULL);
10312 goto checkend_return;
10316 * Parse a redirection operator. The variable "out" points to a string
10317 * specifying the fd to be redirected. The variable "c" contains the
10318 * first character of the redirection operator.
10324 np = stzalloc(sizeof(struct nfile));
10329 np->type = NAPPEND;
10331 np->type = NCLOBBER;
10338 } else { /* c == '<' */
10339 /*np->nfile.fd = 0; - stzalloc did it */
10343 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10344 np = stzalloc(sizeof(struct nhere));
10345 /*np->nfile.fd = 0; - stzalloc did it */
10348 heredoc = stzalloc(sizeof(struct heredoc));
10349 heredoc->here = np;
10352 heredoc->striptabs = 1;
10354 /*heredoc->striptabs = 0; - stzalloc did it */
10360 np->type = NFROMFD;
10364 np->type = NFROMTO;
10374 np->nfile.fd = fd - '0';
10376 goto parseredir_return;
10380 * Parse a substitution. At this point, we have read the dollar sign
10381 * and nothing else.
10384 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
10385 * (assuming ascii char codes, as the original implementation did) */
10386 #define is_special(c) \
10387 ((((unsigned int)c) - 33 < 32) \
10388 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
10394 static const char types[] ALIGN1 = "}-+?=";
10398 c <= PEOA_OR_PEOF ||
10399 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10403 } else if (c == '(') { /* $(command) or $((arith)) */
10404 if (pgetc() == '(') {
10405 #if ENABLE_ASH_MATH_SUPPORT
10408 raise_error_syntax("We unsupport $((arith))");
10415 USTPUTC(CTLVAR, out);
10416 typeloc = out - (char *)stackblock();
10417 USTPUTC(VSNORMAL, out);
10418 subtype = VSNORMAL;
10426 subtype = VSLENGTH;
10430 if (c > PEOA_OR_PEOF && is_name(c)) {
10434 } while (c > PEOA_OR_PEOF && is_in_name(c));
10435 } else if (isdigit(c)) {
10439 } while (isdigit(c));
10440 } else if (is_special(c)) {
10444 badsub: raise_error_syntax("Bad substitution");
10448 if (subtype == 0) {
10455 p = strchr(types, c);
10458 subtype = p - types + VSNORMAL;
10464 subtype = c == '#' ? VSTRIMLEFT :
10477 if (dblquote || arinest)
10479 *((char *)stackblock() + typeloc) = subtype | flags;
10480 if (subtype != VSNORMAL) {
10482 if (dblquote || arinest) {
10487 goto parsesub_return;
10491 * Called to parse command substitutions. Newstyle is set if the command
10492 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10493 * list of commands (passed by reference), and savelen is the number of
10494 * characters on the top of the stack which must be preserved.
10497 struct nodelist **nlpp;
10500 char *volatile str;
10501 struct jmploc jmploc;
10502 struct jmploc *volatile savehandler;
10504 smallint saveprompt = 0;
10507 (void) &saveprompt;
10509 savepbq = parsebackquote;
10510 if (setjmp(jmploc.loc)) {
10512 parsebackquote = 0;
10513 exception_handler = savehandler;
10514 longjmp(exception_handler->loc, 1);
10518 savelen = out - (char *)stackblock();
10520 str = ckmalloc(savelen);
10521 memcpy(str, stackblock(), savelen);
10523 savehandler = exception_handler;
10524 exception_handler = &jmploc;
10527 /* We must read until the closing backquote, giving special
10528 treatment to some slashes, and then push the string and
10529 reread it as input, interpreting it normally. */
10536 STARTSTACKSTR(pout);
10553 * If eating a newline, avoid putting
10554 * the newline into the new character
10555 * stream (via the STPUTC after the
10560 if (pc != '\\' && pc != '`' && pc != '$'
10561 && (!dblquote || pc != '"'))
10562 STPUTC('\\', pout);
10563 if (pc > PEOA_OR_PEOF) {
10569 #if ENABLE_ASH_ALIAS
10572 startlinno = plinno;
10573 raise_error_syntax("EOF in backquote substitution");
10577 needprompt = doprompt;
10586 STPUTC('\0', pout);
10587 psavelen = pout - (char *)stackblock();
10588 if (psavelen > 0) {
10589 pstr = grabstackstr(pout);
10590 setinputstring(pstr);
10595 nlpp = &(*nlpp)->next;
10596 *nlpp = stzalloc(sizeof(**nlpp));
10597 /* (*nlpp)->next = NULL; - stzalloc did it */
10598 parsebackquote = oldstyle;
10601 saveprompt = doprompt;
10608 doprompt = saveprompt;
10609 else if (readtoken() != TRP)
10610 raise_error_unexpected_syntax(TRP);
10615 * Start reading from old file again, ignoring any pushed back
10616 * tokens left from the backquote parsing
10621 while (stackblocksize() <= savelen)
10623 STARTSTACKSTR(out);
10625 memcpy(out, str, savelen);
10626 STADJUST(savelen, out);
10632 parsebackquote = savepbq;
10633 exception_handler = savehandler;
10634 if (arinest || dblquote)
10635 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10637 USTPUTC(CTLBACKQ, out);
10639 goto parsebackq_oldreturn;
10640 goto parsebackq_newreturn;
10643 #if ENABLE_ASH_MATH_SUPPORT
10645 * Parse an arithmetic expansion (indicate start of one and set state)
10648 if (++arinest == 1) {
10649 prevsyntax = syntax;
10650 syntax = ARISYNTAX;
10651 USTPUTC(CTLARI, out);
10658 * we collapse embedded arithmetic expansion to
10659 * parenthesis, which should be equivalent
10663 goto parsearith_return;
10667 } /* end of readtoken */
10670 * Read the next input token.
10671 * If the token is a word, we set backquotelist to the list of cmds in
10672 * backquotes. We set quoteflag to true if any part of the word was
10674 * If the token is TREDIR, then we set redirnode to a structure containing
10676 * In all cases, the variable startlinno is set to the number of the line
10677 * on which the token starts.
10679 * [Change comment: here documents and internal procedures]
10680 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10681 * word parsing code into a separate routine. In this case, readtoken
10682 * doesn't need to have any internal procedures, but parseword does.
10683 * We could also make parseoperator in essence the main routine, and
10684 * have parseword (readtoken1?) handle both words and redirection.]
10686 #define NEW_xxreadtoken
10687 #ifdef NEW_xxreadtoken
10688 /* singles must be first! */
10689 static const char xxreadtoken_chars[7] ALIGN1 = {
10690 '\n', '(', ')', '&', '|', ';', 0
10693 static const char xxreadtoken_tokens[] ALIGN1 = {
10694 TNL, TLP, TRP, /* only single occurrence allowed */
10695 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10696 TEOF, /* corresponds to trailing nul */
10697 TAND, TOR, TENDCASE /* if double occurrence */
10700 #define xxreadtoken_doubles \
10701 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10702 #define xxreadtoken_singles \
10703 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10717 startlinno = plinno;
10718 for (;;) { /* until token or start of word found */
10721 if ((c != ' ') && (c != '\t')
10722 #if ENABLE_ASH_ALIAS
10727 while ((c = pgetc()) != '\n' && c != PEOF);
10729 } else if (c == '\\') {
10730 if (pgetc() != '\n') {
10734 startlinno = ++plinno;
10739 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10744 needprompt = doprompt;
10747 p = strchr(xxreadtoken_chars, c);
10750 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10753 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10754 if (pgetc() == *p) { /* double occurrence? */
10755 p += xxreadtoken_doubles + 1;
10761 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10767 #define RETURN(token) return lasttoken = token
10780 startlinno = plinno;
10781 for (;;) { /* until token or start of word found */
10784 case ' ': case '\t':
10785 #if ENABLE_ASH_ALIAS
10790 while ((c = pgetc()) != '\n' && c != PEOF);
10794 if (pgetc() == '\n') {
10795 startlinno = ++plinno;
10804 needprompt = doprompt;
10809 if (pgetc() == '&')
10814 if (pgetc() == '|')
10819 if (pgetc() == ';')
10832 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10835 #endif /* NEW_xxreadtoken */
10842 smallint alreadyseen = tokpushback;
10845 #if ENABLE_ASH_ALIAS
10854 if (checkkwd & CHKNL) {
10861 if (t != TWORD || quoteflag) {
10866 * check for keywords
10868 if (checkkwd & CHKKWD) {
10869 const char *const *pp;
10871 pp = findkwd(wordtext);
10873 lasttoken = t = pp - tokname_array;
10874 TRACE(("keyword %s recognized\n", tokname(t)));
10879 if (checkkwd & CHKALIAS) {
10880 #if ENABLE_ASH_ALIAS
10882 ap = lookupalias(wordtext, 1);
10885 pushstring(ap->val, ap);
10895 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
10897 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
10909 return tokname_array[t][0];
10913 * Read and parse a command. Returns NEOF on end of file. (NULL is a
10914 * valid parse tree indicating a blank line.)
10916 static union node *
10917 parsecmd(int interact)
10922 doprompt = interact;
10924 setprompt(doprompt);
10936 * Input any here documents.
10941 struct heredoc *here;
10944 here = heredoclist;
10945 heredoclist = NULL;
10951 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10952 here->eofmark, here->striptabs);
10953 n = stzalloc(sizeof(struct narg));
10954 n->narg.type = NARG;
10955 /*n->narg.next = NULL; - stzalloc did it */
10956 n->narg.text = wordtext;
10957 n->narg.backquote = backquotelist;
10958 here->here->nhere.doc = n;
10965 * called by editline -- any expansions to the prompt should be added here.
10967 #if ENABLE_ASH_EXPAND_PRMT
10968 static const char *
10969 expandstr(const char *ps)
10973 /* XXX Fix (char *) cast. */
10974 setinputstring((char *)ps);
10975 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
10978 n.narg.type = NARG;
10979 n.narg.next = NULL;
10980 n.narg.text = wordtext;
10981 n.narg.backquote = backquotelist;
10983 expandarg(&n, NULL, 0);
10984 return stackblock();
10989 * Execute a command or commands contained in a string.
10992 evalstring(char *s, int mask)
10995 struct stackmark smark;
10999 setstackmark(&smark);
11002 while ((n = parsecmd(0)) != NEOF) {
11004 popstackmark(&smark);
11017 * The eval command.
11020 evalcmd(int argc, char **argv)
11029 STARTSTACKSTR(concat);
11032 concat = stack_putstr(p, concat);
11036 STPUTC(' ', concat);
11038 STPUTC('\0', concat);
11039 p = grabstackstr(concat);
11041 evalstring(p, ~SKIPEVAL);
11048 * Read and execute commands. "Top" is nonzero for the top level command
11049 * loop; it turns on prompting if the shell is interactive.
11055 struct stackmark smark;
11059 TRACE(("cmdloop(%d) called\n", top));
11063 setstackmark(&smark);
11066 showjobs(stderr, SHOW_CHANGED);
11069 if (iflag && top) {
11071 #if ENABLE_ASH_MAIL
11075 n = parsecmd(inter);
11076 /* showtree(n); DEBUG */
11078 if (!top || numeof >= 50)
11080 if (!stoppedjobs()) {
11083 out2str("\nUse \"exit\" to leave shell.\n");
11086 } else if (nflag == 0) {
11087 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11092 popstackmark(&smark);
11097 return skip & SKIPEVAL;
11104 * Take commands from a file. To be compatible we should do a path
11105 * search for the file, which is necessary to find sub-commands.
11108 find_dot_file(char *name)
11111 const char *path = pathval();
11114 /* don't try this for absolute or relative paths */
11115 if (strchr(name, '/'))
11118 while ((fullname = padvance(&path, name)) != NULL) {
11119 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11121 * Don't bother freeing here, since it will
11122 * be freed by the caller.
11126 stunalloc(fullname);
11129 /* not found in the PATH */
11130 ash_msg_and_raise_error("%s: not found", name);
11135 dotcmd(int argc, char **argv)
11137 struct strlist *sp;
11138 volatile struct shparam saveparam;
11141 for (sp = cmdenviron; sp; sp = sp->next)
11142 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11144 if (argc >= 2) { /* That's what SVR2 does */
11147 fullname = find_dot_file(argv[1]);
11150 saveparam = shellparam;
11151 shellparam.malloced = 0;
11152 shellparam.nparam = argc - 2;
11153 shellparam.p = argv + 2;
11156 setinputfile(fullname, INPUT_PUSH_FILE);
11157 commandname = fullname;
11162 freeparam(&shellparam);
11163 shellparam = saveparam;
11165 status = exitstatus;
11171 exitcmd(int argc, char **argv)
11176 exitstatus = number(argv[1]);
11177 raise_exception(EXEXIT);
11181 #if ENABLE_ASH_BUILTIN_ECHO
11183 echocmd(int argc, char **argv)
11185 return echo_main(argc, argv);
11189 #if ENABLE_ASH_BUILTIN_TEST
11191 testcmd(int argc, char **argv)
11193 return test_main(argc, argv);
11198 * Read a file containing shell functions.
11201 readcmdfile(char *name)
11203 setinputfile(name, INPUT_PUSH_FILE);
11209 /* ============ find_command inplementation */
11212 * Resolve a command name. If you change this routine, you may have to
11213 * change the shellexec routine as well.
11216 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11218 struct tblentry *cmdp;
11225 struct builtincmd *bcmd;
11227 /* If name contains a slash, don't use PATH or hash table */
11228 if (strchr(name, '/') != NULL) {
11229 entry->u.index = -1;
11230 if (act & DO_ABS) {
11231 while (stat(name, &statb) < 0) {
11233 if (errno == EINTR)
11236 entry->cmdtype = CMDUNKNOWN;
11240 entry->cmdtype = CMDNORMAL;
11244 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11246 updatetbl = (path == pathval());
11249 if (strstr(path, "%builtin") != NULL)
11250 act |= DO_ALTBLTIN;
11253 /* If name is in the table, check answer will be ok */
11254 cmdp = cmdlookup(name, 0);
11255 if (cmdp != NULL) {
11258 switch (cmdp->cmdtype) {
11276 } else if (cmdp->rehash == 0)
11277 /* if not invalidated by cd, we're done */
11281 /* If %builtin not in path, check for builtin next */
11282 bcmd = find_builtin(name);
11284 if (IS_BUILTIN_REGULAR(bcmd))
11285 goto builtin_success;
11286 if (act & DO_ALTPATH) {
11287 if (!(act & DO_ALTBLTIN))
11288 goto builtin_success;
11289 } else if (builtinloc <= 0) {
11290 goto builtin_success;
11294 #if ENABLE_FEATURE_SH_STANDALONE
11295 if (find_applet_by_name(name) >= 0) {
11296 entry->cmdtype = CMDNORMAL;
11297 entry->u.index = -1;
11302 /* We have to search path. */
11303 prev = -1; /* where to start */
11304 if (cmdp && cmdp->rehash) { /* doing a rehash */
11305 if (cmdp->cmdtype == CMDBUILTIN)
11308 prev = cmdp->param.index;
11314 while ((fullname = padvance(&path, name)) != NULL) {
11315 stunalloc(fullname);
11316 /* NB: code below will still use fullname
11317 * despite it being "unallocated" */
11320 if (prefix(pathopt, "builtin")) {
11322 goto builtin_success;
11324 } else if (!(act & DO_NOFUNC)
11325 && prefix(pathopt, "func")) {
11326 /* handled below */
11328 /* ignore unimplemented options */
11332 /* if rehash, don't redo absolute path names */
11333 if (fullname[0] == '/' && idx <= prev) {
11336 TRACE(("searchexec \"%s\": no change\n", name));
11339 while (stat(fullname, &statb) < 0) {
11341 if (errno == EINTR)
11344 if (errno != ENOENT && errno != ENOTDIR)
11348 e = EACCES; /* if we fail, this will be the error */
11349 if (!S_ISREG(statb.st_mode))
11351 if (pathopt) { /* this is a %func directory */
11352 stalloc(strlen(fullname) + 1);
11353 /* NB: stalloc will return space pointed by fullname
11354 * (because we don't have any intervening allocations
11355 * between stunalloc above and this stalloc) */
11356 readcmdfile(fullname);
11357 cmdp = cmdlookup(name, 0);
11358 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
11359 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
11360 stunalloc(fullname);
11363 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
11365 entry->cmdtype = CMDNORMAL;
11366 entry->u.index = idx;
11370 cmdp = cmdlookup(name, 1);
11371 cmdp->cmdtype = CMDNORMAL;
11372 cmdp->param.index = idx;
11377 /* We failed. If there was an entry for this command, delete it */
11378 if (cmdp && updatetbl)
11379 delete_cmd_entry();
11381 ash_msg("%s: %s", name, errmsg(e, "not found"));
11382 entry->cmdtype = CMDUNKNOWN;
11387 entry->cmdtype = CMDBUILTIN;
11388 entry->u.cmd = bcmd;
11392 cmdp = cmdlookup(name, 1);
11393 cmdp->cmdtype = CMDBUILTIN;
11394 cmdp->param.cmd = bcmd;
11398 entry->cmdtype = cmdp->cmdtype;
11399 entry->u = cmdp->param;
11403 /* ============ trap.c */
11406 * The trap builtin.
11409 trapcmd(int argc, char **argv)
11418 for (signo = 0; signo < NSIG; signo++) {
11419 if (trap[signo] != NULL) {
11422 sn = get_signame(signo);
11423 out1fmt("trap -- %s %s\n",
11424 single_quote(trap[signo]), sn);
11434 signo = get_signum(*ap);
11436 ash_msg_and_raise_error("%s: bad trap", *ap);
11439 if (LONE_DASH(action))
11442 action = ckstrdup(action);
11445 trap[signo] = action;
11455 /* ============ Builtins */
11457 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
11459 * Lists available builtins
11462 helpcmd(int argc, char **argv)
11466 out1fmt("\nBuilt-in commands:\n-------------------\n");
11467 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
11468 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11469 builtintab[i].name + 1);
11475 #if ENABLE_FEATURE_SH_STANDALONE
11477 const char *a = applet_names;
11479 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
11484 a += strlen(a) + 1;
11489 return EXIT_SUCCESS;
11491 #endif /* FEATURE_SH_EXTRA_QUIET */
11494 * The export and readonly commands.
11497 exportcmd(int argc, char **argv)
11503 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
11505 if (nextopt("p") != 'p') {
11510 p = strchr(name, '=');
11514 vp = *findvar(hashvar(name), name);
11520 setvar(name, p, flag);
11521 } while ((name = *++aptr) != NULL);
11525 showvars(argv[0], flag, 0);
11530 * Delete a function if it exists.
11533 unsetfunc(const char *name)
11535 struct tblentry *cmdp;
11537 cmdp = cmdlookup(name, 0);
11538 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
11539 delete_cmd_entry();
11543 * The unset builtin command. We unset the function before we unset the
11544 * variable to allow a function to be unset when there is a readonly variable
11545 * with the same name.
11548 unsetcmd(int argc, char **argv)
11555 while ((i = nextopt("vf")) != '\0') {
11559 for (ap = argptr; *ap; ap++) {
11575 #include <sys/times.h>
11577 static const unsigned char timescmd_str[] ALIGN1 = {
11578 ' ', offsetof(struct tms, tms_utime),
11579 '\n', offsetof(struct tms, tms_stime),
11580 ' ', offsetof(struct tms, tms_cutime),
11581 '\n', offsetof(struct tms, tms_cstime),
11586 timescmd(int ac, char **av)
11588 long clk_tck, s, t;
11589 const unsigned char *p;
11592 clk_tck = sysconf(_SC_CLK_TCK);
11597 t = *(clock_t *)(((char *) &buf) + p[1]);
11599 out1fmt("%ldm%ld.%.3lds%c",
11601 ((t - s * clk_tck) * 1000) / clk_tck,
11603 } while (*(p += 2));
11608 #if ENABLE_ASH_MATH_SUPPORT
11610 dash_arith(const char *s)
11616 result = arith(s, &errcode);
11619 ash_msg_and_raise_error("exponent less than 0");
11621 ash_msg_and_raise_error("divide by zero");
11623 ash_msg_and_raise_error("expression recursion loop detected");
11624 raise_error_syntax(s);
11632 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
11633 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
11635 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
11638 letcmd(int argc, char **argv)
11645 ash_msg_and_raise_error("expression expected");
11646 for (ap = argv + 1; *ap; ap++) {
11647 i = dash_arith(*ap);
11652 #endif /* ASH_MATH_SUPPORT */
11655 /* ============ miscbltin.c
11657 * Miscellaneous builtins.
11662 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
11663 typedef enum __rlimit_resource rlim_t;
11667 * The read builtin. The -e option causes backslashes to escape the
11668 * following character.
11670 * This uses unbuffered input, which may be avoidable in some cases.
11673 readcmd(int argc, char **argv)
11685 #if ENABLE_ASH_READ_NCHARS
11689 struct termios tty, old_tty;
11691 #if ENABLE_ASH_READ_TIMEOUT
11695 ts.tv_sec = ts.tv_usec = 0;
11700 #if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT
11701 while ((i = nextopt("p:rt:n:s")) != '\0')
11702 #elif ENABLE_ASH_READ_NCHARS
11703 while ((i = nextopt("p:rn:s")) != '\0')
11704 #elif ENABLE_ASH_READ_TIMEOUT
11705 while ((i = nextopt("p:rt:")) != '\0')
11707 while ((i = nextopt("p:r")) != '\0')
11712 prompt = optionarg;
11714 #if ENABLE_ASH_READ_NCHARS
11716 nchars = bb_strtou(optionarg, NULL, 10);
11717 if (nchars < 0 || errno)
11718 ash_msg_and_raise_error("invalid count");
11719 n_flag = nchars; /* just a flag "nchars is nonzero" */
11725 #if ENABLE_ASH_READ_TIMEOUT
11727 ts.tv_sec = bb_strtou(optionarg, &p, 10);
11729 /* EINVAL means number is ok, but not terminated by NUL */
11730 if (*p == '.' && errno == EINVAL) {
11734 ts.tv_usec = bb_strtou(p, &p2, 10);
11736 ash_msg_and_raise_error("invalid timeout");
11738 /* normalize to usec */
11740 ash_msg_and_raise_error("invalid timeout");
11741 while (scale++ < 6)
11744 } else if (ts.tv_sec < 0 || errno) {
11745 ash_msg_and_raise_error("invalid timeout");
11747 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
11748 ash_msg_and_raise_error("invalid timeout");
11759 if (prompt && isatty(0)) {
11764 ash_msg_and_raise_error("arg count");
11765 ifs = bltinlookup("IFS");
11768 #if ENABLE_ASH_READ_NCHARS
11769 if (n_flag || silent) {
11770 if (tcgetattr(0, &tty) != 0) {
11777 tty.c_lflag &= ~ICANON;
11778 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
11781 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
11783 tcsetattr(0, TCSANOW, &tty);
11787 #if ENABLE_ASH_READ_TIMEOUT
11788 if (ts.tv_sec || ts.tv_usec) {
11792 /* poll-based wait produces bigger code, using select */
11793 i = select(1, &set, NULL, NULL, &ts);
11794 if (!i) { /* timed out! */
11795 #if ENABLE_ASH_READ_NCHARS
11797 tcsetattr(0, TCSANOW, &old_tty);
11808 if (nonblock_safe_read(0, &c, 1) != 1) {
11820 if (!rflag && c == '\\') {
11826 if (startword && *ifs == ' ' && strchr(ifs, c)) {
11830 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
11832 setvar(*ap, stackblock(), 0);
11841 /* end of do {} while: */
11842 #if ENABLE_ASH_READ_NCHARS
11843 while (!n_flag || --nchars);
11848 #if ENABLE_ASH_READ_NCHARS
11849 if (n_flag || silent)
11850 tcsetattr(0, TCSANOW, &old_tty);
11854 /* Remove trailing blanks */
11855 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
11857 setvar(*ap, stackblock(), 0);
11858 while (*++ap != NULL)
11859 setvar(*ap, nullstr, 0);
11864 umaskcmd(int argc, char **argv)
11866 static const char permuser[3] ALIGN1 = "ugo";
11867 static const char permmode[3] ALIGN1 = "rwx";
11868 static const short permmask[] ALIGN2 = {
11869 S_IRUSR, S_IWUSR, S_IXUSR,
11870 S_IRGRP, S_IWGRP, S_IXGRP,
11871 S_IROTH, S_IWOTH, S_IXOTH
11877 int symbolic_mode = 0;
11879 while (nextopt("S") != '\0') {
11890 if (symbolic_mode) {
11894 for (i = 0; i < 3; i++) {
11897 *p++ = permuser[i];
11899 for (j = 0; j < 3; j++) {
11900 if ((mask & permmask[3 * i + j]) == 0) {
11901 *p++ = permmode[j];
11909 out1fmt("%.4o\n", mask);
11912 if (isdigit((unsigned char) *ap)) {
11915 if (*ap >= '8' || *ap < '0')
11916 ash_msg_and_raise_error(illnum, argv[1]);
11917 mask = (mask << 3) + (*ap - '0');
11918 } while (*++ap != '\0');
11921 mask = ~mask & 0777;
11922 if (!bb_parse_mode(ap, &mask)) {
11923 ash_msg_and_raise_error("illegal mode: %s", ap);
11925 umask(~mask & 0777);
11934 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
11935 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
11936 * ash by J.T. Conklin.
11942 uint8_t cmd; /* RLIMIT_xxx fit into it */
11943 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
11947 static const struct limits limits_tbl[] = {
11949 { RLIMIT_CPU, 0, 't' },
11951 #ifdef RLIMIT_FSIZE
11952 { RLIMIT_FSIZE, 9, 'f' },
11955 { RLIMIT_DATA, 10, 'd' },
11957 #ifdef RLIMIT_STACK
11958 { RLIMIT_STACK, 10, 's' },
11961 { RLIMIT_CORE, 9, 'c' },
11964 { RLIMIT_RSS, 10, 'm' },
11966 #ifdef RLIMIT_MEMLOCK
11967 { RLIMIT_MEMLOCK, 10, 'l' },
11969 #ifdef RLIMIT_NPROC
11970 { RLIMIT_NPROC, 0, 'p' },
11972 #ifdef RLIMIT_NOFILE
11973 { RLIMIT_NOFILE, 0, 'n' },
11976 { RLIMIT_AS, 10, 'v' },
11978 #ifdef RLIMIT_LOCKS
11979 { RLIMIT_LOCKS, 0, 'w' },
11982 static const char limits_name[] =
11984 "time(seconds)" "\0"
11986 #ifdef RLIMIT_FSIZE
11987 "file(blocks)" "\0"
11992 #ifdef RLIMIT_STACK
11996 "coredump(blocks)" "\0"
12001 #ifdef RLIMIT_MEMLOCK
12002 "locked memory(kb)" "\0"
12004 #ifdef RLIMIT_NPROC
12007 #ifdef RLIMIT_NOFILE
12013 #ifdef RLIMIT_LOCKS
12018 enum limtype { SOFT = 0x1, HARD = 0x2 };
12021 printlim(enum limtype how, const struct rlimit *limit,
12022 const struct limits *l)
12026 val = limit->rlim_max;
12028 val = limit->rlim_cur;
12030 if (val == RLIM_INFINITY)
12031 out1fmt("unlimited\n");
12033 val >>= l->factor_shift;
12034 out1fmt("%lld\n", (long long) val);
12039 ulimitcmd(int argc, char **argv)
12043 enum limtype how = SOFT | HARD;
12044 const struct limits *l;
12047 struct rlimit limit;
12050 while ((optc = nextopt("HSa"
12054 #ifdef RLIMIT_FSIZE
12060 #ifdef RLIMIT_STACK
12069 #ifdef RLIMIT_MEMLOCK
12072 #ifdef RLIMIT_NPROC
12075 #ifdef RLIMIT_NOFILE
12081 #ifdef RLIMIT_LOCKS
12099 for (l = limits_tbl; l->option != what; l++)
12102 set = *argptr ? 1 : 0;
12106 if (all || argptr[1])
12107 ash_msg_and_raise_error("too many arguments");
12108 if (strncmp(p, "unlimited\n", 9) == 0)
12109 val = RLIM_INFINITY;
12113 while ((c = *p++) >= '0' && c <= '9') {
12114 val = (val * 10) + (long)(c - '0');
12115 if (val < (rlim_t) 0)
12119 ash_msg_and_raise_error("bad number");
12120 val <<= l->factor_shift;
12124 const char *lname = limits_name;
12125 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12126 getrlimit(l->cmd, &limit);
12127 out1fmt("%-20s ", lname);
12128 lname += strlen(lname) + 1;
12129 printlim(how, &limit, l);
12134 getrlimit(l->cmd, &limit);
12137 limit.rlim_max = val;
12139 limit.rlim_cur = val;
12140 if (setrlimit(l->cmd, &limit) < 0)
12141 ash_msg_and_raise_error("error setting limit (%m)");
12143 printlim(how, &limit, l);
12149 /* ============ Math support */
12151 #if ENABLE_ASH_MATH_SUPPORT
12153 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12155 Permission is hereby granted, free of charge, to any person obtaining
12156 a copy of this software and associated documentation files (the
12157 "Software"), to deal in the Software without restriction, including
12158 without limitation the rights to use, copy, modify, merge, publish,
12159 distribute, sublicense, and/or sell copies of the Software, and to
12160 permit persons to whom the Software is furnished to do so, subject to
12161 the following conditions:
12163 The above copyright notice and this permission notice shall be
12164 included in all copies or substantial portions of the Software.
12166 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12167 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12168 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12169 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12170 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12171 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12172 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12175 /* This is my infix parser/evaluator. It is optimized for size, intended
12176 * as a replacement for yacc-based parsers. However, it may well be faster
12177 * than a comparable parser written in yacc. The supported operators are
12178 * listed in #defines below. Parens, order of operations, and error handling
12179 * are supported. This code is thread safe. The exact expression format should
12180 * be that which POSIX specifies for shells. */
12182 /* The code uses a simple two-stack algorithm. See
12183 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12184 * for a detailed explanation of the infix-to-postfix algorithm on which
12185 * this is based (this code differs in that it applies operators immediately
12186 * to the stack instead of adding them to a queue to end up with an
12189 /* To use the routine, call it with an expression string and error return
12193 * Aug 24, 2001 Manuel Novoa III
12195 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12197 * 1) In arith_apply():
12198 * a) Cached values of *numptr and &(numptr[-1]).
12199 * b) Removed redundant test for zero denominator.
12202 * a) Eliminated redundant code for processing operator tokens by moving
12203 * to a table-based implementation. Also folded handling of parens
12205 * b) Combined all 3 loops which called arith_apply to reduce generated
12206 * code size at the cost of speed.
12208 * 3) The following expressions were treated as valid by the original code:
12209 * 1() , 0! , 1 ( *3 ) .
12210 * These bugs have been fixed by internally enclosing the expression in
12211 * parens and then checking that all binary ops and right parens are
12212 * preceded by a valid expression (NUM_TOKEN).
12214 * Note: It may be desirable to replace Aaron's test for whitespace with
12215 * ctype's isspace() if it is used by another busybox applet or if additional
12216 * whitespace chars should be considered. Look below the "#include"s for a
12217 * precompiler test.
12221 * Aug 26, 2001 Manuel Novoa III
12223 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12225 * Merge in Aaron's comments previously posted to the busybox list,
12226 * modified slightly to take account of my changes to the code.
12231 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12233 * - allow access to variable,
12234 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12235 * - realize assign syntax (VAR=expr, +=, *= etc)
12236 * - realize exponentiation (** operator)
12237 * - realize comma separated - expr, expr
12238 * - realise ++expr --expr expr++ expr--
12239 * - realise expr ? expr : expr (but, second expr calculate always)
12240 * - allow hexadecimal and octal numbers
12241 * - was restored loses XOR operator
12242 * - remove one goto label, added three ;-)
12243 * - protect $((num num)) as true zero expr (Manuel`s error)
12244 * - always use special isspace(), see comment from bash ;-)
12247 #define arith_isspace(arithval) \
12248 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12250 typedef unsigned char operator;
12252 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12253 * precedence, and 3 high bits are an ID unique across operators of that
12254 * precedence. The ID portion is so that multiple operators can have the
12255 * same precedence, ensuring that the leftmost one is evaluated first.
12256 * Consider * and /. */
12258 #define tok_decl(prec,id) (((id)<<5)|(prec))
12259 #define PREC(op) ((op) & 0x1F)
12261 #define TOK_LPAREN tok_decl(0,0)
12263 #define TOK_COMMA tok_decl(1,0)
12265 #define TOK_ASSIGN tok_decl(2,0)
12266 #define TOK_AND_ASSIGN tok_decl(2,1)
12267 #define TOK_OR_ASSIGN tok_decl(2,2)
12268 #define TOK_XOR_ASSIGN tok_decl(2,3)
12269 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12270 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12271 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12272 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12274 #define TOK_MUL_ASSIGN tok_decl(3,0)
12275 #define TOK_DIV_ASSIGN tok_decl(3,1)
12276 #define TOK_REM_ASSIGN tok_decl(3,2)
12278 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12279 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12281 /* conditional is right associativity too */
12282 #define TOK_CONDITIONAL tok_decl(4,0)
12283 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12285 #define TOK_OR tok_decl(5,0)
12287 #define TOK_AND tok_decl(6,0)
12289 #define TOK_BOR tok_decl(7,0)
12291 #define TOK_BXOR tok_decl(8,0)
12293 #define TOK_BAND tok_decl(9,0)
12295 #define TOK_EQ tok_decl(10,0)
12296 #define TOK_NE tok_decl(10,1)
12298 #define TOK_LT tok_decl(11,0)
12299 #define TOK_GT tok_decl(11,1)
12300 #define TOK_GE tok_decl(11,2)
12301 #define TOK_LE tok_decl(11,3)
12303 #define TOK_LSHIFT tok_decl(12,0)
12304 #define TOK_RSHIFT tok_decl(12,1)
12306 #define TOK_ADD tok_decl(13,0)
12307 #define TOK_SUB tok_decl(13,1)
12309 #define TOK_MUL tok_decl(14,0)
12310 #define TOK_DIV tok_decl(14,1)
12311 #define TOK_REM tok_decl(14,2)
12313 /* exponent is right associativity */
12314 #define TOK_EXPONENT tok_decl(15,1)
12316 /* For now unary operators. */
12317 #define UNARYPREC 16
12318 #define TOK_BNOT tok_decl(UNARYPREC,0)
12319 #define TOK_NOT tok_decl(UNARYPREC,1)
12321 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12322 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12324 #define PREC_PRE (UNARYPREC+2)
12326 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12327 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12329 #define PREC_POST (UNARYPREC+3)
12331 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12332 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12334 #define SPEC_PREC (UNARYPREC+4)
12336 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12337 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12339 #define NUMPTR (*numstackptr)
12342 tok_have_assign(operator op)
12344 operator prec = PREC(op);
12346 convert_prec_is_assing(prec);
12347 return (prec == PREC(TOK_ASSIGN) ||
12348 prec == PREC_PRE || prec == PREC_POST);
12352 is_right_associativity(operator prec)
12354 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
12355 || prec == PREC(TOK_CONDITIONAL));
12358 typedef struct ARITCH_VAR_NUM {
12360 arith_t contidional_second_val;
12361 char contidional_second_val_initialized;
12362 char *var; /* if NULL then is regular number,
12363 else is variable name */
12366 typedef struct CHK_VAR_RECURSIVE_LOOPED {
12368 struct CHK_VAR_RECURSIVE_LOOPED *next;
12369 } chk_var_recursive_looped_t;
12371 static chk_var_recursive_looped_t *prev_chk_var_recursive;
12374 arith_lookup_val(v_n_t *t)
12377 const char * p = lookupvar(t->var);
12382 /* recursive try as expression */
12383 chk_var_recursive_looped_t *cur;
12384 chk_var_recursive_looped_t cur_save;
12386 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
12387 if (strcmp(cur->var, t->var) == 0) {
12388 /* expression recursion loop detected */
12392 /* save current lookuped var name */
12393 cur = prev_chk_var_recursive;
12394 cur_save.var = t->var;
12395 cur_save.next = cur;
12396 prev_chk_var_recursive = &cur_save;
12398 t->val = arith (p, &errcode);
12399 /* restore previous ptr after recursiving */
12400 prev_chk_var_recursive = cur;
12403 /* allow undefined var as 0 */
12409 /* "applying" a token means performing it on the top elements on the integer
12410 * stack. For a unary operator it will only change the top element, but a
12411 * binary operator will pop two arguments and push a result */
12413 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
12416 arith_t numptr_val, rez;
12417 int ret_arith_lookup_val;
12419 /* There is no operator that can work without arguments */
12420 if (NUMPTR == numstack) goto err;
12421 numptr_m1 = NUMPTR - 1;
12423 /* check operand is var with noninteger value */
12424 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12425 if (ret_arith_lookup_val)
12426 return ret_arith_lookup_val;
12428 rez = numptr_m1->val;
12429 if (op == TOK_UMINUS)
12431 else if (op == TOK_NOT)
12433 else if (op == TOK_BNOT)
12435 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
12437 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
12439 else if (op != TOK_UPLUS) {
12440 /* Binary operators */
12442 /* check and binary operators need two arguments */
12443 if (numptr_m1 == numstack) goto err;
12445 /* ... and they pop one */
12448 if (op == TOK_CONDITIONAL) {
12449 if (! numptr_m1->contidional_second_val_initialized) {
12450 /* protect $((expr1 ? expr2)) without ": expr" */
12453 rez = numptr_m1->contidional_second_val;
12454 } else if (numptr_m1->contidional_second_val_initialized) {
12455 /* protect $((expr1 : expr2)) without "expr ? " */
12458 numptr_m1 = NUMPTR - 1;
12459 if (op != TOK_ASSIGN) {
12460 /* check operand is var with noninteger value for not '=' */
12461 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12462 if (ret_arith_lookup_val)
12463 return ret_arith_lookup_val;
12465 if (op == TOK_CONDITIONAL) {
12466 numptr_m1->contidional_second_val = rez;
12468 rez = numptr_m1->val;
12469 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
12471 else if (op == TOK_OR)
12472 rez = numptr_val || rez;
12473 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
12475 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
12477 else if (op == TOK_AND)
12478 rez = rez && numptr_val;
12479 else if (op == TOK_EQ)
12480 rez = (rez == numptr_val);
12481 else if (op == TOK_NE)
12482 rez = (rez != numptr_val);
12483 else if (op == TOK_GE)
12484 rez = (rez >= numptr_val);
12485 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
12486 rez >>= numptr_val;
12487 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
12488 rez <<= numptr_val;
12489 else if (op == TOK_GT)
12490 rez = (rez > numptr_val);
12491 else if (op == TOK_LT)
12492 rez = (rez < numptr_val);
12493 else if (op == TOK_LE)
12494 rez = (rez <= numptr_val);
12495 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
12497 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
12499 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
12501 else if (op == TOK_ASSIGN || op == TOK_COMMA)
12503 else if (op == TOK_CONDITIONAL_SEP) {
12504 if (numptr_m1 == numstack) {
12505 /* protect $((expr : expr)) without "expr ? " */
12508 numptr_m1->contidional_second_val_initialized = op;
12509 numptr_m1->contidional_second_val = numptr_val;
12510 } else if (op == TOK_CONDITIONAL) {
12512 numptr_val : numptr_m1->contidional_second_val;
12513 } else if (op == TOK_EXPONENT) {
12514 if (numptr_val < 0)
12515 return -3; /* exponent less than 0 */
12520 while (numptr_val--)
12524 } else if (numptr_val==0) /* zero divisor check */
12526 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
12528 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
12531 if (tok_have_assign(op)) {
12532 char buf[sizeof(arith_t_type)*3 + 2];
12534 if (numptr_m1->var == NULL) {
12538 /* save to shell variable */
12539 #if ENABLE_ASH_MATH_SUPPORT_64
12540 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
12542 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
12544 setvar(numptr_m1->var, buf, 0);
12545 /* after saving, make previous value for v++ or v-- */
12546 if (op == TOK_POST_INC)
12548 else if (op == TOK_POST_DEC)
12551 numptr_m1->val = rez;
12552 /* protect geting var value, is number now */
12553 numptr_m1->var = NULL;
12559 /* longest must be first */
12560 static const char op_tokens[] ALIGN1 = {
12561 '<','<','=',0, TOK_LSHIFT_ASSIGN,
12562 '>','>','=',0, TOK_RSHIFT_ASSIGN,
12563 '<','<', 0, TOK_LSHIFT,
12564 '>','>', 0, TOK_RSHIFT,
12565 '|','|', 0, TOK_OR,
12566 '&','&', 0, TOK_AND,
12567 '!','=', 0, TOK_NE,
12568 '<','=', 0, TOK_LE,
12569 '>','=', 0, TOK_GE,
12570 '=','=', 0, TOK_EQ,
12571 '|','=', 0, TOK_OR_ASSIGN,
12572 '&','=', 0, TOK_AND_ASSIGN,
12573 '*','=', 0, TOK_MUL_ASSIGN,
12574 '/','=', 0, TOK_DIV_ASSIGN,
12575 '%','=', 0, TOK_REM_ASSIGN,
12576 '+','=', 0, TOK_PLUS_ASSIGN,
12577 '-','=', 0, TOK_MINUS_ASSIGN,
12578 '-','-', 0, TOK_POST_DEC,
12579 '^','=', 0, TOK_XOR_ASSIGN,
12580 '+','+', 0, TOK_POST_INC,
12581 '*','*', 0, TOK_EXPONENT,
12585 '=', 0, TOK_ASSIGN,
12597 '?', 0, TOK_CONDITIONAL,
12598 ':', 0, TOK_CONDITIONAL_SEP,
12599 ')', 0, TOK_RPAREN,
12600 '(', 0, TOK_LPAREN,
12604 #define endexpression &op_tokens[sizeof(op_tokens)-7]
12607 arith(const char *expr, int *perrcode)
12609 char arithval; /* Current character under analysis */
12610 operator lasttok, op;
12613 const char *p = endexpression;
12616 size_t datasizes = strlen(expr) + 2;
12618 /* Stack of integers */
12619 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
12620 * in any given correct or incorrect expression is left as an exercise to
12622 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
12623 *numstackptr = numstack;
12624 /* Stack of operator tokens */
12625 operator *stack = alloca((datasizes) * sizeof(operator)),
12628 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
12629 *perrcode = errcode = 0;
12633 if (arithval == 0) {
12634 if (p == endexpression) {
12635 /* Null expression. */
12639 /* This is only reached after all tokens have been extracted from the
12640 * input stream. If there are still tokens on the operator stack, they
12641 * are to be applied in order. At the end, there should be a final
12642 * result on the integer stack */
12644 if (expr != endexpression + 1) {
12645 /* If we haven't done so already, */
12646 /* append a closing right paren */
12647 expr = endexpression;
12648 /* and let the loop process it. */
12651 /* At this point, we're done with the expression. */
12652 if (numstackptr != numstack+1) {
12653 /* ... but if there isn't, it's bad */
12655 return (*perrcode = -1);
12657 if (numstack->var) {
12658 /* expression is $((var)) only, lookup now */
12659 errcode = arith_lookup_val(numstack);
12662 *perrcode = errcode;
12663 return numstack->val;
12666 /* Continue processing the expression. */
12667 if (arith_isspace(arithval)) {
12668 /* Skip whitespace */
12671 p = endofname(expr);
12673 size_t var_name_size = (p-expr) + 1; /* trailing zero */
12675 numstackptr->var = alloca(var_name_size);
12676 safe_strncpy(numstackptr->var, expr, var_name_size);
12679 numstackptr->contidional_second_val_initialized = 0;
12684 if (isdigit(arithval)) {
12685 numstackptr->var = NULL;
12686 #if ENABLE_ASH_MATH_SUPPORT_64
12687 numstackptr->val = strtoll(expr, (char **) &expr, 0);
12689 numstackptr->val = strtol(expr, (char **) &expr, 0);
12693 for (p = op_tokens; ; p++) {
12697 /* strange operator not found */
12700 for (o = expr; *p && *o == *p; p++)
12707 /* skip tail uncompared token */
12710 /* skip zero delim */
12715 /* post grammar: a++ reduce to num */
12716 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
12719 /* Plus and minus are binary (not unary) _only_ if the last
12720 * token was as number, or a right paren (which pretends to be
12721 * a number, since it evaluates to one). Think about it.
12722 * It makes sense. */
12723 if (lasttok != TOK_NUM) {
12739 /* We don't want a unary operator to cause recursive descent on the
12740 * stack, because there can be many in a row and it could cause an
12741 * operator to be evaluated before its argument is pushed onto the
12742 * integer stack. */
12743 /* But for binary operators, "apply" everything on the operator
12744 * stack until we find an operator with a lesser priority than the
12745 * one we have just extracted. */
12746 /* Left paren is given the lowest priority so it will never be
12747 * "applied" in this way.
12748 * if associativity is right and priority eq, applied also skip
12751 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
12752 /* not left paren or unary */
12753 if (lasttok != TOK_NUM) {
12754 /* binary op must be preceded by a num */
12757 while (stackptr != stack) {
12758 if (op == TOK_RPAREN) {
12759 /* The algorithm employed here is simple: while we don't
12760 * hit an open paren nor the bottom of the stack, pop
12761 * tokens and apply them */
12762 if (stackptr[-1] == TOK_LPAREN) {
12764 /* Any operator directly after a */
12766 /* close paren should consider itself binary */
12770 operator prev_prec = PREC(stackptr[-1]);
12772 convert_prec_is_assing(prec);
12773 convert_prec_is_assing(prev_prec);
12774 if (prev_prec < prec)
12776 /* check right assoc */
12777 if (prev_prec == prec && is_right_associativity(prec))
12780 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
12781 if (errcode) goto ret;
12783 if (op == TOK_RPAREN) {
12788 /* Push this operator to the stack and remember it. */
12789 *stackptr++ = lasttok = op;
12794 #endif /* ASH_MATH_SUPPORT */
12797 /* ============ main() and helpers */
12800 * Called to exit the shell.
12802 static void exitshell(void) ATTRIBUTE_NORETURN;
12810 status = exitstatus;
12811 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12812 if (setjmp(loc.loc)) {
12813 if (exception == EXEXIT)
12814 /* dash bug: it just does _exit(exitstatus) here
12815 * but we have to do setjobctl(0) first!
12816 * (bug is still not fixed in dash-0.5.3 - if you run dash
12817 * under Midnight Commander, on exit from dash MC is backgrounded) */
12818 status = exitstatus;
12821 exception_handler = &loc;
12827 flush_stdout_stderr();
12837 /* from input.c: */
12838 basepf.nextc = basepf.buf = basebuf;
12841 signal(SIGCHLD, SIG_DFL);
12846 char ppid[sizeof(int)*3 + 1];
12848 struct stat st1, st2;
12851 for (envp = environ; envp && *envp; envp++) {
12852 if (strchr(*envp, '=')) {
12853 setvareq(*envp, VEXPORT|VTEXTFIXED);
12857 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
12858 setvar("PPID", ppid, 0);
12860 p = lookupvar("PWD");
12862 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
12863 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
12870 * Process the shell command line arguments.
12873 procargs(int argc, char **argv)
12876 const char *xminusc;
12883 for (i = 0; i < NOPTS; i++)
12887 /* it already printed err message */
12888 raise_exception(EXERROR);
12892 if (*xargv == NULL) {
12894 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
12897 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
12901 for (i = 0; i < NOPTS; i++)
12902 if (optlist[i] == 2)
12907 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
12912 } else if (!sflag) {
12913 setinputfile(*xargv, 0);
12916 commandname = arg0;
12919 shellparam.p = xargv;
12920 #if ENABLE_ASH_GETOPTS
12921 shellparam.optind = 1;
12922 shellparam.optoff = -1;
12924 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
12926 shellparam.nparam++;
12933 * Read /etc/profile or .profile.
12936 read_profile(const char *name)
12940 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
12949 * This routine is called when an error or an interrupt occurs in an
12950 * interactive shell and control is returned to the main command loop.
12958 /* from input.c: */
12959 parselleft = parsenleft = 0; /* clear input buffer */
12961 /* from parser.c: */
12964 /* from redir.c: */
12969 static short profile_buf[16384];
12970 extern int etext();
12974 * Main routine. We initialize things, parse the arguments, execute
12975 * profiles if we're a login shell, and then call cmdloop to execute
12976 * commands. The setjmp call sets up the location to jump to when an
12977 * exception occurs. When an exception occurs the variable "state"
12978 * is used to figure out how far we had gotten.
12980 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
12981 int ash_main(int argc, char **argv)
12984 volatile int state;
12985 struct jmploc jmploc;
12986 struct stackmark smark;
12988 /* Initialize global data */
12992 #if ENABLE_ASH_ALIAS
12998 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13001 #if ENABLE_FEATURE_EDITING
13002 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13005 if (setjmp(jmploc.loc)) {
13015 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13019 outcslow('\n', stderr);
13021 popstackmark(&smark);
13022 FORCE_INT_ON; /* enable interrupts */
13031 exception_handler = &jmploc;
13034 trace_puts("Shell args: ");
13035 trace_puts_args(argv);
13037 rootpid = getpid();
13039 #if ENABLE_ASH_RANDOM_SUPPORT
13040 rseed = rootpid + time(NULL);
13043 setstackmark(&smark);
13044 procargs(argc, argv);
13045 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13047 const char *hp = lookupvar("HISTFILE");
13050 hp = lookupvar("HOME");
13052 char *defhp = concat_path_file(hp, ".ash_history");
13053 setvar("HISTFILE", defhp, 0);
13059 if (argv[0] && argv[0][0] == '-')
13063 read_profile("/etc/profile");
13066 read_profile(".profile");
13072 getuid() == geteuid() && getgid() == getegid() &&
13076 shinit = lookupvar("ENV");
13077 if (shinit != NULL && *shinit != '\0') {
13078 read_profile(shinit);
13084 evalstring(minusc, 0);
13086 if (sflag || minusc == NULL) {
13087 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13089 const char *hp = lookupvar("HISTFILE");
13092 line_input_state->hist_file = hp;
13095 state4: /* XXX ??? - why isn't this before the "if" statement */
13103 extern void _mcleanup(void);
13112 const char *applet_name = "debug stuff usage";
13113 int main(int argc, char **argv)
13115 return ash_main(argc, argv);
13121 * Copyright (c) 1989, 1991, 1993, 1994
13122 * The Regents of the University of California. All rights reserved.
13124 * This code is derived from software contributed to Berkeley by
13125 * Kenneth Almquist.
13127 * Redistribution and use in source and binary forms, with or without
13128 * modification, are permitted provided that the following conditions
13130 * 1. Redistributions of source code must retain the above copyright
13131 * notice, this list of conditions and the following disclaimer.
13132 * 2. Redistributions in binary form must reproduce the above copyright
13133 * notice, this list of conditions and the following disclaimer in the
13134 * documentation and/or other materials provided with the distribution.
13135 * 3. Neither the name of the University nor the names of its contributors
13136 * may be used to endorse or promote products derived from this software
13137 * without specific prior written permission.
13139 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13140 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13141 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13142 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13143 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13144 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13145 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13146 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13147 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13148 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF