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
544 smallint type; /* Nxxxx */
547 union node *redirect;
552 smallint pipe_backgnd;
553 struct nodelist *cmdlist;
559 union node *redirect;
572 union node *elsepart;
599 struct nodelist *backquote;
602 /* nfile and ndup layout must match!
603 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
604 * that it is actually NTO2 (>&file), and change its type.
621 char *_unused_expfname;
640 struct nredir nredir;
641 struct nbinary nbinary;
645 struct nclist nclist;
654 struct nodelist *next;
667 freefunc(struct funcnode *f)
669 if (f && --f->count < 0)
674 /* ============ Debugging output */
678 static FILE *tracefile;
681 trace_printf(const char *fmt, ...)
688 vfprintf(tracefile, fmt, va);
693 trace_vprintf(const char *fmt, va_list va)
697 vfprintf(tracefile, fmt, va);
701 trace_puts(const char *s)
709 trace_puts_quoted(char *s)
716 putc('"', tracefile);
717 for (p = s; *p; p++) {
719 case '\n': c = 'n'; goto backslash;
720 case '\t': c = 't'; goto backslash;
721 case '\r': c = 'r'; goto backslash;
722 case '"': c = '"'; goto backslash;
723 case '\\': c = '\\'; goto backslash;
724 case CTLESC: c = 'e'; goto backslash;
725 case CTLVAR: c = 'v'; goto backslash;
726 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
727 case CTLBACKQ: c = 'q'; goto backslash;
728 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
730 putc('\\', tracefile);
734 if (*p >= ' ' && *p <= '~')
737 putc('\\', tracefile);
738 putc(*p >> 6 & 03, tracefile);
739 putc(*p >> 3 & 07, tracefile);
740 putc(*p & 07, tracefile);
745 putc('"', tracefile);
749 trace_puts_args(char **ap)
756 trace_puts_quoted(*ap);
758 putc('\n', tracefile);
761 putc(' ', tracefile);
776 /* leave open because libedit might be using it */
779 strcpy(s, "./trace");
781 if (!freopen(s, "a", tracefile)) {
782 fprintf(stderr, "Can't re-open %s\n", s);
787 tracefile = fopen(s, "a");
788 if (tracefile == NULL) {
789 fprintf(stderr, "Can't open %s\n", s);
795 flags = fcntl(fileno(tracefile), F_GETFL);
797 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
799 setlinebuf(tracefile);
800 fputs("\nTracing started.\n", tracefile);
804 indent(int amount, char *pfx, FILE *fp)
808 for (i = 0; i < amount; i++) {
809 if (pfx && i == amount - 1)
815 /* little circular references here... */
816 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
819 sharg(union node *arg, FILE *fp)
822 struct nodelist *bqlist;
825 if (arg->type != NARG) {
826 out1fmt("<node type %d>\n", arg->type);
829 bqlist = arg->narg.backquote;
830 for (p = arg->narg.text; *p; p++) {
839 if (subtype == VSLENGTH)
848 switch (subtype & VSTYPE) {
881 out1fmt("<subtype %d>", subtype);
888 case CTLBACKQ|CTLQUOTE:
891 shtree(bqlist->n, -1, NULL, fp);
902 shcmd(union node *cmd, FILE *fp)
910 for (np = cmd->ncmd.args; np; np = np->narg.next) {
916 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
920 switch (np->nfile.type) {
921 case NTO: s = ">>"+1; dftfd = 1; break;
922 case NCLOBBER: s = ">|"; dftfd = 1; break;
923 case NAPPEND: s = ">>"; dftfd = 1; break;
924 #if ENABLE_ASH_BASH_COMPAT
927 case NTOFD: s = ">&"; dftfd = 1; break;
928 case NFROM: s = "<"; break;
929 case NFROMFD: s = "<&"; break;
930 case NFROMTO: s = "<>"; break;
931 default: s = "*error*"; break;
933 if (np->nfile.fd != dftfd)
934 fprintf(fp, "%d", np->nfile.fd);
936 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
937 fprintf(fp, "%d", np->ndup.dupfd);
939 sharg(np->nfile.fname, fp);
946 shtree(union node *n, int ind, char *pfx, FILE *fp)
954 indent(ind, pfx, fp);
965 shtree(n->nbinary.ch1, ind, NULL, fp);
968 shtree(n->nbinary.ch2, ind, NULL, fp);
976 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
981 if (n->npipe.pipe_backgnd)
987 fprintf(fp, "<node type %d>", n->type);
995 showtree(union node *n)
997 trace_puts("showtree called\n");
998 shtree(n, 1, NULL, stdout);
1001 #define TRACE(param) trace_printf param
1002 #define TRACEV(param) trace_vprintf param
1006 #define TRACE(param)
1007 #define TRACEV(param)
1012 /* ============ Parser data */
1015 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1018 struct strlist *next;
1025 struct strpush *prev; /* preceding string on stack */
1028 #if ENABLE_ASH_ALIAS
1029 struct alias *ap; /* if push was associated with an alias */
1031 char *string; /* remember the string since it may change */
1035 struct parsefile *prev; /* preceding file on stack */
1036 int linno; /* current line */
1037 int fd; /* file descriptor (or -1 if string) */
1038 int nleft; /* number of chars left in this line */
1039 int lleft; /* number of chars left in this buffer */
1040 char *nextc; /* next char in buffer */
1041 char *buf; /* input buffer */
1042 struct strpush *strpush; /* for pushing strings at this level */
1043 struct strpush basestrpush; /* so pushing one is fast */
1046 static struct parsefile basepf; /* top level input file */
1047 static struct parsefile *g_parsefile = &basepf; /* current input file */
1048 static int startlinno; /* line # where last token started */
1049 static char *commandname; /* currently executing command */
1050 static struct strlist *cmdenviron; /* environment for builtin command */
1051 static uint8_t exitstatus; /* exit status of last command */
1054 /* ============ Message printing */
1057 ash_vmsg(const char *msg, va_list ap)
1059 fprintf(stderr, "%s: ", arg0);
1061 if (strcmp(arg0, commandname))
1062 fprintf(stderr, "%s: ", commandname);
1063 if (!iflag || g_parsefile->fd)
1064 fprintf(stderr, "line %d: ", startlinno);
1066 vfprintf(stderr, msg, ap);
1067 outcslow('\n', stderr);
1071 * Exverror is called to raise the error exception. If the second argument
1072 * is not NULL then error prints an error message using printf style
1073 * formatting. It then raises the error exception.
1075 static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1077 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1081 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1083 TRACE(("\") pid=%d\n", getpid()));
1085 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1090 flush_stdout_stderr();
1091 raise_exception(cond);
1095 static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1097 ash_msg_and_raise_error(const char *msg, ...)
1102 ash_vmsg_and_raise(EXERROR, msg, ap);
1107 static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1109 ash_msg_and_raise(int cond, const char *msg, ...)
1114 ash_vmsg_and_raise(cond, msg, ap);
1120 * error/warning routines for external builtins
1123 ash_msg(const char *fmt, ...)
1133 * Return a string describing an error. The returned string may be a
1134 * pointer to a static buffer that will be overwritten on the next call.
1135 * Action describes the operation that got the error.
1138 errmsg(int e, const char *em)
1140 if (e == ENOENT || e == ENOTDIR) {
1147 /* ============ Memory allocation */
1150 * It appears that grabstackstr() will barf with such alignments
1151 * because stalloc() will return a string allocated in a new stackblock.
1153 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1155 /* Most machines require the value returned from malloc to be aligned
1156 * in some way. The following macro will get this right
1157 * on many machines. */
1158 SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,
1159 /* Minimum size of a block */
1160 MINSIZE = SHELL_ALIGN(504),
1163 struct stack_block {
1164 struct stack_block *prev;
1165 char space[MINSIZE];
1169 struct stack_block *stackp;
1172 struct stackmark *marknext;
1176 struct globals_memstack {
1177 struct stack_block *g_stackp; // = &stackbase;
1178 struct stackmark *markp;
1179 char *g_stacknxt; // = stackbase.space;
1180 char *sstrend; // = stackbase.space + MINSIZE;
1181 size_t g_stacknleft; // = MINSIZE;
1182 int herefd; // = -1;
1183 struct stack_block stackbase;
1185 extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1186 #define G_memstack (*ash_ptr_to_globals_memstack)
1187 #define g_stackp (G_memstack.g_stackp )
1188 #define markp (G_memstack.markp )
1189 #define g_stacknxt (G_memstack.g_stacknxt )
1190 #define sstrend (G_memstack.sstrend )
1191 #define g_stacknleft (G_memstack.g_stacknleft)
1192 #define herefd (G_memstack.herefd )
1193 #define stackbase (G_memstack.stackbase )
1194 #define INIT_G_memstack() do { \
1195 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1197 g_stackp = &stackbase; \
1198 g_stacknxt = stackbase.space; \
1199 g_stacknleft = MINSIZE; \
1200 sstrend = stackbase.space + MINSIZE; \
1204 #define stackblock() ((void *)g_stacknxt)
1205 #define stackblocksize() g_stacknleft
1209 ckrealloc(void * p, size_t nbytes)
1211 p = realloc(p, nbytes);
1213 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1218 ckmalloc(size_t nbytes)
1220 return ckrealloc(NULL, nbytes);
1224 ckzalloc(size_t nbytes)
1226 return memset(ckmalloc(nbytes), 0, nbytes);
1230 * Make a copy of a string in safe storage.
1233 ckstrdup(const char *s)
1235 char *p = strdup(s);
1237 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1242 * Parse trees for commands are allocated in lifo order, so we use a stack
1243 * to make this more efficient, and also to avoid all sorts of exception
1244 * handling code to handle interrupts in the middle of a parse.
1246 * The size 504 was chosen because the Ultrix malloc handles that size
1250 stalloc(size_t nbytes)
1255 aligned = SHELL_ALIGN(nbytes);
1256 if (aligned > g_stacknleft) {
1259 struct stack_block *sp;
1261 blocksize = aligned;
1262 if (blocksize < MINSIZE)
1263 blocksize = MINSIZE;
1264 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1265 if (len < blocksize)
1266 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1269 sp->prev = g_stackp;
1270 g_stacknxt = sp->space;
1271 g_stacknleft = blocksize;
1272 sstrend = g_stacknxt + blocksize;
1277 g_stacknxt += aligned;
1278 g_stacknleft -= aligned;
1283 stzalloc(size_t nbytes)
1285 return memset(stalloc(nbytes), 0, nbytes);
1292 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1293 write(STDERR_FILENO, "stunalloc\n", 10);
1297 g_stacknleft += g_stacknxt - (char *)p;
1302 * Like strdup but works with the ash stack.
1305 ststrdup(const char *p)
1307 size_t len = strlen(p) + 1;
1308 return memcpy(stalloc(len), p, len);
1312 setstackmark(struct stackmark *mark)
1314 mark->stackp = g_stackp;
1315 mark->stacknxt = g_stacknxt;
1316 mark->stacknleft = g_stacknleft;
1317 mark->marknext = markp;
1322 popstackmark(struct stackmark *mark)
1324 struct stack_block *sp;
1330 markp = mark->marknext;
1331 while (g_stackp != mark->stackp) {
1333 g_stackp = sp->prev;
1336 g_stacknxt = mark->stacknxt;
1337 g_stacknleft = mark->stacknleft;
1338 sstrend = mark->stacknxt + mark->stacknleft;
1343 * When the parser reads in a string, it wants to stick the string on the
1344 * stack and only adjust the stack pointer when it knows how big the
1345 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1346 * of space on top of the stack and stackblocklen returns the length of
1347 * this block. Growstackblock will grow this space by at least one byte,
1348 * possibly moving it (like realloc). Grabstackblock actually allocates the
1349 * part of the block that has been used.
1352 growstackblock(void)
1356 newlen = g_stacknleft * 2;
1357 if (newlen < g_stacknleft)
1358 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1362 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1363 struct stack_block *oldstackp;
1364 struct stackmark *xmark;
1365 struct stack_block *sp;
1366 struct stack_block *prevstackp;
1370 oldstackp = g_stackp;
1372 prevstackp = sp->prev;
1373 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1374 sp = ckrealloc(sp, grosslen);
1375 sp->prev = prevstackp;
1377 g_stacknxt = sp->space;
1378 g_stacknleft = newlen;
1379 sstrend = sp->space + newlen;
1382 * Stack marks pointing to the start of the old block
1383 * must be relocated to point to the new block
1386 while (xmark != NULL && xmark->stackp == oldstackp) {
1387 xmark->stackp = g_stackp;
1388 xmark->stacknxt = g_stacknxt;
1389 xmark->stacknleft = g_stacknleft;
1390 xmark = xmark->marknext;
1394 char *oldspace = g_stacknxt;
1395 size_t oldlen = g_stacknleft;
1396 char *p = stalloc(newlen);
1398 /* free the space we just allocated */
1399 g_stacknxt = memcpy(p, oldspace, oldlen);
1400 g_stacknleft += newlen;
1405 grabstackblock(size_t len)
1407 len = SHELL_ALIGN(len);
1409 g_stacknleft -= len;
1413 * The following routines are somewhat easier to use than the above.
1414 * The user declares a variable of type STACKSTR, which may be declared
1415 * to be a register. The macro STARTSTACKSTR initializes things. Then
1416 * the user uses the macro STPUTC to add characters to the string. In
1417 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1418 * grown as necessary. When the user is done, she can just leave the
1419 * string there and refer to it using stackblock(). Or she can allocate
1420 * the space for it using grabstackstr(). If it is necessary to allow
1421 * someone else to use the stack temporarily and then continue to grow
1422 * the string, the user should use grabstack to allocate the space, and
1423 * then call ungrabstr(p) to return to the previous mode of operation.
1425 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1426 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1427 * is space for at least one character.
1432 size_t len = stackblocksize();
1433 if (herefd >= 0 && len >= 1024) {
1434 full_write(herefd, stackblock(), len);
1435 return stackblock();
1438 return (char *)stackblock() + len;
1442 * Called from CHECKSTRSPACE.
1445 makestrspace(size_t newlen, char *p)
1447 size_t len = p - g_stacknxt;
1448 size_t size = stackblocksize();
1453 size = stackblocksize();
1455 if (nleft >= newlen)
1459 return (char *)stackblock() + len;
1463 stack_nputstr(const char *s, size_t n, char *p)
1465 p = makestrspace(n, p);
1466 p = (char *)memcpy(p, s, n) + n;
1471 stack_putstr(const char *s, char *p)
1473 return stack_nputstr(s, strlen(s), p);
1477 _STPUTC(int c, char *p)
1485 #define STARTSTACKSTR(p) ((p) = stackblock())
1486 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1487 #define CHECKSTRSPACE(n, p) do { \
1490 size_t m = sstrend - q; \
1492 (p) = makestrspace(l, q); \
1494 #define USTPUTC(c, p) (*(p)++ = (c))
1495 #define STACKSTRNUL(p) do { \
1496 if ((p) == sstrend) \
1497 (p) = growstackstr(); \
1500 #define STUNPUTC(p) (--(p))
1501 #define STTOPC(p) ((p)[-1])
1502 #define STADJUST(amount, p) ((p) += (amount))
1504 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1505 #define ungrabstackstr(s, p) stunalloc(s)
1506 #define stackstrend() ((void *)sstrend)
1509 /* ============ String helpers */
1512 * prefix -- see if pfx is a prefix of string.
1515 prefix(const char *string, const char *pfx)
1518 if (*pfx++ != *string++)
1521 return (char *) string;
1525 * Check for a valid number. This should be elsewhere.
1528 is_number(const char *p)
1533 } while (*++p != '\0');
1538 * Convert a string of digits to an integer, printing an error message on
1542 number(const char *s)
1545 ash_msg_and_raise_error(illnum, s);
1550 * Produce a possibly single quoted string suitable as input to the shell.
1551 * The return string is allocated on the stack.
1554 single_quote(const char *s)
1564 len = strchrnul(s, '\'') - s;
1566 q = p = makestrspace(len + 3, p);
1569 q = (char *)memcpy(q, s, len) + len;
1575 len = strspn(s, "'");
1579 q = p = makestrspace(len + 3, p);
1582 q = (char *)memcpy(q, s, len) + len;
1591 return stackblock();
1595 /* ============ nextopt */
1597 static char **argptr; /* argument list for builtin commands */
1598 static char *optionarg; /* set by nextopt (like getopt) */
1599 static char *optptr; /* used by nextopt */
1602 * XXX - should get rid of. Have all builtins use getopt(3).
1603 * The library getopt must have the BSD extension static variable
1604 * "optreset", otherwise it can't be used within the shell safely.
1606 * Standard option processing (a la getopt) for builtin routines.
1607 * The only argument that is passed to nextopt is the option string;
1608 * the other arguments are unnecessary. It returns the character,
1609 * or '\0' on end of input.
1612 nextopt(const char *optstring)
1619 if (p == NULL || *p == '\0') {
1620 /* We ate entire "-param", take next one */
1626 if (*++p == '\0') /* just "-" ? */
1629 if (LONE_DASH(p)) /* "--" ? */
1631 /* p => next "-param" */
1633 /* p => some option char in the middle of a "-param" */
1635 for (q = optstring; *q != c;) {
1637 ash_msg_and_raise_error("illegal option -%c", c);
1645 ash_msg_and_raise_error("no arg for -%c option", c);
1655 /* ============ Shell variables */
1658 * The parsefile structure pointed to by the global variable parsefile
1659 * contains information about the current file being read.
1662 int nparam; /* # of positional parameters (without $0) */
1663 #if ENABLE_ASH_GETOPTS
1664 int optind; /* next parameter to be processed by getopts */
1665 int optoff; /* used by getopts */
1667 unsigned char malloced; /* if parameter list dynamically allocated */
1668 char **p; /* parameter list */
1672 * Free the list of positional parameters.
1675 freeparam(volatile struct shparam *param)
1677 if (param->malloced) {
1679 ap = ap1 = param->p;
1686 #if ENABLE_ASH_GETOPTS
1687 static void getoptsreset(const char *value);
1691 struct var *next; /* next entry in hash list */
1692 int flags; /* flags are defined above */
1693 const char *text; /* name=value */
1694 void (*func)(const char *); /* function to be called when */
1695 /* the variable gets set/unset */
1699 struct localvar *next; /* next local variable in list */
1700 struct var *vp; /* the variable that was made local */
1701 int flags; /* saved flags */
1702 const char *text; /* saved text */
1706 #define VEXPORT 0x01 /* variable is exported */
1707 #define VREADONLY 0x02 /* variable cannot be modified */
1708 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1709 #define VTEXTFIXED 0x08 /* text is statically allocated */
1710 #define VSTACK 0x10 /* text is allocated on the stack */
1711 #define VUNSET 0x20 /* the variable is not set */
1712 #define VNOFUNC 0x40 /* don't call the callback function */
1713 #define VNOSET 0x80 /* do not set variable - just readonly test */
1714 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1715 #if ENABLE_ASH_RANDOM_SUPPORT
1716 # define VDYNAMIC 0x200 /* dynamic variable */
1722 static const char defifsvar[] ALIGN1 = "IFS= \t\n";
1723 #define defifs (defifsvar + 4)
1725 static const char defifs[] ALIGN1 = " \t\n";
1729 /* Need to be before varinit_data[] */
1730 #if ENABLE_LOCALE_SUPPORT
1732 change_lc_all(const char *value)
1734 if (value && *value != '\0')
1735 setlocale(LC_ALL, value);
1738 change_lc_ctype(const char *value)
1740 if (value && *value != '\0')
1741 setlocale(LC_CTYPE, value);
1745 static void chkmail(void);
1746 static void changemail(const char *);
1748 static void changepath(const char *);
1749 #if ENABLE_ASH_RANDOM_SUPPORT
1750 static void change_random(const char *);
1753 static const struct {
1756 void (*func)(const char *);
1757 } varinit_data[] = {
1759 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1761 { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL },
1764 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0" , changemail },
1765 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1767 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1768 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1769 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1770 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1771 #if ENABLE_ASH_GETOPTS
1772 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
1774 #if ENABLE_ASH_RANDOM_SUPPORT
1775 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1777 #if ENABLE_LOCALE_SUPPORT
1778 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL\0" , change_lc_all },
1779 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE\0", change_lc_ctype },
1781 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1782 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE\0", NULL },
1788 struct globals_var {
1789 struct shparam shellparam; /* $@ current positional parameters */
1790 struct redirtab *redirlist;
1792 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1793 struct var *vartab[VTABSIZE];
1794 struct var varinit[ARRAY_SIZE(varinit_data)];
1796 extern struct globals_var *const ash_ptr_to_globals_var;
1797 #define G_var (*ash_ptr_to_globals_var)
1798 #define shellparam (G_var.shellparam )
1799 //#define redirlist (G_var.redirlist )
1800 #define g_nullredirs (G_var.g_nullredirs )
1801 #define preverrout_fd (G_var.preverrout_fd)
1802 #define vartab (G_var.vartab )
1803 #define varinit (G_var.varinit )
1804 #define INIT_G_var() do { \
1806 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1808 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1809 varinit[i].flags = varinit_data[i].flags; \
1810 varinit[i].text = varinit_data[i].text; \
1811 varinit[i].func = varinit_data[i].func; \
1815 #define vifs varinit[0]
1817 # define vmail (&vifs)[1]
1818 # define vmpath (&vmail)[1]
1819 # define vpath (&vmpath)[1]
1821 # define vpath (&vifs)[1]
1823 #define vps1 (&vpath)[1]
1824 #define vps2 (&vps1)[1]
1825 #define vps4 (&vps2)[1]
1826 #if ENABLE_ASH_GETOPTS
1827 # define voptind (&vps4)[1]
1828 # if ENABLE_ASH_RANDOM_SUPPORT
1829 # define vrandom (&voptind)[1]
1832 # if ENABLE_ASH_RANDOM_SUPPORT
1833 # define vrandom (&vps4)[1]
1838 * The following macros access the values of the above variables.
1839 * They have to skip over the name. They return the null string
1840 * for unset variables.
1842 #define ifsval() (vifs.text + 4)
1843 #define ifsset() ((vifs.flags & VUNSET) == 0)
1845 # define mailval() (vmail.text + 5)
1846 # define mpathval() (vmpath.text + 9)
1847 # define mpathset() ((vmpath.flags & VUNSET) == 0)
1849 #define pathval() (vpath.text + 5)
1850 #define ps1val() (vps1.text + 4)
1851 #define ps2val() (vps2.text + 4)
1852 #define ps4val() (vps4.text + 4)
1853 #if ENABLE_ASH_GETOPTS
1854 # define optindval() (voptind.text + 7)
1858 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1859 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1861 #if ENABLE_ASH_GETOPTS
1863 getoptsreset(const char *value)
1865 shellparam.optind = number(value);
1866 shellparam.optoff = -1;
1871 * Return of a legal variable name (a letter or underscore followed by zero or
1872 * more letters, underscores, and digits).
1875 endofname(const char *name)
1883 if (!is_in_name(*p))
1890 * Compares two strings up to the first = or '\0'. The first
1891 * string must be terminated by '='; the second may be terminated by
1892 * either '=' or '\0'.
1895 varcmp(const char *p, const char *q)
1899 while ((c = *p) == (d = *q)) {
1914 varequal(const char *a, const char *b)
1916 return !varcmp(a, b);
1920 * Find the appropriate entry in the hash table from the name.
1922 static struct var **
1923 hashvar(const char *p)
1927 hashval = ((unsigned char) *p) << 4;
1928 while (*p && *p != '=')
1929 hashval += (unsigned char) *p++;
1930 return &vartab[hashval % VTABSIZE];
1934 vpcmp(const void *a, const void *b)
1936 return varcmp(*(const char **)a, *(const char **)b);
1940 * This routine initializes the builtin variables.
1950 * PS1 depends on uid
1952 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1953 vps1.text = "PS1=\\w \\$ ";
1956 vps1.text = "PS1=# ";
1959 end = vp + ARRAY_SIZE(varinit);
1961 vpp = hashvar(vp->text);
1964 } while (++vp < end);
1967 static struct var **
1968 findvar(struct var **vpp, const char *name)
1970 for (; *vpp; vpp = &(*vpp)->next) {
1971 if (varequal((*vpp)->text, name)) {
1979 * Find the value of a variable. Returns NULL if not set.
1982 lookupvar(const char *name)
1986 v = *findvar(hashvar(name), name);
1988 #if ENABLE_ASH_RANDOM_SUPPORT
1990 * Dynamic variables are implemented roughly the same way they are
1991 * in bash. Namely, they're "special" so long as they aren't unset.
1992 * As soon as they're unset, they're no longer dynamic, and dynamic
1993 * lookup will no longer happen at that point. -- PFM.
1995 if ((v->flags & VDYNAMIC))
1998 if (!(v->flags & VUNSET))
1999 return strchrnul(v->text, '=') + 1;
2005 * Search the environment of a builtin command.
2008 bltinlookup(const char *name)
2012 for (sp = cmdenviron; sp; sp = sp->next) {
2013 if (varequal(sp->text, name))
2014 return strchrnul(sp->text, '=') + 1;
2016 return lookupvar(name);
2020 * Same as setvar except that the variable and value are passed in
2021 * the first argument as name=value. Since the first argument will
2022 * be actually stored in the table, it should not be a string that
2024 * Called with interrupts off.
2027 setvareq(char *s, int flags)
2029 struct var *vp, **vpp;
2032 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2033 vp = *findvar(vpp, s);
2035 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2038 if (flags & VNOSAVE)
2041 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2047 if (vp->func && (flags & VNOFUNC) == 0)
2048 (*vp->func)(strchrnul(s, '=') + 1);
2050 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
2051 free((char*)vp->text);
2053 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2058 vp = ckzalloc(sizeof(*vp));
2060 /*vp->func = NULL; - ckzalloc did it */
2063 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2070 * Set the value of a variable. The flags argument is ored with the
2071 * flags of the variable. If val is NULL, the variable is unset.
2074 setvar(const char *name, const char *val, int flags)
2081 q = endofname(name);
2082 p = strchrnul(q, '=');
2084 if (!namelen || p != q)
2085 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2090 vallen = strlen(val);
2093 nameeq = ckmalloc(namelen + vallen + 2);
2094 p = (char *)memcpy(nameeq, name, namelen) + namelen;
2097 p = (char *)memcpy(p, val, vallen) + vallen;
2100 setvareq(nameeq, flags | VNOSAVE);
2104 #if ENABLE_ASH_GETOPTS
2106 * Safe version of setvar, returns 1 on success 0 on failure.
2109 setvarsafe(const char *name, const char *val, int flags)
2112 volatile int saveint;
2113 struct jmploc *volatile savehandler = exception_handler;
2114 struct jmploc jmploc;
2117 if (setjmp(jmploc.loc))
2120 exception_handler = &jmploc;
2121 setvar(name, val, flags);
2124 exception_handler = savehandler;
2125 RESTORE_INT(saveint);
2131 * Unset the specified variable.
2134 unsetvar(const char *s)
2140 vpp = findvar(hashvar(s), s);
2144 int flags = vp->flags;
2147 if (flags & VREADONLY)
2149 #if ENABLE_ASH_RANDOM_SUPPORT
2150 vp->flags &= ~VDYNAMIC;
2154 if ((flags & VSTRFIXED) == 0) {
2156 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2157 free((char*)vp->text);
2163 vp->flags &= ~VEXPORT;
2173 * Process a linked list of variable assignments.
2176 listsetvar(struct strlist *list_set_var, int flags)
2178 struct strlist *lp = list_set_var;
2184 setvareq(lp->text, flags);
2191 * Generate a list of variables satisfying the given conditions.
2194 listvars(int on, int off, char ***end)
2205 for (vp = *vpp; vp; vp = vp->next) {
2206 if ((vp->flags & mask) == on) {
2207 if (ep == stackstrend())
2208 ep = growstackstr();
2209 *ep++ = (char *) vp->text;
2212 } while (++vpp < vartab + VTABSIZE);
2213 if (ep == stackstrend())
2214 ep = growstackstr();
2218 return grabstackstr(ep);
2222 /* ============ Path search helper
2224 * The variable path (passed by reference) should be set to the start
2225 * of the path before the first call; padvance will update
2226 * this value as it proceeds. Successive calls to padvance will return
2227 * the possible path expansions in sequence. If an option (indicated by
2228 * a percent sign) appears in the path entry then the global variable
2229 * pathopt will be set to point to it; otherwise pathopt will be set to
2232 static const char *pathopt; /* set by padvance */
2235 padvance(const char **path, const char *name)
2245 for (p = start; *p && *p != ':' && *p != '%'; p++)
2247 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2248 while (stackblocksize() < len)
2252 memcpy(q, start, p - start);
2260 while (*p && *p != ':')
2267 return stalloc(len);
2271 /* ============ Prompt */
2273 static smallint doprompt; /* if set, prompt the user */
2274 static smallint needprompt; /* true if interactive and at start of line */
2276 #if ENABLE_FEATURE_EDITING
2277 static line_input_t *line_input_state;
2278 static const char *cmdedit_prompt;
2280 putprompt(const char *s)
2282 if (ENABLE_ASH_EXPAND_PRMT) {
2283 free((char*)cmdedit_prompt);
2284 cmdedit_prompt = ckstrdup(s);
2291 putprompt(const char *s)
2297 #if ENABLE_ASH_EXPAND_PRMT
2298 /* expandstr() needs parsing machinery, so it is far away ahead... */
2299 static const char *expandstr(const char *ps);
2301 #define expandstr(s) s
2305 setprompt(int whichprompt)
2308 #if ENABLE_ASH_EXPAND_PRMT
2309 struct stackmark smark;
2314 switch (whichprompt) {
2324 #if ENABLE_ASH_EXPAND_PRMT
2325 setstackmark(&smark);
2326 stalloc(stackblocksize());
2328 putprompt(expandstr(prompt));
2329 #if ENABLE_ASH_EXPAND_PRMT
2330 popstackmark(&smark);
2335 /* ============ The cd and pwd commands */
2337 #define CD_PHYSICAL 1
2340 static int docd(const char *, int);
2349 while ((i = nextopt("LP"))) {
2351 flags ^= CD_PHYSICAL;
2360 * Update curdir (the name of the current directory) in response to a
2364 updatepwd(const char *dir)
2371 cdcomppath = ststrdup(dir);
2374 if (curdir == nullstr)
2376 new = stack_putstr(curdir, new);
2378 new = makestrspace(strlen(dir) + 2, new);
2379 lim = (char *)stackblock() + 1;
2383 if (new > lim && *lim == '/')
2388 if (dir[1] == '/' && dir[2] != '/') {
2394 p = strtok(cdcomppath, "/");
2398 if (p[1] == '.' && p[2] == '\0') {
2410 new = stack_putstr(p, new);
2418 return stackblock();
2422 * Find out what the current directory is. If we already know the current
2423 * directory, this routine returns immediately.
2428 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2429 return dir ? dir : nullstr;
2433 setpwd(const char *val, int setold)
2437 oldcur = dir = curdir;
2440 setvar("OLDPWD", oldcur, VEXPORT);
2443 if (physdir != nullstr) {
2444 if (physdir != oldcur)
2448 if (oldcur == val || !val) {
2454 dir = ckstrdup(val);
2455 if (oldcur != dir && oldcur != nullstr) {
2460 setvar("PWD", dir, VEXPORT);
2463 static void hashcd(void);
2466 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2467 * know that the current directory has changed.
2470 docd(const char *dest, int flags)
2472 const char *dir = 0;
2475 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2478 if (!(flags & CD_PHYSICAL)) {
2479 dir = updatepwd(dest);
2494 cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2506 dest = bltinlookup(homestr);
2507 else if (LONE_DASH(dest)) {
2508 dest = bltinlookup("OLDPWD");
2530 path = bltinlookup("CDPATH");
2539 p = padvance(&path, dest);
2540 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2544 if (!docd(p, flags))
2549 ash_msg_and_raise_error("can't cd to %s", dest);
2552 if (flags & CD_PRINT)
2553 out1fmt(snlfmt, curdir);
2558 pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2561 const char *dir = curdir;
2565 if (physdir == nullstr)
2569 out1fmt(snlfmt, dir);
2574 /* ============ ... */
2577 #define IBUFSIZ COMMON_BUFSIZE
2578 /* buffer for top level input file */
2579 #define basebuf bb_common_bufsiz1
2581 /* Syntax classes */
2582 #define CWORD 0 /* character is nothing special */
2583 #define CNL 1 /* newline character */
2584 #define CBACK 2 /* a backslash character */
2585 #define CSQUOTE 3 /* single quote */
2586 #define CDQUOTE 4 /* double quote */
2587 #define CENDQUOTE 5 /* a terminating quote */
2588 #define CBQUOTE 6 /* backwards single quote */
2589 #define CVAR 7 /* a dollar sign */
2590 #define CENDVAR 8 /* a '}' character */
2591 #define CLP 9 /* a left paren in arithmetic */
2592 #define CRP 10 /* a right paren in arithmetic */
2593 #define CENDFILE 11 /* end of file */
2594 #define CCTL 12 /* like CWORD, except it must be escaped */
2595 #define CSPCL 13 /* these terminate a word */
2596 #define CIGN 14 /* character should be ignored */
2598 #if ENABLE_ASH_ALIAS
2602 #define PEOA_OR_PEOF PEOA
2606 #define PEOA_OR_PEOF PEOF
2609 /* number syntax index */
2610 #define BASESYNTAX 0 /* not in quotes */
2611 #define DQSYNTAX 1 /* in double quotes */
2612 #define SQSYNTAX 2 /* in single quotes */
2613 #define ARISYNTAX 3 /* in arithmetic */
2614 #define PSSYNTAX 4 /* prompt */
2616 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
2617 #define USE_SIT_FUNCTION
2620 #if ENABLE_ASH_MATH_SUPPORT
2621 static const char S_I_T[][4] = {
2622 #if ENABLE_ASH_ALIAS
2623 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */
2625 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */
2626 { CNL, CNL, CNL, CNL }, /* 2, \n */
2627 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */
2628 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */
2629 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */
2630 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */
2631 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */
2632 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */
2633 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */
2634 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */
2635 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */
2636 #ifndef USE_SIT_FUNCTION
2637 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2638 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2639 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2643 static const char S_I_T[][3] = {
2644 #if ENABLE_ASH_ALIAS
2645 { CSPCL, CIGN, CIGN }, /* 0, PEOA */
2647 { CSPCL, CWORD, CWORD }, /* 1, ' ' */
2648 { CNL, CNL, CNL }, /* 2, \n */
2649 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */
2650 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */
2651 { CVAR, CVAR, CWORD }, /* 5, $ */
2652 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */
2653 { CSPCL, CWORD, CWORD }, /* 7, ( */
2654 { CSPCL, CWORD, CWORD }, /* 8, ) */
2655 { CBACK, CBACK, CCTL }, /* 9, \ */
2656 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */
2657 { CENDVAR, CENDVAR, CWORD }, /* 11, } */
2658 #ifndef USE_SIT_FUNCTION
2659 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2660 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2661 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2664 #endif /* ASH_MATH_SUPPORT */
2666 #ifdef USE_SIT_FUNCTION
2669 SIT(int c, int syntax)
2671 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2672 #if ENABLE_ASH_ALIAS
2673 static const char syntax_index_table[] ALIGN1 = {
2674 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2675 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2676 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2680 static const char syntax_index_table[] ALIGN1 = {
2681 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2682 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2683 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2690 if (c == PEOF) /* 2^8+2 */
2692 #if ENABLE_ASH_ALIAS
2693 if (c == PEOA) /* 2^8+1 */
2698 if ((unsigned char)c >= (unsigned char)(CTLESC)
2699 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
2703 s = strchrnul(spec_symbls, c);
2706 indx = syntax_index_table[s - spec_symbls];
2708 return S_I_T[indx][syntax];
2711 #else /* !USE_SIT_FUNCTION */
2713 #if ENABLE_ASH_ALIAS
2714 #define CSPCL_CIGN_CIGN_CIGN 0
2715 #define CSPCL_CWORD_CWORD_CWORD 1
2716 #define CNL_CNL_CNL_CNL 2
2717 #define CWORD_CCTL_CCTL_CWORD 3
2718 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
2719 #define CVAR_CVAR_CWORD_CVAR 5
2720 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
2721 #define CSPCL_CWORD_CWORD_CLP 7
2722 #define CSPCL_CWORD_CWORD_CRP 8
2723 #define CBACK_CBACK_CCTL_CBACK 9
2724 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
2725 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
2726 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
2727 #define CWORD_CWORD_CWORD_CWORD 13
2728 #define CCTL_CCTL_CCTL_CCTL 14
2730 #define CSPCL_CWORD_CWORD_CWORD 0
2731 #define CNL_CNL_CNL_CNL 1
2732 #define CWORD_CCTL_CCTL_CWORD 2
2733 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
2734 #define CVAR_CVAR_CWORD_CVAR 4
2735 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
2736 #define CSPCL_CWORD_CWORD_CLP 6
2737 #define CSPCL_CWORD_CWORD_CRP 7
2738 #define CBACK_CBACK_CCTL_CBACK 8
2739 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
2740 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
2741 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
2742 #define CWORD_CWORD_CWORD_CWORD 12
2743 #define CCTL_CCTL_CCTL_CCTL 13
2746 static const char syntax_index_table[258] = {
2747 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2748 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2749 #if ENABLE_ASH_ALIAS
2750 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
2752 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2753 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2754 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2755 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2756 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2757 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2758 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2759 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2760 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2761 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
2762 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
2763 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
2764 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
2765 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
2766 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
2767 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
2768 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
2769 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
2770 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
2771 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
2772 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
2773 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
2774 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
2775 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
2776 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
2777 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
2778 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
2779 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
2780 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
2781 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
2782 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
2783 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
2784 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
2785 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
2786 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
2787 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
2788 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
2789 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
2790 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
2791 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
2792 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
2793 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
2794 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
2795 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
2796 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
2797 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
2798 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
2799 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
2800 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
2801 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
2802 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
2803 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
2804 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
2805 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
2806 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
2807 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
2808 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
2809 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
2810 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
2811 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
2812 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
2813 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
2814 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
2815 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
2816 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
2817 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
2818 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
2819 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
2820 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
2821 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
2822 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
2823 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
2824 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
2825 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
2826 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
2827 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
2828 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
2829 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
2830 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
2831 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
2832 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
2833 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
2834 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
2835 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
2836 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
2837 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
2838 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
2839 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
2840 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
2841 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
2842 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
2843 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
2844 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
2845 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
2846 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
2847 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
2848 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
2853 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
2854 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2890 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
2891 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
2898 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
2899 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
2900 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
2901 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
2902 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
2903 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
2904 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
2905 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
2906 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
2907 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
2908 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
2909 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
2910 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
2911 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
2912 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2913 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2914 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2915 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2917 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2919 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2920 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2921 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2922 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2923 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
2925 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2926 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
2927 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2928 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2939 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2940 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2941 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2942 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2943 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2944 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2972 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2973 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2974 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2977 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3003 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3004 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3005 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3006 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3007 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
3010 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])
3012 #endif /* USE_SIT_FUNCTION */
3015 /* ============ Alias handling */
3017 #if ENABLE_ASH_ALIAS
3019 #define ALIASINUSE 1
3030 static struct alias **atab; // [ATABSIZE];
3031 #define INIT_G_alias() do { \
3032 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3036 static struct alias **
3037 __lookupalias(const char *name) {
3038 unsigned int hashval;
3045 ch = (unsigned char)*p;
3049 ch = (unsigned char)*++p;
3051 app = &atab[hashval % ATABSIZE];
3053 for (; *app; app = &(*app)->next) {
3054 if (strcmp(name, (*app)->name) == 0) {
3062 static struct alias *
3063 lookupalias(const char *name, int check)
3065 struct alias *ap = *__lookupalias(name);
3067 if (check && ap && (ap->flag & ALIASINUSE))
3072 static struct alias *
3073 freealias(struct alias *ap)
3077 if (ap->flag & ALIASINUSE) {
3078 ap->flag |= ALIASDEAD;
3090 setalias(const char *name, const char *val)
3092 struct alias *ap, **app;
3094 app = __lookupalias(name);
3098 if (!(ap->flag & ALIASINUSE)) {
3101 ap->val = ckstrdup(val);
3102 ap->flag &= ~ALIASDEAD;
3105 ap = ckzalloc(sizeof(struct alias));
3106 ap->name = ckstrdup(name);
3107 ap->val = ckstrdup(val);
3108 /*ap->flag = 0; - ckzalloc did it */
3109 /*ap->next = NULL;*/
3116 unalias(const char *name)
3120 app = __lookupalias(name);
3124 *app = freealias(*app);
3135 struct alias *ap, **app;
3139 for (i = 0; i < ATABSIZE; i++) {
3141 for (ap = *app; ap; ap = *app) {
3142 *app = freealias(*app);
3152 printalias(const struct alias *ap)
3154 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3158 * TODO - sort output
3161 aliascmd(int argc UNUSED_PARAM, char **argv)
3170 for (i = 0; i < ATABSIZE; i++) {
3171 for (ap = atab[i]; ap; ap = ap->next) {
3177 while ((n = *++argv) != NULL) {
3178 v = strchr(n+1, '=');
3179 if (v == NULL) { /* n+1: funny ksh stuff */
3180 ap = *__lookupalias(n);
3182 fprintf(stderr, "%s: %s not found\n", "alias", n);
3196 unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3200 while ((i = nextopt("a")) != '\0') {
3206 for (i = 0; *argptr; argptr++) {
3207 if (unalias(*argptr)) {
3208 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3216 #endif /* ASH_ALIAS */
3219 /* ============ jobs.c */
3221 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3224 #define FORK_NOJOB 2
3226 /* mode flags for showjob(s) */
3227 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
3228 #define SHOW_PID 0x04 /* include process pid */
3229 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
3232 * A job structure contains information about a job. A job is either a
3233 * single process or a set of processes contained in a pipeline. In the
3234 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3239 pid_t pid; /* process id */
3240 int status; /* last process status from wait() */
3241 char *cmd; /* text of command being run */
3245 struct procstat ps0; /* status of process */
3246 struct procstat *ps; /* status or processes when more than one */
3248 int stopstatus; /* status of a stopped job */
3251 nprocs: 16, /* number of processes */
3253 #define JOBRUNNING 0 /* at least one proc running */
3254 #define JOBSTOPPED 1 /* all procs are stopped */
3255 #define JOBDONE 2 /* all procs are completed */
3257 sigint: 1, /* job was killed by SIGINT */
3258 jobctl: 1, /* job running under job control */
3260 waited: 1, /* true if this entry has been waited for */
3261 used: 1, /* true if this entry is in used */
3262 changed: 1; /* true if status has changed */
3263 struct job *prev_job; /* previous job */
3266 static struct job *makejob(/*union node *,*/ int);
3268 #define forkshell(job, node, mode) forkshell(job, mode)
3270 static int forkshell(struct job *, union node *, int);
3271 static int waitforjob(struct job *);
3274 enum { doing_jobctl = 0 };
3275 #define setjobctl(on) do {} while (0)
3277 static smallint doing_jobctl; //references:8
3278 static void setjobctl(int);
3282 * Set the signal handler for the specified signal. The routine figures
3283 * out what it should be set to.
3286 setsignal(int signo)
3290 struct sigaction act;
3296 else if (*t != '\0')
3298 if (rootshell && action == S_DFL) {
3301 if (iflag || minusc || sflag == 0)
3324 t = &sigmode[signo - 1];
3328 * current setting unknown
3330 if (sigaction(signo, NULL, &act) == -1) {
3332 * Pretend it worked; maybe we should give a warning
3333 * here, but other shells don't. We don't alter
3334 * sigmode, so that we retry every time.
3338 tsig = S_RESET; /* force to be set */
3339 if (act.sa_handler == SIG_IGN) {
3342 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3344 tsig = S_IGN; /* don't hard ignore these */
3348 if (tsig == S_HARD_IGN || tsig == action)
3350 act.sa_handler = SIG_DFL;
3353 act.sa_handler = onsig;
3356 act.sa_handler = SIG_IGN;
3361 sigfillset(&act.sa_mask);
3362 sigaction_set(signo, &act);
3365 /* mode flags for set_curjob */
3366 #define CUR_DELETE 2
3367 #define CUR_RUNNING 1
3368 #define CUR_STOPPED 0
3370 /* mode flags for dowait */
3371 #define DOWAIT_NONBLOCK WNOHANG
3372 #define DOWAIT_BLOCK 0
3375 /* pgrp of shell on invocation */
3376 static int initialpgrp; //references:2
3377 static int ttyfd = -1; //5
3380 static struct job *jobtab; //5
3382 static unsigned njobs; //4
3384 static struct job *curjob; //lots
3385 /* number of presumed living untracked jobs */
3386 static int jobless; //4
3389 set_curjob(struct job *jp, unsigned mode)
3392 struct job **jpp, **curp;
3394 /* first remove from list */
3395 jpp = curp = &curjob;
3400 jpp = &jp1->prev_job;
3402 *jpp = jp1->prev_job;
3404 /* Then re-insert in correct position */
3412 /* job being deleted */
3415 /* newly created job or backgrounded job,
3416 put after all stopped jobs. */
3420 if (!jp1 || jp1->state != JOBSTOPPED)
3423 jpp = &jp1->prev_job;
3429 /* newly stopped job - becomes curjob */
3430 jp->prev_job = *jpp;
3438 jobno(const struct job *jp)
3440 return jp - jobtab + 1;
3445 * Convert a job name to a job structure.
3448 #define getjob(name, getctl) getjob(name)
3451 getjob(const char *name, int getctl)
3455 const char *err_msg = "No such job: %s";
3459 char *(*match)(const char *, const char *);
3474 if (c == '+' || c == '%') {
3476 err_msg = "No current job";
3482 err_msg = "No previous job";
3491 // TODO: number() instead? It does error checking...
3494 jp = jobtab + num - 1;
3511 if (match(jp->ps[0].cmd, p)) {
3515 err_msg = "%s: ambiguous";
3522 err_msg = "job %s not created under job control";
3523 if (getctl && jp->jobctl == 0)
3528 ash_msg_and_raise_error(err_msg, name);
3532 * Mark a job structure as unused.
3535 freejob(struct job *jp)
3537 struct procstat *ps;
3541 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3542 if (ps->cmd != nullstr)
3545 if (jp->ps != &jp->ps0)
3548 set_curjob(jp, CUR_DELETE);
3554 xtcsetpgrp(int fd, pid_t pgrp)
3556 if (tcsetpgrp(fd, pgrp))
3557 ash_msg_and_raise_error("can't set tty process group (%m)");
3561 * Turn job control on and off.
3563 * Note: This code assumes that the third arg to ioctl is a character
3564 * pointer, which is true on Berkeley systems but not System V. Since
3565 * System V doesn't have job control yet, this isn't a problem now.
3567 * Called with interrupts off.
3575 if (on == doing_jobctl || rootshell == 0)
3579 ofd = fd = open(_PATH_TTY, O_RDWR);
3581 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3582 * That sometimes helps to acquire controlling tty.
3583 * Obviously, a workaround for bugs when someone
3584 * failed to provide a controlling tty to bash! :) */
3590 fd = fcntl(fd, F_DUPFD, 10);
3595 /* fd is a tty at this point */
3596 close_on_exec_on(fd);
3597 do { /* while we are in the background */
3598 pgrp = tcgetpgrp(fd);
3601 ash_msg("can't access tty; job control turned off");
3605 if (pgrp == getpgrp())
3616 xtcsetpgrp(fd, pgrp);
3618 /* turning job control off */
3621 /* was xtcsetpgrp, but this can make exiting ash
3622 * loop forever if pty is already deleted */
3623 tcsetpgrp(fd, pgrp);
3638 killcmd(int argc, char **argv)
3641 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3643 if (argv[i][0] == '%') {
3644 struct job *jp = getjob(argv[i], 0);
3645 unsigned pid = jp->ps[0].pid;
3646 /* Enough space for ' -NNN<nul>' */
3647 argv[i] = alloca(sizeof(int)*3 + 3);
3648 /* kill_main has matching code to expect
3649 * leading space. Needed to not confuse
3650 * negative pids with "kill -SIGNAL_NO" syntax */
3651 sprintf(argv[i], " -%u", pid);
3653 } while (argv[++i]);
3655 return kill_main(argc, argv);
3659 showpipe(struct job *jp, FILE *out)
3661 struct procstat *sp;
3662 struct procstat *spend;
3664 spend = jp->ps + jp->nprocs;
3665 for (sp = jp->ps + 1; sp < spend; sp++)
3666 fprintf(out, " | %s", sp->cmd);
3667 outcslow('\n', out);
3668 flush_stdout_stderr();
3673 restartjob(struct job *jp, int mode)
3675 struct procstat *ps;
3681 if (jp->state == JOBDONE)
3683 jp->state = JOBRUNNING;
3685 if (mode == FORK_FG)
3686 xtcsetpgrp(ttyfd, pgid);
3687 killpg(pgid, SIGCONT);
3691 if (WIFSTOPPED(ps->status)) {
3697 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3703 fg_bgcmd(int argc UNUSED_PARAM, char **argv)
3710 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3715 jp = getjob(*argv, 1);
3716 if (mode == FORK_BG) {
3717 set_curjob(jp, CUR_RUNNING);
3718 fprintf(out, "[%d] ", jobno(jp));
3720 outstr(jp->ps->cmd, out);
3722 retval = restartjob(jp, mode);
3723 } while (*argv && *++argv);
3729 sprint_status(char *s, int status, int sigonly)
3735 if (!WIFEXITED(status)) {
3737 if (WIFSTOPPED(status))
3738 st = WSTOPSIG(status);
3741 st = WTERMSIG(status);
3743 if (st == SIGINT || st == SIGPIPE)
3746 if (WIFSTOPPED(status))
3751 col = fmtstr(s, 32, strsignal(st));
3752 if (WCOREDUMP(status)) {
3753 col += fmtstr(s + col, 16, " (core dumped)");
3755 } else if (!sigonly) {
3756 st = WEXITSTATUS(status);
3758 col = fmtstr(s, 16, "Done(%d)", st);
3760 col = fmtstr(s, 16, "Done");
3767 dowait(int wait_flags, struct job *job)
3772 struct job *thisjob;
3775 TRACE(("dowait(0x%x) called\n", wait_flags));
3777 /* Do a wait system call. If job control is compiled in, we accept
3778 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3779 * NB: _not_ safe_waitpid, we need to detect EINTR */
3780 pid = waitpid(-1, &status,
3781 (doing_jobctl ? (wait_flags | WUNTRACED) : wait_flags));
3782 TRACE(("wait returns pid=%d, status=0x%x\n", pid, status));
3785 /* If we were doing blocking wait and (probably) got EINTR,
3786 * check for pending sigs received while waiting.
3787 * (NB: can be moved into callers if needed) */
3788 if (wait_flags == DOWAIT_BLOCK && pendingsig)
3789 raise_exception(EXSIG);
3794 for (jp = curjob; jp; jp = jp->prev_job) {
3795 struct procstat *sp;
3796 struct procstat *spend;
3797 if (jp->state == JOBDONE)
3800 spend = jp->ps + jp->nprocs;
3803 if (sp->pid == pid) {
3804 TRACE(("Job %d: changing status of proc %d "
3805 "from 0x%x to 0x%x\n",
3806 jobno(jp), pid, sp->status, status));
3807 sp->status = status;
3810 if (sp->status == -1)
3813 if (state == JOBRUNNING)
3815 if (WIFSTOPPED(sp->status)) {
3816 jp->stopstatus = sp->status;
3820 } while (++sp < spend);
3825 if (!WIFSTOPPED(status))
3831 if (state != JOBRUNNING) {
3832 thisjob->changed = 1;
3834 if (thisjob->state != state) {
3835 TRACE(("Job %d: changing state from %d to %d\n",
3836 jobno(thisjob), thisjob->state, state));
3837 thisjob->state = state;
3839 if (state == JOBSTOPPED) {
3840 set_curjob(thisjob, CUR_STOPPED);
3849 if (thisjob && thisjob == job) {
3853 len = sprint_status(s, status, 1);
3865 showjob(FILE *out, struct job *jp, int mode)
3867 struct procstat *ps;
3868 struct procstat *psend;
3875 if (mode & SHOW_PGID) {
3876 /* just output process (group) id of pipeline */
3877 fprintf(out, "%d\n", ps->pid);
3881 col = fmtstr(s, 16, "[%d] ", jobno(jp));
3886 else if (curjob && jp == curjob->prev_job)
3889 if (mode & SHOW_PID)
3890 col += fmtstr(s + col, 16, "%d ", ps->pid);
3892 psend = ps + jp->nprocs;
3894 if (jp->state == JOBRUNNING) {
3895 strcpy(s + col, "Running");
3896 col += sizeof("Running") - 1;
3898 int status = psend[-1].status;
3899 if (jp->state == JOBSTOPPED)
3900 status = jp->stopstatus;
3901 col += sprint_status(s + col, status, 0);
3907 /* for each process */
3908 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
3910 fprintf(out, "%s%*c%s",
3911 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
3913 if (!(mode & SHOW_PID)) {
3917 if (++ps == psend) {
3918 outcslow('\n', out);
3925 if (jp->state == JOBDONE) {
3926 TRACE(("showjob: freeing job %d\n", jobno(jp)));
3932 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3933 * statuses have changed since the last call to showjobs.
3936 showjobs(FILE *out, int mode)
3940 TRACE(("showjobs(%x) called\n", mode));
3942 /* If not even one job changed, there is nothing to do */
3943 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3946 for (jp = curjob; jp; jp = jp->prev_job) {
3947 if (!(mode & SHOW_CHANGED) || jp->changed) {
3948 showjob(out, jp, mode);
3954 jobscmd(int argc UNUSED_PARAM, char **argv)
3959 while ((m = nextopt("lp"))) {
3969 showjob(stdout, getjob(*argv,0), mode);
3972 showjobs(stdout, mode);
3979 getstatus(struct job *job)
3984 status = job->ps[job->nprocs - 1].status;
3985 retval = WEXITSTATUS(status);
3986 if (!WIFEXITED(status)) {
3988 retval = WSTOPSIG(status);
3989 if (!WIFSTOPPED(status))
3992 /* XXX: limits number of signals */
3993 retval = WTERMSIG(status);
3995 if (retval == SIGINT)
4001 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
4002 jobno(job), job->nprocs, status, retval));
4007 waitcmd(int argc UNUSED_PARAM, char **argv)
4016 raise_exception(EXSIG);
4023 /* wait for all jobs */
4027 if (!jp) /* no running procs */
4029 if (jp->state == JOBRUNNING)
4034 dowait(DOWAIT_BLOCK, NULL);
4040 if (**argv != '%') {
4041 pid_t pid = number(*argv);
4046 if (job->ps[job->nprocs - 1].pid == pid)
4048 job = job->prev_job;
4051 job = getjob(*argv, 0);
4052 /* loop until process terminated or stopped */
4053 while (job->state == JOBRUNNING)
4054 dowait(DOWAIT_BLOCK, NULL);
4056 retval = getstatus(job);
4070 struct job *jp, *jq;
4072 len = njobs * sizeof(*jp);
4074 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4076 offset = (char *)jp - (char *)jq;
4078 /* Relocate pointers */
4081 jq = (struct job *)((char *)jq + l);
4085 #define joff(p) ((struct job *)((char *)(p) + l))
4086 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4087 if (joff(jp)->ps == &jq->ps0)
4088 jmove(joff(jp)->ps);
4089 if (joff(jp)->prev_job)
4090 jmove(joff(jp)->prev_job);
4100 jp = (struct job *)((char *)jp + len);
4104 } while (--jq >= jp);
4109 * Return a new job structure.
4110 * Called with interrupts off.
4113 makejob(/*union node *node,*/ int nprocs)
4118 for (i = njobs, jp = jobtab; ; jp++) {
4125 if (jp->state != JOBDONE || !jp->waited)
4134 memset(jp, 0, sizeof(*jp));
4136 /* jp->jobctl is a bitfield.
4137 * "jp->jobctl |= jobctl" likely to give awful code */
4141 jp->prev_job = curjob;
4146 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4148 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4155 * Return a string identifying a command (to be printed by the
4158 static char *cmdnextc;
4161 cmdputs(const char *s)
4163 static const char vstype[VSTYPE + 1][3] = {
4164 "", "}", "-", "+", "?", "=",
4165 "%", "%%", "#", "##"
4166 USE_ASH_BASH_COMPAT(, ":", "/", "//")
4169 const char *p, *str;
4170 char c, cc[2] = " ";
4175 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4177 while ((c = *p++) != 0) {
4185 if ((subtype & VSTYPE) == VSLENGTH)
4189 if (!(subtype & VSQUOTE) == !(quoted & 1))
4195 str = "\"}" + !(quoted & 1);
4202 case CTLBACKQ+CTLQUOTE:
4205 #if ENABLE_ASH_MATH_SUPPORT
4220 if ((subtype & VSTYPE) != VSNORMAL)
4222 str = vstype[subtype & VSTYPE];
4223 if (subtype & VSNUL)
4232 /* These can only happen inside quotes */
4245 while ((c = *str++)) {
4250 USTPUTC('"', nextc);
4256 /* cmdtxt() and cmdlist() call each other */
4257 static void cmdtxt(union node *n);
4260 cmdlist(union node *np, int sep)
4262 for (; np; np = np->narg.next) {
4266 if (sep && np->narg.next)
4272 cmdtxt(union node *n)
4275 struct nodelist *lp;
4286 lp = n->npipe.cmdlist;
4304 cmdtxt(n->nbinary.ch1);
4320 cmdtxt(n->nif.test);
4323 if (n->nif.elsepart) {
4326 n = n->nif.elsepart;
4342 cmdtxt(n->nbinary.ch1);
4352 cmdputs(n->nfor.var);
4354 cmdlist(n->nfor.args, 1);
4359 cmdputs(n->narg.text);
4363 cmdlist(n->ncmd.args, 1);
4364 cmdlist(n->ncmd.redirect, 0);
4377 cmdputs(n->ncase.expr->narg.text);
4379 for (np = n->ncase.cases; np; np = np->nclist.next) {
4380 cmdtxt(np->nclist.pattern);
4382 cmdtxt(np->nclist.body);
4396 #if ENABLE_ASH_BASH_COMPAT
4411 cmdputs(utoa(n->nfile.fd));
4413 if (n->type == NTOFD || n->type == NFROMFD) {
4414 cmdputs(utoa(n->ndup.dupfd));
4423 commandtext(union node *n)
4427 STARTSTACKSTR(cmdnextc);
4429 name = stackblock();
4430 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4431 name, cmdnextc, cmdnextc));
4432 return ckstrdup(name);
4437 * Fork off a subshell. If we are doing job control, give the subshell its
4438 * own process group. Jp is a job structure that the job is to be added to.
4439 * N is the command that will be evaluated by the child. Both jp and n may
4440 * be NULL. The mode parameter can be one of the following:
4441 * FORK_FG - Fork off a foreground process.
4442 * FORK_BG - Fork off a background process.
4443 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4444 * process group even if job control is on.
4446 * When job control is turned off, background processes have their standard
4447 * input redirected to /dev/null (except for the second and later processes
4450 * Called with interrupts off.
4453 * Clear traps on a fork.
4460 for (tp = trap; tp < &trap[NSIG]; tp++) {
4461 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4466 setsignal(tp - trap);
4472 /* Lives far away from here, needed for forkchild */
4473 static void closescript(void);
4475 /* Called after fork(), in child */
4477 forkchild(struct job *jp, /*union node *n,*/ int mode)
4481 TRACE(("Child shell %d\n", getpid()));
4488 /* do job control only in root shell */
4490 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4493 if (jp->nprocs == 0)
4496 pgrp = jp->ps[0].pid;
4497 /* This can fail because we are doing it in the parent also */
4498 (void)setpgid(0, pgrp);
4499 if (mode == FORK_FG)
4500 xtcsetpgrp(ttyfd, pgrp);
4505 if (mode == FORK_BG) {
4508 if (jp->nprocs == 0) {
4510 if (open(bb_dev_null, O_RDONLY) != 0)
4511 ash_msg_and_raise_error("can't open %s", bb_dev_null);
4514 if (!oldlvl && iflag) {
4519 for (jp = curjob; jp; jp = jp->prev_job)
4524 /* Called after fork(), in parent */
4526 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4529 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4531 TRACE(("In parent shell: child = %d\n", pid));
4533 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4539 if (mode != FORK_NOJOB && jp->jobctl) {
4542 if (jp->nprocs == 0)
4545 pgrp = jp->ps[0].pid;
4546 /* This can fail because we are doing it in the child also */
4550 if (mode == FORK_BG) {
4551 backgndpid = pid; /* set $! */
4552 set_curjob(jp, CUR_RUNNING);
4555 struct procstat *ps = &jp->ps[jp->nprocs++];
4560 if (doing_jobctl && n)
4561 ps->cmd = commandtext(n);
4567 forkshell(struct job *jp, union node *n, int mode)
4571 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4574 TRACE(("Fork failed, errno=%d", errno));
4577 ash_msg_and_raise_error("can't fork");
4580 forkchild(jp, /*n,*/ mode);
4582 forkparent(jp, n, mode, pid);
4587 * Wait for job to finish.
4589 * Under job control we have the problem that while a child process is
4590 * running interrupts generated by the user are sent to the child but not
4591 * to the shell. This means that an infinite loop started by an inter-
4592 * active user may be hard to kill. With job control turned off, an
4593 * interactive user may place an interactive program inside a loop. If
4594 * the interactive program catches interrupts, the user doesn't want
4595 * these interrupts to also abort the loop. The approach we take here
4596 * is to have the shell ignore interrupt signals while waiting for a
4597 * foreground process to terminate, and then send itself an interrupt
4598 * signal if the child process was terminated by an interrupt signal.
4599 * Unfortunately, some programs want to do a bit of cleanup and then
4600 * exit on interrupt; unless these processes terminate themselves by
4601 * sending a signal to themselves (instead of calling exit) they will
4602 * confuse this approach.
4604 * Called with interrupts off.
4607 waitforjob(struct job *jp)
4611 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4612 while (jp->state == JOBRUNNING) {
4613 dowait(DOWAIT_BLOCK, jp);
4618 xtcsetpgrp(ttyfd, rootpid);
4620 * This is truly gross.
4621 * If we're doing job control, then we did a TIOCSPGRP which
4622 * caused us (the shell) to no longer be in the controlling
4623 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4624 * intuit from the subprocess exit status whether a SIGINT
4625 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4627 if (jp->sigint) /* TODO: do the same with all signals */
4628 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4630 if (jp->state == JOBDONE)
4637 * return 1 if there are stopped jobs, otherwise 0
4649 if (jp && jp->state == JOBSTOPPED) {
4650 out2str("You have stopped jobs.\n");
4659 /* ============ redir.c
4661 * Code for dealing with input/output redirection.
4664 #define EMPTY -2 /* marks an unused slot in redirtab */
4665 #define CLOSED -3 /* marks a slot of previously-closed fd */
4668 * Open a file in noclobber mode.
4669 * The code was copied from bash.
4672 noclobberopen(const char *fname)
4675 struct stat finfo, finfo2;
4678 * If the file exists and is a regular file, return an error
4681 r = stat(fname, &finfo);
4682 if (r == 0 && S_ISREG(finfo.st_mode)) {
4688 * If the file was not present (r != 0), make sure we open it
4689 * exclusively so that if it is created before we open it, our open
4690 * will fail. Make sure that we do not truncate an existing file.
4691 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4692 * file was not a regular file, we leave O_EXCL off.
4695 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4696 fd = open(fname, O_WRONLY|O_CREAT, 0666);
4698 /* If the open failed, return the file descriptor right away. */
4703 * OK, the open succeeded, but the file may have been changed from a
4704 * non-regular file to a regular file between the stat and the open.
4705 * We are assuming that the O_EXCL open handles the case where FILENAME
4706 * did not exist and is symlinked to an existing file between the stat
4711 * If we can open it and fstat the file descriptor, and neither check
4712 * revealed that it was a regular file, and the file has not been
4713 * replaced, return the file descriptor.
4715 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4716 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4719 /* The file has been replaced. badness. */
4726 * Handle here documents. Normally we fork off a process to write the
4727 * data to a pipe. If the document is short, we can stuff the data in
4728 * the pipe without forking.
4730 /* openhere needs this forward reference */
4731 static void expandhere(union node *arg, int fd);
4733 openhere(union node *redir)
4739 ash_msg_and_raise_error("pipe call failed");
4740 if (redir->type == NHERE) {
4741 len = strlen(redir->nhere.doc->narg.text);
4742 if (len <= PIPE_BUF) {
4743 full_write(pip[1], redir->nhere.doc->narg.text, len);
4747 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4750 signal(SIGINT, SIG_IGN);
4751 signal(SIGQUIT, SIG_IGN);
4752 signal(SIGHUP, SIG_IGN);
4754 signal(SIGTSTP, SIG_IGN);
4756 signal(SIGPIPE, SIG_DFL);
4757 if (redir->type == NHERE)
4758 full_write(pip[1], redir->nhere.doc->narg.text, len);
4760 expandhere(redir->nhere.doc, pip[1]);
4761 _exit(EXIT_SUCCESS);
4769 openredirect(union node *redir)
4774 switch (redir->nfile.type) {
4776 fname = redir->nfile.expfname;
4777 f = open(fname, O_RDONLY);
4782 fname = redir->nfile.expfname;
4783 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
4788 #if ENABLE_ASH_BASH_COMPAT
4791 /* Take care of noclobber mode. */
4793 fname = redir->nfile.expfname;
4794 f = noclobberopen(fname);
4801 fname = redir->nfile.expfname;
4802 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4807 fname = redir->nfile.expfname;
4808 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4816 /* Fall through to eliminate warning. */
4817 /* Our single caller does this itself */
4824 f = openhere(redir);
4830 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4832 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
4836 * Copy a file descriptor to be >= to. Returns -1
4837 * if the source file descriptor is closed, EMPTY if there are no unused
4838 * file descriptors left.
4840 /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
4841 * old code was doing close(to) prior to copyfd() to achieve the same */
4843 COPYFD_EXACT = (int)~(INT_MAX),
4844 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
4847 copyfd(int from, int to)
4851 if (to & COPYFD_EXACT) {
4852 to &= ~COPYFD_EXACT;
4854 newfd = dup2(from, to);
4856 newfd = fcntl(from, F_DUPFD, to);
4859 if (errno == EMFILE)
4861 /* Happens when source fd is not open: try "echo >&99" */
4862 ash_msg_and_raise_error("%d: %m", from);
4867 /* Struct def and variable are moved down to the first usage site */
4872 struct redirtab *next;
4875 struct two_fd_t two_fd[0];
4877 #define redirlist (G_var.redirlist)
4879 static int need_to_remember(struct redirtab *rp, int fd)
4883 if (!rp) /* remembering was not requested */
4886 for (i = 0; i < rp->pair_count; i++) {
4887 if (rp->two_fd[i].orig == fd) {
4888 /* already remembered */
4895 /* "hidden" fd is a fd used to read scripts, or a copy of such */
4896 static int is_hidden_fd(struct redirtab *rp, int fd)
4899 struct parsefile *pf;
4912 fd |= COPYFD_RESTORE;
4913 for (i = 0; i < rp->pair_count; i++) {
4914 if (rp->two_fd[i].copy == fd) {
4922 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
4923 * old file descriptors are stashed away so that the redirection can be
4924 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
4925 * standard output, and the standard error if it becomes a duplicate of
4926 * stdout, is saved in memory.
4928 /* flags passed to redirect */
4929 #define REDIR_PUSH 01 /* save previous values of file descriptors */
4930 #define REDIR_SAVEFD2 03 /* set preverrout */
4932 redirect(union node *redir, int flags)
4934 struct redirtab *sv;
4939 int copied_fd2 = -1;
4949 if (flags & REDIR_PUSH) {
4950 union node *tmp = redir;
4953 #if ENABLE_ASH_BASH_COMPAT
4954 if (redir->nfile.type == NTO2)
4957 tmp = tmp->nfile.next;
4959 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
4960 sv->next = redirlist;
4961 sv->pair_count = sv_pos;
4963 sv->nullredirs = g_nullredirs - 1;
4965 while (sv_pos > 0) {
4967 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
4972 fd = redir->nfile.fd;
4973 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
4974 int right_fd = redir->ndup.dupfd;
4975 /* redirect from/to same file descriptor? */
4978 /* echo >&10 and 10 is a fd opened to the sh script? */
4979 if (is_hidden_fd(sv, right_fd)) {
4980 errno = EBADF; /* as if it is closed */
4981 ash_msg_and_raise_error("%d: %m", right_fd);
4985 newfd = openredirect(redir); /* always >= 0 */
4987 /* Descriptor wasn't open before redirect.
4988 * Mark it for close in the future */
4989 if (need_to_remember(sv, fd)) {
4990 goto remember_to_close;
4995 #if ENABLE_ASH_BASH_COMPAT
4998 if (need_to_remember(sv, fd)) {
4999 /* Copy old descriptor */
5000 i = fcntl(fd, F_DUPFD, 10);
5001 /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5002 * are closed in popredir() in the child, preventing them from leaking
5003 * into child. (popredir() also cleans up the mess in case of failures)
5008 /* Strange error (e.g. "too many files" EMFILE?) */
5012 ash_msg_and_raise_error("%d: %m", fd);
5015 /* EBADF: it is not open - good, remember to close it */
5018 } else { /* fd is open, save its copy */
5019 /* "exec fd>&-" should not close fds
5020 * which point to script file(s).
5021 * Force them to be restored afterwards */
5022 if (is_hidden_fd(sv, fd))
5023 i |= COPYFD_RESTORE;
5027 sv->two_fd[sv_pos].orig = fd;
5028 sv->two_fd[sv_pos].copy = i;
5032 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5033 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5036 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
5038 } else if (fd != newfd) { /* move newfd to fd */
5039 copyfd(newfd, fd | COPYFD_EXACT);
5040 #if ENABLE_ASH_BASH_COMPAT
5041 if (!(redir->nfile.type == NTO2 && fd == 2))
5045 #if ENABLE_ASH_BASH_COMPAT
5046 if (redir->nfile.type == NTO2 && fd == 1) {
5047 /* We already redirected it to fd 1, now copy it to 2 */
5053 } while ((redir = redir->nfile.next) != NULL);
5056 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5057 preverrout_fd = copied_fd2;
5061 * Undo the effects of the last redirection.
5064 popredir(int drop, int restore)
5066 struct redirtab *rp;
5069 if (--g_nullredirs >= 0)
5073 for (i = 0; i < rp->pair_count; i++) {
5074 int fd = rp->two_fd[i].orig;
5075 int copy = rp->two_fd[i].copy;
5076 if (copy == CLOSED) {
5081 if (copy != EMPTY) {
5082 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5083 copy &= ~COPYFD_RESTORE;
5085 copyfd(copy, fd | COPYFD_EXACT);
5090 redirlist = rp->next;
5091 g_nullredirs = rp->nullredirs;
5097 * Undo all redirections. Called on error or interrupt.
5101 * Discard all saved file descriptors.
5104 clearredir(int drop)
5110 popredir(drop, /*restore:*/ 0);
5115 redirectsafe(union node *redir, int flags)
5118 volatile int saveint;
5119 struct jmploc *volatile savehandler = exception_handler;
5120 struct jmploc jmploc;
5123 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5124 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5126 exception_handler = &jmploc;
5127 redirect(redir, flags);
5129 exception_handler = savehandler;
5130 if (err && exception != EXERROR)
5131 longjmp(exception_handler->loc, 1);
5132 RESTORE_INT(saveint);
5137 /* ============ Routines to expand arguments to commands
5139 * We have to deal with backquotes, shell variables, and file metacharacters.
5142 #if ENABLE_ASH_MATH_SUPPORT_64
5143 typedef int64_t arith_t;
5144 #define arith_t_type long long
5146 typedef long arith_t;
5147 #define arith_t_type long
5150 #if ENABLE_ASH_MATH_SUPPORT
5151 static arith_t dash_arith(const char *);
5152 static arith_t arith(const char *expr, int *perrcode);
5158 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5159 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5160 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5161 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5162 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5163 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5164 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5165 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5166 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5170 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5171 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5172 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5173 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5174 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5177 * Structure specifying which parts of the string should be searched
5178 * for IFS characters.
5181 struct ifsregion *next; /* next region in list */
5182 int begoff; /* offset of start of region */
5183 int endoff; /* offset of end of region */
5184 int nulonly; /* search for nul bytes only */
5188 struct strlist *list;
5189 struct strlist **lastp;
5192 /* output of current string */
5193 static char *expdest;
5194 /* list of back quote expressions */
5195 static struct nodelist *argbackq;
5196 /* first struct in list of ifs regions */
5197 static struct ifsregion ifsfirst;
5198 /* last struct in list */
5199 static struct ifsregion *ifslastp;
5200 /* holds expanded arg list */
5201 static struct arglist exparg;
5211 expdest = makestrspace(32, expdest);
5212 #if ENABLE_ASH_MATH_SUPPORT_64
5213 len = fmtstr(expdest, 32, "%lld", (long long) num);
5215 len = fmtstr(expdest, 32, "%ld", num);
5217 STADJUST(len, expdest);
5222 esclen(const char *start, const char *p)
5226 while (p > start && *--p == CTLESC) {
5233 * Remove any CTLESC characters from a string.
5236 _rmescapes(char *str, int flag)
5238 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5245 p = strpbrk(str, qchars);
5251 if (flag & RMESCAPE_ALLOC) {
5252 size_t len = p - str;
5253 size_t fulllen = len + strlen(p) + 1;
5255 if (flag & RMESCAPE_GROW) {
5256 r = makestrspace(fulllen, expdest);
5257 } else if (flag & RMESCAPE_HEAP) {
5258 r = ckmalloc(fulllen);
5260 r = stalloc(fulllen);
5264 q = (char *)memcpy(q, str, len) + len;
5267 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5268 globbing = flag & RMESCAPE_GLOB;
5269 notescaped = globbing;
5271 if (*p == CTLQUOTEMARK) {
5272 inquotes = ~inquotes;
5274 notescaped = globbing;
5278 /* naked back slash */
5284 if (notescaped && inquotes && *p != '/') {
5288 notescaped = globbing;
5293 if (flag & RMESCAPE_GROW) {
5295 STADJUST(q - r + 1, expdest);
5299 #define rmescapes(p) _rmescapes((p), 0)
5301 #define pmatch(a, b) !fnmatch((a), (b), 0)
5304 * Prepare a pattern for a expmeta (internal glob(3)) call.
5306 * Returns an stalloced string.
5309 preglob(const char *pattern, int quoted, int flag)
5311 flag |= RMESCAPE_GLOB;
5313 flag |= RMESCAPE_QUOTED;
5315 return _rmescapes((char *)pattern, flag);
5319 * Put a string on the stack.
5322 memtodest(const char *p, size_t len, int syntax, int quotes)
5326 q = makestrspace(len * 2, q);
5329 int c = signed_char2int(*p++);
5332 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5341 strtodest(const char *p, int syntax, int quotes)
5343 memtodest(p, strlen(p), syntax, quotes);
5347 * Record the fact that we have to scan this region of the
5348 * string for IFS characters.
5351 recordregion(int start, int end, int nulonly)
5353 struct ifsregion *ifsp;
5355 if (ifslastp == NULL) {
5359 ifsp = ckzalloc(sizeof(*ifsp));
5360 /*ifsp->next = NULL; - ckzalloc did it */
5361 ifslastp->next = ifsp;
5365 ifslastp->begoff = start;
5366 ifslastp->endoff = end;
5367 ifslastp->nulonly = nulonly;
5371 removerecordregions(int endoff)
5373 if (ifslastp == NULL)
5376 if (ifsfirst.endoff > endoff) {
5377 while (ifsfirst.next != NULL) {
5378 struct ifsregion *ifsp;
5380 ifsp = ifsfirst.next->next;
5381 free(ifsfirst.next);
5382 ifsfirst.next = ifsp;
5385 if (ifsfirst.begoff > endoff)
5388 ifslastp = &ifsfirst;
5389 ifsfirst.endoff = endoff;
5394 ifslastp = &ifsfirst;
5395 while (ifslastp->next && ifslastp->next->begoff < endoff)
5396 ifslastp=ifslastp->next;
5397 while (ifslastp->next != NULL) {
5398 struct ifsregion *ifsp;
5400 ifsp = ifslastp->next->next;
5401 free(ifslastp->next);
5402 ifslastp->next = ifsp;
5405 if (ifslastp->endoff > endoff)
5406 ifslastp->endoff = endoff;
5410 exptilde(char *startp, char *p, int flag)
5416 int quotes = flag & (EXP_FULL | EXP_CASE);
5421 while ((c = *++p) != '\0') {
5428 if (flag & EXP_VARTILDE)
5438 if (*name == '\0') {
5439 home = lookupvar(homestr);
5441 pw = getpwnam(name);
5446 if (!home || !*home)
5449 startloc = expdest - (char *)stackblock();
5450 strtodest(home, SQSYNTAX, quotes);
5451 recordregion(startloc, expdest - (char *)stackblock(), 0);
5459 * Execute a command inside back quotes. If it's a builtin command, we
5460 * want to save its output in a block obtained from malloc. Otherwise
5461 * we fork off a subprocess and get the output of the command via a pipe.
5462 * Should be called with interrupts off.
5464 struct backcmd { /* result of evalbackcmd */
5465 int fd; /* file descriptor to read from */
5466 int nleft; /* number of chars in buffer */
5467 char *buf; /* buffer */
5468 struct job *jp; /* job structure for command */
5471 /* These forward decls are needed to use "eval" code for backticks handling: */
5472 static uint8_t back_exitstatus; /* exit status of backquoted command */
5473 #define EV_EXIT 01 /* exit after evaluating tree */
5474 static void evaltree(union node *, int);
5477 evalbackcmd(union node *n, struct backcmd *result)
5489 saveherefd = herefd;
5497 ash_msg_and_raise_error("pipe call failed");
5498 jp = makejob(/*n,*/ 1);
5499 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5504 copyfd(pip[1], 1 | COPYFD_EXACT);
5508 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5512 result->fd = pip[0];
5515 herefd = saveherefd;
5517 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5518 result->fd, result->buf, result->nleft, result->jp));
5522 * Expand stuff in backwards quotes.
5525 expbackq(union node *cmd, int quoted, int quotes)
5533 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
5534 struct stackmark smark;
5537 setstackmark(&smark);
5539 startloc = dest - (char *)stackblock();
5541 evalbackcmd(cmd, &in);
5542 popstackmark(&smark);
5549 memtodest(p, i, syntax, quotes);
5553 i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5554 TRACE(("expbackq: read returns %d\n", i));
5563 back_exitstatus = waitforjob(in.jp);
5567 /* Eat all trailing newlines */
5569 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5574 recordregion(startloc, dest - (char *)stackblock(), 0);
5575 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5576 (dest - (char *)stackblock()) - startloc,
5577 (dest - (char *)stackblock()) - startloc,
5578 stackblock() + startloc));
5581 #if ENABLE_ASH_MATH_SUPPORT
5583 * Expand arithmetic expression. Backup to start of expression,
5584 * evaluate, place result in (backed up) result, adjust string position.
5597 * This routine is slightly over-complicated for
5598 * efficiency. Next we scan backwards looking for the
5599 * start of arithmetic.
5601 start = stackblock();
5608 while (*p != CTLARI) {
5612 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5617 esc = esclen(start, p);
5627 removerecordregions(begoff);
5636 len = cvtnum(dash_arith(p + 2));
5639 recordregion(begoff, begoff + len, 0);
5643 /* argstr needs it */
5644 static char *evalvar(char *p, int flag, struct strlist *var_str_list);
5647 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5648 * characters to allow for further processing. Otherwise treat
5649 * $@ like $* since no splitting will be performed.
5651 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5652 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5653 * for correct expansion of "B=$A" word.
5656 argstr(char *p, int flag, struct strlist *var_str_list)
5658 static const char spclchars[] ALIGN1 = {
5666 CTLBACKQ | CTLQUOTE,
5667 #if ENABLE_ASH_MATH_SUPPORT
5672 const char *reject = spclchars;
5674 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
5675 int breakall = flag & EXP_WORD;
5680 if (!(flag & EXP_VARTILDE)) {
5682 } else if (flag & EXP_VARTILDE2) {
5687 if (flag & EXP_TILDE) {
5693 if (*q == CTLESC && (flag & EXP_QWORD))
5696 p = exptilde(p, q, flag);
5699 startloc = expdest - (char *)stackblock();
5701 length += strcspn(p + length, reject);
5703 if (c && (!(c & 0x80)
5704 #if ENABLE_ASH_MATH_SUPPORT
5708 /* c == '=' || c == ':' || c == CTLENDARI */
5713 expdest = stack_nputstr(p, length, expdest);
5714 newloc = expdest - (char *)stackblock();
5715 if (breakall && !inquotes && newloc > startloc) {
5716 recordregion(startloc, newloc, 0);
5727 if (flag & EXP_VARTILDE2) {
5731 flag |= EXP_VARTILDE2;
5736 * sort of a hack - expand tildes in variable
5737 * assignments (after the first '=' and after ':'s).
5746 case CTLENDVAR: /* ??? */
5749 /* "$@" syntax adherence hack */
5752 !memcmp(p, dolatstr, 4) &&
5753 (p[4] == CTLQUOTEMARK || (
5754 p[4] == CTLENDVAR &&
5755 p[5] == CTLQUOTEMARK
5758 p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;
5761 inquotes = !inquotes;
5774 p = evalvar(p, flag, var_str_list);
5778 case CTLBACKQ|CTLQUOTE:
5779 expbackq(argbackq->n, c, quotes);
5780 argbackq = argbackq->next;
5782 #if ENABLE_ASH_MATH_SUPPORT
5795 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int quotes,
5798 // This commented out code was added by James Simmons <jsimmons@infradead.org>
5799 // as part of a larger change when he added support for ${var/a/b}.
5800 // However, it broke # and % operators:
5804 //echo ${var#ab} abcdcd abcdcd
5805 //echo ${var##ab} abcdcd abcdcd
5806 //echo ${var#a*b} abcdcd ababcdcd (!)
5807 //echo ${var##a*b} cdcd cdcd
5808 //echo ${var#?} babcdcd ababcdcd (!)
5809 //echo ${var##?} babcdcd babcdcd
5810 //echo ${var#*} ababcdcd babcdcd (!)
5812 //echo ${var%cd} ababcd ababcd
5813 //echo ${var%%cd} ababcd abab (!)
5814 //echo ${var%c*d} ababcd ababcd
5815 //echo ${var%%c*d} abab ababcdcd (!)
5816 //echo ${var%?} ababcdc ababcdc
5817 //echo ${var%%?} ababcdc ababcdcd (!)
5818 //echo ${var%*} ababcdcd ababcdcd
5821 // Commenting it back out helped. Remove it completely if it really
5824 char *loc, *loc2; //, *full;
5830 int match; // = strlen(str);
5831 const char *s = loc2;
5838 match = pmatch(str, s); // this line was deleted
5840 // // chop off end if its '*'
5841 // full = strrchr(str, '*');
5842 // if (full && full != str)
5845 // // If str starts with '*' replace with s.
5846 // if ((*str == '*') && strlen(s) >= match) {
5847 // full = xstrdup(s);
5848 // strncpy(full+strlen(s)-match+1, str+1, match-1);
5850 // full = xstrndup(str, match);
5851 // match = strncmp(s, full, strlen(full));
5855 if (match) // if (!match)
5857 if (quotes && *loc == CTLESC)
5866 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5873 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5876 const char *s = loc2;
5881 match = pmatch(str, s);
5888 esc = esclen(startp, loc);
5899 static void varunset(const char *, const char *, const char *, int) NORETURN;
5901 varunset(const char *end, const char *var, const char *umsg, int varflags)
5907 msg = "parameter not set";
5909 if (*end == CTLENDVAR) {
5910 if (varflags & VSNUL)
5915 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5918 #if ENABLE_ASH_BASH_COMPAT
5920 parse_sub_pattern(char *arg, int inquotes)
5922 char *idx, *repl = NULL;
5931 /* Only the first '/' seen is our separator */
5938 if (!inquotes && c == '\\' && arg[1] == '\\')
5939 arg++; /* skip both \\, not just first one */
5946 #endif /* ENABLE_ASH_BASH_COMPAT */
5949 subevalvar(char *p, char *str, int strloc, int subtype,
5950 int startloc, int varflags, int quotes, struct strlist *var_str_list)
5952 struct nodelist *saveargbackq = argbackq;
5955 char *rmesc, *rmescend;
5956 USE_ASH_BASH_COMPAT(char *repl = NULL;)
5957 USE_ASH_BASH_COMPAT(char null = '\0';)
5958 USE_ASH_BASH_COMPAT(int pos, len, orig_len;)
5959 int saveherefd = herefd;
5960 int amount, workloc, resetloc;
5962 char *(*scan)(char*, char*, char*, char*, int, int);
5965 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
5967 STPUTC('\0', expdest);
5968 herefd = saveherefd;
5969 argbackq = saveargbackq;
5970 startp = (char *)stackblock() + startloc;
5974 setvar(str, startp, 0);
5975 amount = startp - expdest;
5976 STADJUST(amount, expdest);
5979 #if ENABLE_ASH_BASH_COMPAT
5981 loc = str = stackblock() + strloc;
5982 // TODO: number() instead? It does error checking...
5984 len = str - startp - 1;
5986 /* *loc != '\0', guaranteed by parser */
5990 /* We must adjust the length by the number of escapes we find. */
5991 for (ptr = startp; ptr < (str - 1); ptr++) {
5992 if (*ptr == CTLESC) {
6000 if (*loc++ == ':') {
6001 // TODO: number() instead? It does error checking...
6005 while (*loc && *loc != ':')
6008 // TODO: number() instead? It does error checking...
6011 if (pos >= orig_len) {
6015 if (len > (orig_len - pos))
6016 len = orig_len - pos;
6018 for (str = startp; pos; str++, pos--) {
6019 if (quotes && *str == CTLESC)
6022 for (loc = startp; len; len--) {
6023 if (quotes && *str == CTLESC)
6028 amount = loc - expdest;
6029 STADJUST(amount, expdest);
6034 varunset(p, str, startp, varflags);
6037 resetloc = expdest - (char *)stackblock();
6039 /* We'll comeback here if we grow the stack while handling
6040 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6041 * stack will need rebasing, and we'll need to remove our work
6044 USE_ASH_BASH_COMPAT(restart:)
6046 amount = expdest - ((char *)stackblock() + resetloc);
6047 STADJUST(-amount, expdest);
6048 startp = (char *)stackblock() + startloc;
6051 rmescend = (char *)stackblock() + strloc;
6053 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6054 if (rmesc != startp) {
6056 startp = (char *)stackblock() + startloc;
6060 str = (char *)stackblock() + strloc;
6061 preglob(str, varflags & VSQUOTE, 0);
6062 workloc = expdest - (char *)stackblock();
6064 #if ENABLE_ASH_BASH_COMPAT
6065 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6066 char *idx, *end, *restart_detect;
6069 repl = parse_sub_pattern(str, varflags & VSQUOTE);
6074 /* If there's no pattern to match, return the expansion unmolested */
6082 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6084 /* No match, advance */
6085 restart_detect = stackblock();
6086 STPUTC(*idx, expdest);
6087 if (quotes && *idx == CTLESC) {
6090 STPUTC(*idx, expdest);
6092 if (stackblock() != restart_detect)
6100 if (subtype == VSREPLACEALL) {
6102 if (quotes && *idx == CTLESC)
6110 for (loc = repl; *loc; loc++) {
6111 restart_detect = stackblock();
6112 STPUTC(*loc, expdest);
6113 if (stackblock() != restart_detect)
6118 if (subtype == VSREPLACE) {
6120 restart_detect = stackblock();
6121 STPUTC(*idx, expdest);
6122 if (stackblock() != restart_detect)
6131 /* We've put the replaced text into a buffer at workloc, now
6132 * move it to the right place and adjust the stack.
6134 startp = stackblock() + startloc;
6135 STPUTC('\0', expdest);
6136 memmove(startp, stackblock() + workloc, len);
6137 startp[len++] = '\0';
6138 amount = expdest - ((char *)stackblock() + startloc + len - 1);
6139 STADJUST(-amount, expdest);
6142 #endif /* ENABLE_ASH_BASH_COMPAT */
6144 subtype -= VSTRIMRIGHT;
6146 if (subtype < 0 || subtype > 7)
6149 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
6150 zero = subtype >> 1;
6151 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6152 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6154 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6157 memmove(startp, loc, str - loc);
6158 loc = startp + (str - loc) - 1;
6161 amount = loc - expdest;
6162 STADJUST(amount, expdest);
6168 * Add the value of a specialized variable to the stack string.
6171 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6181 int quoted = varflags & VSQUOTE;
6182 int subtype = varflags & VSTYPE;
6183 int quotes = flags & (EXP_FULL | EXP_CASE);
6185 if (quoted && (flags & EXP_FULL))
6186 sep = 1 << CHAR_BIT;
6188 syntax = quoted ? DQSYNTAX : BASESYNTAX;
6197 num = shellparam.nparam;
6207 p = makestrspace(NOPTS, expdest);
6208 for (i = NOPTS - 1; i >= 0; i--) {
6210 USTPUTC(optletters(i), p);
6221 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
6222 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
6228 while ((p = *ap++)) {
6231 partlen = strlen(p);
6234 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6235 memtodest(p, partlen, syntax, quotes);
6241 if (subtype == VSPLUS || subtype == VSLENGTH) {
6262 // TODO: number() instead? It does error checking...
6264 if (num < 0 || num > shellparam.nparam)
6266 p = num ? shellparam.p[num - 1] : arg0;
6269 /* NB: name has form "VAR=..." */
6271 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6272 * which should be considered before we check variables. */
6274 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6278 str = var_str_list->text;
6279 eq = strchr(str, '=');
6280 if (!eq) /* stop at first non-assignment */
6283 if (name_len == (unsigned)(eq - str)
6284 && strncmp(str, name, name_len) == 0) {
6286 /* goto value; - WRONG! */
6287 /* think "A=1 A=2 B=$A" */
6289 var_str_list = var_str_list->next;
6290 } while (var_str_list);
6294 p = lookupvar(name);
6300 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6301 memtodest(p, len, syntax, quotes);
6305 if (subtype == VSPLUS || subtype == VSLENGTH)
6306 STADJUST(-len, expdest);
6311 * Expand a variable, and return a pointer to the next character in the
6315 evalvar(char *p, int flag, struct strlist *var_str_list)
6327 subtype = varflags & VSTYPE;
6328 quoted = varflags & VSQUOTE;
6330 easy = (!quoted || (*var == '@' && shellparam.nparam));
6331 startloc = expdest - (char *)stackblock();
6332 p = strchr(p, '=') + 1;
6335 varlen = varvalue(var, varflags, flag, var_str_list);
6336 if (varflags & VSNUL)
6339 if (subtype == VSPLUS) {
6340 varlen = -1 - varlen;
6344 if (subtype == VSMINUS) {
6348 p, flag | EXP_TILDE |
6349 (quoted ? EXP_QWORD : EXP_WORD),
6359 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6361 if (subevalvar(p, var, /* strloc: */ 0,
6362 subtype, startloc, varflags,
6368 * Remove any recorded regions beyond
6371 removerecordregions(startloc);
6381 if (varlen < 0 && uflag)
6382 varunset(p, var, 0, 0);
6384 if (subtype == VSLENGTH) {
6385 cvtnum(varlen > 0 ? varlen : 0);
6389 if (subtype == VSNORMAL) {
6400 case VSTRIMRIGHTMAX:
6401 #if ENABLE_ASH_BASH_COMPAT
6414 * Terminate the string and start recording the pattern
6417 STPUTC('\0', expdest);
6418 patloc = expdest - (char *)stackblock();
6419 if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6421 /* quotes: */ flag & (EXP_FULL | EXP_CASE),
6424 int amount = expdest - (
6425 (char *)stackblock() + patloc - 1
6427 STADJUST(-amount, expdest);
6429 /* Remove any recorded regions beyond start of variable */
6430 removerecordregions(startloc);
6432 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6436 if (subtype != VSNORMAL) { /* skip to end of alternative */
6442 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6444 argbackq = argbackq->next;
6445 } else if (c == CTLVAR) {
6446 if ((*p++ & VSTYPE) != VSNORMAL)
6448 } else if (c == CTLENDVAR) {
6458 * Break the argument string into pieces based upon IFS and add the
6459 * strings to the argument list. The regions of the string to be
6460 * searched for IFS characters have been stored by recordregion.
6463 ifsbreakup(char *string, struct arglist *arglist)
6465 struct ifsregion *ifsp;
6470 const char *ifs, *realifs;
6475 if (ifslastp != NULL) {
6478 realifs = ifsset() ? ifsval() : defifs;
6481 p = string + ifsp->begoff;
6482 nulonly = ifsp->nulonly;
6483 ifs = nulonly ? nullstr : realifs;
6485 while (p < string + ifsp->endoff) {
6489 if (!strchr(ifs, *p)) {
6494 ifsspc = (strchr(defifs, *p) != NULL);
6495 /* Ignore IFS whitespace at start */
6496 if (q == start && ifsspc) {
6502 sp = stzalloc(sizeof(*sp));
6504 *arglist->lastp = sp;
6505 arglist->lastp = &sp->next;
6509 if (p >= string + ifsp->endoff) {
6515 if (strchr(ifs, *p) == NULL) {
6519 if (strchr(defifs, *p) == NULL) {
6534 } while (ifsp != NULL);
6543 sp = stzalloc(sizeof(*sp));
6545 *arglist->lastp = sp;
6546 arglist->lastp = &sp->next;
6552 struct ifsregion *p;
6557 struct ifsregion *ifsp;
6563 ifsfirst.next = NULL;
6568 * Add a file name to the list.
6571 addfname(const char *name)
6575 sp = stzalloc(sizeof(*sp));
6576 sp->text = ststrdup(name);
6578 exparg.lastp = &sp->next;
6581 static char *expdir;
6584 * Do metacharacter (i.e. *, ?, [...]) expansion.
6587 expmeta(char *enddir, char *name)
6602 for (p = name; *p; p++) {
6603 if (*p == '*' || *p == '?')
6605 else if (*p == '[') {
6612 if (*q == '/' || *q == '\0')
6619 } else if (*p == '\\')
6621 else if (*p == '/') {
6628 if (metaflag == 0) { /* we've reached the end of the file name */
6629 if (enddir != expdir)
6637 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6648 } while (p < start);
6650 if (enddir == expdir) {
6652 } else if (enddir == expdir + 1 && *expdir == '/') {
6661 if (enddir != expdir)
6663 if (*endname == 0) {
6675 while (!intpending && (dp = readdir(dirp)) != NULL) {
6676 if (dp->d_name[0] == '.' && !matchdot)
6678 if (pmatch(start, dp->d_name)) {
6680 strcpy(enddir, dp->d_name);
6683 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6686 expmeta(p, endname);
6695 static struct strlist *
6696 msort(struct strlist *list, int len)
6698 struct strlist *p, *q = NULL;
6699 struct strlist **lpp;
6707 for (n = half; --n >= 0;) {
6711 q->next = NULL; /* terminate first half of list */
6712 q = msort(list, half); /* sort first half of list */
6713 p = msort(p, len - half); /* sort second half */
6716 #if ENABLE_LOCALE_SUPPORT
6717 if (strcoll(p->text, q->text) < 0)
6719 if (strcmp(p->text, q->text) < 0)
6743 * Sort the results of file name expansion. It calculates the number of
6744 * strings to sort and then calls msort (short for merge sort) to do the
6747 static struct strlist *
6748 expsort(struct strlist *str)
6754 for (sp = str; sp; sp = sp->next)
6756 return msort(str, len);
6760 expandmeta(struct strlist *str /*, int flag*/)
6762 static const char metachars[] ALIGN1 = {
6765 /* TODO - EXP_REDIR */
6768 struct strlist **savelastp;
6774 if (!strpbrk(str->text, metachars))
6776 savelastp = exparg.lastp;
6779 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
6781 int i = strlen(str->text);
6782 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
6790 if (exparg.lastp == savelastp) {
6795 *exparg.lastp = str;
6796 rmescapes(str->text);
6797 exparg.lastp = &str->next;
6799 *exparg.lastp = NULL;
6800 *savelastp = sp = expsort(*savelastp);
6801 while (sp->next != NULL)
6803 exparg.lastp = &sp->next;
6810 * Perform variable substitution and command substitution on an argument,
6811 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6812 * perform splitting and file name expansion. When arglist is NULL, perform
6813 * here document expansion.
6816 expandarg(union node *arg, struct arglist *arglist, int flag)
6821 argbackq = arg->narg.backquote;
6822 STARTSTACKSTR(expdest);
6823 ifsfirst.next = NULL;
6825 argstr(arg->narg.text, flag,
6826 /* var_str_list: */ arglist ? arglist->list : NULL);
6827 p = _STPUTC('\0', expdest);
6829 if (arglist == NULL) {
6830 return; /* here document expanded */
6832 p = grabstackstr(p);
6833 exparg.lastp = &exparg.list;
6837 if (flag & EXP_FULL) {
6838 ifsbreakup(p, &exparg);
6839 *exparg.lastp = NULL;
6840 exparg.lastp = &exparg.list;
6841 expandmeta(exparg.list /*, flag*/);
6843 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
6845 sp = stzalloc(sizeof(*sp));
6848 exparg.lastp = &sp->next;
6852 *exparg.lastp = NULL;
6854 *arglist->lastp = exparg.list;
6855 arglist->lastp = exparg.lastp;
6860 * Expand shell variables and backquotes inside a here document.
6863 expandhere(union node *arg, int fd)
6866 expandarg(arg, (struct arglist *)NULL, 0);
6867 full_write(fd, stackblock(), expdest - (char *)stackblock());
6871 * Returns true if the pattern matches the string.
6874 patmatch(char *pattern, const char *string)
6876 return pmatch(preglob(pattern, 0, 0), string);
6880 * See if a pattern matches in a case statement.
6883 casematch(union node *pattern, char *val)
6885 struct stackmark smark;
6888 setstackmark(&smark);
6889 argbackq = pattern->narg.backquote;
6890 STARTSTACKSTR(expdest);
6892 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
6893 /* var_str_list: */ NULL);
6894 STACKSTRNUL(expdest);
6895 result = patmatch(stackblock(), val);
6896 popstackmark(&smark);
6901 /* ============ find_command */
6905 int (*builtin)(int, char **);
6906 /* unsigned flags; */
6908 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
6909 /* "regular" builtins always take precedence over commands,
6910 * regardless of PATH=....%builtin... position */
6911 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
6912 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
6915 smallint cmdtype; /* CMDxxx */
6918 /* index >= 0 for commands without path (slashes) */
6919 /* (TODO: what exactly does the value mean? PATH position?) */
6920 /* index == -1 for commands with slashes */
6921 /* index == (-2 - applet_no) for NOFORK applets */
6922 const struct builtincmd *cmd;
6923 struct funcnode *func;
6926 /* values of cmdtype */
6927 #define CMDUNKNOWN -1 /* no entry in table for command */
6928 #define CMDNORMAL 0 /* command is an executable program */
6929 #define CMDFUNCTION 1 /* command is a shell function */
6930 #define CMDBUILTIN 2 /* command is a shell builtin */
6932 /* action to find_command() */
6933 #define DO_ERR 0x01 /* prints errors */
6934 #define DO_ABS 0x02 /* checks absolute paths */
6935 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
6936 #define DO_ALTPATH 0x08 /* using alternate path */
6937 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
6939 static void find_command(char *, struct cmdentry *, int, const char *);
6942 /* ============ Hashing commands */
6945 * When commands are first encountered, they are entered in a hash table.
6946 * This ensures that a full path search will not have to be done for them
6947 * on each invocation.
6949 * We should investigate converting to a linear search, even though that
6950 * would make the command name "hash" a misnomer.
6954 struct tblentry *next; /* next entry in hash chain */
6955 union param param; /* definition of builtin function */
6956 smallint cmdtype; /* CMDxxx */
6957 char rehash; /* if set, cd done since entry created */
6958 char cmdname[1]; /* name of command */
6961 static struct tblentry **cmdtable;
6962 #define INIT_G_cmdtable() do { \
6963 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
6966 static int builtinloc = -1; /* index in path of %builtin, or -1 */
6970 tryexec(USE_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
6974 #if ENABLE_FEATURE_SH_STANDALONE
6975 if (applet_no >= 0) {
6976 if (APPLET_IS_NOEXEC(applet_no)) {
6979 run_applet_no_and_exit(applet_no, argv);
6981 /* re-exec ourselves with the new arguments */
6982 execve(bb_busybox_exec_path, argv, envp);
6983 /* If they called chroot or otherwise made the binary no longer
6984 * executable, fall through */
6991 execve(cmd, argv, envp);
6992 } while (errno == EINTR);
6994 execve(cmd, argv, envp);
7000 if (errno == ENOEXEC) {
7004 for (ap = argv; *ap; ap++)
7006 ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0]));
7008 ap[0] = cmd = (char *)DEFAULT_SHELL;
7011 while ((*ap++ = *argv++) != NULL)
7020 * Exec a program. Never returns. If you change this routine, you may
7021 * have to change the find_command routine as well.
7023 static void shellexec(char **, const char *, int) NORETURN;
7025 shellexec(char **argv, const char *path, int idx)
7031 #if ENABLE_FEATURE_SH_STANDALONE
7035 clearredir(/*drop:*/ 1);
7036 envp = listvars(VEXPORT, VUNSET, 0);
7037 if (strchr(argv[0], '/') != NULL
7038 #if ENABLE_FEATURE_SH_STANDALONE
7039 || (applet_no = find_applet_by_name(argv[0])) >= 0
7042 tryexec(USE_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7046 while ((cmdname = padvance(&path, argv[0])) != NULL) {
7047 if (--idx < 0 && pathopt == NULL) {
7048 tryexec(USE_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7049 if (errno != ENOENT && errno != ENOTDIR)
7056 /* Map to POSIX errors */
7068 exitstatus = exerrno;
7069 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
7070 argv[0], e, suppressint));
7071 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7076 printentry(struct tblentry *cmdp)
7082 idx = cmdp->param.index;
7085 name = padvance(&path, cmdp->cmdname);
7087 } while (--idx >= 0);
7088 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7092 * Clear out command entries. The argument specifies the first entry in
7093 * PATH which has changed.
7096 clearcmdentry(int firstchange)
7098 struct tblentry **tblp;
7099 struct tblentry **pp;
7100 struct tblentry *cmdp;
7103 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7105 while ((cmdp = *pp) != NULL) {
7106 if ((cmdp->cmdtype == CMDNORMAL &&
7107 cmdp->param.index >= firstchange)
7108 || (cmdp->cmdtype == CMDBUILTIN &&
7109 builtinloc >= firstchange)
7122 * Locate a command in the command hash table. If "add" is nonzero,
7123 * add the command to the table if it is not already present. The
7124 * variable "lastcmdentry" is set to point to the address of the link
7125 * pointing to the entry, so that delete_cmd_entry can delete the
7128 * Interrupts must be off if called with add != 0.
7130 static struct tblentry **lastcmdentry;
7132 static struct tblentry *
7133 cmdlookup(const char *name, int add)
7135 unsigned int hashval;
7137 struct tblentry *cmdp;
7138 struct tblentry **pp;
7141 hashval = (unsigned char)*p << 4;
7143 hashval += (unsigned char)*p++;
7145 pp = &cmdtable[hashval % CMDTABLESIZE];
7146 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7147 if (strcmp(cmdp->cmdname, name) == 0)
7151 if (add && cmdp == NULL) {
7152 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7154 /* + 1 - already done because
7155 * tblentry::cmdname is char[1] */);
7156 /*cmdp->next = NULL; - ckzalloc did it */
7157 cmdp->cmdtype = CMDUNKNOWN;
7158 strcpy(cmdp->cmdname, name);
7165 * Delete the command entry returned on the last lookup.
7168 delete_cmd_entry(void)
7170 struct tblentry *cmdp;
7173 cmdp = *lastcmdentry;
7174 *lastcmdentry = cmdp->next;
7175 if (cmdp->cmdtype == CMDFUNCTION)
7176 freefunc(cmdp->param.func);
7182 * Add a new command entry, replacing any existing command entry for
7183 * the same name - except special builtins.
7186 addcmdentry(char *name, struct cmdentry *entry)
7188 struct tblentry *cmdp;
7190 cmdp = cmdlookup(name, 1);
7191 if (cmdp->cmdtype == CMDFUNCTION) {
7192 freefunc(cmdp->param.func);
7194 cmdp->cmdtype = entry->cmdtype;
7195 cmdp->param = entry->u;
7200 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7202 struct tblentry **pp;
7203 struct tblentry *cmdp;
7205 struct cmdentry entry;
7208 if (nextopt("r") != '\0') {
7213 if (*argptr == NULL) {
7214 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7215 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7216 if (cmdp->cmdtype == CMDNORMAL)
7224 while ((name = *argptr) != NULL) {
7225 cmdp = cmdlookup(name, 0);
7227 && (cmdp->cmdtype == CMDNORMAL
7228 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7232 find_command(name, &entry, DO_ERR, pathval());
7233 if (entry.cmdtype == CMDUNKNOWN)
7241 * Called when a cd is done. Marks all commands so the next time they
7242 * are executed they will be rehashed.
7247 struct tblentry **pp;
7248 struct tblentry *cmdp;
7250 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7251 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7252 if (cmdp->cmdtype == CMDNORMAL
7253 || (cmdp->cmdtype == CMDBUILTIN
7254 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7264 * Fix command hash table when PATH changed.
7265 * Called before PATH is changed. The argument is the new value of PATH;
7266 * pathval() still returns the old value at this point.
7267 * Called with interrupts off.
7270 changepath(const char *new)
7278 firstchange = 9999; /* assume no change */
7284 if ((*old == '\0' && *new == ':')
7285 || (*old == ':' && *new == '\0'))
7287 old = new; /* ignore subsequent differences */
7291 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7297 if (builtinloc < 0 && idx_bltin >= 0)
7298 builtinloc = idx_bltin; /* zap builtins */
7299 if (builtinloc >= 0 && idx_bltin < 0)
7301 clearcmdentry(firstchange);
7302 builtinloc = idx_bltin;
7317 #define TENDBQUOTE 12
7334 typedef smallint token_id_t;
7336 /* first char is indicating which tokens mark the end of a list */
7337 static const char *const tokname_array[] = {
7351 #define KWDOFFSET 13
7352 /* the following are keywords */
7374 static char buf[16];
7377 //if (tok < TSEMI) return tokname_array[tok] + 1;
7378 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
7383 sprintf(buf + (tok >= TSEMI), "%s%c",
7384 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
7388 /* Wrapper around strcmp for qsort/bsearch/... */
7390 pstrcmp(const void *a, const void *b)
7392 return strcmp((char*) a, (*(char**) b) + 1);
7395 static const char *const *
7396 findkwd(const char *s)
7398 return bsearch(s, tokname_array + KWDOFFSET,
7399 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7400 sizeof(tokname_array[0]), pstrcmp);
7404 * Locate and print what a word is...
7407 describe_command(char *command, int describe_command_verbose)
7409 struct cmdentry entry;
7410 struct tblentry *cmdp;
7411 #if ENABLE_ASH_ALIAS
7412 const struct alias *ap;
7414 const char *path = pathval();
7416 if (describe_command_verbose) {
7420 /* First look at the keywords */
7421 if (findkwd(command)) {
7422 out1str(describe_command_verbose ? " is a shell keyword" : command);
7426 #if ENABLE_ASH_ALIAS
7427 /* Then look at the aliases */
7428 ap = lookupalias(command, 0);
7430 if (!describe_command_verbose) {
7435 out1fmt(" is an alias for %s", ap->val);
7439 /* Then check if it is a tracked alias */
7440 cmdp = cmdlookup(command, 0);
7442 entry.cmdtype = cmdp->cmdtype;
7443 entry.u = cmdp->param;
7445 /* Finally use brute force */
7446 find_command(command, &entry, DO_ABS, path);
7449 switch (entry.cmdtype) {
7451 int j = entry.u.index;
7457 p = padvance(&path, command);
7461 if (describe_command_verbose) {
7463 (cmdp ? " a tracked alias for" : nullstr), p
7472 if (describe_command_verbose) {
7473 out1str(" is a shell function");
7480 if (describe_command_verbose) {
7481 out1fmt(" is a %sshell builtin",
7482 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7483 "special " : nullstr
7491 if (describe_command_verbose) {
7492 out1str(": not found\n");
7497 outstr("\n", stdout);
7502 typecmd(int argc UNUSED_PARAM, char **argv)
7508 /* type -p ... ? (we don't bother checking for 'p') */
7509 if (argv[1] && argv[1][0] == '-') {
7514 err |= describe_command(argv[i++], verbose);
7519 #if ENABLE_ASH_CMDCMD
7521 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7529 while ((c = nextopt("pvV")) != '\0')
7531 verify |= VERIFY_VERBOSE;
7533 verify |= VERIFY_BRIEF;
7538 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7539 if (verify && (*argptr != NULL)) {
7540 return describe_command(*argptr, verify - VERIFY_BRIEF);
7548 /* ============ eval.c */
7550 static int funcblocksize; /* size of structures in function */
7551 static int funcstringsize; /* size of strings in node */
7552 static void *funcblock; /* block to allocate function from */
7553 static char *funcstring; /* block to allocate strings from */
7555 /* flags in argument to evaltree */
7556 #define EV_EXIT 01 /* exit after evaluating tree */
7557 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7558 #define EV_BACKCMD 04 /* command executing within back quotes */
7560 static const short nodesize[N_NUMBER] = {
7561 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
7562 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
7563 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
7564 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
7565 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
7566 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
7567 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
7568 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
7569 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
7570 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
7571 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
7572 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
7573 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
7574 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
7575 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
7576 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
7577 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
7578 #if ENABLE_ASH_BASH_COMPAT
7579 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
7581 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
7582 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
7583 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
7584 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
7585 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
7586 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
7587 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
7588 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
7589 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
7592 static void calcsize(union node *n);
7595 sizenodelist(struct nodelist *lp)
7598 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7605 calcsize(union node *n)
7609 funcblocksize += nodesize[n->type];
7612 calcsize(n->ncmd.redirect);
7613 calcsize(n->ncmd.args);
7614 calcsize(n->ncmd.assign);
7617 sizenodelist(n->npipe.cmdlist);
7622 calcsize(n->nredir.redirect);
7623 calcsize(n->nredir.n);
7630 calcsize(n->nbinary.ch2);
7631 calcsize(n->nbinary.ch1);
7634 calcsize(n->nif.elsepart);
7635 calcsize(n->nif.ifpart);
7636 calcsize(n->nif.test);
7639 funcstringsize += strlen(n->nfor.var) + 1;
7640 calcsize(n->nfor.body);
7641 calcsize(n->nfor.args);
7644 calcsize(n->ncase.cases);
7645 calcsize(n->ncase.expr);
7648 calcsize(n->nclist.body);
7649 calcsize(n->nclist.pattern);
7650 calcsize(n->nclist.next);
7654 sizenodelist(n->narg.backquote);
7655 funcstringsize += strlen(n->narg.text) + 1;
7656 calcsize(n->narg.next);
7659 #if ENABLE_ASH_BASH_COMPAT
7666 calcsize(n->nfile.fname);
7667 calcsize(n->nfile.next);
7671 calcsize(n->ndup.vname);
7672 calcsize(n->ndup.next);
7676 calcsize(n->nhere.doc);
7677 calcsize(n->nhere.next);
7680 calcsize(n->nnot.com);
7686 nodeckstrdup(char *s)
7688 char *rtn = funcstring;
7690 strcpy(funcstring, s);
7691 funcstring += strlen(s) + 1;
7695 static union node *copynode(union node *);
7697 static struct nodelist *
7698 copynodelist(struct nodelist *lp)
7700 struct nodelist *start;
7701 struct nodelist **lpp;
7706 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7707 (*lpp)->n = copynode(lp->n);
7709 lpp = &(*lpp)->next;
7716 copynode(union node *n)
7723 funcblock = (char *) funcblock + nodesize[n->type];
7727 new->ncmd.redirect = copynode(n->ncmd.redirect);
7728 new->ncmd.args = copynode(n->ncmd.args);
7729 new->ncmd.assign = copynode(n->ncmd.assign);
7732 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7733 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
7738 new->nredir.redirect = copynode(n->nredir.redirect);
7739 new->nredir.n = copynode(n->nredir.n);
7746 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7747 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7750 new->nif.elsepart = copynode(n->nif.elsepart);
7751 new->nif.ifpart = copynode(n->nif.ifpart);
7752 new->nif.test = copynode(n->nif.test);
7755 new->nfor.var = nodeckstrdup(n->nfor.var);
7756 new->nfor.body = copynode(n->nfor.body);
7757 new->nfor.args = copynode(n->nfor.args);
7760 new->ncase.cases = copynode(n->ncase.cases);
7761 new->ncase.expr = copynode(n->ncase.expr);
7764 new->nclist.body = copynode(n->nclist.body);
7765 new->nclist.pattern = copynode(n->nclist.pattern);
7766 new->nclist.next = copynode(n->nclist.next);
7770 new->narg.backquote = copynodelist(n->narg.backquote);
7771 new->narg.text = nodeckstrdup(n->narg.text);
7772 new->narg.next = copynode(n->narg.next);
7775 #if ENABLE_ASH_BASH_COMPAT
7782 new->nfile.fname = copynode(n->nfile.fname);
7783 new->nfile.fd = n->nfile.fd;
7784 new->nfile.next = copynode(n->nfile.next);
7788 new->ndup.vname = copynode(n->ndup.vname);
7789 new->ndup.dupfd = n->ndup.dupfd;
7790 new->ndup.fd = n->ndup.fd;
7791 new->ndup.next = copynode(n->ndup.next);
7795 new->nhere.doc = copynode(n->nhere.doc);
7796 new->nhere.fd = n->nhere.fd;
7797 new->nhere.next = copynode(n->nhere.next);
7800 new->nnot.com = copynode(n->nnot.com);
7803 new->type = n->type;
7808 * Make a copy of a parse tree.
7810 static struct funcnode *
7811 copyfunc(union node *n)
7816 funcblocksize = offsetof(struct funcnode, n);
7819 blocksize = funcblocksize;
7820 f = ckmalloc(blocksize + funcstringsize);
7821 funcblock = (char *) f + offsetof(struct funcnode, n);
7822 funcstring = (char *) f + blocksize;
7829 * Define a shell function.
7832 defun(char *name, union node *func)
7834 struct cmdentry entry;
7837 entry.cmdtype = CMDFUNCTION;
7838 entry.u.func = copyfunc(func);
7839 addcmdentry(name, &entry);
7843 static int evalskip; /* set if we are skipping commands */
7844 /* reasons for skipping commands (see comment on breakcmd routine) */
7845 #define SKIPBREAK (1 << 0)
7846 #define SKIPCONT (1 << 1)
7847 #define SKIPFUNC (1 << 2)
7848 #define SKIPFILE (1 << 3)
7849 #define SKIPEVAL (1 << 4)
7850 static int skipcount; /* number of levels to skip */
7851 static int funcnest; /* depth of function calls */
7852 static int loopnest; /* current loop nesting level */
7854 /* forward decl way out to parsing code - dotrap needs it */
7855 static int evalstring(char *s, int mask);
7858 * Called to execute a trap. Perhaps we should avoid entering new trap
7859 * handlers while we are executing a trap handler.
7870 savestatus = exitstatus;
7874 for (i = 1, q = gotsig; i < NSIG; i++, q++) {
7882 skip = evalstring(p, SKIPEVAL);
7883 exitstatus = savestatus;
7891 /* forward declarations - evaluation is fairly recursive business... */
7892 static void evalloop(union node *, int);
7893 static void evalfor(union node *, int);
7894 static void evalcase(union node *, int);
7895 static void evalsubshell(union node *, int);
7896 static void expredir(union node *);
7897 static void evalpipe(union node *, int);
7898 static void evalcommand(union node *, int);
7899 static int evalbltin(const struct builtincmd *, int, char **);
7900 static void prehash(union node *);
7903 * Evaluate a parse tree. The value is left in the global variable
7907 evaltree(union node *n, int flags)
7910 struct jmploc *volatile savehandler = exception_handler;
7911 struct jmploc jmploc;
7913 void (*evalfn)(union node *, int);
7917 TRACE(("evaltree(NULL) called\n"));
7920 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
7921 getpid(), n, n->type, flags));
7923 exception_handler = &jmploc;
7925 int err = setjmp(jmploc.loc);
7927 /* if it was a signal, check for trap handlers */
7928 if (exception == EXSIG)
7930 /* continue on the way out */
7931 exception_handler = savehandler;
7932 longjmp(exception_handler->loc, err);
7939 out1fmt("Node type = %d\n", n->type);
7944 evaltree(n->nnot.com, EV_TESTED);
7945 status = !exitstatus;
7948 expredir(n->nredir.redirect);
7949 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
7951 evaltree(n->nredir.n, flags & EV_TESTED);
7952 status = exitstatus;
7954 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
7957 evalfn = evalcommand;
7959 if (eflag && !(flags & EV_TESTED))
7971 evalfn = evalsubshell;
7984 #error NAND + 1 != NOR
7986 #if NOR + 1 != NSEMI
7987 #error NOR + 1 != NSEMI
7989 unsigned is_or = n->type - NAND;
7992 (flags | ((is_or >> 1) - 1)) & EV_TESTED
7994 if (!exitstatus == is_or)
8007 evaltree(n->nif.test, EV_TESTED);
8010 if (exitstatus == 0) {
8013 } else if (n->nif.elsepart) {
8014 n = n->nif.elsepart;
8019 defun(n->narg.text, n->narg.next);
8023 exitstatus = status;
8028 exception_handler = savehandler;
8030 if (checkexit & exitstatus)
8031 evalskip |= SKIPEVAL;
8032 else if (pendingsig && dotrap())
8035 if (flags & EV_EXIT) {
8037 raise_exception(EXEXIT);
8041 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8044 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8047 evalloop(union node *n, int flags)
8057 evaltree(n->nbinary.ch1, EV_TESTED);
8060 if (evalskip == SKIPCONT && --skipcount <= 0) {
8064 if (evalskip == SKIPBREAK && --skipcount <= 0)
8069 if (n->type != NWHILE)
8073 evaltree(n->nbinary.ch2, flags);
8074 status = exitstatus;
8079 exitstatus = status;
8083 evalfor(union node *n, int flags)
8085 struct arglist arglist;
8088 struct stackmark smark;
8090 setstackmark(&smark);
8091 arglist.list = NULL;
8092 arglist.lastp = &arglist.list;
8093 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8094 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
8099 *arglist.lastp = NULL;
8104 for (sp = arglist.list; sp; sp = sp->next) {
8105 setvar(n->nfor.var, sp->text, 0);
8106 evaltree(n->nfor.body, flags);
8108 if (evalskip == SKIPCONT && --skipcount <= 0) {
8112 if (evalskip == SKIPBREAK && --skipcount <= 0)
8119 popstackmark(&smark);
8123 evalcase(union node *n, int flags)
8127 struct arglist arglist;
8128 struct stackmark smark;
8130 setstackmark(&smark);
8131 arglist.list = NULL;
8132 arglist.lastp = &arglist.list;
8133 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8135 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8136 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8137 if (casematch(patp, arglist.list->text)) {
8138 if (evalskip == 0) {
8139 evaltree(cp->nclist.body, flags);
8146 popstackmark(&smark);
8150 * Kick off a subshell to evaluate a tree.
8153 evalsubshell(union node *n, int flags)
8156 int backgnd = (n->type == NBACKGND);
8159 expredir(n->nredir.redirect);
8160 if (!backgnd && flags & EV_EXIT && !trap[0])
8163 jp = makejob(/*n,*/ 1);
8164 if (forkshell(jp, n, backgnd) == 0) {
8168 flags &=~ EV_TESTED;
8170 redirect(n->nredir.redirect, 0);
8171 evaltreenr(n->nredir.n, flags);
8176 status = waitforjob(jp);
8177 exitstatus = status;
8182 * Compute the names of the files in a redirection list.
8184 static void fixredir(union node *, const char *, int);
8186 expredir(union node *n)
8190 for (redir = n; redir; redir = redir->nfile.next) {
8194 fn.lastp = &fn.list;
8195 switch (redir->type) {
8199 #if ENABLE_ASH_BASH_COMPAT
8204 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8205 #if ENABLE_ASH_BASH_COMPAT
8208 redir->nfile.expfname = fn.list->text;
8211 case NTOFD: /* >& */
8212 if (redir->ndup.vname) {
8213 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8214 if (fn.list == NULL)
8215 ash_msg_and_raise_error("redir error");
8216 #if ENABLE_ASH_BASH_COMPAT
8217 //FIXME: we used expandarg with different args!
8218 if (!isdigit_str9(fn.list->text)) {
8219 /* >&file, not >&fd */
8220 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8221 ash_msg_and_raise_error("redir error");
8223 goto store_expfname;
8226 fixredir(redir, fn.list->text, 1);
8234 * Evaluate a pipeline. All the processes in the pipeline are children
8235 * of the process creating the pipeline. (This differs from some versions
8236 * of the shell, which make the last process in a pipeline the parent
8240 evalpipe(union node *n, int flags)
8243 struct nodelist *lp;
8248 TRACE(("evalpipe(0x%lx) called\n", (long)n));
8250 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8254 jp = makejob(/*n,*/ pipelen);
8256 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8260 if (pipe(pip) < 0) {
8262 ash_msg_and_raise_error("pipe call failed");
8265 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8278 evaltreenr(lp->n, flags);
8286 if (n->npipe.pipe_backgnd == 0) {
8287 exitstatus = waitforjob(jp);
8288 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
8294 * Controls whether the shell is interactive or not.
8297 setinteractive(int on)
8299 static smallint is_interactive;
8301 if (++on == is_interactive)
8303 is_interactive = on;
8307 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8308 if (is_interactive > 1) {
8309 /* Looks like they want an interactive shell */
8310 static smallint did_banner;
8315 "%s built-in shell (ash)\n"
8316 "Enter 'help' for a list of built-in commands."
8331 setinteractive(iflag);
8333 #if ENABLE_FEATURE_EDITING_VI
8335 line_input_state->flags |= VI_MODE;
8337 line_input_state->flags &= ~VI_MODE;
8339 viflag = 0; /* forcibly keep the option off */
8343 static struct localvar *localvars;
8346 * Called after a function returns.
8347 * Interrupts must be off.
8352 struct localvar *lvp;
8355 while ((lvp = localvars) != NULL) {
8356 localvars = lvp->next;
8358 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
8359 if (vp == NULL) { /* $- saved */
8360 memcpy(optlist, lvp->text, sizeof(optlist));
8361 free((char*)lvp->text);
8363 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8367 (*vp->func)(strchrnul(lvp->text, '=') + 1);
8368 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8369 free((char*)vp->text);
8370 vp->flags = lvp->flags;
8371 vp->text = lvp->text;
8378 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8380 volatile struct shparam saveparam;
8381 struct localvar *volatile savelocalvars;
8382 struct jmploc *volatile savehandler;
8383 struct jmploc jmploc;
8386 saveparam = shellparam;
8387 savelocalvars = localvars;
8388 e = setjmp(jmploc.loc);
8393 savehandler = exception_handler;
8394 exception_handler = &jmploc;
8396 shellparam.malloced = 0;
8400 shellparam.nparam = argc - 1;
8401 shellparam.p = argv + 1;
8402 #if ENABLE_ASH_GETOPTS
8403 shellparam.optind = 1;
8404 shellparam.optoff = -1;
8406 evaltree(&func->n, flags & EV_TESTED);
8412 localvars = savelocalvars;
8413 freeparam(&shellparam);
8414 shellparam = saveparam;
8415 exception_handler = savehandler;
8417 evalskip &= ~SKIPFUNC;
8421 #if ENABLE_ASH_CMDCMD
8423 parse_command_args(char **argv, const char **path)
8436 if (c == '-' && !*cp) {
8443 *path = bb_default_path;
8446 /* run 'typecmd' for other options */
8457 * Make a variable a local variable. When a variable is made local, it's
8458 * value and flags are saved in a localvar structure. The saved values
8459 * will be restored when the shell function returns. We handle the name
8460 * "-" as a special case.
8465 struct localvar *lvp;
8470 lvp = ckzalloc(sizeof(struct localvar));
8471 if (LONE_DASH(name)) {
8473 p = ckmalloc(sizeof(optlist));
8474 lvp->text = memcpy(p, optlist, sizeof(optlist));
8479 vpp = hashvar(name);
8480 vp = *findvar(vpp, name);
8481 eq = strchr(name, '=');
8484 setvareq(name, VSTRFIXED);
8486 setvar(name, NULL, VSTRFIXED);
8487 vp = *vpp; /* the new variable */
8488 lvp->flags = VUNSET;
8490 lvp->text = vp->text;
8491 lvp->flags = vp->flags;
8492 vp->flags |= VSTRFIXED|VTEXTFIXED;
8498 lvp->next = localvars;
8504 * The "local" command.
8507 localcmd(int argc UNUSED_PARAM, char **argv)
8512 while ((name = *argv++) != NULL) {
8519 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8525 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8531 execcmd(int argc UNUSED_PARAM, char **argv)
8534 iflag = 0; /* exit on error */
8537 shellexec(argv + 1, pathval(), 0);
8543 * The return command.
8546 returncmd(int argc UNUSED_PARAM, char **argv)
8549 * If called outside a function, do what ksh does;
8550 * skip the rest of the file.
8552 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8553 return argv[1] ? number(argv[1]) : exitstatus;
8556 /* Forward declarations for builtintab[] */
8557 static int breakcmd(int, char **);
8558 static int dotcmd(int, char **);
8559 static int evalcmd(int, char **);
8560 static int exitcmd(int, char **);
8561 static int exportcmd(int, char **);
8562 #if ENABLE_ASH_GETOPTS
8563 static int getoptscmd(int, char **);
8565 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8566 static int helpcmd(int, char **);
8568 #if ENABLE_ASH_MATH_SUPPORT
8569 static int letcmd(int, char **);
8571 static int readcmd(int, char **);
8572 static int setcmd(int, char **);
8573 static int shiftcmd(int, char **);
8574 static int timescmd(int, char **);
8575 static int trapcmd(int, char **);
8576 static int umaskcmd(int, char **);
8577 static int unsetcmd(int, char **);
8578 static int ulimitcmd(int, char **);
8580 #define BUILTIN_NOSPEC "0"
8581 #define BUILTIN_SPECIAL "1"
8582 #define BUILTIN_REGULAR "2"
8583 #define BUILTIN_SPEC_REG "3"
8584 #define BUILTIN_ASSIGN "4"
8585 #define BUILTIN_SPEC_ASSG "5"
8586 #define BUILTIN_REG_ASSG "6"
8587 #define BUILTIN_SPEC_REG_ASSG "7"
8589 /* We do not handle [[ expr ]] bashism bash-compatibly,
8590 * we make it a synonym of [ expr ].
8591 * Basically, word splitting and pathname expansion should NOT be performed
8593 * no word splitting: a="a b"; [[ $a = "a b" ]]; echo $? should print "0"
8594 * no pathname expansion: [[ /bin/m* = "/bin/m*" ]]; echo $? should print "0"
8595 * Additional operators:
8596 * || and && should work as -o and -a
8598 * Apart from the above, [[ expr ]] should work as [ expr ]
8601 #define echocmd echo_main
8602 #define printfcmd printf_main
8603 #define testcmd test_main
8605 /* Keep these in proper order since it is searched via bsearch() */
8606 static const struct builtincmd builtintab[] = {
8607 { BUILTIN_SPEC_REG ".", dotcmd },
8608 { BUILTIN_SPEC_REG ":", truecmd },
8609 #if ENABLE_ASH_BUILTIN_TEST
8610 { BUILTIN_REGULAR "[", testcmd },
8611 #if ENABLE_ASH_BASH_COMPAT
8612 { BUILTIN_REGULAR "[[", testcmd },
8615 #if ENABLE_ASH_ALIAS
8616 { BUILTIN_REG_ASSG "alias", aliascmd },
8619 { BUILTIN_REGULAR "bg", fg_bgcmd },
8621 { BUILTIN_SPEC_REG "break", breakcmd },
8622 { BUILTIN_REGULAR "cd", cdcmd },
8623 { BUILTIN_NOSPEC "chdir", cdcmd },
8624 #if ENABLE_ASH_CMDCMD
8625 { BUILTIN_REGULAR "command", commandcmd },
8627 { BUILTIN_SPEC_REG "continue", breakcmd },
8628 #if ENABLE_ASH_BUILTIN_ECHO
8629 { BUILTIN_REGULAR "echo", echocmd },
8631 { BUILTIN_SPEC_REG "eval", evalcmd },
8632 { BUILTIN_SPEC_REG "exec", execcmd },
8633 { BUILTIN_SPEC_REG "exit", exitcmd },
8634 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8635 { BUILTIN_REGULAR "false", falsecmd },
8637 { BUILTIN_REGULAR "fg", fg_bgcmd },
8639 #if ENABLE_ASH_GETOPTS
8640 { BUILTIN_REGULAR "getopts", getoptscmd },
8642 { BUILTIN_NOSPEC "hash", hashcmd },
8643 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8644 { BUILTIN_NOSPEC "help", helpcmd },
8647 { BUILTIN_REGULAR "jobs", jobscmd },
8648 { BUILTIN_REGULAR "kill", killcmd },
8650 #if ENABLE_ASH_MATH_SUPPORT
8651 { BUILTIN_NOSPEC "let", letcmd },
8653 { BUILTIN_ASSIGN "local", localcmd },
8654 #if ENABLE_ASH_BUILTIN_PRINTF
8655 { BUILTIN_REGULAR "printf", printfcmd },
8657 { BUILTIN_NOSPEC "pwd", pwdcmd },
8658 { BUILTIN_REGULAR "read", readcmd },
8659 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8660 { BUILTIN_SPEC_REG "return", returncmd },
8661 { BUILTIN_SPEC_REG "set", setcmd },
8662 { BUILTIN_SPEC_REG "shift", shiftcmd },
8663 { BUILTIN_SPEC_REG "source", dotcmd },
8664 #if ENABLE_ASH_BUILTIN_TEST
8665 { BUILTIN_REGULAR "test", testcmd },
8667 { BUILTIN_SPEC_REG "times", timescmd },
8668 { BUILTIN_SPEC_REG "trap", trapcmd },
8669 { BUILTIN_REGULAR "true", truecmd },
8670 { BUILTIN_NOSPEC "type", typecmd },
8671 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
8672 { BUILTIN_REGULAR "umask", umaskcmd },
8673 #if ENABLE_ASH_ALIAS
8674 { BUILTIN_REGULAR "unalias", unaliascmd },
8676 { BUILTIN_SPEC_REG "unset", unsetcmd },
8677 { BUILTIN_REGULAR "wait", waitcmd },
8680 /* Should match the above table! */
8681 #define COMMANDCMD (builtintab + \
8683 1 * ENABLE_ASH_BUILTIN_TEST + \
8684 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8685 1 * ENABLE_ASH_ALIAS + \
8686 1 * ENABLE_ASH_JOB_CONTROL + \
8688 #define EXECCMD (builtintab + \
8690 1 * ENABLE_ASH_BUILTIN_TEST + \
8691 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8692 1 * ENABLE_ASH_ALIAS + \
8693 1 * ENABLE_ASH_JOB_CONTROL + \
8695 1 * ENABLE_ASH_CMDCMD + \
8697 ENABLE_ASH_BUILTIN_ECHO + \
8701 * Search the table of builtin commands.
8703 static struct builtincmd *
8704 find_builtin(const char *name)
8706 struct builtincmd *bp;
8709 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8716 * Execute a simple command.
8719 isassignment(const char *p)
8721 const char *q = endofname(p);
8727 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8729 /* Preserve exitstatus of a previous possible redirection
8730 * as POSIX mandates */
8731 return back_exitstatus;
8734 evalcommand(union node *cmd, int flags)
8736 static const struct builtincmd null_bltin = {
8737 "\0\0", bltincmd /* why three NULs? */
8739 struct stackmark smark;
8741 struct arglist arglist;
8742 struct arglist varlist;
8745 const struct strlist *sp;
8746 struct cmdentry cmdentry;
8753 struct builtincmd *bcmd;
8754 smallint cmd_is_exec;
8755 smallint pseudovarflag = 0;
8757 /* First expand the arguments. */
8758 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8759 setstackmark(&smark);
8760 back_exitstatus = 0;
8762 cmdentry.cmdtype = CMDBUILTIN;
8763 cmdentry.u.cmd = &null_bltin;
8764 varlist.lastp = &varlist.list;
8765 *varlist.lastp = NULL;
8766 arglist.lastp = &arglist.list;
8767 *arglist.lastp = NULL;
8770 if (cmd->ncmd.args) {
8771 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8772 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8775 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8776 struct strlist **spp;
8778 spp = arglist.lastp;
8779 if (pseudovarflag && isassignment(argp->narg.text))
8780 expandarg(argp, &arglist, EXP_VARTILDE);
8782 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8784 for (sp = *spp; sp; sp = sp->next)
8788 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8789 for (sp = arglist.list; sp; sp = sp->next) {
8790 TRACE(("evalcommand arg: %s\n", sp->text));
8791 *nargv++ = sp->text;
8796 if (iflag && funcnest == 0 && argc > 0)
8797 lastarg = nargv[-1];
8800 expredir(cmd->ncmd.redirect);
8801 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8804 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8805 struct strlist **spp;
8808 spp = varlist.lastp;
8809 expandarg(argp, &varlist, EXP_VARTILDE);
8812 * Modify the command lookup path, if a PATH= assignment
8816 if (varequal(p, path))
8820 /* Print the command if xflag is set. */
8823 const char *p = " %s";
8826 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8829 for (n = 0; n < 2; n++) {
8831 fdprintf(preverrout_fd, p, sp->text);
8839 safe_write(preverrout_fd, "\n", 1);
8845 /* Now locate the command. */
8847 const char *oldpath;
8848 int cmd_flag = DO_ERR;
8853 find_command(argv[0], &cmdentry, cmd_flag, path);
8854 if (cmdentry.cmdtype == CMDUNKNOWN) {
8860 /* implement bltin and command here */
8861 if (cmdentry.cmdtype != CMDBUILTIN)
8864 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8865 if (cmdentry.u.cmd == EXECCMD)
8867 #if ENABLE_ASH_CMDCMD
8868 if (cmdentry.u.cmd == COMMANDCMD) {
8870 nargv = parse_command_args(argv, &path);
8873 argc -= nargv - argv;
8875 cmd_flag |= DO_NOFUNC;
8883 /* We have a redirection error. */
8885 raise_exception(EXERROR);
8887 exitstatus = status;
8891 /* Execute the command. */
8892 switch (cmdentry.cmdtype) {
8895 #if ENABLE_FEATURE_SH_NOFORK
8896 /* Hmmm... shouldn't it happen somewhere in forkshell() instead?
8897 * Why "fork off a child process if necessary" doesn't apply to NOFORK? */
8899 /* find_command() encodes applet_no as (-2 - applet_no) */
8900 int applet_no = (- cmdentry.u.index - 2);
8901 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
8902 listsetvar(varlist.list, VEXPORT|VSTACK);
8903 /* run <applet>_main() */
8904 exitstatus = run_nofork_applet(applet_no, argv);
8909 /* Fork off a child process if necessary. */
8910 if (!(flags & EV_EXIT) || trap[0]) {
8912 jp = makejob(/*cmd,*/ 1);
8913 if (forkshell(jp, cmd, FORK_FG) != 0) {
8914 exitstatus = waitforjob(jp);
8920 listsetvar(varlist.list, VEXPORT|VSTACK);
8921 shellexec(argv, path, cmdentry.u.index);
8925 cmdenviron = varlist.list;
8927 struct strlist *list = cmdenviron;
8929 if (spclbltin > 0 || argc == 0) {
8931 if (cmd_is_exec && argc > 1)
8934 listsetvar(list, i);
8936 /* Tight loop with builtins only:
8937 * "while kill -0 $child; do true; done"
8938 * will never exit even if $child died, unless we do this
8939 * to reap the zombie and make kill detect that it's gone: */
8940 dowait(DOWAIT_NONBLOCK, NULL);
8942 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
8949 exit_status = 128 + SIGINT;
8951 exit_status = 128 + pendingsig;
8952 exitstatus = exit_status;
8953 if (i == EXINT || spclbltin > 0) {
8955 longjmp(exception_handler->loc, 1);
8962 listsetvar(varlist.list, 0);
8963 /* See above for the rationale */
8964 dowait(DOWAIT_NONBLOCK, NULL);
8965 if (evalfun(cmdentry.u.func, argc, argv, flags))
8971 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
8973 /* dsl: I think this is intended to be used to support
8974 * '_' in 'vi' command mode during line editing...
8975 * However I implemented that within libedit itself.
8977 setvar("_", lastarg, 0);
8979 popstackmark(&smark);
8983 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
8985 char *volatile savecmdname;
8986 struct jmploc *volatile savehandler;
8987 struct jmploc jmploc;
8990 savecmdname = commandname;
8991 i = setjmp(jmploc.loc);
8994 savehandler = exception_handler;
8995 exception_handler = &jmploc;
8996 commandname = argv[0];
8998 optptr = NULL; /* initialize nextopt */
8999 exitstatus = (*cmd->builtin)(argc, argv);
9000 flush_stdout_stderr();
9002 exitstatus |= ferror(stdout);
9004 commandname = savecmdname;
9006 exception_handler = savehandler;
9012 goodname(const char *p)
9014 return !*endofname(p);
9019 * Search for a command. This is called before we fork so that the
9020 * location of the command will be available in the parent as well as
9021 * the child. The check for "goodname" is an overly conservative
9022 * check that the name will not be subject to expansion.
9025 prehash(union node *n)
9027 struct cmdentry entry;
9029 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9030 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9034 /* ============ Builtin commands
9036 * Builtin commands whose functions are closely tied to evaluation
9037 * are implemented here.
9041 * Handle break and continue commands. Break, continue, and return are
9042 * all handled by setting the evalskip flag. The evaluation routines
9043 * above all check this flag, and if it is set they start skipping
9044 * commands rather than executing them. The variable skipcount is
9045 * the number of loops to break/continue, or the number of function
9046 * levels to return. (The latter is always 1.) It should probably
9047 * be an error to break out of more loops than exist, but it isn't
9048 * in the standard shell so we don't make it one here.
9051 breakcmd(int argc UNUSED_PARAM, char **argv)
9053 int n = argv[1] ? number(argv[1]) : 1;
9056 ash_msg_and_raise_error(illnum, argv[1]);
9060 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9067 /* ============ input.c
9069 * This implements the input routines used by the parser.
9072 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
9075 INPUT_PUSH_FILE = 1,
9076 INPUT_NOFILE_OK = 2,
9079 static int plinno = 1; /* input line number */
9080 /* number of characters left in input buffer */
9081 static int parsenleft; /* copy of parsefile->nleft */
9082 static int parselleft; /* copy of parsefile->lleft */
9083 /* next character in input buffer */
9084 static char *parsenextc; /* copy of parsefile->nextc */
9086 static smallint checkkwd;
9087 /* values of checkkwd variable */
9088 #define CHKALIAS 0x1
9095 struct strpush *sp = g_parsefile->strpush;
9098 #if ENABLE_ASH_ALIAS
9100 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
9101 checkkwd |= CHKALIAS;
9103 if (sp->string != sp->ap->val) {
9106 sp->ap->flag &= ~ALIASINUSE;
9107 if (sp->ap->flag & ALIASDEAD) {
9108 unalias(sp->ap->name);
9112 parsenextc = sp->prevstring;
9113 parsenleft = sp->prevnleft;
9114 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
9115 g_parsefile->strpush = sp->prev;
9116 if (sp != &(g_parsefile->basestrpush))
9125 char *buf = g_parsefile->buf;
9128 #if ENABLE_FEATURE_EDITING
9130 if (!iflag || g_parsefile->fd)
9131 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9133 #if ENABLE_FEATURE_TAB_COMPLETION
9134 line_input_state->path_lookup = pathval();
9136 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
9138 /* Ctrl+C pressed */
9147 if (nr < 0 && errno == 0) {
9148 /* Ctrl+D pressed */
9153 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9157 /* nonblock_safe_read() handles this problem */
9159 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9160 int flags = fcntl(0, F_GETFL);
9161 if (flags >= 0 && (flags & O_NONBLOCK)) {
9162 flags &= ~O_NONBLOCK;
9163 if (fcntl(0, F_SETFL, flags) >= 0) {
9164 out2str("sh: turning off NDELAY mode\n");
9175 * Refill the input buffer and return the next input character:
9177 * 1) If a string was pushed back on the input, pop it;
9178 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
9179 * from a string so we can't refill the buffer, return EOF.
9180 * 3) If the is more stuff in this buffer, use it else call read to fill it.
9181 * 4) Process input up to the next newline, deleting nul characters.
9190 while (g_parsefile->strpush) {
9191 #if ENABLE_ASH_ALIAS
9192 if (parsenleft == -1 && g_parsefile->strpush->ap
9193 && parsenextc[-1] != ' ' && parsenextc[-1] != '\t'
9199 if (--parsenleft >= 0)
9200 return signed_char2int(*parsenextc++);
9202 if (parsenleft == EOF_NLEFT || g_parsefile->buf == NULL)
9204 flush_stdout_stderr();
9211 parselleft = parsenleft = EOF_NLEFT;
9218 /* delete nul characters */
9226 memmove(q, q + 1, more);
9230 parsenleft = q - parsenextc - 1;
9236 parsenleft = q - parsenextc - 1;
9248 out2str(parsenextc);
9253 return signed_char2int(*parsenextc++);
9256 #define pgetc_as_macro() (--parsenleft >= 0 ? signed_char2int(*parsenextc++) : preadbuffer())
9260 return pgetc_as_macro();
9263 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9264 #define pgetc_fast() pgetc()
9266 #define pgetc_fast() pgetc_as_macro()
9270 * Same as pgetc(), but ignores PEOA.
9272 #if ENABLE_ASH_ALIAS
9279 } while (c == PEOA);
9283 #define pgetc2() pgetc()
9287 * Read a line from the script.
9290 pfgets(char *line, int len)
9296 while (--nleft > 0) {
9312 * Undo the last call to pgetc. Only one character may be pushed back.
9313 * PEOF may be pushed back.
9318 /* check is needed for ash -c 'echo 5&' + BASH_COMPAT to work */
9326 * Push a string back onto the input at this current parsefile level.
9327 * We handle aliases this way.
9329 #if !ENABLE_ASH_ALIAS
9330 #define pushstring(s, ap) pushstring(s)
9333 pushstring(char *s, struct alias *ap)
9340 if (g_parsefile->strpush) {
9341 sp = ckzalloc(sizeof(struct strpush));
9342 sp->prev = g_parsefile->strpush;
9343 g_parsefile->strpush = sp;
9345 sp = g_parsefile->strpush = &(g_parsefile->basestrpush);
9346 sp->prevstring = parsenextc;
9347 sp->prevnleft = parsenleft;
9348 #if ENABLE_ASH_ALIAS
9351 ap->flag |= ALIASINUSE;
9361 * To handle the "." command, a stack of input files is used. Pushfile
9362 * adds a new entry to the stack and popfile restores the previous level.
9367 struct parsefile *pf;
9369 g_parsefile->nleft = parsenleft;
9370 g_parsefile->lleft = parselleft;
9371 g_parsefile->nextc = parsenextc;
9372 g_parsefile->linno = plinno;
9373 pf = ckzalloc(sizeof(*pf));
9374 pf->prev = g_parsefile;
9376 /*pf->strpush = NULL; - ckzalloc did it */
9377 /*pf->basestrpush.prev = NULL;*/
9384 struct parsefile *pf = g_parsefile;
9392 g_parsefile = pf->prev;
9394 parsenleft = g_parsefile->nleft;
9395 parselleft = g_parsefile->lleft;
9396 parsenextc = g_parsefile->nextc;
9397 plinno = g_parsefile->linno;
9402 * Return to top level.
9407 while (g_parsefile != &basepf)
9412 * Close the file(s) that the shell is reading commands from. Called
9413 * after a fork is done.
9419 if (g_parsefile->fd > 0) {
9420 close(g_parsefile->fd);
9421 g_parsefile->fd = 0;
9426 * Like setinputfile, but takes an open file descriptor. Call this with
9430 setinputfd(int fd, int push)
9432 close_on_exec_on(fd);
9435 g_parsefile->buf = 0;
9437 g_parsefile->fd = fd;
9438 if (g_parsefile->buf == NULL)
9439 g_parsefile->buf = ckmalloc(IBUFSIZ);
9440 parselleft = parsenleft = 0;
9445 * Set the input to take input from a file. If push is set, push the
9446 * old input onto the stack first.
9449 setinputfile(const char *fname, int flags)
9455 fd = open(fname, O_RDONLY);
9457 if (flags & INPUT_NOFILE_OK)
9459 ash_msg_and_raise_error("can't open %s", fname);
9462 fd2 = copyfd(fd, 10);
9465 ash_msg_and_raise_error("out of file descriptors");
9468 setinputfd(fd, flags & INPUT_PUSH_FILE);
9475 * Like setinputfile, but takes input from a string.
9478 setinputstring(char *string)
9482 parsenextc = string;
9483 parsenleft = strlen(string);
9484 g_parsefile->buf = NULL;
9490 /* ============ mail.c
9492 * Routines to check for mail.
9497 #define MAXMBOXES 10
9499 /* times of mailboxes */
9500 static time_t mailtime[MAXMBOXES];
9501 /* Set if MAIL or MAILPATH is changed. */
9502 static smallint mail_var_path_changed;
9505 * Print appropriate message(s) if mail has arrived.
9506 * If mail_var_path_changed is set,
9507 * then the value of MAIL has mail_var_path_changed,
9508 * so we just update the values.
9517 struct stackmark smark;
9520 setstackmark(&smark);
9521 mpath = mpathset() ? mpathval() : mailval();
9522 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9523 p = padvance(&mpath, nullstr);
9528 for (q = p; *q; q++)
9534 q[-1] = '\0'; /* delete trailing '/' */
9535 if (stat(p, &statb) < 0) {
9539 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9542 pathopt ? pathopt : "you have mail"
9545 *mtp = statb.st_mtime;
9547 mail_var_path_changed = 0;
9548 popstackmark(&smark);
9552 changemail(const char *val UNUSED_PARAM)
9554 mail_var_path_changed = 1;
9557 #endif /* ASH_MAIL */
9560 /* ============ ??? */
9563 * Set the shell parameters.
9566 setparam(char **argv)
9572 for (nparam = 0; argv[nparam]; nparam++)
9574 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9576 *ap++ = ckstrdup(*argv++);
9579 freeparam(&shellparam);
9580 shellparam.malloced = 1;
9581 shellparam.nparam = nparam;
9582 shellparam.p = newparam;
9583 #if ENABLE_ASH_GETOPTS
9584 shellparam.optind = 1;
9585 shellparam.optoff = -1;
9590 * Process shell options. The global variable argptr contains a pointer
9591 * to the argument list; we advance it past the options.
9593 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9594 * For a non-interactive shell, an error condition encountered
9595 * by a special built-in ... shall cause the shell to write a diagnostic message
9596 * to standard error and exit as shown in the following table:
9597 * Error Special Built-In
9599 * Utility syntax error (option or operand error) Shall exit
9601 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9602 * we see that bash does not do that (set "finishes" with error code 1 instead,
9603 * and shell continues), and people rely on this behavior!
9605 * set -o barfoo 2>/dev/null
9608 * Oh well. Let's mimic that.
9611 plus_minus_o(char *name, int val)
9616 for (i = 0; i < NOPTS; i++) {
9617 if (strcmp(name, optnames(i)) == 0) {
9622 ash_msg("illegal option %co %s", val ? '-' : '+', name);
9625 for (i = 0; i < NOPTS; i++) {
9627 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
9629 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
9635 setoption(int flag, int val)
9639 for (i = 0; i < NOPTS; i++) {
9640 if (optletters(i) == flag) {
9645 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
9649 options(int cmdline)
9657 while ((p = *argptr) != NULL) {
9659 if (c != '-' && c != '+')
9662 val = 0; /* val = 0 if c == '+' */
9665 if (p[0] == '\0' || LONE_DASH(p)) {
9667 /* "-" means turn off -x and -v */
9670 /* "--" means reset params */
9671 else if (*argptr == NULL)
9674 break; /* "-" or "--" terminates options */
9677 /* first char was + or - */
9678 while ((c = *p++) != '\0') {
9679 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9680 if (c == 'c' && cmdline) {
9681 minusc = p; /* command is after shell args */
9682 } else if (c == 'o') {
9683 if (plus_minus_o(*argptr, val)) {
9684 /* it already printed err message */
9685 return 1; /* error */
9689 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9691 /* bash does not accept +-login, we also won't */
9692 } else if (cmdline && val && (c == '-')) { /* long options */
9693 if (strcmp(p, "login") == 0)
9705 * The shift builtin command.
9708 shiftcmd(int argc UNUSED_PARAM, char **argv)
9715 n = number(argv[1]);
9716 if (n > shellparam.nparam)
9717 n = 0; /* bash compat, was = shellparam.nparam; */
9719 shellparam.nparam -= n;
9720 for (ap1 = shellparam.p; --n >= 0; ap1++) {
9721 if (shellparam.malloced)
9725 while ((*ap2++ = *ap1++) != NULL)
9727 #if ENABLE_ASH_GETOPTS
9728 shellparam.optind = 1;
9729 shellparam.optoff = -1;
9736 * POSIX requires that 'set' (but not export or readonly) output the
9737 * variables in lexicographic order - by the locale's collating order (sigh).
9738 * Maybe we could keep them in an ordered balanced binary tree
9739 * instead of hashed lists.
9740 * For now just roll 'em through qsort for printing...
9743 showvars(const char *sep_prefix, int on, int off)
9748 ep = listvars(on, off, &epend);
9749 qsort(ep, epend - ep, sizeof(char *), vpcmp);
9751 sep = *sep_prefix ? " " : sep_prefix;
9753 for (; ep < epend; ep++) {
9757 p = strchrnul(*ep, '=');
9760 q = single_quote(++p);
9761 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9767 * The set command builtin.
9770 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9775 return showvars(nullstr, 0, VUNSET);
9778 if (!options(0)) { /* if no parse error... */
9781 if (*argptr != NULL) {
9789 #if ENABLE_ASH_RANDOM_SUPPORT
9791 change_random(const char *value)
9793 /* Galois LFSR parameter */
9794 /* Taps at 32 31 29 1: */
9795 enum { MASK = 0x8000000b };
9796 /* Another example - taps at 32 31 30 10: */
9797 /* MASK = 0x00400007 */
9799 if (value == NULL) {
9800 /* "get", generate */
9803 /* LCG has period of 2^32 and alternating lowest bit */
9804 random_LCG = 1664525 * random_LCG + 1013904223;
9805 /* Galois LFSR has period of 2^32-1 = 3 * 5 * 17 * 257 * 65537 */
9806 t = (random_galois_LFSR << 1);
9807 if (random_galois_LFSR < 0) /* if we just shifted 1 out of msb... */
9809 random_galois_LFSR = t;
9810 /* Both are weak, combining them gives better randomness
9811 * and ~2^64 period. & 0x7fff is probably bash compat
9812 * for $RANDOM range. Combining with subtraction is
9813 * just for fun. + and ^ would work equally well. */
9814 t = (t - random_LCG) & 0x7fff;
9815 /* set without recursion */
9816 setvar(vrandom.text, utoa(t), VNOFUNC);
9817 vrandom.flags &= ~VNOFUNC;
9820 random_galois_LFSR = random_LCG = strtoul(value, (char **)NULL, 10);
9825 #if ENABLE_ASH_GETOPTS
9827 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9836 if (*param_optind < 1)
9838 optnext = optfirst + *param_optind - 1;
9840 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
9843 p = optnext[-1] + *optoff;
9844 if (p == NULL || *p == '\0') {
9845 /* Current word is done, advance */
9847 if (p == NULL || *p != '-' || *++p == '\0') {
9854 if (LONE_DASH(p)) /* check for "--" */
9859 for (q = optstr; *q != c;) {
9861 if (optstr[0] == ':') {
9864 err |= setvarsafe("OPTARG", s, 0);
9866 fprintf(stderr, "Illegal option -%c\n", c);
9877 if (*p == '\0' && (p = *optnext) == NULL) {
9878 if (optstr[0] == ':') {
9881 err |= setvarsafe("OPTARG", s, 0);
9884 fprintf(stderr, "No arg for -%c option\n", c);
9893 err |= setvarsafe("OPTARG", p, 0);
9896 err |= setvarsafe("OPTARG", nullstr, 0);
9898 *optoff = p ? p - *(optnext - 1) : -1;
9899 *param_optind = optnext - optfirst + 1;
9900 fmtstr(s, sizeof(s), "%d", *param_optind);
9901 err |= setvarsafe("OPTIND", s, VNOFUNC);
9904 err |= setvarsafe(optvar, s, 0);
9908 flush_stdout_stderr();
9909 raise_exception(EXERROR);
9915 * The getopts builtin. Shellparam.optnext points to the next argument
9916 * to be processed. Shellparam.optptr points to the next character to
9917 * be processed in the current argument. If shellparam.optnext is NULL,
9918 * then it's the first time getopts has been called.
9921 getoptscmd(int argc, char **argv)
9926 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
9928 optbase = shellparam.p;
9929 if (shellparam.optind > shellparam.nparam + 1) {
9930 shellparam.optind = 1;
9931 shellparam.optoff = -1;
9935 if (shellparam.optind > argc - 2) {
9936 shellparam.optind = 1;
9937 shellparam.optoff = -1;
9941 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9942 &shellparam.optoff);
9944 #endif /* ASH_GETOPTS */
9947 /* ============ Shell parser */
9950 struct heredoc *next; /* next here document in list */
9951 union node *here; /* redirection node */
9952 char *eofmark; /* string indicating end of input */
9953 smallint striptabs; /* if set, strip leading tabs */
9956 static smallint tokpushback; /* last token pushed back */
9957 static smallint parsebackquote; /* nonzero if we are inside backquotes */
9958 static smallint quoteflag; /* set if (part of) last token was quoted */
9959 static token_id_t lasttoken; /* last token read (integer id Txxx) */
9960 static struct heredoc *heredoclist; /* list of here documents to read */
9961 static char *wordtext; /* text of last word returned by readtoken */
9962 static struct nodelist *backquotelist;
9963 static union node *redirnode;
9964 static struct heredoc *heredoc;
9966 * NEOF is returned by parsecmd when it encounters an end of file. It
9967 * must be distinct from NULL, so we use the address of a variable that
9968 * happens to be handy.
9970 #define NEOF ((union node *)&tokpushback)
9972 static void raise_error_syntax(const char *) NORETURN;
9974 raise_error_syntax(const char *msg)
9976 ash_msg_and_raise_error("syntax error: %s", msg);
9981 * Called when an unexpected token is read during the parse. The argument
9982 * is the token that is expected, or -1 if more than one type of token can
9983 * occur at this point.
9985 static void raise_error_unexpected_syntax(int) NORETURN;
9987 raise_error_unexpected_syntax(int token)
9992 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
9994 sprintf(msg + l, " (expecting %s)", tokname(token));
9995 raise_error_syntax(msg);
9999 #define EOFMARKLEN 79
10001 /* parsing is heavily cross-recursive, need these forward decls */
10002 static union node *andor(void);
10003 static union node *pipeline(void);
10004 static union node *parse_command(void);
10005 static void parseheredoc(void);
10006 static char peektoken(void);
10007 static int readtoken(void);
10009 static union node *
10012 union node *n1, *n2, *n3;
10015 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10016 if (nlflag == 2 && peektoken())
10022 if (tok == TBACKGND) {
10023 if (n2->type == NPIPE) {
10024 n2->npipe.pipe_backgnd = 1;
10026 if (n2->type != NREDIR) {
10027 n3 = stzalloc(sizeof(struct nredir));
10029 /*n3->nredir.redirect = NULL; - stzalloc did it */
10032 n2->type = NBACKGND;
10038 n3 = stzalloc(sizeof(struct nbinary));
10040 n3->nbinary.ch1 = n1;
10041 n3->nbinary.ch2 = n2;
10057 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10065 pungetc(); /* push back EOF on input */
10069 raise_error_unexpected_syntax(-1);
10076 static union node *
10079 union node *n1, *n2, *n3;
10087 } else if (t == TOR) {
10093 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10095 n3 = stzalloc(sizeof(struct nbinary));
10097 n3->nbinary.ch1 = n1;
10098 n3->nbinary.ch2 = n2;
10103 static union node *
10106 union node *n1, *n2, *pipenode;
10107 struct nodelist *lp, *prev;
10111 TRACE(("pipeline: entered\n"));
10112 if (readtoken() == TNOT) {
10114 checkkwd = CHKKWD | CHKALIAS;
10117 n1 = parse_command();
10118 if (readtoken() == TPIPE) {
10119 pipenode = stzalloc(sizeof(struct npipe));
10120 pipenode->type = NPIPE;
10121 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10122 lp = stzalloc(sizeof(struct nodelist));
10123 pipenode->npipe.cmdlist = lp;
10127 lp = stzalloc(sizeof(struct nodelist));
10128 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10129 lp->n = parse_command();
10131 } while (readtoken() == TPIPE);
10137 n2 = stzalloc(sizeof(struct nnot));
10145 static union node *
10150 n = stzalloc(sizeof(struct narg));
10152 /*n->narg.next = NULL; - stzalloc did it */
10153 n->narg.text = wordtext;
10154 n->narg.backquote = backquotelist;
10159 fixredir(union node *n, const char *text, int err)
10163 TRACE(("Fix redir %s %d\n", text, err));
10165 n->ndup.vname = NULL;
10167 fd = bb_strtou(text, NULL, 10);
10168 if (!errno && fd >= 0)
10169 n->ndup.dupfd = fd;
10170 else if (LONE_DASH(text))
10171 n->ndup.dupfd = -1;
10174 raise_error_syntax("bad fd number");
10175 n->ndup.vname = makename();
10180 * Returns true if the text contains nothing to expand (no dollar signs
10184 noexpand(char *text)
10190 while ((c = *p++) != '\0') {
10191 if (c == CTLQUOTEMARK)
10195 else if (SIT(c, BASESYNTAX) == CCTL)
10204 union node *n = redirnode;
10206 if (readtoken() != TWORD)
10207 raise_error_unexpected_syntax(-1);
10208 if (n->type == NHERE) {
10209 struct heredoc *here = heredoc;
10213 if (quoteflag == 0)
10215 TRACE(("Here document %d\n", n->type));
10216 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10217 raise_error_syntax("illegal eof marker for << redirection");
10218 rmescapes(wordtext);
10219 here->eofmark = wordtext;
10221 if (heredoclist == NULL)
10222 heredoclist = here;
10224 for (p = heredoclist; p->next; p = p->next)
10228 } else if (n->type == NTOFD || n->type == NFROMFD) {
10229 fixredir(n, wordtext, 0);
10231 n->nfile.fname = makename();
10235 static union node *
10238 union node *args, **app;
10239 union node *n = NULL;
10240 union node *vars, **vpp;
10241 union node **rpp, *redir;
10243 #if ENABLE_ASH_BASH_COMPAT
10244 smallint double_brackets_flag = 0;
10254 savecheckkwd = CHKALIAS;
10257 checkkwd = savecheckkwd;
10260 #if ENABLE_ASH_BASH_COMPAT
10261 case TAND: /* "&&" */
10262 case TOR: /* "||" */
10263 if (!double_brackets_flag) {
10267 wordtext = (char *) (t == TAND ? "-a" : "-o");
10270 n = stzalloc(sizeof(struct narg));
10272 /*n->narg.next = NULL; - stzalloc did it */
10273 n->narg.text = wordtext;
10274 #if ENABLE_ASH_BASH_COMPAT
10275 if (strcmp("[[", wordtext) == 0)
10276 double_brackets_flag = 1;
10277 else if (strcmp("]]", wordtext) == 0)
10278 double_brackets_flag = 0;
10280 n->narg.backquote = backquotelist;
10281 if (savecheckkwd && isassignment(wordtext)) {
10283 vpp = &n->narg.next;
10286 app = &n->narg.next;
10291 *rpp = n = redirnode;
10292 rpp = &n->nfile.next;
10293 parsefname(); /* read name of redirection file */
10296 if (args && app == &args->narg.next
10299 struct builtincmd *bcmd;
10302 /* We have a function */
10303 if (readtoken() != TRP)
10304 raise_error_unexpected_syntax(TRP);
10305 name = n->narg.text;
10306 if (!goodname(name)
10307 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10309 raise_error_syntax("bad function name");
10312 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10313 n->narg.next = parse_command();
10326 n = stzalloc(sizeof(struct ncmd));
10328 n->ncmd.args = args;
10329 n->ncmd.assign = vars;
10330 n->ncmd.redirect = redir;
10334 static union node *
10335 parse_command(void)
10337 union node *n1, *n2;
10338 union node *ap, **app;
10339 union node *cp, **cpp;
10340 union node *redir, **rpp;
10347 switch (readtoken()) {
10349 raise_error_unexpected_syntax(-1);
10352 n1 = stzalloc(sizeof(struct nif));
10354 n1->nif.test = list(0);
10355 if (readtoken() != TTHEN)
10356 raise_error_unexpected_syntax(TTHEN);
10357 n1->nif.ifpart = list(0);
10359 while (readtoken() == TELIF) {
10360 n2->nif.elsepart = stzalloc(sizeof(struct nif));
10361 n2 = n2->nif.elsepart;
10363 n2->nif.test = list(0);
10364 if (readtoken() != TTHEN)
10365 raise_error_unexpected_syntax(TTHEN);
10366 n2->nif.ifpart = list(0);
10368 if (lasttoken == TELSE)
10369 n2->nif.elsepart = list(0);
10371 n2->nif.elsepart = NULL;
10379 n1 = stzalloc(sizeof(struct nbinary));
10380 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10381 n1->nbinary.ch1 = list(0);
10384 TRACE(("expecting DO got %s %s\n", tokname(got),
10385 got == TWORD ? wordtext : ""));
10386 raise_error_unexpected_syntax(TDO);
10388 n1->nbinary.ch2 = list(0);
10393 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10394 raise_error_syntax("bad for loop variable");
10395 n1 = stzalloc(sizeof(struct nfor));
10397 n1->nfor.var = wordtext;
10398 checkkwd = CHKKWD | CHKALIAS;
10399 if (readtoken() == TIN) {
10401 while (readtoken() == TWORD) {
10402 n2 = stzalloc(sizeof(struct narg));
10404 /*n2->narg.next = NULL; - stzalloc did it */
10405 n2->narg.text = wordtext;
10406 n2->narg.backquote = backquotelist;
10408 app = &n2->narg.next;
10411 n1->nfor.args = ap;
10412 if (lasttoken != TNL && lasttoken != TSEMI)
10413 raise_error_unexpected_syntax(-1);
10415 n2 = stzalloc(sizeof(struct narg));
10417 /*n2->narg.next = NULL; - stzalloc did it */
10418 n2->narg.text = (char *)dolatstr;
10419 /*n2->narg.backquote = NULL;*/
10420 n1->nfor.args = n2;
10422 * Newline or semicolon here is optional (but note
10423 * that the original Bourne shell only allowed NL).
10425 if (lasttoken != TNL && lasttoken != TSEMI)
10428 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10429 if (readtoken() != TDO)
10430 raise_error_unexpected_syntax(TDO);
10431 n1->nfor.body = list(0);
10435 n1 = stzalloc(sizeof(struct ncase));
10437 if (readtoken() != TWORD)
10438 raise_error_unexpected_syntax(TWORD);
10439 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10441 /*n2->narg.next = NULL; - stzalloc did it */
10442 n2->narg.text = wordtext;
10443 n2->narg.backquote = backquotelist;
10445 checkkwd = CHKKWD | CHKALIAS;
10446 } while (readtoken() == TNL);
10447 if (lasttoken != TIN)
10448 raise_error_unexpected_syntax(TIN);
10449 cpp = &n1->ncase.cases;
10451 checkkwd = CHKNL | CHKKWD;
10453 while (t != TESAC) {
10454 if (lasttoken == TLP)
10456 *cpp = cp = stzalloc(sizeof(struct nclist));
10458 app = &cp->nclist.pattern;
10460 *app = ap = stzalloc(sizeof(struct narg));
10462 /*ap->narg.next = NULL; - stzalloc did it */
10463 ap->narg.text = wordtext;
10464 ap->narg.backquote = backquotelist;
10465 if (readtoken() != TPIPE)
10467 app = &ap->narg.next;
10470 //ap->narg.next = NULL;
10471 if (lasttoken != TRP)
10472 raise_error_unexpected_syntax(TRP);
10473 cp->nclist.body = list(2);
10475 cpp = &cp->nclist.next;
10477 checkkwd = CHKNL | CHKKWD;
10481 raise_error_unexpected_syntax(TENDCASE);
10488 n1 = stzalloc(sizeof(struct nredir));
10489 n1->type = NSUBSHELL;
10490 n1->nredir.n = list(0);
10491 /*n1->nredir.redirect = NULL; - stzalloc did it */
10501 return simplecmd();
10504 if (readtoken() != t)
10505 raise_error_unexpected_syntax(t);
10508 /* Now check for redirection which may follow command */
10509 checkkwd = CHKKWD | CHKALIAS;
10511 while (readtoken() == TREDIR) {
10512 *rpp = n2 = redirnode;
10513 rpp = &n2->nfile.next;
10519 if (n1->type != NSUBSHELL) {
10520 n2 = stzalloc(sizeof(struct nredir));
10525 n1->nredir.redirect = redir;
10530 #if ENABLE_ASH_BASH_COMPAT
10531 static int decode_dollar_squote(void)
10533 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
10539 p = strchr(C_escapes, c);
10544 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
10548 } while ((unsigned char)(c - '0') <= 7 && --cnt);
10550 } else if (c == 'x') { /* \xHH */
10554 } while (isxdigit(c) && --cnt);
10556 if (cnt == 3) { /* \x but next char is "bad" */
10560 } else { /* simple seq like \\ or \t */
10565 c = bb_process_escape_sequence((void*)&p);
10566 } else { /* unrecognized "\z": print both chars unless ' or " */
10567 if (c != '\'' && c != '"') {
10569 c |= 0x100; /* "please encode \, then me" */
10577 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10578 * is not NULL, read a here document. In the latter case, eofmark is the
10579 * word which marks the end of the document and striptabs is true if
10580 * leading tabs should be stripped from the document. The argument firstc
10581 * is the first character of the input token or document.
10583 * Because C does not have internal subroutines, I have simulated them
10584 * using goto's to implement the subroutine linkage. The following macros
10585 * will run code that appears at the end of readtoken1.
10587 #define CHECKEND() {goto checkend; checkend_return:;}
10588 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10589 #define PARSESUB() {goto parsesub; parsesub_return:;}
10590 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10591 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10592 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10594 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10596 /* NB: syntax parameter fits into smallint */
10600 char line[EOFMARKLEN + 1];
10601 struct nodelist *bqlist;
10605 smallint prevsyntax; /* syntax before arithmetic */
10606 #if ENABLE_ASH_EXPAND_PRMT
10607 smallint pssyntax; /* we are expanding a prompt string */
10609 int varnest; /* levels of variables expansion */
10610 int arinest; /* levels of arithmetic expansion */
10611 int parenlevel; /* levels of parens in arithmetic */
10612 int dqvarnest; /* levels of variables expansion within double quotes */
10614 USE_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
10617 /* Avoid longjmp clobbering */
10623 (void) &parenlevel;
10626 (void) &prevsyntax;
10629 startlinno = plinno;
10634 #if ENABLE_ASH_EXPAND_PRMT
10635 pssyntax = (syntax == PSSYNTAX);
10639 dblquote = (syntax == DQSYNTAX);
10645 STARTSTACKSTR(out);
10647 /* For each line, until end of word */
10649 CHECKEND(); /* set c to PEOF if at end of here document */
10650 for (;;) { /* until end of line or end of word */
10651 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10652 switch (SIT(c, syntax)) {
10653 case CNL: /* '\n' */
10654 if (syntax == BASESYNTAX)
10655 goto endword; /* exit outer loop */
10661 goto loop; /* continue outer loop */
10666 if (eofmark == NULL || dblquote)
10667 USTPUTC(CTLESC, out);
10668 #if ENABLE_ASH_BASH_COMPAT
10669 if (c == '\\' && bash_dollar_squote) {
10670 c = decode_dollar_squote();
10672 USTPUTC('\\', out);
10673 c = (unsigned char)c;
10679 case CBACK: /* backslash */
10682 USTPUTC(CTLESC, out);
10683 USTPUTC('\\', out);
10685 } else if (c == '\n') {
10689 #if ENABLE_ASH_EXPAND_PRMT
10690 if (c == '$' && pssyntax) {
10691 USTPUTC(CTLESC, out);
10692 USTPUTC('\\', out);
10695 if (dblquote && c != '\\'
10696 && c != '`' && c != '$'
10697 && (c != '"' || eofmark != NULL)
10699 USTPUTC(CTLESC, out);
10700 USTPUTC('\\', out);
10702 if (SIT(c, SQSYNTAX) == CCTL)
10703 USTPUTC(CTLESC, out);
10711 if (eofmark == NULL) {
10712 USTPUTC(CTLQUOTEMARK, out);
10720 USE_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
10721 if (eofmark != NULL && arinest == 0
10726 if (dqvarnest == 0) {
10727 syntax = BASESYNTAX;
10734 case CVAR: /* '$' */
10735 PARSESUB(); /* parse substitution */
10737 case CENDVAR: /* '}' */
10740 if (dqvarnest > 0) {
10743 USTPUTC(CTLENDVAR, out);
10748 #if ENABLE_ASH_MATH_SUPPORT
10749 case CLP: /* '(' in arithmetic */
10753 case CRP: /* ')' in arithmetic */
10754 if (parenlevel > 0) {
10758 if (pgetc() == ')') {
10759 if (--arinest == 0) {
10760 USTPUTC(CTLENDARI, out);
10761 syntax = prevsyntax;
10762 dblquote = (syntax == DQSYNTAX);
10767 * unbalanced parens
10768 * (don't 2nd guess - no error)
10776 case CBQUOTE: /* '`' */
10780 goto endword; /* exit outer loop */
10784 if (varnest == 0) {
10785 #if ENABLE_ASH_BASH_COMPAT
10787 if (pgetc() == '>')
10788 c = 0x100 + '>'; /* flag &> */
10792 goto endword; /* exit outer loop */
10794 #if ENABLE_ASH_ALIAS
10804 #if ENABLE_ASH_MATH_SUPPORT
10805 if (syntax == ARISYNTAX)
10806 raise_error_syntax("missing '))'");
10808 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10809 raise_error_syntax("unterminated quoted string");
10810 if (varnest != 0) {
10811 startlinno = plinno;
10813 raise_error_syntax("missing '}'");
10815 USTPUTC('\0', out);
10816 len = out - (char *)stackblock();
10817 out = stackblock();
10818 if (eofmark == NULL) {
10819 if ((c == '>' || c == '<' USE_ASH_BASH_COMPAT( || c == 0x100 + '>'))
10822 if (isdigit_str9(out)) {
10823 PARSEREDIR(); /* passed as params: out, c */
10824 lasttoken = TREDIR;
10827 /* else: non-number X seen, interpret it
10828 * as "NNNX>file" = "NNNX >file" */
10832 quoteflag = quotef;
10833 backquotelist = bqlist;
10834 grabstackblock(len);
10838 /* end of readtoken routine */
10841 * Check to see whether we are at the end of the here document. When this
10842 * is called, c is set to the first character of the next input line. If
10843 * we are at the end of the here document, this routine sets the c to PEOF.
10847 #if ENABLE_ASH_ALIAS
10853 while (c == '\t') {
10857 if (c == *eofmark) {
10858 if (pfgets(line, sizeof(line)) != NULL) {
10862 for (q = eofmark + 1; *q && *p == *q; p++, q++)
10864 if (*p == '\n' && *q == '\0') {
10867 needprompt = doprompt;
10869 pushstring(line, NULL);
10874 goto checkend_return;
10878 * Parse a redirection operator. The variable "out" points to a string
10879 * specifying the fd to be redirected. The variable "c" contains the
10880 * first character of the redirection operator.
10883 /* out is already checked to be a valid number or "" */
10884 int fd = (*out == '\0' ? -1 : atoi(out));
10887 np = stzalloc(sizeof(struct nfile));
10892 np->type = NAPPEND;
10894 np->type = NCLOBBER;
10897 /* it also can be NTO2 (>&file), but we can't figure it out yet */
10903 #if ENABLE_ASH_BASH_COMPAT
10904 else if (c == 0x100 + '>') { /* this flags &> redirection */
10906 pgetc(); /* this is '>', no need to check */
10910 else { /* c == '<' */
10911 /*np->nfile.fd = 0; - stzalloc did it */
10915 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10916 np = stzalloc(sizeof(struct nhere));
10917 /*np->nfile.fd = 0; - stzalloc did it */
10920 heredoc = stzalloc(sizeof(struct heredoc));
10921 heredoc->here = np;
10924 heredoc->striptabs = 1;
10926 /*heredoc->striptabs = 0; - stzalloc did it */
10932 np->type = NFROMFD;
10936 np->type = NFROMTO;
10948 goto parseredir_return;
10952 * Parse a substitution. At this point, we have read the dollar sign
10953 * and nothing else.
10956 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
10957 * (assuming ascii char codes, as the original implementation did) */
10958 #define is_special(c) \
10959 (((unsigned)(c) - 33 < 32) \
10960 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
10966 static const char types[] ALIGN1 = "}-+?=";
10969 if (c <= PEOA_OR_PEOF
10970 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10972 #if ENABLE_ASH_BASH_COMPAT
10974 bash_dollar_squote = 1;
10979 } else if (c == '(') { /* $(command) or $((arith)) */
10980 if (pgetc() == '(') {
10981 #if ENABLE_ASH_MATH_SUPPORT
10984 raise_error_syntax("you disabled math support for $((arith)) syntax");
10991 USTPUTC(CTLVAR, out);
10992 typeloc = out - (char *)stackblock();
10993 USTPUTC(VSNORMAL, out);
10994 subtype = VSNORMAL;
11002 subtype = VSLENGTH;
11006 if (c > PEOA_OR_PEOF && is_name(c)) {
11010 } while (c > PEOA_OR_PEOF && is_in_name(c));
11011 } else if (isdigit(c)) {
11015 } while (isdigit(c));
11016 } else if (is_special(c)) {
11021 raise_error_syntax("bad substitution");
11026 if (subtype == 0) {
11030 #if ENABLE_ASH_BASH_COMPAT
11031 if (c == ':' || c == '$' || isdigit(c)) {
11033 subtype = VSSUBSTR;
11040 p = strchr(types, c);
11043 subtype = p - types + VSNORMAL;
11048 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
11056 #if ENABLE_ASH_BASH_COMPAT
11058 subtype = VSREPLACE;
11061 subtype++; /* VSREPLACEALL */
11070 if (dblquote || arinest)
11072 *((char *)stackblock() + typeloc) = subtype | flags;
11073 if (subtype != VSNORMAL) {
11075 if (dblquote || arinest) {
11080 goto parsesub_return;
11084 * Called to parse command substitutions. Newstyle is set if the command
11085 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11086 * list of commands (passed by reference), and savelen is the number of
11087 * characters on the top of the stack which must be preserved.
11090 struct nodelist **nlpp;
11093 char *volatile str;
11094 struct jmploc jmploc;
11095 struct jmploc *volatile savehandler;
11097 smallint saveprompt = 0;
11100 (void) &saveprompt;
11102 savepbq = parsebackquote;
11103 if (setjmp(jmploc.loc)) {
11105 parsebackquote = 0;
11106 exception_handler = savehandler;
11107 longjmp(exception_handler->loc, 1);
11111 savelen = out - (char *)stackblock();
11113 str = ckmalloc(savelen);
11114 memcpy(str, stackblock(), savelen);
11116 savehandler = exception_handler;
11117 exception_handler = &jmploc;
11120 /* We must read until the closing backquote, giving special
11121 treatment to some slashes, and then push the string and
11122 reread it as input, interpreting it normally. */
11129 STARTSTACKSTR(pout);
11146 * If eating a newline, avoid putting
11147 * the newline into the new character
11148 * stream (via the STPUTC after the
11153 if (pc != '\\' && pc != '`' && pc != '$'
11154 && (!dblquote || pc != '"'))
11155 STPUTC('\\', pout);
11156 if (pc > PEOA_OR_PEOF) {
11162 #if ENABLE_ASH_ALIAS
11165 startlinno = plinno;
11166 raise_error_syntax("EOF in backquote substitution");
11170 needprompt = doprompt;
11179 STPUTC('\0', pout);
11180 psavelen = pout - (char *)stackblock();
11181 if (psavelen > 0) {
11182 pstr = grabstackstr(pout);
11183 setinputstring(pstr);
11188 nlpp = &(*nlpp)->next;
11189 *nlpp = stzalloc(sizeof(**nlpp));
11190 /* (*nlpp)->next = NULL; - stzalloc did it */
11191 parsebackquote = oldstyle;
11194 saveprompt = doprompt;
11201 doprompt = saveprompt;
11202 else if (readtoken() != TRP)
11203 raise_error_unexpected_syntax(TRP);
11208 * Start reading from old file again, ignoring any pushed back
11209 * tokens left from the backquote parsing
11214 while (stackblocksize() <= savelen)
11216 STARTSTACKSTR(out);
11218 memcpy(out, str, savelen);
11219 STADJUST(savelen, out);
11225 parsebackquote = savepbq;
11226 exception_handler = savehandler;
11227 if (arinest || dblquote)
11228 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11230 USTPUTC(CTLBACKQ, out);
11232 goto parsebackq_oldreturn;
11233 goto parsebackq_newreturn;
11236 #if ENABLE_ASH_MATH_SUPPORT
11238 * Parse an arithmetic expansion (indicate start of one and set state)
11241 if (++arinest == 1) {
11242 prevsyntax = syntax;
11243 syntax = ARISYNTAX;
11244 USTPUTC(CTLARI, out);
11251 * we collapse embedded arithmetic expansion to
11252 * parenthesis, which should be equivalent
11256 goto parsearith_return;
11260 } /* end of readtoken */
11263 * Read the next input token.
11264 * If the token is a word, we set backquotelist to the list of cmds in
11265 * backquotes. We set quoteflag to true if any part of the word was
11267 * If the token is TREDIR, then we set redirnode to a structure containing
11269 * In all cases, the variable startlinno is set to the number of the line
11270 * on which the token starts.
11272 * [Change comment: here documents and internal procedures]
11273 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11274 * word parsing code into a separate routine. In this case, readtoken
11275 * doesn't need to have any internal procedures, but parseword does.
11276 * We could also make parseoperator in essence the main routine, and
11277 * have parseword (readtoken1?) handle both words and redirection.]
11279 #define NEW_xxreadtoken
11280 #ifdef NEW_xxreadtoken
11281 /* singles must be first! */
11282 static const char xxreadtoken_chars[7] ALIGN1 = {
11283 '\n', '(', ')', /* singles */
11284 '&', '|', ';', /* doubles */
11288 #define xxreadtoken_singles 3
11289 #define xxreadtoken_doubles 3
11291 static const char xxreadtoken_tokens[] ALIGN1 = {
11292 TNL, TLP, TRP, /* only single occurrence allowed */
11293 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11294 TEOF, /* corresponds to trailing nul */
11295 TAND, TOR, TENDCASE /* if double occurrence */
11310 startlinno = plinno;
11311 for (;;) { /* until token or start of word found */
11313 if (c == ' ' || c == '\t' USE_ASH_ALIAS( || c == PEOA))
11317 while ((c = pgetc()) != '\n' && c != PEOF)
11320 } else if (c == '\\') {
11321 if (pgetc() != '\n') {
11323 break; /* return readtoken1(...) */
11325 startlinno = ++plinno;
11331 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11335 needprompt = doprompt;
11338 p = strchr(xxreadtoken_chars, c);
11340 break; /* return readtoken1(...) */
11342 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11344 if (cc == c) { /* double occurrence? */
11345 p += xxreadtoken_doubles + 1;
11348 #if ENABLE_ASH_BASH_COMPAT
11349 if (c == '&' && cc == '>') /* &> */
11350 break; /* return readtoken1(...) */
11355 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11360 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11362 #else /* old xxreadtoken */
11363 #define RETURN(token) return lasttoken = token
11376 startlinno = plinno;
11377 for (;;) { /* until token or start of word found */
11380 case ' ': case '\t':
11381 #if ENABLE_ASH_ALIAS
11386 while ((c = pgetc()) != '\n' && c != PEOF)
11391 if (pgetc() == '\n') {
11392 startlinno = ++plinno;
11401 needprompt = doprompt;
11406 if (pgetc() == '&')
11411 if (pgetc() == '|')
11416 if (pgetc() == ';')
11429 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11432 #endif /* old xxreadtoken */
11439 smallint alreadyseen = tokpushback;
11442 #if ENABLE_ASH_ALIAS
11451 if (checkkwd & CHKNL) {
11458 if (t != TWORD || quoteflag) {
11463 * check for keywords
11465 if (checkkwd & CHKKWD) {
11466 const char *const *pp;
11468 pp = findkwd(wordtext);
11470 lasttoken = t = pp - tokname_array;
11471 TRACE(("keyword %s recognized\n", tokname(t)));
11476 if (checkkwd & CHKALIAS) {
11477 #if ENABLE_ASH_ALIAS
11479 ap = lookupalias(wordtext, 1);
11482 pushstring(ap->val, ap);
11492 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11494 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11506 return tokname_array[t][0];
11510 * Read and parse a command. Returns NEOF on end of file. (NULL is a
11511 * valid parse tree indicating a blank line.)
11513 static union node *
11514 parsecmd(int interact)
11519 doprompt = interact;
11521 setprompt(doprompt);
11533 * Input any here documents.
11538 struct heredoc *here;
11541 here = heredoclist;
11542 heredoclist = NULL;
11548 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
11549 here->eofmark, here->striptabs);
11550 n = stzalloc(sizeof(struct narg));
11551 n->narg.type = NARG;
11552 /*n->narg.next = NULL; - stzalloc did it */
11553 n->narg.text = wordtext;
11554 n->narg.backquote = backquotelist;
11555 here->here->nhere.doc = n;
11562 * called by editline -- any expansions to the prompt should be added here.
11564 #if ENABLE_ASH_EXPAND_PRMT
11565 static const char *
11566 expandstr(const char *ps)
11570 /* XXX Fix (char *) cast. */
11571 setinputstring((char *)ps);
11572 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
11575 n.narg.type = NARG;
11576 n.narg.next = NULL;
11577 n.narg.text = wordtext;
11578 n.narg.backquote = backquotelist;
11580 expandarg(&n, NULL, 0);
11581 return stackblock();
11586 * Execute a command or commands contained in a string.
11589 evalstring(char *s, int mask)
11592 struct stackmark smark;
11596 setstackmark(&smark);
11599 while ((n = parsecmd(0)) != NEOF) {
11601 popstackmark(&smark);
11614 * The eval command.
11617 evalcmd(int argc UNUSED_PARAM, char **argv)
11626 STARTSTACKSTR(concat);
11628 concat = stack_putstr(p, concat);
11632 STPUTC(' ', concat);
11634 STPUTC('\0', concat);
11635 p = grabstackstr(concat);
11637 evalstring(p, ~SKIPEVAL);
11644 * Read and execute commands. "Top" is nonzero for the top level command
11645 * loop; it turns on prompting if the shell is interactive.
11651 struct stackmark smark;
11655 TRACE(("cmdloop(%d) called\n", top));
11659 setstackmark(&smark);
11662 showjobs(stderr, SHOW_CHANGED);
11665 if (iflag && top) {
11667 #if ENABLE_ASH_MAIL
11671 n = parsecmd(inter);
11672 /* showtree(n); DEBUG */
11674 if (!top || numeof >= 50)
11676 if (!stoppedjobs()) {
11679 out2str("\nUse \"exit\" to leave shell.\n");
11682 } else if (nflag == 0) {
11683 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11688 popstackmark(&smark);
11693 return skip & SKIPEVAL;
11700 * Take commands from a file. To be compatible we should do a path
11701 * search for the file, which is necessary to find sub-commands.
11704 find_dot_file(char *name)
11707 const char *path = pathval();
11710 /* don't try this for absolute or relative paths */
11711 if (strchr(name, '/'))
11714 while ((fullname = padvance(&path, name)) != NULL) {
11715 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11717 * Don't bother freeing here, since it will
11718 * be freed by the caller.
11722 stunalloc(fullname);
11725 /* not found in the PATH */
11726 ash_msg_and_raise_error("%s: not found", name);
11731 dotcmd(int argc, char **argv)
11733 struct strlist *sp;
11734 volatile struct shparam saveparam;
11737 for (sp = cmdenviron; sp; sp = sp->next)
11738 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11740 if (argv[1]) { /* That's what SVR2 does */
11741 char *fullname = find_dot_file(argv[1]);
11744 if (argc) { /* argc > 0, argv[0] != NULL */
11745 saveparam = shellparam;
11746 shellparam.malloced = 0;
11747 shellparam.nparam = argc;
11748 shellparam.p = argv;
11751 setinputfile(fullname, INPUT_PUSH_FILE);
11752 commandname = fullname;
11757 freeparam(&shellparam);
11758 shellparam = saveparam;
11760 status = exitstatus;
11766 exitcmd(int argc UNUSED_PARAM, char **argv)
11771 exitstatus = number(argv[1]);
11772 raise_exception(EXEXIT);
11777 * Read a file containing shell functions.
11780 readcmdfile(char *name)
11782 setinputfile(name, INPUT_PUSH_FILE);
11788 /* ============ find_command inplementation */
11791 * Resolve a command name. If you change this routine, you may have to
11792 * change the shellexec routine as well.
11795 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11797 struct tblentry *cmdp;
11804 struct builtincmd *bcmd;
11806 /* If name contains a slash, don't use PATH or hash table */
11807 if (strchr(name, '/') != NULL) {
11808 entry->u.index = -1;
11809 if (act & DO_ABS) {
11810 while (stat(name, &statb) < 0) {
11812 if (errno == EINTR)
11815 entry->cmdtype = CMDUNKNOWN;
11819 entry->cmdtype = CMDNORMAL;
11823 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11825 updatetbl = (path == pathval());
11828 if (strstr(path, "%builtin") != NULL)
11829 act |= DO_ALTBLTIN;
11832 /* If name is in the table, check answer will be ok */
11833 cmdp = cmdlookup(name, 0);
11834 if (cmdp != NULL) {
11837 switch (cmdp->cmdtype) {
11855 } else if (cmdp->rehash == 0)
11856 /* if not invalidated by cd, we're done */
11860 /* If %builtin not in path, check for builtin next */
11861 bcmd = find_builtin(name);
11863 if (IS_BUILTIN_REGULAR(bcmd))
11864 goto builtin_success;
11865 if (act & DO_ALTPATH) {
11866 if (!(act & DO_ALTBLTIN))
11867 goto builtin_success;
11868 } else if (builtinloc <= 0) {
11869 goto builtin_success;
11873 #if ENABLE_FEATURE_SH_STANDALONE
11875 int applet_no = find_applet_by_name(name);
11876 if (applet_no >= 0) {
11877 entry->cmdtype = CMDNORMAL;
11878 entry->u.index = -2 - applet_no;
11884 /* We have to search path. */
11885 prev = -1; /* where to start */
11886 if (cmdp && cmdp->rehash) { /* doing a rehash */
11887 if (cmdp->cmdtype == CMDBUILTIN)
11890 prev = cmdp->param.index;
11896 while ((fullname = padvance(&path, name)) != NULL) {
11897 stunalloc(fullname);
11898 /* NB: code below will still use fullname
11899 * despite it being "unallocated" */
11902 if (prefix(pathopt, "builtin")) {
11904 goto builtin_success;
11907 if ((act & DO_NOFUNC)
11908 || !prefix(pathopt, "func")
11909 ) { /* ignore unimplemented options */
11913 /* if rehash, don't redo absolute path names */
11914 if (fullname[0] == '/' && idx <= prev) {
11917 TRACE(("searchexec \"%s\": no change\n", name));
11920 while (stat(fullname, &statb) < 0) {
11922 if (errno == EINTR)
11925 if (errno != ENOENT && errno != ENOTDIR)
11929 e = EACCES; /* if we fail, this will be the error */
11930 if (!S_ISREG(statb.st_mode))
11932 if (pathopt) { /* this is a %func directory */
11933 stalloc(strlen(fullname) + 1);
11934 /* NB: stalloc will return space pointed by fullname
11935 * (because we don't have any intervening allocations
11936 * between stunalloc above and this stalloc) */
11937 readcmdfile(fullname);
11938 cmdp = cmdlookup(name, 0);
11939 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
11940 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
11941 stunalloc(fullname);
11944 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
11946 entry->cmdtype = CMDNORMAL;
11947 entry->u.index = idx;
11951 cmdp = cmdlookup(name, 1);
11952 cmdp->cmdtype = CMDNORMAL;
11953 cmdp->param.index = idx;
11958 /* We failed. If there was an entry for this command, delete it */
11959 if (cmdp && updatetbl)
11960 delete_cmd_entry();
11962 ash_msg("%s: %s", name, errmsg(e, "not found"));
11963 entry->cmdtype = CMDUNKNOWN;
11968 entry->cmdtype = CMDBUILTIN;
11969 entry->u.cmd = bcmd;
11973 cmdp = cmdlookup(name, 1);
11974 cmdp->cmdtype = CMDBUILTIN;
11975 cmdp->param.cmd = bcmd;
11979 entry->cmdtype = cmdp->cmdtype;
11980 entry->u = cmdp->param;
11984 /* ============ trap.c */
11987 * The trap builtin.
11990 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
11999 for (signo = 0; signo < NSIG; signo++) {
12000 if (trap[signo] != NULL) {
12001 out1fmt("trap -- %s %s\n",
12002 single_quote(trap[signo]),
12003 get_signame(signo));
12012 signo = get_signum(*ap);
12014 ash_msg_and_raise_error("%s: bad trap", *ap);
12017 if (LONE_DASH(action))
12020 action = ckstrdup(action);
12023 trap[signo] = action;
12033 /* ============ Builtins */
12035 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
12037 * Lists available builtins
12040 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12045 out1fmt("\nBuilt-in commands:\n-------------------\n");
12046 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12047 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12048 builtintab[i].name + 1);
12054 #if ENABLE_FEATURE_SH_STANDALONE
12056 const char *a = applet_names;
12058 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12063 a += strlen(a) + 1;
12068 return EXIT_SUCCESS;
12070 #endif /* FEATURE_SH_EXTRA_QUIET */
12073 * The export and readonly commands.
12076 exportcmd(int argc UNUSED_PARAM, char **argv)
12082 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;
12084 if (nextopt("p") != 'p') {
12089 p = strchr(name, '=');
12093 vp = *findvar(hashvar(name), name);
12099 setvar(name, p, flag);
12100 } while ((name = *++aptr) != NULL);
12104 showvars(argv[0], flag, 0);
12109 * Delete a function if it exists.
12112 unsetfunc(const char *name)
12114 struct tblentry *cmdp;
12116 cmdp = cmdlookup(name, 0);
12117 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
12118 delete_cmd_entry();
12122 * The unset builtin command. We unset the function before we unset the
12123 * variable to allow a function to be unset when there is a readonly variable
12124 * with the same name.
12127 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12134 while ((i = nextopt("vf")) != '\0') {
12138 for (ap = argptr; *ap; ap++) {
12154 #include <sys/times.h>
12156 static const unsigned char timescmd_str[] ALIGN1 = {
12157 ' ', offsetof(struct tms, tms_utime),
12158 '\n', offsetof(struct tms, tms_stime),
12159 ' ', offsetof(struct tms, tms_cutime),
12160 '\n', offsetof(struct tms, tms_cstime),
12165 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12167 long clk_tck, s, t;
12168 const unsigned char *p;
12171 clk_tck = sysconf(_SC_CLK_TCK);
12176 t = *(clock_t *)(((char *) &buf) + p[1]);
12178 out1fmt("%ldm%ld.%.3lds%c",
12180 ((t - s * clk_tck) * 1000) / clk_tck,
12182 } while (*(p += 2));
12187 #if ENABLE_ASH_MATH_SUPPORT
12189 dash_arith(const char *s)
12195 result = arith(s, &errcode);
12198 ash_msg_and_raise_error("exponent less than 0");
12200 ash_msg_and_raise_error("divide by zero");
12202 ash_msg_and_raise_error("expression recursion loop detected");
12203 raise_error_syntax(s);
12211 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12212 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12214 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12217 letcmd(int argc UNUSED_PARAM, char **argv)
12223 ash_msg_and_raise_error("expression expected");
12225 i = dash_arith(*argv);
12230 #endif /* ASH_MATH_SUPPORT */
12233 /* ============ miscbltin.c
12235 * Miscellaneous builtins.
12240 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12241 typedef enum __rlimit_resource rlim_t;
12245 * The read builtin. Options:
12246 * -r Do not interpret '\' specially
12247 * -s Turn off echo (tty only)
12248 * -n NCHARS Read NCHARS max
12249 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12250 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12251 * -u FD Read from given FD instead of fd 0
12252 * This uses unbuffered input, which may be avoidable in some cases.
12253 * TODO: bash also has:
12254 * -a ARRAY Read into array[0],[1],etc
12255 * -d DELIM End on DELIM char, not newline
12256 * -e Use line editing (tty only)
12259 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12261 static const char *const arg_REPLY[] = { "REPLY", NULL };
12274 #if ENABLE_ASH_READ_NCHARS
12275 int nchars = 0; /* if != 0, -n is in effect */
12277 struct termios tty, old_tty;
12279 #if ENABLE_ASH_READ_TIMEOUT
12280 unsigned end_ms = 0;
12281 unsigned timeout = 0;
12286 while ((i = nextopt("p:u:r"
12287 USE_ASH_READ_TIMEOUT("t:")
12288 USE_ASH_READ_NCHARS("n:s")
12292 prompt = optionarg;
12294 #if ENABLE_ASH_READ_NCHARS
12296 nchars = bb_strtou(optionarg, NULL, 10);
12297 if (nchars < 0 || errno)
12298 ash_msg_and_raise_error("invalid count");
12299 /* nchars == 0: off (bash 3.2 does this too) */
12305 #if ENABLE_ASH_READ_TIMEOUT
12307 timeout = bb_strtou(optionarg, NULL, 10);
12308 if (errno || timeout > UINT_MAX / 2048)
12309 ash_msg_and_raise_error("invalid timeout");
12311 #if 0 /* even bash have no -t N.NNN support */
12312 ts.tv_sec = bb_strtou(optionarg, &p, 10);
12314 /* EINVAL means number is ok, but not terminated by NUL */
12315 if (*p == '.' && errno == EINVAL) {
12319 ts.tv_usec = bb_strtou(p, &p2, 10);
12321 ash_msg_and_raise_error("invalid timeout");
12323 /* normalize to usec */
12325 ash_msg_and_raise_error("invalid timeout");
12326 while (scale++ < 6)
12329 } else if (ts.tv_sec < 0 || errno) {
12330 ash_msg_and_raise_error("invalid timeout");
12332 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
12333 ash_msg_and_raise_error("invalid timeout");
12342 fd = bb_strtou(optionarg, NULL, 10);
12343 if (fd < 0 || errno)
12344 ash_msg_and_raise_error("invalid file descriptor");
12350 if (prompt && isatty(fd)) {
12355 ap = (char**)arg_REPLY;
12356 ifs = bltinlookup("IFS");
12359 #if ENABLE_ASH_READ_NCHARS
12360 tcgetattr(fd, &tty);
12362 if (nchars || silent) {
12364 tty.c_lflag &= ~ICANON;
12365 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
12368 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
12370 /* if tcgetattr failed, tcsetattr will fail too.
12371 * Ignoring, it's harmless. */
12372 tcsetattr(fd, TCSANOW, &tty);
12379 #if ENABLE_ASH_READ_TIMEOUT
12380 if (timeout) /* NB: ensuring end_ms is nonzero */
12381 end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1;
12385 #if ENABLE_ASH_READ_TIMEOUT
12387 struct pollfd pfd[1];
12389 pfd[0].events = POLLIN;
12390 timeout = end_ms - (unsigned)(monotonic_us() / 1000);
12391 if ((int)timeout <= 0 /* already late? */
12392 || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
12393 ) { /* timed out! */
12394 #if ENABLE_ASH_READ_NCHARS
12395 tcsetattr(fd, TCSANOW, &old_tty);
12401 if (nonblock_safe_read(fd, &c, 1) != 1) {
12413 if (!rflag && c == '\\') {
12419 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12423 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12425 setvar(*ap, stackblock(), 0);
12434 /* end of do {} while: */
12435 #if ENABLE_ASH_READ_NCHARS
12441 #if ENABLE_ASH_READ_NCHARS
12442 tcsetattr(fd, TCSANOW, &old_tty);
12446 /* Remove trailing blanks */
12447 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12449 setvar(*ap, stackblock(), 0);
12450 while (*++ap != NULL)
12451 setvar(*ap, nullstr, 0);
12456 umaskcmd(int argc UNUSED_PARAM, char **argv)
12458 static const char permuser[3] ALIGN1 = "ugo";
12459 static const char permmode[3] ALIGN1 = "rwx";
12460 static const short permmask[] ALIGN2 = {
12461 S_IRUSR, S_IWUSR, S_IXUSR,
12462 S_IRGRP, S_IWGRP, S_IXGRP,
12463 S_IROTH, S_IWOTH, S_IXOTH
12469 int symbolic_mode = 0;
12471 while (nextopt("S") != '\0') {
12482 if (symbolic_mode) {
12486 for (i = 0; i < 3; i++) {
12489 *p++ = permuser[i];
12491 for (j = 0; j < 3; j++) {
12492 if ((mask & permmask[3 * i + j]) == 0) {
12493 *p++ = permmode[j];
12501 out1fmt("%.4o\n", mask);
12504 if (isdigit((unsigned char) *ap)) {
12507 if (*ap >= '8' || *ap < '0')
12508 ash_msg_and_raise_error(illnum, argv[1]);
12509 mask = (mask << 3) + (*ap - '0');
12510 } while (*++ap != '\0');
12513 mask = ~mask & 0777;
12514 if (!bb_parse_mode(ap, &mask)) {
12515 ash_msg_and_raise_error("illegal mode: %s", ap);
12517 umask(~mask & 0777);
12526 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12527 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12528 * ash by J.T. Conklin.
12534 uint8_t cmd; /* RLIMIT_xxx fit into it */
12535 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
12539 static const struct limits limits_tbl[] = {
12541 { RLIMIT_CPU, 0, 't' },
12543 #ifdef RLIMIT_FSIZE
12544 { RLIMIT_FSIZE, 9, 'f' },
12547 { RLIMIT_DATA, 10, 'd' },
12549 #ifdef RLIMIT_STACK
12550 { RLIMIT_STACK, 10, 's' },
12553 { RLIMIT_CORE, 9, 'c' },
12556 { RLIMIT_RSS, 10, 'm' },
12558 #ifdef RLIMIT_MEMLOCK
12559 { RLIMIT_MEMLOCK, 10, 'l' },
12561 #ifdef RLIMIT_NPROC
12562 { RLIMIT_NPROC, 0, 'p' },
12564 #ifdef RLIMIT_NOFILE
12565 { RLIMIT_NOFILE, 0, 'n' },
12568 { RLIMIT_AS, 10, 'v' },
12570 #ifdef RLIMIT_LOCKS
12571 { RLIMIT_LOCKS, 0, 'w' },
12574 static const char limits_name[] =
12576 "time(seconds)" "\0"
12578 #ifdef RLIMIT_FSIZE
12579 "file(blocks)" "\0"
12584 #ifdef RLIMIT_STACK
12588 "coredump(blocks)" "\0"
12593 #ifdef RLIMIT_MEMLOCK
12594 "locked memory(kb)" "\0"
12596 #ifdef RLIMIT_NPROC
12599 #ifdef RLIMIT_NOFILE
12605 #ifdef RLIMIT_LOCKS
12610 enum limtype { SOFT = 0x1, HARD = 0x2 };
12613 printlim(enum limtype how, const struct rlimit *limit,
12614 const struct limits *l)
12618 val = limit->rlim_max;
12620 val = limit->rlim_cur;
12622 if (val == RLIM_INFINITY)
12623 out1fmt("unlimited\n");
12625 val >>= l->factor_shift;
12626 out1fmt("%lld\n", (long long) val);
12631 ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12635 enum limtype how = SOFT | HARD;
12636 const struct limits *l;
12639 struct rlimit limit;
12642 while ((optc = nextopt("HSa"
12646 #ifdef RLIMIT_FSIZE
12652 #ifdef RLIMIT_STACK
12661 #ifdef RLIMIT_MEMLOCK
12664 #ifdef RLIMIT_NPROC
12667 #ifdef RLIMIT_NOFILE
12673 #ifdef RLIMIT_LOCKS
12691 for (l = limits_tbl; l->option != what; l++)
12694 set = *argptr ? 1 : 0;
12698 if (all || argptr[1])
12699 ash_msg_and_raise_error("too many arguments");
12700 if (strncmp(p, "unlimited\n", 9) == 0)
12701 val = RLIM_INFINITY;
12705 while ((c = *p++) >= '0' && c <= '9') {
12706 val = (val * 10) + (long)(c - '0');
12707 // val is actually 'unsigned long int' and can't get < 0
12708 if (val < (rlim_t) 0)
12712 ash_msg_and_raise_error("bad number");
12713 val <<= l->factor_shift;
12717 const char *lname = limits_name;
12718 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12719 getrlimit(l->cmd, &limit);
12720 out1fmt("%-20s ", lname);
12721 lname += strlen(lname) + 1;
12722 printlim(how, &limit, l);
12727 getrlimit(l->cmd, &limit);
12730 limit.rlim_max = val;
12732 limit.rlim_cur = val;
12733 if (setrlimit(l->cmd, &limit) < 0)
12734 ash_msg_and_raise_error("error setting limit (%m)");
12736 printlim(how, &limit, l);
12742 /* ============ Math support */
12744 #if ENABLE_ASH_MATH_SUPPORT
12746 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12748 Permission is hereby granted, free of charge, to any person obtaining
12749 a copy of this software and associated documentation files (the
12750 "Software"), to deal in the Software without restriction, including
12751 without limitation the rights to use, copy, modify, merge, publish,
12752 distribute, sublicense, and/or sell copies of the Software, and to
12753 permit persons to whom the Software is furnished to do so, subject to
12754 the following conditions:
12756 The above copyright notice and this permission notice shall be
12757 included in all copies or substantial portions of the Software.
12759 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12760 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12761 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12762 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12763 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12764 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12765 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12768 /* This is my infix parser/evaluator. It is optimized for size, intended
12769 * as a replacement for yacc-based parsers. However, it may well be faster
12770 * than a comparable parser written in yacc. The supported operators are
12771 * listed in #defines below. Parens, order of operations, and error handling
12772 * are supported. This code is thread safe. The exact expression format should
12773 * be that which POSIX specifies for shells. */
12775 /* The code uses a simple two-stack algorithm. See
12776 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12777 * for a detailed explanation of the infix-to-postfix algorithm on which
12778 * this is based (this code differs in that it applies operators immediately
12779 * to the stack instead of adding them to a queue to end up with an
12782 /* To use the routine, call it with an expression string and error return
12786 * Aug 24, 2001 Manuel Novoa III
12788 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12790 * 1) In arith_apply():
12791 * a) Cached values of *numptr and &(numptr[-1]).
12792 * b) Removed redundant test for zero denominator.
12795 * a) Eliminated redundant code for processing operator tokens by moving
12796 * to a table-based implementation. Also folded handling of parens
12798 * b) Combined all 3 loops which called arith_apply to reduce generated
12799 * code size at the cost of speed.
12801 * 3) The following expressions were treated as valid by the original code:
12802 * 1() , 0! , 1 ( *3 ) .
12803 * These bugs have been fixed by internally enclosing the expression in
12804 * parens and then checking that all binary ops and right parens are
12805 * preceded by a valid expression (NUM_TOKEN).
12807 * Note: It may be desirable to replace Aaron's test for whitespace with
12808 * ctype's isspace() if it is used by another busybox applet or if additional
12809 * whitespace chars should be considered. Look below the "#include"s for a
12810 * precompiler test.
12814 * Aug 26, 2001 Manuel Novoa III
12816 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12818 * Merge in Aaron's comments previously posted to the busybox list,
12819 * modified slightly to take account of my changes to the code.
12824 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12826 * - allow access to variable,
12827 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12828 * - realize assign syntax (VAR=expr, +=, *= etc)
12829 * - realize exponentiation (** operator)
12830 * - realize comma separated - expr, expr
12831 * - realise ++expr --expr expr++ expr--
12832 * - realise expr ? expr : expr (but, second expr calculate always)
12833 * - allow hexadecimal and octal numbers
12834 * - was restored loses XOR operator
12835 * - remove one goto label, added three ;-)
12836 * - protect $((num num)) as true zero expr (Manuel`s error)
12837 * - always use special isspace(), see comment from bash ;-)
12840 #define arith_isspace(arithval) \
12841 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12843 typedef unsigned char operator;
12845 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12846 * precedence, and 3 high bits are an ID unique across operators of that
12847 * precedence. The ID portion is so that multiple operators can have the
12848 * same precedence, ensuring that the leftmost one is evaluated first.
12849 * Consider * and /. */
12851 #define tok_decl(prec,id) (((id)<<5)|(prec))
12852 #define PREC(op) ((op) & 0x1F)
12854 #define TOK_LPAREN tok_decl(0,0)
12856 #define TOK_COMMA tok_decl(1,0)
12858 #define TOK_ASSIGN tok_decl(2,0)
12859 #define TOK_AND_ASSIGN tok_decl(2,1)
12860 #define TOK_OR_ASSIGN tok_decl(2,2)
12861 #define TOK_XOR_ASSIGN tok_decl(2,3)
12862 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12863 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12864 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12865 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12867 #define TOK_MUL_ASSIGN tok_decl(3,0)
12868 #define TOK_DIV_ASSIGN tok_decl(3,1)
12869 #define TOK_REM_ASSIGN tok_decl(3,2)
12871 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12872 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12874 /* conditional is right associativity too */
12875 #define TOK_CONDITIONAL tok_decl(4,0)
12876 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12878 #define TOK_OR tok_decl(5,0)
12880 #define TOK_AND tok_decl(6,0)
12882 #define TOK_BOR tok_decl(7,0)
12884 #define TOK_BXOR tok_decl(8,0)
12886 #define TOK_BAND tok_decl(9,0)
12888 #define TOK_EQ tok_decl(10,0)
12889 #define TOK_NE tok_decl(10,1)
12891 #define TOK_LT tok_decl(11,0)
12892 #define TOK_GT tok_decl(11,1)
12893 #define TOK_GE tok_decl(11,2)
12894 #define TOK_LE tok_decl(11,3)
12896 #define TOK_LSHIFT tok_decl(12,0)
12897 #define TOK_RSHIFT tok_decl(12,1)
12899 #define TOK_ADD tok_decl(13,0)
12900 #define TOK_SUB tok_decl(13,1)
12902 #define TOK_MUL tok_decl(14,0)
12903 #define TOK_DIV tok_decl(14,1)
12904 #define TOK_REM tok_decl(14,2)
12906 /* exponent is right associativity */
12907 #define TOK_EXPONENT tok_decl(15,1)
12909 /* For now unary operators. */
12910 #define UNARYPREC 16
12911 #define TOK_BNOT tok_decl(UNARYPREC,0)
12912 #define TOK_NOT tok_decl(UNARYPREC,1)
12914 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12915 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12917 #define PREC_PRE (UNARYPREC+2)
12919 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12920 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12922 #define PREC_POST (UNARYPREC+3)
12924 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12925 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12927 #define SPEC_PREC (UNARYPREC+4)
12929 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12930 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12932 #define NUMPTR (*numstackptr)
12935 tok_have_assign(operator op)
12937 operator prec = PREC(op);
12939 convert_prec_is_assing(prec);
12940 return (prec == PREC(TOK_ASSIGN) ||
12941 prec == PREC_PRE || prec == PREC_POST);
12945 is_right_associativity(operator prec)
12947 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
12948 || prec == PREC(TOK_CONDITIONAL));
12953 arith_t contidional_second_val;
12954 char contidional_second_val_initialized;
12955 char *var; /* if NULL then is regular number,
12956 else is variable name */
12959 typedef struct chk_var_recursive_looped_t {
12961 struct chk_var_recursive_looped_t *next;
12962 } chk_var_recursive_looped_t;
12964 static chk_var_recursive_looped_t *prev_chk_var_recursive;
12967 arith_lookup_val(v_n_t *t)
12970 const char * p = lookupvar(t->var);
12975 /* recursive try as expression */
12976 chk_var_recursive_looped_t *cur;
12977 chk_var_recursive_looped_t cur_save;
12979 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
12980 if (strcmp(cur->var, t->var) == 0) {
12981 /* expression recursion loop detected */
12985 /* save current lookuped var name */
12986 cur = prev_chk_var_recursive;
12987 cur_save.var = t->var;
12988 cur_save.next = cur;
12989 prev_chk_var_recursive = &cur_save;
12991 t->val = arith (p, &errcode);
12992 /* restore previous ptr after recursiving */
12993 prev_chk_var_recursive = cur;
12996 /* allow undefined var as 0 */
13002 /* "applying" a token means performing it on the top elements on the integer
13003 * stack. For a unary operator it will only change the top element, but a
13004 * binary operator will pop two arguments and push a result */
13006 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13009 arith_t numptr_val, rez;
13010 int ret_arith_lookup_val;
13012 /* There is no operator that can work without arguments */
13013 if (NUMPTR == numstack) goto err;
13014 numptr_m1 = NUMPTR - 1;
13016 /* check operand is var with noninteger value */
13017 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13018 if (ret_arith_lookup_val)
13019 return ret_arith_lookup_val;
13021 rez = numptr_m1->val;
13022 if (op == TOK_UMINUS)
13024 else if (op == TOK_NOT)
13026 else if (op == TOK_BNOT)
13028 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13030 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13032 else if (op != TOK_UPLUS) {
13033 /* Binary operators */
13035 /* check and binary operators need two arguments */
13036 if (numptr_m1 == numstack) goto err;
13038 /* ... and they pop one */
13041 if (op == TOK_CONDITIONAL) {
13042 if (!numptr_m1->contidional_second_val_initialized) {
13043 /* protect $((expr1 ? expr2)) without ": expr" */
13046 rez = numptr_m1->contidional_second_val;
13047 } else if (numptr_m1->contidional_second_val_initialized) {
13048 /* protect $((expr1 : expr2)) without "expr ? " */
13051 numptr_m1 = NUMPTR - 1;
13052 if (op != TOK_ASSIGN) {
13053 /* check operand is var with noninteger value for not '=' */
13054 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13055 if (ret_arith_lookup_val)
13056 return ret_arith_lookup_val;
13058 if (op == TOK_CONDITIONAL) {
13059 numptr_m1->contidional_second_val = rez;
13061 rez = numptr_m1->val;
13062 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13064 else if (op == TOK_OR)
13065 rez = numptr_val || rez;
13066 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13068 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13070 else if (op == TOK_AND)
13071 rez = rez && numptr_val;
13072 else if (op == TOK_EQ)
13073 rez = (rez == numptr_val);
13074 else if (op == TOK_NE)
13075 rez = (rez != numptr_val);
13076 else if (op == TOK_GE)
13077 rez = (rez >= numptr_val);
13078 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13079 rez >>= numptr_val;
13080 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13081 rez <<= numptr_val;
13082 else if (op == TOK_GT)
13083 rez = (rez > numptr_val);
13084 else if (op == TOK_LT)
13085 rez = (rez < numptr_val);
13086 else if (op == TOK_LE)
13087 rez = (rez <= numptr_val);
13088 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13090 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13092 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13094 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13096 else if (op == TOK_CONDITIONAL_SEP) {
13097 if (numptr_m1 == numstack) {
13098 /* protect $((expr : expr)) without "expr ? " */
13101 numptr_m1->contidional_second_val_initialized = op;
13102 numptr_m1->contidional_second_val = numptr_val;
13103 } else if (op == TOK_CONDITIONAL) {
13105 numptr_val : numptr_m1->contidional_second_val;
13106 } else if (op == TOK_EXPONENT) {
13107 if (numptr_val < 0)
13108 return -3; /* exponent less than 0 */
13113 while (numptr_val--)
13117 } else if (numptr_val==0) /* zero divisor check */
13119 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13121 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13124 if (tok_have_assign(op)) {
13125 char buf[sizeof(arith_t_type)*3 + 2];
13127 if (numptr_m1->var == NULL) {
13131 /* save to shell variable */
13132 #if ENABLE_ASH_MATH_SUPPORT_64
13133 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
13135 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
13137 setvar(numptr_m1->var, buf, 0);
13138 /* after saving, make previous value for v++ or v-- */
13139 if (op == TOK_POST_INC)
13141 else if (op == TOK_POST_DEC)
13144 numptr_m1->val = rez;
13145 /* protect geting var value, is number now */
13146 numptr_m1->var = NULL;
13152 /* longest must be first */
13153 static const char op_tokens[] ALIGN1 = {
13154 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13155 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13156 '<','<', 0, TOK_LSHIFT,
13157 '>','>', 0, TOK_RSHIFT,
13158 '|','|', 0, TOK_OR,
13159 '&','&', 0, TOK_AND,
13160 '!','=', 0, TOK_NE,
13161 '<','=', 0, TOK_LE,
13162 '>','=', 0, TOK_GE,
13163 '=','=', 0, TOK_EQ,
13164 '|','=', 0, TOK_OR_ASSIGN,
13165 '&','=', 0, TOK_AND_ASSIGN,
13166 '*','=', 0, TOK_MUL_ASSIGN,
13167 '/','=', 0, TOK_DIV_ASSIGN,
13168 '%','=', 0, TOK_REM_ASSIGN,
13169 '+','=', 0, TOK_PLUS_ASSIGN,
13170 '-','=', 0, TOK_MINUS_ASSIGN,
13171 '-','-', 0, TOK_POST_DEC,
13172 '^','=', 0, TOK_XOR_ASSIGN,
13173 '+','+', 0, TOK_POST_INC,
13174 '*','*', 0, TOK_EXPONENT,
13178 '=', 0, TOK_ASSIGN,
13190 '?', 0, TOK_CONDITIONAL,
13191 ':', 0, TOK_CONDITIONAL_SEP,
13192 ')', 0, TOK_RPAREN,
13193 '(', 0, TOK_LPAREN,
13197 #define endexpression (&op_tokens[sizeof(op_tokens)-7])
13200 arith(const char *expr, int *perrcode)
13202 char arithval; /* Current character under analysis */
13203 operator lasttok, op;
13205 operator *stack, *stackptr;
13206 const char *p = endexpression;
13208 v_n_t *numstack, *numstackptr;
13209 unsigned datasizes = strlen(expr) + 2;
13211 /* Stack of integers */
13212 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13213 * in any given correct or incorrect expression is left as an exercise to
13215 numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0]));
13216 /* Stack of operator tokens */
13217 stackptr = stack = alloca(datasizes * sizeof(stack[0]));
13219 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13220 *perrcode = errcode = 0;
13224 if (arithval == 0) {
13225 if (p == endexpression) {
13226 /* Null expression. */
13230 /* This is only reached after all tokens have been extracted from the
13231 * input stream. If there are still tokens on the operator stack, they
13232 * are to be applied in order. At the end, there should be a final
13233 * result on the integer stack */
13235 if (expr != endexpression + 1) {
13236 /* If we haven't done so already, */
13237 /* append a closing right paren */
13238 expr = endexpression;
13239 /* and let the loop process it. */
13242 /* At this point, we're done with the expression. */
13243 if (numstackptr != numstack+1) {
13244 /* ... but if there isn't, it's bad */
13249 if (numstack->var) {
13250 /* expression is $((var)) only, lookup now */
13251 errcode = arith_lookup_val(numstack);
13254 *perrcode = errcode;
13255 return numstack->val;
13258 /* Continue processing the expression. */
13259 if (arith_isspace(arithval)) {
13260 /* Skip whitespace */
13263 p = endofname(expr);
13265 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13267 numstackptr->var = alloca(var_name_size);
13268 safe_strncpy(numstackptr->var, expr, var_name_size);
13271 numstackptr->contidional_second_val_initialized = 0;
13276 if (isdigit(arithval)) {
13277 numstackptr->var = NULL;
13278 #if ENABLE_ASH_MATH_SUPPORT_64
13279 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13281 numstackptr->val = strtol(expr, (char **) &expr, 0);
13285 for (p = op_tokens; ; p++) {
13289 /* strange operator not found */
13292 for (o = expr; *p && *o == *p; p++)
13299 /* skip tail uncompared token */
13302 /* skip zero delim */
13307 /* post grammar: a++ reduce to num */
13308 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13311 /* Plus and minus are binary (not unary) _only_ if the last
13312 * token was as number, or a right paren (which pretends to be
13313 * a number, since it evaluates to one). Think about it.
13314 * It makes sense. */
13315 if (lasttok != TOK_NUM) {
13331 /* We don't want a unary operator to cause recursive descent on the
13332 * stack, because there can be many in a row and it could cause an
13333 * operator to be evaluated before its argument is pushed onto the
13334 * integer stack. */
13335 /* But for binary operators, "apply" everything on the operator
13336 * stack until we find an operator with a lesser priority than the
13337 * one we have just extracted. */
13338 /* Left paren is given the lowest priority so it will never be
13339 * "applied" in this way.
13340 * if associativity is right and priority eq, applied also skip
13343 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13344 /* not left paren or unary */
13345 if (lasttok != TOK_NUM) {
13346 /* binary op must be preceded by a num */
13349 while (stackptr != stack) {
13350 if (op == TOK_RPAREN) {
13351 /* The algorithm employed here is simple: while we don't
13352 * hit an open paren nor the bottom of the stack, pop
13353 * tokens and apply them */
13354 if (stackptr[-1] == TOK_LPAREN) {
13356 /* Any operator directly after a */
13358 /* close paren should consider itself binary */
13362 operator prev_prec = PREC(stackptr[-1]);
13364 convert_prec_is_assing(prec);
13365 convert_prec_is_assing(prev_prec);
13366 if (prev_prec < prec)
13368 /* check right assoc */
13369 if (prev_prec == prec && is_right_associativity(prec))
13372 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13373 if (errcode) goto ret;
13375 if (op == TOK_RPAREN) {
13380 /* Push this operator to the stack and remember it. */
13381 *stackptr++ = lasttok = op;
13386 #endif /* ASH_MATH_SUPPORT */
13389 /* ============ main() and helpers */
13392 * Called to exit the shell.
13394 static void exitshell(void) NORETURN;
13402 status = exitstatus;
13403 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13404 if (setjmp(loc.loc)) {
13405 if (exception == EXEXIT)
13406 /* dash bug: it just does _exit(exitstatus) here
13407 * but we have to do setjobctl(0) first!
13408 * (bug is still not fixed in dash-0.5.3 - if you run dash
13409 * under Midnight Commander, on exit from dash MC is backgrounded) */
13410 status = exitstatus;
13413 exception_handler = &loc;
13419 flush_stdout_stderr();
13429 /* from input.c: */
13430 basepf.nextc = basepf.buf = basebuf;
13433 signal(SIGCHLD, SIG_DFL);
13438 char ppid[sizeof(int)*3 + 1];
13440 struct stat st1, st2;
13443 for (envp = environ; envp && *envp; envp++) {
13444 if (strchr(*envp, '=')) {
13445 setvareq(*envp, VEXPORT|VTEXTFIXED);
13449 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
13450 setvar("PPID", ppid, 0);
13452 p = lookupvar("PWD");
13454 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
13455 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
13462 * Process the shell command line arguments.
13465 procargs(char **argv)
13468 const char *xminusc;
13473 /* if (xargv[0]) - mmm, this is always true! */
13475 for (i = 0; i < NOPTS; i++)
13479 /* it already printed err message */
13480 raise_exception(EXERROR);
13484 if (*xargv == NULL) {
13486 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13489 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13493 for (i = 0; i < NOPTS; i++)
13494 if (optlist[i] == 2)
13499 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13504 } else if (!sflag) {
13505 setinputfile(*xargv, 0);
13508 commandname = arg0;
13511 shellparam.p = xargv;
13512 #if ENABLE_ASH_GETOPTS
13513 shellparam.optind = 1;
13514 shellparam.optoff = -1;
13516 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13518 shellparam.nparam++;
13525 * Read /etc/profile or .profile.
13528 read_profile(const char *name)
13532 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13541 * This routine is called when an error or an interrupt occurs in an
13542 * interactive shell and control is returned to the main command loop.
13550 /* from input.c: */
13551 parselleft = parsenleft = 0; /* clear input buffer */
13553 /* from parser.c: */
13556 /* from redir.c: */
13557 clearredir(/*drop:*/ 0);
13561 static short profile_buf[16384];
13562 extern int etext();
13566 * Main routine. We initialize things, parse the arguments, execute
13567 * profiles if we're a login shell, and then call cmdloop to execute
13568 * commands. The setjmp call sets up the location to jump to when an
13569 * exception occurs. When an exception occurs the variable "state"
13570 * is used to figure out how far we had gotten.
13572 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13573 int ash_main(int argc UNUSED_PARAM, char **argv)
13576 volatile int state;
13577 struct jmploc jmploc;
13578 struct stackmark smark;
13580 /* Initialize global data */
13584 #if ENABLE_ASH_ALIAS
13590 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13593 #if ENABLE_FEATURE_EDITING
13594 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13597 if (setjmp(jmploc.loc)) {
13607 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13611 outcslow('\n', stderr);
13613 popstackmark(&smark);
13614 FORCE_INT_ON; /* enable interrupts */
13623 exception_handler = &jmploc;
13626 trace_puts("Shell args: ");
13627 trace_puts_args(argv);
13629 rootpid = getpid();
13631 #if ENABLE_ASH_RANDOM_SUPPORT
13632 /* Can use monotonic_ns() for better randomness but for now it is
13633 * not used anywhere else in busybox... so avoid bloat */
13634 random_galois_LFSR = random_LCG = rootpid + monotonic_us();
13637 setstackmark(&smark);
13640 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13642 const char *hp = lookupvar("HISTFILE");
13645 hp = lookupvar("HOME");
13647 char *defhp = concat_path_file(hp, ".ash_history");
13648 setvar("HISTFILE", defhp, 0);
13654 if (argv[0] && argv[0][0] == '-')
13658 read_profile("/etc/profile");
13661 read_profile(".profile");
13667 getuid() == geteuid() && getgid() == getegid() &&
13671 shinit = lookupvar("ENV");
13672 if (shinit != NULL && *shinit != '\0') {
13673 read_profile(shinit);
13679 evalstring(minusc, 0);
13681 if (sflag || minusc == NULL) {
13682 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13684 const char *hp = lookupvar("HISTFILE");
13687 line_input_state->hist_file = hp;
13690 state4: /* XXX ??? - why isn't this before the "if" statement */
13698 extern void _mcleanup(void);
13707 const char *applet_name = "debug stuff usage";
13708 int main(int argc, char **argv)
13710 return ash_main(argc, argv);
13716 * Copyright (c) 1989, 1991, 1993, 1994
13717 * The Regents of the University of California. All rights reserved.
13719 * This code is derived from software contributed to Berkeley by
13720 * Kenneth Almquist.
13722 * Redistribution and use in source and binary forms, with or without
13723 * modification, are permitted provided that the following conditions
13725 * 1. Redistributions of source code must retain the above copyright
13726 * notice, this list of conditions and the following disclaimer.
13727 * 2. Redistributions in binary form must reproduce the above copyright
13728 * notice, this list of conditions and the following disclaimer in the
13729 * documentation and/or other materials provided with the distribution.
13730 * 3. Neither the name of the University nor the names of its contributors
13731 * may be used to endorse or promote products derived from this software
13732 * without specific prior written permission.
13734 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13735 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13736 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13737 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13738 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13739 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13740 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13741 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13742 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13743 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF