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 * Make a copy of a string in safe storage.
1192 ckstrdup(const char *s)
1194 char *p = strdup(s);
1196 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1201 * Parse trees for commands are allocated in lifo order, so we use a stack
1202 * to make this more efficient, and also to avoid all sorts of exception
1203 * handling code to handle interrupts in the middle of a parse.
1205 * The size 504 was chosen because the Ultrix malloc handles that size
1209 stalloc(size_t nbytes)
1214 aligned = SHELL_ALIGN(nbytes);
1215 if (aligned > g_stacknleft) {
1218 struct stack_block *sp;
1220 blocksize = aligned;
1221 if (blocksize < MINSIZE)
1222 blocksize = MINSIZE;
1223 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1224 if (len < blocksize)
1225 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1228 sp->prev = g_stackp;
1229 g_stacknxt = sp->space;
1230 g_stacknleft = blocksize;
1231 sstrend = g_stacknxt + blocksize;
1236 g_stacknxt += aligned;
1237 g_stacknleft -= aligned;
1245 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1246 write(2, "stunalloc\n", 10);
1250 g_stacknleft += g_stacknxt - (char *)p;
1255 * Like strdup but works with the ash stack.
1258 ststrdup(const char *p)
1260 size_t len = strlen(p) + 1;
1261 return memcpy(stalloc(len), p, len);
1265 setstackmark(struct stackmark *mark)
1267 mark->stackp = g_stackp;
1268 mark->stacknxt = g_stacknxt;
1269 mark->stacknleft = g_stacknleft;
1270 mark->marknext = markp;
1275 popstackmark(struct stackmark *mark)
1277 struct stack_block *sp;
1283 markp = mark->marknext;
1284 while (g_stackp != mark->stackp) {
1286 g_stackp = sp->prev;
1289 g_stacknxt = mark->stacknxt;
1290 g_stacknleft = mark->stacknleft;
1291 sstrend = mark->stacknxt + mark->stacknleft;
1296 * When the parser reads in a string, it wants to stick the string on the
1297 * stack and only adjust the stack pointer when it knows how big the
1298 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1299 * of space on top of the stack and stackblocklen returns the length of
1300 * this block. Growstackblock will grow this space by at least one byte,
1301 * possibly moving it (like realloc). Grabstackblock actually allocates the
1302 * part of the block that has been used.
1305 growstackblock(void)
1309 newlen = g_stacknleft * 2;
1310 if (newlen < g_stacknleft)
1311 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1315 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1316 struct stack_block *oldstackp;
1317 struct stackmark *xmark;
1318 struct stack_block *sp;
1319 struct stack_block *prevstackp;
1323 oldstackp = g_stackp;
1325 prevstackp = sp->prev;
1326 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1327 sp = ckrealloc(sp, grosslen);
1328 sp->prev = prevstackp;
1330 g_stacknxt = sp->space;
1331 g_stacknleft = newlen;
1332 sstrend = sp->space + newlen;
1335 * Stack marks pointing to the start of the old block
1336 * must be relocated to point to the new block
1339 while (xmark != NULL && xmark->stackp == oldstackp) {
1340 xmark->stackp = g_stackp;
1341 xmark->stacknxt = g_stacknxt;
1342 xmark->stacknleft = g_stacknleft;
1343 xmark = xmark->marknext;
1347 char *oldspace = g_stacknxt;
1348 int oldlen = g_stacknleft;
1349 char *p = stalloc(newlen);
1351 /* free the space we just allocated */
1352 g_stacknxt = memcpy(p, oldspace, oldlen);
1353 g_stacknleft += newlen;
1358 grabstackblock(size_t len)
1360 len = SHELL_ALIGN(len);
1362 g_stacknleft -= len;
1366 * The following routines are somewhat easier to use than the above.
1367 * The user declares a variable of type STACKSTR, which may be declared
1368 * to be a register. The macro STARTSTACKSTR initializes things. Then
1369 * the user uses the macro STPUTC to add characters to the string. In
1370 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1371 * grown as necessary. When the user is done, she can just leave the
1372 * string there and refer to it using stackblock(). Or she can allocate
1373 * the space for it using grabstackstr(). If it is necessary to allow
1374 * someone else to use the stack temporarily and then continue to grow
1375 * the string, the user should use grabstack to allocate the space, and
1376 * then call ungrabstr(p) to return to the previous mode of operation.
1378 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1379 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1380 * is space for at least one character.
1385 size_t len = stackblocksize();
1386 if (herefd >= 0 && len >= 1024) {
1387 full_write(herefd, stackblock(), len);
1388 return stackblock();
1391 return stackblock() + len;
1395 * Called from CHECKSTRSPACE.
1398 makestrspace(size_t newlen, char *p)
1400 size_t len = p - g_stacknxt;
1401 size_t size = stackblocksize();
1406 size = stackblocksize();
1408 if (nleft >= newlen)
1412 return stackblock() + len;
1416 stack_nputstr(const char *s, size_t n, char *p)
1418 p = makestrspace(n, p);
1419 p = memcpy(p, s, n) + n;
1424 stack_putstr(const char *s, char *p)
1426 return stack_nputstr(s, strlen(s), p);
1430 _STPUTC(int c, char *p)
1438 #define STARTSTACKSTR(p) ((p) = stackblock())
1439 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1440 #define CHECKSTRSPACE(n, p) \
1444 size_t m = sstrend - q; \
1446 (p) = makestrspace(l, q); \
1448 #define USTPUTC(c, p) (*p++ = (c))
1449 #define STACKSTRNUL(p) \
1451 if ((p) == sstrend) \
1452 p = growstackstr(); \
1455 #define STUNPUTC(p) (--p)
1456 #define STTOPC(p) (p[-1])
1457 #define STADJUST(amount, p) (p += (amount))
1459 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1460 #define ungrabstackstr(s, p) stunalloc((s))
1461 #define stackstrend() ((void *)sstrend)
1464 /* ============ String helpers */
1467 * prefix -- see if pfx is a prefix of string.
1470 prefix(const char *string, const char *pfx)
1473 if (*pfx++ != *string++)
1476 return (char *) string;
1480 * Check for a valid number. This should be elsewhere.
1483 is_number(const char *p)
1488 } while (*++p != '\0');
1493 * Convert a string of digits to an integer, printing an error message on
1497 number(const char *s)
1500 ash_msg_and_raise_error(illnum, s);
1505 * Produce a possibly single quoted string suitable as input to the shell.
1506 * The return string is allocated on the stack.
1509 single_quote(const char *s)
1519 len = strchrnul(s, '\'') - s;
1521 q = p = makestrspace(len + 3, p);
1524 q = memcpy(q, s, len) + len;
1530 len = strspn(s, "'");
1534 q = p = makestrspace(len + 3, p);
1537 q = memcpy(q, s, len) + len;
1546 return stackblock();
1550 /* ============ nextopt */
1552 static char **argptr; /* argument list for builtin commands */
1553 static char *optionarg; /* set by nextopt (like getopt) */
1554 static char *optptr; /* used by nextopt */
1557 * XXX - should get rid of. have all builtins use getopt(3). the
1558 * library getopt must have the BSD extension static variable "optreset"
1559 * otherwise it can't be used within the shell safely.
1561 * Standard option processing (a la getopt) for builtin routines. The
1562 * only argument that is passed to nextopt is the option string; the
1563 * other arguments are unnecessary. It return the character, or '\0' on
1567 nextopt(const char *optstring)
1574 if (p == NULL || *p == '\0') {
1576 if (p == NULL || *p != '-' || *++p == '\0')
1579 if (LONE_DASH(p)) /* check for "--" */
1583 for (q = optstring; *q != c; ) {
1585 ash_msg_and_raise_error("illegal option -%c", c);
1590 if (*p == '\0' && (p = *argptr++) == NULL)
1591 ash_msg_and_raise_error("no arg for -%c option", c);
1600 /* ============ Math support definitions */
1602 #if ENABLE_ASH_MATH_SUPPORT_64
1603 typedef int64_t arith_t;
1604 #define arith_t_type long long
1606 typedef long arith_t;
1607 #define arith_t_type long
1610 #if ENABLE_ASH_MATH_SUPPORT
1611 static arith_t dash_arith(const char *);
1612 static arith_t arith(const char *expr, int *perrcode);
1615 #if ENABLE_ASH_RANDOM_SUPPORT
1616 static unsigned long rseed;
1623 /* ============ Shell variables */
1626 * The parsefile structure pointed to by the global variable parsefile
1627 * contains information about the current file being read.
1630 struct redirtab *next;
1636 int nparam; /* # of positional parameters (without $0) */
1637 #if ENABLE_ASH_GETOPTS
1638 int optind; /* next parameter to be processed by getopts */
1639 int optoff; /* used by getopts */
1641 unsigned char malloced; /* if parameter list dynamically allocated */
1642 char **p; /* parameter list */
1646 * Free the list of positional parameters.
1649 freeparam(volatile struct shparam *param)
1653 if (param->malloced) {
1654 for (ap = param->p; *ap; ap++)
1660 #if ENABLE_ASH_GETOPTS
1661 static void getoptsreset(const char *value);
1665 struct var *next; /* next entry in hash list */
1666 int flags; /* flags are defined above */
1667 const char *text; /* name=value */
1668 void (*func)(const char *); /* function to be called when */
1669 /* the variable gets set/unset */
1673 struct localvar *next; /* next local variable in list */
1674 struct var *vp; /* the variable that was made local */
1675 int flags; /* saved flags */
1676 const char *text; /* saved text */
1680 #define VEXPORT 0x01 /* variable is exported */
1681 #define VREADONLY 0x02 /* variable cannot be modified */
1682 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1683 #define VTEXTFIXED 0x08 /* text is statically allocated */
1684 #define VSTACK 0x10 /* text is allocated on the stack */
1685 #define VUNSET 0x20 /* the variable is not set */
1686 #define VNOFUNC 0x40 /* don't call the callback function */
1687 #define VNOSET 0x80 /* do not set variable - just readonly test */
1688 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1690 # define VDYNAMIC 0x200 /* dynamic variable */
1696 static const char defifsvar[] ALIGN1 = "IFS= \t\n";
1697 #define defifs (defifsvar + 4)
1699 static const char defifs[] ALIGN1 = " \t\n";
1703 /* Need to be before varinit_data[] */
1704 #if ENABLE_LOCALE_SUPPORT
1706 change_lc_all(const char *value)
1708 if (value && *value != '\0')
1709 setlocale(LC_ALL, value);
1712 change_lc_ctype(const char *value)
1714 if (value && *value != '\0')
1715 setlocale(LC_CTYPE, value);
1719 static void chkmail(void);
1720 static void changemail(const char *);
1722 static void changepath(const char *);
1723 #if ENABLE_ASH_RANDOM_SUPPORT
1724 static void change_random(const char *);
1727 static const struct {
1730 void (*func)(const char *);
1731 } varinit_data[] = {
1733 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1735 { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL },
1738 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0" , changemail },
1739 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1741 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1742 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1743 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1744 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1745 #if ENABLE_ASH_GETOPTS
1746 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
1748 #if ENABLE_ASH_RANDOM_SUPPORT
1749 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1751 #if ENABLE_LOCALE_SUPPORT
1752 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL\0" , change_lc_all },
1753 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE\0", change_lc_ctype },
1755 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1756 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE\0", NULL },
1761 struct globals_var {
1762 struct shparam shellparam; /* $@ current positional parameters */
1763 struct redirtab *redirlist;
1765 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1766 struct var *vartab[VTABSIZE];
1767 struct var varinit[ARRAY_SIZE(varinit_data)];
1769 /* Make it reside in writable memory, yet make compiler understand that it is not going to change. */
1770 static struct globals_var *const ptr_to_globals_var __attribute__ ((section (".data")));
1771 #define G_var (*ptr_to_globals_var)
1772 #define shellparam (G_var.shellparam )
1773 #define redirlist (G_var.redirlist )
1774 #define g_nullredirs (G_var.g_nullredirs )
1775 #define preverrout_fd (G_var.preverrout_fd)
1776 #define vartab (G_var.vartab )
1777 #define varinit (G_var.varinit )
1778 #define INIT_G_var() do { \
1780 (*(struct globals_var**)&ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1781 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1782 varinit[i].flags = varinit_data[i].flags; \
1783 varinit[i].text = varinit_data[i].text; \
1784 varinit[i].func = varinit_data[i].func; \
1788 #define vifs varinit[0]
1790 # define vmail (&vifs)[1]
1791 # define vmpath (&vmail)[1]
1792 # define vpath (&vmpath)[1]
1794 # define vpath (&vifs)[1]
1796 #define vps1 (&vpath)[1]
1797 #define vps2 (&vps1)[1]
1798 #define vps4 (&vps2)[1]
1799 #if ENABLE_ASH_GETOPTS
1800 # define voptind (&vps4)[1]
1801 # if ENABLE_ASH_RANDOM_SUPPORT
1802 # define vrandom (&voptind)[1]
1805 # if ENABLE_ASH_RANDOM_SUPPORT
1806 # define vrandom (&vps4)[1]
1811 * The following macros access the values of the above variables.
1812 * They have to skip over the name. They return the null string
1813 * for unset variables.
1815 #define ifsval() (vifs.text + 4)
1816 #define ifsset() ((vifs.flags & VUNSET) == 0)
1818 # define mailval() (vmail.text + 5)
1819 # define mpathval() (vmpath.text + 9)
1820 # define mpathset() ((vmpath.flags & VUNSET) == 0)
1822 #define pathval() (vpath.text + 5)
1823 #define ps1val() (vps1.text + 4)
1824 #define ps2val() (vps2.text + 4)
1825 #define ps4val() (vps4.text + 4)
1826 #if ENABLE_ASH_GETOPTS
1827 # define optindval() (voptind.text + 7)
1831 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1832 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1834 #if ENABLE_ASH_GETOPTS
1836 getoptsreset(const char *value)
1838 shellparam.optind = number(value);
1839 shellparam.optoff = -1;
1844 * Return of a legal variable name (a letter or underscore followed by zero or
1845 * more letters, underscores, and digits).
1848 endofname(const char *name)
1856 if (!is_in_name(*p))
1863 * Compares two strings up to the first = or '\0'. The first
1864 * string must be terminated by '='; the second may be terminated by
1865 * either '=' or '\0'.
1868 varcmp(const char *p, const char *q)
1872 while ((c = *p) == (d = *q)) {
1887 varequal(const char *a, const char *b)
1889 return !varcmp(a, b);
1893 * Find the appropriate entry in the hash table from the name.
1895 static struct var **
1896 hashvar(const char *p)
1900 hashval = ((unsigned char) *p) << 4;
1901 while (*p && *p != '=')
1902 hashval += (unsigned char) *p++;
1903 return &vartab[hashval % VTABSIZE];
1907 vpcmp(const void *a, const void *b)
1909 return varcmp(*(const char **)a, *(const char **)b);
1913 * This routine initializes the builtin variables.
1923 * PS1 depends on uid
1925 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1926 vps1.text = "PS1=\\w \\$ ";
1929 vps1.text = "PS1=# ";
1932 end = vp + ARRAY_SIZE(varinit);
1934 vpp = hashvar(vp->text);
1937 } while (++vp < end);
1940 static struct var **
1941 findvar(struct var **vpp, const char *name)
1943 for (; *vpp; vpp = &(*vpp)->next) {
1944 if (varequal((*vpp)->text, name)) {
1952 * Find the value of a variable. Returns NULL if not set.
1955 lookupvar(const char *name)
1959 v = *findvar(hashvar(name), name);
1963 * Dynamic variables are implemented roughly the same way they are
1964 * in bash. Namely, they're "special" so long as they aren't unset.
1965 * As soon as they're unset, they're no longer dynamic, and dynamic
1966 * lookup will no longer happen at that point. -- PFM.
1968 if ((v->flags & VDYNAMIC))
1971 if (!(v->flags & VUNSET))
1972 return strchrnul(v->text, '=') + 1;
1978 * Search the environment of a builtin command.
1981 bltinlookup(const char *name)
1985 for (sp = cmdenviron; sp; sp = sp->next) {
1986 if (varequal(sp->text, name))
1987 return strchrnul(sp->text, '=') + 1;
1989 return lookupvar(name);
1993 * Same as setvar except that the variable and value are passed in
1994 * the first argument as name=value. Since the first argument will
1995 * be actually stored in the table, it should not be a string that
1997 * Called with interrupts off.
2000 setvareq(char *s, int flags)
2002 struct var *vp, **vpp;
2005 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2006 vp = *findvar(vpp, s);
2008 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2011 if (flags & VNOSAVE)
2014 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2020 if (vp->func && (flags & VNOFUNC) == 0)
2021 (*vp->func)(strchrnul(s, '=') + 1);
2023 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
2024 free((char*)vp->text);
2026 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2031 vp = ckmalloc(sizeof(*vp));
2036 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2043 * Set the value of a variable. The flags argument is ored with the
2044 * flags of the variable. If val is NULL, the variable is unset.
2047 setvar(const char *name, const char *val, int flags)
2054 q = endofname(name);
2055 p = strchrnul(q, '=');
2057 if (!namelen || p != q)
2058 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2063 vallen = strlen(val);
2066 nameeq = ckmalloc(namelen + vallen + 2);
2067 p = memcpy(nameeq, name, namelen) + namelen;
2070 p = memcpy(p, val, vallen) + vallen;
2073 setvareq(nameeq, flags | VNOSAVE);
2077 #if ENABLE_ASH_GETOPTS
2079 * Safe version of setvar, returns 1 on success 0 on failure.
2082 setvarsafe(const char *name, const char *val, int flags)
2085 volatile int saveint;
2086 struct jmploc *volatile savehandler = exception_handler;
2087 struct jmploc jmploc;
2090 if (setjmp(jmploc.loc))
2093 exception_handler = &jmploc;
2094 setvar(name, val, flags);
2097 exception_handler = savehandler;
2098 RESTORE_INT(saveint);
2104 * Unset the specified variable.
2107 unsetvar(const char *s)
2113 vpp = findvar(hashvar(s), s);
2117 int flags = vp->flags;
2120 if (flags & VREADONLY)
2123 vp->flags &= ~VDYNAMIC;
2127 if ((flags & VSTRFIXED) == 0) {
2129 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2130 free((char*)vp->text);
2136 vp->flags &= ~VEXPORT;
2146 * Process a linked list of variable assignments.
2149 listsetvar(struct strlist *list_set_var, int flags)
2151 struct strlist *lp = list_set_var;
2157 setvareq(lp->text, flags);
2164 * Generate a list of variables satisfying the given conditions.
2167 listvars(int on, int off, char ***end)
2178 for (vp = *vpp; vp; vp = vp->next) {
2179 if ((vp->flags & mask) == on) {
2180 if (ep == stackstrend())
2181 ep = growstackstr();
2182 *ep++ = (char *) vp->text;
2185 } while (++vpp < vartab + VTABSIZE);
2186 if (ep == stackstrend())
2187 ep = growstackstr();
2191 return grabstackstr(ep);
2195 /* ============ Path search helper
2197 * The variable path (passed by reference) should be set to the start
2198 * of the path before the first call; padvance will update
2199 * this value as it proceeds. Successive calls to padvance will return
2200 * the possible path expansions in sequence. If an option (indicated by
2201 * a percent sign) appears in the path entry then the global variable
2202 * pathopt will be set to point to it; otherwise pathopt will be set to
2205 static const char *pathopt; /* set by padvance */
2208 padvance(const char **path, const char *name)
2218 for (p = start; *p && *p != ':' && *p != '%'; p++);
2219 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2220 while (stackblocksize() < len)
2224 memcpy(q, start, p - start);
2232 while (*p && *p != ':') p++;
2238 return stalloc(len);
2242 /* ============ Prompt */
2244 static smallint doprompt; /* if set, prompt the user */
2245 static smallint needprompt; /* true if interactive and at start of line */
2247 #if ENABLE_FEATURE_EDITING
2248 static line_input_t *line_input_state;
2249 static const char *cmdedit_prompt;
2251 putprompt(const char *s)
2253 if (ENABLE_ASH_EXPAND_PRMT) {
2254 free((char*)cmdedit_prompt);
2255 cmdedit_prompt = ckstrdup(s);
2262 putprompt(const char *s)
2268 #if ENABLE_ASH_EXPAND_PRMT
2269 /* expandstr() needs parsing machinery, so it is far away ahead... */
2270 static const char *expandstr(const char *ps);
2272 #define expandstr(s) s
2276 setprompt(int whichprompt)
2279 #if ENABLE_ASH_EXPAND_PRMT
2280 struct stackmark smark;
2285 switch (whichprompt) {
2295 #if ENABLE_ASH_EXPAND_PRMT
2296 setstackmark(&smark);
2297 stalloc(stackblocksize());
2299 putprompt(expandstr(prompt));
2300 #if ENABLE_ASH_EXPAND_PRMT
2301 popstackmark(&smark);
2306 /* ============ The cd and pwd commands */
2308 #define CD_PHYSICAL 1
2311 static int docd(const char *, int);
2320 while ((i = nextopt("LP"))) {
2322 flags ^= CD_PHYSICAL;
2331 * Update curdir (the name of the current directory) in response to a
2335 updatepwd(const char *dir)
2342 cdcomppath = ststrdup(dir);
2345 if (curdir == nullstr)
2347 new = stack_putstr(curdir, new);
2349 new = makestrspace(strlen(dir) + 2, new);
2350 lim = stackblock() + 1;
2354 if (new > lim && *lim == '/')
2359 if (dir[1] == '/' && dir[2] != '/') {
2365 p = strtok(cdcomppath, "/");
2369 if (p[1] == '.' && p[2] == '\0') {
2381 new = stack_putstr(p, new);
2389 return stackblock();
2393 * Find out what the current directory is. If we already know the current
2394 * directory, this routine returns immediately.
2399 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2400 return dir ? dir : nullstr;
2404 setpwd(const char *val, int setold)
2408 oldcur = dir = curdir;
2411 setvar("OLDPWD", oldcur, VEXPORT);
2414 if (physdir != nullstr) {
2415 if (physdir != oldcur)
2419 if (oldcur == val || !val) {
2425 dir = ckstrdup(val);
2426 if (oldcur != dir && oldcur != nullstr) {
2431 setvar("PWD", dir, VEXPORT);
2434 static void hashcd(void);
2437 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2438 * know that the current directory has changed.
2441 docd(const char *dest, int flags)
2443 const char *dir = 0;
2446 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2449 if (!(flags & CD_PHYSICAL)) {
2450 dir = updatepwd(dest);
2465 cdcmd(int argc, char **argv)
2477 dest = bltinlookup(homestr);
2478 else if (LONE_DASH(dest)) {
2479 dest = bltinlookup("OLDPWD");
2501 path = bltinlookup("CDPATH");
2510 p = padvance(&path, dest);
2511 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2515 if (!docd(p, flags))
2520 ash_msg_and_raise_error("can't cd to %s", dest);
2523 if (flags & CD_PRINT)
2524 out1fmt(snlfmt, curdir);
2529 pwdcmd(int argc, char **argv)
2532 const char *dir = curdir;
2536 if (physdir == nullstr)
2540 out1fmt(snlfmt, dir);
2545 /* ============ ... */
2547 #define IBUFSIZ COMMON_BUFSIZE
2548 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */
2550 /* Syntax classes */
2551 #define CWORD 0 /* character is nothing special */
2552 #define CNL 1 /* newline character */
2553 #define CBACK 2 /* a backslash character */
2554 #define CSQUOTE 3 /* single quote */
2555 #define CDQUOTE 4 /* double quote */
2556 #define CENDQUOTE 5 /* a terminating quote */
2557 #define CBQUOTE 6 /* backwards single quote */
2558 #define CVAR 7 /* a dollar sign */
2559 #define CENDVAR 8 /* a '}' character */
2560 #define CLP 9 /* a left paren in arithmetic */
2561 #define CRP 10 /* a right paren in arithmetic */
2562 #define CENDFILE 11 /* end of file */
2563 #define CCTL 12 /* like CWORD, except it must be escaped */
2564 #define CSPCL 13 /* these terminate a word */
2565 #define CIGN 14 /* character should be ignored */
2567 #if ENABLE_ASH_ALIAS
2571 #define PEOA_OR_PEOF PEOA
2575 #define PEOA_OR_PEOF PEOF
2578 /* number syntax index */
2579 #define BASESYNTAX 0 /* not in quotes */
2580 #define DQSYNTAX 1 /* in double quotes */
2581 #define SQSYNTAX 2 /* in single quotes */
2582 #define ARISYNTAX 3 /* in arithmetic */
2583 #define PSSYNTAX 4 /* prompt */
2585 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
2586 #define USE_SIT_FUNCTION
2589 #if ENABLE_ASH_MATH_SUPPORT
2590 static const char S_I_T[][4] = {
2591 #if ENABLE_ASH_ALIAS
2592 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */
2594 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */
2595 { CNL, CNL, CNL, CNL }, /* 2, \n */
2596 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */
2597 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */
2598 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */
2599 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */
2600 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */
2601 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */
2602 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */
2603 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */
2604 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */
2605 #ifndef USE_SIT_FUNCTION
2606 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2607 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2608 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2612 static const char S_I_T[][3] = {
2613 #if ENABLE_ASH_ALIAS
2614 { CSPCL, CIGN, CIGN }, /* 0, PEOA */
2616 { CSPCL, CWORD, CWORD }, /* 1, ' ' */
2617 { CNL, CNL, CNL }, /* 2, \n */
2618 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */
2619 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */
2620 { CVAR, CVAR, CWORD }, /* 5, $ */
2621 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */
2622 { CSPCL, CWORD, CWORD }, /* 7, ( */
2623 { CSPCL, CWORD, CWORD }, /* 8, ) */
2624 { CBACK, CBACK, CCTL }, /* 9, \ */
2625 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */
2626 { CENDVAR, CENDVAR, CWORD }, /* 11, } */
2627 #ifndef USE_SIT_FUNCTION
2628 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2629 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2630 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2633 #endif /* ASH_MATH_SUPPORT */
2635 #ifdef USE_SIT_FUNCTION
2638 SIT(int c, int syntax)
2640 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2641 #if ENABLE_ASH_ALIAS
2642 static const char syntax_index_table[] ALIGN1 = {
2643 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2644 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2645 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2649 static const char syntax_index_table[] ALIGN1 = {
2650 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2651 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2652 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2659 if (c == PEOF) /* 2^8+2 */
2661 #if ENABLE_ASH_ALIAS
2662 if (c == PEOA) /* 2^8+1 */
2666 #define U_C(c) ((unsigned char)(c))
2668 if ((unsigned char)c >= (unsigned char)(CTLESC)
2669 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
2673 s = strchr(spec_symbls, c);
2674 if (s == NULL || *s == '\0')
2676 indx = syntax_index_table[(s - spec_symbls)];
2678 return S_I_T[indx][syntax];
2681 #else /* !USE_SIT_FUNCTION */
2683 #if ENABLE_ASH_ALIAS
2684 #define CSPCL_CIGN_CIGN_CIGN 0
2685 #define CSPCL_CWORD_CWORD_CWORD 1
2686 #define CNL_CNL_CNL_CNL 2
2687 #define CWORD_CCTL_CCTL_CWORD 3
2688 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
2689 #define CVAR_CVAR_CWORD_CVAR 5
2690 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
2691 #define CSPCL_CWORD_CWORD_CLP 7
2692 #define CSPCL_CWORD_CWORD_CRP 8
2693 #define CBACK_CBACK_CCTL_CBACK 9
2694 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
2695 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
2696 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
2697 #define CWORD_CWORD_CWORD_CWORD 13
2698 #define CCTL_CCTL_CCTL_CCTL 14
2700 #define CSPCL_CWORD_CWORD_CWORD 0
2701 #define CNL_CNL_CNL_CNL 1
2702 #define CWORD_CCTL_CCTL_CWORD 2
2703 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
2704 #define CVAR_CVAR_CWORD_CVAR 4
2705 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
2706 #define CSPCL_CWORD_CWORD_CLP 6
2707 #define CSPCL_CWORD_CWORD_CRP 7
2708 #define CBACK_CBACK_CCTL_CBACK 8
2709 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
2710 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
2711 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
2712 #define CWORD_CWORD_CWORD_CWORD 12
2713 #define CCTL_CCTL_CCTL_CCTL 13
2716 static const char syntax_index_table[258] = {
2717 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2718 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2719 #if ENABLE_ASH_ALIAS
2720 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
2722 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2723 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2724 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2725 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2726 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2727 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2728 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2729 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2730 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2731 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
2732 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
2733 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
2734 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
2735 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
2736 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
2737 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
2738 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
2739 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
2740 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
2741 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
2742 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
2743 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
2744 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
2745 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
2746 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
2747 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
2748 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
2749 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
2750 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
2751 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
2752 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
2753 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
2754 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
2755 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
2756 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
2757 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
2758 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
2759 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
2760 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
2761 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
2762 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
2763 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
2764 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
2765 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
2766 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
2767 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
2768 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
2769 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
2770 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
2771 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
2772 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
2773 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
2774 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
2775 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
2776 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
2777 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
2778 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
2779 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
2780 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
2781 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
2782 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
2783 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
2784 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
2785 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
2786 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
2787 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
2788 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
2789 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
2790 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
2791 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
2792 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
2793 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
2794 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
2795 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
2796 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
2797 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
2798 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
2799 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
2800 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
2801 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
2802 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
2803 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
2804 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
2805 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
2806 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
2807 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
2808 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
2809 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
2810 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
2811 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
2812 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
2813 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
2814 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
2815 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
2816 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
2817 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
2818 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
2819 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
2820 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
2821 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
2822 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
2823 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
2824 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
2825 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
2826 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
2827 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
2828 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
2829 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
2830 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
2831 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
2832 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
2833 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
2834 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
2835 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
2836 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
2837 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
2838 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
2839 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
2840 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
2841 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
2842 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
2843 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
2844 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
2845 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
2846 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
2847 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
2848 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
2853 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
2854 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2860 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
2861 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2883 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2884 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2885 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2886 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2887 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2888 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2889 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2890 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2891 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2892 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2893 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2894 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
2895 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2896 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
2897 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2898 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2899 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2900 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2901 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2902 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2903 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2904 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2905 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2906 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2907 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2908 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2909 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2910 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2911 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2912 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2913 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2914 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2942 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2943 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2944 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2947 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2975 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2976 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2977 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
2980 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])
2982 #endif /* USE_SIT_FUNCTION */
2985 /* ============ Alias handling */
2987 #if ENABLE_ASH_ALIAS
2989 #define ALIASINUSE 1
3000 static struct alias **atab; // [ATABSIZE];
3001 #define INIT_G_alias() do { \
3002 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3006 static struct alias **
3007 __lookupalias(const char *name) {
3008 unsigned int hashval;
3015 ch = (unsigned char)*p;
3019 ch = (unsigned char)*++p;
3021 app = &atab[hashval % ATABSIZE];
3023 for (; *app; app = &(*app)->next) {
3024 if (strcmp(name, (*app)->name) == 0) {
3032 static struct alias *
3033 lookupalias(const char *name, int check)
3035 struct alias *ap = *__lookupalias(name);
3037 if (check && ap && (ap->flag & ALIASINUSE))
3042 static struct alias *
3043 freealias(struct alias *ap)
3047 if (ap->flag & ALIASINUSE) {
3048 ap->flag |= ALIASDEAD;
3060 setalias(const char *name, const char *val)
3062 struct alias *ap, **app;
3064 app = __lookupalias(name);
3068 if (!(ap->flag & ALIASINUSE)) {
3071 ap->val = ckstrdup(val);
3072 ap->flag &= ~ALIASDEAD;
3075 ap = ckmalloc(sizeof(struct alias));
3076 ap->name = ckstrdup(name);
3077 ap->val = ckstrdup(val);
3086 unalias(const char *name)
3090 app = __lookupalias(name);
3094 *app = freealias(*app);
3105 struct alias *ap, **app;
3109 for (i = 0; i < ATABSIZE; i++) {
3111 for (ap = *app; ap; ap = *app) {
3112 *app = freealias(*app);
3122 printalias(const struct alias *ap)
3124 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3128 * TODO - sort output
3131 aliascmd(int argc, char **argv)
3140 for (i = 0; i < ATABSIZE; i++)
3141 for (ap = atab[i]; ap; ap = ap->next) {
3146 while ((n = *++argv) != NULL) {
3147 v = strchr(n+1, '=');
3148 if (v == NULL) { /* n+1: funny ksh stuff */
3149 ap = *__lookupalias(n);
3151 fprintf(stderr, "%s: %s not found\n", "alias", n);
3165 unaliascmd(int argc, char **argv)
3169 while ((i = nextopt("a")) != '\0') {
3175 for (i = 0; *argptr; argptr++) {
3176 if (unalias(*argptr)) {
3177 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3185 #endif /* ASH_ALIAS */
3188 /* ============ jobs.c */
3190 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3193 #define FORK_NOJOB 2
3195 /* mode flags for showjob(s) */
3196 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
3197 #define SHOW_PID 0x04 /* include process pid */
3198 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
3201 * A job structure contains information about a job. A job is either a
3202 * single process or a set of processes contained in a pipeline. In the
3203 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3208 pid_t pid; /* process id */
3209 int status; /* last process status from wait() */
3210 char *cmd; /* text of command being run */
3214 struct procstat ps0; /* status of process */
3215 struct procstat *ps; /* status or processes when more than one */
3217 int stopstatus; /* status of a stopped job */
3220 nprocs: 16, /* number of processes */
3222 #define JOBRUNNING 0 /* at least one proc running */
3223 #define JOBSTOPPED 1 /* all procs are stopped */
3224 #define JOBDONE 2 /* all procs are completed */
3226 sigint: 1, /* job was killed by SIGINT */
3227 jobctl: 1, /* job running under job control */
3229 waited: 1, /* true if this entry has been waited for */
3230 used: 1, /* true if this entry is in used */
3231 changed: 1; /* true if status has changed */
3232 struct job *prev_job; /* previous job */
3235 static pid_t backgndpid; /* pid of last background process */
3236 static smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
3238 static struct job *makejob(union node *, int);
3239 static int forkshell(struct job *, union node *, int);
3240 static int waitforjob(struct job *);
3243 enum { jobctl = 0 };
3244 #define setjobctl(on) do {} while (0)
3246 static smallint jobctl; /* true if doing job control */
3247 static void setjobctl(int);
3251 * Set the signal handler for the specified signal. The routine figures
3252 * out what it should be set to.
3255 setsignal(int signo)
3259 struct sigaction act;
3265 else if (*t != '\0')
3267 if (rootshell && action == S_DFL) {
3270 if (iflag || minusc || sflag == 0)
3293 t = &sigmode[signo - 1];
3297 * current setting unknown
3299 if (sigaction(signo, NULL, &act) == -1) {
3301 * Pretend it worked; maybe we should give a warning
3302 * here, but other shells don't. We don't alter
3303 * sigmode, so that we retry every time.
3307 tsig = S_RESET; /* force to be set */
3308 if (act.sa_handler == SIG_IGN) {
3311 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3313 tsig = S_IGN; /* don't hard ignore these */
3317 if (tsig == S_HARD_IGN || tsig == action)
3319 act.sa_handler = SIG_DFL;
3322 act.sa_handler = onsig;
3325 act.sa_handler = SIG_IGN;
3330 sigfillset(&act.sa_mask);
3331 sigaction(signo, &act, NULL);
3334 /* mode flags for set_curjob */
3335 #define CUR_DELETE 2
3336 #define CUR_RUNNING 1
3337 #define CUR_STOPPED 0
3339 /* mode flags for dowait */
3340 #define DOWAIT_NONBLOCK WNOHANG
3341 #define DOWAIT_BLOCK 0
3344 /* pgrp of shell on invocation */
3345 static int initialpgrp;
3346 static int ttyfd = -1;
3349 static struct job *jobtab;
3351 static unsigned njobs;
3353 static struct job *curjob;
3354 /* number of presumed living untracked jobs */
3358 set_curjob(struct job *jp, unsigned mode)
3361 struct job **jpp, **curp;
3363 /* first remove from list */
3364 jpp = curp = &curjob;
3369 jpp = &jp1->prev_job;
3371 *jpp = jp1->prev_job;
3373 /* Then re-insert in correct position */
3381 /* job being deleted */
3384 /* newly created job or backgrounded job,
3385 put after all stopped jobs. */
3389 if (!jp1 || jp1->state != JOBSTOPPED)
3392 jpp = &jp1->prev_job;
3398 /* newly stopped job - becomes curjob */
3399 jp->prev_job = *jpp;
3407 jobno(const struct job *jp)
3409 return jp - jobtab + 1;
3414 * Convert a job name to a job structure.
3417 getjob(const char *name, int getctl)
3421 const char *err_msg = "No such job: %s";
3425 char *(*match)(const char *, const char *);
3440 if (c == '+' || c == '%') {
3442 err_msg = "No current job";
3448 err_msg = "No previous job";
3459 jp = jobtab + num - 1;
3476 if (match(jp->ps[0].cmd, p)) {
3480 err_msg = "%s: ambiguous";
3487 err_msg = "job %s not created under job control";
3488 if (getctl && jp->jobctl == 0)
3493 ash_msg_and_raise_error(err_msg, name);
3497 * Mark a job structure as unused.
3500 freejob(struct job *jp)
3502 struct procstat *ps;
3506 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3507 if (ps->cmd != nullstr)
3510 if (jp->ps != &jp->ps0)
3513 set_curjob(jp, CUR_DELETE);
3519 xtcsetpgrp(int fd, pid_t pgrp)
3521 if (tcsetpgrp(fd, pgrp))
3522 ash_msg_and_raise_error("cannot set tty process group (%m)");
3526 * Turn job control on and off.
3528 * Note: This code assumes that the third arg to ioctl is a character
3529 * pointer, which is true on Berkeley systems but not System V. Since
3530 * System V doesn't have job control yet, this isn't a problem now.
3532 * Called with interrupts off.
3540 if (on == jobctl || rootshell == 0)
3544 ofd = fd = open(_PATH_TTY, O_RDWR);
3546 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3547 * That sometimes helps to acquire controlling tty.
3548 * Obviously, a workaround for bugs when someone
3549 * failed to provide a controlling tty to bash! :) */
3555 fd = fcntl(fd, F_DUPFD, 10);
3560 /* fd is a tty at this point */
3561 close_on_exec_on(fd);
3562 do { /* while we are in the background */
3563 pgrp = tcgetpgrp(fd);
3566 ash_msg("can't access tty; job control turned off");
3570 if (pgrp == getpgrp())
3581 xtcsetpgrp(fd, pgrp);
3583 /* turning job control off */
3586 /* was xtcsetpgrp, but this can make exiting ash
3587 * loop forever if pty is already deleted */
3588 tcsetpgrp(fd, pgrp);
3603 killcmd(int argc, char **argv)
3605 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3608 if (argv[i][0] == '%') {
3609 struct job *jp = getjob(argv[i], 0);
3610 unsigned pid = jp->ps[0].pid;
3611 /* Enough space for ' -NNN<nul>' */
3612 argv[i] = alloca(sizeof(int)*3 + 3);
3613 /* kill_main has matching code to expect
3614 * leading space. Needed to not confuse
3615 * negative pids with "kill -SIGNAL_NO" syntax */
3616 sprintf(argv[i], " -%u", pid);
3618 } while (argv[++i]);
3620 return kill_main(argc, argv);
3624 showpipe(struct job *jp, FILE *out)
3626 struct procstat *sp;
3627 struct procstat *spend;
3629 spend = jp->ps + jp->nprocs;
3630 for (sp = jp->ps + 1; sp < spend; sp++)
3631 fprintf(out, " | %s", sp->cmd);
3632 outcslow('\n', out);
3633 flush_stdout_stderr();
3638 restartjob(struct job *jp, int mode)
3640 struct procstat *ps;
3646 if (jp->state == JOBDONE)
3648 jp->state = JOBRUNNING;
3650 if (mode == FORK_FG)
3651 xtcsetpgrp(ttyfd, pgid);
3652 killpg(pgid, SIGCONT);
3656 if (WIFSTOPPED(ps->status)) {
3662 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3668 fg_bgcmd(int argc, char **argv)
3675 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3680 jp = getjob(*argv, 1);
3681 if (mode == FORK_BG) {
3682 set_curjob(jp, CUR_RUNNING);
3683 fprintf(out, "[%d] ", jobno(jp));
3685 outstr(jp->ps->cmd, out);
3687 retval = restartjob(jp, mode);
3688 } while (*argv && *++argv);
3694 sprint_status(char *s, int status, int sigonly)
3700 if (!WIFEXITED(status)) {
3702 if (WIFSTOPPED(status))
3703 st = WSTOPSIG(status);
3706 st = WTERMSIG(status);
3708 if (st == SIGINT || st == SIGPIPE)
3711 if (WIFSTOPPED(status))
3716 col = fmtstr(s, 32, strsignal(st));
3717 if (WCOREDUMP(status)) {
3718 col += fmtstr(s + col, 16, " (core dumped)");
3720 } else if (!sigonly) {
3721 st = WEXITSTATUS(status);
3723 col = fmtstr(s, 16, "Done(%d)", st);
3725 col = fmtstr(s, 16, "Done");
3732 * Do a wait system call. If job control is compiled in, we accept
3733 * stopped processes. If block is zero, we return a value of zero
3734 * rather than blocking.
3736 * System V doesn't have a non-blocking wait system call. It does
3737 * have a SIGCLD signal that is sent to a process when one of it's
3738 * children dies. The obvious way to use SIGCLD would be to install
3739 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
3740 * was received, and have waitproc bump another counter when it got
3741 * the status of a process. Waitproc would then know that a wait
3742 * system call would not block if the two counters were different.
3743 * This approach doesn't work because if a process has children that
3744 * have not been waited for, System V will send it a SIGCLD when it
3745 * installs a signal handler for SIGCLD. What this means is that when
3746 * a child exits, the shell will be sent SIGCLD signals continuously
3747 * until is runs out of stack space, unless it does a wait call before
3748 * restoring the signal handler. The code below takes advantage of
3749 * this (mis)feature by installing a signal handler for SIGCLD and
3750 * then checking to see whether it was called. If there are any
3751 * children to be waited for, it will be.
3753 * If neither SYSV nor BSD is defined, we don't implement nonblocking
3754 * waits at all. In this case, the user will not be informed when
3755 * a background process until the next time she runs a real program
3756 * (as opposed to running a builtin command or just typing return),
3757 * and the jobs command may give out of date information.
3760 waitproc(int wait_flags, int *status)
3764 wait_flags |= WUNTRACED;
3766 /* NB: _not_ safe_waitpid, we need to detect EINTR */
3767 return waitpid(-1, status, wait_flags);
3771 * Wait for a process to terminate.
3774 dowait(int wait_flags, struct job *job)
3779 struct job *thisjob;
3782 TRACE(("dowait(%d) called\n", wait_flags));
3783 pid = waitproc(wait_flags, &status);
3784 TRACE(("wait returns pid=%d, status=%d\n", pid, status));
3786 /* If we were doing blocking wait and (probably) got EINTR,
3787 * check for pending sigs received while waiting.
3788 * (NB: can be moved into callers if needed) */
3789 if (wait_flags == DOWAIT_BLOCK && pendingsig)
3790 raise_exception(EXSIG);
3795 for (jp = curjob; jp; jp = jp->prev_job) {
3796 struct procstat *sp;
3797 struct procstat *spend;
3798 if (jp->state == JOBDONE)
3801 spend = jp->ps + jp->nprocs;
3804 if (sp->pid == pid) {
3805 TRACE(("Job %d: changing status of proc %d "
3806 "from 0x%x to 0x%x\n",
3807 jobno(jp), pid, sp->status, status));
3808 sp->status = status;
3811 if (sp->status == -1)
3814 if (state == JOBRUNNING)
3816 if (WIFSTOPPED(sp->status)) {
3817 jp->stopstatus = sp->status;
3821 } while (++sp < spend);
3826 if (!WIFSTOPPED(status))
3832 if (state != JOBRUNNING) {
3833 thisjob->changed = 1;
3835 if (thisjob->state != state) {
3836 TRACE(("Job %d: changing state from %d to %d\n",
3837 jobno(thisjob), thisjob->state, state));
3838 thisjob->state = state;
3840 if (state == JOBSTOPPED) {
3841 set_curjob(thisjob, CUR_STOPPED);
3850 if (thisjob && thisjob == job) {
3854 len = sprint_status(s, status, 1);
3866 showjob(FILE *out, struct job *jp, int mode)
3868 struct procstat *ps;
3869 struct procstat *psend;
3876 if (mode & SHOW_PGID) {
3877 /* just output process (group) id of pipeline */
3878 fprintf(out, "%d\n", ps->pid);
3882 col = fmtstr(s, 16, "[%d] ", jobno(jp));
3887 else if (curjob && jp == curjob->prev_job)
3890 if (mode & SHOW_PID)
3891 col += fmtstr(s + col, 16, "%d ", ps->pid);
3893 psend = ps + jp->nprocs;
3895 if (jp->state == JOBRUNNING) {
3896 strcpy(s + col, "Running");
3897 col += sizeof("Running") - 1;
3899 int status = psend[-1].status;
3900 if (jp->state == JOBSTOPPED)
3901 status = jp->stopstatus;
3902 col += sprint_status(s + col, status, 0);
3908 /* for each process */
3909 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
3911 fprintf(out, "%s%*c%s",
3912 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
3914 if (!(mode & SHOW_PID)) {
3918 if (++ps == psend) {
3919 outcslow('\n', out);
3926 if (jp->state == JOBDONE) {
3927 TRACE(("showjob: freeing job %d\n", jobno(jp)));
3933 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3934 * statuses have changed since the last call to showjobs.
3937 showjobs(FILE *out, int mode)
3941 TRACE(("showjobs(%x) called\n", mode));
3943 /* If not even one job changed, there is nothing to do */
3944 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3947 for (jp = curjob; jp; jp = jp->prev_job) {
3948 if (!(mode & SHOW_CHANGED) || jp->changed) {
3949 showjob(out, jp, mode);
3955 jobscmd(int argc, char **argv)
3960 while ((m = nextopt("lp"))) {
3970 showjob(stdout, getjob(*argv,0), mode);
3973 showjobs(stdout, mode);
3980 getstatus(struct job *job)
3985 status = job->ps[job->nprocs - 1].status;
3986 retval = WEXITSTATUS(status);
3987 if (!WIFEXITED(status)) {
3989 retval = WSTOPSIG(status);
3990 if (!WIFSTOPPED(status))
3993 /* XXX: limits number of signals */
3994 retval = WTERMSIG(status);
3996 if (retval == SIGINT)
4002 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
4003 jobno(job), job->nprocs, status, retval));
4008 waitcmd(int argc, char **argv)
4017 raise_exception(EXSIG);
4024 /* wait for all jobs */
4028 if (!jp) /* no running procs */
4030 if (jp->state == JOBRUNNING)
4035 dowait(DOWAIT_BLOCK, NULL);
4041 if (**argv != '%') {
4042 pid_t pid = number(*argv);
4047 if (job->ps[job->nprocs - 1].pid == pid)
4049 job = job->prev_job;
4052 job = getjob(*argv, 0);
4053 /* loop until process terminated or stopped */
4054 while (job->state == JOBRUNNING)
4055 dowait(DOWAIT_BLOCK, NULL);
4057 retval = getstatus(job);
4071 struct job *jp, *jq;
4073 len = njobs * sizeof(*jp);
4075 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4077 offset = (char *)jp - (char *)jq;
4079 /* Relocate pointers */
4082 jq = (struct job *)((char *)jq + l);
4086 #define joff(p) ((struct job *)((char *)(p) + l))
4087 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4088 if (joff(jp)->ps == &jq->ps0)
4089 jmove(joff(jp)->ps);
4090 if (joff(jp)->prev_job)
4091 jmove(joff(jp)->prev_job);
4101 jp = (struct job *)((char *)jp + len);
4105 } while (--jq >= jp);
4110 * Return a new job structure.
4111 * Called with interrupts off.
4114 makejob(union node *node, int nprocs)
4119 for (i = njobs, jp = jobtab; ; jp++) {
4126 if (jp->state != JOBDONE || !jp->waited)
4135 memset(jp, 0, sizeof(*jp));
4137 /* jp->jobctl is a bitfield.
4138 * "jp->jobctl |= jobctl" likely to give awful code */
4142 jp->prev_job = curjob;
4147 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4149 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
4156 * Return a string identifying a command (to be printed by the
4159 static char *cmdnextc;
4162 cmdputs(const char *s)
4164 const char *p, *str;
4165 char c, cc[2] = " ";
4169 static const char vstype[VSTYPE + 1][4] = {
4170 "", "}", "-", "+", "?", "=",
4171 "%", "%%", "#", "##"
4174 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4176 while ((c = *p++) != 0) {
4184 if ((subtype & VSTYPE) == VSLENGTH)
4188 if (!(subtype & VSQUOTE) == !(quoted & 1))
4194 str = "\"}" + !(quoted & 1);
4201 case CTLBACKQ+CTLQUOTE:
4204 #if ENABLE_ASH_MATH_SUPPORT
4219 if ((subtype & VSTYPE) != VSNORMAL)
4221 str = vstype[subtype & VSTYPE];
4222 if (subtype & VSNUL)
4231 /* These can only happen inside quotes */
4244 while ((c = *str++)) {
4249 USTPUTC('"', nextc);
4255 /* cmdtxt() and cmdlist() call each other */
4256 static void cmdtxt(union node *n);
4259 cmdlist(union node *np, int sep)
4261 for (; np; np = np->narg.next) {
4265 if (sep && np->narg.next)
4271 cmdtxt(union node *n)
4274 struct nodelist *lp;
4286 lp = n->npipe.cmdlist;
4304 cmdtxt(n->nbinary.ch1);
4320 cmdtxt(n->nif.test);
4323 if (n->nif.elsepart) {
4326 n = n->nif.elsepart;
4342 cmdtxt(n->nbinary.ch1);
4352 cmdputs(n->nfor.var);
4354 cmdlist(n->nfor.args, 1);
4359 cmdputs(n->narg.text);
4363 cmdlist(n->ncmd.args, 1);
4364 cmdlist(n->ncmd.redirect, 0);
4377 cmdputs(n->ncase.expr->narg.text);
4379 for (np = n->ncase.cases; np; np = np->nclist.next) {
4380 cmdtxt(np->nclist.pattern);
4382 cmdtxt(np->nclist.body);
4408 s[0] = n->nfile.fd + '0';
4412 if (n->type == NTOFD || n->type == NFROMFD) {
4413 s[0] = n->ndup.dupfd + '0';
4423 commandtext(union node *n)
4427 STARTSTACKSTR(cmdnextc);
4429 name = stackblock();
4430 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4431 name, cmdnextc, cmdnextc));
4432 return ckstrdup(name);
4437 * Fork off a subshell. If we are doing job control, give the subshell its
4438 * own process group. Jp is a job structure that the job is to be added to.
4439 * N is the command that will be evaluated by the child. Both jp and n may
4440 * be NULL. The mode parameter can be one of the following:
4441 * FORK_FG - Fork off a foreground process.
4442 * FORK_BG - Fork off a background process.
4443 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4444 * process group even if job control is on.
4446 * When job control is turned off, background processes have their standard
4447 * input redirected to /dev/null (except for the second and later processes
4450 * Called with interrupts off.
4453 * Clear traps on a fork.
4460 for (tp = trap; tp < &trap[NSIG]; tp++) {
4461 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4466 setsignal(tp - trap);
4472 /* Lives far away from here, needed for forkchild */
4473 static void closescript(void);
4475 /* Called after fork(), in child */
4477 forkchild(struct job *jp, union node *n, int mode)
4481 TRACE(("Child shell %d\n", getpid()));
4488 /* do job control only in root shell */
4490 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4493 if (jp->nprocs == 0)
4496 pgrp = jp->ps[0].pid;
4497 /* This can fail because we are doing it in the parent also */
4498 (void)setpgid(0, pgrp);
4499 if (mode == FORK_FG)
4500 xtcsetpgrp(ttyfd, pgrp);
4505 if (mode == FORK_BG) {
4508 if (jp->nprocs == 0) {
4510 if (open(bb_dev_null, O_RDONLY) != 0)
4511 ash_msg_and_raise_error("can't open %s", bb_dev_null);
4514 if (!oldlvl && iflag) {
4519 for (jp = curjob; jp; jp = jp->prev_job)
4524 /* Called after fork(), in parent */
4526 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4528 TRACE(("In parent shell: child = %d\n", pid));
4530 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4536 if (mode != FORK_NOJOB && jp->jobctl) {
4539 if (jp->nprocs == 0)
4542 pgrp = jp->ps[0].pid;
4543 /* This can fail because we are doing it in the child also */
4547 if (mode == FORK_BG) {
4548 backgndpid = pid; /* set $! */
4549 set_curjob(jp, CUR_RUNNING);
4552 struct procstat *ps = &jp->ps[jp->nprocs++];
4558 ps->cmd = commandtext(n);
4564 forkshell(struct job *jp, union node *n, int mode)
4568 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4571 TRACE(("Fork failed, errno=%d", errno));
4574 ash_msg_and_raise_error("cannot fork");
4577 forkchild(jp, n, mode);
4579 forkparent(jp, n, mode, pid);
4584 * Wait for job to finish.
4586 * Under job control we have the problem that while a child process is
4587 * running interrupts generated by the user are sent to the child but not
4588 * to the shell. This means that an infinite loop started by an inter-
4589 * active user may be hard to kill. With job control turned off, an
4590 * interactive user may place an interactive program inside a loop. If
4591 * the interactive program catches interrupts, the user doesn't want
4592 * these interrupts to also abort the loop. The approach we take here
4593 * is to have the shell ignore interrupt signals while waiting for a
4594 * foreground process to terminate, and then send itself an interrupt
4595 * signal if the child process was terminated by an interrupt signal.
4596 * Unfortunately, some programs want to do a bit of cleanup and then
4597 * exit on interrupt; unless these processes terminate themselves by
4598 * sending a signal to themselves (instead of calling exit) they will
4599 * confuse this approach.
4601 * Called with interrupts off.
4604 waitforjob(struct job *jp)
4608 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4609 while (jp->state == JOBRUNNING) {
4610 dowait(DOWAIT_BLOCK, jp);
4615 xtcsetpgrp(ttyfd, rootpid);
4617 * This is truly gross.
4618 * If we're doing job control, then we did a TIOCSPGRP which
4619 * caused us (the shell) to no longer be in the controlling
4620 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4621 * intuit from the subprocess exit status whether a SIGINT
4622 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4624 if (jp->sigint) /* TODO: do the same with all signals */
4625 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4627 if (jp->state == JOBDONE)
4634 * return 1 if there are stopped jobs, otherwise 0
4646 if (jp && jp->state == JOBSTOPPED) {
4647 out2str("You have stopped jobs.\n");
4656 /* ============ redir.c
4658 * Code for dealing with input/output redirection.
4661 #define EMPTY -2 /* marks an unused slot in redirtab */
4662 #define CLOSED -3 /* marks a slot of previously-closed fd */
4664 # define PIPESIZE 4096 /* amount of buffering in a pipe */
4666 # define PIPESIZE PIPE_BUF
4670 * Open a file in noclobber mode.
4671 * The code was copied from bash.
4674 noclobberopen(const char *fname)
4677 struct stat finfo, finfo2;
4680 * If the file exists and is a regular file, return an error
4683 r = stat(fname, &finfo);
4684 if (r == 0 && S_ISREG(finfo.st_mode)) {
4690 * If the file was not present (r != 0), make sure we open it
4691 * exclusively so that if it is created before we open it, our open
4692 * will fail. Make sure that we do not truncate an existing file.
4693 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4694 * file was not a regular file, we leave O_EXCL off.
4697 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4698 fd = open(fname, O_WRONLY|O_CREAT, 0666);
4700 /* If the open failed, return the file descriptor right away. */
4705 * OK, the open succeeded, but the file may have been changed from a
4706 * non-regular file to a regular file between the stat and the open.
4707 * We are assuming that the O_EXCL open handles the case where FILENAME
4708 * did not exist and is symlinked to an existing file between the stat
4713 * If we can open it and fstat the file descriptor, and neither check
4714 * revealed that it was a regular file, and the file has not been
4715 * replaced, return the file descriptor.
4717 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4718 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4721 /* The file has been replaced. badness. */
4728 * Handle here documents. Normally we fork off a process to write the
4729 * data to a pipe. If the document is short, we can stuff the data in
4730 * the pipe without forking.
4732 /* openhere needs this forward reference */
4733 static void expandhere(union node *arg, int fd);
4735 openhere(union node *redir)
4741 ash_msg_and_raise_error("pipe call failed");
4742 if (redir->type == NHERE) {
4743 len = strlen(redir->nhere.doc->narg.text);
4744 if (len <= PIPESIZE) {
4745 full_write(pip[1], redir->nhere.doc->narg.text, len);
4749 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4751 signal(SIGINT, SIG_IGN);
4752 signal(SIGQUIT, SIG_IGN);
4753 signal(SIGHUP, SIG_IGN);
4755 signal(SIGTSTP, SIG_IGN);
4757 signal(SIGPIPE, SIG_DFL);
4758 if (redir->type == NHERE)
4759 full_write(pip[1], redir->nhere.doc->narg.text, len);
4761 expandhere(redir->nhere.doc, pip[1]);
4770 openredirect(union node *redir)
4775 switch (redir->nfile.type) {
4777 fname = redir->nfile.expfname;
4778 f = open(fname, O_RDONLY);
4783 fname = redir->nfile.expfname;
4784 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
4789 /* Take care of noclobber mode. */
4791 fname = redir->nfile.expfname;
4792 f = noclobberopen(fname);
4799 fname = redir->nfile.expfname;
4800 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4805 fname = redir->nfile.expfname;
4806 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4814 /* Fall through to eliminate warning. */
4821 f = openhere(redir);
4827 ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4829 ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "no such file"));
4833 * Copy a file descriptor to be >= to. Returns -1
4834 * if the source file descriptor is closed, EMPTY if there are no unused
4835 * file descriptors left.
4838 copyfd(int from, int to)
4842 newfd = fcntl(from, F_DUPFD, to);
4844 if (errno == EMFILE)
4846 ash_msg_and_raise_error("%d: %m", from);
4852 dupredirect(union node *redir, int f)
4854 int fd = redir->nfile.fd;
4856 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
4857 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
4858 copyfd(redir->ndup.dupfd, fd);
4870 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
4871 * old file descriptors are stashed away so that the redirection can be
4872 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
4873 * standard output, and the standard error if it becomes a duplicate of
4874 * stdout, is saved in memory.
4876 /* flags passed to redirect */
4877 #define REDIR_PUSH 01 /* save previous values of file descriptors */
4878 #define REDIR_SAVEFD2 03 /* set preverrout */
4880 redirect(union node *redir, int flags)
4883 struct redirtab *sv;
4894 if (flags & REDIR_PUSH) {
4895 sv = ckmalloc(sizeof(*sv));
4896 sv->next = redirlist;
4898 sv->nullredirs = g_nullredirs - 1;
4899 for (i = 0; i < 10; i++)
4900 sv->renamed[i] = EMPTY;
4906 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD)
4907 && n->ndup.dupfd == fd)
4908 continue; /* redirect from/to same file descriptor */
4910 newfd = openredirect(n);
4912 /* Descriptor wasn't open before redirect.
4913 * Mark it for close in the future */
4914 if (sv && sv->renamed[fd] == EMPTY)
4915 sv->renamed[fd] = CLOSED;
4918 if (sv && sv->renamed[fd] == EMPTY) {
4919 i = fcntl(fd, F_DUPFD, 10);
4926 ash_msg_and_raise_error("%d: %m", fd);
4930 sv->renamed[fd] = i;
4936 dupredirect(n, newfd);
4937 } while ((n = n->nfile.next));
4939 if ((flags & REDIR_SAVEFD2) && sv && sv->renamed[2] >= 0)
4940 preverrout_fd = sv->renamed[2];
4944 * Undo the effects of the last redirection.
4949 struct redirtab *rp;
4952 if (--g_nullredirs >= 0)
4956 for (i = 0; i < 10; i++) {
4957 if (rp->renamed[i] == CLOSED) {
4962 if (rp->renamed[i] != EMPTY) {
4965 copyfd(rp->renamed[i], i);
4967 close(rp->renamed[i]);
4970 redirlist = rp->next;
4971 g_nullredirs = rp->nullredirs;
4977 * Undo all redirections. Called on error or interrupt.
4981 * Discard all saved file descriptors.
4984 clearredir(int drop)
4995 redirectsafe(union node *redir, int flags)
4998 volatile int saveint;
4999 struct jmploc *volatile savehandler = exception_handler;
5000 struct jmploc jmploc;
5003 err = setjmp(jmploc.loc) * 2;
5005 exception_handler = &jmploc;
5006 redirect(redir, flags);
5008 exception_handler = savehandler;
5009 if (err && exception != EXERROR)
5010 longjmp(exception_handler->loc, 1);
5011 RESTORE_INT(saveint);
5016 /* ============ Routines to expand arguments to commands
5018 * We have to deal with backquotes, shell variables, and file metacharacters.
5024 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5025 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5026 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5027 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5028 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5029 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5030 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5031 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5032 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5036 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5037 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5038 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5039 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5040 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5043 * Structure specifying which parts of the string should be searched
5044 * for IFS characters.
5047 struct ifsregion *next; /* next region in list */
5048 int begoff; /* offset of start of region */
5049 int endoff; /* offset of end of region */
5050 int nulonly; /* search for nul bytes only */
5054 struct strlist *list;
5055 struct strlist **lastp;
5058 /* output of current string */
5059 static char *expdest;
5060 /* list of back quote expressions */
5061 static struct nodelist *argbackq;
5062 /* first struct in list of ifs regions */
5063 static struct ifsregion ifsfirst;
5064 /* last struct in list */
5065 static struct ifsregion *ifslastp;
5066 /* holds expanded arg list */
5067 static struct arglist exparg;
5077 expdest = makestrspace(32, expdest);
5078 #if ENABLE_ASH_MATH_SUPPORT_64
5079 len = fmtstr(expdest, 32, "%lld", (long long) num);
5081 len = fmtstr(expdest, 32, "%ld", num);
5083 STADJUST(len, expdest);
5088 esclen(const char *start, const char *p)
5092 while (p > start && *--p == CTLESC) {
5099 * Remove any CTLESC characters from a string.
5102 _rmescapes(char *str, int flag)
5104 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5111 p = strpbrk(str, qchars);
5117 if (flag & RMESCAPE_ALLOC) {
5118 size_t len = p - str;
5119 size_t fulllen = len + strlen(p) + 1;
5121 if (flag & RMESCAPE_GROW) {
5122 r = makestrspace(fulllen, expdest);
5123 } else if (flag & RMESCAPE_HEAP) {
5124 r = ckmalloc(fulllen);
5126 r = stalloc(fulllen);
5130 q = memcpy(q, str, len) + len;
5133 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5134 globbing = flag & RMESCAPE_GLOB;
5135 notescaped = globbing;
5137 if (*p == CTLQUOTEMARK) {
5138 inquotes = ~inquotes;
5140 notescaped = globbing;
5144 /* naked back slash */
5150 if (notescaped && inquotes && *p != '/') {
5154 notescaped = globbing;
5159 if (flag & RMESCAPE_GROW) {
5161 STADJUST(q - r + 1, expdest);
5165 #define rmescapes(p) _rmescapes((p), 0)
5167 #define pmatch(a, b) !fnmatch((a), (b), 0)
5170 * Prepare a pattern for a expmeta (internal glob(3)) call.
5172 * Returns an stalloced string.
5175 preglob(const char *pattern, int quoted, int flag)
5177 flag |= RMESCAPE_GLOB;
5179 flag |= RMESCAPE_QUOTED;
5181 return _rmescapes((char *)pattern, flag);
5185 * Put a string on the stack.
5188 memtodest(const char *p, size_t len, int syntax, int quotes)
5192 q = makestrspace(len * 2, q);
5195 int c = signed_char2int(*p++);
5198 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5207 strtodest(const char *p, int syntax, int quotes)
5209 memtodest(p, strlen(p), syntax, quotes);
5213 * Record the fact that we have to scan this region of the
5214 * string for IFS characters.
5217 recordregion(int start, int end, int nulonly)
5219 struct ifsregion *ifsp;
5221 if (ifslastp == NULL) {
5225 ifsp = ckmalloc(sizeof(*ifsp));
5227 ifslastp->next = ifsp;
5231 ifslastp->begoff = start;
5232 ifslastp->endoff = end;
5233 ifslastp->nulonly = nulonly;
5237 removerecordregions(int endoff)
5239 if (ifslastp == NULL)
5242 if (ifsfirst.endoff > endoff) {
5243 while (ifsfirst.next != NULL) {
5244 struct ifsregion *ifsp;
5246 ifsp = ifsfirst.next->next;
5247 free(ifsfirst.next);
5248 ifsfirst.next = ifsp;
5251 if (ifsfirst.begoff > endoff)
5254 ifslastp = &ifsfirst;
5255 ifsfirst.endoff = endoff;
5260 ifslastp = &ifsfirst;
5261 while (ifslastp->next && ifslastp->next->begoff < endoff)
5262 ifslastp=ifslastp->next;
5263 while (ifslastp->next != NULL) {
5264 struct ifsregion *ifsp;
5266 ifsp = ifslastp->next->next;
5267 free(ifslastp->next);
5268 ifslastp->next = ifsp;
5271 if (ifslastp->endoff > endoff)
5272 ifslastp->endoff = endoff;
5276 exptilde(char *startp, char *p, int flag)
5282 int quotes = flag & (EXP_FULL | EXP_CASE);
5287 while ((c = *++p) != '\0') {
5294 if (flag & EXP_VARTILDE)
5304 if (*name == '\0') {
5305 home = lookupvar(homestr);
5307 pw = getpwnam(name);
5312 if (!home || !*home)
5315 startloc = expdest - (char *)stackblock();
5316 strtodest(home, SQSYNTAX, quotes);
5317 recordregion(startloc, expdest - (char *)stackblock(), 0);
5325 * Execute a command inside back quotes. If it's a builtin command, we
5326 * want to save its output in a block obtained from malloc. Otherwise
5327 * we fork off a subprocess and get the output of the command via a pipe.
5328 * Should be called with interrupts off.
5330 struct backcmd { /* result of evalbackcmd */
5331 int fd; /* file descriptor to read from */
5332 char *buf; /* buffer */
5333 int nleft; /* number of chars in buffer */
5334 struct job *jp; /* job structure for command */
5337 /* These forward decls are needed to use "eval" code for backticks handling: */
5338 static int back_exitstatus; /* exit status of backquoted command */
5339 #define EV_EXIT 01 /* exit after evaluating tree */
5340 static void evaltree(union node *, int);
5343 evalbackcmd(union node *n, struct backcmd *result)
5355 saveherefd = herefd;
5363 ash_msg_and_raise_error("pipe call failed");
5365 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5374 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5378 result->fd = pip[0];
5381 herefd = saveherefd;
5383 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5384 result->fd, result->buf, result->nleft, result->jp));
5388 * Expand stuff in backwards quotes.
5391 expbackq(union node *cmd, int quoted, int quotes)
5399 int syntax = quoted? DQSYNTAX : BASESYNTAX;
5400 struct stackmark smark;
5403 setstackmark(&smark);
5405 startloc = dest - (char *)stackblock();
5407 evalbackcmd(cmd, &in);
5408 popstackmark(&smark);
5415 memtodest(p, i, syntax, quotes);
5419 i = safe_read(in.fd, buf, sizeof(buf));
5420 TRACE(("expbackq: read returns %d\n", i));
5429 back_exitstatus = waitforjob(in.jp);
5433 /* Eat all trailing newlines */
5435 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5440 recordregion(startloc, dest - (char *)stackblock(), 0);
5441 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5442 (dest - (char *)stackblock()) - startloc,
5443 (dest - (char *)stackblock()) - startloc,
5444 stackblock() + startloc));
5447 #if ENABLE_ASH_MATH_SUPPORT
5449 * Expand arithmetic expression. Backup to start of expression,
5450 * evaluate, place result in (backed up) result, adjust string position.
5463 * This routine is slightly over-complicated for
5464 * efficiency. Next we scan backwards looking for the
5465 * start of arithmetic.
5467 start = stackblock();
5474 while (*p != CTLARI) {
5478 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5483 esc = esclen(start, p);
5493 removerecordregions(begoff);
5502 len = cvtnum(dash_arith(p + 2));
5505 recordregion(begoff, begoff + len, 0);
5509 /* argstr needs it */
5510 static char *evalvar(char *p, int flag, struct strlist *var_str_list);
5513 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5514 * characters to allow for further processing. Otherwise treat
5515 * $@ like $* since no splitting will be performed.
5517 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5518 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5519 * for correct expansion of "B=$A" word.
5522 argstr(char *p, int flag, struct strlist *var_str_list)
5524 static const char spclchars[] ALIGN1 = {
5532 CTLBACKQ | CTLQUOTE,
5533 #if ENABLE_ASH_MATH_SUPPORT
5538 const char *reject = spclchars;
5540 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
5541 int breakall = flag & EXP_WORD;
5546 if (!(flag & EXP_VARTILDE)) {
5548 } else if (flag & EXP_VARTILDE2) {
5553 if (flag & EXP_TILDE) {
5559 if (*q == CTLESC && (flag & EXP_QWORD))
5562 p = exptilde(p, q, flag);
5565 startloc = expdest - (char *)stackblock();
5567 length += strcspn(p + length, reject);
5569 if (c && (!(c & 0x80)
5570 #if ENABLE_ASH_MATH_SUPPORT
5574 /* c == '=' || c == ':' || c == CTLENDARI */
5579 expdest = stack_nputstr(p, length, expdest);
5580 newloc = expdest - (char *)stackblock();
5581 if (breakall && !inquotes && newloc > startloc) {
5582 recordregion(startloc, newloc, 0);
5593 if (flag & EXP_VARTILDE2) {
5597 flag |= EXP_VARTILDE2;
5602 * sort of a hack - expand tildes in variable
5603 * assignments (after the first '=' and after ':'s).
5612 case CTLENDVAR: /* ??? */
5615 /* "$@" syntax adherence hack */
5618 !memcmp(p, dolatstr, 4) &&
5619 (p[4] == CTLQUOTEMARK || (
5620 p[4] == CTLENDVAR &&
5621 p[5] == CTLQUOTEMARK
5624 p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;
5627 inquotes = !inquotes;
5640 p = evalvar(p, flag, var_str_list);
5644 case CTLBACKQ|CTLQUOTE:
5645 expbackq(argbackq->n, c, quotes);
5646 argbackq = argbackq->next;
5648 #if ENABLE_ASH_MATH_SUPPORT
5661 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5672 const char *s = loc2;
5678 match = pmatch(str, s);
5682 if (quotes && *loc == CTLESC)
5691 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5698 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5701 const char *s = loc2;
5706 match = pmatch(str, s);
5713 esc = esclen(startp, loc);
5724 static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN;
5726 varunset(const char *end, const char *var, const char *umsg, int varflags)
5732 msg = "parameter not set";
5734 if (*end == CTLENDVAR) {
5735 if (varflags & VSNUL)
5740 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5744 subevalvar(char *p, char *str, int strloc, int subtype,
5745 int startloc, int varflags, int quotes, struct strlist *var_str_list)
5749 int saveherefd = herefd;
5750 struct nodelist *saveargbackq = argbackq;
5752 char *rmesc, *rmescend;
5754 char *(*scan)(char *, char *, char *, char *, int , int);
5757 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
5759 STPUTC('\0', expdest);
5760 herefd = saveherefd;
5761 argbackq = saveargbackq;
5762 startp = stackblock() + startloc;
5766 setvar(str, startp, 0);
5767 amount = startp - expdest;
5768 STADJUST(amount, expdest);
5772 varunset(p, str, startp, varflags);
5776 subtype -= VSTRIMRIGHT;
5778 if (subtype < 0 || subtype > 3)
5783 rmescend = stackblock() + strloc;
5785 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5786 if (rmesc != startp) {
5788 startp = stackblock() + startloc;
5792 str = stackblock() + strloc;
5793 preglob(str, varflags & VSQUOTE, 0);
5795 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5796 zero = subtype >> 1;
5797 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5798 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5800 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5803 memmove(startp, loc, str - loc);
5804 loc = startp + (str - loc) - 1;
5807 amount = loc - expdest;
5808 STADJUST(amount, expdest);
5814 * Add the value of a specialized variable to the stack string.
5817 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
5827 int quoted = varflags & VSQUOTE;
5828 int subtype = varflags & VSTYPE;
5829 int quotes = flags & (EXP_FULL | EXP_CASE);
5831 if (quoted && (flags & EXP_FULL))
5832 sep = 1 << CHAR_BIT;
5834 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5843 num = shellparam.nparam;
5853 p = makestrspace(NOPTS, expdest);
5854 for (i = NOPTS - 1; i >= 0; i--) {
5856 USTPUTC(optletters(i), p);
5867 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
5868 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5874 while ((p = *ap++)) {
5877 partlen = strlen(p);
5880 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5881 memtodest(p, partlen, syntax, quotes);
5887 if (subtype == VSPLUS || subtype == VSLENGTH) {
5909 if (num < 0 || num > shellparam.nparam)
5911 p = num ? shellparam.p[num - 1] : arg0;
5914 /* NB: name has form "VAR=..." */
5916 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
5917 * which should be considered before we check variables. */
5919 unsigned name_len = (strchrnul(name, '=') - name) + 1;
5923 str = var_str_list->text;
5924 eq = strchr(str, '=');
5925 if (!eq) /* stop at first non-assignment */
5928 if (name_len == (eq - str)
5929 && strncmp(str, name, name_len) == 0) {
5931 /* goto value; - WRONG! */
5932 /* think "A=1 A=2 B=$A" */
5934 var_str_list = var_str_list->next;
5935 } while (var_str_list);
5939 p = lookupvar(name);
5945 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5946 memtodest(p, len, syntax, quotes);
5950 if (subtype == VSPLUS || subtype == VSLENGTH)
5951 STADJUST(-len, expdest);
5956 * Expand a variable, and return a pointer to the next character in the
5960 evalvar(char *p, int flag, struct strlist *var_str_list)
5972 subtype = varflags & VSTYPE;
5973 quoted = varflags & VSQUOTE;
5975 easy = (!quoted || (*var == '@' && shellparam.nparam));
5976 startloc = expdest - (char *)stackblock();
5977 p = strchr(p, '=') + 1;
5980 varlen = varvalue(var, varflags, flag, var_str_list);
5981 if (varflags & VSNUL)
5984 if (subtype == VSPLUS) {
5985 varlen = -1 - varlen;
5989 if (subtype == VSMINUS) {
5993 p, flag | EXP_TILDE |
5994 (quoted ? EXP_QWORD : EXP_WORD),
6004 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6006 if (subevalvar(p, var, /* strloc: */ 0,
6007 subtype, startloc, varflags,
6013 * Remove any recorded regions beyond
6016 removerecordregions(startloc);
6026 if (varlen < 0 && uflag)
6027 varunset(p, var, 0, 0);
6029 if (subtype == VSLENGTH) {
6030 cvtnum(varlen > 0 ? varlen : 0);
6034 if (subtype == VSNORMAL) {
6045 case VSTRIMRIGHTMAX:
6054 * Terminate the string and start recording the pattern
6057 STPUTC('\0', expdest);
6058 patloc = expdest - (char *)stackblock();
6059 if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6061 /* quotes: */ flag & (EXP_FULL | EXP_CASE),
6064 int amount = expdest - (
6065 (char *)stackblock() + patloc - 1
6067 STADJUST(-amount, expdest);
6069 /* Remove any recorded regions beyond start of variable */
6070 removerecordregions(startloc);
6072 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6076 if (subtype != VSNORMAL) { /* skip to end of alternative */
6082 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6084 argbackq = argbackq->next;
6085 } else if (c == CTLVAR) {
6086 if ((*p++ & VSTYPE) != VSNORMAL)
6088 } else if (c == CTLENDVAR) {
6098 * Break the argument string into pieces based upon IFS and add the
6099 * strings to the argument list. The regions of the string to be
6100 * searched for IFS characters have been stored by recordregion.
6103 ifsbreakup(char *string, struct arglist *arglist)
6105 struct ifsregion *ifsp;
6110 const char *ifs, *realifs;
6115 if (ifslastp != NULL) {
6118 realifs = ifsset() ? ifsval() : defifs;
6121 p = string + ifsp->begoff;
6122 nulonly = ifsp->nulonly;
6123 ifs = nulonly ? nullstr : realifs;
6125 while (p < string + ifsp->endoff) {
6129 if (!strchr(ifs, *p)) {
6134 ifsspc = (strchr(defifs, *p) != NULL);
6135 /* Ignore IFS whitespace at start */
6136 if (q == start && ifsspc) {
6142 sp = stalloc(sizeof(*sp));
6144 *arglist->lastp = sp;
6145 arglist->lastp = &sp->next;
6149 if (p >= string + ifsp->endoff) {
6155 if (strchr(ifs, *p) == NULL ) {
6158 } else if (strchr(defifs, *p) == NULL) {
6173 } while (ifsp != NULL);
6182 sp = stalloc(sizeof(*sp));
6184 *arglist->lastp = sp;
6185 arglist->lastp = &sp->next;
6191 struct ifsregion *p;
6196 struct ifsregion *ifsp;
6202 ifsfirst.next = NULL;
6207 * Add a file name to the list.
6210 addfname(const char *name)
6214 sp = stalloc(sizeof(*sp));
6215 sp->text = ststrdup(name);
6217 exparg.lastp = &sp->next;
6220 static char *expdir;
6223 * Do metacharacter (i.e. *, ?, [...]) expansion.
6226 expmeta(char *enddir, char *name)
6241 for (p = name; *p; p++) {
6242 if (*p == '*' || *p == '?')
6244 else if (*p == '[') {
6251 if (*q == '/' || *q == '\0')
6258 } else if (*p == '\\')
6260 else if (*p == '/') {
6267 if (metaflag == 0) { /* we've reached the end of the file name */
6268 if (enddir != expdir)
6276 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6287 } while (p < start);
6289 if (enddir == expdir) {
6291 } else if (enddir == expdir + 1 && *expdir == '/') {
6300 if (enddir != expdir)
6302 if (*endname == 0) {
6314 while (!intpending && (dp = readdir(dirp)) != NULL) {
6315 if (dp->d_name[0] == '.' && ! matchdot)
6317 if (pmatch(start, dp->d_name)) {
6319 strcpy(enddir, dp->d_name);
6322 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6325 expmeta(p, endname);
6334 static struct strlist *
6335 msort(struct strlist *list, int len)
6337 struct strlist *p, *q = NULL;
6338 struct strlist **lpp;
6346 for (n = half; --n >= 0; ) {
6350 q->next = NULL; /* terminate first half of list */
6351 q = msort(list, half); /* sort first half of list */
6352 p = msort(p, len - half); /* sort second half */
6355 #if ENABLE_LOCALE_SUPPORT
6356 if (strcoll(p->text, q->text) < 0)
6358 if (strcmp(p->text, q->text) < 0)
6382 * Sort the results of file name expansion. It calculates the number of
6383 * strings to sort and then calls msort (short for merge sort) to do the
6386 static struct strlist *
6387 expsort(struct strlist *str)
6393 for (sp = str; sp; sp = sp->next)
6395 return msort(str, len);
6399 expandmeta(struct strlist *str, int flag)
6401 static const char metachars[] ALIGN1 = {
6404 /* TODO - EXP_REDIR */
6407 struct strlist **savelastp;
6413 if (!strpbrk(str->text, metachars))
6415 savelastp = exparg.lastp;
6418 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
6420 int i = strlen(str->text);
6421 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
6429 if (exparg.lastp == savelastp) {
6434 *exparg.lastp = str;
6435 rmescapes(str->text);
6436 exparg.lastp = &str->next;
6438 *exparg.lastp = NULL;
6439 *savelastp = sp = expsort(*savelastp);
6440 while (sp->next != NULL)
6442 exparg.lastp = &sp->next;
6449 * Perform variable substitution and command substitution on an argument,
6450 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6451 * perform splitting and file name expansion. When arglist is NULL, perform
6452 * here document expansion.
6455 expandarg(union node *arg, struct arglist *arglist, int flag)
6460 argbackq = arg->narg.backquote;
6461 STARTSTACKSTR(expdest);
6462 ifsfirst.next = NULL;
6464 argstr(arg->narg.text, flag,
6465 /* var_str_list: */ arglist ? arglist->list : NULL);
6466 p = _STPUTC('\0', expdest);
6468 if (arglist == NULL) {
6469 return; /* here document expanded */
6471 p = grabstackstr(p);
6472 exparg.lastp = &exparg.list;
6476 if (flag & EXP_FULL) {
6477 ifsbreakup(p, &exparg);
6478 *exparg.lastp = NULL;
6479 exparg.lastp = &exparg.list;
6480 expandmeta(exparg.list, flag);
6482 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
6484 sp = stalloc(sizeof(*sp));
6487 exparg.lastp = &sp->next;
6491 *exparg.lastp = NULL;
6493 *arglist->lastp = exparg.list;
6494 arglist->lastp = exparg.lastp;
6499 * Expand shell variables and backquotes inside a here document.
6502 expandhere(union node *arg, int fd)
6505 expandarg(arg, (struct arglist *)NULL, 0);
6506 full_write(fd, stackblock(), expdest - (char *)stackblock());
6510 * Returns true if the pattern matches the string.
6513 patmatch(char *pattern, const char *string)
6515 return pmatch(preglob(pattern, 0, 0), string);
6519 * See if a pattern matches in a case statement.
6522 casematch(union node *pattern, char *val)
6524 struct stackmark smark;
6527 setstackmark(&smark);
6528 argbackq = pattern->narg.backquote;
6529 STARTSTACKSTR(expdest);
6531 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
6532 /* var_str_list: */ NULL);
6533 STACKSTRNUL(expdest);
6534 result = patmatch(stackblock(), val);
6535 popstackmark(&smark);
6540 /* ============ find_command */
6544 int (*builtin)(int, char **);
6545 /* unsigned flags; */
6547 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
6548 /* "regular" builtins always take precedence over commands,
6549 * regardless of PATH=....%builtin... position */
6550 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
6551 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
6557 const struct builtincmd *cmd;
6558 struct funcnode *func;
6561 /* values of cmdtype */
6562 #define CMDUNKNOWN -1 /* no entry in table for command */
6563 #define CMDNORMAL 0 /* command is an executable program */
6564 #define CMDFUNCTION 1 /* command is a shell function */
6565 #define CMDBUILTIN 2 /* command is a shell builtin */
6567 /* action to find_command() */
6568 #define DO_ERR 0x01 /* prints errors */
6569 #define DO_ABS 0x02 /* checks absolute paths */
6570 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
6571 #define DO_ALTPATH 0x08 /* using alternate path */
6572 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
6574 static void find_command(char *, struct cmdentry *, int, const char *);
6577 /* ============ Hashing commands */
6580 * When commands are first encountered, they are entered in a hash table.
6581 * This ensures that a full path search will not have to be done for them
6582 * on each invocation.
6584 * We should investigate converting to a linear search, even though that
6585 * would make the command name "hash" a misnomer.
6588 #define ARB 1 /* actual size determined at run time */
6591 struct tblentry *next; /* next entry in hash chain */
6592 union param param; /* definition of builtin function */
6593 short cmdtype; /* index identifying command */
6594 char rehash; /* if set, cd done since entry created */
6595 char cmdname[ARB]; /* name of command */
6598 static struct tblentry **cmdtable;
6599 #define INIT_G_cmdtable() do { \
6600 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
6603 static int builtinloc = -1; /* index in path of %builtin, or -1 */
6607 tryexec(char *cmd, char **argv, char **envp)
6611 #if ENABLE_FEATURE_SH_STANDALONE
6612 if (strchr(cmd, '/') == NULL) {
6613 int a = find_applet_by_name(cmd);
6615 if (APPLET_IS_NOEXEC(a))
6616 run_applet_no_and_exit(a, argv);
6617 /* re-exec ourselves with the new arguments */
6618 execve(bb_busybox_exec_path, argv, envp);
6619 /* If they called chroot or otherwise made the binary no longer
6620 * executable, fall through */
6628 execve(cmd, argv, envp);
6629 } while (errno == EINTR);
6631 execve(cmd, argv, envp);
6635 } else if (errno == ENOEXEC) {
6639 for (ap = argv; *ap; ap++)
6641 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
6643 ap[0] = cmd = (char *)DEFAULT_SHELL;
6646 while ((*ap++ = *argv++))
6654 * Exec a program. Never returns. If you change this routine, you may
6655 * have to change the find_command routine as well.
6657 #define environment() listvars(VEXPORT, VUNSET, 0)
6658 static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
6660 shellexec(char **argv, const char *path, int idx)
6668 envp = environment();
6669 if (strchr(argv[0], '/')
6670 #if ENABLE_FEATURE_SH_STANDALONE
6671 || find_applet_by_name(argv[0]) >= 0
6674 tryexec(argv[0], argv, envp);
6678 while ((cmdname = padvance(&path, argv[0])) != NULL) {
6679 if (--idx < 0 && pathopt == NULL) {
6680 tryexec(cmdname, argv, envp);
6681 if (errno != ENOENT && errno != ENOTDIR)
6688 /* Map to POSIX errors */
6700 exitstatus = exerrno;
6701 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
6702 argv[0], e, suppressint ));
6703 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
6708 printentry(struct tblentry *cmdp)
6714 idx = cmdp->param.index;
6717 name = padvance(&path, cmdp->cmdname);
6719 } while (--idx >= 0);
6720 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
6724 * Clear out command entries. The argument specifies the first entry in
6725 * PATH which has changed.
6728 clearcmdentry(int firstchange)
6730 struct tblentry **tblp;
6731 struct tblentry **pp;
6732 struct tblentry *cmdp;
6735 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
6737 while ((cmdp = *pp) != NULL) {
6738 if ((cmdp->cmdtype == CMDNORMAL &&
6739 cmdp->param.index >= firstchange)
6740 || (cmdp->cmdtype == CMDBUILTIN &&
6741 builtinloc >= firstchange)
6754 * Locate a command in the command hash table. If "add" is nonzero,
6755 * add the command to the table if it is not already present. The
6756 * variable "lastcmdentry" is set to point to the address of the link
6757 * pointing to the entry, so that delete_cmd_entry can delete the
6760 * Interrupts must be off if called with add != 0.
6762 static struct tblentry **lastcmdentry;
6764 static struct tblentry *
6765 cmdlookup(const char *name, int add)
6767 unsigned int hashval;
6769 struct tblentry *cmdp;
6770 struct tblentry **pp;
6773 hashval = (unsigned char)*p << 4;
6775 hashval += (unsigned char)*p++;
6777 pp = &cmdtable[hashval % CMDTABLESIZE];
6778 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6779 if (strcmp(cmdp->cmdname, name) == 0)
6783 if (add && cmdp == NULL) {
6784 cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB
6785 + strlen(name) + 1);
6787 cmdp->cmdtype = CMDUNKNOWN;
6788 strcpy(cmdp->cmdname, name);
6795 * Delete the command entry returned on the last lookup.
6798 delete_cmd_entry(void)
6800 struct tblentry *cmdp;
6803 cmdp = *lastcmdentry;
6804 *lastcmdentry = cmdp->next;
6805 if (cmdp->cmdtype == CMDFUNCTION)
6806 freefunc(cmdp->param.func);
6812 * Add a new command entry, replacing any existing command entry for
6813 * the same name - except special builtins.
6816 addcmdentry(char *name, struct cmdentry *entry)
6818 struct tblentry *cmdp;
6820 cmdp = cmdlookup(name, 1);
6821 if (cmdp->cmdtype == CMDFUNCTION) {
6822 freefunc(cmdp->param.func);
6824 cmdp->cmdtype = entry->cmdtype;
6825 cmdp->param = entry->u;
6830 hashcmd(int argc, char **argv)
6832 struct tblentry **pp;
6833 struct tblentry *cmdp;
6835 struct cmdentry entry;
6838 if (nextopt("r") != '\0') {
6843 if (*argptr == NULL) {
6844 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
6845 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6846 if (cmdp->cmdtype == CMDNORMAL)
6854 while ((name = *argptr) != NULL) {
6855 cmdp = cmdlookup(name, 0);
6857 && (cmdp->cmdtype == CMDNORMAL
6858 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
6862 find_command(name, &entry, DO_ERR, pathval());
6863 if (entry.cmdtype == CMDUNKNOWN)
6871 * Called when a cd is done. Marks all commands so the next time they
6872 * are executed they will be rehashed.
6877 struct tblentry **pp;
6878 struct tblentry *cmdp;
6880 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
6881 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
6882 if (cmdp->cmdtype == CMDNORMAL
6883 || (cmdp->cmdtype == CMDBUILTIN
6884 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
6894 * Fix command hash table when PATH changed.
6895 * Called before PATH is changed. The argument is the new value of PATH;
6896 * pathval() still returns the old value at this point.
6897 * Called with interrupts off.
6900 changepath(const char *new)
6908 firstchange = 9999; /* assume no change */
6914 if ((*old == '\0' && *new == ':')
6915 || (*old == ':' && *new == '\0'))
6917 old = new; /* ignore subsequent differences */
6921 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
6927 if (builtinloc < 0 && idx_bltin >= 0)
6928 builtinloc = idx_bltin; /* zap builtins */
6929 if (builtinloc >= 0 && idx_bltin < 0)
6931 clearcmdentry(firstchange);
6932 builtinloc = idx_bltin;
6947 #define TENDBQUOTE 12
6965 /* first char is indicating which tokens mark the end of a list */
6966 static const char *const tokname_array[] = {
6980 #define KWDOFFSET 13
6981 /* the following are keywords */
7003 static char buf[16];
7006 //if (tok < TSEMI) return tokname_array[tok] + 1;
7007 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
7012 sprintf(buf + (tok >= TSEMI), "%s%c",
7013 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
7017 /* Wrapper around strcmp for qsort/bsearch/... */
7019 pstrcmp(const void *a, const void *b)
7021 return strcmp((char*) a, (*(char**) b) + 1);
7024 static const char *const *
7025 findkwd(const char *s)
7027 return bsearch(s, tokname_array + KWDOFFSET,
7028 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7029 sizeof(tokname_array[0]), pstrcmp);
7033 * Locate and print what a word is...
7036 describe_command(char *command, int describe_command_verbose)
7038 struct cmdentry entry;
7039 struct tblentry *cmdp;
7040 #if ENABLE_ASH_ALIAS
7041 const struct alias *ap;
7043 const char *path = pathval();
7045 if (describe_command_verbose) {
7049 /* First look at the keywords */
7050 if (findkwd(command)) {
7051 out1str(describe_command_verbose ? " is a shell keyword" : command);
7055 #if ENABLE_ASH_ALIAS
7056 /* Then look at the aliases */
7057 ap = lookupalias(command, 0);
7059 if (!describe_command_verbose) {
7064 out1fmt(" is an alias for %s", ap->val);
7068 /* Then check if it is a tracked alias */
7069 cmdp = cmdlookup(command, 0);
7071 entry.cmdtype = cmdp->cmdtype;
7072 entry.u = cmdp->param;
7074 /* Finally use brute force */
7075 find_command(command, &entry, DO_ABS, path);
7078 switch (entry.cmdtype) {
7080 int j = entry.u.index;
7086 p = padvance(&path, command);
7090 if (describe_command_verbose) {
7092 (cmdp ? " a tracked alias for" : nullstr), p
7101 if (describe_command_verbose) {
7102 out1str(" is a shell function");
7109 if (describe_command_verbose) {
7110 out1fmt(" is a %sshell builtin",
7111 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7112 "special " : nullstr
7120 if (describe_command_verbose) {
7121 out1str(": not found\n");
7126 outstr("\n", stdout);
7131 typecmd(int argc, char **argv)
7137 /* type -p ... ? (we don't bother checking for 'p') */
7138 if (argv[1] && argv[1][0] == '-') {
7143 err |= describe_command(argv[i++], verbose);
7148 #if ENABLE_ASH_CMDCMD
7150 commandcmd(int argc, char **argv)
7158 while ((c = nextopt("pvV")) != '\0')
7160 verify |= VERIFY_VERBOSE;
7162 verify |= VERIFY_BRIEF;
7168 return describe_command(*argptr, verify - VERIFY_BRIEF);
7175 /* ============ eval.c */
7177 static int funcblocksize; /* size of structures in function */
7178 static int funcstringsize; /* size of strings in node */
7179 static void *funcblock; /* block to allocate function from */
7180 static char *funcstring; /* block to allocate strings from */
7182 /* flags in argument to evaltree */
7183 #define EV_EXIT 01 /* exit after evaluating tree */
7184 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7185 #define EV_BACKCMD 04 /* command executing within back quotes */
7187 static const short nodesize[26] = {
7188 SHELL_ALIGN(sizeof(struct ncmd)),
7189 SHELL_ALIGN(sizeof(struct npipe)),
7190 SHELL_ALIGN(sizeof(struct nredir)),
7191 SHELL_ALIGN(sizeof(struct nredir)),
7192 SHELL_ALIGN(sizeof(struct nredir)),
7193 SHELL_ALIGN(sizeof(struct nbinary)),
7194 SHELL_ALIGN(sizeof(struct nbinary)),
7195 SHELL_ALIGN(sizeof(struct nbinary)),
7196 SHELL_ALIGN(sizeof(struct nif)),
7197 SHELL_ALIGN(sizeof(struct nbinary)),
7198 SHELL_ALIGN(sizeof(struct nbinary)),
7199 SHELL_ALIGN(sizeof(struct nfor)),
7200 SHELL_ALIGN(sizeof(struct ncase)),
7201 SHELL_ALIGN(sizeof(struct nclist)),
7202 SHELL_ALIGN(sizeof(struct narg)),
7203 SHELL_ALIGN(sizeof(struct narg)),
7204 SHELL_ALIGN(sizeof(struct nfile)),
7205 SHELL_ALIGN(sizeof(struct nfile)),
7206 SHELL_ALIGN(sizeof(struct nfile)),
7207 SHELL_ALIGN(sizeof(struct nfile)),
7208 SHELL_ALIGN(sizeof(struct nfile)),
7209 SHELL_ALIGN(sizeof(struct ndup)),
7210 SHELL_ALIGN(sizeof(struct ndup)),
7211 SHELL_ALIGN(sizeof(struct nhere)),
7212 SHELL_ALIGN(sizeof(struct nhere)),
7213 SHELL_ALIGN(sizeof(struct nnot)),
7216 static void calcsize(union node *n);
7219 sizenodelist(struct nodelist *lp)
7222 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7229 calcsize(union node *n)
7233 funcblocksize += nodesize[n->type];
7236 calcsize(n->ncmd.redirect);
7237 calcsize(n->ncmd.args);
7238 calcsize(n->ncmd.assign);
7241 sizenodelist(n->npipe.cmdlist);
7246 calcsize(n->nredir.redirect);
7247 calcsize(n->nredir.n);
7254 calcsize(n->nbinary.ch2);
7255 calcsize(n->nbinary.ch1);
7258 calcsize(n->nif.elsepart);
7259 calcsize(n->nif.ifpart);
7260 calcsize(n->nif.test);
7263 funcstringsize += strlen(n->nfor.var) + 1;
7264 calcsize(n->nfor.body);
7265 calcsize(n->nfor.args);
7268 calcsize(n->ncase.cases);
7269 calcsize(n->ncase.expr);
7272 calcsize(n->nclist.body);
7273 calcsize(n->nclist.pattern);
7274 calcsize(n->nclist.next);
7278 sizenodelist(n->narg.backquote);
7279 funcstringsize += strlen(n->narg.text) + 1;
7280 calcsize(n->narg.next);
7287 calcsize(n->nfile.fname);
7288 calcsize(n->nfile.next);
7292 calcsize(n->ndup.vname);
7293 calcsize(n->ndup.next);
7297 calcsize(n->nhere.doc);
7298 calcsize(n->nhere.next);
7301 calcsize(n->nnot.com);
7307 nodeckstrdup(char *s)
7309 char *rtn = funcstring;
7311 strcpy(funcstring, s);
7312 funcstring += strlen(s) + 1;
7316 static union node *copynode(union node *);
7318 static struct nodelist *
7319 copynodelist(struct nodelist *lp)
7321 struct nodelist *start;
7322 struct nodelist **lpp;
7327 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7328 (*lpp)->n = copynode(lp->n);
7330 lpp = &(*lpp)->next;
7337 copynode(union node *n)
7344 funcblock = (char *) funcblock + nodesize[n->type];
7348 new->ncmd.redirect = copynode(n->ncmd.redirect);
7349 new->ncmd.args = copynode(n->ncmd.args);
7350 new->ncmd.assign = copynode(n->ncmd.assign);
7353 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7354 new->npipe.backgnd = n->npipe.backgnd;
7359 new->nredir.redirect = copynode(n->nredir.redirect);
7360 new->nredir.n = copynode(n->nredir.n);
7367 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7368 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7371 new->nif.elsepart = copynode(n->nif.elsepart);
7372 new->nif.ifpart = copynode(n->nif.ifpart);
7373 new->nif.test = copynode(n->nif.test);
7376 new->nfor.var = nodeckstrdup(n->nfor.var);
7377 new->nfor.body = copynode(n->nfor.body);
7378 new->nfor.args = copynode(n->nfor.args);
7381 new->ncase.cases = copynode(n->ncase.cases);
7382 new->ncase.expr = copynode(n->ncase.expr);
7385 new->nclist.body = copynode(n->nclist.body);
7386 new->nclist.pattern = copynode(n->nclist.pattern);
7387 new->nclist.next = copynode(n->nclist.next);
7391 new->narg.backquote = copynodelist(n->narg.backquote);
7392 new->narg.text = nodeckstrdup(n->narg.text);
7393 new->narg.next = copynode(n->narg.next);
7400 new->nfile.fname = copynode(n->nfile.fname);
7401 new->nfile.fd = n->nfile.fd;
7402 new->nfile.next = copynode(n->nfile.next);
7406 new->ndup.vname = copynode(n->ndup.vname);
7407 new->ndup.dupfd = n->ndup.dupfd;
7408 new->ndup.fd = n->ndup.fd;
7409 new->ndup.next = copynode(n->ndup.next);
7413 new->nhere.doc = copynode(n->nhere.doc);
7414 new->nhere.fd = n->nhere.fd;
7415 new->nhere.next = copynode(n->nhere.next);
7418 new->nnot.com = copynode(n->nnot.com);
7421 new->type = n->type;
7426 * Make a copy of a parse tree.
7428 static struct funcnode *
7429 copyfunc(union node *n)
7434 funcblocksize = offsetof(struct funcnode, n);
7437 blocksize = funcblocksize;
7438 f = ckmalloc(blocksize + funcstringsize);
7439 funcblock = (char *) f + offsetof(struct funcnode, n);
7440 funcstring = (char *) f + blocksize;
7447 * Define a shell function.
7450 defun(char *name, union node *func)
7452 struct cmdentry entry;
7455 entry.cmdtype = CMDFUNCTION;
7456 entry.u.func = copyfunc(func);
7457 addcmdentry(name, &entry);
7461 static int evalskip; /* set if we are skipping commands */
7462 /* reasons for skipping commands (see comment on breakcmd routine) */
7463 #define SKIPBREAK (1 << 0)
7464 #define SKIPCONT (1 << 1)
7465 #define SKIPFUNC (1 << 2)
7466 #define SKIPFILE (1 << 3)
7467 #define SKIPEVAL (1 << 4)
7468 static int skipcount; /* number of levels to skip */
7469 static int funcnest; /* depth of function calls */
7471 /* forward decl way out to parsing code - dotrap needs it */
7472 static int evalstring(char *s, int mask);
7475 * Called to execute a trap. Perhaps we should avoid entering new trap
7476 * handlers while we are executing a trap handler.
7487 savestatus = exitstatus;
7491 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
7499 skip = evalstring(p, SKIPEVAL);
7500 exitstatus = savestatus;
7508 /* forward declarations - evaluation is fairly recursive business... */
7509 static void evalloop(union node *, int);
7510 static void evalfor(union node *, int);
7511 static void evalcase(union node *, int);
7512 static void evalsubshell(union node *, int);
7513 static void expredir(union node *);
7514 static void evalpipe(union node *, int);
7515 static void evalcommand(union node *, int);
7516 static int evalbltin(const struct builtincmd *, int, char **);
7517 static void prehash(union node *);
7520 * Evaluate a parse tree. The value is left in the global variable
7524 evaltree(union node *n, int flags)
7527 void (*evalfn)(union node *, int);
7531 TRACE(("evaltree(NULL) called\n"));
7534 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
7535 getpid(), n, n->type, flags));
7539 out1fmt("Node type = %d\n", n->type);
7544 evaltree(n->nnot.com, EV_TESTED);
7545 status = !exitstatus;
7548 expredir(n->nredir.redirect);
7549 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
7551 evaltree(n->nredir.n, flags & EV_TESTED);
7552 status = exitstatus;
7557 evalfn = evalcommand;
7559 if (eflag && !(flags & EV_TESTED))
7571 evalfn = evalsubshell;
7583 #error NAND + 1 != NOR
7585 #if NOR + 1 != NSEMI
7586 #error NOR + 1 != NSEMI
7588 isor = n->type - NAND;
7591 (flags | ((isor >> 1) - 1)) & EV_TESTED
7593 if (!exitstatus == isor)
7605 evaltree(n->nif.test, EV_TESTED);
7608 if (exitstatus == 0) {
7611 } else if (n->nif.elsepart) {
7612 n = n->nif.elsepart;
7617 defun(n->narg.text, n->narg.next);
7621 exitstatus = status;
7625 if ((checkexit & exitstatus))
7626 evalskip |= SKIPEVAL;
7627 else if (pendingsig && dotrap())
7630 if (flags & EV_EXIT) {
7632 raise_exception(EXEXIT);
7636 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
7639 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
7641 static int loopnest; /* current loop nesting level */
7644 evalloop(union node *n, int flags)
7654 evaltree(n->nbinary.ch1, EV_TESTED);
7657 if (evalskip == SKIPCONT && --skipcount <= 0) {
7661 if (evalskip == SKIPBREAK && --skipcount <= 0)
7666 if (n->type != NWHILE)
7670 evaltree(n->nbinary.ch2, flags);
7671 status = exitstatus;
7676 exitstatus = status;
7680 evalfor(union node *n, int flags)
7682 struct arglist arglist;
7685 struct stackmark smark;
7687 setstackmark(&smark);
7688 arglist.list = NULL;
7689 arglist.lastp = &arglist.list;
7690 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
7691 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
7696 *arglist.lastp = NULL;
7701 for (sp = arglist.list; sp; sp = sp->next) {
7702 setvar(n->nfor.var, sp->text, 0);
7703 evaltree(n->nfor.body, flags);
7705 if (evalskip == SKIPCONT && --skipcount <= 0) {
7709 if (evalskip == SKIPBREAK && --skipcount <= 0)
7716 popstackmark(&smark);
7720 evalcase(union node *n, int flags)
7724 struct arglist arglist;
7725 struct stackmark smark;
7727 setstackmark(&smark);
7728 arglist.list = NULL;
7729 arglist.lastp = &arglist.list;
7730 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
7732 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
7733 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
7734 if (casematch(patp, arglist.list->text)) {
7735 if (evalskip == 0) {
7736 evaltree(cp->nclist.body, flags);
7743 popstackmark(&smark);
7747 * Kick off a subshell to evaluate a tree.
7750 evalsubshell(union node *n, int flags)
7753 int backgnd = (n->type == NBACKGND);
7756 expredir(n->nredir.redirect);
7757 if (!backgnd && flags & EV_EXIT && !trap[0])
7761 if (forkshell(jp, n, backgnd) == 0) {
7765 flags &=~ EV_TESTED;
7767 redirect(n->nredir.redirect, 0);
7768 evaltreenr(n->nredir.n, flags);
7773 status = waitforjob(jp);
7774 exitstatus = status;
7779 * Compute the names of the files in a redirection list.
7781 static void fixredir(union node *, const char *, int);
7783 expredir(union node *n)
7787 for (redir = n; redir; redir = redir->nfile.next) {
7791 fn.lastp = &fn.list;
7792 switch (redir->type) {
7798 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
7799 redir->nfile.expfname = fn.list->text;
7803 if (redir->ndup.vname) {
7804 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
7805 if (fn.list == NULL)
7806 ash_msg_and_raise_error("redir error");
7807 fixredir(redir, fn.list->text, 1);
7815 * Evaluate a pipeline. All the processes in the pipeline are children
7816 * of the process creating the pipeline. (This differs from some versions
7817 * of the shell, which make the last process in a pipeline the parent
7821 evalpipe(union node *n, int flags)
7824 struct nodelist *lp;
7829 TRACE(("evalpipe(0x%lx) called\n", (long)n));
7831 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
7835 jp = makejob(n, pipelen);
7837 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
7841 if (pipe(pip) < 0) {
7843 ash_msg_and_raise_error("pipe call failed");
7846 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
7859 evaltreenr(lp->n, flags);
7867 if (n->npipe.backgnd == 0) {
7868 exitstatus = waitforjob(jp);
7869 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
7875 * Controls whether the shell is interactive or not.
7878 setinteractive(int on)
7880 static int is_interactive;
7882 if (++on == is_interactive)
7884 is_interactive = on;
7888 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
7889 if (is_interactive > 1) {
7890 /* Looks like they want an interactive shell */
7891 static smallint did_banner;
7896 "%s built-in shell (ash)\n"
7897 "Enter 'help' for a list of built-in commands."
7906 #if ENABLE_FEATURE_EDITING_VI
7907 #define setvimode(on) do { \
7908 if (on) line_input_state->flags |= VI_MODE; \
7909 else line_input_state->flags &= ~VI_MODE; \
7912 #define setvimode(on) viflag = 0 /* forcibly keep the option off */
7921 setinteractive(iflag);
7926 static struct localvar *localvars;
7929 * Called after a function returns.
7930 * Interrupts must be off.
7935 struct localvar *lvp;
7938 while ((lvp = localvars) != NULL) {
7939 localvars = lvp->next;
7941 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
7942 if (vp == NULL) { /* $- saved */
7943 memcpy(optlist, lvp->text, sizeof(optlist));
7944 free((char*)lvp->text);
7946 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
7950 (*vp->func)(strchrnul(lvp->text, '=') + 1);
7951 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
7952 free((char*)vp->text);
7953 vp->flags = lvp->flags;
7954 vp->text = lvp->text;
7961 evalfun(struct funcnode *func, int argc, char **argv, int flags)
7963 volatile struct shparam saveparam;
7964 struct localvar *volatile savelocalvars;
7965 struct jmploc *volatile savehandler;
7966 struct jmploc jmploc;
7969 saveparam = shellparam;
7970 savelocalvars = localvars;
7971 e = setjmp(jmploc.loc);
7976 savehandler = exception_handler;
7977 exception_handler = &jmploc;
7979 shellparam.malloced = 0;
7983 shellparam.nparam = argc - 1;
7984 shellparam.p = argv + 1;
7985 #if ENABLE_ASH_GETOPTS
7986 shellparam.optind = 1;
7987 shellparam.optoff = -1;
7989 evaltree(&func->n, flags & EV_TESTED);
7995 localvars = savelocalvars;
7996 freeparam(&shellparam);
7997 shellparam = saveparam;
7998 exception_handler = savehandler;
8000 evalskip &= ~SKIPFUNC;
8004 #if ENABLE_ASH_CMDCMD
8006 parse_command_args(char **argv, const char **path)
8019 if (c == '-' && !*cp) {
8026 *path = bb_default_path;
8029 /* run 'typecmd' for other options */
8040 * Make a variable a local variable. When a variable is made local, it's
8041 * value and flags are saved in a localvar structure. The saved values
8042 * will be restored when the shell function returns. We handle the name
8043 * "-" as a special case.
8048 struct localvar *lvp;
8053 lvp = ckmalloc(sizeof(struct localvar));
8054 if (LONE_DASH(name)) {
8056 p = ckmalloc(sizeof(optlist));
8057 lvp->text = memcpy(p, optlist, sizeof(optlist));
8062 vpp = hashvar(name);
8063 vp = *findvar(vpp, name);
8064 eq = strchr(name, '=');
8067 setvareq(name, VSTRFIXED);
8069 setvar(name, NULL, VSTRFIXED);
8070 vp = *vpp; /* the new variable */
8071 lvp->flags = VUNSET;
8073 lvp->text = vp->text;
8074 lvp->flags = vp->flags;
8075 vp->flags |= VSTRFIXED|VTEXTFIXED;
8081 lvp->next = localvars;
8087 * The "local" command.
8090 localcmd(int argc, char **argv)
8095 while ((name = *argv++) != NULL) {
8102 falsecmd(int argc, char **argv)
8108 truecmd(int argc, char **argv)
8114 execcmd(int argc, char **argv)
8117 iflag = 0; /* exit on error */
8120 shellexec(argv + 1, pathval(), 0);
8126 * The return command.
8129 returncmd(int argc, char **argv)
8132 * If called outside a function, do what ksh does;
8133 * skip the rest of the file.
8135 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8136 return argv[1] ? number(argv[1]) : exitstatus;
8139 /* Forward declarations for builtintab[] */
8140 static int breakcmd(int, char **);
8141 static int dotcmd(int, char **);
8142 static int evalcmd(int, char **);
8143 #if ENABLE_ASH_BUILTIN_ECHO
8144 static int echocmd(int, char **);
8146 #if ENABLE_ASH_BUILTIN_TEST
8147 static int testcmd(int, char **);
8149 static int exitcmd(int, char **);
8150 static int exportcmd(int, char **);
8151 #if ENABLE_ASH_GETOPTS
8152 static int getoptscmd(int, char **);
8154 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8155 static int helpcmd(int argc, char **argv);
8157 #if ENABLE_ASH_MATH_SUPPORT
8158 static int letcmd(int, char **);
8160 static int readcmd(int, char **);
8161 static int setcmd(int, char **);
8162 static int shiftcmd(int, char **);
8163 static int timescmd(int, char **);
8164 static int trapcmd(int, char **);
8165 static int umaskcmd(int, char **);
8166 static int unsetcmd(int, char **);
8167 static int ulimitcmd(int, char **);
8169 #define BUILTIN_NOSPEC "0"
8170 #define BUILTIN_SPECIAL "1"
8171 #define BUILTIN_REGULAR "2"
8172 #define BUILTIN_SPEC_REG "3"
8173 #define BUILTIN_ASSIGN "4"
8174 #define BUILTIN_SPEC_ASSG "5"
8175 #define BUILTIN_REG_ASSG "6"
8176 #define BUILTIN_SPEC_REG_ASSG "7"
8178 /* make sure to keep these in proper order since it is searched via bsearch() */
8179 static const struct builtincmd builtintab[] = {
8180 { BUILTIN_SPEC_REG ".", dotcmd },
8181 { BUILTIN_SPEC_REG ":", truecmd },
8182 #if ENABLE_ASH_BUILTIN_TEST
8183 { BUILTIN_REGULAR "[", testcmd },
8184 { BUILTIN_REGULAR "[[", testcmd },
8186 #if ENABLE_ASH_ALIAS
8187 { BUILTIN_REG_ASSG "alias", aliascmd },
8190 { BUILTIN_REGULAR "bg", fg_bgcmd },
8192 { BUILTIN_SPEC_REG "break", breakcmd },
8193 { BUILTIN_REGULAR "cd", cdcmd },
8194 { BUILTIN_NOSPEC "chdir", cdcmd },
8195 #if ENABLE_ASH_CMDCMD
8196 { BUILTIN_REGULAR "command", commandcmd },
8198 { BUILTIN_SPEC_REG "continue", breakcmd },
8199 #if ENABLE_ASH_BUILTIN_ECHO
8200 { BUILTIN_REGULAR "echo", echocmd },
8202 { BUILTIN_SPEC_REG "eval", evalcmd },
8203 { BUILTIN_SPEC_REG "exec", execcmd },
8204 { BUILTIN_SPEC_REG "exit", exitcmd },
8205 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8206 { BUILTIN_REGULAR "false", falsecmd },
8208 { BUILTIN_REGULAR "fg", fg_bgcmd },
8210 #if ENABLE_ASH_GETOPTS
8211 { BUILTIN_REGULAR "getopts", getoptscmd },
8213 { BUILTIN_NOSPEC "hash", hashcmd },
8214 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8215 { BUILTIN_NOSPEC "help", helpcmd },
8218 { BUILTIN_REGULAR "jobs", jobscmd },
8219 { BUILTIN_REGULAR "kill", killcmd },
8221 #if ENABLE_ASH_MATH_SUPPORT
8222 { BUILTIN_NOSPEC "let", letcmd },
8224 { BUILTIN_ASSIGN "local", localcmd },
8225 { BUILTIN_NOSPEC "pwd", pwdcmd },
8226 { BUILTIN_REGULAR "read", readcmd },
8227 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8228 { BUILTIN_SPEC_REG "return", returncmd },
8229 { BUILTIN_SPEC_REG "set", setcmd },
8230 { BUILTIN_SPEC_REG "shift", shiftcmd },
8231 { BUILTIN_SPEC_REG "source", dotcmd },
8232 #if ENABLE_ASH_BUILTIN_TEST
8233 { BUILTIN_REGULAR "test", testcmd },
8235 { BUILTIN_SPEC_REG "times", timescmd },
8236 { BUILTIN_SPEC_REG "trap", trapcmd },
8237 { BUILTIN_REGULAR "true", truecmd },
8238 { BUILTIN_NOSPEC "type", typecmd },
8239 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
8240 { BUILTIN_REGULAR "umask", umaskcmd },
8241 #if ENABLE_ASH_ALIAS
8242 { BUILTIN_REGULAR "unalias", unaliascmd },
8244 { BUILTIN_SPEC_REG "unset", unsetcmd },
8245 { BUILTIN_REGULAR "wait", waitcmd },
8249 #define COMMANDCMD (builtintab + 5 + \
8250 2 * ENABLE_ASH_BUILTIN_TEST + \
8251 ENABLE_ASH_ALIAS + \
8252 ENABLE_ASH_JOB_CONTROL)
8253 #define EXECCMD (builtintab + 7 + \
8254 2 * ENABLE_ASH_BUILTIN_TEST + \
8255 ENABLE_ASH_ALIAS + \
8256 ENABLE_ASH_JOB_CONTROL + \
8257 ENABLE_ASH_CMDCMD + \
8258 ENABLE_ASH_BUILTIN_ECHO)
8261 * Search the table of builtin commands.
8263 static struct builtincmd *
8264 find_builtin(const char *name)
8266 struct builtincmd *bp;
8269 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8276 * Execute a simple command.
8278 static int back_exitstatus; /* exit status of backquoted command */
8280 isassignment(const char *p)
8282 const char *q = endofname(p);
8288 bltincmd(int argc, char **argv)
8290 /* Preserve exitstatus of a previous possible redirection
8291 * as POSIX mandates */
8292 return back_exitstatus;
8295 evalcommand(union node *cmd, int flags)
8297 static const struct builtincmd null_bltin = {
8298 "\0\0", bltincmd /* why three NULs? */
8300 struct stackmark smark;
8302 struct arglist arglist;
8303 struct arglist varlist;
8306 const struct strlist *sp;
8307 struct cmdentry cmdentry;
8315 struct builtincmd *bcmd;
8316 int pseudovarflag = 0;
8318 /* First expand the arguments. */
8319 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8320 setstackmark(&smark);
8321 back_exitstatus = 0;
8323 cmdentry.cmdtype = CMDBUILTIN;
8324 cmdentry.u.cmd = &null_bltin;
8325 varlist.lastp = &varlist.list;
8326 *varlist.lastp = NULL;
8327 arglist.lastp = &arglist.list;
8328 *arglist.lastp = NULL;
8331 if (cmd->ncmd.args) {
8332 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8333 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8336 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8337 struct strlist **spp;
8339 spp = arglist.lastp;
8340 if (pseudovarflag && isassignment(argp->narg.text))
8341 expandarg(argp, &arglist, EXP_VARTILDE);
8343 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8345 for (sp = *spp; sp; sp = sp->next)
8349 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8350 for (sp = arglist.list; sp; sp = sp->next) {
8351 TRACE(("evalcommand arg: %s\n", sp->text));
8352 *nargv++ = sp->text;
8357 if (iflag && funcnest == 0 && argc > 0)
8358 lastarg = nargv[-1];
8361 expredir(cmd->ncmd.redirect);
8362 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8365 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8366 struct strlist **spp;
8369 spp = varlist.lastp;
8370 expandarg(argp, &varlist, EXP_VARTILDE);
8373 * Modify the command lookup path, if a PATH= assignment
8377 if (varequal(p, path))
8381 /* Print the command if xflag is set. */
8384 const char *p = " %s";
8387 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8390 for (n = 0; n < 2; n++) {
8392 fdprintf(preverrout_fd, p, sp->text);
8400 safe_write(preverrout_fd, "\n", 1);
8406 /* Now locate the command. */
8408 const char *oldpath;
8409 int cmd_flag = DO_ERR;
8414 find_command(argv[0], &cmdentry, cmd_flag, path);
8415 if (cmdentry.cmdtype == CMDUNKNOWN) {
8421 /* implement bltin and command here */
8422 if (cmdentry.cmdtype != CMDBUILTIN)
8425 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8426 if (cmdentry.u.cmd == EXECCMD)
8428 #if ENABLE_ASH_CMDCMD
8429 if (cmdentry.u.cmd == COMMANDCMD) {
8431 nargv = parse_command_args(argv, &path);
8434 argc -= nargv - argv;
8436 cmd_flag |= DO_NOFUNC;
8444 /* We have a redirection error. */
8446 raise_exception(EXERROR);
8448 exitstatus = status;
8452 /* Execute the command. */
8453 switch (cmdentry.cmdtype) {
8455 /* Fork off a child process if necessary. */
8456 if (!(flags & EV_EXIT) || trap[0]) {
8458 jp = makejob(cmd, 1);
8459 if (forkshell(jp, cmd, FORK_FG) != 0) {
8460 exitstatus = waitforjob(jp);
8466 listsetvar(varlist.list, VEXPORT|VSTACK);
8467 shellexec(argv, path, cmdentry.u.index);
8471 cmdenviron = varlist.list;
8473 struct strlist *list = cmdenviron;
8475 if (spclbltin > 0 || argc == 0) {
8477 if (cmd_is_exec && argc > 1)
8480 listsetvar(list, i);
8482 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
8489 exit_status = 128 + SIGINT;
8491 exit_status = 128 + pendingsig;
8492 exitstatus = exit_status;
8493 if (i == EXINT || spclbltin > 0) {
8495 longjmp(exception_handler->loc, 1);
8502 listsetvar(varlist.list, 0);
8503 if (evalfun(cmdentry.u.func, argc, argv, flags))
8509 popredir(cmd_is_exec);
8511 /* dsl: I think this is intended to be used to support
8512 * '_' in 'vi' command mode during line editing...
8513 * However I implemented that within libedit itself.
8515 setvar("_", lastarg, 0);
8516 popstackmark(&smark);
8520 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
8522 char *volatile savecmdname;
8523 struct jmploc *volatile savehandler;
8524 struct jmploc jmploc;
8527 savecmdname = commandname;
8528 i = setjmp(jmploc.loc);
8531 savehandler = exception_handler;
8532 exception_handler = &jmploc;
8533 commandname = argv[0];
8535 optptr = NULL; /* initialize nextopt */
8536 exitstatus = (*cmd->builtin)(argc, argv);
8537 flush_stdout_stderr();
8539 exitstatus |= ferror(stdout);
8541 commandname = savecmdname;
8543 exception_handler = savehandler;
8549 goodname(const char *p)
8551 return !*endofname(p);
8556 * Search for a command. This is called before we fork so that the
8557 * location of the command will be available in the parent as well as
8558 * the child. The check for "goodname" is an overly conservative
8559 * check that the name will not be subject to expansion.
8562 prehash(union node *n)
8564 struct cmdentry entry;
8566 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
8567 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
8571 /* ============ Builtin commands
8573 * Builtin commands whose functions are closely tied to evaluation
8574 * are implemented here.
8578 * Handle break and continue commands. Break, continue, and return are
8579 * all handled by setting the evalskip flag. The evaluation routines
8580 * above all check this flag, and if it is set they start skipping
8581 * commands rather than executing them. The variable skipcount is
8582 * the number of loops to break/continue, or the number of function
8583 * levels to return. (The latter is always 1.) It should probably
8584 * be an error to break out of more loops than exist, but it isn't
8585 * in the standard shell so we don't make it one here.
8588 breakcmd(int argc, char **argv)
8590 int n = argc > 1 ? number(argv[1]) : 1;
8593 ash_msg_and_raise_error(illnum, argv[1]);
8597 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
8604 /* ============ input.c
8606 * This implements the input routines used by the parser.
8609 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
8612 INPUT_PUSH_FILE = 1,
8613 INPUT_NOFILE_OK = 2,
8616 static int plinno = 1; /* input line number */
8617 /* number of characters left in input buffer */
8618 static int parsenleft; /* copy of parsefile->nleft */
8619 static int parselleft; /* copy of parsefile->lleft */
8620 /* next character in input buffer */
8621 static char *parsenextc; /* copy of parsefile->nextc */
8623 static int checkkwd;
8624 /* values of checkkwd variable */
8625 #define CHKALIAS 0x1
8632 struct strpush *sp = parsefile->strpush;
8635 #if ENABLE_ASH_ALIAS
8637 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
8638 checkkwd |= CHKALIAS;
8640 if (sp->string != sp->ap->val) {
8643 sp->ap->flag &= ~ALIASINUSE;
8644 if (sp->ap->flag & ALIASDEAD) {
8645 unalias(sp->ap->name);
8649 parsenextc = sp->prevstring;
8650 parsenleft = sp->prevnleft;
8651 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
8652 parsefile->strpush = sp->prev;
8653 if (sp != &(parsefile->basestrpush))
8662 char *buf = parsefile->buf;
8666 #if ENABLE_FEATURE_EDITING
8667 if (!iflag || parsefile->fd)
8668 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
8670 #if ENABLE_FEATURE_TAB_COMPLETION
8671 line_input_state->path_lookup = pathval();
8673 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
8675 /* Ctrl+C pressed */
8684 if (nr < 0 && errno == 0) {
8685 /* Ctrl+D pressed */
8690 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
8694 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
8695 int flags = fcntl(0, F_GETFL);
8696 if (flags >= 0 && (flags & O_NONBLOCK)) {
8697 flags &= ~O_NONBLOCK;
8698 if (fcntl(0, F_SETFL, flags) >= 0) {
8699 out2str("sh: turning off NDELAY mode\n");
8709 * Refill the input buffer and return the next input character:
8711 * 1) If a string was pushed back on the input, pop it;
8712 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
8713 * from a string so we can't refill the buffer, return EOF.
8714 * 3) If the is more stuff in this buffer, use it else call read to fill it.
8715 * 4) Process input up to the next newline, deleting nul characters.
8724 while (parsefile->strpush) {
8725 #if ENABLE_ASH_ALIAS
8726 if (parsenleft == -1 && parsefile->strpush->ap &&
8727 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
8732 if (--parsenleft >= 0)
8733 return signed_char2int(*parsenextc++);
8735 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
8737 flush_stdout_stderr();
8744 parselleft = parsenleft = EOF_NLEFT;
8751 /* delete nul characters */
8759 memmove(q, q + 1, more);
8763 parsenleft = q - parsenextc - 1;
8769 parsenleft = q - parsenextc - 1;
8781 out2str(parsenextc);
8786 return signed_char2int(*parsenextc++);
8789 #define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer())
8793 return pgetc_as_macro();
8796 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
8797 #define pgetc_macro() pgetc()
8799 #define pgetc_macro() pgetc_as_macro()
8803 * Same as pgetc(), but ignores PEOA.
8805 #if ENABLE_ASH_ALIAS
8813 } while (c == PEOA);
8820 return pgetc_macro();
8825 * Read a line from the script.
8828 pfgets(char *line, int len)
8834 while (--nleft > 0) {
8850 * Undo the last call to pgetc. Only one character may be pushed back.
8851 * PEOF may be pushed back.
8861 * Push a string back onto the input at this current parsefile level.
8862 * We handle aliases this way.
8865 pushstring(char *s, void *ap)
8872 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
8873 if (parsefile->strpush) {
8874 sp = ckmalloc(sizeof(struct strpush));
8875 sp->prev = parsefile->strpush;
8876 parsefile->strpush = sp;
8878 sp = parsefile->strpush = &(parsefile->basestrpush);
8879 sp->prevstring = parsenextc;
8880 sp->prevnleft = parsenleft;
8881 #if ENABLE_ASH_ALIAS
8882 sp->ap = (struct alias *)ap;
8884 ((struct alias *)ap)->flag |= ALIASINUSE;
8894 * To handle the "." command, a stack of input files is used. Pushfile
8895 * adds a new entry to the stack and popfile restores the previous level.
8900 struct parsefile *pf;
8902 parsefile->nleft = parsenleft;
8903 parsefile->lleft = parselleft;
8904 parsefile->nextc = parsenextc;
8905 parsefile->linno = plinno;
8906 pf = ckmalloc(sizeof(*pf));
8907 pf->prev = parsefile;
8910 pf->basestrpush.prev = NULL;
8917 struct parsefile *pf = parsefile;
8925 parsefile = pf->prev;
8927 parsenleft = parsefile->nleft;
8928 parselleft = parsefile->lleft;
8929 parsenextc = parsefile->nextc;
8930 plinno = parsefile->linno;
8935 * Return to top level.
8940 while (parsefile != &basepf)
8945 * Close the file(s) that the shell is reading commands from. Called
8946 * after a fork is done.
8952 if (parsefile->fd > 0) {
8953 close(parsefile->fd);
8959 * Like setinputfile, but takes an open file descriptor. Call this with
8963 setinputfd(int fd, int push)
8965 close_on_exec_on(fd);
8971 if (parsefile->buf == NULL)
8972 parsefile->buf = ckmalloc(IBUFSIZ);
8973 parselleft = parsenleft = 0;
8978 * Set the input to take input from a file. If push is set, push the
8979 * old input onto the stack first.
8982 setinputfile(const char *fname, int flags)
8988 fd = open(fname, O_RDONLY);
8990 if (flags & INPUT_NOFILE_OK)
8992 ash_msg_and_raise_error("can't open %s", fname);
8995 fd2 = copyfd(fd, 10);
8998 ash_msg_and_raise_error("out of file descriptors");
9001 setinputfd(fd, flags & INPUT_PUSH_FILE);
9008 * Like setinputfile, but takes input from a string.
9011 setinputstring(char *string)
9015 parsenextc = string;
9016 parsenleft = strlen(string);
9017 parsefile->buf = NULL;
9023 /* ============ mail.c
9025 * Routines to check for mail.
9030 #define MAXMBOXES 10
9032 /* times of mailboxes */
9033 static time_t mailtime[MAXMBOXES];
9034 /* Set if MAIL or MAILPATH is changed. */
9035 static smallint mail_var_path_changed;
9038 * Print appropriate message(s) if mail has arrived.
9039 * If mail_var_path_changed is set,
9040 * then the value of MAIL has mail_var_path_changed,
9041 * so we just update the values.
9050 struct stackmark smark;
9053 setstackmark(&smark);
9054 mpath = mpathset() ? mpathval() : mailval();
9055 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9056 p = padvance(&mpath, nullstr);
9061 for (q = p; *q; q++);
9066 q[-1] = '\0'; /* delete trailing '/' */
9067 if (stat(p, &statb) < 0) {
9071 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9074 pathopt ? pathopt : "you have mail"
9077 *mtp = statb.st_mtime;
9079 mail_var_path_changed = 0;
9080 popstackmark(&smark);
9084 changemail(const char *val)
9086 mail_var_path_changed = 1;
9089 #endif /* ASH_MAIL */
9092 /* ============ ??? */
9095 * Set the shell parameters.
9098 setparam(char **argv)
9104 for (nparam = 0; argv[nparam]; nparam++);
9105 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9107 *ap++ = ckstrdup(*argv++);
9110 freeparam(&shellparam);
9111 shellparam.malloced = 1;
9112 shellparam.nparam = nparam;
9113 shellparam.p = newparam;
9114 #if ENABLE_ASH_GETOPTS
9115 shellparam.optind = 1;
9116 shellparam.optoff = -1;
9121 * Process shell options. The global variable argptr contains a pointer
9122 * to the argument list; we advance it past the options.
9124 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9125 * For a non-interactive shell, an error condition encountered
9126 * by a special built-in ... shall cause the shell to write a diagnostic message
9127 * to standard error and exit as shown in the following table:
9128 * Error Special Built-In
9130 * Utility syntax error (option or operand error) Shall exit
9132 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9133 * we see that bash does not do that (set "finishes" with error code 1 instead,
9134 * and shell continues), and people rely on this behavior!
9136 * set -o barfoo 2>/dev/null
9139 * Oh well. Let's mimic that.
9142 minus_o(char *name, int val)
9147 for (i = 0; i < NOPTS; i++) {
9148 if (strcmp(name, optnames(i)) == 0) {
9153 ash_msg("illegal option -o %s", name);
9156 out1str("Current option settings\n");
9157 for (i = 0; i < NOPTS; i++)
9158 out1fmt("%-16s%s\n", optnames(i),
9159 optlist[i] ? "on" : "off");
9163 setoption(int flag, int val)
9167 for (i = 0; i < NOPTS; i++) {
9168 if (optletters(i) == flag) {
9173 ash_msg_and_raise_error("illegal option -%c", flag);
9177 options(int cmdline)
9185 while ((p = *argptr) != NULL) {
9187 if (c != '-' && c != '+')
9190 val = 0; /* val = 0 if c == '+' */
9193 if (p[0] == '\0' || LONE_DASH(p)) {
9195 /* "-" means turn off -x and -v */
9198 /* "--" means reset params */
9199 else if (*argptr == NULL)
9202 break; /* "-" or "--" terminates options */
9205 /* first char was + or - */
9206 while ((c = *p++) != '\0') {
9207 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9208 if (c == 'c' && cmdline) {
9209 minusc = p; /* command is after shell args */
9210 } else if (c == 'o') {
9211 if (minus_o(*argptr, val)) {
9212 /* it already printed err message */
9213 return 1; /* error */
9217 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9219 /* bash does not accept +-login, we also won't */
9220 } else if (cmdline && val && (c == '-')) { /* long options */
9221 if (strcmp(p, "login") == 0)
9233 * The shift builtin command.
9236 shiftcmd(int argc, char **argv)
9243 n = number(argv[1]);
9244 if (n > shellparam.nparam)
9245 ash_msg_and_raise_error("can't shift that many");
9247 shellparam.nparam -= n;
9248 for (ap1 = shellparam.p; --n >= 0; ap1++) {
9249 if (shellparam.malloced)
9253 while ((*ap2++ = *ap1++) != NULL);
9254 #if ENABLE_ASH_GETOPTS
9255 shellparam.optind = 1;
9256 shellparam.optoff = -1;
9263 * POSIX requires that 'set' (but not export or readonly) output the
9264 * variables in lexicographic order - by the locale's collating order (sigh).
9265 * Maybe we could keep them in an ordered balanced binary tree
9266 * instead of hashed lists.
9267 * For now just roll 'em through qsort for printing...
9270 showvars(const char *sep_prefix, int on, int off)
9275 ep = listvars(on, off, &epend);
9276 qsort(ep, epend - ep, sizeof(char *), vpcmp);
9278 sep = *sep_prefix ? " " : sep_prefix;
9280 for (; ep < epend; ep++) {
9284 p = strchrnul(*ep, '=');
9287 q = single_quote(++p);
9288 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9294 * The set command builtin.
9297 setcmd(int argc, char **argv)
9302 return showvars(nullstr, 0, VUNSET);
9305 if (!options(0)) { /* if no parse error... */
9308 if (*argptr != NULL) {
9316 #if ENABLE_ASH_RANDOM_SUPPORT
9317 /* Roughly copied from bash.. */
9319 change_random(const char *value)
9321 if (value == NULL) {
9322 /* "get", generate */
9325 rseed = rseed * 1103515245 + 12345;
9326 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9327 /* set without recursion */
9328 setvar(vrandom.text, buf, VNOFUNC);
9329 vrandom.flags &= ~VNOFUNC;
9332 rseed = strtoul(value, (char **)NULL, 10);
9337 #if ENABLE_ASH_GETOPTS
9339 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9348 if (*param_optind < 1)
9350 optnext = optfirst + *param_optind - 1;
9352 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9355 p = optnext[-1] + *optoff;
9356 if (p == NULL || *p == '\0') {
9357 /* Current word is done, advance */
9359 if (p == NULL || *p != '-' || *++p == '\0') {
9366 if (LONE_DASH(p)) /* check for "--" */
9371 for (q = optstr; *q != c; ) {
9373 if (optstr[0] == ':') {
9376 err |= setvarsafe("OPTARG", s, 0);
9378 fprintf(stderr, "Illegal option -%c\n", c);
9389 if (*p == '\0' && (p = *optnext) == NULL) {
9390 if (optstr[0] == ':') {
9393 err |= setvarsafe("OPTARG", s, 0);
9396 fprintf(stderr, "No arg for -%c option\n", c);
9405 err |= setvarsafe("OPTARG", p, 0);
9408 err |= setvarsafe("OPTARG", nullstr, 0);
9410 *optoff = p ? p - *(optnext - 1) : -1;
9411 *param_optind = optnext - optfirst + 1;
9412 fmtstr(s, sizeof(s), "%d", *param_optind);
9413 err |= setvarsafe("OPTIND", s, VNOFUNC);
9416 err |= setvarsafe(optvar, s, 0);
9420 flush_stdout_stderr();
9421 raise_exception(EXERROR);
9427 * The getopts builtin. Shellparam.optnext points to the next argument
9428 * to be processed. Shellparam.optptr points to the next character to
9429 * be processed in the current argument. If shellparam.optnext is NULL,
9430 * then it's the first time getopts has been called.
9433 getoptscmd(int argc, char **argv)
9438 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
9440 optbase = shellparam.p;
9441 if (shellparam.optind > shellparam.nparam + 1) {
9442 shellparam.optind = 1;
9443 shellparam.optoff = -1;
9447 if (shellparam.optind > argc - 2) {
9448 shellparam.optind = 1;
9449 shellparam.optoff = -1;
9453 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9454 &shellparam.optoff);
9456 #endif /* ASH_GETOPTS */
9459 /* ============ Shell parser */
9462 * NEOF is returned by parsecmd when it encounters an end of file. It
9463 * must be distinct from NULL, so we use the address of a variable that
9464 * happens to be handy.
9466 static smallint tokpushback; /* last token pushed back */
9467 #define NEOF ((union node *)&tokpushback)
9468 static smallint parsebackquote; /* nonzero if we are inside backquotes */
9469 static int lasttoken; /* last token read */
9470 static char *wordtext; /* text of last word returned by readtoken */
9471 static struct nodelist *backquotelist;
9472 static union node *redirnode;
9473 static struct heredoc *heredoc;
9474 static smallint quoteflag; /* set if (part of) last token was quoted */
9476 static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN;
9478 raise_error_syntax(const char *msg)
9480 ash_msg_and_raise_error("syntax error: %s", msg);
9485 * Called when an unexpected token is read during the parse. The argument
9486 * is the token that is expected, or -1 if more than one type of token can
9487 * occur at this point.
9489 static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN;
9491 raise_error_unexpected_syntax(int token)
9496 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
9498 sprintf(msg + l, " (expecting %s)", tokname(token));
9499 raise_error_syntax(msg);
9503 #define EOFMARKLEN 79
9506 struct heredoc *next; /* next here document in list */
9507 union node *here; /* redirection node */
9508 char *eofmark; /* string indicating end of input */
9509 int striptabs; /* if set, strip leading tabs */
9512 static struct heredoc *heredoclist; /* list of here documents to read */
9514 /* parsing is heavily cross-recursive, need these forward decls */
9515 static union node *andor(void);
9516 static union node *pipeline(void);
9517 static union node *parse_command(void);
9518 static void parseheredoc(void);
9519 static char peektoken(void);
9520 static int readtoken(void);
9525 union node *n1, *n2, *n3;
9528 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9529 if (nlflag == 2 && peektoken())
9535 if (tok == TBACKGND) {
9536 if (n2->type == NPIPE) {
9537 n2->npipe.backgnd = 1;
9539 if (n2->type != NREDIR) {
9540 n3 = stalloc(sizeof(struct nredir));
9542 n3->nredir.redirect = NULL;
9545 n2->type = NBACKGND;
9551 n3 = stalloc(sizeof(struct nbinary));
9553 n3->nbinary.ch1 = n1;
9554 n3->nbinary.ch2 = n2;
9570 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9578 pungetc(); /* push back EOF on input */
9582 raise_error_unexpected_syntax(-1);
9592 union node *n1, *n2, *n3;
9600 } else if (t == TOR) {
9606 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9608 n3 = stalloc(sizeof(struct nbinary));
9610 n3->nbinary.ch1 = n1;
9611 n3->nbinary.ch2 = n2;
9619 union node *n1, *n2, *pipenode;
9620 struct nodelist *lp, *prev;
9624 TRACE(("pipeline: entered\n"));
9625 if (readtoken() == TNOT) {
9627 checkkwd = CHKKWD | CHKALIAS;
9630 n1 = parse_command();
9631 if (readtoken() == TPIPE) {
9632 pipenode = stalloc(sizeof(struct npipe));
9633 pipenode->type = NPIPE;
9634 pipenode->npipe.backgnd = 0;
9635 lp = stalloc(sizeof(struct nodelist));
9636 pipenode->npipe.cmdlist = lp;
9640 lp = stalloc(sizeof(struct nodelist));
9641 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9642 lp->n = parse_command();
9644 } while (readtoken() == TPIPE);
9650 n2 = stalloc(sizeof(struct nnot));
9663 n = stalloc(sizeof(struct narg));
9665 n->narg.next = NULL;
9666 n->narg.text = wordtext;
9667 n->narg.backquote = backquotelist;
9672 fixredir(union node *n, const char *text, int err)
9674 TRACE(("Fix redir %s %d\n", text, err));
9676 n->ndup.vname = NULL;
9678 if (isdigit(text[0]) && text[1] == '\0')
9679 n->ndup.dupfd = text[0] - '0';
9680 else if (LONE_DASH(text))
9684 raise_error_syntax("Bad fd number");
9685 n->ndup.vname = makename();
9690 * Returns true if the text contains nothing to expand (no dollar signs
9694 noexpand(char *text)
9700 while ((c = *p++) != '\0') {
9701 if (c == CTLQUOTEMARK)
9705 else if (SIT(c, BASESYNTAX) == CCTL)
9714 union node *n = redirnode;
9716 if (readtoken() != TWORD)
9717 raise_error_unexpected_syntax(-1);
9718 if (n->type == NHERE) {
9719 struct heredoc *here = heredoc;
9725 TRACE(("Here document %d\n", n->type));
9726 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9727 raise_error_syntax("Illegal eof marker for << redirection");
9728 rmescapes(wordtext);
9729 here->eofmark = wordtext;
9731 if (heredoclist == NULL)
9734 for (p = heredoclist; p->next; p = p->next);
9737 } else if (n->type == NTOFD || n->type == NFROMFD) {
9738 fixredir(n, wordtext, 0);
9740 n->nfile.fname = makename();
9747 union node *args, **app;
9748 union node *n = NULL;
9749 union node *vars, **vpp;
9750 union node **rpp, *redir;
9760 savecheckkwd = CHKALIAS;
9762 checkkwd = savecheckkwd;
9763 switch (readtoken()) {
9765 n = stalloc(sizeof(struct narg));
9767 n->narg.text = wordtext;
9768 n->narg.backquote = backquotelist;
9769 if (savecheckkwd && isassignment(wordtext)) {
9771 vpp = &n->narg.next;
9774 app = &n->narg.next;
9779 *rpp = n = redirnode;
9780 rpp = &n->nfile.next;
9781 parsefname(); /* read name of redirection file */
9784 if (args && app == &args->narg.next
9787 struct builtincmd *bcmd;
9790 /* We have a function */
9791 if (readtoken() != TRP)
9792 raise_error_unexpected_syntax(TRP);
9793 name = n->narg.text;
9795 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
9797 raise_error_syntax("Bad function name");
9800 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9801 n->narg.next = parse_command();
9814 n = stalloc(sizeof(struct ncmd));
9816 n->ncmd.args = args;
9817 n->ncmd.assign = vars;
9818 n->ncmd.redirect = redir;
9825 union node *n1, *n2;
9826 union node *ap, **app;
9827 union node *cp, **cpp;
9828 union node *redir, **rpp;
9835 switch (readtoken()) {
9837 raise_error_unexpected_syntax(-1);
9840 n1 = stalloc(sizeof(struct nif));
9842 n1->nif.test = list(0);
9843 if (readtoken() != TTHEN)
9844 raise_error_unexpected_syntax(TTHEN);
9845 n1->nif.ifpart = list(0);
9847 while (readtoken() == TELIF) {
9848 n2->nif.elsepart = stalloc(sizeof(struct nif));
9849 n2 = n2->nif.elsepart;
9851 n2->nif.test = list(0);
9852 if (readtoken() != TTHEN)
9853 raise_error_unexpected_syntax(TTHEN);
9854 n2->nif.ifpart = list(0);
9856 if (lasttoken == TELSE)
9857 n2->nif.elsepart = list(0);
9859 n2->nif.elsepart = NULL;
9867 n1 = stalloc(sizeof(struct nbinary));
9868 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
9869 n1->nbinary.ch1 = list(0);
9872 TRACE(("expecting DO got %s %s\n", tokname(got),
9873 got == TWORD ? wordtext : ""));
9874 raise_error_unexpected_syntax(TDO);
9876 n1->nbinary.ch2 = list(0);
9881 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9882 raise_error_syntax("Bad for loop variable");
9883 n1 = stalloc(sizeof(struct nfor));
9885 n1->nfor.var = wordtext;
9886 checkkwd = CHKKWD | CHKALIAS;
9887 if (readtoken() == TIN) {
9889 while (readtoken() == TWORD) {
9890 n2 = stalloc(sizeof(struct narg));
9892 n2->narg.text = wordtext;
9893 n2->narg.backquote = backquotelist;
9895 app = &n2->narg.next;
9899 if (lasttoken != TNL && lasttoken != TSEMI)
9900 raise_error_unexpected_syntax(-1);
9902 n2 = stalloc(sizeof(struct narg));
9904 n2->narg.text = (char *)dolatstr;
9905 n2->narg.backquote = NULL;
9906 n2->narg.next = NULL;
9909 * Newline or semicolon here is optional (but note
9910 * that the original Bourne shell only allowed NL).
9912 if (lasttoken != TNL && lasttoken != TSEMI)
9915 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9916 if (readtoken() != TDO)
9917 raise_error_unexpected_syntax(TDO);
9918 n1->nfor.body = list(0);
9922 n1 = stalloc(sizeof(struct ncase));
9924 if (readtoken() != TWORD)
9925 raise_error_unexpected_syntax(TWORD);
9926 n1->ncase.expr = n2 = stalloc(sizeof(struct narg));
9928 n2->narg.text = wordtext;
9929 n2->narg.backquote = backquotelist;
9930 n2->narg.next = NULL;
9932 checkkwd = CHKKWD | CHKALIAS;
9933 } while (readtoken() == TNL);
9934 if (lasttoken != TIN)
9935 raise_error_unexpected_syntax(TIN);
9936 cpp = &n1->ncase.cases;
9938 checkkwd = CHKNL | CHKKWD;
9940 while (t != TESAC) {
9941 if (lasttoken == TLP)
9943 *cpp = cp = stalloc(sizeof(struct nclist));
9945 app = &cp->nclist.pattern;
9947 *app = ap = stalloc(sizeof(struct narg));
9949 ap->narg.text = wordtext;
9950 ap->narg.backquote = backquotelist;
9951 if (readtoken() != TPIPE)
9953 app = &ap->narg.next;
9956 ap->narg.next = NULL;
9957 if (lasttoken != TRP)
9958 raise_error_unexpected_syntax(TRP);
9959 cp->nclist.body = list(2);
9961 cpp = &cp->nclist.next;
9963 checkkwd = CHKNL | CHKKWD;
9967 raise_error_unexpected_syntax(TENDCASE);
9974 n1 = stalloc(sizeof(struct nredir));
9975 n1->type = NSUBSHELL;
9976 n1->nredir.n = list(0);
9977 n1->nredir.redirect = NULL;
9990 if (readtoken() != t)
9991 raise_error_unexpected_syntax(t);
9994 /* Now check for redirection which may follow command */
9995 checkkwd = CHKKWD | CHKALIAS;
9997 while (readtoken() == TREDIR) {
9998 *rpp = n2 = redirnode;
9999 rpp = &n2->nfile.next;
10005 if (n1->type != NSUBSHELL) {
10006 n2 = stalloc(sizeof(struct nredir));
10011 n1->nredir.redirect = redir;
10017 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10018 * is not NULL, read a here document. In the latter case, eofmark is the
10019 * word which marks the end of the document and striptabs is true if
10020 * leading tabs should be stripped from the document. The argument firstc
10021 * is the first character of the input token or document.
10023 * Because C does not have internal subroutines, I have simulated them
10024 * using goto's to implement the subroutine linkage. The following macros
10025 * will run code that appears at the end of readtoken1.
10028 #define CHECKEND() {goto checkend; checkend_return:;}
10029 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10030 #define PARSESUB() {goto parsesub; parsesub_return:;}
10031 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10032 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10033 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10036 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10038 /* NB: syntax parameter fits into smallint */
10042 char line[EOFMARKLEN + 1];
10043 struct nodelist *bqlist;
10047 smallint prevsyntax; /* syntax before arithmetic */
10048 #if ENABLE_ASH_EXPAND_PRMT
10049 smallint pssyntax; /* we are expanding a prompt string */
10051 int varnest; /* levels of variables expansion */
10052 int arinest; /* levels of arithmetic expansion */
10053 int parenlevel; /* levels of parens in arithmetic */
10054 int dqvarnest; /* levels of variables expansion within double quotes */
10057 /* Avoid longjmp clobbering */
10063 (void) &parenlevel;
10066 (void) &prevsyntax;
10069 startlinno = plinno;
10074 #if ENABLE_ASH_EXPAND_PRMT
10075 pssyntax = (syntax == PSSYNTAX);
10079 dblquote = (syntax == DQSYNTAX);
10085 STARTSTACKSTR(out);
10086 loop: { /* for each line, until end of word */
10087 CHECKEND(); /* set c to PEOF if at end of here document */
10088 for (;;) { /* until end of line or end of word */
10089 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10090 switch (SIT(c, syntax)) {
10091 case CNL: /* '\n' */
10092 if (syntax == BASESYNTAX)
10093 goto endword; /* exit outer loop */
10099 goto loop; /* continue outer loop */
10104 if (eofmark == NULL || dblquote)
10105 USTPUTC(CTLESC, out);
10108 case CBACK: /* backslash */
10111 USTPUTC(CTLESC, out);
10112 USTPUTC('\\', out);
10114 } else if (c == '\n') {
10118 #if ENABLE_ASH_EXPAND_PRMT
10119 if (c == '$' && pssyntax) {
10120 USTPUTC(CTLESC, out);
10121 USTPUTC('\\', out);
10125 c != '\\' && c != '`' &&
10130 USTPUTC(CTLESC, out);
10131 USTPUTC('\\', out);
10133 if (SIT(c, SQSYNTAX) == CCTL)
10134 USTPUTC(CTLESC, out);
10142 if (eofmark == NULL) {
10143 USTPUTC(CTLQUOTEMARK, out);
10151 if (eofmark != NULL && arinest == 0
10156 if (dqvarnest == 0) {
10157 syntax = BASESYNTAX;
10164 case CVAR: /* '$' */
10165 PARSESUB(); /* parse substitution */
10167 case CENDVAR: /* '}' */
10170 if (dqvarnest > 0) {
10173 USTPUTC(CTLENDVAR, out);
10178 #if ENABLE_ASH_MATH_SUPPORT
10179 case CLP: /* '(' in arithmetic */
10183 case CRP: /* ')' in arithmetic */
10184 if (parenlevel > 0) {
10188 if (pgetc() == ')') {
10189 if (--arinest == 0) {
10190 USTPUTC(CTLENDARI, out);
10191 syntax = prevsyntax;
10192 dblquote = (syntax == DQSYNTAX);
10197 * unbalanced parens
10198 * (don't 2nd guess - no error)
10206 case CBQUOTE: /* '`' */
10210 goto endword; /* exit outer loop */
10215 goto endword; /* exit outer loop */
10216 #if ENABLE_ASH_ALIAS
10226 #if ENABLE_ASH_MATH_SUPPORT
10227 if (syntax == ARISYNTAX)
10228 raise_error_syntax("Missing '))'");
10230 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10231 raise_error_syntax("Unterminated quoted string");
10232 if (varnest != 0) {
10233 startlinno = plinno;
10235 raise_error_syntax("Missing '}'");
10237 USTPUTC('\0', out);
10238 len = out - (char *)stackblock();
10239 out = stackblock();
10240 if (eofmark == NULL) {
10241 if ((c == '>' || c == '<')
10244 && (*out == '\0' || isdigit(*out))) {
10246 return lasttoken = TREDIR;
10251 quoteflag = quotef;
10252 backquotelist = bqlist;
10253 grabstackblock(len);
10257 /* end of readtoken routine */
10260 * Check to see whether we are at the end of the here document. When this
10261 * is called, c is set to the first character of the next input line. If
10262 * we are at the end of the here document, this routine sets the c to PEOF.
10266 #if ENABLE_ASH_ALIAS
10272 while (c == '\t') {
10276 if (c == *eofmark) {
10277 if (pfgets(line, sizeof(line)) != NULL) {
10281 for (q = eofmark + 1; *q && *p == *q; p++, q++);
10282 if (*p == '\n' && *q == '\0') {
10285 needprompt = doprompt;
10287 pushstring(line, NULL);
10292 goto checkend_return;
10296 * Parse a redirection operator. The variable "out" points to a string
10297 * specifying the fd to be redirected. The variable "c" contains the
10298 * first character of the redirection operator.
10304 np = stalloc(sizeof(struct nfile));
10309 np->type = NAPPEND;
10311 np->type = NCLOBBER;
10318 } else { /* c == '<' */
10323 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10324 np = stalloc(sizeof(struct nhere));
10328 heredoc = stalloc(sizeof(struct heredoc));
10329 heredoc->here = np;
10332 heredoc->striptabs = 1;
10334 heredoc->striptabs = 0;
10340 np->type = NFROMFD;
10344 np->type = NFROMTO;
10354 np->nfile.fd = fd - '0';
10356 goto parseredir_return;
10360 * Parse a substitution. At this point, we have read the dollar sign
10361 * and nothing else.
10364 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
10365 * (assuming ascii char codes, as the original implementation did) */
10366 #define is_special(c) \
10367 ((((unsigned int)c) - 33 < 32) \
10368 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
10374 static const char types[] ALIGN1 = "}-+?=";
10378 c <= PEOA_OR_PEOF ||
10379 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10383 } else if (c == '(') { /* $(command) or $((arith)) */
10384 if (pgetc() == '(') {
10385 #if ENABLE_ASH_MATH_SUPPORT
10388 raise_error_syntax("We unsupport $((arith))");
10395 USTPUTC(CTLVAR, out);
10396 typeloc = out - (char *)stackblock();
10397 USTPUTC(VSNORMAL, out);
10398 subtype = VSNORMAL;
10406 subtype = VSLENGTH;
10410 if (c > PEOA_OR_PEOF && is_name(c)) {
10414 } while (c > PEOA_OR_PEOF && is_in_name(c));
10415 } else if (isdigit(c)) {
10419 } while (isdigit(c));
10420 } else if (is_special(c)) {
10424 badsub: raise_error_syntax("Bad substitution");
10428 if (subtype == 0) {
10435 p = strchr(types, c);
10438 subtype = p - types + VSNORMAL;
10444 subtype = c == '#' ? VSTRIMLEFT :
10457 if (dblquote || arinest)
10459 *((char *)stackblock() + typeloc) = subtype | flags;
10460 if (subtype != VSNORMAL) {
10462 if (dblquote || arinest) {
10467 goto parsesub_return;
10471 * Called to parse command substitutions. Newstyle is set if the command
10472 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10473 * list of commands (passed by reference), and savelen is the number of
10474 * characters on the top of the stack which must be preserved.
10477 struct nodelist **nlpp;
10480 char *volatile str;
10481 struct jmploc jmploc;
10482 struct jmploc *volatile savehandler;
10484 smallint saveprompt = 0;
10487 (void) &saveprompt;
10489 savepbq = parsebackquote;
10490 if (setjmp(jmploc.loc)) {
10492 parsebackquote = 0;
10493 exception_handler = savehandler;
10494 longjmp(exception_handler->loc, 1);
10498 savelen = out - (char *)stackblock();
10500 str = ckmalloc(savelen);
10501 memcpy(str, stackblock(), savelen);
10503 savehandler = exception_handler;
10504 exception_handler = &jmploc;
10507 /* We must read until the closing backquote, giving special
10508 treatment to some slashes, and then push the string and
10509 reread it as input, interpreting it normally. */
10516 STARTSTACKSTR(pout);
10533 * If eating a newline, avoid putting
10534 * the newline into the new character
10535 * stream (via the STPUTC after the
10540 if (pc != '\\' && pc != '`' && pc != '$'
10541 && (!dblquote || pc != '"'))
10542 STPUTC('\\', pout);
10543 if (pc > PEOA_OR_PEOF) {
10549 #if ENABLE_ASH_ALIAS
10552 startlinno = plinno;
10553 raise_error_syntax("EOF in backquote substitution");
10557 needprompt = doprompt;
10566 STPUTC('\0', pout);
10567 psavelen = pout - (char *)stackblock();
10568 if (psavelen > 0) {
10569 pstr = grabstackstr(pout);
10570 setinputstring(pstr);
10575 nlpp = &(*nlpp)->next;
10576 *nlpp = stalloc(sizeof(**nlpp));
10577 (*nlpp)->next = NULL;
10578 parsebackquote = oldstyle;
10581 saveprompt = doprompt;
10588 doprompt = saveprompt;
10589 else if (readtoken() != TRP)
10590 raise_error_unexpected_syntax(TRP);
10595 * Start reading from old file again, ignoring any pushed back
10596 * tokens left from the backquote parsing
10601 while (stackblocksize() <= savelen)
10603 STARTSTACKSTR(out);
10605 memcpy(out, str, savelen);
10606 STADJUST(savelen, out);
10612 parsebackquote = savepbq;
10613 exception_handler = savehandler;
10614 if (arinest || dblquote)
10615 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10617 USTPUTC(CTLBACKQ, out);
10619 goto parsebackq_oldreturn;
10620 goto parsebackq_newreturn;
10623 #if ENABLE_ASH_MATH_SUPPORT
10625 * Parse an arithmetic expansion (indicate start of one and set state)
10628 if (++arinest == 1) {
10629 prevsyntax = syntax;
10630 syntax = ARISYNTAX;
10631 USTPUTC(CTLARI, out);
10638 * we collapse embedded arithmetic expansion to
10639 * parenthesis, which should be equivalent
10643 goto parsearith_return;
10647 } /* end of readtoken */
10650 * Read the next input token.
10651 * If the token is a word, we set backquotelist to the list of cmds in
10652 * backquotes. We set quoteflag to true if any part of the word was
10654 * If the token is TREDIR, then we set redirnode to a structure containing
10656 * In all cases, the variable startlinno is set to the number of the line
10657 * on which the token starts.
10659 * [Change comment: here documents and internal procedures]
10660 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10661 * word parsing code into a separate routine. In this case, readtoken
10662 * doesn't need to have any internal procedures, but parseword does.
10663 * We could also make parseoperator in essence the main routine, and
10664 * have parseword (readtoken1?) handle both words and redirection.]
10666 #define NEW_xxreadtoken
10667 #ifdef NEW_xxreadtoken
10668 /* singles must be first! */
10669 static const char xxreadtoken_chars[7] ALIGN1 = {
10670 '\n', '(', ')', '&', '|', ';', 0
10673 static const char xxreadtoken_tokens[] ALIGN1 = {
10674 TNL, TLP, TRP, /* only single occurrence allowed */
10675 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10676 TEOF, /* corresponds to trailing nul */
10677 TAND, TOR, TENDCASE /* if double occurrence */
10680 #define xxreadtoken_doubles \
10681 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10682 #define xxreadtoken_singles \
10683 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10697 startlinno = plinno;
10698 for (;;) { /* until token or start of word found */
10701 if ((c != ' ') && (c != '\t')
10702 #if ENABLE_ASH_ALIAS
10707 while ((c = pgetc()) != '\n' && c != PEOF);
10709 } else if (c == '\\') {
10710 if (pgetc() != '\n') {
10714 startlinno = ++plinno;
10719 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10724 needprompt = doprompt;
10727 p = strchr(xxreadtoken_chars, c);
10730 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10733 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10734 if (pgetc() == *p) { /* double occurrence? */
10735 p += xxreadtoken_doubles + 1;
10741 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10747 #define RETURN(token) return lasttoken = token
10760 startlinno = plinno;
10761 for (;;) { /* until token or start of word found */
10764 case ' ': case '\t':
10765 #if ENABLE_ASH_ALIAS
10770 while ((c = pgetc()) != '\n' && c != PEOF);
10774 if (pgetc() == '\n') {
10775 startlinno = ++plinno;
10784 needprompt = doprompt;
10789 if (pgetc() == '&')
10794 if (pgetc() == '|')
10799 if (pgetc() == ';')
10812 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10815 #endif /* NEW_xxreadtoken */
10822 smallint alreadyseen = tokpushback;
10825 #if ENABLE_ASH_ALIAS
10834 if (checkkwd & CHKNL) {
10841 if (t != TWORD || quoteflag) {
10846 * check for keywords
10848 if (checkkwd & CHKKWD) {
10849 const char *const *pp;
10851 pp = findkwd(wordtext);
10853 lasttoken = t = pp - tokname_array;
10854 TRACE(("keyword %s recognized\n", tokname(t)));
10859 if (checkkwd & CHKALIAS) {
10860 #if ENABLE_ASH_ALIAS
10862 ap = lookupalias(wordtext, 1);
10865 pushstring(ap->val, ap);
10875 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
10877 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
10889 return tokname_array[t][0];
10893 * Read and parse a command. Returns NEOF on end of file. (NULL is a
10894 * valid parse tree indicating a blank line.)
10896 static union node *
10897 parsecmd(int interact)
10902 doprompt = interact;
10904 setprompt(doprompt);
10916 * Input any here documents.
10921 struct heredoc *here;
10924 here = heredoclist;
10931 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10932 here->eofmark, here->striptabs);
10933 n = stalloc(sizeof(struct narg));
10934 n->narg.type = NARG;
10935 n->narg.next = NULL;
10936 n->narg.text = wordtext;
10937 n->narg.backquote = backquotelist;
10938 here->here->nhere.doc = n;
10945 * called by editline -- any expansions to the prompt should be added here.
10947 #if ENABLE_ASH_EXPAND_PRMT
10948 static const char *
10949 expandstr(const char *ps)
10953 /* XXX Fix (char *) cast. */
10954 setinputstring((char *)ps);
10955 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
10958 n.narg.type = NARG;
10959 n.narg.next = NULL;
10960 n.narg.text = wordtext;
10961 n.narg.backquote = backquotelist;
10963 expandarg(&n, NULL, 0);
10964 return stackblock();
10969 * Execute a command or commands contained in a string.
10972 evalstring(char *s, int mask)
10975 struct stackmark smark;
10979 setstackmark(&smark);
10982 while ((n = parsecmd(0)) != NEOF) {
10984 popstackmark(&smark);
10997 * The eval command.
11000 evalcmd(int argc, char **argv)
11009 STARTSTACKSTR(concat);
11012 concat = stack_putstr(p, concat);
11016 STPUTC(' ', concat);
11018 STPUTC('\0', concat);
11019 p = grabstackstr(concat);
11021 evalstring(p, ~SKIPEVAL);
11028 * Read and execute commands. "Top" is nonzero for the top level command
11029 * loop; it turns on prompting if the shell is interactive.
11035 struct stackmark smark;
11039 TRACE(("cmdloop(%d) called\n", top));
11043 setstackmark(&smark);
11046 showjobs(stderr, SHOW_CHANGED);
11049 if (iflag && top) {
11051 #if ENABLE_ASH_MAIL
11055 n = parsecmd(inter);
11056 /* showtree(n); DEBUG */
11058 if (!top || numeof >= 50)
11060 if (!stoppedjobs()) {
11063 out2str("\nUse \"exit\" to leave shell.\n");
11066 } else if (nflag == 0) {
11067 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11072 popstackmark(&smark);
11077 return skip & SKIPEVAL;
11084 * Take commands from a file. To be compatible we should do a path
11085 * search for the file, which is necessary to find sub-commands.
11088 find_dot_file(char *name)
11091 const char *path = pathval();
11094 /* don't try this for absolute or relative paths */
11095 if (strchr(name, '/'))
11098 while ((fullname = padvance(&path, name)) != NULL) {
11099 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11101 * Don't bother freeing here, since it will
11102 * be freed by the caller.
11106 stunalloc(fullname);
11109 /* not found in the PATH */
11110 ash_msg_and_raise_error("%s: not found", name);
11115 dotcmd(int argc, char **argv)
11117 struct strlist *sp;
11118 volatile struct shparam saveparam;
11121 for (sp = cmdenviron; sp; sp = sp->next)
11122 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11124 if (argc >= 2) { /* That's what SVR2 does */
11127 fullname = find_dot_file(argv[1]);
11130 saveparam = shellparam;
11131 shellparam.malloced = 0;
11132 shellparam.nparam = argc - 2;
11133 shellparam.p = argv + 2;
11136 setinputfile(fullname, INPUT_PUSH_FILE);
11137 commandname = fullname;
11142 freeparam(&shellparam);
11143 shellparam = saveparam;
11145 status = exitstatus;
11151 exitcmd(int argc, char **argv)
11156 exitstatus = number(argv[1]);
11157 raise_exception(EXEXIT);
11161 #if ENABLE_ASH_BUILTIN_ECHO
11163 echocmd(int argc, char **argv)
11165 return echo_main(argc, argv);
11169 #if ENABLE_ASH_BUILTIN_TEST
11171 testcmd(int argc, char **argv)
11173 return test_main(argc, argv);
11178 * Read a file containing shell functions.
11181 readcmdfile(char *name)
11183 setinputfile(name, INPUT_PUSH_FILE);
11189 /* ============ find_command inplementation */
11192 * Resolve a command name. If you change this routine, you may have to
11193 * change the shellexec routine as well.
11196 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11198 struct tblentry *cmdp;
11205 struct builtincmd *bcmd;
11207 /* If name contains a slash, don't use PATH or hash table */
11208 if (strchr(name, '/') != NULL) {
11209 entry->u.index = -1;
11210 if (act & DO_ABS) {
11211 while (stat(name, &statb) < 0) {
11213 if (errno == EINTR)
11216 entry->cmdtype = CMDUNKNOWN;
11220 entry->cmdtype = CMDNORMAL;
11224 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11226 updatetbl = (path == pathval());
11229 if (strstr(path, "%builtin") != NULL)
11230 act |= DO_ALTBLTIN;
11233 /* If name is in the table, check answer will be ok */
11234 cmdp = cmdlookup(name, 0);
11235 if (cmdp != NULL) {
11238 switch (cmdp->cmdtype) {
11256 } else if (cmdp->rehash == 0)
11257 /* if not invalidated by cd, we're done */
11261 /* If %builtin not in path, check for builtin next */
11262 bcmd = find_builtin(name);
11264 if (IS_BUILTIN_REGULAR(bcmd))
11265 goto builtin_success;
11266 if (act & DO_ALTPATH) {
11267 if (!(act & DO_ALTBLTIN))
11268 goto builtin_success;
11269 } else if (builtinloc <= 0) {
11270 goto builtin_success;
11274 #if ENABLE_FEATURE_SH_STANDALONE
11275 if (find_applet_by_name(name) >= 0) {
11276 entry->cmdtype = CMDNORMAL;
11277 entry->u.index = -1;
11282 /* We have to search path. */
11283 prev = -1; /* where to start */
11284 if (cmdp && cmdp->rehash) { /* doing a rehash */
11285 if (cmdp->cmdtype == CMDBUILTIN)
11288 prev = cmdp->param.index;
11294 while ((fullname = padvance(&path, name)) != NULL) {
11295 stunalloc(fullname);
11296 /* NB: code below will still use fullname
11297 * despite it being "unallocated" */
11300 if (prefix(pathopt, "builtin")) {
11302 goto builtin_success;
11304 } else if (!(act & DO_NOFUNC)
11305 && prefix(pathopt, "func")) {
11306 /* handled below */
11308 /* ignore unimplemented options */
11312 /* if rehash, don't redo absolute path names */
11313 if (fullname[0] == '/' && idx <= prev) {
11316 TRACE(("searchexec \"%s\": no change\n", name));
11319 while (stat(fullname, &statb) < 0) {
11321 if (errno == EINTR)
11324 if (errno != ENOENT && errno != ENOTDIR)
11328 e = EACCES; /* if we fail, this will be the error */
11329 if (!S_ISREG(statb.st_mode))
11331 if (pathopt) { /* this is a %func directory */
11332 stalloc(strlen(fullname) + 1);
11333 /* NB: stalloc will return space pointed by fullname
11334 * (because we don't have any intervening allocations
11335 * between stunalloc above and this stalloc) */
11336 readcmdfile(fullname);
11337 cmdp = cmdlookup(name, 0);
11338 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
11339 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
11340 stunalloc(fullname);
11343 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
11345 entry->cmdtype = CMDNORMAL;
11346 entry->u.index = idx;
11350 cmdp = cmdlookup(name, 1);
11351 cmdp->cmdtype = CMDNORMAL;
11352 cmdp->param.index = idx;
11357 /* We failed. If there was an entry for this command, delete it */
11358 if (cmdp && updatetbl)
11359 delete_cmd_entry();
11361 ash_msg("%s: %s", name, errmsg(e, "not found"));
11362 entry->cmdtype = CMDUNKNOWN;
11367 entry->cmdtype = CMDBUILTIN;
11368 entry->u.cmd = bcmd;
11372 cmdp = cmdlookup(name, 1);
11373 cmdp->cmdtype = CMDBUILTIN;
11374 cmdp->param.cmd = bcmd;
11378 entry->cmdtype = cmdp->cmdtype;
11379 entry->u = cmdp->param;
11383 /* ============ trap.c */
11386 * The trap builtin.
11389 trapcmd(int argc, char **argv)
11398 for (signo = 0; signo < NSIG; signo++) {
11399 if (trap[signo] != NULL) {
11402 sn = get_signame(signo);
11403 out1fmt("trap -- %s %s\n",
11404 single_quote(trap[signo]), sn);
11414 signo = get_signum(*ap);
11416 ash_msg_and_raise_error("%s: bad trap", *ap);
11419 if (LONE_DASH(action))
11422 action = ckstrdup(action);
11425 trap[signo] = action;
11435 /* ============ Builtins */
11437 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
11439 * Lists available builtins
11442 helpcmd(int argc, char **argv)
11446 out1fmt("\nBuilt-in commands:\n-------------------\n");
11447 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
11448 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11449 builtintab[i].name + 1);
11455 #if ENABLE_FEATURE_SH_STANDALONE
11457 const char *a = applet_names;
11459 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
11464 a += strlen(a) + 1;
11469 return EXIT_SUCCESS;
11471 #endif /* FEATURE_SH_EXTRA_QUIET */
11474 * The export and readonly commands.
11477 exportcmd(int argc, char **argv)
11483 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
11485 if (nextopt("p") != 'p') {
11490 p = strchr(name, '=');
11494 vp = *findvar(hashvar(name), name);
11500 setvar(name, p, flag);
11501 } while ((name = *++aptr) != NULL);
11505 showvars(argv[0], flag, 0);
11510 * Delete a function if it exists.
11513 unsetfunc(const char *name)
11515 struct tblentry *cmdp;
11517 cmdp = cmdlookup(name, 0);
11518 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
11519 delete_cmd_entry();
11523 * The unset builtin command. We unset the function before we unset the
11524 * variable to allow a function to be unset when there is a readonly variable
11525 * with the same name.
11528 unsetcmd(int argc, char **argv)
11535 while ((i = nextopt("vf")) != '\0') {
11539 for (ap = argptr; *ap; ap++) {
11555 #include <sys/times.h>
11557 static const unsigned char timescmd_str[] ALIGN1 = {
11558 ' ', offsetof(struct tms, tms_utime),
11559 '\n', offsetof(struct tms, tms_stime),
11560 ' ', offsetof(struct tms, tms_cutime),
11561 '\n', offsetof(struct tms, tms_cstime),
11566 timescmd(int ac, char **av)
11568 long clk_tck, s, t;
11569 const unsigned char *p;
11572 clk_tck = sysconf(_SC_CLK_TCK);
11577 t = *(clock_t *)(((char *) &buf) + p[1]);
11579 out1fmt("%ldm%ld.%.3lds%c",
11581 ((t - s * clk_tck) * 1000) / clk_tck,
11583 } while (*(p += 2));
11588 #if ENABLE_ASH_MATH_SUPPORT
11590 dash_arith(const char *s)
11596 result = arith(s, &errcode);
11599 ash_msg_and_raise_error("exponent less than 0");
11601 ash_msg_and_raise_error("divide by zero");
11603 ash_msg_and_raise_error("expression recursion loop detected");
11604 raise_error_syntax(s);
11612 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
11613 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
11615 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
11618 letcmd(int argc, char **argv)
11625 ash_msg_and_raise_error("expression expected");
11626 for (ap = argv + 1; *ap; ap++) {
11627 i = dash_arith(*ap);
11632 #endif /* ASH_MATH_SUPPORT */
11635 /* ============ miscbltin.c
11637 * Miscellaneous builtins.
11642 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
11643 typedef enum __rlimit_resource rlim_t;
11647 * The read builtin. The -e option causes backslashes to escape the
11648 * following character.
11650 * This uses unbuffered input, which may be avoidable in some cases.
11653 readcmd(int argc, char **argv)
11665 #if ENABLE_ASH_READ_NCHARS
11669 struct termios tty, old_tty;
11671 #if ENABLE_ASH_READ_TIMEOUT
11675 ts.tv_sec = ts.tv_usec = 0;
11680 #if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT
11681 while ((i = nextopt("p:rt:n:s")) != '\0')
11682 #elif ENABLE_ASH_READ_NCHARS
11683 while ((i = nextopt("p:rn:s")) != '\0')
11684 #elif ENABLE_ASH_READ_TIMEOUT
11685 while ((i = nextopt("p:rt:")) != '\0')
11687 while ((i = nextopt("p:r")) != '\0')
11692 prompt = optionarg;
11694 #if ENABLE_ASH_READ_NCHARS
11696 nchars = bb_strtou(optionarg, NULL, 10);
11697 if (nchars < 0 || errno)
11698 ash_msg_and_raise_error("invalid count");
11699 n_flag = nchars; /* just a flag "nchars is nonzero" */
11705 #if ENABLE_ASH_READ_TIMEOUT
11707 ts.tv_sec = bb_strtou(optionarg, &p, 10);
11709 /* EINVAL means number is ok, but not terminated by NUL */
11710 if (*p == '.' && errno == EINVAL) {
11714 ts.tv_usec = bb_strtou(p, &p2, 10);
11716 ash_msg_and_raise_error("invalid timeout");
11718 /* normalize to usec */
11720 ash_msg_and_raise_error("invalid timeout");
11721 while (scale++ < 6)
11724 } else if (ts.tv_sec < 0 || errno) {
11725 ash_msg_and_raise_error("invalid timeout");
11727 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
11728 ash_msg_and_raise_error("invalid timeout");
11739 if (prompt && isatty(0)) {
11744 ash_msg_and_raise_error("arg count");
11745 ifs = bltinlookup("IFS");
11748 #if ENABLE_ASH_READ_NCHARS
11749 if (n_flag || silent) {
11750 if (tcgetattr(0, &tty) != 0) {
11757 tty.c_lflag &= ~ICANON;
11758 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
11761 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
11763 tcsetattr(0, TCSANOW, &tty);
11767 #if ENABLE_ASH_READ_TIMEOUT
11768 if (ts.tv_sec || ts.tv_usec) {
11772 /* poll-based wait produces bigger code, using select */
11773 i = select(1, &set, NULL, NULL, &ts);
11774 if (!i) { /* timed out! */
11775 #if ENABLE_ASH_READ_NCHARS
11777 tcsetattr(0, TCSANOW, &old_tty);
11788 if (read(0, &c, 1) != 1) {
11800 if (!rflag && c == '\\') {
11806 if (startword && *ifs == ' ' && strchr(ifs, c)) {
11810 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
11812 setvar(*ap, stackblock(), 0);
11821 /* end of do {} while: */
11822 #if ENABLE_ASH_READ_NCHARS
11823 while (!n_flag || --nchars);
11828 #if ENABLE_ASH_READ_NCHARS
11829 if (n_flag || silent)
11830 tcsetattr(0, TCSANOW, &old_tty);
11834 /* Remove trailing blanks */
11835 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
11837 setvar(*ap, stackblock(), 0);
11838 while (*++ap != NULL)
11839 setvar(*ap, nullstr, 0);
11844 umaskcmd(int argc, char **argv)
11846 static const char permuser[3] ALIGN1 = "ugo";
11847 static const char permmode[3] ALIGN1 = "rwx";
11848 static const short permmask[] ALIGN2 = {
11849 S_IRUSR, S_IWUSR, S_IXUSR,
11850 S_IRGRP, S_IWGRP, S_IXGRP,
11851 S_IROTH, S_IWOTH, S_IXOTH
11857 int symbolic_mode = 0;
11859 while (nextopt("S") != '\0') {
11870 if (symbolic_mode) {
11874 for (i = 0; i < 3; i++) {
11877 *p++ = permuser[i];
11879 for (j = 0; j < 3; j++) {
11880 if ((mask & permmask[3 * i + j]) == 0) {
11881 *p++ = permmode[j];
11889 out1fmt("%.4o\n", mask);
11892 if (isdigit((unsigned char) *ap)) {
11895 if (*ap >= '8' || *ap < '0')
11896 ash_msg_and_raise_error(illnum, argv[1]);
11897 mask = (mask << 3) + (*ap - '0');
11898 } while (*++ap != '\0');
11901 mask = ~mask & 0777;
11902 if (!bb_parse_mode(ap, &mask)) {
11903 ash_msg_and_raise_error("illegal mode: %s", ap);
11905 umask(~mask & 0777);
11914 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
11915 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
11916 * ash by J.T. Conklin.
11922 uint8_t cmd; /* RLIMIT_xxx fit into it */
11923 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
11927 static const struct limits limits_tbl[] = {
11929 { RLIMIT_CPU, 0, 't' },
11931 #ifdef RLIMIT_FSIZE
11932 { RLIMIT_FSIZE, 9, 'f' },
11935 { RLIMIT_DATA, 10, 'd' },
11937 #ifdef RLIMIT_STACK
11938 { RLIMIT_STACK, 10, 's' },
11941 { RLIMIT_CORE, 9, 'c' },
11944 { RLIMIT_RSS, 10, 'm' },
11946 #ifdef RLIMIT_MEMLOCK
11947 { RLIMIT_MEMLOCK, 10, 'l' },
11949 #ifdef RLIMIT_NPROC
11950 { RLIMIT_NPROC, 0, 'p' },
11952 #ifdef RLIMIT_NOFILE
11953 { RLIMIT_NOFILE, 0, 'n' },
11956 { RLIMIT_AS, 10, 'v' },
11958 #ifdef RLIMIT_LOCKS
11959 { RLIMIT_LOCKS, 0, 'w' },
11962 static const char limits_name[] =
11964 "time(seconds)" "\0"
11966 #ifdef RLIMIT_FSIZE
11967 "file(blocks)" "\0"
11972 #ifdef RLIMIT_STACK
11976 "coredump(blocks)" "\0"
11981 #ifdef RLIMIT_MEMLOCK
11982 "locked memory(kb)" "\0"
11984 #ifdef RLIMIT_NPROC
11987 #ifdef RLIMIT_NOFILE
11993 #ifdef RLIMIT_LOCKS
11998 enum limtype { SOFT = 0x1, HARD = 0x2 };
12001 printlim(enum limtype how, const struct rlimit *limit,
12002 const struct limits *l)
12006 val = limit->rlim_max;
12008 val = limit->rlim_cur;
12010 if (val == RLIM_INFINITY)
12011 out1fmt("unlimited\n");
12013 val >>= l->factor_shift;
12014 out1fmt("%lld\n", (long long) val);
12019 ulimitcmd(int argc, char **argv)
12023 enum limtype how = SOFT | HARD;
12024 const struct limits *l;
12027 struct rlimit limit;
12030 while ((optc = nextopt("HSa"
12034 #ifdef RLIMIT_FSIZE
12040 #ifdef RLIMIT_STACK
12049 #ifdef RLIMIT_MEMLOCK
12052 #ifdef RLIMIT_NPROC
12055 #ifdef RLIMIT_NOFILE
12061 #ifdef RLIMIT_LOCKS
12079 for (l = limits_tbl; l->option != what; l++)
12082 set = *argptr ? 1 : 0;
12086 if (all || argptr[1])
12087 ash_msg_and_raise_error("too many arguments");
12088 if (strncmp(p, "unlimited\n", 9) == 0)
12089 val = RLIM_INFINITY;
12093 while ((c = *p++) >= '0' && c <= '9') {
12094 val = (val * 10) + (long)(c - '0');
12095 if (val < (rlim_t) 0)
12099 ash_msg_and_raise_error("bad number");
12100 val <<= l->factor_shift;
12104 const char *lname = limits_name;
12105 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12106 getrlimit(l->cmd, &limit);
12107 out1fmt("%-20s ", lname);
12108 lname += strlen(lname) + 1;
12109 printlim(how, &limit, l);
12114 getrlimit(l->cmd, &limit);
12117 limit.rlim_max = val;
12119 limit.rlim_cur = val;
12120 if (setrlimit(l->cmd, &limit) < 0)
12121 ash_msg_and_raise_error("error setting limit (%m)");
12123 printlim(how, &limit, l);
12129 /* ============ Math support */
12131 #if ENABLE_ASH_MATH_SUPPORT
12133 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12135 Permission is hereby granted, free of charge, to any person obtaining
12136 a copy of this software and associated documentation files (the
12137 "Software"), to deal in the Software without restriction, including
12138 without limitation the rights to use, copy, modify, merge, publish,
12139 distribute, sublicense, and/or sell copies of the Software, and to
12140 permit persons to whom the Software is furnished to do so, subject to
12141 the following conditions:
12143 The above copyright notice and this permission notice shall be
12144 included in all copies or substantial portions of the Software.
12146 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12147 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12148 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12149 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12150 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12151 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12152 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12155 /* This is my infix parser/evaluator. It is optimized for size, intended
12156 * as a replacement for yacc-based parsers. However, it may well be faster
12157 * than a comparable parser written in yacc. The supported operators are
12158 * listed in #defines below. Parens, order of operations, and error handling
12159 * are supported. This code is thread safe. The exact expression format should
12160 * be that which POSIX specifies for shells. */
12162 /* The code uses a simple two-stack algorithm. See
12163 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12164 * for a detailed explanation of the infix-to-postfix algorithm on which
12165 * this is based (this code differs in that it applies operators immediately
12166 * to the stack instead of adding them to a queue to end up with an
12169 /* To use the routine, call it with an expression string and error return
12173 * Aug 24, 2001 Manuel Novoa III
12175 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12177 * 1) In arith_apply():
12178 * a) Cached values of *numptr and &(numptr[-1]).
12179 * b) Removed redundant test for zero denominator.
12182 * a) Eliminated redundant code for processing operator tokens by moving
12183 * to a table-based implementation. Also folded handling of parens
12185 * b) Combined all 3 loops which called arith_apply to reduce generated
12186 * code size at the cost of speed.
12188 * 3) The following expressions were treated as valid by the original code:
12189 * 1() , 0! , 1 ( *3 ) .
12190 * These bugs have been fixed by internally enclosing the expression in
12191 * parens and then checking that all binary ops and right parens are
12192 * preceded by a valid expression (NUM_TOKEN).
12194 * Note: It may be desirable to replace Aaron's test for whitespace with
12195 * ctype's isspace() if it is used by another busybox applet or if additional
12196 * whitespace chars should be considered. Look below the "#include"s for a
12197 * precompiler test.
12201 * Aug 26, 2001 Manuel Novoa III
12203 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12205 * Merge in Aaron's comments previously posted to the busybox list,
12206 * modified slightly to take account of my changes to the code.
12211 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12213 * - allow access to variable,
12214 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12215 * - realize assign syntax (VAR=expr, +=, *= etc)
12216 * - realize exponentiation (** operator)
12217 * - realize comma separated - expr, expr
12218 * - realise ++expr --expr expr++ expr--
12219 * - realise expr ? expr : expr (but, second expr calculate always)
12220 * - allow hexadecimal and octal numbers
12221 * - was restored loses XOR operator
12222 * - remove one goto label, added three ;-)
12223 * - protect $((num num)) as true zero expr (Manuel`s error)
12224 * - always use special isspace(), see comment from bash ;-)
12227 #define arith_isspace(arithval) \
12228 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12230 typedef unsigned char operator;
12232 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12233 * precedence, and 3 high bits are an ID unique across operators of that
12234 * precedence. The ID portion is so that multiple operators can have the
12235 * same precedence, ensuring that the leftmost one is evaluated first.
12236 * Consider * and /. */
12238 #define tok_decl(prec,id) (((id)<<5)|(prec))
12239 #define PREC(op) ((op) & 0x1F)
12241 #define TOK_LPAREN tok_decl(0,0)
12243 #define TOK_COMMA tok_decl(1,0)
12245 #define TOK_ASSIGN tok_decl(2,0)
12246 #define TOK_AND_ASSIGN tok_decl(2,1)
12247 #define TOK_OR_ASSIGN tok_decl(2,2)
12248 #define TOK_XOR_ASSIGN tok_decl(2,3)
12249 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12250 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12251 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12252 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12254 #define TOK_MUL_ASSIGN tok_decl(3,0)
12255 #define TOK_DIV_ASSIGN tok_decl(3,1)
12256 #define TOK_REM_ASSIGN tok_decl(3,2)
12258 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12259 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12261 /* conditional is right associativity too */
12262 #define TOK_CONDITIONAL tok_decl(4,0)
12263 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12265 #define TOK_OR tok_decl(5,0)
12267 #define TOK_AND tok_decl(6,0)
12269 #define TOK_BOR tok_decl(7,0)
12271 #define TOK_BXOR tok_decl(8,0)
12273 #define TOK_BAND tok_decl(9,0)
12275 #define TOK_EQ tok_decl(10,0)
12276 #define TOK_NE tok_decl(10,1)
12278 #define TOK_LT tok_decl(11,0)
12279 #define TOK_GT tok_decl(11,1)
12280 #define TOK_GE tok_decl(11,2)
12281 #define TOK_LE tok_decl(11,3)
12283 #define TOK_LSHIFT tok_decl(12,0)
12284 #define TOK_RSHIFT tok_decl(12,1)
12286 #define TOK_ADD tok_decl(13,0)
12287 #define TOK_SUB tok_decl(13,1)
12289 #define TOK_MUL tok_decl(14,0)
12290 #define TOK_DIV tok_decl(14,1)
12291 #define TOK_REM tok_decl(14,2)
12293 /* exponent is right associativity */
12294 #define TOK_EXPONENT tok_decl(15,1)
12296 /* For now unary operators. */
12297 #define UNARYPREC 16
12298 #define TOK_BNOT tok_decl(UNARYPREC,0)
12299 #define TOK_NOT tok_decl(UNARYPREC,1)
12301 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12302 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12304 #define PREC_PRE (UNARYPREC+2)
12306 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12307 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12309 #define PREC_POST (UNARYPREC+3)
12311 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12312 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12314 #define SPEC_PREC (UNARYPREC+4)
12316 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12317 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12319 #define NUMPTR (*numstackptr)
12322 tok_have_assign(operator op)
12324 operator prec = PREC(op);
12326 convert_prec_is_assing(prec);
12327 return (prec == PREC(TOK_ASSIGN) ||
12328 prec == PREC_PRE || prec == PREC_POST);
12332 is_right_associativity(operator prec)
12334 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
12335 || prec == PREC(TOK_CONDITIONAL));
12338 typedef struct ARITCH_VAR_NUM {
12340 arith_t contidional_second_val;
12341 char contidional_second_val_initialized;
12342 char *var; /* if NULL then is regular number,
12343 else is variable name */
12346 typedef struct CHK_VAR_RECURSIVE_LOOPED {
12348 struct CHK_VAR_RECURSIVE_LOOPED *next;
12349 } chk_var_recursive_looped_t;
12351 static chk_var_recursive_looped_t *prev_chk_var_recursive;
12354 arith_lookup_val(v_n_t *t)
12357 const char * p = lookupvar(t->var);
12362 /* recursive try as expression */
12363 chk_var_recursive_looped_t *cur;
12364 chk_var_recursive_looped_t cur_save;
12366 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
12367 if (strcmp(cur->var, t->var) == 0) {
12368 /* expression recursion loop detected */
12372 /* save current lookuped var name */
12373 cur = prev_chk_var_recursive;
12374 cur_save.var = t->var;
12375 cur_save.next = cur;
12376 prev_chk_var_recursive = &cur_save;
12378 t->val = arith (p, &errcode);
12379 /* restore previous ptr after recursiving */
12380 prev_chk_var_recursive = cur;
12383 /* allow undefined var as 0 */
12389 /* "applying" a token means performing it on the top elements on the integer
12390 * stack. For a unary operator it will only change the top element, but a
12391 * binary operator will pop two arguments and push a result */
12393 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
12396 arith_t numptr_val, rez;
12397 int ret_arith_lookup_val;
12399 /* There is no operator that can work without arguments */
12400 if (NUMPTR == numstack) goto err;
12401 numptr_m1 = NUMPTR - 1;
12403 /* check operand is var with noninteger value */
12404 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12405 if (ret_arith_lookup_val)
12406 return ret_arith_lookup_val;
12408 rez = numptr_m1->val;
12409 if (op == TOK_UMINUS)
12411 else if (op == TOK_NOT)
12413 else if (op == TOK_BNOT)
12415 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
12417 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
12419 else if (op != TOK_UPLUS) {
12420 /* Binary operators */
12422 /* check and binary operators need two arguments */
12423 if (numptr_m1 == numstack) goto err;
12425 /* ... and they pop one */
12428 if (op == TOK_CONDITIONAL) {
12429 if (! numptr_m1->contidional_second_val_initialized) {
12430 /* protect $((expr1 ? expr2)) without ": expr" */
12433 rez = numptr_m1->contidional_second_val;
12434 } else if (numptr_m1->contidional_second_val_initialized) {
12435 /* protect $((expr1 : expr2)) without "expr ? " */
12438 numptr_m1 = NUMPTR - 1;
12439 if (op != TOK_ASSIGN) {
12440 /* check operand is var with noninteger value for not '=' */
12441 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12442 if (ret_arith_lookup_val)
12443 return ret_arith_lookup_val;
12445 if (op == TOK_CONDITIONAL) {
12446 numptr_m1->contidional_second_val = rez;
12448 rez = numptr_m1->val;
12449 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
12451 else if (op == TOK_OR)
12452 rez = numptr_val || rez;
12453 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
12455 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
12457 else if (op == TOK_AND)
12458 rez = rez && numptr_val;
12459 else if (op == TOK_EQ)
12460 rez = (rez == numptr_val);
12461 else if (op == TOK_NE)
12462 rez = (rez != numptr_val);
12463 else if (op == TOK_GE)
12464 rez = (rez >= numptr_val);
12465 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
12466 rez >>= numptr_val;
12467 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
12468 rez <<= numptr_val;
12469 else if (op == TOK_GT)
12470 rez = (rez > numptr_val);
12471 else if (op == TOK_LT)
12472 rez = (rez < numptr_val);
12473 else if (op == TOK_LE)
12474 rez = (rez <= numptr_val);
12475 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
12477 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
12479 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
12481 else if (op == TOK_ASSIGN || op == TOK_COMMA)
12483 else if (op == TOK_CONDITIONAL_SEP) {
12484 if (numptr_m1 == numstack) {
12485 /* protect $((expr : expr)) without "expr ? " */
12488 numptr_m1->contidional_second_val_initialized = op;
12489 numptr_m1->contidional_second_val = numptr_val;
12490 } else if (op == TOK_CONDITIONAL) {
12492 numptr_val : numptr_m1->contidional_second_val;
12493 } else if (op == TOK_EXPONENT) {
12494 if (numptr_val < 0)
12495 return -3; /* exponent less than 0 */
12500 while (numptr_val--)
12504 } else if (numptr_val==0) /* zero divisor check */
12506 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
12508 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
12511 if (tok_have_assign(op)) {
12512 char buf[sizeof(arith_t_type)*3 + 2];
12514 if (numptr_m1->var == NULL) {
12518 /* save to shell variable */
12519 #if ENABLE_ASH_MATH_SUPPORT_64
12520 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
12522 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
12524 setvar(numptr_m1->var, buf, 0);
12525 /* after saving, make previous value for v++ or v-- */
12526 if (op == TOK_POST_INC)
12528 else if (op == TOK_POST_DEC)
12531 numptr_m1->val = rez;
12532 /* protect geting var value, is number now */
12533 numptr_m1->var = NULL;
12539 /* longest must be first */
12540 static const char op_tokens[] ALIGN1 = {
12541 '<','<','=',0, TOK_LSHIFT_ASSIGN,
12542 '>','>','=',0, TOK_RSHIFT_ASSIGN,
12543 '<','<', 0, TOK_LSHIFT,
12544 '>','>', 0, TOK_RSHIFT,
12545 '|','|', 0, TOK_OR,
12546 '&','&', 0, TOK_AND,
12547 '!','=', 0, TOK_NE,
12548 '<','=', 0, TOK_LE,
12549 '>','=', 0, TOK_GE,
12550 '=','=', 0, TOK_EQ,
12551 '|','=', 0, TOK_OR_ASSIGN,
12552 '&','=', 0, TOK_AND_ASSIGN,
12553 '*','=', 0, TOK_MUL_ASSIGN,
12554 '/','=', 0, TOK_DIV_ASSIGN,
12555 '%','=', 0, TOK_REM_ASSIGN,
12556 '+','=', 0, TOK_PLUS_ASSIGN,
12557 '-','=', 0, TOK_MINUS_ASSIGN,
12558 '-','-', 0, TOK_POST_DEC,
12559 '^','=', 0, TOK_XOR_ASSIGN,
12560 '+','+', 0, TOK_POST_INC,
12561 '*','*', 0, TOK_EXPONENT,
12565 '=', 0, TOK_ASSIGN,
12577 '?', 0, TOK_CONDITIONAL,
12578 ':', 0, TOK_CONDITIONAL_SEP,
12579 ')', 0, TOK_RPAREN,
12580 '(', 0, TOK_LPAREN,
12584 #define endexpression &op_tokens[sizeof(op_tokens)-7]
12587 arith(const char *expr, int *perrcode)
12589 char arithval; /* Current character under analysis */
12590 operator lasttok, op;
12593 const char *p = endexpression;
12596 size_t datasizes = strlen(expr) + 2;
12598 /* Stack of integers */
12599 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
12600 * in any given correct or incorrect expression is left as an exercise to
12602 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
12603 *numstackptr = numstack;
12604 /* Stack of operator tokens */
12605 operator *stack = alloca((datasizes) * sizeof(operator)),
12608 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
12609 *perrcode = errcode = 0;
12613 if (arithval == 0) {
12614 if (p == endexpression) {
12615 /* Null expression. */
12619 /* This is only reached after all tokens have been extracted from the
12620 * input stream. If there are still tokens on the operator stack, they
12621 * are to be applied in order. At the end, there should be a final
12622 * result on the integer stack */
12624 if (expr != endexpression + 1) {
12625 /* If we haven't done so already, */
12626 /* append a closing right paren */
12627 expr = endexpression;
12628 /* and let the loop process it. */
12631 /* At this point, we're done with the expression. */
12632 if (numstackptr != numstack+1) {
12633 /* ... but if there isn't, it's bad */
12635 return (*perrcode = -1);
12637 if (numstack->var) {
12638 /* expression is $((var)) only, lookup now */
12639 errcode = arith_lookup_val(numstack);
12642 *perrcode = errcode;
12643 return numstack->val;
12646 /* Continue processing the expression. */
12647 if (arith_isspace(arithval)) {
12648 /* Skip whitespace */
12651 p = endofname(expr);
12653 size_t var_name_size = (p-expr) + 1; /* trailing zero */
12655 numstackptr->var = alloca(var_name_size);
12656 safe_strncpy(numstackptr->var, expr, var_name_size);
12659 numstackptr->contidional_second_val_initialized = 0;
12664 if (isdigit(arithval)) {
12665 numstackptr->var = NULL;
12666 #if ENABLE_ASH_MATH_SUPPORT_64
12667 numstackptr->val = strtoll(expr, (char **) &expr, 0);
12669 numstackptr->val = strtol(expr, (char **) &expr, 0);
12673 for (p = op_tokens; ; p++) {
12677 /* strange operator not found */
12680 for (o = expr; *p && *o == *p; p++)
12687 /* skip tail uncompared token */
12690 /* skip zero delim */
12695 /* post grammar: a++ reduce to num */
12696 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
12699 /* Plus and minus are binary (not unary) _only_ if the last
12700 * token was as number, or a right paren (which pretends to be
12701 * a number, since it evaluates to one). Think about it.
12702 * It makes sense. */
12703 if (lasttok != TOK_NUM) {
12719 /* We don't want a unary operator to cause recursive descent on the
12720 * stack, because there can be many in a row and it could cause an
12721 * operator to be evaluated before its argument is pushed onto the
12722 * integer stack. */
12723 /* But for binary operators, "apply" everything on the operator
12724 * stack until we find an operator with a lesser priority than the
12725 * one we have just extracted. */
12726 /* Left paren is given the lowest priority so it will never be
12727 * "applied" in this way.
12728 * if associativity is right and priority eq, applied also skip
12731 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
12732 /* not left paren or unary */
12733 if (lasttok != TOK_NUM) {
12734 /* binary op must be preceded by a num */
12737 while (stackptr != stack) {
12738 if (op == TOK_RPAREN) {
12739 /* The algorithm employed here is simple: while we don't
12740 * hit an open paren nor the bottom of the stack, pop
12741 * tokens and apply them */
12742 if (stackptr[-1] == TOK_LPAREN) {
12744 /* Any operator directly after a */
12746 /* close paren should consider itself binary */
12750 operator prev_prec = PREC(stackptr[-1]);
12752 convert_prec_is_assing(prec);
12753 convert_prec_is_assing(prev_prec);
12754 if (prev_prec < prec)
12756 /* check right assoc */
12757 if (prev_prec == prec && is_right_associativity(prec))
12760 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
12761 if (errcode) goto ret;
12763 if (op == TOK_RPAREN) {
12768 /* Push this operator to the stack and remember it. */
12769 *stackptr++ = lasttok = op;
12774 #endif /* ASH_MATH_SUPPORT */
12777 /* ============ main() and helpers */
12780 * Called to exit the shell.
12782 static void exitshell(void) ATTRIBUTE_NORETURN;
12790 status = exitstatus;
12791 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12792 if (setjmp(loc.loc)) {
12793 if (exception == EXEXIT)
12794 /* dash bug: it just does _exit(exitstatus) here
12795 * but we have to do setjobctl(0) first!
12796 * (bug is still not fixed in dash-0.5.3 - if you run dash
12797 * under Midnight Commander, on exit from dash MC is backgrounded) */
12798 status = exitstatus;
12801 exception_handler = &loc;
12807 flush_stdout_stderr();
12817 /* from input.c: */
12818 basepf.nextc = basepf.buf = basebuf;
12821 signal(SIGCHLD, SIG_DFL);
12826 char ppid[sizeof(int)*3 + 1];
12828 struct stat st1, st2;
12831 for (envp = environ; envp && *envp; envp++) {
12832 if (strchr(*envp, '=')) {
12833 setvareq(*envp, VEXPORT|VTEXTFIXED);
12837 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
12838 setvar("PPID", ppid, 0);
12840 p = lookupvar("PWD");
12842 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
12843 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
12850 * Process the shell command line arguments.
12853 procargs(int argc, char **argv)
12856 const char *xminusc;
12863 for (i = 0; i < NOPTS; i++)
12867 /* it already printed err message */
12868 raise_exception(EXERROR);
12872 if (*xargv == NULL) {
12874 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
12877 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
12881 for (i = 0; i < NOPTS; i++)
12882 if (optlist[i] == 2)
12887 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
12892 } else if (!sflag) {
12893 setinputfile(*xargv, 0);
12896 commandname = arg0;
12899 shellparam.p = xargv;
12900 #if ENABLE_ASH_GETOPTS
12901 shellparam.optind = 1;
12902 shellparam.optoff = -1;
12904 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
12906 shellparam.nparam++;
12913 * Read /etc/profile or .profile.
12916 read_profile(const char *name)
12920 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
12929 * This routine is called when an error or an interrupt occurs in an
12930 * interactive shell and control is returned to the main command loop.
12938 /* from input.c: */
12939 parselleft = parsenleft = 0; /* clear input buffer */
12941 /* from parser.c: */
12944 /* from redir.c: */
12949 static short profile_buf[16384];
12950 extern int etext();
12954 * Main routine. We initialize things, parse the arguments, execute
12955 * profiles if we're a login shell, and then call cmdloop to execute
12956 * commands. The setjmp call sets up the location to jump to when an
12957 * exception occurs. When an exception occurs the variable "state"
12958 * is used to figure out how far we had gotten.
12960 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
12961 int ash_main(int argc, char **argv)
12964 volatile int state;
12965 struct jmploc jmploc;
12966 struct stackmark smark;
12968 /* Initialize global data */
12972 #if ENABLE_ASH_ALIAS
12978 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
12981 #if ENABLE_FEATURE_EDITING
12982 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
12985 if (setjmp(jmploc.loc)) {
12995 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
12999 outcslow('\n', stderr);
13001 popstackmark(&smark);
13002 FORCE_INT_ON; /* enable interrupts */
13011 exception_handler = &jmploc;
13014 trace_puts("Shell args: ");
13015 trace_puts_args(argv);
13017 rootpid = getpid();
13019 #if ENABLE_ASH_RANDOM_SUPPORT
13020 rseed = rootpid + time(NULL);
13023 setstackmark(&smark);
13024 procargs(argc, argv);
13025 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13027 const char *hp = lookupvar("HISTFILE");
13030 hp = lookupvar("HOME");
13032 char *defhp = concat_path_file(hp, ".ash_history");
13033 setvar("HISTFILE", defhp, 0);
13039 if (argv[0] && argv[0][0] == '-')
13043 read_profile("/etc/profile");
13046 read_profile(".profile");
13052 getuid() == geteuid() && getgid() == getegid() &&
13056 shinit = lookupvar("ENV");
13057 if (shinit != NULL && *shinit != '\0') {
13058 read_profile(shinit);
13064 evalstring(minusc, 0);
13066 if (sflag || minusc == NULL) {
13067 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13069 const char *hp = lookupvar("HISTFILE");
13072 line_input_state->hist_file = hp;
13075 state4: /* XXX ??? - why isn't this before the "if" statement */
13083 extern void _mcleanup(void);
13092 const char *applet_name = "debug stuff usage";
13093 int main(int argc, char **argv)
13095 return ash_main(argc, argv);
13101 * Copyright (c) 1989, 1991, 1993, 1994
13102 * The Regents of the University of California. All rights reserved.
13104 * This code is derived from software contributed to Berkeley by
13105 * Kenneth Almquist.
13107 * Redistribution and use in source and binary forms, with or without
13108 * modification, are permitted provided that the following conditions
13110 * 1. Redistributions of source code must retain the above copyright
13111 * notice, this list of conditions and the following disclaimer.
13112 * 2. Redistributions in binary form must reproduce the above copyright
13113 * notice, this list of conditions and the following disclaimer in the
13114 * documentation and/or other materials provided with the distribution.
13115 * 3. Neither the name of the University nor the names of its contributors
13116 * may be used to endorse or promote products derived from this software
13117 * without specific prior written permission.
13119 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13120 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13121 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13122 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13123 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13124 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13125 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13126 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13127 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13128 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF