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 */
56 //TODO: pull in some .h and find out do we have SINGLE_APPLET_MAIN?
57 //#include "applet_tables.h" doesn't work
62 #if defined SINGLE_APPLET_MAIN
63 /* STANDALONE does not make sense, and won't compile */
64 #undef CONFIG_FEATURE_SH_STANDALONE
65 #undef ENABLE_FEATURE_SH_STANDALONE
66 #undef USE_FEATURE_SH_STANDALONE
67 #undef SKIP_FEATURE_SH_STANDALONE(...)
68 #define ENABLE_FEATURE_SH_STANDALONE 0
69 #define USE_FEATURE_SH_STANDALONE(...)
70 #define SKIP_FEATURE_SH_STANDALONE(...) __VA_ARGS__
74 #define PIPE_BUF 4096 /* amount of buffering in a pipe */
77 #if defined(__uClinux__)
78 #error "Do not even bother, ash will not run on NOMMU machine"
82 /* ============ Hash table sizes. Configurable. */
86 #define CMDTABLESIZE 31 /* should be prime */
89 /* ============ Misc helpers */
91 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
93 /* C99 says: "char" declaration may be signed or unsigned by default */
94 #define signed_char2int(sc) ((int)((signed char)sc))
97 /* ============ Shell options */
99 static const char *const optletters_optnames[] = {
120 #define optletters(n) optletters_optnames[(n)][0]
121 #define optnames(n) (&optletters_optnames[(n)][1])
123 enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
126 /* ============ Misc data */
128 static const char homestr[] ALIGN1 = "HOME";
129 static const char snlfmt[] ALIGN1 = "%s\n";
130 static const char illnum[] ALIGN1 = "Illegal number: %s";
133 * We enclose jmp_buf in a structure so that we can declare pointers to
134 * jump locations. The global variable handler contains the location to
135 * jump to when an exception occurs, and the global variable exception
136 * contains a code identifying the exception. To implement nested
137 * exception handlers, the user should save the value of handler on entry
138 * to an inner scope, set handler to point to a jmploc structure for the
139 * inner scope, and restore handler on exit from the scope.
145 struct globals_misc {
146 /* pid of main shell */
148 /* shell level: 0 for the main shell, 1 for its children, and so on */
150 #define rootshell (!shlvl)
151 char *minusc; /* argument to -c option */
153 char *curdir; // = nullstr; /* current working directory */
154 char *physdir; // = nullstr; /* physical working directory */
156 char *arg0; /* value of $0 */
158 struct jmploc *exception_handler;
160 // disabled by vda: cannot understand how it was supposed to work -
161 // cannot fix bugs. That's why you have to explain your non-trivial designs!
162 // /* do we generate EXSIG events */
163 // int exsig; /* counter */
164 volatile int suppressint; /* counter */
165 volatile /*sig_atomic_t*/ smallint intpending; /* 1 = got SIGINT */
166 /* last pending signal */
167 volatile /*sig_atomic_t*/ smallint pendingsig;
168 smallint exception_type; /* kind of exception (0..5) */
170 #define EXINT 0 /* SIGINT received */
171 #define EXERROR 1 /* a generic error */
172 #define EXSHELLPROC 2 /* execute a shell procedure */
173 #define EXEXEC 3 /* command execution failed */
174 #define EXEXIT 4 /* exit the shell */
175 #define EXSIG 5 /* trapped signal in wait(1) */
178 char nullstr[1]; /* zero length string */
181 #define eflag optlist[0]
182 #define fflag optlist[1]
183 #define Iflag optlist[2]
184 #define iflag optlist[3]
185 #define mflag optlist[4]
186 #define nflag optlist[5]
187 #define sflag optlist[6]
188 #define xflag optlist[7]
189 #define vflag optlist[8]
190 #define Cflag optlist[9]
191 #define aflag optlist[10]
192 #define bflag optlist[11]
193 #define uflag optlist[12]
194 #define viflag optlist[13]
196 #define nolog optlist[14]
197 #define debug optlist[15]
200 /* trap handler commands */
202 * Sigmode records the current value of the signal handlers for the various
203 * modes. A value of zero means that the current handler is not known.
204 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
206 char sigmode[NSIG - 1];
207 #define S_DFL 1 /* default signal handling (SIG_DFL) */
208 #define S_CATCH 2 /* signal is caught */
209 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
210 #define S_HARD_IGN 4 /* signal is ignored permenantly */
212 /* indicates specified signal received */
213 char gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
216 /* Rarely referenced stuff */
217 #if ENABLE_ASH_RANDOM_SUPPORT
218 /* Random number generators */
219 int32_t random_galois_LFSR; /* Galois LFSR (fast but weak). signed! */
220 uint32_t random_LCG; /* LCG (fast but weak) */
222 pid_t backgndpid; /* pid of last background process */
223 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
225 extern struct globals_misc *const ash_ptr_to_globals_misc;
226 #define G_misc (*ash_ptr_to_globals_misc)
227 #define rootpid (G_misc.rootpid )
228 #define shlvl (G_misc.shlvl )
229 #define minusc (G_misc.minusc )
230 #define curdir (G_misc.curdir )
231 #define physdir (G_misc.physdir )
232 #define arg0 (G_misc.arg0 )
233 #define exception_handler (G_misc.exception_handler)
234 #define exception_type (G_misc.exception_type )
235 #define suppressint (G_misc.suppressint )
236 #define intpending (G_misc.intpending )
237 //#define exsig (G_misc.exsig )
238 #define pendingsig (G_misc.pendingsig )
239 #define isloginsh (G_misc.isloginsh )
240 #define nullstr (G_misc.nullstr )
241 #define optlist (G_misc.optlist )
242 #define sigmode (G_misc.sigmode )
243 #define gotsig (G_misc.gotsig )
244 #define trap (G_misc.trap )
245 #define random_galois_LFSR (G_misc.random_galois_LFSR)
246 #define random_LCG (G_misc.random_LCG )
247 #define backgndpid (G_misc.backgndpid )
248 #define job_warning (G_misc.job_warning)
249 #define INIT_G_misc() do { \
250 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
257 /* ============ Utility functions */
258 static int isdigit_str9(const char *str)
260 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
261 while (--maxlen && isdigit(*str))
263 return (*str == '\0');
267 /* ============ Interrupts / exceptions */
269 * These macros allow the user to suspend the handling of interrupt signals
270 * over a period of time. This is similar to SIGHOLD or to sigblock, but
271 * much more efficient and portable. (But hacking the kernel is so much
272 * more fun than worrying about efficiency and portability. :-))
274 #define INT_OFF do { \
280 * Called to raise an exception. Since C doesn't include exceptions, we
281 * just do a longjmp to the exception handler. The type of exception is
282 * stored in the global variable "exception".
284 static void raise_exception(int) NORETURN;
286 raise_exception(int e)
289 if (exception_handler == NULL)
294 longjmp(exception_handler->loc, 1);
298 * Called from trap.c when a SIGINT is received. (If the user specifies
299 * that SIGINT is to be trapped or ignored using the trap builtin, then
300 * this routine is not called.) Suppressint is nonzero when interrupts
301 * are held using the INT_OFF macro. (The test for iflag is just
302 * defensive programming.)
304 static void raise_interrupt(void) NORETURN;
306 raise_interrupt(void)
311 /* Signal is not automatically unmasked after it is raised,
312 * do it ourself - unmask all signals */
313 sigprocmask_allsigs(SIG_UNBLOCK);
314 /* pendingsig = 0; - now done in onsig() */
317 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
318 if (!(rootshell && iflag)) {
319 /* Kill ourself with SIGINT */
320 signal(SIGINT, SIG_DFL);
329 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
333 if (--suppressint == 0 && intpending) {
337 #define INT_ON int_on()
345 #define FORCE_INT_ON force_int_on()
347 #define INT_ON do { \
349 if (--suppressint == 0 && intpending) \
352 #define FORCE_INT_ON do { \
358 #endif /* ASH_OPTIMIZE_FOR_SIZE */
360 #define SAVE_INT(v) ((v) = suppressint)
362 #define RESTORE_INT(v) do { \
365 if (suppressint == 0 && intpending) \
370 * Ignore a signal. Avoids unnecessary system calls.
375 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
376 signal(signo, SIG_IGN);
378 sigmode[signo - 1] = S_HARD_IGN;
382 * Signal handler. Only one usage site - in setsignal()
387 gotsig[signo - 1] = 1;
389 if (/* exsig || */ (signo == SIGINT && !trap[SIGINT])) {
392 raise_interrupt(); /* does not return */
401 /* ============ Stdout/stderr output */
404 outstr(const char *p, FILE *file)
412 flush_stdout_stderr(void)
429 outcslow(int c, FILE *dest)
437 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
439 out1fmt(const char *fmt, ...)
446 r = vprintf(fmt, ap);
452 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
454 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
461 ret = vsnprintf(outbuf, length, fmt, ap);
468 out1str(const char *p)
474 out2str(const char *p)
481 /* ============ Parser structures */
483 /* control characters in argument strings */
484 #define CTLESC '\201' /* escape next character */
485 #define CTLVAR '\202' /* variable defn */
486 #define CTLENDVAR '\203'
487 #define CTLBACKQ '\204'
488 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
489 /* CTLBACKQ | CTLQUOTE == '\205' */
490 #define CTLARI '\206' /* arithmetic expression */
491 #define CTLENDARI '\207'
492 #define CTLQUOTEMARK '\210'
494 /* variable substitution byte (follows CTLVAR) */
495 #define VSTYPE 0x0f /* type of variable substitution */
496 #define VSNUL 0x10 /* colon--treat the empty string as unset */
497 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
499 /* values of VSTYPE field */
500 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
501 #define VSMINUS 0x2 /* ${var-text} */
502 #define VSPLUS 0x3 /* ${var+text} */
503 #define VSQUESTION 0x4 /* ${var?message} */
504 #define VSASSIGN 0x5 /* ${var=text} */
505 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
506 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
507 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
508 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
509 #define VSLENGTH 0xa /* ${#var} */
510 #if ENABLE_ASH_BASH_COMPAT
511 #define VSSUBSTR 0xc /* ${var:position:length} */
512 #define VSREPLACE 0xd /* ${var/pattern/replacement} */
513 #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
516 static const char dolatstr[] ALIGN1 = {
517 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
537 #if ENABLE_ASH_BASH_COMPAT
554 smallint type; /* Nxxxx */
557 union node *redirect;
562 smallint pipe_backgnd;
563 struct nodelist *cmdlist;
569 union node *redirect;
582 union node *elsepart;
609 struct nodelist *backquote;
612 /* nfile and ndup layout must match!
613 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
614 * that it is actually NTO2 (>&file), and change its type.
631 char *_unused_expfname;
650 struct nredir nredir;
651 struct nbinary nbinary;
655 struct nclist nclist;
664 struct nodelist *next;
677 freefunc(struct funcnode *f)
679 if (f && --f->count < 0)
684 /* ============ Debugging output */
688 static FILE *tracefile;
691 trace_printf(const char *fmt, ...)
698 vfprintf(tracefile, fmt, va);
703 trace_vprintf(const char *fmt, va_list va)
707 vfprintf(tracefile, fmt, va);
711 trace_puts(const char *s)
719 trace_puts_quoted(char *s)
726 putc('"', tracefile);
727 for (p = s; *p; p++) {
729 case '\n': c = 'n'; goto backslash;
730 case '\t': c = 't'; goto backslash;
731 case '\r': c = 'r'; goto backslash;
732 case '"': c = '"'; goto backslash;
733 case '\\': c = '\\'; goto backslash;
734 case CTLESC: c = 'e'; goto backslash;
735 case CTLVAR: c = 'v'; goto backslash;
736 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
737 case CTLBACKQ: c = 'q'; goto backslash;
738 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
740 putc('\\', tracefile);
744 if (*p >= ' ' && *p <= '~')
747 putc('\\', tracefile);
748 putc(*p >> 6 & 03, tracefile);
749 putc(*p >> 3 & 07, tracefile);
750 putc(*p & 07, tracefile);
755 putc('"', tracefile);
759 trace_puts_args(char **ap)
766 trace_puts_quoted(*ap);
768 putc('\n', tracefile);
771 putc(' ', tracefile);
786 /* leave open because libedit might be using it */
789 strcpy(s, "./trace");
791 if (!freopen(s, "a", tracefile)) {
792 fprintf(stderr, "Can't re-open %s\n", s);
797 tracefile = fopen(s, "a");
798 if (tracefile == NULL) {
799 fprintf(stderr, "Can't open %s\n", s);
805 flags = fcntl(fileno(tracefile), F_GETFL);
807 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
809 setlinebuf(tracefile);
810 fputs("\nTracing started.\n", tracefile);
814 indent(int amount, char *pfx, FILE *fp)
818 for (i = 0; i < amount; i++) {
819 if (pfx && i == amount - 1)
825 /* little circular references here... */
826 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
829 sharg(union node *arg, FILE *fp)
832 struct nodelist *bqlist;
835 if (arg->type != NARG) {
836 out1fmt("<node type %d>\n", arg->type);
839 bqlist = arg->narg.backquote;
840 for (p = arg->narg.text; *p; p++) {
849 if (subtype == VSLENGTH)
858 switch (subtype & VSTYPE) {
891 out1fmt("<subtype %d>", subtype);
898 case CTLBACKQ|CTLQUOTE:
901 shtree(bqlist->n, -1, NULL, fp);
912 shcmd(union node *cmd, FILE *fp)
920 for (np = cmd->ncmd.args; np; np = np->narg.next) {
926 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
930 switch (np->nfile.type) {
931 case NTO: s = ">>"+1; dftfd = 1; break;
932 case NCLOBBER: s = ">|"; dftfd = 1; break;
933 case NAPPEND: s = ">>"; dftfd = 1; break;
934 #if ENABLE_ASH_BASH_COMPAT
937 case NTOFD: s = ">&"; dftfd = 1; break;
938 case NFROM: s = "<"; break;
939 case NFROMFD: s = "<&"; break;
940 case NFROMTO: s = "<>"; break;
941 default: s = "*error*"; break;
943 if (np->nfile.fd != dftfd)
944 fprintf(fp, "%d", np->nfile.fd);
946 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
947 fprintf(fp, "%d", np->ndup.dupfd);
949 sharg(np->nfile.fname, fp);
956 shtree(union node *n, int ind, char *pfx, FILE *fp)
964 indent(ind, pfx, fp);
975 shtree(n->nbinary.ch1, ind, NULL, fp);
978 shtree(n->nbinary.ch2, ind, NULL, fp);
986 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
991 if (n->npipe.pipe_backgnd)
997 fprintf(fp, "<node type %d>", n->type);
1005 showtree(union node *n)
1007 trace_puts("showtree called\n");
1008 shtree(n, 1, NULL, stdout);
1011 #define TRACE(param) trace_printf param
1012 #define TRACEV(param) trace_vprintf param
1016 #define TRACE(param)
1017 #define TRACEV(param)
1022 /* ============ Parser data */
1025 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1028 struct strlist *next;
1035 struct strpush *prev; /* preceding string on stack */
1037 int prev_left_in_line;
1038 #if ENABLE_ASH_ALIAS
1039 struct alias *ap; /* if push was associated with an alias */
1041 char *string; /* remember the string since it may change */
1045 struct parsefile *prev; /* preceding file on stack */
1046 int linno; /* current line */
1047 int fd; /* file descriptor (or -1 if string) */
1048 int left_in_line; /* number of chars left in this line */
1049 int left_in_buffer; /* number of chars left in this buffer past the line */
1050 char *next_to_pgetc; /* next char in buffer */
1051 char *buf; /* input buffer */
1052 struct strpush *strpush; /* for pushing strings at this level */
1053 struct strpush basestrpush; /* so pushing one is fast */
1056 static struct parsefile basepf; /* top level input file */
1057 static struct parsefile *g_parsefile = &basepf; /* current input file */
1058 static int startlinno; /* line # where last token started */
1059 static char *commandname; /* currently executing command */
1060 static struct strlist *cmdenviron; /* environment for builtin command */
1061 static uint8_t exitstatus; /* exit status of last command */
1064 /* ============ Message printing */
1067 ash_vmsg(const char *msg, va_list ap)
1069 fprintf(stderr, "%s: ", arg0);
1071 if (strcmp(arg0, commandname))
1072 fprintf(stderr, "%s: ", commandname);
1073 if (!iflag || g_parsefile->fd)
1074 fprintf(stderr, "line %d: ", startlinno);
1076 vfprintf(stderr, msg, ap);
1077 outcslow('\n', stderr);
1081 * Exverror is called to raise the error exception. If the second argument
1082 * is not NULL then error prints an error message using printf style
1083 * formatting. It then raises the error exception.
1085 static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1087 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1091 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1093 TRACE(("\") pid=%d\n", getpid()));
1095 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1100 flush_stdout_stderr();
1101 raise_exception(cond);
1105 static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1107 ash_msg_and_raise_error(const char *msg, ...)
1112 ash_vmsg_and_raise(EXERROR, msg, ap);
1117 static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1119 ash_msg_and_raise(int cond, const char *msg, ...)
1124 ash_vmsg_and_raise(cond, msg, ap);
1130 * error/warning routines for external builtins
1133 ash_msg(const char *fmt, ...)
1143 * Return a string describing an error. The returned string may be a
1144 * pointer to a static buffer that will be overwritten on the next call.
1145 * Action describes the operation that got the error.
1148 errmsg(int e, const char *em)
1150 if (e == ENOENT || e == ENOTDIR) {
1157 /* ============ Memory allocation */
1160 * It appears that grabstackstr() will barf with such alignments
1161 * because stalloc() will return a string allocated in a new stackblock.
1163 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1165 /* Most machines require the value returned from malloc to be aligned
1166 * in some way. The following macro will get this right
1167 * on many machines. */
1168 SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,
1169 /* Minimum size of a block */
1170 MINSIZE = SHELL_ALIGN(504),
1173 struct stack_block {
1174 struct stack_block *prev;
1175 char space[MINSIZE];
1179 struct stack_block *stackp;
1182 struct stackmark *marknext;
1186 struct globals_memstack {
1187 struct stack_block *g_stackp; // = &stackbase;
1188 struct stackmark *markp;
1189 char *g_stacknxt; // = stackbase.space;
1190 char *sstrend; // = stackbase.space + MINSIZE;
1191 size_t g_stacknleft; // = MINSIZE;
1192 int herefd; // = -1;
1193 struct stack_block stackbase;
1195 extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1196 #define G_memstack (*ash_ptr_to_globals_memstack)
1197 #define g_stackp (G_memstack.g_stackp )
1198 #define markp (G_memstack.markp )
1199 #define g_stacknxt (G_memstack.g_stacknxt )
1200 #define sstrend (G_memstack.sstrend )
1201 #define g_stacknleft (G_memstack.g_stacknleft)
1202 #define herefd (G_memstack.herefd )
1203 #define stackbase (G_memstack.stackbase )
1204 #define INIT_G_memstack() do { \
1205 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1207 g_stackp = &stackbase; \
1208 g_stacknxt = stackbase.space; \
1209 g_stacknleft = MINSIZE; \
1210 sstrend = stackbase.space + MINSIZE; \
1214 #define stackblock() ((void *)g_stacknxt)
1215 #define stackblocksize() g_stacknleft
1219 ckrealloc(void * p, size_t nbytes)
1221 p = realloc(p, nbytes);
1223 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1228 ckmalloc(size_t nbytes)
1230 return ckrealloc(NULL, nbytes);
1234 ckzalloc(size_t nbytes)
1236 return memset(ckmalloc(nbytes), 0, nbytes);
1240 * Make a copy of a string in safe storage.
1243 ckstrdup(const char *s)
1245 char *p = strdup(s);
1247 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1252 * Parse trees for commands are allocated in lifo order, so we use a stack
1253 * to make this more efficient, and also to avoid all sorts of exception
1254 * handling code to handle interrupts in the middle of a parse.
1256 * The size 504 was chosen because the Ultrix malloc handles that size
1260 stalloc(size_t nbytes)
1265 aligned = SHELL_ALIGN(nbytes);
1266 if (aligned > g_stacknleft) {
1269 struct stack_block *sp;
1271 blocksize = aligned;
1272 if (blocksize < MINSIZE)
1273 blocksize = MINSIZE;
1274 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1275 if (len < blocksize)
1276 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1279 sp->prev = g_stackp;
1280 g_stacknxt = sp->space;
1281 g_stacknleft = blocksize;
1282 sstrend = g_stacknxt + blocksize;
1287 g_stacknxt += aligned;
1288 g_stacknleft -= aligned;
1293 stzalloc(size_t nbytes)
1295 return memset(stalloc(nbytes), 0, nbytes);
1302 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1303 write(STDERR_FILENO, "stunalloc\n", 10);
1307 g_stacknleft += g_stacknxt - (char *)p;
1312 * Like strdup but works with the ash stack.
1315 ststrdup(const char *p)
1317 size_t len = strlen(p) + 1;
1318 return memcpy(stalloc(len), p, len);
1322 setstackmark(struct stackmark *mark)
1324 mark->stackp = g_stackp;
1325 mark->stacknxt = g_stacknxt;
1326 mark->stacknleft = g_stacknleft;
1327 mark->marknext = markp;
1332 popstackmark(struct stackmark *mark)
1334 struct stack_block *sp;
1340 markp = mark->marknext;
1341 while (g_stackp != mark->stackp) {
1343 g_stackp = sp->prev;
1346 g_stacknxt = mark->stacknxt;
1347 g_stacknleft = mark->stacknleft;
1348 sstrend = mark->stacknxt + mark->stacknleft;
1353 * When the parser reads in a string, it wants to stick the string on the
1354 * stack and only adjust the stack pointer when it knows how big the
1355 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1356 * of space on top of the stack and stackblocklen returns the length of
1357 * this block. Growstackblock will grow this space by at least one byte,
1358 * possibly moving it (like realloc). Grabstackblock actually allocates the
1359 * part of the block that has been used.
1362 growstackblock(void)
1366 newlen = g_stacknleft * 2;
1367 if (newlen < g_stacknleft)
1368 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1372 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1373 struct stack_block *oldstackp;
1374 struct stackmark *xmark;
1375 struct stack_block *sp;
1376 struct stack_block *prevstackp;
1380 oldstackp = g_stackp;
1382 prevstackp = sp->prev;
1383 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1384 sp = ckrealloc(sp, grosslen);
1385 sp->prev = prevstackp;
1387 g_stacknxt = sp->space;
1388 g_stacknleft = newlen;
1389 sstrend = sp->space + newlen;
1392 * Stack marks pointing to the start of the old block
1393 * must be relocated to point to the new block
1396 while (xmark != NULL && xmark->stackp == oldstackp) {
1397 xmark->stackp = g_stackp;
1398 xmark->stacknxt = g_stacknxt;
1399 xmark->stacknleft = g_stacknleft;
1400 xmark = xmark->marknext;
1404 char *oldspace = g_stacknxt;
1405 size_t oldlen = g_stacknleft;
1406 char *p = stalloc(newlen);
1408 /* free the space we just allocated */
1409 g_stacknxt = memcpy(p, oldspace, oldlen);
1410 g_stacknleft += newlen;
1415 grabstackblock(size_t len)
1417 len = SHELL_ALIGN(len);
1419 g_stacknleft -= len;
1423 * The following routines are somewhat easier to use than the above.
1424 * The user declares a variable of type STACKSTR, which may be declared
1425 * to be a register. The macro STARTSTACKSTR initializes things. Then
1426 * the user uses the macro STPUTC to add characters to the string. In
1427 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1428 * grown as necessary. When the user is done, she can just leave the
1429 * string there and refer to it using stackblock(). Or she can allocate
1430 * the space for it using grabstackstr(). If it is necessary to allow
1431 * someone else to use the stack temporarily and then continue to grow
1432 * the string, the user should use grabstack to allocate the space, and
1433 * then call ungrabstr(p) to return to the previous mode of operation.
1435 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1436 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1437 * is space for at least one character.
1442 size_t len = stackblocksize();
1443 if (herefd >= 0 && len >= 1024) {
1444 full_write(herefd, stackblock(), len);
1445 return stackblock();
1448 return (char *)stackblock() + len;
1452 * Called from CHECKSTRSPACE.
1455 makestrspace(size_t newlen, char *p)
1457 size_t len = p - g_stacknxt;
1458 size_t size = stackblocksize();
1463 size = stackblocksize();
1465 if (nleft >= newlen)
1469 return (char *)stackblock() + len;
1473 stack_nputstr(const char *s, size_t n, char *p)
1475 p = makestrspace(n, p);
1476 p = (char *)memcpy(p, s, n) + n;
1481 stack_putstr(const char *s, char *p)
1483 return stack_nputstr(s, strlen(s), p);
1487 _STPUTC(int c, char *p)
1495 #define STARTSTACKSTR(p) ((p) = stackblock())
1496 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1497 #define CHECKSTRSPACE(n, p) do { \
1500 size_t m = sstrend - q; \
1502 (p) = makestrspace(l, q); \
1504 #define USTPUTC(c, p) (*(p)++ = (c))
1505 #define STACKSTRNUL(p) do { \
1506 if ((p) == sstrend) \
1507 (p) = growstackstr(); \
1510 #define STUNPUTC(p) (--(p))
1511 #define STTOPC(p) ((p)[-1])
1512 #define STADJUST(amount, p) ((p) += (amount))
1514 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1515 #define ungrabstackstr(s, p) stunalloc(s)
1516 #define stackstrend() ((void *)sstrend)
1519 /* ============ String helpers */
1522 * prefix -- see if pfx is a prefix of string.
1525 prefix(const char *string, const char *pfx)
1528 if (*pfx++ != *string++)
1531 return (char *) string;
1535 * Check for a valid number. This should be elsewhere.
1538 is_number(const char *p)
1543 } while (*++p != '\0');
1548 * Convert a string of digits to an integer, printing an error message on
1552 number(const char *s)
1555 ash_msg_and_raise_error(illnum, s);
1560 * Produce a possibly single quoted string suitable as input to the shell.
1561 * The return string is allocated on the stack.
1564 single_quote(const char *s)
1574 len = strchrnul(s, '\'') - s;
1576 q = p = makestrspace(len + 3, p);
1579 q = (char *)memcpy(q, s, len) + len;
1585 len = strspn(s, "'");
1589 q = p = makestrspace(len + 3, p);
1592 q = (char *)memcpy(q, s, len) + len;
1601 return stackblock();
1605 /* ============ nextopt */
1607 static char **argptr; /* argument list for builtin commands */
1608 static char *optionarg; /* set by nextopt (like getopt) */
1609 static char *optptr; /* used by nextopt */
1612 * XXX - should get rid of. Have all builtins use getopt(3).
1613 * The library getopt must have the BSD extension static variable
1614 * "optreset", otherwise it can't be used within the shell safely.
1616 * Standard option processing (a la getopt) for builtin routines.
1617 * The only argument that is passed to nextopt is the option string;
1618 * the other arguments are unnecessary. It returns the character,
1619 * or '\0' on end of input.
1622 nextopt(const char *optstring)
1629 if (p == NULL || *p == '\0') {
1630 /* We ate entire "-param", take next one */
1636 if (*++p == '\0') /* just "-" ? */
1639 if (LONE_DASH(p)) /* "--" ? */
1641 /* p => next "-param" */
1643 /* p => some option char in the middle of a "-param" */
1645 for (q = optstring; *q != c;) {
1647 ash_msg_and_raise_error("illegal option -%c", c);
1655 ash_msg_and_raise_error("no arg for -%c option", c);
1665 /* ============ Shell variables */
1668 * The parsefile structure pointed to by the global variable parsefile
1669 * contains information about the current file being read.
1672 int nparam; /* # of positional parameters (without $0) */
1673 #if ENABLE_ASH_GETOPTS
1674 int optind; /* next parameter to be processed by getopts */
1675 int optoff; /* used by getopts */
1677 unsigned char malloced; /* if parameter list dynamically allocated */
1678 char **p; /* parameter list */
1682 * Free the list of positional parameters.
1685 freeparam(volatile struct shparam *param)
1687 if (param->malloced) {
1689 ap = ap1 = param->p;
1696 #if ENABLE_ASH_GETOPTS
1697 static void getoptsreset(const char *value);
1701 struct var *next; /* next entry in hash list */
1702 int flags; /* flags are defined above */
1703 const char *text; /* name=value */
1704 void (*func)(const char *); /* function to be called when */
1705 /* the variable gets set/unset */
1709 struct localvar *next; /* next local variable in list */
1710 struct var *vp; /* the variable that was made local */
1711 int flags; /* saved flags */
1712 const char *text; /* saved text */
1716 #define VEXPORT 0x01 /* variable is exported */
1717 #define VREADONLY 0x02 /* variable cannot be modified */
1718 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1719 #define VTEXTFIXED 0x08 /* text is statically allocated */
1720 #define VSTACK 0x10 /* text is allocated on the stack */
1721 #define VUNSET 0x20 /* the variable is not set */
1722 #define VNOFUNC 0x40 /* don't call the callback function */
1723 #define VNOSET 0x80 /* do not set variable - just readonly test */
1724 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1725 #if ENABLE_ASH_RANDOM_SUPPORT
1726 # define VDYNAMIC 0x200 /* dynamic variable */
1732 static const char defifsvar[] ALIGN1 = "IFS= \t\n";
1733 #define defifs (defifsvar + 4)
1735 static const char defifs[] ALIGN1 = " \t\n";
1739 /* Need to be before varinit_data[] */
1740 #if ENABLE_LOCALE_SUPPORT
1742 change_lc_all(const char *value)
1744 if (value && *value != '\0')
1745 setlocale(LC_ALL, value);
1748 change_lc_ctype(const char *value)
1750 if (value && *value != '\0')
1751 setlocale(LC_CTYPE, value);
1755 static void chkmail(void);
1756 static void changemail(const char *);
1758 static void changepath(const char *);
1759 #if ENABLE_ASH_RANDOM_SUPPORT
1760 static void change_random(const char *);
1763 static const struct {
1766 void (*func)(const char *);
1767 } varinit_data[] = {
1769 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1771 { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL },
1774 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0" , changemail },
1775 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1777 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1778 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1779 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1780 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1781 #if ENABLE_ASH_GETOPTS
1782 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
1784 #if ENABLE_ASH_RANDOM_SUPPORT
1785 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1787 #if ENABLE_LOCALE_SUPPORT
1788 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL\0" , change_lc_all },
1789 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE\0", change_lc_ctype },
1791 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1792 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE\0", NULL },
1798 struct globals_var {
1799 struct shparam shellparam; /* $@ current positional parameters */
1800 struct redirtab *redirlist;
1802 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1803 struct var *vartab[VTABSIZE];
1804 struct var varinit[ARRAY_SIZE(varinit_data)];
1806 extern struct globals_var *const ash_ptr_to_globals_var;
1807 #define G_var (*ash_ptr_to_globals_var)
1808 #define shellparam (G_var.shellparam )
1809 //#define redirlist (G_var.redirlist )
1810 #define g_nullredirs (G_var.g_nullredirs )
1811 #define preverrout_fd (G_var.preverrout_fd)
1812 #define vartab (G_var.vartab )
1813 #define varinit (G_var.varinit )
1814 #define INIT_G_var() do { \
1816 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1818 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1819 varinit[i].flags = varinit_data[i].flags; \
1820 varinit[i].text = varinit_data[i].text; \
1821 varinit[i].func = varinit_data[i].func; \
1825 #define vifs varinit[0]
1827 # define vmail (&vifs)[1]
1828 # define vmpath (&vmail)[1]
1829 # define vpath (&vmpath)[1]
1831 # define vpath (&vifs)[1]
1833 #define vps1 (&vpath)[1]
1834 #define vps2 (&vps1)[1]
1835 #define vps4 (&vps2)[1]
1836 #if ENABLE_ASH_GETOPTS
1837 # define voptind (&vps4)[1]
1838 # if ENABLE_ASH_RANDOM_SUPPORT
1839 # define vrandom (&voptind)[1]
1842 # if ENABLE_ASH_RANDOM_SUPPORT
1843 # define vrandom (&vps4)[1]
1848 * The following macros access the values of the above variables.
1849 * They have to skip over the name. They return the null string
1850 * for unset variables.
1852 #define ifsval() (vifs.text + 4)
1853 #define ifsset() ((vifs.flags & VUNSET) == 0)
1855 # define mailval() (vmail.text + 5)
1856 # define mpathval() (vmpath.text + 9)
1857 # define mpathset() ((vmpath.flags & VUNSET) == 0)
1859 #define pathval() (vpath.text + 5)
1860 #define ps1val() (vps1.text + 4)
1861 #define ps2val() (vps2.text + 4)
1862 #define ps4val() (vps4.text + 4)
1863 #if ENABLE_ASH_GETOPTS
1864 # define optindval() (voptind.text + 7)
1868 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1869 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1871 #if ENABLE_ASH_GETOPTS
1873 getoptsreset(const char *value)
1875 shellparam.optind = number(value);
1876 shellparam.optoff = -1;
1881 * Return of a legal variable name (a letter or underscore followed by zero or
1882 * more letters, underscores, and digits).
1885 endofname(const char *name)
1893 if (!is_in_name(*p))
1900 * Compares two strings up to the first = or '\0'. The first
1901 * string must be terminated by '='; the second may be terminated by
1902 * either '=' or '\0'.
1905 varcmp(const char *p, const char *q)
1909 while ((c = *p) == (d = *q)) {
1924 varequal(const char *a, const char *b)
1926 return !varcmp(a, b);
1930 * Find the appropriate entry in the hash table from the name.
1932 static struct var **
1933 hashvar(const char *p)
1937 hashval = ((unsigned char) *p) << 4;
1938 while (*p && *p != '=')
1939 hashval += (unsigned char) *p++;
1940 return &vartab[hashval % VTABSIZE];
1944 vpcmp(const void *a, const void *b)
1946 return varcmp(*(const char **)a, *(const char **)b);
1950 * This routine initializes the builtin variables.
1960 * PS1 depends on uid
1962 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1963 vps1.text = "PS1=\\w \\$ ";
1966 vps1.text = "PS1=# ";
1969 end = vp + ARRAY_SIZE(varinit);
1971 vpp = hashvar(vp->text);
1974 } while (++vp < end);
1977 static struct var **
1978 findvar(struct var **vpp, const char *name)
1980 for (; *vpp; vpp = &(*vpp)->next) {
1981 if (varequal((*vpp)->text, name)) {
1989 * Find the value of a variable. Returns NULL if not set.
1992 lookupvar(const char *name)
1996 v = *findvar(hashvar(name), name);
1998 #if ENABLE_ASH_RANDOM_SUPPORT
2000 * Dynamic variables are implemented roughly the same way they are
2001 * in bash. Namely, they're "special" so long as they aren't unset.
2002 * As soon as they're unset, they're no longer dynamic, and dynamic
2003 * lookup will no longer happen at that point. -- PFM.
2005 if ((v->flags & VDYNAMIC))
2008 if (!(v->flags & VUNSET))
2009 return strchrnul(v->text, '=') + 1;
2015 * Search the environment of a builtin command.
2018 bltinlookup(const char *name)
2022 for (sp = cmdenviron; sp; sp = sp->next) {
2023 if (varequal(sp->text, name))
2024 return strchrnul(sp->text, '=') + 1;
2026 return lookupvar(name);
2030 * Same as setvar except that the variable and value are passed in
2031 * the first argument as name=value. Since the first argument will
2032 * be actually stored in the table, it should not be a string that
2034 * Called with interrupts off.
2037 setvareq(char *s, int flags)
2039 struct var *vp, **vpp;
2042 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2043 vp = *findvar(vpp, s);
2045 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2048 if (flags & VNOSAVE)
2051 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2057 if (vp->func && (flags & VNOFUNC) == 0)
2058 (*vp->func)(strchrnul(s, '=') + 1);
2060 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
2061 free((char*)vp->text);
2063 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2068 vp = ckzalloc(sizeof(*vp));
2070 /*vp->func = NULL; - ckzalloc did it */
2073 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2080 * Set the value of a variable. The flags argument is ored with the
2081 * flags of the variable. If val is NULL, the variable is unset.
2084 setvar(const char *name, const char *val, int flags)
2091 q = endofname(name);
2092 p = strchrnul(q, '=');
2094 if (!namelen || p != q)
2095 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2100 vallen = strlen(val);
2103 nameeq = ckmalloc(namelen + vallen + 2);
2104 p = (char *)memcpy(nameeq, name, namelen) + namelen;
2107 p = (char *)memcpy(p, val, vallen) + vallen;
2110 setvareq(nameeq, flags | VNOSAVE);
2114 #if ENABLE_ASH_GETOPTS
2116 * Safe version of setvar, returns 1 on success 0 on failure.
2119 setvarsafe(const char *name, const char *val, int flags)
2122 volatile int saveint;
2123 struct jmploc *volatile savehandler = exception_handler;
2124 struct jmploc jmploc;
2127 if (setjmp(jmploc.loc))
2130 exception_handler = &jmploc;
2131 setvar(name, val, flags);
2134 exception_handler = savehandler;
2135 RESTORE_INT(saveint);
2141 * Unset the specified variable.
2144 unsetvar(const char *s)
2150 vpp = findvar(hashvar(s), s);
2154 int flags = vp->flags;
2157 if (flags & VREADONLY)
2159 #if ENABLE_ASH_RANDOM_SUPPORT
2160 vp->flags &= ~VDYNAMIC;
2164 if ((flags & VSTRFIXED) == 0) {
2166 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2167 free((char*)vp->text);
2173 vp->flags &= ~VEXPORT;
2183 * Process a linked list of variable assignments.
2186 listsetvar(struct strlist *list_set_var, int flags)
2188 struct strlist *lp = list_set_var;
2194 setvareq(lp->text, flags);
2201 * Generate a list of variables satisfying the given conditions.
2204 listvars(int on, int off, char ***end)
2215 for (vp = *vpp; vp; vp = vp->next) {
2216 if ((vp->flags & mask) == on) {
2217 if (ep == stackstrend())
2218 ep = growstackstr();
2219 *ep++ = (char *) vp->text;
2222 } while (++vpp < vartab + VTABSIZE);
2223 if (ep == stackstrend())
2224 ep = growstackstr();
2228 return grabstackstr(ep);
2232 /* ============ Path search helper
2234 * The variable path (passed by reference) should be set to the start
2235 * of the path before the first call; padvance will update
2236 * this value as it proceeds. Successive calls to padvance will return
2237 * the possible path expansions in sequence. If an option (indicated by
2238 * a percent sign) appears in the path entry then the global variable
2239 * pathopt will be set to point to it; otherwise pathopt will be set to
2242 static const char *pathopt; /* set by padvance */
2245 padvance(const char **path, const char *name)
2255 for (p = start; *p && *p != ':' && *p != '%'; p++)
2257 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2258 while (stackblocksize() < len)
2262 memcpy(q, start, p - start);
2270 while (*p && *p != ':')
2277 return stalloc(len);
2281 /* ============ Prompt */
2283 static smallint doprompt; /* if set, prompt the user */
2284 static smallint needprompt; /* true if interactive and at start of line */
2286 #if ENABLE_FEATURE_EDITING
2287 static line_input_t *line_input_state;
2288 static const char *cmdedit_prompt;
2290 putprompt(const char *s)
2292 if (ENABLE_ASH_EXPAND_PRMT) {
2293 free((char*)cmdedit_prompt);
2294 cmdedit_prompt = ckstrdup(s);
2301 putprompt(const char *s)
2307 #if ENABLE_ASH_EXPAND_PRMT
2308 /* expandstr() needs parsing machinery, so it is far away ahead... */
2309 static const char *expandstr(const char *ps);
2311 #define expandstr(s) s
2315 setprompt(int whichprompt)
2318 #if ENABLE_ASH_EXPAND_PRMT
2319 struct stackmark smark;
2324 switch (whichprompt) {
2334 #if ENABLE_ASH_EXPAND_PRMT
2335 setstackmark(&smark);
2336 stalloc(stackblocksize());
2338 putprompt(expandstr(prompt));
2339 #if ENABLE_ASH_EXPAND_PRMT
2340 popstackmark(&smark);
2345 /* ============ The cd and pwd commands */
2347 #define CD_PHYSICAL 1
2350 static int docd(const char *, int);
2359 while ((i = nextopt("LP"))) {
2361 flags ^= CD_PHYSICAL;
2370 * Update curdir (the name of the current directory) in response to a
2374 updatepwd(const char *dir)
2381 cdcomppath = ststrdup(dir);
2384 if (curdir == nullstr)
2386 new = stack_putstr(curdir, new);
2388 new = makestrspace(strlen(dir) + 2, new);
2389 lim = (char *)stackblock() + 1;
2393 if (new > lim && *lim == '/')
2398 if (dir[1] == '/' && dir[2] != '/') {
2404 p = strtok(cdcomppath, "/");
2408 if (p[1] == '.' && p[2] == '\0') {
2420 new = stack_putstr(p, new);
2428 return stackblock();
2432 * Find out what the current directory is. If we already know the current
2433 * directory, this routine returns immediately.
2438 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2439 return dir ? dir : nullstr;
2443 setpwd(const char *val, int setold)
2447 oldcur = dir = curdir;
2450 setvar("OLDPWD", oldcur, VEXPORT);
2453 if (physdir != nullstr) {
2454 if (physdir != oldcur)
2458 if (oldcur == val || !val) {
2464 dir = ckstrdup(val);
2465 if (oldcur != dir && oldcur != nullstr) {
2470 setvar("PWD", dir, VEXPORT);
2473 static void hashcd(void);
2476 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2477 * know that the current directory has changed.
2480 docd(const char *dest, int flags)
2482 const char *dir = 0;
2485 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2488 if (!(flags & CD_PHYSICAL)) {
2489 dir = updatepwd(dest);
2504 cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2516 dest = bltinlookup(homestr);
2517 else if (LONE_DASH(dest)) {
2518 dest = bltinlookup("OLDPWD");
2540 path = bltinlookup("CDPATH");
2549 p = padvance(&path, dest);
2550 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2554 if (!docd(p, flags))
2559 ash_msg_and_raise_error("can't cd to %s", dest);
2562 if (flags & CD_PRINT)
2563 out1fmt(snlfmt, curdir);
2568 pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2571 const char *dir = curdir;
2575 if (physdir == nullstr)
2579 out1fmt(snlfmt, dir);
2584 /* ============ ... */
2587 #define IBUFSIZ COMMON_BUFSIZE
2588 /* buffer for top level input file */
2589 #define basebuf bb_common_bufsiz1
2591 /* Syntax classes */
2592 #define CWORD 0 /* character is nothing special */
2593 #define CNL 1 /* newline character */
2594 #define CBACK 2 /* a backslash character */
2595 #define CSQUOTE 3 /* single quote */
2596 #define CDQUOTE 4 /* double quote */
2597 #define CENDQUOTE 5 /* a terminating quote */
2598 #define CBQUOTE 6 /* backwards single quote */
2599 #define CVAR 7 /* a dollar sign */
2600 #define CENDVAR 8 /* a '}' character */
2601 #define CLP 9 /* a left paren in arithmetic */
2602 #define CRP 10 /* a right paren in arithmetic */
2603 #define CENDFILE 11 /* end of file */
2604 #define CCTL 12 /* like CWORD, except it must be escaped */
2605 #define CSPCL 13 /* these terminate a word */
2606 #define CIGN 14 /* character should be ignored */
2608 #if ENABLE_ASH_ALIAS
2612 #define PEOA_OR_PEOF PEOA
2616 #define PEOA_OR_PEOF PEOF
2619 /* number syntax index */
2620 #define BASESYNTAX 0 /* not in quotes */
2621 #define DQSYNTAX 1 /* in double quotes */
2622 #define SQSYNTAX 2 /* in single quotes */
2623 #define ARISYNTAX 3 /* in arithmetic */
2624 #define PSSYNTAX 4 /* prompt */
2626 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
2627 #define USE_SIT_FUNCTION
2630 #if ENABLE_ASH_MATH_SUPPORT
2631 static const char S_I_T[][4] = {
2632 #if ENABLE_ASH_ALIAS
2633 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */
2635 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */
2636 { CNL, CNL, CNL, CNL }, /* 2, \n */
2637 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */
2638 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */
2639 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */
2640 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */
2641 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */
2642 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */
2643 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */
2644 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */
2645 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */
2646 #ifndef USE_SIT_FUNCTION
2647 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2648 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2649 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2653 static const char S_I_T[][3] = {
2654 #if ENABLE_ASH_ALIAS
2655 { CSPCL, CIGN, CIGN }, /* 0, PEOA */
2657 { CSPCL, CWORD, CWORD }, /* 1, ' ' */
2658 { CNL, CNL, CNL }, /* 2, \n */
2659 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */
2660 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */
2661 { CVAR, CVAR, CWORD }, /* 5, $ */
2662 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */
2663 { CSPCL, CWORD, CWORD }, /* 7, ( */
2664 { CSPCL, CWORD, CWORD }, /* 8, ) */
2665 { CBACK, CBACK, CCTL }, /* 9, \ */
2666 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */
2667 { CENDVAR, CENDVAR, CWORD }, /* 11, } */
2668 #ifndef USE_SIT_FUNCTION
2669 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2670 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2671 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2674 #endif /* ASH_MATH_SUPPORT */
2676 #ifdef USE_SIT_FUNCTION
2679 SIT(int c, int syntax)
2681 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2682 #if ENABLE_ASH_ALIAS
2683 static const char syntax_index_table[] ALIGN1 = {
2684 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2685 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2686 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2690 static const char syntax_index_table[] ALIGN1 = {
2691 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2692 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2693 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2700 if (c == PEOF) /* 2^8+2 */
2702 #if ENABLE_ASH_ALIAS
2703 if (c == PEOA) /* 2^8+1 */
2708 if ((unsigned char)c >= (unsigned char)(CTLESC)
2709 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
2713 s = strchrnul(spec_symbls, c);
2716 indx = syntax_index_table[s - spec_symbls];
2717 return S_I_T[indx][syntax];
2720 #else /* !USE_SIT_FUNCTION */
2722 #if ENABLE_ASH_ALIAS
2723 #define CSPCL_CIGN_CIGN_CIGN 0
2724 #define CSPCL_CWORD_CWORD_CWORD 1
2725 #define CNL_CNL_CNL_CNL 2
2726 #define CWORD_CCTL_CCTL_CWORD 3
2727 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
2728 #define CVAR_CVAR_CWORD_CVAR 5
2729 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
2730 #define CSPCL_CWORD_CWORD_CLP 7
2731 #define CSPCL_CWORD_CWORD_CRP 8
2732 #define CBACK_CBACK_CCTL_CBACK 9
2733 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
2734 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
2735 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
2736 #define CWORD_CWORD_CWORD_CWORD 13
2737 #define CCTL_CCTL_CCTL_CCTL 14
2739 #define CSPCL_CWORD_CWORD_CWORD 0
2740 #define CNL_CNL_CNL_CNL 1
2741 #define CWORD_CCTL_CCTL_CWORD 2
2742 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
2743 #define CVAR_CVAR_CWORD_CVAR 4
2744 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
2745 #define CSPCL_CWORD_CWORD_CLP 6
2746 #define CSPCL_CWORD_CWORD_CRP 7
2747 #define CBACK_CBACK_CCTL_CBACK 8
2748 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
2749 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
2750 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
2751 #define CWORD_CWORD_CWORD_CWORD 12
2752 #define CCTL_CCTL_CCTL_CCTL 13
2755 static const char syntax_index_table[258] = {
2756 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2757 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2758 #if ENABLE_ASH_ALIAS
2759 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
2761 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2762 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2763 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2764 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2765 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2766 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2767 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2768 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2769 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2770 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
2771 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
2772 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
2773 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
2774 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
2775 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
2776 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
2777 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
2778 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
2779 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
2780 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
2781 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
2782 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
2783 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
2784 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
2785 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
2786 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
2787 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
2788 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
2789 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
2790 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
2791 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
2792 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
2793 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
2794 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
2795 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
2796 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
2797 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
2798 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
2799 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
2800 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
2801 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
2802 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
2803 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
2804 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
2805 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
2806 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
2807 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
2808 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
2809 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
2810 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
2811 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
2812 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
2813 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
2814 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
2815 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
2816 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
2817 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
2818 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
2819 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
2820 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
2821 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
2822 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
2823 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
2824 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
2825 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
2826 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
2827 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
2828 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
2829 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
2830 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
2831 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
2832 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
2833 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
2834 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
2835 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
2836 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
2837 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
2838 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
2839 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
2840 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
2841 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
2842 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
2843 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
2844 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
2845 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
2846 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
2847 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
2848 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
2853 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
2854 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
2898 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2899 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
2900 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
2901 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
2902 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
2903 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
2904 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
2905 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
2906 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
2907 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
2908 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
2909 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
2910 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
2911 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
2912 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
2913 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
2914 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
2915 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
2916 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
2917 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
2918 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
2919 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
2920 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
2921 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2922 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2923 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2924 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2926 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2928 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2929 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2930 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2931 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2932 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
2934 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2935 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
2936 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2937 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2948 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2949 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2950 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2951 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2952 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2953 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2981 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2982 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2983 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2986 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3003 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3004 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3005 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3006 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3007 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3008 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3009 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3010 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3011 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3012 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3013 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3014 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3015 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3016 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
3019 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax])
3021 #endif /* USE_SIT_FUNCTION */
3024 /* ============ Alias handling */
3026 #if ENABLE_ASH_ALIAS
3028 #define ALIASINUSE 1
3039 static struct alias **atab; // [ATABSIZE];
3040 #define INIT_G_alias() do { \
3041 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3045 static struct alias **
3046 __lookupalias(const char *name) {
3047 unsigned int hashval;
3054 ch = (unsigned char)*p;
3058 ch = (unsigned char)*++p;
3060 app = &atab[hashval % ATABSIZE];
3062 for (; *app; app = &(*app)->next) {
3063 if (strcmp(name, (*app)->name) == 0) {
3071 static struct alias *
3072 lookupalias(const char *name, int check)
3074 struct alias *ap = *__lookupalias(name);
3076 if (check && ap && (ap->flag & ALIASINUSE))
3081 static struct alias *
3082 freealias(struct alias *ap)
3086 if (ap->flag & ALIASINUSE) {
3087 ap->flag |= ALIASDEAD;
3099 setalias(const char *name, const char *val)
3101 struct alias *ap, **app;
3103 app = __lookupalias(name);
3107 if (!(ap->flag & ALIASINUSE)) {
3110 ap->val = ckstrdup(val);
3111 ap->flag &= ~ALIASDEAD;
3114 ap = ckzalloc(sizeof(struct alias));
3115 ap->name = ckstrdup(name);
3116 ap->val = ckstrdup(val);
3117 /*ap->flag = 0; - ckzalloc did it */
3118 /*ap->next = NULL;*/
3125 unalias(const char *name)
3129 app = __lookupalias(name);
3133 *app = freealias(*app);
3144 struct alias *ap, **app;
3148 for (i = 0; i < ATABSIZE; i++) {
3150 for (ap = *app; ap; ap = *app) {
3151 *app = freealias(*app);
3161 printalias(const struct alias *ap)
3163 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3167 * TODO - sort output
3170 aliascmd(int argc UNUSED_PARAM, char **argv)
3179 for (i = 0; i < ATABSIZE; i++) {
3180 for (ap = atab[i]; ap; ap = ap->next) {
3186 while ((n = *++argv) != NULL) {
3187 v = strchr(n+1, '=');
3188 if (v == NULL) { /* n+1: funny ksh stuff */
3189 ap = *__lookupalias(n);
3191 fprintf(stderr, "%s: %s not found\n", "alias", n);
3205 unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3209 while ((i = nextopt("a")) != '\0') {
3215 for (i = 0; *argptr; argptr++) {
3216 if (unalias(*argptr)) {
3217 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3225 #endif /* ASH_ALIAS */
3228 /* ============ jobs.c */
3230 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3233 #define FORK_NOJOB 2
3235 /* mode flags for showjob(s) */
3236 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
3237 #define SHOW_PID 0x04 /* include process pid */
3238 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
3241 * A job structure contains information about a job. A job is either a
3242 * single process or a set of processes contained in a pipeline. In the
3243 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3248 pid_t pid; /* process id */
3249 int status; /* last process status from wait() */
3250 char *cmd; /* text of command being run */
3254 struct procstat ps0; /* status of process */
3255 struct procstat *ps; /* status or processes when more than one */
3257 int stopstatus; /* status of a stopped job */
3260 nprocs: 16, /* number of processes */
3262 #define JOBRUNNING 0 /* at least one proc running */
3263 #define JOBSTOPPED 1 /* all procs are stopped */
3264 #define JOBDONE 2 /* all procs are completed */
3266 sigint: 1, /* job was killed by SIGINT */
3267 jobctl: 1, /* job running under job control */
3269 waited: 1, /* true if this entry has been waited for */
3270 used: 1, /* true if this entry is in used */
3271 changed: 1; /* true if status has changed */
3272 struct job *prev_job; /* previous job */
3275 static struct job *makejob(/*union node *,*/ int);
3277 #define forkshell(job, node, mode) forkshell(job, mode)
3279 static int forkshell(struct job *, union node *, int);
3280 static int waitforjob(struct job *);
3283 enum { doing_jobctl = 0 };
3284 #define setjobctl(on) do {} while (0)
3286 static smallint doing_jobctl; //references:8
3287 static void setjobctl(int);
3291 * Set the signal handler for the specified signal. The routine figures
3292 * out what it should be set to.
3295 setsignal(int signo)
3298 char cur_act, new_act;
3299 struct sigaction act;
3303 if (t != NULL) { /* trap for this sig is set */
3305 if (t[0] == '\0') /* trap is "": ignore this sig */
3309 if (rootshell && new_act == S_DFL) {
3312 if (iflag || minusc || sflag == 0)
3321 * "In all cases, bash ignores SIGQUIT. Non-builtin
3322 * commands run by bash have signal handlers
3323 * set to the values inherited by the shell
3324 * from its parent". */
3340 //TODO: if !rootshell, we reset SIGQUIT to DFL,
3341 //whereas we have to restore it to what shell got on entry
3342 //from the parent. See comment above
3344 t = &sigmode[signo - 1];
3347 /* current setting is not yet known */
3348 if (sigaction(signo, NULL, &act)) {
3349 /* pretend it worked; maybe we should give a warning,
3350 * but other shells don't. We don't alter sigmode,
3351 * so we retry every time.
3352 * btw, in Linux it never fails. --vda */
3355 if (act.sa_handler == SIG_IGN) {
3356 cur_act = S_HARD_IGN;
3358 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3360 cur_act = S_IGN; /* don't hard ignore these */
3364 if (cur_act == S_HARD_IGN || cur_act == new_act)
3367 act.sa_handler = SIG_DFL;
3370 act.sa_handler = onsig;
3371 act.sa_flags = 0; /* matters only if !DFL and !IGN */
3372 sigfillset(&act.sa_mask); /* ditto */
3375 act.sa_handler = SIG_IGN;
3378 sigaction_set(signo, &act);
3383 /* mode flags for set_curjob */
3384 #define CUR_DELETE 2
3385 #define CUR_RUNNING 1
3386 #define CUR_STOPPED 0
3388 /* mode flags for dowait */
3389 #define DOWAIT_NONBLOCK WNOHANG
3390 #define DOWAIT_BLOCK 0
3393 /* pgrp of shell on invocation */
3394 static int initialpgrp; //references:2
3395 static int ttyfd = -1; //5
3398 static struct job *jobtab; //5
3400 static unsigned njobs; //4
3402 static struct job *curjob; //lots
3403 /* number of presumed living untracked jobs */
3404 static int jobless; //4
3407 set_curjob(struct job *jp, unsigned mode)
3410 struct job **jpp, **curp;
3412 /* first remove from list */
3413 jpp = curp = &curjob;
3418 jpp = &jp1->prev_job;
3420 *jpp = jp1->prev_job;
3422 /* Then re-insert in correct position */
3430 /* job being deleted */
3433 /* newly created job or backgrounded job,
3434 put after all stopped jobs. */
3438 if (!jp1 || jp1->state != JOBSTOPPED)
3441 jpp = &jp1->prev_job;
3447 /* newly stopped job - becomes curjob */
3448 jp->prev_job = *jpp;
3456 jobno(const struct job *jp)
3458 return jp - jobtab + 1;
3463 * Convert a job name to a job structure.
3466 #define getjob(name, getctl) getjob(name)
3469 getjob(const char *name, int getctl)
3473 const char *err_msg = "No such job: %s";
3477 char *(*match)(const char *, const char *);
3492 if (c == '+' || c == '%') {
3494 err_msg = "No current job";
3500 err_msg = "No previous job";
3509 // TODO: number() instead? It does error checking...
3512 jp = jobtab + num - 1;
3529 if (match(jp->ps[0].cmd, p)) {
3533 err_msg = "%s: ambiguous";
3540 err_msg = "job %s not created under job control";
3541 if (getctl && jp->jobctl == 0)
3546 ash_msg_and_raise_error(err_msg, name);
3550 * Mark a job structure as unused.
3553 freejob(struct job *jp)
3555 struct procstat *ps;
3559 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3560 if (ps->cmd != nullstr)
3563 if (jp->ps != &jp->ps0)
3566 set_curjob(jp, CUR_DELETE);
3572 xtcsetpgrp(int fd, pid_t pgrp)
3574 if (tcsetpgrp(fd, pgrp))
3575 ash_msg_and_raise_error("can't set tty process group (%m)");
3579 * Turn job control on and off.
3581 * Note: This code assumes that the third arg to ioctl is a character
3582 * pointer, which is true on Berkeley systems but not System V. Since
3583 * System V doesn't have job control yet, this isn't a problem now.
3585 * Called with interrupts off.
3593 if (on == doing_jobctl || rootshell == 0)
3597 ofd = fd = open(_PATH_TTY, O_RDWR);
3599 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3600 * That sometimes helps to acquire controlling tty.
3601 * Obviously, a workaround for bugs when someone
3602 * failed to provide a controlling tty to bash! :) */
3608 fd = fcntl(fd, F_DUPFD, 10);
3613 /* fd is a tty at this point */
3614 close_on_exec_on(fd);
3615 do { /* while we are in the background */
3616 pgrp = tcgetpgrp(fd);
3619 ash_msg("can't access tty; job control turned off");
3623 if (pgrp == getpgrp())
3634 xtcsetpgrp(fd, pgrp);
3636 /* turning job control off */
3639 /* was xtcsetpgrp, but this can make exiting ash
3640 * loop forever if pty is already deleted */
3641 tcsetpgrp(fd, pgrp);
3656 killcmd(int argc, char **argv)
3659 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3661 if (argv[i][0] == '%') {
3662 struct job *jp = getjob(argv[i], 0);
3663 unsigned pid = jp->ps[0].pid;
3664 /* Enough space for ' -NNN<nul>' */
3665 argv[i] = alloca(sizeof(int)*3 + 3);
3666 /* kill_main has matching code to expect
3667 * leading space. Needed to not confuse
3668 * negative pids with "kill -SIGNAL_NO" syntax */
3669 sprintf(argv[i], " -%u", pid);
3671 } while (argv[++i]);
3673 return kill_main(argc, argv);
3677 showpipe(struct job *jp, FILE *out)
3679 struct procstat *sp;
3680 struct procstat *spend;
3682 spend = jp->ps + jp->nprocs;
3683 for (sp = jp->ps + 1; sp < spend; sp++)
3684 fprintf(out, " | %s", sp->cmd);
3685 outcslow('\n', out);
3686 flush_stdout_stderr();
3691 restartjob(struct job *jp, int mode)
3693 struct procstat *ps;
3699 if (jp->state == JOBDONE)
3701 jp->state = JOBRUNNING;
3703 if (mode == FORK_FG)
3704 xtcsetpgrp(ttyfd, pgid);
3705 killpg(pgid, SIGCONT);
3709 if (WIFSTOPPED(ps->status)) {
3715 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3721 fg_bgcmd(int argc UNUSED_PARAM, char **argv)
3728 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3733 jp = getjob(*argv, 1);
3734 if (mode == FORK_BG) {
3735 set_curjob(jp, CUR_RUNNING);
3736 fprintf(out, "[%d] ", jobno(jp));
3738 outstr(jp->ps->cmd, out);
3740 retval = restartjob(jp, mode);
3741 } while (*argv && *++argv);
3747 sprint_status(char *s, int status, int sigonly)
3753 if (!WIFEXITED(status)) {
3755 if (WIFSTOPPED(status))
3756 st = WSTOPSIG(status);
3759 st = WTERMSIG(status);
3761 if (st == SIGINT || st == SIGPIPE)
3764 if (WIFSTOPPED(status))
3769 col = fmtstr(s, 32, strsignal(st));
3770 if (WCOREDUMP(status)) {
3771 col += fmtstr(s + col, 16, " (core dumped)");
3773 } else if (!sigonly) {
3774 st = WEXITSTATUS(status);
3776 col = fmtstr(s, 16, "Done(%d)", st);
3778 col = fmtstr(s, 16, "Done");
3785 dowait(int wait_flags, struct job *job)
3790 struct job *thisjob;
3793 TRACE(("dowait(0x%x) called\n", wait_flags));
3795 /* Do a wait system call. If job control is compiled in, we accept
3796 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3797 * NB: _not_ safe_waitpid, we need to detect EINTR */
3798 pid = waitpid(-1, &status,
3799 (doing_jobctl ? (wait_flags | WUNTRACED) : wait_flags));
3800 TRACE(("wait returns pid=%d, status=0x%x\n", pid, status));
3806 for (jp = curjob; jp; jp = jp->prev_job) {
3807 struct procstat *sp;
3808 struct procstat *spend;
3809 if (jp->state == JOBDONE)
3812 spend = jp->ps + jp->nprocs;
3815 if (sp->pid == pid) {
3816 TRACE(("Job %d: changing status of proc %d "
3817 "from 0x%x to 0x%x\n",
3818 jobno(jp), pid, sp->status, status));
3819 sp->status = status;
3822 if (sp->status == -1)
3825 if (state == JOBRUNNING)
3827 if (WIFSTOPPED(sp->status)) {
3828 jp->stopstatus = sp->status;
3832 } while (++sp < spend);
3837 if (!WIFSTOPPED(status))
3843 if (state != JOBRUNNING) {
3844 thisjob->changed = 1;
3846 if (thisjob->state != state) {
3847 TRACE(("Job %d: changing state from %d to %d\n",
3848 jobno(thisjob), thisjob->state, state));
3849 thisjob->state = state;
3851 if (state == JOBSTOPPED) {
3852 set_curjob(thisjob, CUR_STOPPED);
3861 if (thisjob && thisjob == job) {
3865 len = sprint_status(s, status, 1);
3876 blocking_wait_with_raise_on_sig(struct job *job)
3878 pid_t pid = dowait(DOWAIT_BLOCK, job);
3879 if (pid <= 0 && pendingsig)
3880 raise_exception(EXSIG);
3886 showjob(FILE *out, struct job *jp, int mode)
3888 struct procstat *ps;
3889 struct procstat *psend;
3896 if (mode & SHOW_PGID) {
3897 /* just output process (group) id of pipeline */
3898 fprintf(out, "%d\n", ps->pid);
3902 col = fmtstr(s, 16, "[%d] ", jobno(jp));
3907 else if (curjob && jp == curjob->prev_job)
3910 if (mode & SHOW_PID)
3911 col += fmtstr(s + col, 16, "%d ", ps->pid);
3913 psend = ps + jp->nprocs;
3915 if (jp->state == JOBRUNNING) {
3916 strcpy(s + col, "Running");
3917 col += sizeof("Running") - 1;
3919 int status = psend[-1].status;
3920 if (jp->state == JOBSTOPPED)
3921 status = jp->stopstatus;
3922 col += sprint_status(s + col, status, 0);
3928 /* for each process */
3929 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
3931 fprintf(out, "%s%*c%s",
3932 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
3934 if (!(mode & SHOW_PID)) {
3938 if (++ps == psend) {
3939 outcslow('\n', out);
3946 if (jp->state == JOBDONE) {
3947 TRACE(("showjob: freeing job %d\n", jobno(jp)));
3953 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3954 * statuses have changed since the last call to showjobs.
3957 showjobs(FILE *out, int mode)
3961 TRACE(("showjobs(%x) called\n", mode));
3963 /* Handle all finished jobs */
3964 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3967 for (jp = curjob; jp; jp = jp->prev_job) {
3968 if (!(mode & SHOW_CHANGED) || jp->changed) {
3969 showjob(out, jp, mode);
3975 jobscmd(int argc UNUSED_PARAM, char **argv)
3980 while ((m = nextopt("lp"))) {
3990 showjob(stdout, getjob(*argv,0), mode);
3993 showjobs(stdout, mode);
4000 getstatus(struct job *job)
4005 status = job->ps[job->nprocs - 1].status;
4006 retval = WEXITSTATUS(status);
4007 if (!WIFEXITED(status)) {
4009 retval = WSTOPSIG(status);
4010 if (!WIFSTOPPED(status))
4013 /* XXX: limits number of signals */
4014 retval = WTERMSIG(status);
4016 if (retval == SIGINT)
4022 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
4023 jobno(job), job->nprocs, status, retval));
4028 waitcmd(int argc UNUSED_PARAM, char **argv)
4037 raise_exception(EXSIG);
4044 /* wait for all jobs */
4048 if (!jp) /* no running procs */
4050 if (jp->state == JOBRUNNING)
4056 * "When bash is waiting for an asynchronous command via
4057 * the wait builtin, the reception of a signal for which a trap
4058 * has been set will cause the wait builtin to return immediately
4059 * with an exit status greater than 128, immediately after which
4060 * the trap is executed."
4061 * Do we do it that way? */
4062 blocking_wait_with_raise_on_sig(NULL);
4068 if (**argv != '%') {
4069 pid_t pid = number(*argv);
4074 if (job->ps[job->nprocs - 1].pid == pid)
4076 job = job->prev_job;
4079 job = getjob(*argv, 0);
4080 /* loop until process terminated or stopped */
4081 while (job->state == JOBRUNNING)
4082 blocking_wait_with_raise_on_sig(NULL);
4084 retval = getstatus(job);
4097 struct job *jp, *jq;
4099 len = njobs * sizeof(*jp);
4101 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4103 offset = (char *)jp - (char *)jq;
4105 /* Relocate pointers */
4108 jq = (struct job *)((char *)jq + l);
4112 #define joff(p) ((struct job *)((char *)(p) + l))
4113 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4114 if (joff(jp)->ps == &jq->ps0)
4115 jmove(joff(jp)->ps);
4116 if (joff(jp)->prev_job)
4117 jmove(joff(jp)->prev_job);
4127 jp = (struct job *)((char *)jp + len);
4131 } while (--jq >= jp);
4136 * Return a new job structure.
4137 * Called with interrupts off.
4140 makejob(/*union node *node,*/ int nprocs)
4145 for (i = njobs, jp = jobtab; ; jp++) {
4152 if (jp->state != JOBDONE || !jp->waited)
4161 memset(jp, 0, sizeof(*jp));
4163 /* jp->jobctl is a bitfield.
4164 * "jp->jobctl |= jobctl" likely to give awful code */
4168 jp->prev_job = curjob;
4173 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4175 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4182 * Return a string identifying a command (to be printed by the
4185 static char *cmdnextc;
4188 cmdputs(const char *s)
4190 static const char vstype[VSTYPE + 1][3] = {
4191 "", "}", "-", "+", "?", "=",
4192 "%", "%%", "#", "##"
4193 USE_ASH_BASH_COMPAT(, ":", "/", "//")
4196 const char *p, *str;
4197 char c, cc[2] = " ";
4202 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4204 while ((c = *p++) != 0) {
4212 if ((subtype & VSTYPE) == VSLENGTH)
4216 if (!(subtype & VSQUOTE) == !(quoted & 1))
4222 str = "\"}" + !(quoted & 1);
4229 case CTLBACKQ+CTLQUOTE:
4232 #if ENABLE_ASH_MATH_SUPPORT
4247 if ((subtype & VSTYPE) != VSNORMAL)
4249 str = vstype[subtype & VSTYPE];
4250 if (subtype & VSNUL)
4259 /* These can only happen inside quotes */
4272 while ((c = *str++)) {
4277 USTPUTC('"', nextc);
4283 /* cmdtxt() and cmdlist() call each other */
4284 static void cmdtxt(union node *n);
4287 cmdlist(union node *np, int sep)
4289 for (; np; np = np->narg.next) {
4293 if (sep && np->narg.next)
4299 cmdtxt(union node *n)
4302 struct nodelist *lp;
4313 lp = n->npipe.cmdlist;
4331 cmdtxt(n->nbinary.ch1);
4347 cmdtxt(n->nif.test);
4350 if (n->nif.elsepart) {
4353 n = n->nif.elsepart;
4369 cmdtxt(n->nbinary.ch1);
4379 cmdputs(n->nfor.var);
4381 cmdlist(n->nfor.args, 1);
4386 cmdputs(n->narg.text);
4390 cmdlist(n->ncmd.args, 1);
4391 cmdlist(n->ncmd.redirect, 0);
4404 cmdputs(n->ncase.expr->narg.text);
4406 for (np = n->ncase.cases; np; np = np->nclist.next) {
4407 cmdtxt(np->nclist.pattern);
4409 cmdtxt(np->nclist.body);
4423 #if ENABLE_ASH_BASH_COMPAT
4438 cmdputs(utoa(n->nfile.fd));
4440 if (n->type == NTOFD || n->type == NFROMFD) {
4441 cmdputs(utoa(n->ndup.dupfd));
4450 commandtext(union node *n)
4454 STARTSTACKSTR(cmdnextc);
4456 name = stackblock();
4457 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4458 name, cmdnextc, cmdnextc));
4459 return ckstrdup(name);
4464 * Fork off a subshell. If we are doing job control, give the subshell its
4465 * own process group. Jp is a job structure that the job is to be added to.
4466 * N is the command that will be evaluated by the child. Both jp and n may
4467 * be NULL. The mode parameter can be one of the following:
4468 * FORK_FG - Fork off a foreground process.
4469 * FORK_BG - Fork off a background process.
4470 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4471 * process group even if job control is on.
4473 * When job control is turned off, background processes have their standard
4474 * input redirected to /dev/null (except for the second and later processes
4477 * Called with interrupts off.
4480 * Clear traps on a fork.
4487 for (tp = trap; tp < &trap[NSIG]; tp++) {
4488 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4493 setsignal(tp - trap);
4499 /* Lives far away from here, needed for forkchild */
4500 static void closescript(void);
4502 /* Called after fork(), in child */
4504 forkchild(struct job *jp, /*union node *n,*/ int mode)
4508 TRACE(("Child shell %d\n", getpid()));
4512 /* man bash: "Non-builtin commands run by bash have signal handlers
4513 * set to the values inherited by the shell from its parent".
4514 * Do we do it correctly? */
4519 /* do job control only in root shell */
4521 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4524 if (jp->nprocs == 0)
4527 pgrp = jp->ps[0].pid;
4528 /* this can fail because we are doing it in the parent also */
4530 if (mode == FORK_FG)
4531 xtcsetpgrp(ttyfd, pgrp);
4536 if (mode == FORK_BG) {
4537 /* man bash: "When job control is not in effect,
4538 * asynchronous commands ignore SIGINT and SIGQUIT" */
4541 if (jp->nprocs == 0) {
4543 if (open(bb_dev_null, O_RDONLY) != 0)
4544 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
4548 if (iflag) { /* why if iflag only? */
4553 * "In all cases, bash ignores SIGQUIT. Non-builtin
4554 * commands run by bash have signal handlers
4555 * set to the values inherited by the shell
4557 * Take care of the second rule: */
4560 for (jp = curjob; jp; jp = jp->prev_job)
4565 /* Called after fork(), in parent */
4567 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4570 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4572 TRACE(("In parent shell: child = %d\n", pid));
4574 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4580 if (mode != FORK_NOJOB && jp->jobctl) {
4583 if (jp->nprocs == 0)
4586 pgrp = jp->ps[0].pid;
4587 /* This can fail because we are doing it in the child also */
4591 if (mode == FORK_BG) {
4592 backgndpid = pid; /* set $! */
4593 set_curjob(jp, CUR_RUNNING);
4596 struct procstat *ps = &jp->ps[jp->nprocs++];
4601 if (doing_jobctl && n)
4602 ps->cmd = commandtext(n);
4608 forkshell(struct job *jp, union node *n, int mode)
4612 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4615 TRACE(("Fork failed, errno=%d", errno));
4618 ash_msg_and_raise_error("can't fork");
4621 forkchild(jp, /*n,*/ mode);
4623 forkparent(jp, n, mode, pid);
4628 * Wait for job to finish.
4630 * Under job control we have the problem that while a child process
4631 * is running interrupts generated by the user are sent to the child
4632 * but not to the shell. This means that an infinite loop started by
4633 * an interactive user may be hard to kill. With job control turned off,
4634 * an interactive user may place an interactive program inside a loop.
4635 * If the interactive program catches interrupts, the user doesn't want
4636 * these interrupts to also abort the loop. The approach we take here
4637 * is to have the shell ignore interrupt signals while waiting for a
4638 * foreground process to terminate, and then send itself an interrupt
4639 * signal if the child process was terminated by an interrupt signal.
4640 * Unfortunately, some programs want to do a bit of cleanup and then
4641 * exit on interrupt; unless these processes terminate themselves by
4642 * sending a signal to themselves (instead of calling exit) they will
4643 * confuse this approach.
4645 * Called with interrupts off.
4648 waitforjob(struct job *jp)
4652 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4655 while (jp->state == JOBRUNNING) {
4656 /* In non-interactive shells, we _can_ get
4657 * a keyboard signal here and be EINTRed,
4658 * but we just loop back, waiting for command to complete.
4661 * "If bash is waiting for a command to complete and receives
4662 * a signal for which a trap has been set, the trap
4663 * will not be executed until the command completes."
4665 * Reality is that even if trap is not set, bash
4666 * will not act on the signal until command completes.
4667 * Try this. sleep5intoff.c:
4668 * #include <signal.h>
4669 * #include <unistd.h>
4672 * sigemptyset(&set);
4673 * sigaddset(&set, SIGINT);
4674 * sigaddset(&set, SIGQUIT);
4675 * sigprocmask(SIG_BLOCK, &set, NULL);
4679 * $ bash -c './sleep5intoff; echo hi'
4680 * ^C^C^C^C <--- pressing ^C once a second
4682 * $ bash -c './sleep5intoff; echo hi'
4683 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4686 dowait(DOWAIT_BLOCK, jp);
4693 xtcsetpgrp(ttyfd, rootpid);
4695 * This is truly gross.
4696 * If we're doing job control, then we did a TIOCSPGRP which
4697 * caused us (the shell) to no longer be in the controlling
4698 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4699 * intuit from the subprocess exit status whether a SIGINT
4700 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4702 if (jp->sigint) /* TODO: do the same with all signals */
4703 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4705 if (jp->state == JOBDONE)
4712 * return 1 if there are stopped jobs, otherwise 0
4724 if (jp && jp->state == JOBSTOPPED) {
4725 out2str("You have stopped jobs.\n");
4734 /* ============ redir.c
4736 * Code for dealing with input/output redirection.
4739 #define EMPTY -2 /* marks an unused slot in redirtab */
4740 #define CLOSED -3 /* marks a slot of previously-closed fd */
4743 * Open a file in noclobber mode.
4744 * The code was copied from bash.
4747 noclobberopen(const char *fname)
4750 struct stat finfo, finfo2;
4753 * If the file exists and is a regular file, return an error
4756 r = stat(fname, &finfo);
4757 if (r == 0 && S_ISREG(finfo.st_mode)) {
4763 * If the file was not present (r != 0), make sure we open it
4764 * exclusively so that if it is created before we open it, our open
4765 * will fail. Make sure that we do not truncate an existing file.
4766 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4767 * file was not a regular file, we leave O_EXCL off.
4770 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4771 fd = open(fname, O_WRONLY|O_CREAT, 0666);
4773 /* If the open failed, return the file descriptor right away. */
4778 * OK, the open succeeded, but the file may have been changed from a
4779 * non-regular file to a regular file between the stat and the open.
4780 * We are assuming that the O_EXCL open handles the case where FILENAME
4781 * did not exist and is symlinked to an existing file between the stat
4786 * If we can open it and fstat the file descriptor, and neither check
4787 * revealed that it was a regular file, and the file has not been
4788 * replaced, return the file descriptor.
4790 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4791 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4794 /* The file has been replaced. badness. */
4801 * Handle here documents. Normally we fork off a process to write the
4802 * data to a pipe. If the document is short, we can stuff the data in
4803 * the pipe without forking.
4805 /* openhere needs this forward reference */
4806 static void expandhere(union node *arg, int fd);
4808 openhere(union node *redir)
4814 ash_msg_and_raise_error("pipe call failed");
4815 if (redir->type == NHERE) {
4816 len = strlen(redir->nhere.doc->narg.text);
4817 if (len <= PIPE_BUF) {
4818 full_write(pip[1], redir->nhere.doc->narg.text, len);
4822 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4825 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
4826 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
4827 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
4828 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
4829 signal(SIGPIPE, SIG_DFL);
4830 if (redir->type == NHERE)
4831 full_write(pip[1], redir->nhere.doc->narg.text, len);
4833 expandhere(redir->nhere.doc, pip[1]);
4834 _exit(EXIT_SUCCESS);
4842 openredirect(union node *redir)
4847 switch (redir->nfile.type) {
4849 fname = redir->nfile.expfname;
4850 f = open(fname, O_RDONLY);
4855 fname = redir->nfile.expfname;
4856 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
4861 #if ENABLE_ASH_BASH_COMPAT
4864 /* Take care of noclobber mode. */
4866 fname = redir->nfile.expfname;
4867 f = noclobberopen(fname);
4874 fname = redir->nfile.expfname;
4875 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4880 fname = redir->nfile.expfname;
4881 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4889 /* Fall through to eliminate warning. */
4890 /* Our single caller does this itself */
4897 f = openhere(redir);
4903 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4905 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
4909 * Copy a file descriptor to be >= to. Returns -1
4910 * if the source file descriptor is closed, EMPTY if there are no unused
4911 * file descriptors left.
4913 /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
4914 * old code was doing close(to) prior to copyfd() to achieve the same */
4916 COPYFD_EXACT = (int)~(INT_MAX),
4917 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
4920 copyfd(int from, int to)
4924 if (to & COPYFD_EXACT) {
4925 to &= ~COPYFD_EXACT;
4927 newfd = dup2(from, to);
4929 newfd = fcntl(from, F_DUPFD, to);
4932 if (errno == EMFILE)
4934 /* Happens when source fd is not open: try "echo >&99" */
4935 ash_msg_and_raise_error("%d: %m", from);
4940 /* Struct def and variable are moved down to the first usage site */
4945 struct redirtab *next;
4948 struct two_fd_t two_fd[0];
4950 #define redirlist (G_var.redirlist)
4952 static int need_to_remember(struct redirtab *rp, int fd)
4956 if (!rp) /* remembering was not requested */
4959 for (i = 0; i < rp->pair_count; i++) {
4960 if (rp->two_fd[i].orig == fd) {
4961 /* already remembered */
4968 /* "hidden" fd is a fd used to read scripts, or a copy of such */
4969 static int is_hidden_fd(struct redirtab *rp, int fd)
4972 struct parsefile *pf;
4985 fd |= COPYFD_RESTORE;
4986 for (i = 0; i < rp->pair_count; i++) {
4987 if (rp->two_fd[i].copy == fd) {
4995 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
4996 * old file descriptors are stashed away so that the redirection can be
4997 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
4998 * standard output, and the standard error if it becomes a duplicate of
4999 * stdout, is saved in memory.
5001 /* flags passed to redirect */
5002 #define REDIR_PUSH 01 /* save previous values of file descriptors */
5003 #define REDIR_SAVEFD2 03 /* set preverrout */
5005 redirect(union node *redir, int flags)
5007 struct redirtab *sv;
5012 int copied_fd2 = -1;
5022 if (flags & REDIR_PUSH) {
5023 union node *tmp = redir;
5026 #if ENABLE_ASH_BASH_COMPAT
5027 if (redir->nfile.type == NTO2)
5030 tmp = tmp->nfile.next;
5032 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
5033 sv->next = redirlist;
5034 sv->pair_count = sv_pos;
5036 sv->nullredirs = g_nullredirs - 1;
5038 while (sv_pos > 0) {
5040 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5045 fd = redir->nfile.fd;
5046 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5047 int right_fd = redir->ndup.dupfd;
5048 /* redirect from/to same file descriptor? */
5051 /* echo >&10 and 10 is a fd opened to the sh script? */
5052 if (is_hidden_fd(sv, right_fd)) {
5053 errno = EBADF; /* as if it is closed */
5054 ash_msg_and_raise_error("%d: %m", right_fd);
5058 newfd = openredirect(redir); /* always >= 0 */
5060 /* Descriptor wasn't open before redirect.
5061 * Mark it for close in the future */
5062 if (need_to_remember(sv, fd)) {
5063 goto remember_to_close;
5068 #if ENABLE_ASH_BASH_COMPAT
5071 if (need_to_remember(sv, fd)) {
5072 /* Copy old descriptor */
5073 i = fcntl(fd, F_DUPFD, 10);
5074 /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5075 * are closed in popredir() in the child, preventing them from leaking
5076 * into child. (popredir() also cleans up the mess in case of failures)
5081 /* Strange error (e.g. "too many files" EMFILE?) */
5085 ash_msg_and_raise_error("%d: %m", fd);
5088 /* EBADF: it is not open - good, remember to close it */
5091 } else { /* fd is open, save its copy */
5092 /* "exec fd>&-" should not close fds
5093 * which point to script file(s).
5094 * Force them to be restored afterwards */
5095 if (is_hidden_fd(sv, fd))
5096 i |= COPYFD_RESTORE;
5100 sv->two_fd[sv_pos].orig = fd;
5101 sv->two_fd[sv_pos].copy = i;
5105 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5106 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5109 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
5111 } else if (fd != newfd) { /* move newfd to fd */
5112 copyfd(newfd, fd | COPYFD_EXACT);
5113 #if ENABLE_ASH_BASH_COMPAT
5114 if (!(redir->nfile.type == NTO2 && fd == 2))
5118 #if ENABLE_ASH_BASH_COMPAT
5119 if (redir->nfile.type == NTO2 && fd == 1) {
5120 /* We already redirected it to fd 1, now copy it to 2 */
5126 } while ((redir = redir->nfile.next) != NULL);
5129 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5130 preverrout_fd = copied_fd2;
5134 * Undo the effects of the last redirection.
5137 popredir(int drop, int restore)
5139 struct redirtab *rp;
5142 if (--g_nullredirs >= 0)
5146 for (i = 0; i < rp->pair_count; i++) {
5147 int fd = rp->two_fd[i].orig;
5148 int copy = rp->two_fd[i].copy;
5149 if (copy == CLOSED) {
5154 if (copy != EMPTY) {
5155 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5156 copy &= ~COPYFD_RESTORE;
5158 copyfd(copy, fd | COPYFD_EXACT);
5163 redirlist = rp->next;
5164 g_nullredirs = rp->nullredirs;
5170 * Undo all redirections. Called on error or interrupt.
5174 * Discard all saved file descriptors.
5177 clearredir(int drop)
5183 popredir(drop, /*restore:*/ 0);
5188 redirectsafe(union node *redir, int flags)
5191 volatile int saveint;
5192 struct jmploc *volatile savehandler = exception_handler;
5193 struct jmploc jmploc;
5196 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5197 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5199 exception_handler = &jmploc;
5200 redirect(redir, flags);
5202 exception_handler = savehandler;
5203 if (err && exception_type != EXERROR)
5204 longjmp(exception_handler->loc, 1);
5205 RESTORE_INT(saveint);
5210 /* ============ Routines to expand arguments to commands
5212 * We have to deal with backquotes, shell variables, and file metacharacters.
5215 #if ENABLE_ASH_MATH_SUPPORT_64
5216 typedef int64_t arith_t;
5217 #define arith_t_type long long
5219 typedef long arith_t;
5220 #define arith_t_type long
5223 #if ENABLE_ASH_MATH_SUPPORT
5224 static arith_t dash_arith(const char *);
5225 static arith_t arith(const char *expr, int *perrcode);
5231 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5232 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5233 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5234 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5235 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5236 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5237 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5238 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5239 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5243 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5244 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5245 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5246 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5247 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5250 * Structure specifying which parts of the string should be searched
5251 * for IFS characters.
5254 struct ifsregion *next; /* next region in list */
5255 int begoff; /* offset of start of region */
5256 int endoff; /* offset of end of region */
5257 int nulonly; /* search for nul bytes only */
5261 struct strlist *list;
5262 struct strlist **lastp;
5265 /* output of current string */
5266 static char *expdest;
5267 /* list of back quote expressions */
5268 static struct nodelist *argbackq;
5269 /* first struct in list of ifs regions */
5270 static struct ifsregion ifsfirst;
5271 /* last struct in list */
5272 static struct ifsregion *ifslastp;
5273 /* holds expanded arg list */
5274 static struct arglist exparg;
5284 expdest = makestrspace(32, expdest);
5285 #if ENABLE_ASH_MATH_SUPPORT_64
5286 len = fmtstr(expdest, 32, "%lld", (long long) num);
5288 len = fmtstr(expdest, 32, "%ld", num);
5290 STADJUST(len, expdest);
5295 esclen(const char *start, const char *p)
5299 while (p > start && *--p == CTLESC) {
5306 * Remove any CTLESC characters from a string.
5309 _rmescapes(char *str, int flag)
5311 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5318 p = strpbrk(str, qchars);
5324 if (flag & RMESCAPE_ALLOC) {
5325 size_t len = p - str;
5326 size_t fulllen = len + strlen(p) + 1;
5328 if (flag & RMESCAPE_GROW) {
5329 r = makestrspace(fulllen, expdest);
5330 } else if (flag & RMESCAPE_HEAP) {
5331 r = ckmalloc(fulllen);
5333 r = stalloc(fulllen);
5337 q = (char *)memcpy(q, str, len) + len;
5340 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5341 globbing = flag & RMESCAPE_GLOB;
5342 notescaped = globbing;
5344 if (*p == CTLQUOTEMARK) {
5345 inquotes = ~inquotes;
5347 notescaped = globbing;
5351 /* naked back slash */
5357 if (notescaped && inquotes && *p != '/') {
5361 notescaped = globbing;
5366 if (flag & RMESCAPE_GROW) {
5368 STADJUST(q - r + 1, expdest);
5372 #define rmescapes(p) _rmescapes((p), 0)
5374 #define pmatch(a, b) !fnmatch((a), (b), 0)
5377 * Prepare a pattern for a expmeta (internal glob(3)) call.
5379 * Returns an stalloced string.
5382 preglob(const char *pattern, int quoted, int flag)
5384 flag |= RMESCAPE_GLOB;
5386 flag |= RMESCAPE_QUOTED;
5388 return _rmescapes((char *)pattern, flag);
5392 * Put a string on the stack.
5395 memtodest(const char *p, size_t len, int syntax, int quotes)
5399 q = makestrspace(len * 2, q);
5402 int c = signed_char2int(*p++);
5405 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5414 strtodest(const char *p, int syntax, int quotes)
5416 memtodest(p, strlen(p), syntax, quotes);
5420 * Record the fact that we have to scan this region of the
5421 * string for IFS characters.
5424 recordregion(int start, int end, int nulonly)
5426 struct ifsregion *ifsp;
5428 if (ifslastp == NULL) {
5432 ifsp = ckzalloc(sizeof(*ifsp));
5433 /*ifsp->next = NULL; - ckzalloc did it */
5434 ifslastp->next = ifsp;
5438 ifslastp->begoff = start;
5439 ifslastp->endoff = end;
5440 ifslastp->nulonly = nulonly;
5444 removerecordregions(int endoff)
5446 if (ifslastp == NULL)
5449 if (ifsfirst.endoff > endoff) {
5450 while (ifsfirst.next != NULL) {
5451 struct ifsregion *ifsp;
5453 ifsp = ifsfirst.next->next;
5454 free(ifsfirst.next);
5455 ifsfirst.next = ifsp;
5458 if (ifsfirst.begoff > endoff)
5461 ifslastp = &ifsfirst;
5462 ifsfirst.endoff = endoff;
5467 ifslastp = &ifsfirst;
5468 while (ifslastp->next && ifslastp->next->begoff < endoff)
5469 ifslastp=ifslastp->next;
5470 while (ifslastp->next != NULL) {
5471 struct ifsregion *ifsp;
5473 ifsp = ifslastp->next->next;
5474 free(ifslastp->next);
5475 ifslastp->next = ifsp;
5478 if (ifslastp->endoff > endoff)
5479 ifslastp->endoff = endoff;
5483 exptilde(char *startp, char *p, int flag)
5489 int quotes = flag & (EXP_FULL | EXP_CASE);
5494 while ((c = *++p) != '\0') {
5501 if (flag & EXP_VARTILDE)
5511 if (*name == '\0') {
5512 home = lookupvar(homestr);
5514 pw = getpwnam(name);
5519 if (!home || !*home)
5522 startloc = expdest - (char *)stackblock();
5523 strtodest(home, SQSYNTAX, quotes);
5524 recordregion(startloc, expdest - (char *)stackblock(), 0);
5532 * Execute a command inside back quotes. If it's a builtin command, we
5533 * want to save its output in a block obtained from malloc. Otherwise
5534 * we fork off a subprocess and get the output of the command via a pipe.
5535 * Should be called with interrupts off.
5537 struct backcmd { /* result of evalbackcmd */
5538 int fd; /* file descriptor to read from */
5539 int nleft; /* number of chars in buffer */
5540 char *buf; /* buffer */
5541 struct job *jp; /* job structure for command */
5544 /* These forward decls are needed to use "eval" code for backticks handling: */
5545 static uint8_t back_exitstatus; /* exit status of backquoted command */
5546 #define EV_EXIT 01 /* exit after evaluating tree */
5547 static void evaltree(union node *, int);
5550 evalbackcmd(union node *n, struct backcmd *result)
5561 saveherefd = herefd;
5569 ash_msg_and_raise_error("pipe call failed");
5570 jp = makejob(/*n,*/ 1);
5571 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5576 copyfd(pip[1], 1 | COPYFD_EXACT);
5580 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5584 result->fd = pip[0];
5587 herefd = saveherefd;
5589 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5590 result->fd, result->buf, result->nleft, result->jp));
5594 * Expand stuff in backwards quotes.
5597 expbackq(union node *cmd, int quoted, int quotes)
5605 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
5606 struct stackmark smark;
5609 setstackmark(&smark);
5611 startloc = dest - (char *)stackblock();
5613 evalbackcmd(cmd, &in);
5614 popstackmark(&smark);
5621 memtodest(p, i, syntax, quotes);
5625 i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5626 TRACE(("expbackq: read returns %d\n", i));
5635 back_exitstatus = waitforjob(in.jp);
5639 /* Eat all trailing newlines */
5641 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5646 recordregion(startloc, dest - (char *)stackblock(), 0);
5647 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5648 (dest - (char *)stackblock()) - startloc,
5649 (dest - (char *)stackblock()) - startloc,
5650 stackblock() + startloc));
5653 #if ENABLE_ASH_MATH_SUPPORT
5655 * Expand arithmetic expression. Backup to start of expression,
5656 * evaluate, place result in (backed up) result, adjust string position.
5669 * This routine is slightly over-complicated for
5670 * efficiency. Next we scan backwards looking for the
5671 * start of arithmetic.
5673 start = stackblock();
5680 while (*p != CTLARI) {
5684 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5689 esc = esclen(start, p);
5699 removerecordregions(begoff);
5708 len = cvtnum(dash_arith(p + 2));
5711 recordregion(begoff, begoff + len, 0);
5715 /* argstr needs it */
5716 static char *evalvar(char *p, int flag, struct strlist *var_str_list);
5719 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5720 * characters to allow for further processing. Otherwise treat
5721 * $@ like $* since no splitting will be performed.
5723 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5724 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5725 * for correct expansion of "B=$A" word.
5728 argstr(char *p, int flag, struct strlist *var_str_list)
5730 static const char spclchars[] ALIGN1 = {
5738 CTLBACKQ | CTLQUOTE,
5739 #if ENABLE_ASH_MATH_SUPPORT
5744 const char *reject = spclchars;
5746 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
5747 int breakall = flag & EXP_WORD;
5752 if (!(flag & EXP_VARTILDE)) {
5754 } else if (flag & EXP_VARTILDE2) {
5759 if (flag & EXP_TILDE) {
5765 if (*q == CTLESC && (flag & EXP_QWORD))
5768 p = exptilde(p, q, flag);
5771 startloc = expdest - (char *)stackblock();
5773 length += strcspn(p + length, reject);
5775 if (c && (!(c & 0x80)
5776 #if ENABLE_ASH_MATH_SUPPORT
5780 /* c == '=' || c == ':' || c == CTLENDARI */
5785 expdest = stack_nputstr(p, length, expdest);
5786 newloc = expdest - (char *)stackblock();
5787 if (breakall && !inquotes && newloc > startloc) {
5788 recordregion(startloc, newloc, 0);
5799 if (flag & EXP_VARTILDE2) {
5803 flag |= EXP_VARTILDE2;
5808 * sort of a hack - expand tildes in variable
5809 * assignments (after the first '=' and after ':'s).
5818 case CTLENDVAR: /* ??? */
5821 /* "$@" syntax adherence hack */
5824 !memcmp(p, dolatstr, 4) &&
5825 (p[4] == CTLQUOTEMARK || (
5826 p[4] == CTLENDVAR &&
5827 p[5] == CTLQUOTEMARK
5830 p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;
5833 inquotes = !inquotes;
5846 p = evalvar(p, flag, var_str_list);
5850 case CTLBACKQ|CTLQUOTE:
5851 expbackq(argbackq->n, c, quotes);
5852 argbackq = argbackq->next;
5854 #if ENABLE_ASH_MATH_SUPPORT
5867 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int quotes,
5870 // This commented out code was added by James Simmons <jsimmons@infradead.org>
5871 // as part of a larger change when he added support for ${var/a/b}.
5872 // However, it broke # and % operators:
5876 //echo ${var#ab} abcdcd abcdcd
5877 //echo ${var##ab} abcdcd abcdcd
5878 //echo ${var#a*b} abcdcd ababcdcd (!)
5879 //echo ${var##a*b} cdcd cdcd
5880 //echo ${var#?} babcdcd ababcdcd (!)
5881 //echo ${var##?} babcdcd babcdcd
5882 //echo ${var#*} ababcdcd babcdcd (!)
5884 //echo ${var%cd} ababcd ababcd
5885 //echo ${var%%cd} ababcd abab (!)
5886 //echo ${var%c*d} ababcd ababcd
5887 //echo ${var%%c*d} abab ababcdcd (!)
5888 //echo ${var%?} ababcdc ababcdc
5889 //echo ${var%%?} ababcdc ababcdcd (!)
5890 //echo ${var%*} ababcdcd ababcdcd
5893 // Commenting it back out helped. Remove it completely if it really
5896 char *loc, *loc2; //, *full;
5902 int match; // = strlen(str);
5903 const char *s = loc2;
5910 match = pmatch(str, s); // this line was deleted
5912 // // chop off end if its '*'
5913 // full = strrchr(str, '*');
5914 // if (full && full != str)
5917 // // If str starts with '*' replace with s.
5918 // if ((*str == '*') && strlen(s) >= match) {
5919 // full = xstrdup(s);
5920 // strncpy(full+strlen(s)-match+1, str+1, match-1);
5922 // full = xstrndup(str, match);
5923 // match = strncmp(s, full, strlen(full));
5927 if (match) // if (!match)
5929 if (quotes && *loc == CTLESC)
5938 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5945 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5948 const char *s = loc2;
5953 match = pmatch(str, s);
5960 esc = esclen(startp, loc);
5971 static void varunset(const char *, const char *, const char *, int) NORETURN;
5973 varunset(const char *end, const char *var, const char *umsg, int varflags)
5979 msg = "parameter not set";
5981 if (*end == CTLENDVAR) {
5982 if (varflags & VSNUL)
5988 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5991 #if ENABLE_ASH_BASH_COMPAT
5993 parse_sub_pattern(char *arg, int inquotes)
5995 char *idx, *repl = NULL;
6004 /* Only the first '/' seen is our separator */
6011 if (!inquotes && c == '\\' && arg[1] == '\\')
6012 arg++; /* skip both \\, not just first one */
6019 #endif /* ENABLE_ASH_BASH_COMPAT */
6022 subevalvar(char *p, char *str, int strloc, int subtype,
6023 int startloc, int varflags, int quotes, struct strlist *var_str_list)
6025 struct nodelist *saveargbackq = argbackq;
6028 char *rmesc, *rmescend;
6029 USE_ASH_BASH_COMPAT(char *repl = NULL;)
6030 USE_ASH_BASH_COMPAT(char null = '\0';)
6031 USE_ASH_BASH_COMPAT(int pos, len, orig_len;)
6032 int saveherefd = herefd;
6033 int amount, workloc, resetloc;
6035 char *(*scan)(char*, char*, char*, char*, int, int);
6038 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
6040 STPUTC('\0', expdest);
6041 herefd = saveherefd;
6042 argbackq = saveargbackq;
6043 startp = (char *)stackblock() + startloc;
6047 setvar(str, startp, 0);
6048 amount = startp - expdest;
6049 STADJUST(amount, expdest);
6052 #if ENABLE_ASH_BASH_COMPAT
6054 loc = str = stackblock() + strloc;
6055 // TODO: number() instead? It does error checking...
6057 len = str - startp - 1;
6059 /* *loc != '\0', guaranteed by parser */
6063 /* We must adjust the length by the number of escapes we find. */
6064 for (ptr = startp; ptr < (str - 1); ptr++) {
6065 if (*ptr == CTLESC) {
6073 if (*loc++ == ':') {
6074 // TODO: number() instead? It does error checking...
6078 while (*loc && *loc != ':')
6081 // TODO: number() instead? It does error checking...
6084 if (pos >= orig_len) {
6088 if (len > (orig_len - pos))
6089 len = orig_len - pos;
6091 for (str = startp; pos; str++, pos--) {
6092 if (quotes && *str == CTLESC)
6095 for (loc = startp; len; len--) {
6096 if (quotes && *str == CTLESC)
6101 amount = loc - expdest;
6102 STADJUST(amount, expdest);
6107 varunset(p, str, startp, varflags);
6110 resetloc = expdest - (char *)stackblock();
6112 /* We'll comeback here if we grow the stack while handling
6113 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6114 * stack will need rebasing, and we'll need to remove our work
6117 USE_ASH_BASH_COMPAT(restart:)
6119 amount = expdest - ((char *)stackblock() + resetloc);
6120 STADJUST(-amount, expdest);
6121 startp = (char *)stackblock() + startloc;
6124 rmescend = (char *)stackblock() + strloc;
6126 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6127 if (rmesc != startp) {
6129 startp = (char *)stackblock() + startloc;
6133 str = (char *)stackblock() + strloc;
6134 preglob(str, varflags & VSQUOTE, 0);
6135 workloc = expdest - (char *)stackblock();
6137 #if ENABLE_ASH_BASH_COMPAT
6138 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6139 char *idx, *end, *restart_detect;
6142 repl = parse_sub_pattern(str, varflags & VSQUOTE);
6147 /* If there's no pattern to match, return the expansion unmolested */
6155 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6157 /* No match, advance */
6158 restart_detect = stackblock();
6159 STPUTC(*idx, expdest);
6160 if (quotes && *idx == CTLESC) {
6163 STPUTC(*idx, expdest);
6165 if (stackblock() != restart_detect)
6173 if (subtype == VSREPLACEALL) {
6175 if (quotes && *idx == CTLESC)
6184 for (loc = repl; *loc; loc++) {
6185 restart_detect = stackblock();
6186 STPUTC(*loc, expdest);
6187 if (stackblock() != restart_detect)
6192 if (subtype == VSREPLACE) {
6194 restart_detect = stackblock();
6195 STPUTC(*idx, expdest);
6196 if (stackblock() != restart_detect)
6205 /* We've put the replaced text into a buffer at workloc, now
6206 * move it to the right place and adjust the stack.
6208 startp = stackblock() + startloc;
6209 STPUTC('\0', expdest);
6210 memmove(startp, stackblock() + workloc, len);
6211 startp[len++] = '\0';
6212 amount = expdest - ((char *)stackblock() + startloc + len - 1);
6213 STADJUST(-amount, expdest);
6216 #endif /* ENABLE_ASH_BASH_COMPAT */
6218 subtype -= VSTRIMRIGHT;
6220 if (subtype < 0 || subtype > 7)
6223 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
6224 zero = subtype >> 1;
6225 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6226 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6228 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6231 memmove(startp, loc, str - loc);
6232 loc = startp + (str - loc) - 1;
6235 amount = loc - expdest;
6236 STADJUST(amount, expdest);
6242 * Add the value of a specialized variable to the stack string.
6245 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6255 int quoted = varflags & VSQUOTE;
6256 int subtype = varflags & VSTYPE;
6257 int quotes = flags & (EXP_FULL | EXP_CASE);
6259 if (quoted && (flags & EXP_FULL))
6260 sep = 1 << CHAR_BIT;
6262 syntax = quoted ? DQSYNTAX : BASESYNTAX;
6271 num = shellparam.nparam;
6281 p = makestrspace(NOPTS, expdest);
6282 for (i = NOPTS - 1; i >= 0; i--) {
6284 USTPUTC(optletters(i), p);
6295 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
6296 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
6302 while ((p = *ap++)) {
6305 partlen = strlen(p);
6308 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6309 memtodest(p, partlen, syntax, quotes);
6315 if (subtype == VSPLUS || subtype == VSLENGTH) {
6336 // TODO: number() instead? It does error checking...
6338 if (num < 0 || num > shellparam.nparam)
6340 p = num ? shellparam.p[num - 1] : arg0;
6343 /* NB: name has form "VAR=..." */
6345 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6346 * which should be considered before we check variables. */
6348 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6352 str = var_str_list->text;
6353 eq = strchr(str, '=');
6354 if (!eq) /* stop at first non-assignment */
6357 if (name_len == (unsigned)(eq - str)
6358 && strncmp(str, name, name_len) == 0) {
6360 /* goto value; - WRONG! */
6361 /* think "A=1 A=2 B=$A" */
6363 var_str_list = var_str_list->next;
6364 } while (var_str_list);
6368 p = lookupvar(name);
6374 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6375 memtodest(p, len, syntax, quotes);
6379 if (subtype == VSPLUS || subtype == VSLENGTH)
6380 STADJUST(-len, expdest);
6385 * Expand a variable, and return a pointer to the next character in the
6389 evalvar(char *p, int flag, struct strlist *var_str_list)
6401 subtype = varflags & VSTYPE;
6402 quoted = varflags & VSQUOTE;
6404 easy = (!quoted || (*var == '@' && shellparam.nparam));
6405 startloc = expdest - (char *)stackblock();
6406 p = strchr(p, '=') + 1;
6409 varlen = varvalue(var, varflags, flag, var_str_list);
6410 if (varflags & VSNUL)
6413 if (subtype == VSPLUS) {
6414 varlen = -1 - varlen;
6418 if (subtype == VSMINUS) {
6422 p, flag | EXP_TILDE |
6423 (quoted ? EXP_QWORD : EXP_WORD),
6433 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6435 if (subevalvar(p, var, /* strloc: */ 0,
6436 subtype, startloc, varflags,
6442 * Remove any recorded regions beyond
6445 removerecordregions(startloc);
6455 if (varlen < 0 && uflag)
6456 varunset(p, var, 0, 0);
6458 if (subtype == VSLENGTH) {
6459 cvtnum(varlen > 0 ? varlen : 0);
6463 if (subtype == VSNORMAL) {
6474 case VSTRIMRIGHTMAX:
6475 #if ENABLE_ASH_BASH_COMPAT
6488 * Terminate the string and start recording the pattern
6491 STPUTC('\0', expdest);
6492 patloc = expdest - (char *)stackblock();
6493 if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6495 /* quotes: */ flag & (EXP_FULL | EXP_CASE),
6498 int amount = expdest - (
6499 (char *)stackblock() + patloc - 1
6501 STADJUST(-amount, expdest);
6503 /* Remove any recorded regions beyond start of variable */
6504 removerecordregions(startloc);
6506 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6510 if (subtype != VSNORMAL) { /* skip to end of alternative */
6516 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6518 argbackq = argbackq->next;
6519 } else if (c == CTLVAR) {
6520 if ((*p++ & VSTYPE) != VSNORMAL)
6522 } else if (c == CTLENDVAR) {
6532 * Break the argument string into pieces based upon IFS and add the
6533 * strings to the argument list. The regions of the string to be
6534 * searched for IFS characters have been stored by recordregion.
6537 ifsbreakup(char *string, struct arglist *arglist)
6539 struct ifsregion *ifsp;
6544 const char *ifs, *realifs;
6549 if (ifslastp != NULL) {
6552 realifs = ifsset() ? ifsval() : defifs;
6555 p = string + ifsp->begoff;
6556 nulonly = ifsp->nulonly;
6557 ifs = nulonly ? nullstr : realifs;
6559 while (p < string + ifsp->endoff) {
6563 if (!strchr(ifs, *p)) {
6568 ifsspc = (strchr(defifs, *p) != NULL);
6569 /* Ignore IFS whitespace at start */
6570 if (q == start && ifsspc) {
6576 sp = stzalloc(sizeof(*sp));
6578 *arglist->lastp = sp;
6579 arglist->lastp = &sp->next;
6583 if (p >= string + ifsp->endoff) {
6589 if (strchr(ifs, *p) == NULL) {
6593 if (strchr(defifs, *p) == NULL) {
6608 } while (ifsp != NULL);
6617 sp = stzalloc(sizeof(*sp));
6619 *arglist->lastp = sp;
6620 arglist->lastp = &sp->next;
6626 struct ifsregion *p;
6631 struct ifsregion *ifsp;
6637 ifsfirst.next = NULL;
6642 * Add a file name to the list.
6645 addfname(const char *name)
6649 sp = stzalloc(sizeof(*sp));
6650 sp->text = ststrdup(name);
6652 exparg.lastp = &sp->next;
6655 static char *expdir;
6658 * Do metacharacter (i.e. *, ?, [...]) expansion.
6661 expmeta(char *enddir, char *name)
6676 for (p = name; *p; p++) {
6677 if (*p == '*' || *p == '?')
6679 else if (*p == '[') {
6686 if (*q == '/' || *q == '\0')
6693 } else if (*p == '\\')
6695 else if (*p == '/') {
6702 if (metaflag == 0) { /* we've reached the end of the file name */
6703 if (enddir != expdir)
6711 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6722 } while (p < start);
6724 if (enddir == expdir) {
6726 } else if (enddir == expdir + 1 && *expdir == '/') {
6735 if (enddir != expdir)
6737 if (*endname == 0) {
6749 while (!intpending && (dp = readdir(dirp)) != NULL) {
6750 if (dp->d_name[0] == '.' && !matchdot)
6752 if (pmatch(start, dp->d_name)) {
6754 strcpy(enddir, dp->d_name);
6757 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6760 expmeta(p, endname);
6769 static struct strlist *
6770 msort(struct strlist *list, int len)
6772 struct strlist *p, *q = NULL;
6773 struct strlist **lpp;
6781 for (n = half; --n >= 0;) {
6785 q->next = NULL; /* terminate first half of list */
6786 q = msort(list, half); /* sort first half of list */
6787 p = msort(p, len - half); /* sort second half */
6790 #if ENABLE_LOCALE_SUPPORT
6791 if (strcoll(p->text, q->text) < 0)
6793 if (strcmp(p->text, q->text) < 0)
6817 * Sort the results of file name expansion. It calculates the number of
6818 * strings to sort and then calls msort (short for merge sort) to do the
6821 static struct strlist *
6822 expsort(struct strlist *str)
6828 for (sp = str; sp; sp = sp->next)
6830 return msort(str, len);
6834 expandmeta(struct strlist *str /*, int flag*/)
6836 static const char metachars[] ALIGN1 = {
6839 /* TODO - EXP_REDIR */
6842 struct strlist **savelastp;
6848 if (!strpbrk(str->text, metachars))
6850 savelastp = exparg.lastp;
6853 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
6855 int i = strlen(str->text);
6856 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
6864 if (exparg.lastp == savelastp) {
6869 *exparg.lastp = str;
6870 rmescapes(str->text);
6871 exparg.lastp = &str->next;
6873 *exparg.lastp = NULL;
6874 *savelastp = sp = expsort(*savelastp);
6875 while (sp->next != NULL)
6877 exparg.lastp = &sp->next;
6884 * Perform variable substitution and command substitution on an argument,
6885 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6886 * perform splitting and file name expansion. When arglist is NULL, perform
6887 * here document expansion.
6890 expandarg(union node *arg, struct arglist *arglist, int flag)
6895 argbackq = arg->narg.backquote;
6896 STARTSTACKSTR(expdest);
6897 ifsfirst.next = NULL;
6899 argstr(arg->narg.text, flag,
6900 /* var_str_list: */ arglist ? arglist->list : NULL);
6901 p = _STPUTC('\0', expdest);
6903 if (arglist == NULL) {
6904 return; /* here document expanded */
6906 p = grabstackstr(p);
6907 exparg.lastp = &exparg.list;
6911 if (flag & EXP_FULL) {
6912 ifsbreakup(p, &exparg);
6913 *exparg.lastp = NULL;
6914 exparg.lastp = &exparg.list;
6915 expandmeta(exparg.list /*, flag*/);
6917 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
6919 sp = stzalloc(sizeof(*sp));
6922 exparg.lastp = &sp->next;
6926 *exparg.lastp = NULL;
6928 *arglist->lastp = exparg.list;
6929 arglist->lastp = exparg.lastp;
6934 * Expand shell variables and backquotes inside a here document.
6937 expandhere(union node *arg, int fd)
6940 expandarg(arg, (struct arglist *)NULL, 0);
6941 full_write(fd, stackblock(), expdest - (char *)stackblock());
6945 * Returns true if the pattern matches the string.
6948 patmatch(char *pattern, const char *string)
6950 return pmatch(preglob(pattern, 0, 0), string);
6954 * See if a pattern matches in a case statement.
6957 casematch(union node *pattern, char *val)
6959 struct stackmark smark;
6962 setstackmark(&smark);
6963 argbackq = pattern->narg.backquote;
6964 STARTSTACKSTR(expdest);
6966 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
6967 /* var_str_list: */ NULL);
6968 STACKSTRNUL(expdest);
6969 result = patmatch(stackblock(), val);
6970 popstackmark(&smark);
6975 /* ============ find_command */
6979 int (*builtin)(int, char **);
6980 /* unsigned flags; */
6982 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
6983 /* "regular" builtins always take precedence over commands,
6984 * regardless of PATH=....%builtin... position */
6985 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
6986 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
6989 smallint cmdtype; /* CMDxxx */
6992 /* index >= 0 for commands without path (slashes) */
6993 /* (TODO: what exactly does the value mean? PATH position?) */
6994 /* index == -1 for commands with slashes */
6995 /* index == (-2 - applet_no) for NOFORK applets */
6996 const struct builtincmd *cmd;
6997 struct funcnode *func;
7000 /* values of cmdtype */
7001 #define CMDUNKNOWN -1 /* no entry in table for command */
7002 #define CMDNORMAL 0 /* command is an executable program */
7003 #define CMDFUNCTION 1 /* command is a shell function */
7004 #define CMDBUILTIN 2 /* command is a shell builtin */
7006 /* action to find_command() */
7007 #define DO_ERR 0x01 /* prints errors */
7008 #define DO_ABS 0x02 /* checks absolute paths */
7009 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7010 #define DO_ALTPATH 0x08 /* using alternate path */
7011 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7013 static void find_command(char *, struct cmdentry *, int, const char *);
7016 /* ============ Hashing commands */
7019 * When commands are first encountered, they are entered in a hash table.
7020 * This ensures that a full path search will not have to be done for them
7021 * on each invocation.
7023 * We should investigate converting to a linear search, even though that
7024 * would make the command name "hash" a misnomer.
7028 struct tblentry *next; /* next entry in hash chain */
7029 union param param; /* definition of builtin function */
7030 smallint cmdtype; /* CMDxxx */
7031 char rehash; /* if set, cd done since entry created */
7032 char cmdname[1]; /* name of command */
7035 static struct tblentry **cmdtable;
7036 #define INIT_G_cmdtable() do { \
7037 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7040 static int builtinloc = -1; /* index in path of %builtin, or -1 */
7044 tryexec(USE_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
7048 #if ENABLE_FEATURE_SH_STANDALONE
7049 if (applet_no >= 0) {
7050 if (APPLET_IS_NOEXEC(applet_no)) {
7053 run_applet_no_and_exit(applet_no, argv);
7055 /* re-exec ourselves with the new arguments */
7056 execve(bb_busybox_exec_path, argv, envp);
7057 /* If they called chroot or otherwise made the binary no longer
7058 * executable, fall through */
7065 execve(cmd, argv, envp);
7066 } while (errno == EINTR);
7068 execve(cmd, argv, envp);
7074 if (errno == ENOEXEC) {
7078 for (ap = argv; *ap; ap++)
7080 ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0]));
7082 ap[0] = cmd = (char *)DEFAULT_SHELL;
7085 while ((*ap++ = *argv++) != NULL)
7094 * Exec a program. Never returns. If you change this routine, you may
7095 * have to change the find_command routine as well.
7097 static void shellexec(char **, const char *, int) NORETURN;
7099 shellexec(char **argv, const char *path, int idx)
7105 #if ENABLE_FEATURE_SH_STANDALONE
7109 clearredir(/*drop:*/ 1);
7110 envp = listvars(VEXPORT, VUNSET, 0);
7111 if (strchr(argv[0], '/') != NULL
7112 #if ENABLE_FEATURE_SH_STANDALONE
7113 || (applet_no = find_applet_by_name(argv[0])) >= 0
7116 tryexec(USE_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7120 while ((cmdname = padvance(&path, argv[0])) != NULL) {
7121 if (--idx < 0 && pathopt == NULL) {
7122 tryexec(USE_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7123 if (errno != ENOENT && errno != ENOTDIR)
7130 /* Map to POSIX errors */
7142 exitstatus = exerrno;
7143 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
7144 argv[0], e, suppressint));
7145 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7150 printentry(struct tblentry *cmdp)
7156 idx = cmdp->param.index;
7159 name = padvance(&path, cmdp->cmdname);
7161 } while (--idx >= 0);
7162 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7166 * Clear out command entries. The argument specifies the first entry in
7167 * PATH which has changed.
7170 clearcmdentry(int firstchange)
7172 struct tblentry **tblp;
7173 struct tblentry **pp;
7174 struct tblentry *cmdp;
7177 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7179 while ((cmdp = *pp) != NULL) {
7180 if ((cmdp->cmdtype == CMDNORMAL &&
7181 cmdp->param.index >= firstchange)
7182 || (cmdp->cmdtype == CMDBUILTIN &&
7183 builtinloc >= firstchange)
7196 * Locate a command in the command hash table. If "add" is nonzero,
7197 * add the command to the table if it is not already present. The
7198 * variable "lastcmdentry" is set to point to the address of the link
7199 * pointing to the entry, so that delete_cmd_entry can delete the
7202 * Interrupts must be off if called with add != 0.
7204 static struct tblentry **lastcmdentry;
7206 static struct tblentry *
7207 cmdlookup(const char *name, int add)
7209 unsigned int hashval;
7211 struct tblentry *cmdp;
7212 struct tblentry **pp;
7215 hashval = (unsigned char)*p << 4;
7217 hashval += (unsigned char)*p++;
7219 pp = &cmdtable[hashval % CMDTABLESIZE];
7220 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7221 if (strcmp(cmdp->cmdname, name) == 0)
7225 if (add && cmdp == NULL) {
7226 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7228 /* + 1 - already done because
7229 * tblentry::cmdname is char[1] */);
7230 /*cmdp->next = NULL; - ckzalloc did it */
7231 cmdp->cmdtype = CMDUNKNOWN;
7232 strcpy(cmdp->cmdname, name);
7239 * Delete the command entry returned on the last lookup.
7242 delete_cmd_entry(void)
7244 struct tblentry *cmdp;
7247 cmdp = *lastcmdentry;
7248 *lastcmdentry = cmdp->next;
7249 if (cmdp->cmdtype == CMDFUNCTION)
7250 freefunc(cmdp->param.func);
7256 * Add a new command entry, replacing any existing command entry for
7257 * the same name - except special builtins.
7260 addcmdentry(char *name, struct cmdentry *entry)
7262 struct tblentry *cmdp;
7264 cmdp = cmdlookup(name, 1);
7265 if (cmdp->cmdtype == CMDFUNCTION) {
7266 freefunc(cmdp->param.func);
7268 cmdp->cmdtype = entry->cmdtype;
7269 cmdp->param = entry->u;
7274 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7276 struct tblentry **pp;
7277 struct tblentry *cmdp;
7279 struct cmdentry entry;
7282 if (nextopt("r") != '\0') {
7287 if (*argptr == NULL) {
7288 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7289 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7290 if (cmdp->cmdtype == CMDNORMAL)
7298 while ((name = *argptr) != NULL) {
7299 cmdp = cmdlookup(name, 0);
7301 && (cmdp->cmdtype == CMDNORMAL
7302 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7306 find_command(name, &entry, DO_ERR, pathval());
7307 if (entry.cmdtype == CMDUNKNOWN)
7315 * Called when a cd is done. Marks all commands so the next time they
7316 * are executed they will be rehashed.
7321 struct tblentry **pp;
7322 struct tblentry *cmdp;
7324 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7325 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7326 if (cmdp->cmdtype == CMDNORMAL
7327 || (cmdp->cmdtype == CMDBUILTIN
7328 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7338 * Fix command hash table when PATH changed.
7339 * Called before PATH is changed. The argument is the new value of PATH;
7340 * pathval() still returns the old value at this point.
7341 * Called with interrupts off.
7344 changepath(const char *new)
7352 firstchange = 9999; /* assume no change */
7358 if ((*old == '\0' && *new == ':')
7359 || (*old == ':' && *new == '\0'))
7361 old = new; /* ignore subsequent differences */
7365 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7371 if (builtinloc < 0 && idx_bltin >= 0)
7372 builtinloc = idx_bltin; /* zap builtins */
7373 if (builtinloc >= 0 && idx_bltin < 0)
7375 clearcmdentry(firstchange);
7376 builtinloc = idx_bltin;
7391 #define TENDBQUOTE 12
7408 typedef smallint token_id_t;
7410 /* first char is indicating which tokens mark the end of a list */
7411 static const char *const tokname_array[] = {
7425 #define KWDOFFSET 13
7426 /* the following are keywords */
7448 static char buf[16];
7451 //if (tok < TSEMI) return tokname_array[tok] + 1;
7452 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
7457 sprintf(buf + (tok >= TSEMI), "%s%c",
7458 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
7462 /* Wrapper around strcmp for qsort/bsearch/... */
7464 pstrcmp(const void *a, const void *b)
7466 return strcmp((char*) a, (*(char**) b) + 1);
7469 static const char *const *
7470 findkwd(const char *s)
7472 return bsearch(s, tokname_array + KWDOFFSET,
7473 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7474 sizeof(tokname_array[0]), pstrcmp);
7478 * Locate and print what a word is...
7481 describe_command(char *command, int describe_command_verbose)
7483 struct cmdentry entry;
7484 struct tblentry *cmdp;
7485 #if ENABLE_ASH_ALIAS
7486 const struct alias *ap;
7488 const char *path = pathval();
7490 if (describe_command_verbose) {
7494 /* First look at the keywords */
7495 if (findkwd(command)) {
7496 out1str(describe_command_verbose ? " is a shell keyword" : command);
7500 #if ENABLE_ASH_ALIAS
7501 /* Then look at the aliases */
7502 ap = lookupalias(command, 0);
7504 if (!describe_command_verbose) {
7509 out1fmt(" is an alias for %s", ap->val);
7513 /* Then check if it is a tracked alias */
7514 cmdp = cmdlookup(command, 0);
7516 entry.cmdtype = cmdp->cmdtype;
7517 entry.u = cmdp->param;
7519 /* Finally use brute force */
7520 find_command(command, &entry, DO_ABS, path);
7523 switch (entry.cmdtype) {
7525 int j = entry.u.index;
7531 p = padvance(&path, command);
7535 if (describe_command_verbose) {
7537 (cmdp ? " a tracked alias for" : nullstr), p
7546 if (describe_command_verbose) {
7547 out1str(" is a shell function");
7554 if (describe_command_verbose) {
7555 out1fmt(" is a %sshell builtin",
7556 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7557 "special " : nullstr
7565 if (describe_command_verbose) {
7566 out1str(": not found\n");
7571 outstr("\n", stdout);
7576 typecmd(int argc UNUSED_PARAM, char **argv)
7582 /* type -p ... ? (we don't bother checking for 'p') */
7583 if (argv[1] && argv[1][0] == '-') {
7588 err |= describe_command(argv[i++], verbose);
7593 #if ENABLE_ASH_CMDCMD
7595 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7603 while ((c = nextopt("pvV")) != '\0')
7605 verify |= VERIFY_VERBOSE;
7607 verify |= VERIFY_BRIEF;
7612 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7613 if (verify && (*argptr != NULL)) {
7614 return describe_command(*argptr, verify - VERIFY_BRIEF);
7622 /* ============ eval.c */
7624 static int funcblocksize; /* size of structures in function */
7625 static int funcstringsize; /* size of strings in node */
7626 static void *funcblock; /* block to allocate function from */
7627 static char *funcstring; /* block to allocate strings from */
7629 /* flags in argument to evaltree */
7630 #define EV_EXIT 01 /* exit after evaluating tree */
7631 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7632 #define EV_BACKCMD 04 /* command executing within back quotes */
7634 static const short nodesize[N_NUMBER] = {
7635 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
7636 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
7637 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
7638 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
7639 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
7640 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
7641 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
7642 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
7643 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
7644 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
7645 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
7646 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
7647 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
7648 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
7649 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
7650 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
7651 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
7652 #if ENABLE_ASH_BASH_COMPAT
7653 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
7655 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
7656 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
7657 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
7658 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
7659 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
7660 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
7661 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
7662 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
7663 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
7666 static void calcsize(union node *n);
7669 sizenodelist(struct nodelist *lp)
7672 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7679 calcsize(union node *n)
7683 funcblocksize += nodesize[n->type];
7686 calcsize(n->ncmd.redirect);
7687 calcsize(n->ncmd.args);
7688 calcsize(n->ncmd.assign);
7691 sizenodelist(n->npipe.cmdlist);
7696 calcsize(n->nredir.redirect);
7697 calcsize(n->nredir.n);
7704 calcsize(n->nbinary.ch2);
7705 calcsize(n->nbinary.ch1);
7708 calcsize(n->nif.elsepart);
7709 calcsize(n->nif.ifpart);
7710 calcsize(n->nif.test);
7713 funcstringsize += strlen(n->nfor.var) + 1;
7714 calcsize(n->nfor.body);
7715 calcsize(n->nfor.args);
7718 calcsize(n->ncase.cases);
7719 calcsize(n->ncase.expr);
7722 calcsize(n->nclist.body);
7723 calcsize(n->nclist.pattern);
7724 calcsize(n->nclist.next);
7728 sizenodelist(n->narg.backquote);
7729 funcstringsize += strlen(n->narg.text) + 1;
7730 calcsize(n->narg.next);
7733 #if ENABLE_ASH_BASH_COMPAT
7740 calcsize(n->nfile.fname);
7741 calcsize(n->nfile.next);
7745 calcsize(n->ndup.vname);
7746 calcsize(n->ndup.next);
7750 calcsize(n->nhere.doc);
7751 calcsize(n->nhere.next);
7754 calcsize(n->nnot.com);
7760 nodeckstrdup(char *s)
7762 char *rtn = funcstring;
7764 strcpy(funcstring, s);
7765 funcstring += strlen(s) + 1;
7769 static union node *copynode(union node *);
7771 static struct nodelist *
7772 copynodelist(struct nodelist *lp)
7774 struct nodelist *start;
7775 struct nodelist **lpp;
7780 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7781 (*lpp)->n = copynode(lp->n);
7783 lpp = &(*lpp)->next;
7790 copynode(union node *n)
7797 funcblock = (char *) funcblock + nodesize[n->type];
7801 new->ncmd.redirect = copynode(n->ncmd.redirect);
7802 new->ncmd.args = copynode(n->ncmd.args);
7803 new->ncmd.assign = copynode(n->ncmd.assign);
7806 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7807 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
7812 new->nredir.redirect = copynode(n->nredir.redirect);
7813 new->nredir.n = copynode(n->nredir.n);
7820 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7821 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7824 new->nif.elsepart = copynode(n->nif.elsepart);
7825 new->nif.ifpart = copynode(n->nif.ifpart);
7826 new->nif.test = copynode(n->nif.test);
7829 new->nfor.var = nodeckstrdup(n->nfor.var);
7830 new->nfor.body = copynode(n->nfor.body);
7831 new->nfor.args = copynode(n->nfor.args);
7834 new->ncase.cases = copynode(n->ncase.cases);
7835 new->ncase.expr = copynode(n->ncase.expr);
7838 new->nclist.body = copynode(n->nclist.body);
7839 new->nclist.pattern = copynode(n->nclist.pattern);
7840 new->nclist.next = copynode(n->nclist.next);
7844 new->narg.backquote = copynodelist(n->narg.backquote);
7845 new->narg.text = nodeckstrdup(n->narg.text);
7846 new->narg.next = copynode(n->narg.next);
7849 #if ENABLE_ASH_BASH_COMPAT
7856 new->nfile.fname = copynode(n->nfile.fname);
7857 new->nfile.fd = n->nfile.fd;
7858 new->nfile.next = copynode(n->nfile.next);
7862 new->ndup.vname = copynode(n->ndup.vname);
7863 new->ndup.dupfd = n->ndup.dupfd;
7864 new->ndup.fd = n->ndup.fd;
7865 new->ndup.next = copynode(n->ndup.next);
7869 new->nhere.doc = copynode(n->nhere.doc);
7870 new->nhere.fd = n->nhere.fd;
7871 new->nhere.next = copynode(n->nhere.next);
7874 new->nnot.com = copynode(n->nnot.com);
7877 new->type = n->type;
7882 * Make a copy of a parse tree.
7884 static struct funcnode *
7885 copyfunc(union node *n)
7890 funcblocksize = offsetof(struct funcnode, n);
7893 blocksize = funcblocksize;
7894 f = ckmalloc(blocksize + funcstringsize);
7895 funcblock = (char *) f + offsetof(struct funcnode, n);
7896 funcstring = (char *) f + blocksize;
7903 * Define a shell function.
7906 defun(char *name, union node *func)
7908 struct cmdentry entry;
7911 entry.cmdtype = CMDFUNCTION;
7912 entry.u.func = copyfunc(func);
7913 addcmdentry(name, &entry);
7917 static int evalskip; /* set if we are skipping commands */
7918 /* reasons for skipping commands (see comment on breakcmd routine) */
7919 #define SKIPBREAK (1 << 0)
7920 #define SKIPCONT (1 << 1)
7921 #define SKIPFUNC (1 << 2)
7922 #define SKIPFILE (1 << 3)
7923 #define SKIPEVAL (1 << 4)
7924 static int skipcount; /* number of levels to skip */
7925 static int funcnest; /* depth of function calls */
7926 static int loopnest; /* current loop nesting level */
7928 /* forward decl way out to parsing code - dotrap needs it */
7929 static int evalstring(char *s, int mask);
7932 * Called to execute a trap. Perhaps we should avoid entering new trap
7933 * handlers while we are executing a trap handler.
7944 savestatus = exitstatus;
7948 for (i = 1, q = gotsig; i < NSIG; i++, q++) {
7956 skip = evalstring(p, SKIPEVAL);
7957 exitstatus = savestatus;
7965 /* forward declarations - evaluation is fairly recursive business... */
7966 static void evalloop(union node *, int);
7967 static void evalfor(union node *, int);
7968 static void evalcase(union node *, int);
7969 static void evalsubshell(union node *, int);
7970 static void expredir(union node *);
7971 static void evalpipe(union node *, int);
7972 static void evalcommand(union node *, int);
7973 static int evalbltin(const struct builtincmd *, int, char **);
7974 static void prehash(union node *);
7977 * Evaluate a parse tree. The value is left in the global variable
7981 evaltree(union node *n, int flags)
7983 struct jmploc *volatile savehandler = exception_handler;
7984 struct jmploc jmploc;
7986 void (*evalfn)(union node *, int);
7990 TRACE(("evaltree(NULL) called\n"));
7993 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
7994 getpid(), n, n->type, flags));
7996 exception_handler = &jmploc;
7998 int err = setjmp(jmploc.loc);
8000 /* if it was a signal, check for trap handlers */
8001 if (exception_type == EXSIG)
8003 /* continue on the way out */
8004 exception_handler = savehandler;
8005 longjmp(exception_handler->loc, err);
8012 out1fmt("Node type = %d\n", n->type);
8017 evaltree(n->nnot.com, EV_TESTED);
8018 status = !exitstatus;
8021 expredir(n->nredir.redirect);
8022 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8024 evaltree(n->nredir.n, flags & EV_TESTED);
8025 status = exitstatus;
8027 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
8030 evalfn = evalcommand;
8032 if (eflag && !(flags & EV_TESTED))
8044 evalfn = evalsubshell;
8057 #error NAND + 1 != NOR
8059 #if NOR + 1 != NSEMI
8060 #error NOR + 1 != NSEMI
8062 unsigned is_or = n->type - NAND;
8065 (flags | ((is_or >> 1) - 1)) & EV_TESTED
8067 if (!exitstatus == is_or)
8080 evaltree(n->nif.test, EV_TESTED);
8083 if (exitstatus == 0) {
8086 } else if (n->nif.elsepart) {
8087 n = n->nif.elsepart;
8092 defun(n->narg.text, n->narg.next);
8096 exitstatus = status;
8101 exception_handler = savehandler;
8103 if (checkexit & exitstatus)
8104 evalskip |= SKIPEVAL;
8105 else if (pendingsig && dotrap())
8108 if (flags & EV_EXIT) {
8110 raise_exception(EXEXIT);
8114 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8117 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8120 evalloop(union node *n, int flags)
8130 evaltree(n->nbinary.ch1, EV_TESTED);
8133 if (evalskip == SKIPCONT && --skipcount <= 0) {
8137 if (evalskip == SKIPBREAK && --skipcount <= 0)
8142 if (n->type != NWHILE)
8146 evaltree(n->nbinary.ch2, flags);
8147 status = exitstatus;
8152 exitstatus = status;
8156 evalfor(union node *n, int flags)
8158 struct arglist arglist;
8161 struct stackmark smark;
8163 setstackmark(&smark);
8164 arglist.list = NULL;
8165 arglist.lastp = &arglist.list;
8166 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8167 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
8172 *arglist.lastp = NULL;
8177 for (sp = arglist.list; sp; sp = sp->next) {
8178 setvar(n->nfor.var, sp->text, 0);
8179 evaltree(n->nfor.body, flags);
8181 if (evalskip == SKIPCONT && --skipcount <= 0) {
8185 if (evalskip == SKIPBREAK && --skipcount <= 0)
8192 popstackmark(&smark);
8196 evalcase(union node *n, int flags)
8200 struct arglist arglist;
8201 struct stackmark smark;
8203 setstackmark(&smark);
8204 arglist.list = NULL;
8205 arglist.lastp = &arglist.list;
8206 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8208 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8209 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8210 if (casematch(patp, arglist.list->text)) {
8211 if (evalskip == 0) {
8212 evaltree(cp->nclist.body, flags);
8219 popstackmark(&smark);
8223 * Kick off a subshell to evaluate a tree.
8226 evalsubshell(union node *n, int flags)
8229 int backgnd = (n->type == NBACKGND);
8232 expredir(n->nredir.redirect);
8233 if (!backgnd && flags & EV_EXIT && !trap[0])
8236 jp = makejob(/*n,*/ 1);
8237 if (forkshell(jp, n, backgnd) == 0) {
8241 flags &=~ EV_TESTED;
8243 redirect(n->nredir.redirect, 0);
8244 evaltreenr(n->nredir.n, flags);
8249 status = waitforjob(jp);
8250 exitstatus = status;
8255 * Compute the names of the files in a redirection list.
8257 static void fixredir(union node *, const char *, int);
8259 expredir(union node *n)
8263 for (redir = n; redir; redir = redir->nfile.next) {
8267 fn.lastp = &fn.list;
8268 switch (redir->type) {
8272 #if ENABLE_ASH_BASH_COMPAT
8277 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8278 #if ENABLE_ASH_BASH_COMPAT
8281 redir->nfile.expfname = fn.list->text;
8284 case NTOFD: /* >& */
8285 if (redir->ndup.vname) {
8286 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8287 if (fn.list == NULL)
8288 ash_msg_and_raise_error("redir error");
8289 #if ENABLE_ASH_BASH_COMPAT
8290 //FIXME: we used expandarg with different args!
8291 if (!isdigit_str9(fn.list->text)) {
8292 /* >&file, not >&fd */
8293 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8294 ash_msg_and_raise_error("redir error");
8296 goto store_expfname;
8299 fixredir(redir, fn.list->text, 1);
8307 * Evaluate a pipeline. All the processes in the pipeline are children
8308 * of the process creating the pipeline. (This differs from some versions
8309 * of the shell, which make the last process in a pipeline the parent
8313 evalpipe(union node *n, int flags)
8316 struct nodelist *lp;
8321 TRACE(("evalpipe(0x%lx) called\n", (long)n));
8323 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8327 jp = makejob(/*n,*/ pipelen);
8329 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8333 if (pipe(pip) < 0) {
8335 ash_msg_and_raise_error("pipe call failed");
8338 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8351 evaltreenr(lp->n, flags);
8359 if (n->npipe.pipe_backgnd == 0) {
8360 exitstatus = waitforjob(jp);
8361 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
8367 * Controls whether the shell is interactive or not.
8370 setinteractive(int on)
8372 static smallint is_interactive;
8374 if (++on == is_interactive)
8376 is_interactive = on;
8380 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8381 if (is_interactive > 1) {
8382 /* Looks like they want an interactive shell */
8383 static smallint did_banner;
8388 "%s built-in shell (ash)\n"
8389 "Enter 'help' for a list of built-in commands."
8404 setinteractive(iflag);
8406 #if ENABLE_FEATURE_EDITING_VI
8408 line_input_state->flags |= VI_MODE;
8410 line_input_state->flags &= ~VI_MODE;
8412 viflag = 0; /* forcibly keep the option off */
8416 static struct localvar *localvars;
8419 * Called after a function returns.
8420 * Interrupts must be off.
8425 struct localvar *lvp;
8428 while ((lvp = localvars) != NULL) {
8429 localvars = lvp->next;
8431 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
8432 if (vp == NULL) { /* $- saved */
8433 memcpy(optlist, lvp->text, sizeof(optlist));
8434 free((char*)lvp->text);
8436 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8440 (*vp->func)(strchrnul(lvp->text, '=') + 1);
8441 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8442 free((char*)vp->text);
8443 vp->flags = lvp->flags;
8444 vp->text = lvp->text;
8451 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8453 volatile struct shparam saveparam;
8454 struct localvar *volatile savelocalvars;
8455 struct jmploc *volatile savehandler;
8456 struct jmploc jmploc;
8459 saveparam = shellparam;
8460 savelocalvars = localvars;
8461 e = setjmp(jmploc.loc);
8466 savehandler = exception_handler;
8467 exception_handler = &jmploc;
8469 shellparam.malloced = 0;
8473 shellparam.nparam = argc - 1;
8474 shellparam.p = argv + 1;
8475 #if ENABLE_ASH_GETOPTS
8476 shellparam.optind = 1;
8477 shellparam.optoff = -1;
8479 evaltree(&func->n, flags & EV_TESTED);
8485 localvars = savelocalvars;
8486 freeparam(&shellparam);
8487 shellparam = saveparam;
8488 exception_handler = savehandler;
8490 evalskip &= ~SKIPFUNC;
8494 #if ENABLE_ASH_CMDCMD
8496 parse_command_args(char **argv, const char **path)
8509 if (c == '-' && !*cp) {
8516 *path = bb_default_path;
8519 /* run 'typecmd' for other options */
8530 * Make a variable a local variable. When a variable is made local, it's
8531 * value and flags are saved in a localvar structure. The saved values
8532 * will be restored when the shell function returns. We handle the name
8533 * "-" as a special case.
8538 struct localvar *lvp;
8543 lvp = ckzalloc(sizeof(struct localvar));
8544 if (LONE_DASH(name)) {
8546 p = ckmalloc(sizeof(optlist));
8547 lvp->text = memcpy(p, optlist, sizeof(optlist));
8552 vpp = hashvar(name);
8553 vp = *findvar(vpp, name);
8554 eq = strchr(name, '=');
8557 setvareq(name, VSTRFIXED);
8559 setvar(name, NULL, VSTRFIXED);
8560 vp = *vpp; /* the new variable */
8561 lvp->flags = VUNSET;
8563 lvp->text = vp->text;
8564 lvp->flags = vp->flags;
8565 vp->flags |= VSTRFIXED|VTEXTFIXED;
8571 lvp->next = localvars;
8577 * The "local" command.
8580 localcmd(int argc UNUSED_PARAM, char **argv)
8585 while ((name = *argv++) != NULL) {
8592 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8598 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8604 execcmd(int argc UNUSED_PARAM, char **argv)
8607 iflag = 0; /* exit on error */
8610 shellexec(argv + 1, pathval(), 0);
8616 * The return command.
8619 returncmd(int argc UNUSED_PARAM, char **argv)
8622 * If called outside a function, do what ksh does;
8623 * skip the rest of the file.
8625 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8626 return argv[1] ? number(argv[1]) : exitstatus;
8629 /* Forward declarations for builtintab[] */
8630 static int breakcmd(int, char **);
8631 static int dotcmd(int, char **);
8632 static int evalcmd(int, char **);
8633 static int exitcmd(int, char **);
8634 static int exportcmd(int, char **);
8635 #if ENABLE_ASH_GETOPTS
8636 static int getoptscmd(int, char **);
8638 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8639 static int helpcmd(int, char **);
8641 #if ENABLE_ASH_MATH_SUPPORT
8642 static int letcmd(int, char **);
8644 static int readcmd(int, char **);
8645 static int setcmd(int, char **);
8646 static int shiftcmd(int, char **);
8647 static int timescmd(int, char **);
8648 static int trapcmd(int, char **);
8649 static int umaskcmd(int, char **);
8650 static int unsetcmd(int, char **);
8651 static int ulimitcmd(int, char **);
8653 #define BUILTIN_NOSPEC "0"
8654 #define BUILTIN_SPECIAL "1"
8655 #define BUILTIN_REGULAR "2"
8656 #define BUILTIN_SPEC_REG "3"
8657 #define BUILTIN_ASSIGN "4"
8658 #define BUILTIN_SPEC_ASSG "5"
8659 #define BUILTIN_REG_ASSG "6"
8660 #define BUILTIN_SPEC_REG_ASSG "7"
8662 /* We do not handle [[ expr ]] bashism bash-compatibly,
8663 * we make it a synonym of [ expr ].
8664 * Basically, word splitting and pathname expansion should NOT be performed
8666 * no word splitting: a="a b"; [[ $a = "a b" ]]; echo $? should print "0"
8667 * no pathname expansion: [[ /bin/m* = "/bin/m*" ]]; echo $? should print "0"
8668 * Additional operators:
8669 * || and && should work as -o and -a
8671 * Apart from the above, [[ expr ]] should work as [ expr ]
8674 #define echocmd echo_main
8675 #define printfcmd printf_main
8676 #define testcmd test_main
8678 /* Keep these in proper order since it is searched via bsearch() */
8679 static const struct builtincmd builtintab[] = {
8680 { BUILTIN_SPEC_REG ".", dotcmd },
8681 { BUILTIN_SPEC_REG ":", truecmd },
8682 #if ENABLE_ASH_BUILTIN_TEST
8683 { BUILTIN_REGULAR "[", testcmd },
8684 #if ENABLE_ASH_BASH_COMPAT
8685 { BUILTIN_REGULAR "[[", testcmd },
8688 #if ENABLE_ASH_ALIAS
8689 { BUILTIN_REG_ASSG "alias", aliascmd },
8692 { BUILTIN_REGULAR "bg", fg_bgcmd },
8694 { BUILTIN_SPEC_REG "break", breakcmd },
8695 { BUILTIN_REGULAR "cd", cdcmd },
8696 { BUILTIN_NOSPEC "chdir", cdcmd },
8697 #if ENABLE_ASH_CMDCMD
8698 { BUILTIN_REGULAR "command", commandcmd },
8700 { BUILTIN_SPEC_REG "continue", breakcmd },
8701 #if ENABLE_ASH_BUILTIN_ECHO
8702 { BUILTIN_REGULAR "echo", echocmd },
8704 { BUILTIN_SPEC_REG "eval", evalcmd },
8705 { BUILTIN_SPEC_REG "exec", execcmd },
8706 { BUILTIN_SPEC_REG "exit", exitcmd },
8707 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8708 { BUILTIN_REGULAR "false", falsecmd },
8710 { BUILTIN_REGULAR "fg", fg_bgcmd },
8712 #if ENABLE_ASH_GETOPTS
8713 { BUILTIN_REGULAR "getopts", getoptscmd },
8715 { BUILTIN_NOSPEC "hash", hashcmd },
8716 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8717 { BUILTIN_NOSPEC "help", helpcmd },
8720 { BUILTIN_REGULAR "jobs", jobscmd },
8721 { BUILTIN_REGULAR "kill", killcmd },
8723 #if ENABLE_ASH_MATH_SUPPORT
8724 { BUILTIN_NOSPEC "let", letcmd },
8726 { BUILTIN_ASSIGN "local", localcmd },
8727 #if ENABLE_ASH_BUILTIN_PRINTF
8728 { BUILTIN_REGULAR "printf", printfcmd },
8730 { BUILTIN_NOSPEC "pwd", pwdcmd },
8731 { BUILTIN_REGULAR "read", readcmd },
8732 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8733 { BUILTIN_SPEC_REG "return", returncmd },
8734 { BUILTIN_SPEC_REG "set", setcmd },
8735 { BUILTIN_SPEC_REG "shift", shiftcmd },
8736 { BUILTIN_SPEC_REG "source", dotcmd },
8737 #if ENABLE_ASH_BUILTIN_TEST
8738 { BUILTIN_REGULAR "test", testcmd },
8740 { BUILTIN_SPEC_REG "times", timescmd },
8741 { BUILTIN_SPEC_REG "trap", trapcmd },
8742 { BUILTIN_REGULAR "true", truecmd },
8743 { BUILTIN_NOSPEC "type", typecmd },
8744 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
8745 { BUILTIN_REGULAR "umask", umaskcmd },
8746 #if ENABLE_ASH_ALIAS
8747 { BUILTIN_REGULAR "unalias", unaliascmd },
8749 { BUILTIN_SPEC_REG "unset", unsetcmd },
8750 { BUILTIN_REGULAR "wait", waitcmd },
8753 /* Should match the above table! */
8754 #define COMMANDCMD (builtintab + \
8756 1 * ENABLE_ASH_BUILTIN_TEST + \
8757 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8758 1 * ENABLE_ASH_ALIAS + \
8759 1 * ENABLE_ASH_JOB_CONTROL + \
8761 #define EXECCMD (builtintab + \
8763 1 * ENABLE_ASH_BUILTIN_TEST + \
8764 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8765 1 * ENABLE_ASH_ALIAS + \
8766 1 * ENABLE_ASH_JOB_CONTROL + \
8768 1 * ENABLE_ASH_CMDCMD + \
8770 ENABLE_ASH_BUILTIN_ECHO + \
8774 * Search the table of builtin commands.
8776 static struct builtincmd *
8777 find_builtin(const char *name)
8779 struct builtincmd *bp;
8782 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8789 * Execute a simple command.
8792 isassignment(const char *p)
8794 const char *q = endofname(p);
8800 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8802 /* Preserve exitstatus of a previous possible redirection
8803 * as POSIX mandates */
8804 return back_exitstatus;
8807 evalcommand(union node *cmd, int flags)
8809 static const struct builtincmd null_bltin = {
8810 "\0\0", bltincmd /* why three NULs? */
8812 struct stackmark smark;
8814 struct arglist arglist;
8815 struct arglist varlist;
8818 const struct strlist *sp;
8819 struct cmdentry cmdentry;
8826 struct builtincmd *bcmd;
8827 smallint cmd_is_exec;
8828 smallint pseudovarflag = 0;
8830 /* First expand the arguments. */
8831 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8832 setstackmark(&smark);
8833 back_exitstatus = 0;
8835 cmdentry.cmdtype = CMDBUILTIN;
8836 cmdentry.u.cmd = &null_bltin;
8837 varlist.lastp = &varlist.list;
8838 *varlist.lastp = NULL;
8839 arglist.lastp = &arglist.list;
8840 *arglist.lastp = NULL;
8843 if (cmd->ncmd.args) {
8844 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8845 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8848 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8849 struct strlist **spp;
8851 spp = arglist.lastp;
8852 if (pseudovarflag && isassignment(argp->narg.text))
8853 expandarg(argp, &arglist, EXP_VARTILDE);
8855 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8857 for (sp = *spp; sp; sp = sp->next)
8861 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8862 for (sp = arglist.list; sp; sp = sp->next) {
8863 TRACE(("evalcommand arg: %s\n", sp->text));
8864 *nargv++ = sp->text;
8869 if (iflag && funcnest == 0 && argc > 0)
8870 lastarg = nargv[-1];
8873 expredir(cmd->ncmd.redirect);
8874 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8877 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8878 struct strlist **spp;
8881 spp = varlist.lastp;
8882 expandarg(argp, &varlist, EXP_VARTILDE);
8885 * Modify the command lookup path, if a PATH= assignment
8889 if (varequal(p, path))
8893 /* Print the command if xflag is set. */
8896 const char *p = " %s";
8899 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8902 for (n = 0; n < 2; n++) {
8904 fdprintf(preverrout_fd, p, sp->text);
8912 safe_write(preverrout_fd, "\n", 1);
8918 /* Now locate the command. */
8920 const char *oldpath;
8921 int cmd_flag = DO_ERR;
8926 find_command(argv[0], &cmdentry, cmd_flag, path);
8927 if (cmdentry.cmdtype == CMDUNKNOWN) {
8933 /* implement bltin and command here */
8934 if (cmdentry.cmdtype != CMDBUILTIN)
8937 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
8938 if (cmdentry.u.cmd == EXECCMD)
8940 #if ENABLE_ASH_CMDCMD
8941 if (cmdentry.u.cmd == COMMANDCMD) {
8943 nargv = parse_command_args(argv, &path);
8946 argc -= nargv - argv;
8948 cmd_flag |= DO_NOFUNC;
8956 /* We have a redirection error. */
8958 raise_exception(EXERROR);
8960 exitstatus = status;
8964 /* Execute the command. */
8965 switch (cmdentry.cmdtype) {
8968 #if ENABLE_FEATURE_SH_NOFORK
8969 /* Hmmm... shouldn't it happen somewhere in forkshell() instead?
8970 * Why "fork off a child process if necessary" doesn't apply to NOFORK? */
8972 /* find_command() encodes applet_no as (-2 - applet_no) */
8973 int applet_no = (- cmdentry.u.index - 2);
8974 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
8975 listsetvar(varlist.list, VEXPORT|VSTACK);
8976 /* run <applet>_main() */
8977 exitstatus = run_nofork_applet(applet_no, argv);
8982 /* Fork off a child process if necessary. */
8983 if (!(flags & EV_EXIT) || trap[0]) {
8985 jp = makejob(/*cmd,*/ 1);
8986 if (forkshell(jp, cmd, FORK_FG) != 0) {
8987 exitstatus = waitforjob(jp);
8993 listsetvar(varlist.list, VEXPORT|VSTACK);
8994 shellexec(argv, path, cmdentry.u.index);
8998 cmdenviron = varlist.list;
9000 struct strlist *list = cmdenviron;
9002 if (spclbltin > 0 || argc == 0) {
9004 if (cmd_is_exec && argc > 1)
9007 listsetvar(list, i);
9009 /* Tight loop with builtins only:
9010 * "while kill -0 $child; do true; done"
9011 * will never exit even if $child died, unless we do this
9012 * to reap the zombie and make kill detect that it's gone: */
9013 dowait(DOWAIT_NONBLOCK, NULL);
9015 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9017 int i = exception_type;
9022 exit_status = 128 + SIGINT;
9024 exit_status = 128 + pendingsig;
9025 exitstatus = exit_status;
9026 if (i == EXINT || spclbltin > 0) {
9028 longjmp(exception_handler->loc, 1);
9035 listsetvar(varlist.list, 0);
9036 /* See above for the rationale */
9037 dowait(DOWAIT_NONBLOCK, NULL);
9038 if (evalfun(cmdentry.u.func, argc, argv, flags))
9044 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
9046 /* dsl: I think this is intended to be used to support
9047 * '_' in 'vi' command mode during line editing...
9048 * However I implemented that within libedit itself.
9050 setvar("_", lastarg, 0);
9052 popstackmark(&smark);
9056 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9058 char *volatile savecmdname;
9059 struct jmploc *volatile savehandler;
9060 struct jmploc jmploc;
9063 savecmdname = commandname;
9064 i = setjmp(jmploc.loc);
9067 savehandler = exception_handler;
9068 exception_handler = &jmploc;
9069 commandname = argv[0];
9071 optptr = NULL; /* initialize nextopt */
9072 exitstatus = (*cmd->builtin)(argc, argv);
9073 flush_stdout_stderr();
9075 exitstatus |= ferror(stdout);
9077 commandname = savecmdname;
9079 exception_handler = savehandler;
9085 goodname(const char *p)
9087 return !*endofname(p);
9092 * Search for a command. This is called before we fork so that the
9093 * location of the command will be available in the parent as well as
9094 * the child. The check for "goodname" is an overly conservative
9095 * check that the name will not be subject to expansion.
9098 prehash(union node *n)
9100 struct cmdentry entry;
9102 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9103 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9107 /* ============ Builtin commands
9109 * Builtin commands whose functions are closely tied to evaluation
9110 * are implemented here.
9114 * Handle break and continue commands. Break, continue, and return are
9115 * all handled by setting the evalskip flag. The evaluation routines
9116 * above all check this flag, and if it is set they start skipping
9117 * commands rather than executing them. The variable skipcount is
9118 * the number of loops to break/continue, or the number of function
9119 * levels to return. (The latter is always 1.) It should probably
9120 * be an error to break out of more loops than exist, but it isn't
9121 * in the standard shell so we don't make it one here.
9124 breakcmd(int argc UNUSED_PARAM, char **argv)
9126 int n = argv[1] ? number(argv[1]) : 1;
9129 ash_msg_and_raise_error(illnum, argv[1]);
9133 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9140 /* ============ input.c
9142 * This implements the input routines used by the parser.
9146 INPUT_PUSH_FILE = 1,
9147 INPUT_NOFILE_OK = 2,
9150 static smallint checkkwd;
9151 /* values of checkkwd variable */
9152 #define CHKALIAS 0x1
9157 * Push a string back onto the input at this current parsefile level.
9158 * We handle aliases this way.
9160 #if !ENABLE_ASH_ALIAS
9161 #define pushstring(s, ap) pushstring(s)
9164 pushstring(char *s, struct alias *ap)
9171 if (g_parsefile->strpush) {
9172 sp = ckzalloc(sizeof(*sp));
9173 sp->prev = g_parsefile->strpush;
9175 sp = &(g_parsefile->basestrpush);
9177 g_parsefile->strpush = sp;
9178 sp->prev_string = g_parsefile->next_to_pgetc;
9179 sp->prev_left_in_line = g_parsefile->left_in_line;
9180 #if ENABLE_ASH_ALIAS
9183 ap->flag |= ALIASINUSE;
9187 g_parsefile->next_to_pgetc = s;
9188 g_parsefile->left_in_line = len;
9195 struct strpush *sp = g_parsefile->strpush;
9198 #if ENABLE_ASH_ALIAS
9200 if (g_parsefile->next_to_pgetc[-1] == ' '
9201 || g_parsefile->next_to_pgetc[-1] == '\t'
9203 checkkwd |= CHKALIAS;
9205 if (sp->string != sp->ap->val) {
9208 sp->ap->flag &= ~ALIASINUSE;
9209 if (sp->ap->flag & ALIASDEAD) {
9210 unalias(sp->ap->name);
9214 g_parsefile->next_to_pgetc = sp->prev_string;
9215 g_parsefile->left_in_line = sp->prev_left_in_line;
9216 g_parsefile->strpush = sp->prev;
9217 if (sp != &(g_parsefile->basestrpush))
9222 //FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9223 //it peeks whether it is &>, and then pushes back both chars.
9224 //This function needs to save last *next_to_pgetc to buf[0]
9225 //to make two pungetc() reliable. Currently,
9226 // pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
9231 char *buf = g_parsefile->buf;
9233 g_parsefile->next_to_pgetc = buf;
9234 #if ENABLE_FEATURE_EDITING
9236 if (!iflag || g_parsefile->fd != STDIN_FILENO)
9237 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9239 #if ENABLE_FEATURE_TAB_COMPLETION
9240 line_input_state->path_lookup = pathval();
9242 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
9244 /* Ctrl+C pressed */
9253 if (nr < 0 && errno == 0) {
9254 /* Ctrl+D pressed */
9259 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9263 /* nonblock_safe_read() handles this problem */
9265 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9266 int flags = fcntl(0, F_GETFL);
9267 if (flags >= 0 && (flags & O_NONBLOCK)) {
9268 flags &= ~O_NONBLOCK;
9269 if (fcntl(0, F_SETFL, flags) >= 0) {
9270 out2str("sh: turning off NDELAY mode\n");
9281 * Refill the input buffer and return the next input character:
9283 * 1) If a string was pushed back on the input, pop it;
9284 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9285 * or we are reading from a string so we can't refill the buffer,
9287 * 3) If the is more stuff in this buffer, use it else call read to fill it.
9288 * 4) Process input up to the next newline, deleting nul characters.
9290 //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9291 #define pgetc_debug(...) ((void)0)
9293 * NB: due to SIT(c) internals (syntax_index_table[] vector),
9294 * pgetc() and related functions must return chars SIGN-EXTENDED into ints,
9295 * not zero-extended. Seems fragile to me. Affects only !USE_SIT_FUNCTION case,
9296 * so we can fix it by ditching !USE_SIT_FUNCTION if Unicode requires that.
9304 while (g_parsefile->strpush) {
9305 #if ENABLE_ASH_ALIAS
9306 if (g_parsefile->left_in_line == -1
9307 && g_parsefile->strpush->ap
9308 && g_parsefile->next_to_pgetc[-1] != ' '
9309 && g_parsefile->next_to_pgetc[-1] != '\t'
9311 pgetc_debug("preadbuffer PEOA");
9316 /* try "pgetc" now: */
9317 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9318 g_parsefile->left_in_line,
9319 g_parsefile->next_to_pgetc,
9320 g_parsefile->next_to_pgetc);
9321 if (--g_parsefile->left_in_line >= 0)
9322 return (unsigned char)(*g_parsefile->next_to_pgetc++);
9324 /* on both branches above g_parsefile->left_in_line < 0.
9325 * "pgetc" needs refilling.
9328 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
9329 * pungetc() may increment it a few times.
9330 * Assuming it won't increment it to less than -90.
9332 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
9333 pgetc_debug("preadbuffer PEOF1");
9334 /* even in failure keep left_in_line and next_to_pgetc
9335 * in lock step, for correct multi-layer pungetc.
9336 * left_in_line was decremented before preadbuffer(),
9337 * must inc next_to_pgetc: */
9338 g_parsefile->next_to_pgetc++;
9342 more = g_parsefile->left_in_buffer;
9344 flush_stdout_stderr();
9348 /* don't try reading again */
9349 g_parsefile->left_in_line = -99;
9350 pgetc_debug("preadbuffer PEOF2");
9351 g_parsefile->next_to_pgetc++;
9356 /* Find out where's the end of line.
9357 * Set g_parsefile->left_in_line
9358 * and g_parsefile->left_in_buffer acordingly.
9359 * NUL chars are deleted.
9361 q = g_parsefile->next_to_pgetc;
9369 memmove(q, q + 1, more);
9373 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9379 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9380 if (g_parsefile->left_in_line < 0)
9385 g_parsefile->left_in_buffer = more;
9390 out2str(g_parsefile->next_to_pgetc);
9394 pgetc_debug("preadbuffer at %d:%p'%s'",
9395 g_parsefile->left_in_line,
9396 g_parsefile->next_to_pgetc,
9397 g_parsefile->next_to_pgetc);
9398 return signed_char2int(*g_parsefile->next_to_pgetc++);
9401 #define pgetc_as_macro() \
9402 (--g_parsefile->left_in_line >= 0 \
9403 ? signed_char2int(*g_parsefile->next_to_pgetc++) \
9410 pgetc_debug("pgetc_fast at %d:%p'%s'",
9411 g_parsefile->left_in_line,
9412 g_parsefile->next_to_pgetc,
9413 g_parsefile->next_to_pgetc);
9414 return pgetc_as_macro();
9417 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9418 #define pgetc_fast() pgetc()
9420 #define pgetc_fast() pgetc_as_macro()
9424 * Same as pgetc(), but ignores PEOA.
9426 #if ENABLE_ASH_ALIAS
9432 pgetc_debug("pgetc_fast at %d:%p'%s'",
9433 g_parsefile->left_in_line,
9434 g_parsefile->next_to_pgetc,
9435 g_parsefile->next_to_pgetc);
9437 } while (c == PEOA);
9441 #define pgetc2() pgetc()
9445 * Read a line from the script.
9448 pfgets(char *line, int len)
9454 while (--nleft > 0) {
9470 * Undo the last call to pgetc. Only one character may be pushed back.
9471 * PEOF may be pushed back.
9476 g_parsefile->left_in_line++;
9477 g_parsefile->next_to_pgetc--;
9478 pgetc_debug("pushed back to %d:%p'%s'",
9479 g_parsefile->left_in_line,
9480 g_parsefile->next_to_pgetc,
9481 g_parsefile->next_to_pgetc);
9485 * To handle the "." command, a stack of input files is used. Pushfile
9486 * adds a new entry to the stack and popfile restores the previous level.
9491 struct parsefile *pf;
9493 pf = ckzalloc(sizeof(*pf));
9494 pf->prev = g_parsefile;
9496 /*pf->strpush = NULL; - ckzalloc did it */
9497 /*pf->basestrpush.prev = NULL;*/
9504 struct parsefile *pf = g_parsefile;
9512 g_parsefile = pf->prev;
9518 * Return to top level.
9523 while (g_parsefile != &basepf)
9528 * Close the file(s) that the shell is reading commands from. Called
9529 * after a fork is done.
9535 if (g_parsefile->fd > 0) {
9536 close(g_parsefile->fd);
9537 g_parsefile->fd = 0;
9542 * Like setinputfile, but takes an open file descriptor. Call this with
9546 setinputfd(int fd, int push)
9548 close_on_exec_on(fd);
9551 g_parsefile->buf = NULL;
9553 g_parsefile->fd = fd;
9554 if (g_parsefile->buf == NULL)
9555 g_parsefile->buf = ckmalloc(IBUFSIZ);
9556 g_parsefile->left_in_buffer = 0;
9557 g_parsefile->left_in_line = 0;
9558 g_parsefile->linno = 1;
9562 * Set the input to take input from a file. If push is set, push the
9563 * old input onto the stack first.
9566 setinputfile(const char *fname, int flags)
9572 fd = open(fname, O_RDONLY);
9574 if (flags & INPUT_NOFILE_OK)
9576 ash_msg_and_raise_error("can't open '%s'", fname);
9579 fd2 = copyfd(fd, 10);
9582 ash_msg_and_raise_error("out of file descriptors");
9585 setinputfd(fd, flags & INPUT_PUSH_FILE);
9592 * Like setinputfile, but takes input from a string.
9595 setinputstring(char *string)
9599 g_parsefile->next_to_pgetc = string;
9600 g_parsefile->left_in_line = strlen(string);
9601 g_parsefile->buf = NULL;
9602 g_parsefile->linno = 1;
9607 /* ============ mail.c
9609 * Routines to check for mail.
9614 #define MAXMBOXES 10
9616 /* times of mailboxes */
9617 static time_t mailtime[MAXMBOXES];
9618 /* Set if MAIL or MAILPATH is changed. */
9619 static smallint mail_var_path_changed;
9622 * Print appropriate message(s) if mail has arrived.
9623 * If mail_var_path_changed is set,
9624 * then the value of MAIL has mail_var_path_changed,
9625 * so we just update the values.
9634 struct stackmark smark;
9637 setstackmark(&smark);
9638 mpath = mpathset() ? mpathval() : mailval();
9639 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9640 p = padvance(&mpath, nullstr);
9645 for (q = p; *q; q++)
9651 q[-1] = '\0'; /* delete trailing '/' */
9652 if (stat(p, &statb) < 0) {
9656 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9659 pathopt ? pathopt : "you have mail"
9662 *mtp = statb.st_mtime;
9664 mail_var_path_changed = 0;
9665 popstackmark(&smark);
9669 changemail(const char *val UNUSED_PARAM)
9671 mail_var_path_changed = 1;
9674 #endif /* ASH_MAIL */
9677 /* ============ ??? */
9680 * Set the shell parameters.
9683 setparam(char **argv)
9689 for (nparam = 0; argv[nparam]; nparam++)
9691 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9693 *ap++ = ckstrdup(*argv++);
9696 freeparam(&shellparam);
9697 shellparam.malloced = 1;
9698 shellparam.nparam = nparam;
9699 shellparam.p = newparam;
9700 #if ENABLE_ASH_GETOPTS
9701 shellparam.optind = 1;
9702 shellparam.optoff = -1;
9707 * Process shell options. The global variable argptr contains a pointer
9708 * to the argument list; we advance it past the options.
9710 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9711 * For a non-interactive shell, an error condition encountered
9712 * by a special built-in ... shall cause the shell to write a diagnostic message
9713 * to standard error and exit as shown in the following table:
9714 * Error Special Built-In
9716 * Utility syntax error (option or operand error) Shall exit
9718 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9719 * we see that bash does not do that (set "finishes" with error code 1 instead,
9720 * and shell continues), and people rely on this behavior!
9722 * set -o barfoo 2>/dev/null
9725 * Oh well. Let's mimic that.
9728 plus_minus_o(char *name, int val)
9733 for (i = 0; i < NOPTS; i++) {
9734 if (strcmp(name, optnames(i)) == 0) {
9739 ash_msg("illegal option %co %s", val ? '-' : '+', name);
9742 for (i = 0; i < NOPTS; i++) {
9744 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
9746 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
9752 setoption(int flag, int val)
9756 for (i = 0; i < NOPTS; i++) {
9757 if (optletters(i) == flag) {
9762 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
9766 options(int cmdline)
9774 while ((p = *argptr) != NULL) {
9776 if (c != '-' && c != '+')
9779 val = 0; /* val = 0 if c == '+' */
9782 if (p[0] == '\0' || LONE_DASH(p)) {
9784 /* "-" means turn off -x and -v */
9787 /* "--" means reset params */
9788 else if (*argptr == NULL)
9791 break; /* "-" or "--" terminates options */
9794 /* first char was + or - */
9795 while ((c = *p++) != '\0') {
9796 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9797 if (c == 'c' && cmdline) {
9798 minusc = p; /* command is after shell args */
9799 } else if (c == 'o') {
9800 if (plus_minus_o(*argptr, val)) {
9801 /* it already printed err message */
9802 return 1; /* error */
9806 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9808 /* bash does not accept +-login, we also won't */
9809 } else if (cmdline && val && (c == '-')) { /* long options */
9810 if (strcmp(p, "login") == 0)
9822 * The shift builtin command.
9825 shiftcmd(int argc UNUSED_PARAM, char **argv)
9832 n = number(argv[1]);
9833 if (n > shellparam.nparam)
9834 n = 0; /* bash compat, was = shellparam.nparam; */
9836 shellparam.nparam -= n;
9837 for (ap1 = shellparam.p; --n >= 0; ap1++) {
9838 if (shellparam.malloced)
9842 while ((*ap2++ = *ap1++) != NULL)
9844 #if ENABLE_ASH_GETOPTS
9845 shellparam.optind = 1;
9846 shellparam.optoff = -1;
9853 * POSIX requires that 'set' (but not export or readonly) output the
9854 * variables in lexicographic order - by the locale's collating order (sigh).
9855 * Maybe we could keep them in an ordered balanced binary tree
9856 * instead of hashed lists.
9857 * For now just roll 'em through qsort for printing...
9860 showvars(const char *sep_prefix, int on, int off)
9865 ep = listvars(on, off, &epend);
9866 qsort(ep, epend - ep, sizeof(char *), vpcmp);
9868 sep = *sep_prefix ? " " : sep_prefix;
9870 for (; ep < epend; ep++) {
9874 p = strchrnul(*ep, '=');
9877 q = single_quote(++p);
9878 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9884 * The set command builtin.
9887 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9892 return showvars(nullstr, 0, VUNSET);
9895 if (!options(0)) { /* if no parse error... */
9898 if (*argptr != NULL) {
9906 #if ENABLE_ASH_RANDOM_SUPPORT
9908 change_random(const char *value)
9910 /* Galois LFSR parameter */
9911 /* Taps at 32 31 29 1: */
9912 enum { MASK = 0x8000000b };
9913 /* Another example - taps at 32 31 30 10: */
9914 /* MASK = 0x00400007 */
9916 if (value == NULL) {
9917 /* "get", generate */
9920 /* LCG has period of 2^32 and alternating lowest bit */
9921 random_LCG = 1664525 * random_LCG + 1013904223;
9922 /* Galois LFSR has period of 2^32-1 = 3 * 5 * 17 * 257 * 65537 */
9923 t = (random_galois_LFSR << 1);
9924 if (random_galois_LFSR < 0) /* if we just shifted 1 out of msb... */
9926 random_galois_LFSR = t;
9927 /* Both are weak, combining them gives better randomness
9928 * and ~2^64 period. & 0x7fff is probably bash compat
9929 * for $RANDOM range. Combining with subtraction is
9930 * just for fun. + and ^ would work equally well. */
9931 t = (t - random_LCG) & 0x7fff;
9932 /* set without recursion */
9933 setvar(vrandom.text, utoa(t), VNOFUNC);
9934 vrandom.flags &= ~VNOFUNC;
9937 random_galois_LFSR = random_LCG = strtoul(value, (char **)NULL, 10);
9942 #if ENABLE_ASH_GETOPTS
9944 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9953 if (*param_optind < 1)
9955 optnext = optfirst + *param_optind - 1;
9957 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
9960 p = optnext[-1] + *optoff;
9961 if (p == NULL || *p == '\0') {
9962 /* Current word is done, advance */
9964 if (p == NULL || *p != '-' || *++p == '\0') {
9971 if (LONE_DASH(p)) /* check for "--" */
9976 for (q = optstr; *q != c;) {
9978 if (optstr[0] == ':') {
9981 err |= setvarsafe("OPTARG", s, 0);
9983 fprintf(stderr, "Illegal option -%c\n", c);
9994 if (*p == '\0' && (p = *optnext) == NULL) {
9995 if (optstr[0] == ':') {
9998 err |= setvarsafe("OPTARG", s, 0);
10001 fprintf(stderr, "No arg for -%c option\n", c);
10002 unsetvar("OPTARG");
10010 err |= setvarsafe("OPTARG", p, 0);
10013 err |= setvarsafe("OPTARG", nullstr, 0);
10015 *optoff = p ? p - *(optnext - 1) : -1;
10016 *param_optind = optnext - optfirst + 1;
10017 fmtstr(s, sizeof(s), "%d", *param_optind);
10018 err |= setvarsafe("OPTIND", s, VNOFUNC);
10021 err |= setvarsafe(optvar, s, 0);
10025 flush_stdout_stderr();
10026 raise_exception(EXERROR);
10032 * The getopts builtin. Shellparam.optnext points to the next argument
10033 * to be processed. Shellparam.optptr points to the next character to
10034 * be processed in the current argument. If shellparam.optnext is NULL,
10035 * then it's the first time getopts has been called.
10038 getoptscmd(int argc, char **argv)
10043 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
10045 optbase = shellparam.p;
10046 if (shellparam.optind > shellparam.nparam + 1) {
10047 shellparam.optind = 1;
10048 shellparam.optoff = -1;
10051 optbase = &argv[3];
10052 if (shellparam.optind > argc - 2) {
10053 shellparam.optind = 1;
10054 shellparam.optoff = -1;
10058 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
10059 &shellparam.optoff);
10061 #endif /* ASH_GETOPTS */
10064 /* ============ Shell parser */
10067 struct heredoc *next; /* next here document in list */
10068 union node *here; /* redirection node */
10069 char *eofmark; /* string indicating end of input */
10070 smallint striptabs; /* if set, strip leading tabs */
10073 static smallint tokpushback; /* last token pushed back */
10074 static smallint parsebackquote; /* nonzero if we are inside backquotes */
10075 static smallint quoteflag; /* set if (part of) last token was quoted */
10076 static token_id_t lasttoken; /* last token read (integer id Txxx) */
10077 static struct heredoc *heredoclist; /* list of here documents to read */
10078 static char *wordtext; /* text of last word returned by readtoken */
10079 static struct nodelist *backquotelist;
10080 static union node *redirnode;
10081 static struct heredoc *heredoc;
10083 * NEOF is returned by parsecmd when it encounters an end of file. It
10084 * must be distinct from NULL, so we use the address of a variable that
10085 * happens to be handy.
10087 #define NEOF ((union node *)&tokpushback)
10089 static void raise_error_syntax(const char *) NORETURN;
10091 raise_error_syntax(const char *msg)
10093 ash_msg_and_raise_error("syntax error: %s", msg);
10098 * Called when an unexpected token is read during the parse. The argument
10099 * is the token that is expected, or -1 if more than one type of token can
10100 * occur at this point.
10102 static void raise_error_unexpected_syntax(int) NORETURN;
10104 raise_error_unexpected_syntax(int token)
10109 l = sprintf(msg, "unexpected %s", tokname(lasttoken));
10111 sprintf(msg + l, " (expecting %s)", tokname(token));
10112 raise_error_syntax(msg);
10116 #define EOFMARKLEN 79
10118 /* parsing is heavily cross-recursive, need these forward decls */
10119 static union node *andor(void);
10120 static union node *pipeline(void);
10121 static union node *parse_command(void);
10122 static void parseheredoc(void);
10123 static char peektoken(void);
10124 static int readtoken(void);
10126 static union node *
10129 union node *n1, *n2, *n3;
10132 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10133 if (nlflag == 2 && peektoken())
10139 if (tok == TBACKGND) {
10140 if (n2->type == NPIPE) {
10141 n2->npipe.pipe_backgnd = 1;
10143 if (n2->type != NREDIR) {
10144 n3 = stzalloc(sizeof(struct nredir));
10146 /*n3->nredir.redirect = NULL; - stzalloc did it */
10149 n2->type = NBACKGND;
10155 n3 = stzalloc(sizeof(struct nbinary));
10157 n3->nbinary.ch1 = n1;
10158 n3->nbinary.ch2 = n2;
10174 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10182 pungetc(); /* push back EOF on input */
10186 raise_error_unexpected_syntax(-1);
10193 static union node *
10196 union node *n1, *n2, *n3;
10204 } else if (t == TOR) {
10210 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10212 n3 = stzalloc(sizeof(struct nbinary));
10214 n3->nbinary.ch1 = n1;
10215 n3->nbinary.ch2 = n2;
10220 static union node *
10223 union node *n1, *n2, *pipenode;
10224 struct nodelist *lp, *prev;
10228 TRACE(("pipeline: entered\n"));
10229 if (readtoken() == TNOT) {
10231 checkkwd = CHKKWD | CHKALIAS;
10234 n1 = parse_command();
10235 if (readtoken() == TPIPE) {
10236 pipenode = stzalloc(sizeof(struct npipe));
10237 pipenode->type = NPIPE;
10238 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10239 lp = stzalloc(sizeof(struct nodelist));
10240 pipenode->npipe.cmdlist = lp;
10244 lp = stzalloc(sizeof(struct nodelist));
10245 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10246 lp->n = parse_command();
10248 } while (readtoken() == TPIPE);
10254 n2 = stzalloc(sizeof(struct nnot));
10262 static union node *
10267 n = stzalloc(sizeof(struct narg));
10269 /*n->narg.next = NULL; - stzalloc did it */
10270 n->narg.text = wordtext;
10271 n->narg.backquote = backquotelist;
10276 fixredir(union node *n, const char *text, int err)
10280 TRACE(("Fix redir %s %d\n", text, err));
10282 n->ndup.vname = NULL;
10284 fd = bb_strtou(text, NULL, 10);
10285 if (!errno && fd >= 0)
10286 n->ndup.dupfd = fd;
10287 else if (LONE_DASH(text))
10288 n->ndup.dupfd = -1;
10291 raise_error_syntax("bad fd number");
10292 n->ndup.vname = makename();
10297 * Returns true if the text contains nothing to expand (no dollar signs
10301 noexpand(const char *text)
10307 while ((c = *p++) != '\0') {
10308 if (c == CTLQUOTEMARK)
10312 else if (SIT((signed char)c, BASESYNTAX) == CCTL)
10321 union node *n = redirnode;
10323 if (readtoken() != TWORD)
10324 raise_error_unexpected_syntax(-1);
10325 if (n->type == NHERE) {
10326 struct heredoc *here = heredoc;
10330 if (quoteflag == 0)
10332 TRACE(("Here document %d\n", n->type));
10333 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10334 raise_error_syntax("illegal eof marker for << redirection");
10335 rmescapes(wordtext);
10336 here->eofmark = wordtext;
10338 if (heredoclist == NULL)
10339 heredoclist = here;
10341 for (p = heredoclist; p->next; p = p->next)
10345 } else if (n->type == NTOFD || n->type == NFROMFD) {
10346 fixredir(n, wordtext, 0);
10348 n->nfile.fname = makename();
10352 static union node *
10355 union node *args, **app;
10356 union node *n = NULL;
10357 union node *vars, **vpp;
10358 union node **rpp, *redir;
10360 #if ENABLE_ASH_BASH_COMPAT
10361 smallint double_brackets_flag = 0;
10371 savecheckkwd = CHKALIAS;
10374 checkkwd = savecheckkwd;
10377 #if ENABLE_ASH_BASH_COMPAT
10378 case TAND: /* "&&" */
10379 case TOR: /* "||" */
10380 if (!double_brackets_flag) {
10384 wordtext = (char *) (t == TAND ? "-a" : "-o");
10387 n = stzalloc(sizeof(struct narg));
10389 /*n->narg.next = NULL; - stzalloc did it */
10390 n->narg.text = wordtext;
10391 #if ENABLE_ASH_BASH_COMPAT
10392 if (strcmp("[[", wordtext) == 0)
10393 double_brackets_flag = 1;
10394 else if (strcmp("]]", wordtext) == 0)
10395 double_brackets_flag = 0;
10397 n->narg.backquote = backquotelist;
10398 if (savecheckkwd && isassignment(wordtext)) {
10400 vpp = &n->narg.next;
10403 app = &n->narg.next;
10408 *rpp = n = redirnode;
10409 rpp = &n->nfile.next;
10410 parsefname(); /* read name of redirection file */
10413 if (args && app == &args->narg.next
10416 struct builtincmd *bcmd;
10419 /* We have a function */
10420 if (readtoken() != TRP)
10421 raise_error_unexpected_syntax(TRP);
10422 name = n->narg.text;
10423 if (!goodname(name)
10424 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10426 raise_error_syntax("bad function name");
10429 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10430 n->narg.next = parse_command();
10443 n = stzalloc(sizeof(struct ncmd));
10445 n->ncmd.args = args;
10446 n->ncmd.assign = vars;
10447 n->ncmd.redirect = redir;
10451 static union node *
10452 parse_command(void)
10454 union node *n1, *n2;
10455 union node *ap, **app;
10456 union node *cp, **cpp;
10457 union node *redir, **rpp;
10464 switch (readtoken()) {
10466 raise_error_unexpected_syntax(-1);
10469 n1 = stzalloc(sizeof(struct nif));
10471 n1->nif.test = list(0);
10472 if (readtoken() != TTHEN)
10473 raise_error_unexpected_syntax(TTHEN);
10474 n1->nif.ifpart = list(0);
10476 while (readtoken() == TELIF) {
10477 n2->nif.elsepart = stzalloc(sizeof(struct nif));
10478 n2 = n2->nif.elsepart;
10480 n2->nif.test = list(0);
10481 if (readtoken() != TTHEN)
10482 raise_error_unexpected_syntax(TTHEN);
10483 n2->nif.ifpart = list(0);
10485 if (lasttoken == TELSE)
10486 n2->nif.elsepart = list(0);
10488 n2->nif.elsepart = NULL;
10496 n1 = stzalloc(sizeof(struct nbinary));
10497 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10498 n1->nbinary.ch1 = list(0);
10501 TRACE(("expecting DO got %s %s\n", tokname(got),
10502 got == TWORD ? wordtext : ""));
10503 raise_error_unexpected_syntax(TDO);
10505 n1->nbinary.ch2 = list(0);
10510 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10511 raise_error_syntax("bad for loop variable");
10512 n1 = stzalloc(sizeof(struct nfor));
10514 n1->nfor.var = wordtext;
10515 checkkwd = CHKKWD | CHKALIAS;
10516 if (readtoken() == TIN) {
10518 while (readtoken() == TWORD) {
10519 n2 = stzalloc(sizeof(struct narg));
10521 /*n2->narg.next = NULL; - stzalloc did it */
10522 n2->narg.text = wordtext;
10523 n2->narg.backquote = backquotelist;
10525 app = &n2->narg.next;
10528 n1->nfor.args = ap;
10529 if (lasttoken != TNL && lasttoken != TSEMI)
10530 raise_error_unexpected_syntax(-1);
10532 n2 = stzalloc(sizeof(struct narg));
10534 /*n2->narg.next = NULL; - stzalloc did it */
10535 n2->narg.text = (char *)dolatstr;
10536 /*n2->narg.backquote = NULL;*/
10537 n1->nfor.args = n2;
10539 * Newline or semicolon here is optional (but note
10540 * that the original Bourne shell only allowed NL).
10542 if (lasttoken != TNL && lasttoken != TSEMI)
10545 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10546 if (readtoken() != TDO)
10547 raise_error_unexpected_syntax(TDO);
10548 n1->nfor.body = list(0);
10552 n1 = stzalloc(sizeof(struct ncase));
10554 if (readtoken() != TWORD)
10555 raise_error_unexpected_syntax(TWORD);
10556 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10558 /*n2->narg.next = NULL; - stzalloc did it */
10559 n2->narg.text = wordtext;
10560 n2->narg.backquote = backquotelist;
10562 checkkwd = CHKKWD | CHKALIAS;
10563 } while (readtoken() == TNL);
10564 if (lasttoken != TIN)
10565 raise_error_unexpected_syntax(TIN);
10566 cpp = &n1->ncase.cases;
10568 checkkwd = CHKNL | CHKKWD;
10570 while (t != TESAC) {
10571 if (lasttoken == TLP)
10573 *cpp = cp = stzalloc(sizeof(struct nclist));
10575 app = &cp->nclist.pattern;
10577 *app = ap = stzalloc(sizeof(struct narg));
10579 /*ap->narg.next = NULL; - stzalloc did it */
10580 ap->narg.text = wordtext;
10581 ap->narg.backquote = backquotelist;
10582 if (readtoken() != TPIPE)
10584 app = &ap->narg.next;
10587 //ap->narg.next = NULL;
10588 if (lasttoken != TRP)
10589 raise_error_unexpected_syntax(TRP);
10590 cp->nclist.body = list(2);
10592 cpp = &cp->nclist.next;
10594 checkkwd = CHKNL | CHKKWD;
10598 raise_error_unexpected_syntax(TENDCASE);
10605 n1 = stzalloc(sizeof(struct nredir));
10606 n1->type = NSUBSHELL;
10607 n1->nredir.n = list(0);
10608 /*n1->nredir.redirect = NULL; - stzalloc did it */
10618 return simplecmd();
10621 if (readtoken() != t)
10622 raise_error_unexpected_syntax(t);
10625 /* Now check for redirection which may follow command */
10626 checkkwd = CHKKWD | CHKALIAS;
10628 while (readtoken() == TREDIR) {
10629 *rpp = n2 = redirnode;
10630 rpp = &n2->nfile.next;
10636 if (n1->type != NSUBSHELL) {
10637 n2 = stzalloc(sizeof(struct nredir));
10642 n1->nredir.redirect = redir;
10647 #if ENABLE_ASH_BASH_COMPAT
10648 static int decode_dollar_squote(void)
10650 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
10656 p = strchr(C_escapes, c);
10661 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
10665 } while ((unsigned char)(c - '0') <= 7 && --cnt);
10667 } else if (c == 'x') { /* \xHH */
10671 } while (isxdigit(c) && --cnt);
10673 if (cnt == 3) { /* \x but next char is "bad" */
10677 } else { /* simple seq like \\ or \t */
10682 c = bb_process_escape_sequence((void*)&p);
10683 } else { /* unrecognized "\z": print both chars unless ' or " */
10684 if (c != '\'' && c != '"') {
10686 c |= 0x100; /* "please encode \, then me" */
10694 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10695 * is not NULL, read a here document. In the latter case, eofmark is the
10696 * word which marks the end of the document and striptabs is true if
10697 * leading tabs should be stripped from the document. The argument firstc
10698 * is the first character of the input token or document.
10700 * Because C does not have internal subroutines, I have simulated them
10701 * using goto's to implement the subroutine linkage. The following macros
10702 * will run code that appears at the end of readtoken1.
10704 #define CHECKEND() {goto checkend; checkend_return:;}
10705 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10706 #define PARSESUB() {goto parsesub; parsesub_return:;}
10707 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10708 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10709 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10711 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10713 /* NB: syntax parameter fits into smallint */
10717 char line[EOFMARKLEN + 1];
10718 struct nodelist *bqlist;
10722 smallint prevsyntax; /* syntax before arithmetic */
10723 #if ENABLE_ASH_EXPAND_PRMT
10724 smallint pssyntax; /* we are expanding a prompt string */
10726 int varnest; /* levels of variables expansion */
10727 int arinest; /* levels of arithmetic expansion */
10728 int parenlevel; /* levels of parens in arithmetic */
10729 int dqvarnest; /* levels of variables expansion within double quotes */
10731 USE_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
10734 /* Avoid longjmp clobbering */
10740 (void) &parenlevel;
10743 (void) &prevsyntax;
10746 startlinno = g_parsefile->linno;
10751 #if ENABLE_ASH_EXPAND_PRMT
10752 pssyntax = (syntax == PSSYNTAX);
10756 dblquote = (syntax == DQSYNTAX);
10762 STARTSTACKSTR(out);
10764 /* For each line, until end of word */
10766 CHECKEND(); /* set c to PEOF if at end of here document */
10767 for (;;) { /* until end of line or end of word */
10768 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10769 switch (SIT(c, syntax)) {
10770 case CNL: /* '\n' */
10771 if (syntax == BASESYNTAX)
10772 goto endword; /* exit outer loop */
10774 g_parsefile->linno++;
10778 goto loop; /* continue outer loop */
10783 if (eofmark == NULL || dblquote)
10784 USTPUTC(CTLESC, out);
10785 #if ENABLE_ASH_BASH_COMPAT
10786 if (c == '\\' && bash_dollar_squote) {
10787 c = decode_dollar_squote();
10789 USTPUTC('\\', out);
10790 c = (unsigned char)c;
10796 case CBACK: /* backslash */
10799 USTPUTC(CTLESC, out);
10800 USTPUTC('\\', out);
10802 } else if (c == '\n') {
10806 #if ENABLE_ASH_EXPAND_PRMT
10807 if (c == '$' && pssyntax) {
10808 USTPUTC(CTLESC, out);
10809 USTPUTC('\\', out);
10812 if (dblquote && c != '\\'
10813 && c != '`' && c != '$'
10814 && (c != '"' || eofmark != NULL)
10816 USTPUTC(CTLESC, out);
10817 USTPUTC('\\', out);
10819 if (SIT(c, SQSYNTAX) == CCTL)
10820 USTPUTC(CTLESC, out);
10828 if (eofmark == NULL) {
10829 USTPUTC(CTLQUOTEMARK, out);
10837 USE_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
10838 if (eofmark != NULL && arinest == 0
10843 if (dqvarnest == 0) {
10844 syntax = BASESYNTAX;
10851 case CVAR: /* '$' */
10852 PARSESUB(); /* parse substitution */
10854 case CENDVAR: /* '}' */
10857 if (dqvarnest > 0) {
10860 USTPUTC(CTLENDVAR, out);
10865 #if ENABLE_ASH_MATH_SUPPORT
10866 case CLP: /* '(' in arithmetic */
10870 case CRP: /* ')' in arithmetic */
10871 if (parenlevel > 0) {
10875 if (pgetc() == ')') {
10876 if (--arinest == 0) {
10877 USTPUTC(CTLENDARI, out);
10878 syntax = prevsyntax;
10879 dblquote = (syntax == DQSYNTAX);
10884 * unbalanced parens
10885 * (don't 2nd guess - no error)
10893 case CBQUOTE: /* '`' */
10897 goto endword; /* exit outer loop */
10901 if (varnest == 0) {
10902 #if ENABLE_ASH_BASH_COMPAT
10904 if (pgetc() == '>')
10905 c = 0x100 + '>'; /* flag &> */
10909 goto endword; /* exit outer loop */
10911 #if ENABLE_ASH_ALIAS
10921 #if ENABLE_ASH_MATH_SUPPORT
10922 if (syntax == ARISYNTAX)
10923 raise_error_syntax("missing '))'");
10925 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10926 raise_error_syntax("unterminated quoted string");
10927 if (varnest != 0) {
10928 startlinno = g_parsefile->linno;
10930 raise_error_syntax("missing '}'");
10932 USTPUTC('\0', out);
10933 len = out - (char *)stackblock();
10934 out = stackblock();
10935 if (eofmark == NULL) {
10936 if ((c == '>' || c == '<' USE_ASH_BASH_COMPAT( || c == 0x100 + '>'))
10939 if (isdigit_str9(out)) {
10940 PARSEREDIR(); /* passed as params: out, c */
10941 lasttoken = TREDIR;
10944 /* else: non-number X seen, interpret it
10945 * as "NNNX>file" = "NNNX >file" */
10949 quoteflag = quotef;
10950 backquotelist = bqlist;
10951 grabstackblock(len);
10955 /* end of readtoken routine */
10958 * Check to see whether we are at the end of the here document. When this
10959 * is called, c is set to the first character of the next input line. If
10960 * we are at the end of the here document, this routine sets the c to PEOF.
10964 #if ENABLE_ASH_ALIAS
10970 while (c == '\t') {
10974 if (c == *eofmark) {
10975 if (pfgets(line, sizeof(line)) != NULL) {
10979 for (q = eofmark + 1; *q && *p == *q; p++, q++)
10981 if (*p == '\n' && *q == '\0') {
10983 g_parsefile->linno++;
10984 needprompt = doprompt;
10986 pushstring(line, NULL);
10991 goto checkend_return;
10995 * Parse a redirection operator. The variable "out" points to a string
10996 * specifying the fd to be redirected. The variable "c" contains the
10997 * first character of the redirection operator.
11000 /* out is already checked to be a valid number or "" */
11001 int fd = (*out == '\0' ? -1 : atoi(out));
11004 np = stzalloc(sizeof(struct nfile));
11009 np->type = NAPPEND;
11011 np->type = NCLOBBER;
11014 /* it also can be NTO2 (>&file), but we can't figure it out yet */
11020 #if ENABLE_ASH_BASH_COMPAT
11021 else if (c == 0x100 + '>') { /* this flags &> redirection */
11023 pgetc(); /* this is '>', no need to check */
11027 else { /* c == '<' */
11028 /*np->nfile.fd = 0; - stzalloc did it */
11032 if (sizeof(struct nfile) != sizeof(struct nhere)) {
11033 np = stzalloc(sizeof(struct nhere));
11034 /*np->nfile.fd = 0; - stzalloc did it */
11037 heredoc = stzalloc(sizeof(struct heredoc));
11038 heredoc->here = np;
11041 heredoc->striptabs = 1;
11043 /*heredoc->striptabs = 0; - stzalloc did it */
11049 np->type = NFROMFD;
11053 np->type = NFROMTO;
11065 goto parseredir_return;
11069 * Parse a substitution. At this point, we have read the dollar sign
11070 * and nothing else.
11073 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11074 * (assuming ascii char codes, as the original implementation did) */
11075 #define is_special(c) \
11076 (((unsigned)(c) - 33 < 32) \
11077 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
11083 static const char types[] ALIGN1 = "}-+?=";
11086 if (c <= PEOA_OR_PEOF
11087 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
11089 #if ENABLE_ASH_BASH_COMPAT
11091 bash_dollar_squote = 1;
11096 } else if (c == '(') { /* $(command) or $((arith)) */
11097 if (pgetc() == '(') {
11098 #if ENABLE_ASH_MATH_SUPPORT
11101 raise_error_syntax("you disabled math support for $((arith)) syntax");
11108 USTPUTC(CTLVAR, out);
11109 typeloc = out - (char *)stackblock();
11110 USTPUTC(VSNORMAL, out);
11111 subtype = VSNORMAL;
11119 subtype = VSLENGTH;
11123 if (c > PEOA_OR_PEOF && is_name(c)) {
11127 } while (c > PEOA_OR_PEOF && is_in_name(c));
11128 } else if (isdigit(c)) {
11132 } while (isdigit(c));
11133 } else if (is_special(c)) {
11138 raise_error_syntax("bad substitution");
11143 if (subtype == 0) {
11147 #if ENABLE_ASH_BASH_COMPAT
11148 if (c == ':' || c == '$' || isdigit(c)) {
11150 subtype = VSSUBSTR;
11157 p = strchr(types, c);
11160 subtype = p - types + VSNORMAL;
11165 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
11173 #if ENABLE_ASH_BASH_COMPAT
11175 subtype = VSREPLACE;
11178 subtype++; /* VSREPLACEALL */
11187 if (dblquote || arinest)
11189 *((char *)stackblock() + typeloc) = subtype | flags;
11190 if (subtype != VSNORMAL) {
11192 if (dblquote || arinest) {
11197 goto parsesub_return;
11201 * Called to parse command substitutions. Newstyle is set if the command
11202 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11203 * list of commands (passed by reference), and savelen is the number of
11204 * characters on the top of the stack which must be preserved.
11207 struct nodelist **nlpp;
11210 char *volatile str;
11211 struct jmploc jmploc;
11212 struct jmploc *volatile savehandler;
11214 smallint saveprompt = 0;
11217 (void) &saveprompt;
11219 savepbq = parsebackquote;
11220 if (setjmp(jmploc.loc)) {
11222 parsebackquote = 0;
11223 exception_handler = savehandler;
11224 longjmp(exception_handler->loc, 1);
11228 savelen = out - (char *)stackblock();
11230 str = ckmalloc(savelen);
11231 memcpy(str, stackblock(), savelen);
11233 savehandler = exception_handler;
11234 exception_handler = &jmploc;
11237 /* We must read until the closing backquote, giving special
11238 treatment to some slashes, and then push the string and
11239 reread it as input, interpreting it normally. */
11246 STARTSTACKSTR(pout);
11259 g_parsefile->linno++;
11263 * If eating a newline, avoid putting
11264 * the newline into the new character
11265 * stream (via the STPUTC after the
11270 if (pc != '\\' && pc != '`' && pc != '$'
11271 && (!dblquote || pc != '"'))
11272 STPUTC('\\', pout);
11273 if (pc > PEOA_OR_PEOF) {
11279 #if ENABLE_ASH_ALIAS
11282 startlinno = g_parsefile->linno;
11283 raise_error_syntax("EOF in backquote substitution");
11286 g_parsefile->linno++;
11287 needprompt = doprompt;
11296 STPUTC('\0', pout);
11297 psavelen = pout - (char *)stackblock();
11298 if (psavelen > 0) {
11299 pstr = grabstackstr(pout);
11300 setinputstring(pstr);
11305 nlpp = &(*nlpp)->next;
11306 *nlpp = stzalloc(sizeof(**nlpp));
11307 /* (*nlpp)->next = NULL; - stzalloc did it */
11308 parsebackquote = oldstyle;
11311 saveprompt = doprompt;
11318 doprompt = saveprompt;
11319 else if (readtoken() != TRP)
11320 raise_error_unexpected_syntax(TRP);
11325 * Start reading from old file again, ignoring any pushed back
11326 * tokens left from the backquote parsing
11331 while (stackblocksize() <= savelen)
11333 STARTSTACKSTR(out);
11335 memcpy(out, str, savelen);
11336 STADJUST(savelen, out);
11342 parsebackquote = savepbq;
11343 exception_handler = savehandler;
11344 if (arinest || dblquote)
11345 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11347 USTPUTC(CTLBACKQ, out);
11349 goto parsebackq_oldreturn;
11350 goto parsebackq_newreturn;
11353 #if ENABLE_ASH_MATH_SUPPORT
11355 * Parse an arithmetic expansion (indicate start of one and set state)
11358 if (++arinest == 1) {
11359 prevsyntax = syntax;
11360 syntax = ARISYNTAX;
11361 USTPUTC(CTLARI, out);
11368 * we collapse embedded arithmetic expansion to
11369 * parenthesis, which should be equivalent
11373 goto parsearith_return;
11377 } /* end of readtoken */
11380 * Read the next input token.
11381 * If the token is a word, we set backquotelist to the list of cmds in
11382 * backquotes. We set quoteflag to true if any part of the word was
11384 * If the token is TREDIR, then we set redirnode to a structure containing
11386 * In all cases, the variable startlinno is set to the number of the line
11387 * on which the token starts.
11389 * [Change comment: here documents and internal procedures]
11390 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11391 * word parsing code into a separate routine. In this case, readtoken
11392 * doesn't need to have any internal procedures, but parseword does.
11393 * We could also make parseoperator in essence the main routine, and
11394 * have parseword (readtoken1?) handle both words and redirection.]
11396 #define NEW_xxreadtoken
11397 #ifdef NEW_xxreadtoken
11398 /* singles must be first! */
11399 static const char xxreadtoken_chars[7] ALIGN1 = {
11400 '\n', '(', ')', /* singles */
11401 '&', '|', ';', /* doubles */
11405 #define xxreadtoken_singles 3
11406 #define xxreadtoken_doubles 3
11408 static const char xxreadtoken_tokens[] ALIGN1 = {
11409 TNL, TLP, TRP, /* only single occurrence allowed */
11410 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11411 TEOF, /* corresponds to trailing nul */
11412 TAND, TOR, TENDCASE /* if double occurrence */
11427 startlinno = g_parsefile->linno;
11428 for (;;) { /* until token or start of word found */
11430 if (c == ' ' || c == '\t' USE_ASH_ALIAS( || c == PEOA))
11434 while ((c = pgetc()) != '\n' && c != PEOF)
11437 } else if (c == '\\') {
11438 if (pgetc() != '\n') {
11440 break; /* return readtoken1(...) */
11442 startlinno = ++g_parsefile->linno;
11448 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11451 g_parsefile->linno++;
11452 needprompt = doprompt;
11455 p = strchr(xxreadtoken_chars, c);
11457 break; /* return readtoken1(...) */
11459 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11461 if (cc == c) { /* double occurrence? */
11462 p += xxreadtoken_doubles + 1;
11465 #if ENABLE_ASH_BASH_COMPAT
11466 if (c == '&' && cc == '>') /* &> */
11467 break; /* return readtoken1(...) */
11472 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11477 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11479 #else /* old xxreadtoken */
11480 #define RETURN(token) return lasttoken = token
11493 startlinno = g_parsefile->linno;
11494 for (;;) { /* until token or start of word found */
11497 case ' ': case '\t':
11498 #if ENABLE_ASH_ALIAS
11503 while ((c = pgetc()) != '\n' && c != PEOF)
11508 if (pgetc() == '\n') {
11509 startlinno = ++g_parsefile->linno;
11517 g_parsefile->linno++;
11518 needprompt = doprompt;
11523 if (pgetc() == '&')
11528 if (pgetc() == '|')
11533 if (pgetc() == ';')
11546 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11549 #endif /* old xxreadtoken */
11556 smallint alreadyseen = tokpushback;
11559 #if ENABLE_ASH_ALIAS
11568 if (checkkwd & CHKNL) {
11575 if (t != TWORD || quoteflag) {
11580 * check for keywords
11582 if (checkkwd & CHKKWD) {
11583 const char *const *pp;
11585 pp = findkwd(wordtext);
11587 lasttoken = t = pp - tokname_array;
11588 TRACE(("keyword %s recognized\n", tokname(t)));
11593 if (checkkwd & CHKALIAS) {
11594 #if ENABLE_ASH_ALIAS
11596 ap = lookupalias(wordtext, 1);
11599 pushstring(ap->val, ap);
11609 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11611 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11623 return tokname_array[t][0];
11627 * Read and parse a command. Returns NEOF on end of file. (NULL is a
11628 * valid parse tree indicating a blank line.)
11630 static union node *
11631 parsecmd(int interact)
11636 doprompt = interact;
11638 setprompt(doprompt);
11650 * Input any here documents.
11655 struct heredoc *here;
11658 here = heredoclist;
11659 heredoclist = NULL;
11665 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
11666 here->eofmark, here->striptabs);
11667 n = stzalloc(sizeof(struct narg));
11668 n->narg.type = NARG;
11669 /*n->narg.next = NULL; - stzalloc did it */
11670 n->narg.text = wordtext;
11671 n->narg.backquote = backquotelist;
11672 here->here->nhere.doc = n;
11679 * called by editline -- any expansions to the prompt should be added here.
11681 #if ENABLE_ASH_EXPAND_PRMT
11682 static const char *
11683 expandstr(const char *ps)
11687 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
11688 * and token processing _can_ alter it (delete NULs etc). */
11689 setinputstring((char *)ps);
11690 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
11693 n.narg.type = NARG;
11694 n.narg.next = NULL;
11695 n.narg.text = wordtext;
11696 n.narg.backquote = backquotelist;
11698 expandarg(&n, NULL, 0);
11699 return stackblock();
11704 * Execute a command or commands contained in a string.
11707 evalstring(char *s, int mask)
11710 struct stackmark smark;
11714 setstackmark(&smark);
11717 while ((n = parsecmd(0)) != NEOF) {
11719 popstackmark(&smark);
11732 * The eval command.
11735 evalcmd(int argc UNUSED_PARAM, char **argv)
11744 STARTSTACKSTR(concat);
11746 concat = stack_putstr(p, concat);
11750 STPUTC(' ', concat);
11752 STPUTC('\0', concat);
11753 p = grabstackstr(concat);
11755 evalstring(p, ~SKIPEVAL);
11762 * Read and execute commands. "Top" is nonzero for the top level command
11763 * loop; it turns on prompting if the shell is interactive.
11769 struct stackmark smark;
11773 TRACE(("cmdloop(%d) called\n", top));
11777 setstackmark(&smark);
11780 showjobs(stderr, SHOW_CHANGED);
11783 if (iflag && top) {
11785 #if ENABLE_ASH_MAIL
11789 n = parsecmd(inter);
11790 /* showtree(n); DEBUG */
11792 if (!top || numeof >= 50)
11794 if (!stoppedjobs()) {
11797 out2str("\nUse \"exit\" to leave shell.\n");
11800 } else if (nflag == 0) {
11801 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11806 popstackmark(&smark);
11811 return skip & SKIPEVAL;
11818 * Take commands from a file. To be compatible we should do a path
11819 * search for the file, which is necessary to find sub-commands.
11822 find_dot_file(char *name)
11825 const char *path = pathval();
11828 /* don't try this for absolute or relative paths */
11829 if (strchr(name, '/'))
11832 /* IIRC standards do not say whether . is to be searched.
11833 * And it is even smaller this way, making it unconditional for now:
11835 if (1) { /* ENABLE_ASH_BASH_COMPAT */
11840 while ((fullname = padvance(&path, name)) != NULL) {
11842 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11844 * Don't bother freeing here, since it will
11845 * be freed by the caller.
11849 stunalloc(fullname);
11852 /* not found in the PATH */
11853 ash_msg_and_raise_error("%s: not found", name);
11858 dotcmd(int argc, char **argv)
11860 struct strlist *sp;
11861 volatile struct shparam saveparam;
11864 for (sp = cmdenviron; sp; sp = sp->next)
11865 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11867 if (argv[1]) { /* That's what SVR2 does */
11868 char *fullname = find_dot_file(argv[1]);
11871 if (argc) { /* argc > 0, argv[0] != NULL */
11872 saveparam = shellparam;
11873 shellparam.malloced = 0;
11874 shellparam.nparam = argc;
11875 shellparam.p = argv;
11878 setinputfile(fullname, INPUT_PUSH_FILE);
11879 commandname = fullname;
11884 freeparam(&shellparam);
11885 shellparam = saveparam;
11887 status = exitstatus;
11893 exitcmd(int argc UNUSED_PARAM, char **argv)
11898 exitstatus = number(argv[1]);
11899 raise_exception(EXEXIT);
11904 * Read a file containing shell functions.
11907 readcmdfile(char *name)
11909 setinputfile(name, INPUT_PUSH_FILE);
11915 /* ============ find_command inplementation */
11918 * Resolve a command name. If you change this routine, you may have to
11919 * change the shellexec routine as well.
11922 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11924 struct tblentry *cmdp;
11931 struct builtincmd *bcmd;
11933 /* If name contains a slash, don't use PATH or hash table */
11934 if (strchr(name, '/') != NULL) {
11935 entry->u.index = -1;
11936 if (act & DO_ABS) {
11937 while (stat(name, &statb) < 0) {
11939 if (errno == EINTR)
11942 entry->cmdtype = CMDUNKNOWN;
11946 entry->cmdtype = CMDNORMAL;
11950 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
11952 updatetbl = (path == pathval());
11955 if (strstr(path, "%builtin") != NULL)
11956 act |= DO_ALTBLTIN;
11959 /* If name is in the table, check answer will be ok */
11960 cmdp = cmdlookup(name, 0);
11961 if (cmdp != NULL) {
11964 switch (cmdp->cmdtype) {
11982 } else if (cmdp->rehash == 0)
11983 /* if not invalidated by cd, we're done */
11987 /* If %builtin not in path, check for builtin next */
11988 bcmd = find_builtin(name);
11990 if (IS_BUILTIN_REGULAR(bcmd))
11991 goto builtin_success;
11992 if (act & DO_ALTPATH) {
11993 if (!(act & DO_ALTBLTIN))
11994 goto builtin_success;
11995 } else if (builtinloc <= 0) {
11996 goto builtin_success;
12000 #if ENABLE_FEATURE_SH_STANDALONE
12002 int applet_no = find_applet_by_name(name);
12003 if (applet_no >= 0) {
12004 entry->cmdtype = CMDNORMAL;
12005 entry->u.index = -2 - applet_no;
12011 /* We have to search path. */
12012 prev = -1; /* where to start */
12013 if (cmdp && cmdp->rehash) { /* doing a rehash */
12014 if (cmdp->cmdtype == CMDBUILTIN)
12017 prev = cmdp->param.index;
12023 while ((fullname = padvance(&path, name)) != NULL) {
12024 stunalloc(fullname);
12025 /* NB: code below will still use fullname
12026 * despite it being "unallocated" */
12029 if (prefix(pathopt, "builtin")) {
12031 goto builtin_success;
12034 if ((act & DO_NOFUNC)
12035 || !prefix(pathopt, "func")
12036 ) { /* ignore unimplemented options */
12040 /* if rehash, don't redo absolute path names */
12041 if (fullname[0] == '/' && idx <= prev) {
12044 TRACE(("searchexec \"%s\": no change\n", name));
12047 while (stat(fullname, &statb) < 0) {
12049 if (errno == EINTR)
12052 if (errno != ENOENT && errno != ENOTDIR)
12056 e = EACCES; /* if we fail, this will be the error */
12057 if (!S_ISREG(statb.st_mode))
12059 if (pathopt) { /* this is a %func directory */
12060 stalloc(strlen(fullname) + 1);
12061 /* NB: stalloc will return space pointed by fullname
12062 * (because we don't have any intervening allocations
12063 * between stunalloc above and this stalloc) */
12064 readcmdfile(fullname);
12065 cmdp = cmdlookup(name, 0);
12066 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12067 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12068 stunalloc(fullname);
12071 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12073 entry->cmdtype = CMDNORMAL;
12074 entry->u.index = idx;
12078 cmdp = cmdlookup(name, 1);
12079 cmdp->cmdtype = CMDNORMAL;
12080 cmdp->param.index = idx;
12085 /* We failed. If there was an entry for this command, delete it */
12086 if (cmdp && updatetbl)
12087 delete_cmd_entry();
12089 ash_msg("%s: %s", name, errmsg(e, "not found"));
12090 entry->cmdtype = CMDUNKNOWN;
12095 entry->cmdtype = CMDBUILTIN;
12096 entry->u.cmd = bcmd;
12100 cmdp = cmdlookup(name, 1);
12101 cmdp->cmdtype = CMDBUILTIN;
12102 cmdp->param.cmd = bcmd;
12106 entry->cmdtype = cmdp->cmdtype;
12107 entry->u = cmdp->param;
12111 /* ============ trap.c */
12114 * The trap builtin.
12117 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12126 for (signo = 0; signo < NSIG; signo++) {
12127 if (trap[signo] != NULL) {
12128 out1fmt("trap -- %s %s\n",
12129 single_quote(trap[signo]),
12130 get_signame(signo));
12139 signo = get_signum(*ap);
12141 ash_msg_and_raise_error("%s: bad trap", *ap);
12144 if (LONE_DASH(action))
12147 action = ckstrdup(action);
12150 trap[signo] = action;
12160 /* ============ Builtins */
12162 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
12164 * Lists available builtins
12167 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12172 out1fmt("\nBuilt-in commands:\n-------------------\n");
12173 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12174 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12175 builtintab[i].name + 1);
12181 #if ENABLE_FEATURE_SH_STANDALONE
12183 const char *a = applet_names;
12185 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12190 a += strlen(a) + 1;
12195 return EXIT_SUCCESS;
12197 #endif /* FEATURE_SH_EXTRA_QUIET */
12200 * The export and readonly commands.
12203 exportcmd(int argc UNUSED_PARAM, char **argv)
12209 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;
12211 if (nextopt("p") != 'p') {
12216 p = strchr(name, '=');
12220 vp = *findvar(hashvar(name), name);
12226 setvar(name, p, flag);
12227 } while ((name = *++aptr) != NULL);
12231 showvars(argv[0], flag, 0);
12236 * Delete a function if it exists.
12239 unsetfunc(const char *name)
12241 struct tblentry *cmdp;
12243 cmdp = cmdlookup(name, 0);
12244 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
12245 delete_cmd_entry();
12249 * The unset builtin command. We unset the function before we unset the
12250 * variable to allow a function to be unset when there is a readonly variable
12251 * with the same name.
12254 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12261 while ((i = nextopt("vf")) != '\0') {
12265 for (ap = argptr; *ap; ap++) {
12281 #include <sys/times.h>
12283 static const unsigned char timescmd_str[] ALIGN1 = {
12284 ' ', offsetof(struct tms, tms_utime),
12285 '\n', offsetof(struct tms, tms_stime),
12286 ' ', offsetof(struct tms, tms_cutime),
12287 '\n', offsetof(struct tms, tms_cstime),
12292 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12294 long clk_tck, s, t;
12295 const unsigned char *p;
12298 clk_tck = sysconf(_SC_CLK_TCK);
12303 t = *(clock_t *)(((char *) &buf) + p[1]);
12305 out1fmt("%ldm%ld.%.3lds%c",
12307 ((t - s * clk_tck) * 1000) / clk_tck,
12309 } while (*(p += 2));
12314 #if ENABLE_ASH_MATH_SUPPORT
12316 dash_arith(const char *s)
12322 result = arith(s, &errcode);
12325 ash_msg_and_raise_error("exponent less than 0");
12327 ash_msg_and_raise_error("divide by zero");
12329 ash_msg_and_raise_error("expression recursion loop detected");
12330 raise_error_syntax(s);
12338 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12339 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12341 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12344 letcmd(int argc UNUSED_PARAM, char **argv)
12350 ash_msg_and_raise_error("expression expected");
12352 i = dash_arith(*argv);
12357 #endif /* ASH_MATH_SUPPORT */
12360 /* ============ miscbltin.c
12362 * Miscellaneous builtins.
12367 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12368 typedef enum __rlimit_resource rlim_t;
12372 * The read builtin. Options:
12373 * -r Do not interpret '\' specially
12374 * -s Turn off echo (tty only)
12375 * -n NCHARS Read NCHARS max
12376 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12377 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12378 * -u FD Read from given FD instead of fd 0
12379 * This uses unbuffered input, which may be avoidable in some cases.
12380 * TODO: bash also has:
12381 * -a ARRAY Read into array[0],[1],etc
12382 * -d DELIM End on DELIM char, not newline
12383 * -e Use line editing (tty only)
12386 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12388 static const char *const arg_REPLY[] = { "REPLY", NULL };
12401 #if ENABLE_ASH_READ_NCHARS
12402 int nchars = 0; /* if != 0, -n is in effect */
12404 struct termios tty, old_tty;
12406 #if ENABLE_ASH_READ_TIMEOUT
12407 unsigned end_ms = 0;
12408 unsigned timeout = 0;
12413 while ((i = nextopt("p:u:r"
12414 USE_ASH_READ_TIMEOUT("t:")
12415 USE_ASH_READ_NCHARS("n:s")
12419 prompt = optionarg;
12421 #if ENABLE_ASH_READ_NCHARS
12423 nchars = bb_strtou(optionarg, NULL, 10);
12424 if (nchars < 0 || errno)
12425 ash_msg_and_raise_error("invalid count");
12426 /* nchars == 0: off (bash 3.2 does this too) */
12432 #if ENABLE_ASH_READ_TIMEOUT
12434 timeout = bb_strtou(optionarg, NULL, 10);
12435 if (errno || timeout > UINT_MAX / 2048)
12436 ash_msg_and_raise_error("invalid timeout");
12438 #if 0 /* even bash have no -t N.NNN support */
12439 ts.tv_sec = bb_strtou(optionarg, &p, 10);
12441 /* EINVAL means number is ok, but not terminated by NUL */
12442 if (*p == '.' && errno == EINVAL) {
12446 ts.tv_usec = bb_strtou(p, &p2, 10);
12448 ash_msg_and_raise_error("invalid timeout");
12450 /* normalize to usec */
12452 ash_msg_and_raise_error("invalid timeout");
12453 while (scale++ < 6)
12456 } else if (ts.tv_sec < 0 || errno) {
12457 ash_msg_and_raise_error("invalid timeout");
12459 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
12460 ash_msg_and_raise_error("invalid timeout");
12469 fd = bb_strtou(optionarg, NULL, 10);
12470 if (fd < 0 || errno)
12471 ash_msg_and_raise_error("invalid file descriptor");
12477 if (prompt && isatty(fd)) {
12482 ap = (char**)arg_REPLY;
12483 ifs = bltinlookup("IFS");
12486 #if ENABLE_ASH_READ_NCHARS
12487 tcgetattr(fd, &tty);
12489 if (nchars || silent) {
12491 tty.c_lflag &= ~ICANON;
12492 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
12495 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
12497 /* if tcgetattr failed, tcsetattr will fail too.
12498 * Ignoring, it's harmless. */
12499 tcsetattr(fd, TCSANOW, &tty);
12506 #if ENABLE_ASH_READ_TIMEOUT
12507 if (timeout) /* NB: ensuring end_ms is nonzero */
12508 end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1;
12512 #if ENABLE_ASH_READ_TIMEOUT
12514 struct pollfd pfd[1];
12516 pfd[0].events = POLLIN;
12517 timeout = end_ms - (unsigned)(monotonic_us() / 1000);
12518 if ((int)timeout <= 0 /* already late? */
12519 || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
12520 ) { /* timed out! */
12521 #if ENABLE_ASH_READ_NCHARS
12522 tcsetattr(fd, TCSANOW, &old_tty);
12528 if (nonblock_safe_read(fd, &c, 1) != 1) {
12540 if (!rflag && c == '\\') {
12546 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12550 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12552 setvar(*ap, stackblock(), 0);
12561 /* end of do {} while: */
12562 #if ENABLE_ASH_READ_NCHARS
12568 #if ENABLE_ASH_READ_NCHARS
12569 tcsetattr(fd, TCSANOW, &old_tty);
12573 /* Remove trailing blanks */
12574 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12576 setvar(*ap, stackblock(), 0);
12577 while (*++ap != NULL)
12578 setvar(*ap, nullstr, 0);
12583 umaskcmd(int argc UNUSED_PARAM, char **argv)
12585 static const char permuser[3] ALIGN1 = "ugo";
12586 static const char permmode[3] ALIGN1 = "rwx";
12587 static const short permmask[] ALIGN2 = {
12588 S_IRUSR, S_IWUSR, S_IXUSR,
12589 S_IRGRP, S_IWGRP, S_IXGRP,
12590 S_IROTH, S_IWOTH, S_IXOTH
12596 int symbolic_mode = 0;
12598 while (nextopt("S") != '\0') {
12609 if (symbolic_mode) {
12613 for (i = 0; i < 3; i++) {
12616 *p++ = permuser[i];
12618 for (j = 0; j < 3; j++) {
12619 if ((mask & permmask[3 * i + j]) == 0) {
12620 *p++ = permmode[j];
12628 out1fmt("%.4o\n", mask);
12631 if (isdigit((unsigned char) *ap)) {
12634 if (*ap >= '8' || *ap < '0')
12635 ash_msg_and_raise_error(illnum, argv[1]);
12636 mask = (mask << 3) + (*ap - '0');
12637 } while (*++ap != '\0');
12640 mask = ~mask & 0777;
12641 if (!bb_parse_mode(ap, &mask)) {
12642 ash_msg_and_raise_error("illegal mode: %s", ap);
12644 umask(~mask & 0777);
12653 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12654 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12655 * ash by J.T. Conklin.
12661 uint8_t cmd; /* RLIMIT_xxx fit into it */
12662 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
12666 static const struct limits limits_tbl[] = {
12668 { RLIMIT_CPU, 0, 't' },
12670 #ifdef RLIMIT_FSIZE
12671 { RLIMIT_FSIZE, 9, 'f' },
12674 { RLIMIT_DATA, 10, 'd' },
12676 #ifdef RLIMIT_STACK
12677 { RLIMIT_STACK, 10, 's' },
12680 { RLIMIT_CORE, 9, 'c' },
12683 { RLIMIT_RSS, 10, 'm' },
12685 #ifdef RLIMIT_MEMLOCK
12686 { RLIMIT_MEMLOCK, 10, 'l' },
12688 #ifdef RLIMIT_NPROC
12689 { RLIMIT_NPROC, 0, 'p' },
12691 #ifdef RLIMIT_NOFILE
12692 { RLIMIT_NOFILE, 0, 'n' },
12695 { RLIMIT_AS, 10, 'v' },
12697 #ifdef RLIMIT_LOCKS
12698 { RLIMIT_LOCKS, 0, 'w' },
12701 static const char limits_name[] =
12703 "time(seconds)" "\0"
12705 #ifdef RLIMIT_FSIZE
12706 "file(blocks)" "\0"
12711 #ifdef RLIMIT_STACK
12715 "coredump(blocks)" "\0"
12720 #ifdef RLIMIT_MEMLOCK
12721 "locked memory(kb)" "\0"
12723 #ifdef RLIMIT_NPROC
12726 #ifdef RLIMIT_NOFILE
12732 #ifdef RLIMIT_LOCKS
12737 enum limtype { SOFT = 0x1, HARD = 0x2 };
12740 printlim(enum limtype how, const struct rlimit *limit,
12741 const struct limits *l)
12745 val = limit->rlim_max;
12747 val = limit->rlim_cur;
12749 if (val == RLIM_INFINITY)
12750 out1fmt("unlimited\n");
12752 val >>= l->factor_shift;
12753 out1fmt("%lld\n", (long long) val);
12758 ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12762 enum limtype how = SOFT | HARD;
12763 const struct limits *l;
12766 struct rlimit limit;
12769 while ((optc = nextopt("HSa"
12773 #ifdef RLIMIT_FSIZE
12779 #ifdef RLIMIT_STACK
12788 #ifdef RLIMIT_MEMLOCK
12791 #ifdef RLIMIT_NPROC
12794 #ifdef RLIMIT_NOFILE
12800 #ifdef RLIMIT_LOCKS
12818 for (l = limits_tbl; l->option != what; l++)
12821 set = *argptr ? 1 : 0;
12825 if (all || argptr[1])
12826 ash_msg_and_raise_error("too many arguments");
12827 if (strncmp(p, "unlimited\n", 9) == 0)
12828 val = RLIM_INFINITY;
12832 while ((c = *p++) >= '0' && c <= '9') {
12833 val = (val * 10) + (long)(c - '0');
12834 // val is actually 'unsigned long int' and can't get < 0
12835 if (val < (rlim_t) 0)
12839 ash_msg_and_raise_error("bad number");
12840 val <<= l->factor_shift;
12844 const char *lname = limits_name;
12845 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12846 getrlimit(l->cmd, &limit);
12847 out1fmt("%-20s ", lname);
12848 lname += strlen(lname) + 1;
12849 printlim(how, &limit, l);
12854 getrlimit(l->cmd, &limit);
12857 limit.rlim_max = val;
12859 limit.rlim_cur = val;
12860 if (setrlimit(l->cmd, &limit) < 0)
12861 ash_msg_and_raise_error("error setting limit (%m)");
12863 printlim(how, &limit, l);
12869 /* ============ Math support */
12871 #if ENABLE_ASH_MATH_SUPPORT
12873 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12875 Permission is hereby granted, free of charge, to any person obtaining
12876 a copy of this software and associated documentation files (the
12877 "Software"), to deal in the Software without restriction, including
12878 without limitation the rights to use, copy, modify, merge, publish,
12879 distribute, sublicense, and/or sell copies of the Software, and to
12880 permit persons to whom the Software is furnished to do so, subject to
12881 the following conditions:
12883 The above copyright notice and this permission notice shall be
12884 included in all copies or substantial portions of the Software.
12886 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12887 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12888 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12889 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12890 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12891 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12892 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12895 /* This is my infix parser/evaluator. It is optimized for size, intended
12896 * as a replacement for yacc-based parsers. However, it may well be faster
12897 * than a comparable parser written in yacc. The supported operators are
12898 * listed in #defines below. Parens, order of operations, and error handling
12899 * are supported. This code is thread safe. The exact expression format should
12900 * be that which POSIX specifies for shells. */
12902 /* The code uses a simple two-stack algorithm. See
12903 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12904 * for a detailed explanation of the infix-to-postfix algorithm on which
12905 * this is based (this code differs in that it applies operators immediately
12906 * to the stack instead of adding them to a queue to end up with an
12909 /* To use the routine, call it with an expression string and error return
12913 * Aug 24, 2001 Manuel Novoa III
12915 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12917 * 1) In arith_apply():
12918 * a) Cached values of *numptr and &(numptr[-1]).
12919 * b) Removed redundant test for zero denominator.
12922 * a) Eliminated redundant code for processing operator tokens by moving
12923 * to a table-based implementation. Also folded handling of parens
12925 * b) Combined all 3 loops which called arith_apply to reduce generated
12926 * code size at the cost of speed.
12928 * 3) The following expressions were treated as valid by the original code:
12929 * 1() , 0! , 1 ( *3 ) .
12930 * These bugs have been fixed by internally enclosing the expression in
12931 * parens and then checking that all binary ops and right parens are
12932 * preceded by a valid expression (NUM_TOKEN).
12934 * Note: It may be desirable to replace Aaron's test for whitespace with
12935 * ctype's isspace() if it is used by another busybox applet or if additional
12936 * whitespace chars should be considered. Look below the "#include"s for a
12937 * precompiler test.
12941 * Aug 26, 2001 Manuel Novoa III
12943 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12945 * Merge in Aaron's comments previously posted to the busybox list,
12946 * modified slightly to take account of my changes to the code.
12951 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12953 * - allow access to variable,
12954 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12955 * - realize assign syntax (VAR=expr, +=, *= etc)
12956 * - realize exponentiation (** operator)
12957 * - realize comma separated - expr, expr
12958 * - realise ++expr --expr expr++ expr--
12959 * - realise expr ? expr : expr (but, second expr calculate always)
12960 * - allow hexadecimal and octal numbers
12961 * - was restored loses XOR operator
12962 * - remove one goto label, added three ;-)
12963 * - protect $((num num)) as true zero expr (Manuel`s error)
12964 * - always use special isspace(), see comment from bash ;-)
12967 #define arith_isspace(arithval) \
12968 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12970 typedef unsigned char operator;
12972 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12973 * precedence, and 3 high bits are an ID unique across operators of that
12974 * precedence. The ID portion is so that multiple operators can have the
12975 * same precedence, ensuring that the leftmost one is evaluated first.
12976 * Consider * and /. */
12978 #define tok_decl(prec,id) (((id)<<5)|(prec))
12979 #define PREC(op) ((op) & 0x1F)
12981 #define TOK_LPAREN tok_decl(0,0)
12983 #define TOK_COMMA tok_decl(1,0)
12985 #define TOK_ASSIGN tok_decl(2,0)
12986 #define TOK_AND_ASSIGN tok_decl(2,1)
12987 #define TOK_OR_ASSIGN tok_decl(2,2)
12988 #define TOK_XOR_ASSIGN tok_decl(2,3)
12989 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12990 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12991 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12992 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12994 #define TOK_MUL_ASSIGN tok_decl(3,0)
12995 #define TOK_DIV_ASSIGN tok_decl(3,1)
12996 #define TOK_REM_ASSIGN tok_decl(3,2)
12998 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12999 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
13001 /* conditional is right associativity too */
13002 #define TOK_CONDITIONAL tok_decl(4,0)
13003 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
13005 #define TOK_OR tok_decl(5,0)
13007 #define TOK_AND tok_decl(6,0)
13009 #define TOK_BOR tok_decl(7,0)
13011 #define TOK_BXOR tok_decl(8,0)
13013 #define TOK_BAND tok_decl(9,0)
13015 #define TOK_EQ tok_decl(10,0)
13016 #define TOK_NE tok_decl(10,1)
13018 #define TOK_LT tok_decl(11,0)
13019 #define TOK_GT tok_decl(11,1)
13020 #define TOK_GE tok_decl(11,2)
13021 #define TOK_LE tok_decl(11,3)
13023 #define TOK_LSHIFT tok_decl(12,0)
13024 #define TOK_RSHIFT tok_decl(12,1)
13026 #define TOK_ADD tok_decl(13,0)
13027 #define TOK_SUB tok_decl(13,1)
13029 #define TOK_MUL tok_decl(14,0)
13030 #define TOK_DIV tok_decl(14,1)
13031 #define TOK_REM tok_decl(14,2)
13033 /* exponent is right associativity */
13034 #define TOK_EXPONENT tok_decl(15,1)
13036 /* For now unary operators. */
13037 #define UNARYPREC 16
13038 #define TOK_BNOT tok_decl(UNARYPREC,0)
13039 #define TOK_NOT tok_decl(UNARYPREC,1)
13041 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13042 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13044 #define PREC_PRE (UNARYPREC+2)
13046 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13047 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13049 #define PREC_POST (UNARYPREC+3)
13051 #define TOK_POST_INC tok_decl(PREC_POST, 0)
13052 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
13054 #define SPEC_PREC (UNARYPREC+4)
13056 #define TOK_NUM tok_decl(SPEC_PREC, 0)
13057 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13059 #define NUMPTR (*numstackptr)
13062 tok_have_assign(operator op)
13064 operator prec = PREC(op);
13066 convert_prec_is_assing(prec);
13067 return (prec == PREC(TOK_ASSIGN) ||
13068 prec == PREC_PRE || prec == PREC_POST);
13072 is_right_associativity(operator prec)
13074 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
13075 || prec == PREC(TOK_CONDITIONAL));
13080 arith_t contidional_second_val;
13081 char contidional_second_val_initialized;
13082 char *var; /* if NULL then is regular number,
13083 else is variable name */
13086 typedef struct chk_var_recursive_looped_t {
13088 struct chk_var_recursive_looped_t *next;
13089 } chk_var_recursive_looped_t;
13091 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13094 arith_lookup_val(v_n_t *t)
13097 const char * p = lookupvar(t->var);
13102 /* recursive try as expression */
13103 chk_var_recursive_looped_t *cur;
13104 chk_var_recursive_looped_t cur_save;
13106 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
13107 if (strcmp(cur->var, t->var) == 0) {
13108 /* expression recursion loop detected */
13112 /* save current lookuped var name */
13113 cur = prev_chk_var_recursive;
13114 cur_save.var = t->var;
13115 cur_save.next = cur;
13116 prev_chk_var_recursive = &cur_save;
13118 t->val = arith (p, &errcode);
13119 /* restore previous ptr after recursiving */
13120 prev_chk_var_recursive = cur;
13123 /* allow undefined var as 0 */
13129 /* "applying" a token means performing it on the top elements on the integer
13130 * stack. For a unary operator it will only change the top element, but a
13131 * binary operator will pop two arguments and push a result */
13133 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13136 arith_t numptr_val, rez;
13137 int ret_arith_lookup_val;
13139 /* There is no operator that can work without arguments */
13140 if (NUMPTR == numstack) goto err;
13141 numptr_m1 = NUMPTR - 1;
13143 /* check operand is var with noninteger value */
13144 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13145 if (ret_arith_lookup_val)
13146 return ret_arith_lookup_val;
13148 rez = numptr_m1->val;
13149 if (op == TOK_UMINUS)
13151 else if (op == TOK_NOT)
13153 else if (op == TOK_BNOT)
13155 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13157 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13159 else if (op != TOK_UPLUS) {
13160 /* Binary operators */
13162 /* check and binary operators need two arguments */
13163 if (numptr_m1 == numstack) goto err;
13165 /* ... and they pop one */
13168 if (op == TOK_CONDITIONAL) {
13169 if (!numptr_m1->contidional_second_val_initialized) {
13170 /* protect $((expr1 ? expr2)) without ": expr" */
13173 rez = numptr_m1->contidional_second_val;
13174 } else if (numptr_m1->contidional_second_val_initialized) {
13175 /* protect $((expr1 : expr2)) without "expr ? " */
13178 numptr_m1 = NUMPTR - 1;
13179 if (op != TOK_ASSIGN) {
13180 /* check operand is var with noninteger value for not '=' */
13181 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13182 if (ret_arith_lookup_val)
13183 return ret_arith_lookup_val;
13185 if (op == TOK_CONDITIONAL) {
13186 numptr_m1->contidional_second_val = rez;
13188 rez = numptr_m1->val;
13189 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13191 else if (op == TOK_OR)
13192 rez = numptr_val || rez;
13193 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13195 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13197 else if (op == TOK_AND)
13198 rez = rez && numptr_val;
13199 else if (op == TOK_EQ)
13200 rez = (rez == numptr_val);
13201 else if (op == TOK_NE)
13202 rez = (rez != numptr_val);
13203 else if (op == TOK_GE)
13204 rez = (rez >= numptr_val);
13205 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13206 rez >>= numptr_val;
13207 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13208 rez <<= numptr_val;
13209 else if (op == TOK_GT)
13210 rez = (rez > numptr_val);
13211 else if (op == TOK_LT)
13212 rez = (rez < numptr_val);
13213 else if (op == TOK_LE)
13214 rez = (rez <= numptr_val);
13215 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13217 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13219 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13221 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13223 else if (op == TOK_CONDITIONAL_SEP) {
13224 if (numptr_m1 == numstack) {
13225 /* protect $((expr : expr)) without "expr ? " */
13228 numptr_m1->contidional_second_val_initialized = op;
13229 numptr_m1->contidional_second_val = numptr_val;
13230 } else if (op == TOK_CONDITIONAL) {
13232 numptr_val : numptr_m1->contidional_second_val;
13233 } else if (op == TOK_EXPONENT) {
13234 if (numptr_val < 0)
13235 return -3; /* exponent less than 0 */
13240 while (numptr_val--)
13244 } else if (numptr_val==0) /* zero divisor check */
13246 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13248 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13251 if (tok_have_assign(op)) {
13252 char buf[sizeof(arith_t_type)*3 + 2];
13254 if (numptr_m1->var == NULL) {
13258 /* save to shell variable */
13259 #if ENABLE_ASH_MATH_SUPPORT_64
13260 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez);
13262 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez);
13264 setvar(numptr_m1->var, buf, 0);
13265 /* after saving, make previous value for v++ or v-- */
13266 if (op == TOK_POST_INC)
13268 else if (op == TOK_POST_DEC)
13271 numptr_m1->val = rez;
13272 /* protect geting var value, is number now */
13273 numptr_m1->var = NULL;
13279 /* longest must be first */
13280 static const char op_tokens[] ALIGN1 = {
13281 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13282 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13283 '<','<', 0, TOK_LSHIFT,
13284 '>','>', 0, TOK_RSHIFT,
13285 '|','|', 0, TOK_OR,
13286 '&','&', 0, TOK_AND,
13287 '!','=', 0, TOK_NE,
13288 '<','=', 0, TOK_LE,
13289 '>','=', 0, TOK_GE,
13290 '=','=', 0, TOK_EQ,
13291 '|','=', 0, TOK_OR_ASSIGN,
13292 '&','=', 0, TOK_AND_ASSIGN,
13293 '*','=', 0, TOK_MUL_ASSIGN,
13294 '/','=', 0, TOK_DIV_ASSIGN,
13295 '%','=', 0, TOK_REM_ASSIGN,
13296 '+','=', 0, TOK_PLUS_ASSIGN,
13297 '-','=', 0, TOK_MINUS_ASSIGN,
13298 '-','-', 0, TOK_POST_DEC,
13299 '^','=', 0, TOK_XOR_ASSIGN,
13300 '+','+', 0, TOK_POST_INC,
13301 '*','*', 0, TOK_EXPONENT,
13305 '=', 0, TOK_ASSIGN,
13317 '?', 0, TOK_CONDITIONAL,
13318 ':', 0, TOK_CONDITIONAL_SEP,
13319 ')', 0, TOK_RPAREN,
13320 '(', 0, TOK_LPAREN,
13324 #define endexpression (&op_tokens[sizeof(op_tokens)-7])
13327 arith(const char *expr, int *perrcode)
13329 char arithval; /* Current character under analysis */
13330 operator lasttok, op;
13332 operator *stack, *stackptr;
13333 const char *p = endexpression;
13335 v_n_t *numstack, *numstackptr;
13336 unsigned datasizes = strlen(expr) + 2;
13338 /* Stack of integers */
13339 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13340 * in any given correct or incorrect expression is left as an exercise to
13342 numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0]));
13343 /* Stack of operator tokens */
13344 stackptr = stack = alloca(datasizes * sizeof(stack[0]));
13346 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13347 *perrcode = errcode = 0;
13351 if (arithval == 0) {
13352 if (p == endexpression) {
13353 /* Null expression. */
13357 /* This is only reached after all tokens have been extracted from the
13358 * input stream. If there are still tokens on the operator stack, they
13359 * are to be applied in order. At the end, there should be a final
13360 * result on the integer stack */
13362 if (expr != endexpression + 1) {
13363 /* If we haven't done so already, */
13364 /* append a closing right paren */
13365 expr = endexpression;
13366 /* and let the loop process it. */
13369 /* At this point, we're done with the expression. */
13370 if (numstackptr != numstack+1) {
13371 /* ... but if there isn't, it's bad */
13376 if (numstack->var) {
13377 /* expression is $((var)) only, lookup now */
13378 errcode = arith_lookup_val(numstack);
13381 *perrcode = errcode;
13382 return numstack->val;
13385 /* Continue processing the expression. */
13386 if (arith_isspace(arithval)) {
13387 /* Skip whitespace */
13390 p = endofname(expr);
13392 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13394 numstackptr->var = alloca(var_name_size);
13395 safe_strncpy(numstackptr->var, expr, var_name_size);
13398 numstackptr->contidional_second_val_initialized = 0;
13403 if (isdigit(arithval)) {
13404 numstackptr->var = NULL;
13405 #if ENABLE_ASH_MATH_SUPPORT_64
13406 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13408 numstackptr->val = strtol(expr, (char **) &expr, 0);
13412 for (p = op_tokens; ; p++) {
13416 /* strange operator not found */
13419 for (o = expr; *p && *o == *p; p++)
13426 /* skip tail uncompared token */
13429 /* skip zero delim */
13434 /* post grammar: a++ reduce to num */
13435 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13438 /* Plus and minus are binary (not unary) _only_ if the last
13439 * token was as number, or a right paren (which pretends to be
13440 * a number, since it evaluates to one). Think about it.
13441 * It makes sense. */
13442 if (lasttok != TOK_NUM) {
13458 /* We don't want a unary operator to cause recursive descent on the
13459 * stack, because there can be many in a row and it could cause an
13460 * operator to be evaluated before its argument is pushed onto the
13461 * integer stack. */
13462 /* But for binary operators, "apply" everything on the operator
13463 * stack until we find an operator with a lesser priority than the
13464 * one we have just extracted. */
13465 /* Left paren is given the lowest priority so it will never be
13466 * "applied" in this way.
13467 * if associativity is right and priority eq, applied also skip
13470 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13471 /* not left paren or unary */
13472 if (lasttok != TOK_NUM) {
13473 /* binary op must be preceded by a num */
13476 while (stackptr != stack) {
13477 if (op == TOK_RPAREN) {
13478 /* The algorithm employed here is simple: while we don't
13479 * hit an open paren nor the bottom of the stack, pop
13480 * tokens and apply them */
13481 if (stackptr[-1] == TOK_LPAREN) {
13483 /* Any operator directly after a */
13485 /* close paren should consider itself binary */
13489 operator prev_prec = PREC(stackptr[-1]);
13491 convert_prec_is_assing(prec);
13492 convert_prec_is_assing(prev_prec);
13493 if (prev_prec < prec)
13495 /* check right assoc */
13496 if (prev_prec == prec && is_right_associativity(prec))
13499 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13500 if (errcode) goto ret;
13502 if (op == TOK_RPAREN) {
13507 /* Push this operator to the stack and remember it. */
13508 *stackptr++ = lasttok = op;
13513 #endif /* ASH_MATH_SUPPORT */
13516 /* ============ main() and helpers */
13519 * Called to exit the shell.
13521 static void exitshell(void) NORETURN;
13529 status = exitstatus;
13530 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13531 if (setjmp(loc.loc)) {
13532 if (exception_type == EXEXIT)
13533 /* dash bug: it just does _exit(exitstatus) here
13534 * but we have to do setjobctl(0) first!
13535 * (bug is still not fixed in dash-0.5.3 - if you run dash
13536 * under Midnight Commander, on exit from dash MC is backgrounded) */
13537 status = exitstatus;
13540 exception_handler = &loc;
13546 flush_stdout_stderr();
13556 /* from input.c: */
13557 basepf.next_to_pgetc = basepf.buf = basebuf;
13560 signal(SIGCHLD, SIG_DFL);
13565 char ppid[sizeof(int)*3 + 1];
13567 struct stat st1, st2;
13570 for (envp = environ; envp && *envp; envp++) {
13571 if (strchr(*envp, '=')) {
13572 setvareq(*envp, VEXPORT|VTEXTFIXED);
13576 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
13577 setvar("PPID", ppid, 0);
13579 p = lookupvar("PWD");
13581 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
13582 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
13589 * Process the shell command line arguments.
13592 procargs(char **argv)
13595 const char *xminusc;
13600 /* if (xargv[0]) - mmm, this is always true! */
13602 for (i = 0; i < NOPTS; i++)
13606 /* it already printed err message */
13607 raise_exception(EXERROR);
13611 if (*xargv == NULL) {
13613 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13616 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13620 for (i = 0; i < NOPTS; i++)
13621 if (optlist[i] == 2)
13626 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13631 } else if (!sflag) {
13632 setinputfile(*xargv, 0);
13635 commandname = arg0;
13638 shellparam.p = xargv;
13639 #if ENABLE_ASH_GETOPTS
13640 shellparam.optind = 1;
13641 shellparam.optoff = -1;
13643 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13645 shellparam.nparam++;
13652 * Read /etc/profile or .profile.
13655 read_profile(const char *name)
13659 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13668 * This routine is called when an error or an interrupt occurs in an
13669 * interactive shell and control is returned to the main command loop.
13677 /* from input.c: */
13678 g_parsefile->left_in_buffer = 0;
13679 g_parsefile->left_in_line = 0; /* clear input buffer */
13681 /* from parser.c: */
13684 /* from redir.c: */
13685 clearredir(/*drop:*/ 0);
13689 static short profile_buf[16384];
13690 extern int etext();
13694 * Main routine. We initialize things, parse the arguments, execute
13695 * profiles if we're a login shell, and then call cmdloop to execute
13696 * commands. The setjmp call sets up the location to jump to when an
13697 * exception occurs. When an exception occurs the variable "state"
13698 * is used to figure out how far we had gotten.
13700 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13701 int ash_main(int argc UNUSED_PARAM, char **argv)
13704 volatile smallint state;
13705 struct jmploc jmploc;
13706 struct stackmark smark;
13708 /* Initialize global data */
13712 #if ENABLE_ASH_ALIAS
13718 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13721 #if ENABLE_FEATURE_EDITING
13722 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13725 if (setjmp(jmploc.loc)) {
13731 e = exception_type;
13735 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13738 outcslow('\n', stderr);
13740 popstackmark(&smark);
13741 FORCE_INT_ON; /* enable interrupts */
13750 exception_handler = &jmploc;
13753 trace_puts("Shell args: ");
13754 trace_puts_args(argv);
13756 rootpid = getpid();
13758 #if ENABLE_ASH_RANDOM_SUPPORT
13759 /* Can use monotonic_ns() for better randomness but for now it is
13760 * not used anywhere else in busybox... so avoid bloat */
13761 random_galois_LFSR = random_LCG = rootpid + monotonic_us();
13764 setstackmark(&smark);
13767 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13769 const char *hp = lookupvar("HISTFILE");
13772 hp = lookupvar("HOME");
13774 char *defhp = concat_path_file(hp, ".ash_history");
13775 setvar("HISTFILE", defhp, 0);
13781 if (/* argv[0] && */ argv[0][0] == '-')
13785 read_profile("/etc/profile");
13788 read_profile(".profile");
13794 getuid() == geteuid() && getgid() == getegid() &&
13798 shinit = lookupvar("ENV");
13799 if (shinit != NULL && *shinit != '\0') {
13800 read_profile(shinit);
13806 /* evalstring pushes parsefile stack.
13807 * Ensure we don't falsely claim that 0 (stdin)
13808 * is one of stacked source fds */
13810 g_parsefile->fd = -1;
13811 evalstring(minusc, 0);
13814 if (sflag || minusc == NULL) {
13815 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13817 const char *hp = lookupvar("HISTFILE");
13819 line_input_state->hist_file = hp;
13822 state4: /* XXX ??? - why isn't this before the "if" statement */
13830 extern void _mcleanup(void);
13839 const char *applet_name = "debug stuff usage";
13840 int main(int argc, char **argv)
13842 return ash_main(argc, argv);
13848 * Copyright (c) 1989, 1991, 1993, 1994
13849 * The Regents of the University of California. All rights reserved.
13851 * This code is derived from software contributed to Berkeley by
13852 * Kenneth Almquist.
13854 * Redistribution and use in source and binary forms, with or without
13855 * modification, are permitted provided that the following conditions
13857 * 1. Redistributions of source code must retain the above copyright
13858 * notice, this list of conditions and the following disclaimer.
13859 * 2. Redistributions in binary form must reproduce the above copyright
13860 * notice, this list of conditions and the following disclaimer in the
13861 * documentation and/or other materials provided with the distribution.
13862 * 3. Neither the name of the University nor the names of its contributors
13863 * may be used to endorse or promote products derived from this software
13864 * without specific prior written permission.
13866 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13867 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13868 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13869 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13870 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13871 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13872 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13873 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13874 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13875 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF