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 /* ============ ... */
2576 #define IBUFSIZ COMMON_BUFSIZE
2577 /* buffer for top level input file */
2578 #define basebuf bb_common_bufsiz1
2580 /* Syntax classes */
2581 #define CWORD 0 /* character is nothing special */
2582 #define CNL 1 /* newline character */
2583 #define CBACK 2 /* a backslash character */
2584 #define CSQUOTE 3 /* single quote */
2585 #define CDQUOTE 4 /* double quote */
2586 #define CENDQUOTE 5 /* a terminating quote */
2587 #define CBQUOTE 6 /* backwards single quote */
2588 #define CVAR 7 /* a dollar sign */
2589 #define CENDVAR 8 /* a '}' character */
2590 #define CLP 9 /* a left paren in arithmetic */
2591 #define CRP 10 /* a right paren in arithmetic */
2592 #define CENDFILE 11 /* end of file */
2593 #define CCTL 12 /* like CWORD, except it must be escaped */
2594 #define CSPCL 13 /* these terminate a word */
2595 #define CIGN 14 /* character should be ignored */
2597 #if ENABLE_ASH_ALIAS
2601 #define PEOA_OR_PEOF PEOA
2605 #define PEOA_OR_PEOF PEOF
2608 /* number syntax index */
2609 #define BASESYNTAX 0 /* not in quotes */
2610 #define DQSYNTAX 1 /* in double quotes */
2611 #define SQSYNTAX 2 /* in single quotes */
2612 #define ARISYNTAX 3 /* in arithmetic */
2613 #define PSSYNTAX 4 /* prompt */
2615 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
2616 #define USE_SIT_FUNCTION
2619 #if ENABLE_ASH_MATH_SUPPORT
2620 static const char S_I_T[][4] = {
2621 #if ENABLE_ASH_ALIAS
2622 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */
2624 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */
2625 { CNL, CNL, CNL, CNL }, /* 2, \n */
2626 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */
2627 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */
2628 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */
2629 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */
2630 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */
2631 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */
2632 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */
2633 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */
2634 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */
2635 #ifndef USE_SIT_FUNCTION
2636 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2637 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2638 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2642 static const char S_I_T[][3] = {
2643 #if ENABLE_ASH_ALIAS
2644 { CSPCL, CIGN, CIGN }, /* 0, PEOA */
2646 { CSPCL, CWORD, CWORD }, /* 1, ' ' */
2647 { CNL, CNL, CNL }, /* 2, \n */
2648 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */
2649 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */
2650 { CVAR, CVAR, CWORD }, /* 5, $ */
2651 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */
2652 { CSPCL, CWORD, CWORD }, /* 7, ( */
2653 { CSPCL, CWORD, CWORD }, /* 8, ) */
2654 { CBACK, CBACK, CCTL }, /* 9, \ */
2655 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */
2656 { CENDVAR, CENDVAR, CWORD }, /* 11, } */
2657 #ifndef USE_SIT_FUNCTION
2658 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2659 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2660 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2663 #endif /* ASH_MATH_SUPPORT */
2665 #ifdef USE_SIT_FUNCTION
2668 SIT(int c, int syntax)
2670 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2671 #if ENABLE_ASH_ALIAS
2672 static const char syntax_index_table[] ALIGN1 = {
2673 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2674 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2675 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2679 static const char syntax_index_table[] ALIGN1 = {
2680 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2681 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2682 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2689 if (c == PEOF) /* 2^8+2 */
2691 #if ENABLE_ASH_ALIAS
2692 if (c == PEOA) /* 2^8+1 */
2697 if ((unsigned char)c >= (unsigned char)(CTLESC)
2698 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
2702 s = strchrnul(spec_symbls, c);
2705 indx = syntax_index_table[s - spec_symbls];
2707 return S_I_T[indx][syntax];
2710 #else /* !USE_SIT_FUNCTION */
2712 #if ENABLE_ASH_ALIAS
2713 #define CSPCL_CIGN_CIGN_CIGN 0
2714 #define CSPCL_CWORD_CWORD_CWORD 1
2715 #define CNL_CNL_CNL_CNL 2
2716 #define CWORD_CCTL_CCTL_CWORD 3
2717 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
2718 #define CVAR_CVAR_CWORD_CVAR 5
2719 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
2720 #define CSPCL_CWORD_CWORD_CLP 7
2721 #define CSPCL_CWORD_CWORD_CRP 8
2722 #define CBACK_CBACK_CCTL_CBACK 9
2723 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
2724 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
2725 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
2726 #define CWORD_CWORD_CWORD_CWORD 13
2727 #define CCTL_CCTL_CCTL_CCTL 14
2729 #define CSPCL_CWORD_CWORD_CWORD 0
2730 #define CNL_CNL_CNL_CNL 1
2731 #define CWORD_CCTL_CCTL_CWORD 2
2732 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
2733 #define CVAR_CVAR_CWORD_CVAR 4
2734 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
2735 #define CSPCL_CWORD_CWORD_CLP 6
2736 #define CSPCL_CWORD_CWORD_CRP 7
2737 #define CBACK_CBACK_CCTL_CBACK 8
2738 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
2739 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
2740 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
2741 #define CWORD_CWORD_CWORD_CWORD 12
2742 #define CCTL_CCTL_CCTL_CCTL 13
2745 static const char syntax_index_table[258] = {
2746 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2747 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2748 #if ENABLE_ASH_ALIAS
2749 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
2751 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2752 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2753 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2754 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2755 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2756 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2757 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2758 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2759 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2760 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
2761 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
2762 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
2763 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
2764 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
2765 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
2766 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
2767 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
2768 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
2769 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
2770 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
2771 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
2772 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
2773 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
2774 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
2775 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
2776 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
2777 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
2778 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
2779 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
2780 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
2781 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
2782 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
2783 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
2784 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
2785 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
2786 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
2787 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
2788 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
2789 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
2790 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
2791 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
2792 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
2793 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
2794 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
2795 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
2796 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
2797 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
2798 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
2799 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
2800 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
2801 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
2802 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
2803 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
2804 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
2805 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
2806 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
2807 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
2808 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
2809 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
2810 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
2811 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
2812 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
2813 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
2814 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
2815 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
2816 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
2817 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
2818 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
2819 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
2820 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
2821 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
2822 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
2823 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
2824 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
2825 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
2826 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
2827 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
2828 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
2829 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
2830 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
2831 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
2832 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
2833 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
2834 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
2835 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
2836 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
2837 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
2838 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
2839 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
2840 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
2841 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
2842 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
2843 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
2844 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
2845 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
2846 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
2847 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
2848 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
2853 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
2854 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2889 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
2890 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
2898 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
2899 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
2900 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
2901 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
2902 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
2903 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
2904 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
2905 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
2906 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
2907 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
2908 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
2909 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
2910 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
2911 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2912 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2913 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2914 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2916 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2918 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2919 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2920 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2921 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2922 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
2924 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2925 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
2926 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2927 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2938 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2939 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2940 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2941 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2942 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2943 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2971 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2972 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2973 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2976 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3003 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3004 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3005 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3006 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
3009 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])
3011 #endif /* USE_SIT_FUNCTION */
3014 /* ============ Alias handling */
3016 #if ENABLE_ASH_ALIAS
3018 #define ALIASINUSE 1
3029 static struct alias **atab; // [ATABSIZE];
3030 #define INIT_G_alias() do { \
3031 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3035 static struct alias **
3036 __lookupalias(const char *name) {
3037 unsigned int hashval;
3044 ch = (unsigned char)*p;
3048 ch = (unsigned char)*++p;
3050 app = &atab[hashval % ATABSIZE];
3052 for (; *app; app = &(*app)->next) {
3053 if (strcmp(name, (*app)->name) == 0) {
3061 static struct alias *
3062 lookupalias(const char *name, int check)
3064 struct alias *ap = *__lookupalias(name);
3066 if (check && ap && (ap->flag & ALIASINUSE))
3071 static struct alias *
3072 freealias(struct alias *ap)
3076 if (ap->flag & ALIASINUSE) {
3077 ap->flag |= ALIASDEAD;
3089 setalias(const char *name, const char *val)
3091 struct alias *ap, **app;
3093 app = __lookupalias(name);
3097 if (!(ap->flag & ALIASINUSE)) {
3100 ap->val = ckstrdup(val);
3101 ap->flag &= ~ALIASDEAD;
3104 ap = ckzalloc(sizeof(struct alias));
3105 ap->name = ckstrdup(name);
3106 ap->val = ckstrdup(val);
3107 /*ap->flag = 0; - ckzalloc did it */
3108 /*ap->next = NULL;*/
3115 unalias(const char *name)
3119 app = __lookupalias(name);
3123 *app = freealias(*app);
3134 struct alias *ap, **app;
3138 for (i = 0; i < ATABSIZE; i++) {
3140 for (ap = *app; ap; ap = *app) {
3141 *app = freealias(*app);
3151 printalias(const struct alias *ap)
3153 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3157 * TODO - sort output
3160 aliascmd(int argc UNUSED_PARAM, char **argv)
3169 for (i = 0; i < ATABSIZE; i++) {
3170 for (ap = atab[i]; ap; ap = ap->next) {
3176 while ((n = *++argv) != NULL) {
3177 v = strchr(n+1, '=');
3178 if (v == NULL) { /* n+1: funny ksh stuff */
3179 ap = *__lookupalias(n);
3181 fprintf(stderr, "%s: %s not found\n", "alias", n);
3195 unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3199 while ((i = nextopt("a")) != '\0') {
3205 for (i = 0; *argptr; argptr++) {
3206 if (unalias(*argptr)) {
3207 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3215 #endif /* ASH_ALIAS */
3218 /* ============ jobs.c */
3220 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3223 #define FORK_NOJOB 2
3225 /* mode flags for showjob(s) */
3226 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
3227 #define SHOW_PID 0x04 /* include process pid */
3228 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
3231 * A job structure contains information about a job. A job is either a
3232 * single process or a set of processes contained in a pipeline. In the
3233 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3238 pid_t pid; /* process id */
3239 int status; /* last process status from wait() */
3240 char *cmd; /* text of command being run */
3244 struct procstat ps0; /* status of process */
3245 struct procstat *ps; /* status or processes when more than one */
3247 int stopstatus; /* status of a stopped job */
3250 nprocs: 16, /* number of processes */
3252 #define JOBRUNNING 0 /* at least one proc running */
3253 #define JOBSTOPPED 1 /* all procs are stopped */
3254 #define JOBDONE 2 /* all procs are completed */
3256 sigint: 1, /* job was killed by SIGINT */
3257 jobctl: 1, /* job running under job control */
3259 waited: 1, /* true if this entry has been waited for */
3260 used: 1, /* true if this entry is in used */
3261 changed: 1; /* true if status has changed */
3262 struct job *prev_job; /* previous job */
3265 static struct job *makejob(/*union node *,*/ int);
3267 #define forkshell(job, node, mode) forkshell(job, mode)
3269 static int forkshell(struct job *, union node *, int);
3270 static int waitforjob(struct job *);
3273 enum { doing_jobctl = 0 };
3274 #define setjobctl(on) do {} while (0)
3276 static smallint doing_jobctl; //references:8
3277 static void setjobctl(int);
3281 * Set the signal handler for the specified signal. The routine figures
3282 * out what it should be set to.
3285 setsignal(int signo)
3289 struct sigaction act;
3295 else if (*t != '\0')
3297 if (rootshell && action == S_DFL) {
3300 if (iflag || minusc || sflag == 0)
3323 t = &sigmode[signo - 1];
3327 * current setting unknown
3329 if (sigaction(signo, NULL, &act) == -1) {
3331 * Pretend it worked; maybe we should give a warning
3332 * here, but other shells don't. We don't alter
3333 * sigmode, so that we retry every time.
3337 tsig = S_RESET; /* force to be set */
3338 if (act.sa_handler == SIG_IGN) {
3341 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3343 tsig = S_IGN; /* don't hard ignore these */
3347 if (tsig == S_HARD_IGN || tsig == action)
3349 act.sa_handler = SIG_DFL;
3352 act.sa_handler = onsig;
3355 act.sa_handler = SIG_IGN;
3360 sigfillset(&act.sa_mask);
3361 sigaction_set(signo, &act);
3364 /* mode flags for set_curjob */
3365 #define CUR_DELETE 2
3366 #define CUR_RUNNING 1
3367 #define CUR_STOPPED 0
3369 /* mode flags for dowait */
3370 #define DOWAIT_NONBLOCK WNOHANG
3371 #define DOWAIT_BLOCK 0
3374 /* pgrp of shell on invocation */
3375 static int initialpgrp; //references:2
3376 static int ttyfd = -1; //5
3379 static struct job *jobtab; //5
3381 static unsigned njobs; //4
3383 static struct job *curjob; //lots
3384 /* number of presumed living untracked jobs */
3385 static int jobless; //4
3388 set_curjob(struct job *jp, unsigned mode)
3391 struct job **jpp, **curp;
3393 /* first remove from list */
3394 jpp = curp = &curjob;
3399 jpp = &jp1->prev_job;
3401 *jpp = jp1->prev_job;
3403 /* Then re-insert in correct position */
3411 /* job being deleted */
3414 /* newly created job or backgrounded job,
3415 put after all stopped jobs. */
3419 if (!jp1 || jp1->state != JOBSTOPPED)
3422 jpp = &jp1->prev_job;
3428 /* newly stopped job - becomes curjob */
3429 jp->prev_job = *jpp;
3437 jobno(const struct job *jp)
3439 return jp - jobtab + 1;
3444 * Convert a job name to a job structure.
3447 #define getjob(name, getctl) getjob(name)
3450 getjob(const char *name, int getctl)
3454 const char *err_msg = "No such job: %s";
3458 char *(*match)(const char *, const char *);
3473 if (c == '+' || c == '%') {
3475 err_msg = "No current job";
3481 err_msg = "No previous job";
3490 // TODO: number() instead? It does error checking...
3493 jp = jobtab + num - 1;
3510 if (match(jp->ps[0].cmd, p)) {
3514 err_msg = "%s: ambiguous";
3521 err_msg = "job %s not created under job control";
3522 if (getctl && jp->jobctl == 0)
3527 ash_msg_and_raise_error(err_msg, name);
3531 * Mark a job structure as unused.
3534 freejob(struct job *jp)
3536 struct procstat *ps;
3540 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3541 if (ps->cmd != nullstr)
3544 if (jp->ps != &jp->ps0)
3547 set_curjob(jp, CUR_DELETE);
3553 xtcsetpgrp(int fd, pid_t pgrp)
3555 if (tcsetpgrp(fd, pgrp))
3556 ash_msg_and_raise_error("can't set tty process group (%m)");
3560 * Turn job control on and off.
3562 * Note: This code assumes that the third arg to ioctl is a character
3563 * pointer, which is true on Berkeley systems but not System V. Since
3564 * System V doesn't have job control yet, this isn't a problem now.
3566 * Called with interrupts off.
3574 if (on == doing_jobctl || rootshell == 0)
3578 ofd = fd = open(_PATH_TTY, O_RDWR);
3580 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3581 * That sometimes helps to acquire controlling tty.
3582 * Obviously, a workaround for bugs when someone
3583 * failed to provide a controlling tty to bash! :) */
3589 fd = fcntl(fd, F_DUPFD, 10);
3594 /* fd is a tty at this point */
3595 close_on_exec_on(fd);
3596 do { /* while we are in the background */
3597 pgrp = tcgetpgrp(fd);
3600 ash_msg("can't access tty; job control turned off");
3604 if (pgrp == getpgrp())
3615 xtcsetpgrp(fd, pgrp);
3617 /* turning job control off */
3620 /* was xtcsetpgrp, but this can make exiting ash
3621 * loop forever if pty is already deleted */
3622 tcsetpgrp(fd, pgrp);
3637 killcmd(int argc, char **argv)
3640 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3642 if (argv[i][0] == '%') {
3643 struct job *jp = getjob(argv[i], 0);
3644 unsigned pid = jp->ps[0].pid;
3645 /* Enough space for ' -NNN<nul>' */
3646 argv[i] = alloca(sizeof(int)*3 + 3);
3647 /* kill_main has matching code to expect
3648 * leading space. Needed to not confuse
3649 * negative pids with "kill -SIGNAL_NO" syntax */
3650 sprintf(argv[i], " -%u", pid);
3652 } while (argv[++i]);
3654 return kill_main(argc, argv);
3658 showpipe(struct job *jp, FILE *out)
3660 struct procstat *sp;
3661 struct procstat *spend;
3663 spend = jp->ps + jp->nprocs;
3664 for (sp = jp->ps + 1; sp < spend; sp++)
3665 fprintf(out, " | %s", sp->cmd);
3666 outcslow('\n', out);
3667 flush_stdout_stderr();
3672 restartjob(struct job *jp, int mode)
3674 struct procstat *ps;
3680 if (jp->state == JOBDONE)
3682 jp->state = JOBRUNNING;
3684 if (mode == FORK_FG)
3685 xtcsetpgrp(ttyfd, pgid);
3686 killpg(pgid, SIGCONT);
3690 if (WIFSTOPPED(ps->status)) {
3696 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3702 fg_bgcmd(int argc UNUSED_PARAM, char **argv)
3709 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3714 jp = getjob(*argv, 1);
3715 if (mode == FORK_BG) {
3716 set_curjob(jp, CUR_RUNNING);
3717 fprintf(out, "[%d] ", jobno(jp));
3719 outstr(jp->ps->cmd, out);
3721 retval = restartjob(jp, mode);
3722 } while (*argv && *++argv);
3728 sprint_status(char *s, int status, int sigonly)
3734 if (!WIFEXITED(status)) {
3736 if (WIFSTOPPED(status))
3737 st = WSTOPSIG(status);
3740 st = WTERMSIG(status);
3742 if (st == SIGINT || st == SIGPIPE)
3745 if (WIFSTOPPED(status))
3750 col = fmtstr(s, 32, strsignal(st));
3751 if (WCOREDUMP(status)) {
3752 col += fmtstr(s + col, 16, " (core dumped)");
3754 } else if (!sigonly) {
3755 st = WEXITSTATUS(status);
3757 col = fmtstr(s, 16, "Done(%d)", st);
3759 col = fmtstr(s, 16, "Done");
3766 dowait(int wait_flags, struct job *job)
3771 struct job *thisjob;
3774 TRACE(("dowait(0x%x) called\n", wait_flags));
3776 /* Do a wait system call. If job control is compiled in, we accept
3777 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3778 * NB: _not_ safe_waitpid, we need to detect EINTR */
3779 pid = waitpid(-1, &status,
3780 (doing_jobctl ? (wait_flags | WUNTRACED) : wait_flags));
3781 TRACE(("wait returns pid=%d, status=0x%x\n", pid, status));
3784 /* If we were doing blocking wait and (probably) got EINTR,
3785 * check for pending sigs received while waiting.
3786 * (NB: can be moved into callers if needed) */
3787 if (wait_flags == DOWAIT_BLOCK && pendingsig)
3788 raise_exception(EXSIG);
3793 for (jp = curjob; jp; jp = jp->prev_job) {
3794 struct procstat *sp;
3795 struct procstat *spend;
3796 if (jp->state == JOBDONE)
3799 spend = jp->ps + jp->nprocs;
3802 if (sp->pid == pid) {
3803 TRACE(("Job %d: changing status of proc %d "
3804 "from 0x%x to 0x%x\n",
3805 jobno(jp), pid, sp->status, status));
3806 sp->status = status;
3809 if (sp->status == -1)
3812 if (state == JOBRUNNING)
3814 if (WIFSTOPPED(sp->status)) {
3815 jp->stopstatus = sp->status;
3819 } while (++sp < spend);
3824 if (!WIFSTOPPED(status))
3830 if (state != JOBRUNNING) {
3831 thisjob->changed = 1;
3833 if (thisjob->state != state) {
3834 TRACE(("Job %d: changing state from %d to %d\n",
3835 jobno(thisjob), thisjob->state, state));
3836 thisjob->state = state;
3838 if (state == JOBSTOPPED) {
3839 set_curjob(thisjob, CUR_STOPPED);
3848 if (thisjob && thisjob == job) {
3852 len = sprint_status(s, status, 1);
3864 showjob(FILE *out, struct job *jp, int mode)
3866 struct procstat *ps;
3867 struct procstat *psend;
3874 if (mode & SHOW_PGID) {
3875 /* just output process (group) id of pipeline */
3876 fprintf(out, "%d\n", ps->pid);
3880 col = fmtstr(s, 16, "[%d] ", jobno(jp));
3885 else if (curjob && jp == curjob->prev_job)
3888 if (mode & SHOW_PID)
3889 col += fmtstr(s + col, 16, "%d ", ps->pid);
3891 psend = ps + jp->nprocs;
3893 if (jp->state == JOBRUNNING) {
3894 strcpy(s + col, "Running");
3895 col += sizeof("Running") - 1;
3897 int status = psend[-1].status;
3898 if (jp->state == JOBSTOPPED)
3899 status = jp->stopstatus;
3900 col += sprint_status(s + col, status, 0);
3906 /* for each process */
3907 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
3909 fprintf(out, "%s%*c%s",
3910 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
3912 if (!(mode & SHOW_PID)) {
3916 if (++ps == psend) {
3917 outcslow('\n', out);
3924 if (jp->state == JOBDONE) {
3925 TRACE(("showjob: freeing job %d\n", jobno(jp)));
3931 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3932 * statuses have changed since the last call to showjobs.
3935 showjobs(FILE *out, int mode)
3939 TRACE(("showjobs(%x) called\n", mode));
3941 /* If not even one job changed, there is nothing to do */
3942 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3945 for (jp = curjob; jp; jp = jp->prev_job) {
3946 if (!(mode & SHOW_CHANGED) || jp->changed) {
3947 showjob(out, jp, mode);
3953 jobscmd(int argc UNUSED_PARAM, char **argv)
3958 while ((m = nextopt("lp"))) {
3968 showjob(stdout, getjob(*argv,0), mode);
3971 showjobs(stdout, mode);
3978 getstatus(struct job *job)
3983 status = job->ps[job->nprocs - 1].status;
3984 retval = WEXITSTATUS(status);
3985 if (!WIFEXITED(status)) {
3987 retval = WSTOPSIG(status);
3988 if (!WIFSTOPPED(status))
3991 /* XXX: limits number of signals */
3992 retval = WTERMSIG(status);
3994 if (retval == SIGINT)
4000 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
4001 jobno(job), job->nprocs, status, retval));
4006 waitcmd(int argc UNUSED_PARAM, char **argv)
4015 raise_exception(EXSIG);
4022 /* wait for all jobs */
4026 if (!jp) /* no running procs */
4028 if (jp->state == JOBRUNNING)
4033 dowait(DOWAIT_BLOCK, NULL);
4039 if (**argv != '%') {
4040 pid_t pid = number(*argv);
4045 if (job->ps[job->nprocs - 1].pid == pid)
4047 job = job->prev_job;
4050 job = getjob(*argv, 0);
4051 /* loop until process terminated or stopped */
4052 while (job->state == JOBRUNNING)
4053 dowait(DOWAIT_BLOCK, NULL);
4055 retval = getstatus(job);
4069 struct job *jp, *jq;
4071 len = njobs * sizeof(*jp);
4073 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4075 offset = (char *)jp - (char *)jq;
4077 /* Relocate pointers */
4080 jq = (struct job *)((char *)jq + l);
4084 #define joff(p) ((struct job *)((char *)(p) + l))
4085 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4086 if (joff(jp)->ps == &jq->ps0)
4087 jmove(joff(jp)->ps);
4088 if (joff(jp)->prev_job)
4089 jmove(joff(jp)->prev_job);
4099 jp = (struct job *)((char *)jp + len);
4103 } while (--jq >= jp);
4108 * Return a new job structure.
4109 * Called with interrupts off.
4112 makejob(/*union node *node,*/ int nprocs)
4117 for (i = njobs, jp = jobtab; ; jp++) {
4124 if (jp->state != JOBDONE || !jp->waited)
4133 memset(jp, 0, sizeof(*jp));
4135 /* jp->jobctl is a bitfield.
4136 * "jp->jobctl |= jobctl" likely to give awful code */
4140 jp->prev_job = curjob;
4145 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4147 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4154 * Return a string identifying a command (to be printed by the
4157 static char *cmdnextc;
4160 cmdputs(const char *s)
4162 static const char vstype[VSTYPE + 1][3] = {
4163 "", "}", "-", "+", "?", "=",
4164 "%", "%%", "#", "##"
4165 USE_ASH_BASH_COMPAT(, ":", "/", "//")
4168 const char *p, *str;
4169 char c, cc[2] = " ";
4174 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4176 while ((c = *p++) != 0) {
4184 if ((subtype & VSTYPE) == VSLENGTH)
4188 if (!(subtype & VSQUOTE) == !(quoted & 1))
4194 str = "\"}" + !(quoted & 1);
4201 case CTLBACKQ+CTLQUOTE:
4204 #if ENABLE_ASH_MATH_SUPPORT
4219 if ((subtype & VSTYPE) != VSNORMAL)
4221 str = vstype[subtype & VSTYPE];
4222 if (subtype & VSNUL)
4231 /* These can only happen inside quotes */
4244 while ((c = *str++)) {
4249 USTPUTC('"', nextc);
4255 /* cmdtxt() and cmdlist() call each other */
4256 static void cmdtxt(union node *n);
4259 cmdlist(union node *np, int sep)
4261 for (; np; np = np->narg.next) {
4265 if (sep && np->narg.next)
4271 cmdtxt(union node *n)
4274 struct nodelist *lp;
4285 lp = n->npipe.cmdlist;
4303 cmdtxt(n->nbinary.ch1);
4319 cmdtxt(n->nif.test);
4322 if (n->nif.elsepart) {
4325 n = n->nif.elsepart;
4341 cmdtxt(n->nbinary.ch1);
4351 cmdputs(n->nfor.var);
4353 cmdlist(n->nfor.args, 1);
4358 cmdputs(n->narg.text);
4362 cmdlist(n->ncmd.args, 1);
4363 cmdlist(n->ncmd.redirect, 0);
4376 cmdputs(n->ncase.expr->narg.text);
4378 for (np = n->ncase.cases; np; np = np->nclist.next) {
4379 cmdtxt(np->nclist.pattern);
4381 cmdtxt(np->nclist.body);
4395 #if ENABLE_ASH_BASH_COMPAT
4410 cmdputs(utoa(n->nfile.fd));
4412 if (n->type == NTOFD || n->type == NFROMFD) {
4413 cmdputs(utoa(n->ndup.dupfd));
4422 commandtext(union node *n)
4426 STARTSTACKSTR(cmdnextc);
4428 name = stackblock();
4429 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4430 name, cmdnextc, cmdnextc));
4431 return ckstrdup(name);
4436 * Fork off a subshell. If we are doing job control, give the subshell its
4437 * own process group. Jp is a job structure that the job is to be added to.
4438 * N is the command that will be evaluated by the child. Both jp and n may
4439 * be NULL. The mode parameter can be one of the following:
4440 * FORK_FG - Fork off a foreground process.
4441 * FORK_BG - Fork off a background process.
4442 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4443 * process group even if job control is on.
4445 * When job control is turned off, background processes have their standard
4446 * input redirected to /dev/null (except for the second and later processes
4449 * Called with interrupts off.
4452 * Clear traps on a fork.
4459 for (tp = trap; tp < &trap[NSIG]; tp++) {
4460 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4465 setsignal(tp - trap);
4471 /* Lives far away from here, needed for forkchild */
4472 static void closescript(void);
4474 /* Called after fork(), in child */
4476 forkchild(struct job *jp, /*union node *n,*/ int mode)
4480 TRACE(("Child shell %d\n", getpid()));
4487 /* do job control only in root shell */
4489 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4492 if (jp->nprocs == 0)
4495 pgrp = jp->ps[0].pid;
4496 /* This can fail because we are doing it in the parent also */
4497 (void)setpgid(0, pgrp);
4498 if (mode == FORK_FG)
4499 xtcsetpgrp(ttyfd, pgrp);
4504 if (mode == FORK_BG) {
4507 if (jp->nprocs == 0) {
4509 if (open(bb_dev_null, O_RDONLY) != 0)
4510 ash_msg_and_raise_error("can't open %s", bb_dev_null);
4513 if (!oldlvl && iflag) {
4518 for (jp = curjob; jp; jp = jp->prev_job)
4523 /* Called after fork(), in parent */
4525 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4528 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4530 TRACE(("In parent shell: child = %d\n", pid));
4532 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4538 if (mode != FORK_NOJOB && jp->jobctl) {
4541 if (jp->nprocs == 0)
4544 pgrp = jp->ps[0].pid;
4545 /* This can fail because we are doing it in the child also */
4549 if (mode == FORK_BG) {
4550 backgndpid = pid; /* set $! */
4551 set_curjob(jp, CUR_RUNNING);
4554 struct procstat *ps = &jp->ps[jp->nprocs++];
4559 if (doing_jobctl && n)
4560 ps->cmd = commandtext(n);
4566 forkshell(struct job *jp, union node *n, int mode)
4570 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4573 TRACE(("Fork failed, errno=%d", errno));
4576 ash_msg_and_raise_error("can't fork");
4579 forkchild(jp, /*n,*/ mode);
4581 forkparent(jp, n, mode, pid);
4586 * Wait for job to finish.
4588 * Under job control we have the problem that while a child process is
4589 * running interrupts generated by the user are sent to the child but not
4590 * to the shell. This means that an infinite loop started by an inter-
4591 * active user may be hard to kill. With job control turned off, an
4592 * interactive user may place an interactive program inside a loop. If
4593 * the interactive program catches interrupts, the user doesn't want
4594 * these interrupts to also abort the loop. The approach we take here
4595 * is to have the shell ignore interrupt signals while waiting for a
4596 * foreground process to terminate, and then send itself an interrupt
4597 * signal if the child process was terminated by an interrupt signal.
4598 * Unfortunately, some programs want to do a bit of cleanup and then
4599 * exit on interrupt; unless these processes terminate themselves by
4600 * sending a signal to themselves (instead of calling exit) they will
4601 * confuse this approach.
4603 * Called with interrupts off.
4606 waitforjob(struct job *jp)
4610 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4611 while (jp->state == JOBRUNNING) {
4612 dowait(DOWAIT_BLOCK, jp);
4617 xtcsetpgrp(ttyfd, rootpid);
4619 * This is truly gross.
4620 * If we're doing job control, then we did a TIOCSPGRP which
4621 * caused us (the shell) to no longer be in the controlling
4622 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4623 * intuit from the subprocess exit status whether a SIGINT
4624 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4626 if (jp->sigint) /* TODO: do the same with all signals */
4627 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4629 if (jp->state == JOBDONE)
4636 * return 1 if there are stopped jobs, otherwise 0
4648 if (jp && jp->state == JOBSTOPPED) {
4649 out2str("You have stopped jobs.\n");
4658 /* ============ redir.c
4660 * Code for dealing with input/output redirection.
4663 #define EMPTY -2 /* marks an unused slot in redirtab */
4664 #define CLOSED -3 /* marks a slot of previously-closed fd */
4667 * Open a file in noclobber mode.
4668 * The code was copied from bash.
4671 noclobberopen(const char *fname)
4674 struct stat finfo, finfo2;
4677 * If the file exists and is a regular file, return an error
4680 r = stat(fname, &finfo);
4681 if (r == 0 && S_ISREG(finfo.st_mode)) {
4687 * If the file was not present (r != 0), make sure we open it
4688 * exclusively so that if it is created before we open it, our open
4689 * will fail. Make sure that we do not truncate an existing file.
4690 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4691 * file was not a regular file, we leave O_EXCL off.
4694 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4695 fd = open(fname, O_WRONLY|O_CREAT, 0666);
4697 /* If the open failed, return the file descriptor right away. */
4702 * OK, the open succeeded, but the file may have been changed from a
4703 * non-regular file to a regular file between the stat and the open.
4704 * We are assuming that the O_EXCL open handles the case where FILENAME
4705 * did not exist and is symlinked to an existing file between the stat
4710 * If we can open it and fstat the file descriptor, and neither check
4711 * revealed that it was a regular file, and the file has not been
4712 * replaced, return the file descriptor.
4714 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4715 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4718 /* The file has been replaced. badness. */
4725 * Handle here documents. Normally we fork off a process to write the
4726 * data to a pipe. If the document is short, we can stuff the data in
4727 * the pipe without forking.
4729 /* openhere needs this forward reference */
4730 static void expandhere(union node *arg, int fd);
4732 openhere(union node *redir)
4738 ash_msg_and_raise_error("pipe call failed");
4739 if (redir->type == NHERE) {
4740 len = strlen(redir->nhere.doc->narg.text);
4741 if (len <= PIPE_BUF) {
4742 full_write(pip[1], redir->nhere.doc->narg.text, len);
4746 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4749 signal(SIGINT, SIG_IGN);
4750 signal(SIGQUIT, SIG_IGN);
4751 signal(SIGHUP, SIG_IGN);
4753 signal(SIGTSTP, SIG_IGN);
4755 signal(SIGPIPE, SIG_DFL);
4756 if (redir->type == NHERE)
4757 full_write(pip[1], redir->nhere.doc->narg.text, len);
4759 expandhere(redir->nhere.doc, pip[1]);
4760 _exit(EXIT_SUCCESS);
4768 openredirect(union node *redir)
4773 switch (redir->nfile.type) {
4775 fname = redir->nfile.expfname;
4776 f = open(fname, O_RDONLY);
4781 fname = redir->nfile.expfname;
4782 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
4787 #if ENABLE_ASH_BASH_COMPAT
4790 /* Take care of noclobber mode. */
4792 fname = redir->nfile.expfname;
4793 f = noclobberopen(fname);
4800 fname = redir->nfile.expfname;
4801 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4806 fname = redir->nfile.expfname;
4807 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4815 /* Fall through to eliminate warning. */
4816 /* Our single caller does this itself */
4823 f = openhere(redir);
4829 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4831 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
4835 * Copy a file descriptor to be >= to. Returns -1
4836 * if the source file descriptor is closed, EMPTY if there are no unused
4837 * file descriptors left.
4839 /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
4840 * old code was doing close(to) prior to copyfd() to achieve the same */
4842 COPYFD_EXACT = (int)~(INT_MAX),
4843 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
4846 copyfd(int from, int to)
4850 if (to & COPYFD_EXACT) {
4851 to &= ~COPYFD_EXACT;
4853 newfd = dup2(from, to);
4855 newfd = fcntl(from, F_DUPFD, to);
4858 if (errno == EMFILE)
4860 /* Happens when source fd is not open: try "echo >&99" */
4861 ash_msg_and_raise_error("%d: %m", from);
4866 /* Struct def and variable are moved down to the first usage site */
4871 struct redirtab *next;
4874 struct two_fd_t two_fd[0];
4876 #define redirlist (G_var.redirlist)
4878 static int need_to_remember(struct redirtab *rp, int fd)
4882 if (!rp) /* remembering was not requested */
4885 for (i = 0; i < rp->pair_count; i++) {
4886 if (rp->two_fd[i].orig == fd) {
4887 /* already remembered */
4894 /* "hidden" fd is a fd used to read scripts, or a copy of such */
4895 static int is_hidden_fd(struct redirtab *rp, int fd)
4898 struct parsefile *pf;
4911 fd |= COPYFD_RESTORE;
4912 for (i = 0; i < rp->pair_count; i++) {
4913 if (rp->two_fd[i].copy == fd) {
4921 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
4922 * old file descriptors are stashed away so that the redirection can be
4923 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
4924 * standard output, and the standard error if it becomes a duplicate of
4925 * stdout, is saved in memory.
4927 /* flags passed to redirect */
4928 #define REDIR_PUSH 01 /* save previous values of file descriptors */
4929 #define REDIR_SAVEFD2 03 /* set preverrout */
4931 redirect(union node *redir, int flags)
4933 struct redirtab *sv;
4938 int copied_fd2 = -1;
4948 if (flags & REDIR_PUSH) {
4949 union node *tmp = redir;
4952 #if ENABLE_ASH_BASH_COMPAT
4953 if (redir->nfile.type == NTO2)
4956 tmp = tmp->nfile.next;
4958 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
4959 sv->next = redirlist;
4960 sv->pair_count = sv_pos;
4962 sv->nullredirs = g_nullredirs - 1;
4964 while (sv_pos > 0) {
4966 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
4971 fd = redir->nfile.fd;
4972 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
4973 int right_fd = redir->ndup.dupfd;
4974 /* redirect from/to same file descriptor? */
4977 /* echo >&10 and 10 is a fd opened to the sh script? */
4978 if (is_hidden_fd(sv, right_fd)) {
4979 errno = EBADF; /* as if it is closed */
4980 ash_msg_and_raise_error("%d: %m", right_fd);
4984 newfd = openredirect(redir); /* always >= 0 */
4986 /* Descriptor wasn't open before redirect.
4987 * Mark it for close in the future */
4988 if (need_to_remember(sv, fd)) {
4989 goto remember_to_close;
4994 #if ENABLE_ASH_BASH_COMPAT
4997 if (need_to_remember(sv, fd)) {
4998 /* Copy old descriptor */
4999 i = fcntl(fd, F_DUPFD, 10);
5000 /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5001 * are closed in popredir() in the child, preventing them from leaking
5002 * into child. (popredir() also cleans up the mess in case of failures)
5007 /* Strange error (e.g. "too many files" EMFILE?) */
5011 ash_msg_and_raise_error("%d: %m", fd);
5014 /* EBADF: it is not open - good, remember to close it */
5017 } else { /* fd is open, save its copy */
5018 /* "exec fd>&-" should not close fds
5019 * which point to script file(s).
5020 * Force them to be restored afterwards */
5021 if (is_hidden_fd(sv, fd))
5022 i |= COPYFD_RESTORE;
5026 sv->two_fd[sv_pos].orig = fd;
5027 sv->two_fd[sv_pos].copy = i;
5031 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5032 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5035 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
5037 } else if (fd != newfd) { /* move newfd to fd */
5038 copyfd(newfd, fd | COPYFD_EXACT);
5039 #if ENABLE_ASH_BASH_COMPAT
5040 if (!(redir->nfile.type == NTO2 && fd == 2))
5044 #if ENABLE_ASH_BASH_COMPAT
5045 if (redir->nfile.type == NTO2 && fd == 1) {
5046 /* We already redirected it to fd 1, now copy it to 2 */
5052 } while ((redir = redir->nfile.next) != NULL);
5055 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5056 preverrout_fd = copied_fd2;
5060 * Undo the effects of the last redirection.
5063 popredir(int drop, int restore)
5065 struct redirtab *rp;
5068 if (--g_nullredirs >= 0)
5072 for (i = 0; i < rp->pair_count; i++) {
5073 int fd = rp->two_fd[i].orig;
5074 int copy = rp->two_fd[i].copy;
5075 if (copy == CLOSED) {
5080 if (copy != EMPTY) {
5081 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5082 copy &= ~COPYFD_RESTORE;
5084 copyfd(copy, fd | COPYFD_EXACT);
5089 redirlist = rp->next;
5090 g_nullredirs = rp->nullredirs;
5096 * Undo all redirections. Called on error or interrupt.
5100 * Discard all saved file descriptors.
5103 clearredir(int drop)
5109 popredir(drop, /*restore:*/ 0);
5114 redirectsafe(union node *redir, int flags)
5117 volatile int saveint;
5118 struct jmploc *volatile savehandler = exception_handler;
5119 struct jmploc jmploc;
5122 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5123 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5125 exception_handler = &jmploc;
5126 redirect(redir, flags);
5128 exception_handler = savehandler;
5129 if (err && exception != EXERROR)
5130 longjmp(exception_handler->loc, 1);
5131 RESTORE_INT(saveint);
5136 /* ============ Routines to expand arguments to commands
5138 * We have to deal with backquotes, shell variables, and file metacharacters.
5141 #if ENABLE_ASH_MATH_SUPPORT_64
5142 typedef int64_t arith_t;
5143 #define arith_t_type long long
5145 typedef long arith_t;
5146 #define arith_t_type long
5149 #if ENABLE_ASH_MATH_SUPPORT
5150 static arith_t dash_arith(const char *);
5151 static arith_t arith(const char *expr, int *perrcode);
5157 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5158 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5159 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5160 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5161 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5162 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5163 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5164 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5165 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5169 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5170 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5171 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5172 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5173 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5176 * Structure specifying which parts of the string should be searched
5177 * for IFS characters.
5180 struct ifsregion *next; /* next region in list */
5181 int begoff; /* offset of start of region */
5182 int endoff; /* offset of end of region */
5183 int nulonly; /* search for nul bytes only */
5187 struct strlist *list;
5188 struct strlist **lastp;
5191 /* output of current string */
5192 static char *expdest;
5193 /* list of back quote expressions */
5194 static struct nodelist *argbackq;
5195 /* first struct in list of ifs regions */
5196 static struct ifsregion ifsfirst;
5197 /* last struct in list */
5198 static struct ifsregion *ifslastp;
5199 /* holds expanded arg list */
5200 static struct arglist exparg;
5210 expdest = makestrspace(32, expdest);
5211 #if ENABLE_ASH_MATH_SUPPORT_64
5212 len = fmtstr(expdest, 32, "%lld", (long long) num);
5214 len = fmtstr(expdest, 32, "%ld", num);
5216 STADJUST(len, expdest);
5221 esclen(const char *start, const char *p)
5225 while (p > start && *--p == CTLESC) {
5232 * Remove any CTLESC characters from a string.
5235 _rmescapes(char *str, int flag)
5237 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5244 p = strpbrk(str, qchars);
5250 if (flag & RMESCAPE_ALLOC) {
5251 size_t len = p - str;
5252 size_t fulllen = len + strlen(p) + 1;
5254 if (flag & RMESCAPE_GROW) {
5255 r = makestrspace(fulllen, expdest);
5256 } else if (flag & RMESCAPE_HEAP) {
5257 r = ckmalloc(fulllen);
5259 r = stalloc(fulllen);
5263 q = (char *)memcpy(q, str, len) + len;
5266 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5267 globbing = flag & RMESCAPE_GLOB;
5268 notescaped = globbing;
5270 if (*p == CTLQUOTEMARK) {
5271 inquotes = ~inquotes;
5273 notescaped = globbing;
5277 /* naked back slash */
5283 if (notescaped && inquotes && *p != '/') {
5287 notescaped = globbing;
5292 if (flag & RMESCAPE_GROW) {
5294 STADJUST(q - r + 1, expdest);
5298 #define rmescapes(p) _rmescapes((p), 0)
5300 #define pmatch(a, b) !fnmatch((a), (b), 0)
5303 * Prepare a pattern for a expmeta (internal glob(3)) call.
5305 * Returns an stalloced string.
5308 preglob(const char *pattern, int quoted, int flag)
5310 flag |= RMESCAPE_GLOB;
5312 flag |= RMESCAPE_QUOTED;
5314 return _rmescapes((char *)pattern, flag);
5318 * Put a string on the stack.
5321 memtodest(const char *p, size_t len, int syntax, int quotes)
5325 q = makestrspace(len * 2, q);
5328 int c = signed_char2int(*p++);
5331 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5340 strtodest(const char *p, int syntax, int quotes)
5342 memtodest(p, strlen(p), syntax, quotes);
5346 * Record the fact that we have to scan this region of the
5347 * string for IFS characters.
5350 recordregion(int start, int end, int nulonly)
5352 struct ifsregion *ifsp;
5354 if (ifslastp == NULL) {
5358 ifsp = ckzalloc(sizeof(*ifsp));
5359 /*ifsp->next = NULL; - ckzalloc did it */
5360 ifslastp->next = ifsp;
5364 ifslastp->begoff = start;
5365 ifslastp->endoff = end;
5366 ifslastp->nulonly = nulonly;
5370 removerecordregions(int endoff)
5372 if (ifslastp == NULL)
5375 if (ifsfirst.endoff > endoff) {
5376 while (ifsfirst.next != NULL) {
5377 struct ifsregion *ifsp;
5379 ifsp = ifsfirst.next->next;
5380 free(ifsfirst.next);
5381 ifsfirst.next = ifsp;
5384 if (ifsfirst.begoff > endoff)
5387 ifslastp = &ifsfirst;
5388 ifsfirst.endoff = endoff;
5393 ifslastp = &ifsfirst;
5394 while (ifslastp->next && ifslastp->next->begoff < endoff)
5395 ifslastp=ifslastp->next;
5396 while (ifslastp->next != NULL) {
5397 struct ifsregion *ifsp;
5399 ifsp = ifslastp->next->next;
5400 free(ifslastp->next);
5401 ifslastp->next = ifsp;
5404 if (ifslastp->endoff > endoff)
5405 ifslastp->endoff = endoff;
5409 exptilde(char *startp, char *p, int flag)
5415 int quotes = flag & (EXP_FULL | EXP_CASE);
5420 while ((c = *++p) != '\0') {
5427 if (flag & EXP_VARTILDE)
5437 if (*name == '\0') {
5438 home = lookupvar(homestr);
5440 pw = getpwnam(name);
5445 if (!home || !*home)
5448 startloc = expdest - (char *)stackblock();
5449 strtodest(home, SQSYNTAX, quotes);
5450 recordregion(startloc, expdest - (char *)stackblock(), 0);
5458 * Execute a command inside back quotes. If it's a builtin command, we
5459 * want to save its output in a block obtained from malloc. Otherwise
5460 * we fork off a subprocess and get the output of the command via a pipe.
5461 * Should be called with interrupts off.
5463 struct backcmd { /* result of evalbackcmd */
5464 int fd; /* file descriptor to read from */
5465 int nleft; /* number of chars in buffer */
5466 char *buf; /* buffer */
5467 struct job *jp; /* job structure for command */
5470 /* These forward decls are needed to use "eval" code for backticks handling: */
5471 static uint8_t back_exitstatus; /* exit status of backquoted command */
5472 #define EV_EXIT 01 /* exit after evaluating tree */
5473 static void evaltree(union node *, int);
5476 evalbackcmd(union node *n, struct backcmd *result)
5488 saveherefd = herefd;
5496 ash_msg_and_raise_error("pipe call failed");
5497 jp = makejob(/*n,*/ 1);
5498 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5503 copyfd(pip[1], 1 | COPYFD_EXACT);
5507 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5511 result->fd = pip[0];
5514 herefd = saveherefd;
5516 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5517 result->fd, result->buf, result->nleft, result->jp));
5521 * Expand stuff in backwards quotes.
5524 expbackq(union node *cmd, int quoted, int quotes)
5532 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
5533 struct stackmark smark;
5536 setstackmark(&smark);
5538 startloc = dest - (char *)stackblock();
5540 evalbackcmd(cmd, &in);
5541 popstackmark(&smark);
5548 memtodest(p, i, syntax, quotes);
5552 i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5553 TRACE(("expbackq: read returns %d\n", i));
5562 back_exitstatus = waitforjob(in.jp);
5566 /* Eat all trailing newlines */
5568 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5573 recordregion(startloc, dest - (char *)stackblock(), 0);
5574 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5575 (dest - (char *)stackblock()) - startloc,
5576 (dest - (char *)stackblock()) - startloc,
5577 stackblock() + startloc));
5580 #if ENABLE_ASH_MATH_SUPPORT
5582 * Expand arithmetic expression. Backup to start of expression,
5583 * evaluate, place result in (backed up) result, adjust string position.
5596 * This routine is slightly over-complicated for
5597 * efficiency. Next we scan backwards looking for the
5598 * start of arithmetic.
5600 start = stackblock();
5607 while (*p != CTLARI) {
5611 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5616 esc = esclen(start, p);
5626 removerecordregions(begoff);
5635 len = cvtnum(dash_arith(p + 2));
5638 recordregion(begoff, begoff + len, 0);
5642 /* argstr needs it */
5643 static char *evalvar(char *p, int flag, struct strlist *var_str_list);
5646 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5647 * characters to allow for further processing. Otherwise treat
5648 * $@ like $* since no splitting will be performed.
5650 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5651 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5652 * for correct expansion of "B=$A" word.
5655 argstr(char *p, int flag, struct strlist *var_str_list)
5657 static const char spclchars[] ALIGN1 = {
5665 CTLBACKQ | CTLQUOTE,
5666 #if ENABLE_ASH_MATH_SUPPORT
5671 const char *reject = spclchars;
5673 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
5674 int breakall = flag & EXP_WORD;
5679 if (!(flag & EXP_VARTILDE)) {
5681 } else if (flag & EXP_VARTILDE2) {
5686 if (flag & EXP_TILDE) {
5692 if (*q == CTLESC && (flag & EXP_QWORD))
5695 p = exptilde(p, q, flag);
5698 startloc = expdest - (char *)stackblock();
5700 length += strcspn(p + length, reject);
5702 if (c && (!(c & 0x80)
5703 #if ENABLE_ASH_MATH_SUPPORT
5707 /* c == '=' || c == ':' || c == CTLENDARI */
5712 expdest = stack_nputstr(p, length, expdest);
5713 newloc = expdest - (char *)stackblock();
5714 if (breakall && !inquotes && newloc > startloc) {
5715 recordregion(startloc, newloc, 0);
5726 if (flag & EXP_VARTILDE2) {
5730 flag |= EXP_VARTILDE2;
5735 * sort of a hack - expand tildes in variable
5736 * assignments (after the first '=' and after ':'s).
5745 case CTLENDVAR: /* ??? */
5748 /* "$@" syntax adherence hack */
5751 !memcmp(p, dolatstr, 4) &&
5752 (p[4] == CTLQUOTEMARK || (
5753 p[4] == CTLENDVAR &&
5754 p[5] == CTLQUOTEMARK
5757 p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;
5760 inquotes = !inquotes;
5773 p = evalvar(p, flag, var_str_list);
5777 case CTLBACKQ|CTLQUOTE:
5778 expbackq(argbackq->n, c, quotes);
5779 argbackq = argbackq->next;
5781 #if ENABLE_ASH_MATH_SUPPORT
5794 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int quotes,
5797 // This commented out code was added by James Simmons <jsimmons@infradead.org>
5798 // as part of a larger change when he added support for ${var/a/b}.
5799 // However, it broke # and % operators:
5803 //echo ${var#ab} abcdcd abcdcd
5804 //echo ${var##ab} abcdcd abcdcd
5805 //echo ${var#a*b} abcdcd ababcdcd (!)
5806 //echo ${var##a*b} cdcd cdcd
5807 //echo ${var#?} babcdcd ababcdcd (!)
5808 //echo ${var##?} babcdcd babcdcd
5809 //echo ${var#*} ababcdcd babcdcd (!)
5811 //echo ${var%cd} ababcd ababcd
5812 //echo ${var%%cd} ababcd abab (!)
5813 //echo ${var%c*d} ababcd ababcd
5814 //echo ${var%%c*d} abab ababcdcd (!)
5815 //echo ${var%?} ababcdc ababcdc
5816 //echo ${var%%?} ababcdc ababcdcd (!)
5817 //echo ${var%*} ababcdcd ababcdcd
5820 // Commenting it back out helped. Remove it completely if it really
5823 char *loc, *loc2; //, *full;
5829 int match; // = strlen(str);
5830 const char *s = loc2;
5837 match = pmatch(str, s); // this line was deleted
5839 // // chop off end if its '*'
5840 // full = strrchr(str, '*');
5841 // if (full && full != str)
5844 // // If str starts with '*' replace with s.
5845 // if ((*str == '*') && strlen(s) >= match) {
5846 // full = xstrdup(s);
5847 // strncpy(full+strlen(s)-match+1, str+1, match-1);
5849 // full = xstrndup(str, match);
5850 // match = strncmp(s, full, strlen(full));
5854 if (match) // if (!match)
5856 if (quotes && *loc == CTLESC)
5865 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5872 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5875 const char *s = loc2;
5880 match = pmatch(str, s);
5887 esc = esclen(startp, loc);
5898 static void varunset(const char *, const char *, const char *, int) NORETURN;
5900 varunset(const char *end, const char *var, const char *umsg, int varflags)
5906 msg = "parameter not set";
5908 if (*end == CTLENDVAR) {
5909 if (varflags & VSNUL)
5914 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5917 #if ENABLE_ASH_BASH_COMPAT
5919 parse_sub_pattern(char *arg, int inquotes)
5921 char *idx, *repl = NULL;
5930 /* Only the first '/' seen is our separator */
5937 if (!inquotes && c == '\\' && arg[1] == '\\')
5938 arg++; /* skip both \\, not just first one */
5945 #endif /* ENABLE_ASH_BASH_COMPAT */
5948 subevalvar(char *p, char *str, int strloc, int subtype,
5949 int startloc, int varflags, int quotes, struct strlist *var_str_list)
5951 struct nodelist *saveargbackq = argbackq;
5954 char *rmesc, *rmescend;
5955 USE_ASH_BASH_COMPAT(char *repl = NULL;)
5956 USE_ASH_BASH_COMPAT(char null = '\0';)
5957 USE_ASH_BASH_COMPAT(int pos, len, orig_len;)
5958 int saveherefd = herefd;
5959 int amount, workloc, resetloc;
5961 char *(*scan)(char*, char*, char*, char*, int, int);
5964 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
5966 STPUTC('\0', expdest);
5967 herefd = saveherefd;
5968 argbackq = saveargbackq;
5969 startp = (char *)stackblock() + startloc;
5973 setvar(str, startp, 0);
5974 amount = startp - expdest;
5975 STADJUST(amount, expdest);
5978 #if ENABLE_ASH_BASH_COMPAT
5980 loc = str = stackblock() + strloc;
5981 // TODO: number() instead? It does error checking...
5983 len = str - startp - 1;
5985 /* *loc != '\0', guaranteed by parser */
5989 /* We must adjust the length by the number of escapes we find. */
5990 for (ptr = startp; ptr < (str - 1); ptr++) {
5991 if (*ptr == CTLESC) {
5999 if (*loc++ == ':') {
6000 // TODO: number() instead? It does error checking...
6004 while (*loc && *loc != ':')
6007 // TODO: number() instead? It does error checking...
6010 if (pos >= orig_len) {
6014 if (len > (orig_len - pos))
6015 len = orig_len - pos;
6017 for (str = startp; pos; str++, pos--) {
6018 if (quotes && *str == CTLESC)
6021 for (loc = startp; len; len--) {
6022 if (quotes && *str == CTLESC)
6027 amount = loc - expdest;
6028 STADJUST(amount, expdest);
6033 varunset(p, str, startp, varflags);
6036 resetloc = expdest - (char *)stackblock();
6038 /* We'll comeback here if we grow the stack while handling
6039 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6040 * stack will need rebasing, and we'll need to remove our work
6043 USE_ASH_BASH_COMPAT(restart:)
6045 amount = expdest - ((char *)stackblock() + resetloc);
6046 STADJUST(-amount, expdest);
6047 startp = (char *)stackblock() + startloc;
6050 rmescend = (char *)stackblock() + strloc;
6052 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6053 if (rmesc != startp) {
6055 startp = (char *)stackblock() + startloc;
6059 str = (char *)stackblock() + strloc;
6060 preglob(str, varflags & VSQUOTE, 0);
6061 workloc = expdest - (char *)stackblock();
6063 #if ENABLE_ASH_BASH_COMPAT
6064 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6065 char *idx, *end, *restart_detect;
6068 repl = parse_sub_pattern(str, varflags & VSQUOTE);
6073 /* If there's no pattern to match, return the expansion unmolested */
6081 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6083 /* No match, advance */
6084 restart_detect = stackblock();
6085 STPUTC(*idx, expdest);
6086 if (quotes && *idx == CTLESC) {
6089 STPUTC(*idx, expdest);
6091 if (stackblock() != restart_detect)
6099 if (subtype == VSREPLACEALL) {
6101 if (quotes && *idx == CTLESC)
6109 for (loc = repl; *loc; loc++) {
6110 restart_detect = stackblock();
6111 STPUTC(*loc, expdest);
6112 if (stackblock() != restart_detect)
6117 if (subtype == VSREPLACE) {
6119 restart_detect = stackblock();
6120 STPUTC(*idx, expdest);
6121 if (stackblock() != restart_detect)
6130 /* We've put the replaced text into a buffer at workloc, now
6131 * move it to the right place and adjust the stack.
6133 startp = stackblock() + startloc;
6134 STPUTC('\0', expdest);
6135 memmove(startp, stackblock() + workloc, len);
6136 startp[len++] = '\0';
6137 amount = expdest - ((char *)stackblock() + startloc + len - 1);
6138 STADJUST(-amount, expdest);
6141 #endif /* ENABLE_ASH_BASH_COMPAT */
6143 subtype -= VSTRIMRIGHT;
6145 if (subtype < 0 || subtype > 7)
6148 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
6149 zero = subtype >> 1;
6150 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6151 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6153 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6156 memmove(startp, loc, str - loc);
6157 loc = startp + (str - loc) - 1;
6160 amount = loc - expdest;
6161 STADJUST(amount, expdest);
6167 * Add the value of a specialized variable to the stack string.
6170 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6180 int quoted = varflags & VSQUOTE;
6181 int subtype = varflags & VSTYPE;
6182 int quotes = flags & (EXP_FULL | EXP_CASE);
6184 if (quoted && (flags & EXP_FULL))
6185 sep = 1 << CHAR_BIT;
6187 syntax = quoted ? DQSYNTAX : BASESYNTAX;
6196 num = shellparam.nparam;
6206 p = makestrspace(NOPTS, expdest);
6207 for (i = NOPTS - 1; i >= 0; i--) {
6209 USTPUTC(optletters(i), p);
6220 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
6221 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
6227 while ((p = *ap++)) {
6230 partlen = strlen(p);
6233 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6234 memtodest(p, partlen, syntax, quotes);
6240 if (subtype == VSPLUS || subtype == VSLENGTH) {
6261 // TODO: number() instead? It does error checking...
6263 if (num < 0 || num > shellparam.nparam)
6265 p = num ? shellparam.p[num - 1] : arg0;
6268 /* NB: name has form "VAR=..." */
6270 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6271 * which should be considered before we check variables. */
6273 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6277 str = var_str_list->text;
6278 eq = strchr(str, '=');
6279 if (!eq) /* stop at first non-assignment */
6282 if (name_len == (unsigned)(eq - str)
6283 && strncmp(str, name, name_len) == 0) {
6285 /* goto value; - WRONG! */
6286 /* think "A=1 A=2 B=$A" */
6288 var_str_list = var_str_list->next;
6289 } while (var_str_list);
6293 p = lookupvar(name);
6299 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6300 memtodest(p, len, syntax, quotes);
6304 if (subtype == VSPLUS || subtype == VSLENGTH)
6305 STADJUST(-len, expdest);
6310 * Expand a variable, and return a pointer to the next character in the
6314 evalvar(char *p, int flag, struct strlist *var_str_list)
6326 subtype = varflags & VSTYPE;
6327 quoted = varflags & VSQUOTE;
6329 easy = (!quoted || (*var == '@' && shellparam.nparam));
6330 startloc = expdest - (char *)stackblock();
6331 p = strchr(p, '=') + 1;
6334 varlen = varvalue(var, varflags, flag, var_str_list);
6335 if (varflags & VSNUL)
6338 if (subtype == VSPLUS) {
6339 varlen = -1 - varlen;
6343 if (subtype == VSMINUS) {
6347 p, flag | EXP_TILDE |
6348 (quoted ? EXP_QWORD : EXP_WORD),
6358 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6360 if (subevalvar(p, var, /* strloc: */ 0,
6361 subtype, startloc, varflags,
6367 * Remove any recorded regions beyond
6370 removerecordregions(startloc);
6380 if (varlen < 0 && uflag)
6381 varunset(p, var, 0, 0);
6383 if (subtype == VSLENGTH) {
6384 cvtnum(varlen > 0 ? varlen : 0);
6388 if (subtype == VSNORMAL) {
6399 case VSTRIMRIGHTMAX:
6400 #if ENABLE_ASH_BASH_COMPAT
6413 * Terminate the string and start recording the pattern
6416 STPUTC('\0', expdest);
6417 patloc = expdest - (char *)stackblock();
6418 if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6420 /* quotes: */ flag & (EXP_FULL | EXP_CASE),
6423 int amount = expdest - (
6424 (char *)stackblock() + patloc - 1
6426 STADJUST(-amount, expdest);
6428 /* Remove any recorded regions beyond start of variable */
6429 removerecordregions(startloc);
6431 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6435 if (subtype != VSNORMAL) { /* skip to end of alternative */
6441 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6443 argbackq = argbackq->next;
6444 } else if (c == CTLVAR) {
6445 if ((*p++ & VSTYPE) != VSNORMAL)
6447 } else if (c == CTLENDVAR) {
6457 * Break the argument string into pieces based upon IFS and add the
6458 * strings to the argument list. The regions of the string to be
6459 * searched for IFS characters have been stored by recordregion.
6462 ifsbreakup(char *string, struct arglist *arglist)
6464 struct ifsregion *ifsp;
6469 const char *ifs, *realifs;
6474 if (ifslastp != NULL) {
6477 realifs = ifsset() ? ifsval() : defifs;
6480 p = string + ifsp->begoff;
6481 nulonly = ifsp->nulonly;
6482 ifs = nulonly ? nullstr : realifs;
6484 while (p < string + ifsp->endoff) {
6488 if (!strchr(ifs, *p)) {
6493 ifsspc = (strchr(defifs, *p) != NULL);
6494 /* Ignore IFS whitespace at start */
6495 if (q == start && ifsspc) {
6501 sp = stzalloc(sizeof(*sp));
6503 *arglist->lastp = sp;
6504 arglist->lastp = &sp->next;
6508 if (p >= string + ifsp->endoff) {
6514 if (strchr(ifs, *p) == NULL) {
6518 if (strchr(defifs, *p) == NULL) {
6533 } while (ifsp != NULL);
6542 sp = stzalloc(sizeof(*sp));
6544 *arglist->lastp = sp;
6545 arglist->lastp = &sp->next;
6551 struct ifsregion *p;
6556 struct ifsregion *ifsp;
6562 ifsfirst.next = NULL;
6567 * Add a file name to the list.
6570 addfname(const char *name)
6574 sp = stzalloc(sizeof(*sp));
6575 sp->text = ststrdup(name);
6577 exparg.lastp = &sp->next;
6580 static char *expdir;
6583 * Do metacharacter (i.e. *, ?, [...]) expansion.
6586 expmeta(char *enddir, char *name)
6601 for (p = name; *p; p++) {
6602 if (*p == '*' || *p == '?')
6604 else if (*p == '[') {
6611 if (*q == '/' || *q == '\0')
6618 } else if (*p == '\\')
6620 else if (*p == '/') {
6627 if (metaflag == 0) { /* we've reached the end of the file name */
6628 if (enddir != expdir)
6636 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6647 } while (p < start);
6649 if (enddir == expdir) {
6651 } else if (enddir == expdir + 1 && *expdir == '/') {
6660 if (enddir != expdir)
6662 if (*endname == 0) {
6674 while (!intpending && (dp = readdir(dirp)) != NULL) {
6675 if (dp->d_name[0] == '.' && !matchdot)
6677 if (pmatch(start, dp->d_name)) {
6679 strcpy(enddir, dp->d_name);
6682 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6685 expmeta(p, endname);
6694 static struct strlist *
6695 msort(struct strlist *list, int len)
6697 struct strlist *p, *q = NULL;
6698 struct strlist **lpp;
6706 for (n = half; --n >= 0;) {
6710 q->next = NULL; /* terminate first half of list */
6711 q = msort(list, half); /* sort first half of list */
6712 p = msort(p, len - half); /* sort second half */
6715 #if ENABLE_LOCALE_SUPPORT
6716 if (strcoll(p->text, q->text) < 0)
6718 if (strcmp(p->text, q->text) < 0)
6742 * Sort the results of file name expansion. It calculates the number of
6743 * strings to sort and then calls msort (short for merge sort) to do the
6746 static struct strlist *
6747 expsort(struct strlist *str)
6753 for (sp = str; sp; sp = sp->next)
6755 return msort(str, len);
6759 expandmeta(struct strlist *str /*, int flag*/)
6761 static const char metachars[] ALIGN1 = {
6764 /* TODO - EXP_REDIR */
6767 struct strlist **savelastp;
6773 if (!strpbrk(str->text, metachars))
6775 savelastp = exparg.lastp;
6778 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
6780 int i = strlen(str->text);
6781 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
6789 if (exparg.lastp == savelastp) {
6794 *exparg.lastp = str;
6795 rmescapes(str->text);
6796 exparg.lastp = &str->next;
6798 *exparg.lastp = NULL;
6799 *savelastp = sp = expsort(*savelastp);
6800 while (sp->next != NULL)
6802 exparg.lastp = &sp->next;
6809 * Perform variable substitution and command substitution on an argument,
6810 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6811 * perform splitting and file name expansion. When arglist is NULL, perform
6812 * here document expansion.
6815 expandarg(union node *arg, struct arglist *arglist, int flag)
6820 argbackq = arg->narg.backquote;
6821 STARTSTACKSTR(expdest);
6822 ifsfirst.next = NULL;
6824 argstr(arg->narg.text, flag,
6825 /* var_str_list: */ arglist ? arglist->list : NULL);
6826 p = _STPUTC('\0', expdest);
6828 if (arglist == NULL) {
6829 return; /* here document expanded */
6831 p = grabstackstr(p);
6832 exparg.lastp = &exparg.list;
6836 if (flag & EXP_FULL) {
6837 ifsbreakup(p, &exparg);
6838 *exparg.lastp = NULL;
6839 exparg.lastp = &exparg.list;
6840 expandmeta(exparg.list /*, flag*/);
6842 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
6844 sp = stzalloc(sizeof(*sp));
6847 exparg.lastp = &sp->next;
6851 *exparg.lastp = NULL;
6853 *arglist->lastp = exparg.list;
6854 arglist->lastp = exparg.lastp;
6859 * Expand shell variables and backquotes inside a here document.
6862 expandhere(union node *arg, int fd)
6865 expandarg(arg, (struct arglist *)NULL, 0);
6866 full_write(fd, stackblock(), expdest - (char *)stackblock());
6870 * Returns true if the pattern matches the string.
6873 patmatch(char *pattern, const char *string)
6875 return pmatch(preglob(pattern, 0, 0), string);
6879 * See if a pattern matches in a case statement.
6882 casematch(union node *pattern, char *val)
6884 struct stackmark smark;
6887 setstackmark(&smark);
6888 argbackq = pattern->narg.backquote;
6889 STARTSTACKSTR(expdest);
6891 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
6892 /* var_str_list: */ NULL);
6893 STACKSTRNUL(expdest);
6894 result = patmatch(stackblock(), val);
6895 popstackmark(&smark);
6900 /* ============ find_command */
6904 int (*builtin)(int, char **);
6905 /* unsigned flags; */
6907 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
6908 /* "regular" builtins always take precedence over commands,
6909 * regardless of PATH=....%builtin... position */
6910 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
6911 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
6914 smallint cmdtype; /* CMDxxx */
6917 /* index >= 0 for commands without path (slashes) */
6918 /* (TODO: what exactly does the value mean? PATH position?) */
6919 /* index == -1 for commands with slashes */
6920 /* index == (-2 - applet_no) for NOFORK applets */
6921 const struct builtincmd *cmd;
6922 struct funcnode *func;
6925 /* values of cmdtype */
6926 #define CMDUNKNOWN -1 /* no entry in table for command */
6927 #define CMDNORMAL 0 /* command is an executable program */
6928 #define CMDFUNCTION 1 /* command is a shell function */
6929 #define CMDBUILTIN 2 /* command is a shell builtin */
6931 /* action to find_command() */
6932 #define DO_ERR 0x01 /* prints errors */
6933 #define DO_ABS 0x02 /* checks absolute paths */
6934 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
6935 #define DO_ALTPATH 0x08 /* using alternate path */
6936 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
6938 static void find_command(char *, struct cmdentry *, int, const char *);
6941 /* ============ Hashing commands */
6944 * When commands are first encountered, they are entered in a hash table.
6945 * This ensures that a full path search will not have to be done for them
6946 * on each invocation.
6948 * We should investigate converting to a linear search, even though that
6949 * would make the command name "hash" a misnomer.
6953 struct tblentry *next; /* next entry in hash chain */
6954 union param param; /* definition of builtin function */
6955 smallint cmdtype; /* CMDxxx */
6956 char rehash; /* if set, cd done since entry created */
6957 char cmdname[1]; /* name of command */
6960 static struct tblentry **cmdtable;
6961 #define INIT_G_cmdtable() do { \
6962 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
6965 static int builtinloc = -1; /* index in path of %builtin, or -1 */
6969 tryexec(USE_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
6973 #if ENABLE_FEATURE_SH_STANDALONE
6974 if (applet_no >= 0) {
6975 if (APPLET_IS_NOEXEC(applet_no)) {
6978 run_applet_no_and_exit(applet_no, argv);
6980 /* re-exec ourselves with the new arguments */
6981 execve(bb_busybox_exec_path, argv, envp);
6982 /* If they called chroot or otherwise made the binary no longer
6983 * executable, fall through */
6990 execve(cmd, argv, envp);
6991 } while (errno == EINTR);
6993 execve(cmd, argv, envp);
6999 if (errno == ENOEXEC) {
7003 for (ap = argv; *ap; ap++)
7005 ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0]));
7007 ap[0] = cmd = (char *)DEFAULT_SHELL;
7010 while ((*ap++ = *argv++) != NULL)
7019 * Exec a program. Never returns. If you change this routine, you may
7020 * have to change the find_command routine as well.
7022 static void shellexec(char **, const char *, int) NORETURN;
7024 shellexec(char **argv, const char *path, int idx)
7030 #if ENABLE_FEATURE_SH_STANDALONE
7034 clearredir(/*drop:*/ 1);
7035 envp = listvars(VEXPORT, VUNSET, 0);
7036 if (strchr(argv[0], '/') != NULL
7037 #if ENABLE_FEATURE_SH_STANDALONE
7038 || (applet_no = find_applet_by_name(argv[0])) >= 0
7041 tryexec(USE_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7045 while ((cmdname = padvance(&path, argv[0])) != NULL) {
7046 if (--idx < 0 && pathopt == NULL) {
7047 tryexec(USE_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7048 if (errno != ENOENT && errno != ENOTDIR)
7055 /* Map to POSIX errors */
7067 exitstatus = exerrno;
7068 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
7069 argv[0], e, suppressint));
7070 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7075 printentry(struct tblentry *cmdp)
7081 idx = cmdp->param.index;
7084 name = padvance(&path, cmdp->cmdname);
7086 } while (--idx >= 0);
7087 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7091 * Clear out command entries. The argument specifies the first entry in
7092 * PATH which has changed.
7095 clearcmdentry(int firstchange)
7097 struct tblentry **tblp;
7098 struct tblentry **pp;
7099 struct tblentry *cmdp;
7102 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7104 while ((cmdp = *pp) != NULL) {
7105 if ((cmdp->cmdtype == CMDNORMAL &&
7106 cmdp->param.index >= firstchange)
7107 || (cmdp->cmdtype == CMDBUILTIN &&
7108 builtinloc >= firstchange)
7121 * Locate a command in the command hash table. If "add" is nonzero,
7122 * add the command to the table if it is not already present. The
7123 * variable "lastcmdentry" is set to point to the address of the link
7124 * pointing to the entry, so that delete_cmd_entry can delete the
7127 * Interrupts must be off if called with add != 0.
7129 static struct tblentry **lastcmdentry;
7131 static struct tblentry *
7132 cmdlookup(const char *name, int add)
7134 unsigned int hashval;
7136 struct tblentry *cmdp;
7137 struct tblentry **pp;
7140 hashval = (unsigned char)*p << 4;
7142 hashval += (unsigned char)*p++;
7144 pp = &cmdtable[hashval % CMDTABLESIZE];
7145 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7146 if (strcmp(cmdp->cmdname, name) == 0)
7150 if (add && cmdp == NULL) {
7151 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7153 /* + 1 - already done because
7154 * tblentry::cmdname is char[1] */);
7155 /*cmdp->next = NULL; - ckzalloc did it */
7156 cmdp->cmdtype = CMDUNKNOWN;
7157 strcpy(cmdp->cmdname, name);
7164 * Delete the command entry returned on the last lookup.
7167 delete_cmd_entry(void)
7169 struct tblentry *cmdp;
7172 cmdp = *lastcmdentry;
7173 *lastcmdentry = cmdp->next;
7174 if (cmdp->cmdtype == CMDFUNCTION)
7175 freefunc(cmdp->param.func);
7181 * Add a new command entry, replacing any existing command entry for
7182 * the same name - except special builtins.
7185 addcmdentry(char *name, struct cmdentry *entry)
7187 struct tblentry *cmdp;
7189 cmdp = cmdlookup(name, 1);
7190 if (cmdp->cmdtype == CMDFUNCTION) {
7191 freefunc(cmdp->param.func);
7193 cmdp->cmdtype = entry->cmdtype;
7194 cmdp->param = entry->u;
7199 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7201 struct tblentry **pp;
7202 struct tblentry *cmdp;
7204 struct cmdentry entry;
7207 if (nextopt("r") != '\0') {
7212 if (*argptr == NULL) {
7213 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7214 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7215 if (cmdp->cmdtype == CMDNORMAL)
7223 while ((name = *argptr) != NULL) {
7224 cmdp = cmdlookup(name, 0);
7226 && (cmdp->cmdtype == CMDNORMAL
7227 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7231 find_command(name, &entry, DO_ERR, pathval());
7232 if (entry.cmdtype == CMDUNKNOWN)
7240 * Called when a cd is done. Marks all commands so the next time they
7241 * are executed they will be rehashed.
7246 struct tblentry **pp;
7247 struct tblentry *cmdp;
7249 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7250 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7251 if (cmdp->cmdtype == CMDNORMAL
7252 || (cmdp->cmdtype == CMDBUILTIN
7253 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7263 * Fix command hash table when PATH changed.
7264 * Called before PATH is changed. The argument is the new value of PATH;
7265 * pathval() still returns the old value at this point.
7266 * Called with interrupts off.
7269 changepath(const char *new)
7277 firstchange = 9999; /* assume no change */
7283 if ((*old == '\0' && *new == ':')
7284 || (*old == ':' && *new == '\0'))
7286 old = new; /* ignore subsequent differences */
7290 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7296 if (builtinloc < 0 && idx_bltin >= 0)
7297 builtinloc = idx_bltin; /* zap builtins */
7298 if (builtinloc >= 0 && idx_bltin < 0)
7300 clearcmdentry(firstchange);
7301 builtinloc = idx_bltin;
7316 #define TENDBQUOTE 12
7333 typedef smallint token_id_t;
7335 /* first char is indicating which tokens mark the end of a list */
7336 static const char *const tokname_array[] = {
7350 #define KWDOFFSET 13
7351 /* the following are keywords */
7373 static char buf[16];
7376 //if (tok < TSEMI) return tokname_array[tok] + 1;
7377 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
7382 sprintf(buf + (tok >= TSEMI), "%s%c",
7383 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
7387 /* Wrapper around strcmp for qsort/bsearch/... */
7389 pstrcmp(const void *a, const void *b)
7391 return strcmp((char*) a, (*(char**) b) + 1);
7394 static const char *const *
7395 findkwd(const char *s)
7397 return bsearch(s, tokname_array + KWDOFFSET,
7398 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7399 sizeof(tokname_array[0]), pstrcmp);
7403 * Locate and print what a word is...
7406 describe_command(char *command, int describe_command_verbose)
7408 struct cmdentry entry;
7409 struct tblentry *cmdp;
7410 #if ENABLE_ASH_ALIAS
7411 const struct alias *ap;
7413 const char *path = pathval();
7415 if (describe_command_verbose) {
7419 /* First look at the keywords */
7420 if (findkwd(command)) {
7421 out1str(describe_command_verbose ? " is a shell keyword" : command);
7425 #if ENABLE_ASH_ALIAS
7426 /* Then look at the aliases */
7427 ap = lookupalias(command, 0);
7429 if (!describe_command_verbose) {
7434 out1fmt(" is an alias for %s", ap->val);
7438 /* Then check if it is a tracked alias */
7439 cmdp = cmdlookup(command, 0);
7441 entry.cmdtype = cmdp->cmdtype;
7442 entry.u = cmdp->param;
7444 /* Finally use brute force */
7445 find_command(command, &entry, DO_ABS, path);
7448 switch (entry.cmdtype) {
7450 int j = entry.u.index;
7456 p = padvance(&path, command);
7460 if (describe_command_verbose) {
7462 (cmdp ? " a tracked alias for" : nullstr), p
7471 if (describe_command_verbose) {
7472 out1str(" is a shell function");
7479 if (describe_command_verbose) {
7480 out1fmt(" is a %sshell builtin",
7481 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7482 "special " : nullstr
7490 if (describe_command_verbose) {
7491 out1str(": not found\n");
7496 outstr("\n", stdout);
7501 typecmd(int argc UNUSED_PARAM, char **argv)
7507 /* type -p ... ? (we don't bother checking for 'p') */
7508 if (argv[1] && argv[1][0] == '-') {
7513 err |= describe_command(argv[i++], verbose);
7518 #if ENABLE_ASH_CMDCMD
7520 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7528 while ((c = nextopt("pvV")) != '\0')
7530 verify |= VERIFY_VERBOSE;
7532 verify |= VERIFY_BRIEF;
7537 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7538 if (verify && (*argptr != NULL)) {
7539 return describe_command(*argptr, verify - VERIFY_BRIEF);
7547 /* ============ eval.c */
7549 static int funcblocksize; /* size of structures in function */
7550 static int funcstringsize; /* size of strings in node */
7551 static void *funcblock; /* block to allocate function from */
7552 static char *funcstring; /* block to allocate strings from */
7554 /* flags in argument to evaltree */
7555 #define EV_EXIT 01 /* exit after evaluating tree */
7556 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7557 #define EV_BACKCMD 04 /* command executing within back quotes */
7559 static const short nodesize[26] = {
7560 SHELL_ALIGN(sizeof(struct ncmd)),
7561 SHELL_ALIGN(sizeof(struct npipe)),
7562 SHELL_ALIGN(sizeof(struct nredir)),
7563 SHELL_ALIGN(sizeof(struct nredir)),
7564 SHELL_ALIGN(sizeof(struct nredir)),
7565 SHELL_ALIGN(sizeof(struct nbinary)),
7566 SHELL_ALIGN(sizeof(struct nbinary)),
7567 SHELL_ALIGN(sizeof(struct nbinary)),
7568 SHELL_ALIGN(sizeof(struct nif)),
7569 SHELL_ALIGN(sizeof(struct nbinary)),
7570 SHELL_ALIGN(sizeof(struct nbinary)),
7571 SHELL_ALIGN(sizeof(struct nfor)),
7572 SHELL_ALIGN(sizeof(struct ncase)),
7573 SHELL_ALIGN(sizeof(struct nclist)),
7574 SHELL_ALIGN(sizeof(struct narg)),
7575 SHELL_ALIGN(sizeof(struct narg)),
7576 SHELL_ALIGN(sizeof(struct nfile)),
7577 SHELL_ALIGN(sizeof(struct nfile)),
7578 SHELL_ALIGN(sizeof(struct nfile)),
7579 SHELL_ALIGN(sizeof(struct nfile)),
7580 SHELL_ALIGN(sizeof(struct nfile)),
7581 SHELL_ALIGN(sizeof(struct ndup)),
7582 SHELL_ALIGN(sizeof(struct ndup)),
7583 SHELL_ALIGN(sizeof(struct nhere)),
7584 SHELL_ALIGN(sizeof(struct nhere)),
7585 SHELL_ALIGN(sizeof(struct nnot)),
7588 static void calcsize(union node *n);
7591 sizenodelist(struct nodelist *lp)
7594 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7601 calcsize(union node *n)
7605 funcblocksize += nodesize[n->type];
7608 calcsize(n->ncmd.redirect);
7609 calcsize(n->ncmd.args);
7610 calcsize(n->ncmd.assign);
7613 sizenodelist(n->npipe.cmdlist);
7618 calcsize(n->nredir.redirect);
7619 calcsize(n->nredir.n);
7626 calcsize(n->nbinary.ch2);
7627 calcsize(n->nbinary.ch1);
7630 calcsize(n->nif.elsepart);
7631 calcsize(n->nif.ifpart);
7632 calcsize(n->nif.test);
7635 funcstringsize += strlen(n->nfor.var) + 1;
7636 calcsize(n->nfor.body);
7637 calcsize(n->nfor.args);
7640 calcsize(n->ncase.cases);
7641 calcsize(n->ncase.expr);
7644 calcsize(n->nclist.body);
7645 calcsize(n->nclist.pattern);
7646 calcsize(n->nclist.next);
7650 sizenodelist(n->narg.backquote);
7651 funcstringsize += strlen(n->narg.text) + 1;
7652 calcsize(n->narg.next);
7655 #if ENABLE_ASH_BASH_COMPAT
7662 calcsize(n->nfile.fname);
7663 calcsize(n->nfile.next);
7667 calcsize(n->ndup.vname);
7668 calcsize(n->ndup.next);
7672 calcsize(n->nhere.doc);
7673 calcsize(n->nhere.next);
7676 calcsize(n->nnot.com);
7682 nodeckstrdup(char *s)
7684 char *rtn = funcstring;
7686 strcpy(funcstring, s);
7687 funcstring += strlen(s) + 1;
7691 static union node *copynode(union node *);
7693 static struct nodelist *
7694 copynodelist(struct nodelist *lp)
7696 struct nodelist *start;
7697 struct nodelist **lpp;
7702 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7703 (*lpp)->n = copynode(lp->n);
7705 lpp = &(*lpp)->next;
7712 copynode(union node *n)
7719 funcblock = (char *) funcblock + nodesize[n->type];
7723 new->ncmd.redirect = copynode(n->ncmd.redirect);
7724 new->ncmd.args = copynode(n->ncmd.args);
7725 new->ncmd.assign = copynode(n->ncmd.assign);
7728 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7729 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
7734 new->nredir.redirect = copynode(n->nredir.redirect);
7735 new->nredir.n = copynode(n->nredir.n);
7742 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7743 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7746 new->nif.elsepart = copynode(n->nif.elsepart);
7747 new->nif.ifpart = copynode(n->nif.ifpart);
7748 new->nif.test = copynode(n->nif.test);
7751 new->nfor.var = nodeckstrdup(n->nfor.var);
7752 new->nfor.body = copynode(n->nfor.body);
7753 new->nfor.args = copynode(n->nfor.args);
7756 new->ncase.cases = copynode(n->ncase.cases);
7757 new->ncase.expr = copynode(n->ncase.expr);
7760 new->nclist.body = copynode(n->nclist.body);
7761 new->nclist.pattern = copynode(n->nclist.pattern);
7762 new->nclist.next = copynode(n->nclist.next);
7766 new->narg.backquote = copynodelist(n->narg.backquote);
7767 new->narg.text = nodeckstrdup(n->narg.text);
7768 new->narg.next = copynode(n->narg.next);
7771 #if ENABLE_ASH_BASH_COMPAT
7778 new->nfile.fname = copynode(n->nfile.fname);
7779 new->nfile.fd = n->nfile.fd;
7780 new->nfile.next = copynode(n->nfile.next);
7784 new->ndup.vname = copynode(n->ndup.vname);
7785 new->ndup.dupfd = n->ndup.dupfd;
7786 new->ndup.fd = n->ndup.fd;
7787 new->ndup.next = copynode(n->ndup.next);
7791 new->nhere.doc = copynode(n->nhere.doc);
7792 new->nhere.fd = n->nhere.fd;
7793 new->nhere.next = copynode(n->nhere.next);
7796 new->nnot.com = copynode(n->nnot.com);
7799 new->type = n->type;
7804 * Make a copy of a parse tree.
7806 static struct funcnode *
7807 copyfunc(union node *n)
7812 funcblocksize = offsetof(struct funcnode, n);
7815 blocksize = funcblocksize;
7816 f = ckmalloc(blocksize + funcstringsize);
7817 funcblock = (char *) f + offsetof(struct funcnode, n);
7818 funcstring = (char *) f + blocksize;
7825 * Define a shell function.
7828 defun(char *name, union node *func)
7830 struct cmdentry entry;
7833 entry.cmdtype = CMDFUNCTION;
7834 entry.u.func = copyfunc(func);
7835 addcmdentry(name, &entry);
7839 static int evalskip; /* set if we are skipping commands */
7840 /* reasons for skipping commands (see comment on breakcmd routine) */
7841 #define SKIPBREAK (1 << 0)
7842 #define SKIPCONT (1 << 1)
7843 #define SKIPFUNC (1 << 2)
7844 #define SKIPFILE (1 << 3)
7845 #define SKIPEVAL (1 << 4)
7846 static int skipcount; /* number of levels to skip */
7847 static int funcnest; /* depth of function calls */
7848 static int loopnest; /* current loop nesting level */
7850 /* forward decl way out to parsing code - dotrap needs it */
7851 static int evalstring(char *s, int mask);
7854 * Called to execute a trap. Perhaps we should avoid entering new trap
7855 * handlers while we are executing a trap handler.
7866 savestatus = exitstatus;
7870 for (i = 1, q = gotsig; i < NSIG; i++, q++) {
7878 skip = evalstring(p, SKIPEVAL);
7879 exitstatus = savestatus;
7887 /* forward declarations - evaluation is fairly recursive business... */
7888 static void evalloop(union node *, int);
7889 static void evalfor(union node *, int);
7890 static void evalcase(union node *, int);
7891 static void evalsubshell(union node *, int);
7892 static void expredir(union node *);
7893 static void evalpipe(union node *, int);
7894 static void evalcommand(union node *, int);
7895 static int evalbltin(const struct builtincmd *, int, char **);
7896 static void prehash(union node *);
7899 * Evaluate a parse tree. The value is left in the global variable
7903 evaltree(union node *n, int flags)
7906 struct jmploc *volatile savehandler = exception_handler;
7907 struct jmploc jmploc;
7909 void (*evalfn)(union node *, int);
7913 TRACE(("evaltree(NULL) called\n"));
7916 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
7917 getpid(), n, n->type, flags));
7919 exception_handler = &jmploc;
7921 int err = setjmp(jmploc.loc);
7923 /* if it was a signal, check for trap handlers */
7924 if (exception == EXSIG)
7926 /* continue on the way out */
7927 exception_handler = savehandler;
7928 longjmp(exception_handler->loc, err);
7935 out1fmt("Node type = %d\n", n->type);
7940 evaltree(n->nnot.com, EV_TESTED);
7941 status = !exitstatus;
7944 expredir(n->nredir.redirect);
7945 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
7947 evaltree(n->nredir.n, flags & EV_TESTED);
7948 status = exitstatus;
7950 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
7953 evalfn = evalcommand;
7955 if (eflag && !(flags & EV_TESTED))
7967 evalfn = evalsubshell;
7980 #error NAND + 1 != NOR
7982 #if NOR + 1 != NSEMI
7983 #error NOR + 1 != NSEMI
7985 unsigned is_or = n->type - NAND;
7988 (flags | ((is_or >> 1) - 1)) & EV_TESTED
7990 if (!exitstatus == is_or)
8003 evaltree(n->nif.test, EV_TESTED);
8006 if (exitstatus == 0) {
8009 } else if (n->nif.elsepart) {
8010 n = n->nif.elsepart;
8015 defun(n->narg.text, n->narg.next);
8019 exitstatus = status;
8024 exception_handler = savehandler;
8026 if (checkexit & exitstatus)
8027 evalskip |= SKIPEVAL;
8028 else if (pendingsig && dotrap())
8031 if (flags & EV_EXIT) {
8033 raise_exception(EXEXIT);
8037 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8040 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8043 evalloop(union node *n, int flags)
8053 evaltree(n->nbinary.ch1, EV_TESTED);
8056 if (evalskip == SKIPCONT && --skipcount <= 0) {
8060 if (evalskip == SKIPBREAK && --skipcount <= 0)
8065 if (n->type != NWHILE)
8069 evaltree(n->nbinary.ch2, flags);
8070 status = exitstatus;
8075 exitstatus = status;
8079 evalfor(union node *n, int flags)
8081 struct arglist arglist;
8084 struct stackmark smark;
8086 setstackmark(&smark);
8087 arglist.list = NULL;
8088 arglist.lastp = &arglist.list;
8089 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8090 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
8095 *arglist.lastp = NULL;
8100 for (sp = arglist.list; sp; sp = sp->next) {
8101 setvar(n->nfor.var, sp->text, 0);
8102 evaltree(n->nfor.body, flags);
8104 if (evalskip == SKIPCONT && --skipcount <= 0) {
8108 if (evalskip == SKIPBREAK && --skipcount <= 0)
8115 popstackmark(&smark);
8119 evalcase(union node *n, int flags)
8123 struct arglist arglist;
8124 struct stackmark smark;
8126 setstackmark(&smark);
8127 arglist.list = NULL;
8128 arglist.lastp = &arglist.list;
8129 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8131 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8132 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8133 if (casematch(patp, arglist.list->text)) {
8134 if (evalskip == 0) {
8135 evaltree(cp->nclist.body, flags);
8142 popstackmark(&smark);
8146 * Kick off a subshell to evaluate a tree.
8149 evalsubshell(union node *n, int flags)
8152 int backgnd = (n->type == NBACKGND);
8155 expredir(n->nredir.redirect);
8156 if (!backgnd && flags & EV_EXIT && !trap[0])
8159 jp = makejob(/*n,*/ 1);
8160 if (forkshell(jp, n, backgnd) == 0) {
8164 flags &=~ EV_TESTED;
8166 redirect(n->nredir.redirect, 0);
8167 evaltreenr(n->nredir.n, flags);
8172 status = waitforjob(jp);
8173 exitstatus = status;
8178 * Compute the names of the files in a redirection list.
8180 static void fixredir(union node *, const char *, int);
8182 expredir(union node *n)
8186 for (redir = n; redir; redir = redir->nfile.next) {
8190 fn.lastp = &fn.list;
8191 switch (redir->type) {
8195 #if ENABLE_ASH_BASH_COMPAT
8200 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8201 #if ENABLE_ASH_BASH_COMPAT
8204 redir->nfile.expfname = fn.list->text;
8207 case NTOFD: /* >& */
8208 if (redir->ndup.vname) {
8209 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8210 if (fn.list == NULL)
8211 ash_msg_and_raise_error("redir error");
8212 #if ENABLE_ASH_BASH_COMPAT
8213 //FIXME: we used expandarg with different args!
8214 if (!isdigit_str9(fn.list->text)) {
8215 /* >&file, not >&fd */
8216 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8217 ash_msg_and_raise_error("redir error");
8219 goto store_expfname;
8222 fixredir(redir, fn.list->text, 1);
8230 * Evaluate a pipeline. All the processes in the pipeline are children
8231 * of the process creating the pipeline. (This differs from some versions
8232 * of the shell, which make the last process in a pipeline the parent
8236 evalpipe(union node *n, int flags)
8239 struct nodelist *lp;
8244 TRACE(("evalpipe(0x%lx) called\n", (long)n));
8246 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8250 jp = makejob(/*n,*/ pipelen);
8252 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8256 if (pipe(pip) < 0) {
8258 ash_msg_and_raise_error("pipe call failed");
8261 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8274 evaltreenr(lp->n, flags);
8282 if (n->npipe.pipe_backgnd == 0) {
8283 exitstatus = waitforjob(jp);
8284 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
8290 * Controls whether the shell is interactive or not.
8293 setinteractive(int on)
8295 static smallint is_interactive;
8297 if (++on == is_interactive)
8299 is_interactive = on;
8303 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8304 if (is_interactive > 1) {
8305 /* Looks like they want an interactive shell */
8306 static smallint did_banner;
8311 "%s built-in shell (ash)\n"
8312 "Enter 'help' for a list of built-in commands."
8327 setinteractive(iflag);
8329 #if ENABLE_FEATURE_EDITING_VI
8331 line_input_state->flags |= VI_MODE;
8333 line_input_state->flags &= ~VI_MODE;
8335 viflag = 0; /* forcibly keep the option off */
8339 static struct localvar *localvars;
8342 * Called after a function returns.
8343 * Interrupts must be off.
8348 struct localvar *lvp;
8351 while ((lvp = localvars) != NULL) {
8352 localvars = lvp->next;
8354 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
8355 if (vp == NULL) { /* $- saved */
8356 memcpy(optlist, lvp->text, sizeof(optlist));
8357 free((char*)lvp->text);
8359 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8363 (*vp->func)(strchrnul(lvp->text, '=') + 1);
8364 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8365 free((char*)vp->text);
8366 vp->flags = lvp->flags;
8367 vp->text = lvp->text;
8374 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8376 volatile struct shparam saveparam;
8377 struct localvar *volatile savelocalvars;
8378 struct jmploc *volatile savehandler;
8379 struct jmploc jmploc;
8382 saveparam = shellparam;
8383 savelocalvars = localvars;
8384 e = setjmp(jmploc.loc);
8389 savehandler = exception_handler;
8390 exception_handler = &jmploc;
8392 shellparam.malloced = 0;
8396 shellparam.nparam = argc - 1;
8397 shellparam.p = argv + 1;
8398 #if ENABLE_ASH_GETOPTS
8399 shellparam.optind = 1;
8400 shellparam.optoff = -1;
8402 evaltree(&func->n, flags & EV_TESTED);
8408 localvars = savelocalvars;
8409 freeparam(&shellparam);
8410 shellparam = saveparam;
8411 exception_handler = savehandler;
8413 evalskip &= ~SKIPFUNC;
8417 #if ENABLE_ASH_CMDCMD
8419 parse_command_args(char **argv, const char **path)
8432 if (c == '-' && !*cp) {
8439 *path = bb_default_path;
8442 /* run 'typecmd' for other options */
8453 * Make a variable a local variable. When a variable is made local, it's
8454 * value and flags are saved in a localvar structure. The saved values
8455 * will be restored when the shell function returns. We handle the name
8456 * "-" as a special case.
8461 struct localvar *lvp;
8466 lvp = ckzalloc(sizeof(struct localvar));
8467 if (LONE_DASH(name)) {
8469 p = ckmalloc(sizeof(optlist));
8470 lvp->text = memcpy(p, optlist, sizeof(optlist));
8475 vpp = hashvar(name);
8476 vp = *findvar(vpp, name);
8477 eq = strchr(name, '=');
8480 setvareq(name, VSTRFIXED);
8482 setvar(name, NULL, VSTRFIXED);
8483 vp = *vpp; /* the new variable */
8484 lvp->flags = VUNSET;
8486 lvp->text = vp->text;
8487 lvp->flags = vp->flags;
8488 vp->flags |= VSTRFIXED|VTEXTFIXED;
8494 lvp->next = localvars;
8500 * The "local" command.
8503 localcmd(int argc UNUSED_PARAM, char **argv)
8508 while ((name = *argv++) != NULL) {
8515 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8521 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8527 execcmd(int argc UNUSED_PARAM, char **argv)
8530 iflag = 0; /* exit on error */
8533 shellexec(argv + 1, pathval(), 0);
8539 * The return command.
8542 returncmd(int argc UNUSED_PARAM, char **argv)
8545 * If called outside a function, do what ksh does;
8546 * skip the rest of the file.
8548 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8549 return argv[1] ? number(argv[1]) : exitstatus;
8552 /* Forward declarations for builtintab[] */
8553 static int breakcmd(int, char **);
8554 static int dotcmd(int, char **);
8555 static int evalcmd(int, char **);
8556 static int exitcmd(int, char **);
8557 static int exportcmd(int, char **);
8558 #if ENABLE_ASH_GETOPTS
8559 static int getoptscmd(int, char **);
8561 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8562 static int helpcmd(int, char **);
8564 #if ENABLE_ASH_MATH_SUPPORT
8565 static int letcmd(int, char **);
8567 static int readcmd(int, char **);
8568 static int setcmd(int, char **);
8569 static int shiftcmd(int, char **);
8570 static int timescmd(int, char **);
8571 static int trapcmd(int, char **);
8572 static int umaskcmd(int, char **);
8573 static int unsetcmd(int, char **);
8574 static int ulimitcmd(int, char **);
8576 #define BUILTIN_NOSPEC "0"
8577 #define BUILTIN_SPECIAL "1"
8578 #define BUILTIN_REGULAR "2"
8579 #define BUILTIN_SPEC_REG "3"
8580 #define BUILTIN_ASSIGN "4"
8581 #define BUILTIN_SPEC_ASSG "5"
8582 #define BUILTIN_REG_ASSG "6"
8583 #define BUILTIN_SPEC_REG_ASSG "7"
8585 /* We do not handle [[ expr ]] bashism bash-compatibly,
8586 * we make it a synonym of [ expr ].
8587 * Basically, word splitting and pathname expansion should NOT be performed
8589 * no word splitting: a="a b"; [[ $a = "a b" ]]; echo $? should print "0"
8590 * no pathname expansion: [[ /bin/m* = "/bin/m*" ]]; echo $? should print "0"
8591 * Additional operators:
8592 * || and && should work as -o and -a
8594 * Apart from the above, [[ expr ]] should work as [ expr ]
8597 #define echocmd echo_main
8598 #define printfcmd printf_main
8599 #define testcmd test_main
8601 /* Keep these in proper order since it is searched via bsearch() */
8602 static const struct builtincmd builtintab[] = {
8603 { BUILTIN_SPEC_REG ".", dotcmd },
8604 { BUILTIN_SPEC_REG ":", truecmd },
8605 #if ENABLE_ASH_BUILTIN_TEST
8606 { BUILTIN_REGULAR "[", testcmd },
8607 #if ENABLE_ASH_BASH_COMPAT
8608 { BUILTIN_REGULAR "[[", testcmd },
8611 #if ENABLE_ASH_ALIAS
8612 { BUILTIN_REG_ASSG "alias", aliascmd },
8615 { BUILTIN_REGULAR "bg", fg_bgcmd },
8617 { BUILTIN_SPEC_REG "break", breakcmd },
8618 { BUILTIN_REGULAR "cd", cdcmd },
8619 { BUILTIN_NOSPEC "chdir", cdcmd },
8620 #if ENABLE_ASH_CMDCMD
8621 { BUILTIN_REGULAR "command", commandcmd },
8623 { BUILTIN_SPEC_REG "continue", breakcmd },
8624 #if ENABLE_ASH_BUILTIN_ECHO
8625 { BUILTIN_REGULAR "echo", echocmd },
8627 { BUILTIN_SPEC_REG "eval", evalcmd },
8628 { BUILTIN_SPEC_REG "exec", execcmd },
8629 { BUILTIN_SPEC_REG "exit", exitcmd },
8630 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8631 { BUILTIN_REGULAR "false", falsecmd },
8633 { BUILTIN_REGULAR "fg", fg_bgcmd },
8635 #if ENABLE_ASH_GETOPTS
8636 { BUILTIN_REGULAR "getopts", getoptscmd },
8638 { BUILTIN_NOSPEC "hash", hashcmd },
8639 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8640 { BUILTIN_NOSPEC "help", helpcmd },
8643 { BUILTIN_REGULAR "jobs", jobscmd },
8644 { BUILTIN_REGULAR "kill", killcmd },
8646 #if ENABLE_ASH_MATH_SUPPORT
8647 { BUILTIN_NOSPEC "let", letcmd },
8649 { BUILTIN_ASSIGN "local", localcmd },
8650 #if ENABLE_ASH_BUILTIN_PRINTF
8651 { BUILTIN_REGULAR "printf", printfcmd },
8653 { BUILTIN_NOSPEC "pwd", pwdcmd },
8654 { BUILTIN_REGULAR "read", readcmd },
8655 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8656 { BUILTIN_SPEC_REG "return", returncmd },
8657 { BUILTIN_SPEC_REG "set", setcmd },
8658 { BUILTIN_SPEC_REG "shift", shiftcmd },
8659 { BUILTIN_SPEC_REG "source", dotcmd },
8660 #if ENABLE_ASH_BUILTIN_TEST
8661 { BUILTIN_REGULAR "test", testcmd },
8663 { BUILTIN_SPEC_REG "times", timescmd },
8664 { BUILTIN_SPEC_REG "trap", trapcmd },
8665 { BUILTIN_REGULAR "true", truecmd },
8666 { BUILTIN_NOSPEC "type", typecmd },
8667 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
8668 { BUILTIN_REGULAR "umask", umaskcmd },
8669 #if ENABLE_ASH_ALIAS
8670 { BUILTIN_REGULAR "unalias", unaliascmd },
8672 { BUILTIN_SPEC_REG "unset", unsetcmd },
8673 { BUILTIN_REGULAR "wait", waitcmd },
8676 /* Should match the above table! */
8677 #define COMMANDCMD (builtintab + \
8679 1 * ENABLE_ASH_BUILTIN_TEST + \
8680 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8681 1 * ENABLE_ASH_ALIAS + \
8682 1 * ENABLE_ASH_JOB_CONTROL + \
8684 #define EXECCMD (builtintab + \
8686 1 * ENABLE_ASH_BUILTIN_TEST + \
8687 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8688 1 * ENABLE_ASH_ALIAS + \
8689 1 * ENABLE_ASH_JOB_CONTROL + \
8691 1 * ENABLE_ASH_CMDCMD + \
8693 ENABLE_ASH_BUILTIN_ECHO + \
8697 * Search the table of builtin commands.
8699 static struct builtincmd *
8700 find_builtin(const char *name)
8702 struct builtincmd *bp;
8705 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8712 * Execute a simple command.
8715 isassignment(const char *p)
8717 const char *q = endofname(p);
8723 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8725 /* Preserve exitstatus of a previous possible redirection
8726 * as POSIX mandates */
8727 return back_exitstatus;
8730 evalcommand(union node *cmd, int flags)
8732 static const struct builtincmd null_bltin = {
8733 "\0\0", bltincmd /* why three NULs? */
8735 struct stackmark smark;
8737 struct arglist arglist;
8738 struct arglist varlist;
8741 const struct strlist *sp;
8742 struct cmdentry cmdentry;
8749 struct builtincmd *bcmd;
8750 smallint cmd_is_exec;
8751 smallint pseudovarflag = 0;
8753 /* First expand the arguments. */
8754 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8755 setstackmark(&smark);
8756 back_exitstatus = 0;
8758 cmdentry.cmdtype = CMDBUILTIN;
8759 cmdentry.u.cmd = &null_bltin;
8760 varlist.lastp = &varlist.list;
8761 *varlist.lastp = NULL;
8762 arglist.lastp = &arglist.list;
8763 *arglist.lastp = NULL;
8766 if (cmd->ncmd.args) {
8767 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8768 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8771 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8772 struct strlist **spp;
8774 spp = arglist.lastp;
8775 if (pseudovarflag && isassignment(argp->narg.text))
8776 expandarg(argp, &arglist, EXP_VARTILDE);
8778 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8780 for (sp = *spp; sp; sp = sp->next)
8784 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8785 for (sp = arglist.list; sp; sp = sp->next) {
8786 TRACE(("evalcommand arg: %s\n", sp->text));
8787 *nargv++ = sp->text;
8792 if (iflag && funcnest == 0 && argc > 0)
8793 lastarg = nargv[-1];
8796 expredir(cmd->ncmd.redirect);
8797 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8800 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8801 struct strlist **spp;
8804 spp = varlist.lastp;
8805 expandarg(argp, &varlist, EXP_VARTILDE);
8808 * Modify the command lookup path, if a PATH= assignment
8812 if (varequal(p, path))
8816 /* Print the command if xflag is set. */
8819 const char *p = " %s";
8822 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8825 for (n = 0; n < 2; n++) {
8827 fdprintf(preverrout_fd, p, sp->text);
8835 safe_write(preverrout_fd, "\n", 1);
8841 /* Now locate the command. */
8843 const char *oldpath;
8844 int cmd_flag = DO_ERR;
8849 find_command(argv[0], &cmdentry, cmd_flag, path);
8850 if (cmdentry.cmdtype == CMDUNKNOWN) {
8856 /* implement bltin and command here */
8857 if (cmdentry.cmdtype != CMDBUILTIN)
8860 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8861 if (cmdentry.u.cmd == EXECCMD)
8863 #if ENABLE_ASH_CMDCMD
8864 if (cmdentry.u.cmd == COMMANDCMD) {
8866 nargv = parse_command_args(argv, &path);
8869 argc -= nargv - argv;
8871 cmd_flag |= DO_NOFUNC;
8879 /* We have a redirection error. */
8881 raise_exception(EXERROR);
8883 exitstatus = status;
8887 /* Execute the command. */
8888 switch (cmdentry.cmdtype) {
8891 #if ENABLE_FEATURE_SH_NOFORK
8892 /* Hmmm... shouldn't it happen somewhere in forkshell() instead?
8893 * Why "fork off a child process if necessary" doesn't apply to NOFORK? */
8895 /* find_command() encodes applet_no as (-2 - applet_no) */
8896 int applet_no = (- cmdentry.u.index - 2);
8897 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
8898 listsetvar(varlist.list, VEXPORT|VSTACK);
8899 /* run <applet>_main() */
8900 exitstatus = run_nofork_applet(applet_no, argv);
8905 /* Fork off a child process if necessary. */
8906 if (!(flags & EV_EXIT) || trap[0]) {
8908 jp = makejob(/*cmd,*/ 1);
8909 if (forkshell(jp, cmd, FORK_FG) != 0) {
8910 exitstatus = waitforjob(jp);
8916 listsetvar(varlist.list, VEXPORT|VSTACK);
8917 shellexec(argv, path, cmdentry.u.index);
8921 cmdenviron = varlist.list;
8923 struct strlist *list = cmdenviron;
8925 if (spclbltin > 0 || argc == 0) {
8927 if (cmd_is_exec && argc > 1)
8930 listsetvar(list, i);
8932 /* Tight loop with builtins only:
8933 * "while kill -0 $child; do true; done"
8934 * will never exit even if $child died, unless we do this
8935 * to reap the zombie and make kill detect that it's gone: */
8936 dowait(DOWAIT_NONBLOCK, NULL);
8938 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
8945 exit_status = 128 + SIGINT;
8947 exit_status = 128 + pendingsig;
8948 exitstatus = exit_status;
8949 if (i == EXINT || spclbltin > 0) {
8951 longjmp(exception_handler->loc, 1);
8958 listsetvar(varlist.list, 0);
8959 /* See above for the rationale */
8960 dowait(DOWAIT_NONBLOCK, NULL);
8961 if (evalfun(cmdentry.u.func, argc, argv, flags))
8967 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
8969 /* dsl: I think this is intended to be used to support
8970 * '_' in 'vi' command mode during line editing...
8971 * However I implemented that within libedit itself.
8973 setvar("_", lastarg, 0);
8975 popstackmark(&smark);
8979 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
8981 char *volatile savecmdname;
8982 struct jmploc *volatile savehandler;
8983 struct jmploc jmploc;
8986 savecmdname = commandname;
8987 i = setjmp(jmploc.loc);
8990 savehandler = exception_handler;
8991 exception_handler = &jmploc;
8992 commandname = argv[0];
8994 optptr = NULL; /* initialize nextopt */
8995 exitstatus = (*cmd->builtin)(argc, argv);
8996 flush_stdout_stderr();
8998 exitstatus |= ferror(stdout);
9000 commandname = savecmdname;
9002 exception_handler = savehandler;
9008 goodname(const char *p)
9010 return !*endofname(p);
9015 * Search for a command. This is called before we fork so that the
9016 * location of the command will be available in the parent as well as
9017 * the child. The check for "goodname" is an overly conservative
9018 * check that the name will not be subject to expansion.
9021 prehash(union node *n)
9023 struct cmdentry entry;
9025 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9026 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9030 /* ============ Builtin commands
9032 * Builtin commands whose functions are closely tied to evaluation
9033 * are implemented here.
9037 * Handle break and continue commands. Break, continue, and return are
9038 * all handled by setting the evalskip flag. The evaluation routines
9039 * above all check this flag, and if it is set they start skipping
9040 * commands rather than executing them. The variable skipcount is
9041 * the number of loops to break/continue, or the number of function
9042 * levels to return. (The latter is always 1.) It should probably
9043 * be an error to break out of more loops than exist, but it isn't
9044 * in the standard shell so we don't make it one here.
9047 breakcmd(int argc UNUSED_PARAM, char **argv)
9049 int n = argv[1] ? number(argv[1]) : 1;
9052 ash_msg_and_raise_error(illnum, argv[1]);
9056 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9063 /* ============ input.c
9065 * This implements the input routines used by the parser.
9068 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
9071 INPUT_PUSH_FILE = 1,
9072 INPUT_NOFILE_OK = 2,
9075 static int plinno = 1; /* input line number */
9076 /* number of characters left in input buffer */
9077 static int parsenleft; /* copy of parsefile->nleft */
9078 static int parselleft; /* copy of parsefile->lleft */
9079 /* next character in input buffer */
9080 static char *parsenextc; /* copy of parsefile->nextc */
9082 static smallint checkkwd;
9083 /* values of checkkwd variable */
9084 #define CHKALIAS 0x1
9091 struct strpush *sp = g_parsefile->strpush;
9094 #if ENABLE_ASH_ALIAS
9096 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
9097 checkkwd |= CHKALIAS;
9099 if (sp->string != sp->ap->val) {
9102 sp->ap->flag &= ~ALIASINUSE;
9103 if (sp->ap->flag & ALIASDEAD) {
9104 unalias(sp->ap->name);
9108 parsenextc = sp->prevstring;
9109 parsenleft = sp->prevnleft;
9110 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
9111 g_parsefile->strpush = sp->prev;
9112 if (sp != &(g_parsefile->basestrpush))
9121 char *buf = g_parsefile->buf;
9124 #if ENABLE_FEATURE_EDITING
9126 if (!iflag || g_parsefile->fd)
9127 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9129 #if ENABLE_FEATURE_TAB_COMPLETION
9130 line_input_state->path_lookup = pathval();
9132 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
9134 /* Ctrl+C pressed */
9143 if (nr < 0 && errno == 0) {
9144 /* Ctrl+D pressed */
9149 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9153 /* nonblock_safe_read() handles this problem */
9155 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9156 int flags = fcntl(0, F_GETFL);
9157 if (flags >= 0 && (flags & O_NONBLOCK)) {
9158 flags &= ~O_NONBLOCK;
9159 if (fcntl(0, F_SETFL, flags) >= 0) {
9160 out2str("sh: turning off NDELAY mode\n");
9171 * Refill the input buffer and return the next input character:
9173 * 1) If a string was pushed back on the input, pop it;
9174 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
9175 * from a string so we can't refill the buffer, return EOF.
9176 * 3) If the is more stuff in this buffer, use it else call read to fill it.
9177 * 4) Process input up to the next newline, deleting nul characters.
9186 while (g_parsefile->strpush) {
9187 #if ENABLE_ASH_ALIAS
9188 if (parsenleft == -1 && g_parsefile->strpush->ap &&
9189 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
9194 if (--parsenleft >= 0)
9195 return signed_char2int(*parsenextc++);
9197 if (parsenleft == EOF_NLEFT || g_parsefile->buf == NULL)
9199 flush_stdout_stderr();
9206 parselleft = parsenleft = EOF_NLEFT;
9213 /* delete nul characters */
9221 memmove(q, q + 1, more);
9225 parsenleft = q - parsenextc - 1;
9231 parsenleft = q - parsenextc - 1;
9243 out2str(parsenextc);
9248 return signed_char2int(*parsenextc++);
9251 #define pgetc_as_macro() (--parsenleft >= 0 ? signed_char2int(*parsenextc++) : preadbuffer())
9255 return pgetc_as_macro();
9258 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9259 #define pgetc_fast() pgetc()
9261 #define pgetc_fast() pgetc_as_macro()
9265 * Same as pgetc(), but ignores PEOA.
9267 #if ENABLE_ASH_ALIAS
9274 } while (c == PEOA);
9278 #define pgetc2() pgetc()
9282 * Read a line from the script.
9285 pfgets(char *line, int len)
9291 while (--nleft > 0) {
9307 * Undo the last call to pgetc. Only one character may be pushed back.
9308 * PEOF may be pushed back.
9318 * Push a string back onto the input at this current parsefile level.
9319 * We handle aliases this way.
9321 #if !ENABLE_ASH_ALIAS
9322 #define pushstring(s, ap) pushstring(s)
9325 pushstring(char *s, struct alias *ap)
9332 if (g_parsefile->strpush) {
9333 sp = ckzalloc(sizeof(struct strpush));
9334 sp->prev = g_parsefile->strpush;
9335 g_parsefile->strpush = sp;
9337 sp = g_parsefile->strpush = &(g_parsefile->basestrpush);
9338 sp->prevstring = parsenextc;
9339 sp->prevnleft = parsenleft;
9340 #if ENABLE_ASH_ALIAS
9343 ap->flag |= ALIASINUSE;
9353 * To handle the "." command, a stack of input files is used. Pushfile
9354 * adds a new entry to the stack and popfile restores the previous level.
9359 struct parsefile *pf;
9361 g_parsefile->nleft = parsenleft;
9362 g_parsefile->lleft = parselleft;
9363 g_parsefile->nextc = parsenextc;
9364 g_parsefile->linno = plinno;
9365 pf = ckzalloc(sizeof(*pf));
9366 pf->prev = g_parsefile;
9368 /*pf->strpush = NULL; - ckzalloc did it */
9369 /*pf->basestrpush.prev = NULL;*/
9376 struct parsefile *pf = g_parsefile;
9384 g_parsefile = pf->prev;
9386 parsenleft = g_parsefile->nleft;
9387 parselleft = g_parsefile->lleft;
9388 parsenextc = g_parsefile->nextc;
9389 plinno = g_parsefile->linno;
9394 * Return to top level.
9399 while (g_parsefile != &basepf)
9404 * Close the file(s) that the shell is reading commands from. Called
9405 * after a fork is done.
9411 if (g_parsefile->fd > 0) {
9412 close(g_parsefile->fd);
9413 g_parsefile->fd = 0;
9418 * Like setinputfile, but takes an open file descriptor. Call this with
9422 setinputfd(int fd, int push)
9424 close_on_exec_on(fd);
9427 g_parsefile->buf = 0;
9429 g_parsefile->fd = fd;
9430 if (g_parsefile->buf == NULL)
9431 g_parsefile->buf = ckmalloc(IBUFSIZ);
9432 parselleft = parsenleft = 0;
9437 * Set the input to take input from a file. If push is set, push the
9438 * old input onto the stack first.
9441 setinputfile(const char *fname, int flags)
9447 fd = open(fname, O_RDONLY);
9449 if (flags & INPUT_NOFILE_OK)
9451 ash_msg_and_raise_error("can't open %s", fname);
9454 fd2 = copyfd(fd, 10);
9457 ash_msg_and_raise_error("out of file descriptors");
9460 setinputfd(fd, flags & INPUT_PUSH_FILE);
9467 * Like setinputfile, but takes input from a string.
9470 setinputstring(char *string)
9474 parsenextc = string;
9475 parsenleft = strlen(string);
9476 g_parsefile->buf = NULL;
9482 /* ============ mail.c
9484 * Routines to check for mail.
9489 #define MAXMBOXES 10
9491 /* times of mailboxes */
9492 static time_t mailtime[MAXMBOXES];
9493 /* Set if MAIL or MAILPATH is changed. */
9494 static smallint mail_var_path_changed;
9497 * Print appropriate message(s) if mail has arrived.
9498 * If mail_var_path_changed is set,
9499 * then the value of MAIL has mail_var_path_changed,
9500 * so we just update the values.
9509 struct stackmark smark;
9512 setstackmark(&smark);
9513 mpath = mpathset() ? mpathval() : mailval();
9514 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9515 p = padvance(&mpath, nullstr);
9520 for (q = p; *q; q++)
9526 q[-1] = '\0'; /* delete trailing '/' */
9527 if (stat(p, &statb) < 0) {
9531 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9534 pathopt ? pathopt : "you have mail"
9537 *mtp = statb.st_mtime;
9539 mail_var_path_changed = 0;
9540 popstackmark(&smark);
9544 changemail(const char *val UNUSED_PARAM)
9546 mail_var_path_changed = 1;
9549 #endif /* ASH_MAIL */
9552 /* ============ ??? */
9555 * Set the shell parameters.
9558 setparam(char **argv)
9564 for (nparam = 0; argv[nparam]; nparam++)
9566 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9568 *ap++ = ckstrdup(*argv++);
9571 freeparam(&shellparam);
9572 shellparam.malloced = 1;
9573 shellparam.nparam = nparam;
9574 shellparam.p = newparam;
9575 #if ENABLE_ASH_GETOPTS
9576 shellparam.optind = 1;
9577 shellparam.optoff = -1;
9582 * Process shell options. The global variable argptr contains a pointer
9583 * to the argument list; we advance it past the options.
9585 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9586 * For a non-interactive shell, an error condition encountered
9587 * by a special built-in ... shall cause the shell to write a diagnostic message
9588 * to standard error and exit as shown in the following table:
9589 * Error Special Built-In
9591 * Utility syntax error (option or operand error) Shall exit
9593 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9594 * we see that bash does not do that (set "finishes" with error code 1 instead,
9595 * and shell continues), and people rely on this behavior!
9597 * set -o barfoo 2>/dev/null
9600 * Oh well. Let's mimic that.
9603 plus_minus_o(char *name, int val)
9608 for (i = 0; i < NOPTS; i++) {
9609 if (strcmp(name, optnames(i)) == 0) {
9614 ash_msg("illegal option %co %s", val ? '-' : '+', name);
9617 for (i = 0; i < NOPTS; i++) {
9619 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
9621 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
9627 setoption(int flag, int val)
9631 for (i = 0; i < NOPTS; i++) {
9632 if (optletters(i) == flag) {
9637 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
9641 options(int cmdline)
9649 while ((p = *argptr) != NULL) {
9651 if (c != '-' && c != '+')
9654 val = 0; /* val = 0 if c == '+' */
9657 if (p[0] == '\0' || LONE_DASH(p)) {
9659 /* "-" means turn off -x and -v */
9662 /* "--" means reset params */
9663 else if (*argptr == NULL)
9666 break; /* "-" or "--" terminates options */
9669 /* first char was + or - */
9670 while ((c = *p++) != '\0') {
9671 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9672 if (c == 'c' && cmdline) {
9673 minusc = p; /* command is after shell args */
9674 } else if (c == 'o') {
9675 if (plus_minus_o(*argptr, val)) {
9676 /* it already printed err message */
9677 return 1; /* error */
9681 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9683 /* bash does not accept +-login, we also won't */
9684 } else if (cmdline && val && (c == '-')) { /* long options */
9685 if (strcmp(p, "login") == 0)
9697 * The shift builtin command.
9700 shiftcmd(int argc UNUSED_PARAM, char **argv)
9707 n = number(argv[1]);
9708 if (n > shellparam.nparam)
9709 n = 0; /* bash compat, was = shellparam.nparam; */
9711 shellparam.nparam -= n;
9712 for (ap1 = shellparam.p; --n >= 0; ap1++) {
9713 if (shellparam.malloced)
9717 while ((*ap2++ = *ap1++) != NULL)
9719 #if ENABLE_ASH_GETOPTS
9720 shellparam.optind = 1;
9721 shellparam.optoff = -1;
9728 * POSIX requires that 'set' (but not export or readonly) output the
9729 * variables in lexicographic order - by the locale's collating order (sigh).
9730 * Maybe we could keep them in an ordered balanced binary tree
9731 * instead of hashed lists.
9732 * For now just roll 'em through qsort for printing...
9735 showvars(const char *sep_prefix, int on, int off)
9740 ep = listvars(on, off, &epend);
9741 qsort(ep, epend - ep, sizeof(char *), vpcmp);
9743 sep = *sep_prefix ? " " : sep_prefix;
9745 for (; ep < epend; ep++) {
9749 p = strchrnul(*ep, '=');
9752 q = single_quote(++p);
9753 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9759 * The set command builtin.
9762 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9767 return showvars(nullstr, 0, VUNSET);
9770 if (!options(0)) { /* if no parse error... */
9773 if (*argptr != NULL) {
9781 #if ENABLE_ASH_RANDOM_SUPPORT
9783 change_random(const char *value)
9785 /* Galois LFSR parameter */
9786 /* Taps at 32 31 29 1: */
9787 enum { MASK = 0x8000000b };
9788 /* Another example - taps at 32 31 30 10: */
9789 /* MASK = 0x00400007 */
9791 if (value == NULL) {
9792 /* "get", generate */
9795 /* LCG has period of 2^32 and alternating lowest bit */
9796 random_LCG = 1664525 * random_LCG + 1013904223;
9797 /* Galois LFSR has period of 2^32-1 = 3 * 5 * 17 * 257 * 65537 */
9798 t = (random_galois_LFSR << 1);
9799 if (random_galois_LFSR < 0) /* if we just shifted 1 out of msb... */
9801 random_galois_LFSR = t;
9802 /* Both are weak, combining them gives better randomness
9803 * and ~2^64 period. & 0x7fff is probably bash compat
9804 * for $RANDOM range. Combining with subtraction is
9805 * just for fun. + and ^ would work equally well. */
9806 t = (t - random_LCG) & 0x7fff;
9807 /* set without recursion */
9808 setvar(vrandom.text, utoa(t), VNOFUNC);
9809 vrandom.flags &= ~VNOFUNC;
9812 random_galois_LFSR = random_LCG = strtoul(value, (char **)NULL, 10);
9817 #if ENABLE_ASH_GETOPTS
9819 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9828 if (*param_optind < 1)
9830 optnext = optfirst + *param_optind - 1;
9832 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
9835 p = optnext[-1] + *optoff;
9836 if (p == NULL || *p == '\0') {
9837 /* Current word is done, advance */
9839 if (p == NULL || *p != '-' || *++p == '\0') {
9846 if (LONE_DASH(p)) /* check for "--" */
9851 for (q = optstr; *q != c;) {
9853 if (optstr[0] == ':') {
9856 err |= setvarsafe("OPTARG", s, 0);
9858 fprintf(stderr, "Illegal option -%c\n", c);
9869 if (*p == '\0' && (p = *optnext) == NULL) {
9870 if (optstr[0] == ':') {
9873 err |= setvarsafe("OPTARG", s, 0);
9876 fprintf(stderr, "No arg for -%c option\n", c);
9885 err |= setvarsafe("OPTARG", p, 0);
9888 err |= setvarsafe("OPTARG", nullstr, 0);
9890 *optoff = p ? p - *(optnext - 1) : -1;
9891 *param_optind = optnext - optfirst + 1;
9892 fmtstr(s, sizeof(s), "%d", *param_optind);
9893 err |= setvarsafe("OPTIND", s, VNOFUNC);
9896 err |= setvarsafe(optvar, s, 0);
9900 flush_stdout_stderr();
9901 raise_exception(EXERROR);
9907 * The getopts builtin. Shellparam.optnext points to the next argument
9908 * to be processed. Shellparam.optptr points to the next character to
9909 * be processed in the current argument. If shellparam.optnext is NULL,
9910 * then it's the first time getopts has been called.
9913 getoptscmd(int argc, char **argv)
9918 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
9920 optbase = shellparam.p;
9921 if (shellparam.optind > shellparam.nparam + 1) {
9922 shellparam.optind = 1;
9923 shellparam.optoff = -1;
9927 if (shellparam.optind > argc - 2) {
9928 shellparam.optind = 1;
9929 shellparam.optoff = -1;
9933 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9934 &shellparam.optoff);
9936 #endif /* ASH_GETOPTS */
9939 /* ============ Shell parser */
9942 struct heredoc *next; /* next here document in list */
9943 union node *here; /* redirection node */
9944 char *eofmark; /* string indicating end of input */
9945 smallint striptabs; /* if set, strip leading tabs */
9948 static smallint tokpushback; /* last token pushed back */
9949 static smallint parsebackquote; /* nonzero if we are inside backquotes */
9950 static smallint quoteflag; /* set if (part of) last token was quoted */
9951 static token_id_t lasttoken; /* last token read (integer id Txxx) */
9952 static struct heredoc *heredoclist; /* list of here documents to read */
9953 static char *wordtext; /* text of last word returned by readtoken */
9954 static struct nodelist *backquotelist;
9955 static union node *redirnode;
9956 static struct heredoc *heredoc;
9958 * NEOF is returned by parsecmd when it encounters an end of file. It
9959 * must be distinct from NULL, so we use the address of a variable that
9960 * happens to be handy.
9962 #define NEOF ((union node *)&tokpushback)
9964 static void raise_error_syntax(const char *) NORETURN;
9966 raise_error_syntax(const char *msg)
9968 ash_msg_and_raise_error("syntax error: %s", msg);
9973 * Called when an unexpected token is read during the parse. The argument
9974 * is the token that is expected, or -1 if more than one type of token can
9975 * occur at this point.
9977 static void raise_error_unexpected_syntax(int) NORETURN;
9979 raise_error_unexpected_syntax(int token)
9984 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
9986 sprintf(msg + l, " (expecting %s)", tokname(token));
9987 raise_error_syntax(msg);
9991 #define EOFMARKLEN 79
9993 /* parsing is heavily cross-recursive, need these forward decls */
9994 static union node *andor(void);
9995 static union node *pipeline(void);
9996 static union node *parse_command(void);
9997 static void parseheredoc(void);
9998 static char peektoken(void);
9999 static int readtoken(void);
10001 static union node *
10004 union node *n1, *n2, *n3;
10007 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10008 if (nlflag == 2 && peektoken())
10014 if (tok == TBACKGND) {
10015 if (n2->type == NPIPE) {
10016 n2->npipe.pipe_backgnd = 1;
10018 if (n2->type != NREDIR) {
10019 n3 = stzalloc(sizeof(struct nredir));
10021 /*n3->nredir.redirect = NULL; - stzalloc did it */
10024 n2->type = NBACKGND;
10030 n3 = stzalloc(sizeof(struct nbinary));
10032 n3->nbinary.ch1 = n1;
10033 n3->nbinary.ch2 = n2;
10049 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10057 pungetc(); /* push back EOF on input */
10061 raise_error_unexpected_syntax(-1);
10068 static union node *
10071 union node *n1, *n2, *n3;
10079 } else if (t == TOR) {
10085 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10087 n3 = stzalloc(sizeof(struct nbinary));
10089 n3->nbinary.ch1 = n1;
10090 n3->nbinary.ch2 = n2;
10095 static union node *
10098 union node *n1, *n2, *pipenode;
10099 struct nodelist *lp, *prev;
10103 TRACE(("pipeline: entered\n"));
10104 if (readtoken() == TNOT) {
10106 checkkwd = CHKKWD | CHKALIAS;
10109 n1 = parse_command();
10110 if (readtoken() == TPIPE) {
10111 pipenode = stzalloc(sizeof(struct npipe));
10112 pipenode->type = NPIPE;
10113 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10114 lp = stzalloc(sizeof(struct nodelist));
10115 pipenode->npipe.cmdlist = lp;
10119 lp = stzalloc(sizeof(struct nodelist));
10120 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10121 lp->n = parse_command();
10123 } while (readtoken() == TPIPE);
10129 n2 = stzalloc(sizeof(struct nnot));
10137 static union node *
10142 n = stzalloc(sizeof(struct narg));
10144 /*n->narg.next = NULL; - stzalloc did it */
10145 n->narg.text = wordtext;
10146 n->narg.backquote = backquotelist;
10151 fixredir(union node *n, const char *text, int err)
10155 TRACE(("Fix redir %s %d\n", text, err));
10157 n->ndup.vname = NULL;
10159 fd = bb_strtou(text, NULL, 10);
10160 if (!errno && fd >= 0)
10161 n->ndup.dupfd = fd;
10162 else if (LONE_DASH(text))
10163 n->ndup.dupfd = -1;
10166 raise_error_syntax("bad fd number");
10167 n->ndup.vname = makename();
10172 * Returns true if the text contains nothing to expand (no dollar signs
10176 noexpand(char *text)
10182 while ((c = *p++) != '\0') {
10183 if (c == CTLQUOTEMARK)
10187 else if (SIT(c, BASESYNTAX) == CCTL)
10196 union node *n = redirnode;
10198 if (readtoken() != TWORD)
10199 raise_error_unexpected_syntax(-1);
10200 if (n->type == NHERE) {
10201 struct heredoc *here = heredoc;
10205 if (quoteflag == 0)
10207 TRACE(("Here document %d\n", n->type));
10208 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10209 raise_error_syntax("illegal eof marker for << redirection");
10210 rmescapes(wordtext);
10211 here->eofmark = wordtext;
10213 if (heredoclist == NULL)
10214 heredoclist = here;
10216 for (p = heredoclist; p->next; p = p->next)
10220 } else if (n->type == NTOFD || n->type == NFROMFD) {
10221 fixredir(n, wordtext, 0);
10223 n->nfile.fname = makename();
10227 static union node *
10230 union node *args, **app;
10231 union node *n = NULL;
10232 union node *vars, **vpp;
10233 union node **rpp, *redir;
10235 #if ENABLE_ASH_BASH_COMPAT
10236 smallint double_brackets_flag = 0;
10246 savecheckkwd = CHKALIAS;
10249 checkkwd = savecheckkwd;
10252 #if ENABLE_ASH_BASH_COMPAT
10253 case TAND: /* "&&" */
10254 case TOR: /* "||" */
10255 if (!double_brackets_flag) {
10259 wordtext = (char *) (t == TAND ? "-a" : "-o");
10262 n = stzalloc(sizeof(struct narg));
10264 /*n->narg.next = NULL; - stzalloc did it */
10265 n->narg.text = wordtext;
10266 #if ENABLE_ASH_BASH_COMPAT
10267 if (strcmp("[[", wordtext) == 0)
10268 double_brackets_flag = 1;
10269 else if (strcmp("]]", wordtext) == 0)
10270 double_brackets_flag = 0;
10272 n->narg.backquote = backquotelist;
10273 if (savecheckkwd && isassignment(wordtext)) {
10275 vpp = &n->narg.next;
10278 app = &n->narg.next;
10283 *rpp = n = redirnode;
10284 rpp = &n->nfile.next;
10285 parsefname(); /* read name of redirection file */
10288 if (args && app == &args->narg.next
10291 struct builtincmd *bcmd;
10294 /* We have a function */
10295 if (readtoken() != TRP)
10296 raise_error_unexpected_syntax(TRP);
10297 name = n->narg.text;
10298 if (!goodname(name)
10299 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10301 raise_error_syntax("bad function name");
10304 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10305 n->narg.next = parse_command();
10318 n = stzalloc(sizeof(struct ncmd));
10320 n->ncmd.args = args;
10321 n->ncmd.assign = vars;
10322 n->ncmd.redirect = redir;
10326 static union node *
10327 parse_command(void)
10329 union node *n1, *n2;
10330 union node *ap, **app;
10331 union node *cp, **cpp;
10332 union node *redir, **rpp;
10339 switch (readtoken()) {
10341 raise_error_unexpected_syntax(-1);
10344 n1 = stzalloc(sizeof(struct nif));
10346 n1->nif.test = list(0);
10347 if (readtoken() != TTHEN)
10348 raise_error_unexpected_syntax(TTHEN);
10349 n1->nif.ifpart = list(0);
10351 while (readtoken() == TELIF) {
10352 n2->nif.elsepart = stzalloc(sizeof(struct nif));
10353 n2 = n2->nif.elsepart;
10355 n2->nif.test = list(0);
10356 if (readtoken() != TTHEN)
10357 raise_error_unexpected_syntax(TTHEN);
10358 n2->nif.ifpart = list(0);
10360 if (lasttoken == TELSE)
10361 n2->nif.elsepart = list(0);
10363 n2->nif.elsepart = NULL;
10371 n1 = stzalloc(sizeof(struct nbinary));
10372 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10373 n1->nbinary.ch1 = list(0);
10376 TRACE(("expecting DO got %s %s\n", tokname(got),
10377 got == TWORD ? wordtext : ""));
10378 raise_error_unexpected_syntax(TDO);
10380 n1->nbinary.ch2 = list(0);
10385 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10386 raise_error_syntax("bad for loop variable");
10387 n1 = stzalloc(sizeof(struct nfor));
10389 n1->nfor.var = wordtext;
10390 checkkwd = CHKKWD | CHKALIAS;
10391 if (readtoken() == TIN) {
10393 while (readtoken() == TWORD) {
10394 n2 = stzalloc(sizeof(struct narg));
10396 /*n2->narg.next = NULL; - stzalloc did it */
10397 n2->narg.text = wordtext;
10398 n2->narg.backquote = backquotelist;
10400 app = &n2->narg.next;
10403 n1->nfor.args = ap;
10404 if (lasttoken != TNL && lasttoken != TSEMI)
10405 raise_error_unexpected_syntax(-1);
10407 n2 = stzalloc(sizeof(struct narg));
10409 /*n2->narg.next = NULL; - stzalloc did it */
10410 n2->narg.text = (char *)dolatstr;
10411 /*n2->narg.backquote = NULL;*/
10412 n1->nfor.args = n2;
10414 * Newline or semicolon here is optional (but note
10415 * that the original Bourne shell only allowed NL).
10417 if (lasttoken != TNL && lasttoken != TSEMI)
10420 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10421 if (readtoken() != TDO)
10422 raise_error_unexpected_syntax(TDO);
10423 n1->nfor.body = list(0);
10427 n1 = stzalloc(sizeof(struct ncase));
10429 if (readtoken() != TWORD)
10430 raise_error_unexpected_syntax(TWORD);
10431 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10433 /*n2->narg.next = NULL; - stzalloc did it */
10434 n2->narg.text = wordtext;
10435 n2->narg.backquote = backquotelist;
10437 checkkwd = CHKKWD | CHKALIAS;
10438 } while (readtoken() == TNL);
10439 if (lasttoken != TIN)
10440 raise_error_unexpected_syntax(TIN);
10441 cpp = &n1->ncase.cases;
10443 checkkwd = CHKNL | CHKKWD;
10445 while (t != TESAC) {
10446 if (lasttoken == TLP)
10448 *cpp = cp = stzalloc(sizeof(struct nclist));
10450 app = &cp->nclist.pattern;
10452 *app = ap = stzalloc(sizeof(struct narg));
10454 /*ap->narg.next = NULL; - stzalloc did it */
10455 ap->narg.text = wordtext;
10456 ap->narg.backquote = backquotelist;
10457 if (readtoken() != TPIPE)
10459 app = &ap->narg.next;
10462 //ap->narg.next = NULL;
10463 if (lasttoken != TRP)
10464 raise_error_unexpected_syntax(TRP);
10465 cp->nclist.body = list(2);
10467 cpp = &cp->nclist.next;
10469 checkkwd = CHKNL | CHKKWD;
10473 raise_error_unexpected_syntax(TENDCASE);
10480 n1 = stzalloc(sizeof(struct nredir));
10481 n1->type = NSUBSHELL;
10482 n1->nredir.n = list(0);
10483 /*n1->nredir.redirect = NULL; - stzalloc did it */
10493 return simplecmd();
10496 if (readtoken() != t)
10497 raise_error_unexpected_syntax(t);
10500 /* Now check for redirection which may follow command */
10501 checkkwd = CHKKWD | CHKALIAS;
10503 while (readtoken() == TREDIR) {
10504 *rpp = n2 = redirnode;
10505 rpp = &n2->nfile.next;
10511 if (n1->type != NSUBSHELL) {
10512 n2 = stzalloc(sizeof(struct nredir));
10517 n1->nredir.redirect = redir;
10522 #if ENABLE_ASH_BASH_COMPAT
10523 static int decode_dollar_squote(void)
10525 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
10531 p = strchr(C_escapes, c);
10536 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
10540 } while ((unsigned char)(c - '0') <= 7 && --cnt);
10542 } else if (c == 'x') { /* \xHH */
10546 } while (isxdigit(c) && --cnt);
10548 if (cnt == 3) { /* \x but next char is "bad" */
10552 } else { /* simple seq like \\ or \t */
10557 c = bb_process_escape_sequence((void*)&p);
10558 } else { /* unrecognized "\z": print both chars unless ' or " */
10559 if (c != '\'' && c != '"') {
10561 c |= 0x100; /* "please encode \, then me" */
10569 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10570 * is not NULL, read a here document. In the latter case, eofmark is the
10571 * word which marks the end of the document and striptabs is true if
10572 * leading tabs should be stripped from the document. The argument firstc
10573 * is the first character of the input token or document.
10575 * Because C does not have internal subroutines, I have simulated them
10576 * using goto's to implement the subroutine linkage. The following macros
10577 * will run code that appears at the end of readtoken1.
10579 #define CHECKEND() {goto checkend; checkend_return:;}
10580 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10581 #define PARSESUB() {goto parsesub; parsesub_return:;}
10582 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10583 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10584 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10586 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10588 /* NB: syntax parameter fits into smallint */
10592 char line[EOFMARKLEN + 1];
10593 struct nodelist *bqlist;
10597 smallint prevsyntax; /* syntax before arithmetic */
10598 #if ENABLE_ASH_EXPAND_PRMT
10599 smallint pssyntax; /* we are expanding a prompt string */
10601 int varnest; /* levels of variables expansion */
10602 int arinest; /* levels of arithmetic expansion */
10603 int parenlevel; /* levels of parens in arithmetic */
10604 int dqvarnest; /* levels of variables expansion within double quotes */
10606 USE_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
10609 /* Avoid longjmp clobbering */
10615 (void) &parenlevel;
10618 (void) &prevsyntax;
10621 startlinno = plinno;
10626 #if ENABLE_ASH_EXPAND_PRMT
10627 pssyntax = (syntax == PSSYNTAX);
10631 dblquote = (syntax == DQSYNTAX);
10637 STARTSTACKSTR(out);
10639 /* For each line, until end of word */
10641 CHECKEND(); /* set c to PEOF if at end of here document */
10642 for (;;) { /* until end of line or end of word */
10643 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10644 switch (SIT(c, syntax)) {
10645 case CNL: /* '\n' */
10646 if (syntax == BASESYNTAX)
10647 goto endword; /* exit outer loop */
10653 goto loop; /* continue outer loop */
10658 if (eofmark == NULL || dblquote)
10659 USTPUTC(CTLESC, out);
10660 #if ENABLE_ASH_BASH_COMPAT
10661 if (c == '\\' && bash_dollar_squote) {
10662 c = decode_dollar_squote();
10664 USTPUTC('\\', out);
10665 c = (unsigned char)c;
10671 case CBACK: /* backslash */
10674 USTPUTC(CTLESC, out);
10675 USTPUTC('\\', out);
10677 } else if (c == '\n') {
10681 #if ENABLE_ASH_EXPAND_PRMT
10682 if (c == '$' && pssyntax) {
10683 USTPUTC(CTLESC, out);
10684 USTPUTC('\\', out);
10687 if (dblquote && c != '\\'
10688 && c != '`' && c != '$'
10689 && (c != '"' || eofmark != NULL)
10691 USTPUTC(CTLESC, out);
10692 USTPUTC('\\', out);
10694 if (SIT(c, SQSYNTAX) == CCTL)
10695 USTPUTC(CTLESC, out);
10703 if (eofmark == NULL) {
10704 USTPUTC(CTLQUOTEMARK, out);
10712 USE_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
10713 if (eofmark != NULL && arinest == 0
10718 if (dqvarnest == 0) {
10719 syntax = BASESYNTAX;
10726 case CVAR: /* '$' */
10727 PARSESUB(); /* parse substitution */
10729 case CENDVAR: /* '}' */
10732 if (dqvarnest > 0) {
10735 USTPUTC(CTLENDVAR, out);
10740 #if ENABLE_ASH_MATH_SUPPORT
10741 case CLP: /* '(' in arithmetic */
10745 case CRP: /* ')' in arithmetic */
10746 if (parenlevel > 0) {
10750 if (pgetc() == ')') {
10751 if (--arinest == 0) {
10752 USTPUTC(CTLENDARI, out);
10753 syntax = prevsyntax;
10754 dblquote = (syntax == DQSYNTAX);
10759 * unbalanced parens
10760 * (don't 2nd guess - no error)
10768 case CBQUOTE: /* '`' */
10772 goto endword; /* exit outer loop */
10776 if (varnest == 0) {
10777 #if ENABLE_ASH_BASH_COMPAT
10779 if (pgetc() == '>')
10780 c = 0x100 + '>'; /* flag &> */
10784 goto endword; /* exit outer loop */
10786 #if ENABLE_ASH_ALIAS
10796 #if ENABLE_ASH_MATH_SUPPORT
10797 if (syntax == ARISYNTAX)
10798 raise_error_syntax("missing '))'");
10800 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10801 raise_error_syntax("unterminated quoted string");
10802 if (varnest != 0) {
10803 startlinno = plinno;
10805 raise_error_syntax("missing '}'");
10807 USTPUTC('\0', out);
10808 len = out - (char *)stackblock();
10809 out = stackblock();
10810 if (eofmark == NULL) {
10811 if ((c == '>' || c == '<' USE_ASH_BASH_COMPAT( || c == 0x100 + '>'))
10814 if (isdigit_str9(out)) {
10815 PARSEREDIR(); /* passed as params: out, c */
10816 lasttoken = TREDIR;
10819 /* else: non-number X seen, interpret it
10820 * as "NNNX>file" = "NNNX >file" */
10824 quoteflag = quotef;
10825 backquotelist = bqlist;
10826 grabstackblock(len);
10830 /* end of readtoken routine */
10833 * Check to see whether we are at the end of the here document. When this
10834 * is called, c is set to the first character of the next input line. If
10835 * we are at the end of the here document, this routine sets the c to PEOF.
10839 #if ENABLE_ASH_ALIAS
10845 while (c == '\t') {
10849 if (c == *eofmark) {
10850 if (pfgets(line, sizeof(line)) != NULL) {
10854 for (q = eofmark + 1; *q && *p == *q; p++, q++)
10856 if (*p == '\n' && *q == '\0') {
10859 needprompt = doprompt;
10861 pushstring(line, NULL);
10866 goto checkend_return;
10870 * Parse a redirection operator. The variable "out" points to a string
10871 * specifying the fd to be redirected. The variable "c" contains the
10872 * first character of the redirection operator.
10875 /* out is already checked to be a valid number or "" */
10876 int fd = (*out == '\0' ? -1 : atoi(out));
10879 np = stzalloc(sizeof(struct nfile));
10884 np->type = NAPPEND;
10886 np->type = NCLOBBER;
10889 /* it also can be NTO2 (>&file), but we can't figure it out yet */
10895 #if ENABLE_ASH_BASH_COMPAT
10896 else if (c == 0x100 + '>') { /* this flags &> redirection */
10898 pgetc(); /* this is '>', no need to check */
10902 else { /* c == '<' */
10903 /*np->nfile.fd = 0; - stzalloc did it */
10907 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10908 np = stzalloc(sizeof(struct nhere));
10909 /*np->nfile.fd = 0; - stzalloc did it */
10912 heredoc = stzalloc(sizeof(struct heredoc));
10913 heredoc->here = np;
10916 heredoc->striptabs = 1;
10918 /*heredoc->striptabs = 0; - stzalloc did it */
10924 np->type = NFROMFD;
10928 np->type = NFROMTO;
10940 goto parseredir_return;
10944 * Parse a substitution. At this point, we have read the dollar sign
10945 * and nothing else.
10948 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
10949 * (assuming ascii char codes, as the original implementation did) */
10950 #define is_special(c) \
10951 (((unsigned)(c) - 33 < 32) \
10952 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
10958 static const char types[] ALIGN1 = "}-+?=";
10961 if (c <= PEOA_OR_PEOF
10962 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10964 #if ENABLE_ASH_BASH_COMPAT
10966 bash_dollar_squote = 1;
10971 } else if (c == '(') { /* $(command) or $((arith)) */
10972 if (pgetc() == '(') {
10973 #if ENABLE_ASH_MATH_SUPPORT
10976 raise_error_syntax("you disabled math support for $((arith)) syntax");
10983 USTPUTC(CTLVAR, out);
10984 typeloc = out - (char *)stackblock();
10985 USTPUTC(VSNORMAL, out);
10986 subtype = VSNORMAL;
10994 subtype = VSLENGTH;
10998 if (c > PEOA_OR_PEOF && is_name(c)) {
11002 } while (c > PEOA_OR_PEOF && is_in_name(c));
11003 } else if (isdigit(c)) {
11007 } while (isdigit(c));
11008 } else if (is_special(c)) {
11013 raise_error_syntax("bad substitution");
11018 if (subtype == 0) {
11022 #if ENABLE_ASH_BASH_COMPAT
11023 if (c == ':' || c == '$' || isdigit(c)) {
11025 subtype = VSSUBSTR;
11032 p = strchr(types, c);
11035 subtype = p - types + VSNORMAL;
11040 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
11048 #if ENABLE_ASH_BASH_COMPAT
11050 subtype = VSREPLACE;
11053 subtype++; /* VSREPLACEALL */
11062 if (dblquote || arinest)
11064 *((char *)stackblock() + typeloc) = subtype | flags;
11065 if (subtype != VSNORMAL) {
11067 if (dblquote || arinest) {
11072 goto parsesub_return;
11076 * Called to parse command substitutions. Newstyle is set if the command
11077 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11078 * list of commands (passed by reference), and savelen is the number of
11079 * characters on the top of the stack which must be preserved.
11082 struct nodelist **nlpp;
11085 char *volatile str;
11086 struct jmploc jmploc;
11087 struct jmploc *volatile savehandler;
11089 smallint saveprompt = 0;
11092 (void) &saveprompt;
11094 savepbq = parsebackquote;
11095 if (setjmp(jmploc.loc)) {
11097 parsebackquote = 0;
11098 exception_handler = savehandler;
11099 longjmp(exception_handler->loc, 1);
11103 savelen = out - (char *)stackblock();
11105 str = ckmalloc(savelen);
11106 memcpy(str, stackblock(), savelen);
11108 savehandler = exception_handler;
11109 exception_handler = &jmploc;
11112 /* We must read until the closing backquote, giving special
11113 treatment to some slashes, and then push the string and
11114 reread it as input, interpreting it normally. */
11121 STARTSTACKSTR(pout);
11138 * If eating a newline, avoid putting
11139 * the newline into the new character
11140 * stream (via the STPUTC after the
11145 if (pc != '\\' && pc != '`' && pc != '$'
11146 && (!dblquote || pc != '"'))
11147 STPUTC('\\', pout);
11148 if (pc > PEOA_OR_PEOF) {
11154 #if ENABLE_ASH_ALIAS
11157 startlinno = plinno;
11158 raise_error_syntax("EOF in backquote substitution");
11162 needprompt = doprompt;
11171 STPUTC('\0', pout);
11172 psavelen = pout - (char *)stackblock();
11173 if (psavelen > 0) {
11174 pstr = grabstackstr(pout);
11175 setinputstring(pstr);
11180 nlpp = &(*nlpp)->next;
11181 *nlpp = stzalloc(sizeof(**nlpp));
11182 /* (*nlpp)->next = NULL; - stzalloc did it */
11183 parsebackquote = oldstyle;
11186 saveprompt = doprompt;
11193 doprompt = saveprompt;
11194 else if (readtoken() != TRP)
11195 raise_error_unexpected_syntax(TRP);
11200 * Start reading from old file again, ignoring any pushed back
11201 * tokens left from the backquote parsing
11206 while (stackblocksize() <= savelen)
11208 STARTSTACKSTR(out);
11210 memcpy(out, str, savelen);
11211 STADJUST(savelen, out);
11217 parsebackquote = savepbq;
11218 exception_handler = savehandler;
11219 if (arinest || dblquote)
11220 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11222 USTPUTC(CTLBACKQ, out);
11224 goto parsebackq_oldreturn;
11225 goto parsebackq_newreturn;
11228 #if ENABLE_ASH_MATH_SUPPORT
11230 * Parse an arithmetic expansion (indicate start of one and set state)
11233 if (++arinest == 1) {
11234 prevsyntax = syntax;
11235 syntax = ARISYNTAX;
11236 USTPUTC(CTLARI, out);
11243 * we collapse embedded arithmetic expansion to
11244 * parenthesis, which should be equivalent
11248 goto parsearith_return;
11252 } /* end of readtoken */
11255 * Read the next input token.
11256 * If the token is a word, we set backquotelist to the list of cmds in
11257 * backquotes. We set quoteflag to true if any part of the word was
11259 * If the token is TREDIR, then we set redirnode to a structure containing
11261 * In all cases, the variable startlinno is set to the number of the line
11262 * on which the token starts.
11264 * [Change comment: here documents and internal procedures]
11265 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11266 * word parsing code into a separate routine. In this case, readtoken
11267 * doesn't need to have any internal procedures, but parseword does.
11268 * We could also make parseoperator in essence the main routine, and
11269 * have parseword (readtoken1?) handle both words and redirection.]
11271 #define NEW_xxreadtoken
11272 #ifdef NEW_xxreadtoken
11273 /* singles must be first! */
11274 static const char xxreadtoken_chars[7] ALIGN1 = {
11275 '\n', '(', ')', /* singles */
11276 '&', '|', ';', /* doubles */
11280 #define xxreadtoken_singles 3
11281 #define xxreadtoken_doubles 3
11283 static const char xxreadtoken_tokens[] ALIGN1 = {
11284 TNL, TLP, TRP, /* only single occurrence allowed */
11285 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11286 TEOF, /* corresponds to trailing nul */
11287 TAND, TOR, TENDCASE /* if double occurrence */
11302 startlinno = plinno;
11303 for (;;) { /* until token or start of word found */
11305 if (c == ' ' || c == '\t' USE_ASH_ALIAS( || c == PEOA))
11309 while ((c = pgetc()) != '\n' && c != PEOF)
11312 } else if (c == '\\') {
11313 if (pgetc() != '\n') {
11315 break; /* return readtoken1(...) */
11317 startlinno = ++plinno;
11323 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11327 needprompt = doprompt;
11330 p = strchr(xxreadtoken_chars, c);
11332 break; /* return readtoken1(...) */
11334 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11336 if (cc == c) { /* double occurrence? */
11337 p += xxreadtoken_doubles + 1;
11340 #if ENABLE_ASH_BASH_COMPAT
11341 if (c == '&' && cc == '>') /* &> */
11342 break; /* return readtoken1(...) */
11347 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11352 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11354 #else /* old xxreadtoken */
11355 #define RETURN(token) return lasttoken = token
11368 startlinno = plinno;
11369 for (;;) { /* until token or start of word found */
11372 case ' ': case '\t':
11373 #if ENABLE_ASH_ALIAS
11378 while ((c = pgetc()) != '\n' && c != PEOF)
11383 if (pgetc() == '\n') {
11384 startlinno = ++plinno;
11393 needprompt = doprompt;
11398 if (pgetc() == '&')
11403 if (pgetc() == '|')
11408 if (pgetc() == ';')
11421 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11424 #endif /* old xxreadtoken */
11431 smallint alreadyseen = tokpushback;
11434 #if ENABLE_ASH_ALIAS
11443 if (checkkwd & CHKNL) {
11450 if (t != TWORD || quoteflag) {
11455 * check for keywords
11457 if (checkkwd & CHKKWD) {
11458 const char *const *pp;
11460 pp = findkwd(wordtext);
11462 lasttoken = t = pp - tokname_array;
11463 TRACE(("keyword %s recognized\n", tokname(t)));
11468 if (checkkwd & CHKALIAS) {
11469 #if ENABLE_ASH_ALIAS
11471 ap = lookupalias(wordtext, 1);
11474 pushstring(ap->val, ap);
11484 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11486 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11498 return tokname_array[t][0];
11502 * Read and parse a command. Returns NEOF on end of file. (NULL is a
11503 * valid parse tree indicating a blank line.)
11505 static union node *
11506 parsecmd(int interact)
11511 doprompt = interact;
11513 setprompt(doprompt);
11525 * Input any here documents.
11530 struct heredoc *here;
11533 here = heredoclist;
11534 heredoclist = NULL;
11540 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
11541 here->eofmark, here->striptabs);
11542 n = stzalloc(sizeof(struct narg));
11543 n->narg.type = NARG;
11544 /*n->narg.next = NULL; - stzalloc did it */
11545 n->narg.text = wordtext;
11546 n->narg.backquote = backquotelist;
11547 here->here->nhere.doc = n;
11554 * called by editline -- any expansions to the prompt should be added here.
11556 #if ENABLE_ASH_EXPAND_PRMT
11557 static const char *
11558 expandstr(const char *ps)
11562 /* XXX Fix (char *) cast. */
11563 setinputstring((char *)ps);
11564 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
11567 n.narg.type = NARG;
11568 n.narg.next = NULL;
11569 n.narg.text = wordtext;
11570 n.narg.backquote = backquotelist;
11572 expandarg(&n, NULL, 0);
11573 return stackblock();
11578 * Execute a command or commands contained in a string.
11581 evalstring(char *s, int mask)
11584 struct stackmark smark;
11588 setstackmark(&smark);
11591 while ((n = parsecmd(0)) != NEOF) {
11593 popstackmark(&smark);
11606 * The eval command.
11609 evalcmd(int argc UNUSED_PARAM, char **argv)
11618 STARTSTACKSTR(concat);
11620 concat = stack_putstr(p, concat);
11624 STPUTC(' ', concat);
11626 STPUTC('\0', concat);
11627 p = grabstackstr(concat);
11629 evalstring(p, ~SKIPEVAL);
11636 * Read and execute commands. "Top" is nonzero for the top level command
11637 * loop; it turns on prompting if the shell is interactive.
11643 struct stackmark smark;
11647 TRACE(("cmdloop(%d) called\n", top));
11651 setstackmark(&smark);
11654 showjobs(stderr, SHOW_CHANGED);
11657 if (iflag && top) {
11659 #if ENABLE_ASH_MAIL
11663 n = parsecmd(inter);
11664 /* showtree(n); DEBUG */
11666 if (!top || numeof >= 50)
11668 if (!stoppedjobs()) {
11671 out2str("\nUse \"exit\" to leave shell.\n");
11674 } else if (nflag == 0) {
11675 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11680 popstackmark(&smark);
11685 return skip & SKIPEVAL;
11692 * Take commands from a file. To be compatible we should do a path
11693 * search for the file, which is necessary to find sub-commands.
11696 find_dot_file(char *name)
11699 const char *path = pathval();
11702 /* don't try this for absolute or relative paths */
11703 if (strchr(name, '/'))
11706 while ((fullname = padvance(&path, name)) != NULL) {
11707 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11709 * Don't bother freeing here, since it will
11710 * be freed by the caller.
11714 stunalloc(fullname);
11717 /* not found in the PATH */
11718 ash_msg_and_raise_error("%s: not found", name);
11723 dotcmd(int argc, char **argv)
11725 struct strlist *sp;
11726 volatile struct shparam saveparam;
11729 for (sp = cmdenviron; sp; sp = sp->next)
11730 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11732 if (argv[1]) { /* That's what SVR2 does */
11733 char *fullname = find_dot_file(argv[1]);
11736 if (argc) { /* argc > 0, argv[0] != NULL */
11737 saveparam = shellparam;
11738 shellparam.malloced = 0;
11739 shellparam.nparam = argc;
11740 shellparam.p = argv;
11743 setinputfile(fullname, INPUT_PUSH_FILE);
11744 commandname = fullname;
11749 freeparam(&shellparam);
11750 shellparam = saveparam;
11752 status = exitstatus;
11758 exitcmd(int argc UNUSED_PARAM, char **argv)
11763 exitstatus = number(argv[1]);
11764 raise_exception(EXEXIT);
11769 * Read a file containing shell functions.
11772 readcmdfile(char *name)
11774 setinputfile(name, INPUT_PUSH_FILE);
11780 /* ============ find_command inplementation */
11783 * Resolve a command name. If you change this routine, you may have to
11784 * change the shellexec routine as well.
11787 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11789 struct tblentry *cmdp;
11796 struct builtincmd *bcmd;
11798 /* If name contains a slash, don't use PATH or hash table */
11799 if (strchr(name, '/') != NULL) {
11800 entry->u.index = -1;
11801 if (act & DO_ABS) {
11802 while (stat(name, &statb) < 0) {
11804 if (errno == EINTR)
11807 entry->cmdtype = CMDUNKNOWN;
11811 entry->cmdtype = CMDNORMAL;
11815 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11817 updatetbl = (path == pathval());
11820 if (strstr(path, "%builtin") != NULL)
11821 act |= DO_ALTBLTIN;
11824 /* If name is in the table, check answer will be ok */
11825 cmdp = cmdlookup(name, 0);
11826 if (cmdp != NULL) {
11829 switch (cmdp->cmdtype) {
11847 } else if (cmdp->rehash == 0)
11848 /* if not invalidated by cd, we're done */
11852 /* If %builtin not in path, check for builtin next */
11853 bcmd = find_builtin(name);
11855 if (IS_BUILTIN_REGULAR(bcmd))
11856 goto builtin_success;
11857 if (act & DO_ALTPATH) {
11858 if (!(act & DO_ALTBLTIN))
11859 goto builtin_success;
11860 } else if (builtinloc <= 0) {
11861 goto builtin_success;
11865 #if ENABLE_FEATURE_SH_STANDALONE
11867 int applet_no = find_applet_by_name(name);
11868 if (applet_no >= 0) {
11869 entry->cmdtype = CMDNORMAL;
11870 entry->u.index = -2 - applet_no;
11876 /* We have to search path. */
11877 prev = -1; /* where to start */
11878 if (cmdp && cmdp->rehash) { /* doing a rehash */
11879 if (cmdp->cmdtype == CMDBUILTIN)
11882 prev = cmdp->param.index;
11888 while ((fullname = padvance(&path, name)) != NULL) {
11889 stunalloc(fullname);
11890 /* NB: code below will still use fullname
11891 * despite it being "unallocated" */
11894 if (prefix(pathopt, "builtin")) {
11896 goto builtin_success;
11899 if ((act & DO_NOFUNC)
11900 || !prefix(pathopt, "func")
11901 ) { /* ignore unimplemented options */
11905 /* if rehash, don't redo absolute path names */
11906 if (fullname[0] == '/' && idx <= prev) {
11909 TRACE(("searchexec \"%s\": no change\n", name));
11912 while (stat(fullname, &statb) < 0) {
11914 if (errno == EINTR)
11917 if (errno != ENOENT && errno != ENOTDIR)
11921 e = EACCES; /* if we fail, this will be the error */
11922 if (!S_ISREG(statb.st_mode))
11924 if (pathopt) { /* this is a %func directory */
11925 stalloc(strlen(fullname) + 1);
11926 /* NB: stalloc will return space pointed by fullname
11927 * (because we don't have any intervening allocations
11928 * between stunalloc above and this stalloc) */
11929 readcmdfile(fullname);
11930 cmdp = cmdlookup(name, 0);
11931 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
11932 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
11933 stunalloc(fullname);
11936 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
11938 entry->cmdtype = CMDNORMAL;
11939 entry->u.index = idx;
11943 cmdp = cmdlookup(name, 1);
11944 cmdp->cmdtype = CMDNORMAL;
11945 cmdp->param.index = idx;
11950 /* We failed. If there was an entry for this command, delete it */
11951 if (cmdp && updatetbl)
11952 delete_cmd_entry();
11954 ash_msg("%s: %s", name, errmsg(e, "not found"));
11955 entry->cmdtype = CMDUNKNOWN;
11960 entry->cmdtype = CMDBUILTIN;
11961 entry->u.cmd = bcmd;
11965 cmdp = cmdlookup(name, 1);
11966 cmdp->cmdtype = CMDBUILTIN;
11967 cmdp->param.cmd = bcmd;
11971 entry->cmdtype = cmdp->cmdtype;
11972 entry->u = cmdp->param;
11976 /* ============ trap.c */
11979 * The trap builtin.
11982 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11991 for (signo = 0; signo < NSIG; signo++) {
11992 if (trap[signo] != NULL) {
11993 out1fmt("trap -- %s %s\n",
11994 single_quote(trap[signo]),
11995 get_signame(signo));
12004 signo = get_signum(*ap);
12006 ash_msg_and_raise_error("%s: bad trap", *ap);
12009 if (LONE_DASH(action))
12012 action = ckstrdup(action);
12015 trap[signo] = action;
12025 /* ============ Builtins */
12027 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
12029 * Lists available builtins
12032 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12037 out1fmt("\nBuilt-in commands:\n-------------------\n");
12038 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12039 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12040 builtintab[i].name + 1);
12046 #if ENABLE_FEATURE_SH_STANDALONE
12048 const char *a = applet_names;
12050 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12055 a += strlen(a) + 1;
12060 return EXIT_SUCCESS;
12062 #endif /* FEATURE_SH_EXTRA_QUIET */
12065 * The export and readonly commands.
12068 exportcmd(int argc UNUSED_PARAM, char **argv)
12074 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;
12076 if (nextopt("p") != 'p') {
12081 p = strchr(name, '=');
12085 vp = *findvar(hashvar(name), name);
12091 setvar(name, p, flag);
12092 } while ((name = *++aptr) != NULL);
12096 showvars(argv[0], flag, 0);
12101 * Delete a function if it exists.
12104 unsetfunc(const char *name)
12106 struct tblentry *cmdp;
12108 cmdp = cmdlookup(name, 0);
12109 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
12110 delete_cmd_entry();
12114 * The unset builtin command. We unset the function before we unset the
12115 * variable to allow a function to be unset when there is a readonly variable
12116 * with the same name.
12119 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12126 while ((i = nextopt("vf")) != '\0') {
12130 for (ap = argptr; *ap; ap++) {
12146 #include <sys/times.h>
12148 static const unsigned char timescmd_str[] ALIGN1 = {
12149 ' ', offsetof(struct tms, tms_utime),
12150 '\n', offsetof(struct tms, tms_stime),
12151 ' ', offsetof(struct tms, tms_cutime),
12152 '\n', offsetof(struct tms, tms_cstime),
12157 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12159 long clk_tck, s, t;
12160 const unsigned char *p;
12163 clk_tck = sysconf(_SC_CLK_TCK);
12168 t = *(clock_t *)(((char *) &buf) + p[1]);
12170 out1fmt("%ldm%ld.%.3lds%c",
12172 ((t - s * clk_tck) * 1000) / clk_tck,
12174 } while (*(p += 2));
12179 #if ENABLE_ASH_MATH_SUPPORT
12181 dash_arith(const char *s)
12187 result = arith(s, &errcode);
12190 ash_msg_and_raise_error("exponent less than 0");
12192 ash_msg_and_raise_error("divide by zero");
12194 ash_msg_and_raise_error("expression recursion loop detected");
12195 raise_error_syntax(s);
12203 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12204 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12206 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12209 letcmd(int argc UNUSED_PARAM, char **argv)
12215 ash_msg_and_raise_error("expression expected");
12217 i = dash_arith(*argv);
12222 #endif /* ASH_MATH_SUPPORT */
12225 /* ============ miscbltin.c
12227 * Miscellaneous builtins.
12232 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12233 typedef enum __rlimit_resource rlim_t;
12237 * The read builtin. Options:
12238 * -r Do not interpret '\' specially
12239 * -s Turn off echo (tty only)
12240 * -n NCHARS Read NCHARS max
12241 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12242 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12243 * -u FD Read from given FD instead of fd 0
12244 * This uses unbuffered input, which may be avoidable in some cases.
12245 * TODO: bash also has:
12246 * -a ARRAY Read into array[0],[1],etc
12247 * -d DELIM End on DELIM char, not newline
12248 * -e Use line editing (tty only)
12251 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12253 static const char *const arg_REPLY[] = { "REPLY", NULL };
12266 #if ENABLE_ASH_READ_NCHARS
12267 int nchars = 0; /* if != 0, -n is in effect */
12269 struct termios tty, old_tty;
12271 #if ENABLE_ASH_READ_TIMEOUT
12272 unsigned end_ms = 0;
12273 unsigned timeout = 0;
12278 while ((i = nextopt("p:u:r"
12279 USE_ASH_READ_TIMEOUT("t:")
12280 USE_ASH_READ_NCHARS("n:s")
12284 prompt = optionarg;
12286 #if ENABLE_ASH_READ_NCHARS
12288 nchars = bb_strtou(optionarg, NULL, 10);
12289 if (nchars < 0 || errno)
12290 ash_msg_and_raise_error("invalid count");
12291 /* nchars == 0: off (bash 3.2 does this too) */
12297 #if ENABLE_ASH_READ_TIMEOUT
12299 timeout = bb_strtou(optionarg, NULL, 10);
12300 if (errno || timeout > UINT_MAX / 2048)
12301 ash_msg_and_raise_error("invalid timeout");
12303 #if 0 /* even bash have no -t N.NNN support */
12304 ts.tv_sec = bb_strtou(optionarg, &p, 10);
12306 /* EINVAL means number is ok, but not terminated by NUL */
12307 if (*p == '.' && errno == EINVAL) {
12311 ts.tv_usec = bb_strtou(p, &p2, 10);
12313 ash_msg_and_raise_error("invalid timeout");
12315 /* normalize to usec */
12317 ash_msg_and_raise_error("invalid timeout");
12318 while (scale++ < 6)
12321 } else if (ts.tv_sec < 0 || errno) {
12322 ash_msg_and_raise_error("invalid timeout");
12324 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
12325 ash_msg_and_raise_error("invalid timeout");
12334 fd = bb_strtou(optionarg, NULL, 10);
12335 if (fd < 0 || errno)
12336 ash_msg_and_raise_error("invalid file descriptor");
12342 if (prompt && isatty(fd)) {
12347 ap = (char**)arg_REPLY;
12348 ifs = bltinlookup("IFS");
12351 #if ENABLE_ASH_READ_NCHARS
12352 tcgetattr(fd, &tty);
12354 if (nchars || silent) {
12356 tty.c_lflag &= ~ICANON;
12357 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
12360 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
12362 /* if tcgetattr failed, tcsetattr will fail too.
12363 * Ignoring, it's harmless. */
12364 tcsetattr(fd, TCSANOW, &tty);
12371 #if ENABLE_ASH_READ_TIMEOUT
12372 if (timeout) /* NB: ensuring end_ms is nonzero */
12373 end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1;
12377 #if ENABLE_ASH_READ_TIMEOUT
12379 struct pollfd pfd[1];
12381 pfd[0].events = POLLIN;
12382 timeout = end_ms - (unsigned)(monotonic_us() / 1000);
12383 if ((int)timeout <= 0 /* already late? */
12384 || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
12385 ) { /* timed out! */
12386 #if ENABLE_ASH_READ_NCHARS
12387 tcsetattr(fd, TCSANOW, &old_tty);
12393 if (nonblock_safe_read(fd, &c, 1) != 1) {
12405 if (!rflag && c == '\\') {
12411 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12415 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12417 setvar(*ap, stackblock(), 0);
12426 /* end of do {} while: */
12427 #if ENABLE_ASH_READ_NCHARS
12433 #if ENABLE_ASH_READ_NCHARS
12434 tcsetattr(fd, TCSANOW, &old_tty);
12438 /* Remove trailing blanks */
12439 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12441 setvar(*ap, stackblock(), 0);
12442 while (*++ap != NULL)
12443 setvar(*ap, nullstr, 0);
12448 umaskcmd(int argc UNUSED_PARAM, char **argv)
12450 static const char permuser[3] ALIGN1 = "ugo";
12451 static const char permmode[3] ALIGN1 = "rwx";
12452 static const short permmask[] ALIGN2 = {
12453 S_IRUSR, S_IWUSR, S_IXUSR,
12454 S_IRGRP, S_IWGRP, S_IXGRP,
12455 S_IROTH, S_IWOTH, S_IXOTH
12461 int symbolic_mode = 0;
12463 while (nextopt("S") != '\0') {
12474 if (symbolic_mode) {
12478 for (i = 0; i < 3; i++) {
12481 *p++ = permuser[i];
12483 for (j = 0; j < 3; j++) {
12484 if ((mask & permmask[3 * i + j]) == 0) {
12485 *p++ = permmode[j];
12493 out1fmt("%.4o\n", mask);
12496 if (isdigit((unsigned char) *ap)) {
12499 if (*ap >= '8' || *ap < '0')
12500 ash_msg_and_raise_error(illnum, argv[1]);
12501 mask = (mask << 3) + (*ap - '0');
12502 } while (*++ap != '\0');
12505 mask = ~mask & 0777;
12506 if (!bb_parse_mode(ap, &mask)) {
12507 ash_msg_and_raise_error("illegal mode: %s", ap);
12509 umask(~mask & 0777);
12518 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12519 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12520 * ash by J.T. Conklin.
12526 uint8_t cmd; /* RLIMIT_xxx fit into it */
12527 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
12531 static const struct limits limits_tbl[] = {
12533 { RLIMIT_CPU, 0, 't' },
12535 #ifdef RLIMIT_FSIZE
12536 { RLIMIT_FSIZE, 9, 'f' },
12539 { RLIMIT_DATA, 10, 'd' },
12541 #ifdef RLIMIT_STACK
12542 { RLIMIT_STACK, 10, 's' },
12545 { RLIMIT_CORE, 9, 'c' },
12548 { RLIMIT_RSS, 10, 'm' },
12550 #ifdef RLIMIT_MEMLOCK
12551 { RLIMIT_MEMLOCK, 10, 'l' },
12553 #ifdef RLIMIT_NPROC
12554 { RLIMIT_NPROC, 0, 'p' },
12556 #ifdef RLIMIT_NOFILE
12557 { RLIMIT_NOFILE, 0, 'n' },
12560 { RLIMIT_AS, 10, 'v' },
12562 #ifdef RLIMIT_LOCKS
12563 { RLIMIT_LOCKS, 0, 'w' },
12566 static const char limits_name[] =
12568 "time(seconds)" "\0"
12570 #ifdef RLIMIT_FSIZE
12571 "file(blocks)" "\0"
12576 #ifdef RLIMIT_STACK
12580 "coredump(blocks)" "\0"
12585 #ifdef RLIMIT_MEMLOCK
12586 "locked memory(kb)" "\0"
12588 #ifdef RLIMIT_NPROC
12591 #ifdef RLIMIT_NOFILE
12597 #ifdef RLIMIT_LOCKS
12602 enum limtype { SOFT = 0x1, HARD = 0x2 };
12605 printlim(enum limtype how, const struct rlimit *limit,
12606 const struct limits *l)
12610 val = limit->rlim_max;
12612 val = limit->rlim_cur;
12614 if (val == RLIM_INFINITY)
12615 out1fmt("unlimited\n");
12617 val >>= l->factor_shift;
12618 out1fmt("%lld\n", (long long) val);
12623 ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12627 enum limtype how = SOFT | HARD;
12628 const struct limits *l;
12631 struct rlimit limit;
12634 while ((optc = nextopt("HSa"
12638 #ifdef RLIMIT_FSIZE
12644 #ifdef RLIMIT_STACK
12653 #ifdef RLIMIT_MEMLOCK
12656 #ifdef RLIMIT_NPROC
12659 #ifdef RLIMIT_NOFILE
12665 #ifdef RLIMIT_LOCKS
12683 for (l = limits_tbl; l->option != what; l++)
12686 set = *argptr ? 1 : 0;
12690 if (all || argptr[1])
12691 ash_msg_and_raise_error("too many arguments");
12692 if (strncmp(p, "unlimited\n", 9) == 0)
12693 val = RLIM_INFINITY;
12697 while ((c = *p++) >= '0' && c <= '9') {
12698 val = (val * 10) + (long)(c - '0');
12699 // val is actually 'unsigned long int' and can't get < 0
12700 if (val < (rlim_t) 0)
12704 ash_msg_and_raise_error("bad number");
12705 val <<= l->factor_shift;
12709 const char *lname = limits_name;
12710 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12711 getrlimit(l->cmd, &limit);
12712 out1fmt("%-20s ", lname);
12713 lname += strlen(lname) + 1;
12714 printlim(how, &limit, l);
12719 getrlimit(l->cmd, &limit);
12722 limit.rlim_max = val;
12724 limit.rlim_cur = val;
12725 if (setrlimit(l->cmd, &limit) < 0)
12726 ash_msg_and_raise_error("error setting limit (%m)");
12728 printlim(how, &limit, l);
12734 /* ============ Math support */
12736 #if ENABLE_ASH_MATH_SUPPORT
12738 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12740 Permission is hereby granted, free of charge, to any person obtaining
12741 a copy of this software and associated documentation files (the
12742 "Software"), to deal in the Software without restriction, including
12743 without limitation the rights to use, copy, modify, merge, publish,
12744 distribute, sublicense, and/or sell copies of the Software, and to
12745 permit persons to whom the Software is furnished to do so, subject to
12746 the following conditions:
12748 The above copyright notice and this permission notice shall be
12749 included in all copies or substantial portions of the Software.
12751 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12752 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12753 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12754 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12755 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12756 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12757 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12760 /* This is my infix parser/evaluator. It is optimized for size, intended
12761 * as a replacement for yacc-based parsers. However, it may well be faster
12762 * than a comparable parser written in yacc. The supported operators are
12763 * listed in #defines below. Parens, order of operations, and error handling
12764 * are supported. This code is thread safe. The exact expression format should
12765 * be that which POSIX specifies for shells. */
12767 /* The code uses a simple two-stack algorithm. See
12768 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12769 * for a detailed explanation of the infix-to-postfix algorithm on which
12770 * this is based (this code differs in that it applies operators immediately
12771 * to the stack instead of adding them to a queue to end up with an
12774 /* To use the routine, call it with an expression string and error return
12778 * Aug 24, 2001 Manuel Novoa III
12780 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12782 * 1) In arith_apply():
12783 * a) Cached values of *numptr and &(numptr[-1]).
12784 * b) Removed redundant test for zero denominator.
12787 * a) Eliminated redundant code for processing operator tokens by moving
12788 * to a table-based implementation. Also folded handling of parens
12790 * b) Combined all 3 loops which called arith_apply to reduce generated
12791 * code size at the cost of speed.
12793 * 3) The following expressions were treated as valid by the original code:
12794 * 1() , 0! , 1 ( *3 ) .
12795 * These bugs have been fixed by internally enclosing the expression in
12796 * parens and then checking that all binary ops and right parens are
12797 * preceded by a valid expression (NUM_TOKEN).
12799 * Note: It may be desirable to replace Aaron's test for whitespace with
12800 * ctype's isspace() if it is used by another busybox applet or if additional
12801 * whitespace chars should be considered. Look below the "#include"s for a
12802 * precompiler test.
12806 * Aug 26, 2001 Manuel Novoa III
12808 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12810 * Merge in Aaron's comments previously posted to the busybox list,
12811 * modified slightly to take account of my changes to the code.
12816 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12818 * - allow access to variable,
12819 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12820 * - realize assign syntax (VAR=expr, +=, *= etc)
12821 * - realize exponentiation (** operator)
12822 * - realize comma separated - expr, expr
12823 * - realise ++expr --expr expr++ expr--
12824 * - realise expr ? expr : expr (but, second expr calculate always)
12825 * - allow hexadecimal and octal numbers
12826 * - was restored loses XOR operator
12827 * - remove one goto label, added three ;-)
12828 * - protect $((num num)) as true zero expr (Manuel`s error)
12829 * - always use special isspace(), see comment from bash ;-)
12832 #define arith_isspace(arithval) \
12833 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12835 typedef unsigned char operator;
12837 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12838 * precedence, and 3 high bits are an ID unique across operators of that
12839 * precedence. The ID portion is so that multiple operators can have the
12840 * same precedence, ensuring that the leftmost one is evaluated first.
12841 * Consider * and /. */
12843 #define tok_decl(prec,id) (((id)<<5)|(prec))
12844 #define PREC(op) ((op) & 0x1F)
12846 #define TOK_LPAREN tok_decl(0,0)
12848 #define TOK_COMMA tok_decl(1,0)
12850 #define TOK_ASSIGN tok_decl(2,0)
12851 #define TOK_AND_ASSIGN tok_decl(2,1)
12852 #define TOK_OR_ASSIGN tok_decl(2,2)
12853 #define TOK_XOR_ASSIGN tok_decl(2,3)
12854 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12855 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12856 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12857 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12859 #define TOK_MUL_ASSIGN tok_decl(3,0)
12860 #define TOK_DIV_ASSIGN tok_decl(3,1)
12861 #define TOK_REM_ASSIGN tok_decl(3,2)
12863 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12864 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12866 /* conditional is right associativity too */
12867 #define TOK_CONDITIONAL tok_decl(4,0)
12868 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12870 #define TOK_OR tok_decl(5,0)
12872 #define TOK_AND tok_decl(6,0)
12874 #define TOK_BOR tok_decl(7,0)
12876 #define TOK_BXOR tok_decl(8,0)
12878 #define TOK_BAND tok_decl(9,0)
12880 #define TOK_EQ tok_decl(10,0)
12881 #define TOK_NE tok_decl(10,1)
12883 #define TOK_LT tok_decl(11,0)
12884 #define TOK_GT tok_decl(11,1)
12885 #define TOK_GE tok_decl(11,2)
12886 #define TOK_LE tok_decl(11,3)
12888 #define TOK_LSHIFT tok_decl(12,0)
12889 #define TOK_RSHIFT tok_decl(12,1)
12891 #define TOK_ADD tok_decl(13,0)
12892 #define TOK_SUB tok_decl(13,1)
12894 #define TOK_MUL tok_decl(14,0)
12895 #define TOK_DIV tok_decl(14,1)
12896 #define TOK_REM tok_decl(14,2)
12898 /* exponent is right associativity */
12899 #define TOK_EXPONENT tok_decl(15,1)
12901 /* For now unary operators. */
12902 #define UNARYPREC 16
12903 #define TOK_BNOT tok_decl(UNARYPREC,0)
12904 #define TOK_NOT tok_decl(UNARYPREC,1)
12906 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12907 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12909 #define PREC_PRE (UNARYPREC+2)
12911 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12912 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12914 #define PREC_POST (UNARYPREC+3)
12916 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12917 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12919 #define SPEC_PREC (UNARYPREC+4)
12921 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12922 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12924 #define NUMPTR (*numstackptr)
12927 tok_have_assign(operator op)
12929 operator prec = PREC(op);
12931 convert_prec_is_assing(prec);
12932 return (prec == PREC(TOK_ASSIGN) ||
12933 prec == PREC_PRE || prec == PREC_POST);
12937 is_right_associativity(operator prec)
12939 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
12940 || prec == PREC(TOK_CONDITIONAL));
12945 arith_t contidional_second_val;
12946 char contidional_second_val_initialized;
12947 char *var; /* if NULL then is regular number,
12948 else is variable name */
12951 typedef struct chk_var_recursive_looped_t {
12953 struct chk_var_recursive_looped_t *next;
12954 } chk_var_recursive_looped_t;
12956 static chk_var_recursive_looped_t *prev_chk_var_recursive;
12959 arith_lookup_val(v_n_t *t)
12962 const char * p = lookupvar(t->var);
12967 /* recursive try as expression */
12968 chk_var_recursive_looped_t *cur;
12969 chk_var_recursive_looped_t cur_save;
12971 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
12972 if (strcmp(cur->var, t->var) == 0) {
12973 /* expression recursion loop detected */
12977 /* save current lookuped var name */
12978 cur = prev_chk_var_recursive;
12979 cur_save.var = t->var;
12980 cur_save.next = cur;
12981 prev_chk_var_recursive = &cur_save;
12983 t->val = arith (p, &errcode);
12984 /* restore previous ptr after recursiving */
12985 prev_chk_var_recursive = cur;
12988 /* allow undefined var as 0 */
12994 /* "applying" a token means performing it on the top elements on the integer
12995 * stack. For a unary operator it will only change the top element, but a
12996 * binary operator will pop two arguments and push a result */
12998 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13001 arith_t numptr_val, rez;
13002 int ret_arith_lookup_val;
13004 /* There is no operator that can work without arguments */
13005 if (NUMPTR == numstack) goto err;
13006 numptr_m1 = NUMPTR - 1;
13008 /* check operand is var with noninteger value */
13009 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13010 if (ret_arith_lookup_val)
13011 return ret_arith_lookup_val;
13013 rez = numptr_m1->val;
13014 if (op == TOK_UMINUS)
13016 else if (op == TOK_NOT)
13018 else if (op == TOK_BNOT)
13020 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13022 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13024 else if (op != TOK_UPLUS) {
13025 /* Binary operators */
13027 /* check and binary operators need two arguments */
13028 if (numptr_m1 == numstack) goto err;
13030 /* ... and they pop one */
13033 if (op == TOK_CONDITIONAL) {
13034 if (!numptr_m1->contidional_second_val_initialized) {
13035 /* protect $((expr1 ? expr2)) without ": expr" */
13038 rez = numptr_m1->contidional_second_val;
13039 } else if (numptr_m1->contidional_second_val_initialized) {
13040 /* protect $((expr1 : expr2)) without "expr ? " */
13043 numptr_m1 = NUMPTR - 1;
13044 if (op != TOK_ASSIGN) {
13045 /* check operand is var with noninteger value for not '=' */
13046 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13047 if (ret_arith_lookup_val)
13048 return ret_arith_lookup_val;
13050 if (op == TOK_CONDITIONAL) {
13051 numptr_m1->contidional_second_val = rez;
13053 rez = numptr_m1->val;
13054 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13056 else if (op == TOK_OR)
13057 rez = numptr_val || rez;
13058 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13060 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13062 else if (op == TOK_AND)
13063 rez = rez && numptr_val;
13064 else if (op == TOK_EQ)
13065 rez = (rez == numptr_val);
13066 else if (op == TOK_NE)
13067 rez = (rez != numptr_val);
13068 else if (op == TOK_GE)
13069 rez = (rez >= numptr_val);
13070 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13071 rez >>= numptr_val;
13072 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13073 rez <<= numptr_val;
13074 else if (op == TOK_GT)
13075 rez = (rez > numptr_val);
13076 else if (op == TOK_LT)
13077 rez = (rez < numptr_val);
13078 else if (op == TOK_LE)
13079 rez = (rez <= numptr_val);
13080 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13082 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13084 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13086 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13088 else if (op == TOK_CONDITIONAL_SEP) {
13089 if (numptr_m1 == numstack) {
13090 /* protect $((expr : expr)) without "expr ? " */
13093 numptr_m1->contidional_second_val_initialized = op;
13094 numptr_m1->contidional_second_val = numptr_val;
13095 } else if (op == TOK_CONDITIONAL) {
13097 numptr_val : numptr_m1->contidional_second_val;
13098 } else if (op == TOK_EXPONENT) {
13099 if (numptr_val < 0)
13100 return -3; /* exponent less than 0 */
13105 while (numptr_val--)
13109 } else if (numptr_val==0) /* zero divisor check */
13111 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13113 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13116 if (tok_have_assign(op)) {
13117 char buf[sizeof(arith_t_type)*3 + 2];
13119 if (numptr_m1->var == NULL) {
13123 /* save to shell variable */
13124 #if ENABLE_ASH_MATH_SUPPORT_64
13125 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
13127 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
13129 setvar(numptr_m1->var, buf, 0);
13130 /* after saving, make previous value for v++ or v-- */
13131 if (op == TOK_POST_INC)
13133 else if (op == TOK_POST_DEC)
13136 numptr_m1->val = rez;
13137 /* protect geting var value, is number now */
13138 numptr_m1->var = NULL;
13144 /* longest must be first */
13145 static const char op_tokens[] ALIGN1 = {
13146 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13147 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13148 '<','<', 0, TOK_LSHIFT,
13149 '>','>', 0, TOK_RSHIFT,
13150 '|','|', 0, TOK_OR,
13151 '&','&', 0, TOK_AND,
13152 '!','=', 0, TOK_NE,
13153 '<','=', 0, TOK_LE,
13154 '>','=', 0, TOK_GE,
13155 '=','=', 0, TOK_EQ,
13156 '|','=', 0, TOK_OR_ASSIGN,
13157 '&','=', 0, TOK_AND_ASSIGN,
13158 '*','=', 0, TOK_MUL_ASSIGN,
13159 '/','=', 0, TOK_DIV_ASSIGN,
13160 '%','=', 0, TOK_REM_ASSIGN,
13161 '+','=', 0, TOK_PLUS_ASSIGN,
13162 '-','=', 0, TOK_MINUS_ASSIGN,
13163 '-','-', 0, TOK_POST_DEC,
13164 '^','=', 0, TOK_XOR_ASSIGN,
13165 '+','+', 0, TOK_POST_INC,
13166 '*','*', 0, TOK_EXPONENT,
13170 '=', 0, TOK_ASSIGN,
13182 '?', 0, TOK_CONDITIONAL,
13183 ':', 0, TOK_CONDITIONAL_SEP,
13184 ')', 0, TOK_RPAREN,
13185 '(', 0, TOK_LPAREN,
13189 #define endexpression (&op_tokens[sizeof(op_tokens)-7])
13192 arith(const char *expr, int *perrcode)
13194 char arithval; /* Current character under analysis */
13195 operator lasttok, op;
13197 operator *stack, *stackptr;
13198 const char *p = endexpression;
13200 v_n_t *numstack, *numstackptr;
13201 unsigned datasizes = strlen(expr) + 2;
13203 /* Stack of integers */
13204 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13205 * in any given correct or incorrect expression is left as an exercise to
13207 numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0]));
13208 /* Stack of operator tokens */
13209 stackptr = stack = alloca(datasizes * sizeof(stack[0]));
13211 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13212 *perrcode = errcode = 0;
13216 if (arithval == 0) {
13217 if (p == endexpression) {
13218 /* Null expression. */
13222 /* This is only reached after all tokens have been extracted from the
13223 * input stream. If there are still tokens on the operator stack, they
13224 * are to be applied in order. At the end, there should be a final
13225 * result on the integer stack */
13227 if (expr != endexpression + 1) {
13228 /* If we haven't done so already, */
13229 /* append a closing right paren */
13230 expr = endexpression;
13231 /* and let the loop process it. */
13234 /* At this point, we're done with the expression. */
13235 if (numstackptr != numstack+1) {
13236 /* ... but if there isn't, it's bad */
13241 if (numstack->var) {
13242 /* expression is $((var)) only, lookup now */
13243 errcode = arith_lookup_val(numstack);
13246 *perrcode = errcode;
13247 return numstack->val;
13250 /* Continue processing the expression. */
13251 if (arith_isspace(arithval)) {
13252 /* Skip whitespace */
13255 p = endofname(expr);
13257 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13259 numstackptr->var = alloca(var_name_size);
13260 safe_strncpy(numstackptr->var, expr, var_name_size);
13263 numstackptr->contidional_second_val_initialized = 0;
13268 if (isdigit(arithval)) {
13269 numstackptr->var = NULL;
13270 #if ENABLE_ASH_MATH_SUPPORT_64
13271 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13273 numstackptr->val = strtol(expr, (char **) &expr, 0);
13277 for (p = op_tokens; ; p++) {
13281 /* strange operator not found */
13284 for (o = expr; *p && *o == *p; p++)
13291 /* skip tail uncompared token */
13294 /* skip zero delim */
13299 /* post grammar: a++ reduce to num */
13300 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13303 /* Plus and minus are binary (not unary) _only_ if the last
13304 * token was as number, or a right paren (which pretends to be
13305 * a number, since it evaluates to one). Think about it.
13306 * It makes sense. */
13307 if (lasttok != TOK_NUM) {
13323 /* We don't want a unary operator to cause recursive descent on the
13324 * stack, because there can be many in a row and it could cause an
13325 * operator to be evaluated before its argument is pushed onto the
13326 * integer stack. */
13327 /* But for binary operators, "apply" everything on the operator
13328 * stack until we find an operator with a lesser priority than the
13329 * one we have just extracted. */
13330 /* Left paren is given the lowest priority so it will never be
13331 * "applied" in this way.
13332 * if associativity is right and priority eq, applied also skip
13335 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13336 /* not left paren or unary */
13337 if (lasttok != TOK_NUM) {
13338 /* binary op must be preceded by a num */
13341 while (stackptr != stack) {
13342 if (op == TOK_RPAREN) {
13343 /* The algorithm employed here is simple: while we don't
13344 * hit an open paren nor the bottom of the stack, pop
13345 * tokens and apply them */
13346 if (stackptr[-1] == TOK_LPAREN) {
13348 /* Any operator directly after a */
13350 /* close paren should consider itself binary */
13354 operator prev_prec = PREC(stackptr[-1]);
13356 convert_prec_is_assing(prec);
13357 convert_prec_is_assing(prev_prec);
13358 if (prev_prec < prec)
13360 /* check right assoc */
13361 if (prev_prec == prec && is_right_associativity(prec))
13364 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13365 if (errcode) goto ret;
13367 if (op == TOK_RPAREN) {
13372 /* Push this operator to the stack and remember it. */
13373 *stackptr++ = lasttok = op;
13378 #endif /* ASH_MATH_SUPPORT */
13381 /* ============ main() and helpers */
13384 * Called to exit the shell.
13386 static void exitshell(void) NORETURN;
13394 status = exitstatus;
13395 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13396 if (setjmp(loc.loc)) {
13397 if (exception == EXEXIT)
13398 /* dash bug: it just does _exit(exitstatus) here
13399 * but we have to do setjobctl(0) first!
13400 * (bug is still not fixed in dash-0.5.3 - if you run dash
13401 * under Midnight Commander, on exit from dash MC is backgrounded) */
13402 status = exitstatus;
13405 exception_handler = &loc;
13411 flush_stdout_stderr();
13421 /* from input.c: */
13422 basepf.nextc = basepf.buf = basebuf;
13425 signal(SIGCHLD, SIG_DFL);
13430 char ppid[sizeof(int)*3 + 1];
13432 struct stat st1, st2;
13435 for (envp = environ; envp && *envp; envp++) {
13436 if (strchr(*envp, '=')) {
13437 setvareq(*envp, VEXPORT|VTEXTFIXED);
13441 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
13442 setvar("PPID", ppid, 0);
13444 p = lookupvar("PWD");
13446 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
13447 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
13454 * Process the shell command line arguments.
13457 procargs(char **argv)
13460 const char *xminusc;
13465 /* if (xargv[0]) - mmm, this is always true! */
13467 for (i = 0; i < NOPTS; i++)
13471 /* it already printed err message */
13472 raise_exception(EXERROR);
13476 if (*xargv == NULL) {
13478 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13481 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13485 for (i = 0; i < NOPTS; i++)
13486 if (optlist[i] == 2)
13491 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13496 } else if (!sflag) {
13497 setinputfile(*xargv, 0);
13500 commandname = arg0;
13503 shellparam.p = xargv;
13504 #if ENABLE_ASH_GETOPTS
13505 shellparam.optind = 1;
13506 shellparam.optoff = -1;
13508 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13510 shellparam.nparam++;
13517 * Read /etc/profile or .profile.
13520 read_profile(const char *name)
13524 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13533 * This routine is called when an error or an interrupt occurs in an
13534 * interactive shell and control is returned to the main command loop.
13542 /* from input.c: */
13543 parselleft = parsenleft = 0; /* clear input buffer */
13545 /* from parser.c: */
13548 /* from redir.c: */
13549 clearredir(/*drop:*/ 0);
13553 static short profile_buf[16384];
13554 extern int etext();
13558 * Main routine. We initialize things, parse the arguments, execute
13559 * profiles if we're a login shell, and then call cmdloop to execute
13560 * commands. The setjmp call sets up the location to jump to when an
13561 * exception occurs. When an exception occurs the variable "state"
13562 * is used to figure out how far we had gotten.
13564 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13565 int ash_main(int argc UNUSED_PARAM, char **argv)
13568 volatile int state;
13569 struct jmploc jmploc;
13570 struct stackmark smark;
13572 /* Initialize global data */
13576 #if ENABLE_ASH_ALIAS
13582 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13585 #if ENABLE_FEATURE_EDITING
13586 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13589 if (setjmp(jmploc.loc)) {
13599 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13603 outcslow('\n', stderr);
13605 popstackmark(&smark);
13606 FORCE_INT_ON; /* enable interrupts */
13615 exception_handler = &jmploc;
13618 trace_puts("Shell args: ");
13619 trace_puts_args(argv);
13621 rootpid = getpid();
13623 #if ENABLE_ASH_RANDOM_SUPPORT
13624 /* Can use monotonic_ns() for better randomness but for now it is
13625 * not used anywhere else in busybox... so avoid bloat */
13626 random_galois_LFSR = random_LCG = rootpid + monotonic_us();
13629 setstackmark(&smark);
13632 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13634 const char *hp = lookupvar("HISTFILE");
13637 hp = lookupvar("HOME");
13639 char *defhp = concat_path_file(hp, ".ash_history");
13640 setvar("HISTFILE", defhp, 0);
13646 if (argv[0] && argv[0][0] == '-')
13650 read_profile("/etc/profile");
13653 read_profile(".profile");
13659 getuid() == geteuid() && getgid() == getegid() &&
13663 shinit = lookupvar("ENV");
13664 if (shinit != NULL && *shinit != '\0') {
13665 read_profile(shinit);
13671 evalstring(minusc, 0);
13673 if (sflag || minusc == NULL) {
13674 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13676 const char *hp = lookupvar("HISTFILE");
13679 line_input_state->hist_file = hp;
13682 state4: /* XXX ??? - why isn't this before the "if" statement */
13690 extern void _mcleanup(void);
13699 const char *applet_name = "debug stuff usage";
13700 int main(int argc, char **argv)
13702 return ash_main(argc, argv);
13708 * Copyright (c) 1989, 1991, 1993, 1994
13709 * The Regents of the University of California. All rights reserved.
13711 * This code is derived from software contributed to Berkeley by
13712 * Kenneth Almquist.
13714 * Redistribution and use in source and binary forms, with or without
13715 * modification, are permitted provided that the following conditions
13717 * 1. Redistributions of source code must retain the above copyright
13718 * notice, this list of conditions and the following disclaimer.
13719 * 2. Redistributions in binary form must reproduce the above copyright
13720 * notice, this list of conditions and the following disclaimer in the
13721 * documentation and/or other materials provided with the distribution.
13722 * 3. Neither the name of the University nor the names of its contributors
13723 * may be used to endorse or promote products derived from this software
13724 * without specific prior written permission.
13726 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13727 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13728 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13729 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13730 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13731 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13732 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13733 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13734 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13735 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF