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.
11 * This code is derived from software contributed to Berkeley by
14 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
16 * Original BSD copyright notice is retained at the end of this file.
20 * rewrite arith.y to micro stack based cryptic algorithm by
21 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
23 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
26 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be
27 * used in busybox and size optimizations,
28 * rewrote arith (see notes to this), added locale support,
29 * rewrote dynamic variables.
33 * The follow should be set to reflect the type of system you have:
34 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
35 * define SYSV if you are running under System V.
36 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
37 * define DEBUG=2 to compile in and turn on debugging.
39 * When debugging is on, debugging info will be written to ./trace and
40 * a quit signal will generate a core dump.
47 #define JOBS ENABLE_ASH_JOB_CONTROL
55 #include "busybox.h" /* for applet_names */
59 #if JOBS || ENABLE_ASH_READ_NCHARS
64 #define PIPE_BUF 4096 /* amount of buffering in a pipe */
67 #if defined(__uClinux__)
68 #error "Do not even bother, ash will not run on uClinux"
72 /* ============ Hash table sizes. Configurable. */
76 #define CMDTABLESIZE 31 /* should be prime */
79 /* ============ Misc helpers */
81 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
83 /* C99 say: "char" declaration may be signed or unsigned default */
84 #define signed_char2int(sc) ((int)((signed char)sc))
87 /* ============ Shell options */
89 static const char *const optletters_optnames[] = {
110 #define optletters(n) optletters_optnames[(n)][0]
111 #define optnames(n) (&optletters_optnames[(n)][1])
113 enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
116 /* ============ Misc data */
118 static const char homestr[] ALIGN1 = "HOME";
119 static const char snlfmt[] ALIGN1 = "%s\n";
120 static const char illnum[] ALIGN1 = "Illegal number: %s";
123 * We enclose jmp_buf in a structure so that we can declare pointers to
124 * jump locations. The global variable handler contains the location to
125 * jump to when an exception occurs, and the global variable exception
126 * contains a code identifying the exception. To implement nested
127 * exception handlers, the user should save the value of handler on entry
128 * to an inner scope, set handler to point to a jmploc structure for the
129 * inner scope, and restore handler on exit from the scope.
135 struct globals_misc {
136 /* pid of main shell */
138 /* shell level: 0 for the main shell, 1 for its children, and so on */
140 #define rootshell (!shlvl)
141 char *minusc; /* argument to -c option */
143 char *curdir; // = nullstr; /* current working directory */
144 char *physdir; // = nullstr; /* physical working directory */
146 char *arg0; /* value of $0 */
148 struct jmploc *exception_handler;
150 // disabled by vda: cannot understand how it was supposed to work -
151 // cannot fix bugs. That's why you have to explain your non-trivial designs!
152 // /* do we generate EXSIG events */
153 // int exsig; /* counter */
154 volatile int suppressint; /* counter */
155 volatile /*sig_atomic_t*/ smallint intpending; /* 1 = got SIGINT */
156 /* last pending signal */
157 volatile /*sig_atomic_t*/ smallint pendingsig;
158 smallint exception; /* kind of exception (0..5) */
160 #define EXINT 0 /* SIGINT received */
161 #define EXERROR 1 /* a generic error */
162 #define EXSHELLPROC 2 /* execute a shell procedure */
163 #define EXEXEC 3 /* command execution failed */
164 #define EXEXIT 4 /* exit the shell */
165 #define EXSIG 5 /* trapped signal in wait(1) */
168 char nullstr[1]; /* zero length string */
171 #define eflag optlist[0]
172 #define fflag optlist[1]
173 #define Iflag optlist[2]
174 #define iflag optlist[3]
175 #define mflag optlist[4]
176 #define nflag optlist[5]
177 #define sflag optlist[6]
178 #define xflag optlist[7]
179 #define vflag optlist[8]
180 #define Cflag optlist[9]
181 #define aflag optlist[10]
182 #define bflag optlist[11]
183 #define uflag optlist[12]
184 #define viflag optlist[13]
186 #define nolog optlist[14]
187 #define debug optlist[15]
190 /* trap handler commands */
192 * Sigmode records the current value of the signal handlers for the various
193 * modes. A value of zero means that the current handler is not known.
194 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
196 char sigmode[NSIG - 1];
197 #define S_DFL 1 /* default signal handling (SIG_DFL) */
198 #define S_CATCH 2 /* signal is caught */
199 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
200 #define S_HARD_IGN 4 /* signal is ignored permenantly */
201 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
203 /* indicates specified signal received */
204 char gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
207 /* Rarely referenced stuff */
208 #if ENABLE_ASH_RANDOM_SUPPORT
209 /* Random number generators */
210 int32_t random_galois_LFSR; /* Galois LFSR (fast but weak). signed! */
211 uint32_t random_LCG; /* LCG (fast but weak) */
213 pid_t backgndpid; /* pid of last background process */
214 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
216 extern struct globals_misc *const ash_ptr_to_globals_misc;
217 #define G_misc (*ash_ptr_to_globals_misc)
218 #define rootpid (G_misc.rootpid )
219 #define shlvl (G_misc.shlvl )
220 #define minusc (G_misc.minusc )
221 #define curdir (G_misc.curdir )
222 #define physdir (G_misc.physdir )
223 #define arg0 (G_misc.arg0 )
224 #define exception_handler (G_misc.exception_handler)
225 #define exception (G_misc.exception )
226 #define suppressint (G_misc.suppressint )
227 #define intpending (G_misc.intpending )
228 //#define exsig (G_misc.exsig )
229 #define pendingsig (G_misc.pendingsig )
230 #define isloginsh (G_misc.isloginsh )
231 #define nullstr (G_misc.nullstr )
232 #define optlist (G_misc.optlist )
233 #define sigmode (G_misc.sigmode )
234 #define gotsig (G_misc.gotsig )
235 #define trap (G_misc.trap )
236 #define random_galois_LFSR (G_misc.random_galois_LFSR)
237 #define random_LCG (G_misc.random_LCG )
238 #define backgndpid (G_misc.backgndpid )
239 #define job_warning (G_misc.job_warning)
240 #define INIT_G_misc() do { \
241 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
248 /* ============ Utility functions */
249 static int isdigit_str9(const char *str)
251 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
252 while (--maxlen && isdigit(*str))
254 return (*str == '\0');
258 /* ============ Interrupts / exceptions */
260 * These macros allow the user to suspend the handling of interrupt signals
261 * over a period of time. This is similar to SIGHOLD or to sigblock, but
262 * much more efficient and portable. (But hacking the kernel is so much
263 * more fun than worrying about efficiency and portability. :-))
265 #define INT_OFF do { \
271 * Called to raise an exception. Since C doesn't include exceptions, we
272 * just do a longjmp to the exception handler. The type of exception is
273 * stored in the global variable "exception".
275 static void raise_exception(int) NORETURN;
277 raise_exception(int e)
280 if (exception_handler == NULL)
285 longjmp(exception_handler->loc, 1);
289 * Called from trap.c when a SIGINT is received. (If the user specifies
290 * that SIGINT is to be trapped or ignored using the trap builtin, then
291 * this routine is not called.) Suppressint is nonzero when interrupts
292 * are held using the INT_OFF macro. (The test for iflag is just
293 * defensive programming.)
295 static void raise_interrupt(void) NORETURN;
297 raise_interrupt(void)
302 /* Signal is not automatically unmasked after it is raised,
303 * do it ourself - unmask all signals */
304 sigprocmask_allsigs(SIG_UNBLOCK);
305 /* pendingsig = 0; - now done in onsig() */
308 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
309 if (!(rootshell && iflag)) {
310 /* Kill ourself with SIGINT */
311 signal(SIGINT, SIG_DFL);
320 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
324 if (--suppressint == 0 && intpending) {
328 #define INT_ON int_on()
336 #define FORCE_INT_ON force_int_on()
338 #define INT_ON do { \
340 if (--suppressint == 0 && intpending) \
343 #define FORCE_INT_ON do { \
349 #endif /* ASH_OPTIMIZE_FOR_SIZE */
351 #define SAVE_INT(v) ((v) = suppressint)
353 #define RESTORE_INT(v) do { \
356 if (suppressint == 0 && intpending) \
361 * Ignore a signal. Only one usage site - in forkchild()
366 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
367 signal(signo, SIG_IGN);
369 sigmode[signo - 1] = S_HARD_IGN;
373 * Signal handler. Only one usage site - in setsignal()
378 gotsig[signo - 1] = 1;
381 if (/* exsig || */ (signo == SIGINT && !trap[SIGINT])) {
384 raise_interrupt(); /* does not return */
391 /* ============ Stdout/stderr output */
394 outstr(const char *p, FILE *file)
402 flush_stdout_stderr(void)
419 outcslow(int c, FILE *dest)
427 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
429 out1fmt(const char *fmt, ...)
436 r = vprintf(fmt, ap);
442 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
444 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
451 ret = vsnprintf(outbuf, length, fmt, ap);
458 out1str(const char *p)
464 out2str(const char *p)
471 /* ============ Parser structures */
473 /* control characters in argument strings */
474 #define CTLESC '\201' /* escape next character */
475 #define CTLVAR '\202' /* variable defn */
476 #define CTLENDVAR '\203'
477 #define CTLBACKQ '\204'
478 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
479 /* CTLBACKQ | CTLQUOTE == '\205' */
480 #define CTLARI '\206' /* arithmetic expression */
481 #define CTLENDARI '\207'
482 #define CTLQUOTEMARK '\210'
484 /* variable substitution byte (follows CTLVAR) */
485 #define VSTYPE 0x0f /* type of variable substitution */
486 #define VSNUL 0x10 /* colon--treat the empty string as unset */
487 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
489 /* values of VSTYPE field */
490 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
491 #define VSMINUS 0x2 /* ${var-text} */
492 #define VSPLUS 0x3 /* ${var+text} */
493 #define VSQUESTION 0x4 /* ${var?message} */
494 #define VSASSIGN 0x5 /* ${var=text} */
495 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
496 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
497 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
498 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
499 #define VSLENGTH 0xa /* ${#var} */
500 #if ENABLE_ASH_BASH_COMPAT
501 #define VSSUBSTR 0xc /* ${var:position:length} */
502 #define VSREPLACE 0xd /* ${var/pattern/replacement} */
503 #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
506 static const char dolatstr[] ALIGN1 = {
507 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
527 #if ENABLE_ASH_BASH_COMPAT
543 smallint type; /* Nxxxx */
546 union node *redirect;
551 smallint pipe_backgnd;
552 struct nodelist *cmdlist;
558 union node *redirect;
571 union node *elsepart;
598 struct nodelist *backquote;
601 /* nfile and ndup layout must match!
602 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
603 * that it is actually NTO2 (>&file), and change its type.
620 char *_unused_expfname;
639 struct nredir nredir;
640 struct nbinary nbinary;
644 struct nclist nclist;
653 struct nodelist *next;
666 freefunc(struct funcnode *f)
668 if (f && --f->count < 0)
673 /* ============ Debugging output */
677 static FILE *tracefile;
680 trace_printf(const char *fmt, ...)
687 vfprintf(tracefile, fmt, va);
692 trace_vprintf(const char *fmt, va_list va)
696 vfprintf(tracefile, fmt, va);
700 trace_puts(const char *s)
708 trace_puts_quoted(char *s)
715 putc('"', tracefile);
716 for (p = s; *p; p++) {
718 case '\n': c = 'n'; goto backslash;
719 case '\t': c = 't'; goto backslash;
720 case '\r': c = 'r'; goto backslash;
721 case '"': c = '"'; goto backslash;
722 case '\\': c = '\\'; goto backslash;
723 case CTLESC: c = 'e'; goto backslash;
724 case CTLVAR: c = 'v'; goto backslash;
725 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
726 case CTLBACKQ: c = 'q'; goto backslash;
727 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
729 putc('\\', tracefile);
733 if (*p >= ' ' && *p <= '~')
736 putc('\\', tracefile);
737 putc(*p >> 6 & 03, tracefile);
738 putc(*p >> 3 & 07, tracefile);
739 putc(*p & 07, tracefile);
744 putc('"', tracefile);
748 trace_puts_args(char **ap)
755 trace_puts_quoted(*ap);
757 putc('\n', tracefile);
760 putc(' ', tracefile);
775 /* leave open because libedit might be using it */
778 strcpy(s, "./trace");
780 if (!freopen(s, "a", tracefile)) {
781 fprintf(stderr, "Can't re-open %s\n", s);
786 tracefile = fopen(s, "a");
787 if (tracefile == NULL) {
788 fprintf(stderr, "Can't open %s\n", s);
794 flags = fcntl(fileno(tracefile), F_GETFL);
796 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
798 setlinebuf(tracefile);
799 fputs("\nTracing started.\n", tracefile);
803 indent(int amount, char *pfx, FILE *fp)
807 for (i = 0; i < amount; i++) {
808 if (pfx && i == amount - 1)
814 /* little circular references here... */
815 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
818 sharg(union node *arg, FILE *fp)
821 struct nodelist *bqlist;
824 if (arg->type != NARG) {
825 out1fmt("<node type %d>\n", arg->type);
828 bqlist = arg->narg.backquote;
829 for (p = arg->narg.text; *p; p++) {
838 if (subtype == VSLENGTH)
847 switch (subtype & VSTYPE) {
880 out1fmt("<subtype %d>", subtype);
887 case CTLBACKQ|CTLQUOTE:
890 shtree(bqlist->n, -1, NULL, fp);
901 shcmd(union node *cmd, FILE *fp)
909 for (np = cmd->ncmd.args; np; np = np->narg.next) {
915 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
919 switch (np->nfile.type) {
920 case NTO: s = ">>"+1; dftfd = 1; break;
921 case NCLOBBER: s = ">|"; dftfd = 1; break;
922 case NAPPEND: s = ">>"; dftfd = 1; break;
923 #if ENABLE_ASH_BASH_COMPAT
926 case NTOFD: s = ">&"; dftfd = 1; break;
927 case NFROM: s = "<"; break;
928 case NFROMFD: s = "<&"; break;
929 case NFROMTO: s = "<>"; break;
930 default: s = "*error*"; break;
932 if (np->nfile.fd != dftfd)
933 fprintf(fp, "%d", np->nfile.fd);
935 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
936 fprintf(fp, "%d", np->ndup.dupfd);
938 sharg(np->nfile.fname, fp);
945 shtree(union node *n, int ind, char *pfx, FILE *fp)
953 indent(ind, pfx, fp);
964 shtree(n->nbinary.ch1, ind, NULL, fp);
967 shtree(n->nbinary.ch2, ind, NULL, fp);
975 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
980 if (n->npipe.pipe_backgnd)
986 fprintf(fp, "<node type %d>", n->type);
994 showtree(union node *n)
996 trace_puts("showtree called\n");
997 shtree(n, 1, NULL, stdout);
1000 #define TRACE(param) trace_printf param
1001 #define TRACEV(param) trace_vprintf param
1005 #define TRACE(param)
1006 #define TRACEV(param)
1011 /* ============ Parser data */
1014 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1017 struct strlist *next;
1024 struct strpush *prev; /* preceding string on stack */
1027 #if ENABLE_ASH_ALIAS
1028 struct alias *ap; /* if push was associated with an alias */
1030 char *string; /* remember the string since it may change */
1034 struct parsefile *prev; /* preceding file on stack */
1035 int linno; /* current line */
1036 int fd; /* file descriptor (or -1 if string) */
1037 int nleft; /* number of chars left in this line */
1038 int lleft; /* number of chars left in this buffer */
1039 char *nextc; /* next char in buffer */
1040 char *buf; /* input buffer */
1041 struct strpush *strpush; /* for pushing strings at this level */
1042 struct strpush basestrpush; /* so pushing one is fast */
1045 static struct parsefile basepf; /* top level input file */
1046 static struct parsefile *g_parsefile = &basepf; /* current input file */
1047 static int startlinno; /* line # where last token started */
1048 static char *commandname; /* currently executing command */
1049 static struct strlist *cmdenviron; /* environment for builtin command */
1050 static uint8_t exitstatus; /* exit status of last command */
1053 /* ============ Message printing */
1056 ash_vmsg(const char *msg, va_list ap)
1058 fprintf(stderr, "%s: ", arg0);
1060 if (strcmp(arg0, commandname))
1061 fprintf(stderr, "%s: ", commandname);
1062 if (!iflag || g_parsefile->fd)
1063 fprintf(stderr, "line %d: ", startlinno);
1065 vfprintf(stderr, msg, ap);
1066 outcslow('\n', stderr);
1070 * Exverror is called to raise the error exception. If the second argument
1071 * is not NULL then error prints an error message using printf style
1072 * formatting. It then raises the error exception.
1074 static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1076 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1080 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1082 TRACE(("\") pid=%d\n", getpid()));
1084 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1089 flush_stdout_stderr();
1090 raise_exception(cond);
1094 static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1096 ash_msg_and_raise_error(const char *msg, ...)
1101 ash_vmsg_and_raise(EXERROR, msg, ap);
1106 static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1108 ash_msg_and_raise(int cond, const char *msg, ...)
1113 ash_vmsg_and_raise(cond, msg, ap);
1119 * error/warning routines for external builtins
1122 ash_msg(const char *fmt, ...)
1132 * Return a string describing an error. The returned string may be a
1133 * pointer to a static buffer that will be overwritten on the next call.
1134 * Action describes the operation that got the error.
1137 errmsg(int e, const char *em)
1139 if (e == ENOENT || e == ENOTDIR) {
1146 /* ============ Memory allocation */
1149 * It appears that grabstackstr() will barf with such alignments
1150 * because stalloc() will return a string allocated in a new stackblock.
1152 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1154 /* Most machines require the value returned from malloc to be aligned
1155 * in some way. The following macro will get this right
1156 * on many machines. */
1157 SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,
1158 /* Minimum size of a block */
1159 MINSIZE = SHELL_ALIGN(504),
1162 struct stack_block {
1163 struct stack_block *prev;
1164 char space[MINSIZE];
1168 struct stack_block *stackp;
1171 struct stackmark *marknext;
1175 struct globals_memstack {
1176 struct stack_block *g_stackp; // = &stackbase;
1177 struct stackmark *markp;
1178 char *g_stacknxt; // = stackbase.space;
1179 char *sstrend; // = stackbase.space + MINSIZE;
1180 size_t g_stacknleft; // = MINSIZE;
1181 int herefd; // = -1;
1182 struct stack_block stackbase;
1184 extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1185 #define G_memstack (*ash_ptr_to_globals_memstack)
1186 #define g_stackp (G_memstack.g_stackp )
1187 #define markp (G_memstack.markp )
1188 #define g_stacknxt (G_memstack.g_stacknxt )
1189 #define sstrend (G_memstack.sstrend )
1190 #define g_stacknleft (G_memstack.g_stacknleft)
1191 #define herefd (G_memstack.herefd )
1192 #define stackbase (G_memstack.stackbase )
1193 #define INIT_G_memstack() do { \
1194 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1196 g_stackp = &stackbase; \
1197 g_stacknxt = stackbase.space; \
1198 g_stacknleft = MINSIZE; \
1199 sstrend = stackbase.space + MINSIZE; \
1203 #define stackblock() ((void *)g_stacknxt)
1204 #define stackblocksize() g_stacknleft
1208 ckrealloc(void * p, size_t nbytes)
1210 p = realloc(p, nbytes);
1212 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1217 ckmalloc(size_t nbytes)
1219 return ckrealloc(NULL, nbytes);
1223 ckzalloc(size_t nbytes)
1225 return memset(ckmalloc(nbytes), 0, nbytes);
1229 * Make a copy of a string in safe storage.
1232 ckstrdup(const char *s)
1234 char *p = strdup(s);
1236 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1241 * Parse trees for commands are allocated in lifo order, so we use a stack
1242 * to make this more efficient, and also to avoid all sorts of exception
1243 * handling code to handle interrupts in the middle of a parse.
1245 * The size 504 was chosen because the Ultrix malloc handles that size
1249 stalloc(size_t nbytes)
1254 aligned = SHELL_ALIGN(nbytes);
1255 if (aligned > g_stacknleft) {
1258 struct stack_block *sp;
1260 blocksize = aligned;
1261 if (blocksize < MINSIZE)
1262 blocksize = MINSIZE;
1263 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1264 if (len < blocksize)
1265 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1268 sp->prev = g_stackp;
1269 g_stacknxt = sp->space;
1270 g_stacknleft = blocksize;
1271 sstrend = g_stacknxt + blocksize;
1276 g_stacknxt += aligned;
1277 g_stacknleft -= aligned;
1282 stzalloc(size_t nbytes)
1284 return memset(stalloc(nbytes), 0, nbytes);
1291 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1292 write(STDERR_FILENO, "stunalloc\n", 10);
1296 g_stacknleft += g_stacknxt - (char *)p;
1301 * Like strdup but works with the ash stack.
1304 ststrdup(const char *p)
1306 size_t len = strlen(p) + 1;
1307 return memcpy(stalloc(len), p, len);
1311 setstackmark(struct stackmark *mark)
1313 mark->stackp = g_stackp;
1314 mark->stacknxt = g_stacknxt;
1315 mark->stacknleft = g_stacknleft;
1316 mark->marknext = markp;
1321 popstackmark(struct stackmark *mark)
1323 struct stack_block *sp;
1329 markp = mark->marknext;
1330 while (g_stackp != mark->stackp) {
1332 g_stackp = sp->prev;
1335 g_stacknxt = mark->stacknxt;
1336 g_stacknleft = mark->stacknleft;
1337 sstrend = mark->stacknxt + mark->stacknleft;
1342 * When the parser reads in a string, it wants to stick the string on the
1343 * stack and only adjust the stack pointer when it knows how big the
1344 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1345 * of space on top of the stack and stackblocklen returns the length of
1346 * this block. Growstackblock will grow this space by at least one byte,
1347 * possibly moving it (like realloc). Grabstackblock actually allocates the
1348 * part of the block that has been used.
1351 growstackblock(void)
1355 newlen = g_stacknleft * 2;
1356 if (newlen < g_stacknleft)
1357 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1361 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1362 struct stack_block *oldstackp;
1363 struct stackmark *xmark;
1364 struct stack_block *sp;
1365 struct stack_block *prevstackp;
1369 oldstackp = g_stackp;
1371 prevstackp = sp->prev;
1372 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1373 sp = ckrealloc(sp, grosslen);
1374 sp->prev = prevstackp;
1376 g_stacknxt = sp->space;
1377 g_stacknleft = newlen;
1378 sstrend = sp->space + newlen;
1381 * Stack marks pointing to the start of the old block
1382 * must be relocated to point to the new block
1385 while (xmark != NULL && xmark->stackp == oldstackp) {
1386 xmark->stackp = g_stackp;
1387 xmark->stacknxt = g_stacknxt;
1388 xmark->stacknleft = g_stacknleft;
1389 xmark = xmark->marknext;
1393 char *oldspace = g_stacknxt;
1394 size_t oldlen = g_stacknleft;
1395 char *p = stalloc(newlen);
1397 /* free the space we just allocated */
1398 g_stacknxt = memcpy(p, oldspace, oldlen);
1399 g_stacknleft += newlen;
1404 grabstackblock(size_t len)
1406 len = SHELL_ALIGN(len);
1408 g_stacknleft -= len;
1412 * The following routines are somewhat easier to use than the above.
1413 * The user declares a variable of type STACKSTR, which may be declared
1414 * to be a register. The macro STARTSTACKSTR initializes things. Then
1415 * the user uses the macro STPUTC to add characters to the string. In
1416 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1417 * grown as necessary. When the user is done, she can just leave the
1418 * string there and refer to it using stackblock(). Or she can allocate
1419 * the space for it using grabstackstr(). If it is necessary to allow
1420 * someone else to use the stack temporarily and then continue to grow
1421 * the string, the user should use grabstack to allocate the space, and
1422 * then call ungrabstr(p) to return to the previous mode of operation.
1424 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1425 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1426 * is space for at least one character.
1431 size_t len = stackblocksize();
1432 if (herefd >= 0 && len >= 1024) {
1433 full_write(herefd, stackblock(), len);
1434 return stackblock();
1437 return (char *)stackblock() + len;
1441 * Called from CHECKSTRSPACE.
1444 makestrspace(size_t newlen, char *p)
1446 size_t len = p - g_stacknxt;
1447 size_t size = stackblocksize();
1452 size = stackblocksize();
1454 if (nleft >= newlen)
1458 return (char *)stackblock() + len;
1462 stack_nputstr(const char *s, size_t n, char *p)
1464 p = makestrspace(n, p);
1465 p = (char *)memcpy(p, s, n) + n;
1470 stack_putstr(const char *s, char *p)
1472 return stack_nputstr(s, strlen(s), p);
1476 _STPUTC(int c, char *p)
1484 #define STARTSTACKSTR(p) ((p) = stackblock())
1485 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1486 #define CHECKSTRSPACE(n, p) do { \
1489 size_t m = sstrend - q; \
1491 (p) = makestrspace(l, q); \
1493 #define USTPUTC(c, p) (*(p)++ = (c))
1494 #define STACKSTRNUL(p) do { \
1495 if ((p) == sstrend) \
1496 (p) = growstackstr(); \
1499 #define STUNPUTC(p) (--(p))
1500 #define STTOPC(p) ((p)[-1])
1501 #define STADJUST(amount, p) ((p) += (amount))
1503 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1504 #define ungrabstackstr(s, p) stunalloc(s)
1505 #define stackstrend() ((void *)sstrend)
1508 /* ============ String helpers */
1511 * prefix -- see if pfx is a prefix of string.
1514 prefix(const char *string, const char *pfx)
1517 if (*pfx++ != *string++)
1520 return (char *) string;
1524 * Check for a valid number. This should be elsewhere.
1527 is_number(const char *p)
1532 } while (*++p != '\0');
1537 * Convert a string of digits to an integer, printing an error message on
1541 number(const char *s)
1544 ash_msg_and_raise_error(illnum, s);
1549 * Produce a possibly single quoted string suitable as input to the shell.
1550 * The return string is allocated on the stack.
1553 single_quote(const char *s)
1563 len = strchrnul(s, '\'') - s;
1565 q = p = makestrspace(len + 3, p);
1568 q = (char *)memcpy(q, s, len) + len;
1574 len = strspn(s, "'");
1578 q = p = makestrspace(len + 3, p);
1581 q = (char *)memcpy(q, s, len) + len;
1590 return stackblock();
1594 /* ============ nextopt */
1596 static char **argptr; /* argument list for builtin commands */
1597 static char *optionarg; /* set by nextopt (like getopt) */
1598 static char *optptr; /* used by nextopt */
1601 * XXX - should get rid of. Have all builtins use getopt(3).
1602 * The library getopt must have the BSD extension static variable
1603 * "optreset", otherwise it can't be used within the shell safely.
1605 * Standard option processing (a la getopt) for builtin routines.
1606 * The only argument that is passed to nextopt is the option string;
1607 * the other arguments are unnecessary. It returns the character,
1608 * or '\0' on end of input.
1611 nextopt(const char *optstring)
1618 if (p == NULL || *p == '\0') {
1619 /* We ate entire "-param", take next one */
1625 if (*++p == '\0') /* just "-" ? */
1628 if (LONE_DASH(p)) /* "--" ? */
1630 /* p => next "-param" */
1632 /* p => some option char in the middle of a "-param" */
1634 for (q = optstring; *q != c;) {
1636 ash_msg_and_raise_error("illegal option -%c", c);
1644 ash_msg_and_raise_error("no arg for -%c option", c);
1654 /* ============ Shell variables */
1657 * The parsefile structure pointed to by the global variable parsefile
1658 * contains information about the current file being read.
1661 int nparam; /* # of positional parameters (without $0) */
1662 #if ENABLE_ASH_GETOPTS
1663 int optind; /* next parameter to be processed by getopts */
1664 int optoff; /* used by getopts */
1666 unsigned char malloced; /* if parameter list dynamically allocated */
1667 char **p; /* parameter list */
1671 * Free the list of positional parameters.
1674 freeparam(volatile struct shparam *param)
1676 if (param->malloced) {
1678 ap = ap1 = param->p;
1685 #if ENABLE_ASH_GETOPTS
1686 static void getoptsreset(const char *value);
1690 struct var *next; /* next entry in hash list */
1691 int flags; /* flags are defined above */
1692 const char *text; /* name=value */
1693 void (*func)(const char *); /* function to be called when */
1694 /* the variable gets set/unset */
1698 struct localvar *next; /* next local variable in list */
1699 struct var *vp; /* the variable that was made local */
1700 int flags; /* saved flags */
1701 const char *text; /* saved text */
1705 #define VEXPORT 0x01 /* variable is exported */
1706 #define VREADONLY 0x02 /* variable cannot be modified */
1707 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1708 #define VTEXTFIXED 0x08 /* text is statically allocated */
1709 #define VSTACK 0x10 /* text is allocated on the stack */
1710 #define VUNSET 0x20 /* the variable is not set */
1711 #define VNOFUNC 0x40 /* don't call the callback function */
1712 #define VNOSET 0x80 /* do not set variable - just readonly test */
1713 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1714 #if ENABLE_ASH_RANDOM_SUPPORT
1715 # define VDYNAMIC 0x200 /* dynamic variable */
1721 static const char defifsvar[] ALIGN1 = "IFS= \t\n";
1722 #define defifs (defifsvar + 4)
1724 static const char defifs[] ALIGN1 = " \t\n";
1728 /* Need to be before varinit_data[] */
1729 #if ENABLE_LOCALE_SUPPORT
1731 change_lc_all(const char *value)
1733 if (value && *value != '\0')
1734 setlocale(LC_ALL, value);
1737 change_lc_ctype(const char *value)
1739 if (value && *value != '\0')
1740 setlocale(LC_CTYPE, value);
1744 static void chkmail(void);
1745 static void changemail(const char *);
1747 static void changepath(const char *);
1748 #if ENABLE_ASH_RANDOM_SUPPORT
1749 static void change_random(const char *);
1752 static const struct {
1755 void (*func)(const char *);
1756 } varinit_data[] = {
1758 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1760 { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL },
1763 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0" , changemail },
1764 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1766 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1767 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1768 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1769 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1770 #if ENABLE_ASH_GETOPTS
1771 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
1773 #if ENABLE_ASH_RANDOM_SUPPORT
1774 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1776 #if ENABLE_LOCALE_SUPPORT
1777 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL\0" , change_lc_all },
1778 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE\0", change_lc_ctype },
1780 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1781 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE\0", NULL },
1787 struct globals_var {
1788 struct shparam shellparam; /* $@ current positional parameters */
1789 struct redirtab *redirlist;
1791 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1792 struct var *vartab[VTABSIZE];
1793 struct var varinit[ARRAY_SIZE(varinit_data)];
1795 extern struct globals_var *const ash_ptr_to_globals_var;
1796 #define G_var (*ash_ptr_to_globals_var)
1797 #define shellparam (G_var.shellparam )
1798 //#define redirlist (G_var.redirlist )
1799 #define g_nullredirs (G_var.g_nullredirs )
1800 #define preverrout_fd (G_var.preverrout_fd)
1801 #define vartab (G_var.vartab )
1802 #define varinit (G_var.varinit )
1803 #define INIT_G_var() do { \
1805 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1807 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1808 varinit[i].flags = varinit_data[i].flags; \
1809 varinit[i].text = varinit_data[i].text; \
1810 varinit[i].func = varinit_data[i].func; \
1814 #define vifs varinit[0]
1816 # define vmail (&vifs)[1]
1817 # define vmpath (&vmail)[1]
1818 # define vpath (&vmpath)[1]
1820 # define vpath (&vifs)[1]
1822 #define vps1 (&vpath)[1]
1823 #define vps2 (&vps1)[1]
1824 #define vps4 (&vps2)[1]
1825 #if ENABLE_ASH_GETOPTS
1826 # define voptind (&vps4)[1]
1827 # if ENABLE_ASH_RANDOM_SUPPORT
1828 # define vrandom (&voptind)[1]
1831 # if ENABLE_ASH_RANDOM_SUPPORT
1832 # define vrandom (&vps4)[1]
1837 * The following macros access the values of the above variables.
1838 * They have to skip over the name. They return the null string
1839 * for unset variables.
1841 #define ifsval() (vifs.text + 4)
1842 #define ifsset() ((vifs.flags & VUNSET) == 0)
1844 # define mailval() (vmail.text + 5)
1845 # define mpathval() (vmpath.text + 9)
1846 # define mpathset() ((vmpath.flags & VUNSET) == 0)
1848 #define pathval() (vpath.text + 5)
1849 #define ps1val() (vps1.text + 4)
1850 #define ps2val() (vps2.text + 4)
1851 #define ps4val() (vps4.text + 4)
1852 #if ENABLE_ASH_GETOPTS
1853 # define optindval() (voptind.text + 7)
1857 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1858 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1860 #if ENABLE_ASH_GETOPTS
1862 getoptsreset(const char *value)
1864 shellparam.optind = number(value);
1865 shellparam.optoff = -1;
1870 * Return of a legal variable name (a letter or underscore followed by zero or
1871 * more letters, underscores, and digits).
1874 endofname(const char *name)
1882 if (!is_in_name(*p))
1889 * Compares two strings up to the first = or '\0'. The first
1890 * string must be terminated by '='; the second may be terminated by
1891 * either '=' or '\0'.
1894 varcmp(const char *p, const char *q)
1898 while ((c = *p) == (d = *q)) {
1913 varequal(const char *a, const char *b)
1915 return !varcmp(a, b);
1919 * Find the appropriate entry in the hash table from the name.
1921 static struct var **
1922 hashvar(const char *p)
1926 hashval = ((unsigned char) *p) << 4;
1927 while (*p && *p != '=')
1928 hashval += (unsigned char) *p++;
1929 return &vartab[hashval % VTABSIZE];
1933 vpcmp(const void *a, const void *b)
1935 return varcmp(*(const char **)a, *(const char **)b);
1939 * This routine initializes the builtin variables.
1949 * PS1 depends on uid
1951 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1952 vps1.text = "PS1=\\w \\$ ";
1955 vps1.text = "PS1=# ";
1958 end = vp + ARRAY_SIZE(varinit);
1960 vpp = hashvar(vp->text);
1963 } while (++vp < end);
1966 static struct var **
1967 findvar(struct var **vpp, const char *name)
1969 for (; *vpp; vpp = &(*vpp)->next) {
1970 if (varequal((*vpp)->text, name)) {
1978 * Find the value of a variable. Returns NULL if not set.
1981 lookupvar(const char *name)
1985 v = *findvar(hashvar(name), name);
1987 #if ENABLE_ASH_RANDOM_SUPPORT
1989 * Dynamic variables are implemented roughly the same way they are
1990 * in bash. Namely, they're "special" so long as they aren't unset.
1991 * As soon as they're unset, they're no longer dynamic, and dynamic
1992 * lookup will no longer happen at that point. -- PFM.
1994 if ((v->flags & VDYNAMIC))
1997 if (!(v->flags & VUNSET))
1998 return strchrnul(v->text, '=') + 1;
2004 * Search the environment of a builtin command.
2007 bltinlookup(const char *name)
2011 for (sp = cmdenviron; sp; sp = sp->next) {
2012 if (varequal(sp->text, name))
2013 return strchrnul(sp->text, '=') + 1;
2015 return lookupvar(name);
2019 * Same as setvar except that the variable and value are passed in
2020 * the first argument as name=value. Since the first argument will
2021 * be actually stored in the table, it should not be a string that
2023 * Called with interrupts off.
2026 setvareq(char *s, int flags)
2028 struct var *vp, **vpp;
2031 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2032 vp = *findvar(vpp, s);
2034 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2037 if (flags & VNOSAVE)
2040 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2046 if (vp->func && (flags & VNOFUNC) == 0)
2047 (*vp->func)(strchrnul(s, '=') + 1);
2049 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
2050 free((char*)vp->text);
2052 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2057 vp = ckzalloc(sizeof(*vp));
2059 /*vp->func = NULL; - ckzalloc did it */
2062 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2069 * Set the value of a variable. The flags argument is ored with the
2070 * flags of the variable. If val is NULL, the variable is unset.
2073 setvar(const char *name, const char *val, int flags)
2080 q = endofname(name);
2081 p = strchrnul(q, '=');
2083 if (!namelen || p != q)
2084 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2089 vallen = strlen(val);
2092 nameeq = ckmalloc(namelen + vallen + 2);
2093 p = (char *)memcpy(nameeq, name, namelen) + namelen;
2096 p = (char *)memcpy(p, val, vallen) + vallen;
2099 setvareq(nameeq, flags | VNOSAVE);
2103 #if ENABLE_ASH_GETOPTS
2105 * Safe version of setvar, returns 1 on success 0 on failure.
2108 setvarsafe(const char *name, const char *val, int flags)
2111 volatile int saveint;
2112 struct jmploc *volatile savehandler = exception_handler;
2113 struct jmploc jmploc;
2116 if (setjmp(jmploc.loc))
2119 exception_handler = &jmploc;
2120 setvar(name, val, flags);
2123 exception_handler = savehandler;
2124 RESTORE_INT(saveint);
2130 * Unset the specified variable.
2133 unsetvar(const char *s)
2139 vpp = findvar(hashvar(s), s);
2143 int flags = vp->flags;
2146 if (flags & VREADONLY)
2148 #if ENABLE_ASH_RANDOM_SUPPORT
2149 vp->flags &= ~VDYNAMIC;
2153 if ((flags & VSTRFIXED) == 0) {
2155 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2156 free((char*)vp->text);
2162 vp->flags &= ~VEXPORT;
2172 * Process a linked list of variable assignments.
2175 listsetvar(struct strlist *list_set_var, int flags)
2177 struct strlist *lp = list_set_var;
2183 setvareq(lp->text, flags);
2190 * Generate a list of variables satisfying the given conditions.
2193 listvars(int on, int off, char ***end)
2204 for (vp = *vpp; vp; vp = vp->next) {
2205 if ((vp->flags & mask) == on) {
2206 if (ep == stackstrend())
2207 ep = growstackstr();
2208 *ep++ = (char *) vp->text;
2211 } while (++vpp < vartab + VTABSIZE);
2212 if (ep == stackstrend())
2213 ep = growstackstr();
2217 return grabstackstr(ep);
2221 /* ============ Path search helper
2223 * The variable path (passed by reference) should be set to the start
2224 * of the path before the first call; padvance will update
2225 * this value as it proceeds. Successive calls to padvance will return
2226 * the possible path expansions in sequence. If an option (indicated by
2227 * a percent sign) appears in the path entry then the global variable
2228 * pathopt will be set to point to it; otherwise pathopt will be set to
2231 static const char *pathopt; /* set by padvance */
2234 padvance(const char **path, const char *name)
2244 for (p = start; *p && *p != ':' && *p != '%'; p++)
2246 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2247 while (stackblocksize() < len)
2251 memcpy(q, start, p - start);
2259 while (*p && *p != ':')
2266 return stalloc(len);
2270 /* ============ Prompt */
2272 static smallint doprompt; /* if set, prompt the user */
2273 static smallint needprompt; /* true if interactive and at start of line */
2275 #if ENABLE_FEATURE_EDITING
2276 static line_input_t *line_input_state;
2277 static const char *cmdedit_prompt;
2279 putprompt(const char *s)
2281 if (ENABLE_ASH_EXPAND_PRMT) {
2282 free((char*)cmdedit_prompt);
2283 cmdedit_prompt = ckstrdup(s);
2290 putprompt(const char *s)
2296 #if ENABLE_ASH_EXPAND_PRMT
2297 /* expandstr() needs parsing machinery, so it is far away ahead... */
2298 static const char *expandstr(const char *ps);
2300 #define expandstr(s) s
2304 setprompt(int whichprompt)
2307 #if ENABLE_ASH_EXPAND_PRMT
2308 struct stackmark smark;
2313 switch (whichprompt) {
2323 #if ENABLE_ASH_EXPAND_PRMT
2324 setstackmark(&smark);
2325 stalloc(stackblocksize());
2327 putprompt(expandstr(prompt));
2328 #if ENABLE_ASH_EXPAND_PRMT
2329 popstackmark(&smark);
2334 /* ============ The cd and pwd commands */
2336 #define CD_PHYSICAL 1
2339 static int docd(const char *, int);
2348 while ((i = nextopt("LP"))) {
2350 flags ^= CD_PHYSICAL;
2359 * Update curdir (the name of the current directory) in response to a
2363 updatepwd(const char *dir)
2370 cdcomppath = ststrdup(dir);
2373 if (curdir == nullstr)
2375 new = stack_putstr(curdir, new);
2377 new = makestrspace(strlen(dir) + 2, new);
2378 lim = (char *)stackblock() + 1;
2382 if (new > lim && *lim == '/')
2387 if (dir[1] == '/' && dir[2] != '/') {
2393 p = strtok(cdcomppath, "/");
2397 if (p[1] == '.' && p[2] == '\0') {
2409 new = stack_putstr(p, new);
2417 return stackblock();
2421 * Find out what the current directory is. If we already know the current
2422 * directory, this routine returns immediately.
2427 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2428 return dir ? dir : nullstr;
2432 setpwd(const char *val, int setold)
2436 oldcur = dir = curdir;
2439 setvar("OLDPWD", oldcur, VEXPORT);
2442 if (physdir != nullstr) {
2443 if (physdir != oldcur)
2447 if (oldcur == val || !val) {
2453 dir = ckstrdup(val);
2454 if (oldcur != dir && oldcur != nullstr) {
2459 setvar("PWD", dir, VEXPORT);
2462 static void hashcd(void);
2465 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2466 * know that the current directory has changed.
2469 docd(const char *dest, int flags)
2471 const char *dir = 0;
2474 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2477 if (!(flags & CD_PHYSICAL)) {
2478 dir = updatepwd(dest);
2493 cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2505 dest = bltinlookup(homestr);
2506 else if (LONE_DASH(dest)) {
2507 dest = bltinlookup("OLDPWD");
2529 path = bltinlookup("CDPATH");
2538 p = padvance(&path, dest);
2539 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2543 if (!docd(p, flags))
2548 ash_msg_and_raise_error("can't cd to %s", dest);
2551 if (flags & CD_PRINT)
2552 out1fmt(snlfmt, curdir);
2557 pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2560 const char *dir = curdir;
2564 if (physdir == nullstr)
2568 out1fmt(snlfmt, dir);
2573 /* ============ ... */
2575 #define IBUFSIZ COMMON_BUFSIZE
2576 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */
2578 /* Syntax classes */
2579 #define CWORD 0 /* character is nothing special */
2580 #define CNL 1 /* newline character */
2581 #define CBACK 2 /* a backslash character */
2582 #define CSQUOTE 3 /* single quote */
2583 #define CDQUOTE 4 /* double quote */
2584 #define CENDQUOTE 5 /* a terminating quote */
2585 #define CBQUOTE 6 /* backwards single quote */
2586 #define CVAR 7 /* a dollar sign */
2587 #define CENDVAR 8 /* a '}' character */
2588 #define CLP 9 /* a left paren in arithmetic */
2589 #define CRP 10 /* a right paren in arithmetic */
2590 #define CENDFILE 11 /* end of file */
2591 #define CCTL 12 /* like CWORD, except it must be escaped */
2592 #define CSPCL 13 /* these terminate a word */
2593 #define CIGN 14 /* character should be ignored */
2595 #if ENABLE_ASH_ALIAS
2599 #define PEOA_OR_PEOF PEOA
2603 #define PEOA_OR_PEOF PEOF
2606 /* number syntax index */
2607 #define BASESYNTAX 0 /* not in quotes */
2608 #define DQSYNTAX 1 /* in double quotes */
2609 #define SQSYNTAX 2 /* in single quotes */
2610 #define ARISYNTAX 3 /* in arithmetic */
2611 #define PSSYNTAX 4 /* prompt */
2613 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
2614 #define USE_SIT_FUNCTION
2617 #if ENABLE_ASH_MATH_SUPPORT
2618 static const char S_I_T[][4] = {
2619 #if ENABLE_ASH_ALIAS
2620 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */
2622 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */
2623 { CNL, CNL, CNL, CNL }, /* 2, \n */
2624 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */
2625 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */
2626 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */
2627 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */
2628 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */
2629 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */
2630 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */
2631 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */
2632 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */
2633 #ifndef USE_SIT_FUNCTION
2634 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2635 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2636 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2640 static const char S_I_T[][3] = {
2641 #if ENABLE_ASH_ALIAS
2642 { CSPCL, CIGN, CIGN }, /* 0, PEOA */
2644 { CSPCL, CWORD, CWORD }, /* 1, ' ' */
2645 { CNL, CNL, CNL }, /* 2, \n */
2646 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */
2647 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */
2648 { CVAR, CVAR, CWORD }, /* 5, $ */
2649 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */
2650 { CSPCL, CWORD, CWORD }, /* 7, ( */
2651 { CSPCL, CWORD, CWORD }, /* 8, ) */
2652 { CBACK, CBACK, CCTL }, /* 9, \ */
2653 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */
2654 { CENDVAR, CENDVAR, CWORD }, /* 11, } */
2655 #ifndef USE_SIT_FUNCTION
2656 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2657 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2658 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2661 #endif /* ASH_MATH_SUPPORT */
2663 #ifdef USE_SIT_FUNCTION
2666 SIT(int c, int syntax)
2668 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2669 #if ENABLE_ASH_ALIAS
2670 static const char syntax_index_table[] ALIGN1 = {
2671 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2672 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2673 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2677 static const char syntax_index_table[] ALIGN1 = {
2678 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2679 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2680 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2687 if (c == PEOF) /* 2^8+2 */
2689 #if ENABLE_ASH_ALIAS
2690 if (c == PEOA) /* 2^8+1 */
2694 #define U_C(c) ((unsigned char)(c))
2696 if ((unsigned char)c >= (unsigned char)(CTLESC)
2697 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
2701 s = strchrnul(spec_symbls, c);
2704 indx = syntax_index_table[s - spec_symbls];
2706 return S_I_T[indx][syntax];
2709 #else /* !USE_SIT_FUNCTION */
2711 #if ENABLE_ASH_ALIAS
2712 #define CSPCL_CIGN_CIGN_CIGN 0
2713 #define CSPCL_CWORD_CWORD_CWORD 1
2714 #define CNL_CNL_CNL_CNL 2
2715 #define CWORD_CCTL_CCTL_CWORD 3
2716 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
2717 #define CVAR_CVAR_CWORD_CVAR 5
2718 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
2719 #define CSPCL_CWORD_CWORD_CLP 7
2720 #define CSPCL_CWORD_CWORD_CRP 8
2721 #define CBACK_CBACK_CCTL_CBACK 9
2722 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
2723 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
2724 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
2725 #define CWORD_CWORD_CWORD_CWORD 13
2726 #define CCTL_CCTL_CCTL_CCTL 14
2728 #define CSPCL_CWORD_CWORD_CWORD 0
2729 #define CNL_CNL_CNL_CNL 1
2730 #define CWORD_CCTL_CCTL_CWORD 2
2731 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
2732 #define CVAR_CVAR_CWORD_CVAR 4
2733 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
2734 #define CSPCL_CWORD_CWORD_CLP 6
2735 #define CSPCL_CWORD_CWORD_CRP 7
2736 #define CBACK_CBACK_CCTL_CBACK 8
2737 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
2738 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
2739 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
2740 #define CWORD_CWORD_CWORD_CWORD 12
2741 #define CCTL_CCTL_CCTL_CCTL 13
2744 static const char syntax_index_table[258] = {
2745 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2746 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2747 #if ENABLE_ASH_ALIAS
2748 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
2750 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2751 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2752 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2753 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2754 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2755 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2756 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2757 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2758 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2759 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
2760 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
2761 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
2762 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
2763 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
2764 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
2765 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
2766 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
2767 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
2768 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
2769 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
2770 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
2771 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
2772 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
2773 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
2774 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
2775 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
2776 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
2777 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
2778 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
2779 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
2780 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
2781 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
2782 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
2783 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
2784 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
2785 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
2786 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
2787 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
2788 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
2789 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
2790 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
2791 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
2792 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
2793 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
2794 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
2795 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
2796 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
2797 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
2798 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
2799 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
2800 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
2801 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
2802 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
2803 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
2804 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
2805 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
2806 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
2807 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
2808 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
2809 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
2810 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
2811 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
2812 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
2813 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
2814 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
2815 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
2816 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
2817 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
2818 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
2819 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
2820 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
2821 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
2822 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
2823 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
2824 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
2825 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
2826 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
2827 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
2828 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
2829 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
2830 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
2831 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
2832 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
2833 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
2834 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
2835 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
2836 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
2837 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
2838 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
2839 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
2840 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
2841 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
2842 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
2843 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
2844 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
2845 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
2846 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
2847 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
2848 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
2853 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
2854 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2888 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
2889 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
2898 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
2899 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
2900 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
2901 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
2902 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
2903 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
2904 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
2905 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
2906 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
2907 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
2908 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
2909 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
2910 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2911 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2912 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2913 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2915 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2917 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2918 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2919 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2920 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2921 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
2923 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2924 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
2925 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2926 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2937 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2938 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2939 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2940 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2941 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2942 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2970 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2971 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2972 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2975 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3003 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3004 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3005 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
3008 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])
3010 #endif /* USE_SIT_FUNCTION */
3013 /* ============ Alias handling */
3015 #if ENABLE_ASH_ALIAS
3017 #define ALIASINUSE 1
3028 static struct alias **atab; // [ATABSIZE];
3029 #define INIT_G_alias() do { \
3030 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3034 static struct alias **
3035 __lookupalias(const char *name) {
3036 unsigned int hashval;
3043 ch = (unsigned char)*p;
3047 ch = (unsigned char)*++p;
3049 app = &atab[hashval % ATABSIZE];
3051 for (; *app; app = &(*app)->next) {
3052 if (strcmp(name, (*app)->name) == 0) {
3060 static struct alias *
3061 lookupalias(const char *name, int check)
3063 struct alias *ap = *__lookupalias(name);
3065 if (check && ap && (ap->flag & ALIASINUSE))
3070 static struct alias *
3071 freealias(struct alias *ap)
3075 if (ap->flag & ALIASINUSE) {
3076 ap->flag |= ALIASDEAD;
3088 setalias(const char *name, const char *val)
3090 struct alias *ap, **app;
3092 app = __lookupalias(name);
3096 if (!(ap->flag & ALIASINUSE)) {
3099 ap->val = ckstrdup(val);
3100 ap->flag &= ~ALIASDEAD;
3103 ap = ckzalloc(sizeof(struct alias));
3104 ap->name = ckstrdup(name);
3105 ap->val = ckstrdup(val);
3106 /*ap->flag = 0; - ckzalloc did it */
3107 /*ap->next = NULL;*/
3114 unalias(const char *name)
3118 app = __lookupalias(name);
3122 *app = freealias(*app);
3133 struct alias *ap, **app;
3137 for (i = 0; i < ATABSIZE; i++) {
3139 for (ap = *app; ap; ap = *app) {
3140 *app = freealias(*app);
3150 printalias(const struct alias *ap)
3152 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3156 * TODO - sort output
3159 aliascmd(int argc UNUSED_PARAM, char **argv)
3168 for (i = 0; i < ATABSIZE; i++) {
3169 for (ap = atab[i]; ap; ap = ap->next) {
3175 while ((n = *++argv) != NULL) {
3176 v = strchr(n+1, '=');
3177 if (v == NULL) { /* n+1: funny ksh stuff */
3178 ap = *__lookupalias(n);
3180 fprintf(stderr, "%s: %s not found\n", "alias", n);
3194 unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3198 while ((i = nextopt("a")) != '\0') {
3204 for (i = 0; *argptr; argptr++) {
3205 if (unalias(*argptr)) {
3206 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3214 #endif /* ASH_ALIAS */
3217 /* ============ jobs.c */
3219 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3222 #define FORK_NOJOB 2
3224 /* mode flags for showjob(s) */
3225 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
3226 #define SHOW_PID 0x04 /* include process pid */
3227 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
3230 * A job structure contains information about a job. A job is either a
3231 * single process or a set of processes contained in a pipeline. In the
3232 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3237 pid_t pid; /* process id */
3238 int status; /* last process status from wait() */
3239 char *cmd; /* text of command being run */
3243 struct procstat ps0; /* status of process */
3244 struct procstat *ps; /* status or processes when more than one */
3246 int stopstatus; /* status of a stopped job */
3249 nprocs: 16, /* number of processes */
3251 #define JOBRUNNING 0 /* at least one proc running */
3252 #define JOBSTOPPED 1 /* all procs are stopped */
3253 #define JOBDONE 2 /* all procs are completed */
3255 sigint: 1, /* job was killed by SIGINT */
3256 jobctl: 1, /* job running under job control */
3258 waited: 1, /* true if this entry has been waited for */
3259 used: 1, /* true if this entry is in used */
3260 changed: 1; /* true if status has changed */
3261 struct job *prev_job; /* previous job */
3264 static struct job *makejob(/*union node *,*/ int);
3266 #define forkshell(job, node, mode) forkshell(job, mode)
3268 static int forkshell(struct job *, union node *, int);
3269 static int waitforjob(struct job *);
3272 enum { doing_jobctl = 0 };
3273 #define setjobctl(on) do {} while (0)
3275 static smallint doing_jobctl; //references:8
3276 static void setjobctl(int);
3280 * Set the signal handler for the specified signal. The routine figures
3281 * out what it should be set to.
3284 setsignal(int signo)
3288 struct sigaction act;
3294 else if (*t != '\0')
3296 if (rootshell && action == S_DFL) {
3299 if (iflag || minusc || sflag == 0)
3322 t = &sigmode[signo - 1];
3326 * current setting unknown
3328 if (sigaction(signo, NULL, &act) == -1) {
3330 * Pretend it worked; maybe we should give a warning
3331 * here, but other shells don't. We don't alter
3332 * sigmode, so that we retry every time.
3336 tsig = S_RESET; /* force to be set */
3337 if (act.sa_handler == SIG_IGN) {
3340 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3342 tsig = S_IGN; /* don't hard ignore these */
3346 if (tsig == S_HARD_IGN || tsig == action)
3348 act.sa_handler = SIG_DFL;
3351 act.sa_handler = onsig;
3354 act.sa_handler = SIG_IGN;
3359 sigfillset(&act.sa_mask);
3360 sigaction_set(signo, &act);
3363 /* mode flags for set_curjob */
3364 #define CUR_DELETE 2
3365 #define CUR_RUNNING 1
3366 #define CUR_STOPPED 0
3368 /* mode flags for dowait */
3369 #define DOWAIT_NONBLOCK WNOHANG
3370 #define DOWAIT_BLOCK 0
3373 /* pgrp of shell on invocation */
3374 static int initialpgrp; //references:2
3375 static int ttyfd = -1; //5
3378 static struct job *jobtab; //5
3380 static unsigned njobs; //4
3382 static struct job *curjob; //lots
3383 /* number of presumed living untracked jobs */
3384 static int jobless; //4
3387 set_curjob(struct job *jp, unsigned mode)
3390 struct job **jpp, **curp;
3392 /* first remove from list */
3393 jpp = curp = &curjob;
3398 jpp = &jp1->prev_job;
3400 *jpp = jp1->prev_job;
3402 /* Then re-insert in correct position */
3410 /* job being deleted */
3413 /* newly created job or backgrounded job,
3414 put after all stopped jobs. */
3418 if (!jp1 || jp1->state != JOBSTOPPED)
3421 jpp = &jp1->prev_job;
3427 /* newly stopped job - becomes curjob */
3428 jp->prev_job = *jpp;
3436 jobno(const struct job *jp)
3438 return jp - jobtab + 1;
3443 * Convert a job name to a job structure.
3446 #define getjob(name, getctl) getjob(name)
3449 getjob(const char *name, int getctl)
3453 const char *err_msg = "No such job: %s";
3457 char *(*match)(const char *, const char *);
3472 if (c == '+' || c == '%') {
3474 err_msg = "No current job";
3480 err_msg = "No previous job";
3489 // TODO: number() instead? It does error checking...
3492 jp = jobtab + num - 1;
3509 if (match(jp->ps[0].cmd, p)) {
3513 err_msg = "%s: ambiguous";
3520 err_msg = "job %s not created under job control";
3521 if (getctl && jp->jobctl == 0)
3526 ash_msg_and_raise_error(err_msg, name);
3530 * Mark a job structure as unused.
3533 freejob(struct job *jp)
3535 struct procstat *ps;
3539 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3540 if (ps->cmd != nullstr)
3543 if (jp->ps != &jp->ps0)
3546 set_curjob(jp, CUR_DELETE);
3552 xtcsetpgrp(int fd, pid_t pgrp)
3554 if (tcsetpgrp(fd, pgrp))
3555 ash_msg_and_raise_error("can't set tty process group (%m)");
3559 * Turn job control on and off.
3561 * Note: This code assumes that the third arg to ioctl is a character
3562 * pointer, which is true on Berkeley systems but not System V. Since
3563 * System V doesn't have job control yet, this isn't a problem now.
3565 * Called with interrupts off.
3573 if (on == doing_jobctl || rootshell == 0)
3577 ofd = fd = open(_PATH_TTY, O_RDWR);
3579 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3580 * That sometimes helps to acquire controlling tty.
3581 * Obviously, a workaround for bugs when someone
3582 * failed to provide a controlling tty to bash! :) */
3588 fd = fcntl(fd, F_DUPFD, 10);
3593 /* fd is a tty at this point */
3594 close_on_exec_on(fd);
3595 do { /* while we are in the background */
3596 pgrp = tcgetpgrp(fd);
3599 ash_msg("can't access tty; job control turned off");
3603 if (pgrp == getpgrp())
3614 xtcsetpgrp(fd, pgrp);
3616 /* turning job control off */
3619 /* was xtcsetpgrp, but this can make exiting ash
3620 * loop forever if pty is already deleted */
3621 tcsetpgrp(fd, pgrp);
3636 killcmd(int argc, char **argv)
3639 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3641 if (argv[i][0] == '%') {
3642 struct job *jp = getjob(argv[i], 0);
3643 unsigned pid = jp->ps[0].pid;
3644 /* Enough space for ' -NNN<nul>' */
3645 argv[i] = alloca(sizeof(int)*3 + 3);
3646 /* kill_main has matching code to expect
3647 * leading space. Needed to not confuse
3648 * negative pids with "kill -SIGNAL_NO" syntax */
3649 sprintf(argv[i], " -%u", pid);
3651 } while (argv[++i]);
3653 return kill_main(argc, argv);
3657 showpipe(struct job *jp, FILE *out)
3659 struct procstat *sp;
3660 struct procstat *spend;
3662 spend = jp->ps + jp->nprocs;
3663 for (sp = jp->ps + 1; sp < spend; sp++)
3664 fprintf(out, " | %s", sp->cmd);
3665 outcslow('\n', out);
3666 flush_stdout_stderr();
3671 restartjob(struct job *jp, int mode)
3673 struct procstat *ps;
3679 if (jp->state == JOBDONE)
3681 jp->state = JOBRUNNING;
3683 if (mode == FORK_FG)
3684 xtcsetpgrp(ttyfd, pgid);
3685 killpg(pgid, SIGCONT);
3689 if (WIFSTOPPED(ps->status)) {
3695 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3701 fg_bgcmd(int argc UNUSED_PARAM, char **argv)
3708 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3713 jp = getjob(*argv, 1);
3714 if (mode == FORK_BG) {
3715 set_curjob(jp, CUR_RUNNING);
3716 fprintf(out, "[%d] ", jobno(jp));
3718 outstr(jp->ps->cmd, out);
3720 retval = restartjob(jp, mode);
3721 } while (*argv && *++argv);
3727 sprint_status(char *s, int status, int sigonly)
3733 if (!WIFEXITED(status)) {
3735 if (WIFSTOPPED(status))
3736 st = WSTOPSIG(status);
3739 st = WTERMSIG(status);
3741 if (st == SIGINT || st == SIGPIPE)
3744 if (WIFSTOPPED(status))
3749 col = fmtstr(s, 32, strsignal(st));
3750 if (WCOREDUMP(status)) {
3751 col += fmtstr(s + col, 16, " (core dumped)");
3753 } else if (!sigonly) {
3754 st = WEXITSTATUS(status);
3756 col = fmtstr(s, 16, "Done(%d)", st);
3758 col = fmtstr(s, 16, "Done");
3765 * Do a wait system call. If job control is compiled in, we accept
3766 * stopped processes. If block is zero, we return a value of zero
3767 * rather than blocking.
3769 * System V doesn't have a non-blocking wait system call. It does
3770 * have a SIGCLD signal that is sent to a process when one of it's
3771 * children dies. The obvious way to use SIGCLD would be to install
3772 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
3773 * was received, and have waitproc bump another counter when it got
3774 * the status of a process. Waitproc would then know that a wait
3775 * system call would not block if the two counters were different.
3776 * This approach doesn't work because if a process has children that
3777 * have not been waited for, System V will send it a SIGCLD when it
3778 * installs a signal handler for SIGCLD. What this means is that when
3779 * a child exits, the shell will be sent SIGCLD signals continuously
3780 * until is runs out of stack space, unless it does a wait call before
3781 * restoring the signal handler. The code below takes advantage of
3782 * this (mis)feature by installing a signal handler for SIGCLD and
3783 * then checking to see whether it was called. If there are any
3784 * children to be waited for, it will be.
3786 * If neither SYSV nor BSD is defined, we don't implement nonblocking
3787 * waits at all. In this case, the user will not be informed when
3788 * a background process until the next time she runs a real program
3789 * (as opposed to running a builtin command or just typing return),
3790 * and the jobs command may give out of date information.
3793 waitproc(int wait_flags, int *status)
3797 wait_flags |= WUNTRACED;
3799 /* NB: _not_ safe_waitpid, we need to detect EINTR */
3800 return waitpid(-1, status, wait_flags);
3804 * Wait for a process to terminate.
3807 dowait(int wait_flags, struct job *job)
3812 struct job *thisjob;
3815 TRACE(("dowait(%d) called\n", wait_flags));
3816 pid = waitproc(wait_flags, &status);
3817 TRACE(("wait returns pid=%d, status=%d\n", pid, status));
3819 /* If we were doing blocking wait and (probably) got EINTR,
3820 * check for pending sigs received while waiting.
3821 * (NB: can be moved into callers if needed) */
3822 if (wait_flags == DOWAIT_BLOCK && pendingsig)
3823 raise_exception(EXSIG);
3828 for (jp = curjob; jp; jp = jp->prev_job) {
3829 struct procstat *sp;
3830 struct procstat *spend;
3831 if (jp->state == JOBDONE)
3834 spend = jp->ps + jp->nprocs;
3837 if (sp->pid == pid) {
3838 TRACE(("Job %d: changing status of proc %d "
3839 "from 0x%x to 0x%x\n",
3840 jobno(jp), pid, sp->status, status));
3841 sp->status = status;
3844 if (sp->status == -1)
3847 if (state == JOBRUNNING)
3849 if (WIFSTOPPED(sp->status)) {
3850 jp->stopstatus = sp->status;
3854 } while (++sp < spend);
3859 if (!WIFSTOPPED(status))
3865 if (state != JOBRUNNING) {
3866 thisjob->changed = 1;
3868 if (thisjob->state != state) {
3869 TRACE(("Job %d: changing state from %d to %d\n",
3870 jobno(thisjob), thisjob->state, state));
3871 thisjob->state = state;
3873 if (state == JOBSTOPPED) {
3874 set_curjob(thisjob, CUR_STOPPED);
3883 if (thisjob && thisjob == job) {
3887 len = sprint_status(s, status, 1);
3899 showjob(FILE *out, struct job *jp, int mode)
3901 struct procstat *ps;
3902 struct procstat *psend;
3909 if (mode & SHOW_PGID) {
3910 /* just output process (group) id of pipeline */
3911 fprintf(out, "%d\n", ps->pid);
3915 col = fmtstr(s, 16, "[%d] ", jobno(jp));
3920 else if (curjob && jp == curjob->prev_job)
3923 if (mode & SHOW_PID)
3924 col += fmtstr(s + col, 16, "%d ", ps->pid);
3926 psend = ps + jp->nprocs;
3928 if (jp->state == JOBRUNNING) {
3929 strcpy(s + col, "Running");
3930 col += sizeof("Running") - 1;
3932 int status = psend[-1].status;
3933 if (jp->state == JOBSTOPPED)
3934 status = jp->stopstatus;
3935 col += sprint_status(s + col, status, 0);
3941 /* for each process */
3942 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
3944 fprintf(out, "%s%*c%s",
3945 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
3947 if (!(mode & SHOW_PID)) {
3951 if (++ps == psend) {
3952 outcslow('\n', out);
3959 if (jp->state == JOBDONE) {
3960 TRACE(("showjob: freeing job %d\n", jobno(jp)));
3966 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3967 * statuses have changed since the last call to showjobs.
3970 showjobs(FILE *out, int mode)
3974 TRACE(("showjobs(%x) called\n", mode));
3976 /* If not even one job changed, there is nothing to do */
3977 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3980 for (jp = curjob; jp; jp = jp->prev_job) {
3981 if (!(mode & SHOW_CHANGED) || jp->changed) {
3982 showjob(out, jp, mode);
3988 jobscmd(int argc UNUSED_PARAM, char **argv)
3993 while ((m = nextopt("lp"))) {
4003 showjob(stdout, getjob(*argv,0), mode);
4006 showjobs(stdout, mode);
4013 getstatus(struct job *job)
4018 status = job->ps[job->nprocs - 1].status;
4019 retval = WEXITSTATUS(status);
4020 if (!WIFEXITED(status)) {
4022 retval = WSTOPSIG(status);
4023 if (!WIFSTOPPED(status))
4026 /* XXX: limits number of signals */
4027 retval = WTERMSIG(status);
4029 if (retval == SIGINT)
4035 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
4036 jobno(job), job->nprocs, status, retval));
4041 waitcmd(int argc UNUSED_PARAM, char **argv)
4050 raise_exception(EXSIG);
4057 /* wait for all jobs */
4061 if (!jp) /* no running procs */
4063 if (jp->state == JOBRUNNING)
4068 dowait(DOWAIT_BLOCK, NULL);
4074 if (**argv != '%') {
4075 pid_t pid = number(*argv);
4080 if (job->ps[job->nprocs - 1].pid == pid)
4082 job = job->prev_job;
4085 job = getjob(*argv, 0);
4086 /* loop until process terminated or stopped */
4087 while (job->state == JOBRUNNING)
4088 dowait(DOWAIT_BLOCK, NULL);
4090 retval = getstatus(job);
4104 struct job *jp, *jq;
4106 len = njobs * sizeof(*jp);
4108 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4110 offset = (char *)jp - (char *)jq;
4112 /* Relocate pointers */
4115 jq = (struct job *)((char *)jq + l);
4119 #define joff(p) ((struct job *)((char *)(p) + l))
4120 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4121 if (joff(jp)->ps == &jq->ps0)
4122 jmove(joff(jp)->ps);
4123 if (joff(jp)->prev_job)
4124 jmove(joff(jp)->prev_job);
4134 jp = (struct job *)((char *)jp + len);
4138 } while (--jq >= jp);
4143 * Return a new job structure.
4144 * Called with interrupts off.
4147 makejob(/*union node *node,*/ int nprocs)
4152 for (i = njobs, jp = jobtab; ; jp++) {
4159 if (jp->state != JOBDONE || !jp->waited)
4168 memset(jp, 0, sizeof(*jp));
4170 /* jp->jobctl is a bitfield.
4171 * "jp->jobctl |= jobctl" likely to give awful code */
4175 jp->prev_job = curjob;
4180 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4182 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4189 * Return a string identifying a command (to be printed by the
4192 static char *cmdnextc;
4195 cmdputs(const char *s)
4197 static const char vstype[VSTYPE + 1][3] = {
4198 "", "}", "-", "+", "?", "=",
4199 "%", "%%", "#", "##"
4200 USE_ASH_BASH_COMPAT(, ":", "/", "//")
4203 const char *p, *str;
4204 char c, cc[2] = " ";
4209 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4211 while ((c = *p++) != 0) {
4219 if ((subtype & VSTYPE) == VSLENGTH)
4223 if (!(subtype & VSQUOTE) == !(quoted & 1))
4229 str = "\"}" + !(quoted & 1);
4236 case CTLBACKQ+CTLQUOTE:
4239 #if ENABLE_ASH_MATH_SUPPORT
4254 if ((subtype & VSTYPE) != VSNORMAL)
4256 str = vstype[subtype & VSTYPE];
4257 if (subtype & VSNUL)
4266 /* These can only happen inside quotes */
4279 while ((c = *str++)) {
4284 USTPUTC('"', nextc);
4290 /* cmdtxt() and cmdlist() call each other */
4291 static void cmdtxt(union node *n);
4294 cmdlist(union node *np, int sep)
4296 for (; np; np = np->narg.next) {
4300 if (sep && np->narg.next)
4306 cmdtxt(union node *n)
4309 struct nodelist *lp;
4320 lp = n->npipe.cmdlist;
4338 cmdtxt(n->nbinary.ch1);
4354 cmdtxt(n->nif.test);
4357 if (n->nif.elsepart) {
4360 n = n->nif.elsepart;
4376 cmdtxt(n->nbinary.ch1);
4386 cmdputs(n->nfor.var);
4388 cmdlist(n->nfor.args, 1);
4393 cmdputs(n->narg.text);
4397 cmdlist(n->ncmd.args, 1);
4398 cmdlist(n->ncmd.redirect, 0);
4411 cmdputs(n->ncase.expr->narg.text);
4413 for (np = n->ncase.cases; np; np = np->nclist.next) {
4414 cmdtxt(np->nclist.pattern);
4416 cmdtxt(np->nclist.body);
4430 #if ENABLE_ASH_BASH_COMPAT
4445 cmdputs(utoa(n->nfile.fd));
4447 if (n->type == NTOFD || n->type == NFROMFD) {
4448 cmdputs(utoa(n->ndup.dupfd));
4457 commandtext(union node *n)
4461 STARTSTACKSTR(cmdnextc);
4463 name = stackblock();
4464 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4465 name, cmdnextc, cmdnextc));
4466 return ckstrdup(name);
4471 * Fork off a subshell. If we are doing job control, give the subshell its
4472 * own process group. Jp is a job structure that the job is to be added to.
4473 * N is the command that will be evaluated by the child. Both jp and n may
4474 * be NULL. The mode parameter can be one of the following:
4475 * FORK_FG - Fork off a foreground process.
4476 * FORK_BG - Fork off a background process.
4477 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4478 * process group even if job control is on.
4480 * When job control is turned off, background processes have their standard
4481 * input redirected to /dev/null (except for the second and later processes
4484 * Called with interrupts off.
4487 * Clear traps on a fork.
4494 for (tp = trap; tp < &trap[NSIG]; tp++) {
4495 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4500 setsignal(tp - trap);
4506 /* Lives far away from here, needed for forkchild */
4507 static void closescript(void);
4509 /* Called after fork(), in child */
4511 forkchild(struct job *jp, /*union node *n,*/ int mode)
4515 TRACE(("Child shell %d\n", getpid()));
4522 /* do job control only in root shell */
4524 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4527 if (jp->nprocs == 0)
4530 pgrp = jp->ps[0].pid;
4531 /* This can fail because we are doing it in the parent also */
4532 (void)setpgid(0, pgrp);
4533 if (mode == FORK_FG)
4534 xtcsetpgrp(ttyfd, pgrp);
4539 if (mode == FORK_BG) {
4542 if (jp->nprocs == 0) {
4544 if (open(bb_dev_null, O_RDONLY) != 0)
4545 ash_msg_and_raise_error("can't open %s", bb_dev_null);
4548 if (!oldlvl && iflag) {
4553 for (jp = curjob; jp; jp = jp->prev_job)
4558 /* Called after fork(), in parent */
4560 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4563 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4565 TRACE(("In parent shell: child = %d\n", pid));
4567 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4573 if (mode != FORK_NOJOB && jp->jobctl) {
4576 if (jp->nprocs == 0)
4579 pgrp = jp->ps[0].pid;
4580 /* This can fail because we are doing it in the child also */
4584 if (mode == FORK_BG) {
4585 backgndpid = pid; /* set $! */
4586 set_curjob(jp, CUR_RUNNING);
4589 struct procstat *ps = &jp->ps[jp->nprocs++];
4594 if (doing_jobctl && n)
4595 ps->cmd = commandtext(n);
4601 forkshell(struct job *jp, union node *n, int mode)
4605 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4608 TRACE(("Fork failed, errno=%d", errno));
4611 ash_msg_and_raise_error("can't fork");
4614 forkchild(jp, /*n,*/ mode);
4616 forkparent(jp, n, mode, pid);
4621 * Wait for job to finish.
4623 * Under job control we have the problem that while a child process is
4624 * running interrupts generated by the user are sent to the child but not
4625 * to the shell. This means that an infinite loop started by an inter-
4626 * active user may be hard to kill. With job control turned off, an
4627 * interactive user may place an interactive program inside a loop. If
4628 * the interactive program catches interrupts, the user doesn't want
4629 * these interrupts to also abort the loop. The approach we take here
4630 * is to have the shell ignore interrupt signals while waiting for a
4631 * foreground process to terminate, and then send itself an interrupt
4632 * signal if the child process was terminated by an interrupt signal.
4633 * Unfortunately, some programs want to do a bit of cleanup and then
4634 * exit on interrupt; unless these processes terminate themselves by
4635 * sending a signal to themselves (instead of calling exit) they will
4636 * confuse this approach.
4638 * Called with interrupts off.
4641 waitforjob(struct job *jp)
4645 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4646 while (jp->state == JOBRUNNING) {
4647 dowait(DOWAIT_BLOCK, jp);
4652 xtcsetpgrp(ttyfd, rootpid);
4654 * This is truly gross.
4655 * If we're doing job control, then we did a TIOCSPGRP which
4656 * caused us (the shell) to no longer be in the controlling
4657 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4658 * intuit from the subprocess exit status whether a SIGINT
4659 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4661 if (jp->sigint) /* TODO: do the same with all signals */
4662 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4664 if (jp->state == JOBDONE)
4671 * return 1 if there are stopped jobs, otherwise 0
4683 if (jp && jp->state == JOBSTOPPED) {
4684 out2str("You have stopped jobs.\n");
4693 /* ============ redir.c
4695 * Code for dealing with input/output redirection.
4698 #define EMPTY -2 /* marks an unused slot in redirtab */
4699 #define CLOSED -3 /* marks a slot of previously-closed fd */
4702 * Open a file in noclobber mode.
4703 * The code was copied from bash.
4706 noclobberopen(const char *fname)
4709 struct stat finfo, finfo2;
4712 * If the file exists and is a regular file, return an error
4715 r = stat(fname, &finfo);
4716 if (r == 0 && S_ISREG(finfo.st_mode)) {
4722 * If the file was not present (r != 0), make sure we open it
4723 * exclusively so that if it is created before we open it, our open
4724 * will fail. Make sure that we do not truncate an existing file.
4725 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4726 * file was not a regular file, we leave O_EXCL off.
4729 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4730 fd = open(fname, O_WRONLY|O_CREAT, 0666);
4732 /* If the open failed, return the file descriptor right away. */
4737 * OK, the open succeeded, but the file may have been changed from a
4738 * non-regular file to a regular file between the stat and the open.
4739 * We are assuming that the O_EXCL open handles the case where FILENAME
4740 * did not exist and is symlinked to an existing file between the stat
4745 * If we can open it and fstat the file descriptor, and neither check
4746 * revealed that it was a regular file, and the file has not been
4747 * replaced, return the file descriptor.
4749 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4750 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4753 /* The file has been replaced. badness. */
4760 * Handle here documents. Normally we fork off a process to write the
4761 * data to a pipe. If the document is short, we can stuff the data in
4762 * the pipe without forking.
4764 /* openhere needs this forward reference */
4765 static void expandhere(union node *arg, int fd);
4767 openhere(union node *redir)
4773 ash_msg_and_raise_error("pipe call failed");
4774 if (redir->type == NHERE) {
4775 len = strlen(redir->nhere.doc->narg.text);
4776 if (len <= PIPE_BUF) {
4777 full_write(pip[1], redir->nhere.doc->narg.text, len);
4781 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4784 signal(SIGINT, SIG_IGN);
4785 signal(SIGQUIT, SIG_IGN);
4786 signal(SIGHUP, SIG_IGN);
4788 signal(SIGTSTP, SIG_IGN);
4790 signal(SIGPIPE, SIG_DFL);
4791 if (redir->type == NHERE)
4792 full_write(pip[1], redir->nhere.doc->narg.text, len);
4794 expandhere(redir->nhere.doc, pip[1]);
4795 _exit(EXIT_SUCCESS);
4803 openredirect(union node *redir)
4808 switch (redir->nfile.type) {
4810 fname = redir->nfile.expfname;
4811 f = open(fname, O_RDONLY);
4816 fname = redir->nfile.expfname;
4817 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
4822 #if ENABLE_ASH_BASH_COMPAT
4825 /* Take care of noclobber mode. */
4827 fname = redir->nfile.expfname;
4828 f = noclobberopen(fname);
4835 fname = redir->nfile.expfname;
4836 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4841 fname = redir->nfile.expfname;
4842 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4850 /* Fall through to eliminate warning. */
4851 /* Our single caller does this itself */
4858 f = openhere(redir);
4864 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4866 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
4870 * Copy a file descriptor to be >= to. Returns -1
4871 * if the source file descriptor is closed, EMPTY if there are no unused
4872 * file descriptors left.
4874 /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
4875 * old code was doing close(to) prior to copyfd() to achieve the same */
4877 COPYFD_EXACT = (int)~(INT_MAX),
4878 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
4881 copyfd(int from, int to)
4885 if (to & COPYFD_EXACT) {
4886 to &= ~COPYFD_EXACT;
4888 newfd = dup2(from, to);
4890 newfd = fcntl(from, F_DUPFD, to);
4893 if (errno == EMFILE)
4895 /* Happens when source fd is not open: try "echo >&99" */
4896 ash_msg_and_raise_error("%d: %m", from);
4901 /* Struct def and variable are moved down to the first usage site */
4906 struct redirtab *next;
4909 struct two_fd_t two_fd[0];
4911 #define redirlist (G_var.redirlist)
4913 static int need_to_remember(struct redirtab *rp, int fd)
4917 if (!rp) /* remembering was not requested */
4920 for (i = 0; i < rp->pair_count; i++) {
4921 if (rp->two_fd[i].orig == fd) {
4922 /* already remembered */
4929 /* "hidden" fd is a fd used to read scripts, or a copy of such */
4930 static int is_hidden_fd(struct redirtab *rp, int fd)
4933 struct parsefile *pf;
4946 fd |= COPYFD_RESTORE;
4947 for (i = 0; i < rp->pair_count; i++) {
4948 if (rp->two_fd[i].copy == fd) {
4956 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
4957 * old file descriptors are stashed away so that the redirection can be
4958 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
4959 * standard output, and the standard error if it becomes a duplicate of
4960 * stdout, is saved in memory.
4962 /* flags passed to redirect */
4963 #define REDIR_PUSH 01 /* save previous values of file descriptors */
4964 #define REDIR_SAVEFD2 03 /* set preverrout */
4966 redirect(union node *redir, int flags)
4968 struct redirtab *sv;
4973 int copied_fd2 = -1;
4983 if (flags & REDIR_PUSH) {
4984 union node *tmp = redir;
4987 #if ENABLE_ASH_BASH_COMPAT
4988 if (redir->nfile.type == NTO2)
4991 tmp = tmp->nfile.next;
4993 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
4994 sv->next = redirlist;
4995 sv->pair_count = sv_pos;
4997 sv->nullredirs = g_nullredirs - 1;
4999 while (sv_pos > 0) {
5001 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5006 fd = redir->nfile.fd;
5007 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5008 int right_fd = redir->ndup.dupfd;
5009 /* redirect from/to same file descriptor? */
5012 /* echo >&10 and 10 is a fd opened to the sh script? */
5013 if (is_hidden_fd(sv, right_fd)) {
5014 errno = EBADF; /* as if it is closed */
5015 ash_msg_and_raise_error("%d: %m", right_fd);
5019 newfd = openredirect(redir); /* always >= 0 */
5021 /* Descriptor wasn't open before redirect.
5022 * Mark it for close in the future */
5023 if (need_to_remember(sv, fd)) {
5024 goto remember_to_close;
5029 #if ENABLE_ASH_BASH_COMPAT
5032 if (need_to_remember(sv, fd)) {
5033 /* Copy old descriptor */
5034 i = fcntl(fd, F_DUPFD, 10);
5035 /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5036 * are closed in popredir() in the child, preventing them from leaking
5037 * into child. (popredir() also cleans up the mess in case of failures)
5042 /* Strange error (e.g. "too many files" EMFILE?) */
5046 ash_msg_and_raise_error("%d: %m", fd);
5049 /* EBADF: it is not open - good, remember to close it */
5052 } else { /* fd is open, save its copy */
5053 /* "exec fd>&-" should not close fds
5054 * which point to script file(s).
5055 * Force them to be restored afterwards */
5056 if (is_hidden_fd(sv, fd))
5057 i |= COPYFD_RESTORE;
5061 sv->two_fd[sv_pos].orig = fd;
5062 sv->two_fd[sv_pos].copy = i;
5066 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5067 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5070 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
5072 } else if (fd != newfd) { /* move newfd to fd */
5073 copyfd(newfd, fd | COPYFD_EXACT);
5074 #if ENABLE_ASH_BASH_COMPAT
5075 if (!(redir->nfile.type == NTO2 && fd == 2))
5079 #if ENABLE_ASH_BASH_COMPAT
5080 if (redir->nfile.type == NTO2 && fd == 1) {
5081 /* We already redirected it to fd 1, now copy it to 2 */
5087 } while ((redir = redir->nfile.next) != NULL);
5090 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5091 preverrout_fd = copied_fd2;
5095 * Undo the effects of the last redirection.
5098 popredir(int drop, int restore)
5100 struct redirtab *rp;
5103 if (--g_nullredirs >= 0)
5107 for (i = 0; i < rp->pair_count; i++) {
5108 int fd = rp->two_fd[i].orig;
5109 int copy = rp->two_fd[i].copy;
5110 if (copy == CLOSED) {
5115 if (copy != EMPTY) {
5116 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5117 copy &= ~COPYFD_RESTORE;
5119 copyfd(copy, fd | COPYFD_EXACT);
5124 redirlist = rp->next;
5125 g_nullredirs = rp->nullredirs;
5131 * Undo all redirections. Called on error or interrupt.
5135 * Discard all saved file descriptors.
5138 clearredir(int drop)
5144 popredir(drop, /*restore:*/ 0);
5149 redirectsafe(union node *redir, int flags)
5152 volatile int saveint;
5153 struct jmploc *volatile savehandler = exception_handler;
5154 struct jmploc jmploc;
5157 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5158 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5160 exception_handler = &jmploc;
5161 redirect(redir, flags);
5163 exception_handler = savehandler;
5164 if (err && exception != EXERROR)
5165 longjmp(exception_handler->loc, 1);
5166 RESTORE_INT(saveint);
5171 /* ============ Routines to expand arguments to commands
5173 * We have to deal with backquotes, shell variables, and file metacharacters.
5176 #if ENABLE_ASH_MATH_SUPPORT_64
5177 typedef int64_t arith_t;
5178 #define arith_t_type long long
5180 typedef long arith_t;
5181 #define arith_t_type long
5184 #if ENABLE_ASH_MATH_SUPPORT
5185 static arith_t dash_arith(const char *);
5186 static arith_t arith(const char *expr, int *perrcode);
5192 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5193 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5194 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5195 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5196 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5197 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5198 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5199 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5200 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5204 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5205 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5206 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5207 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5208 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5211 * Structure specifying which parts of the string should be searched
5212 * for IFS characters.
5215 struct ifsregion *next; /* next region in list */
5216 int begoff; /* offset of start of region */
5217 int endoff; /* offset of end of region */
5218 int nulonly; /* search for nul bytes only */
5222 struct strlist *list;
5223 struct strlist **lastp;
5226 /* output of current string */
5227 static char *expdest;
5228 /* list of back quote expressions */
5229 static struct nodelist *argbackq;
5230 /* first struct in list of ifs regions */
5231 static struct ifsregion ifsfirst;
5232 /* last struct in list */
5233 static struct ifsregion *ifslastp;
5234 /* holds expanded arg list */
5235 static struct arglist exparg;
5245 expdest = makestrspace(32, expdest);
5246 #if ENABLE_ASH_MATH_SUPPORT_64
5247 len = fmtstr(expdest, 32, "%lld", (long long) num);
5249 len = fmtstr(expdest, 32, "%ld", num);
5251 STADJUST(len, expdest);
5256 esclen(const char *start, const char *p)
5260 while (p > start && *--p == CTLESC) {
5267 * Remove any CTLESC characters from a string.
5270 _rmescapes(char *str, int flag)
5272 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5279 p = strpbrk(str, qchars);
5285 if (flag & RMESCAPE_ALLOC) {
5286 size_t len = p - str;
5287 size_t fulllen = len + strlen(p) + 1;
5289 if (flag & RMESCAPE_GROW) {
5290 r = makestrspace(fulllen, expdest);
5291 } else if (flag & RMESCAPE_HEAP) {
5292 r = ckmalloc(fulllen);
5294 r = stalloc(fulllen);
5298 q = (char *)memcpy(q, str, len) + len;
5301 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5302 globbing = flag & RMESCAPE_GLOB;
5303 notescaped = globbing;
5305 if (*p == CTLQUOTEMARK) {
5306 inquotes = ~inquotes;
5308 notescaped = globbing;
5312 /* naked back slash */
5318 if (notescaped && inquotes && *p != '/') {
5322 notescaped = globbing;
5327 if (flag & RMESCAPE_GROW) {
5329 STADJUST(q - r + 1, expdest);
5333 #define rmescapes(p) _rmescapes((p), 0)
5335 #define pmatch(a, b) !fnmatch((a), (b), 0)
5338 * Prepare a pattern for a expmeta (internal glob(3)) call.
5340 * Returns an stalloced string.
5343 preglob(const char *pattern, int quoted, int flag)
5345 flag |= RMESCAPE_GLOB;
5347 flag |= RMESCAPE_QUOTED;
5349 return _rmescapes((char *)pattern, flag);
5353 * Put a string on the stack.
5356 memtodest(const char *p, size_t len, int syntax, int quotes)
5360 q = makestrspace(len * 2, q);
5363 int c = signed_char2int(*p++);
5366 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5375 strtodest(const char *p, int syntax, int quotes)
5377 memtodest(p, strlen(p), syntax, quotes);
5381 * Record the fact that we have to scan this region of the
5382 * string for IFS characters.
5385 recordregion(int start, int end, int nulonly)
5387 struct ifsregion *ifsp;
5389 if (ifslastp == NULL) {
5393 ifsp = ckzalloc(sizeof(*ifsp));
5394 /*ifsp->next = NULL; - ckzalloc did it */
5395 ifslastp->next = ifsp;
5399 ifslastp->begoff = start;
5400 ifslastp->endoff = end;
5401 ifslastp->nulonly = nulonly;
5405 removerecordregions(int endoff)
5407 if (ifslastp == NULL)
5410 if (ifsfirst.endoff > endoff) {
5411 while (ifsfirst.next != NULL) {
5412 struct ifsregion *ifsp;
5414 ifsp = ifsfirst.next->next;
5415 free(ifsfirst.next);
5416 ifsfirst.next = ifsp;
5419 if (ifsfirst.begoff > endoff)
5422 ifslastp = &ifsfirst;
5423 ifsfirst.endoff = endoff;
5428 ifslastp = &ifsfirst;
5429 while (ifslastp->next && ifslastp->next->begoff < endoff)
5430 ifslastp=ifslastp->next;
5431 while (ifslastp->next != NULL) {
5432 struct ifsregion *ifsp;
5434 ifsp = ifslastp->next->next;
5435 free(ifslastp->next);
5436 ifslastp->next = ifsp;
5439 if (ifslastp->endoff > endoff)
5440 ifslastp->endoff = endoff;
5444 exptilde(char *startp, char *p, int flag)
5450 int quotes = flag & (EXP_FULL | EXP_CASE);
5455 while ((c = *++p) != '\0') {
5462 if (flag & EXP_VARTILDE)
5472 if (*name == '\0') {
5473 home = lookupvar(homestr);
5475 pw = getpwnam(name);
5480 if (!home || !*home)
5483 startloc = expdest - (char *)stackblock();
5484 strtodest(home, SQSYNTAX, quotes);
5485 recordregion(startloc, expdest - (char *)stackblock(), 0);
5493 * Execute a command inside back quotes. If it's a builtin command, we
5494 * want to save its output in a block obtained from malloc. Otherwise
5495 * we fork off a subprocess and get the output of the command via a pipe.
5496 * Should be called with interrupts off.
5498 struct backcmd { /* result of evalbackcmd */
5499 int fd; /* file descriptor to read from */
5500 int nleft; /* number of chars in buffer */
5501 char *buf; /* buffer */
5502 struct job *jp; /* job structure for command */
5505 /* These forward decls are needed to use "eval" code for backticks handling: */
5506 static uint8_t back_exitstatus; /* exit status of backquoted command */
5507 #define EV_EXIT 01 /* exit after evaluating tree */
5508 static void evaltree(union node *, int);
5511 evalbackcmd(union node *n, struct backcmd *result)
5523 saveherefd = herefd;
5531 ash_msg_and_raise_error("pipe call failed");
5532 jp = makejob(/*n,*/ 1);
5533 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5538 copyfd(pip[1], 1 | COPYFD_EXACT);
5542 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5546 result->fd = pip[0];
5549 herefd = saveherefd;
5551 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5552 result->fd, result->buf, result->nleft, result->jp));
5556 * Expand stuff in backwards quotes.
5559 expbackq(union node *cmd, int quoted, int quotes)
5567 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
5568 struct stackmark smark;
5571 setstackmark(&smark);
5573 startloc = dest - (char *)stackblock();
5575 evalbackcmd(cmd, &in);
5576 popstackmark(&smark);
5583 memtodest(p, i, syntax, quotes);
5587 i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5588 TRACE(("expbackq: read returns %d\n", i));
5597 back_exitstatus = waitforjob(in.jp);
5601 /* Eat all trailing newlines */
5603 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5608 recordregion(startloc, dest - (char *)stackblock(), 0);
5609 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5610 (dest - (char *)stackblock()) - startloc,
5611 (dest - (char *)stackblock()) - startloc,
5612 stackblock() + startloc));
5615 #if ENABLE_ASH_MATH_SUPPORT
5617 * Expand arithmetic expression. Backup to start of expression,
5618 * evaluate, place result in (backed up) result, adjust string position.
5631 * This routine is slightly over-complicated for
5632 * efficiency. Next we scan backwards looking for the
5633 * start of arithmetic.
5635 start = stackblock();
5642 while (*p != CTLARI) {
5646 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5651 esc = esclen(start, p);
5661 removerecordregions(begoff);
5670 len = cvtnum(dash_arith(p + 2));
5673 recordregion(begoff, begoff + len, 0);
5677 /* argstr needs it */
5678 static char *evalvar(char *p, int flag, struct strlist *var_str_list);
5681 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5682 * characters to allow for further processing. Otherwise treat
5683 * $@ like $* since no splitting will be performed.
5685 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5686 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5687 * for correct expansion of "B=$A" word.
5690 argstr(char *p, int flag, struct strlist *var_str_list)
5692 static const char spclchars[] ALIGN1 = {
5700 CTLBACKQ | CTLQUOTE,
5701 #if ENABLE_ASH_MATH_SUPPORT
5706 const char *reject = spclchars;
5708 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
5709 int breakall = flag & EXP_WORD;
5714 if (!(flag & EXP_VARTILDE)) {
5716 } else if (flag & EXP_VARTILDE2) {
5721 if (flag & EXP_TILDE) {
5727 if (*q == CTLESC && (flag & EXP_QWORD))
5730 p = exptilde(p, q, flag);
5733 startloc = expdest - (char *)stackblock();
5735 length += strcspn(p + length, reject);
5737 if (c && (!(c & 0x80)
5738 #if ENABLE_ASH_MATH_SUPPORT
5742 /* c == '=' || c == ':' || c == CTLENDARI */
5747 expdest = stack_nputstr(p, length, expdest);
5748 newloc = expdest - (char *)stackblock();
5749 if (breakall && !inquotes && newloc > startloc) {
5750 recordregion(startloc, newloc, 0);
5761 if (flag & EXP_VARTILDE2) {
5765 flag |= EXP_VARTILDE2;
5770 * sort of a hack - expand tildes in variable
5771 * assignments (after the first '=' and after ':'s).
5780 case CTLENDVAR: /* ??? */
5783 /* "$@" syntax adherence hack */
5786 !memcmp(p, dolatstr, 4) &&
5787 (p[4] == CTLQUOTEMARK || (
5788 p[4] == CTLENDVAR &&
5789 p[5] == CTLQUOTEMARK
5792 p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;
5795 inquotes = !inquotes;
5808 p = evalvar(p, flag, var_str_list);
5812 case CTLBACKQ|CTLQUOTE:
5813 expbackq(argbackq->n, c, quotes);
5814 argbackq = argbackq->next;
5816 #if ENABLE_ASH_MATH_SUPPORT
5829 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int quotes,
5832 // This commented out code was added by James Simmons <jsimmons@infradead.org>
5833 // as part of a larger change when he added support for ${var/a/b}.
5834 // However, it broke # and % operators:
5838 //echo ${var#ab} abcdcd abcdcd
5839 //echo ${var##ab} abcdcd abcdcd
5840 //echo ${var#a*b} abcdcd ababcdcd (!)
5841 //echo ${var##a*b} cdcd cdcd
5842 //echo ${var#?} babcdcd ababcdcd (!)
5843 //echo ${var##?} babcdcd babcdcd
5844 //echo ${var#*} ababcdcd babcdcd (!)
5846 //echo ${var%cd} ababcd ababcd
5847 //echo ${var%%cd} ababcd abab (!)
5848 //echo ${var%c*d} ababcd ababcd
5849 //echo ${var%%c*d} abab ababcdcd (!)
5850 //echo ${var%?} ababcdc ababcdc
5851 //echo ${var%%?} ababcdc ababcdcd (!)
5852 //echo ${var%*} ababcdcd ababcdcd
5855 // Commenting it back out helped. Remove it completely if it really
5858 char *loc, *loc2; //, *full;
5864 int match; // = strlen(str);
5865 const char *s = loc2;
5872 match = pmatch(str, s); // this line was deleted
5874 // // chop off end if its '*'
5875 // full = strrchr(str, '*');
5876 // if (full && full != str)
5879 // // If str starts with '*' replace with s.
5880 // if ((*str == '*') && strlen(s) >= match) {
5881 // full = xstrdup(s);
5882 // strncpy(full+strlen(s)-match+1, str+1, match-1);
5884 // full = xstrndup(str, match);
5885 // match = strncmp(s, full, strlen(full));
5889 if (match) // if (!match)
5891 if (quotes && *loc == CTLESC)
5900 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5907 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5910 const char *s = loc2;
5915 match = pmatch(str, s);
5922 esc = esclen(startp, loc);
5933 static void varunset(const char *, const char *, const char *, int) NORETURN;
5935 varunset(const char *end, const char *var, const char *umsg, int varflags)
5941 msg = "parameter not set";
5943 if (*end == CTLENDVAR) {
5944 if (varflags & VSNUL)
5949 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5952 #if ENABLE_ASH_BASH_COMPAT
5954 parse_sub_pattern(char *arg, int inquotes)
5956 char *idx, *repl = NULL;
5965 /* Only the first '/' seen is our separator */
5972 if (!inquotes && c == '\\' && arg[1] == '\\')
5973 arg++; /* skip both \\, not just first one */
5980 #endif /* ENABLE_ASH_BASH_COMPAT */
5983 subevalvar(char *p, char *str, int strloc, int subtype,
5984 int startloc, int varflags, int quotes, struct strlist *var_str_list)
5986 struct nodelist *saveargbackq = argbackq;
5989 char *rmesc, *rmescend;
5990 USE_ASH_BASH_COMPAT(char *repl = NULL;)
5991 USE_ASH_BASH_COMPAT(char null = '\0';)
5992 USE_ASH_BASH_COMPAT(int pos, len, orig_len;)
5993 int saveherefd = herefd;
5994 int amount, workloc, resetloc;
5996 char *(*scan)(char*, char*, char*, char*, int, int);
5999 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
6001 STPUTC('\0', expdest);
6002 herefd = saveherefd;
6003 argbackq = saveargbackq;
6004 startp = (char *)stackblock() + startloc;
6008 setvar(str, startp, 0);
6009 amount = startp - expdest;
6010 STADJUST(amount, expdest);
6013 #if ENABLE_ASH_BASH_COMPAT
6015 loc = str = stackblock() + strloc;
6016 // TODO: number() instead? It does error checking...
6018 len = str - startp - 1;
6020 /* *loc != '\0', guaranteed by parser */
6024 /* We must adjust the length by the number of escapes we find. */
6025 for (ptr = startp; ptr < (str - 1); ptr++) {
6026 if (*ptr == CTLESC) {
6034 if (*loc++ == ':') {
6035 // TODO: number() instead? It does error checking...
6039 while (*loc && *loc != ':')
6042 // TODO: number() instead? It does error checking...
6045 if (pos >= orig_len) {
6049 if (len > (orig_len - pos))
6050 len = orig_len - pos;
6052 for (str = startp; pos; str++, pos--) {
6053 if (quotes && *str == CTLESC)
6056 for (loc = startp; len; len--) {
6057 if (quotes && *str == CTLESC)
6062 amount = loc - expdest;
6063 STADJUST(amount, expdest);
6068 varunset(p, str, startp, varflags);
6071 resetloc = expdest - (char *)stackblock();
6073 /* We'll comeback here if we grow the stack while handling
6074 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6075 * stack will need rebasing, and we'll need to remove our work
6078 USE_ASH_BASH_COMPAT(restart:)
6080 amount = expdest - ((char *)stackblock() + resetloc);
6081 STADJUST(-amount, expdest);
6082 startp = (char *)stackblock() + startloc;
6085 rmescend = (char *)stackblock() + strloc;
6087 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6088 if (rmesc != startp) {
6090 startp = (char *)stackblock() + startloc;
6094 str = (char *)stackblock() + strloc;
6095 preglob(str, varflags & VSQUOTE, 0);
6096 workloc = expdest - (char *)stackblock();
6098 #if ENABLE_ASH_BASH_COMPAT
6099 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6100 char *idx, *end, *restart_detect;
6103 repl = parse_sub_pattern(str, varflags & VSQUOTE);
6108 /* If there's no pattern to match, return the expansion unmolested */
6116 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6118 /* No match, advance */
6119 restart_detect = stackblock();
6120 STPUTC(*idx, expdest);
6121 if (quotes && *idx == CTLESC) {
6124 STPUTC(*idx, expdest);
6126 if (stackblock() != restart_detect)
6134 if (subtype == VSREPLACEALL) {
6136 if (quotes && *idx == CTLESC)
6144 for (loc = repl; *loc; loc++) {
6145 restart_detect = stackblock();
6146 STPUTC(*loc, expdest);
6147 if (stackblock() != restart_detect)
6152 if (subtype == VSREPLACE) {
6154 restart_detect = stackblock();
6155 STPUTC(*idx, expdest);
6156 if (stackblock() != restart_detect)
6165 /* We've put the replaced text into a buffer at workloc, now
6166 * move it to the right place and adjust the stack.
6168 startp = stackblock() + startloc;
6169 STPUTC('\0', expdest);
6170 memmove(startp, stackblock() + workloc, len);
6171 startp[len++] = '\0';
6172 amount = expdest - ((char *)stackblock() + startloc + len - 1);
6173 STADJUST(-amount, expdest);
6176 #endif /* ENABLE_ASH_BASH_COMPAT */
6178 subtype -= VSTRIMRIGHT;
6180 if (subtype < 0 || subtype > 7)
6183 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
6184 zero = subtype >> 1;
6185 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6186 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6188 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6191 memmove(startp, loc, str - loc);
6192 loc = startp + (str - loc) - 1;
6195 amount = loc - expdest;
6196 STADJUST(amount, expdest);
6202 * Add the value of a specialized variable to the stack string.
6205 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6215 int quoted = varflags & VSQUOTE;
6216 int subtype = varflags & VSTYPE;
6217 int quotes = flags & (EXP_FULL | EXP_CASE);
6219 if (quoted && (flags & EXP_FULL))
6220 sep = 1 << CHAR_BIT;
6222 syntax = quoted ? DQSYNTAX : BASESYNTAX;
6231 num = shellparam.nparam;
6241 p = makestrspace(NOPTS, expdest);
6242 for (i = NOPTS - 1; i >= 0; i--) {
6244 USTPUTC(optletters(i), p);
6255 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
6256 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
6262 while ((p = *ap++)) {
6265 partlen = strlen(p);
6268 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6269 memtodest(p, partlen, syntax, quotes);
6275 if (subtype == VSPLUS || subtype == VSLENGTH) {
6296 // TODO: number() instead? It does error checking...
6298 if (num < 0 || num > shellparam.nparam)
6300 p = num ? shellparam.p[num - 1] : arg0;
6303 /* NB: name has form "VAR=..." */
6305 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6306 * which should be considered before we check variables. */
6308 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6312 str = var_str_list->text;
6313 eq = strchr(str, '=');
6314 if (!eq) /* stop at first non-assignment */
6317 if (name_len == (unsigned)(eq - str)
6318 && strncmp(str, name, name_len) == 0) {
6320 /* goto value; - WRONG! */
6321 /* think "A=1 A=2 B=$A" */
6323 var_str_list = var_str_list->next;
6324 } while (var_str_list);
6328 p = lookupvar(name);
6334 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6335 memtodest(p, len, syntax, quotes);
6339 if (subtype == VSPLUS || subtype == VSLENGTH)
6340 STADJUST(-len, expdest);
6345 * Expand a variable, and return a pointer to the next character in the
6349 evalvar(char *p, int flag, struct strlist *var_str_list)
6361 subtype = varflags & VSTYPE;
6362 quoted = varflags & VSQUOTE;
6364 easy = (!quoted || (*var == '@' && shellparam.nparam));
6365 startloc = expdest - (char *)stackblock();
6366 p = strchr(p, '=') + 1;
6369 varlen = varvalue(var, varflags, flag, var_str_list);
6370 if (varflags & VSNUL)
6373 if (subtype == VSPLUS) {
6374 varlen = -1 - varlen;
6378 if (subtype == VSMINUS) {
6382 p, flag | EXP_TILDE |
6383 (quoted ? EXP_QWORD : EXP_WORD),
6393 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6395 if (subevalvar(p, var, /* strloc: */ 0,
6396 subtype, startloc, varflags,
6402 * Remove any recorded regions beyond
6405 removerecordregions(startloc);
6415 if (varlen < 0 && uflag)
6416 varunset(p, var, 0, 0);
6418 if (subtype == VSLENGTH) {
6419 cvtnum(varlen > 0 ? varlen : 0);
6423 if (subtype == VSNORMAL) {
6434 case VSTRIMRIGHTMAX:
6435 #if ENABLE_ASH_BASH_COMPAT
6448 * Terminate the string and start recording the pattern
6451 STPUTC('\0', expdest);
6452 patloc = expdest - (char *)stackblock();
6453 if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6455 /* quotes: */ flag & (EXP_FULL | EXP_CASE),
6458 int amount = expdest - (
6459 (char *)stackblock() + patloc - 1
6461 STADJUST(-amount, expdest);
6463 /* Remove any recorded regions beyond start of variable */
6464 removerecordregions(startloc);
6466 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6470 if (subtype != VSNORMAL) { /* skip to end of alternative */
6476 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6478 argbackq = argbackq->next;
6479 } else if (c == CTLVAR) {
6480 if ((*p++ & VSTYPE) != VSNORMAL)
6482 } else if (c == CTLENDVAR) {
6492 * Break the argument string into pieces based upon IFS and add the
6493 * strings to the argument list. The regions of the string to be
6494 * searched for IFS characters have been stored by recordregion.
6497 ifsbreakup(char *string, struct arglist *arglist)
6499 struct ifsregion *ifsp;
6504 const char *ifs, *realifs;
6509 if (ifslastp != NULL) {
6512 realifs = ifsset() ? ifsval() : defifs;
6515 p = string + ifsp->begoff;
6516 nulonly = ifsp->nulonly;
6517 ifs = nulonly ? nullstr : realifs;
6519 while (p < string + ifsp->endoff) {
6523 if (!strchr(ifs, *p)) {
6528 ifsspc = (strchr(defifs, *p) != NULL);
6529 /* Ignore IFS whitespace at start */
6530 if (q == start && ifsspc) {
6536 sp = stzalloc(sizeof(*sp));
6538 *arglist->lastp = sp;
6539 arglist->lastp = &sp->next;
6543 if (p >= string + ifsp->endoff) {
6549 if (strchr(ifs, *p) == NULL) {
6553 if (strchr(defifs, *p) == NULL) {
6568 } while (ifsp != NULL);
6577 sp = stzalloc(sizeof(*sp));
6579 *arglist->lastp = sp;
6580 arglist->lastp = &sp->next;
6586 struct ifsregion *p;
6591 struct ifsregion *ifsp;
6597 ifsfirst.next = NULL;
6602 * Add a file name to the list.
6605 addfname(const char *name)
6609 sp = stzalloc(sizeof(*sp));
6610 sp->text = ststrdup(name);
6612 exparg.lastp = &sp->next;
6615 static char *expdir;
6618 * Do metacharacter (i.e. *, ?, [...]) expansion.
6621 expmeta(char *enddir, char *name)
6636 for (p = name; *p; p++) {
6637 if (*p == '*' || *p == '?')
6639 else if (*p == '[') {
6646 if (*q == '/' || *q == '\0')
6653 } else if (*p == '\\')
6655 else if (*p == '/') {
6662 if (metaflag == 0) { /* we've reached the end of the file name */
6663 if (enddir != expdir)
6671 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6682 } while (p < start);
6684 if (enddir == expdir) {
6686 } else if (enddir == expdir + 1 && *expdir == '/') {
6695 if (enddir != expdir)
6697 if (*endname == 0) {
6709 while (!intpending && (dp = readdir(dirp)) != NULL) {
6710 if (dp->d_name[0] == '.' && !matchdot)
6712 if (pmatch(start, dp->d_name)) {
6714 strcpy(enddir, dp->d_name);
6717 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6720 expmeta(p, endname);
6729 static struct strlist *
6730 msort(struct strlist *list, int len)
6732 struct strlist *p, *q = NULL;
6733 struct strlist **lpp;
6741 for (n = half; --n >= 0;) {
6745 q->next = NULL; /* terminate first half of list */
6746 q = msort(list, half); /* sort first half of list */
6747 p = msort(p, len - half); /* sort second half */
6750 #if ENABLE_LOCALE_SUPPORT
6751 if (strcoll(p->text, q->text) < 0)
6753 if (strcmp(p->text, q->text) < 0)
6777 * Sort the results of file name expansion. It calculates the number of
6778 * strings to sort and then calls msort (short for merge sort) to do the
6781 static struct strlist *
6782 expsort(struct strlist *str)
6788 for (sp = str; sp; sp = sp->next)
6790 return msort(str, len);
6794 expandmeta(struct strlist *str /*, int flag*/)
6796 static const char metachars[] ALIGN1 = {
6799 /* TODO - EXP_REDIR */
6802 struct strlist **savelastp;
6808 if (!strpbrk(str->text, metachars))
6810 savelastp = exparg.lastp;
6813 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
6815 int i = strlen(str->text);
6816 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
6824 if (exparg.lastp == savelastp) {
6829 *exparg.lastp = str;
6830 rmescapes(str->text);
6831 exparg.lastp = &str->next;
6833 *exparg.lastp = NULL;
6834 *savelastp = sp = expsort(*savelastp);
6835 while (sp->next != NULL)
6837 exparg.lastp = &sp->next;
6844 * Perform variable substitution and command substitution on an argument,
6845 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6846 * perform splitting and file name expansion. When arglist is NULL, perform
6847 * here document expansion.
6850 expandarg(union node *arg, struct arglist *arglist, int flag)
6855 argbackq = arg->narg.backquote;
6856 STARTSTACKSTR(expdest);
6857 ifsfirst.next = NULL;
6859 argstr(arg->narg.text, flag,
6860 /* var_str_list: */ arglist ? arglist->list : NULL);
6861 p = _STPUTC('\0', expdest);
6863 if (arglist == NULL) {
6864 return; /* here document expanded */
6866 p = grabstackstr(p);
6867 exparg.lastp = &exparg.list;
6871 if (flag & EXP_FULL) {
6872 ifsbreakup(p, &exparg);
6873 *exparg.lastp = NULL;
6874 exparg.lastp = &exparg.list;
6875 expandmeta(exparg.list /*, flag*/);
6877 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
6879 sp = stzalloc(sizeof(*sp));
6882 exparg.lastp = &sp->next;
6886 *exparg.lastp = NULL;
6888 *arglist->lastp = exparg.list;
6889 arglist->lastp = exparg.lastp;
6894 * Expand shell variables and backquotes inside a here document.
6897 expandhere(union node *arg, int fd)
6900 expandarg(arg, (struct arglist *)NULL, 0);
6901 full_write(fd, stackblock(), expdest - (char *)stackblock());
6905 * Returns true if the pattern matches the string.
6908 patmatch(char *pattern, const char *string)
6910 return pmatch(preglob(pattern, 0, 0), string);
6914 * See if a pattern matches in a case statement.
6917 casematch(union node *pattern, char *val)
6919 struct stackmark smark;
6922 setstackmark(&smark);
6923 argbackq = pattern->narg.backquote;
6924 STARTSTACKSTR(expdest);
6926 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
6927 /* var_str_list: */ NULL);
6928 STACKSTRNUL(expdest);
6929 result = patmatch(stackblock(), val);
6930 popstackmark(&smark);
6935 /* ============ find_command */
6939 int (*builtin)(int, char **);
6940 /* unsigned flags; */
6942 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
6943 /* "regular" builtins always take precedence over commands,
6944 * regardless of PATH=....%builtin... position */
6945 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
6946 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
6949 smallint cmdtype; /* CMDxxx */
6952 /* index >= 0 for commands without path (slashes) */
6953 /* (TODO: what exactly does the value mean? PATH position?) */
6954 /* index == -1 for commands with slashes */
6955 /* index == (-2 - applet_no) for NOFORK applets */
6956 const struct builtincmd *cmd;
6957 struct funcnode *func;
6960 /* values of cmdtype */
6961 #define CMDUNKNOWN -1 /* no entry in table for command */
6962 #define CMDNORMAL 0 /* command is an executable program */
6963 #define CMDFUNCTION 1 /* command is a shell function */
6964 #define CMDBUILTIN 2 /* command is a shell builtin */
6966 /* action to find_command() */
6967 #define DO_ERR 0x01 /* prints errors */
6968 #define DO_ABS 0x02 /* checks absolute paths */
6969 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
6970 #define DO_ALTPATH 0x08 /* using alternate path */
6971 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
6973 static void find_command(char *, struct cmdentry *, int, const char *);
6976 /* ============ Hashing commands */
6979 * When commands are first encountered, they are entered in a hash table.
6980 * This ensures that a full path search will not have to be done for them
6981 * on each invocation.
6983 * We should investigate converting to a linear search, even though that
6984 * would make the command name "hash" a misnomer.
6988 struct tblentry *next; /* next entry in hash chain */
6989 union param param; /* definition of builtin function */
6990 smallint cmdtype; /* CMDxxx */
6991 char rehash; /* if set, cd done since entry created */
6992 char cmdname[1]; /* name of command */
6995 static struct tblentry **cmdtable;
6996 #define INIT_G_cmdtable() do { \
6997 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7000 static int builtinloc = -1; /* index in path of %builtin, or -1 */
7004 tryexec(USE_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
7008 #if ENABLE_FEATURE_SH_STANDALONE
7009 if (applet_no >= 0) {
7010 if (APPLET_IS_NOEXEC(applet_no))
7011 run_applet_no_and_exit(applet_no, argv);
7012 /* re-exec ourselves with the new arguments */
7013 execve(bb_busybox_exec_path, argv, envp);
7014 /* If they called chroot or otherwise made the binary no longer
7015 * executable, fall through */
7022 execve(cmd, argv, envp);
7023 } while (errno == EINTR);
7025 execve(cmd, argv, envp);
7031 if (errno == ENOEXEC) {
7035 for (ap = argv; *ap; ap++)
7037 ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0]));
7039 ap[0] = cmd = (char *)DEFAULT_SHELL;
7042 while ((*ap++ = *argv++) != NULL)
7051 * Exec a program. Never returns. If you change this routine, you may
7052 * have to change the find_command routine as well.
7054 static void shellexec(char **, const char *, int) NORETURN;
7056 shellexec(char **argv, const char *path, int idx)
7062 #if ENABLE_FEATURE_SH_STANDALONE
7066 clearredir(/*drop:*/ 1);
7067 envp = listvars(VEXPORT, VUNSET, 0);
7068 if (strchr(argv[0], '/') != NULL
7069 #if ENABLE_FEATURE_SH_STANDALONE
7070 || (applet_no = find_applet_by_name(argv[0])) >= 0
7073 tryexec(USE_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7077 while ((cmdname = padvance(&path, argv[0])) != NULL) {
7078 if (--idx < 0 && pathopt == NULL) {
7079 tryexec(USE_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7080 if (errno != ENOENT && errno != ENOTDIR)
7087 /* Map to POSIX errors */
7099 exitstatus = exerrno;
7100 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
7101 argv[0], e, suppressint));
7102 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7107 printentry(struct tblentry *cmdp)
7113 idx = cmdp->param.index;
7116 name = padvance(&path, cmdp->cmdname);
7118 } while (--idx >= 0);
7119 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7123 * Clear out command entries. The argument specifies the first entry in
7124 * PATH which has changed.
7127 clearcmdentry(int firstchange)
7129 struct tblentry **tblp;
7130 struct tblentry **pp;
7131 struct tblentry *cmdp;
7134 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7136 while ((cmdp = *pp) != NULL) {
7137 if ((cmdp->cmdtype == CMDNORMAL &&
7138 cmdp->param.index >= firstchange)
7139 || (cmdp->cmdtype == CMDBUILTIN &&
7140 builtinloc >= firstchange)
7153 * Locate a command in the command hash table. If "add" is nonzero,
7154 * add the command to the table if it is not already present. The
7155 * variable "lastcmdentry" is set to point to the address of the link
7156 * pointing to the entry, so that delete_cmd_entry can delete the
7159 * Interrupts must be off if called with add != 0.
7161 static struct tblentry **lastcmdentry;
7163 static struct tblentry *
7164 cmdlookup(const char *name, int add)
7166 unsigned int hashval;
7168 struct tblentry *cmdp;
7169 struct tblentry **pp;
7172 hashval = (unsigned char)*p << 4;
7174 hashval += (unsigned char)*p++;
7176 pp = &cmdtable[hashval % CMDTABLESIZE];
7177 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7178 if (strcmp(cmdp->cmdname, name) == 0)
7182 if (add && cmdp == NULL) {
7183 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7185 /* + 1 - already done because
7186 * tblentry::cmdname is char[1] */);
7187 /*cmdp->next = NULL; - ckzalloc did it */
7188 cmdp->cmdtype = CMDUNKNOWN;
7189 strcpy(cmdp->cmdname, name);
7196 * Delete the command entry returned on the last lookup.
7199 delete_cmd_entry(void)
7201 struct tblentry *cmdp;
7204 cmdp = *lastcmdentry;
7205 *lastcmdentry = cmdp->next;
7206 if (cmdp->cmdtype == CMDFUNCTION)
7207 freefunc(cmdp->param.func);
7213 * Add a new command entry, replacing any existing command entry for
7214 * the same name - except special builtins.
7217 addcmdentry(char *name, struct cmdentry *entry)
7219 struct tblentry *cmdp;
7221 cmdp = cmdlookup(name, 1);
7222 if (cmdp->cmdtype == CMDFUNCTION) {
7223 freefunc(cmdp->param.func);
7225 cmdp->cmdtype = entry->cmdtype;
7226 cmdp->param = entry->u;
7231 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7233 struct tblentry **pp;
7234 struct tblentry *cmdp;
7236 struct cmdentry entry;
7239 if (nextopt("r") != '\0') {
7244 if (*argptr == NULL) {
7245 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7246 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7247 if (cmdp->cmdtype == CMDNORMAL)
7255 while ((name = *argptr) != NULL) {
7256 cmdp = cmdlookup(name, 0);
7258 && (cmdp->cmdtype == CMDNORMAL
7259 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7263 find_command(name, &entry, DO_ERR, pathval());
7264 if (entry.cmdtype == CMDUNKNOWN)
7272 * Called when a cd is done. Marks all commands so the next time they
7273 * are executed they will be rehashed.
7278 struct tblentry **pp;
7279 struct tblentry *cmdp;
7281 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7282 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7283 if (cmdp->cmdtype == CMDNORMAL
7284 || (cmdp->cmdtype == CMDBUILTIN
7285 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7295 * Fix command hash table when PATH changed.
7296 * Called before PATH is changed. The argument is the new value of PATH;
7297 * pathval() still returns the old value at this point.
7298 * Called with interrupts off.
7301 changepath(const char *new)
7309 firstchange = 9999; /* assume no change */
7315 if ((*old == '\0' && *new == ':')
7316 || (*old == ':' && *new == '\0'))
7318 old = new; /* ignore subsequent differences */
7322 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7328 if (builtinloc < 0 && idx_bltin >= 0)
7329 builtinloc = idx_bltin; /* zap builtins */
7330 if (builtinloc >= 0 && idx_bltin < 0)
7332 clearcmdentry(firstchange);
7333 builtinloc = idx_bltin;
7348 #define TENDBQUOTE 12
7365 typedef smallint token_id_t;
7367 /* first char is indicating which tokens mark the end of a list */
7368 static const char *const tokname_array[] = {
7382 #define KWDOFFSET 13
7383 /* the following are keywords */
7405 static char buf[16];
7408 //if (tok < TSEMI) return tokname_array[tok] + 1;
7409 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
7414 sprintf(buf + (tok >= TSEMI), "%s%c",
7415 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
7419 /* Wrapper around strcmp for qsort/bsearch/... */
7421 pstrcmp(const void *a, const void *b)
7423 return strcmp((char*) a, (*(char**) b) + 1);
7426 static const char *const *
7427 findkwd(const char *s)
7429 return bsearch(s, tokname_array + KWDOFFSET,
7430 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7431 sizeof(tokname_array[0]), pstrcmp);
7435 * Locate and print what a word is...
7438 describe_command(char *command, int describe_command_verbose)
7440 struct cmdentry entry;
7441 struct tblentry *cmdp;
7442 #if ENABLE_ASH_ALIAS
7443 const struct alias *ap;
7445 const char *path = pathval();
7447 if (describe_command_verbose) {
7451 /* First look at the keywords */
7452 if (findkwd(command)) {
7453 out1str(describe_command_verbose ? " is a shell keyword" : command);
7457 #if ENABLE_ASH_ALIAS
7458 /* Then look at the aliases */
7459 ap = lookupalias(command, 0);
7461 if (!describe_command_verbose) {
7466 out1fmt(" is an alias for %s", ap->val);
7470 /* Then check if it is a tracked alias */
7471 cmdp = cmdlookup(command, 0);
7473 entry.cmdtype = cmdp->cmdtype;
7474 entry.u = cmdp->param;
7476 /* Finally use brute force */
7477 find_command(command, &entry, DO_ABS, path);
7480 switch (entry.cmdtype) {
7482 int j = entry.u.index;
7488 p = padvance(&path, command);
7492 if (describe_command_verbose) {
7494 (cmdp ? " a tracked alias for" : nullstr), p
7503 if (describe_command_verbose) {
7504 out1str(" is a shell function");
7511 if (describe_command_verbose) {
7512 out1fmt(" is a %sshell builtin",
7513 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7514 "special " : nullstr
7522 if (describe_command_verbose) {
7523 out1str(": not found\n");
7528 outstr("\n", stdout);
7533 typecmd(int argc UNUSED_PARAM, char **argv)
7539 /* type -p ... ? (we don't bother checking for 'p') */
7540 if (argv[1] && argv[1][0] == '-') {
7545 err |= describe_command(argv[i++], verbose);
7550 #if ENABLE_ASH_CMDCMD
7552 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7560 while ((c = nextopt("pvV")) != '\0')
7562 verify |= VERIFY_VERBOSE;
7564 verify |= VERIFY_BRIEF;
7569 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7570 if (verify && (*argptr != NULL)) {
7571 return describe_command(*argptr, verify - VERIFY_BRIEF);
7579 /* ============ eval.c */
7581 static int funcblocksize; /* size of structures in function */
7582 static int funcstringsize; /* size of strings in node */
7583 static void *funcblock; /* block to allocate function from */
7584 static char *funcstring; /* block to allocate strings from */
7586 /* flags in argument to evaltree */
7587 #define EV_EXIT 01 /* exit after evaluating tree */
7588 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7589 #define EV_BACKCMD 04 /* command executing within back quotes */
7591 static const short nodesize[26] = {
7592 SHELL_ALIGN(sizeof(struct ncmd)),
7593 SHELL_ALIGN(sizeof(struct npipe)),
7594 SHELL_ALIGN(sizeof(struct nredir)),
7595 SHELL_ALIGN(sizeof(struct nredir)),
7596 SHELL_ALIGN(sizeof(struct nredir)),
7597 SHELL_ALIGN(sizeof(struct nbinary)),
7598 SHELL_ALIGN(sizeof(struct nbinary)),
7599 SHELL_ALIGN(sizeof(struct nbinary)),
7600 SHELL_ALIGN(sizeof(struct nif)),
7601 SHELL_ALIGN(sizeof(struct nbinary)),
7602 SHELL_ALIGN(sizeof(struct nbinary)),
7603 SHELL_ALIGN(sizeof(struct nfor)),
7604 SHELL_ALIGN(sizeof(struct ncase)),
7605 SHELL_ALIGN(sizeof(struct nclist)),
7606 SHELL_ALIGN(sizeof(struct narg)),
7607 SHELL_ALIGN(sizeof(struct narg)),
7608 SHELL_ALIGN(sizeof(struct nfile)),
7609 SHELL_ALIGN(sizeof(struct nfile)),
7610 SHELL_ALIGN(sizeof(struct nfile)),
7611 SHELL_ALIGN(sizeof(struct nfile)),
7612 SHELL_ALIGN(sizeof(struct nfile)),
7613 SHELL_ALIGN(sizeof(struct ndup)),
7614 SHELL_ALIGN(sizeof(struct ndup)),
7615 SHELL_ALIGN(sizeof(struct nhere)),
7616 SHELL_ALIGN(sizeof(struct nhere)),
7617 SHELL_ALIGN(sizeof(struct nnot)),
7620 static void calcsize(union node *n);
7623 sizenodelist(struct nodelist *lp)
7626 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7633 calcsize(union node *n)
7637 funcblocksize += nodesize[n->type];
7640 calcsize(n->ncmd.redirect);
7641 calcsize(n->ncmd.args);
7642 calcsize(n->ncmd.assign);
7645 sizenodelist(n->npipe.cmdlist);
7650 calcsize(n->nredir.redirect);
7651 calcsize(n->nredir.n);
7658 calcsize(n->nbinary.ch2);
7659 calcsize(n->nbinary.ch1);
7662 calcsize(n->nif.elsepart);
7663 calcsize(n->nif.ifpart);
7664 calcsize(n->nif.test);
7667 funcstringsize += strlen(n->nfor.var) + 1;
7668 calcsize(n->nfor.body);
7669 calcsize(n->nfor.args);
7672 calcsize(n->ncase.cases);
7673 calcsize(n->ncase.expr);
7676 calcsize(n->nclist.body);
7677 calcsize(n->nclist.pattern);
7678 calcsize(n->nclist.next);
7682 sizenodelist(n->narg.backquote);
7683 funcstringsize += strlen(n->narg.text) + 1;
7684 calcsize(n->narg.next);
7687 #if ENABLE_ASH_BASH_COMPAT
7694 calcsize(n->nfile.fname);
7695 calcsize(n->nfile.next);
7699 calcsize(n->ndup.vname);
7700 calcsize(n->ndup.next);
7704 calcsize(n->nhere.doc);
7705 calcsize(n->nhere.next);
7708 calcsize(n->nnot.com);
7714 nodeckstrdup(char *s)
7716 char *rtn = funcstring;
7718 strcpy(funcstring, s);
7719 funcstring += strlen(s) + 1;
7723 static union node *copynode(union node *);
7725 static struct nodelist *
7726 copynodelist(struct nodelist *lp)
7728 struct nodelist *start;
7729 struct nodelist **lpp;
7734 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7735 (*lpp)->n = copynode(lp->n);
7737 lpp = &(*lpp)->next;
7744 copynode(union node *n)
7751 funcblock = (char *) funcblock + nodesize[n->type];
7755 new->ncmd.redirect = copynode(n->ncmd.redirect);
7756 new->ncmd.args = copynode(n->ncmd.args);
7757 new->ncmd.assign = copynode(n->ncmd.assign);
7760 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7761 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
7766 new->nredir.redirect = copynode(n->nredir.redirect);
7767 new->nredir.n = copynode(n->nredir.n);
7774 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7775 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7778 new->nif.elsepart = copynode(n->nif.elsepart);
7779 new->nif.ifpart = copynode(n->nif.ifpart);
7780 new->nif.test = copynode(n->nif.test);
7783 new->nfor.var = nodeckstrdup(n->nfor.var);
7784 new->nfor.body = copynode(n->nfor.body);
7785 new->nfor.args = copynode(n->nfor.args);
7788 new->ncase.cases = copynode(n->ncase.cases);
7789 new->ncase.expr = copynode(n->ncase.expr);
7792 new->nclist.body = copynode(n->nclist.body);
7793 new->nclist.pattern = copynode(n->nclist.pattern);
7794 new->nclist.next = copynode(n->nclist.next);
7798 new->narg.backquote = copynodelist(n->narg.backquote);
7799 new->narg.text = nodeckstrdup(n->narg.text);
7800 new->narg.next = copynode(n->narg.next);
7803 #if ENABLE_ASH_BASH_COMPAT
7810 new->nfile.fname = copynode(n->nfile.fname);
7811 new->nfile.fd = n->nfile.fd;
7812 new->nfile.next = copynode(n->nfile.next);
7816 new->ndup.vname = copynode(n->ndup.vname);
7817 new->ndup.dupfd = n->ndup.dupfd;
7818 new->ndup.fd = n->ndup.fd;
7819 new->ndup.next = copynode(n->ndup.next);
7823 new->nhere.doc = copynode(n->nhere.doc);
7824 new->nhere.fd = n->nhere.fd;
7825 new->nhere.next = copynode(n->nhere.next);
7828 new->nnot.com = copynode(n->nnot.com);
7831 new->type = n->type;
7836 * Make a copy of a parse tree.
7838 static struct funcnode *
7839 copyfunc(union node *n)
7844 funcblocksize = offsetof(struct funcnode, n);
7847 blocksize = funcblocksize;
7848 f = ckmalloc(blocksize + funcstringsize);
7849 funcblock = (char *) f + offsetof(struct funcnode, n);
7850 funcstring = (char *) f + blocksize;
7857 * Define a shell function.
7860 defun(char *name, union node *func)
7862 struct cmdentry entry;
7865 entry.cmdtype = CMDFUNCTION;
7866 entry.u.func = copyfunc(func);
7867 addcmdentry(name, &entry);
7871 static int evalskip; /* set if we are skipping commands */
7872 /* reasons for skipping commands (see comment on breakcmd routine) */
7873 #define SKIPBREAK (1 << 0)
7874 #define SKIPCONT (1 << 1)
7875 #define SKIPFUNC (1 << 2)
7876 #define SKIPFILE (1 << 3)
7877 #define SKIPEVAL (1 << 4)
7878 static int skipcount; /* number of levels to skip */
7879 static int funcnest; /* depth of function calls */
7880 static int loopnest; /* current loop nesting level */
7882 /* forward decl way out to parsing code - dotrap needs it */
7883 static int evalstring(char *s, int mask);
7886 * Called to execute a trap. Perhaps we should avoid entering new trap
7887 * handlers while we are executing a trap handler.
7898 savestatus = exitstatus;
7902 for (i = 1, q = gotsig; i < NSIG; i++, q++) {
7910 skip = evalstring(p, SKIPEVAL);
7911 exitstatus = savestatus;
7919 /* forward declarations - evaluation is fairly recursive business... */
7920 static void evalloop(union node *, int);
7921 static void evalfor(union node *, int);
7922 static void evalcase(union node *, int);
7923 static void evalsubshell(union node *, int);
7924 static void expredir(union node *);
7925 static void evalpipe(union node *, int);
7926 static void evalcommand(union node *, int);
7927 static int evalbltin(const struct builtincmd *, int, char **);
7928 static void prehash(union node *);
7931 * Evaluate a parse tree. The value is left in the global variable
7935 evaltree(union node *n, int flags)
7938 struct jmploc *volatile savehandler = exception_handler;
7939 struct jmploc jmploc;
7941 void (*evalfn)(union node *, int);
7945 TRACE(("evaltree(NULL) called\n"));
7948 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
7949 getpid(), n, n->type, flags));
7951 exception_handler = &jmploc;
7953 int err = setjmp(jmploc.loc);
7955 /* if it was a signal, check for trap handlers */
7956 if (exception == EXSIG)
7958 /* continue on the way out */
7959 exception_handler = savehandler;
7960 longjmp(exception_handler->loc, err);
7967 out1fmt("Node type = %d\n", n->type);
7972 evaltree(n->nnot.com, EV_TESTED);
7973 status = !exitstatus;
7976 expredir(n->nredir.redirect);
7977 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
7979 evaltree(n->nredir.n, flags & EV_TESTED);
7980 status = exitstatus;
7982 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
7985 evalfn = evalcommand;
7987 if (eflag && !(flags & EV_TESTED))
7999 evalfn = evalsubshell;
8012 #error NAND + 1 != NOR
8014 #if NOR + 1 != NSEMI
8015 #error NOR + 1 != NSEMI
8017 unsigned is_or = n->type - NAND;
8020 (flags | ((is_or >> 1) - 1)) & EV_TESTED
8022 if (!exitstatus == is_or)
8035 evaltree(n->nif.test, EV_TESTED);
8038 if (exitstatus == 0) {
8041 } else if (n->nif.elsepart) {
8042 n = n->nif.elsepart;
8047 defun(n->narg.text, n->narg.next);
8051 exitstatus = status;
8056 exception_handler = savehandler;
8058 if (checkexit & exitstatus)
8059 evalskip |= SKIPEVAL;
8060 else if (pendingsig && dotrap())
8063 if (flags & EV_EXIT) {
8065 raise_exception(EXEXIT);
8069 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8072 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8075 evalloop(union node *n, int flags)
8085 evaltree(n->nbinary.ch1, EV_TESTED);
8088 if (evalskip == SKIPCONT && --skipcount <= 0) {
8092 if (evalskip == SKIPBREAK && --skipcount <= 0)
8097 if (n->type != NWHILE)
8101 evaltree(n->nbinary.ch2, flags);
8102 status = exitstatus;
8107 exitstatus = status;
8111 evalfor(union node *n, int flags)
8113 struct arglist arglist;
8116 struct stackmark smark;
8118 setstackmark(&smark);
8119 arglist.list = NULL;
8120 arglist.lastp = &arglist.list;
8121 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8122 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
8127 *arglist.lastp = NULL;
8132 for (sp = arglist.list; sp; sp = sp->next) {
8133 setvar(n->nfor.var, sp->text, 0);
8134 evaltree(n->nfor.body, flags);
8136 if (evalskip == SKIPCONT && --skipcount <= 0) {
8140 if (evalskip == SKIPBREAK && --skipcount <= 0)
8147 popstackmark(&smark);
8151 evalcase(union node *n, int flags)
8155 struct arglist arglist;
8156 struct stackmark smark;
8158 setstackmark(&smark);
8159 arglist.list = NULL;
8160 arglist.lastp = &arglist.list;
8161 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8163 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8164 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8165 if (casematch(patp, arglist.list->text)) {
8166 if (evalskip == 0) {
8167 evaltree(cp->nclist.body, flags);
8174 popstackmark(&smark);
8178 * Kick off a subshell to evaluate a tree.
8181 evalsubshell(union node *n, int flags)
8184 int backgnd = (n->type == NBACKGND);
8187 expredir(n->nredir.redirect);
8188 if (!backgnd && flags & EV_EXIT && !trap[0])
8191 jp = makejob(/*n,*/ 1);
8192 if (forkshell(jp, n, backgnd) == 0) {
8196 flags &=~ EV_TESTED;
8198 redirect(n->nredir.redirect, 0);
8199 evaltreenr(n->nredir.n, flags);
8204 status = waitforjob(jp);
8205 exitstatus = status;
8210 * Compute the names of the files in a redirection list.
8212 static void fixredir(union node *, const char *, int);
8214 expredir(union node *n)
8218 for (redir = n; redir; redir = redir->nfile.next) {
8222 fn.lastp = &fn.list;
8223 switch (redir->type) {
8227 #if ENABLE_ASH_BASH_COMPAT
8232 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8233 #if ENABLE_ASH_BASH_COMPAT
8236 redir->nfile.expfname = fn.list->text;
8239 case NTOFD: /* >& */
8240 if (redir->ndup.vname) {
8241 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8242 if (fn.list == NULL)
8243 ash_msg_and_raise_error("redir error");
8244 #if ENABLE_ASH_BASH_COMPAT
8245 //FIXME: we used expandarg with different args!
8246 if (!isdigit_str9(fn.list->text)) {
8247 /* >&file, not >&fd */
8248 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8249 ash_msg_and_raise_error("redir error");
8251 goto store_expfname;
8254 fixredir(redir, fn.list->text, 1);
8262 * Evaluate a pipeline. All the processes in the pipeline are children
8263 * of the process creating the pipeline. (This differs from some versions
8264 * of the shell, which make the last process in a pipeline the parent
8268 evalpipe(union node *n, int flags)
8271 struct nodelist *lp;
8276 TRACE(("evalpipe(0x%lx) called\n", (long)n));
8278 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8282 jp = makejob(/*n,*/ pipelen);
8284 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8288 if (pipe(pip) < 0) {
8290 ash_msg_and_raise_error("pipe call failed");
8293 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8306 evaltreenr(lp->n, flags);
8314 if (n->npipe.pipe_backgnd == 0) {
8315 exitstatus = waitforjob(jp);
8316 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
8322 * Controls whether the shell is interactive or not.
8325 setinteractive(int on)
8327 static smallint is_interactive;
8329 if (++on == is_interactive)
8331 is_interactive = on;
8335 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8336 if (is_interactive > 1) {
8337 /* Looks like they want an interactive shell */
8338 static smallint did_banner;
8343 "%s built-in shell (ash)\n"
8344 "Enter 'help' for a list of built-in commands."
8359 setinteractive(iflag);
8361 #if ENABLE_FEATURE_EDITING_VI
8363 line_input_state->flags |= VI_MODE;
8365 line_input_state->flags &= ~VI_MODE;
8367 viflag = 0; /* forcibly keep the option off */
8371 static struct localvar *localvars;
8374 * Called after a function returns.
8375 * Interrupts must be off.
8380 struct localvar *lvp;
8383 while ((lvp = localvars) != NULL) {
8384 localvars = lvp->next;
8386 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
8387 if (vp == NULL) { /* $- saved */
8388 memcpy(optlist, lvp->text, sizeof(optlist));
8389 free((char*)lvp->text);
8391 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8395 (*vp->func)(strchrnul(lvp->text, '=') + 1);
8396 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8397 free((char*)vp->text);
8398 vp->flags = lvp->flags;
8399 vp->text = lvp->text;
8406 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8408 volatile struct shparam saveparam;
8409 struct localvar *volatile savelocalvars;
8410 struct jmploc *volatile savehandler;
8411 struct jmploc jmploc;
8414 saveparam = shellparam;
8415 savelocalvars = localvars;
8416 e = setjmp(jmploc.loc);
8421 savehandler = exception_handler;
8422 exception_handler = &jmploc;
8424 shellparam.malloced = 0;
8428 shellparam.nparam = argc - 1;
8429 shellparam.p = argv + 1;
8430 #if ENABLE_ASH_GETOPTS
8431 shellparam.optind = 1;
8432 shellparam.optoff = -1;
8434 evaltree(&func->n, flags & EV_TESTED);
8440 localvars = savelocalvars;
8441 freeparam(&shellparam);
8442 shellparam = saveparam;
8443 exception_handler = savehandler;
8445 evalskip &= ~SKIPFUNC;
8449 #if ENABLE_ASH_CMDCMD
8451 parse_command_args(char **argv, const char **path)
8464 if (c == '-' && !*cp) {
8471 *path = bb_default_path;
8474 /* run 'typecmd' for other options */
8485 * Make a variable a local variable. When a variable is made local, it's
8486 * value and flags are saved in a localvar structure. The saved values
8487 * will be restored when the shell function returns. We handle the name
8488 * "-" as a special case.
8493 struct localvar *lvp;
8498 lvp = ckzalloc(sizeof(struct localvar));
8499 if (LONE_DASH(name)) {
8501 p = ckmalloc(sizeof(optlist));
8502 lvp->text = memcpy(p, optlist, sizeof(optlist));
8507 vpp = hashvar(name);
8508 vp = *findvar(vpp, name);
8509 eq = strchr(name, '=');
8512 setvareq(name, VSTRFIXED);
8514 setvar(name, NULL, VSTRFIXED);
8515 vp = *vpp; /* the new variable */
8516 lvp->flags = VUNSET;
8518 lvp->text = vp->text;
8519 lvp->flags = vp->flags;
8520 vp->flags |= VSTRFIXED|VTEXTFIXED;
8526 lvp->next = localvars;
8532 * The "local" command.
8535 localcmd(int argc UNUSED_PARAM, char **argv)
8540 while ((name = *argv++) != NULL) {
8547 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8553 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8559 execcmd(int argc UNUSED_PARAM, char **argv)
8562 iflag = 0; /* exit on error */
8565 shellexec(argv + 1, pathval(), 0);
8571 * The return command.
8574 returncmd(int argc UNUSED_PARAM, char **argv)
8577 * If called outside a function, do what ksh does;
8578 * skip the rest of the file.
8580 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8581 return argv[1] ? number(argv[1]) : exitstatus;
8584 /* Forward declarations for builtintab[] */
8585 static int breakcmd(int, char **);
8586 static int dotcmd(int, char **);
8587 static int evalcmd(int, char **);
8588 static int exitcmd(int, char **);
8589 static int exportcmd(int, char **);
8590 #if ENABLE_ASH_GETOPTS
8591 static int getoptscmd(int, char **);
8593 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8594 static int helpcmd(int, char **);
8596 #if ENABLE_ASH_MATH_SUPPORT
8597 static int letcmd(int, char **);
8599 static int readcmd(int, char **);
8600 static int setcmd(int, char **);
8601 static int shiftcmd(int, char **);
8602 static int timescmd(int, char **);
8603 static int trapcmd(int, char **);
8604 static int umaskcmd(int, char **);
8605 static int unsetcmd(int, char **);
8606 static int ulimitcmd(int, char **);
8608 #define BUILTIN_NOSPEC "0"
8609 #define BUILTIN_SPECIAL "1"
8610 #define BUILTIN_REGULAR "2"
8611 #define BUILTIN_SPEC_REG "3"
8612 #define BUILTIN_ASSIGN "4"
8613 #define BUILTIN_SPEC_ASSG "5"
8614 #define BUILTIN_REG_ASSG "6"
8615 #define BUILTIN_SPEC_REG_ASSG "7"
8617 /* We do not handle [[ expr ]] bashism bash-compatibly,
8618 * we make it a synonym of [ expr ].
8619 * Basically, word splitting and pathname expansion should NOT be performed
8621 * no word splitting: a="a b"; [[ $a = "a b" ]]; echo $? should print "0"
8622 * no pathname expansion: [[ /bin/m* = "/bin/m*" ]]; echo $? should print "0"
8623 * Additional operators:
8624 * || and && should work as -o and -a
8626 * Apart from the above, [[ expr ]] should work as [ expr ]
8629 #define echocmd echo_main
8630 #define printfcmd printf_main
8631 #define testcmd test_main
8633 /* Keep these in proper order since it is searched via bsearch() */
8634 static const struct builtincmd builtintab[] = {
8635 { BUILTIN_SPEC_REG ".", dotcmd },
8636 { BUILTIN_SPEC_REG ":", truecmd },
8637 #if ENABLE_ASH_BUILTIN_TEST
8638 { BUILTIN_REGULAR "[", testcmd },
8639 #if ENABLE_ASH_BASH_COMPAT
8640 { BUILTIN_REGULAR "[[", testcmd },
8643 #if ENABLE_ASH_ALIAS
8644 { BUILTIN_REG_ASSG "alias", aliascmd },
8647 { BUILTIN_REGULAR "bg", fg_bgcmd },
8649 { BUILTIN_SPEC_REG "break", breakcmd },
8650 { BUILTIN_REGULAR "cd", cdcmd },
8651 { BUILTIN_NOSPEC "chdir", cdcmd },
8652 #if ENABLE_ASH_CMDCMD
8653 { BUILTIN_REGULAR "command", commandcmd },
8655 { BUILTIN_SPEC_REG "continue", breakcmd },
8656 #if ENABLE_ASH_BUILTIN_ECHO
8657 { BUILTIN_REGULAR "echo", echocmd },
8659 { BUILTIN_SPEC_REG "eval", evalcmd },
8660 { BUILTIN_SPEC_REG "exec", execcmd },
8661 { BUILTIN_SPEC_REG "exit", exitcmd },
8662 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8663 { BUILTIN_REGULAR "false", falsecmd },
8665 { BUILTIN_REGULAR "fg", fg_bgcmd },
8667 #if ENABLE_ASH_GETOPTS
8668 { BUILTIN_REGULAR "getopts", getoptscmd },
8670 { BUILTIN_NOSPEC "hash", hashcmd },
8671 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8672 { BUILTIN_NOSPEC "help", helpcmd },
8675 { BUILTIN_REGULAR "jobs", jobscmd },
8676 { BUILTIN_REGULAR "kill", killcmd },
8678 #if ENABLE_ASH_MATH_SUPPORT
8679 { BUILTIN_NOSPEC "let", letcmd },
8681 { BUILTIN_ASSIGN "local", localcmd },
8682 #if ENABLE_ASH_BUILTIN_PRINTF
8683 { BUILTIN_REGULAR "printf", printfcmd },
8685 { BUILTIN_NOSPEC "pwd", pwdcmd },
8686 { BUILTIN_REGULAR "read", readcmd },
8687 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8688 { BUILTIN_SPEC_REG "return", returncmd },
8689 { BUILTIN_SPEC_REG "set", setcmd },
8690 { BUILTIN_SPEC_REG "shift", shiftcmd },
8691 { BUILTIN_SPEC_REG "source", dotcmd },
8692 #if ENABLE_ASH_BUILTIN_TEST
8693 { BUILTIN_REGULAR "test", testcmd },
8695 { BUILTIN_SPEC_REG "times", timescmd },
8696 { BUILTIN_SPEC_REG "trap", trapcmd },
8697 { BUILTIN_REGULAR "true", truecmd },
8698 { BUILTIN_NOSPEC "type", typecmd },
8699 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
8700 { BUILTIN_REGULAR "umask", umaskcmd },
8701 #if ENABLE_ASH_ALIAS
8702 { BUILTIN_REGULAR "unalias", unaliascmd },
8704 { BUILTIN_SPEC_REG "unset", unsetcmd },
8705 { BUILTIN_REGULAR "wait", waitcmd },
8708 /* Should match the above table! */
8709 #define COMMANDCMD (builtintab + \
8711 1 * ENABLE_ASH_BUILTIN_TEST + \
8712 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8713 1 * ENABLE_ASH_ALIAS + \
8714 1 * ENABLE_ASH_JOB_CONTROL + \
8716 #define EXECCMD (builtintab + \
8718 1 * ENABLE_ASH_BUILTIN_TEST + \
8719 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8720 1 * ENABLE_ASH_ALIAS + \
8721 1 * ENABLE_ASH_JOB_CONTROL + \
8723 1 * ENABLE_ASH_CMDCMD + \
8725 ENABLE_ASH_BUILTIN_ECHO + \
8729 * Search the table of builtin commands.
8731 static struct builtincmd *
8732 find_builtin(const char *name)
8734 struct builtincmd *bp;
8737 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8744 * Execute a simple command.
8747 isassignment(const char *p)
8749 const char *q = endofname(p);
8755 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8757 /* Preserve exitstatus of a previous possible redirection
8758 * as POSIX mandates */
8759 return back_exitstatus;
8762 evalcommand(union node *cmd, int flags)
8764 static const struct builtincmd null_bltin = {
8765 "\0\0", bltincmd /* why three NULs? */
8767 struct stackmark smark;
8769 struct arglist arglist;
8770 struct arglist varlist;
8773 const struct strlist *sp;
8774 struct cmdentry cmdentry;
8781 struct builtincmd *bcmd;
8782 smallint cmd_is_exec;
8783 smallint pseudovarflag = 0;
8785 /* First expand the arguments. */
8786 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8787 setstackmark(&smark);
8788 back_exitstatus = 0;
8790 cmdentry.cmdtype = CMDBUILTIN;
8791 cmdentry.u.cmd = &null_bltin;
8792 varlist.lastp = &varlist.list;
8793 *varlist.lastp = NULL;
8794 arglist.lastp = &arglist.list;
8795 *arglist.lastp = NULL;
8798 if (cmd->ncmd.args) {
8799 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8800 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8803 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8804 struct strlist **spp;
8806 spp = arglist.lastp;
8807 if (pseudovarflag && isassignment(argp->narg.text))
8808 expandarg(argp, &arglist, EXP_VARTILDE);
8810 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8812 for (sp = *spp; sp; sp = sp->next)
8816 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8817 for (sp = arglist.list; sp; sp = sp->next) {
8818 TRACE(("evalcommand arg: %s\n", sp->text));
8819 *nargv++ = sp->text;
8824 if (iflag && funcnest == 0 && argc > 0)
8825 lastarg = nargv[-1];
8828 expredir(cmd->ncmd.redirect);
8829 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8832 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8833 struct strlist **spp;
8836 spp = varlist.lastp;
8837 expandarg(argp, &varlist, EXP_VARTILDE);
8840 * Modify the command lookup path, if a PATH= assignment
8844 if (varequal(p, path))
8848 /* Print the command if xflag is set. */
8851 const char *p = " %s";
8854 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8857 for (n = 0; n < 2; n++) {
8859 fdprintf(preverrout_fd, p, sp->text);
8867 safe_write(preverrout_fd, "\n", 1);
8873 /* Now locate the command. */
8875 const char *oldpath;
8876 int cmd_flag = DO_ERR;
8881 find_command(argv[0], &cmdentry, cmd_flag, path);
8882 if (cmdentry.cmdtype == CMDUNKNOWN) {
8888 /* implement bltin and command here */
8889 if (cmdentry.cmdtype != CMDBUILTIN)
8892 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8893 if (cmdentry.u.cmd == EXECCMD)
8895 #if ENABLE_ASH_CMDCMD
8896 if (cmdentry.u.cmd == COMMANDCMD) {
8898 nargv = parse_command_args(argv, &path);
8901 argc -= nargv - argv;
8903 cmd_flag |= DO_NOFUNC;
8911 /* We have a redirection error. */
8913 raise_exception(EXERROR);
8915 exitstatus = status;
8919 /* Execute the command. */
8920 switch (cmdentry.cmdtype) {
8922 #if ENABLE_FEATURE_SH_NOFORK
8924 /* find_command() encodes applet_no as (-2 - applet_no) */
8925 int applet_no = (- cmdentry.u.index - 2);
8926 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
8927 listsetvar(varlist.list, VEXPORT|VSTACK);
8928 /* run <applet>_main() */
8929 exitstatus = run_nofork_applet(applet_no, argv);
8935 /* Fork off a child process if necessary. */
8936 if (!(flags & EV_EXIT) || trap[0]) {
8938 jp = makejob(/*cmd,*/ 1);
8939 if (forkshell(jp, cmd, FORK_FG) != 0) {
8940 exitstatus = waitforjob(jp);
8946 listsetvar(varlist.list, VEXPORT|VSTACK);
8947 shellexec(argv, path, cmdentry.u.index);
8951 cmdenviron = varlist.list;
8953 struct strlist *list = cmdenviron;
8955 if (spclbltin > 0 || argc == 0) {
8957 if (cmd_is_exec && argc > 1)
8960 listsetvar(list, i);
8962 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
8969 exit_status = 128 + SIGINT;
8971 exit_status = 128 + pendingsig;
8972 exitstatus = exit_status;
8973 if (i == EXINT || spclbltin > 0) {
8975 longjmp(exception_handler->loc, 1);
8982 listsetvar(varlist.list, 0);
8983 if (evalfun(cmdentry.u.func, argc, argv, flags))
8989 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
8991 /* dsl: I think this is intended to be used to support
8992 * '_' in 'vi' command mode during line editing...
8993 * However I implemented that within libedit itself.
8995 setvar("_", lastarg, 0);
8997 popstackmark(&smark);
9001 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9003 char *volatile savecmdname;
9004 struct jmploc *volatile savehandler;
9005 struct jmploc jmploc;
9008 savecmdname = commandname;
9009 i = setjmp(jmploc.loc);
9012 savehandler = exception_handler;
9013 exception_handler = &jmploc;
9014 commandname = argv[0];
9016 optptr = NULL; /* initialize nextopt */
9017 exitstatus = (*cmd->builtin)(argc, argv);
9018 flush_stdout_stderr();
9020 exitstatus |= ferror(stdout);
9022 commandname = savecmdname;
9024 exception_handler = savehandler;
9030 goodname(const char *p)
9032 return !*endofname(p);
9037 * Search for a command. This is called before we fork so that the
9038 * location of the command will be available in the parent as well as
9039 * the child. The check for "goodname" is an overly conservative
9040 * check that the name will not be subject to expansion.
9043 prehash(union node *n)
9045 struct cmdentry entry;
9047 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9048 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9052 /* ============ Builtin commands
9054 * Builtin commands whose functions are closely tied to evaluation
9055 * are implemented here.
9059 * Handle break and continue commands. Break, continue, and return are
9060 * all handled by setting the evalskip flag. The evaluation routines
9061 * above all check this flag, and if it is set they start skipping
9062 * commands rather than executing them. The variable skipcount is
9063 * the number of loops to break/continue, or the number of function
9064 * levels to return. (The latter is always 1.) It should probably
9065 * be an error to break out of more loops than exist, but it isn't
9066 * in the standard shell so we don't make it one here.
9069 breakcmd(int argc UNUSED_PARAM, char **argv)
9071 int n = argv[1] ? number(argv[1]) : 1;
9074 ash_msg_and_raise_error(illnum, argv[1]);
9078 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9085 /* ============ input.c
9087 * This implements the input routines used by the parser.
9090 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
9093 INPUT_PUSH_FILE = 1,
9094 INPUT_NOFILE_OK = 2,
9097 static int plinno = 1; /* input line number */
9098 /* number of characters left in input buffer */
9099 static int parsenleft; /* copy of parsefile->nleft */
9100 static int parselleft; /* copy of parsefile->lleft */
9101 /* next character in input buffer */
9102 static char *parsenextc; /* copy of parsefile->nextc */
9104 static smallint checkkwd;
9105 /* values of checkkwd variable */
9106 #define CHKALIAS 0x1
9113 struct strpush *sp = g_parsefile->strpush;
9116 #if ENABLE_ASH_ALIAS
9118 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
9119 checkkwd |= CHKALIAS;
9121 if (sp->string != sp->ap->val) {
9124 sp->ap->flag &= ~ALIASINUSE;
9125 if (sp->ap->flag & ALIASDEAD) {
9126 unalias(sp->ap->name);
9130 parsenextc = sp->prevstring;
9131 parsenleft = sp->prevnleft;
9132 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
9133 g_parsefile->strpush = sp->prev;
9134 if (sp != &(g_parsefile->basestrpush))
9143 char *buf = g_parsefile->buf;
9146 #if ENABLE_FEATURE_EDITING
9148 if (!iflag || g_parsefile->fd)
9149 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9151 #if ENABLE_FEATURE_TAB_COMPLETION
9152 line_input_state->path_lookup = pathval();
9154 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
9156 /* Ctrl+C pressed */
9165 if (nr < 0 && errno == 0) {
9166 /* Ctrl+D pressed */
9171 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9175 /* nonblock_safe_read() handles this problem */
9177 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9178 int flags = fcntl(0, F_GETFL);
9179 if (flags >= 0 && (flags & O_NONBLOCK)) {
9180 flags &= ~O_NONBLOCK;
9181 if (fcntl(0, F_SETFL, flags) >= 0) {
9182 out2str("sh: turning off NDELAY mode\n");
9193 * Refill the input buffer and return the next input character:
9195 * 1) If a string was pushed back on the input, pop it;
9196 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
9197 * from a string so we can't refill the buffer, return EOF.
9198 * 3) If the is more stuff in this buffer, use it else call read to fill it.
9199 * 4) Process input up to the next newline, deleting nul characters.
9208 while (g_parsefile->strpush) {
9209 #if ENABLE_ASH_ALIAS
9210 if (parsenleft == -1 && g_parsefile->strpush->ap &&
9211 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
9216 if (--parsenleft >= 0)
9217 return signed_char2int(*parsenextc++);
9219 if (parsenleft == EOF_NLEFT || g_parsefile->buf == NULL)
9221 flush_stdout_stderr();
9228 parselleft = parsenleft = EOF_NLEFT;
9235 /* delete nul characters */
9243 memmove(q, q + 1, more);
9247 parsenleft = q - parsenextc - 1;
9253 parsenleft = q - parsenextc - 1;
9265 out2str(parsenextc);
9270 return signed_char2int(*parsenextc++);
9273 #define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer())
9277 return pgetc_as_macro();
9280 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9281 #define pgetc_macro() pgetc()
9283 #define pgetc_macro() pgetc_as_macro()
9287 * Same as pgetc(), but ignores PEOA.
9289 #if ENABLE_ASH_ALIAS
9297 } while (c == PEOA);
9304 return pgetc_macro();
9309 * Read a line from the script.
9312 pfgets(char *line, int len)
9318 while (--nleft > 0) {
9334 * Undo the last call to pgetc. Only one character may be pushed back.
9335 * PEOF may be pushed back.
9345 * Push a string back onto the input at this current parsefile level.
9346 * We handle aliases this way.
9348 #if !ENABLE_ASH_ALIAS
9349 #define pushstring(s, ap) pushstring(s)
9352 pushstring(char *s, struct alias *ap)
9359 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
9360 if (g_parsefile->strpush) {
9361 sp = ckzalloc(sizeof(struct strpush));
9362 sp->prev = g_parsefile->strpush;
9363 g_parsefile->strpush = sp;
9365 sp = g_parsefile->strpush = &(g_parsefile->basestrpush);
9366 sp->prevstring = parsenextc;
9367 sp->prevnleft = parsenleft;
9368 #if ENABLE_ASH_ALIAS
9371 ap->flag |= ALIASINUSE;
9381 * To handle the "." command, a stack of input files is used. Pushfile
9382 * adds a new entry to the stack and popfile restores the previous level.
9387 struct parsefile *pf;
9389 g_parsefile->nleft = parsenleft;
9390 g_parsefile->lleft = parselleft;
9391 g_parsefile->nextc = parsenextc;
9392 g_parsefile->linno = plinno;
9393 pf = ckzalloc(sizeof(*pf));
9394 pf->prev = g_parsefile;
9396 /*pf->strpush = NULL; - ckzalloc did it */
9397 /*pf->basestrpush.prev = NULL;*/
9404 struct parsefile *pf = g_parsefile;
9412 g_parsefile = pf->prev;
9414 parsenleft = g_parsefile->nleft;
9415 parselleft = g_parsefile->lleft;
9416 parsenextc = g_parsefile->nextc;
9417 plinno = g_parsefile->linno;
9422 * Return to top level.
9427 while (g_parsefile != &basepf)
9432 * Close the file(s) that the shell is reading commands from. Called
9433 * after a fork is done.
9439 if (g_parsefile->fd > 0) {
9440 close(g_parsefile->fd);
9441 g_parsefile->fd = 0;
9446 * Like setinputfile, but takes an open file descriptor. Call this with
9450 setinputfd(int fd, int push)
9452 close_on_exec_on(fd);
9455 g_parsefile->buf = 0;
9457 g_parsefile->fd = fd;
9458 if (g_parsefile->buf == NULL)
9459 g_parsefile->buf = ckmalloc(IBUFSIZ);
9460 parselleft = parsenleft = 0;
9465 * Set the input to take input from a file. If push is set, push the
9466 * old input onto the stack first.
9469 setinputfile(const char *fname, int flags)
9475 fd = open(fname, O_RDONLY);
9477 if (flags & INPUT_NOFILE_OK)
9479 ash_msg_and_raise_error("can't open %s", fname);
9482 fd2 = copyfd(fd, 10);
9485 ash_msg_and_raise_error("out of file descriptors");
9488 setinputfd(fd, flags & INPUT_PUSH_FILE);
9495 * Like setinputfile, but takes input from a string.
9498 setinputstring(char *string)
9502 parsenextc = string;
9503 parsenleft = strlen(string);
9504 g_parsefile->buf = NULL;
9510 /* ============ mail.c
9512 * Routines to check for mail.
9517 #define MAXMBOXES 10
9519 /* times of mailboxes */
9520 static time_t mailtime[MAXMBOXES];
9521 /* Set if MAIL or MAILPATH is changed. */
9522 static smallint mail_var_path_changed;
9525 * Print appropriate message(s) if mail has arrived.
9526 * If mail_var_path_changed is set,
9527 * then the value of MAIL has mail_var_path_changed,
9528 * so we just update the values.
9537 struct stackmark smark;
9540 setstackmark(&smark);
9541 mpath = mpathset() ? mpathval() : mailval();
9542 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9543 p = padvance(&mpath, nullstr);
9548 for (q = p; *q; q++)
9554 q[-1] = '\0'; /* delete trailing '/' */
9555 if (stat(p, &statb) < 0) {
9559 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9562 pathopt ? pathopt : "you have mail"
9565 *mtp = statb.st_mtime;
9567 mail_var_path_changed = 0;
9568 popstackmark(&smark);
9572 changemail(const char *val UNUSED_PARAM)
9574 mail_var_path_changed = 1;
9577 #endif /* ASH_MAIL */
9580 /* ============ ??? */
9583 * Set the shell parameters.
9586 setparam(char **argv)
9592 for (nparam = 0; argv[nparam]; nparam++)
9594 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9596 *ap++ = ckstrdup(*argv++);
9599 freeparam(&shellparam);
9600 shellparam.malloced = 1;
9601 shellparam.nparam = nparam;
9602 shellparam.p = newparam;
9603 #if ENABLE_ASH_GETOPTS
9604 shellparam.optind = 1;
9605 shellparam.optoff = -1;
9610 * Process shell options. The global variable argptr contains a pointer
9611 * to the argument list; we advance it past the options.
9613 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9614 * For a non-interactive shell, an error condition encountered
9615 * by a special built-in ... shall cause the shell to write a diagnostic message
9616 * to standard error and exit as shown in the following table:
9617 * Error Special Built-In
9619 * Utility syntax error (option or operand error) Shall exit
9621 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9622 * we see that bash does not do that (set "finishes" with error code 1 instead,
9623 * and shell continues), and people rely on this behavior!
9625 * set -o barfoo 2>/dev/null
9628 * Oh well. Let's mimic that.
9631 plus_minus_o(char *name, int val)
9636 for (i = 0; i < NOPTS; i++) {
9637 if (strcmp(name, optnames(i)) == 0) {
9642 ash_msg("illegal option %co %s", val ? '-' : '+', name);
9645 for (i = 0; i < NOPTS; i++) {
9647 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
9649 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
9655 setoption(int flag, int val)
9659 for (i = 0; i < NOPTS; i++) {
9660 if (optletters(i) == flag) {
9665 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
9669 options(int cmdline)
9677 while ((p = *argptr) != NULL) {
9679 if (c != '-' && c != '+')
9682 val = 0; /* val = 0 if c == '+' */
9685 if (p[0] == '\0' || LONE_DASH(p)) {
9687 /* "-" means turn off -x and -v */
9690 /* "--" means reset params */
9691 else if (*argptr == NULL)
9694 break; /* "-" or "--" terminates options */
9697 /* first char was + or - */
9698 while ((c = *p++) != '\0') {
9699 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9700 if (c == 'c' && cmdline) {
9701 minusc = p; /* command is after shell args */
9702 } else if (c == 'o') {
9703 if (plus_minus_o(*argptr, val)) {
9704 /* it already printed err message */
9705 return 1; /* error */
9709 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9711 /* bash does not accept +-login, we also won't */
9712 } else if (cmdline && val && (c == '-')) { /* long options */
9713 if (strcmp(p, "login") == 0)
9725 * The shift builtin command.
9728 shiftcmd(int argc UNUSED_PARAM, char **argv)
9735 n = number(argv[1]);
9736 if (n > shellparam.nparam)
9737 n = 0; /* bash compat, was = shellparam.nparam; */
9739 shellparam.nparam -= n;
9740 for (ap1 = shellparam.p; --n >= 0; ap1++) {
9741 if (shellparam.malloced)
9745 while ((*ap2++ = *ap1++) != NULL)
9747 #if ENABLE_ASH_GETOPTS
9748 shellparam.optind = 1;
9749 shellparam.optoff = -1;
9756 * POSIX requires that 'set' (but not export or readonly) output the
9757 * variables in lexicographic order - by the locale's collating order (sigh).
9758 * Maybe we could keep them in an ordered balanced binary tree
9759 * instead of hashed lists.
9760 * For now just roll 'em through qsort for printing...
9763 showvars(const char *sep_prefix, int on, int off)
9768 ep = listvars(on, off, &epend);
9769 qsort(ep, epend - ep, sizeof(char *), vpcmp);
9771 sep = *sep_prefix ? " " : sep_prefix;
9773 for (; ep < epend; ep++) {
9777 p = strchrnul(*ep, '=');
9780 q = single_quote(++p);
9781 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9787 * The set command builtin.
9790 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9795 return showvars(nullstr, 0, VUNSET);
9798 if (!options(0)) { /* if no parse error... */
9801 if (*argptr != NULL) {
9809 #if ENABLE_ASH_RANDOM_SUPPORT
9811 change_random(const char *value)
9813 /* Galois LFSR parameter */
9814 /* Taps at 32 31 29 1: */
9815 enum { MASK = 0x8000000b };
9816 /* Another example - taps at 32 31 30 10: */
9817 /* MASK = 0x00400007 */
9819 if (value == NULL) {
9820 /* "get", generate */
9823 /* LCG has period of 2^32 and alternating lowest bit */
9824 random_LCG = 1664525 * random_LCG + 1013904223;
9825 /* Galois LFSR has period of 2^32-1 = 3 * 5 * 17 * 257 * 65537 */
9826 t = (random_galois_LFSR << 1);
9827 if (random_galois_LFSR < 0) /* if we just shifted 1 out of msb... */
9829 random_galois_LFSR = t;
9830 /* Both are weak, combining them gives better randomness
9831 * and ~2^64 period. & 0x7fff is probably bash compat
9832 * for $RANDOM range. Combining with subtraction is
9833 * just for fun. + and ^ would work equally well. */
9834 t = (t - random_LCG) & 0x7fff;
9835 /* set without recursion */
9836 setvar(vrandom.text, utoa(t), VNOFUNC);
9837 vrandom.flags &= ~VNOFUNC;
9840 random_galois_LFSR = random_LCG = strtoul(value, (char **)NULL, 10);
9845 #if ENABLE_ASH_GETOPTS
9847 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9856 if (*param_optind < 1)
9858 optnext = optfirst + *param_optind - 1;
9860 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
9863 p = optnext[-1] + *optoff;
9864 if (p == NULL || *p == '\0') {
9865 /* Current word is done, advance */
9867 if (p == NULL || *p != '-' || *++p == '\0') {
9874 if (LONE_DASH(p)) /* check for "--" */
9879 for (q = optstr; *q != c;) {
9881 if (optstr[0] == ':') {
9884 err |= setvarsafe("OPTARG", s, 0);
9886 fprintf(stderr, "Illegal option -%c\n", c);
9897 if (*p == '\0' && (p = *optnext) == NULL) {
9898 if (optstr[0] == ':') {
9901 err |= setvarsafe("OPTARG", s, 0);
9904 fprintf(stderr, "No arg for -%c option\n", c);
9913 err |= setvarsafe("OPTARG", p, 0);
9916 err |= setvarsafe("OPTARG", nullstr, 0);
9918 *optoff = p ? p - *(optnext - 1) : -1;
9919 *param_optind = optnext - optfirst + 1;
9920 fmtstr(s, sizeof(s), "%d", *param_optind);
9921 err |= setvarsafe("OPTIND", s, VNOFUNC);
9924 err |= setvarsafe(optvar, s, 0);
9928 flush_stdout_stderr();
9929 raise_exception(EXERROR);
9935 * The getopts builtin. Shellparam.optnext points to the next argument
9936 * to be processed. Shellparam.optptr points to the next character to
9937 * be processed in the current argument. If shellparam.optnext is NULL,
9938 * then it's the first time getopts has been called.
9941 getoptscmd(int argc, char **argv)
9946 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
9948 optbase = shellparam.p;
9949 if (shellparam.optind > shellparam.nparam + 1) {
9950 shellparam.optind = 1;
9951 shellparam.optoff = -1;
9955 if (shellparam.optind > argc - 2) {
9956 shellparam.optind = 1;
9957 shellparam.optoff = -1;
9961 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9962 &shellparam.optoff);
9964 #endif /* ASH_GETOPTS */
9967 /* ============ Shell parser */
9970 struct heredoc *next; /* next here document in list */
9971 union node *here; /* redirection node */
9972 char *eofmark; /* string indicating end of input */
9973 smallint striptabs; /* if set, strip leading tabs */
9976 static smallint tokpushback; /* last token pushed back */
9977 static smallint parsebackquote; /* nonzero if we are inside backquotes */
9978 static smallint quoteflag; /* set if (part of) last token was quoted */
9979 static token_id_t lasttoken; /* last token read (integer id Txxx) */
9980 static struct heredoc *heredoclist; /* list of here documents to read */
9981 static char *wordtext; /* text of last word returned by readtoken */
9982 static struct nodelist *backquotelist;
9983 static union node *redirnode;
9984 static struct heredoc *heredoc;
9986 * NEOF is returned by parsecmd when it encounters an end of file. It
9987 * must be distinct from NULL, so we use the address of a variable that
9988 * happens to be handy.
9990 #define NEOF ((union node *)&tokpushback)
9992 static void raise_error_syntax(const char *) NORETURN;
9994 raise_error_syntax(const char *msg)
9996 ash_msg_and_raise_error("syntax error: %s", msg);
10001 * Called when an unexpected token is read during the parse. The argument
10002 * is the token that is expected, or -1 if more than one type of token can
10003 * occur at this point.
10005 static void raise_error_unexpected_syntax(int) NORETURN;
10007 raise_error_unexpected_syntax(int token)
10012 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10014 sprintf(msg + l, " (expecting %s)", tokname(token));
10015 raise_error_syntax(msg);
10019 #define EOFMARKLEN 79
10021 /* parsing is heavily cross-recursive, need these forward decls */
10022 static union node *andor(void);
10023 static union node *pipeline(void);
10024 static union node *parse_command(void);
10025 static void parseheredoc(void);
10026 static char peektoken(void);
10027 static int readtoken(void);
10029 static union node *
10032 union node *n1, *n2, *n3;
10035 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10036 if (nlflag == 2 && peektoken())
10042 if (tok == TBACKGND) {
10043 if (n2->type == NPIPE) {
10044 n2->npipe.pipe_backgnd = 1;
10046 if (n2->type != NREDIR) {
10047 n3 = stzalloc(sizeof(struct nredir));
10049 /*n3->nredir.redirect = NULL; - stzalloc did it */
10052 n2->type = NBACKGND;
10058 n3 = stzalloc(sizeof(struct nbinary));
10060 n3->nbinary.ch1 = n1;
10061 n3->nbinary.ch2 = n2;
10077 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10085 pungetc(); /* push back EOF on input */
10089 raise_error_unexpected_syntax(-1);
10096 static union node *
10099 union node *n1, *n2, *n3;
10107 } else if (t == TOR) {
10113 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10115 n3 = stzalloc(sizeof(struct nbinary));
10117 n3->nbinary.ch1 = n1;
10118 n3->nbinary.ch2 = n2;
10123 static union node *
10126 union node *n1, *n2, *pipenode;
10127 struct nodelist *lp, *prev;
10131 TRACE(("pipeline: entered\n"));
10132 if (readtoken() == TNOT) {
10134 checkkwd = CHKKWD | CHKALIAS;
10137 n1 = parse_command();
10138 if (readtoken() == TPIPE) {
10139 pipenode = stzalloc(sizeof(struct npipe));
10140 pipenode->type = NPIPE;
10141 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10142 lp = stzalloc(sizeof(struct nodelist));
10143 pipenode->npipe.cmdlist = lp;
10147 lp = stzalloc(sizeof(struct nodelist));
10148 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10149 lp->n = parse_command();
10151 } while (readtoken() == TPIPE);
10157 n2 = stzalloc(sizeof(struct nnot));
10165 static union node *
10170 n = stzalloc(sizeof(struct narg));
10172 /*n->narg.next = NULL; - stzalloc did it */
10173 n->narg.text = wordtext;
10174 n->narg.backquote = backquotelist;
10179 fixredir(union node *n, const char *text, int err)
10183 TRACE(("Fix redir %s %d\n", text, err));
10185 n->ndup.vname = NULL;
10187 fd = bb_strtou(text, NULL, 10);
10188 if (!errno && fd >= 0)
10189 n->ndup.dupfd = fd;
10190 else if (LONE_DASH(text))
10191 n->ndup.dupfd = -1;
10194 raise_error_syntax("bad fd number");
10195 n->ndup.vname = makename();
10200 * Returns true if the text contains nothing to expand (no dollar signs
10204 noexpand(char *text)
10210 while ((c = *p++) != '\0') {
10211 if (c == CTLQUOTEMARK)
10215 else if (SIT(c, BASESYNTAX) == CCTL)
10224 union node *n = redirnode;
10226 if (readtoken() != TWORD)
10227 raise_error_unexpected_syntax(-1);
10228 if (n->type == NHERE) {
10229 struct heredoc *here = heredoc;
10233 if (quoteflag == 0)
10235 TRACE(("Here document %d\n", n->type));
10236 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10237 raise_error_syntax("illegal eof marker for << redirection");
10238 rmescapes(wordtext);
10239 here->eofmark = wordtext;
10241 if (heredoclist == NULL)
10242 heredoclist = here;
10244 for (p = heredoclist; p->next; p = p->next)
10248 } else if (n->type == NTOFD || n->type == NFROMFD) {
10249 fixredir(n, wordtext, 0);
10251 n->nfile.fname = makename();
10255 static union node *
10258 union node *args, **app;
10259 union node *n = NULL;
10260 union node *vars, **vpp;
10261 union node **rpp, *redir;
10263 #if ENABLE_ASH_BASH_COMPAT
10264 smallint double_brackets_flag = 0;
10274 savecheckkwd = CHKALIAS;
10277 checkkwd = savecheckkwd;
10280 #if ENABLE_ASH_BASH_COMPAT
10281 case TAND: /* "&&" */
10282 case TOR: /* "||" */
10283 if (!double_brackets_flag) {
10287 wordtext = (char *) (t == TAND ? "-a" : "-o");
10290 n = stzalloc(sizeof(struct narg));
10292 /*n->narg.next = NULL; - stzalloc did it */
10293 n->narg.text = wordtext;
10294 #if ENABLE_ASH_BASH_COMPAT
10295 if (strcmp("[[", wordtext) == 0)
10296 double_brackets_flag = 1;
10297 else if (strcmp("]]", wordtext) == 0)
10298 double_brackets_flag = 0;
10300 n->narg.backquote = backquotelist;
10301 if (savecheckkwd && isassignment(wordtext)) {
10303 vpp = &n->narg.next;
10306 app = &n->narg.next;
10311 *rpp = n = redirnode;
10312 rpp = &n->nfile.next;
10313 parsefname(); /* read name of redirection file */
10316 if (args && app == &args->narg.next
10319 struct builtincmd *bcmd;
10322 /* We have a function */
10323 if (readtoken() != TRP)
10324 raise_error_unexpected_syntax(TRP);
10325 name = n->narg.text;
10326 if (!goodname(name)
10327 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10329 raise_error_syntax("bad function name");
10332 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10333 n->narg.next = parse_command();
10346 n = stzalloc(sizeof(struct ncmd));
10348 n->ncmd.args = args;
10349 n->ncmd.assign = vars;
10350 n->ncmd.redirect = redir;
10354 static union node *
10355 parse_command(void)
10357 union node *n1, *n2;
10358 union node *ap, **app;
10359 union node *cp, **cpp;
10360 union node *redir, **rpp;
10367 switch (readtoken()) {
10369 raise_error_unexpected_syntax(-1);
10372 n1 = stzalloc(sizeof(struct nif));
10374 n1->nif.test = list(0);
10375 if (readtoken() != TTHEN)
10376 raise_error_unexpected_syntax(TTHEN);
10377 n1->nif.ifpart = list(0);
10379 while (readtoken() == TELIF) {
10380 n2->nif.elsepart = stzalloc(sizeof(struct nif));
10381 n2 = n2->nif.elsepart;
10383 n2->nif.test = list(0);
10384 if (readtoken() != TTHEN)
10385 raise_error_unexpected_syntax(TTHEN);
10386 n2->nif.ifpart = list(0);
10388 if (lasttoken == TELSE)
10389 n2->nif.elsepart = list(0);
10391 n2->nif.elsepart = NULL;
10399 n1 = stzalloc(sizeof(struct nbinary));
10400 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10401 n1->nbinary.ch1 = list(0);
10404 TRACE(("expecting DO got %s %s\n", tokname(got),
10405 got == TWORD ? wordtext : ""));
10406 raise_error_unexpected_syntax(TDO);
10408 n1->nbinary.ch2 = list(0);
10413 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10414 raise_error_syntax("bad for loop variable");
10415 n1 = stzalloc(sizeof(struct nfor));
10417 n1->nfor.var = wordtext;
10418 checkkwd = CHKKWD | CHKALIAS;
10419 if (readtoken() == TIN) {
10421 while (readtoken() == TWORD) {
10422 n2 = stzalloc(sizeof(struct narg));
10424 /*n2->narg.next = NULL; - stzalloc did it */
10425 n2->narg.text = wordtext;
10426 n2->narg.backquote = backquotelist;
10428 app = &n2->narg.next;
10431 n1->nfor.args = ap;
10432 if (lasttoken != TNL && lasttoken != TSEMI)
10433 raise_error_unexpected_syntax(-1);
10435 n2 = stzalloc(sizeof(struct narg));
10437 /*n2->narg.next = NULL; - stzalloc did it */
10438 n2->narg.text = (char *)dolatstr;
10439 /*n2->narg.backquote = NULL;*/
10440 n1->nfor.args = n2;
10442 * Newline or semicolon here is optional (but note
10443 * that the original Bourne shell only allowed NL).
10445 if (lasttoken != TNL && lasttoken != TSEMI)
10448 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10449 if (readtoken() != TDO)
10450 raise_error_unexpected_syntax(TDO);
10451 n1->nfor.body = list(0);
10455 n1 = stzalloc(sizeof(struct ncase));
10457 if (readtoken() != TWORD)
10458 raise_error_unexpected_syntax(TWORD);
10459 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10461 /*n2->narg.next = NULL; - stzalloc did it */
10462 n2->narg.text = wordtext;
10463 n2->narg.backquote = backquotelist;
10465 checkkwd = CHKKWD | CHKALIAS;
10466 } while (readtoken() == TNL);
10467 if (lasttoken != TIN)
10468 raise_error_unexpected_syntax(TIN);
10469 cpp = &n1->ncase.cases;
10471 checkkwd = CHKNL | CHKKWD;
10473 while (t != TESAC) {
10474 if (lasttoken == TLP)
10476 *cpp = cp = stzalloc(sizeof(struct nclist));
10478 app = &cp->nclist.pattern;
10480 *app = ap = stzalloc(sizeof(struct narg));
10482 /*ap->narg.next = NULL; - stzalloc did it */
10483 ap->narg.text = wordtext;
10484 ap->narg.backquote = backquotelist;
10485 if (readtoken() != TPIPE)
10487 app = &ap->narg.next;
10490 //ap->narg.next = NULL;
10491 if (lasttoken != TRP)
10492 raise_error_unexpected_syntax(TRP);
10493 cp->nclist.body = list(2);
10495 cpp = &cp->nclist.next;
10497 checkkwd = CHKNL | CHKKWD;
10501 raise_error_unexpected_syntax(TENDCASE);
10508 n1 = stzalloc(sizeof(struct nredir));
10509 n1->type = NSUBSHELL;
10510 n1->nredir.n = list(0);
10511 /*n1->nredir.redirect = NULL; - stzalloc did it */
10521 return simplecmd();
10524 if (readtoken() != t)
10525 raise_error_unexpected_syntax(t);
10528 /* Now check for redirection which may follow command */
10529 checkkwd = CHKKWD | CHKALIAS;
10531 while (readtoken() == TREDIR) {
10532 *rpp = n2 = redirnode;
10533 rpp = &n2->nfile.next;
10539 if (n1->type != NSUBSHELL) {
10540 n2 = stzalloc(sizeof(struct nredir));
10545 n1->nredir.redirect = redir;
10550 #if ENABLE_ASH_BASH_COMPAT
10551 static int decode_dollar_squote(void)
10553 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
10559 p = strchr(C_escapes, c);
10564 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
10568 } while ((unsigned char)(c - '0') <= 7 && --cnt);
10570 } else if (c == 'x') { /* \xHH */
10574 } while (isxdigit(c) && --cnt);
10576 if (cnt == 3) { /* \x but next char is "bad" */
10580 } else { /* simple seq like \\ or \t */
10585 c = bb_process_escape_sequence((void*)&p);
10586 } else { /* unrecognized "\z": print both chars unless ' or " */
10587 if (c != '\'' && c != '"') {
10589 c |= 0x100; /* "please encode \, then me" */
10597 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10598 * is not NULL, read a here document. In the latter case, eofmark is the
10599 * word which marks the end of the document and striptabs is true if
10600 * leading tabs should be stripped from the document. The argument firstc
10601 * is the first character of the input token or document.
10603 * Because C does not have internal subroutines, I have simulated them
10604 * using goto's to implement the subroutine linkage. The following macros
10605 * will run code that appears at the end of readtoken1.
10607 #define CHECKEND() {goto checkend; checkend_return:;}
10608 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10609 #define PARSESUB() {goto parsesub; parsesub_return:;}
10610 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10611 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10612 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10614 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10616 /* NB: syntax parameter fits into smallint */
10620 char line[EOFMARKLEN + 1];
10621 struct nodelist *bqlist;
10625 smallint prevsyntax; /* syntax before arithmetic */
10626 #if ENABLE_ASH_EXPAND_PRMT
10627 smallint pssyntax; /* we are expanding a prompt string */
10629 int varnest; /* levels of variables expansion */
10630 int arinest; /* levels of arithmetic expansion */
10631 int parenlevel; /* levels of parens in arithmetic */
10632 int dqvarnest; /* levels of variables expansion within double quotes */
10634 USE_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
10637 /* Avoid longjmp clobbering */
10643 (void) &parenlevel;
10646 (void) &prevsyntax;
10649 startlinno = plinno;
10654 #if ENABLE_ASH_EXPAND_PRMT
10655 pssyntax = (syntax == PSSYNTAX);
10659 dblquote = (syntax == DQSYNTAX);
10665 STARTSTACKSTR(out);
10666 loop: { /* for each line, until end of word */
10667 CHECKEND(); /* set c to PEOF if at end of here document */
10668 for (;;) { /* until end of line or end of word */
10669 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10670 switch (SIT(c, syntax)) {
10671 case CNL: /* '\n' */
10672 if (syntax == BASESYNTAX)
10673 goto endword; /* exit outer loop */
10679 goto loop; /* continue outer loop */
10684 if (eofmark == NULL || dblquote)
10685 USTPUTC(CTLESC, out);
10686 #if ENABLE_ASH_BASH_COMPAT
10687 if (c == '\\' && bash_dollar_squote) {
10688 c = decode_dollar_squote();
10690 USTPUTC('\\', out);
10691 c = (unsigned char)c;
10697 case CBACK: /* backslash */
10700 USTPUTC(CTLESC, out);
10701 USTPUTC('\\', out);
10703 } else if (c == '\n') {
10707 #if ENABLE_ASH_EXPAND_PRMT
10708 if (c == '$' && pssyntax) {
10709 USTPUTC(CTLESC, out);
10710 USTPUTC('\\', out);
10713 if (dblquote && c != '\\'
10714 && c != '`' && c != '$'
10715 && (c != '"' || eofmark != NULL)
10717 USTPUTC(CTLESC, out);
10718 USTPUTC('\\', out);
10720 if (SIT(c, SQSYNTAX) == CCTL)
10721 USTPUTC(CTLESC, out);
10729 if (eofmark == NULL) {
10730 USTPUTC(CTLQUOTEMARK, out);
10738 USE_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
10739 if (eofmark != NULL && arinest == 0
10744 if (dqvarnest == 0) {
10745 syntax = BASESYNTAX;
10752 case CVAR: /* '$' */
10753 PARSESUB(); /* parse substitution */
10755 case CENDVAR: /* '}' */
10758 if (dqvarnest > 0) {
10761 USTPUTC(CTLENDVAR, out);
10766 #if ENABLE_ASH_MATH_SUPPORT
10767 case CLP: /* '(' in arithmetic */
10771 case CRP: /* ')' in arithmetic */
10772 if (parenlevel > 0) {
10776 if (pgetc() == ')') {
10777 if (--arinest == 0) {
10778 USTPUTC(CTLENDARI, out);
10779 syntax = prevsyntax;
10780 dblquote = (syntax == DQSYNTAX);
10785 * unbalanced parens
10786 * (don't 2nd guess - no error)
10794 case CBQUOTE: /* '`' */
10798 goto endword; /* exit outer loop */
10803 goto endword; /* exit outer loop */
10804 #if ENABLE_ASH_ALIAS
10814 #if ENABLE_ASH_MATH_SUPPORT
10815 if (syntax == ARISYNTAX)
10816 raise_error_syntax("missing '))'");
10818 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10819 raise_error_syntax("unterminated quoted string");
10820 if (varnest != 0) {
10821 startlinno = plinno;
10823 raise_error_syntax("missing '}'");
10825 USTPUTC('\0', out);
10826 len = out - (char *)stackblock();
10827 out = stackblock();
10828 if (eofmark == NULL) {
10829 if ((c == '>' || c == '<') && quotef == 0) {
10830 if (isdigit_str9(out)) {
10831 PARSEREDIR(); /* passed as params: out, c */
10832 lasttoken = TREDIR;
10835 /* else: non-number X seen, interpret it
10836 * as "NNNX>file" = "NNNX >file" */
10840 quoteflag = quotef;
10841 backquotelist = bqlist;
10842 grabstackblock(len);
10846 /* end of readtoken routine */
10849 * Check to see whether we are at the end of the here document. When this
10850 * is called, c is set to the first character of the next input line. If
10851 * we are at the end of the here document, this routine sets the c to PEOF.
10855 #if ENABLE_ASH_ALIAS
10861 while (c == '\t') {
10865 if (c == *eofmark) {
10866 if (pfgets(line, sizeof(line)) != NULL) {
10870 for (q = eofmark + 1; *q && *p == *q; p++, q++)
10872 if (*p == '\n' && *q == '\0') {
10875 needprompt = doprompt;
10877 pushstring(line, NULL);
10882 goto checkend_return;
10886 * Parse a redirection operator. The variable "out" points to a string
10887 * specifying the fd to be redirected. The variable "c" contains the
10888 * first character of the redirection operator.
10891 /* out is already checked to be a valid number or "" */
10892 int fd = (*out == '\0' ? -1 : atoi(out));
10895 np = stzalloc(sizeof(struct nfile));
10900 np->type = NAPPEND;
10902 np->type = NCLOBBER;
10905 /* it also can be NTO2 (>&file), but we can't figure it out yet */
10910 } else { /* c == '<' */
10911 /*np->nfile.fd = 0; - stzalloc did it */
10915 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10916 np = stzalloc(sizeof(struct nhere));
10917 /*np->nfile.fd = 0; - stzalloc did it */
10920 heredoc = stzalloc(sizeof(struct heredoc));
10921 heredoc->here = np;
10924 heredoc->striptabs = 1;
10926 /*heredoc->striptabs = 0; - stzalloc did it */
10932 np->type = NFROMFD;
10936 np->type = NFROMTO;
10948 goto parseredir_return;
10952 * Parse a substitution. At this point, we have read the dollar sign
10953 * and nothing else.
10956 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
10957 * (assuming ascii char codes, as the original implementation did) */
10958 #define is_special(c) \
10959 (((unsigned)(c) - 33 < 32) \
10960 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
10966 static const char types[] ALIGN1 = "}-+?=";
10969 if (c <= PEOA_OR_PEOF
10970 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10972 #if ENABLE_ASH_BASH_COMPAT
10974 bash_dollar_squote = 1;
10979 } else if (c == '(') { /* $(command) or $((arith)) */
10980 if (pgetc() == '(') {
10981 #if ENABLE_ASH_MATH_SUPPORT
10984 raise_error_syntax("you disabled math support for $((arith)) syntax");
10991 USTPUTC(CTLVAR, out);
10992 typeloc = out - (char *)stackblock();
10993 USTPUTC(VSNORMAL, out);
10994 subtype = VSNORMAL;
11002 subtype = VSLENGTH;
11006 if (c > PEOA_OR_PEOF && is_name(c)) {
11010 } while (c > PEOA_OR_PEOF && is_in_name(c));
11011 } else if (isdigit(c)) {
11015 } while (isdigit(c));
11016 } else if (is_special(c)) {
11021 raise_error_syntax("bad substitution");
11026 if (subtype == 0) {
11030 #if ENABLE_ASH_BASH_COMPAT
11031 if (c == ':' || c == '$' || isdigit(c)) {
11033 subtype = VSSUBSTR;
11040 p = strchr(types, c);
11043 subtype = p - types + VSNORMAL;
11048 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
11056 #if ENABLE_ASH_BASH_COMPAT
11058 subtype = VSREPLACE;
11061 subtype++; /* VSREPLACEALL */
11070 if (dblquote || arinest)
11072 *((char *)stackblock() + typeloc) = subtype | flags;
11073 if (subtype != VSNORMAL) {
11075 if (dblquote || arinest) {
11080 goto parsesub_return;
11084 * Called to parse command substitutions. Newstyle is set if the command
11085 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11086 * list of commands (passed by reference), and savelen is the number of
11087 * characters on the top of the stack which must be preserved.
11090 struct nodelist **nlpp;
11093 char *volatile str;
11094 struct jmploc jmploc;
11095 struct jmploc *volatile savehandler;
11097 smallint saveprompt = 0;
11100 (void) &saveprompt;
11102 savepbq = parsebackquote;
11103 if (setjmp(jmploc.loc)) {
11105 parsebackquote = 0;
11106 exception_handler = savehandler;
11107 longjmp(exception_handler->loc, 1);
11111 savelen = out - (char *)stackblock();
11113 str = ckmalloc(savelen);
11114 memcpy(str, stackblock(), savelen);
11116 savehandler = exception_handler;
11117 exception_handler = &jmploc;
11120 /* We must read until the closing backquote, giving special
11121 treatment to some slashes, and then push the string and
11122 reread it as input, interpreting it normally. */
11129 STARTSTACKSTR(pout);
11146 * If eating a newline, avoid putting
11147 * the newline into the new character
11148 * stream (via the STPUTC after the
11153 if (pc != '\\' && pc != '`' && pc != '$'
11154 && (!dblquote || pc != '"'))
11155 STPUTC('\\', pout);
11156 if (pc > PEOA_OR_PEOF) {
11162 #if ENABLE_ASH_ALIAS
11165 startlinno = plinno;
11166 raise_error_syntax("EOF in backquote substitution");
11170 needprompt = doprompt;
11179 STPUTC('\0', pout);
11180 psavelen = pout - (char *)stackblock();
11181 if (psavelen > 0) {
11182 pstr = grabstackstr(pout);
11183 setinputstring(pstr);
11188 nlpp = &(*nlpp)->next;
11189 *nlpp = stzalloc(sizeof(**nlpp));
11190 /* (*nlpp)->next = NULL; - stzalloc did it */
11191 parsebackquote = oldstyle;
11194 saveprompt = doprompt;
11201 doprompt = saveprompt;
11202 else if (readtoken() != TRP)
11203 raise_error_unexpected_syntax(TRP);
11208 * Start reading from old file again, ignoring any pushed back
11209 * tokens left from the backquote parsing
11214 while (stackblocksize() <= savelen)
11216 STARTSTACKSTR(out);
11218 memcpy(out, str, savelen);
11219 STADJUST(savelen, out);
11225 parsebackquote = savepbq;
11226 exception_handler = savehandler;
11227 if (arinest || dblquote)
11228 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11230 USTPUTC(CTLBACKQ, out);
11232 goto parsebackq_oldreturn;
11233 goto parsebackq_newreturn;
11236 #if ENABLE_ASH_MATH_SUPPORT
11238 * Parse an arithmetic expansion (indicate start of one and set state)
11241 if (++arinest == 1) {
11242 prevsyntax = syntax;
11243 syntax = ARISYNTAX;
11244 USTPUTC(CTLARI, out);
11251 * we collapse embedded arithmetic expansion to
11252 * parenthesis, which should be equivalent
11256 goto parsearith_return;
11260 } /* end of readtoken */
11263 * Read the next input token.
11264 * If the token is a word, we set backquotelist to the list of cmds in
11265 * backquotes. We set quoteflag to true if any part of the word was
11267 * If the token is TREDIR, then we set redirnode to a structure containing
11269 * In all cases, the variable startlinno is set to the number of the line
11270 * on which the token starts.
11272 * [Change comment: here documents and internal procedures]
11273 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11274 * word parsing code into a separate routine. In this case, readtoken
11275 * doesn't need to have any internal procedures, but parseword does.
11276 * We could also make parseoperator in essence the main routine, and
11277 * have parseword (readtoken1?) handle both words and redirection.]
11279 #define NEW_xxreadtoken
11280 #ifdef NEW_xxreadtoken
11281 /* singles must be first! */
11282 static const char xxreadtoken_chars[7] ALIGN1 = {
11283 '\n', '(', ')', '&', '|', ';', 0
11286 static const char xxreadtoken_tokens[] ALIGN1 = {
11287 TNL, TLP, TRP, /* only single occurrence allowed */
11288 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11289 TEOF, /* corresponds to trailing nul */
11290 TAND, TOR, TENDCASE /* if double occurrence */
11293 #define xxreadtoken_doubles \
11294 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
11295 #define xxreadtoken_singles \
11296 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
11310 startlinno = plinno;
11311 for (;;) { /* until token or start of word found */
11314 if ((c != ' ') && (c != '\t')
11315 #if ENABLE_ASH_ALIAS
11320 while ((c = pgetc()) != '\n' && c != PEOF)
11323 } else if (c == '\\') {
11324 if (pgetc() != '\n') {
11328 startlinno = ++plinno;
11333 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11338 needprompt = doprompt;
11341 p = strchr(xxreadtoken_chars, c);
11344 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11347 if ((size_t)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11348 if (pgetc() == *p) { /* double occurrence? */
11349 p += xxreadtoken_doubles + 1;
11355 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11362 #define RETURN(token) return lasttoken = token
11375 startlinno = plinno;
11376 for (;;) { /* until token or start of word found */
11379 case ' ': case '\t':
11380 #if ENABLE_ASH_ALIAS
11385 while ((c = pgetc()) != '\n' && c != PEOF)
11390 if (pgetc() == '\n') {
11391 startlinno = ++plinno;
11400 needprompt = doprompt;
11405 if (pgetc() == '&')
11410 if (pgetc() == '|')
11415 if (pgetc() == ';')
11428 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11431 #endif /* NEW_xxreadtoken */
11438 smallint alreadyseen = tokpushback;
11441 #if ENABLE_ASH_ALIAS
11450 if (checkkwd & CHKNL) {
11457 if (t != TWORD || quoteflag) {
11462 * check for keywords
11464 if (checkkwd & CHKKWD) {
11465 const char *const *pp;
11467 pp = findkwd(wordtext);
11469 lasttoken = t = pp - tokname_array;
11470 TRACE(("keyword %s recognized\n", tokname(t)));
11475 if (checkkwd & CHKALIAS) {
11476 #if ENABLE_ASH_ALIAS
11478 ap = lookupalias(wordtext, 1);
11481 pushstring(ap->val, ap);
11491 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11493 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11505 return tokname_array[t][0];
11509 * Read and parse a command. Returns NEOF on end of file. (NULL is a
11510 * valid parse tree indicating a blank line.)
11512 static union node *
11513 parsecmd(int interact)
11518 doprompt = interact;
11520 setprompt(doprompt);
11532 * Input any here documents.
11537 struct heredoc *here;
11540 here = heredoclist;
11541 heredoclist = NULL;
11547 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
11548 here->eofmark, here->striptabs);
11549 n = stzalloc(sizeof(struct narg));
11550 n->narg.type = NARG;
11551 /*n->narg.next = NULL; - stzalloc did it */
11552 n->narg.text = wordtext;
11553 n->narg.backquote = backquotelist;
11554 here->here->nhere.doc = n;
11561 * called by editline -- any expansions to the prompt should be added here.
11563 #if ENABLE_ASH_EXPAND_PRMT
11564 static const char *
11565 expandstr(const char *ps)
11569 /* XXX Fix (char *) cast. */
11570 setinputstring((char *)ps);
11571 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
11574 n.narg.type = NARG;
11575 n.narg.next = NULL;
11576 n.narg.text = wordtext;
11577 n.narg.backquote = backquotelist;
11579 expandarg(&n, NULL, 0);
11580 return stackblock();
11585 * Execute a command or commands contained in a string.
11588 evalstring(char *s, int mask)
11591 struct stackmark smark;
11595 setstackmark(&smark);
11598 while ((n = parsecmd(0)) != NEOF) {
11600 popstackmark(&smark);
11613 * The eval command.
11616 evalcmd(int argc UNUSED_PARAM, char **argv)
11625 STARTSTACKSTR(concat);
11627 concat = stack_putstr(p, concat);
11631 STPUTC(' ', concat);
11633 STPUTC('\0', concat);
11634 p = grabstackstr(concat);
11636 evalstring(p, ~SKIPEVAL);
11643 * Read and execute commands. "Top" is nonzero for the top level command
11644 * loop; it turns on prompting if the shell is interactive.
11650 struct stackmark smark;
11654 TRACE(("cmdloop(%d) called\n", top));
11658 setstackmark(&smark);
11661 showjobs(stderr, SHOW_CHANGED);
11664 if (iflag && top) {
11666 #if ENABLE_ASH_MAIL
11670 n = parsecmd(inter);
11671 /* showtree(n); DEBUG */
11673 if (!top || numeof >= 50)
11675 if (!stoppedjobs()) {
11678 out2str("\nUse \"exit\" to leave shell.\n");
11681 } else if (nflag == 0) {
11682 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11687 popstackmark(&smark);
11692 return skip & SKIPEVAL;
11699 * Take commands from a file. To be compatible we should do a path
11700 * search for the file, which is necessary to find sub-commands.
11703 find_dot_file(char *name)
11706 const char *path = pathval();
11709 /* don't try this for absolute or relative paths */
11710 if (strchr(name, '/'))
11713 while ((fullname = padvance(&path, name)) != NULL) {
11714 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11716 * Don't bother freeing here, since it will
11717 * be freed by the caller.
11721 stunalloc(fullname);
11724 /* not found in the PATH */
11725 ash_msg_and_raise_error("%s: not found", name);
11730 dotcmd(int argc, char **argv)
11732 struct strlist *sp;
11733 volatile struct shparam saveparam;
11736 for (sp = cmdenviron; sp; sp = sp->next)
11737 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11739 if (argv[1]) { /* That's what SVR2 does */
11740 char *fullname = find_dot_file(argv[1]);
11743 if (argc) { /* argc > 0, argv[0] != NULL */
11744 saveparam = shellparam;
11745 shellparam.malloced = 0;
11746 shellparam.nparam = argc;
11747 shellparam.p = argv;
11750 setinputfile(fullname, INPUT_PUSH_FILE);
11751 commandname = fullname;
11756 freeparam(&shellparam);
11757 shellparam = saveparam;
11759 status = exitstatus;
11765 exitcmd(int argc UNUSED_PARAM, char **argv)
11770 exitstatus = number(argv[1]);
11771 raise_exception(EXEXIT);
11776 * Read a file containing shell functions.
11779 readcmdfile(char *name)
11781 setinputfile(name, INPUT_PUSH_FILE);
11787 /* ============ find_command inplementation */
11790 * Resolve a command name. If you change this routine, you may have to
11791 * change the shellexec routine as well.
11794 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11796 struct tblentry *cmdp;
11803 struct builtincmd *bcmd;
11805 /* If name contains a slash, don't use PATH or hash table */
11806 if (strchr(name, '/') != NULL) {
11807 entry->u.index = -1;
11808 if (act & DO_ABS) {
11809 while (stat(name, &statb) < 0) {
11811 if (errno == EINTR)
11814 entry->cmdtype = CMDUNKNOWN;
11818 entry->cmdtype = CMDNORMAL;
11822 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11824 updatetbl = (path == pathval());
11827 if (strstr(path, "%builtin") != NULL)
11828 act |= DO_ALTBLTIN;
11831 /* If name is in the table, check answer will be ok */
11832 cmdp = cmdlookup(name, 0);
11833 if (cmdp != NULL) {
11836 switch (cmdp->cmdtype) {
11854 } else if (cmdp->rehash == 0)
11855 /* if not invalidated by cd, we're done */
11859 /* If %builtin not in path, check for builtin next */
11860 bcmd = find_builtin(name);
11862 if (IS_BUILTIN_REGULAR(bcmd))
11863 goto builtin_success;
11864 if (act & DO_ALTPATH) {
11865 if (!(act & DO_ALTBLTIN))
11866 goto builtin_success;
11867 } else if (builtinloc <= 0) {
11868 goto builtin_success;
11872 #if ENABLE_FEATURE_SH_STANDALONE
11874 int applet_no = find_applet_by_name(name);
11875 if (applet_no >= 0) {
11876 entry->cmdtype = CMDNORMAL;
11877 entry->u.index = -2 - applet_no;
11883 /* We have to search path. */
11884 prev = -1; /* where to start */
11885 if (cmdp && cmdp->rehash) { /* doing a rehash */
11886 if (cmdp->cmdtype == CMDBUILTIN)
11889 prev = cmdp->param.index;
11895 while ((fullname = padvance(&path, name)) != NULL) {
11896 stunalloc(fullname);
11897 /* NB: code below will still use fullname
11898 * despite it being "unallocated" */
11901 if (prefix(pathopt, "builtin")) {
11903 goto builtin_success;
11906 if ((act & DO_NOFUNC)
11907 || !prefix(pathopt, "func")
11908 ) { /* ignore unimplemented options */
11912 /* if rehash, don't redo absolute path names */
11913 if (fullname[0] == '/' && idx <= prev) {
11916 TRACE(("searchexec \"%s\": no change\n", name));
11919 while (stat(fullname, &statb) < 0) {
11921 if (errno == EINTR)
11924 if (errno != ENOENT && errno != ENOTDIR)
11928 e = EACCES; /* if we fail, this will be the error */
11929 if (!S_ISREG(statb.st_mode))
11931 if (pathopt) { /* this is a %func directory */
11932 stalloc(strlen(fullname) + 1);
11933 /* NB: stalloc will return space pointed by fullname
11934 * (because we don't have any intervening allocations
11935 * between stunalloc above and this stalloc) */
11936 readcmdfile(fullname);
11937 cmdp = cmdlookup(name, 0);
11938 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
11939 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
11940 stunalloc(fullname);
11943 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
11945 entry->cmdtype = CMDNORMAL;
11946 entry->u.index = idx;
11950 cmdp = cmdlookup(name, 1);
11951 cmdp->cmdtype = CMDNORMAL;
11952 cmdp->param.index = idx;
11957 /* We failed. If there was an entry for this command, delete it */
11958 if (cmdp && updatetbl)
11959 delete_cmd_entry();
11961 ash_msg("%s: %s", name, errmsg(e, "not found"));
11962 entry->cmdtype = CMDUNKNOWN;
11967 entry->cmdtype = CMDBUILTIN;
11968 entry->u.cmd = bcmd;
11972 cmdp = cmdlookup(name, 1);
11973 cmdp->cmdtype = CMDBUILTIN;
11974 cmdp->param.cmd = bcmd;
11978 entry->cmdtype = cmdp->cmdtype;
11979 entry->u = cmdp->param;
11983 /* ============ trap.c */
11986 * The trap builtin.
11989 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11998 for (signo = 0; signo < NSIG; signo++) {
11999 if (trap[signo] != NULL) {
12000 out1fmt("trap -- %s %s\n",
12001 single_quote(trap[signo]),
12002 get_signame(signo));
12011 signo = get_signum(*ap);
12013 ash_msg_and_raise_error("%s: bad trap", *ap);
12016 if (LONE_DASH(action))
12019 action = ckstrdup(action);
12022 trap[signo] = action;
12032 /* ============ Builtins */
12034 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
12036 * Lists available builtins
12039 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12044 out1fmt("\nBuilt-in commands:\n-------------------\n");
12045 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12046 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12047 builtintab[i].name + 1);
12053 #if ENABLE_FEATURE_SH_STANDALONE
12055 const char *a = applet_names;
12057 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12062 a += strlen(a) + 1;
12067 return EXIT_SUCCESS;
12069 #endif /* FEATURE_SH_EXTRA_QUIET */
12072 * The export and readonly commands.
12075 exportcmd(int argc UNUSED_PARAM, char **argv)
12081 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12083 if (nextopt("p") != 'p') {
12088 p = strchr(name, '=');
12092 vp = *findvar(hashvar(name), name);
12098 setvar(name, p, flag);
12099 } while ((name = *++aptr) != NULL);
12103 showvars(argv[0], flag, 0);
12108 * Delete a function if it exists.
12111 unsetfunc(const char *name)
12113 struct tblentry *cmdp;
12115 cmdp = cmdlookup(name, 0);
12116 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
12117 delete_cmd_entry();
12121 * The unset builtin command. We unset the function before we unset the
12122 * variable to allow a function to be unset when there is a readonly variable
12123 * with the same name.
12126 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12133 while ((i = nextopt("vf")) != '\0') {
12137 for (ap = argptr; *ap; ap++) {
12153 #include <sys/times.h>
12155 static const unsigned char timescmd_str[] ALIGN1 = {
12156 ' ', offsetof(struct tms, tms_utime),
12157 '\n', offsetof(struct tms, tms_stime),
12158 ' ', offsetof(struct tms, tms_cutime),
12159 '\n', offsetof(struct tms, tms_cstime),
12164 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12166 long clk_tck, s, t;
12167 const unsigned char *p;
12170 clk_tck = sysconf(_SC_CLK_TCK);
12175 t = *(clock_t *)(((char *) &buf) + p[1]);
12177 out1fmt("%ldm%ld.%.3lds%c",
12179 ((t - s * clk_tck) * 1000) / clk_tck,
12181 } while (*(p += 2));
12186 #if ENABLE_ASH_MATH_SUPPORT
12188 dash_arith(const char *s)
12194 result = arith(s, &errcode);
12197 ash_msg_and_raise_error("exponent less than 0");
12199 ash_msg_and_raise_error("divide by zero");
12201 ash_msg_and_raise_error("expression recursion loop detected");
12202 raise_error_syntax(s);
12210 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12211 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12213 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12216 letcmd(int argc UNUSED_PARAM, char **argv)
12222 ash_msg_and_raise_error("expression expected");
12224 i = dash_arith(*argv);
12229 #endif /* ASH_MATH_SUPPORT */
12232 /* ============ miscbltin.c
12234 * Miscellaneous builtins.
12239 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12240 typedef enum __rlimit_resource rlim_t;
12244 * The read builtin. Options:
12245 * -r Do not interpret '\' specially
12246 * -s Turn off echo (tty only)
12247 * -n NCHARS Read NCHARS max
12248 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12249 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12250 * -u FD Read from given FD instead of fd 0
12251 * This uses unbuffered input, which may be avoidable in some cases.
12252 * TODO: bash also has:
12253 * -a ARRAY Read into array[0],[1],etc
12254 * -d DELIM End on DELIM char, not newline
12255 * -e Use line editing (tty only)
12258 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12260 static const char *const arg_REPLY[] = { "REPLY", NULL };
12273 #if ENABLE_ASH_READ_NCHARS
12274 int nchars = 0; /* if != 0, -n is in effect */
12276 struct termios tty, old_tty;
12278 #if ENABLE_ASH_READ_TIMEOUT
12279 unsigned end_ms = 0;
12280 unsigned timeout = 0;
12285 while ((i = nextopt("p:u:r"
12286 USE_ASH_READ_TIMEOUT("t:")
12287 USE_ASH_READ_NCHARS("n:s")
12291 prompt = optionarg;
12293 #if ENABLE_ASH_READ_NCHARS
12295 nchars = bb_strtou(optionarg, NULL, 10);
12296 if (nchars < 0 || errno)
12297 ash_msg_and_raise_error("invalid count");
12298 /* nchars == 0: off (bash 3.2 does this too) */
12304 #if ENABLE_ASH_READ_TIMEOUT
12306 timeout = bb_strtou(optionarg, NULL, 10);
12307 if (errno || timeout > UINT_MAX / 2048)
12308 ash_msg_and_raise_error("invalid timeout");
12310 #if 0 /* even bash have no -t N.NNN support */
12311 ts.tv_sec = bb_strtou(optionarg, &p, 10);
12313 /* EINVAL means number is ok, but not terminated by NUL */
12314 if (*p == '.' && errno == EINVAL) {
12318 ts.tv_usec = bb_strtou(p, &p2, 10);
12320 ash_msg_and_raise_error("invalid timeout");
12322 /* normalize to usec */
12324 ash_msg_and_raise_error("invalid timeout");
12325 while (scale++ < 6)
12328 } else if (ts.tv_sec < 0 || errno) {
12329 ash_msg_and_raise_error("invalid timeout");
12331 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
12332 ash_msg_and_raise_error("invalid timeout");
12341 fd = bb_strtou(optionarg, NULL, 10);
12342 if (fd < 0 || errno)
12343 ash_msg_and_raise_error("invalid file descriptor");
12349 if (prompt && isatty(fd)) {
12354 ap = (char**)arg_REPLY;
12355 ifs = bltinlookup("IFS");
12358 #if ENABLE_ASH_READ_NCHARS
12359 tcgetattr(fd, &tty);
12361 if (nchars || silent) {
12363 tty.c_lflag &= ~ICANON;
12364 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
12367 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
12369 /* if tcgetattr failed, tcsetattr will fail too.
12370 * Ignoring, it's harmless. */
12371 tcsetattr(fd, TCSANOW, &tty);
12378 #if ENABLE_ASH_READ_TIMEOUT
12379 if (timeout) /* NB: ensuring end_ms is nonzero */
12380 end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1;
12384 #if ENABLE_ASH_READ_TIMEOUT
12386 struct pollfd pfd[1];
12388 pfd[0].events = POLLIN;
12389 timeout = end_ms - (unsigned)(monotonic_us() / 1000);
12390 if ((int)timeout <= 0 /* already late? */
12391 || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
12392 ) { /* timed out! */
12393 #if ENABLE_ASH_READ_NCHARS
12394 tcsetattr(fd, TCSANOW, &old_tty);
12400 if (nonblock_safe_read(fd, &c, 1) != 1) {
12412 if (!rflag && c == '\\') {
12418 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12422 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12424 setvar(*ap, stackblock(), 0);
12433 /* end of do {} while: */
12434 #if ENABLE_ASH_READ_NCHARS
12440 #if ENABLE_ASH_READ_NCHARS
12441 tcsetattr(fd, TCSANOW, &old_tty);
12445 /* Remove trailing blanks */
12446 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12448 setvar(*ap, stackblock(), 0);
12449 while (*++ap != NULL)
12450 setvar(*ap, nullstr, 0);
12455 umaskcmd(int argc UNUSED_PARAM, char **argv)
12457 static const char permuser[3] ALIGN1 = "ugo";
12458 static const char permmode[3] ALIGN1 = "rwx";
12459 static const short permmask[] ALIGN2 = {
12460 S_IRUSR, S_IWUSR, S_IXUSR,
12461 S_IRGRP, S_IWGRP, S_IXGRP,
12462 S_IROTH, S_IWOTH, S_IXOTH
12468 int symbolic_mode = 0;
12470 while (nextopt("S") != '\0') {
12481 if (symbolic_mode) {
12485 for (i = 0; i < 3; i++) {
12488 *p++ = permuser[i];
12490 for (j = 0; j < 3; j++) {
12491 if ((mask & permmask[3 * i + j]) == 0) {
12492 *p++ = permmode[j];
12500 out1fmt("%.4o\n", mask);
12503 if (isdigit((unsigned char) *ap)) {
12506 if (*ap >= '8' || *ap < '0')
12507 ash_msg_and_raise_error(illnum, argv[1]);
12508 mask = (mask << 3) + (*ap - '0');
12509 } while (*++ap != '\0');
12512 mask = ~mask & 0777;
12513 if (!bb_parse_mode(ap, &mask)) {
12514 ash_msg_and_raise_error("illegal mode: %s", ap);
12516 umask(~mask & 0777);
12525 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12526 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12527 * ash by J.T. Conklin.
12533 uint8_t cmd; /* RLIMIT_xxx fit into it */
12534 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
12538 static const struct limits limits_tbl[] = {
12540 { RLIMIT_CPU, 0, 't' },
12542 #ifdef RLIMIT_FSIZE
12543 { RLIMIT_FSIZE, 9, 'f' },
12546 { RLIMIT_DATA, 10, 'd' },
12548 #ifdef RLIMIT_STACK
12549 { RLIMIT_STACK, 10, 's' },
12552 { RLIMIT_CORE, 9, 'c' },
12555 { RLIMIT_RSS, 10, 'm' },
12557 #ifdef RLIMIT_MEMLOCK
12558 { RLIMIT_MEMLOCK, 10, 'l' },
12560 #ifdef RLIMIT_NPROC
12561 { RLIMIT_NPROC, 0, 'p' },
12563 #ifdef RLIMIT_NOFILE
12564 { RLIMIT_NOFILE, 0, 'n' },
12567 { RLIMIT_AS, 10, 'v' },
12569 #ifdef RLIMIT_LOCKS
12570 { RLIMIT_LOCKS, 0, 'w' },
12573 static const char limits_name[] =
12575 "time(seconds)" "\0"
12577 #ifdef RLIMIT_FSIZE
12578 "file(blocks)" "\0"
12583 #ifdef RLIMIT_STACK
12587 "coredump(blocks)" "\0"
12592 #ifdef RLIMIT_MEMLOCK
12593 "locked memory(kb)" "\0"
12595 #ifdef RLIMIT_NPROC
12598 #ifdef RLIMIT_NOFILE
12604 #ifdef RLIMIT_LOCKS
12609 enum limtype { SOFT = 0x1, HARD = 0x2 };
12612 printlim(enum limtype how, const struct rlimit *limit,
12613 const struct limits *l)
12617 val = limit->rlim_max;
12619 val = limit->rlim_cur;
12621 if (val == RLIM_INFINITY)
12622 out1fmt("unlimited\n");
12624 val >>= l->factor_shift;
12625 out1fmt("%lld\n", (long long) val);
12630 ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12634 enum limtype how = SOFT | HARD;
12635 const struct limits *l;
12638 struct rlimit limit;
12641 while ((optc = nextopt("HSa"
12645 #ifdef RLIMIT_FSIZE
12651 #ifdef RLIMIT_STACK
12660 #ifdef RLIMIT_MEMLOCK
12663 #ifdef RLIMIT_NPROC
12666 #ifdef RLIMIT_NOFILE
12672 #ifdef RLIMIT_LOCKS
12690 for (l = limits_tbl; l->option != what; l++)
12693 set = *argptr ? 1 : 0;
12697 if (all || argptr[1])
12698 ash_msg_and_raise_error("too many arguments");
12699 if (strncmp(p, "unlimited\n", 9) == 0)
12700 val = RLIM_INFINITY;
12704 while ((c = *p++) >= '0' && c <= '9') {
12705 val = (val * 10) + (long)(c - '0');
12706 // val is actually 'unsigned long int' and can't get < 0
12707 if (val < (rlim_t) 0)
12711 ash_msg_and_raise_error("bad number");
12712 val <<= l->factor_shift;
12716 const char *lname = limits_name;
12717 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12718 getrlimit(l->cmd, &limit);
12719 out1fmt("%-20s ", lname);
12720 lname += strlen(lname) + 1;
12721 printlim(how, &limit, l);
12726 getrlimit(l->cmd, &limit);
12729 limit.rlim_max = val;
12731 limit.rlim_cur = val;
12732 if (setrlimit(l->cmd, &limit) < 0)
12733 ash_msg_and_raise_error("error setting limit (%m)");
12735 printlim(how, &limit, l);
12741 /* ============ Math support */
12743 #if ENABLE_ASH_MATH_SUPPORT
12745 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12747 Permission is hereby granted, free of charge, to any person obtaining
12748 a copy of this software and associated documentation files (the
12749 "Software"), to deal in the Software without restriction, including
12750 without limitation the rights to use, copy, modify, merge, publish,
12751 distribute, sublicense, and/or sell copies of the Software, and to
12752 permit persons to whom the Software is furnished to do so, subject to
12753 the following conditions:
12755 The above copyright notice and this permission notice shall be
12756 included in all copies or substantial portions of the Software.
12758 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12759 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12760 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12761 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12762 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12763 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12764 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12767 /* This is my infix parser/evaluator. It is optimized for size, intended
12768 * as a replacement for yacc-based parsers. However, it may well be faster
12769 * than a comparable parser written in yacc. The supported operators are
12770 * listed in #defines below. Parens, order of operations, and error handling
12771 * are supported. This code is thread safe. The exact expression format should
12772 * be that which POSIX specifies for shells. */
12774 /* The code uses a simple two-stack algorithm. See
12775 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12776 * for a detailed explanation of the infix-to-postfix algorithm on which
12777 * this is based (this code differs in that it applies operators immediately
12778 * to the stack instead of adding them to a queue to end up with an
12781 /* To use the routine, call it with an expression string and error return
12785 * Aug 24, 2001 Manuel Novoa III
12787 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12789 * 1) In arith_apply():
12790 * a) Cached values of *numptr and &(numptr[-1]).
12791 * b) Removed redundant test for zero denominator.
12794 * a) Eliminated redundant code for processing operator tokens by moving
12795 * to a table-based implementation. Also folded handling of parens
12797 * b) Combined all 3 loops which called arith_apply to reduce generated
12798 * code size at the cost of speed.
12800 * 3) The following expressions were treated as valid by the original code:
12801 * 1() , 0! , 1 ( *3 ) .
12802 * These bugs have been fixed by internally enclosing the expression in
12803 * parens and then checking that all binary ops and right parens are
12804 * preceded by a valid expression (NUM_TOKEN).
12806 * Note: It may be desirable to replace Aaron's test for whitespace with
12807 * ctype's isspace() if it is used by another busybox applet or if additional
12808 * whitespace chars should be considered. Look below the "#include"s for a
12809 * precompiler test.
12813 * Aug 26, 2001 Manuel Novoa III
12815 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12817 * Merge in Aaron's comments previously posted to the busybox list,
12818 * modified slightly to take account of my changes to the code.
12823 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12825 * - allow access to variable,
12826 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12827 * - realize assign syntax (VAR=expr, +=, *= etc)
12828 * - realize exponentiation (** operator)
12829 * - realize comma separated - expr, expr
12830 * - realise ++expr --expr expr++ expr--
12831 * - realise expr ? expr : expr (but, second expr calculate always)
12832 * - allow hexadecimal and octal numbers
12833 * - was restored loses XOR operator
12834 * - remove one goto label, added three ;-)
12835 * - protect $((num num)) as true zero expr (Manuel`s error)
12836 * - always use special isspace(), see comment from bash ;-)
12839 #define arith_isspace(arithval) \
12840 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12842 typedef unsigned char operator;
12844 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12845 * precedence, and 3 high bits are an ID unique across operators of that
12846 * precedence. The ID portion is so that multiple operators can have the
12847 * same precedence, ensuring that the leftmost one is evaluated first.
12848 * Consider * and /. */
12850 #define tok_decl(prec,id) (((id)<<5)|(prec))
12851 #define PREC(op) ((op) & 0x1F)
12853 #define TOK_LPAREN tok_decl(0,0)
12855 #define TOK_COMMA tok_decl(1,0)
12857 #define TOK_ASSIGN tok_decl(2,0)
12858 #define TOK_AND_ASSIGN tok_decl(2,1)
12859 #define TOK_OR_ASSIGN tok_decl(2,2)
12860 #define TOK_XOR_ASSIGN tok_decl(2,3)
12861 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12862 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12863 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12864 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12866 #define TOK_MUL_ASSIGN tok_decl(3,0)
12867 #define TOK_DIV_ASSIGN tok_decl(3,1)
12868 #define TOK_REM_ASSIGN tok_decl(3,2)
12870 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12871 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12873 /* conditional is right associativity too */
12874 #define TOK_CONDITIONAL tok_decl(4,0)
12875 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12877 #define TOK_OR tok_decl(5,0)
12879 #define TOK_AND tok_decl(6,0)
12881 #define TOK_BOR tok_decl(7,0)
12883 #define TOK_BXOR tok_decl(8,0)
12885 #define TOK_BAND tok_decl(9,0)
12887 #define TOK_EQ tok_decl(10,0)
12888 #define TOK_NE tok_decl(10,1)
12890 #define TOK_LT tok_decl(11,0)
12891 #define TOK_GT tok_decl(11,1)
12892 #define TOK_GE tok_decl(11,2)
12893 #define TOK_LE tok_decl(11,3)
12895 #define TOK_LSHIFT tok_decl(12,0)
12896 #define TOK_RSHIFT tok_decl(12,1)
12898 #define TOK_ADD tok_decl(13,0)
12899 #define TOK_SUB tok_decl(13,1)
12901 #define TOK_MUL tok_decl(14,0)
12902 #define TOK_DIV tok_decl(14,1)
12903 #define TOK_REM tok_decl(14,2)
12905 /* exponent is right associativity */
12906 #define TOK_EXPONENT tok_decl(15,1)
12908 /* For now unary operators. */
12909 #define UNARYPREC 16
12910 #define TOK_BNOT tok_decl(UNARYPREC,0)
12911 #define TOK_NOT tok_decl(UNARYPREC,1)
12913 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12914 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12916 #define PREC_PRE (UNARYPREC+2)
12918 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12919 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12921 #define PREC_POST (UNARYPREC+3)
12923 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12924 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12926 #define SPEC_PREC (UNARYPREC+4)
12928 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12929 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12931 #define NUMPTR (*numstackptr)
12934 tok_have_assign(operator op)
12936 operator prec = PREC(op);
12938 convert_prec_is_assing(prec);
12939 return (prec == PREC(TOK_ASSIGN) ||
12940 prec == PREC_PRE || prec == PREC_POST);
12944 is_right_associativity(operator prec)
12946 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
12947 || prec == PREC(TOK_CONDITIONAL));
12952 arith_t contidional_second_val;
12953 char contidional_second_val_initialized;
12954 char *var; /* if NULL then is regular number,
12955 else is variable name */
12958 typedef struct chk_var_recursive_looped_t {
12960 struct chk_var_recursive_looped_t *next;
12961 } chk_var_recursive_looped_t;
12963 static chk_var_recursive_looped_t *prev_chk_var_recursive;
12966 arith_lookup_val(v_n_t *t)
12969 const char * p = lookupvar(t->var);
12974 /* recursive try as expression */
12975 chk_var_recursive_looped_t *cur;
12976 chk_var_recursive_looped_t cur_save;
12978 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
12979 if (strcmp(cur->var, t->var) == 0) {
12980 /* expression recursion loop detected */
12984 /* save current lookuped var name */
12985 cur = prev_chk_var_recursive;
12986 cur_save.var = t->var;
12987 cur_save.next = cur;
12988 prev_chk_var_recursive = &cur_save;
12990 t->val = arith (p, &errcode);
12991 /* restore previous ptr after recursiving */
12992 prev_chk_var_recursive = cur;
12995 /* allow undefined var as 0 */
13001 /* "applying" a token means performing it on the top elements on the integer
13002 * stack. For a unary operator it will only change the top element, but a
13003 * binary operator will pop two arguments and push a result */
13005 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13008 arith_t numptr_val, rez;
13009 int ret_arith_lookup_val;
13011 /* There is no operator that can work without arguments */
13012 if (NUMPTR == numstack) goto err;
13013 numptr_m1 = NUMPTR - 1;
13015 /* check operand is var with noninteger value */
13016 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13017 if (ret_arith_lookup_val)
13018 return ret_arith_lookup_val;
13020 rez = numptr_m1->val;
13021 if (op == TOK_UMINUS)
13023 else if (op == TOK_NOT)
13025 else if (op == TOK_BNOT)
13027 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13029 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13031 else if (op != TOK_UPLUS) {
13032 /* Binary operators */
13034 /* check and binary operators need two arguments */
13035 if (numptr_m1 == numstack) goto err;
13037 /* ... and they pop one */
13040 if (op == TOK_CONDITIONAL) {
13041 if (!numptr_m1->contidional_second_val_initialized) {
13042 /* protect $((expr1 ? expr2)) without ": expr" */
13045 rez = numptr_m1->contidional_second_val;
13046 } else if (numptr_m1->contidional_second_val_initialized) {
13047 /* protect $((expr1 : expr2)) without "expr ? " */
13050 numptr_m1 = NUMPTR - 1;
13051 if (op != TOK_ASSIGN) {
13052 /* check operand is var with noninteger value for not '=' */
13053 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13054 if (ret_arith_lookup_val)
13055 return ret_arith_lookup_val;
13057 if (op == TOK_CONDITIONAL) {
13058 numptr_m1->contidional_second_val = rez;
13060 rez = numptr_m1->val;
13061 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13063 else if (op == TOK_OR)
13064 rez = numptr_val || rez;
13065 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13067 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13069 else if (op == TOK_AND)
13070 rez = rez && numptr_val;
13071 else if (op == TOK_EQ)
13072 rez = (rez == numptr_val);
13073 else if (op == TOK_NE)
13074 rez = (rez != numptr_val);
13075 else if (op == TOK_GE)
13076 rez = (rez >= numptr_val);
13077 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13078 rez >>= numptr_val;
13079 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13080 rez <<= numptr_val;
13081 else if (op == TOK_GT)
13082 rez = (rez > numptr_val);
13083 else if (op == TOK_LT)
13084 rez = (rez < numptr_val);
13085 else if (op == TOK_LE)
13086 rez = (rez <= numptr_val);
13087 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13089 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13091 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13093 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13095 else if (op == TOK_CONDITIONAL_SEP) {
13096 if (numptr_m1 == numstack) {
13097 /* protect $((expr : expr)) without "expr ? " */
13100 numptr_m1->contidional_second_val_initialized = op;
13101 numptr_m1->contidional_second_val = numptr_val;
13102 } else if (op == TOK_CONDITIONAL) {
13104 numptr_val : numptr_m1->contidional_second_val;
13105 } else if (op == TOK_EXPONENT) {
13106 if (numptr_val < 0)
13107 return -3; /* exponent less than 0 */
13112 while (numptr_val--)
13116 } else if (numptr_val==0) /* zero divisor check */
13118 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13120 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13123 if (tok_have_assign(op)) {
13124 char buf[sizeof(arith_t_type)*3 + 2];
13126 if (numptr_m1->var == NULL) {
13130 /* save to shell variable */
13131 #if ENABLE_ASH_MATH_SUPPORT_64
13132 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
13134 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
13136 setvar(numptr_m1->var, buf, 0);
13137 /* after saving, make previous value for v++ or v-- */
13138 if (op == TOK_POST_INC)
13140 else if (op == TOK_POST_DEC)
13143 numptr_m1->val = rez;
13144 /* protect geting var value, is number now */
13145 numptr_m1->var = NULL;
13151 /* longest must be first */
13152 static const char op_tokens[] ALIGN1 = {
13153 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13154 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13155 '<','<', 0, TOK_LSHIFT,
13156 '>','>', 0, TOK_RSHIFT,
13157 '|','|', 0, TOK_OR,
13158 '&','&', 0, TOK_AND,
13159 '!','=', 0, TOK_NE,
13160 '<','=', 0, TOK_LE,
13161 '>','=', 0, TOK_GE,
13162 '=','=', 0, TOK_EQ,
13163 '|','=', 0, TOK_OR_ASSIGN,
13164 '&','=', 0, TOK_AND_ASSIGN,
13165 '*','=', 0, TOK_MUL_ASSIGN,
13166 '/','=', 0, TOK_DIV_ASSIGN,
13167 '%','=', 0, TOK_REM_ASSIGN,
13168 '+','=', 0, TOK_PLUS_ASSIGN,
13169 '-','=', 0, TOK_MINUS_ASSIGN,
13170 '-','-', 0, TOK_POST_DEC,
13171 '^','=', 0, TOK_XOR_ASSIGN,
13172 '+','+', 0, TOK_POST_INC,
13173 '*','*', 0, TOK_EXPONENT,
13177 '=', 0, TOK_ASSIGN,
13189 '?', 0, TOK_CONDITIONAL,
13190 ':', 0, TOK_CONDITIONAL_SEP,
13191 ')', 0, TOK_RPAREN,
13192 '(', 0, TOK_LPAREN,
13196 #define endexpression (&op_tokens[sizeof(op_tokens)-7])
13199 arith(const char *expr, int *perrcode)
13201 char arithval; /* Current character under analysis */
13202 operator lasttok, op;
13204 operator *stack, *stackptr;
13205 const char *p = endexpression;
13207 v_n_t *numstack, *numstackptr;
13208 unsigned datasizes = strlen(expr) + 2;
13210 /* Stack of integers */
13211 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13212 * in any given correct or incorrect expression is left as an exercise to
13214 numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0]));
13215 /* Stack of operator tokens */
13216 stackptr = stack = alloca(datasizes * sizeof(stack[0]));
13218 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13219 *perrcode = errcode = 0;
13223 if (arithval == 0) {
13224 if (p == endexpression) {
13225 /* Null expression. */
13229 /* This is only reached after all tokens have been extracted from the
13230 * input stream. If there are still tokens on the operator stack, they
13231 * are to be applied in order. At the end, there should be a final
13232 * result on the integer stack */
13234 if (expr != endexpression + 1) {
13235 /* If we haven't done so already, */
13236 /* append a closing right paren */
13237 expr = endexpression;
13238 /* and let the loop process it. */
13241 /* At this point, we're done with the expression. */
13242 if (numstackptr != numstack+1) {
13243 /* ... but if there isn't, it's bad */
13248 if (numstack->var) {
13249 /* expression is $((var)) only, lookup now */
13250 errcode = arith_lookup_val(numstack);
13253 *perrcode = errcode;
13254 return numstack->val;
13257 /* Continue processing the expression. */
13258 if (arith_isspace(arithval)) {
13259 /* Skip whitespace */
13262 p = endofname(expr);
13264 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13266 numstackptr->var = alloca(var_name_size);
13267 safe_strncpy(numstackptr->var, expr, var_name_size);
13270 numstackptr->contidional_second_val_initialized = 0;
13275 if (isdigit(arithval)) {
13276 numstackptr->var = NULL;
13277 #if ENABLE_ASH_MATH_SUPPORT_64
13278 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13280 numstackptr->val = strtol(expr, (char **) &expr, 0);
13284 for (p = op_tokens; ; p++) {
13288 /* strange operator not found */
13291 for (o = expr; *p && *o == *p; p++)
13298 /* skip tail uncompared token */
13301 /* skip zero delim */
13306 /* post grammar: a++ reduce to num */
13307 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13310 /* Plus and minus are binary (not unary) _only_ if the last
13311 * token was as number, or a right paren (which pretends to be
13312 * a number, since it evaluates to one). Think about it.
13313 * It makes sense. */
13314 if (lasttok != TOK_NUM) {
13330 /* We don't want a unary operator to cause recursive descent on the
13331 * stack, because there can be many in a row and it could cause an
13332 * operator to be evaluated before its argument is pushed onto the
13333 * integer stack. */
13334 /* But for binary operators, "apply" everything on the operator
13335 * stack until we find an operator with a lesser priority than the
13336 * one we have just extracted. */
13337 /* Left paren is given the lowest priority so it will never be
13338 * "applied" in this way.
13339 * if associativity is right and priority eq, applied also skip
13342 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13343 /* not left paren or unary */
13344 if (lasttok != TOK_NUM) {
13345 /* binary op must be preceded by a num */
13348 while (stackptr != stack) {
13349 if (op == TOK_RPAREN) {
13350 /* The algorithm employed here is simple: while we don't
13351 * hit an open paren nor the bottom of the stack, pop
13352 * tokens and apply them */
13353 if (stackptr[-1] == TOK_LPAREN) {
13355 /* Any operator directly after a */
13357 /* close paren should consider itself binary */
13361 operator prev_prec = PREC(stackptr[-1]);
13363 convert_prec_is_assing(prec);
13364 convert_prec_is_assing(prev_prec);
13365 if (prev_prec < prec)
13367 /* check right assoc */
13368 if (prev_prec == prec && is_right_associativity(prec))
13371 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13372 if (errcode) goto ret;
13374 if (op == TOK_RPAREN) {
13379 /* Push this operator to the stack and remember it. */
13380 *stackptr++ = lasttok = op;
13385 #endif /* ASH_MATH_SUPPORT */
13388 /* ============ main() and helpers */
13391 * Called to exit the shell.
13393 static void exitshell(void) NORETURN;
13401 status = exitstatus;
13402 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13403 if (setjmp(loc.loc)) {
13404 if (exception == EXEXIT)
13405 /* dash bug: it just does _exit(exitstatus) here
13406 * but we have to do setjobctl(0) first!
13407 * (bug is still not fixed in dash-0.5.3 - if you run dash
13408 * under Midnight Commander, on exit from dash MC is backgrounded) */
13409 status = exitstatus;
13412 exception_handler = &loc;
13418 flush_stdout_stderr();
13428 /* from input.c: */
13429 basepf.nextc = basepf.buf = basebuf;
13432 signal(SIGCHLD, SIG_DFL);
13437 char ppid[sizeof(int)*3 + 1];
13439 struct stat st1, st2;
13442 for (envp = environ; envp && *envp; envp++) {
13443 if (strchr(*envp, '=')) {
13444 setvareq(*envp, VEXPORT|VTEXTFIXED);
13448 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
13449 setvar("PPID", ppid, 0);
13451 p = lookupvar("PWD");
13453 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
13454 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
13461 * Process the shell command line arguments.
13464 procargs(char **argv)
13467 const char *xminusc;
13472 /* if (xargv[0]) - mmm, this is always true! */
13474 for (i = 0; i < NOPTS; i++)
13478 /* it already printed err message */
13479 raise_exception(EXERROR);
13483 if (*xargv == NULL) {
13485 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13488 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13492 for (i = 0; i < NOPTS; i++)
13493 if (optlist[i] == 2)
13498 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13503 } else if (!sflag) {
13504 setinputfile(*xargv, 0);
13507 commandname = arg0;
13510 shellparam.p = xargv;
13511 #if ENABLE_ASH_GETOPTS
13512 shellparam.optind = 1;
13513 shellparam.optoff = -1;
13515 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13517 shellparam.nparam++;
13524 * Read /etc/profile or .profile.
13527 read_profile(const char *name)
13531 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13540 * This routine is called when an error or an interrupt occurs in an
13541 * interactive shell and control is returned to the main command loop.
13549 /* from input.c: */
13550 parselleft = parsenleft = 0; /* clear input buffer */
13552 /* from parser.c: */
13555 /* from redir.c: */
13556 clearredir(/*drop:*/ 0);
13560 static short profile_buf[16384];
13561 extern int etext();
13565 * Main routine. We initialize things, parse the arguments, execute
13566 * profiles if we're a login shell, and then call cmdloop to execute
13567 * commands. The setjmp call sets up the location to jump to when an
13568 * exception occurs. When an exception occurs the variable "state"
13569 * is used to figure out how far we had gotten.
13571 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13572 int ash_main(int argc UNUSED_PARAM, char **argv)
13575 volatile int state;
13576 struct jmploc jmploc;
13577 struct stackmark smark;
13579 /* Initialize global data */
13583 #if ENABLE_ASH_ALIAS
13589 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13592 #if ENABLE_FEATURE_EDITING
13593 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13596 if (setjmp(jmploc.loc)) {
13606 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13610 outcslow('\n', stderr);
13612 popstackmark(&smark);
13613 FORCE_INT_ON; /* enable interrupts */
13622 exception_handler = &jmploc;
13625 trace_puts("Shell args: ");
13626 trace_puts_args(argv);
13628 rootpid = getpid();
13630 #if ENABLE_ASH_RANDOM_SUPPORT
13631 /* Can use monotonic_ns() for better randomness but for now it is
13632 * not used anywhere else in busybox... so avoid bloat */
13633 random_galois_LFSR = random_LCG = rootpid + monotonic_us();
13636 setstackmark(&smark);
13639 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13641 const char *hp = lookupvar("HISTFILE");
13644 hp = lookupvar("HOME");
13646 char *defhp = concat_path_file(hp, ".ash_history");
13647 setvar("HISTFILE", defhp, 0);
13653 if (argv[0] && argv[0][0] == '-')
13657 read_profile("/etc/profile");
13660 read_profile(".profile");
13666 getuid() == geteuid() && getgid() == getegid() &&
13670 shinit = lookupvar("ENV");
13671 if (shinit != NULL && *shinit != '\0') {
13672 read_profile(shinit);
13678 evalstring(minusc, 0);
13680 if (sflag || minusc == NULL) {
13681 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13683 const char *hp = lookupvar("HISTFILE");
13686 line_input_state->hist_file = hp;
13689 state4: /* XXX ??? - why isn't this before the "if" statement */
13697 extern void _mcleanup(void);
13706 const char *applet_name = "debug stuff usage";
13707 int main(int argc, char **argv)
13709 return ash_main(argc, argv);
13715 * Copyright (c) 1989, 1991, 1993, 1994
13716 * The Regents of the University of California. All rights reserved.
13718 * This code is derived from software contributed to Berkeley by
13719 * Kenneth Almquist.
13721 * Redistribution and use in source and binary forms, with or without
13722 * modification, are permitted provided that the following conditions
13724 * 1. Redistributions of source code must retain the above copyright
13725 * notice, this list of conditions and the following disclaimer.
13726 * 2. Redistributions in binary form must reproduce the above copyright
13727 * notice, this list of conditions and the following disclaimer in the
13728 * documentation and/or other materials provided with the distribution.
13729 * 3. Neither the name of the University nor the names of its contributors
13730 * may be used to endorse or promote products derived from this software
13731 * without specific prior written permission.
13733 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13734 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13735 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13736 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13737 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13738 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13739 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13740 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13741 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13742 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF