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 * Do a wait system call. If job control is compiled in, we accept
3767 * stopped processes. If block is zero, we return a value of zero
3768 * rather than blocking.
3770 * System V doesn't have a non-blocking wait system call. It does
3771 * have a SIGCLD signal that is sent to a process when one of it's
3772 * children dies. The obvious way to use SIGCLD would be to install
3773 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
3774 * was received, and have waitproc bump another counter when it got
3775 * the status of a process. Waitproc would then know that a wait
3776 * system call would not block if the two counters were different.
3777 * This approach doesn't work because if a process has children that
3778 * have not been waited for, System V will send it a SIGCLD when it
3779 * installs a signal handler for SIGCLD. What this means is that when
3780 * a child exits, the shell will be sent SIGCLD signals continuously
3781 * until is runs out of stack space, unless it does a wait call before
3782 * restoring the signal handler. The code below takes advantage of
3783 * this (mis)feature by installing a signal handler for SIGCLD and
3784 * then checking to see whether it was called. If there are any
3785 * children to be waited for, it will be.
3787 * If neither SYSV nor BSD is defined, we don't implement nonblocking
3788 * waits at all. In this case, the user will not be informed when
3789 * a background process until the next time she runs a real program
3790 * (as opposed to running a builtin command or just typing return),
3791 * and the jobs command may give out of date information.
3794 waitproc(int wait_flags, int *status)
3798 wait_flags |= WUNTRACED;
3800 /* NB: _not_ safe_waitpid, we need to detect EINTR */
3801 return waitpid(-1, status, wait_flags);
3805 * Wait for a process to terminate.
3808 dowait(int wait_flags, struct job *job)
3813 struct job *thisjob;
3816 TRACE(("dowait(%d) called\n", wait_flags));
3817 pid = waitproc(wait_flags, &status);
3818 TRACE(("wait returns pid=%d, status=%d\n", pid, status));
3820 /* If we were doing blocking wait and (probably) got EINTR,
3821 * check for pending sigs received while waiting.
3822 * (NB: can be moved into callers if needed) */
3823 if (wait_flags == DOWAIT_BLOCK && pendingsig)
3824 raise_exception(EXSIG);
3829 for (jp = curjob; jp; jp = jp->prev_job) {
3830 struct procstat *sp;
3831 struct procstat *spend;
3832 if (jp->state == JOBDONE)
3835 spend = jp->ps + jp->nprocs;
3838 if (sp->pid == pid) {
3839 TRACE(("Job %d: changing status of proc %d "
3840 "from 0x%x to 0x%x\n",
3841 jobno(jp), pid, sp->status, status));
3842 sp->status = status;
3845 if (sp->status == -1)
3848 if (state == JOBRUNNING)
3850 if (WIFSTOPPED(sp->status)) {
3851 jp->stopstatus = sp->status;
3855 } while (++sp < spend);
3860 if (!WIFSTOPPED(status))
3866 if (state != JOBRUNNING) {
3867 thisjob->changed = 1;
3869 if (thisjob->state != state) {
3870 TRACE(("Job %d: changing state from %d to %d\n",
3871 jobno(thisjob), thisjob->state, state));
3872 thisjob->state = state;
3874 if (state == JOBSTOPPED) {
3875 set_curjob(thisjob, CUR_STOPPED);
3884 if (thisjob && thisjob == job) {
3888 len = sprint_status(s, status, 1);
3900 showjob(FILE *out, struct job *jp, int mode)
3902 struct procstat *ps;
3903 struct procstat *psend;
3910 if (mode & SHOW_PGID) {
3911 /* just output process (group) id of pipeline */
3912 fprintf(out, "%d\n", ps->pid);
3916 col = fmtstr(s, 16, "[%d] ", jobno(jp));
3921 else if (curjob && jp == curjob->prev_job)
3924 if (mode & SHOW_PID)
3925 col += fmtstr(s + col, 16, "%d ", ps->pid);
3927 psend = ps + jp->nprocs;
3929 if (jp->state == JOBRUNNING) {
3930 strcpy(s + col, "Running");
3931 col += sizeof("Running") - 1;
3933 int status = psend[-1].status;
3934 if (jp->state == JOBSTOPPED)
3935 status = jp->stopstatus;
3936 col += sprint_status(s + col, status, 0);
3942 /* for each process */
3943 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
3945 fprintf(out, "%s%*c%s",
3946 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
3948 if (!(mode & SHOW_PID)) {
3952 if (++ps == psend) {
3953 outcslow('\n', out);
3960 if (jp->state == JOBDONE) {
3961 TRACE(("showjob: freeing job %d\n", jobno(jp)));
3967 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3968 * statuses have changed since the last call to showjobs.
3971 showjobs(FILE *out, int mode)
3975 TRACE(("showjobs(%x) called\n", mode));
3977 /* If not even one job changed, there is nothing to do */
3978 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3981 for (jp = curjob; jp; jp = jp->prev_job) {
3982 if (!(mode & SHOW_CHANGED) || jp->changed) {
3983 showjob(out, jp, mode);
3989 jobscmd(int argc UNUSED_PARAM, char **argv)
3994 while ((m = nextopt("lp"))) {
4004 showjob(stdout, getjob(*argv,0), mode);
4007 showjobs(stdout, mode);
4014 getstatus(struct job *job)
4019 status = job->ps[job->nprocs - 1].status;
4020 retval = WEXITSTATUS(status);
4021 if (!WIFEXITED(status)) {
4023 retval = WSTOPSIG(status);
4024 if (!WIFSTOPPED(status))
4027 /* XXX: limits number of signals */
4028 retval = WTERMSIG(status);
4030 if (retval == SIGINT)
4036 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
4037 jobno(job), job->nprocs, status, retval));
4042 waitcmd(int argc UNUSED_PARAM, char **argv)
4051 raise_exception(EXSIG);
4058 /* wait for all jobs */
4062 if (!jp) /* no running procs */
4064 if (jp->state == JOBRUNNING)
4069 dowait(DOWAIT_BLOCK, NULL);
4075 if (**argv != '%') {
4076 pid_t pid = number(*argv);
4081 if (job->ps[job->nprocs - 1].pid == pid)
4083 job = job->prev_job;
4086 job = getjob(*argv, 0);
4087 /* loop until process terminated or stopped */
4088 while (job->state == JOBRUNNING)
4089 dowait(DOWAIT_BLOCK, NULL);
4091 retval = getstatus(job);
4105 struct job *jp, *jq;
4107 len = njobs * sizeof(*jp);
4109 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4111 offset = (char *)jp - (char *)jq;
4113 /* Relocate pointers */
4116 jq = (struct job *)((char *)jq + l);
4120 #define joff(p) ((struct job *)((char *)(p) + l))
4121 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4122 if (joff(jp)->ps == &jq->ps0)
4123 jmove(joff(jp)->ps);
4124 if (joff(jp)->prev_job)
4125 jmove(joff(jp)->prev_job);
4135 jp = (struct job *)((char *)jp + len);
4139 } while (--jq >= jp);
4144 * Return a new job structure.
4145 * Called with interrupts off.
4148 makejob(/*union node *node,*/ int nprocs)
4153 for (i = njobs, jp = jobtab; ; jp++) {
4160 if (jp->state != JOBDONE || !jp->waited)
4169 memset(jp, 0, sizeof(*jp));
4171 /* jp->jobctl is a bitfield.
4172 * "jp->jobctl |= jobctl" likely to give awful code */
4176 jp->prev_job = curjob;
4181 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4183 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4190 * Return a string identifying a command (to be printed by the
4193 static char *cmdnextc;
4196 cmdputs(const char *s)
4198 static const char vstype[VSTYPE + 1][3] = {
4199 "", "}", "-", "+", "?", "=",
4200 "%", "%%", "#", "##"
4201 USE_ASH_BASH_COMPAT(, ":", "/", "//")
4204 const char *p, *str;
4205 char c, cc[2] = " ";
4210 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4212 while ((c = *p++) != 0) {
4220 if ((subtype & VSTYPE) == VSLENGTH)
4224 if (!(subtype & VSQUOTE) == !(quoted & 1))
4230 str = "\"}" + !(quoted & 1);
4237 case CTLBACKQ+CTLQUOTE:
4240 #if ENABLE_ASH_MATH_SUPPORT
4255 if ((subtype & VSTYPE) != VSNORMAL)
4257 str = vstype[subtype & VSTYPE];
4258 if (subtype & VSNUL)
4267 /* These can only happen inside quotes */
4280 while ((c = *str++)) {
4285 USTPUTC('"', nextc);
4291 /* cmdtxt() and cmdlist() call each other */
4292 static void cmdtxt(union node *n);
4295 cmdlist(union node *np, int sep)
4297 for (; np; np = np->narg.next) {
4301 if (sep && np->narg.next)
4307 cmdtxt(union node *n)
4310 struct nodelist *lp;
4321 lp = n->npipe.cmdlist;
4339 cmdtxt(n->nbinary.ch1);
4355 cmdtxt(n->nif.test);
4358 if (n->nif.elsepart) {
4361 n = n->nif.elsepart;
4377 cmdtxt(n->nbinary.ch1);
4387 cmdputs(n->nfor.var);
4389 cmdlist(n->nfor.args, 1);
4394 cmdputs(n->narg.text);
4398 cmdlist(n->ncmd.args, 1);
4399 cmdlist(n->ncmd.redirect, 0);
4412 cmdputs(n->ncase.expr->narg.text);
4414 for (np = n->ncase.cases; np; np = np->nclist.next) {
4415 cmdtxt(np->nclist.pattern);
4417 cmdtxt(np->nclist.body);
4431 #if ENABLE_ASH_BASH_COMPAT
4446 cmdputs(utoa(n->nfile.fd));
4448 if (n->type == NTOFD || n->type == NFROMFD) {
4449 cmdputs(utoa(n->ndup.dupfd));
4458 commandtext(union node *n)
4462 STARTSTACKSTR(cmdnextc);
4464 name = stackblock();
4465 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4466 name, cmdnextc, cmdnextc));
4467 return ckstrdup(name);
4472 * Fork off a subshell. If we are doing job control, give the subshell its
4473 * own process group. Jp is a job structure that the job is to be added to.
4474 * N is the command that will be evaluated by the child. Both jp and n may
4475 * be NULL. The mode parameter can be one of the following:
4476 * FORK_FG - Fork off a foreground process.
4477 * FORK_BG - Fork off a background process.
4478 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4479 * process group even if job control is on.
4481 * When job control is turned off, background processes have their standard
4482 * input redirected to /dev/null (except for the second and later processes
4485 * Called with interrupts off.
4488 * Clear traps on a fork.
4495 for (tp = trap; tp < &trap[NSIG]; tp++) {
4496 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4501 setsignal(tp - trap);
4507 /* Lives far away from here, needed for forkchild */
4508 static void closescript(void);
4510 /* Called after fork(), in child */
4512 forkchild(struct job *jp, /*union node *n,*/ int mode)
4516 TRACE(("Child shell %d\n", getpid()));
4523 /* do job control only in root shell */
4525 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4528 if (jp->nprocs == 0)
4531 pgrp = jp->ps[0].pid;
4532 /* This can fail because we are doing it in the parent also */
4533 (void)setpgid(0, pgrp);
4534 if (mode == FORK_FG)
4535 xtcsetpgrp(ttyfd, pgrp);
4540 if (mode == FORK_BG) {
4543 if (jp->nprocs == 0) {
4545 if (open(bb_dev_null, O_RDONLY) != 0)
4546 ash_msg_and_raise_error("can't open %s", bb_dev_null);
4549 if (!oldlvl && iflag) {
4554 for (jp = curjob; jp; jp = jp->prev_job)
4559 /* Called after fork(), in parent */
4561 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4564 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4566 TRACE(("In parent shell: child = %d\n", pid));
4568 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4574 if (mode != FORK_NOJOB && jp->jobctl) {
4577 if (jp->nprocs == 0)
4580 pgrp = jp->ps[0].pid;
4581 /* This can fail because we are doing it in the child also */
4585 if (mode == FORK_BG) {
4586 backgndpid = pid; /* set $! */
4587 set_curjob(jp, CUR_RUNNING);
4590 struct procstat *ps = &jp->ps[jp->nprocs++];
4595 if (doing_jobctl && n)
4596 ps->cmd = commandtext(n);
4602 forkshell(struct job *jp, union node *n, int mode)
4606 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4609 TRACE(("Fork failed, errno=%d", errno));
4612 ash_msg_and_raise_error("can't fork");
4615 forkchild(jp, /*n,*/ mode);
4617 forkparent(jp, n, mode, pid);
4622 * Wait for job to finish.
4624 * Under job control we have the problem that while a child process is
4625 * running interrupts generated by the user are sent to the child but not
4626 * to the shell. This means that an infinite loop started by an inter-
4627 * active user may be hard to kill. With job control turned off, an
4628 * interactive user may place an interactive program inside a loop. If
4629 * the interactive program catches interrupts, the user doesn't want
4630 * these interrupts to also abort the loop. The approach we take here
4631 * is to have the shell ignore interrupt signals while waiting for a
4632 * foreground process to terminate, and then send itself an interrupt
4633 * signal if the child process was terminated by an interrupt signal.
4634 * Unfortunately, some programs want to do a bit of cleanup and then
4635 * exit on interrupt; unless these processes terminate themselves by
4636 * sending a signal to themselves (instead of calling exit) they will
4637 * confuse this approach.
4639 * Called with interrupts off.
4642 waitforjob(struct job *jp)
4646 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4647 while (jp->state == JOBRUNNING) {
4648 dowait(DOWAIT_BLOCK, jp);
4653 xtcsetpgrp(ttyfd, rootpid);
4655 * This is truly gross.
4656 * If we're doing job control, then we did a TIOCSPGRP which
4657 * caused us (the shell) to no longer be in the controlling
4658 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4659 * intuit from the subprocess exit status whether a SIGINT
4660 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4662 if (jp->sigint) /* TODO: do the same with all signals */
4663 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4665 if (jp->state == JOBDONE)
4672 * return 1 if there are stopped jobs, otherwise 0
4684 if (jp && jp->state == JOBSTOPPED) {
4685 out2str("You have stopped jobs.\n");
4694 /* ============ redir.c
4696 * Code for dealing with input/output redirection.
4699 #define EMPTY -2 /* marks an unused slot in redirtab */
4700 #define CLOSED -3 /* marks a slot of previously-closed fd */
4703 * Open a file in noclobber mode.
4704 * The code was copied from bash.
4707 noclobberopen(const char *fname)
4710 struct stat finfo, finfo2;
4713 * If the file exists and is a regular file, return an error
4716 r = stat(fname, &finfo);
4717 if (r == 0 && S_ISREG(finfo.st_mode)) {
4723 * If the file was not present (r != 0), make sure we open it
4724 * exclusively so that if it is created before we open it, our open
4725 * will fail. Make sure that we do not truncate an existing file.
4726 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4727 * file was not a regular file, we leave O_EXCL off.
4730 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4731 fd = open(fname, O_WRONLY|O_CREAT, 0666);
4733 /* If the open failed, return the file descriptor right away. */
4738 * OK, the open succeeded, but the file may have been changed from a
4739 * non-regular file to a regular file between the stat and the open.
4740 * We are assuming that the O_EXCL open handles the case where FILENAME
4741 * did not exist and is symlinked to an existing file between the stat
4746 * If we can open it and fstat the file descriptor, and neither check
4747 * revealed that it was a regular file, and the file has not been
4748 * replaced, return the file descriptor.
4750 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4751 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4754 /* The file has been replaced. badness. */
4761 * Handle here documents. Normally we fork off a process to write the
4762 * data to a pipe. If the document is short, we can stuff the data in
4763 * the pipe without forking.
4765 /* openhere needs this forward reference */
4766 static void expandhere(union node *arg, int fd);
4768 openhere(union node *redir)
4774 ash_msg_and_raise_error("pipe call failed");
4775 if (redir->type == NHERE) {
4776 len = strlen(redir->nhere.doc->narg.text);
4777 if (len <= PIPE_BUF) {
4778 full_write(pip[1], redir->nhere.doc->narg.text, len);
4782 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4785 signal(SIGINT, SIG_IGN);
4786 signal(SIGQUIT, SIG_IGN);
4787 signal(SIGHUP, SIG_IGN);
4789 signal(SIGTSTP, SIG_IGN);
4791 signal(SIGPIPE, SIG_DFL);
4792 if (redir->type == NHERE)
4793 full_write(pip[1], redir->nhere.doc->narg.text, len);
4795 expandhere(redir->nhere.doc, pip[1]);
4796 _exit(EXIT_SUCCESS);
4804 openredirect(union node *redir)
4809 switch (redir->nfile.type) {
4811 fname = redir->nfile.expfname;
4812 f = open(fname, O_RDONLY);
4817 fname = redir->nfile.expfname;
4818 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
4823 #if ENABLE_ASH_BASH_COMPAT
4826 /* Take care of noclobber mode. */
4828 fname = redir->nfile.expfname;
4829 f = noclobberopen(fname);
4836 fname = redir->nfile.expfname;
4837 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4842 fname = redir->nfile.expfname;
4843 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4851 /* Fall through to eliminate warning. */
4852 /* Our single caller does this itself */
4859 f = openhere(redir);
4865 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4867 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
4871 * Copy a file descriptor to be >= to. Returns -1
4872 * if the source file descriptor is closed, EMPTY if there are no unused
4873 * file descriptors left.
4875 /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
4876 * old code was doing close(to) prior to copyfd() to achieve the same */
4878 COPYFD_EXACT = (int)~(INT_MAX),
4879 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
4882 copyfd(int from, int to)
4886 if (to & COPYFD_EXACT) {
4887 to &= ~COPYFD_EXACT;
4889 newfd = dup2(from, to);
4891 newfd = fcntl(from, F_DUPFD, to);
4894 if (errno == EMFILE)
4896 /* Happens when source fd is not open: try "echo >&99" */
4897 ash_msg_and_raise_error("%d: %m", from);
4902 /* Struct def and variable are moved down to the first usage site */
4907 struct redirtab *next;
4910 struct two_fd_t two_fd[0];
4912 #define redirlist (G_var.redirlist)
4914 static int need_to_remember(struct redirtab *rp, int fd)
4918 if (!rp) /* remembering was not requested */
4921 for (i = 0; i < rp->pair_count; i++) {
4922 if (rp->two_fd[i].orig == fd) {
4923 /* already remembered */
4930 /* "hidden" fd is a fd used to read scripts, or a copy of such */
4931 static int is_hidden_fd(struct redirtab *rp, int fd)
4934 struct parsefile *pf;
4947 fd |= COPYFD_RESTORE;
4948 for (i = 0; i < rp->pair_count; i++) {
4949 if (rp->two_fd[i].copy == fd) {
4957 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
4958 * old file descriptors are stashed away so that the redirection can be
4959 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
4960 * standard output, and the standard error if it becomes a duplicate of
4961 * stdout, is saved in memory.
4963 /* flags passed to redirect */
4964 #define REDIR_PUSH 01 /* save previous values of file descriptors */
4965 #define REDIR_SAVEFD2 03 /* set preverrout */
4967 redirect(union node *redir, int flags)
4969 struct redirtab *sv;
4974 int copied_fd2 = -1;
4984 if (flags & REDIR_PUSH) {
4985 union node *tmp = redir;
4988 #if ENABLE_ASH_BASH_COMPAT
4989 if (redir->nfile.type == NTO2)
4992 tmp = tmp->nfile.next;
4994 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
4995 sv->next = redirlist;
4996 sv->pair_count = sv_pos;
4998 sv->nullredirs = g_nullredirs - 1;
5000 while (sv_pos > 0) {
5002 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5007 fd = redir->nfile.fd;
5008 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5009 int right_fd = redir->ndup.dupfd;
5010 /* redirect from/to same file descriptor? */
5013 /* echo >&10 and 10 is a fd opened to the sh script? */
5014 if (is_hidden_fd(sv, right_fd)) {
5015 errno = EBADF; /* as if it is closed */
5016 ash_msg_and_raise_error("%d: %m", right_fd);
5020 newfd = openredirect(redir); /* always >= 0 */
5022 /* Descriptor wasn't open before redirect.
5023 * Mark it for close in the future */
5024 if (need_to_remember(sv, fd)) {
5025 goto remember_to_close;
5030 #if ENABLE_ASH_BASH_COMPAT
5033 if (need_to_remember(sv, fd)) {
5034 /* Copy old descriptor */
5035 i = fcntl(fd, F_DUPFD, 10);
5036 /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5037 * are closed in popredir() in the child, preventing them from leaking
5038 * into child. (popredir() also cleans up the mess in case of failures)
5043 /* Strange error (e.g. "too many files" EMFILE?) */
5047 ash_msg_and_raise_error("%d: %m", fd);
5050 /* EBADF: it is not open - good, remember to close it */
5053 } else { /* fd is open, save its copy */
5054 /* "exec fd>&-" should not close fds
5055 * which point to script file(s).
5056 * Force them to be restored afterwards */
5057 if (is_hidden_fd(sv, fd))
5058 i |= COPYFD_RESTORE;
5062 sv->two_fd[sv_pos].orig = fd;
5063 sv->two_fd[sv_pos].copy = i;
5067 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5068 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5071 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
5073 } else if (fd != newfd) { /* move newfd to fd */
5074 copyfd(newfd, fd | COPYFD_EXACT);
5075 #if ENABLE_ASH_BASH_COMPAT
5076 if (!(redir->nfile.type == NTO2 && fd == 2))
5080 #if ENABLE_ASH_BASH_COMPAT
5081 if (redir->nfile.type == NTO2 && fd == 1) {
5082 /* We already redirected it to fd 1, now copy it to 2 */
5088 } while ((redir = redir->nfile.next) != NULL);
5091 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5092 preverrout_fd = copied_fd2;
5096 * Undo the effects of the last redirection.
5099 popredir(int drop, int restore)
5101 struct redirtab *rp;
5104 if (--g_nullredirs >= 0)
5108 for (i = 0; i < rp->pair_count; i++) {
5109 int fd = rp->two_fd[i].orig;
5110 int copy = rp->two_fd[i].copy;
5111 if (copy == CLOSED) {
5116 if (copy != EMPTY) {
5117 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5118 copy &= ~COPYFD_RESTORE;
5120 copyfd(copy, fd | COPYFD_EXACT);
5125 redirlist = rp->next;
5126 g_nullredirs = rp->nullredirs;
5132 * Undo all redirections. Called on error or interrupt.
5136 * Discard all saved file descriptors.
5139 clearredir(int drop)
5145 popredir(drop, /*restore:*/ 0);
5150 redirectsafe(union node *redir, int flags)
5153 volatile int saveint;
5154 struct jmploc *volatile savehandler = exception_handler;
5155 struct jmploc jmploc;
5158 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5159 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5161 exception_handler = &jmploc;
5162 redirect(redir, flags);
5164 exception_handler = savehandler;
5165 if (err && exception != EXERROR)
5166 longjmp(exception_handler->loc, 1);
5167 RESTORE_INT(saveint);
5172 /* ============ Routines to expand arguments to commands
5174 * We have to deal with backquotes, shell variables, and file metacharacters.
5177 #if ENABLE_ASH_MATH_SUPPORT_64
5178 typedef int64_t arith_t;
5179 #define arith_t_type long long
5181 typedef long arith_t;
5182 #define arith_t_type long
5185 #if ENABLE_ASH_MATH_SUPPORT
5186 static arith_t dash_arith(const char *);
5187 static arith_t arith(const char *expr, int *perrcode);
5193 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5194 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5195 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5196 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5197 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5198 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5199 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5200 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5201 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5205 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5206 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5207 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5208 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5209 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5212 * Structure specifying which parts of the string should be searched
5213 * for IFS characters.
5216 struct ifsregion *next; /* next region in list */
5217 int begoff; /* offset of start of region */
5218 int endoff; /* offset of end of region */
5219 int nulonly; /* search for nul bytes only */
5223 struct strlist *list;
5224 struct strlist **lastp;
5227 /* output of current string */
5228 static char *expdest;
5229 /* list of back quote expressions */
5230 static struct nodelist *argbackq;
5231 /* first struct in list of ifs regions */
5232 static struct ifsregion ifsfirst;
5233 /* last struct in list */
5234 static struct ifsregion *ifslastp;
5235 /* holds expanded arg list */
5236 static struct arglist exparg;
5246 expdest = makestrspace(32, expdest);
5247 #if ENABLE_ASH_MATH_SUPPORT_64
5248 len = fmtstr(expdest, 32, "%lld", (long long) num);
5250 len = fmtstr(expdest, 32, "%ld", num);
5252 STADJUST(len, expdest);
5257 esclen(const char *start, const char *p)
5261 while (p > start && *--p == CTLESC) {
5268 * Remove any CTLESC characters from a string.
5271 _rmescapes(char *str, int flag)
5273 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5280 p = strpbrk(str, qchars);
5286 if (flag & RMESCAPE_ALLOC) {
5287 size_t len = p - str;
5288 size_t fulllen = len + strlen(p) + 1;
5290 if (flag & RMESCAPE_GROW) {
5291 r = makestrspace(fulllen, expdest);
5292 } else if (flag & RMESCAPE_HEAP) {
5293 r = ckmalloc(fulllen);
5295 r = stalloc(fulllen);
5299 q = (char *)memcpy(q, str, len) + len;
5302 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5303 globbing = flag & RMESCAPE_GLOB;
5304 notescaped = globbing;
5306 if (*p == CTLQUOTEMARK) {
5307 inquotes = ~inquotes;
5309 notescaped = globbing;
5313 /* naked back slash */
5319 if (notescaped && inquotes && *p != '/') {
5323 notescaped = globbing;
5328 if (flag & RMESCAPE_GROW) {
5330 STADJUST(q - r + 1, expdest);
5334 #define rmescapes(p) _rmescapes((p), 0)
5336 #define pmatch(a, b) !fnmatch((a), (b), 0)
5339 * Prepare a pattern for a expmeta (internal glob(3)) call.
5341 * Returns an stalloced string.
5344 preglob(const char *pattern, int quoted, int flag)
5346 flag |= RMESCAPE_GLOB;
5348 flag |= RMESCAPE_QUOTED;
5350 return _rmescapes((char *)pattern, flag);
5354 * Put a string on the stack.
5357 memtodest(const char *p, size_t len, int syntax, int quotes)
5361 q = makestrspace(len * 2, q);
5364 int c = signed_char2int(*p++);
5367 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5376 strtodest(const char *p, int syntax, int quotes)
5378 memtodest(p, strlen(p), syntax, quotes);
5382 * Record the fact that we have to scan this region of the
5383 * string for IFS characters.
5386 recordregion(int start, int end, int nulonly)
5388 struct ifsregion *ifsp;
5390 if (ifslastp == NULL) {
5394 ifsp = ckzalloc(sizeof(*ifsp));
5395 /*ifsp->next = NULL; - ckzalloc did it */
5396 ifslastp->next = ifsp;
5400 ifslastp->begoff = start;
5401 ifslastp->endoff = end;
5402 ifslastp->nulonly = nulonly;
5406 removerecordregions(int endoff)
5408 if (ifslastp == NULL)
5411 if (ifsfirst.endoff > endoff) {
5412 while (ifsfirst.next != NULL) {
5413 struct ifsregion *ifsp;
5415 ifsp = ifsfirst.next->next;
5416 free(ifsfirst.next);
5417 ifsfirst.next = ifsp;
5420 if (ifsfirst.begoff > endoff)
5423 ifslastp = &ifsfirst;
5424 ifsfirst.endoff = endoff;
5429 ifslastp = &ifsfirst;
5430 while (ifslastp->next && ifslastp->next->begoff < endoff)
5431 ifslastp=ifslastp->next;
5432 while (ifslastp->next != NULL) {
5433 struct ifsregion *ifsp;
5435 ifsp = ifslastp->next->next;
5436 free(ifslastp->next);
5437 ifslastp->next = ifsp;
5440 if (ifslastp->endoff > endoff)
5441 ifslastp->endoff = endoff;
5445 exptilde(char *startp, char *p, int flag)
5451 int quotes = flag & (EXP_FULL | EXP_CASE);
5456 while ((c = *++p) != '\0') {
5463 if (flag & EXP_VARTILDE)
5473 if (*name == '\0') {
5474 home = lookupvar(homestr);
5476 pw = getpwnam(name);
5481 if (!home || !*home)
5484 startloc = expdest - (char *)stackblock();
5485 strtodest(home, SQSYNTAX, quotes);
5486 recordregion(startloc, expdest - (char *)stackblock(), 0);
5494 * Execute a command inside back quotes. If it's a builtin command, we
5495 * want to save its output in a block obtained from malloc. Otherwise
5496 * we fork off a subprocess and get the output of the command via a pipe.
5497 * Should be called with interrupts off.
5499 struct backcmd { /* result of evalbackcmd */
5500 int fd; /* file descriptor to read from */
5501 int nleft; /* number of chars in buffer */
5502 char *buf; /* buffer */
5503 struct job *jp; /* job structure for command */
5506 /* These forward decls are needed to use "eval" code for backticks handling: */
5507 static uint8_t back_exitstatus; /* exit status of backquoted command */
5508 #define EV_EXIT 01 /* exit after evaluating tree */
5509 static void evaltree(union node *, int);
5512 evalbackcmd(union node *n, struct backcmd *result)
5524 saveherefd = herefd;
5532 ash_msg_and_raise_error("pipe call failed");
5533 jp = makejob(/*n,*/ 1);
5534 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5539 copyfd(pip[1], 1 | COPYFD_EXACT);
5543 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5547 result->fd = pip[0];
5550 herefd = saveherefd;
5552 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5553 result->fd, result->buf, result->nleft, result->jp));
5557 * Expand stuff in backwards quotes.
5560 expbackq(union node *cmd, int quoted, int quotes)
5568 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
5569 struct stackmark smark;
5572 setstackmark(&smark);
5574 startloc = dest - (char *)stackblock();
5576 evalbackcmd(cmd, &in);
5577 popstackmark(&smark);
5584 memtodest(p, i, syntax, quotes);
5588 i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5589 TRACE(("expbackq: read returns %d\n", i));
5598 back_exitstatus = waitforjob(in.jp);
5602 /* Eat all trailing newlines */
5604 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5609 recordregion(startloc, dest - (char *)stackblock(), 0);
5610 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5611 (dest - (char *)stackblock()) - startloc,
5612 (dest - (char *)stackblock()) - startloc,
5613 stackblock() + startloc));
5616 #if ENABLE_ASH_MATH_SUPPORT
5618 * Expand arithmetic expression. Backup to start of expression,
5619 * evaluate, place result in (backed up) result, adjust string position.
5632 * This routine is slightly over-complicated for
5633 * efficiency. Next we scan backwards looking for the
5634 * start of arithmetic.
5636 start = stackblock();
5643 while (*p != CTLARI) {
5647 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5652 esc = esclen(start, p);
5662 removerecordregions(begoff);
5671 len = cvtnum(dash_arith(p + 2));
5674 recordregion(begoff, begoff + len, 0);
5678 /* argstr needs it */
5679 static char *evalvar(char *p, int flag, struct strlist *var_str_list);
5682 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5683 * characters to allow for further processing. Otherwise treat
5684 * $@ like $* since no splitting will be performed.
5686 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5687 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5688 * for correct expansion of "B=$A" word.
5691 argstr(char *p, int flag, struct strlist *var_str_list)
5693 static const char spclchars[] ALIGN1 = {
5701 CTLBACKQ | CTLQUOTE,
5702 #if ENABLE_ASH_MATH_SUPPORT
5707 const char *reject = spclchars;
5709 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
5710 int breakall = flag & EXP_WORD;
5715 if (!(flag & EXP_VARTILDE)) {
5717 } else if (flag & EXP_VARTILDE2) {
5722 if (flag & EXP_TILDE) {
5728 if (*q == CTLESC && (flag & EXP_QWORD))
5731 p = exptilde(p, q, flag);
5734 startloc = expdest - (char *)stackblock();
5736 length += strcspn(p + length, reject);
5738 if (c && (!(c & 0x80)
5739 #if ENABLE_ASH_MATH_SUPPORT
5743 /* c == '=' || c == ':' || c == CTLENDARI */
5748 expdest = stack_nputstr(p, length, expdest);
5749 newloc = expdest - (char *)stackblock();
5750 if (breakall && !inquotes && newloc > startloc) {
5751 recordregion(startloc, newloc, 0);
5762 if (flag & EXP_VARTILDE2) {
5766 flag |= EXP_VARTILDE2;
5771 * sort of a hack - expand tildes in variable
5772 * assignments (after the first '=' and after ':'s).
5781 case CTLENDVAR: /* ??? */
5784 /* "$@" syntax adherence hack */
5787 !memcmp(p, dolatstr, 4) &&
5788 (p[4] == CTLQUOTEMARK || (
5789 p[4] == CTLENDVAR &&
5790 p[5] == CTLQUOTEMARK
5793 p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;
5796 inquotes = !inquotes;
5809 p = evalvar(p, flag, var_str_list);
5813 case CTLBACKQ|CTLQUOTE:
5814 expbackq(argbackq->n, c, quotes);
5815 argbackq = argbackq->next;
5817 #if ENABLE_ASH_MATH_SUPPORT
5830 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int quotes,
5833 // This commented out code was added by James Simmons <jsimmons@infradead.org>
5834 // as part of a larger change when he added support for ${var/a/b}.
5835 // However, it broke # and % operators:
5839 //echo ${var#ab} abcdcd abcdcd
5840 //echo ${var##ab} abcdcd abcdcd
5841 //echo ${var#a*b} abcdcd ababcdcd (!)
5842 //echo ${var##a*b} cdcd cdcd
5843 //echo ${var#?} babcdcd ababcdcd (!)
5844 //echo ${var##?} babcdcd babcdcd
5845 //echo ${var#*} ababcdcd babcdcd (!)
5847 //echo ${var%cd} ababcd ababcd
5848 //echo ${var%%cd} ababcd abab (!)
5849 //echo ${var%c*d} ababcd ababcd
5850 //echo ${var%%c*d} abab ababcdcd (!)
5851 //echo ${var%?} ababcdc ababcdc
5852 //echo ${var%%?} ababcdc ababcdcd (!)
5853 //echo ${var%*} ababcdcd ababcdcd
5856 // Commenting it back out helped. Remove it completely if it really
5859 char *loc, *loc2; //, *full;
5865 int match; // = strlen(str);
5866 const char *s = loc2;
5873 match = pmatch(str, s); // this line was deleted
5875 // // chop off end if its '*'
5876 // full = strrchr(str, '*');
5877 // if (full && full != str)
5880 // // If str starts with '*' replace with s.
5881 // if ((*str == '*') && strlen(s) >= match) {
5882 // full = xstrdup(s);
5883 // strncpy(full+strlen(s)-match+1, str+1, match-1);
5885 // full = xstrndup(str, match);
5886 // match = strncmp(s, full, strlen(full));
5890 if (match) // if (!match)
5892 if (quotes && *loc == CTLESC)
5901 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5908 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5911 const char *s = loc2;
5916 match = pmatch(str, s);
5923 esc = esclen(startp, loc);
5934 static void varunset(const char *, const char *, const char *, int) NORETURN;
5936 varunset(const char *end, const char *var, const char *umsg, int varflags)
5942 msg = "parameter not set";
5944 if (*end == CTLENDVAR) {
5945 if (varflags & VSNUL)
5950 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5953 #if ENABLE_ASH_BASH_COMPAT
5955 parse_sub_pattern(char *arg, int inquotes)
5957 char *idx, *repl = NULL;
5966 /* Only the first '/' seen is our separator */
5973 if (!inquotes && c == '\\' && arg[1] == '\\')
5974 arg++; /* skip both \\, not just first one */
5981 #endif /* ENABLE_ASH_BASH_COMPAT */
5984 subevalvar(char *p, char *str, int strloc, int subtype,
5985 int startloc, int varflags, int quotes, struct strlist *var_str_list)
5987 struct nodelist *saveargbackq = argbackq;
5990 char *rmesc, *rmescend;
5991 USE_ASH_BASH_COMPAT(char *repl = NULL;)
5992 USE_ASH_BASH_COMPAT(char null = '\0';)
5993 USE_ASH_BASH_COMPAT(int pos, len, orig_len;)
5994 int saveherefd = herefd;
5995 int amount, workloc, resetloc;
5997 char *(*scan)(char*, char*, char*, char*, int, int);
6000 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
6002 STPUTC('\0', expdest);
6003 herefd = saveherefd;
6004 argbackq = saveargbackq;
6005 startp = (char *)stackblock() + startloc;
6009 setvar(str, startp, 0);
6010 amount = startp - expdest;
6011 STADJUST(amount, expdest);
6014 #if ENABLE_ASH_BASH_COMPAT
6016 loc = str = stackblock() + strloc;
6017 // TODO: number() instead? It does error checking...
6019 len = str - startp - 1;
6021 /* *loc != '\0', guaranteed by parser */
6025 /* We must adjust the length by the number of escapes we find. */
6026 for (ptr = startp; ptr < (str - 1); ptr++) {
6027 if (*ptr == CTLESC) {
6035 if (*loc++ == ':') {
6036 // TODO: number() instead? It does error checking...
6040 while (*loc && *loc != ':')
6043 // TODO: number() instead? It does error checking...
6046 if (pos >= orig_len) {
6050 if (len > (orig_len - pos))
6051 len = orig_len - pos;
6053 for (str = startp; pos; str++, pos--) {
6054 if (quotes && *str == CTLESC)
6057 for (loc = startp; len; len--) {
6058 if (quotes && *str == CTLESC)
6063 amount = loc - expdest;
6064 STADJUST(amount, expdest);
6069 varunset(p, str, startp, varflags);
6072 resetloc = expdest - (char *)stackblock();
6074 /* We'll comeback here if we grow the stack while handling
6075 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6076 * stack will need rebasing, and we'll need to remove our work
6079 USE_ASH_BASH_COMPAT(restart:)
6081 amount = expdest - ((char *)stackblock() + resetloc);
6082 STADJUST(-amount, expdest);
6083 startp = (char *)stackblock() + startloc;
6086 rmescend = (char *)stackblock() + strloc;
6088 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6089 if (rmesc != startp) {
6091 startp = (char *)stackblock() + startloc;
6095 str = (char *)stackblock() + strloc;
6096 preglob(str, varflags & VSQUOTE, 0);
6097 workloc = expdest - (char *)stackblock();
6099 #if ENABLE_ASH_BASH_COMPAT
6100 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6101 char *idx, *end, *restart_detect;
6104 repl = parse_sub_pattern(str, varflags & VSQUOTE);
6109 /* If there's no pattern to match, return the expansion unmolested */
6117 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6119 /* No match, advance */
6120 restart_detect = stackblock();
6121 STPUTC(*idx, expdest);
6122 if (quotes && *idx == CTLESC) {
6125 STPUTC(*idx, expdest);
6127 if (stackblock() != restart_detect)
6135 if (subtype == VSREPLACEALL) {
6137 if (quotes && *idx == CTLESC)
6145 for (loc = repl; *loc; loc++) {
6146 restart_detect = stackblock();
6147 STPUTC(*loc, expdest);
6148 if (stackblock() != restart_detect)
6153 if (subtype == VSREPLACE) {
6155 restart_detect = stackblock();
6156 STPUTC(*idx, expdest);
6157 if (stackblock() != restart_detect)
6166 /* We've put the replaced text into a buffer at workloc, now
6167 * move it to the right place and adjust the stack.
6169 startp = stackblock() + startloc;
6170 STPUTC('\0', expdest);
6171 memmove(startp, stackblock() + workloc, len);
6172 startp[len++] = '\0';
6173 amount = expdest - ((char *)stackblock() + startloc + len - 1);
6174 STADJUST(-amount, expdest);
6177 #endif /* ENABLE_ASH_BASH_COMPAT */
6179 subtype -= VSTRIMRIGHT;
6181 if (subtype < 0 || subtype > 7)
6184 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
6185 zero = subtype >> 1;
6186 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6187 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6189 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6192 memmove(startp, loc, str - loc);
6193 loc = startp + (str - loc) - 1;
6196 amount = loc - expdest;
6197 STADJUST(amount, expdest);
6203 * Add the value of a specialized variable to the stack string.
6206 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6216 int quoted = varflags & VSQUOTE;
6217 int subtype = varflags & VSTYPE;
6218 int quotes = flags & (EXP_FULL | EXP_CASE);
6220 if (quoted && (flags & EXP_FULL))
6221 sep = 1 << CHAR_BIT;
6223 syntax = quoted ? DQSYNTAX : BASESYNTAX;
6232 num = shellparam.nparam;
6242 p = makestrspace(NOPTS, expdest);
6243 for (i = NOPTS - 1; i >= 0; i--) {
6245 USTPUTC(optletters(i), p);
6256 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
6257 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
6263 while ((p = *ap++)) {
6266 partlen = strlen(p);
6269 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6270 memtodest(p, partlen, syntax, quotes);
6276 if (subtype == VSPLUS || subtype == VSLENGTH) {
6297 // TODO: number() instead? It does error checking...
6299 if (num < 0 || num > shellparam.nparam)
6301 p = num ? shellparam.p[num - 1] : arg0;
6304 /* NB: name has form "VAR=..." */
6306 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6307 * which should be considered before we check variables. */
6309 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6313 str = var_str_list->text;
6314 eq = strchr(str, '=');
6315 if (!eq) /* stop at first non-assignment */
6318 if (name_len == (unsigned)(eq - str)
6319 && strncmp(str, name, name_len) == 0) {
6321 /* goto value; - WRONG! */
6322 /* think "A=1 A=2 B=$A" */
6324 var_str_list = var_str_list->next;
6325 } while (var_str_list);
6329 p = lookupvar(name);
6335 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6336 memtodest(p, len, syntax, quotes);
6340 if (subtype == VSPLUS || subtype == VSLENGTH)
6341 STADJUST(-len, expdest);
6346 * Expand a variable, and return a pointer to the next character in the
6350 evalvar(char *p, int flag, struct strlist *var_str_list)
6362 subtype = varflags & VSTYPE;
6363 quoted = varflags & VSQUOTE;
6365 easy = (!quoted || (*var == '@' && shellparam.nparam));
6366 startloc = expdest - (char *)stackblock();
6367 p = strchr(p, '=') + 1;
6370 varlen = varvalue(var, varflags, flag, var_str_list);
6371 if (varflags & VSNUL)
6374 if (subtype == VSPLUS) {
6375 varlen = -1 - varlen;
6379 if (subtype == VSMINUS) {
6383 p, flag | EXP_TILDE |
6384 (quoted ? EXP_QWORD : EXP_WORD),
6394 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6396 if (subevalvar(p, var, /* strloc: */ 0,
6397 subtype, startloc, varflags,
6403 * Remove any recorded regions beyond
6406 removerecordregions(startloc);
6416 if (varlen < 0 && uflag)
6417 varunset(p, var, 0, 0);
6419 if (subtype == VSLENGTH) {
6420 cvtnum(varlen > 0 ? varlen : 0);
6424 if (subtype == VSNORMAL) {
6435 case VSTRIMRIGHTMAX:
6436 #if ENABLE_ASH_BASH_COMPAT
6449 * Terminate the string and start recording the pattern
6452 STPUTC('\0', expdest);
6453 patloc = expdest - (char *)stackblock();
6454 if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6456 /* quotes: */ flag & (EXP_FULL | EXP_CASE),
6459 int amount = expdest - (
6460 (char *)stackblock() + patloc - 1
6462 STADJUST(-amount, expdest);
6464 /* Remove any recorded regions beyond start of variable */
6465 removerecordregions(startloc);
6467 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6471 if (subtype != VSNORMAL) { /* skip to end of alternative */
6477 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6479 argbackq = argbackq->next;
6480 } else if (c == CTLVAR) {
6481 if ((*p++ & VSTYPE) != VSNORMAL)
6483 } else if (c == CTLENDVAR) {
6493 * Break the argument string into pieces based upon IFS and add the
6494 * strings to the argument list. The regions of the string to be
6495 * searched for IFS characters have been stored by recordregion.
6498 ifsbreakup(char *string, struct arglist *arglist)
6500 struct ifsregion *ifsp;
6505 const char *ifs, *realifs;
6510 if (ifslastp != NULL) {
6513 realifs = ifsset() ? ifsval() : defifs;
6516 p = string + ifsp->begoff;
6517 nulonly = ifsp->nulonly;
6518 ifs = nulonly ? nullstr : realifs;
6520 while (p < string + ifsp->endoff) {
6524 if (!strchr(ifs, *p)) {
6529 ifsspc = (strchr(defifs, *p) != NULL);
6530 /* Ignore IFS whitespace at start */
6531 if (q == start && ifsspc) {
6537 sp = stzalloc(sizeof(*sp));
6539 *arglist->lastp = sp;
6540 arglist->lastp = &sp->next;
6544 if (p >= string + ifsp->endoff) {
6550 if (strchr(ifs, *p) == NULL) {
6554 if (strchr(defifs, *p) == NULL) {
6569 } while (ifsp != NULL);
6578 sp = stzalloc(sizeof(*sp));
6580 *arglist->lastp = sp;
6581 arglist->lastp = &sp->next;
6587 struct ifsregion *p;
6592 struct ifsregion *ifsp;
6598 ifsfirst.next = NULL;
6603 * Add a file name to the list.
6606 addfname(const char *name)
6610 sp = stzalloc(sizeof(*sp));
6611 sp->text = ststrdup(name);
6613 exparg.lastp = &sp->next;
6616 static char *expdir;
6619 * Do metacharacter (i.e. *, ?, [...]) expansion.
6622 expmeta(char *enddir, char *name)
6637 for (p = name; *p; p++) {
6638 if (*p == '*' || *p == '?')
6640 else if (*p == '[') {
6647 if (*q == '/' || *q == '\0')
6654 } else if (*p == '\\')
6656 else if (*p == '/') {
6663 if (metaflag == 0) { /* we've reached the end of the file name */
6664 if (enddir != expdir)
6672 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6683 } while (p < start);
6685 if (enddir == expdir) {
6687 } else if (enddir == expdir + 1 && *expdir == '/') {
6696 if (enddir != expdir)
6698 if (*endname == 0) {
6710 while (!intpending && (dp = readdir(dirp)) != NULL) {
6711 if (dp->d_name[0] == '.' && !matchdot)
6713 if (pmatch(start, dp->d_name)) {
6715 strcpy(enddir, dp->d_name);
6718 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6721 expmeta(p, endname);
6730 static struct strlist *
6731 msort(struct strlist *list, int len)
6733 struct strlist *p, *q = NULL;
6734 struct strlist **lpp;
6742 for (n = half; --n >= 0;) {
6746 q->next = NULL; /* terminate first half of list */
6747 q = msort(list, half); /* sort first half of list */
6748 p = msort(p, len - half); /* sort second half */
6751 #if ENABLE_LOCALE_SUPPORT
6752 if (strcoll(p->text, q->text) < 0)
6754 if (strcmp(p->text, q->text) < 0)
6778 * Sort the results of file name expansion. It calculates the number of
6779 * strings to sort and then calls msort (short for merge sort) to do the
6782 static struct strlist *
6783 expsort(struct strlist *str)
6789 for (sp = str; sp; sp = sp->next)
6791 return msort(str, len);
6795 expandmeta(struct strlist *str /*, int flag*/)
6797 static const char metachars[] ALIGN1 = {
6800 /* TODO - EXP_REDIR */
6803 struct strlist **savelastp;
6809 if (!strpbrk(str->text, metachars))
6811 savelastp = exparg.lastp;
6814 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
6816 int i = strlen(str->text);
6817 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
6825 if (exparg.lastp == savelastp) {
6830 *exparg.lastp = str;
6831 rmescapes(str->text);
6832 exparg.lastp = &str->next;
6834 *exparg.lastp = NULL;
6835 *savelastp = sp = expsort(*savelastp);
6836 while (sp->next != NULL)
6838 exparg.lastp = &sp->next;
6845 * Perform variable substitution and command substitution on an argument,
6846 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6847 * perform splitting and file name expansion. When arglist is NULL, perform
6848 * here document expansion.
6851 expandarg(union node *arg, struct arglist *arglist, int flag)
6856 argbackq = arg->narg.backquote;
6857 STARTSTACKSTR(expdest);
6858 ifsfirst.next = NULL;
6860 argstr(arg->narg.text, flag,
6861 /* var_str_list: */ arglist ? arglist->list : NULL);
6862 p = _STPUTC('\0', expdest);
6864 if (arglist == NULL) {
6865 return; /* here document expanded */
6867 p = grabstackstr(p);
6868 exparg.lastp = &exparg.list;
6872 if (flag & EXP_FULL) {
6873 ifsbreakup(p, &exparg);
6874 *exparg.lastp = NULL;
6875 exparg.lastp = &exparg.list;
6876 expandmeta(exparg.list /*, flag*/);
6878 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
6880 sp = stzalloc(sizeof(*sp));
6883 exparg.lastp = &sp->next;
6887 *exparg.lastp = NULL;
6889 *arglist->lastp = exparg.list;
6890 arglist->lastp = exparg.lastp;
6895 * Expand shell variables and backquotes inside a here document.
6898 expandhere(union node *arg, int fd)
6901 expandarg(arg, (struct arglist *)NULL, 0);
6902 full_write(fd, stackblock(), expdest - (char *)stackblock());
6906 * Returns true if the pattern matches the string.
6909 patmatch(char *pattern, const char *string)
6911 return pmatch(preglob(pattern, 0, 0), string);
6915 * See if a pattern matches in a case statement.
6918 casematch(union node *pattern, char *val)
6920 struct stackmark smark;
6923 setstackmark(&smark);
6924 argbackq = pattern->narg.backquote;
6925 STARTSTACKSTR(expdest);
6927 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
6928 /* var_str_list: */ NULL);
6929 STACKSTRNUL(expdest);
6930 result = patmatch(stackblock(), val);
6931 popstackmark(&smark);
6936 /* ============ find_command */
6940 int (*builtin)(int, char **);
6941 /* unsigned flags; */
6943 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
6944 /* "regular" builtins always take precedence over commands,
6945 * regardless of PATH=....%builtin... position */
6946 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
6947 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
6950 smallint cmdtype; /* CMDxxx */
6953 /* index >= 0 for commands without path (slashes) */
6954 /* (TODO: what exactly does the value mean? PATH position?) */
6955 /* index == -1 for commands with slashes */
6956 /* index == (-2 - applet_no) for NOFORK applets */
6957 const struct builtincmd *cmd;
6958 struct funcnode *func;
6961 /* values of cmdtype */
6962 #define CMDUNKNOWN -1 /* no entry in table for command */
6963 #define CMDNORMAL 0 /* command is an executable program */
6964 #define CMDFUNCTION 1 /* command is a shell function */
6965 #define CMDBUILTIN 2 /* command is a shell builtin */
6967 /* action to find_command() */
6968 #define DO_ERR 0x01 /* prints errors */
6969 #define DO_ABS 0x02 /* checks absolute paths */
6970 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
6971 #define DO_ALTPATH 0x08 /* using alternate path */
6972 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
6974 static void find_command(char *, struct cmdentry *, int, const char *);
6977 /* ============ Hashing commands */
6980 * When commands are first encountered, they are entered in a hash table.
6981 * This ensures that a full path search will not have to be done for them
6982 * on each invocation.
6984 * We should investigate converting to a linear search, even though that
6985 * would make the command name "hash" a misnomer.
6989 struct tblentry *next; /* next entry in hash chain */
6990 union param param; /* definition of builtin function */
6991 smallint cmdtype; /* CMDxxx */
6992 char rehash; /* if set, cd done since entry created */
6993 char cmdname[1]; /* name of command */
6996 static struct tblentry **cmdtable;
6997 #define INIT_G_cmdtable() do { \
6998 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7001 static int builtinloc = -1; /* index in path of %builtin, or -1 */
7005 tryexec(USE_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
7009 #if ENABLE_FEATURE_SH_STANDALONE
7010 if (applet_no >= 0) {
7011 if (APPLET_IS_NOEXEC(applet_no)) {
7014 run_applet_no_and_exit(applet_no, argv);
7016 /* re-exec ourselves with the new arguments */
7017 execve(bb_busybox_exec_path, argv, envp);
7018 /* If they called chroot or otherwise made the binary no longer
7019 * executable, fall through */
7026 execve(cmd, argv, envp);
7027 } while (errno == EINTR);
7029 execve(cmd, argv, envp);
7035 if (errno == ENOEXEC) {
7039 for (ap = argv; *ap; ap++)
7041 ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0]));
7043 ap[0] = cmd = (char *)DEFAULT_SHELL;
7046 while ((*ap++ = *argv++) != NULL)
7055 * Exec a program. Never returns. If you change this routine, you may
7056 * have to change the find_command routine as well.
7058 static void shellexec(char **, const char *, int) NORETURN;
7060 shellexec(char **argv, const char *path, int idx)
7066 #if ENABLE_FEATURE_SH_STANDALONE
7070 clearredir(/*drop:*/ 1);
7071 envp = listvars(VEXPORT, VUNSET, 0);
7072 if (strchr(argv[0], '/') != NULL
7073 #if ENABLE_FEATURE_SH_STANDALONE
7074 || (applet_no = find_applet_by_name(argv[0])) >= 0
7077 tryexec(USE_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7081 while ((cmdname = padvance(&path, argv[0])) != NULL) {
7082 if (--idx < 0 && pathopt == NULL) {
7083 tryexec(USE_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7084 if (errno != ENOENT && errno != ENOTDIR)
7091 /* Map to POSIX errors */
7103 exitstatus = exerrno;
7104 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
7105 argv[0], e, suppressint));
7106 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7111 printentry(struct tblentry *cmdp)
7117 idx = cmdp->param.index;
7120 name = padvance(&path, cmdp->cmdname);
7122 } while (--idx >= 0);
7123 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7127 * Clear out command entries. The argument specifies the first entry in
7128 * PATH which has changed.
7131 clearcmdentry(int firstchange)
7133 struct tblentry **tblp;
7134 struct tblentry **pp;
7135 struct tblentry *cmdp;
7138 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7140 while ((cmdp = *pp) != NULL) {
7141 if ((cmdp->cmdtype == CMDNORMAL &&
7142 cmdp->param.index >= firstchange)
7143 || (cmdp->cmdtype == CMDBUILTIN &&
7144 builtinloc >= firstchange)
7157 * Locate a command in the command hash table. If "add" is nonzero,
7158 * add the command to the table if it is not already present. The
7159 * variable "lastcmdentry" is set to point to the address of the link
7160 * pointing to the entry, so that delete_cmd_entry can delete the
7163 * Interrupts must be off if called with add != 0.
7165 static struct tblentry **lastcmdentry;
7167 static struct tblentry *
7168 cmdlookup(const char *name, int add)
7170 unsigned int hashval;
7172 struct tblentry *cmdp;
7173 struct tblentry **pp;
7176 hashval = (unsigned char)*p << 4;
7178 hashval += (unsigned char)*p++;
7180 pp = &cmdtable[hashval % CMDTABLESIZE];
7181 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7182 if (strcmp(cmdp->cmdname, name) == 0)
7186 if (add && cmdp == NULL) {
7187 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7189 /* + 1 - already done because
7190 * tblentry::cmdname is char[1] */);
7191 /*cmdp->next = NULL; - ckzalloc did it */
7192 cmdp->cmdtype = CMDUNKNOWN;
7193 strcpy(cmdp->cmdname, name);
7200 * Delete the command entry returned on the last lookup.
7203 delete_cmd_entry(void)
7205 struct tblentry *cmdp;
7208 cmdp = *lastcmdentry;
7209 *lastcmdentry = cmdp->next;
7210 if (cmdp->cmdtype == CMDFUNCTION)
7211 freefunc(cmdp->param.func);
7217 * Add a new command entry, replacing any existing command entry for
7218 * the same name - except special builtins.
7221 addcmdentry(char *name, struct cmdentry *entry)
7223 struct tblentry *cmdp;
7225 cmdp = cmdlookup(name, 1);
7226 if (cmdp->cmdtype == CMDFUNCTION) {
7227 freefunc(cmdp->param.func);
7229 cmdp->cmdtype = entry->cmdtype;
7230 cmdp->param = entry->u;
7235 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7237 struct tblentry **pp;
7238 struct tblentry *cmdp;
7240 struct cmdentry entry;
7243 if (nextopt("r") != '\0') {
7248 if (*argptr == NULL) {
7249 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7250 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7251 if (cmdp->cmdtype == CMDNORMAL)
7259 while ((name = *argptr) != NULL) {
7260 cmdp = cmdlookup(name, 0);
7262 && (cmdp->cmdtype == CMDNORMAL
7263 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7267 find_command(name, &entry, DO_ERR, pathval());
7268 if (entry.cmdtype == CMDUNKNOWN)
7276 * Called when a cd is done. Marks all commands so the next time they
7277 * are executed they will be rehashed.
7282 struct tblentry **pp;
7283 struct tblentry *cmdp;
7285 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7286 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7287 if (cmdp->cmdtype == CMDNORMAL
7288 || (cmdp->cmdtype == CMDBUILTIN
7289 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7299 * Fix command hash table when PATH changed.
7300 * Called before PATH is changed. The argument is the new value of PATH;
7301 * pathval() still returns the old value at this point.
7302 * Called with interrupts off.
7305 changepath(const char *new)
7313 firstchange = 9999; /* assume no change */
7319 if ((*old == '\0' && *new == ':')
7320 || (*old == ':' && *new == '\0'))
7322 old = new; /* ignore subsequent differences */
7326 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7332 if (builtinloc < 0 && idx_bltin >= 0)
7333 builtinloc = idx_bltin; /* zap builtins */
7334 if (builtinloc >= 0 && idx_bltin < 0)
7336 clearcmdentry(firstchange);
7337 builtinloc = idx_bltin;
7352 #define TENDBQUOTE 12
7369 typedef smallint token_id_t;
7371 /* first char is indicating which tokens mark the end of a list */
7372 static const char *const tokname_array[] = {
7386 #define KWDOFFSET 13
7387 /* the following are keywords */
7409 static char buf[16];
7412 //if (tok < TSEMI) return tokname_array[tok] + 1;
7413 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
7418 sprintf(buf + (tok >= TSEMI), "%s%c",
7419 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
7423 /* Wrapper around strcmp for qsort/bsearch/... */
7425 pstrcmp(const void *a, const void *b)
7427 return strcmp((char*) a, (*(char**) b) + 1);
7430 static const char *const *
7431 findkwd(const char *s)
7433 return bsearch(s, tokname_array + KWDOFFSET,
7434 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7435 sizeof(tokname_array[0]), pstrcmp);
7439 * Locate and print what a word is...
7442 describe_command(char *command, int describe_command_verbose)
7444 struct cmdentry entry;
7445 struct tblentry *cmdp;
7446 #if ENABLE_ASH_ALIAS
7447 const struct alias *ap;
7449 const char *path = pathval();
7451 if (describe_command_verbose) {
7455 /* First look at the keywords */
7456 if (findkwd(command)) {
7457 out1str(describe_command_verbose ? " is a shell keyword" : command);
7461 #if ENABLE_ASH_ALIAS
7462 /* Then look at the aliases */
7463 ap = lookupalias(command, 0);
7465 if (!describe_command_verbose) {
7470 out1fmt(" is an alias for %s", ap->val);
7474 /* Then check if it is a tracked alias */
7475 cmdp = cmdlookup(command, 0);
7477 entry.cmdtype = cmdp->cmdtype;
7478 entry.u = cmdp->param;
7480 /* Finally use brute force */
7481 find_command(command, &entry, DO_ABS, path);
7484 switch (entry.cmdtype) {
7486 int j = entry.u.index;
7492 p = padvance(&path, command);
7496 if (describe_command_verbose) {
7498 (cmdp ? " a tracked alias for" : nullstr), p
7507 if (describe_command_verbose) {
7508 out1str(" is a shell function");
7515 if (describe_command_verbose) {
7516 out1fmt(" is a %sshell builtin",
7517 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7518 "special " : nullstr
7526 if (describe_command_verbose) {
7527 out1str(": not found\n");
7532 outstr("\n", stdout);
7537 typecmd(int argc UNUSED_PARAM, char **argv)
7543 /* type -p ... ? (we don't bother checking for 'p') */
7544 if (argv[1] && argv[1][0] == '-') {
7549 err |= describe_command(argv[i++], verbose);
7554 #if ENABLE_ASH_CMDCMD
7556 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7564 while ((c = nextopt("pvV")) != '\0')
7566 verify |= VERIFY_VERBOSE;
7568 verify |= VERIFY_BRIEF;
7573 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7574 if (verify && (*argptr != NULL)) {
7575 return describe_command(*argptr, verify - VERIFY_BRIEF);
7583 /* ============ eval.c */
7585 static int funcblocksize; /* size of structures in function */
7586 static int funcstringsize; /* size of strings in node */
7587 static void *funcblock; /* block to allocate function from */
7588 static char *funcstring; /* block to allocate strings from */
7590 /* flags in argument to evaltree */
7591 #define EV_EXIT 01 /* exit after evaluating tree */
7592 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7593 #define EV_BACKCMD 04 /* command executing within back quotes */
7595 static const short nodesize[26] = {
7596 SHELL_ALIGN(sizeof(struct ncmd)),
7597 SHELL_ALIGN(sizeof(struct npipe)),
7598 SHELL_ALIGN(sizeof(struct nredir)),
7599 SHELL_ALIGN(sizeof(struct nredir)),
7600 SHELL_ALIGN(sizeof(struct nredir)),
7601 SHELL_ALIGN(sizeof(struct nbinary)),
7602 SHELL_ALIGN(sizeof(struct nbinary)),
7603 SHELL_ALIGN(sizeof(struct nbinary)),
7604 SHELL_ALIGN(sizeof(struct nif)),
7605 SHELL_ALIGN(sizeof(struct nbinary)),
7606 SHELL_ALIGN(sizeof(struct nbinary)),
7607 SHELL_ALIGN(sizeof(struct nfor)),
7608 SHELL_ALIGN(sizeof(struct ncase)),
7609 SHELL_ALIGN(sizeof(struct nclist)),
7610 SHELL_ALIGN(sizeof(struct narg)),
7611 SHELL_ALIGN(sizeof(struct narg)),
7612 SHELL_ALIGN(sizeof(struct nfile)),
7613 SHELL_ALIGN(sizeof(struct nfile)),
7614 SHELL_ALIGN(sizeof(struct nfile)),
7615 SHELL_ALIGN(sizeof(struct nfile)),
7616 SHELL_ALIGN(sizeof(struct nfile)),
7617 SHELL_ALIGN(sizeof(struct ndup)),
7618 SHELL_ALIGN(sizeof(struct ndup)),
7619 SHELL_ALIGN(sizeof(struct nhere)),
7620 SHELL_ALIGN(sizeof(struct nhere)),
7621 SHELL_ALIGN(sizeof(struct nnot)),
7624 static void calcsize(union node *n);
7627 sizenodelist(struct nodelist *lp)
7630 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7637 calcsize(union node *n)
7641 funcblocksize += nodesize[n->type];
7644 calcsize(n->ncmd.redirect);
7645 calcsize(n->ncmd.args);
7646 calcsize(n->ncmd.assign);
7649 sizenodelist(n->npipe.cmdlist);
7654 calcsize(n->nredir.redirect);
7655 calcsize(n->nredir.n);
7662 calcsize(n->nbinary.ch2);
7663 calcsize(n->nbinary.ch1);
7666 calcsize(n->nif.elsepart);
7667 calcsize(n->nif.ifpart);
7668 calcsize(n->nif.test);
7671 funcstringsize += strlen(n->nfor.var) + 1;
7672 calcsize(n->nfor.body);
7673 calcsize(n->nfor.args);
7676 calcsize(n->ncase.cases);
7677 calcsize(n->ncase.expr);
7680 calcsize(n->nclist.body);
7681 calcsize(n->nclist.pattern);
7682 calcsize(n->nclist.next);
7686 sizenodelist(n->narg.backquote);
7687 funcstringsize += strlen(n->narg.text) + 1;
7688 calcsize(n->narg.next);
7691 #if ENABLE_ASH_BASH_COMPAT
7698 calcsize(n->nfile.fname);
7699 calcsize(n->nfile.next);
7703 calcsize(n->ndup.vname);
7704 calcsize(n->ndup.next);
7708 calcsize(n->nhere.doc);
7709 calcsize(n->nhere.next);
7712 calcsize(n->nnot.com);
7718 nodeckstrdup(char *s)
7720 char *rtn = funcstring;
7722 strcpy(funcstring, s);
7723 funcstring += strlen(s) + 1;
7727 static union node *copynode(union node *);
7729 static struct nodelist *
7730 copynodelist(struct nodelist *lp)
7732 struct nodelist *start;
7733 struct nodelist **lpp;
7738 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7739 (*lpp)->n = copynode(lp->n);
7741 lpp = &(*lpp)->next;
7748 copynode(union node *n)
7755 funcblock = (char *) funcblock + nodesize[n->type];
7759 new->ncmd.redirect = copynode(n->ncmd.redirect);
7760 new->ncmd.args = copynode(n->ncmd.args);
7761 new->ncmd.assign = copynode(n->ncmd.assign);
7764 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7765 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
7770 new->nredir.redirect = copynode(n->nredir.redirect);
7771 new->nredir.n = copynode(n->nredir.n);
7778 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7779 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7782 new->nif.elsepart = copynode(n->nif.elsepart);
7783 new->nif.ifpart = copynode(n->nif.ifpart);
7784 new->nif.test = copynode(n->nif.test);
7787 new->nfor.var = nodeckstrdup(n->nfor.var);
7788 new->nfor.body = copynode(n->nfor.body);
7789 new->nfor.args = copynode(n->nfor.args);
7792 new->ncase.cases = copynode(n->ncase.cases);
7793 new->ncase.expr = copynode(n->ncase.expr);
7796 new->nclist.body = copynode(n->nclist.body);
7797 new->nclist.pattern = copynode(n->nclist.pattern);
7798 new->nclist.next = copynode(n->nclist.next);
7802 new->narg.backquote = copynodelist(n->narg.backquote);
7803 new->narg.text = nodeckstrdup(n->narg.text);
7804 new->narg.next = copynode(n->narg.next);
7807 #if ENABLE_ASH_BASH_COMPAT
7814 new->nfile.fname = copynode(n->nfile.fname);
7815 new->nfile.fd = n->nfile.fd;
7816 new->nfile.next = copynode(n->nfile.next);
7820 new->ndup.vname = copynode(n->ndup.vname);
7821 new->ndup.dupfd = n->ndup.dupfd;
7822 new->ndup.fd = n->ndup.fd;
7823 new->ndup.next = copynode(n->ndup.next);
7827 new->nhere.doc = copynode(n->nhere.doc);
7828 new->nhere.fd = n->nhere.fd;
7829 new->nhere.next = copynode(n->nhere.next);
7832 new->nnot.com = copynode(n->nnot.com);
7835 new->type = n->type;
7840 * Make a copy of a parse tree.
7842 static struct funcnode *
7843 copyfunc(union node *n)
7848 funcblocksize = offsetof(struct funcnode, n);
7851 blocksize = funcblocksize;
7852 f = ckmalloc(blocksize + funcstringsize);
7853 funcblock = (char *) f + offsetof(struct funcnode, n);
7854 funcstring = (char *) f + blocksize;
7861 * Define a shell function.
7864 defun(char *name, union node *func)
7866 struct cmdentry entry;
7869 entry.cmdtype = CMDFUNCTION;
7870 entry.u.func = copyfunc(func);
7871 addcmdentry(name, &entry);
7875 static int evalskip; /* set if we are skipping commands */
7876 /* reasons for skipping commands (see comment on breakcmd routine) */
7877 #define SKIPBREAK (1 << 0)
7878 #define SKIPCONT (1 << 1)
7879 #define SKIPFUNC (1 << 2)
7880 #define SKIPFILE (1 << 3)
7881 #define SKIPEVAL (1 << 4)
7882 static int skipcount; /* number of levels to skip */
7883 static int funcnest; /* depth of function calls */
7884 static int loopnest; /* current loop nesting level */
7886 /* forward decl way out to parsing code - dotrap needs it */
7887 static int evalstring(char *s, int mask);
7890 * Called to execute a trap. Perhaps we should avoid entering new trap
7891 * handlers while we are executing a trap handler.
7902 savestatus = exitstatus;
7906 for (i = 1, q = gotsig; i < NSIG; i++, q++) {
7914 skip = evalstring(p, SKIPEVAL);
7915 exitstatus = savestatus;
7923 /* forward declarations - evaluation is fairly recursive business... */
7924 static void evalloop(union node *, int);
7925 static void evalfor(union node *, int);
7926 static void evalcase(union node *, int);
7927 static void evalsubshell(union node *, int);
7928 static void expredir(union node *);
7929 static void evalpipe(union node *, int);
7930 static void evalcommand(union node *, int);
7931 static int evalbltin(const struct builtincmd *, int, char **);
7932 static void prehash(union node *);
7935 * Evaluate a parse tree. The value is left in the global variable
7939 evaltree(union node *n, int flags)
7942 struct jmploc *volatile savehandler = exception_handler;
7943 struct jmploc jmploc;
7945 void (*evalfn)(union node *, int);
7949 TRACE(("evaltree(NULL) called\n"));
7952 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
7953 getpid(), n, n->type, flags));
7955 exception_handler = &jmploc;
7957 int err = setjmp(jmploc.loc);
7959 /* if it was a signal, check for trap handlers */
7960 if (exception == EXSIG)
7962 /* continue on the way out */
7963 exception_handler = savehandler;
7964 longjmp(exception_handler->loc, err);
7971 out1fmt("Node type = %d\n", n->type);
7976 evaltree(n->nnot.com, EV_TESTED);
7977 status = !exitstatus;
7980 expredir(n->nredir.redirect);
7981 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
7983 evaltree(n->nredir.n, flags & EV_TESTED);
7984 status = exitstatus;
7986 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
7989 evalfn = evalcommand;
7991 if (eflag && !(flags & EV_TESTED))
8003 evalfn = evalsubshell;
8016 #error NAND + 1 != NOR
8018 #if NOR + 1 != NSEMI
8019 #error NOR + 1 != NSEMI
8021 unsigned is_or = n->type - NAND;
8024 (flags | ((is_or >> 1) - 1)) & EV_TESTED
8026 if (!exitstatus == is_or)
8039 evaltree(n->nif.test, EV_TESTED);
8042 if (exitstatus == 0) {
8045 } else if (n->nif.elsepart) {
8046 n = n->nif.elsepart;
8051 defun(n->narg.text, n->narg.next);
8055 exitstatus = status;
8060 exception_handler = savehandler;
8062 if (checkexit & exitstatus)
8063 evalskip |= SKIPEVAL;
8064 else if (pendingsig && dotrap())
8067 if (flags & EV_EXIT) {
8069 raise_exception(EXEXIT);
8073 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8076 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8079 evalloop(union node *n, int flags)
8089 evaltree(n->nbinary.ch1, EV_TESTED);
8092 if (evalskip == SKIPCONT && --skipcount <= 0) {
8096 if (evalskip == SKIPBREAK && --skipcount <= 0)
8101 if (n->type != NWHILE)
8105 evaltree(n->nbinary.ch2, flags);
8106 status = exitstatus;
8111 exitstatus = status;
8115 evalfor(union node *n, int flags)
8117 struct arglist arglist;
8120 struct stackmark smark;
8122 setstackmark(&smark);
8123 arglist.list = NULL;
8124 arglist.lastp = &arglist.list;
8125 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8126 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
8131 *arglist.lastp = NULL;
8136 for (sp = arglist.list; sp; sp = sp->next) {
8137 setvar(n->nfor.var, sp->text, 0);
8138 evaltree(n->nfor.body, flags);
8140 if (evalskip == SKIPCONT && --skipcount <= 0) {
8144 if (evalskip == SKIPBREAK && --skipcount <= 0)
8151 popstackmark(&smark);
8155 evalcase(union node *n, int flags)
8159 struct arglist arglist;
8160 struct stackmark smark;
8162 setstackmark(&smark);
8163 arglist.list = NULL;
8164 arglist.lastp = &arglist.list;
8165 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8167 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8168 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8169 if (casematch(patp, arglist.list->text)) {
8170 if (evalskip == 0) {
8171 evaltree(cp->nclist.body, flags);
8178 popstackmark(&smark);
8182 * Kick off a subshell to evaluate a tree.
8185 evalsubshell(union node *n, int flags)
8188 int backgnd = (n->type == NBACKGND);
8191 expredir(n->nredir.redirect);
8192 if (!backgnd && flags & EV_EXIT && !trap[0])
8195 jp = makejob(/*n,*/ 1);
8196 if (forkshell(jp, n, backgnd) == 0) {
8200 flags &=~ EV_TESTED;
8202 redirect(n->nredir.redirect, 0);
8203 evaltreenr(n->nredir.n, flags);
8208 status = waitforjob(jp);
8209 exitstatus = status;
8214 * Compute the names of the files in a redirection list.
8216 static void fixredir(union node *, const char *, int);
8218 expredir(union node *n)
8222 for (redir = n; redir; redir = redir->nfile.next) {
8226 fn.lastp = &fn.list;
8227 switch (redir->type) {
8231 #if ENABLE_ASH_BASH_COMPAT
8236 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8237 #if ENABLE_ASH_BASH_COMPAT
8240 redir->nfile.expfname = fn.list->text;
8243 case NTOFD: /* >& */
8244 if (redir->ndup.vname) {
8245 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8246 if (fn.list == NULL)
8247 ash_msg_and_raise_error("redir error");
8248 #if ENABLE_ASH_BASH_COMPAT
8249 //FIXME: we used expandarg with different args!
8250 if (!isdigit_str9(fn.list->text)) {
8251 /* >&file, not >&fd */
8252 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8253 ash_msg_and_raise_error("redir error");
8255 goto store_expfname;
8258 fixredir(redir, fn.list->text, 1);
8266 * Evaluate a pipeline. All the processes in the pipeline are children
8267 * of the process creating the pipeline. (This differs from some versions
8268 * of the shell, which make the last process in a pipeline the parent
8272 evalpipe(union node *n, int flags)
8275 struct nodelist *lp;
8280 TRACE(("evalpipe(0x%lx) called\n", (long)n));
8282 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8286 jp = makejob(/*n,*/ pipelen);
8288 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8292 if (pipe(pip) < 0) {
8294 ash_msg_and_raise_error("pipe call failed");
8297 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8310 evaltreenr(lp->n, flags);
8318 if (n->npipe.pipe_backgnd == 0) {
8319 exitstatus = waitforjob(jp);
8320 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
8326 * Controls whether the shell is interactive or not.
8329 setinteractive(int on)
8331 static smallint is_interactive;
8333 if (++on == is_interactive)
8335 is_interactive = on;
8339 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8340 if (is_interactive > 1) {
8341 /* Looks like they want an interactive shell */
8342 static smallint did_banner;
8347 "%s built-in shell (ash)\n"
8348 "Enter 'help' for a list of built-in commands."
8363 setinteractive(iflag);
8365 #if ENABLE_FEATURE_EDITING_VI
8367 line_input_state->flags |= VI_MODE;
8369 line_input_state->flags &= ~VI_MODE;
8371 viflag = 0; /* forcibly keep the option off */
8375 static struct localvar *localvars;
8378 * Called after a function returns.
8379 * Interrupts must be off.
8384 struct localvar *lvp;
8387 while ((lvp = localvars) != NULL) {
8388 localvars = lvp->next;
8390 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
8391 if (vp == NULL) { /* $- saved */
8392 memcpy(optlist, lvp->text, sizeof(optlist));
8393 free((char*)lvp->text);
8395 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8399 (*vp->func)(strchrnul(lvp->text, '=') + 1);
8400 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8401 free((char*)vp->text);
8402 vp->flags = lvp->flags;
8403 vp->text = lvp->text;
8410 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8412 volatile struct shparam saveparam;
8413 struct localvar *volatile savelocalvars;
8414 struct jmploc *volatile savehandler;
8415 struct jmploc jmploc;
8418 saveparam = shellparam;
8419 savelocalvars = localvars;
8420 e = setjmp(jmploc.loc);
8425 savehandler = exception_handler;
8426 exception_handler = &jmploc;
8428 shellparam.malloced = 0;
8432 shellparam.nparam = argc - 1;
8433 shellparam.p = argv + 1;
8434 #if ENABLE_ASH_GETOPTS
8435 shellparam.optind = 1;
8436 shellparam.optoff = -1;
8438 evaltree(&func->n, flags & EV_TESTED);
8444 localvars = savelocalvars;
8445 freeparam(&shellparam);
8446 shellparam = saveparam;
8447 exception_handler = savehandler;
8449 evalskip &= ~SKIPFUNC;
8453 #if ENABLE_ASH_CMDCMD
8455 parse_command_args(char **argv, const char **path)
8468 if (c == '-' && !*cp) {
8475 *path = bb_default_path;
8478 /* run 'typecmd' for other options */
8489 * Make a variable a local variable. When a variable is made local, it's
8490 * value and flags are saved in a localvar structure. The saved values
8491 * will be restored when the shell function returns. We handle the name
8492 * "-" as a special case.
8497 struct localvar *lvp;
8502 lvp = ckzalloc(sizeof(struct localvar));
8503 if (LONE_DASH(name)) {
8505 p = ckmalloc(sizeof(optlist));
8506 lvp->text = memcpy(p, optlist, sizeof(optlist));
8511 vpp = hashvar(name);
8512 vp = *findvar(vpp, name);
8513 eq = strchr(name, '=');
8516 setvareq(name, VSTRFIXED);
8518 setvar(name, NULL, VSTRFIXED);
8519 vp = *vpp; /* the new variable */
8520 lvp->flags = VUNSET;
8522 lvp->text = vp->text;
8523 lvp->flags = vp->flags;
8524 vp->flags |= VSTRFIXED|VTEXTFIXED;
8530 lvp->next = localvars;
8536 * The "local" command.
8539 localcmd(int argc UNUSED_PARAM, char **argv)
8544 while ((name = *argv++) != NULL) {
8551 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8557 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8563 execcmd(int argc UNUSED_PARAM, char **argv)
8566 iflag = 0; /* exit on error */
8569 shellexec(argv + 1, pathval(), 0);
8575 * The return command.
8578 returncmd(int argc UNUSED_PARAM, char **argv)
8581 * If called outside a function, do what ksh does;
8582 * skip the rest of the file.
8584 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8585 return argv[1] ? number(argv[1]) : exitstatus;
8588 /* Forward declarations for builtintab[] */
8589 static int breakcmd(int, char **);
8590 static int dotcmd(int, char **);
8591 static int evalcmd(int, char **);
8592 static int exitcmd(int, char **);
8593 static int exportcmd(int, char **);
8594 #if ENABLE_ASH_GETOPTS
8595 static int getoptscmd(int, char **);
8597 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8598 static int helpcmd(int, char **);
8600 #if ENABLE_ASH_MATH_SUPPORT
8601 static int letcmd(int, char **);
8603 static int readcmd(int, char **);
8604 static int setcmd(int, char **);
8605 static int shiftcmd(int, char **);
8606 static int timescmd(int, char **);
8607 static int trapcmd(int, char **);
8608 static int umaskcmd(int, char **);
8609 static int unsetcmd(int, char **);
8610 static int ulimitcmd(int, char **);
8612 #define BUILTIN_NOSPEC "0"
8613 #define BUILTIN_SPECIAL "1"
8614 #define BUILTIN_REGULAR "2"
8615 #define BUILTIN_SPEC_REG "3"
8616 #define BUILTIN_ASSIGN "4"
8617 #define BUILTIN_SPEC_ASSG "5"
8618 #define BUILTIN_REG_ASSG "6"
8619 #define BUILTIN_SPEC_REG_ASSG "7"
8621 /* We do not handle [[ expr ]] bashism bash-compatibly,
8622 * we make it a synonym of [ expr ].
8623 * Basically, word splitting and pathname expansion should NOT be performed
8625 * no word splitting: a="a b"; [[ $a = "a b" ]]; echo $? should print "0"
8626 * no pathname expansion: [[ /bin/m* = "/bin/m*" ]]; echo $? should print "0"
8627 * Additional operators:
8628 * || and && should work as -o and -a
8630 * Apart from the above, [[ expr ]] should work as [ expr ]
8633 #define echocmd echo_main
8634 #define printfcmd printf_main
8635 #define testcmd test_main
8637 /* Keep these in proper order since it is searched via bsearch() */
8638 static const struct builtincmd builtintab[] = {
8639 { BUILTIN_SPEC_REG ".", dotcmd },
8640 { BUILTIN_SPEC_REG ":", truecmd },
8641 #if ENABLE_ASH_BUILTIN_TEST
8642 { BUILTIN_REGULAR "[", testcmd },
8643 #if ENABLE_ASH_BASH_COMPAT
8644 { BUILTIN_REGULAR "[[", testcmd },
8647 #if ENABLE_ASH_ALIAS
8648 { BUILTIN_REG_ASSG "alias", aliascmd },
8651 { BUILTIN_REGULAR "bg", fg_bgcmd },
8653 { BUILTIN_SPEC_REG "break", breakcmd },
8654 { BUILTIN_REGULAR "cd", cdcmd },
8655 { BUILTIN_NOSPEC "chdir", cdcmd },
8656 #if ENABLE_ASH_CMDCMD
8657 { BUILTIN_REGULAR "command", commandcmd },
8659 { BUILTIN_SPEC_REG "continue", breakcmd },
8660 #if ENABLE_ASH_BUILTIN_ECHO
8661 { BUILTIN_REGULAR "echo", echocmd },
8663 { BUILTIN_SPEC_REG "eval", evalcmd },
8664 { BUILTIN_SPEC_REG "exec", execcmd },
8665 { BUILTIN_SPEC_REG "exit", exitcmd },
8666 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8667 { BUILTIN_REGULAR "false", falsecmd },
8669 { BUILTIN_REGULAR "fg", fg_bgcmd },
8671 #if ENABLE_ASH_GETOPTS
8672 { BUILTIN_REGULAR "getopts", getoptscmd },
8674 { BUILTIN_NOSPEC "hash", hashcmd },
8675 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8676 { BUILTIN_NOSPEC "help", helpcmd },
8679 { BUILTIN_REGULAR "jobs", jobscmd },
8680 { BUILTIN_REGULAR "kill", killcmd },
8682 #if ENABLE_ASH_MATH_SUPPORT
8683 { BUILTIN_NOSPEC "let", letcmd },
8685 { BUILTIN_ASSIGN "local", localcmd },
8686 #if ENABLE_ASH_BUILTIN_PRINTF
8687 { BUILTIN_REGULAR "printf", printfcmd },
8689 { BUILTIN_NOSPEC "pwd", pwdcmd },
8690 { BUILTIN_REGULAR "read", readcmd },
8691 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8692 { BUILTIN_SPEC_REG "return", returncmd },
8693 { BUILTIN_SPEC_REG "set", setcmd },
8694 { BUILTIN_SPEC_REG "shift", shiftcmd },
8695 { BUILTIN_SPEC_REG "source", dotcmd },
8696 #if ENABLE_ASH_BUILTIN_TEST
8697 { BUILTIN_REGULAR "test", testcmd },
8699 { BUILTIN_SPEC_REG "times", timescmd },
8700 { BUILTIN_SPEC_REG "trap", trapcmd },
8701 { BUILTIN_REGULAR "true", truecmd },
8702 { BUILTIN_NOSPEC "type", typecmd },
8703 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
8704 { BUILTIN_REGULAR "umask", umaskcmd },
8705 #if ENABLE_ASH_ALIAS
8706 { BUILTIN_REGULAR "unalias", unaliascmd },
8708 { BUILTIN_SPEC_REG "unset", unsetcmd },
8709 { BUILTIN_REGULAR "wait", waitcmd },
8712 /* Should match the above table! */
8713 #define COMMANDCMD (builtintab + \
8715 1 * ENABLE_ASH_BUILTIN_TEST + \
8716 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8717 1 * ENABLE_ASH_ALIAS + \
8718 1 * ENABLE_ASH_JOB_CONTROL + \
8720 #define EXECCMD (builtintab + \
8722 1 * ENABLE_ASH_BUILTIN_TEST + \
8723 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8724 1 * ENABLE_ASH_ALIAS + \
8725 1 * ENABLE_ASH_JOB_CONTROL + \
8727 1 * ENABLE_ASH_CMDCMD + \
8729 ENABLE_ASH_BUILTIN_ECHO + \
8733 * Search the table of builtin commands.
8735 static struct builtincmd *
8736 find_builtin(const char *name)
8738 struct builtincmd *bp;
8741 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8748 * Execute a simple command.
8751 isassignment(const char *p)
8753 const char *q = endofname(p);
8759 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8761 /* Preserve exitstatus of a previous possible redirection
8762 * as POSIX mandates */
8763 return back_exitstatus;
8766 evalcommand(union node *cmd, int flags)
8768 static const struct builtincmd null_bltin = {
8769 "\0\0", bltincmd /* why three NULs? */
8771 struct stackmark smark;
8773 struct arglist arglist;
8774 struct arglist varlist;
8777 const struct strlist *sp;
8778 struct cmdentry cmdentry;
8785 struct builtincmd *bcmd;
8786 smallint cmd_is_exec;
8787 smallint pseudovarflag = 0;
8789 /* First expand the arguments. */
8790 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8791 setstackmark(&smark);
8792 back_exitstatus = 0;
8794 cmdentry.cmdtype = CMDBUILTIN;
8795 cmdentry.u.cmd = &null_bltin;
8796 varlist.lastp = &varlist.list;
8797 *varlist.lastp = NULL;
8798 arglist.lastp = &arglist.list;
8799 *arglist.lastp = NULL;
8802 if (cmd->ncmd.args) {
8803 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8804 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8807 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8808 struct strlist **spp;
8810 spp = arglist.lastp;
8811 if (pseudovarflag && isassignment(argp->narg.text))
8812 expandarg(argp, &arglist, EXP_VARTILDE);
8814 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8816 for (sp = *spp; sp; sp = sp->next)
8820 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8821 for (sp = arglist.list; sp; sp = sp->next) {
8822 TRACE(("evalcommand arg: %s\n", sp->text));
8823 *nargv++ = sp->text;
8828 if (iflag && funcnest == 0 && argc > 0)
8829 lastarg = nargv[-1];
8832 expredir(cmd->ncmd.redirect);
8833 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8836 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8837 struct strlist **spp;
8840 spp = varlist.lastp;
8841 expandarg(argp, &varlist, EXP_VARTILDE);
8844 * Modify the command lookup path, if a PATH= assignment
8848 if (varequal(p, path))
8852 /* Print the command if xflag is set. */
8855 const char *p = " %s";
8858 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8861 for (n = 0; n < 2; n++) {
8863 fdprintf(preverrout_fd, p, sp->text);
8871 safe_write(preverrout_fd, "\n", 1);
8877 /* Now locate the command. */
8879 const char *oldpath;
8880 int cmd_flag = DO_ERR;
8885 find_command(argv[0], &cmdentry, cmd_flag, path);
8886 if (cmdentry.cmdtype == CMDUNKNOWN) {
8892 /* implement bltin and command here */
8893 if (cmdentry.cmdtype != CMDBUILTIN)
8896 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8897 if (cmdentry.u.cmd == EXECCMD)
8899 #if ENABLE_ASH_CMDCMD
8900 if (cmdentry.u.cmd == COMMANDCMD) {
8902 nargv = parse_command_args(argv, &path);
8905 argc -= nargv - argv;
8907 cmd_flag |= DO_NOFUNC;
8915 /* We have a redirection error. */
8917 raise_exception(EXERROR);
8919 exitstatus = status;
8923 /* Execute the command. */
8924 switch (cmdentry.cmdtype) {
8926 #if ENABLE_FEATURE_SH_NOFORK
8928 /* find_command() encodes applet_no as (-2 - applet_no) */
8929 int applet_no = (- cmdentry.u.index - 2);
8930 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
8931 listsetvar(varlist.list, VEXPORT|VSTACK);
8932 /* run <applet>_main() */
8933 exitstatus = run_nofork_applet(applet_no, argv);
8939 /* Fork off a child process if necessary. */
8940 if (!(flags & EV_EXIT) || trap[0]) {
8942 jp = makejob(/*cmd,*/ 1);
8943 if (forkshell(jp, cmd, FORK_FG) != 0) {
8944 exitstatus = waitforjob(jp);
8950 listsetvar(varlist.list, VEXPORT|VSTACK);
8951 shellexec(argv, path, cmdentry.u.index);
8955 cmdenviron = varlist.list;
8957 struct strlist *list = cmdenviron;
8959 if (spclbltin > 0 || argc == 0) {
8961 if (cmd_is_exec && argc > 1)
8964 listsetvar(list, i);
8966 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
8973 exit_status = 128 + SIGINT;
8975 exit_status = 128 + pendingsig;
8976 exitstatus = exit_status;
8977 if (i == EXINT || spclbltin > 0) {
8979 longjmp(exception_handler->loc, 1);
8986 listsetvar(varlist.list, 0);
8987 if (evalfun(cmdentry.u.func, argc, argv, flags))
8993 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
8995 /* dsl: I think this is intended to be used to support
8996 * '_' in 'vi' command mode during line editing...
8997 * However I implemented that within libedit itself.
8999 setvar("_", lastarg, 0);
9001 popstackmark(&smark);
9005 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9007 char *volatile savecmdname;
9008 struct jmploc *volatile savehandler;
9009 struct jmploc jmploc;
9012 savecmdname = commandname;
9013 i = setjmp(jmploc.loc);
9016 savehandler = exception_handler;
9017 exception_handler = &jmploc;
9018 commandname = argv[0];
9020 optptr = NULL; /* initialize nextopt */
9021 exitstatus = (*cmd->builtin)(argc, argv);
9022 flush_stdout_stderr();
9024 exitstatus |= ferror(stdout);
9026 commandname = savecmdname;
9028 exception_handler = savehandler;
9034 goodname(const char *p)
9036 return !*endofname(p);
9041 * Search for a command. This is called before we fork so that the
9042 * location of the command will be available in the parent as well as
9043 * the child. The check for "goodname" is an overly conservative
9044 * check that the name will not be subject to expansion.
9047 prehash(union node *n)
9049 struct cmdentry entry;
9051 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9052 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9056 /* ============ Builtin commands
9058 * Builtin commands whose functions are closely tied to evaluation
9059 * are implemented here.
9063 * Handle break and continue commands. Break, continue, and return are
9064 * all handled by setting the evalskip flag. The evaluation routines
9065 * above all check this flag, and if it is set they start skipping
9066 * commands rather than executing them. The variable skipcount is
9067 * the number of loops to break/continue, or the number of function
9068 * levels to return. (The latter is always 1.) It should probably
9069 * be an error to break out of more loops than exist, but it isn't
9070 * in the standard shell so we don't make it one here.
9073 breakcmd(int argc UNUSED_PARAM, char **argv)
9075 int n = argv[1] ? number(argv[1]) : 1;
9078 ash_msg_and_raise_error(illnum, argv[1]);
9082 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9089 /* ============ input.c
9091 * This implements the input routines used by the parser.
9094 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
9097 INPUT_PUSH_FILE = 1,
9098 INPUT_NOFILE_OK = 2,
9101 static int plinno = 1; /* input line number */
9102 /* number of characters left in input buffer */
9103 static int parsenleft; /* copy of parsefile->nleft */
9104 static int parselleft; /* copy of parsefile->lleft */
9105 /* next character in input buffer */
9106 static char *parsenextc; /* copy of parsefile->nextc */
9108 static smallint checkkwd;
9109 /* values of checkkwd variable */
9110 #define CHKALIAS 0x1
9117 struct strpush *sp = g_parsefile->strpush;
9120 #if ENABLE_ASH_ALIAS
9122 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
9123 checkkwd |= CHKALIAS;
9125 if (sp->string != sp->ap->val) {
9128 sp->ap->flag &= ~ALIASINUSE;
9129 if (sp->ap->flag & ALIASDEAD) {
9130 unalias(sp->ap->name);
9134 parsenextc = sp->prevstring;
9135 parsenleft = sp->prevnleft;
9136 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
9137 g_parsefile->strpush = sp->prev;
9138 if (sp != &(g_parsefile->basestrpush))
9147 char *buf = g_parsefile->buf;
9150 #if ENABLE_FEATURE_EDITING
9152 if (!iflag || g_parsefile->fd)
9153 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9155 #if ENABLE_FEATURE_TAB_COMPLETION
9156 line_input_state->path_lookup = pathval();
9158 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
9160 /* Ctrl+C pressed */
9169 if (nr < 0 && errno == 0) {
9170 /* Ctrl+D pressed */
9175 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9179 /* nonblock_safe_read() handles this problem */
9181 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9182 int flags = fcntl(0, F_GETFL);
9183 if (flags >= 0 && (flags & O_NONBLOCK)) {
9184 flags &= ~O_NONBLOCK;
9185 if (fcntl(0, F_SETFL, flags) >= 0) {
9186 out2str("sh: turning off NDELAY mode\n");
9197 * Refill the input buffer and return the next input character:
9199 * 1) If a string was pushed back on the input, pop it;
9200 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
9201 * from a string so we can't refill the buffer, return EOF.
9202 * 3) If the is more stuff in this buffer, use it else call read to fill it.
9203 * 4) Process input up to the next newline, deleting nul characters.
9212 while (g_parsefile->strpush) {
9213 #if ENABLE_ASH_ALIAS
9214 if (parsenleft == -1 && g_parsefile->strpush->ap &&
9215 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
9220 if (--parsenleft >= 0)
9221 return signed_char2int(*parsenextc++);
9223 if (parsenleft == EOF_NLEFT || g_parsefile->buf == NULL)
9225 flush_stdout_stderr();
9232 parselleft = parsenleft = EOF_NLEFT;
9239 /* delete nul characters */
9247 memmove(q, q + 1, more);
9251 parsenleft = q - parsenextc - 1;
9257 parsenleft = q - parsenextc - 1;
9269 out2str(parsenextc);
9274 return signed_char2int(*parsenextc++);
9277 #define pgetc_as_macro() (--parsenleft >= 0 ? signed_char2int(*parsenextc++) : preadbuffer())
9281 return pgetc_as_macro();
9284 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9285 #define pgetc_fast() pgetc()
9287 #define pgetc_fast() pgetc_as_macro()
9291 * Same as pgetc(), but ignores PEOA.
9293 #if ENABLE_ASH_ALIAS
9300 } while (c == PEOA);
9304 #define pgetc2() pgetc()
9308 * Read a line from the script.
9311 pfgets(char *line, int len)
9317 while (--nleft > 0) {
9333 * Undo the last call to pgetc. Only one character may be pushed back.
9334 * PEOF may be pushed back.
9344 * Push a string back onto the input at this current parsefile level.
9345 * We handle aliases this way.
9347 #if !ENABLE_ASH_ALIAS
9348 #define pushstring(s, ap) pushstring(s)
9351 pushstring(char *s, struct alias *ap)
9358 if (g_parsefile->strpush) {
9359 sp = ckzalloc(sizeof(struct strpush));
9360 sp->prev = g_parsefile->strpush;
9361 g_parsefile->strpush = sp;
9363 sp = g_parsefile->strpush = &(g_parsefile->basestrpush);
9364 sp->prevstring = parsenextc;
9365 sp->prevnleft = parsenleft;
9366 #if ENABLE_ASH_ALIAS
9369 ap->flag |= ALIASINUSE;
9379 * To handle the "." command, a stack of input files is used. Pushfile
9380 * adds a new entry to the stack and popfile restores the previous level.
9385 struct parsefile *pf;
9387 g_parsefile->nleft = parsenleft;
9388 g_parsefile->lleft = parselleft;
9389 g_parsefile->nextc = parsenextc;
9390 g_parsefile->linno = plinno;
9391 pf = ckzalloc(sizeof(*pf));
9392 pf->prev = g_parsefile;
9394 /*pf->strpush = NULL; - ckzalloc did it */
9395 /*pf->basestrpush.prev = NULL;*/
9402 struct parsefile *pf = g_parsefile;
9410 g_parsefile = pf->prev;
9412 parsenleft = g_parsefile->nleft;
9413 parselleft = g_parsefile->lleft;
9414 parsenextc = g_parsefile->nextc;
9415 plinno = g_parsefile->linno;
9420 * Return to top level.
9425 while (g_parsefile != &basepf)
9430 * Close the file(s) that the shell is reading commands from. Called
9431 * after a fork is done.
9437 if (g_parsefile->fd > 0) {
9438 close(g_parsefile->fd);
9439 g_parsefile->fd = 0;
9444 * Like setinputfile, but takes an open file descriptor. Call this with
9448 setinputfd(int fd, int push)
9450 close_on_exec_on(fd);
9453 g_parsefile->buf = 0;
9455 g_parsefile->fd = fd;
9456 if (g_parsefile->buf == NULL)
9457 g_parsefile->buf = ckmalloc(IBUFSIZ);
9458 parselleft = parsenleft = 0;
9463 * Set the input to take input from a file. If push is set, push the
9464 * old input onto the stack first.
9467 setinputfile(const char *fname, int flags)
9473 fd = open(fname, O_RDONLY);
9475 if (flags & INPUT_NOFILE_OK)
9477 ash_msg_and_raise_error("can't open %s", fname);
9480 fd2 = copyfd(fd, 10);
9483 ash_msg_and_raise_error("out of file descriptors");
9486 setinputfd(fd, flags & INPUT_PUSH_FILE);
9493 * Like setinputfile, but takes input from a string.
9496 setinputstring(char *string)
9500 parsenextc = string;
9501 parsenleft = strlen(string);
9502 g_parsefile->buf = NULL;
9508 /* ============ mail.c
9510 * Routines to check for mail.
9515 #define MAXMBOXES 10
9517 /* times of mailboxes */
9518 static time_t mailtime[MAXMBOXES];
9519 /* Set if MAIL or MAILPATH is changed. */
9520 static smallint mail_var_path_changed;
9523 * Print appropriate message(s) if mail has arrived.
9524 * If mail_var_path_changed is set,
9525 * then the value of MAIL has mail_var_path_changed,
9526 * so we just update the values.
9535 struct stackmark smark;
9538 setstackmark(&smark);
9539 mpath = mpathset() ? mpathval() : mailval();
9540 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9541 p = padvance(&mpath, nullstr);
9546 for (q = p; *q; q++)
9552 q[-1] = '\0'; /* delete trailing '/' */
9553 if (stat(p, &statb) < 0) {
9557 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9560 pathopt ? pathopt : "you have mail"
9563 *mtp = statb.st_mtime;
9565 mail_var_path_changed = 0;
9566 popstackmark(&smark);
9570 changemail(const char *val UNUSED_PARAM)
9572 mail_var_path_changed = 1;
9575 #endif /* ASH_MAIL */
9578 /* ============ ??? */
9581 * Set the shell parameters.
9584 setparam(char **argv)
9590 for (nparam = 0; argv[nparam]; nparam++)
9592 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9594 *ap++ = ckstrdup(*argv++);
9597 freeparam(&shellparam);
9598 shellparam.malloced = 1;
9599 shellparam.nparam = nparam;
9600 shellparam.p = newparam;
9601 #if ENABLE_ASH_GETOPTS
9602 shellparam.optind = 1;
9603 shellparam.optoff = -1;
9608 * Process shell options. The global variable argptr contains a pointer
9609 * to the argument list; we advance it past the options.
9611 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9612 * For a non-interactive shell, an error condition encountered
9613 * by a special built-in ... shall cause the shell to write a diagnostic message
9614 * to standard error and exit as shown in the following table:
9615 * Error Special Built-In
9617 * Utility syntax error (option or operand error) Shall exit
9619 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9620 * we see that bash does not do that (set "finishes" with error code 1 instead,
9621 * and shell continues), and people rely on this behavior!
9623 * set -o barfoo 2>/dev/null
9626 * Oh well. Let's mimic that.
9629 plus_minus_o(char *name, int val)
9634 for (i = 0; i < NOPTS; i++) {
9635 if (strcmp(name, optnames(i)) == 0) {
9640 ash_msg("illegal option %co %s", val ? '-' : '+', name);
9643 for (i = 0; i < NOPTS; i++) {
9645 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
9647 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
9653 setoption(int flag, int val)
9657 for (i = 0; i < NOPTS; i++) {
9658 if (optletters(i) == flag) {
9663 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
9667 options(int cmdline)
9675 while ((p = *argptr) != NULL) {
9677 if (c != '-' && c != '+')
9680 val = 0; /* val = 0 if c == '+' */
9683 if (p[0] == '\0' || LONE_DASH(p)) {
9685 /* "-" means turn off -x and -v */
9688 /* "--" means reset params */
9689 else if (*argptr == NULL)
9692 break; /* "-" or "--" terminates options */
9695 /* first char was + or - */
9696 while ((c = *p++) != '\0') {
9697 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9698 if (c == 'c' && cmdline) {
9699 minusc = p; /* command is after shell args */
9700 } else if (c == 'o') {
9701 if (plus_minus_o(*argptr, val)) {
9702 /* it already printed err message */
9703 return 1; /* error */
9707 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9709 /* bash does not accept +-login, we also won't */
9710 } else if (cmdline && val && (c == '-')) { /* long options */
9711 if (strcmp(p, "login") == 0)
9723 * The shift builtin command.
9726 shiftcmd(int argc UNUSED_PARAM, char **argv)
9733 n = number(argv[1]);
9734 if (n > shellparam.nparam)
9735 n = 0; /* bash compat, was = shellparam.nparam; */
9737 shellparam.nparam -= n;
9738 for (ap1 = shellparam.p; --n >= 0; ap1++) {
9739 if (shellparam.malloced)
9743 while ((*ap2++ = *ap1++) != NULL)
9745 #if ENABLE_ASH_GETOPTS
9746 shellparam.optind = 1;
9747 shellparam.optoff = -1;
9754 * POSIX requires that 'set' (but not export or readonly) output the
9755 * variables in lexicographic order - by the locale's collating order (sigh).
9756 * Maybe we could keep them in an ordered balanced binary tree
9757 * instead of hashed lists.
9758 * For now just roll 'em through qsort for printing...
9761 showvars(const char *sep_prefix, int on, int off)
9766 ep = listvars(on, off, &epend);
9767 qsort(ep, epend - ep, sizeof(char *), vpcmp);
9769 sep = *sep_prefix ? " " : sep_prefix;
9771 for (; ep < epend; ep++) {
9775 p = strchrnul(*ep, '=');
9778 q = single_quote(++p);
9779 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9785 * The set command builtin.
9788 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9793 return showvars(nullstr, 0, VUNSET);
9796 if (!options(0)) { /* if no parse error... */
9799 if (*argptr != NULL) {
9807 #if ENABLE_ASH_RANDOM_SUPPORT
9809 change_random(const char *value)
9811 /* Galois LFSR parameter */
9812 /* Taps at 32 31 29 1: */
9813 enum { MASK = 0x8000000b };
9814 /* Another example - taps at 32 31 30 10: */
9815 /* MASK = 0x00400007 */
9817 if (value == NULL) {
9818 /* "get", generate */
9821 /* LCG has period of 2^32 and alternating lowest bit */
9822 random_LCG = 1664525 * random_LCG + 1013904223;
9823 /* Galois LFSR has period of 2^32-1 = 3 * 5 * 17 * 257 * 65537 */
9824 t = (random_galois_LFSR << 1);
9825 if (random_galois_LFSR < 0) /* if we just shifted 1 out of msb... */
9827 random_galois_LFSR = t;
9828 /* Both are weak, combining them gives better randomness
9829 * and ~2^64 period. & 0x7fff is probably bash compat
9830 * for $RANDOM range. Combining with subtraction is
9831 * just for fun. + and ^ would work equally well. */
9832 t = (t - random_LCG) & 0x7fff;
9833 /* set without recursion */
9834 setvar(vrandom.text, utoa(t), VNOFUNC);
9835 vrandom.flags &= ~VNOFUNC;
9838 random_galois_LFSR = random_LCG = strtoul(value, (char **)NULL, 10);
9843 #if ENABLE_ASH_GETOPTS
9845 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9854 if (*param_optind < 1)
9856 optnext = optfirst + *param_optind - 1;
9858 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
9861 p = optnext[-1] + *optoff;
9862 if (p == NULL || *p == '\0') {
9863 /* Current word is done, advance */
9865 if (p == NULL || *p != '-' || *++p == '\0') {
9872 if (LONE_DASH(p)) /* check for "--" */
9877 for (q = optstr; *q != c;) {
9879 if (optstr[0] == ':') {
9882 err |= setvarsafe("OPTARG", s, 0);
9884 fprintf(stderr, "Illegal option -%c\n", c);
9895 if (*p == '\0' && (p = *optnext) == NULL) {
9896 if (optstr[0] == ':') {
9899 err |= setvarsafe("OPTARG", s, 0);
9902 fprintf(stderr, "No arg for -%c option\n", c);
9911 err |= setvarsafe("OPTARG", p, 0);
9914 err |= setvarsafe("OPTARG", nullstr, 0);
9916 *optoff = p ? p - *(optnext - 1) : -1;
9917 *param_optind = optnext - optfirst + 1;
9918 fmtstr(s, sizeof(s), "%d", *param_optind);
9919 err |= setvarsafe("OPTIND", s, VNOFUNC);
9922 err |= setvarsafe(optvar, s, 0);
9926 flush_stdout_stderr();
9927 raise_exception(EXERROR);
9933 * The getopts builtin. Shellparam.optnext points to the next argument
9934 * to be processed. Shellparam.optptr points to the next character to
9935 * be processed in the current argument. If shellparam.optnext is NULL,
9936 * then it's the first time getopts has been called.
9939 getoptscmd(int argc, char **argv)
9944 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
9946 optbase = shellparam.p;
9947 if (shellparam.optind > shellparam.nparam + 1) {
9948 shellparam.optind = 1;
9949 shellparam.optoff = -1;
9953 if (shellparam.optind > argc - 2) {
9954 shellparam.optind = 1;
9955 shellparam.optoff = -1;
9959 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9960 &shellparam.optoff);
9962 #endif /* ASH_GETOPTS */
9965 /* ============ Shell parser */
9968 struct heredoc *next; /* next here document in list */
9969 union node *here; /* redirection node */
9970 char *eofmark; /* string indicating end of input */
9971 smallint striptabs; /* if set, strip leading tabs */
9974 static smallint tokpushback; /* last token pushed back */
9975 static smallint parsebackquote; /* nonzero if we are inside backquotes */
9976 static smallint quoteflag; /* set if (part of) last token was quoted */
9977 static token_id_t lasttoken; /* last token read (integer id Txxx) */
9978 static struct heredoc *heredoclist; /* list of here documents to read */
9979 static char *wordtext; /* text of last word returned by readtoken */
9980 static struct nodelist *backquotelist;
9981 static union node *redirnode;
9982 static struct heredoc *heredoc;
9984 * NEOF is returned by parsecmd when it encounters an end of file. It
9985 * must be distinct from NULL, so we use the address of a variable that
9986 * happens to be handy.
9988 #define NEOF ((union node *)&tokpushback)
9990 static void raise_error_syntax(const char *) NORETURN;
9992 raise_error_syntax(const char *msg)
9994 ash_msg_and_raise_error("syntax error: %s", msg);
9999 * Called when an unexpected token is read during the parse. The argument
10000 * is the token that is expected, or -1 if more than one type of token can
10001 * occur at this point.
10003 static void raise_error_unexpected_syntax(int) NORETURN;
10005 raise_error_unexpected_syntax(int token)
10010 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10012 sprintf(msg + l, " (expecting %s)", tokname(token));
10013 raise_error_syntax(msg);
10017 #define EOFMARKLEN 79
10019 /* parsing is heavily cross-recursive, need these forward decls */
10020 static union node *andor(void);
10021 static union node *pipeline(void);
10022 static union node *parse_command(void);
10023 static void parseheredoc(void);
10024 static char peektoken(void);
10025 static int readtoken(void);
10027 static union node *
10030 union node *n1, *n2, *n3;
10033 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10034 if (nlflag == 2 && peektoken())
10040 if (tok == TBACKGND) {
10041 if (n2->type == NPIPE) {
10042 n2->npipe.pipe_backgnd = 1;
10044 if (n2->type != NREDIR) {
10045 n3 = stzalloc(sizeof(struct nredir));
10047 /*n3->nredir.redirect = NULL; - stzalloc did it */
10050 n2->type = NBACKGND;
10056 n3 = stzalloc(sizeof(struct nbinary));
10058 n3->nbinary.ch1 = n1;
10059 n3->nbinary.ch2 = n2;
10075 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10083 pungetc(); /* push back EOF on input */
10087 raise_error_unexpected_syntax(-1);
10094 static union node *
10097 union node *n1, *n2, *n3;
10105 } else if (t == TOR) {
10111 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10113 n3 = stzalloc(sizeof(struct nbinary));
10115 n3->nbinary.ch1 = n1;
10116 n3->nbinary.ch2 = n2;
10121 static union node *
10124 union node *n1, *n2, *pipenode;
10125 struct nodelist *lp, *prev;
10129 TRACE(("pipeline: entered\n"));
10130 if (readtoken() == TNOT) {
10132 checkkwd = CHKKWD | CHKALIAS;
10135 n1 = parse_command();
10136 if (readtoken() == TPIPE) {
10137 pipenode = stzalloc(sizeof(struct npipe));
10138 pipenode->type = NPIPE;
10139 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10140 lp = stzalloc(sizeof(struct nodelist));
10141 pipenode->npipe.cmdlist = lp;
10145 lp = stzalloc(sizeof(struct nodelist));
10146 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10147 lp->n = parse_command();
10149 } while (readtoken() == TPIPE);
10155 n2 = stzalloc(sizeof(struct nnot));
10163 static union node *
10168 n = stzalloc(sizeof(struct narg));
10170 /*n->narg.next = NULL; - stzalloc did it */
10171 n->narg.text = wordtext;
10172 n->narg.backquote = backquotelist;
10177 fixredir(union node *n, const char *text, int err)
10181 TRACE(("Fix redir %s %d\n", text, err));
10183 n->ndup.vname = NULL;
10185 fd = bb_strtou(text, NULL, 10);
10186 if (!errno && fd >= 0)
10187 n->ndup.dupfd = fd;
10188 else if (LONE_DASH(text))
10189 n->ndup.dupfd = -1;
10192 raise_error_syntax("bad fd number");
10193 n->ndup.vname = makename();
10198 * Returns true if the text contains nothing to expand (no dollar signs
10202 noexpand(char *text)
10208 while ((c = *p++) != '\0') {
10209 if (c == CTLQUOTEMARK)
10213 else if (SIT(c, BASESYNTAX) == CCTL)
10222 union node *n = redirnode;
10224 if (readtoken() != TWORD)
10225 raise_error_unexpected_syntax(-1);
10226 if (n->type == NHERE) {
10227 struct heredoc *here = heredoc;
10231 if (quoteflag == 0)
10233 TRACE(("Here document %d\n", n->type));
10234 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10235 raise_error_syntax("illegal eof marker for << redirection");
10236 rmescapes(wordtext);
10237 here->eofmark = wordtext;
10239 if (heredoclist == NULL)
10240 heredoclist = here;
10242 for (p = heredoclist; p->next; p = p->next)
10246 } else if (n->type == NTOFD || n->type == NFROMFD) {
10247 fixredir(n, wordtext, 0);
10249 n->nfile.fname = makename();
10253 static union node *
10256 union node *args, **app;
10257 union node *n = NULL;
10258 union node *vars, **vpp;
10259 union node **rpp, *redir;
10261 #if ENABLE_ASH_BASH_COMPAT
10262 smallint double_brackets_flag = 0;
10272 savecheckkwd = CHKALIAS;
10275 checkkwd = savecheckkwd;
10278 #if ENABLE_ASH_BASH_COMPAT
10279 case TAND: /* "&&" */
10280 case TOR: /* "||" */
10281 if (!double_brackets_flag) {
10285 wordtext = (char *) (t == TAND ? "-a" : "-o");
10288 n = stzalloc(sizeof(struct narg));
10290 /*n->narg.next = NULL; - stzalloc did it */
10291 n->narg.text = wordtext;
10292 #if ENABLE_ASH_BASH_COMPAT
10293 if (strcmp("[[", wordtext) == 0)
10294 double_brackets_flag = 1;
10295 else if (strcmp("]]", wordtext) == 0)
10296 double_brackets_flag = 0;
10298 n->narg.backquote = backquotelist;
10299 if (savecheckkwd && isassignment(wordtext)) {
10301 vpp = &n->narg.next;
10304 app = &n->narg.next;
10309 *rpp = n = redirnode;
10310 rpp = &n->nfile.next;
10311 parsefname(); /* read name of redirection file */
10314 if (args && app == &args->narg.next
10317 struct builtincmd *bcmd;
10320 /* We have a function */
10321 if (readtoken() != TRP)
10322 raise_error_unexpected_syntax(TRP);
10323 name = n->narg.text;
10324 if (!goodname(name)
10325 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10327 raise_error_syntax("bad function name");
10330 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10331 n->narg.next = parse_command();
10344 n = stzalloc(sizeof(struct ncmd));
10346 n->ncmd.args = args;
10347 n->ncmd.assign = vars;
10348 n->ncmd.redirect = redir;
10352 static union node *
10353 parse_command(void)
10355 union node *n1, *n2;
10356 union node *ap, **app;
10357 union node *cp, **cpp;
10358 union node *redir, **rpp;
10365 switch (readtoken()) {
10367 raise_error_unexpected_syntax(-1);
10370 n1 = stzalloc(sizeof(struct nif));
10372 n1->nif.test = list(0);
10373 if (readtoken() != TTHEN)
10374 raise_error_unexpected_syntax(TTHEN);
10375 n1->nif.ifpart = list(0);
10377 while (readtoken() == TELIF) {
10378 n2->nif.elsepart = stzalloc(sizeof(struct nif));
10379 n2 = n2->nif.elsepart;
10381 n2->nif.test = list(0);
10382 if (readtoken() != TTHEN)
10383 raise_error_unexpected_syntax(TTHEN);
10384 n2->nif.ifpart = list(0);
10386 if (lasttoken == TELSE)
10387 n2->nif.elsepart = list(0);
10389 n2->nif.elsepart = NULL;
10397 n1 = stzalloc(sizeof(struct nbinary));
10398 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10399 n1->nbinary.ch1 = list(0);
10402 TRACE(("expecting DO got %s %s\n", tokname(got),
10403 got == TWORD ? wordtext : ""));
10404 raise_error_unexpected_syntax(TDO);
10406 n1->nbinary.ch2 = list(0);
10411 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10412 raise_error_syntax("bad for loop variable");
10413 n1 = stzalloc(sizeof(struct nfor));
10415 n1->nfor.var = wordtext;
10416 checkkwd = CHKKWD | CHKALIAS;
10417 if (readtoken() == TIN) {
10419 while (readtoken() == TWORD) {
10420 n2 = stzalloc(sizeof(struct narg));
10422 /*n2->narg.next = NULL; - stzalloc did it */
10423 n2->narg.text = wordtext;
10424 n2->narg.backquote = backquotelist;
10426 app = &n2->narg.next;
10429 n1->nfor.args = ap;
10430 if (lasttoken != TNL && lasttoken != TSEMI)
10431 raise_error_unexpected_syntax(-1);
10433 n2 = stzalloc(sizeof(struct narg));
10435 /*n2->narg.next = NULL; - stzalloc did it */
10436 n2->narg.text = (char *)dolatstr;
10437 /*n2->narg.backquote = NULL;*/
10438 n1->nfor.args = n2;
10440 * Newline or semicolon here is optional (but note
10441 * that the original Bourne shell only allowed NL).
10443 if (lasttoken != TNL && lasttoken != TSEMI)
10446 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10447 if (readtoken() != TDO)
10448 raise_error_unexpected_syntax(TDO);
10449 n1->nfor.body = list(0);
10453 n1 = stzalloc(sizeof(struct ncase));
10455 if (readtoken() != TWORD)
10456 raise_error_unexpected_syntax(TWORD);
10457 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10459 /*n2->narg.next = NULL; - stzalloc did it */
10460 n2->narg.text = wordtext;
10461 n2->narg.backquote = backquotelist;
10463 checkkwd = CHKKWD | CHKALIAS;
10464 } while (readtoken() == TNL);
10465 if (lasttoken != TIN)
10466 raise_error_unexpected_syntax(TIN);
10467 cpp = &n1->ncase.cases;
10469 checkkwd = CHKNL | CHKKWD;
10471 while (t != TESAC) {
10472 if (lasttoken == TLP)
10474 *cpp = cp = stzalloc(sizeof(struct nclist));
10476 app = &cp->nclist.pattern;
10478 *app = ap = stzalloc(sizeof(struct narg));
10480 /*ap->narg.next = NULL; - stzalloc did it */
10481 ap->narg.text = wordtext;
10482 ap->narg.backquote = backquotelist;
10483 if (readtoken() != TPIPE)
10485 app = &ap->narg.next;
10488 //ap->narg.next = NULL;
10489 if (lasttoken != TRP)
10490 raise_error_unexpected_syntax(TRP);
10491 cp->nclist.body = list(2);
10493 cpp = &cp->nclist.next;
10495 checkkwd = CHKNL | CHKKWD;
10499 raise_error_unexpected_syntax(TENDCASE);
10506 n1 = stzalloc(sizeof(struct nredir));
10507 n1->type = NSUBSHELL;
10508 n1->nredir.n = list(0);
10509 /*n1->nredir.redirect = NULL; - stzalloc did it */
10519 return simplecmd();
10522 if (readtoken() != t)
10523 raise_error_unexpected_syntax(t);
10526 /* Now check for redirection which may follow command */
10527 checkkwd = CHKKWD | CHKALIAS;
10529 while (readtoken() == TREDIR) {
10530 *rpp = n2 = redirnode;
10531 rpp = &n2->nfile.next;
10537 if (n1->type != NSUBSHELL) {
10538 n2 = stzalloc(sizeof(struct nredir));
10543 n1->nredir.redirect = redir;
10548 #if ENABLE_ASH_BASH_COMPAT
10549 static int decode_dollar_squote(void)
10551 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
10557 p = strchr(C_escapes, c);
10562 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
10566 } while ((unsigned char)(c - '0') <= 7 && --cnt);
10568 } else if (c == 'x') { /* \xHH */
10572 } while (isxdigit(c) && --cnt);
10574 if (cnt == 3) { /* \x but next char is "bad" */
10578 } else { /* simple seq like \\ or \t */
10583 c = bb_process_escape_sequence((void*)&p);
10584 } else { /* unrecognized "\z": print both chars unless ' or " */
10585 if (c != '\'' && c != '"') {
10587 c |= 0x100; /* "please encode \, then me" */
10595 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10596 * is not NULL, read a here document. In the latter case, eofmark is the
10597 * word which marks the end of the document and striptabs is true if
10598 * leading tabs should be stripped from the document. The argument firstc
10599 * is the first character of the input token or document.
10601 * Because C does not have internal subroutines, I have simulated them
10602 * using goto's to implement the subroutine linkage. The following macros
10603 * will run code that appears at the end of readtoken1.
10605 #define CHECKEND() {goto checkend; checkend_return:;}
10606 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10607 #define PARSESUB() {goto parsesub; parsesub_return:;}
10608 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10609 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10610 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10612 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10614 /* NB: syntax parameter fits into smallint */
10618 char line[EOFMARKLEN + 1];
10619 struct nodelist *bqlist;
10623 smallint prevsyntax; /* syntax before arithmetic */
10624 #if ENABLE_ASH_EXPAND_PRMT
10625 smallint pssyntax; /* we are expanding a prompt string */
10627 int varnest; /* levels of variables expansion */
10628 int arinest; /* levels of arithmetic expansion */
10629 int parenlevel; /* levels of parens in arithmetic */
10630 int dqvarnest; /* levels of variables expansion within double quotes */
10632 USE_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
10635 /* Avoid longjmp clobbering */
10641 (void) &parenlevel;
10644 (void) &prevsyntax;
10647 startlinno = plinno;
10652 #if ENABLE_ASH_EXPAND_PRMT
10653 pssyntax = (syntax == PSSYNTAX);
10657 dblquote = (syntax == DQSYNTAX);
10663 STARTSTACKSTR(out);
10665 /* For each line, until end of word */
10667 CHECKEND(); /* set c to PEOF if at end of here document */
10668 for (;;) { /* until end of line or end of word */
10669 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10670 switch (SIT(c, syntax)) {
10671 case CNL: /* '\n' */
10672 if (syntax == BASESYNTAX)
10673 goto endword; /* exit outer loop */
10679 goto loop; /* continue outer loop */
10684 if (eofmark == NULL || dblquote)
10685 USTPUTC(CTLESC, out);
10686 #if ENABLE_ASH_BASH_COMPAT
10687 if (c == '\\' && bash_dollar_squote) {
10688 c = decode_dollar_squote();
10690 USTPUTC('\\', out);
10691 c = (unsigned char)c;
10697 case CBACK: /* backslash */
10700 USTPUTC(CTLESC, out);
10701 USTPUTC('\\', out);
10703 } else if (c == '\n') {
10707 #if ENABLE_ASH_EXPAND_PRMT
10708 if (c == '$' && pssyntax) {
10709 USTPUTC(CTLESC, out);
10710 USTPUTC('\\', out);
10713 if (dblquote && c != '\\'
10714 && c != '`' && c != '$'
10715 && (c != '"' || eofmark != NULL)
10717 USTPUTC(CTLESC, out);
10718 USTPUTC('\\', out);
10720 if (SIT(c, SQSYNTAX) == CCTL)
10721 USTPUTC(CTLESC, out);
10729 if (eofmark == NULL) {
10730 USTPUTC(CTLQUOTEMARK, out);
10738 USE_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
10739 if (eofmark != NULL && arinest == 0
10744 if (dqvarnest == 0) {
10745 syntax = BASESYNTAX;
10752 case CVAR: /* '$' */
10753 PARSESUB(); /* parse substitution */
10755 case CENDVAR: /* '}' */
10758 if (dqvarnest > 0) {
10761 USTPUTC(CTLENDVAR, out);
10766 #if ENABLE_ASH_MATH_SUPPORT
10767 case CLP: /* '(' in arithmetic */
10771 case CRP: /* ')' in arithmetic */
10772 if (parenlevel > 0) {
10776 if (pgetc() == ')') {
10777 if (--arinest == 0) {
10778 USTPUTC(CTLENDARI, out);
10779 syntax = prevsyntax;
10780 dblquote = (syntax == DQSYNTAX);
10785 * unbalanced parens
10786 * (don't 2nd guess - no error)
10794 case CBQUOTE: /* '`' */
10798 goto endword; /* exit outer loop */
10802 if (varnest == 0) {
10803 #if ENABLE_ASH_BASH_COMPAT
10805 if (pgetc() == '>')
10806 c = 0x100 + '>'; /* flag &> */
10810 goto endword; /* exit outer loop */
10812 #if ENABLE_ASH_ALIAS
10822 #if ENABLE_ASH_MATH_SUPPORT
10823 if (syntax == ARISYNTAX)
10824 raise_error_syntax("missing '))'");
10826 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10827 raise_error_syntax("unterminated quoted string");
10828 if (varnest != 0) {
10829 startlinno = plinno;
10831 raise_error_syntax("missing '}'");
10833 USTPUTC('\0', out);
10834 len = out - (char *)stackblock();
10835 out = stackblock();
10836 if (eofmark == NULL) {
10837 if ((c == '>' || c == '<' USE_ASH_BASH_COMPAT( || c == 0x100 + '>'))
10840 if (isdigit_str9(out)) {
10841 PARSEREDIR(); /* passed as params: out, c */
10842 lasttoken = TREDIR;
10845 /* else: non-number X seen, interpret it
10846 * as "NNNX>file" = "NNNX >file" */
10850 quoteflag = quotef;
10851 backquotelist = bqlist;
10852 grabstackblock(len);
10856 /* end of readtoken routine */
10859 * Check to see whether we are at the end of the here document. When this
10860 * is called, c is set to the first character of the next input line. If
10861 * we are at the end of the here document, this routine sets the c to PEOF.
10865 #if ENABLE_ASH_ALIAS
10871 while (c == '\t') {
10875 if (c == *eofmark) {
10876 if (pfgets(line, sizeof(line)) != NULL) {
10880 for (q = eofmark + 1; *q && *p == *q; p++, q++)
10882 if (*p == '\n' && *q == '\0') {
10885 needprompt = doprompt;
10887 pushstring(line, NULL);
10892 goto checkend_return;
10896 * Parse a redirection operator. The variable "out" points to a string
10897 * specifying the fd to be redirected. The variable "c" contains the
10898 * first character of the redirection operator.
10901 /* out is already checked to be a valid number or "" */
10902 int fd = (*out == '\0' ? -1 : atoi(out));
10905 np = stzalloc(sizeof(struct nfile));
10910 np->type = NAPPEND;
10912 np->type = NCLOBBER;
10915 /* it also can be NTO2 (>&file), but we can't figure it out yet */
10921 #if ENABLE_ASH_BASH_COMPAT
10922 else if (c == 0x100 + '>') { /* this flags &> redirection */
10924 pgetc(); /* this is '>', no need to check */
10928 else { /* c == '<' */
10929 /*np->nfile.fd = 0; - stzalloc did it */
10933 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10934 np = stzalloc(sizeof(struct nhere));
10935 /*np->nfile.fd = 0; - stzalloc did it */
10938 heredoc = stzalloc(sizeof(struct heredoc));
10939 heredoc->here = np;
10942 heredoc->striptabs = 1;
10944 /*heredoc->striptabs = 0; - stzalloc did it */
10950 np->type = NFROMFD;
10954 np->type = NFROMTO;
10966 goto parseredir_return;
10970 * Parse a substitution. At this point, we have read the dollar sign
10971 * and nothing else.
10974 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
10975 * (assuming ascii char codes, as the original implementation did) */
10976 #define is_special(c) \
10977 (((unsigned)(c) - 33 < 32) \
10978 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
10984 static const char types[] ALIGN1 = "}-+?=";
10987 if (c <= PEOA_OR_PEOF
10988 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10990 #if ENABLE_ASH_BASH_COMPAT
10992 bash_dollar_squote = 1;
10997 } else if (c == '(') { /* $(command) or $((arith)) */
10998 if (pgetc() == '(') {
10999 #if ENABLE_ASH_MATH_SUPPORT
11002 raise_error_syntax("you disabled math support for $((arith)) syntax");
11009 USTPUTC(CTLVAR, out);
11010 typeloc = out - (char *)stackblock();
11011 USTPUTC(VSNORMAL, out);
11012 subtype = VSNORMAL;
11020 subtype = VSLENGTH;
11024 if (c > PEOA_OR_PEOF && is_name(c)) {
11028 } while (c > PEOA_OR_PEOF && is_in_name(c));
11029 } else if (isdigit(c)) {
11033 } while (isdigit(c));
11034 } else if (is_special(c)) {
11039 raise_error_syntax("bad substitution");
11044 if (subtype == 0) {
11048 #if ENABLE_ASH_BASH_COMPAT
11049 if (c == ':' || c == '$' || isdigit(c)) {
11051 subtype = VSSUBSTR;
11058 p = strchr(types, c);
11061 subtype = p - types + VSNORMAL;
11066 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
11074 #if ENABLE_ASH_BASH_COMPAT
11076 subtype = VSREPLACE;
11079 subtype++; /* VSREPLACEALL */
11088 if (dblquote || arinest)
11090 *((char *)stackblock() + typeloc) = subtype | flags;
11091 if (subtype != VSNORMAL) {
11093 if (dblquote || arinest) {
11098 goto parsesub_return;
11102 * Called to parse command substitutions. Newstyle is set if the command
11103 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11104 * list of commands (passed by reference), and savelen is the number of
11105 * characters on the top of the stack which must be preserved.
11108 struct nodelist **nlpp;
11111 char *volatile str;
11112 struct jmploc jmploc;
11113 struct jmploc *volatile savehandler;
11115 smallint saveprompt = 0;
11118 (void) &saveprompt;
11120 savepbq = parsebackquote;
11121 if (setjmp(jmploc.loc)) {
11123 parsebackquote = 0;
11124 exception_handler = savehandler;
11125 longjmp(exception_handler->loc, 1);
11129 savelen = out - (char *)stackblock();
11131 str = ckmalloc(savelen);
11132 memcpy(str, stackblock(), savelen);
11134 savehandler = exception_handler;
11135 exception_handler = &jmploc;
11138 /* We must read until the closing backquote, giving special
11139 treatment to some slashes, and then push the string and
11140 reread it as input, interpreting it normally. */
11147 STARTSTACKSTR(pout);
11164 * If eating a newline, avoid putting
11165 * the newline into the new character
11166 * stream (via the STPUTC after the
11171 if (pc != '\\' && pc != '`' && pc != '$'
11172 && (!dblquote || pc != '"'))
11173 STPUTC('\\', pout);
11174 if (pc > PEOA_OR_PEOF) {
11180 #if ENABLE_ASH_ALIAS
11183 startlinno = plinno;
11184 raise_error_syntax("EOF in backquote substitution");
11188 needprompt = doprompt;
11197 STPUTC('\0', pout);
11198 psavelen = pout - (char *)stackblock();
11199 if (psavelen > 0) {
11200 pstr = grabstackstr(pout);
11201 setinputstring(pstr);
11206 nlpp = &(*nlpp)->next;
11207 *nlpp = stzalloc(sizeof(**nlpp));
11208 /* (*nlpp)->next = NULL; - stzalloc did it */
11209 parsebackquote = oldstyle;
11212 saveprompt = doprompt;
11219 doprompt = saveprompt;
11220 else if (readtoken() != TRP)
11221 raise_error_unexpected_syntax(TRP);
11226 * Start reading from old file again, ignoring any pushed back
11227 * tokens left from the backquote parsing
11232 while (stackblocksize() <= savelen)
11234 STARTSTACKSTR(out);
11236 memcpy(out, str, savelen);
11237 STADJUST(savelen, out);
11243 parsebackquote = savepbq;
11244 exception_handler = savehandler;
11245 if (arinest || dblquote)
11246 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11248 USTPUTC(CTLBACKQ, out);
11250 goto parsebackq_oldreturn;
11251 goto parsebackq_newreturn;
11254 #if ENABLE_ASH_MATH_SUPPORT
11256 * Parse an arithmetic expansion (indicate start of one and set state)
11259 if (++arinest == 1) {
11260 prevsyntax = syntax;
11261 syntax = ARISYNTAX;
11262 USTPUTC(CTLARI, out);
11269 * we collapse embedded arithmetic expansion to
11270 * parenthesis, which should be equivalent
11274 goto parsearith_return;
11278 } /* end of readtoken */
11281 * Read the next input token.
11282 * If the token is a word, we set backquotelist to the list of cmds in
11283 * backquotes. We set quoteflag to true if any part of the word was
11285 * If the token is TREDIR, then we set redirnode to a structure containing
11287 * In all cases, the variable startlinno is set to the number of the line
11288 * on which the token starts.
11290 * [Change comment: here documents and internal procedures]
11291 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11292 * word parsing code into a separate routine. In this case, readtoken
11293 * doesn't need to have any internal procedures, but parseword does.
11294 * We could also make parseoperator in essence the main routine, and
11295 * have parseword (readtoken1?) handle both words and redirection.]
11297 #define NEW_xxreadtoken
11298 #ifdef NEW_xxreadtoken
11299 /* singles must be first! */
11300 static const char xxreadtoken_chars[7] ALIGN1 = {
11301 '\n', '(', ')', /* singles */
11302 '&', '|', ';', /* doubles */
11306 #define xxreadtoken_singles 3
11307 #define xxreadtoken_doubles 3
11309 static const char xxreadtoken_tokens[] ALIGN1 = {
11310 TNL, TLP, TRP, /* only single occurrence allowed */
11311 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11312 TEOF, /* corresponds to trailing nul */
11313 TAND, TOR, TENDCASE /* if double occurrence */
11328 startlinno = plinno;
11329 for (;;) { /* until token or start of word found */
11331 if (c == ' ' || c == '\t' USE_ASH_ALIAS( || c == PEOA))
11335 while ((c = pgetc()) != '\n' && c != PEOF)
11338 } else if (c == '\\') {
11339 if (pgetc() != '\n') {
11341 break; /* return readtoken1(...) */
11343 startlinno = ++plinno;
11349 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11353 needprompt = doprompt;
11356 p = strchr(xxreadtoken_chars, c);
11358 break; /* return readtoken1(...) */
11360 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11362 if (cc == c) { /* double occurrence? */
11363 p += xxreadtoken_doubles + 1;
11366 #if ENABLE_ASH_BASH_COMPAT
11367 if (c == '&' && cc == '>') /* &> */
11368 break; /* return readtoken1(...) */
11373 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11378 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11380 #else /* old xxreadtoken */
11381 #define RETURN(token) return lasttoken = token
11394 startlinno = plinno;
11395 for (;;) { /* until token or start of word found */
11398 case ' ': case '\t':
11399 #if ENABLE_ASH_ALIAS
11404 while ((c = pgetc()) != '\n' && c != PEOF)
11409 if (pgetc() == '\n') {
11410 startlinno = ++plinno;
11419 needprompt = doprompt;
11424 if (pgetc() == '&')
11429 if (pgetc() == '|')
11434 if (pgetc() == ';')
11447 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11450 #endif /* old xxreadtoken */
11457 smallint alreadyseen = tokpushback;
11460 #if ENABLE_ASH_ALIAS
11469 if (checkkwd & CHKNL) {
11476 if (t != TWORD || quoteflag) {
11481 * check for keywords
11483 if (checkkwd & CHKKWD) {
11484 const char *const *pp;
11486 pp = findkwd(wordtext);
11488 lasttoken = t = pp - tokname_array;
11489 TRACE(("keyword %s recognized\n", tokname(t)));
11494 if (checkkwd & CHKALIAS) {
11495 #if ENABLE_ASH_ALIAS
11497 ap = lookupalias(wordtext, 1);
11500 pushstring(ap->val, ap);
11510 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11512 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11524 return tokname_array[t][0];
11528 * Read and parse a command. Returns NEOF on end of file. (NULL is a
11529 * valid parse tree indicating a blank line.)
11531 static union node *
11532 parsecmd(int interact)
11537 doprompt = interact;
11539 setprompt(doprompt);
11551 * Input any here documents.
11556 struct heredoc *here;
11559 here = heredoclist;
11560 heredoclist = NULL;
11566 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
11567 here->eofmark, here->striptabs);
11568 n = stzalloc(sizeof(struct narg));
11569 n->narg.type = NARG;
11570 /*n->narg.next = NULL; - stzalloc did it */
11571 n->narg.text = wordtext;
11572 n->narg.backquote = backquotelist;
11573 here->here->nhere.doc = n;
11580 * called by editline -- any expansions to the prompt should be added here.
11582 #if ENABLE_ASH_EXPAND_PRMT
11583 static const char *
11584 expandstr(const char *ps)
11588 /* XXX Fix (char *) cast. */
11589 setinputstring((char *)ps);
11590 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
11593 n.narg.type = NARG;
11594 n.narg.next = NULL;
11595 n.narg.text = wordtext;
11596 n.narg.backquote = backquotelist;
11598 expandarg(&n, NULL, 0);
11599 return stackblock();
11604 * Execute a command or commands contained in a string.
11607 evalstring(char *s, int mask)
11610 struct stackmark smark;
11614 setstackmark(&smark);
11617 while ((n = parsecmd(0)) != NEOF) {
11619 popstackmark(&smark);
11632 * The eval command.
11635 evalcmd(int argc UNUSED_PARAM, char **argv)
11644 STARTSTACKSTR(concat);
11646 concat = stack_putstr(p, concat);
11650 STPUTC(' ', concat);
11652 STPUTC('\0', concat);
11653 p = grabstackstr(concat);
11655 evalstring(p, ~SKIPEVAL);
11662 * Read and execute commands. "Top" is nonzero for the top level command
11663 * loop; it turns on prompting if the shell is interactive.
11669 struct stackmark smark;
11673 TRACE(("cmdloop(%d) called\n", top));
11677 setstackmark(&smark);
11680 showjobs(stderr, SHOW_CHANGED);
11683 if (iflag && top) {
11685 #if ENABLE_ASH_MAIL
11689 n = parsecmd(inter);
11690 /* showtree(n); DEBUG */
11692 if (!top || numeof >= 50)
11694 if (!stoppedjobs()) {
11697 out2str("\nUse \"exit\" to leave shell.\n");
11700 } else if (nflag == 0) {
11701 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11706 popstackmark(&smark);
11711 return skip & SKIPEVAL;
11718 * Take commands from a file. To be compatible we should do a path
11719 * search for the file, which is necessary to find sub-commands.
11722 find_dot_file(char *name)
11725 const char *path = pathval();
11728 /* don't try this for absolute or relative paths */
11729 if (strchr(name, '/'))
11732 while ((fullname = padvance(&path, name)) != NULL) {
11733 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11735 * Don't bother freeing here, since it will
11736 * be freed by the caller.
11740 stunalloc(fullname);
11743 /* not found in the PATH */
11744 ash_msg_and_raise_error("%s: not found", name);
11749 dotcmd(int argc, char **argv)
11751 struct strlist *sp;
11752 volatile struct shparam saveparam;
11755 for (sp = cmdenviron; sp; sp = sp->next)
11756 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11758 if (argv[1]) { /* That's what SVR2 does */
11759 char *fullname = find_dot_file(argv[1]);
11762 if (argc) { /* argc > 0, argv[0] != NULL */
11763 saveparam = shellparam;
11764 shellparam.malloced = 0;
11765 shellparam.nparam = argc;
11766 shellparam.p = argv;
11769 setinputfile(fullname, INPUT_PUSH_FILE);
11770 commandname = fullname;
11775 freeparam(&shellparam);
11776 shellparam = saveparam;
11778 status = exitstatus;
11784 exitcmd(int argc UNUSED_PARAM, char **argv)
11789 exitstatus = number(argv[1]);
11790 raise_exception(EXEXIT);
11795 * Read a file containing shell functions.
11798 readcmdfile(char *name)
11800 setinputfile(name, INPUT_PUSH_FILE);
11806 /* ============ find_command inplementation */
11809 * Resolve a command name. If you change this routine, you may have to
11810 * change the shellexec routine as well.
11813 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11815 struct tblentry *cmdp;
11822 struct builtincmd *bcmd;
11824 /* If name contains a slash, don't use PATH or hash table */
11825 if (strchr(name, '/') != NULL) {
11826 entry->u.index = -1;
11827 if (act & DO_ABS) {
11828 while (stat(name, &statb) < 0) {
11830 if (errno == EINTR)
11833 entry->cmdtype = CMDUNKNOWN;
11837 entry->cmdtype = CMDNORMAL;
11841 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11843 updatetbl = (path == pathval());
11846 if (strstr(path, "%builtin") != NULL)
11847 act |= DO_ALTBLTIN;
11850 /* If name is in the table, check answer will be ok */
11851 cmdp = cmdlookup(name, 0);
11852 if (cmdp != NULL) {
11855 switch (cmdp->cmdtype) {
11873 } else if (cmdp->rehash == 0)
11874 /* if not invalidated by cd, we're done */
11878 /* If %builtin not in path, check for builtin next */
11879 bcmd = find_builtin(name);
11881 if (IS_BUILTIN_REGULAR(bcmd))
11882 goto builtin_success;
11883 if (act & DO_ALTPATH) {
11884 if (!(act & DO_ALTBLTIN))
11885 goto builtin_success;
11886 } else if (builtinloc <= 0) {
11887 goto builtin_success;
11891 #if ENABLE_FEATURE_SH_STANDALONE
11893 int applet_no = find_applet_by_name(name);
11894 if (applet_no >= 0) {
11895 entry->cmdtype = CMDNORMAL;
11896 entry->u.index = -2 - applet_no;
11902 /* We have to search path. */
11903 prev = -1; /* where to start */
11904 if (cmdp && cmdp->rehash) { /* doing a rehash */
11905 if (cmdp->cmdtype == CMDBUILTIN)
11908 prev = cmdp->param.index;
11914 while ((fullname = padvance(&path, name)) != NULL) {
11915 stunalloc(fullname);
11916 /* NB: code below will still use fullname
11917 * despite it being "unallocated" */
11920 if (prefix(pathopt, "builtin")) {
11922 goto builtin_success;
11925 if ((act & DO_NOFUNC)
11926 || !prefix(pathopt, "func")
11927 ) { /* ignore unimplemented options */
11931 /* if rehash, don't redo absolute path names */
11932 if (fullname[0] == '/' && idx <= prev) {
11935 TRACE(("searchexec \"%s\": no change\n", name));
11938 while (stat(fullname, &statb) < 0) {
11940 if (errno == EINTR)
11943 if (errno != ENOENT && errno != ENOTDIR)
11947 e = EACCES; /* if we fail, this will be the error */
11948 if (!S_ISREG(statb.st_mode))
11950 if (pathopt) { /* this is a %func directory */
11951 stalloc(strlen(fullname) + 1);
11952 /* NB: stalloc will return space pointed by fullname
11953 * (because we don't have any intervening allocations
11954 * between stunalloc above and this stalloc) */
11955 readcmdfile(fullname);
11956 cmdp = cmdlookup(name, 0);
11957 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
11958 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
11959 stunalloc(fullname);
11962 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
11964 entry->cmdtype = CMDNORMAL;
11965 entry->u.index = idx;
11969 cmdp = cmdlookup(name, 1);
11970 cmdp->cmdtype = CMDNORMAL;
11971 cmdp->param.index = idx;
11976 /* We failed. If there was an entry for this command, delete it */
11977 if (cmdp && updatetbl)
11978 delete_cmd_entry();
11980 ash_msg("%s: %s", name, errmsg(e, "not found"));
11981 entry->cmdtype = CMDUNKNOWN;
11986 entry->cmdtype = CMDBUILTIN;
11987 entry->u.cmd = bcmd;
11991 cmdp = cmdlookup(name, 1);
11992 cmdp->cmdtype = CMDBUILTIN;
11993 cmdp->param.cmd = bcmd;
11997 entry->cmdtype = cmdp->cmdtype;
11998 entry->u = cmdp->param;
12002 /* ============ trap.c */
12005 * The trap builtin.
12008 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12017 for (signo = 0; signo < NSIG; signo++) {
12018 if (trap[signo] != NULL) {
12019 out1fmt("trap -- %s %s\n",
12020 single_quote(trap[signo]),
12021 get_signame(signo));
12030 signo = get_signum(*ap);
12032 ash_msg_and_raise_error("%s: bad trap", *ap);
12035 if (LONE_DASH(action))
12038 action = ckstrdup(action);
12041 trap[signo] = action;
12051 /* ============ Builtins */
12053 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
12055 * Lists available builtins
12058 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12063 out1fmt("\nBuilt-in commands:\n-------------------\n");
12064 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12065 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12066 builtintab[i].name + 1);
12072 #if ENABLE_FEATURE_SH_STANDALONE
12074 const char *a = applet_names;
12076 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12081 a += strlen(a) + 1;
12086 return EXIT_SUCCESS;
12088 #endif /* FEATURE_SH_EXTRA_QUIET */
12091 * The export and readonly commands.
12094 exportcmd(int argc UNUSED_PARAM, char **argv)
12100 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;
12102 if (nextopt("p") != 'p') {
12107 p = strchr(name, '=');
12111 vp = *findvar(hashvar(name), name);
12117 setvar(name, p, flag);
12118 } while ((name = *++aptr) != NULL);
12122 showvars(argv[0], flag, 0);
12127 * Delete a function if it exists.
12130 unsetfunc(const char *name)
12132 struct tblentry *cmdp;
12134 cmdp = cmdlookup(name, 0);
12135 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
12136 delete_cmd_entry();
12140 * The unset builtin command. We unset the function before we unset the
12141 * variable to allow a function to be unset when there is a readonly variable
12142 * with the same name.
12145 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12152 while ((i = nextopt("vf")) != '\0') {
12156 for (ap = argptr; *ap; ap++) {
12172 #include <sys/times.h>
12174 static const unsigned char timescmd_str[] ALIGN1 = {
12175 ' ', offsetof(struct tms, tms_utime),
12176 '\n', offsetof(struct tms, tms_stime),
12177 ' ', offsetof(struct tms, tms_cutime),
12178 '\n', offsetof(struct tms, tms_cstime),
12183 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12185 long clk_tck, s, t;
12186 const unsigned char *p;
12189 clk_tck = sysconf(_SC_CLK_TCK);
12194 t = *(clock_t *)(((char *) &buf) + p[1]);
12196 out1fmt("%ldm%ld.%.3lds%c",
12198 ((t - s * clk_tck) * 1000) / clk_tck,
12200 } while (*(p += 2));
12205 #if ENABLE_ASH_MATH_SUPPORT
12207 dash_arith(const char *s)
12213 result = arith(s, &errcode);
12216 ash_msg_and_raise_error("exponent less than 0");
12218 ash_msg_and_raise_error("divide by zero");
12220 ash_msg_and_raise_error("expression recursion loop detected");
12221 raise_error_syntax(s);
12229 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12230 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12232 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12235 letcmd(int argc UNUSED_PARAM, char **argv)
12241 ash_msg_and_raise_error("expression expected");
12243 i = dash_arith(*argv);
12248 #endif /* ASH_MATH_SUPPORT */
12251 /* ============ miscbltin.c
12253 * Miscellaneous builtins.
12258 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12259 typedef enum __rlimit_resource rlim_t;
12263 * The read builtin. Options:
12264 * -r Do not interpret '\' specially
12265 * -s Turn off echo (tty only)
12266 * -n NCHARS Read NCHARS max
12267 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12268 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12269 * -u FD Read from given FD instead of fd 0
12270 * This uses unbuffered input, which may be avoidable in some cases.
12271 * TODO: bash also has:
12272 * -a ARRAY Read into array[0],[1],etc
12273 * -d DELIM End on DELIM char, not newline
12274 * -e Use line editing (tty only)
12277 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12279 static const char *const arg_REPLY[] = { "REPLY", NULL };
12292 #if ENABLE_ASH_READ_NCHARS
12293 int nchars = 0; /* if != 0, -n is in effect */
12295 struct termios tty, old_tty;
12297 #if ENABLE_ASH_READ_TIMEOUT
12298 unsigned end_ms = 0;
12299 unsigned timeout = 0;
12304 while ((i = nextopt("p:u:r"
12305 USE_ASH_READ_TIMEOUT("t:")
12306 USE_ASH_READ_NCHARS("n:s")
12310 prompt = optionarg;
12312 #if ENABLE_ASH_READ_NCHARS
12314 nchars = bb_strtou(optionarg, NULL, 10);
12315 if (nchars < 0 || errno)
12316 ash_msg_and_raise_error("invalid count");
12317 /* nchars == 0: off (bash 3.2 does this too) */
12323 #if ENABLE_ASH_READ_TIMEOUT
12325 timeout = bb_strtou(optionarg, NULL, 10);
12326 if (errno || timeout > UINT_MAX / 2048)
12327 ash_msg_and_raise_error("invalid timeout");
12329 #if 0 /* even bash have no -t N.NNN support */
12330 ts.tv_sec = bb_strtou(optionarg, &p, 10);
12332 /* EINVAL means number is ok, but not terminated by NUL */
12333 if (*p == '.' && errno == EINVAL) {
12337 ts.tv_usec = bb_strtou(p, &p2, 10);
12339 ash_msg_and_raise_error("invalid timeout");
12341 /* normalize to usec */
12343 ash_msg_and_raise_error("invalid timeout");
12344 while (scale++ < 6)
12347 } else if (ts.tv_sec < 0 || errno) {
12348 ash_msg_and_raise_error("invalid timeout");
12350 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
12351 ash_msg_and_raise_error("invalid timeout");
12360 fd = bb_strtou(optionarg, NULL, 10);
12361 if (fd < 0 || errno)
12362 ash_msg_and_raise_error("invalid file descriptor");
12368 if (prompt && isatty(fd)) {
12373 ap = (char**)arg_REPLY;
12374 ifs = bltinlookup("IFS");
12377 #if ENABLE_ASH_READ_NCHARS
12378 tcgetattr(fd, &tty);
12380 if (nchars || silent) {
12382 tty.c_lflag &= ~ICANON;
12383 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
12386 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
12388 /* if tcgetattr failed, tcsetattr will fail too.
12389 * Ignoring, it's harmless. */
12390 tcsetattr(fd, TCSANOW, &tty);
12397 #if ENABLE_ASH_READ_TIMEOUT
12398 if (timeout) /* NB: ensuring end_ms is nonzero */
12399 end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1;
12403 #if ENABLE_ASH_READ_TIMEOUT
12405 struct pollfd pfd[1];
12407 pfd[0].events = POLLIN;
12408 timeout = end_ms - (unsigned)(monotonic_us() / 1000);
12409 if ((int)timeout <= 0 /* already late? */
12410 || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
12411 ) { /* timed out! */
12412 #if ENABLE_ASH_READ_NCHARS
12413 tcsetattr(fd, TCSANOW, &old_tty);
12419 if (nonblock_safe_read(fd, &c, 1) != 1) {
12431 if (!rflag && c == '\\') {
12437 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12441 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12443 setvar(*ap, stackblock(), 0);
12452 /* end of do {} while: */
12453 #if ENABLE_ASH_READ_NCHARS
12459 #if ENABLE_ASH_READ_NCHARS
12460 tcsetattr(fd, TCSANOW, &old_tty);
12464 /* Remove trailing blanks */
12465 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12467 setvar(*ap, stackblock(), 0);
12468 while (*++ap != NULL)
12469 setvar(*ap, nullstr, 0);
12474 umaskcmd(int argc UNUSED_PARAM, char **argv)
12476 static const char permuser[3] ALIGN1 = "ugo";
12477 static const char permmode[3] ALIGN1 = "rwx";
12478 static const short permmask[] ALIGN2 = {
12479 S_IRUSR, S_IWUSR, S_IXUSR,
12480 S_IRGRP, S_IWGRP, S_IXGRP,
12481 S_IROTH, S_IWOTH, S_IXOTH
12487 int symbolic_mode = 0;
12489 while (nextopt("S") != '\0') {
12500 if (symbolic_mode) {
12504 for (i = 0; i < 3; i++) {
12507 *p++ = permuser[i];
12509 for (j = 0; j < 3; j++) {
12510 if ((mask & permmask[3 * i + j]) == 0) {
12511 *p++ = permmode[j];
12519 out1fmt("%.4o\n", mask);
12522 if (isdigit((unsigned char) *ap)) {
12525 if (*ap >= '8' || *ap < '0')
12526 ash_msg_and_raise_error(illnum, argv[1]);
12527 mask = (mask << 3) + (*ap - '0');
12528 } while (*++ap != '\0');
12531 mask = ~mask & 0777;
12532 if (!bb_parse_mode(ap, &mask)) {
12533 ash_msg_and_raise_error("illegal mode: %s", ap);
12535 umask(~mask & 0777);
12544 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12545 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12546 * ash by J.T. Conklin.
12552 uint8_t cmd; /* RLIMIT_xxx fit into it */
12553 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
12557 static const struct limits limits_tbl[] = {
12559 { RLIMIT_CPU, 0, 't' },
12561 #ifdef RLIMIT_FSIZE
12562 { RLIMIT_FSIZE, 9, 'f' },
12565 { RLIMIT_DATA, 10, 'd' },
12567 #ifdef RLIMIT_STACK
12568 { RLIMIT_STACK, 10, 's' },
12571 { RLIMIT_CORE, 9, 'c' },
12574 { RLIMIT_RSS, 10, 'm' },
12576 #ifdef RLIMIT_MEMLOCK
12577 { RLIMIT_MEMLOCK, 10, 'l' },
12579 #ifdef RLIMIT_NPROC
12580 { RLIMIT_NPROC, 0, 'p' },
12582 #ifdef RLIMIT_NOFILE
12583 { RLIMIT_NOFILE, 0, 'n' },
12586 { RLIMIT_AS, 10, 'v' },
12588 #ifdef RLIMIT_LOCKS
12589 { RLIMIT_LOCKS, 0, 'w' },
12592 static const char limits_name[] =
12594 "time(seconds)" "\0"
12596 #ifdef RLIMIT_FSIZE
12597 "file(blocks)" "\0"
12602 #ifdef RLIMIT_STACK
12606 "coredump(blocks)" "\0"
12611 #ifdef RLIMIT_MEMLOCK
12612 "locked memory(kb)" "\0"
12614 #ifdef RLIMIT_NPROC
12617 #ifdef RLIMIT_NOFILE
12623 #ifdef RLIMIT_LOCKS
12628 enum limtype { SOFT = 0x1, HARD = 0x2 };
12631 printlim(enum limtype how, const struct rlimit *limit,
12632 const struct limits *l)
12636 val = limit->rlim_max;
12638 val = limit->rlim_cur;
12640 if (val == RLIM_INFINITY)
12641 out1fmt("unlimited\n");
12643 val >>= l->factor_shift;
12644 out1fmt("%lld\n", (long long) val);
12649 ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12653 enum limtype how = SOFT | HARD;
12654 const struct limits *l;
12657 struct rlimit limit;
12660 while ((optc = nextopt("HSa"
12664 #ifdef RLIMIT_FSIZE
12670 #ifdef RLIMIT_STACK
12679 #ifdef RLIMIT_MEMLOCK
12682 #ifdef RLIMIT_NPROC
12685 #ifdef RLIMIT_NOFILE
12691 #ifdef RLIMIT_LOCKS
12709 for (l = limits_tbl; l->option != what; l++)
12712 set = *argptr ? 1 : 0;
12716 if (all || argptr[1])
12717 ash_msg_and_raise_error("too many arguments");
12718 if (strncmp(p, "unlimited\n", 9) == 0)
12719 val = RLIM_INFINITY;
12723 while ((c = *p++) >= '0' && c <= '9') {
12724 val = (val * 10) + (long)(c - '0');
12725 // val is actually 'unsigned long int' and can't get < 0
12726 if (val < (rlim_t) 0)
12730 ash_msg_and_raise_error("bad number");
12731 val <<= l->factor_shift;
12735 const char *lname = limits_name;
12736 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12737 getrlimit(l->cmd, &limit);
12738 out1fmt("%-20s ", lname);
12739 lname += strlen(lname) + 1;
12740 printlim(how, &limit, l);
12745 getrlimit(l->cmd, &limit);
12748 limit.rlim_max = val;
12750 limit.rlim_cur = val;
12751 if (setrlimit(l->cmd, &limit) < 0)
12752 ash_msg_and_raise_error("error setting limit (%m)");
12754 printlim(how, &limit, l);
12760 /* ============ Math support */
12762 #if ENABLE_ASH_MATH_SUPPORT
12764 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12766 Permission is hereby granted, free of charge, to any person obtaining
12767 a copy of this software and associated documentation files (the
12768 "Software"), to deal in the Software without restriction, including
12769 without limitation the rights to use, copy, modify, merge, publish,
12770 distribute, sublicense, and/or sell copies of the Software, and to
12771 permit persons to whom the Software is furnished to do so, subject to
12772 the following conditions:
12774 The above copyright notice and this permission notice shall be
12775 included in all copies or substantial portions of the Software.
12777 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12778 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12779 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12780 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12781 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12782 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12783 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12786 /* This is my infix parser/evaluator. It is optimized for size, intended
12787 * as a replacement for yacc-based parsers. However, it may well be faster
12788 * than a comparable parser written in yacc. The supported operators are
12789 * listed in #defines below. Parens, order of operations, and error handling
12790 * are supported. This code is thread safe. The exact expression format should
12791 * be that which POSIX specifies for shells. */
12793 /* The code uses a simple two-stack algorithm. See
12794 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12795 * for a detailed explanation of the infix-to-postfix algorithm on which
12796 * this is based (this code differs in that it applies operators immediately
12797 * to the stack instead of adding them to a queue to end up with an
12800 /* To use the routine, call it with an expression string and error return
12804 * Aug 24, 2001 Manuel Novoa III
12806 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12808 * 1) In arith_apply():
12809 * a) Cached values of *numptr and &(numptr[-1]).
12810 * b) Removed redundant test for zero denominator.
12813 * a) Eliminated redundant code for processing operator tokens by moving
12814 * to a table-based implementation. Also folded handling of parens
12816 * b) Combined all 3 loops which called arith_apply to reduce generated
12817 * code size at the cost of speed.
12819 * 3) The following expressions were treated as valid by the original code:
12820 * 1() , 0! , 1 ( *3 ) .
12821 * These bugs have been fixed by internally enclosing the expression in
12822 * parens and then checking that all binary ops and right parens are
12823 * preceded by a valid expression (NUM_TOKEN).
12825 * Note: It may be desirable to replace Aaron's test for whitespace with
12826 * ctype's isspace() if it is used by another busybox applet or if additional
12827 * whitespace chars should be considered. Look below the "#include"s for a
12828 * precompiler test.
12832 * Aug 26, 2001 Manuel Novoa III
12834 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12836 * Merge in Aaron's comments previously posted to the busybox list,
12837 * modified slightly to take account of my changes to the code.
12842 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12844 * - allow access to variable,
12845 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12846 * - realize assign syntax (VAR=expr, +=, *= etc)
12847 * - realize exponentiation (** operator)
12848 * - realize comma separated - expr, expr
12849 * - realise ++expr --expr expr++ expr--
12850 * - realise expr ? expr : expr (but, second expr calculate always)
12851 * - allow hexadecimal and octal numbers
12852 * - was restored loses XOR operator
12853 * - remove one goto label, added three ;-)
12854 * - protect $((num num)) as true zero expr (Manuel`s error)
12855 * - always use special isspace(), see comment from bash ;-)
12858 #define arith_isspace(arithval) \
12859 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12861 typedef unsigned char operator;
12863 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12864 * precedence, and 3 high bits are an ID unique across operators of that
12865 * precedence. The ID portion is so that multiple operators can have the
12866 * same precedence, ensuring that the leftmost one is evaluated first.
12867 * Consider * and /. */
12869 #define tok_decl(prec,id) (((id)<<5)|(prec))
12870 #define PREC(op) ((op) & 0x1F)
12872 #define TOK_LPAREN tok_decl(0,0)
12874 #define TOK_COMMA tok_decl(1,0)
12876 #define TOK_ASSIGN tok_decl(2,0)
12877 #define TOK_AND_ASSIGN tok_decl(2,1)
12878 #define TOK_OR_ASSIGN tok_decl(2,2)
12879 #define TOK_XOR_ASSIGN tok_decl(2,3)
12880 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12881 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12882 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12883 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12885 #define TOK_MUL_ASSIGN tok_decl(3,0)
12886 #define TOK_DIV_ASSIGN tok_decl(3,1)
12887 #define TOK_REM_ASSIGN tok_decl(3,2)
12889 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12890 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12892 /* conditional is right associativity too */
12893 #define TOK_CONDITIONAL tok_decl(4,0)
12894 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12896 #define TOK_OR tok_decl(5,0)
12898 #define TOK_AND tok_decl(6,0)
12900 #define TOK_BOR tok_decl(7,0)
12902 #define TOK_BXOR tok_decl(8,0)
12904 #define TOK_BAND tok_decl(9,0)
12906 #define TOK_EQ tok_decl(10,0)
12907 #define TOK_NE tok_decl(10,1)
12909 #define TOK_LT tok_decl(11,0)
12910 #define TOK_GT tok_decl(11,1)
12911 #define TOK_GE tok_decl(11,2)
12912 #define TOK_LE tok_decl(11,3)
12914 #define TOK_LSHIFT tok_decl(12,0)
12915 #define TOK_RSHIFT tok_decl(12,1)
12917 #define TOK_ADD tok_decl(13,0)
12918 #define TOK_SUB tok_decl(13,1)
12920 #define TOK_MUL tok_decl(14,0)
12921 #define TOK_DIV tok_decl(14,1)
12922 #define TOK_REM tok_decl(14,2)
12924 /* exponent is right associativity */
12925 #define TOK_EXPONENT tok_decl(15,1)
12927 /* For now unary operators. */
12928 #define UNARYPREC 16
12929 #define TOK_BNOT tok_decl(UNARYPREC,0)
12930 #define TOK_NOT tok_decl(UNARYPREC,1)
12932 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12933 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12935 #define PREC_PRE (UNARYPREC+2)
12937 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12938 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12940 #define PREC_POST (UNARYPREC+3)
12942 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12943 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12945 #define SPEC_PREC (UNARYPREC+4)
12947 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12948 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12950 #define NUMPTR (*numstackptr)
12953 tok_have_assign(operator op)
12955 operator prec = PREC(op);
12957 convert_prec_is_assing(prec);
12958 return (prec == PREC(TOK_ASSIGN) ||
12959 prec == PREC_PRE || prec == PREC_POST);
12963 is_right_associativity(operator prec)
12965 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
12966 || prec == PREC(TOK_CONDITIONAL));
12971 arith_t contidional_second_val;
12972 char contidional_second_val_initialized;
12973 char *var; /* if NULL then is regular number,
12974 else is variable name */
12977 typedef struct chk_var_recursive_looped_t {
12979 struct chk_var_recursive_looped_t *next;
12980 } chk_var_recursive_looped_t;
12982 static chk_var_recursive_looped_t *prev_chk_var_recursive;
12985 arith_lookup_val(v_n_t *t)
12988 const char * p = lookupvar(t->var);
12993 /* recursive try as expression */
12994 chk_var_recursive_looped_t *cur;
12995 chk_var_recursive_looped_t cur_save;
12997 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
12998 if (strcmp(cur->var, t->var) == 0) {
12999 /* expression recursion loop detected */
13003 /* save current lookuped var name */
13004 cur = prev_chk_var_recursive;
13005 cur_save.var = t->var;
13006 cur_save.next = cur;
13007 prev_chk_var_recursive = &cur_save;
13009 t->val = arith (p, &errcode);
13010 /* restore previous ptr after recursiving */
13011 prev_chk_var_recursive = cur;
13014 /* allow undefined var as 0 */
13020 /* "applying" a token means performing it on the top elements on the integer
13021 * stack. For a unary operator it will only change the top element, but a
13022 * binary operator will pop two arguments and push a result */
13024 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13027 arith_t numptr_val, rez;
13028 int ret_arith_lookup_val;
13030 /* There is no operator that can work without arguments */
13031 if (NUMPTR == numstack) goto err;
13032 numptr_m1 = NUMPTR - 1;
13034 /* check operand is var with noninteger value */
13035 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13036 if (ret_arith_lookup_val)
13037 return ret_arith_lookup_val;
13039 rez = numptr_m1->val;
13040 if (op == TOK_UMINUS)
13042 else if (op == TOK_NOT)
13044 else if (op == TOK_BNOT)
13046 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13048 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13050 else if (op != TOK_UPLUS) {
13051 /* Binary operators */
13053 /* check and binary operators need two arguments */
13054 if (numptr_m1 == numstack) goto err;
13056 /* ... and they pop one */
13059 if (op == TOK_CONDITIONAL) {
13060 if (!numptr_m1->contidional_second_val_initialized) {
13061 /* protect $((expr1 ? expr2)) without ": expr" */
13064 rez = numptr_m1->contidional_second_val;
13065 } else if (numptr_m1->contidional_second_val_initialized) {
13066 /* protect $((expr1 : expr2)) without "expr ? " */
13069 numptr_m1 = NUMPTR - 1;
13070 if (op != TOK_ASSIGN) {
13071 /* check operand is var with noninteger value for not '=' */
13072 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13073 if (ret_arith_lookup_val)
13074 return ret_arith_lookup_val;
13076 if (op == TOK_CONDITIONAL) {
13077 numptr_m1->contidional_second_val = rez;
13079 rez = numptr_m1->val;
13080 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13082 else if (op == TOK_OR)
13083 rez = numptr_val || rez;
13084 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13086 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13088 else if (op == TOK_AND)
13089 rez = rez && numptr_val;
13090 else if (op == TOK_EQ)
13091 rez = (rez == numptr_val);
13092 else if (op == TOK_NE)
13093 rez = (rez != numptr_val);
13094 else if (op == TOK_GE)
13095 rez = (rez >= numptr_val);
13096 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13097 rez >>= numptr_val;
13098 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13099 rez <<= numptr_val;
13100 else if (op == TOK_GT)
13101 rez = (rez > numptr_val);
13102 else if (op == TOK_LT)
13103 rez = (rez < numptr_val);
13104 else if (op == TOK_LE)
13105 rez = (rez <= numptr_val);
13106 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13108 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13110 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13112 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13114 else if (op == TOK_CONDITIONAL_SEP) {
13115 if (numptr_m1 == numstack) {
13116 /* protect $((expr : expr)) without "expr ? " */
13119 numptr_m1->contidional_second_val_initialized = op;
13120 numptr_m1->contidional_second_val = numptr_val;
13121 } else if (op == TOK_CONDITIONAL) {
13123 numptr_val : numptr_m1->contidional_second_val;
13124 } else if (op == TOK_EXPONENT) {
13125 if (numptr_val < 0)
13126 return -3; /* exponent less than 0 */
13131 while (numptr_val--)
13135 } else if (numptr_val==0) /* zero divisor check */
13137 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13139 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13142 if (tok_have_assign(op)) {
13143 char buf[sizeof(arith_t_type)*3 + 2];
13145 if (numptr_m1->var == NULL) {
13149 /* save to shell variable */
13150 #if ENABLE_ASH_MATH_SUPPORT_64
13151 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
13153 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
13155 setvar(numptr_m1->var, buf, 0);
13156 /* after saving, make previous value for v++ or v-- */
13157 if (op == TOK_POST_INC)
13159 else if (op == TOK_POST_DEC)
13162 numptr_m1->val = rez;
13163 /* protect geting var value, is number now */
13164 numptr_m1->var = NULL;
13170 /* longest must be first */
13171 static const char op_tokens[] ALIGN1 = {
13172 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13173 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13174 '<','<', 0, TOK_LSHIFT,
13175 '>','>', 0, TOK_RSHIFT,
13176 '|','|', 0, TOK_OR,
13177 '&','&', 0, TOK_AND,
13178 '!','=', 0, TOK_NE,
13179 '<','=', 0, TOK_LE,
13180 '>','=', 0, TOK_GE,
13181 '=','=', 0, TOK_EQ,
13182 '|','=', 0, TOK_OR_ASSIGN,
13183 '&','=', 0, TOK_AND_ASSIGN,
13184 '*','=', 0, TOK_MUL_ASSIGN,
13185 '/','=', 0, TOK_DIV_ASSIGN,
13186 '%','=', 0, TOK_REM_ASSIGN,
13187 '+','=', 0, TOK_PLUS_ASSIGN,
13188 '-','=', 0, TOK_MINUS_ASSIGN,
13189 '-','-', 0, TOK_POST_DEC,
13190 '^','=', 0, TOK_XOR_ASSIGN,
13191 '+','+', 0, TOK_POST_INC,
13192 '*','*', 0, TOK_EXPONENT,
13196 '=', 0, TOK_ASSIGN,
13208 '?', 0, TOK_CONDITIONAL,
13209 ':', 0, TOK_CONDITIONAL_SEP,
13210 ')', 0, TOK_RPAREN,
13211 '(', 0, TOK_LPAREN,
13215 #define endexpression (&op_tokens[sizeof(op_tokens)-7])
13218 arith(const char *expr, int *perrcode)
13220 char arithval; /* Current character under analysis */
13221 operator lasttok, op;
13223 operator *stack, *stackptr;
13224 const char *p = endexpression;
13226 v_n_t *numstack, *numstackptr;
13227 unsigned datasizes = strlen(expr) + 2;
13229 /* Stack of integers */
13230 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13231 * in any given correct or incorrect expression is left as an exercise to
13233 numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0]));
13234 /* Stack of operator tokens */
13235 stackptr = stack = alloca(datasizes * sizeof(stack[0]));
13237 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13238 *perrcode = errcode = 0;
13242 if (arithval == 0) {
13243 if (p == endexpression) {
13244 /* Null expression. */
13248 /* This is only reached after all tokens have been extracted from the
13249 * input stream. If there are still tokens on the operator stack, they
13250 * are to be applied in order. At the end, there should be a final
13251 * result on the integer stack */
13253 if (expr != endexpression + 1) {
13254 /* If we haven't done so already, */
13255 /* append a closing right paren */
13256 expr = endexpression;
13257 /* and let the loop process it. */
13260 /* At this point, we're done with the expression. */
13261 if (numstackptr != numstack+1) {
13262 /* ... but if there isn't, it's bad */
13267 if (numstack->var) {
13268 /* expression is $((var)) only, lookup now */
13269 errcode = arith_lookup_val(numstack);
13272 *perrcode = errcode;
13273 return numstack->val;
13276 /* Continue processing the expression. */
13277 if (arith_isspace(arithval)) {
13278 /* Skip whitespace */
13281 p = endofname(expr);
13283 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13285 numstackptr->var = alloca(var_name_size);
13286 safe_strncpy(numstackptr->var, expr, var_name_size);
13289 numstackptr->contidional_second_val_initialized = 0;
13294 if (isdigit(arithval)) {
13295 numstackptr->var = NULL;
13296 #if ENABLE_ASH_MATH_SUPPORT_64
13297 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13299 numstackptr->val = strtol(expr, (char **) &expr, 0);
13303 for (p = op_tokens; ; p++) {
13307 /* strange operator not found */
13310 for (o = expr; *p && *o == *p; p++)
13317 /* skip tail uncompared token */
13320 /* skip zero delim */
13325 /* post grammar: a++ reduce to num */
13326 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13329 /* Plus and minus are binary (not unary) _only_ if the last
13330 * token was as number, or a right paren (which pretends to be
13331 * a number, since it evaluates to one). Think about it.
13332 * It makes sense. */
13333 if (lasttok != TOK_NUM) {
13349 /* We don't want a unary operator to cause recursive descent on the
13350 * stack, because there can be many in a row and it could cause an
13351 * operator to be evaluated before its argument is pushed onto the
13352 * integer stack. */
13353 /* But for binary operators, "apply" everything on the operator
13354 * stack until we find an operator with a lesser priority than the
13355 * one we have just extracted. */
13356 /* Left paren is given the lowest priority so it will never be
13357 * "applied" in this way.
13358 * if associativity is right and priority eq, applied also skip
13361 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13362 /* not left paren or unary */
13363 if (lasttok != TOK_NUM) {
13364 /* binary op must be preceded by a num */
13367 while (stackptr != stack) {
13368 if (op == TOK_RPAREN) {
13369 /* The algorithm employed here is simple: while we don't
13370 * hit an open paren nor the bottom of the stack, pop
13371 * tokens and apply them */
13372 if (stackptr[-1] == TOK_LPAREN) {
13374 /* Any operator directly after a */
13376 /* close paren should consider itself binary */
13380 operator prev_prec = PREC(stackptr[-1]);
13382 convert_prec_is_assing(prec);
13383 convert_prec_is_assing(prev_prec);
13384 if (prev_prec < prec)
13386 /* check right assoc */
13387 if (prev_prec == prec && is_right_associativity(prec))
13390 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13391 if (errcode) goto ret;
13393 if (op == TOK_RPAREN) {
13398 /* Push this operator to the stack and remember it. */
13399 *stackptr++ = lasttok = op;
13404 #endif /* ASH_MATH_SUPPORT */
13407 /* ============ main() and helpers */
13410 * Called to exit the shell.
13412 static void exitshell(void) NORETURN;
13420 status = exitstatus;
13421 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13422 if (setjmp(loc.loc)) {
13423 if (exception == EXEXIT)
13424 /* dash bug: it just does _exit(exitstatus) here
13425 * but we have to do setjobctl(0) first!
13426 * (bug is still not fixed in dash-0.5.3 - if you run dash
13427 * under Midnight Commander, on exit from dash MC is backgrounded) */
13428 status = exitstatus;
13431 exception_handler = &loc;
13437 flush_stdout_stderr();
13447 /* from input.c: */
13448 basepf.nextc = basepf.buf = basebuf;
13451 signal(SIGCHLD, SIG_DFL);
13456 char ppid[sizeof(int)*3 + 1];
13458 struct stat st1, st2;
13461 for (envp = environ; envp && *envp; envp++) {
13462 if (strchr(*envp, '=')) {
13463 setvareq(*envp, VEXPORT|VTEXTFIXED);
13467 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
13468 setvar("PPID", ppid, 0);
13470 p = lookupvar("PWD");
13472 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
13473 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
13480 * Process the shell command line arguments.
13483 procargs(char **argv)
13486 const char *xminusc;
13491 /* if (xargv[0]) - mmm, this is always true! */
13493 for (i = 0; i < NOPTS; i++)
13497 /* it already printed err message */
13498 raise_exception(EXERROR);
13502 if (*xargv == NULL) {
13504 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13507 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13511 for (i = 0; i < NOPTS; i++)
13512 if (optlist[i] == 2)
13517 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13522 } else if (!sflag) {
13523 setinputfile(*xargv, 0);
13526 commandname = arg0;
13529 shellparam.p = xargv;
13530 #if ENABLE_ASH_GETOPTS
13531 shellparam.optind = 1;
13532 shellparam.optoff = -1;
13534 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13536 shellparam.nparam++;
13543 * Read /etc/profile or .profile.
13546 read_profile(const char *name)
13550 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13559 * This routine is called when an error or an interrupt occurs in an
13560 * interactive shell and control is returned to the main command loop.
13568 /* from input.c: */
13569 parselleft = parsenleft = 0; /* clear input buffer */
13571 /* from parser.c: */
13574 /* from redir.c: */
13575 clearredir(/*drop:*/ 0);
13579 static short profile_buf[16384];
13580 extern int etext();
13584 * Main routine. We initialize things, parse the arguments, execute
13585 * profiles if we're a login shell, and then call cmdloop to execute
13586 * commands. The setjmp call sets up the location to jump to when an
13587 * exception occurs. When an exception occurs the variable "state"
13588 * is used to figure out how far we had gotten.
13590 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13591 int ash_main(int argc UNUSED_PARAM, char **argv)
13594 volatile int state;
13595 struct jmploc jmploc;
13596 struct stackmark smark;
13598 /* Initialize global data */
13602 #if ENABLE_ASH_ALIAS
13608 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13611 #if ENABLE_FEATURE_EDITING
13612 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13615 if (setjmp(jmploc.loc)) {
13625 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13629 outcslow('\n', stderr);
13631 popstackmark(&smark);
13632 FORCE_INT_ON; /* enable interrupts */
13641 exception_handler = &jmploc;
13644 trace_puts("Shell args: ");
13645 trace_puts_args(argv);
13647 rootpid = getpid();
13649 #if ENABLE_ASH_RANDOM_SUPPORT
13650 /* Can use monotonic_ns() for better randomness but for now it is
13651 * not used anywhere else in busybox... so avoid bloat */
13652 random_galois_LFSR = random_LCG = rootpid + monotonic_us();
13655 setstackmark(&smark);
13658 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13660 const char *hp = lookupvar("HISTFILE");
13663 hp = lookupvar("HOME");
13665 char *defhp = concat_path_file(hp, ".ash_history");
13666 setvar("HISTFILE", defhp, 0);
13672 if (argv[0] && argv[0][0] == '-')
13676 read_profile("/etc/profile");
13679 read_profile(".profile");
13685 getuid() == geteuid() && getgid() == getegid() &&
13689 shinit = lookupvar("ENV");
13690 if (shinit != NULL && *shinit != '\0') {
13691 read_profile(shinit);
13697 evalstring(minusc, 0);
13699 if (sflag || minusc == NULL) {
13700 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13702 const char *hp = lookupvar("HISTFILE");
13705 line_input_state->hist_file = hp;
13708 state4: /* XXX ??? - why isn't this before the "if" statement */
13716 extern void _mcleanup(void);
13725 const char *applet_name = "debug stuff usage";
13726 int main(int argc, char **argv)
13728 return ash_main(argc, argv);
13734 * Copyright (c) 1989, 1991, 1993, 1994
13735 * The Regents of the University of California. All rights reserved.
13737 * This code is derived from software contributed to Berkeley by
13738 * Kenneth Almquist.
13740 * Redistribution and use in source and binary forms, with or without
13741 * modification, are permitted provided that the following conditions
13743 * 1. Redistributions of source code must retain the above copyright
13744 * notice, this list of conditions and the following disclaimer.
13745 * 2. Redistributions in binary form must reproduce the above copyright
13746 * notice, this list of conditions and the following disclaimer in the
13747 * documentation and/or other materials provided with the distribution.
13748 * 3. Neither the name of the University nor the names of its contributors
13749 * may be used to endorse or promote products derived from this software
13750 * without specific prior written permission.
13752 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13753 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13754 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13755 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13756 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13757 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13758 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13759 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13760 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13761 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF