Tomato 1.28
[tomato.git] / release / src / router / busybox / shell / ash.c
blobf753a5bae30829d27329fc29669191d1711a5647
1 /* vi: set sw=4 ts=4: */
2 /*
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
12 * Kenneth Almquist.
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 * The following should be set to reflect the type of system you have:
21 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
22 * define SYSV if you are running under System V.
23 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
24 * define DEBUG=2 to compile in and turn on debugging.
26 * When debugging is on, debugging info will be written to ./trace and
27 * a quit signal will generate a core dump.
29 #define DEBUG 0
30 /* Tweak debug output verbosity here */
31 #define DEBUG_TIME 0
32 #define DEBUG_PID 1
33 #define DEBUG_SIG 1
35 #define PROFILE 0
37 #define IFS_BROKEN
39 #define JOBS ENABLE_ASH_JOB_CONTROL
41 #if DEBUG
42 # ifndef _GNU_SOURCE
43 # define _GNU_SOURCE
44 # endif
45 #endif
47 #include "busybox.h" /* for applet_names */
48 //TODO: pull in some .h and find out do we have SINGLE_APPLET_MAIN?
49 //#include "applet_tables.h" doesn't work
50 #include <paths.h>
51 #include <setjmp.h>
52 #include <fnmatch.h>
53 #include "math.h"
55 #if defined SINGLE_APPLET_MAIN
56 /* STANDALONE does not make sense, and won't compile */
57 #undef CONFIG_FEATURE_SH_STANDALONE
58 #undef ENABLE_FEATURE_SH_STANDALONE
59 #undef USE_FEATURE_SH_STANDALONE
60 #undef SKIP_FEATURE_SH_STANDALONE(...)
61 #define ENABLE_FEATURE_SH_STANDALONE 0
62 #define USE_FEATURE_SH_STANDALONE(...)
63 #define SKIP_FEATURE_SH_STANDALONE(...) __VA_ARGS__
64 #endif
66 #ifndef PIPE_BUF
67 # define PIPE_BUF 4096 /* amount of buffering in a pipe */
68 #endif
70 #if defined(__uClinux__)
71 # error "Do not even bother, ash will not run on NOMMU machine"
72 #endif
75 /* ============ Hash table sizes. Configurable. */
77 #define VTABSIZE 39
78 #define ATABSIZE 39
79 #define CMDTABLESIZE 31 /* should be prime */
82 /* ============ Shell options */
84 static const char *const optletters_optnames[] = {
85 "e" "errexit",
86 "f" "noglob",
87 "I" "ignoreeof",
88 "i" "interactive",
89 "m" "monitor",
90 "n" "noexec",
91 "s" "stdin",
92 "x" "xtrace",
93 "v" "verbose",
94 "C" "noclobber",
95 "a" "allexport",
96 "b" "notify",
97 "u" "nounset",
98 "\0" "vi"
99 #if DEBUG
100 ,"\0" "nolog"
101 ,"\0" "debug"
102 #endif
105 #define optletters(n) optletters_optnames[(n)][0]
106 #define optnames(n) (&optletters_optnames[(n)][1])
108 enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
111 /* ============ Misc data */
113 static const char homestr[] ALIGN1 = "HOME";
114 static const char snlfmt[] ALIGN1 = "%s\n";
115 static const char illnum[] ALIGN1 = "Illegal number: %s";
118 * We enclose jmp_buf in a structure so that we can declare pointers to
119 * jump locations. The global variable handler contains the location to
120 * jump to when an exception occurs, and the global variable exception_type
121 * contains a code identifying the exception. To implement nested
122 * exception handlers, the user should save the value of handler on entry
123 * to an inner scope, set handler to point to a jmploc structure for the
124 * inner scope, and restore handler on exit from the scope.
126 struct jmploc {
127 jmp_buf loc;
130 struct globals_misc {
131 /* pid of main shell */
132 int rootpid;
133 /* shell level: 0 for the main shell, 1 for its children, and so on */
134 int shlvl;
135 #define rootshell (!shlvl)
136 char *minusc; /* argument to -c option */
138 char *curdir; // = nullstr; /* current working directory */
139 char *physdir; // = nullstr; /* physical working directory */
141 char *arg0; /* value of $0 */
143 struct jmploc *exception_handler;
145 // disabled by vda: cannot understand how it was supposed to work -
146 // cannot fix bugs. That's why you have to explain your non-trivial designs!
147 // /* do we generate EXSIG events */
148 // int exsig; /* counter */
149 volatile int suppressint; /* counter */
150 // TODO: rename
151 // pendingsig -> pending_sig
152 // intpending -> pending_int
153 volatile /*sig_atomic_t*/ smallint intpending; /* 1 = got SIGINT */
154 /* last pending signal */
155 volatile /*sig_atomic_t*/ smallint pendingsig;
156 smallint exception_type; /* kind of exception (0..5) */
157 /* exceptions */
158 #define EXINT 0 /* SIGINT received */
159 #define EXERROR 1 /* a generic error */
160 #define EXSHELLPROC 2 /* execute a shell procedure */
161 #define EXEXEC 3 /* command execution failed */
162 #define EXEXIT 4 /* exit the shell */
163 #define EXSIG 5 /* trapped signal in wait(1) */
165 smallint isloginsh;
166 char nullstr[1]; /* zero length string */
168 char optlist[NOPTS];
169 #define eflag optlist[0]
170 #define fflag optlist[1]
171 #define Iflag optlist[2]
172 #define iflag optlist[3]
173 #define mflag optlist[4]
174 #define nflag optlist[5]
175 #define sflag optlist[6]
176 #define xflag optlist[7]
177 #define vflag optlist[8]
178 #define Cflag optlist[9]
179 #define aflag optlist[10]
180 #define bflag optlist[11]
181 #define uflag optlist[12]
182 #define viflag optlist[13]
183 #if DEBUG
184 #define nolog optlist[14]
185 #define debug optlist[15]
186 #endif
188 /* trap handler commands */
190 * Sigmode records the current value of the signal handlers for the various
191 * modes. A value of zero means that the current handler is not known.
192 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
194 char sigmode[NSIG - 1];
195 #define S_DFL 1 /* default signal handling (SIG_DFL) */
196 #define S_CATCH 2 /* signal is caught */
197 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
198 #define S_HARD_IGN 4 /* signal is ignored permenantly */
200 /* indicates specified signal received */
201 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
202 char *trap[NSIG];
204 /* Rarely referenced stuff */
205 #if ENABLE_ASH_RANDOM_SUPPORT
206 /* Random number generators */
207 int32_t random_galois_LFSR; /* Galois LFSR (fast but weak). signed! */
208 uint32_t random_LCG; /* LCG (fast but weak) */
209 #endif
210 pid_t backgndpid; /* pid of last background process */
211 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
213 extern struct globals_misc *const ash_ptr_to_globals_misc;
214 #define G_misc (*ash_ptr_to_globals_misc)
215 #define rootpid (G_misc.rootpid )
216 #define shlvl (G_misc.shlvl )
217 #define minusc (G_misc.minusc )
218 #define curdir (G_misc.curdir )
219 #define physdir (G_misc.physdir )
220 #define arg0 (G_misc.arg0 )
221 #define exception_handler (G_misc.exception_handler)
222 #define exception_type (G_misc.exception_type )
223 #define suppressint (G_misc.suppressint )
224 #define intpending (G_misc.intpending )
225 //#define exsig (G_misc.exsig )
226 #define pendingsig (G_misc.pendingsig )
227 #define isloginsh (G_misc.isloginsh )
228 #define nullstr (G_misc.nullstr )
229 #define optlist (G_misc.optlist )
230 #define sigmode (G_misc.sigmode )
231 #define gotsig (G_misc.gotsig )
232 #define trap (G_misc.trap )
233 #define random_galois_LFSR (G_misc.random_galois_LFSR)
234 #define random_LCG (G_misc.random_LCG )
235 #define backgndpid (G_misc.backgndpid )
236 #define job_warning (G_misc.job_warning)
237 #define INIT_G_misc() do { \
238 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
239 barrier(); \
240 curdir = nullstr; \
241 physdir = nullstr; \
242 } while (0)
245 /* ============ DEBUG */
246 #if DEBUG
247 static void trace_printf(const char *fmt, ...);
248 static void trace_vprintf(const char *fmt, va_list va);
249 # define TRACE(param) trace_printf param
250 # define TRACEV(param) trace_vprintf param
251 # define close(fd) do { \
252 int dfd = (fd); \
253 if (close(dfd) < 0) \
254 bb_error_msg("bug on %d: closing %d(%x)", \
255 __LINE__, dfd, dfd); \
256 } while (0)
257 #else
258 # define TRACE(param)
259 # define TRACEV(param)
260 #endif
263 /* ============ Utility functions */
264 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
266 /* C99 say: "char" declaration may be signed or unsigned by default */
267 #define signed_char2int(sc) ((int)(signed char)(sc))
269 static int isdigit_str9(const char *str)
271 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
272 while (--maxlen && isdigit(*str))
273 str++;
274 return (*str == '\0');
278 /* ============ Interrupts / exceptions */
280 * These macros allow the user to suspend the handling of interrupt signals
281 * over a period of time. This is similar to SIGHOLD or to sigblock, but
282 * much more efficient and portable. (But hacking the kernel is so much
283 * more fun than worrying about efficiency and portability. :-))
285 #define INT_OFF do { \
286 suppressint++; \
287 xbarrier(); \
288 } while (0)
291 * Called to raise an exception. Since C doesn't include exceptions, we
292 * just do a longjmp to the exception handler. The type of exception is
293 * stored in the global variable "exception_type".
295 static void raise_exception(int) NORETURN;
296 static void
297 raise_exception(int e)
299 #if DEBUG
300 if (exception_handler == NULL)
301 abort();
302 #endif
303 INT_OFF;
304 exception_type = e;
305 longjmp(exception_handler->loc, 1);
307 #if DEBUG
308 #define raise_exception(e) do { \
309 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
310 raise_exception(e); \
311 } while (0)
312 #endif
315 * Called from trap.c when a SIGINT is received. (If the user specifies
316 * that SIGINT is to be trapped or ignored using the trap builtin, then
317 * this routine is not called.) Suppressint is nonzero when interrupts
318 * are held using the INT_OFF macro. (The test for iflag is just
319 * defensive programming.)
321 static void raise_interrupt(void) NORETURN;
322 static void
323 raise_interrupt(void)
325 int ex_type;
327 intpending = 0;
328 /* Signal is not automatically unmasked after it is raised,
329 * do it ourself - unmask all signals */
330 sigprocmask_allsigs(SIG_UNBLOCK);
331 /* pendingsig = 0; - now done in onsig() */
333 ex_type = EXSIG;
334 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
335 if (!(rootshell && iflag)) {
336 /* Kill ourself with SIGINT */
337 signal(SIGINT, SIG_DFL);
338 raise(SIGINT);
340 ex_type = EXINT;
342 raise_exception(ex_type);
343 /* NOTREACHED */
345 #if DEBUG
346 #define raise_interrupt() do { \
347 TRACE(("raising interrupt on line %d\n", __LINE__)); \
348 raise_interrupt(); \
349 } while (0)
350 #endif
352 static USE_ASH_OPTIMIZE_FOR_SIZE(inline) void
353 int_on(void)
355 xbarrier();
356 if (--suppressint == 0 && intpending) {
357 raise_interrupt();
360 #define INT_ON int_on()
361 static USE_ASH_OPTIMIZE_FOR_SIZE(inline) void
362 force_int_on(void)
364 xbarrier();
365 suppressint = 0;
366 if (intpending)
367 raise_interrupt();
369 #define FORCE_INT_ON force_int_on()
371 #define SAVE_INT(v) ((v) = suppressint)
373 #define RESTORE_INT(v) do { \
374 xbarrier(); \
375 suppressint = (v); \
376 if (suppressint == 0 && intpending) \
377 raise_interrupt(); \
378 } while (0)
381 /* ============ Stdout/stderr output */
383 static void
384 outstr(const char *p, FILE *file)
386 INT_OFF;
387 fputs(p, file);
388 INT_ON;
391 static void
392 flush_stdout_stderr(void)
394 INT_OFF;
395 fflush(stdout);
396 fflush(stderr);
397 INT_ON;
400 static void
401 flush_stderr(void)
403 INT_OFF;
404 fflush(stderr);
405 INT_ON;
408 static void
409 outcslow(int c, FILE *dest)
411 INT_OFF;
412 putc(c, dest);
413 fflush(dest);
414 INT_ON;
417 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
418 static int
419 out1fmt(const char *fmt, ...)
421 va_list ap;
422 int r;
424 INT_OFF;
425 va_start(ap, fmt);
426 r = vprintf(fmt, ap);
427 va_end(ap);
428 INT_ON;
429 return r;
432 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
433 static int
434 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
436 va_list ap;
437 int ret;
439 va_start(ap, fmt);
440 INT_OFF;
441 ret = vsnprintf(outbuf, length, fmt, ap);
442 va_end(ap);
443 INT_ON;
444 return ret;
447 static void
448 out1str(const char *p)
450 outstr(p, stdout);
453 static void
454 out2str(const char *p)
456 outstr(p, stderr);
457 flush_stderr();
461 /* ============ Parser structures */
463 /* control characters in argument strings */
464 #define CTLESC '\201' /* escape next character */
465 #define CTLVAR '\202' /* variable defn */
466 #define CTLENDVAR '\203'
467 #define CTLBACKQ '\204'
468 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
469 /* CTLBACKQ | CTLQUOTE == '\205' */
470 #define CTLARI '\206' /* arithmetic expression */
471 #define CTLENDARI '\207'
472 #define CTLQUOTEMARK '\210'
474 /* variable substitution byte (follows CTLVAR) */
475 #define VSTYPE 0x0f /* type of variable substitution */
476 #define VSNUL 0x10 /* colon--treat the empty string as unset */
477 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
479 /* values of VSTYPE field */
480 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
481 #define VSMINUS 0x2 /* ${var-text} */
482 #define VSPLUS 0x3 /* ${var+text} */
483 #define VSQUESTION 0x4 /* ${var?message} */
484 #define VSASSIGN 0x5 /* ${var=text} */
485 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
486 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
487 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
488 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
489 #define VSLENGTH 0xa /* ${#var} */
490 #if ENABLE_ASH_BASH_COMPAT
491 #define VSSUBSTR 0xc /* ${var:position:length} */
492 #define VSREPLACE 0xd /* ${var/pattern/replacement} */
493 #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
494 #endif
496 static const char dolatstr[] ALIGN1 = {
497 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
500 #define NCMD 0
501 #define NPIPE 1
502 #define NREDIR 2
503 #define NBACKGND 3
504 #define NSUBSHELL 4
505 #define NAND 5
506 #define NOR 6
507 #define NSEMI 7
508 #define NIF 8
509 #define NWHILE 9
510 #define NUNTIL 10
511 #define NFOR 11
512 #define NCASE 12
513 #define NCLIST 13
514 #define NDEFUN 14
515 #define NARG 15
516 #define NTO 16
517 #if ENABLE_ASH_BASH_COMPAT
518 #define NTO2 17
519 #endif
520 #define NCLOBBER 18
521 #define NFROM 19
522 #define NFROMTO 20
523 #define NAPPEND 21
524 #define NTOFD 22
525 #define NFROMFD 23
526 #define NHERE 24
527 #define NXHERE 25
528 #define NNOT 26
529 #define N_NUMBER 27
531 union node;
533 struct ncmd {
534 smallint type; /* Nxxxx */
535 union node *assign;
536 union node *args;
537 union node *redirect;
540 struct npipe {
541 smallint type;
542 smallint pipe_backgnd;
543 struct nodelist *cmdlist;
546 struct nredir {
547 smallint type;
548 union node *n;
549 union node *redirect;
552 struct nbinary {
553 smallint type;
554 union node *ch1;
555 union node *ch2;
558 struct nif {
559 smallint type;
560 union node *test;
561 union node *ifpart;
562 union node *elsepart;
565 struct nfor {
566 smallint type;
567 union node *args;
568 union node *body;
569 char *var;
572 struct ncase {
573 smallint type;
574 union node *expr;
575 union node *cases;
578 struct nclist {
579 smallint type;
580 union node *next;
581 union node *pattern;
582 union node *body;
585 struct narg {
586 smallint type;
587 union node *next;
588 char *text;
589 struct nodelist *backquote;
592 /* nfile and ndup layout must match!
593 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
594 * that it is actually NTO2 (>&file), and change its type.
596 struct nfile {
597 smallint type;
598 union node *next;
599 int fd;
600 int _unused_dupfd;
601 union node *fname;
602 char *expfname;
605 struct ndup {
606 smallint type;
607 union node *next;
608 int fd;
609 int dupfd;
610 union node *vname;
611 char *_unused_expfname;
614 struct nhere {
615 smallint type;
616 union node *next;
617 int fd;
618 union node *doc;
621 struct nnot {
622 smallint type;
623 union node *com;
626 union node {
627 smallint type;
628 struct ncmd ncmd;
629 struct npipe npipe;
630 struct nredir nredir;
631 struct nbinary nbinary;
632 struct nif nif;
633 struct nfor nfor;
634 struct ncase ncase;
635 struct nclist nclist;
636 struct narg narg;
637 struct nfile nfile;
638 struct ndup ndup;
639 struct nhere nhere;
640 struct nnot nnot;
643 struct nodelist {
644 struct nodelist *next;
645 union node *n;
648 struct funcnode {
649 int count;
650 union node n;
654 * Free a parse tree.
656 static void
657 freefunc(struct funcnode *f)
659 if (f && --f->count < 0)
660 free(f);
664 /* ============ Debugging output */
666 #if DEBUG
668 static FILE *tracefile;
670 static void
671 trace_printf(const char *fmt, ...)
673 va_list va;
675 if (debug != 1)
676 return;
677 if (DEBUG_TIME)
678 fprintf(tracefile, "%u ", (int) time(NULL));
679 if (DEBUG_PID)
680 fprintf(tracefile, "[%u] ", (int) getpid());
681 if (DEBUG_SIG)
682 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pendingsig, intpending, suppressint);
683 va_start(va, fmt);
684 vfprintf(tracefile, fmt, va);
685 va_end(va);
688 static void
689 trace_vprintf(const char *fmt, va_list va)
691 if (debug != 1)
692 return;
693 if (DEBUG_TIME)
694 fprintf(tracefile, "%u ", (int) time(NULL));
695 if (DEBUG_PID)
696 fprintf(tracefile, "[%u] ", (int) getpid());
697 if (DEBUG_SIG)
698 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pendingsig, intpending, suppressint);
699 vfprintf(tracefile, fmt, va);
702 static void
703 trace_puts(const char *s)
705 if (debug != 1)
706 return;
707 fputs(s, tracefile);
710 static void
711 trace_puts_quoted(char *s)
713 char *p;
714 char c;
716 if (debug != 1)
717 return;
718 putc('"', tracefile);
719 for (p = s; *p; p++) {
720 switch (*p) {
721 case '\n': c = 'n'; goto backslash;
722 case '\t': c = 't'; goto backslash;
723 case '\r': c = 'r'; goto backslash;
724 case '"': c = '"'; goto backslash;
725 case '\\': c = '\\'; goto backslash;
726 case CTLESC: c = 'e'; goto backslash;
727 case CTLVAR: c = 'v'; goto backslash;
728 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
729 case CTLBACKQ: c = 'q'; goto backslash;
730 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
731 backslash:
732 putc('\\', tracefile);
733 putc(c, tracefile);
734 break;
735 default:
736 if (*p >= ' ' && *p <= '~')
737 putc(*p, tracefile);
738 else {
739 putc('\\', tracefile);
740 putc(*p >> 6 & 03, tracefile);
741 putc(*p >> 3 & 07, tracefile);
742 putc(*p & 07, tracefile);
744 break;
747 putc('"', tracefile);
750 static void
751 trace_puts_args(char **ap)
753 if (debug != 1)
754 return;
755 if (!*ap)
756 return;
757 while (1) {
758 trace_puts_quoted(*ap);
759 if (!*++ap) {
760 putc('\n', tracefile);
761 break;
763 putc(' ', tracefile);
767 static void
768 opentrace(void)
770 char s[100];
771 #ifdef O_APPEND
772 int flags;
773 #endif
775 if (debug != 1) {
776 if (tracefile)
777 fflush(tracefile);
778 /* leave open because libedit might be using it */
779 return;
781 strcpy(s, "./trace");
782 if (tracefile) {
783 if (!freopen(s, "a", tracefile)) {
784 fprintf(stderr, "Can't re-open %s\n", s);
785 debug = 0;
786 return;
788 } else {
789 tracefile = fopen(s, "a");
790 if (tracefile == NULL) {
791 fprintf(stderr, "Can't open %s\n", s);
792 debug = 0;
793 return;
796 #ifdef O_APPEND
797 flags = fcntl(fileno(tracefile), F_GETFL);
798 if (flags >= 0)
799 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
800 #endif
801 setlinebuf(tracefile);
802 fputs("\nTracing started.\n", tracefile);
805 static void
806 indent(int amount, char *pfx, FILE *fp)
808 int i;
810 for (i = 0; i < amount; i++) {
811 if (pfx && i == amount - 1)
812 fputs(pfx, fp);
813 putc('\t', fp);
817 /* little circular references here... */
818 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
820 static void
821 sharg(union node *arg, FILE *fp)
823 char *p;
824 struct nodelist *bqlist;
825 int subtype;
827 if (arg->type != NARG) {
828 out1fmt("<node type %d>\n", arg->type);
829 abort();
831 bqlist = arg->narg.backquote;
832 for (p = arg->narg.text; *p; p++) {
833 switch (*p) {
834 case CTLESC:
835 putc(*++p, fp);
836 break;
837 case CTLVAR:
838 putc('$', fp);
839 putc('{', fp);
840 subtype = *++p;
841 if (subtype == VSLENGTH)
842 putc('#', fp);
844 while (*p != '=')
845 putc(*p++, fp);
847 if (subtype & VSNUL)
848 putc(':', fp);
850 switch (subtype & VSTYPE) {
851 case VSNORMAL:
852 putc('}', fp);
853 break;
854 case VSMINUS:
855 putc('-', fp);
856 break;
857 case VSPLUS:
858 putc('+', fp);
859 break;
860 case VSQUESTION:
861 putc('?', fp);
862 break;
863 case VSASSIGN:
864 putc('=', fp);
865 break;
866 case VSTRIMLEFT:
867 putc('#', fp);
868 break;
869 case VSTRIMLEFTMAX:
870 putc('#', fp);
871 putc('#', fp);
872 break;
873 case VSTRIMRIGHT:
874 putc('%', fp);
875 break;
876 case VSTRIMRIGHTMAX:
877 putc('%', fp);
878 putc('%', fp);
879 break;
880 case VSLENGTH:
881 break;
882 default:
883 out1fmt("<subtype %d>", subtype);
885 break;
886 case CTLENDVAR:
887 putc('}', fp);
888 break;
889 case CTLBACKQ:
890 case CTLBACKQ|CTLQUOTE:
891 putc('$', fp);
892 putc('(', fp);
893 shtree(bqlist->n, -1, NULL, fp);
894 putc(')', fp);
895 break;
896 default:
897 putc(*p, fp);
898 break;
903 static void
904 shcmd(union node *cmd, FILE *fp)
906 union node *np;
907 int first;
908 const char *s;
909 int dftfd;
911 first = 1;
912 for (np = cmd->ncmd.args; np; np = np->narg.next) {
913 if (!first)
914 putc(' ', fp);
915 sharg(np, fp);
916 first = 0;
918 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
919 if (!first)
920 putc(' ', fp);
921 dftfd = 0;
922 switch (np->nfile.type) {
923 case NTO: s = ">>"+1; dftfd = 1; break;
924 case NCLOBBER: s = ">|"; dftfd = 1; break;
925 case NAPPEND: s = ">>"; dftfd = 1; break;
926 #if ENABLE_ASH_BASH_COMPAT
927 case NTO2:
928 #endif
929 case NTOFD: s = ">&"; dftfd = 1; break;
930 case NFROM: s = "<"; break;
931 case NFROMFD: s = "<&"; break;
932 case NFROMTO: s = "<>"; break;
933 default: s = "*error*"; break;
935 if (np->nfile.fd != dftfd)
936 fprintf(fp, "%d", np->nfile.fd);
937 fputs(s, fp);
938 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
939 fprintf(fp, "%d", np->ndup.dupfd);
940 } else {
941 sharg(np->nfile.fname, fp);
943 first = 0;
947 static void
948 shtree(union node *n, int ind, char *pfx, FILE *fp)
950 struct nodelist *lp;
951 const char *s;
953 if (n == NULL)
954 return;
956 indent(ind, pfx, fp);
957 switch (n->type) {
958 case NSEMI:
959 s = "; ";
960 goto binop;
961 case NAND:
962 s = " && ";
963 goto binop;
964 case NOR:
965 s = " || ";
966 binop:
967 shtree(n->nbinary.ch1, ind, NULL, fp);
968 /* if (ind < 0) */
969 fputs(s, fp);
970 shtree(n->nbinary.ch2, ind, NULL, fp);
971 break;
972 case NCMD:
973 shcmd(n, fp);
974 if (ind >= 0)
975 putc('\n', fp);
976 break;
977 case NPIPE:
978 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
979 shcmd(lp->n, fp);
980 if (lp->next)
981 fputs(" | ", fp);
983 if (n->npipe.pipe_backgnd)
984 fputs(" &", fp);
985 if (ind >= 0)
986 putc('\n', fp);
987 break;
988 default:
989 fprintf(fp, "<node type %d>", n->type);
990 if (ind >= 0)
991 putc('\n', fp);
992 break;
996 static void
997 showtree(union node *n)
999 trace_puts("showtree called\n");
1000 shtree(n, 1, NULL, stdout);
1003 #endif /* DEBUG */
1006 /* ============ Parser data */
1009 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1011 struct strlist {
1012 struct strlist *next;
1013 char *text;
1016 struct alias;
1018 struct strpush {
1019 struct strpush *prev; /* preceding string on stack */
1020 char *prev_string;
1021 int prev_left_in_line;
1022 #if ENABLE_ASH_ALIAS
1023 struct alias *ap; /* if push was associated with an alias */
1024 #endif
1025 char *string; /* remember the string since it may change */
1028 struct parsefile {
1029 struct parsefile *prev; /* preceding file on stack */
1030 int linno; /* current line */
1031 int fd; /* file descriptor (or -1 if string) */
1032 int left_in_line; /* number of chars left in this line */
1033 int left_in_buffer; /* number of chars left in this buffer past the line */
1034 char *next_to_pgetc; /* next char in buffer */
1035 char *buf; /* input buffer */
1036 struct strpush *strpush; /* for pushing strings at this level */
1037 struct strpush basestrpush; /* so pushing one is fast */
1040 static struct parsefile basepf; /* top level input file */
1041 static struct parsefile *g_parsefile = &basepf; /* current input file */
1042 static int startlinno; /* line # where last token started */
1043 static char *commandname; /* currently executing command */
1044 static struct strlist *cmdenviron; /* environment for builtin command */
1045 static uint8_t exitstatus; /* exit status of last command */
1048 /* ============ Message printing */
1050 static void
1051 ash_vmsg(const char *msg, va_list ap)
1053 fprintf(stderr, "%s: ", arg0);
1054 if (commandname) {
1055 if (strcmp(arg0, commandname))
1056 fprintf(stderr, "%s: ", commandname);
1057 if (!iflag || g_parsefile->fd)
1058 fprintf(stderr, "line %d: ", startlinno);
1060 vfprintf(stderr, msg, ap);
1061 outcslow('\n', stderr);
1065 * Exverror is called to raise the error exception. If the second argument
1066 * is not NULL then error prints an error message using printf style
1067 * formatting. It then raises the error exception.
1069 static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1070 static void
1071 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1073 #if DEBUG
1074 if (msg) {
1075 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1076 TRACEV((msg, ap));
1077 TRACE(("\") pid=%d\n", getpid()));
1078 } else
1079 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1080 if (msg)
1081 #endif
1082 ash_vmsg(msg, ap);
1084 flush_stdout_stderr();
1085 raise_exception(cond);
1086 /* NOTREACHED */
1089 static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1090 static void
1091 ash_msg_and_raise_error(const char *msg, ...)
1093 va_list ap;
1095 va_start(ap, msg);
1096 ash_vmsg_and_raise(EXERROR, msg, ap);
1097 /* NOTREACHED */
1098 va_end(ap);
1101 static void raise_error_syntax(const char *) NORETURN;
1102 static void
1103 raise_error_syntax(const char *msg)
1105 ash_msg_and_raise_error("syntax error: %s", msg);
1106 /* NOTREACHED */
1109 static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1110 static void
1111 ash_msg_and_raise(int cond, const char *msg, ...)
1113 va_list ap;
1115 va_start(ap, msg);
1116 ash_vmsg_and_raise(cond, msg, ap);
1117 /* NOTREACHED */
1118 va_end(ap);
1122 * error/warning routines for external builtins
1124 static void
1125 ash_msg(const char *fmt, ...)
1127 va_list ap;
1129 va_start(ap, fmt);
1130 ash_vmsg(fmt, ap);
1131 va_end(ap);
1135 * Return a string describing an error. The returned string may be a
1136 * pointer to a static buffer that will be overwritten on the next call.
1137 * Action describes the operation that got the error.
1139 static const char *
1140 errmsg(int e, const char *em)
1142 if (e == ENOENT || e == ENOTDIR) {
1143 return em;
1145 return strerror(e);
1149 /* ============ Memory allocation */
1152 * It appears that grabstackstr() will barf with such alignments
1153 * because stalloc() will return a string allocated in a new stackblock.
1155 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1156 enum {
1157 /* Most machines require the value returned from malloc to be aligned
1158 * in some way. The following macro will get this right
1159 * on many machines. */
1160 SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1,
1161 /* Minimum size of a block */
1162 MINSIZE = SHELL_ALIGN(504),
1165 struct stack_block {
1166 struct stack_block *prev;
1167 char space[MINSIZE];
1170 struct stackmark {
1171 struct stack_block *stackp;
1172 char *stacknxt;
1173 size_t stacknleft;
1174 struct stackmark *marknext;
1178 struct globals_memstack {
1179 struct stack_block *g_stackp; // = &stackbase;
1180 struct stackmark *markp;
1181 char *g_stacknxt; // = stackbase.space;
1182 char *sstrend; // = stackbase.space + MINSIZE;
1183 size_t g_stacknleft; // = MINSIZE;
1184 int herefd; // = -1;
1185 struct stack_block stackbase;
1187 extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1188 #define G_memstack (*ash_ptr_to_globals_memstack)
1189 #define g_stackp (G_memstack.g_stackp )
1190 #define markp (G_memstack.markp )
1191 #define g_stacknxt (G_memstack.g_stacknxt )
1192 #define sstrend (G_memstack.sstrend )
1193 #define g_stacknleft (G_memstack.g_stacknleft)
1194 #define herefd (G_memstack.herefd )
1195 #define stackbase (G_memstack.stackbase )
1196 #define INIT_G_memstack() do { \
1197 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1198 barrier(); \
1199 g_stackp = &stackbase; \
1200 g_stacknxt = stackbase.space; \
1201 g_stacknleft = MINSIZE; \
1202 sstrend = stackbase.space + MINSIZE; \
1203 herefd = -1; \
1204 } while (0)
1206 #define stackblock() ((void *)g_stacknxt)
1207 #define stackblocksize() g_stacknleft
1210 static void *
1211 ckrealloc(void * p, size_t nbytes)
1213 p = realloc(p, nbytes);
1214 if (!p)
1215 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1216 return p;
1219 static void *
1220 ckmalloc(size_t nbytes)
1222 return ckrealloc(NULL, nbytes);
1225 static void *
1226 ckzalloc(size_t nbytes)
1228 return memset(ckmalloc(nbytes), 0, nbytes);
1232 * Make a copy of a string in safe storage.
1234 static char *
1235 ckstrdup(const char *s)
1237 char *p = strdup(s);
1238 if (!p)
1239 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1240 return p;
1244 * Parse trees for commands are allocated in lifo order, so we use a stack
1245 * to make this more efficient, and also to avoid all sorts of exception
1246 * handling code to handle interrupts in the middle of a parse.
1248 * The size 504 was chosen because the Ultrix malloc handles that size
1249 * well.
1251 static void *
1252 stalloc(size_t nbytes)
1254 char *p;
1255 size_t aligned;
1257 aligned = SHELL_ALIGN(nbytes);
1258 if (aligned > g_stacknleft) {
1259 size_t len;
1260 size_t blocksize;
1261 struct stack_block *sp;
1263 blocksize = aligned;
1264 if (blocksize < MINSIZE)
1265 blocksize = MINSIZE;
1266 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1267 if (len < blocksize)
1268 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1269 INT_OFF;
1270 sp = ckmalloc(len);
1271 sp->prev = g_stackp;
1272 g_stacknxt = sp->space;
1273 g_stacknleft = blocksize;
1274 sstrend = g_stacknxt + blocksize;
1275 g_stackp = sp;
1276 INT_ON;
1278 p = g_stacknxt;
1279 g_stacknxt += aligned;
1280 g_stacknleft -= aligned;
1281 return p;
1284 static void *
1285 stzalloc(size_t nbytes)
1287 return memset(stalloc(nbytes), 0, nbytes);
1290 static void
1291 stunalloc(void *p)
1293 #if DEBUG
1294 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1295 write(STDERR_FILENO, "stunalloc\n", 10);
1296 abort();
1298 #endif
1299 g_stacknleft += g_stacknxt - (char *)p;
1300 g_stacknxt = p;
1304 * Like strdup but works with the ash stack.
1306 static char *
1307 ststrdup(const char *p)
1309 size_t len = strlen(p) + 1;
1310 return memcpy(stalloc(len), p, len);
1313 static void
1314 setstackmark(struct stackmark *mark)
1316 mark->stackp = g_stackp;
1317 mark->stacknxt = g_stacknxt;
1318 mark->stacknleft = g_stacknleft;
1319 mark->marknext = markp;
1320 markp = mark;
1323 static void
1324 popstackmark(struct stackmark *mark)
1326 struct stack_block *sp;
1328 if (!mark->stackp)
1329 return;
1331 INT_OFF;
1332 markp = mark->marknext;
1333 while (g_stackp != mark->stackp) {
1334 sp = g_stackp;
1335 g_stackp = sp->prev;
1336 free(sp);
1338 g_stacknxt = mark->stacknxt;
1339 g_stacknleft = mark->stacknleft;
1340 sstrend = mark->stacknxt + mark->stacknleft;
1341 INT_ON;
1345 * When the parser reads in a string, it wants to stick the string on the
1346 * stack and only adjust the stack pointer when it knows how big the
1347 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1348 * of space on top of the stack and stackblocklen returns the length of
1349 * this block. Growstackblock will grow this space by at least one byte,
1350 * possibly moving it (like realloc). Grabstackblock actually allocates the
1351 * part of the block that has been used.
1353 static void
1354 growstackblock(void)
1356 size_t newlen;
1358 newlen = g_stacknleft * 2;
1359 if (newlen < g_stacknleft)
1360 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1361 if (newlen < 128)
1362 newlen += 128;
1364 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1365 struct stack_block *oldstackp;
1366 struct stackmark *xmark;
1367 struct stack_block *sp;
1368 struct stack_block *prevstackp;
1369 size_t grosslen;
1371 INT_OFF;
1372 oldstackp = g_stackp;
1373 sp = g_stackp;
1374 prevstackp = sp->prev;
1375 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1376 sp = ckrealloc(sp, grosslen);
1377 sp->prev = prevstackp;
1378 g_stackp = sp;
1379 g_stacknxt = sp->space;
1380 g_stacknleft = newlen;
1381 sstrend = sp->space + newlen;
1384 * Stack marks pointing to the start of the old block
1385 * must be relocated to point to the new block
1387 xmark = markp;
1388 while (xmark != NULL && xmark->stackp == oldstackp) {
1389 xmark->stackp = g_stackp;
1390 xmark->stacknxt = g_stacknxt;
1391 xmark->stacknleft = g_stacknleft;
1392 xmark = xmark->marknext;
1394 INT_ON;
1395 } else {
1396 char *oldspace = g_stacknxt;
1397 size_t oldlen = g_stacknleft;
1398 char *p = stalloc(newlen);
1400 /* free the space we just allocated */
1401 g_stacknxt = memcpy(p, oldspace, oldlen);
1402 g_stacknleft += newlen;
1406 static void
1407 grabstackblock(size_t len)
1409 len = SHELL_ALIGN(len);
1410 g_stacknxt += len;
1411 g_stacknleft -= len;
1415 * The following routines are somewhat easier to use than the above.
1416 * The user declares a variable of type STACKSTR, which may be declared
1417 * to be a register. The macro STARTSTACKSTR initializes things. Then
1418 * the user uses the macro STPUTC to add characters to the string. In
1419 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1420 * grown as necessary. When the user is done, she can just leave the
1421 * string there and refer to it using stackblock(). Or she can allocate
1422 * the space for it using grabstackstr(). If it is necessary to allow
1423 * someone else to use the stack temporarily and then continue to grow
1424 * the string, the user should use grabstack to allocate the space, and
1425 * then call ungrabstr(p) to return to the previous mode of operation.
1427 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1428 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1429 * is space for at least one character.
1431 static void *
1432 growstackstr(void)
1434 size_t len = stackblocksize();
1435 if (herefd >= 0 && len >= 1024) {
1436 full_write(herefd, stackblock(), len);
1437 return stackblock();
1439 growstackblock();
1440 return (char *)stackblock() + len;
1444 * Called from CHECKSTRSPACE.
1446 static char *
1447 makestrspace(size_t newlen, char *p)
1449 size_t len = p - g_stacknxt;
1450 size_t size = stackblocksize();
1452 for (;;) {
1453 size_t nleft;
1455 size = stackblocksize();
1456 nleft = size - len;
1457 if (nleft >= newlen)
1458 break;
1459 growstackblock();
1461 return (char *)stackblock() + len;
1464 static char *
1465 stack_nputstr(const char *s, size_t n, char *p)
1467 p = makestrspace(n, p);
1468 p = (char *)memcpy(p, s, n) + n;
1469 return p;
1472 static char *
1473 stack_putstr(const char *s, char *p)
1475 return stack_nputstr(s, strlen(s), p);
1478 static char *
1479 _STPUTC(int c, char *p)
1481 if (p == sstrend)
1482 p = growstackstr();
1483 *p++ = c;
1484 return p;
1487 #define STARTSTACKSTR(p) ((p) = stackblock())
1488 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1489 #define CHECKSTRSPACE(n, p) do { \
1490 char *q = (p); \
1491 size_t l = (n); \
1492 size_t m = sstrend - q; \
1493 if (l > m) \
1494 (p) = makestrspace(l, q); \
1495 } while (0)
1496 #define USTPUTC(c, p) (*(p)++ = (c))
1497 #define STACKSTRNUL(p) do { \
1498 if ((p) == sstrend) \
1499 (p) = growstackstr(); \
1500 *(p) = '\0'; \
1501 } while (0)
1502 #define STUNPUTC(p) (--(p))
1503 #define STTOPC(p) ((p)[-1])
1504 #define STADJUST(amount, p) ((p) += (amount))
1506 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1507 #define ungrabstackstr(s, p) stunalloc(s)
1508 #define stackstrend() ((void *)sstrend)
1511 /* ============ String helpers */
1514 * prefix -- see if pfx is a prefix of string.
1516 static char *
1517 prefix(const char *string, const char *pfx)
1519 while (*pfx) {
1520 if (*pfx++ != *string++)
1521 return NULL;
1523 return (char *) string;
1527 * Check for a valid number. This should be elsewhere.
1529 static int
1530 is_number(const char *p)
1532 do {
1533 if (!isdigit(*p))
1534 return 0;
1535 } while (*++p != '\0');
1536 return 1;
1540 * Convert a string of digits to an integer, printing an error message on
1541 * failure.
1543 static int
1544 number(const char *s)
1546 if (!is_number(s))
1547 ash_msg_and_raise_error(illnum, s);
1548 return atoi(s);
1552 * Produce a possibly single quoted string suitable as input to the shell.
1553 * The return string is allocated on the stack.
1555 static char *
1556 single_quote(const char *s)
1558 char *p;
1560 STARTSTACKSTR(p);
1562 do {
1563 char *q;
1564 size_t len;
1566 len = strchrnul(s, '\'') - s;
1568 q = p = makestrspace(len + 3, p);
1570 *q++ = '\'';
1571 q = (char *)memcpy(q, s, len) + len;
1572 *q++ = '\'';
1573 s += len;
1575 STADJUST(q - p, p);
1577 len = strspn(s, "'");
1578 if (!len)
1579 break;
1581 q = p = makestrspace(len + 3, p);
1583 *q++ = '"';
1584 q = (char *)memcpy(q, s, len) + len;
1585 *q++ = '"';
1586 s += len;
1588 STADJUST(q - p, p);
1589 } while (*s);
1591 USTPUTC(0, p);
1593 return stackblock();
1597 /* ============ nextopt */
1599 static char **argptr; /* argument list for builtin commands */
1600 static char *optionarg; /* set by nextopt (like getopt) */
1601 static char *optptr; /* used by nextopt */
1604 * XXX - should get rid of. Have all builtins use getopt(3).
1605 * The library getopt must have the BSD extension static variable
1606 * "optreset", otherwise it can't be used within the shell safely.
1608 * Standard option processing (a la getopt) for builtin routines.
1609 * The only argument that is passed to nextopt is the option string;
1610 * the other arguments are unnecessary. It returns the character,
1611 * or '\0' on end of input.
1613 static int
1614 nextopt(const char *optstring)
1616 char *p;
1617 const char *q;
1618 char c;
1620 p = optptr;
1621 if (p == NULL || *p == '\0') {
1622 /* We ate entire "-param", take next one */
1623 p = *argptr;
1624 if (p == NULL)
1625 return '\0';
1626 if (*p != '-')
1627 return '\0';
1628 if (*++p == '\0') /* just "-" ? */
1629 return '\0';
1630 argptr++;
1631 if (LONE_DASH(p)) /* "--" ? */
1632 return '\0';
1633 /* p => next "-param" */
1635 /* p => some option char in the middle of a "-param" */
1636 c = *p++;
1637 for (q = optstring; *q != c;) {
1638 if (*q == '\0')
1639 ash_msg_and_raise_error("illegal option -%c", c);
1640 if (*++q == ':')
1641 q++;
1643 if (*++q == ':') {
1644 if (*p == '\0') {
1645 p = *argptr++;
1646 if (p == NULL)
1647 ash_msg_and_raise_error("no arg for -%c option", c);
1649 optionarg = p;
1650 p = NULL;
1652 optptr = p;
1653 return c;
1657 /* ============ Shell variables */
1660 * The parsefile structure pointed to by the global variable parsefile
1661 * contains information about the current file being read.
1663 struct shparam {
1664 int nparam; /* # of positional parameters (without $0) */
1665 #if ENABLE_ASH_GETOPTS
1666 int optind; /* next parameter to be processed by getopts */
1667 int optoff; /* used by getopts */
1668 #endif
1669 unsigned char malloced; /* if parameter list dynamically allocated */
1670 char **p; /* parameter list */
1674 * Free the list of positional parameters.
1676 static void
1677 freeparam(volatile struct shparam *param)
1679 if (param->malloced) {
1680 char **ap, **ap1;
1681 ap = ap1 = param->p;
1682 while (*ap)
1683 free(*ap++);
1684 free(ap1);
1688 #if ENABLE_ASH_GETOPTS
1689 static void getoptsreset(const char *value);
1690 #endif
1692 struct var {
1693 struct var *next; /* next entry in hash list */
1694 int flags; /* flags are defined above */
1695 const char *text; /* name=value */
1696 void (*func)(const char *); /* function to be called when */
1697 /* the variable gets set/unset */
1700 struct localvar {
1701 struct localvar *next; /* next local variable in list */
1702 struct var *vp; /* the variable that was made local */
1703 int flags; /* saved flags */
1704 const char *text; /* saved text */
1707 /* flags */
1708 #define VEXPORT 0x01 /* variable is exported */
1709 #define VREADONLY 0x02 /* variable cannot be modified */
1710 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1711 #define VTEXTFIXED 0x08 /* text is statically allocated */
1712 #define VSTACK 0x10 /* text is allocated on the stack */
1713 #define VUNSET 0x20 /* the variable is not set */
1714 #define VNOFUNC 0x40 /* don't call the callback function */
1715 #define VNOSET 0x80 /* do not set variable - just readonly test */
1716 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1717 #if ENABLE_ASH_RANDOM_SUPPORT
1718 # define VDYNAMIC 0x200 /* dynamic variable */
1719 #else
1720 # define VDYNAMIC 0
1721 #endif
1723 #ifdef IFS_BROKEN
1724 static const char defifsvar[] ALIGN1 = "IFS= \t\n";
1725 #define defifs (defifsvar + 4)
1726 #else
1727 static const char defifs[] ALIGN1 = " \t\n";
1728 #endif
1731 /* Need to be before varinit_data[] */
1732 #if ENABLE_LOCALE_SUPPORT
1733 static void
1734 change_lc_all(const char *value)
1736 if (value && *value != '\0')
1737 setlocale(LC_ALL, value);
1739 static void
1740 change_lc_ctype(const char *value)
1742 if (value && *value != '\0')
1743 setlocale(LC_CTYPE, value);
1745 #endif
1746 #if ENABLE_ASH_MAIL
1747 static void chkmail(void);
1748 static void changemail(const char *);
1749 #endif
1750 static void changepath(const char *);
1751 #if ENABLE_ASH_RANDOM_SUPPORT
1752 static void change_random(const char *);
1753 #endif
1755 static const struct {
1756 int flags;
1757 const char *text;
1758 void (*func)(const char *);
1759 } varinit_data[] = {
1760 #ifdef IFS_BROKEN
1761 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1762 #else
1763 { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL },
1764 #endif
1765 #if ENABLE_ASH_MAIL
1766 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0" , changemail },
1767 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1768 #endif
1769 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1770 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1771 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1772 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1773 #if ENABLE_ASH_GETOPTS
1774 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
1775 #endif
1776 #if ENABLE_ASH_RANDOM_SUPPORT
1777 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1778 #endif
1779 #if ENABLE_LOCALE_SUPPORT
1780 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL\0" , change_lc_all },
1781 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE\0", change_lc_ctype },
1782 #endif
1783 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1784 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE\0", NULL },
1785 #endif
1788 struct redirtab;
1790 struct globals_var {
1791 struct shparam shellparam; /* $@ current positional parameters */
1792 struct redirtab *redirlist;
1793 int g_nullredirs;
1794 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1795 struct var *vartab[VTABSIZE];
1796 struct var varinit[ARRAY_SIZE(varinit_data)];
1798 extern struct globals_var *const ash_ptr_to_globals_var;
1799 #define G_var (*ash_ptr_to_globals_var)
1800 #define shellparam (G_var.shellparam )
1801 //#define redirlist (G_var.redirlist )
1802 #define g_nullredirs (G_var.g_nullredirs )
1803 #define preverrout_fd (G_var.preverrout_fd)
1804 #define vartab (G_var.vartab )
1805 #define varinit (G_var.varinit )
1806 #define INIT_G_var() do { \
1807 unsigned i; \
1808 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1809 barrier(); \
1810 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1811 varinit[i].flags = varinit_data[i].flags; \
1812 varinit[i].text = varinit_data[i].text; \
1813 varinit[i].func = varinit_data[i].func; \
1815 } while (0)
1817 #define vifs varinit[0]
1818 #if ENABLE_ASH_MAIL
1819 # define vmail (&vifs)[1]
1820 # define vmpath (&vmail)[1]
1821 # define vpath (&vmpath)[1]
1822 #else
1823 # define vpath (&vifs)[1]
1824 #endif
1825 #define vps1 (&vpath)[1]
1826 #define vps2 (&vps1)[1]
1827 #define vps4 (&vps2)[1]
1828 #if ENABLE_ASH_GETOPTS
1829 # define voptind (&vps4)[1]
1830 # if ENABLE_ASH_RANDOM_SUPPORT
1831 # define vrandom (&voptind)[1]
1832 # endif
1833 #else
1834 # if ENABLE_ASH_RANDOM_SUPPORT
1835 # define vrandom (&vps4)[1]
1836 # endif
1837 #endif
1840 * The following macros access the values of the above variables.
1841 * They have to skip over the name. They return the null string
1842 * for unset variables.
1844 #define ifsval() (vifs.text + 4)
1845 #define ifsset() ((vifs.flags & VUNSET) == 0)
1846 #if ENABLE_ASH_MAIL
1847 # define mailval() (vmail.text + 5)
1848 # define mpathval() (vmpath.text + 9)
1849 # define mpathset() ((vmpath.flags & VUNSET) == 0)
1850 #endif
1851 #define pathval() (vpath.text + 5)
1852 #define ps1val() (vps1.text + 4)
1853 #define ps2val() (vps2.text + 4)
1854 #define ps4val() (vps4.text + 4)
1855 #if ENABLE_ASH_GETOPTS
1856 # define optindval() (voptind.text + 7)
1857 #endif
1860 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1861 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1863 #if ENABLE_ASH_GETOPTS
1864 static void
1865 getoptsreset(const char *value)
1867 shellparam.optind = number(value);
1868 shellparam.optoff = -1;
1870 #endif
1873 * Return of a legal variable name (a letter or underscore followed by zero or
1874 * more letters, underscores, and digits).
1876 static char *
1877 endofname(const char *name)
1879 char *p;
1881 p = (char *) name;
1882 if (!is_name(*p))
1883 return p;
1884 while (*++p) {
1885 if (!is_in_name(*p))
1886 break;
1888 return p;
1892 * Compares two strings up to the first = or '\0'. The first
1893 * string must be terminated by '='; the second may be terminated by
1894 * either '=' or '\0'.
1896 static int
1897 varcmp(const char *p, const char *q)
1899 int c, d;
1901 while ((c = *p) == (d = *q)) {
1902 if (!c || c == '=')
1903 goto out;
1904 p++;
1905 q++;
1907 if (c == '=')
1908 c = '\0';
1909 if (d == '=')
1910 d = '\0';
1911 out:
1912 return c - d;
1915 static int
1916 varequal(const char *a, const char *b)
1918 return !varcmp(a, b);
1922 * Find the appropriate entry in the hash table from the name.
1924 static struct var **
1925 hashvar(const char *p)
1927 unsigned hashval;
1929 hashval = ((unsigned char) *p) << 4;
1930 while (*p && *p != '=')
1931 hashval += (unsigned char) *p++;
1932 return &vartab[hashval % VTABSIZE];
1935 static int
1936 vpcmp(const void *a, const void *b)
1938 return varcmp(*(const char **)a, *(const char **)b);
1942 * This routine initializes the builtin variables.
1944 static void
1945 initvar(void)
1947 struct var *vp;
1948 struct var *end;
1949 struct var **vpp;
1952 * PS1 depends on uid
1954 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1955 vps1.text = "PS1=\\w \\$ ";
1956 #else
1957 if (!geteuid())
1958 vps1.text = "PS1=# ";
1959 #endif
1960 vp = varinit;
1961 end = vp + ARRAY_SIZE(varinit);
1962 do {
1963 vpp = hashvar(vp->text);
1964 vp->next = *vpp;
1965 *vpp = vp;
1966 } while (++vp < end);
1969 static struct var **
1970 findvar(struct var **vpp, const char *name)
1972 for (; *vpp; vpp = &(*vpp)->next) {
1973 if (varequal((*vpp)->text, name)) {
1974 break;
1977 return vpp;
1981 * Find the value of a variable. Returns NULL if not set.
1983 static const char *
1984 lookupvar(const char *name)
1986 struct var *v;
1988 v = *findvar(hashvar(name), name);
1989 if (v) {
1990 #if ENABLE_ASH_RANDOM_SUPPORT
1992 * Dynamic variables are implemented roughly the same way they are
1993 * in bash. Namely, they're "special" so long as they aren't unset.
1994 * As soon as they're unset, they're no longer dynamic, and dynamic
1995 * lookup will no longer happen at that point. -- PFM.
1997 if ((v->flags & VDYNAMIC))
1998 (*v->func)(NULL);
1999 #endif
2000 if (!(v->flags & VUNSET))
2001 return strchrnul(v->text, '=') + 1;
2003 return NULL;
2007 * Search the environment of a builtin command.
2009 static const char *
2010 bltinlookup(const char *name)
2012 struct strlist *sp;
2014 for (sp = cmdenviron; sp; sp = sp->next) {
2015 if (varequal(sp->text, name))
2016 return strchrnul(sp->text, '=') + 1;
2018 return lookupvar(name);
2022 * Same as setvar except that the variable and value are passed in
2023 * the first argument as name=value. Since the first argument will
2024 * be actually stored in the table, it should not be a string that
2025 * will go away.
2026 * Called with interrupts off.
2028 static void
2029 setvareq(char *s, int flags)
2031 struct var *vp, **vpp;
2033 vpp = hashvar(s);
2034 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2035 vp = *findvar(vpp, s);
2036 if (vp) {
2037 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2038 const char *n;
2040 if (flags & VNOSAVE)
2041 free(s);
2042 n = vp->text;
2043 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2046 if (flags & VNOSET)
2047 return;
2049 if (vp->func && (flags & VNOFUNC) == 0)
2050 (*vp->func)(strchrnul(s, '=') + 1);
2052 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
2053 free((char*)vp->text);
2055 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2056 } else {
2057 if (flags & VNOSET)
2058 return;
2059 /* not found */
2060 vp = ckzalloc(sizeof(*vp));
2061 vp->next = *vpp;
2062 /*vp->func = NULL; - ckzalloc did it */
2063 *vpp = vp;
2065 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2066 s = ckstrdup(s);
2067 vp->text = s;
2068 vp->flags = flags;
2072 * Set the value of a variable. The flags argument is ored with the
2073 * flags of the variable. If val is NULL, the variable is unset.
2075 static void
2076 setvar(const char *name, const char *val, int flags)
2078 char *p, *q;
2079 size_t namelen;
2080 char *nameeq;
2081 size_t vallen;
2083 q = endofname(name);
2084 p = strchrnul(q, '=');
2085 namelen = p - name;
2086 if (!namelen || p != q)
2087 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2088 vallen = 0;
2089 if (val == NULL) {
2090 flags |= VUNSET;
2091 } else {
2092 vallen = strlen(val);
2094 INT_OFF;
2095 nameeq = ckmalloc(namelen + vallen + 2);
2096 p = (char *)memcpy(nameeq, name, namelen) + namelen;
2097 if (val) {
2098 *p++ = '=';
2099 p = (char *)memcpy(p, val, vallen) + vallen;
2101 *p = '\0';
2102 setvareq(nameeq, flags | VNOSAVE);
2103 INT_ON;
2106 #if ENABLE_ASH_GETOPTS
2108 * Safe version of setvar, returns 1 on success 0 on failure.
2110 static int
2111 setvarsafe(const char *name, const char *val, int flags)
2113 int err;
2114 volatile int saveint;
2115 struct jmploc *volatile savehandler = exception_handler;
2116 struct jmploc jmploc;
2118 SAVE_INT(saveint);
2119 if (setjmp(jmploc.loc))
2120 err = 1;
2121 else {
2122 exception_handler = &jmploc;
2123 setvar(name, val, flags);
2124 err = 0;
2126 exception_handler = savehandler;
2127 RESTORE_INT(saveint);
2128 return err;
2130 #endif
2133 * Unset the specified variable.
2135 static int
2136 unsetvar(const char *s)
2138 struct var **vpp;
2139 struct var *vp;
2140 int retval;
2142 vpp = findvar(hashvar(s), s);
2143 vp = *vpp;
2144 retval = 2;
2145 if (vp) {
2146 int flags = vp->flags;
2148 retval = 1;
2149 if (flags & VREADONLY)
2150 goto out;
2151 #if ENABLE_ASH_RANDOM_SUPPORT
2152 vp->flags &= ~VDYNAMIC;
2153 #endif
2154 if (flags & VUNSET)
2155 goto ok;
2156 if ((flags & VSTRFIXED) == 0) {
2157 INT_OFF;
2158 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2159 free((char*)vp->text);
2160 *vpp = vp->next;
2161 free(vp);
2162 INT_ON;
2163 } else {
2164 setvar(s, 0, 0);
2165 vp->flags &= ~VEXPORT;
2168 retval = 0;
2170 out:
2171 return retval;
2175 * Process a linked list of variable assignments.
2177 static void
2178 listsetvar(struct strlist *list_set_var, int flags)
2180 struct strlist *lp = list_set_var;
2182 if (!lp)
2183 return;
2184 INT_OFF;
2185 do {
2186 setvareq(lp->text, flags);
2187 lp = lp->next;
2188 } while (lp);
2189 INT_ON;
2193 * Generate a list of variables satisfying the given conditions.
2195 static char **
2196 listvars(int on, int off, char ***end)
2198 struct var **vpp;
2199 struct var *vp;
2200 char **ep;
2201 int mask;
2203 STARTSTACKSTR(ep);
2204 vpp = vartab;
2205 mask = on | off;
2206 do {
2207 for (vp = *vpp; vp; vp = vp->next) {
2208 if ((vp->flags & mask) == on) {
2209 if (ep == stackstrend())
2210 ep = growstackstr();
2211 *ep++ = (char *) vp->text;
2214 } while (++vpp < vartab + VTABSIZE);
2215 if (ep == stackstrend())
2216 ep = growstackstr();
2217 if (end)
2218 *end = ep;
2219 *ep++ = NULL;
2220 return grabstackstr(ep);
2224 /* ============ Path search helper
2226 * The variable path (passed by reference) should be set to the start
2227 * of the path before the first call; padvance will update
2228 * this value as it proceeds. Successive calls to padvance will return
2229 * the possible path expansions in sequence. If an option (indicated by
2230 * a percent sign) appears in the path entry then the global variable
2231 * pathopt will be set to point to it; otherwise pathopt will be set to
2232 * NULL.
2234 static const char *pathopt; /* set by padvance */
2236 static char *
2237 padvance(const char **path, const char *name)
2239 const char *p;
2240 char *q;
2241 const char *start;
2242 size_t len;
2244 if (*path == NULL)
2245 return NULL;
2246 start = *path;
2247 for (p = start; *p && *p != ':' && *p != '%'; p++)
2248 continue;
2249 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2250 while (stackblocksize() < len)
2251 growstackblock();
2252 q = stackblock();
2253 if (p != start) {
2254 memcpy(q, start, p - start);
2255 q += p - start;
2256 *q++ = '/';
2258 strcpy(q, name);
2259 pathopt = NULL;
2260 if (*p == '%') {
2261 pathopt = ++p;
2262 while (*p && *p != ':')
2263 p++;
2265 if (*p == ':')
2266 *path = p + 1;
2267 else
2268 *path = NULL;
2269 return stalloc(len);
2273 /* ============ Prompt */
2275 static smallint doprompt; /* if set, prompt the user */
2276 static smallint needprompt; /* true if interactive and at start of line */
2278 #if ENABLE_FEATURE_EDITING
2279 static line_input_t *line_input_state;
2280 static const char *cmdedit_prompt;
2281 static void
2282 putprompt(const char *s)
2284 if (ENABLE_ASH_EXPAND_PRMT) {
2285 free((char*)cmdedit_prompt);
2286 cmdedit_prompt = ckstrdup(s);
2287 return;
2289 cmdedit_prompt = s;
2291 #else
2292 static void
2293 putprompt(const char *s)
2295 out2str(s);
2297 #endif
2299 #if ENABLE_ASH_EXPAND_PRMT
2300 /* expandstr() needs parsing machinery, so it is far away ahead... */
2301 static const char *expandstr(const char *ps);
2302 #else
2303 #define expandstr(s) s
2304 #endif
2306 static void
2307 setprompt(int whichprompt)
2309 const char *prompt;
2310 #if ENABLE_ASH_EXPAND_PRMT
2311 struct stackmark smark;
2312 #endif
2314 needprompt = 0;
2316 switch (whichprompt) {
2317 case 1:
2318 prompt = ps1val();
2319 break;
2320 case 2:
2321 prompt = ps2val();
2322 break;
2323 default: /* 0 */
2324 prompt = nullstr;
2326 #if ENABLE_ASH_EXPAND_PRMT
2327 setstackmark(&smark);
2328 stalloc(stackblocksize());
2329 #endif
2330 putprompt(expandstr(prompt));
2331 #if ENABLE_ASH_EXPAND_PRMT
2332 popstackmark(&smark);
2333 #endif
2337 /* ============ The cd and pwd commands */
2339 #define CD_PHYSICAL 1
2340 #define CD_PRINT 2
2342 static int docd(const char *, int);
2344 static int
2345 cdopt(void)
2347 int flags = 0;
2348 int i, j;
2350 j = 'L';
2351 while ((i = nextopt("LP"))) {
2352 if (i != j) {
2353 flags ^= CD_PHYSICAL;
2354 j = i;
2358 return flags;
2362 * Update curdir (the name of the current directory) in response to a
2363 * cd command.
2365 static const char *
2366 updatepwd(const char *dir)
2368 char *new;
2369 char *p;
2370 char *cdcomppath;
2371 const char *lim;
2373 cdcomppath = ststrdup(dir);
2374 STARTSTACKSTR(new);
2375 if (*dir != '/') {
2376 if (curdir == nullstr)
2377 return 0;
2378 new = stack_putstr(curdir, new);
2380 new = makestrspace(strlen(dir) + 2, new);
2381 lim = (char *)stackblock() + 1;
2382 if (*dir != '/') {
2383 if (new[-1] != '/')
2384 USTPUTC('/', new);
2385 if (new > lim && *lim == '/')
2386 lim++;
2387 } else {
2388 USTPUTC('/', new);
2389 cdcomppath++;
2390 if (dir[1] == '/' && dir[2] != '/') {
2391 USTPUTC('/', new);
2392 cdcomppath++;
2393 lim++;
2396 p = strtok(cdcomppath, "/");
2397 while (p) {
2398 switch (*p) {
2399 case '.':
2400 if (p[1] == '.' && p[2] == '\0') {
2401 while (new > lim) {
2402 STUNPUTC(new);
2403 if (new[-1] == '/')
2404 break;
2406 break;
2408 if (p[1] == '\0')
2409 break;
2410 /* fall through */
2411 default:
2412 new = stack_putstr(p, new);
2413 USTPUTC('/', new);
2415 p = strtok(0, "/");
2417 if (new > lim)
2418 STUNPUTC(new);
2419 *new = 0;
2420 return stackblock();
2424 * Find out what the current directory is. If we already know the current
2425 * directory, this routine returns immediately.
2427 static char *
2428 getpwd(void)
2430 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2431 return dir ? dir : nullstr;
2434 static void
2435 setpwd(const char *val, int setold)
2437 char *oldcur, *dir;
2439 oldcur = dir = curdir;
2441 if (setold) {
2442 setvar("OLDPWD", oldcur, VEXPORT);
2444 INT_OFF;
2445 if (physdir != nullstr) {
2446 if (physdir != oldcur)
2447 free(physdir);
2448 physdir = nullstr;
2450 if (oldcur == val || !val) {
2451 char *s = getpwd();
2452 physdir = s;
2453 if (!val)
2454 dir = s;
2455 } else
2456 dir = ckstrdup(val);
2457 if (oldcur != dir && oldcur != nullstr) {
2458 free(oldcur);
2460 curdir = dir;
2461 INT_ON;
2462 setvar("PWD", dir, VEXPORT);
2465 static void hashcd(void);
2468 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2469 * know that the current directory has changed.
2471 static int
2472 docd(const char *dest, int flags)
2474 const char *dir = 0;
2475 int err;
2477 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2479 INT_OFF;
2480 if (!(flags & CD_PHYSICAL)) {
2481 dir = updatepwd(dest);
2482 if (dir)
2483 dest = dir;
2485 err = chdir(dest);
2486 if (err)
2487 goto out;
2488 setpwd(dir, 1);
2489 hashcd();
2490 out:
2491 INT_ON;
2492 return err;
2495 static int
2496 cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2498 const char *dest;
2499 const char *path;
2500 const char *p;
2501 char c;
2502 struct stat statb;
2503 int flags;
2505 flags = cdopt();
2506 dest = *argptr;
2507 if (!dest)
2508 dest = bltinlookup(homestr);
2509 else if (LONE_DASH(dest)) {
2510 dest = bltinlookup("OLDPWD");
2511 flags |= CD_PRINT;
2513 if (!dest)
2514 dest = nullstr;
2515 if (*dest == '/')
2516 goto step7;
2517 if (*dest == '.') {
2518 c = dest[1];
2519 dotdot:
2520 switch (c) {
2521 case '\0':
2522 case '/':
2523 goto step6;
2524 case '.':
2525 c = dest[2];
2526 if (c != '.')
2527 goto dotdot;
2530 if (!*dest)
2531 dest = ".";
2532 path = bltinlookup("CDPATH");
2533 if (!path) {
2534 step6:
2535 step7:
2536 p = dest;
2537 goto docd;
2539 do {
2540 c = *path;
2541 p = padvance(&path, dest);
2542 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2543 if (c && c != ':')
2544 flags |= CD_PRINT;
2545 docd:
2546 if (!docd(p, flags))
2547 goto out;
2548 break;
2550 } while (path);
2551 ash_msg_and_raise_error("can't cd to %s", dest);
2552 /* NOTREACHED */
2553 out:
2554 if (flags & CD_PRINT)
2555 out1fmt(snlfmt, curdir);
2556 return 0;
2559 static int
2560 pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2562 int flags;
2563 const char *dir = curdir;
2565 flags = cdopt();
2566 if (flags) {
2567 if (physdir == nullstr)
2568 setpwd(dir, 0);
2569 dir = physdir;
2571 out1fmt(snlfmt, dir);
2572 return 0;
2576 /* ============ ... */
2579 #define IBUFSIZ COMMON_BUFSIZE
2580 /* buffer for top level input file */
2581 #define basebuf bb_common_bufsiz1
2583 /* Syntax classes */
2584 #define CWORD 0 /* character is nothing special */
2585 #define CNL 1 /* newline character */
2586 #define CBACK 2 /* a backslash character */
2587 #define CSQUOTE 3 /* single quote */
2588 #define CDQUOTE 4 /* double quote */
2589 #define CENDQUOTE 5 /* a terminating quote */
2590 #define CBQUOTE 6 /* backwards single quote */
2591 #define CVAR 7 /* a dollar sign */
2592 #define CENDVAR 8 /* a '}' character */
2593 #define CLP 9 /* a left paren in arithmetic */
2594 #define CRP 10 /* a right paren in arithmetic */
2595 #define CENDFILE 11 /* end of file */
2596 #define CCTL 12 /* like CWORD, except it must be escaped */
2597 #define CSPCL 13 /* these terminate a word */
2598 #define CIGN 14 /* character should be ignored */
2600 #if ENABLE_ASH_ALIAS
2601 #define SYNBASE 130
2602 #define PEOF -130
2603 #define PEOA -129
2604 #define PEOA_OR_PEOF PEOA
2605 #else
2606 #define SYNBASE 129
2607 #define PEOF -129
2608 #define PEOA_OR_PEOF PEOF
2609 #endif
2611 /* number syntax index */
2612 #define BASESYNTAX 0 /* not in quotes */
2613 #define DQSYNTAX 1 /* in double quotes */
2614 #define SQSYNTAX 2 /* in single quotes */
2615 #define ARISYNTAX 3 /* in arithmetic */
2616 #define PSSYNTAX 4 /* prompt */
2618 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
2619 #define USE_SIT_FUNCTION
2620 #endif
2622 #if ENABLE_SH_MATH_SUPPORT
2623 static const char S_I_T[][4] = {
2624 #if ENABLE_ASH_ALIAS
2625 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */
2626 #endif
2627 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */
2628 { CNL, CNL, CNL, CNL }, /* 2, \n */
2629 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */
2630 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */
2631 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */
2632 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */
2633 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */
2634 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */
2635 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */
2636 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */
2637 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */
2638 #ifndef USE_SIT_FUNCTION
2639 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2640 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2641 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2642 #endif
2644 #else
2645 static const char S_I_T[][3] = {
2646 #if ENABLE_ASH_ALIAS
2647 { CSPCL, CIGN, CIGN }, /* 0, PEOA */
2648 #endif
2649 { CSPCL, CWORD, CWORD }, /* 1, ' ' */
2650 { CNL, CNL, CNL }, /* 2, \n */
2651 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */
2652 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */
2653 { CVAR, CVAR, CWORD }, /* 5, $ */
2654 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */
2655 { CSPCL, CWORD, CWORD }, /* 7, ( */
2656 { CSPCL, CWORD, CWORD }, /* 8, ) */
2657 { CBACK, CBACK, CCTL }, /* 9, \ */
2658 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */
2659 { CENDVAR, CENDVAR, CWORD }, /* 11, } */
2660 #ifndef USE_SIT_FUNCTION
2661 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */
2662 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */
2663 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */
2664 #endif
2666 #endif /* SH_MATH_SUPPORT */
2668 #ifdef USE_SIT_FUNCTION
2670 static int
2671 SIT(int c, int syntax)
2673 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2674 #if ENABLE_ASH_ALIAS
2675 static const char syntax_index_table[] ALIGN1 = {
2676 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2677 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2678 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2679 11, 3 /* "}~" */
2681 #else
2682 static const char syntax_index_table[] ALIGN1 = {
2683 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2684 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2685 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2686 10, 2 /* "}~" */
2688 #endif
2689 const char *s;
2690 int indx;
2692 if (c == PEOF) { /* 2^8+2 */
2693 return CENDFILE;
2695 #if ENABLE_ASH_ALIAS
2696 if (c == PEOA) { /* 2^8+1 */
2697 indx = 0;
2698 } else
2699 #endif
2701 if ((unsigned char)c >= (unsigned char)(CTLESC)
2702 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK)
2704 return CCTL;
2706 s = strchrnul(spec_symbls, c);
2707 if (*s == '\0') {
2708 return CWORD;
2710 indx = syntax_index_table[s - spec_symbls];
2712 return S_I_T[indx][syntax];
2715 #else /* !USE_SIT_FUNCTION */
2717 #if ENABLE_ASH_ALIAS
2718 #define CSPCL_CIGN_CIGN_CIGN 0
2719 #define CSPCL_CWORD_CWORD_CWORD 1
2720 #define CNL_CNL_CNL_CNL 2
2721 #define CWORD_CCTL_CCTL_CWORD 3
2722 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
2723 #define CVAR_CVAR_CWORD_CVAR 5
2724 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
2725 #define CSPCL_CWORD_CWORD_CLP 7
2726 #define CSPCL_CWORD_CWORD_CRP 8
2727 #define CBACK_CBACK_CCTL_CBACK 9
2728 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
2729 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
2730 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
2731 #define CWORD_CWORD_CWORD_CWORD 13
2732 #define CCTL_CCTL_CCTL_CCTL 14
2733 #else
2734 #define CSPCL_CWORD_CWORD_CWORD 0
2735 #define CNL_CNL_CNL_CNL 1
2736 #define CWORD_CCTL_CCTL_CWORD 2
2737 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
2738 #define CVAR_CVAR_CWORD_CVAR 4
2739 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
2740 #define CSPCL_CWORD_CWORD_CLP 6
2741 #define CSPCL_CWORD_CWORD_CRP 7
2742 #define CBACK_CBACK_CCTL_CBACK 8
2743 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
2744 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
2745 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
2746 #define CWORD_CWORD_CWORD_CWORD 12
2747 #define CCTL_CCTL_CCTL_CCTL 13
2748 #endif
2750 static const char syntax_index_table[258] = {
2751 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2752 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
2753 #if ENABLE_ASH_ALIAS
2754 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
2755 #endif
2756 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2757 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2758 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2759 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2760 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2761 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2762 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2763 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2764 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2765 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
2766 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
2767 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
2768 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
2769 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
2770 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
2771 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
2772 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
2773 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
2774 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
2775 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
2776 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
2777 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
2778 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
2779 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
2780 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
2781 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
2782 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
2783 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
2784 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
2785 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
2786 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
2787 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
2788 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
2789 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
2790 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
2791 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
2792 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
2793 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
2794 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
2795 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
2796 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
2797 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
2798 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
2799 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
2800 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
2801 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
2802 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
2803 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
2804 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
2805 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
2806 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
2807 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
2808 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
2809 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
2810 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
2811 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
2812 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
2813 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
2814 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
2815 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
2816 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
2817 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
2818 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
2819 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
2820 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
2821 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
2822 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
2823 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
2824 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
2825 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
2826 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
2827 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
2828 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
2829 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
2830 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
2831 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
2832 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
2833 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
2834 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
2835 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
2836 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
2837 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
2838 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
2839 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
2840 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
2841 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
2842 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
2843 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
2844 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
2845 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
2846 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
2847 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
2848 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
2853 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
2854 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2894 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
2895 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
2898 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
2899 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
2900 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
2901 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
2902 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
2903 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
2904 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
2905 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
2906 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
2907 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
2908 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
2909 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
2910 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
2911 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
2912 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
2913 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
2914 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
2915 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
2916 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2917 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2918 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2919 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2921 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2923 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2924 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2925 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2926 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2927 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
2929 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2930 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
2931 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2932 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2943 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2944 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2945 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2946 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2947 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2948 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2976 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2977 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2978 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2981 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3003 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3004 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3005 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3006 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3007 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3008 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3009 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3010 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3011 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
3014 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[(int)(c) + SYNBASE]][syntax])
3016 #endif /* USE_SIT_FUNCTION */
3019 /* ============ Alias handling */
3021 #if ENABLE_ASH_ALIAS
3023 #define ALIASINUSE 1
3024 #define ALIASDEAD 2
3026 struct alias {
3027 struct alias *next;
3028 char *name;
3029 char *val;
3030 int flag;
3034 static struct alias **atab; // [ATABSIZE];
3035 #define INIT_G_alias() do { \
3036 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3037 } while (0)
3040 static struct alias **
3041 __lookupalias(const char *name) {
3042 unsigned int hashval;
3043 struct alias **app;
3044 const char *p;
3045 unsigned int ch;
3047 p = name;
3049 ch = (unsigned char)*p;
3050 hashval = ch << 4;
3051 while (ch) {
3052 hashval += ch;
3053 ch = (unsigned char)*++p;
3055 app = &atab[hashval % ATABSIZE];
3057 for (; *app; app = &(*app)->next) {
3058 if (strcmp(name, (*app)->name) == 0) {
3059 break;
3063 return app;
3066 static struct alias *
3067 lookupalias(const char *name, int check)
3069 struct alias *ap = *__lookupalias(name);
3071 if (check && ap && (ap->flag & ALIASINUSE))
3072 return NULL;
3073 return ap;
3076 static struct alias *
3077 freealias(struct alias *ap)
3079 struct alias *next;
3081 if (ap->flag & ALIASINUSE) {
3082 ap->flag |= ALIASDEAD;
3083 return ap;
3086 next = ap->next;
3087 free(ap->name);
3088 free(ap->val);
3089 free(ap);
3090 return next;
3093 static void
3094 setalias(const char *name, const char *val)
3096 struct alias *ap, **app;
3098 app = __lookupalias(name);
3099 ap = *app;
3100 INT_OFF;
3101 if (ap) {
3102 if (!(ap->flag & ALIASINUSE)) {
3103 free(ap->val);
3105 ap->val = ckstrdup(val);
3106 ap->flag &= ~ALIASDEAD;
3107 } else {
3108 /* not found */
3109 ap = ckzalloc(sizeof(struct alias));
3110 ap->name = ckstrdup(name);
3111 ap->val = ckstrdup(val);
3112 /*ap->flag = 0; - ckzalloc did it */
3113 /*ap->next = NULL;*/
3114 *app = ap;
3116 INT_ON;
3119 static int
3120 unalias(const char *name)
3122 struct alias **app;
3124 app = __lookupalias(name);
3126 if (*app) {
3127 INT_OFF;
3128 *app = freealias(*app);
3129 INT_ON;
3130 return 0;
3133 return 1;
3136 static void
3137 rmaliases(void)
3139 struct alias *ap, **app;
3140 int i;
3142 INT_OFF;
3143 for (i = 0; i < ATABSIZE; i++) {
3144 app = &atab[i];
3145 for (ap = *app; ap; ap = *app) {
3146 *app = freealias(*app);
3147 if (ap == *app) {
3148 app = &ap->next;
3152 INT_ON;
3155 static void
3156 printalias(const struct alias *ap)
3158 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3162 * TODO - sort output
3164 static int
3165 aliascmd(int argc UNUSED_PARAM, char **argv)
3167 char *n, *v;
3168 int ret = 0;
3169 struct alias *ap;
3171 if (!argv[1]) {
3172 int i;
3174 for (i = 0; i < ATABSIZE; i++) {
3175 for (ap = atab[i]; ap; ap = ap->next) {
3176 printalias(ap);
3179 return 0;
3181 while ((n = *++argv) != NULL) {
3182 v = strchr(n+1, '=');
3183 if (v == NULL) { /* n+1: funny ksh stuff */
3184 ap = *__lookupalias(n);
3185 if (ap == NULL) {
3186 fprintf(stderr, "%s: %s not found\n", "alias", n);
3187 ret = 1;
3188 } else
3189 printalias(ap);
3190 } else {
3191 *v++ = '\0';
3192 setalias(n, v);
3196 return ret;
3199 static int
3200 unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3202 int i;
3204 while ((i = nextopt("a")) != '\0') {
3205 if (i == 'a') {
3206 rmaliases();
3207 return 0;
3210 for (i = 0; *argptr; argptr++) {
3211 if (unalias(*argptr)) {
3212 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3213 i = 1;
3217 return i;
3220 #endif /* ASH_ALIAS */
3223 /* ============ jobs.c */
3225 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3226 #define FORK_FG 0
3227 #define FORK_BG 1
3228 #define FORK_NOJOB 2
3230 /* mode flags for showjob(s) */
3231 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
3232 #define SHOW_PID 0x04 /* include process pid */
3233 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
3236 * A job structure contains information about a job. A job is either a
3237 * single process or a set of processes contained in a pipeline. In the
3238 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3239 * array of pids.
3242 struct procstat {
3243 pid_t pid; /* process id */
3244 int status; /* last process status from wait() */
3245 char *cmd; /* text of command being run */
3248 struct job {
3249 struct procstat ps0; /* status of process */
3250 struct procstat *ps; /* status or processes when more than one */
3251 #if JOBS
3252 int stopstatus; /* status of a stopped job */
3253 #endif
3254 uint32_t
3255 nprocs: 16, /* number of processes */
3256 state: 8,
3257 #define JOBRUNNING 0 /* at least one proc running */
3258 #define JOBSTOPPED 1 /* all procs are stopped */
3259 #define JOBDONE 2 /* all procs are completed */
3260 #if JOBS
3261 sigint: 1, /* job was killed by SIGINT */
3262 jobctl: 1, /* job running under job control */
3263 #endif
3264 waited: 1, /* true if this entry has been waited for */
3265 used: 1, /* true if this entry is in used */
3266 changed: 1; /* true if status has changed */
3267 struct job *prev_job; /* previous job */
3270 static struct job *makejob(/*union node *,*/ int);
3271 #if !JOBS
3272 #define forkshell(job, node, mode) forkshell(job, mode)
3273 #endif
3274 static int forkshell(struct job *, union node *, int);
3275 static int waitforjob(struct job *);
3277 #if !JOBS
3278 enum { doing_jobctl = 0 };
3279 #define setjobctl(on) do {} while (0)
3280 #else
3281 static smallint doing_jobctl; //references:8
3282 static void setjobctl(int);
3283 #endif
3286 * Ignore a signal.
3288 static void
3289 ignoresig(int signo)
3291 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3292 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3293 /* No, need to do it */
3294 signal(signo, SIG_IGN);
3296 sigmode[signo - 1] = S_HARD_IGN;
3300 * Signal handler. Only one usage site - in setsignal()
3302 static void
3303 onsig(int signo)
3305 gotsig[signo - 1] = 1;
3307 if (/* exsig || */ (signo == SIGINT && !trap[SIGINT])) {
3308 if (!suppressint) {
3309 pendingsig = 0;
3310 raise_interrupt(); /* does not return */
3312 intpending = 1;
3313 } else {
3314 pendingsig = signo;
3319 * Set the signal handler for the specified signal. The routine figures
3320 * out what it should be set to.
3322 static void
3323 setsignal(int signo)
3325 char *t;
3326 char cur_act, new_act;
3327 struct sigaction act;
3329 t = trap[signo];
3330 new_act = S_DFL;
3331 if (t != NULL) { /* trap for this sig is set */
3332 new_act = S_CATCH;
3333 if (t[0] == '\0') /* trap is "": ignore this sig */
3334 new_act = S_IGN;
3337 if (rootshell && new_act == S_DFL) {
3338 switch (signo) {
3339 case SIGINT:
3340 if (iflag || minusc || sflag == 0)
3341 new_act = S_CATCH;
3342 break;
3343 case SIGQUIT:
3344 #if DEBUG
3345 if (debug)
3346 break;
3347 #endif
3348 /* man bash:
3349 * "In all cases, bash ignores SIGQUIT. Non-builtin
3350 * commands run by bash have signal handlers
3351 * set to the values inherited by the shell
3352 * from its parent". */
3353 new_act = S_IGN;
3354 break;
3355 case SIGTERM:
3356 if (iflag)
3357 new_act = S_IGN;
3358 break;
3359 #if JOBS
3360 case SIGTSTP:
3361 case SIGTTOU:
3362 if (mflag)
3363 new_act = S_IGN;
3364 break;
3365 #endif
3368 //TODO: if !rootshell, we reset SIGQUIT to DFL,
3369 //whereas we have to restore it to what shell got on entry
3370 //from the parent. See comment above
3372 t = &sigmode[signo - 1];
3373 cur_act = *t;
3374 if (cur_act == 0) {
3375 /* current setting is not yet known */
3376 if (sigaction(signo, NULL, &act)) {
3377 /* pretend it worked; maybe we should give a warning,
3378 * but other shells don't. We don't alter sigmode,
3379 * so we retry every time.
3380 * btw, in Linux it never fails. --vda */
3381 return;
3383 if (act.sa_handler == SIG_IGN) {
3384 cur_act = S_HARD_IGN;
3385 if (mflag
3386 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3388 cur_act = S_IGN; /* don't hard ignore these */
3392 if (cur_act == S_HARD_IGN || cur_act == new_act)
3393 return;
3395 act.sa_handler = SIG_DFL;
3396 switch (new_act) {
3397 case S_CATCH:
3398 act.sa_handler = onsig;
3399 act.sa_flags = 0; /* matters only if !DFL and !IGN */
3400 sigfillset(&act.sa_mask); /* ditto */
3401 break;
3402 case S_IGN:
3403 act.sa_handler = SIG_IGN;
3404 break;
3406 sigaction_set(signo, &act);
3408 *t = new_act;
3411 /* mode flags for set_curjob */
3412 #define CUR_DELETE 2
3413 #define CUR_RUNNING 1
3414 #define CUR_STOPPED 0
3416 /* mode flags for dowait */
3417 #define DOWAIT_NONBLOCK WNOHANG
3418 #define DOWAIT_BLOCK 0
3420 #if JOBS
3421 /* pgrp of shell on invocation */
3422 static int initialpgrp; //references:2
3423 static int ttyfd = -1; //5
3424 #endif
3425 /* array of jobs */
3426 static struct job *jobtab; //5
3427 /* size of array */
3428 static unsigned njobs; //4
3429 /* current job */
3430 static struct job *curjob; //lots
3431 /* number of presumed living untracked jobs */
3432 static int jobless; //4
3434 static void
3435 set_curjob(struct job *jp, unsigned mode)
3437 struct job *jp1;
3438 struct job **jpp, **curp;
3440 /* first remove from list */
3441 jpp = curp = &curjob;
3442 do {
3443 jp1 = *jpp;
3444 if (jp1 == jp)
3445 break;
3446 jpp = &jp1->prev_job;
3447 } while (1);
3448 *jpp = jp1->prev_job;
3450 /* Then re-insert in correct position */
3451 jpp = curp;
3452 switch (mode) {
3453 default:
3454 #if DEBUG
3455 abort();
3456 #endif
3457 case CUR_DELETE:
3458 /* job being deleted */
3459 break;
3460 case CUR_RUNNING:
3461 /* newly created job or backgrounded job,
3462 put after all stopped jobs. */
3463 do {
3464 jp1 = *jpp;
3465 #if JOBS
3466 if (!jp1 || jp1->state != JOBSTOPPED)
3467 #endif
3468 break;
3469 jpp = &jp1->prev_job;
3470 } while (1);
3471 /* FALLTHROUGH */
3472 #if JOBS
3473 case CUR_STOPPED:
3474 #endif
3475 /* newly stopped job - becomes curjob */
3476 jp->prev_job = *jpp;
3477 *jpp = jp;
3478 break;
3482 #if JOBS || DEBUG
3483 static int
3484 jobno(const struct job *jp)
3486 return jp - jobtab + 1;
3488 #endif
3491 * Convert a job name to a job structure.
3493 #if !JOBS
3494 #define getjob(name, getctl) getjob(name)
3495 #endif
3496 static struct job *
3497 getjob(const char *name, int getctl)
3499 struct job *jp;
3500 struct job *found;
3501 const char *err_msg = "No such job: %s";
3502 unsigned num;
3503 int c;
3504 const char *p;
3505 char *(*match)(const char *, const char *);
3507 jp = curjob;
3508 p = name;
3509 if (!p)
3510 goto currentjob;
3512 if (*p != '%')
3513 goto err;
3515 c = *++p;
3516 if (!c)
3517 goto currentjob;
3519 if (!p[1]) {
3520 if (c == '+' || c == '%') {
3521 currentjob:
3522 err_msg = "No current job";
3523 goto check;
3525 if (c == '-') {
3526 if (jp)
3527 jp = jp->prev_job;
3528 err_msg = "No previous job";
3529 check:
3530 if (!jp)
3531 goto err;
3532 goto gotit;
3536 if (is_number(p)) {
3537 // TODO: number() instead? It does error checking...
3538 num = atoi(p);
3539 if (num < njobs) {
3540 jp = jobtab + num - 1;
3541 if (jp->used)
3542 goto gotit;
3543 goto err;
3547 match = prefix;
3548 if (*p == '?') {
3549 match = strstr;
3550 p++;
3553 found = 0;
3554 while (1) {
3555 if (!jp)
3556 goto err;
3557 if (match(jp->ps[0].cmd, p)) {
3558 if (found)
3559 goto err;
3560 found = jp;
3561 err_msg = "%s: ambiguous";
3563 jp = jp->prev_job;
3566 gotit:
3567 #if JOBS
3568 err_msg = "job %s not created under job control";
3569 if (getctl && jp->jobctl == 0)
3570 goto err;
3571 #endif
3572 return jp;
3573 err:
3574 ash_msg_and_raise_error(err_msg, name);
3578 * Mark a job structure as unused.
3580 static void
3581 freejob(struct job *jp)
3583 struct procstat *ps;
3584 int i;
3586 INT_OFF;
3587 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3588 if (ps->cmd != nullstr)
3589 free(ps->cmd);
3591 if (jp->ps != &jp->ps0)
3592 free(jp->ps);
3593 jp->used = 0;
3594 set_curjob(jp, CUR_DELETE);
3595 INT_ON;
3598 #if JOBS
3599 static void
3600 xtcsetpgrp(int fd, pid_t pgrp)
3602 if (tcsetpgrp(fd, pgrp))
3603 ash_msg_and_raise_error("can't set tty process group (%m)");
3607 * Turn job control on and off.
3609 * Note: This code assumes that the third arg to ioctl is a character
3610 * pointer, which is true on Berkeley systems but not System V. Since
3611 * System V doesn't have job control yet, this isn't a problem now.
3613 * Called with interrupts off.
3615 static void
3616 setjobctl(int on)
3618 int fd;
3619 int pgrp;
3621 if (on == doing_jobctl || rootshell == 0)
3622 return;
3623 if (on) {
3624 int ofd;
3625 ofd = fd = open(_PATH_TTY, O_RDWR);
3626 if (fd < 0) {
3627 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3628 * That sometimes helps to acquire controlling tty.
3629 * Obviously, a workaround for bugs when someone
3630 * failed to provide a controlling tty to bash! :) */
3631 fd = 2;
3632 while (!isatty(fd))
3633 if (--fd < 0)
3634 goto out;
3636 fd = fcntl(fd, F_DUPFD, 10);
3637 if (ofd >= 0)
3638 close(ofd);
3639 if (fd < 0)
3640 goto out;
3641 /* fd is a tty at this point */
3642 close_on_exec_on(fd);
3643 do { /* while we are in the background */
3644 pgrp = tcgetpgrp(fd);
3645 if (pgrp < 0) {
3646 out:
3647 ash_msg("can't access tty; job control turned off");
3648 mflag = on = 0;
3649 goto close;
3651 if (pgrp == getpgrp())
3652 break;
3653 killpg(0, SIGTTIN);
3654 } while (1);
3655 initialpgrp = pgrp;
3657 setsignal(SIGTSTP);
3658 setsignal(SIGTTOU);
3659 setsignal(SIGTTIN);
3660 pgrp = rootpid;
3661 setpgid(0, pgrp);
3662 xtcsetpgrp(fd, pgrp);
3663 } else {
3664 /* turning job control off */
3665 fd = ttyfd;
3666 pgrp = initialpgrp;
3667 /* was xtcsetpgrp, but this can make exiting ash
3668 * loop forever if pty is already deleted */
3669 tcsetpgrp(fd, pgrp);
3670 setpgid(0, pgrp);
3671 setsignal(SIGTSTP);
3672 setsignal(SIGTTOU);
3673 setsignal(SIGTTIN);
3674 close:
3675 if (fd >= 0)
3676 close(fd);
3677 fd = -1;
3679 ttyfd = fd;
3680 doing_jobctl = on;
3683 static int
3684 killcmd(int argc, char **argv)
3686 int i = 1;
3687 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3688 do {
3689 if (argv[i][0] == '%') {
3690 struct job *jp = getjob(argv[i], 0);
3691 unsigned pid = jp->ps[0].pid;
3692 /* Enough space for ' -NNN<nul>' */
3693 argv[i] = alloca(sizeof(int)*3 + 3);
3694 /* kill_main has matching code to expect
3695 * leading space. Needed to not confuse
3696 * negative pids with "kill -SIGNAL_NO" syntax */
3697 sprintf(argv[i], " -%u", pid);
3699 } while (argv[++i]);
3701 return kill_main(argc, argv);
3704 static void
3705 showpipe(struct job *jp, FILE *out)
3707 struct procstat *sp;
3708 struct procstat *spend;
3710 spend = jp->ps + jp->nprocs;
3711 for (sp = jp->ps + 1; sp < spend; sp++)
3712 fprintf(out, " | %s", sp->cmd);
3713 outcslow('\n', out);
3714 flush_stdout_stderr();
3718 static int
3719 restartjob(struct job *jp, int mode)
3721 struct procstat *ps;
3722 int i;
3723 int status;
3724 pid_t pgid;
3726 INT_OFF;
3727 if (jp->state == JOBDONE)
3728 goto out;
3729 jp->state = JOBRUNNING;
3730 pgid = jp->ps->pid;
3731 if (mode == FORK_FG)
3732 xtcsetpgrp(ttyfd, pgid);
3733 killpg(pgid, SIGCONT);
3734 ps = jp->ps;
3735 i = jp->nprocs;
3736 do {
3737 if (WIFSTOPPED(ps->status)) {
3738 ps->status = -1;
3740 ps++;
3741 } while (--i);
3742 out:
3743 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3744 INT_ON;
3745 return status;
3748 static int
3749 fg_bgcmd(int argc UNUSED_PARAM, char **argv)
3751 struct job *jp;
3752 FILE *out;
3753 int mode;
3754 int retval;
3756 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3757 nextopt(nullstr);
3758 argv = argptr;
3759 out = stdout;
3760 do {
3761 jp = getjob(*argv, 1);
3762 if (mode == FORK_BG) {
3763 set_curjob(jp, CUR_RUNNING);
3764 fprintf(out, "[%d] ", jobno(jp));
3766 outstr(jp->ps->cmd, out);
3767 showpipe(jp, out);
3768 retval = restartjob(jp, mode);
3769 } while (*argv && *++argv);
3770 return retval;
3772 #endif
3774 static int
3775 sprint_status(char *s, int status, int sigonly)
3777 int col;
3778 int st;
3780 col = 0;
3781 if (!WIFEXITED(status)) {
3782 #if JOBS
3783 if (WIFSTOPPED(status))
3784 st = WSTOPSIG(status);
3785 else
3786 #endif
3787 st = WTERMSIG(status);
3788 if (sigonly) {
3789 if (st == SIGINT || st == SIGPIPE)
3790 goto out;
3791 #if JOBS
3792 if (WIFSTOPPED(status))
3793 goto out;
3794 #endif
3796 st &= 0x7f;
3797 col = fmtstr(s, 32, strsignal(st));
3798 if (WCOREDUMP(status)) {
3799 col += fmtstr(s + col, 16, " (core dumped)");
3801 } else if (!sigonly) {
3802 st = WEXITSTATUS(status);
3803 if (st)
3804 col = fmtstr(s, 16, "Done(%d)", st);
3805 else
3806 col = fmtstr(s, 16, "Done");
3808 out:
3809 return col;
3812 static int
3813 dowait(int wait_flags, struct job *job)
3815 int pid;
3816 int status;
3817 struct job *jp;
3818 struct job *thisjob;
3819 int state;
3821 TRACE(("dowait(0x%x) called\n", wait_flags));
3823 /* Do a wait system call. If job control is compiled in, we accept
3824 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3825 * NB: _not_ safe_waitpid, we need to detect EINTR */
3826 pid = waitpid(-1, &status,
3827 (doing_jobctl ? (wait_flags | WUNTRACED) : wait_flags));
3828 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3829 pid, status, errno, strerror(errno)));
3830 if (pid <= 0)
3831 return pid;
3833 INT_OFF;
3834 thisjob = NULL;
3835 for (jp = curjob; jp; jp = jp->prev_job) {
3836 struct procstat *sp;
3837 struct procstat *spend;
3838 if (jp->state == JOBDONE)
3839 continue;
3840 state = JOBDONE;
3841 spend = jp->ps + jp->nprocs;
3842 sp = jp->ps;
3843 do {
3844 if (sp->pid == pid) {
3845 TRACE(("Job %d: changing status of proc %d "
3846 "from 0x%x to 0x%x\n",
3847 jobno(jp), pid, sp->status, status));
3848 sp->status = status;
3849 thisjob = jp;
3851 if (sp->status == -1)
3852 state = JOBRUNNING;
3853 #if JOBS
3854 if (state == JOBRUNNING)
3855 continue;
3856 if (WIFSTOPPED(sp->status)) {
3857 jp->stopstatus = sp->status;
3858 state = JOBSTOPPED;
3860 #endif
3861 } while (++sp < spend);
3862 if (thisjob)
3863 goto gotjob;
3865 #if JOBS
3866 if (!WIFSTOPPED(status))
3867 #endif
3868 jobless--;
3869 goto out;
3871 gotjob:
3872 if (state != JOBRUNNING) {
3873 thisjob->changed = 1;
3875 if (thisjob->state != state) {
3876 TRACE(("Job %d: changing state from %d to %d\n",
3877 jobno(thisjob), thisjob->state, state));
3878 thisjob->state = state;
3879 #if JOBS
3880 if (state == JOBSTOPPED) {
3881 set_curjob(thisjob, CUR_STOPPED);
3883 #endif
3887 out:
3888 INT_ON;
3890 if (thisjob && thisjob == job) {
3891 char s[48 + 1];
3892 int len;
3894 len = sprint_status(s, status, 1);
3895 if (len) {
3896 s[len] = '\n';
3897 s[len + 1] = '\0';
3898 out2str(s);
3901 return pid;
3904 static int
3905 blocking_wait_with_raise_on_sig(struct job *job)
3907 pid_t pid = dowait(DOWAIT_BLOCK, job);
3908 if (pid <= 0 && pendingsig)
3909 raise_exception(EXSIG);
3910 return pid;
3913 #if JOBS
3914 static void
3915 showjob(FILE *out, struct job *jp, int mode)
3917 struct procstat *ps;
3918 struct procstat *psend;
3919 int col;
3920 int indent_col;
3921 char s[80];
3923 ps = jp->ps;
3925 if (mode & SHOW_PGID) {
3926 /* just output process (group) id of pipeline */
3927 fprintf(out, "%d\n", ps->pid);
3928 return;
3931 col = fmtstr(s, 16, "[%d] ", jobno(jp));
3932 indent_col = col;
3934 if (jp == curjob)
3935 s[col - 2] = '+';
3936 else if (curjob && jp == curjob->prev_job)
3937 s[col - 2] = '-';
3939 if (mode & SHOW_PID)
3940 col += fmtstr(s + col, 16, "%d ", ps->pid);
3942 psend = ps + jp->nprocs;
3944 if (jp->state == JOBRUNNING) {
3945 strcpy(s + col, "Running");
3946 col += sizeof("Running") - 1;
3947 } else {
3948 int status = psend[-1].status;
3949 if (jp->state == JOBSTOPPED)
3950 status = jp->stopstatus;
3951 col += sprint_status(s + col, status, 0);
3954 goto start;
3956 do {
3957 /* for each process */
3958 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3;
3959 start:
3960 fprintf(out, "%s%*c%s",
3961 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
3963 if (!(mode & SHOW_PID)) {
3964 showpipe(jp, out);
3965 break;
3967 if (++ps == psend) {
3968 outcslow('\n', out);
3969 break;
3971 } while (1);
3973 jp->changed = 0;
3975 if (jp->state == JOBDONE) {
3976 TRACE(("showjob: freeing job %d\n", jobno(jp)));
3977 freejob(jp);
3982 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3983 * statuses have changed since the last call to showjobs.
3985 static void
3986 showjobs(FILE *out, int mode)
3988 struct job *jp;
3990 TRACE(("showjobs(%x) called\n", mode));
3992 /* Handle all finished jobs */
3993 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
3994 continue;
3996 for (jp = curjob; jp; jp = jp->prev_job) {
3997 if (!(mode & SHOW_CHANGED) || jp->changed) {
3998 showjob(out, jp, mode);
4003 static int
4004 jobscmd(int argc UNUSED_PARAM, char **argv)
4006 int mode, m;
4008 mode = 0;
4009 while ((m = nextopt("lp"))) {
4010 if (m == 'l')
4011 mode = SHOW_PID;
4012 else
4013 mode = SHOW_PGID;
4016 argv = argptr;
4017 if (*argv) {
4019 showjob(stdout, getjob(*argv,0), mode);
4020 while (*++argv);
4021 } else
4022 showjobs(stdout, mode);
4024 return 0;
4026 #endif /* JOBS */
4028 static int
4029 getstatus(struct job *job)
4031 int status;
4032 int retval;
4034 status = job->ps[job->nprocs - 1].status;
4035 retval = WEXITSTATUS(status);
4036 if (!WIFEXITED(status)) {
4037 #if JOBS
4038 retval = WSTOPSIG(status);
4039 if (!WIFSTOPPED(status))
4040 #endif
4042 /* XXX: limits number of signals */
4043 retval = WTERMSIG(status);
4044 #if JOBS
4045 if (retval == SIGINT)
4046 job->sigint = 1;
4047 #endif
4049 retval += 128;
4051 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
4052 jobno(job), job->nprocs, status, retval));
4053 return retval;
4056 static int
4057 waitcmd(int argc UNUSED_PARAM, char **argv)
4059 struct job *job;
4060 int retval;
4061 struct job *jp;
4063 // exsig++;
4064 // xbarrier();
4065 if (pendingsig)
4066 raise_exception(EXSIG);
4068 nextopt(nullstr);
4069 retval = 0;
4071 argv = argptr;
4072 if (!*argv) {
4073 /* wait for all jobs */
4074 for (;;) {
4075 jp = curjob;
4076 while (1) {
4077 if (!jp) /* no running procs */
4078 goto ret;
4079 if (jp->state == JOBRUNNING)
4080 break;
4081 jp->waited = 1;
4082 jp = jp->prev_job;
4084 /* man bash:
4085 * "When bash is waiting for an asynchronous command via
4086 * the wait builtin, the reception of a signal for which a trap
4087 * has been set will cause the wait builtin to return immediately
4088 * with an exit status greater than 128, immediately after which
4089 * the trap is executed."
4090 * Do we do it that way? */
4091 blocking_wait_with_raise_on_sig(NULL);
4095 retval = 127;
4096 do {
4097 if (**argv != '%') {
4098 pid_t pid = number(*argv);
4099 job = curjob;
4100 while (1) {
4101 if (!job)
4102 goto repeat;
4103 if (job->ps[job->nprocs - 1].pid == pid)
4104 break;
4105 job = job->prev_job;
4107 } else
4108 job = getjob(*argv, 0);
4109 /* loop until process terminated or stopped */
4110 while (job->state == JOBRUNNING)
4111 blocking_wait_with_raise_on_sig(NULL);
4112 job->waited = 1;
4113 retval = getstatus(job);
4114 repeat: ;
4115 } while (*++argv);
4117 ret:
4118 return retval;
4121 static struct job *
4122 growjobtab(void)
4124 size_t len;
4125 ptrdiff_t offset;
4126 struct job *jp, *jq;
4128 len = njobs * sizeof(*jp);
4129 jq = jobtab;
4130 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4132 offset = (char *)jp - (char *)jq;
4133 if (offset) {
4134 /* Relocate pointers */
4135 size_t l = len;
4137 jq = (struct job *)((char *)jq + l);
4138 while (l) {
4139 l -= sizeof(*jp);
4140 jq--;
4141 #define joff(p) ((struct job *)((char *)(p) + l))
4142 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4143 if (joff(jp)->ps == &jq->ps0)
4144 jmove(joff(jp)->ps);
4145 if (joff(jp)->prev_job)
4146 jmove(joff(jp)->prev_job);
4148 if (curjob)
4149 jmove(curjob);
4150 #undef joff
4151 #undef jmove
4154 njobs += 4;
4155 jobtab = jp;
4156 jp = (struct job *)((char *)jp + len);
4157 jq = jp + 3;
4158 do {
4159 jq->used = 0;
4160 } while (--jq >= jp);
4161 return jp;
4165 * Return a new job structure.
4166 * Called with interrupts off.
4168 static struct job *
4169 makejob(/*union node *node,*/ int nprocs)
4171 int i;
4172 struct job *jp;
4174 for (i = njobs, jp = jobtab; ; jp++) {
4175 if (--i < 0) {
4176 jp = growjobtab();
4177 break;
4179 if (jp->used == 0)
4180 break;
4181 if (jp->state != JOBDONE || !jp->waited)
4182 continue;
4183 #if JOBS
4184 if (doing_jobctl)
4185 continue;
4186 #endif
4187 freejob(jp);
4188 break;
4190 memset(jp, 0, sizeof(*jp));
4191 #if JOBS
4192 /* jp->jobctl is a bitfield.
4193 * "jp->jobctl |= jobctl" likely to give awful code */
4194 if (doing_jobctl)
4195 jp->jobctl = 1;
4196 #endif
4197 jp->prev_job = curjob;
4198 curjob = jp;
4199 jp->used = 1;
4200 jp->ps = &jp->ps0;
4201 if (nprocs > 1) {
4202 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4204 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4205 jobno(jp)));
4206 return jp;
4209 #if JOBS
4211 * Return a string identifying a command (to be printed by the
4212 * jobs command).
4214 static char *cmdnextc;
4216 static void
4217 cmdputs(const char *s)
4219 static const char vstype[VSTYPE + 1][3] = {
4220 "", "}", "-", "+", "?", "=",
4221 "%", "%%", "#", "##"
4222 USE_ASH_BASH_COMPAT(, ":", "/", "//")
4225 const char *p, *str;
4226 char c, cc[2] = " ";
4227 char *nextc;
4228 int subtype = 0;
4229 int quoted = 0;
4231 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4232 p = s;
4233 while ((c = *p++) != 0) {
4234 str = NULL;
4235 switch (c) {
4236 case CTLESC:
4237 c = *p++;
4238 break;
4239 case CTLVAR:
4240 subtype = *p++;
4241 if ((subtype & VSTYPE) == VSLENGTH)
4242 str = "${#";
4243 else
4244 str = "${";
4245 if (!(subtype & VSQUOTE) == !(quoted & 1))
4246 goto dostr;
4247 quoted ^= 1;
4248 c = '"';
4249 break;
4250 case CTLENDVAR:
4251 str = "\"}" + !(quoted & 1);
4252 quoted >>= 1;
4253 subtype = 0;
4254 goto dostr;
4255 case CTLBACKQ:
4256 str = "$(...)";
4257 goto dostr;
4258 case CTLBACKQ+CTLQUOTE:
4259 str = "\"$(...)\"";
4260 goto dostr;
4261 #if ENABLE_SH_MATH_SUPPORT
4262 case CTLARI:
4263 str = "$((";
4264 goto dostr;
4265 case CTLENDARI:
4266 str = "))";
4267 goto dostr;
4268 #endif
4269 case CTLQUOTEMARK:
4270 quoted ^= 1;
4271 c = '"';
4272 break;
4273 case '=':
4274 if (subtype == 0)
4275 break;
4276 if ((subtype & VSTYPE) != VSNORMAL)
4277 quoted <<= 1;
4278 str = vstype[subtype & VSTYPE];
4279 if (subtype & VSNUL)
4280 c = ':';
4281 else
4282 goto checkstr;
4283 break;
4284 case '\'':
4285 case '\\':
4286 case '"':
4287 case '$':
4288 /* These can only happen inside quotes */
4289 cc[0] = c;
4290 str = cc;
4291 c = '\\';
4292 break;
4293 default:
4294 break;
4296 USTPUTC(c, nextc);
4297 checkstr:
4298 if (!str)
4299 continue;
4300 dostr:
4301 while ((c = *str++)) {
4302 USTPUTC(c, nextc);
4305 if (quoted & 1) {
4306 USTPUTC('"', nextc);
4308 *nextc = 0;
4309 cmdnextc = nextc;
4312 /* cmdtxt() and cmdlist() call each other */
4313 static void cmdtxt(union node *n);
4315 static void
4316 cmdlist(union node *np, int sep)
4318 for (; np; np = np->narg.next) {
4319 if (!sep)
4320 cmdputs(" ");
4321 cmdtxt(np);
4322 if (sep && np->narg.next)
4323 cmdputs(" ");
4327 static void
4328 cmdtxt(union node *n)
4330 union node *np;
4331 struct nodelist *lp;
4332 const char *p;
4334 if (!n)
4335 return;
4336 switch (n->type) {
4337 default:
4338 #if DEBUG
4339 abort();
4340 #endif
4341 case NPIPE:
4342 lp = n->npipe.cmdlist;
4343 for (;;) {
4344 cmdtxt(lp->n);
4345 lp = lp->next;
4346 if (!lp)
4347 break;
4348 cmdputs(" | ");
4350 break;
4351 case NSEMI:
4352 p = "; ";
4353 goto binop;
4354 case NAND:
4355 p = " && ";
4356 goto binop;
4357 case NOR:
4358 p = " || ";
4359 binop:
4360 cmdtxt(n->nbinary.ch1);
4361 cmdputs(p);
4362 n = n->nbinary.ch2;
4363 goto donode;
4364 case NREDIR:
4365 case NBACKGND:
4366 n = n->nredir.n;
4367 goto donode;
4368 case NNOT:
4369 cmdputs("!");
4370 n = n->nnot.com;
4371 donode:
4372 cmdtxt(n);
4373 break;
4374 case NIF:
4375 cmdputs("if ");
4376 cmdtxt(n->nif.test);
4377 cmdputs("; then ");
4378 n = n->nif.ifpart;
4379 if (n->nif.elsepart) {
4380 cmdtxt(n);
4381 cmdputs("; else ");
4382 n = n->nif.elsepart;
4384 p = "; fi";
4385 goto dotail;
4386 case NSUBSHELL:
4387 cmdputs("(");
4388 n = n->nredir.n;
4389 p = ")";
4390 goto dotail;
4391 case NWHILE:
4392 p = "while ";
4393 goto until;
4394 case NUNTIL:
4395 p = "until ";
4396 until:
4397 cmdputs(p);
4398 cmdtxt(n->nbinary.ch1);
4399 n = n->nbinary.ch2;
4400 p = "; done";
4401 dodo:
4402 cmdputs("; do ");
4403 dotail:
4404 cmdtxt(n);
4405 goto dotail2;
4406 case NFOR:
4407 cmdputs("for ");
4408 cmdputs(n->nfor.var);
4409 cmdputs(" in ");
4410 cmdlist(n->nfor.args, 1);
4411 n = n->nfor.body;
4412 p = "; done";
4413 goto dodo;
4414 case NDEFUN:
4415 cmdputs(n->narg.text);
4416 p = "() { ... }";
4417 goto dotail2;
4418 case NCMD:
4419 cmdlist(n->ncmd.args, 1);
4420 cmdlist(n->ncmd.redirect, 0);
4421 break;
4422 case NARG:
4423 p = n->narg.text;
4424 dotail2:
4425 cmdputs(p);
4426 break;
4427 case NHERE:
4428 case NXHERE:
4429 p = "<<...";
4430 goto dotail2;
4431 case NCASE:
4432 cmdputs("case ");
4433 cmdputs(n->ncase.expr->narg.text);
4434 cmdputs(" in ");
4435 for (np = n->ncase.cases; np; np = np->nclist.next) {
4436 cmdtxt(np->nclist.pattern);
4437 cmdputs(") ");
4438 cmdtxt(np->nclist.body);
4439 cmdputs(";; ");
4441 p = "esac";
4442 goto dotail2;
4443 case NTO:
4444 p = ">";
4445 goto redir;
4446 case NCLOBBER:
4447 p = ">|";
4448 goto redir;
4449 case NAPPEND:
4450 p = ">>";
4451 goto redir;
4452 #if ENABLE_ASH_BASH_COMPAT
4453 case NTO2:
4454 #endif
4455 case NTOFD:
4456 p = ">&";
4457 goto redir;
4458 case NFROM:
4459 p = "<";
4460 goto redir;
4461 case NFROMFD:
4462 p = "<&";
4463 goto redir;
4464 case NFROMTO:
4465 p = "<>";
4466 redir:
4467 cmdputs(utoa(n->nfile.fd));
4468 cmdputs(p);
4469 if (n->type == NTOFD || n->type == NFROMFD) {
4470 cmdputs(utoa(n->ndup.dupfd));
4471 break;
4473 n = n->nfile.fname;
4474 goto donode;
4478 static char *
4479 commandtext(union node *n)
4481 char *name;
4483 STARTSTACKSTR(cmdnextc);
4484 cmdtxt(n);
4485 name = stackblock();
4486 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4487 name, cmdnextc, cmdnextc));
4488 return ckstrdup(name);
4490 #endif /* JOBS */
4493 * Fork off a subshell. If we are doing job control, give the subshell its
4494 * own process group. Jp is a job structure that the job is to be added to.
4495 * N is the command that will be evaluated by the child. Both jp and n may
4496 * be NULL. The mode parameter can be one of the following:
4497 * FORK_FG - Fork off a foreground process.
4498 * FORK_BG - Fork off a background process.
4499 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4500 * process group even if job control is on.
4502 * When job control is turned off, background processes have their standard
4503 * input redirected to /dev/null (except for the second and later processes
4504 * in a pipeline).
4506 * Called with interrupts off.
4509 * Clear traps on a fork.
4511 static void
4512 clear_traps(void)
4514 char **tp;
4516 for (tp = trap; tp < &trap[NSIG]; tp++) {
4517 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4518 INT_OFF;
4519 free(*tp);
4520 *tp = NULL;
4521 if (tp != &trap[0])
4522 setsignal(tp - trap);
4523 INT_ON;
4528 /* Lives far away from here, needed for forkchild */
4529 static void closescript(void);
4531 /* Called after fork(), in child */
4532 static void
4533 forkchild(struct job *jp, /*union node *n,*/ int mode)
4535 int oldlvl;
4537 TRACE(("Child shell %d\n", getpid()));
4538 oldlvl = shlvl;
4539 shlvl++;
4541 /* man bash: "Non-builtin commands run by bash have signal handlers
4542 * set to the values inherited by the shell from its parent".
4543 * Do we do it correctly? */
4545 closescript();
4546 clear_traps();
4547 #if JOBS
4548 /* do job control only in root shell */
4549 doing_jobctl = 0;
4550 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
4551 pid_t pgrp;
4553 if (jp->nprocs == 0)
4554 pgrp = getpid();
4555 else
4556 pgrp = jp->ps[0].pid;
4557 /* this can fail because we are doing it in the parent also */
4558 setpgid(0, pgrp);
4559 if (mode == FORK_FG)
4560 xtcsetpgrp(ttyfd, pgrp);
4561 setsignal(SIGTSTP);
4562 setsignal(SIGTTOU);
4563 } else
4564 #endif
4565 if (mode == FORK_BG) {
4566 /* man bash: "When job control is not in effect,
4567 * asynchronous commands ignore SIGINT and SIGQUIT" */
4568 ignoresig(SIGINT);
4569 ignoresig(SIGQUIT);
4570 if (jp->nprocs == 0) {
4571 close(0);
4572 if (open(bb_dev_null, O_RDONLY) != 0)
4573 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
4576 if (!oldlvl) {
4577 if (iflag) { /* why if iflag only? */
4578 setsignal(SIGINT);
4579 setsignal(SIGTERM);
4581 /* man bash:
4582 * "In all cases, bash ignores SIGQUIT. Non-builtin
4583 * commands run by bash have signal handlers
4584 * set to the values inherited by the shell
4585 * from its parent".
4586 * Take care of the second rule: */
4587 setsignal(SIGQUIT);
4589 for (jp = curjob; jp; jp = jp->prev_job)
4590 freejob(jp);
4591 jobless = 0;
4594 /* Called after fork(), in parent */
4595 #if !JOBS
4596 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4597 #endif
4598 static void
4599 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4601 TRACE(("In parent shell: child = %d\n", pid));
4602 if (!jp) {
4603 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4604 continue;
4605 jobless++;
4606 return;
4608 #if JOBS
4609 if (mode != FORK_NOJOB && jp->jobctl) {
4610 int pgrp;
4612 if (jp->nprocs == 0)
4613 pgrp = pid;
4614 else
4615 pgrp = jp->ps[0].pid;
4616 /* This can fail because we are doing it in the child also */
4617 setpgid(pid, pgrp);
4619 #endif
4620 if (mode == FORK_BG) {
4621 backgndpid = pid; /* set $! */
4622 set_curjob(jp, CUR_RUNNING);
4624 if (jp) {
4625 struct procstat *ps = &jp->ps[jp->nprocs++];
4626 ps->pid = pid;
4627 ps->status = -1;
4628 ps->cmd = nullstr;
4629 #if JOBS
4630 if (doing_jobctl && n)
4631 ps->cmd = commandtext(n);
4632 #endif
4636 static int
4637 forkshell(struct job *jp, union node *n, int mode)
4639 int pid;
4641 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4642 pid = fork();
4643 if (pid < 0) {
4644 TRACE(("Fork failed, errno=%d", errno));
4645 if (jp)
4646 freejob(jp);
4647 ash_msg_and_raise_error("can't fork");
4649 if (pid == 0)
4650 forkchild(jp, /*n,*/ mode);
4651 else
4652 forkparent(jp, n, mode, pid);
4653 return pid;
4657 * Wait for job to finish.
4659 * Under job control we have the problem that while a child process
4660 * is running interrupts generated by the user are sent to the child
4661 * but not to the shell. This means that an infinite loop started by
4662 * an interactive user may be hard to kill. With job control turned off,
4663 * an interactive user may place an interactive program inside a loop.
4664 * If the interactive program catches interrupts, the user doesn't want
4665 * these interrupts to also abort the loop. The approach we take here
4666 * is to have the shell ignore interrupt signals while waiting for a
4667 * foreground process to terminate, and then send itself an interrupt
4668 * signal if the child process was terminated by an interrupt signal.
4669 * Unfortunately, some programs want to do a bit of cleanup and then
4670 * exit on interrupt; unless these processes terminate themselves by
4671 * sending a signal to themselves (instead of calling exit) they will
4672 * confuse this approach.
4674 * Called with interrupts off.
4676 static int
4677 waitforjob(struct job *jp)
4679 int st;
4681 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4683 INT_OFF;
4684 while (jp->state == JOBRUNNING) {
4685 /* In non-interactive shells, we _can_ get
4686 * a keyboard signal here and be EINTRed,
4687 * but we just loop back, waiting for command to complete.
4689 * man bash:
4690 * "If bash is waiting for a command to complete and receives
4691 * a signal for which a trap has been set, the trap
4692 * will not be executed until the command completes."
4694 * Reality is that even if trap is not set, bash
4695 * will not act on the signal until command completes.
4696 * Try this. sleep5intoff.c:
4697 * #include <signal.h>
4698 * #include <unistd.h>
4699 * int main() {
4700 * sigset_t set;
4701 * sigemptyset(&set);
4702 * sigaddset(&set, SIGINT);
4703 * sigaddset(&set, SIGQUIT);
4704 * sigprocmask(SIG_BLOCK, &set, NULL);
4705 * sleep(5);
4706 * return 0;
4708 * $ bash -c './sleep5intoff; echo hi'
4709 * ^C^C^C^C <--- pressing ^C once a second
4710 * $ _
4711 * $ bash -c './sleep5intoff; echo hi'
4712 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4713 * $ _
4715 dowait(DOWAIT_BLOCK, jp);
4717 INT_ON;
4719 st = getstatus(jp);
4720 #if JOBS
4721 if (jp->jobctl) {
4722 xtcsetpgrp(ttyfd, rootpid);
4724 * This is truly gross.
4725 * If we're doing job control, then we did a TIOCSPGRP which
4726 * caused us (the shell) to no longer be in the controlling
4727 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4728 * intuit from the subprocess exit status whether a SIGINT
4729 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4731 if (jp->sigint) /* TODO: do the same with all signals */
4732 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4734 if (jp->state == JOBDONE)
4735 #endif
4736 freejob(jp);
4737 return st;
4741 * return 1 if there are stopped jobs, otherwise 0
4743 static int
4744 stoppedjobs(void)
4746 struct job *jp;
4747 int retval;
4749 retval = 0;
4750 if (job_warning)
4751 goto out;
4752 jp = curjob;
4753 if (jp && jp->state == JOBSTOPPED) {
4754 out2str("You have stopped jobs.\n");
4755 job_warning = 2;
4756 retval++;
4758 out:
4759 return retval;
4763 /* ============ redir.c
4765 * Code for dealing with input/output redirection.
4768 #define EMPTY -2 /* marks an unused slot in redirtab */
4769 #define CLOSED -3 /* marks a slot of previously-closed fd */
4772 * Open a file in noclobber mode.
4773 * The code was copied from bash.
4775 static int
4776 noclobberopen(const char *fname)
4778 int r, fd;
4779 struct stat finfo, finfo2;
4782 * If the file exists and is a regular file, return an error
4783 * immediately.
4785 r = stat(fname, &finfo);
4786 if (r == 0 && S_ISREG(finfo.st_mode)) {
4787 errno = EEXIST;
4788 return -1;
4792 * If the file was not present (r != 0), make sure we open it
4793 * exclusively so that if it is created before we open it, our open
4794 * will fail. Make sure that we do not truncate an existing file.
4795 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4796 * file was not a regular file, we leave O_EXCL off.
4798 if (r != 0)
4799 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
4800 fd = open(fname, O_WRONLY|O_CREAT, 0666);
4802 /* If the open failed, return the file descriptor right away. */
4803 if (fd < 0)
4804 return fd;
4807 * OK, the open succeeded, but the file may have been changed from a
4808 * non-regular file to a regular file between the stat and the open.
4809 * We are assuming that the O_EXCL open handles the case where FILENAME
4810 * did not exist and is symlinked to an existing file between the stat
4811 * and open.
4815 * If we can open it and fstat the file descriptor, and neither check
4816 * revealed that it was a regular file, and the file has not been
4817 * replaced, return the file descriptor.
4819 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
4820 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
4821 return fd;
4823 /* The file has been replaced. badness. */
4824 close(fd);
4825 errno = EEXIST;
4826 return -1;
4830 * Handle here documents. Normally we fork off a process to write the
4831 * data to a pipe. If the document is short, we can stuff the data in
4832 * the pipe without forking.
4834 /* openhere needs this forward reference */
4835 static void expandhere(union node *arg, int fd);
4836 static int
4837 openhere(union node *redir)
4839 int pip[2];
4840 size_t len = 0;
4842 if (pipe(pip) < 0)
4843 ash_msg_and_raise_error("pipe call failed");
4844 if (redir->type == NHERE) {
4845 len = strlen(redir->nhere.doc->narg.text);
4846 if (len <= PIPE_BUF) {
4847 full_write(pip[1], redir->nhere.doc->narg.text, len);
4848 goto out;
4851 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
4852 /* child */
4853 close(pip[0]);
4854 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
4855 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
4856 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
4857 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
4858 signal(SIGPIPE, SIG_DFL);
4859 if (redir->type == NHERE)
4860 full_write(pip[1], redir->nhere.doc->narg.text, len);
4861 else /* NXHERE */
4862 expandhere(redir->nhere.doc, pip[1]);
4863 _exit(EXIT_SUCCESS);
4865 out:
4866 close(pip[1]);
4867 return pip[0];
4870 static int
4871 openredirect(union node *redir)
4873 char *fname;
4874 int f;
4876 switch (redir->nfile.type) {
4877 case NFROM:
4878 fname = redir->nfile.expfname;
4879 f = open(fname, O_RDONLY);
4880 if (f < 0)
4881 goto eopen;
4882 break;
4883 case NFROMTO:
4884 fname = redir->nfile.expfname;
4885 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
4886 if (f < 0)
4887 goto ecreate;
4888 break;
4889 case NTO:
4890 #if ENABLE_ASH_BASH_COMPAT
4891 case NTO2:
4892 #endif
4893 /* Take care of noclobber mode. */
4894 if (Cflag) {
4895 fname = redir->nfile.expfname;
4896 f = noclobberopen(fname);
4897 if (f < 0)
4898 goto ecreate;
4899 break;
4901 /* FALLTHROUGH */
4902 case NCLOBBER:
4903 fname = redir->nfile.expfname;
4904 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
4905 if (f < 0)
4906 goto ecreate;
4907 break;
4908 case NAPPEND:
4909 fname = redir->nfile.expfname;
4910 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
4911 if (f < 0)
4912 goto ecreate;
4913 break;
4914 default:
4915 #if DEBUG
4916 abort();
4917 #endif
4918 /* Fall through to eliminate warning. */
4919 /* Our single caller does this itself */
4920 // case NTOFD:
4921 // case NFROMFD:
4922 // f = -1;
4923 // break;
4924 case NHERE:
4925 case NXHERE:
4926 f = openhere(redir);
4927 break;
4930 return f;
4931 ecreate:
4932 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
4933 eopen:
4934 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
4938 * Copy a file descriptor to be >= to. Returns -1
4939 * if the source file descriptor is closed, EMPTY if there are no unused
4940 * file descriptors left.
4942 /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
4943 * old code was doing close(to) prior to copyfd() to achieve the same */
4944 enum {
4945 COPYFD_EXACT = (int)~(INT_MAX),
4946 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
4948 static int
4949 copyfd(int from, int to)
4951 int newfd;
4953 if (to & COPYFD_EXACT) {
4954 to &= ~COPYFD_EXACT;
4955 /*if (from != to)*/
4956 newfd = dup2(from, to);
4957 } else {
4958 newfd = fcntl(from, F_DUPFD, to);
4960 if (newfd < 0) {
4961 if (errno == EMFILE)
4962 return EMPTY;
4963 /* Happens when source fd is not open: try "echo >&99" */
4964 ash_msg_and_raise_error("%d: %m", from);
4966 return newfd;
4969 /* Struct def and variable are moved down to the first usage site */
4970 struct two_fd_t {
4971 int orig, copy;
4973 struct redirtab {
4974 struct redirtab *next;
4975 int nullredirs;
4976 int pair_count;
4977 struct two_fd_t two_fd[0];
4979 #define redirlist (G_var.redirlist)
4981 static int need_to_remember(struct redirtab *rp, int fd)
4983 int i;
4985 if (!rp) /* remembering was not requested */
4986 return 0;
4988 for (i = 0; i < rp->pair_count; i++) {
4989 if (rp->two_fd[i].orig == fd) {
4990 /* already remembered */
4991 return 0;
4994 return 1;
4997 /* "hidden" fd is a fd used to read scripts, or a copy of such */
4998 static int is_hidden_fd(struct redirtab *rp, int fd)
5000 int i;
5001 struct parsefile *pf;
5003 if (fd == -1)
5004 return 0;
5005 pf = g_parsefile;
5006 while (pf) {
5007 if (fd == pf->fd) {
5008 return 1;
5010 pf = pf->prev;
5012 if (!rp)
5013 return 0;
5014 fd |= COPYFD_RESTORE;
5015 for (i = 0; i < rp->pair_count; i++) {
5016 if (rp->two_fd[i].copy == fd) {
5017 return 1;
5020 return 0;
5024 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5025 * old file descriptors are stashed away so that the redirection can be
5026 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
5027 * standard output, and the standard error if it becomes a duplicate of
5028 * stdout, is saved in memory.
5030 /* flags passed to redirect */
5031 #define REDIR_PUSH 01 /* save previous values of file descriptors */
5032 #define REDIR_SAVEFD2 03 /* set preverrout */
5033 static void
5034 redirect(union node *redir, int flags)
5036 struct redirtab *sv;
5037 int sv_pos;
5038 int i;
5039 int fd;
5040 int newfd;
5041 int copied_fd2 = -1;
5043 g_nullredirs++;
5044 if (!redir) {
5045 return;
5048 sv = NULL;
5049 sv_pos = 0;
5050 INT_OFF;
5051 if (flags & REDIR_PUSH) {
5052 union node *tmp = redir;
5053 do {
5054 sv_pos++;
5055 #if ENABLE_ASH_BASH_COMPAT
5056 if (redir->nfile.type == NTO2)
5057 sv_pos++;
5058 #endif
5059 tmp = tmp->nfile.next;
5060 } while (tmp);
5061 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
5062 sv->next = redirlist;
5063 sv->pair_count = sv_pos;
5064 redirlist = sv;
5065 sv->nullredirs = g_nullredirs - 1;
5066 g_nullredirs = 0;
5067 while (sv_pos > 0) {
5068 sv_pos--;
5069 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5073 do {
5074 fd = redir->nfile.fd;
5075 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5076 int right_fd = redir->ndup.dupfd;
5077 /* redirect from/to same file descriptor? */
5078 if (right_fd == fd)
5079 continue;
5080 /* echo >&10 and 10 is a fd opened to the sh script? */
5081 if (is_hidden_fd(sv, right_fd)) {
5082 errno = EBADF; /* as if it is closed */
5083 ash_msg_and_raise_error("%d: %m", right_fd);
5085 newfd = -1;
5086 } else {
5087 newfd = openredirect(redir); /* always >= 0 */
5088 if (fd == newfd) {
5089 /* Descriptor wasn't open before redirect.
5090 * Mark it for close in the future */
5091 if (need_to_remember(sv, fd)) {
5092 goto remember_to_close;
5094 continue;
5097 #if ENABLE_ASH_BASH_COMPAT
5098 redirect_more:
5099 #endif
5100 if (need_to_remember(sv, fd)) {
5101 /* Copy old descriptor */
5102 i = fcntl(fd, F_DUPFD, 10);
5103 /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5104 * are closed in popredir() in the child, preventing them from leaking
5105 * into child. (popredir() also cleans up the mess in case of failures)
5107 if (i == -1) {
5108 i = errno;
5109 if (i != EBADF) {
5110 /* Strange error (e.g. "too many files" EMFILE?) */
5111 if (newfd >= 0)
5112 close(newfd);
5113 errno = i;
5114 ash_msg_and_raise_error("%d: %m", fd);
5115 /* NOTREACHED */
5117 /* EBADF: it is not open - good, remember to close it */
5118 remember_to_close:
5119 i = CLOSED;
5120 } else { /* fd is open, save its copy */
5121 /* "exec fd>&-" should not close fds
5122 * which point to script file(s).
5123 * Force them to be restored afterwards */
5124 if (is_hidden_fd(sv, fd))
5125 i |= COPYFD_RESTORE;
5127 if (fd == 2)
5128 copied_fd2 = i;
5129 sv->two_fd[sv_pos].orig = fd;
5130 sv->two_fd[sv_pos].copy = i;
5131 sv_pos++;
5133 if (newfd < 0) {
5134 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5135 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5136 /* Don't want to trigger debugging */
5137 if (fd != -1)
5138 close(fd);
5139 } else {
5140 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
5142 } else if (fd != newfd) { /* move newfd to fd */
5143 copyfd(newfd, fd | COPYFD_EXACT);
5144 #if ENABLE_ASH_BASH_COMPAT
5145 if (!(redir->nfile.type == NTO2 && fd == 2))
5146 #endif
5147 close(newfd);
5149 #if ENABLE_ASH_BASH_COMPAT
5150 if (redir->nfile.type == NTO2 && fd == 1) {
5151 /* We already redirected it to fd 1, now copy it to 2 */
5152 newfd = 1;
5153 fd = 2;
5154 goto redirect_more;
5156 #endif
5157 } while ((redir = redir->nfile.next) != NULL);
5159 INT_ON;
5160 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5161 preverrout_fd = copied_fd2;
5165 * Undo the effects of the last redirection.
5167 static void
5168 popredir(int drop, int restore)
5170 struct redirtab *rp;
5171 int i;
5173 if (--g_nullredirs >= 0)
5174 return;
5175 INT_OFF;
5176 rp = redirlist;
5177 for (i = 0; i < rp->pair_count; i++) {
5178 int fd = rp->two_fd[i].orig;
5179 int copy = rp->two_fd[i].copy;
5180 if (copy == CLOSED) {
5181 if (!drop)
5182 close(fd);
5183 continue;
5185 if (copy != EMPTY) {
5186 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5187 copy &= ~COPYFD_RESTORE;
5188 /*close(fd);*/
5189 copyfd(copy, fd | COPYFD_EXACT);
5191 close(copy & ~COPYFD_RESTORE);
5194 redirlist = rp->next;
5195 g_nullredirs = rp->nullredirs;
5196 free(rp);
5197 INT_ON;
5201 * Undo all redirections. Called on error or interrupt.
5205 * Discard all saved file descriptors.
5207 static void
5208 clearredir(int drop)
5210 for (;;) {
5211 g_nullredirs = 0;
5212 if (!redirlist)
5213 break;
5214 popredir(drop, /*restore:*/ 0);
5218 static int
5219 redirectsafe(union node *redir, int flags)
5221 int err;
5222 volatile int saveint;
5223 struct jmploc *volatile savehandler = exception_handler;
5224 struct jmploc jmploc;
5226 SAVE_INT(saveint);
5227 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5228 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5229 if (!err) {
5230 exception_handler = &jmploc;
5231 redirect(redir, flags);
5233 exception_handler = savehandler;
5234 if (err && exception_type != EXERROR)
5235 longjmp(exception_handler->loc, 1);
5236 RESTORE_INT(saveint);
5237 return err;
5241 /* ============ Routines to expand arguments to commands
5243 * We have to deal with backquotes, shell variables, and file metacharacters.
5246 #if ENABLE_SH_MATH_SUPPORT
5247 static arith_t
5248 ash_arith(const char *s)
5250 arith_eval_hooks_t math_hooks;
5251 arith_t result;
5252 int errcode = 0;
5254 math_hooks.lookupvar = lookupvar;
5255 math_hooks.setvar = setvar;
5256 math_hooks.endofname = endofname;
5258 INT_OFF;
5259 result = arith(s, &errcode, &math_hooks);
5260 if (errcode < 0) {
5261 if (errcode == -3)
5262 ash_msg_and_raise_error("exponent less than 0");
5263 if (errcode == -2)
5264 ash_msg_and_raise_error("divide by zero");
5265 if (errcode == -5)
5266 ash_msg_and_raise_error("expression recursion loop detected");
5267 raise_error_syntax(s);
5269 INT_ON;
5271 return result;
5273 #endif
5276 * expandarg flags
5278 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5279 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5280 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5281 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5282 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5283 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5284 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5285 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5286 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5288 * _rmescape() flags
5290 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5291 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5292 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5293 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5294 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5297 * Structure specifying which parts of the string should be searched
5298 * for IFS characters.
5300 struct ifsregion {
5301 struct ifsregion *next; /* next region in list */
5302 int begoff; /* offset of start of region */
5303 int endoff; /* offset of end of region */
5304 int nulonly; /* search for nul bytes only */
5307 struct arglist {
5308 struct strlist *list;
5309 struct strlist **lastp;
5312 /* output of current string */
5313 static char *expdest;
5314 /* list of back quote expressions */
5315 static struct nodelist *argbackq;
5316 /* first struct in list of ifs regions */
5317 static struct ifsregion ifsfirst;
5318 /* last struct in list */
5319 static struct ifsregion *ifslastp;
5320 /* holds expanded arg list */
5321 static struct arglist exparg;
5324 * Our own itoa().
5326 static int
5327 cvtnum(arith_t num)
5329 int len;
5331 expdest = makestrspace(32, expdest);
5332 len = fmtstr(expdest, 32, arith_t_fmt, num);
5333 STADJUST(len, expdest);
5334 return len;
5337 static size_t
5338 esclen(const char *start, const char *p)
5340 size_t esc = 0;
5342 while (p > start && *--p == CTLESC) {
5343 esc++;
5345 return esc;
5349 * Remove any CTLESC characters from a string.
5351 static char *
5352 _rmescapes(char *str, int flag)
5354 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5356 char *p, *q, *r;
5357 unsigned inquotes;
5358 int notescaped;
5359 int globbing;
5361 p = strpbrk(str, qchars);
5362 if (!p) {
5363 return str;
5365 q = p;
5366 r = str;
5367 if (flag & RMESCAPE_ALLOC) {
5368 size_t len = p - str;
5369 size_t fulllen = len + strlen(p) + 1;
5371 if (flag & RMESCAPE_GROW) {
5372 r = makestrspace(fulllen, expdest);
5373 } else if (flag & RMESCAPE_HEAP) {
5374 r = ckmalloc(fulllen);
5375 } else {
5376 r = stalloc(fulllen);
5378 q = r;
5379 if (len > 0) {
5380 q = (char *)memcpy(q, str, len) + len;
5383 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5384 globbing = flag & RMESCAPE_GLOB;
5385 notescaped = globbing;
5386 while (*p) {
5387 if (*p == CTLQUOTEMARK) {
5388 inquotes = ~inquotes;
5389 p++;
5390 notescaped = globbing;
5391 continue;
5393 if (*p == '\\') {
5394 /* naked back slash */
5395 notescaped = 0;
5396 goto copy;
5398 if (*p == CTLESC) {
5399 p++;
5400 if (notescaped && inquotes && *p != '/') {
5401 *q++ = '\\';
5404 notescaped = globbing;
5405 copy:
5406 *q++ = *p++;
5408 *q = '\0';
5409 if (flag & RMESCAPE_GROW) {
5410 expdest = r;
5411 STADJUST(q - r + 1, expdest);
5413 return r;
5415 #define rmescapes(p) _rmescapes((p), 0)
5417 #define pmatch(a, b) !fnmatch((a), (b), 0)
5420 * Prepare a pattern for a expmeta (internal glob(3)) call.
5422 * Returns an stalloced string.
5424 static char *
5425 preglob(const char *pattern, int quoted, int flag)
5427 flag |= RMESCAPE_GLOB;
5428 if (quoted) {
5429 flag |= RMESCAPE_QUOTED;
5431 return _rmescapes((char *)pattern, flag);
5435 * Put a string on the stack.
5437 static void
5438 memtodest(const char *p, size_t len, int syntax, int quotes)
5440 char *q = expdest;
5442 q = makestrspace(len * 2, q);
5444 while (len--) {
5445 int c = signed_char2int(*p++);
5446 if (!c)
5447 continue;
5448 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5449 USTPUTC(CTLESC, q);
5450 USTPUTC(c, q);
5453 expdest = q;
5456 static void
5457 strtodest(const char *p, int syntax, int quotes)
5459 memtodest(p, strlen(p), syntax, quotes);
5463 * Record the fact that we have to scan this region of the
5464 * string for IFS characters.
5466 static void
5467 recordregion(int start, int end, int nulonly)
5469 struct ifsregion *ifsp;
5471 if (ifslastp == NULL) {
5472 ifsp = &ifsfirst;
5473 } else {
5474 INT_OFF;
5475 ifsp = ckzalloc(sizeof(*ifsp));
5476 /*ifsp->next = NULL; - ckzalloc did it */
5477 ifslastp->next = ifsp;
5478 INT_ON;
5480 ifslastp = ifsp;
5481 ifslastp->begoff = start;
5482 ifslastp->endoff = end;
5483 ifslastp->nulonly = nulonly;
5486 static void
5487 removerecordregions(int endoff)
5489 if (ifslastp == NULL)
5490 return;
5492 if (ifsfirst.endoff > endoff) {
5493 while (ifsfirst.next != NULL) {
5494 struct ifsregion *ifsp;
5495 INT_OFF;
5496 ifsp = ifsfirst.next->next;
5497 free(ifsfirst.next);
5498 ifsfirst.next = ifsp;
5499 INT_ON;
5501 if (ifsfirst.begoff > endoff)
5502 ifslastp = NULL;
5503 else {
5504 ifslastp = &ifsfirst;
5505 ifsfirst.endoff = endoff;
5507 return;
5510 ifslastp = &ifsfirst;
5511 while (ifslastp->next && ifslastp->next->begoff < endoff)
5512 ifslastp=ifslastp->next;
5513 while (ifslastp->next != NULL) {
5514 struct ifsregion *ifsp;
5515 INT_OFF;
5516 ifsp = ifslastp->next->next;
5517 free(ifslastp->next);
5518 ifslastp->next = ifsp;
5519 INT_ON;
5521 if (ifslastp->endoff > endoff)
5522 ifslastp->endoff = endoff;
5525 static char *
5526 exptilde(char *startp, char *p, int flag)
5528 char c;
5529 char *name;
5530 struct passwd *pw;
5531 const char *home;
5532 int quotes = flag & (EXP_FULL | EXP_CASE);
5533 int startloc;
5535 name = p + 1;
5537 while ((c = *++p) != '\0') {
5538 switch (c) {
5539 case CTLESC:
5540 return startp;
5541 case CTLQUOTEMARK:
5542 return startp;
5543 case ':':
5544 if (flag & EXP_VARTILDE)
5545 goto done;
5546 break;
5547 case '/':
5548 case CTLENDVAR:
5549 goto done;
5552 done:
5553 *p = '\0';
5554 if (*name == '\0') {
5555 home = lookupvar(homestr);
5556 } else {
5557 pw = getpwnam(name);
5558 if (pw == NULL)
5559 goto lose;
5560 home = pw->pw_dir;
5562 if (!home || !*home)
5563 goto lose;
5564 *p = c;
5565 startloc = expdest - (char *)stackblock();
5566 strtodest(home, SQSYNTAX, quotes);
5567 recordregion(startloc, expdest - (char *)stackblock(), 0);
5568 return p;
5569 lose:
5570 *p = c;
5571 return startp;
5575 * Execute a command inside back quotes. If it's a builtin command, we
5576 * want to save its output in a block obtained from malloc. Otherwise
5577 * we fork off a subprocess and get the output of the command via a pipe.
5578 * Should be called with interrupts off.
5580 struct backcmd { /* result of evalbackcmd */
5581 int fd; /* file descriptor to read from */
5582 int nleft; /* number of chars in buffer */
5583 char *buf; /* buffer */
5584 struct job *jp; /* job structure for command */
5587 /* These forward decls are needed to use "eval" code for backticks handling: */
5588 static uint8_t back_exitstatus; /* exit status of backquoted command */
5589 #define EV_EXIT 01 /* exit after evaluating tree */
5590 static void evaltree(union node *, int);
5592 static void
5593 evalbackcmd(union node *n, struct backcmd *result)
5595 int saveherefd;
5597 result->fd = -1;
5598 result->buf = NULL;
5599 result->nleft = 0;
5600 result->jp = NULL;
5601 if (n == NULL)
5602 goto out;
5604 saveherefd = herefd;
5605 herefd = -1;
5608 int pip[2];
5609 struct job *jp;
5611 if (pipe(pip) < 0)
5612 ash_msg_and_raise_error("pipe call failed");
5613 jp = makejob(/*n,*/ 1);
5614 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5615 FORCE_INT_ON;
5616 close(pip[0]);
5617 if (pip[1] != 1) {
5618 /*close(1);*/
5619 copyfd(pip[1], 1 | COPYFD_EXACT);
5620 close(pip[1]);
5622 eflag = 0;
5623 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5624 /* NOTREACHED */
5626 close(pip[1]);
5627 result->fd = pip[0];
5628 result->jp = jp;
5630 herefd = saveherefd;
5631 out:
5632 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5633 result->fd, result->buf, result->nleft, result->jp));
5637 * Expand stuff in backwards quotes.
5639 static void
5640 expbackq(union node *cmd, int quoted, int quotes)
5642 struct backcmd in;
5643 int i;
5644 char buf[128];
5645 char *p;
5646 char *dest;
5647 int startloc;
5648 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
5649 struct stackmark smark;
5651 INT_OFF;
5652 setstackmark(&smark);
5653 dest = expdest;
5654 startloc = dest - (char *)stackblock();
5655 grabstackstr(dest);
5656 evalbackcmd(cmd, &in);
5657 popstackmark(&smark);
5659 p = in.buf;
5660 i = in.nleft;
5661 if (i == 0)
5662 goto read;
5663 for (;;) {
5664 memtodest(p, i, syntax, quotes);
5665 read:
5666 if (in.fd < 0)
5667 break;
5668 i = nonblock_safe_read(in.fd, buf, sizeof(buf));
5669 TRACE(("expbackq: read returns %d\n", i));
5670 if (i <= 0)
5671 break;
5672 p = buf;
5675 free(in.buf);
5676 if (in.fd >= 0) {
5677 close(in.fd);
5678 back_exitstatus = waitforjob(in.jp);
5680 INT_ON;
5682 /* Eat all trailing newlines */
5683 dest = expdest;
5684 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5685 STUNPUTC(dest);
5686 expdest = dest;
5688 if (quoted == 0)
5689 recordregion(startloc, dest - (char *)stackblock(), 0);
5690 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5691 (dest - (char *)stackblock()) - startloc,
5692 (dest - (char *)stackblock()) - startloc,
5693 stackblock() + startloc));
5696 #if ENABLE_SH_MATH_SUPPORT
5698 * Expand arithmetic expression. Backup to start of expression,
5699 * evaluate, place result in (backed up) result, adjust string position.
5701 static void
5702 expari(int quotes)
5704 char *p, *start;
5705 int begoff;
5706 int flag;
5707 int len;
5709 /* ifsfree(); */
5712 * This routine is slightly over-complicated for
5713 * efficiency. Next we scan backwards looking for the
5714 * start of arithmetic.
5716 start = stackblock();
5717 p = expdest - 1;
5718 *p = '\0';
5719 p--;
5720 do {
5721 int esc;
5723 while (*p != CTLARI) {
5724 p--;
5725 #if DEBUG
5726 if (p < start) {
5727 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5729 #endif
5732 esc = esclen(start, p);
5733 if (!(esc % 2)) {
5734 break;
5737 p -= esc + 1;
5738 } while (1);
5740 begoff = p - start;
5742 removerecordregions(begoff);
5744 flag = p[1];
5746 expdest = p;
5748 if (quotes)
5749 rmescapes(p + 2);
5751 len = cvtnum(ash_arith(p + 2));
5753 if (flag != '"')
5754 recordregion(begoff, begoff + len, 0);
5756 #endif
5758 /* argstr needs it */
5759 static char *evalvar(char *p, int flag, struct strlist *var_str_list);
5762 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5763 * characters to allow for further processing. Otherwise treat
5764 * $@ like $* since no splitting will be performed.
5766 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5767 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5768 * for correct expansion of "B=$A" word.
5770 static void
5771 argstr(char *p, int flag, struct strlist *var_str_list)
5773 static const char spclchars[] ALIGN1 = {
5774 '=',
5775 ':',
5776 CTLQUOTEMARK,
5777 CTLENDVAR,
5778 CTLESC,
5779 CTLVAR,
5780 CTLBACKQ,
5781 CTLBACKQ | CTLQUOTE,
5782 #if ENABLE_SH_MATH_SUPPORT
5783 CTLENDARI,
5784 #endif
5787 const char *reject = spclchars;
5788 int c;
5789 int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
5790 int breakall = flag & EXP_WORD;
5791 int inquotes;
5792 size_t length;
5793 int startloc;
5795 if (!(flag & EXP_VARTILDE)) {
5796 reject += 2;
5797 } else if (flag & EXP_VARTILDE2) {
5798 reject++;
5800 inquotes = 0;
5801 length = 0;
5802 if (flag & EXP_TILDE) {
5803 char *q;
5805 flag &= ~EXP_TILDE;
5806 tilde:
5807 q = p;
5808 if (*q == CTLESC && (flag & EXP_QWORD))
5809 q++;
5810 if (*q == '~')
5811 p = exptilde(p, q, flag);
5813 start:
5814 startloc = expdest - (char *)stackblock();
5815 for (;;) {
5816 length += strcspn(p + length, reject);
5817 c = p[length];
5818 if (c && (!(c & 0x80)
5819 #if ENABLE_SH_MATH_SUPPORT
5820 || c == CTLENDARI
5821 #endif
5822 )) {
5823 /* c == '=' || c == ':' || c == CTLENDARI */
5824 length++;
5826 if (length > 0) {
5827 int newloc;
5828 expdest = stack_nputstr(p, length, expdest);
5829 newloc = expdest - (char *)stackblock();
5830 if (breakall && !inquotes && newloc > startloc) {
5831 recordregion(startloc, newloc, 0);
5833 startloc = newloc;
5835 p += length + 1;
5836 length = 0;
5838 switch (c) {
5839 case '\0':
5840 goto breakloop;
5841 case '=':
5842 if (flag & EXP_VARTILDE2) {
5843 p--;
5844 continue;
5846 flag |= EXP_VARTILDE2;
5847 reject++;
5848 /* fall through */
5849 case ':':
5851 * sort of a hack - expand tildes in variable
5852 * assignments (after the first '=' and after ':'s).
5854 if (*--p == '~') {
5855 goto tilde;
5857 continue;
5860 switch (c) {
5861 case CTLENDVAR: /* ??? */
5862 goto breakloop;
5863 case CTLQUOTEMARK:
5864 /* "$@" syntax adherence hack */
5865 if (
5866 !inquotes &&
5867 !memcmp(p, dolatstr, 4) &&
5868 (p[4] == CTLQUOTEMARK || (
5869 p[4] == CTLENDVAR &&
5870 p[5] == CTLQUOTEMARK
5873 p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;
5874 goto start;
5876 inquotes = !inquotes;
5877 addquote:
5878 if (quotes) {
5879 p--;
5880 length++;
5881 startloc++;
5883 break;
5884 case CTLESC:
5885 startloc++;
5886 length++;
5887 goto addquote;
5888 case CTLVAR:
5889 p = evalvar(p, flag, var_str_list);
5890 goto start;
5891 case CTLBACKQ:
5892 c = 0;
5893 case CTLBACKQ|CTLQUOTE:
5894 expbackq(argbackq->n, c, quotes);
5895 argbackq = argbackq->next;
5896 goto start;
5897 #if ENABLE_SH_MATH_SUPPORT
5898 case CTLENDARI:
5899 p--;
5900 expari(quotes);
5901 goto start;
5902 #endif
5905 breakloop:
5909 static char *
5910 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int quotes,
5911 int zero)
5913 // This commented out code was added by James Simmons <jsimmons@infradead.org>
5914 // as part of a larger change when he added support for ${var/a/b}.
5915 // However, it broke # and % operators:
5917 //var=ababcdcd
5918 // ok bad
5919 //echo ${var#ab} abcdcd abcdcd
5920 //echo ${var##ab} abcdcd abcdcd
5921 //echo ${var#a*b} abcdcd ababcdcd (!)
5922 //echo ${var##a*b} cdcd cdcd
5923 //echo ${var#?} babcdcd ababcdcd (!)
5924 //echo ${var##?} babcdcd babcdcd
5925 //echo ${var#*} ababcdcd babcdcd (!)
5926 //echo ${var##*}
5927 //echo ${var%cd} ababcd ababcd
5928 //echo ${var%%cd} ababcd abab (!)
5929 //echo ${var%c*d} ababcd ababcd
5930 //echo ${var%%c*d} abab ababcdcd (!)
5931 //echo ${var%?} ababcdc ababcdc
5932 //echo ${var%%?} ababcdc ababcdcd (!)
5933 //echo ${var%*} ababcdcd ababcdcd
5934 //echo ${var%%*}
5936 // Commenting it back out helped. Remove it completely if it really
5937 // is not needed.
5939 char *loc, *loc2; //, *full;
5940 char c;
5942 loc = startp;
5943 loc2 = rmesc;
5944 do {
5945 int match; // = strlen(str);
5946 const char *s = loc2;
5948 c = *loc2;
5949 if (zero) {
5950 *loc2 = '\0';
5951 s = rmesc;
5953 match = pmatch(str, s); // this line was deleted
5955 // // chop off end if its '*'
5956 // full = strrchr(str, '*');
5957 // if (full && full != str)
5958 // match--;
5960 // // If str starts with '*' replace with s.
5961 // if ((*str == '*') && strlen(s) >= match) {
5962 // full = xstrdup(s);
5963 // strncpy(full+strlen(s)-match+1, str+1, match-1);
5964 // } else
5965 // full = xstrndup(str, match);
5966 // match = strncmp(s, full, strlen(full));
5967 // free(full);
5969 *loc2 = c;
5970 if (match) // if (!match)
5971 return loc;
5972 if (quotes && *loc == CTLESC)
5973 loc++;
5974 loc++;
5975 loc2++;
5976 } while (c);
5977 return 0;
5980 static char *
5981 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5982 int zero)
5984 int esc = 0;
5985 char *loc;
5986 char *loc2;
5988 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5989 int match;
5990 char c = *loc2;
5991 const char *s = loc2;
5992 if (zero) {
5993 *loc2 = '\0';
5994 s = rmesc;
5996 match = pmatch(str, s);
5997 *loc2 = c;
5998 if (match)
5999 return loc;
6000 loc--;
6001 if (quotes) {
6002 if (--esc < 0) {
6003 esc = esclen(startp, loc);
6005 if (esc % 2) {
6006 esc--;
6007 loc--;
6011 return 0;
6014 static void varunset(const char *, const char *, const char *, int) NORETURN;
6015 static void
6016 varunset(const char *end, const char *var, const char *umsg, int varflags)
6018 const char *msg;
6019 const char *tail;
6021 tail = nullstr;
6022 msg = "parameter not set";
6023 if (umsg) {
6024 if (*end == CTLENDVAR) {
6025 if (varflags & VSNUL)
6026 tail = " or null";
6027 } else {
6028 msg = umsg;
6031 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
6034 #if ENABLE_ASH_BASH_COMPAT
6035 static char *
6036 parse_sub_pattern(char *arg, int inquotes)
6038 char *idx, *repl = NULL;
6039 unsigned char c;
6041 idx = arg;
6042 while (1) {
6043 c = *arg;
6044 if (!c)
6045 break;
6046 if (c == '/') {
6047 /* Only the first '/' seen is our separator */
6048 if (!repl) {
6049 repl = idx + 1;
6050 c = '\0';
6053 *idx++ = c;
6054 if (!inquotes && c == '\\' && arg[1] == '\\')
6055 arg++; /* skip both \\, not just first one */
6056 arg++;
6058 *idx = c; /* NUL */
6060 return repl;
6062 #endif /* ENABLE_ASH_BASH_COMPAT */
6064 static const char *
6065 subevalvar(char *p, char *str, int strloc, int subtype,
6066 int startloc, int varflags, int quotes, struct strlist *var_str_list)
6068 struct nodelist *saveargbackq = argbackq;
6069 char *startp;
6070 char *loc;
6071 char *rmesc, *rmescend;
6072 USE_ASH_BASH_COMPAT(char *repl = NULL;)
6073 USE_ASH_BASH_COMPAT(char null = '\0';)
6074 USE_ASH_BASH_COMPAT(int pos, len, orig_len;)
6075 int saveherefd = herefd;
6076 int amount, workloc, resetloc;
6077 int zero;
6078 char *(*scan)(char*, char*, char*, char*, int, int);
6080 herefd = -1;
6081 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
6082 var_str_list);
6083 STPUTC('\0', expdest);
6084 herefd = saveherefd;
6085 argbackq = saveargbackq;
6086 startp = (char *)stackblock() + startloc;
6088 switch (subtype) {
6089 case VSASSIGN:
6090 setvar(str, startp, 0);
6091 amount = startp - expdest;
6092 STADJUST(amount, expdest);
6093 return startp;
6095 #if ENABLE_ASH_BASH_COMPAT
6096 case VSSUBSTR:
6097 loc = str = stackblock() + strloc;
6098 // TODO: number() instead? It does error checking...
6099 pos = atoi(loc);
6100 len = str - startp - 1;
6102 /* *loc != '\0', guaranteed by parser */
6103 if (quotes) {
6104 char *ptr;
6106 /* We must adjust the length by the number of escapes we find. */
6107 for (ptr = startp; ptr < (str - 1); ptr++) {
6108 if (*ptr == CTLESC) {
6109 len--;
6110 ptr++;
6114 orig_len = len;
6116 if (*loc++ == ':') {
6117 // TODO: number() instead? It does error checking...
6118 len = atoi(loc);
6119 } else {
6120 len = orig_len;
6121 while (*loc && *loc != ':')
6122 loc++;
6123 if (*loc++ == ':')
6124 // TODO: number() instead? It does error checking...
6125 len = atoi(loc);
6127 if (pos >= orig_len) {
6128 pos = 0;
6129 len = 0;
6131 if (len > (orig_len - pos))
6132 len = orig_len - pos;
6134 for (str = startp; pos; str++, pos--) {
6135 if (quotes && *str == CTLESC)
6136 str++;
6138 for (loc = startp; len; len--) {
6139 if (quotes && *str == CTLESC)
6140 *loc++ = *str++;
6141 *loc++ = *str++;
6143 *loc = '\0';
6144 amount = loc - expdest;
6145 STADJUST(amount, expdest);
6146 return loc;
6147 #endif
6149 case VSQUESTION:
6150 varunset(p, str, startp, varflags);
6151 /* NOTREACHED */
6153 resetloc = expdest - (char *)stackblock();
6155 /* We'll comeback here if we grow the stack while handling
6156 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6157 * stack will need rebasing, and we'll need to remove our work
6158 * areas each time
6160 USE_ASH_BASH_COMPAT(restart:)
6162 amount = expdest - ((char *)stackblock() + resetloc);
6163 STADJUST(-amount, expdest);
6164 startp = (char *)stackblock() + startloc;
6166 rmesc = startp;
6167 rmescend = (char *)stackblock() + strloc;
6168 if (quotes) {
6169 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6170 if (rmesc != startp) {
6171 rmescend = expdest;
6172 startp = (char *)stackblock() + startloc;
6175 rmescend--;
6176 str = (char *)stackblock() + strloc;
6177 preglob(str, varflags & VSQUOTE, 0);
6178 workloc = expdest - (char *)stackblock();
6180 #if ENABLE_ASH_BASH_COMPAT
6181 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6182 char *idx, *end, *restart_detect;
6184 if (!repl) {
6185 repl = parse_sub_pattern(str, varflags & VSQUOTE);
6186 if (!repl)
6187 repl = &null;
6190 /* If there's no pattern to match, return the expansion unmolested */
6191 if (*str == '\0')
6192 return 0;
6194 len = 0;
6195 idx = startp;
6196 end = str - 1;
6197 while (idx < end) {
6198 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6199 if (!loc) {
6200 /* No match, advance */
6201 restart_detect = stackblock();
6202 STPUTC(*idx, expdest);
6203 if (quotes && *idx == CTLESC) {
6204 idx++;
6205 len++;
6206 STPUTC(*idx, expdest);
6208 if (stackblock() != restart_detect)
6209 goto restart;
6210 idx++;
6211 len++;
6212 rmesc++;
6213 continue;
6216 if (subtype == VSREPLACEALL) {
6217 while (idx < loc) {
6218 if (quotes && *idx == CTLESC)
6219 idx++;
6220 idx++;
6221 rmesc++;
6223 } else {
6224 idx = loc;
6227 for (loc = repl; *loc; loc++) {
6228 restart_detect = stackblock();
6229 STPUTC(*loc, expdest);
6230 if (stackblock() != restart_detect)
6231 goto restart;
6232 len++;
6235 if (subtype == VSREPLACE) {
6236 while (*idx) {
6237 restart_detect = stackblock();
6238 STPUTC(*idx, expdest);
6239 if (stackblock() != restart_detect)
6240 goto restart;
6241 len++;
6242 idx++;
6244 break;
6248 /* We've put the replaced text into a buffer at workloc, now
6249 * move it to the right place and adjust the stack.
6251 startp = stackblock() + startloc;
6252 STPUTC('\0', expdest);
6253 memmove(startp, stackblock() + workloc, len);
6254 startp[len++] = '\0';
6255 amount = expdest - ((char *)stackblock() + startloc + len - 1);
6256 STADJUST(-amount, expdest);
6257 return startp;
6259 #endif /* ENABLE_ASH_BASH_COMPAT */
6261 subtype -= VSTRIMRIGHT;
6262 #if DEBUG
6263 if (subtype < 0 || subtype > 7)
6264 abort();
6265 #endif
6266 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
6267 zero = subtype >> 1;
6268 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6269 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6271 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6272 if (loc) {
6273 if (zero) {
6274 memmove(startp, loc, str - loc);
6275 loc = startp + (str - loc) - 1;
6277 *loc = '\0';
6278 amount = loc - expdest;
6279 STADJUST(amount, expdest);
6281 return loc;
6285 * Add the value of a specialized variable to the stack string.
6287 static ssize_t
6288 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6290 int num;
6291 const char *p;
6292 int i;
6293 int sep = 0;
6294 int sepq = 0;
6295 ssize_t len = 0;
6296 char **ap;
6297 int syntax;
6298 int quoted = varflags & VSQUOTE;
6299 int subtype = varflags & VSTYPE;
6300 int quotes = flags & (EXP_FULL | EXP_CASE);
6302 if (quoted && (flags & EXP_FULL))
6303 sep = 1 << CHAR_BIT;
6305 syntax = quoted ? DQSYNTAX : BASESYNTAX;
6306 switch (*name) {
6307 case '$':
6308 num = rootpid;
6309 goto numvar;
6310 case '?':
6311 num = exitstatus;
6312 goto numvar;
6313 case '#':
6314 num = shellparam.nparam;
6315 goto numvar;
6316 case '!':
6317 num = backgndpid;
6318 if (num == 0)
6319 return -1;
6320 numvar:
6321 len = cvtnum(num);
6322 break;
6323 case '-':
6324 expdest = makestrspace(NOPTS, expdest);
6325 for (i = NOPTS - 1; i >= 0; i--) {
6326 if (optlist[i]) {
6327 USTPUTC(optletters(i), expdest);
6328 len++;
6331 break;
6332 case '@':
6333 if (sep)
6334 goto param;
6335 /* fall through */
6336 case '*':
6337 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' ';
6338 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
6339 sepq = 1;
6340 param:
6341 ap = shellparam.p;
6342 if (!ap)
6343 return -1;
6344 while ((p = *ap++)) {
6345 size_t partlen;
6347 partlen = strlen(p);
6348 len += partlen;
6350 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6351 memtodest(p, partlen, syntax, quotes);
6353 if (*ap && sep) {
6354 char *q;
6356 len++;
6357 if (subtype == VSPLUS || subtype == VSLENGTH) {
6358 continue;
6360 q = expdest;
6361 if (sepq)
6362 STPUTC(CTLESC, q);
6363 STPUTC(sep, q);
6364 expdest = q;
6367 return len;
6368 case '0':
6369 case '1':
6370 case '2':
6371 case '3':
6372 case '4':
6373 case '5':
6374 case '6':
6375 case '7':
6376 case '8':
6377 case '9':
6378 // TODO: number() instead? It does error checking...
6379 num = atoi(name);
6380 if (num < 0 || num > shellparam.nparam)
6381 return -1;
6382 p = num ? shellparam.p[num - 1] : arg0;
6383 goto value;
6384 default:
6385 /* NB: name has form "VAR=..." */
6387 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6388 * which should be considered before we check variables. */
6389 if (var_str_list) {
6390 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6391 p = NULL;
6392 do {
6393 char *str, *eq;
6394 str = var_str_list->text;
6395 eq = strchr(str, '=');
6396 if (!eq) /* stop at first non-assignment */
6397 break;
6398 eq++;
6399 if (name_len == (unsigned)(eq - str)
6400 && strncmp(str, name, name_len) == 0) {
6401 p = eq;
6402 /* goto value; - WRONG! */
6403 /* think "A=1 A=2 B=$A" */
6405 var_str_list = var_str_list->next;
6406 } while (var_str_list);
6407 if (p)
6408 goto value;
6410 p = lookupvar(name);
6411 value:
6412 if (!p)
6413 return -1;
6415 len = strlen(p);
6416 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6417 memtodest(p, len, syntax, quotes);
6418 return len;
6421 if (subtype == VSPLUS || subtype == VSLENGTH)
6422 STADJUST(-len, expdest);
6423 return len;
6427 * Expand a variable, and return a pointer to the next character in the
6428 * input string.
6430 static char *
6431 evalvar(char *p, int flag, struct strlist *var_str_list)
6433 char varflags;
6434 char subtype;
6435 char quoted;
6436 char easy;
6437 char *var;
6438 int patloc;
6439 int startloc;
6440 ssize_t varlen;
6442 varflags = *p++;
6443 subtype = varflags & VSTYPE;
6444 quoted = varflags & VSQUOTE;
6445 var = p;
6446 easy = (!quoted || (*var == '@' && shellparam.nparam));
6447 startloc = expdest - (char *)stackblock();
6448 p = strchr(p, '=') + 1;
6450 again:
6451 varlen = varvalue(var, varflags, flag, var_str_list);
6452 if (varflags & VSNUL)
6453 varlen--;
6455 if (subtype == VSPLUS) {
6456 varlen = -1 - varlen;
6457 goto vsplus;
6460 if (subtype == VSMINUS) {
6461 vsplus:
6462 if (varlen < 0) {
6463 argstr(
6464 p, flag | EXP_TILDE |
6465 (quoted ? EXP_QWORD : EXP_WORD),
6466 var_str_list
6468 goto end;
6470 if (easy)
6471 goto record;
6472 goto end;
6475 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6476 if (varlen < 0) {
6477 if (subevalvar(p, var, /* strloc: */ 0,
6478 subtype, startloc, varflags,
6479 /* quotes: */ 0,
6480 var_str_list)
6482 varflags &= ~VSNUL;
6484 * Remove any recorded regions beyond
6485 * start of variable
6487 removerecordregions(startloc);
6488 goto again;
6490 goto end;
6492 if (easy)
6493 goto record;
6494 goto end;
6497 if (varlen < 0 && uflag)
6498 varunset(p, var, 0, 0);
6500 if (subtype == VSLENGTH) {
6501 cvtnum(varlen > 0 ? varlen : 0);
6502 goto record;
6505 if (subtype == VSNORMAL) {
6506 if (easy)
6507 goto record;
6508 goto end;
6511 #if DEBUG
6512 switch (subtype) {
6513 case VSTRIMLEFT:
6514 case VSTRIMLEFTMAX:
6515 case VSTRIMRIGHT:
6516 case VSTRIMRIGHTMAX:
6517 #if ENABLE_ASH_BASH_COMPAT
6518 case VSSUBSTR:
6519 case VSREPLACE:
6520 case VSREPLACEALL:
6521 #endif
6522 break;
6523 default:
6524 abort();
6526 #endif
6528 if (varlen >= 0) {
6530 * Terminate the string and start recording the pattern
6531 * right after it
6533 STPUTC('\0', expdest);
6534 patloc = expdest - (char *)stackblock();
6535 if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6536 startloc, varflags,
6537 /* quotes: */ flag & (EXP_FULL | EXP_CASE),
6538 var_str_list)
6540 int amount = expdest - (
6541 (char *)stackblock() + patloc - 1
6543 STADJUST(-amount, expdest);
6545 /* Remove any recorded regions beyond start of variable */
6546 removerecordregions(startloc);
6547 record:
6548 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6551 end:
6552 if (subtype != VSNORMAL) { /* skip to end of alternative */
6553 int nesting = 1;
6554 for (;;) {
6555 char c = *p++;
6556 if (c == CTLESC)
6557 p++;
6558 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6559 if (varlen >= 0)
6560 argbackq = argbackq->next;
6561 } else if (c == CTLVAR) {
6562 if ((*p++ & VSTYPE) != VSNORMAL)
6563 nesting++;
6564 } else if (c == CTLENDVAR) {
6565 if (--nesting == 0)
6566 break;
6570 return p;
6574 * Break the argument string into pieces based upon IFS and add the
6575 * strings to the argument list. The regions of the string to be
6576 * searched for IFS characters have been stored by recordregion.
6578 static void
6579 ifsbreakup(char *string, struct arglist *arglist)
6581 struct ifsregion *ifsp;
6582 struct strlist *sp;
6583 char *start;
6584 char *p;
6585 char *q;
6586 const char *ifs, *realifs;
6587 int ifsspc;
6588 int nulonly;
6590 start = string;
6591 if (ifslastp != NULL) {
6592 ifsspc = 0;
6593 nulonly = 0;
6594 realifs = ifsset() ? ifsval() : defifs;
6595 ifsp = &ifsfirst;
6596 do {
6597 p = string + ifsp->begoff;
6598 nulonly = ifsp->nulonly;
6599 ifs = nulonly ? nullstr : realifs;
6600 ifsspc = 0;
6601 while (p < string + ifsp->endoff) {
6602 q = p;
6603 if (*p == CTLESC)
6604 p++;
6605 if (!strchr(ifs, *p)) {
6606 p++;
6607 continue;
6609 if (!nulonly)
6610 ifsspc = (strchr(defifs, *p) != NULL);
6611 /* Ignore IFS whitespace at start */
6612 if (q == start && ifsspc) {
6613 p++;
6614 start = p;
6615 continue;
6617 *q = '\0';
6618 sp = stzalloc(sizeof(*sp));
6619 sp->text = start;
6620 *arglist->lastp = sp;
6621 arglist->lastp = &sp->next;
6622 p++;
6623 if (!nulonly) {
6624 for (;;) {
6625 if (p >= string + ifsp->endoff) {
6626 break;
6628 q = p;
6629 if (*p == CTLESC)
6630 p++;
6631 if (strchr(ifs, *p) == NULL) {
6632 p = q;
6633 break;
6635 if (strchr(defifs, *p) == NULL) {
6636 if (ifsspc) {
6637 p++;
6638 ifsspc = 0;
6639 } else {
6640 p = q;
6641 break;
6643 } else
6644 p++;
6647 start = p;
6648 } /* while */
6649 ifsp = ifsp->next;
6650 } while (ifsp != NULL);
6651 if (nulonly)
6652 goto add;
6655 if (!*start)
6656 return;
6658 add:
6659 sp = stzalloc(sizeof(*sp));
6660 sp->text = start;
6661 *arglist->lastp = sp;
6662 arglist->lastp = &sp->next;
6665 static void
6666 ifsfree(void)
6668 struct ifsregion *p;
6670 INT_OFF;
6671 p = ifsfirst.next;
6672 do {
6673 struct ifsregion *ifsp;
6674 ifsp = p->next;
6675 free(p);
6676 p = ifsp;
6677 } while (p);
6678 ifslastp = NULL;
6679 ifsfirst.next = NULL;
6680 INT_ON;
6684 * Add a file name to the list.
6686 static void
6687 addfname(const char *name)
6689 struct strlist *sp;
6691 sp = stzalloc(sizeof(*sp));
6692 sp->text = ststrdup(name);
6693 *exparg.lastp = sp;
6694 exparg.lastp = &sp->next;
6697 static char *expdir;
6700 * Do metacharacter (i.e. *, ?, [...]) expansion.
6702 static void
6703 expmeta(char *enddir, char *name)
6705 char *p;
6706 const char *cp;
6707 char *start;
6708 char *endname;
6709 int metaflag;
6710 struct stat statb;
6711 DIR *dirp;
6712 struct dirent *dp;
6713 int atend;
6714 int matchdot;
6716 metaflag = 0;
6717 start = name;
6718 for (p = name; *p; p++) {
6719 if (*p == '*' || *p == '?')
6720 metaflag = 1;
6721 else if (*p == '[') {
6722 char *q = p + 1;
6723 if (*q == '!')
6724 q++;
6725 for (;;) {
6726 if (*q == '\\')
6727 q++;
6728 if (*q == '/' || *q == '\0')
6729 break;
6730 if (*++q == ']') {
6731 metaflag = 1;
6732 break;
6735 } else if (*p == '\\')
6736 p++;
6737 else if (*p == '/') {
6738 if (metaflag)
6739 goto out;
6740 start = p + 1;
6743 out:
6744 if (metaflag == 0) { /* we've reached the end of the file name */
6745 if (enddir != expdir)
6746 metaflag++;
6747 p = name;
6748 do {
6749 if (*p == '\\')
6750 p++;
6751 *enddir++ = *p;
6752 } while (*p++);
6753 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
6754 addfname(expdir);
6755 return;
6757 endname = p;
6758 if (name < start) {
6759 p = name;
6760 do {
6761 if (*p == '\\')
6762 p++;
6763 *enddir++ = *p++;
6764 } while (p < start);
6766 if (enddir == expdir) {
6767 cp = ".";
6768 } else if (enddir == expdir + 1 && *expdir == '/') {
6769 cp = "/";
6770 } else {
6771 cp = expdir;
6772 enddir[-1] = '\0';
6774 dirp = opendir(cp);
6775 if (dirp == NULL)
6776 return;
6777 if (enddir != expdir)
6778 enddir[-1] = '/';
6779 if (*endname == 0) {
6780 atend = 1;
6781 } else {
6782 atend = 0;
6783 *endname++ = '\0';
6785 matchdot = 0;
6786 p = start;
6787 if (*p == '\\')
6788 p++;
6789 if (*p == '.')
6790 matchdot++;
6791 while (!intpending && (dp = readdir(dirp)) != NULL) {
6792 if (dp->d_name[0] == '.' && !matchdot)
6793 continue;
6794 if (pmatch(start, dp->d_name)) {
6795 if (atend) {
6796 strcpy(enddir, dp->d_name);
6797 addfname(expdir);
6798 } else {
6799 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
6800 continue;
6801 p[-1] = '/';
6802 expmeta(p, endname);
6806 closedir(dirp);
6807 if (!atend)
6808 endname[-1] = '/';
6811 static struct strlist *
6812 msort(struct strlist *list, int len)
6814 struct strlist *p, *q = NULL;
6815 struct strlist **lpp;
6816 int half;
6817 int n;
6819 if (len <= 1)
6820 return list;
6821 half = len >> 1;
6822 p = list;
6823 for (n = half; --n >= 0;) {
6824 q = p;
6825 p = p->next;
6827 q->next = NULL; /* terminate first half of list */
6828 q = msort(list, half); /* sort first half of list */
6829 p = msort(p, len - half); /* sort second half */
6830 lpp = &list;
6831 for (;;) {
6832 #if ENABLE_LOCALE_SUPPORT
6833 if (strcoll(p->text, q->text) < 0)
6834 #else
6835 if (strcmp(p->text, q->text) < 0)
6836 #endif
6838 *lpp = p;
6839 lpp = &p->next;
6840 p = *lpp;
6841 if (p == NULL) {
6842 *lpp = q;
6843 break;
6845 } else {
6846 *lpp = q;
6847 lpp = &q->next;
6848 q = *lpp;
6849 if (q == NULL) {
6850 *lpp = p;
6851 break;
6855 return list;
6859 * Sort the results of file name expansion. It calculates the number of
6860 * strings to sort and then calls msort (short for merge sort) to do the
6861 * work.
6863 static struct strlist *
6864 expsort(struct strlist *str)
6866 int len;
6867 struct strlist *sp;
6869 len = 0;
6870 for (sp = str; sp; sp = sp->next)
6871 len++;
6872 return msort(str, len);
6875 static void
6876 expandmeta(struct strlist *str /*, int flag*/)
6878 static const char metachars[] ALIGN1 = {
6879 '*', '?', '[', 0
6881 /* TODO - EXP_REDIR */
6883 while (str) {
6884 struct strlist **savelastp;
6885 struct strlist *sp;
6886 char *p;
6888 if (fflag)
6889 goto nometa;
6890 if (!strpbrk(str->text, metachars))
6891 goto nometa;
6892 savelastp = exparg.lastp;
6894 INT_OFF;
6895 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
6897 int i = strlen(str->text);
6898 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
6901 expmeta(expdir, p);
6902 free(expdir);
6903 if (p != str->text)
6904 free(p);
6905 INT_ON;
6906 if (exparg.lastp == savelastp) {
6908 * no matches
6910 nometa:
6911 *exparg.lastp = str;
6912 rmescapes(str->text);
6913 exparg.lastp = &str->next;
6914 } else {
6915 *exparg.lastp = NULL;
6916 *savelastp = sp = expsort(*savelastp);
6917 while (sp->next != NULL)
6918 sp = sp->next;
6919 exparg.lastp = &sp->next;
6921 str = str->next;
6926 * Perform variable substitution and command substitution on an argument,
6927 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6928 * perform splitting and file name expansion. When arglist is NULL, perform
6929 * here document expansion.
6931 static void
6932 expandarg(union node *arg, struct arglist *arglist, int flag)
6934 struct strlist *sp;
6935 char *p;
6937 argbackq = arg->narg.backquote;
6938 STARTSTACKSTR(expdest);
6939 ifsfirst.next = NULL;
6940 ifslastp = NULL;
6941 argstr(arg->narg.text, flag,
6942 /* var_str_list: */ arglist ? arglist->list : NULL);
6943 p = _STPUTC('\0', expdest);
6944 expdest = p - 1;
6945 if (arglist == NULL) {
6946 return; /* here document expanded */
6948 p = grabstackstr(p);
6949 exparg.lastp = &exparg.list;
6951 * TODO - EXP_REDIR
6953 if (flag & EXP_FULL) {
6954 ifsbreakup(p, &exparg);
6955 *exparg.lastp = NULL;
6956 exparg.lastp = &exparg.list;
6957 expandmeta(exparg.list /*, flag*/);
6958 } else {
6959 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
6960 rmescapes(p);
6961 sp = stzalloc(sizeof(*sp));
6962 sp->text = p;
6963 *exparg.lastp = sp;
6964 exparg.lastp = &sp->next;
6966 if (ifsfirst.next)
6967 ifsfree();
6968 *exparg.lastp = NULL;
6969 if (exparg.list) {
6970 *arglist->lastp = exparg.list;
6971 arglist->lastp = exparg.lastp;
6976 * Expand shell variables and backquotes inside a here document.
6978 static void
6979 expandhere(union node *arg, int fd)
6981 herefd = fd;
6982 expandarg(arg, (struct arglist *)NULL, 0);
6983 full_write(fd, stackblock(), expdest - (char *)stackblock());
6987 * Returns true if the pattern matches the string.
6989 static int
6990 patmatch(char *pattern, const char *string)
6992 return pmatch(preglob(pattern, 0, 0), string);
6996 * See if a pattern matches in a case statement.
6998 static int
6999 casematch(union node *pattern, char *val)
7001 struct stackmark smark;
7002 int result;
7004 setstackmark(&smark);
7005 argbackq = pattern->narg.backquote;
7006 STARTSTACKSTR(expdest);
7007 ifslastp = NULL;
7008 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7009 /* var_str_list: */ NULL);
7010 STACKSTRNUL(expdest);
7011 result = patmatch(stackblock(), val);
7012 popstackmark(&smark);
7013 return result;
7017 /* ============ find_command */
7019 struct builtincmd {
7020 const char *name;
7021 int (*builtin)(int, char **);
7022 /* unsigned flags; */
7024 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
7025 /* "regular" builtins always take precedence over commands,
7026 * regardless of PATH=....%builtin... position */
7027 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
7028 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
7030 struct cmdentry {
7031 smallint cmdtype; /* CMDxxx */
7032 union param {
7033 int index;
7034 /* index >= 0 for commands without path (slashes) */
7035 /* (TODO: what exactly does the value mean? PATH position?) */
7036 /* index == -1 for commands with slashes */
7037 /* index == (-2 - applet_no) for NOFORK applets */
7038 const struct builtincmd *cmd;
7039 struct funcnode *func;
7040 } u;
7042 /* values of cmdtype */
7043 #define CMDUNKNOWN -1 /* no entry in table for command */
7044 #define CMDNORMAL 0 /* command is an executable program */
7045 #define CMDFUNCTION 1 /* command is a shell function */
7046 #define CMDBUILTIN 2 /* command is a shell builtin */
7048 /* action to find_command() */
7049 #define DO_ERR 0x01 /* prints errors */
7050 #define DO_ABS 0x02 /* checks absolute paths */
7051 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7052 #define DO_ALTPATH 0x08 /* using alternate path */
7053 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7055 static void find_command(char *, struct cmdentry *, int, const char *);
7058 /* ============ Hashing commands */
7061 * When commands are first encountered, they are entered in a hash table.
7062 * This ensures that a full path search will not have to be done for them
7063 * on each invocation.
7065 * We should investigate converting to a linear search, even though that
7066 * would make the command name "hash" a misnomer.
7069 struct tblentry {
7070 struct tblentry *next; /* next entry in hash chain */
7071 union param param; /* definition of builtin function */
7072 smallint cmdtype; /* CMDxxx */
7073 char rehash; /* if set, cd done since entry created */
7074 char cmdname[1]; /* name of command */
7077 static struct tblentry **cmdtable;
7078 #define INIT_G_cmdtable() do { \
7079 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7080 } while (0)
7082 static int builtinloc = -1; /* index in path of %builtin, or -1 */
7085 static void
7086 tryexec(USE_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
7088 int repeated = 0;
7090 #if ENABLE_FEATURE_SH_STANDALONE
7091 if (applet_no >= 0) {
7092 if (APPLET_IS_NOEXEC(applet_no)) {
7093 while (*envp)
7094 putenv(*envp++);
7095 run_applet_no_and_exit(applet_no, argv);
7097 /* re-exec ourselves with the new arguments */
7098 execve(bb_busybox_exec_path, argv, envp);
7099 /* If they called chroot or otherwise made the binary no longer
7100 * executable, fall through */
7102 #endif
7104 repeat:
7105 #ifdef SYSV
7106 do {
7107 execve(cmd, argv, envp);
7108 } while (errno == EINTR);
7109 #else
7110 execve(cmd, argv, envp);
7111 #endif
7112 if (repeated) {
7113 free(argv);
7114 return;
7116 if (errno == ENOEXEC) {
7117 char **ap;
7118 char **new;
7120 for (ap = argv; *ap; ap++)
7121 continue;
7122 ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0]));
7123 ap[1] = cmd;
7124 ap[0] = cmd = (char *)DEFAULT_SHELL;
7125 ap += 2;
7126 argv++;
7127 while ((*ap++ = *argv++) != NULL)
7128 continue;
7129 argv = new;
7130 repeated++;
7131 goto repeat;
7136 * Exec a program. Never returns. If you change this routine, you may
7137 * have to change the find_command routine as well.
7139 static void shellexec(char **, const char *, int) NORETURN;
7140 static void
7141 shellexec(char **argv, const char *path, int idx)
7143 char *cmdname;
7144 int e;
7145 char **envp;
7146 int exerrno;
7147 #if ENABLE_FEATURE_SH_STANDALONE
7148 int applet_no = -1;
7149 #endif
7151 clearredir(/*drop:*/ 1);
7152 envp = listvars(VEXPORT, VUNSET, 0);
7153 if (strchr(argv[0], '/') != NULL
7154 #if ENABLE_FEATURE_SH_STANDALONE
7155 || (applet_no = find_applet_by_name(argv[0])) >= 0
7156 #endif
7158 tryexec(USE_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7159 e = errno;
7160 } else {
7161 e = ENOENT;
7162 while ((cmdname = padvance(&path, argv[0])) != NULL) {
7163 if (--idx < 0 && pathopt == NULL) {
7164 tryexec(USE_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7165 if (errno != ENOENT && errno != ENOTDIR)
7166 e = errno;
7168 stunalloc(cmdname);
7172 /* Map to POSIX errors */
7173 switch (e) {
7174 case EACCES:
7175 exerrno = 126;
7176 break;
7177 case ENOENT:
7178 exerrno = 127;
7179 break;
7180 default:
7181 exerrno = 2;
7182 break;
7184 exitstatus = exerrno;
7185 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
7186 argv[0], e, suppressint));
7187 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7188 /* NOTREACHED */
7191 static void
7192 printentry(struct tblentry *cmdp)
7194 int idx;
7195 const char *path;
7196 char *name;
7198 idx = cmdp->param.index;
7199 path = pathval();
7200 do {
7201 name = padvance(&path, cmdp->cmdname);
7202 stunalloc(name);
7203 } while (--idx >= 0);
7204 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7208 * Clear out command entries. The argument specifies the first entry in
7209 * PATH which has changed.
7211 static void
7212 clearcmdentry(int firstchange)
7214 struct tblentry **tblp;
7215 struct tblentry **pp;
7216 struct tblentry *cmdp;
7218 INT_OFF;
7219 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7220 pp = tblp;
7221 while ((cmdp = *pp) != NULL) {
7222 if ((cmdp->cmdtype == CMDNORMAL &&
7223 cmdp->param.index >= firstchange)
7224 || (cmdp->cmdtype == CMDBUILTIN &&
7225 builtinloc >= firstchange)
7227 *pp = cmdp->next;
7228 free(cmdp);
7229 } else {
7230 pp = &cmdp->next;
7234 INT_ON;
7238 * Locate a command in the command hash table. If "add" is nonzero,
7239 * add the command to the table if it is not already present. The
7240 * variable "lastcmdentry" is set to point to the address of the link
7241 * pointing to the entry, so that delete_cmd_entry can delete the
7242 * entry.
7244 * Interrupts must be off if called with add != 0.
7246 static struct tblentry **lastcmdentry;
7248 static struct tblentry *
7249 cmdlookup(const char *name, int add)
7251 unsigned int hashval;
7252 const char *p;
7253 struct tblentry *cmdp;
7254 struct tblentry **pp;
7256 p = name;
7257 hashval = (unsigned char)*p << 4;
7258 while (*p)
7259 hashval += (unsigned char)*p++;
7260 hashval &= 0x7FFF;
7261 pp = &cmdtable[hashval % CMDTABLESIZE];
7262 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7263 if (strcmp(cmdp->cmdname, name) == 0)
7264 break;
7265 pp = &cmdp->next;
7267 if (add && cmdp == NULL) {
7268 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7269 + strlen(name)
7270 /* + 1 - already done because
7271 * tblentry::cmdname is char[1] */);
7272 /*cmdp->next = NULL; - ckzalloc did it */
7273 cmdp->cmdtype = CMDUNKNOWN;
7274 strcpy(cmdp->cmdname, name);
7276 lastcmdentry = pp;
7277 return cmdp;
7281 * Delete the command entry returned on the last lookup.
7283 static void
7284 delete_cmd_entry(void)
7286 struct tblentry *cmdp;
7288 INT_OFF;
7289 cmdp = *lastcmdentry;
7290 *lastcmdentry = cmdp->next;
7291 if (cmdp->cmdtype == CMDFUNCTION)
7292 freefunc(cmdp->param.func);
7293 free(cmdp);
7294 INT_ON;
7298 * Add a new command entry, replacing any existing command entry for
7299 * the same name - except special builtins.
7301 static void
7302 addcmdentry(char *name, struct cmdentry *entry)
7304 struct tblentry *cmdp;
7306 cmdp = cmdlookup(name, 1);
7307 if (cmdp->cmdtype == CMDFUNCTION) {
7308 freefunc(cmdp->param.func);
7310 cmdp->cmdtype = entry->cmdtype;
7311 cmdp->param = entry->u;
7312 cmdp->rehash = 0;
7315 static int
7316 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7318 struct tblentry **pp;
7319 struct tblentry *cmdp;
7320 int c;
7321 struct cmdentry entry;
7322 char *name;
7324 if (nextopt("r") != '\0') {
7325 clearcmdentry(0);
7326 return 0;
7329 if (*argptr == NULL) {
7330 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7331 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7332 if (cmdp->cmdtype == CMDNORMAL)
7333 printentry(cmdp);
7336 return 0;
7339 c = 0;
7340 while ((name = *argptr) != NULL) {
7341 cmdp = cmdlookup(name, 0);
7342 if (cmdp != NULL
7343 && (cmdp->cmdtype == CMDNORMAL
7344 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7346 delete_cmd_entry();
7348 find_command(name, &entry, DO_ERR, pathval());
7349 if (entry.cmdtype == CMDUNKNOWN)
7350 c = 1;
7351 argptr++;
7353 return c;
7357 * Called when a cd is done. Marks all commands so the next time they
7358 * are executed they will be rehashed.
7360 static void
7361 hashcd(void)
7363 struct tblentry **pp;
7364 struct tblentry *cmdp;
7366 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7367 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7368 if (cmdp->cmdtype == CMDNORMAL
7369 || (cmdp->cmdtype == CMDBUILTIN
7370 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7371 && builtinloc > 0)
7373 cmdp->rehash = 1;
7380 * Fix command hash table when PATH changed.
7381 * Called before PATH is changed. The argument is the new value of PATH;
7382 * pathval() still returns the old value at this point.
7383 * Called with interrupts off.
7385 static void
7386 changepath(const char *new)
7388 const char *old;
7389 int firstchange;
7390 int idx;
7391 int idx_bltin;
7393 old = pathval();
7394 firstchange = 9999; /* assume no change */
7395 idx = 0;
7396 idx_bltin = -1;
7397 for (;;) {
7398 if (*old != *new) {
7399 firstchange = idx;
7400 if ((*old == '\0' && *new == ':')
7401 || (*old == ':' && *new == '\0'))
7402 firstchange++;
7403 old = new; /* ignore subsequent differences */
7405 if (*new == '\0')
7406 break;
7407 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7408 idx_bltin = idx;
7409 if (*new == ':')
7410 idx++;
7411 new++, old++;
7413 if (builtinloc < 0 && idx_bltin >= 0)
7414 builtinloc = idx_bltin; /* zap builtins */
7415 if (builtinloc >= 0 && idx_bltin < 0)
7416 firstchange = 0;
7417 clearcmdentry(firstchange);
7418 builtinloc = idx_bltin;
7421 #define TEOF 0
7422 #define TNL 1
7423 #define TREDIR 2
7424 #define TWORD 3
7425 #define TSEMI 4
7426 #define TBACKGND 5
7427 #define TAND 6
7428 #define TOR 7
7429 #define TPIPE 8
7430 #define TLP 9
7431 #define TRP 10
7432 #define TENDCASE 11
7433 #define TENDBQUOTE 12
7434 #define TNOT 13
7435 #define TCASE 14
7436 #define TDO 15
7437 #define TDONE 16
7438 #define TELIF 17
7439 #define TELSE 18
7440 #define TESAC 19
7441 #define TFI 20
7442 #define TFOR 21
7443 #define TIF 22
7444 #define TIN 23
7445 #define TTHEN 24
7446 #define TUNTIL 25
7447 #define TWHILE 26
7448 #define TBEGIN 27
7449 #define TEND 28
7450 typedef smallint token_id_t;
7452 /* first char is indicating which tokens mark the end of a list */
7453 static const char *const tokname_array[] = {
7454 "\1end of file",
7455 "\0newline",
7456 "\0redirection",
7457 "\0word",
7458 "\0;",
7459 "\0&",
7460 "\0&&",
7461 "\0||",
7462 "\0|",
7463 "\0(",
7464 "\1)",
7465 "\1;;",
7466 "\1`",
7467 #define KWDOFFSET 13
7468 /* the following are keywords */
7469 "\0!",
7470 "\0case",
7471 "\1do",
7472 "\1done",
7473 "\1elif",
7474 "\1else",
7475 "\1esac",
7476 "\1fi",
7477 "\0for",
7478 "\0if",
7479 "\0in",
7480 "\1then",
7481 "\0until",
7482 "\0while",
7483 "\0{",
7484 "\1}",
7487 static const char *
7488 tokname(int tok)
7490 static char buf[16];
7492 //try this:
7493 //if (tok < TSEMI) return tokname_array[tok] + 1;
7494 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
7495 //return buf;
7497 if (tok >= TSEMI)
7498 buf[0] = '"';
7499 sprintf(buf + (tok >= TSEMI), "%s%c",
7500 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
7501 return buf;
7504 /* Wrapper around strcmp for qsort/bsearch/... */
7505 static int
7506 pstrcmp(const void *a, const void *b)
7508 return strcmp((char*) a, (*(char**) b) + 1);
7511 static const char *const *
7512 findkwd(const char *s)
7514 return bsearch(s, tokname_array + KWDOFFSET,
7515 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7516 sizeof(tokname_array[0]), pstrcmp);
7520 * Locate and print what a word is...
7522 static int
7523 describe_command(char *command, int describe_command_verbose)
7525 struct cmdentry entry;
7526 struct tblentry *cmdp;
7527 #if ENABLE_ASH_ALIAS
7528 const struct alias *ap;
7529 #endif
7530 const char *path = pathval();
7532 if (describe_command_verbose) {
7533 out1str(command);
7536 /* First look at the keywords */
7537 if (findkwd(command)) {
7538 out1str(describe_command_verbose ? " is a shell keyword" : command);
7539 goto out;
7542 #if ENABLE_ASH_ALIAS
7543 /* Then look at the aliases */
7544 ap = lookupalias(command, 0);
7545 if (ap != NULL) {
7546 if (!describe_command_verbose) {
7547 out1str("alias ");
7548 printalias(ap);
7549 return 0;
7551 out1fmt(" is an alias for %s", ap->val);
7552 goto out;
7554 #endif
7555 /* Then check if it is a tracked alias */
7556 cmdp = cmdlookup(command, 0);
7557 if (cmdp != NULL) {
7558 entry.cmdtype = cmdp->cmdtype;
7559 entry.u = cmdp->param;
7560 } else {
7561 /* Finally use brute force */
7562 find_command(command, &entry, DO_ABS, path);
7565 switch (entry.cmdtype) {
7566 case CMDNORMAL: {
7567 int j = entry.u.index;
7568 char *p;
7569 if (j < 0) {
7570 p = command;
7571 } else {
7572 do {
7573 p = padvance(&path, command);
7574 stunalloc(p);
7575 } while (--j >= 0);
7577 if (describe_command_verbose) {
7578 out1fmt(" is%s %s",
7579 (cmdp ? " a tracked alias for" : nullstr), p
7581 } else {
7582 out1str(p);
7584 break;
7587 case CMDFUNCTION:
7588 if (describe_command_verbose) {
7589 out1str(" is a shell function");
7590 } else {
7591 out1str(command);
7593 break;
7595 case CMDBUILTIN:
7596 if (describe_command_verbose) {
7597 out1fmt(" is a %sshell builtin",
7598 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7599 "special " : nullstr
7601 } else {
7602 out1str(command);
7604 break;
7606 default:
7607 if (describe_command_verbose) {
7608 out1str(": not found\n");
7610 return 127;
7612 out:
7613 outstr("\n", stdout);
7614 return 0;
7617 static int
7618 typecmd(int argc UNUSED_PARAM, char **argv)
7620 int i = 1;
7621 int err = 0;
7622 int verbose = 1;
7624 /* type -p ... ? (we don't bother checking for 'p') */
7625 if (argv[1] && argv[1][0] == '-') {
7626 i++;
7627 verbose = 0;
7629 while (argv[i]) {
7630 err |= describe_command(argv[i++], verbose);
7632 return err;
7635 #if ENABLE_ASH_CMDCMD
7636 static int
7637 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7639 int c;
7640 enum {
7641 VERIFY_BRIEF = 1,
7642 VERIFY_VERBOSE = 2,
7643 } verify = 0;
7645 while ((c = nextopt("pvV")) != '\0')
7646 if (c == 'V')
7647 verify |= VERIFY_VERBOSE;
7648 else if (c == 'v')
7649 verify |= VERIFY_BRIEF;
7650 #if DEBUG
7651 else if (c != 'p')
7652 abort();
7653 #endif
7654 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7655 if (verify && (*argptr != NULL)) {
7656 return describe_command(*argptr, verify - VERIFY_BRIEF);
7659 return 0;
7661 #endif
7664 /* ============ eval.c */
7666 static int funcblocksize; /* size of structures in function */
7667 static int funcstringsize; /* size of strings in node */
7668 static void *funcblock; /* block to allocate function from */
7669 static char *funcstring; /* block to allocate strings from */
7671 /* flags in argument to evaltree */
7672 #define EV_EXIT 01 /* exit after evaluating tree */
7673 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7674 #define EV_BACKCMD 04 /* command executing within back quotes */
7676 static const short nodesize[N_NUMBER] = {
7677 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
7678 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
7679 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
7680 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
7681 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
7682 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
7683 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
7684 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
7685 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
7686 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
7687 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
7688 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
7689 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
7690 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
7691 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
7692 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
7693 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
7694 #if ENABLE_ASH_BASH_COMPAT
7695 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
7696 #endif
7697 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
7698 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
7699 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
7700 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
7701 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
7702 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
7703 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
7704 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
7705 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
7708 static void calcsize(union node *n);
7710 static void
7711 sizenodelist(struct nodelist *lp)
7713 while (lp) {
7714 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
7715 calcsize(lp->n);
7716 lp = lp->next;
7720 static void
7721 calcsize(union node *n)
7723 if (n == NULL)
7724 return;
7725 funcblocksize += nodesize[n->type];
7726 switch (n->type) {
7727 case NCMD:
7728 calcsize(n->ncmd.redirect);
7729 calcsize(n->ncmd.args);
7730 calcsize(n->ncmd.assign);
7731 break;
7732 case NPIPE:
7733 sizenodelist(n->npipe.cmdlist);
7734 break;
7735 case NREDIR:
7736 case NBACKGND:
7737 case NSUBSHELL:
7738 calcsize(n->nredir.redirect);
7739 calcsize(n->nredir.n);
7740 break;
7741 case NAND:
7742 case NOR:
7743 case NSEMI:
7744 case NWHILE:
7745 case NUNTIL:
7746 calcsize(n->nbinary.ch2);
7747 calcsize(n->nbinary.ch1);
7748 break;
7749 case NIF:
7750 calcsize(n->nif.elsepart);
7751 calcsize(n->nif.ifpart);
7752 calcsize(n->nif.test);
7753 break;
7754 case NFOR:
7755 funcstringsize += strlen(n->nfor.var) + 1;
7756 calcsize(n->nfor.body);
7757 calcsize(n->nfor.args);
7758 break;
7759 case NCASE:
7760 calcsize(n->ncase.cases);
7761 calcsize(n->ncase.expr);
7762 break;
7763 case NCLIST:
7764 calcsize(n->nclist.body);
7765 calcsize(n->nclist.pattern);
7766 calcsize(n->nclist.next);
7767 break;
7768 case NDEFUN:
7769 case NARG:
7770 sizenodelist(n->narg.backquote);
7771 funcstringsize += strlen(n->narg.text) + 1;
7772 calcsize(n->narg.next);
7773 break;
7774 case NTO:
7775 #if ENABLE_ASH_BASH_COMPAT
7776 case NTO2:
7777 #endif
7778 case NCLOBBER:
7779 case NFROM:
7780 case NFROMTO:
7781 case NAPPEND:
7782 calcsize(n->nfile.fname);
7783 calcsize(n->nfile.next);
7784 break;
7785 case NTOFD:
7786 case NFROMFD:
7787 calcsize(n->ndup.vname);
7788 calcsize(n->ndup.next);
7789 break;
7790 case NHERE:
7791 case NXHERE:
7792 calcsize(n->nhere.doc);
7793 calcsize(n->nhere.next);
7794 break;
7795 case NNOT:
7796 calcsize(n->nnot.com);
7797 break;
7801 static char *
7802 nodeckstrdup(char *s)
7804 char *rtn = funcstring;
7806 strcpy(funcstring, s);
7807 funcstring += strlen(s) + 1;
7808 return rtn;
7811 static union node *copynode(union node *);
7813 static struct nodelist *
7814 copynodelist(struct nodelist *lp)
7816 struct nodelist *start;
7817 struct nodelist **lpp;
7819 lpp = &start;
7820 while (lp) {
7821 *lpp = funcblock;
7822 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
7823 (*lpp)->n = copynode(lp->n);
7824 lp = lp->next;
7825 lpp = &(*lpp)->next;
7827 *lpp = NULL;
7828 return start;
7831 static union node *
7832 copynode(union node *n)
7834 union node *new;
7836 if (n == NULL)
7837 return NULL;
7838 new = funcblock;
7839 funcblock = (char *) funcblock + nodesize[n->type];
7841 switch (n->type) {
7842 case NCMD:
7843 new->ncmd.redirect = copynode(n->ncmd.redirect);
7844 new->ncmd.args = copynode(n->ncmd.args);
7845 new->ncmd.assign = copynode(n->ncmd.assign);
7846 break;
7847 case NPIPE:
7848 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
7849 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
7850 break;
7851 case NREDIR:
7852 case NBACKGND:
7853 case NSUBSHELL:
7854 new->nredir.redirect = copynode(n->nredir.redirect);
7855 new->nredir.n = copynode(n->nredir.n);
7856 break;
7857 case NAND:
7858 case NOR:
7859 case NSEMI:
7860 case NWHILE:
7861 case NUNTIL:
7862 new->nbinary.ch2 = copynode(n->nbinary.ch2);
7863 new->nbinary.ch1 = copynode(n->nbinary.ch1);
7864 break;
7865 case NIF:
7866 new->nif.elsepart = copynode(n->nif.elsepart);
7867 new->nif.ifpart = copynode(n->nif.ifpart);
7868 new->nif.test = copynode(n->nif.test);
7869 break;
7870 case NFOR:
7871 new->nfor.var = nodeckstrdup(n->nfor.var);
7872 new->nfor.body = copynode(n->nfor.body);
7873 new->nfor.args = copynode(n->nfor.args);
7874 break;
7875 case NCASE:
7876 new->ncase.cases = copynode(n->ncase.cases);
7877 new->ncase.expr = copynode(n->ncase.expr);
7878 break;
7879 case NCLIST:
7880 new->nclist.body = copynode(n->nclist.body);
7881 new->nclist.pattern = copynode(n->nclist.pattern);
7882 new->nclist.next = copynode(n->nclist.next);
7883 break;
7884 case NDEFUN:
7885 case NARG:
7886 new->narg.backquote = copynodelist(n->narg.backquote);
7887 new->narg.text = nodeckstrdup(n->narg.text);
7888 new->narg.next = copynode(n->narg.next);
7889 break;
7890 case NTO:
7891 #if ENABLE_ASH_BASH_COMPAT
7892 case NTO2:
7893 #endif
7894 case NCLOBBER:
7895 case NFROM:
7896 case NFROMTO:
7897 case NAPPEND:
7898 new->nfile.fname = copynode(n->nfile.fname);
7899 new->nfile.fd = n->nfile.fd;
7900 new->nfile.next = copynode(n->nfile.next);
7901 break;
7902 case NTOFD:
7903 case NFROMFD:
7904 new->ndup.vname = copynode(n->ndup.vname);
7905 new->ndup.dupfd = n->ndup.dupfd;
7906 new->ndup.fd = n->ndup.fd;
7907 new->ndup.next = copynode(n->ndup.next);
7908 break;
7909 case NHERE:
7910 case NXHERE:
7911 new->nhere.doc = copynode(n->nhere.doc);
7912 new->nhere.fd = n->nhere.fd;
7913 new->nhere.next = copynode(n->nhere.next);
7914 break;
7915 case NNOT:
7916 new->nnot.com = copynode(n->nnot.com);
7917 break;
7919 new->type = n->type;
7920 return new;
7924 * Make a copy of a parse tree.
7926 static struct funcnode *
7927 copyfunc(union node *n)
7929 struct funcnode *f;
7930 size_t blocksize;
7932 funcblocksize = offsetof(struct funcnode, n);
7933 funcstringsize = 0;
7934 calcsize(n);
7935 blocksize = funcblocksize;
7936 f = ckmalloc(blocksize + funcstringsize);
7937 funcblock = (char *) f + offsetof(struct funcnode, n);
7938 funcstring = (char *) f + blocksize;
7939 copynode(n);
7940 f->count = 0;
7941 return f;
7945 * Define a shell function.
7947 static void
7948 defun(char *name, union node *func)
7950 struct cmdentry entry;
7952 INT_OFF;
7953 entry.cmdtype = CMDFUNCTION;
7954 entry.u.func = copyfunc(func);
7955 addcmdentry(name, &entry);
7956 INT_ON;
7959 /* Reasons for skipping commands (see comment on breakcmd routine) */
7960 #define SKIPBREAK (1 << 0)
7961 #define SKIPCONT (1 << 1)
7962 #define SKIPFUNC (1 << 2)
7963 #define SKIPFILE (1 << 3)
7964 #define SKIPEVAL (1 << 4)
7965 static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
7966 static int skipcount; /* number of levels to skip */
7967 static int funcnest; /* depth of function calls */
7968 static int loopnest; /* current loop nesting level */
7970 /* Forward decl way out to parsing code - dotrap needs it */
7971 static int evalstring(char *s, int mask);
7973 /* Called to execute a trap.
7974 * Single callsite - at the end of evaltree().
7975 * If we return non-zero, exaltree raises EXEXIT exception.
7977 * Perhaps we should avoid entering new trap handlers
7978 * while we are executing a trap handler. [is it a TODO?]
7980 static int
7981 dotrap(void)
7983 uint8_t *g;
7984 int sig;
7985 uint8_t savestatus;
7987 savestatus = exitstatus;
7988 pendingsig = 0;
7989 xbarrier();
7991 TRACE(("dotrap entered\n"));
7992 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
7993 int want_exexit;
7994 char *t;
7996 if (*g == 0)
7997 continue;
7998 t = trap[sig];
7999 /* non-trapped SIGINT is handled separately by raise_interrupt,
8000 * don't upset it by resetting gotsig[SIGINT-1] */
8001 if (sig == SIGINT && !t)
8002 continue;
8004 TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
8005 *g = 0;
8006 if (!t)
8007 continue;
8008 want_exexit = evalstring(t, SKIPEVAL);
8009 exitstatus = savestatus;
8010 if (want_exexit) {
8011 TRACE(("dotrap returns %d\n", want_exexit));
8012 return want_exexit;
8016 TRACE(("dotrap returns 0\n"));
8017 return 0;
8020 /* forward declarations - evaluation is fairly recursive business... */
8021 static void evalloop(union node *, int);
8022 static void evalfor(union node *, int);
8023 static void evalcase(union node *, int);
8024 static void evalsubshell(union node *, int);
8025 static void expredir(union node *);
8026 static void evalpipe(union node *, int);
8027 static void evalcommand(union node *, int);
8028 static int evalbltin(const struct builtincmd *, int, char **);
8029 static void prehash(union node *);
8032 * Evaluate a parse tree. The value is left in the global variable
8033 * exitstatus.
8035 static void
8036 evaltree(union node *n, int flags)
8038 struct jmploc *volatile savehandler = exception_handler;
8039 struct jmploc jmploc;
8040 int checkexit = 0;
8041 void (*evalfn)(union node *, int);
8042 int status;
8043 int int_level;
8045 SAVE_INT(int_level);
8047 if (n == NULL) {
8048 TRACE(("evaltree(NULL) called\n"));
8049 goto out1;
8051 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
8053 exception_handler = &jmploc;
8055 int err = setjmp(jmploc.loc);
8056 if (err) {
8057 /* if it was a signal, check for trap handlers */
8058 if (exception_type == EXSIG) {
8059 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8060 exception_type, err));
8061 goto out;
8063 /* continue on the way out */
8064 TRACE(("exception %d in evaltree, propagating err=%d\n",
8065 exception_type, err));
8066 exception_handler = savehandler;
8067 longjmp(exception_handler->loc, err);
8071 switch (n->type) {
8072 default:
8073 #if DEBUG
8074 out1fmt("Node type = %d\n", n->type);
8075 fflush(stdout);
8076 break;
8077 #endif
8078 case NNOT:
8079 evaltree(n->nnot.com, EV_TESTED);
8080 status = !exitstatus;
8081 goto setstatus;
8082 case NREDIR:
8083 expredir(n->nredir.redirect);
8084 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8085 if (!status) {
8086 evaltree(n->nredir.n, flags & EV_TESTED);
8087 status = exitstatus;
8089 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
8090 goto setstatus;
8091 case NCMD:
8092 evalfn = evalcommand;
8093 checkexit:
8094 if (eflag && !(flags & EV_TESTED))
8095 checkexit = ~0;
8096 goto calleval;
8097 case NFOR:
8098 evalfn = evalfor;
8099 goto calleval;
8100 case NWHILE:
8101 case NUNTIL:
8102 evalfn = evalloop;
8103 goto calleval;
8104 case NSUBSHELL:
8105 case NBACKGND:
8106 evalfn = evalsubshell;
8107 goto calleval;
8108 case NPIPE:
8109 evalfn = evalpipe;
8110 goto checkexit;
8111 case NCASE:
8112 evalfn = evalcase;
8113 goto calleval;
8114 case NAND:
8115 case NOR:
8116 case NSEMI: {
8118 #if NAND + 1 != NOR
8119 #error NAND + 1 != NOR
8120 #endif
8121 #if NOR + 1 != NSEMI
8122 #error NOR + 1 != NSEMI
8123 #endif
8124 unsigned is_or = n->type - NAND;
8125 evaltree(
8126 n->nbinary.ch1,
8127 (flags | ((is_or >> 1) - 1)) & EV_TESTED
8129 if (!exitstatus == is_or)
8130 break;
8131 if (!evalskip) {
8132 n = n->nbinary.ch2;
8133 evaln:
8134 evalfn = evaltree;
8135 calleval:
8136 evalfn(n, flags);
8137 break;
8139 break;
8141 case NIF:
8142 evaltree(n->nif.test, EV_TESTED);
8143 if (evalskip)
8144 break;
8145 if (exitstatus == 0) {
8146 n = n->nif.ifpart;
8147 goto evaln;
8149 if (n->nif.elsepart) {
8150 n = n->nif.elsepart;
8151 goto evaln;
8153 goto success;
8154 case NDEFUN:
8155 defun(n->narg.text, n->narg.next);
8156 success:
8157 status = 0;
8158 setstatus:
8159 exitstatus = status;
8160 break;
8163 out:
8164 exception_handler = savehandler;
8165 out1:
8166 if (checkexit & exitstatus)
8167 evalskip |= SKIPEVAL;
8168 else if (pendingsig && dotrap())
8169 goto exexit;
8171 if (flags & EV_EXIT) {
8172 exexit:
8173 raise_exception(EXEXIT);
8176 RESTORE_INT(int_level);
8177 TRACE(("leaving evaltree (no interrupts)\n"));
8180 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8181 static
8182 #endif
8183 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8185 static void
8186 evalloop(union node *n, int flags)
8188 int status;
8190 loopnest++;
8191 status = 0;
8192 flags &= EV_TESTED;
8193 for (;;) {
8194 int i;
8196 evaltree(n->nbinary.ch1, EV_TESTED);
8197 if (evalskip) {
8198 skipping:
8199 if (evalskip == SKIPCONT && --skipcount <= 0) {
8200 evalskip = 0;
8201 continue;
8203 if (evalskip == SKIPBREAK && --skipcount <= 0)
8204 evalskip = 0;
8205 break;
8207 i = exitstatus;
8208 if (n->type != NWHILE)
8209 i = !i;
8210 if (i != 0)
8211 break;
8212 evaltree(n->nbinary.ch2, flags);
8213 status = exitstatus;
8214 if (evalskip)
8215 goto skipping;
8217 loopnest--;
8218 exitstatus = status;
8221 static void
8222 evalfor(union node *n, int flags)
8224 struct arglist arglist;
8225 union node *argp;
8226 struct strlist *sp;
8227 struct stackmark smark;
8229 setstackmark(&smark);
8230 arglist.list = NULL;
8231 arglist.lastp = &arglist.list;
8232 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8233 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
8234 /* XXX */
8235 if (evalskip)
8236 goto out;
8238 *arglist.lastp = NULL;
8240 exitstatus = 0;
8241 loopnest++;
8242 flags &= EV_TESTED;
8243 for (sp = arglist.list; sp; sp = sp->next) {
8244 setvar(n->nfor.var, sp->text, 0);
8245 evaltree(n->nfor.body, flags);
8246 if (evalskip) {
8247 if (evalskip == SKIPCONT && --skipcount <= 0) {
8248 evalskip = 0;
8249 continue;
8251 if (evalskip == SKIPBREAK && --skipcount <= 0)
8252 evalskip = 0;
8253 break;
8256 loopnest--;
8257 out:
8258 popstackmark(&smark);
8261 static void
8262 evalcase(union node *n, int flags)
8264 union node *cp;
8265 union node *patp;
8266 struct arglist arglist;
8267 struct stackmark smark;
8269 setstackmark(&smark);
8270 arglist.list = NULL;
8271 arglist.lastp = &arglist.list;
8272 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8273 exitstatus = 0;
8274 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8275 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8276 if (casematch(patp, arglist.list->text)) {
8277 if (evalskip == 0) {
8278 evaltree(cp->nclist.body, flags);
8280 goto out;
8284 out:
8285 popstackmark(&smark);
8289 * Kick off a subshell to evaluate a tree.
8291 static void
8292 evalsubshell(union node *n, int flags)
8294 struct job *jp;
8295 int backgnd = (n->type == NBACKGND);
8296 int status;
8298 expredir(n->nredir.redirect);
8299 if (!backgnd && flags & EV_EXIT && !trap[0])
8300 goto nofork;
8301 INT_OFF;
8302 jp = makejob(/*n,*/ 1);
8303 if (forkshell(jp, n, backgnd) == 0) {
8304 INT_ON;
8305 flags |= EV_EXIT;
8306 if (backgnd)
8307 flags &=~ EV_TESTED;
8308 nofork:
8309 redirect(n->nredir.redirect, 0);
8310 evaltreenr(n->nredir.n, flags);
8311 /* never returns */
8313 status = 0;
8314 if (!backgnd)
8315 status = waitforjob(jp);
8316 exitstatus = status;
8317 INT_ON;
8321 * Compute the names of the files in a redirection list.
8323 static void fixredir(union node *, const char *, int);
8324 static void
8325 expredir(union node *n)
8327 union node *redir;
8329 for (redir = n; redir; redir = redir->nfile.next) {
8330 struct arglist fn;
8332 fn.list = NULL;
8333 fn.lastp = &fn.list;
8334 switch (redir->type) {
8335 case NFROMTO:
8336 case NFROM:
8337 case NTO:
8338 #if ENABLE_ASH_BASH_COMPAT
8339 case NTO2:
8340 #endif
8341 case NCLOBBER:
8342 case NAPPEND:
8343 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8344 #if ENABLE_ASH_BASH_COMPAT
8345 store_expfname:
8346 #endif
8347 redir->nfile.expfname = fn.list->text;
8348 break;
8349 case NFROMFD:
8350 case NTOFD: /* >& */
8351 if (redir->ndup.vname) {
8352 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8353 if (fn.list == NULL)
8354 ash_msg_and_raise_error("redir error");
8355 #if ENABLE_ASH_BASH_COMPAT
8356 //FIXME: we used expandarg with different args!
8357 if (!isdigit_str9(fn.list->text)) {
8358 /* >&file, not >&fd */
8359 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8360 ash_msg_and_raise_error("redir error");
8361 redir->type = NTO2;
8362 goto store_expfname;
8364 #endif
8365 fixredir(redir, fn.list->text, 1);
8367 break;
8373 * Evaluate a pipeline. All the processes in the pipeline are children
8374 * of the process creating the pipeline. (This differs from some versions
8375 * of the shell, which make the last process in a pipeline the parent
8376 * of all the rest.)
8378 static void
8379 evalpipe(union node *n, int flags)
8381 struct job *jp;
8382 struct nodelist *lp;
8383 int pipelen;
8384 int prevfd;
8385 int pip[2];
8387 TRACE(("evalpipe(0x%lx) called\n", (long)n));
8388 pipelen = 0;
8389 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8390 pipelen++;
8391 flags |= EV_EXIT;
8392 INT_OFF;
8393 jp = makejob(/*n,*/ pipelen);
8394 prevfd = -1;
8395 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8396 prehash(lp->n);
8397 pip[1] = -1;
8398 if (lp->next) {
8399 if (pipe(pip) < 0) {
8400 close(prevfd);
8401 ash_msg_and_raise_error("pipe call failed");
8404 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8405 INT_ON;
8406 if (pip[1] >= 0) {
8407 close(pip[0]);
8409 if (prevfd > 0) {
8410 dup2(prevfd, 0);
8411 close(prevfd);
8413 if (pip[1] > 1) {
8414 dup2(pip[1], 1);
8415 close(pip[1]);
8417 evaltreenr(lp->n, flags);
8418 /* never returns */
8420 if (prevfd >= 0)
8421 close(prevfd);
8422 prevfd = pip[0];
8423 /* Don't want to trigger debugging */
8424 if (pip[1] != -1)
8425 close(pip[1]);
8427 if (n->npipe.pipe_backgnd == 0) {
8428 exitstatus = waitforjob(jp);
8429 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
8431 INT_ON;
8435 * Controls whether the shell is interactive or not.
8437 static void
8438 setinteractive(int on)
8440 static smallint is_interactive;
8442 if (++on == is_interactive)
8443 return;
8444 is_interactive = on;
8445 setsignal(SIGINT);
8446 setsignal(SIGQUIT);
8447 setsignal(SIGTERM);
8448 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8449 if (is_interactive > 1) {
8450 /* Looks like they want an interactive shell */
8451 static smallint did_banner;
8453 if (!did_banner) {
8454 out1fmt(
8455 "\n\n"
8456 "%s built-in shell (ash)\n"
8457 "Enter 'help' for a list of built-in commands."
8458 "\n\n",
8459 bb_banner);
8460 did_banner = 1;
8463 #endif
8466 static void
8467 optschanged(void)
8469 #if DEBUG
8470 opentrace();
8471 #endif
8472 setinteractive(iflag);
8473 setjobctl(mflag);
8474 #if ENABLE_FEATURE_EDITING_VI
8475 if (viflag)
8476 line_input_state->flags |= VI_MODE;
8477 else
8478 line_input_state->flags &= ~VI_MODE;
8479 #else
8480 viflag = 0; /* forcibly keep the option off */
8481 #endif
8484 static struct localvar *localvars;
8487 * Called after a function returns.
8488 * Interrupts must be off.
8490 static void
8491 poplocalvars(void)
8493 struct localvar *lvp;
8494 struct var *vp;
8496 while ((lvp = localvars) != NULL) {
8497 localvars = lvp->next;
8498 vp = lvp->vp;
8499 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
8500 if (vp == NULL) { /* $- saved */
8501 memcpy(optlist, lvp->text, sizeof(optlist));
8502 free((char*)lvp->text);
8503 optschanged();
8504 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8505 unsetvar(vp->text);
8506 } else {
8507 if (vp->func)
8508 (*vp->func)(strchrnul(lvp->text, '=') + 1);
8509 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8510 free((char*)vp->text);
8511 vp->flags = lvp->flags;
8512 vp->text = lvp->text;
8514 free(lvp);
8518 static int
8519 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8521 volatile struct shparam saveparam;
8522 struct localvar *volatile savelocalvars;
8523 struct jmploc *volatile savehandler;
8524 struct jmploc jmploc;
8525 int e;
8527 saveparam = shellparam;
8528 savelocalvars = localvars;
8529 e = setjmp(jmploc.loc);
8530 if (e) {
8531 goto funcdone;
8533 INT_OFF;
8534 savehandler = exception_handler;
8535 exception_handler = &jmploc;
8536 localvars = NULL;
8537 shellparam.malloced = 0;
8538 func->count++;
8539 funcnest++;
8540 INT_ON;
8541 shellparam.nparam = argc - 1;
8542 shellparam.p = argv + 1;
8543 #if ENABLE_ASH_GETOPTS
8544 shellparam.optind = 1;
8545 shellparam.optoff = -1;
8546 #endif
8547 evaltree(&func->n, flags & EV_TESTED);
8548 funcdone:
8549 INT_OFF;
8550 funcnest--;
8551 freefunc(func);
8552 poplocalvars();
8553 localvars = savelocalvars;
8554 freeparam(&shellparam);
8555 shellparam = saveparam;
8556 exception_handler = savehandler;
8557 INT_ON;
8558 evalskip &= ~SKIPFUNC;
8559 return e;
8562 #if ENABLE_ASH_CMDCMD
8563 static char **
8564 parse_command_args(char **argv, const char **path)
8566 char *cp, c;
8568 for (;;) {
8569 cp = *++argv;
8570 if (!cp)
8571 return 0;
8572 if (*cp++ != '-')
8573 break;
8574 c = *cp++;
8575 if (!c)
8576 break;
8577 if (c == '-' && !*cp) {
8578 argv++;
8579 break;
8581 do {
8582 switch (c) {
8583 case 'p':
8584 *path = bb_default_path;
8585 break;
8586 default:
8587 /* run 'typecmd' for other options */
8588 return 0;
8590 c = *cp++;
8591 } while (c);
8593 return argv;
8595 #endif
8598 * Make a variable a local variable. When a variable is made local, it's
8599 * value and flags are saved in a localvar structure. The saved values
8600 * will be restored when the shell function returns. We handle the name
8601 * "-" as a special case.
8603 static void
8604 mklocal(char *name)
8606 struct localvar *lvp;
8607 struct var **vpp;
8608 struct var *vp;
8610 INT_OFF;
8611 lvp = ckzalloc(sizeof(struct localvar));
8612 if (LONE_DASH(name)) {
8613 char *p;
8614 p = ckmalloc(sizeof(optlist));
8615 lvp->text = memcpy(p, optlist, sizeof(optlist));
8616 vp = NULL;
8617 } else {
8618 char *eq;
8620 vpp = hashvar(name);
8621 vp = *findvar(vpp, name);
8622 eq = strchr(name, '=');
8623 if (vp == NULL) {
8624 if (eq)
8625 setvareq(name, VSTRFIXED);
8626 else
8627 setvar(name, NULL, VSTRFIXED);
8628 vp = *vpp; /* the new variable */
8629 lvp->flags = VUNSET;
8630 } else {
8631 lvp->text = vp->text;
8632 lvp->flags = vp->flags;
8633 vp->flags |= VSTRFIXED|VTEXTFIXED;
8634 if (eq)
8635 setvareq(name, 0);
8638 lvp->vp = vp;
8639 lvp->next = localvars;
8640 localvars = lvp;
8641 INT_ON;
8645 * The "local" command.
8647 static int
8648 localcmd(int argc UNUSED_PARAM, char **argv)
8650 char *name;
8652 argv = argptr;
8653 while ((name = *argv++) != NULL) {
8654 mklocal(name);
8656 return 0;
8659 static int
8660 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8662 return 1;
8665 static int
8666 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8668 return 0;
8671 static int
8672 execcmd(int argc UNUSED_PARAM, char **argv)
8674 if (argv[1]) {
8675 iflag = 0; /* exit on error */
8676 mflag = 0;
8677 optschanged();
8678 shellexec(argv + 1, pathval(), 0);
8680 return 0;
8684 * The return command.
8686 static int
8687 returncmd(int argc UNUSED_PARAM, char **argv)
8690 * If called outside a function, do what ksh does;
8691 * skip the rest of the file.
8693 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
8694 return argv[1] ? number(argv[1]) : exitstatus;
8697 /* Forward declarations for builtintab[] */
8698 static int breakcmd(int, char **);
8699 static int dotcmd(int, char **);
8700 static int evalcmd(int, char **);
8701 static int exitcmd(int, char **);
8702 static int exportcmd(int, char **);
8703 #if ENABLE_ASH_GETOPTS
8704 static int getoptscmd(int, char **);
8705 #endif
8706 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8707 static int helpcmd(int, char **);
8708 #endif
8709 #if ENABLE_SH_MATH_SUPPORT
8710 static int letcmd(int, char **);
8711 #endif
8712 static int readcmd(int, char **);
8713 static int setcmd(int, char **);
8714 static int shiftcmd(int, char **);
8715 static int timescmd(int, char **);
8716 static int trapcmd(int, char **);
8717 static int umaskcmd(int, char **);
8718 static int unsetcmd(int, char **);
8719 static int ulimitcmd(int, char **);
8721 #define BUILTIN_NOSPEC "0"
8722 #define BUILTIN_SPECIAL "1"
8723 #define BUILTIN_REGULAR "2"
8724 #define BUILTIN_SPEC_REG "3"
8725 #define BUILTIN_ASSIGN "4"
8726 #define BUILTIN_SPEC_ASSG "5"
8727 #define BUILTIN_REG_ASSG "6"
8728 #define BUILTIN_SPEC_REG_ASSG "7"
8730 /* We do not handle [[ expr ]] bashism bash-compatibly,
8731 * we make it a synonym of [ expr ].
8732 * Basically, word splitting and pathname expansion should NOT be performed
8733 * Examples:
8734 * no word splitting: a="a b"; [[ $a = "a b" ]]; echo $? should print "0"
8735 * no pathname expansion: [[ /bin/m* = "/bin/m*" ]]; echo $? should print "0"
8736 * Additional operators:
8737 * || and && should work as -o and -a
8738 * =~ regexp match
8739 * Apart from the above, [[ expr ]] should work as [ expr ]
8742 #define echocmd echo_main
8743 #define printfcmd printf_main
8744 #define testcmd test_main
8746 /* Keep these in proper order since it is searched via bsearch() */
8747 static const struct builtincmd builtintab[] = {
8748 { BUILTIN_SPEC_REG ".", dotcmd },
8749 { BUILTIN_SPEC_REG ":", truecmd },
8750 #if ENABLE_ASH_BUILTIN_TEST
8751 { BUILTIN_REGULAR "[", testcmd },
8752 #if ENABLE_ASH_BASH_COMPAT
8753 { BUILTIN_REGULAR "[[", testcmd },
8754 #endif
8755 #endif
8756 #if ENABLE_ASH_ALIAS
8757 { BUILTIN_REG_ASSG "alias", aliascmd },
8758 #endif
8759 #if JOBS
8760 { BUILTIN_REGULAR "bg", fg_bgcmd },
8761 #endif
8762 { BUILTIN_SPEC_REG "break", breakcmd },
8763 { BUILTIN_REGULAR "cd", cdcmd },
8764 { BUILTIN_NOSPEC "chdir", cdcmd },
8765 #if ENABLE_ASH_CMDCMD
8766 { BUILTIN_REGULAR "command", commandcmd },
8767 #endif
8768 { BUILTIN_SPEC_REG "continue", breakcmd },
8769 #if ENABLE_ASH_BUILTIN_ECHO
8770 { BUILTIN_REGULAR "echo", echocmd },
8771 #endif
8772 { BUILTIN_SPEC_REG "eval", evalcmd },
8773 { BUILTIN_SPEC_REG "exec", execcmd },
8774 { BUILTIN_SPEC_REG "exit", exitcmd },
8775 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
8776 { BUILTIN_REGULAR "false", falsecmd },
8777 #if JOBS
8778 { BUILTIN_REGULAR "fg", fg_bgcmd },
8779 #endif
8780 #if ENABLE_ASH_GETOPTS
8781 { BUILTIN_REGULAR "getopts", getoptscmd },
8782 #endif
8783 { BUILTIN_NOSPEC "hash", hashcmd },
8784 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8785 { BUILTIN_NOSPEC "help", helpcmd },
8786 #endif
8787 #if JOBS
8788 { BUILTIN_REGULAR "jobs", jobscmd },
8789 { BUILTIN_REGULAR "kill", killcmd },
8790 #endif
8791 #if ENABLE_SH_MATH_SUPPORT
8792 { BUILTIN_NOSPEC "let", letcmd },
8793 #endif
8794 { BUILTIN_ASSIGN "local", localcmd },
8795 #if ENABLE_ASH_BUILTIN_PRINTF
8796 { BUILTIN_REGULAR "printf", printfcmd },
8797 #endif
8798 { BUILTIN_NOSPEC "pwd", pwdcmd },
8799 { BUILTIN_REGULAR "read", readcmd },
8800 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
8801 { BUILTIN_SPEC_REG "return", returncmd },
8802 { BUILTIN_SPEC_REG "set", setcmd },
8803 { BUILTIN_SPEC_REG "shift", shiftcmd },
8804 { BUILTIN_SPEC_REG "source", dotcmd },
8805 #if ENABLE_ASH_BUILTIN_TEST
8806 { BUILTIN_REGULAR "test", testcmd },
8807 #endif
8808 { BUILTIN_SPEC_REG "times", timescmd },
8809 { BUILTIN_SPEC_REG "trap", trapcmd },
8810 { BUILTIN_REGULAR "true", truecmd },
8811 { BUILTIN_NOSPEC "type", typecmd },
8812 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
8813 { BUILTIN_REGULAR "umask", umaskcmd },
8814 #if ENABLE_ASH_ALIAS
8815 { BUILTIN_REGULAR "unalias", unaliascmd },
8816 #endif
8817 { BUILTIN_SPEC_REG "unset", unsetcmd },
8818 { BUILTIN_REGULAR "wait", waitcmd },
8821 /* Should match the above table! */
8822 #define COMMANDCMD (builtintab + \
8823 2 + \
8824 1 * ENABLE_ASH_BUILTIN_TEST + \
8825 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8826 1 * ENABLE_ASH_ALIAS + \
8827 1 * ENABLE_ASH_JOB_CONTROL + \
8829 #define EXECCMD (builtintab + \
8830 2 + \
8831 1 * ENABLE_ASH_BUILTIN_TEST + \
8832 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8833 1 * ENABLE_ASH_ALIAS + \
8834 1 * ENABLE_ASH_JOB_CONTROL + \
8835 3 + \
8836 1 * ENABLE_ASH_CMDCMD + \
8837 1 + \
8838 ENABLE_ASH_BUILTIN_ECHO + \
8842 * Search the table of builtin commands.
8844 static struct builtincmd *
8845 find_builtin(const char *name)
8847 struct builtincmd *bp;
8849 bp = bsearch(
8850 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
8851 pstrcmp
8853 return bp;
8857 * Execute a simple command.
8859 static int
8860 isassignment(const char *p)
8862 const char *q = endofname(p);
8863 if (p == q)
8864 return 0;
8865 return *q == '=';
8867 static int
8868 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8870 /* Preserve exitstatus of a previous possible redirection
8871 * as POSIX mandates */
8872 return back_exitstatus;
8874 static void
8875 evalcommand(union node *cmd, int flags)
8877 static const struct builtincmd null_bltin = {
8878 "\0\0", bltincmd /* why three NULs? */
8880 struct stackmark smark;
8881 union node *argp;
8882 struct arglist arglist;
8883 struct arglist varlist;
8884 char **argv;
8885 int argc;
8886 const struct strlist *sp;
8887 struct cmdentry cmdentry;
8888 struct job *jp;
8889 char *lastarg;
8890 const char *path;
8891 int spclbltin;
8892 int status;
8893 char **nargv;
8894 struct builtincmd *bcmd;
8895 smallint cmd_is_exec;
8896 smallint pseudovarflag = 0;
8898 /* First expand the arguments. */
8899 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
8900 setstackmark(&smark);
8901 back_exitstatus = 0;
8903 cmdentry.cmdtype = CMDBUILTIN;
8904 cmdentry.u.cmd = &null_bltin;
8905 varlist.lastp = &varlist.list;
8906 *varlist.lastp = NULL;
8907 arglist.lastp = &arglist.list;
8908 *arglist.lastp = NULL;
8910 argc = 0;
8911 if (cmd->ncmd.args) {
8912 bcmd = find_builtin(cmd->ncmd.args->narg.text);
8913 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
8916 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
8917 struct strlist **spp;
8919 spp = arglist.lastp;
8920 if (pseudovarflag && isassignment(argp->narg.text))
8921 expandarg(argp, &arglist, EXP_VARTILDE);
8922 else
8923 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8925 for (sp = *spp; sp; sp = sp->next)
8926 argc++;
8929 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
8930 for (sp = arglist.list; sp; sp = sp->next) {
8931 TRACE(("evalcommand arg: %s\n", sp->text));
8932 *nargv++ = sp->text;
8934 *nargv = NULL;
8936 lastarg = NULL;
8937 if (iflag && funcnest == 0 && argc > 0)
8938 lastarg = nargv[-1];
8940 preverrout_fd = 2;
8941 expredir(cmd->ncmd.redirect);
8942 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
8944 path = vpath.text;
8945 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
8946 struct strlist **spp;
8947 char *p;
8949 spp = varlist.lastp;
8950 expandarg(argp, &varlist, EXP_VARTILDE);
8953 * Modify the command lookup path, if a PATH= assignment
8954 * is present
8956 p = (*spp)->text;
8957 if (varequal(p, path))
8958 path = p;
8961 /* Print the command if xflag is set. */
8962 if (xflag) {
8963 int n;
8964 const char *p = " %s";
8966 p++;
8967 fdprintf(preverrout_fd, p, expandstr(ps4val()));
8969 sp = varlist.list;
8970 for (n = 0; n < 2; n++) {
8971 while (sp) {
8972 fdprintf(preverrout_fd, p, sp->text);
8973 sp = sp->next;
8974 if (*p == '%') {
8975 p--;
8978 sp = arglist.list;
8980 safe_write(preverrout_fd, "\n", 1);
8983 cmd_is_exec = 0;
8984 spclbltin = -1;
8986 /* Now locate the command. */
8987 if (argc) {
8988 const char *oldpath;
8989 int cmd_flag = DO_ERR;
8991 path += 5;
8992 oldpath = path;
8993 for (;;) {
8994 find_command(argv[0], &cmdentry, cmd_flag, path);
8995 if (cmdentry.cmdtype == CMDUNKNOWN) {
8996 flush_stderr();
8997 status = 127;
8998 goto bail;
9001 /* implement bltin and command here */
9002 if (cmdentry.cmdtype != CMDBUILTIN)
9003 break;
9004 if (spclbltin < 0)
9005 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9006 if (cmdentry.u.cmd == EXECCMD)
9007 cmd_is_exec = 1;
9008 #if ENABLE_ASH_CMDCMD
9009 if (cmdentry.u.cmd == COMMANDCMD) {
9010 path = oldpath;
9011 nargv = parse_command_args(argv, &path);
9012 if (!nargv)
9013 break;
9014 argc -= nargv - argv;
9015 argv = nargv;
9016 cmd_flag |= DO_NOFUNC;
9017 } else
9018 #endif
9019 break;
9023 if (status) {
9024 /* We have a redirection error. */
9025 if (spclbltin > 0)
9026 raise_exception(EXERROR);
9027 bail:
9028 exitstatus = status;
9029 goto out;
9032 /* Execute the command. */
9033 switch (cmdentry.cmdtype) {
9034 default:
9036 #if ENABLE_FEATURE_SH_NOFORK
9037 /* Hmmm... shouldn't it happen somewhere in forkshell() instead?
9038 * Why "fork off a child process if necessary" doesn't apply to NOFORK? */
9040 /* find_command() encodes applet_no as (-2 - applet_no) */
9041 int applet_no = (- cmdentry.u.index - 2);
9042 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
9043 listsetvar(varlist.list, VEXPORT|VSTACK);
9044 /* run <applet>_main() */
9045 exitstatus = run_nofork_applet(applet_no, argv);
9046 break;
9049 #endif
9050 /* Fork off a child process if necessary. */
9051 if (!(flags & EV_EXIT) || trap[0]) {
9052 INT_OFF;
9053 jp = makejob(/*cmd,*/ 1);
9054 if (forkshell(jp, cmd, FORK_FG) != 0) {
9055 exitstatus = waitforjob(jp);
9056 INT_ON;
9057 TRACE(("forked child exited with %d\n", exitstatus));
9058 break;
9060 FORCE_INT_ON;
9062 listsetvar(varlist.list, VEXPORT|VSTACK);
9063 shellexec(argv, path, cmdentry.u.index);
9064 /* NOTREACHED */
9066 case CMDBUILTIN:
9067 cmdenviron = varlist.list;
9068 if (cmdenviron) {
9069 struct strlist *list = cmdenviron;
9070 int i = VNOSET;
9071 if (spclbltin > 0 || argc == 0) {
9072 i = 0;
9073 if (cmd_is_exec && argc > 1)
9074 i = VEXPORT;
9076 listsetvar(list, i);
9078 /* Tight loop with builtins only:
9079 * "while kill -0 $child; do true; done"
9080 * will never exit even if $child died, unless we do this
9081 * to reap the zombie and make kill detect that it's gone: */
9082 dowait(DOWAIT_NONBLOCK, NULL);
9084 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9085 int exit_status;
9086 int i = exception_type;
9087 if (i == EXEXIT)
9088 goto raise;
9089 exit_status = 2;
9090 if (i == EXINT)
9091 exit_status = 128 + SIGINT;
9092 if (i == EXSIG)
9093 exit_status = 128 + pendingsig;
9094 exitstatus = exit_status;
9095 if (i == EXINT || spclbltin > 0) {
9096 raise:
9097 longjmp(exception_handler->loc, 1);
9099 FORCE_INT_ON;
9101 break;
9103 case CMDFUNCTION:
9104 listsetvar(varlist.list, 0);
9105 /* See above for the rationale */
9106 dowait(DOWAIT_NONBLOCK, NULL);
9107 if (evalfun(cmdentry.u.func, argc, argv, flags))
9108 goto raise;
9109 break;
9112 out:
9113 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
9114 if (lastarg) {
9115 /* dsl: I think this is intended to be used to support
9116 * '_' in 'vi' command mode during line editing...
9117 * However I implemented that within libedit itself.
9119 setvar("_", lastarg, 0);
9121 popstackmark(&smark);
9124 static int
9125 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9127 char *volatile savecmdname;
9128 struct jmploc *volatile savehandler;
9129 struct jmploc jmploc;
9130 int i;
9132 savecmdname = commandname;
9133 i = setjmp(jmploc.loc);
9134 if (i)
9135 goto cmddone;
9136 savehandler = exception_handler;
9137 exception_handler = &jmploc;
9138 commandname = argv[0];
9139 argptr = argv + 1;
9140 optptr = NULL; /* initialize nextopt */
9141 exitstatus = (*cmd->builtin)(argc, argv);
9142 flush_stdout_stderr();
9143 cmddone:
9144 exitstatus |= ferror(stdout);
9145 clearerr(stdout);
9146 commandname = savecmdname;
9147 // exsig = 0;
9148 exception_handler = savehandler;
9150 return i;
9153 static int
9154 goodname(const char *p)
9156 return !*endofname(p);
9161 * Search for a command. This is called before we fork so that the
9162 * location of the command will be available in the parent as well as
9163 * the child. The check for "goodname" is an overly conservative
9164 * check that the name will not be subject to expansion.
9166 static void
9167 prehash(union node *n)
9169 struct cmdentry entry;
9171 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9172 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9176 /* ============ Builtin commands
9178 * Builtin commands whose functions are closely tied to evaluation
9179 * are implemented here.
9183 * Handle break and continue commands. Break, continue, and return are
9184 * all handled by setting the evalskip flag. The evaluation routines
9185 * above all check this flag, and if it is set they start skipping
9186 * commands rather than executing them. The variable skipcount is
9187 * the number of loops to break/continue, or the number of function
9188 * levels to return. (The latter is always 1.) It should probably
9189 * be an error to break out of more loops than exist, but it isn't
9190 * in the standard shell so we don't make it one here.
9192 static int
9193 breakcmd(int argc UNUSED_PARAM, char **argv)
9195 int n = argv[1] ? number(argv[1]) : 1;
9197 if (n <= 0)
9198 ash_msg_and_raise_error(illnum, argv[1]);
9199 if (n > loopnest)
9200 n = loopnest;
9201 if (n > 0) {
9202 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9203 skipcount = n;
9205 return 0;
9209 /* ============ input.c
9211 * This implements the input routines used by the parser.
9214 enum {
9215 INPUT_PUSH_FILE = 1,
9216 INPUT_NOFILE_OK = 2,
9219 static smallint checkkwd;
9220 /* values of checkkwd variable */
9221 #define CHKALIAS 0x1
9222 #define CHKKWD 0x2
9223 #define CHKNL 0x4
9226 * Push a string back onto the input at this current parsefile level.
9227 * We handle aliases this way.
9229 #if !ENABLE_ASH_ALIAS
9230 #define pushstring(s, ap) pushstring(s)
9231 #endif
9232 static void
9233 pushstring(char *s, struct alias *ap)
9235 struct strpush *sp;
9236 int len;
9238 len = strlen(s);
9239 INT_OFF;
9240 if (g_parsefile->strpush) {
9241 sp = ckzalloc(sizeof(*sp));
9242 sp->prev = g_parsefile->strpush;
9243 } else {
9244 sp = &(g_parsefile->basestrpush);
9246 g_parsefile->strpush = sp;
9247 sp->prev_string = g_parsefile->next_to_pgetc;
9248 sp->prev_left_in_line = g_parsefile->left_in_line;
9249 #if ENABLE_ASH_ALIAS
9250 sp->ap = ap;
9251 if (ap) {
9252 ap->flag |= ALIASINUSE;
9253 sp->string = s;
9255 #endif
9256 g_parsefile->next_to_pgetc = s;
9257 g_parsefile->left_in_line = len;
9258 INT_ON;
9261 static void
9262 popstring(void)
9264 struct strpush *sp = g_parsefile->strpush;
9266 INT_OFF;
9267 #if ENABLE_ASH_ALIAS
9268 if (sp->ap) {
9269 if (g_parsefile->next_to_pgetc[-1] == ' '
9270 || g_parsefile->next_to_pgetc[-1] == '\t'
9272 checkkwd |= CHKALIAS;
9274 if (sp->string != sp->ap->val) {
9275 free(sp->string);
9277 sp->ap->flag &= ~ALIASINUSE;
9278 if (sp->ap->flag & ALIASDEAD) {
9279 unalias(sp->ap->name);
9282 #endif
9283 g_parsefile->next_to_pgetc = sp->prev_string;
9284 g_parsefile->left_in_line = sp->prev_left_in_line;
9285 g_parsefile->strpush = sp->prev;
9286 if (sp != &(g_parsefile->basestrpush))
9287 free(sp);
9288 INT_ON;
9291 //FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9292 //it peeks whether it is &>, and then pushes back both chars.
9293 //This function needs to save last *next_to_pgetc to buf[0]
9294 //to make two pungetc() reliable. Currently,
9295 // pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
9296 static int
9297 preadfd(void)
9299 int nr;
9300 char *buf = g_parsefile->buf;
9302 g_parsefile->next_to_pgetc = buf;
9303 #if ENABLE_FEATURE_EDITING
9304 retry:
9305 if (!iflag || g_parsefile->fd != STDIN_FILENO)
9306 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9307 else {
9308 #if ENABLE_FEATURE_TAB_COMPLETION
9309 line_input_state->path_lookup = pathval();
9310 #endif
9311 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
9312 if (nr == 0) {
9313 /* Ctrl+C pressed */
9314 if (trap[SIGINT]) {
9315 buf[0] = '\n';
9316 buf[1] = '\0';
9317 raise(SIGINT);
9318 return 1;
9320 goto retry;
9322 if (nr < 0 && errno == 0) {
9323 /* Ctrl+D pressed */
9324 nr = 0;
9327 #else
9328 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1);
9329 #endif
9331 #if 0
9332 /* nonblock_safe_read() handles this problem */
9333 if (nr < 0) {
9334 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9335 int flags = fcntl(0, F_GETFL);
9336 if (flags >= 0 && (flags & O_NONBLOCK)) {
9337 flags &= ~O_NONBLOCK;
9338 if (fcntl(0, F_SETFL, flags) >= 0) {
9339 out2str("sh: turning off NDELAY mode\n");
9340 goto retry;
9345 #endif
9346 return nr;
9350 * Refill the input buffer and return the next input character:
9352 * 1) If a string was pushed back on the input, pop it;
9353 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9354 * or we are reading from a string so we can't refill the buffer,
9355 * return EOF.
9356 * 3) If the is more stuff in this buffer, use it else call read to fill it.
9357 * 4) Process input up to the next newline, deleting nul characters.
9359 //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9360 #define pgetc_debug(...) ((void)0)
9362 * NB: due to SIT(c) internals (syntax_index_table[] vector),
9363 * pgetc() and related functions must return chars SIGN-EXTENDED into ints,
9364 * not zero-extended. Seems fragile to me. Affects only !USE_SIT_FUNCTION case,
9365 * so we can fix it by ditching !USE_SIT_FUNCTION if Unicode requires that.
9367 static int
9368 preadbuffer(void)
9370 char *q;
9371 int more;
9373 while (g_parsefile->strpush) {
9374 #if ENABLE_ASH_ALIAS
9375 if (g_parsefile->left_in_line == -1
9376 && g_parsefile->strpush->ap
9377 && g_parsefile->next_to_pgetc[-1] != ' '
9378 && g_parsefile->next_to_pgetc[-1] != '\t'
9380 pgetc_debug("preadbuffer PEOA");
9381 return PEOA;
9383 #endif
9384 popstring();
9385 /* try "pgetc" now: */
9386 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9387 g_parsefile->left_in_line,
9388 g_parsefile->next_to_pgetc,
9389 g_parsefile->next_to_pgetc);
9390 if (--g_parsefile->left_in_line >= 0)
9391 return (unsigned char)(*g_parsefile->next_to_pgetc++);
9393 /* on both branches above g_parsefile->left_in_line < 0.
9394 * "pgetc" needs refilling.
9397 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
9398 * pungetc() may increment it a few times.
9399 * Assuming it won't increment it to less than -90.
9401 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
9402 pgetc_debug("preadbuffer PEOF1");
9403 /* even in failure keep left_in_line and next_to_pgetc
9404 * in lock step, for correct multi-layer pungetc.
9405 * left_in_line was decremented before preadbuffer(),
9406 * must inc next_to_pgetc: */
9407 g_parsefile->next_to_pgetc++;
9408 return PEOF;
9411 more = g_parsefile->left_in_buffer;
9412 if (more <= 0) {
9413 flush_stdout_stderr();
9414 again:
9415 more = preadfd();
9416 if (more <= 0) {
9417 /* don't try reading again */
9418 g_parsefile->left_in_line = -99;
9419 pgetc_debug("preadbuffer PEOF2");
9420 g_parsefile->next_to_pgetc++;
9421 return PEOF;
9425 /* Find out where's the end of line.
9426 * Set g_parsefile->left_in_line
9427 * and g_parsefile->left_in_buffer acordingly.
9428 * NUL chars are deleted.
9430 q = g_parsefile->next_to_pgetc;
9431 for (;;) {
9432 char c;
9434 more--;
9436 c = *q;
9437 if (c == '\0') {
9438 memmove(q, q + 1, more);
9439 } else {
9440 q++;
9441 if (c == '\n') {
9442 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9443 break;
9447 if (more <= 0) {
9448 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9449 if (g_parsefile->left_in_line < 0)
9450 goto again;
9451 break;
9454 g_parsefile->left_in_buffer = more;
9456 if (vflag) {
9457 char save = *q;
9458 *q = '\0';
9459 out2str(g_parsefile->next_to_pgetc);
9460 *q = save;
9463 pgetc_debug("preadbuffer at %d:%p'%s'",
9464 g_parsefile->left_in_line,
9465 g_parsefile->next_to_pgetc,
9466 g_parsefile->next_to_pgetc);
9467 return signed_char2int(*g_parsefile->next_to_pgetc++);
9470 #define pgetc_as_macro() \
9471 (--g_parsefile->left_in_line >= 0 \
9472 ? signed_char2int(*g_parsefile->next_to_pgetc++) \
9473 : preadbuffer() \
9476 static int
9477 pgetc(void)
9479 pgetc_debug("pgetc_fast at %d:%p'%s'",
9480 g_parsefile->left_in_line,
9481 g_parsefile->next_to_pgetc,
9482 g_parsefile->next_to_pgetc);
9483 return pgetc_as_macro();
9486 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9487 #define pgetc_fast() pgetc()
9488 #else
9489 #define pgetc_fast() pgetc_as_macro()
9490 #endif
9493 * Same as pgetc(), but ignores PEOA.
9495 #if ENABLE_ASH_ALIAS
9496 static int
9497 pgetc2(void)
9499 int c;
9500 do {
9501 pgetc_debug("pgetc_fast at %d:%p'%s'",
9502 g_parsefile->left_in_line,
9503 g_parsefile->next_to_pgetc,
9504 g_parsefile->next_to_pgetc);
9505 c = pgetc_fast();
9506 } while (c == PEOA);
9507 return c;
9509 #else
9510 #define pgetc2() pgetc()
9511 #endif
9514 * Read a line from the script.
9516 static char *
9517 pfgets(char *line, int len)
9519 char *p = line;
9520 int nleft = len;
9521 int c;
9523 while (--nleft > 0) {
9524 c = pgetc2();
9525 if (c == PEOF) {
9526 if (p == line)
9527 return NULL;
9528 break;
9530 *p++ = c;
9531 if (c == '\n')
9532 break;
9534 *p = '\0';
9535 return line;
9539 * Undo the last call to pgetc. Only one character may be pushed back.
9540 * PEOF may be pushed back.
9542 static void
9543 pungetc(void)
9545 g_parsefile->left_in_line++;
9546 g_parsefile->next_to_pgetc--;
9547 pgetc_debug("pushed back to %d:%p'%s'",
9548 g_parsefile->left_in_line,
9549 g_parsefile->next_to_pgetc,
9550 g_parsefile->next_to_pgetc);
9554 * To handle the "." command, a stack of input files is used. Pushfile
9555 * adds a new entry to the stack and popfile restores the previous level.
9557 static void
9558 pushfile(void)
9560 struct parsefile *pf;
9562 pf = ckzalloc(sizeof(*pf));
9563 pf->prev = g_parsefile;
9564 pf->fd = -1;
9565 /*pf->strpush = NULL; - ckzalloc did it */
9566 /*pf->basestrpush.prev = NULL;*/
9567 g_parsefile = pf;
9570 static void
9571 popfile(void)
9573 struct parsefile *pf = g_parsefile;
9575 INT_OFF;
9576 if (pf->fd >= 0)
9577 close(pf->fd);
9578 free(pf->buf);
9579 while (pf->strpush)
9580 popstring();
9581 g_parsefile = pf->prev;
9582 free(pf);
9583 INT_ON;
9587 * Return to top level.
9589 static void
9590 popallfiles(void)
9592 while (g_parsefile != &basepf)
9593 popfile();
9597 * Close the file(s) that the shell is reading commands from. Called
9598 * after a fork is done.
9600 static void
9601 closescript(void)
9603 popallfiles();
9604 if (g_parsefile->fd > 0) {
9605 close(g_parsefile->fd);
9606 g_parsefile->fd = 0;
9611 * Like setinputfile, but takes an open file descriptor. Call this with
9612 * interrupts off.
9614 static void
9615 setinputfd(int fd, int push)
9617 close_on_exec_on(fd);
9618 if (push) {
9619 pushfile();
9620 g_parsefile->buf = NULL;
9622 g_parsefile->fd = fd;
9623 if (g_parsefile->buf == NULL)
9624 g_parsefile->buf = ckmalloc(IBUFSIZ);
9625 g_parsefile->left_in_buffer = 0;
9626 g_parsefile->left_in_line = 0;
9627 g_parsefile->linno = 1;
9631 * Set the input to take input from a file. If push is set, push the
9632 * old input onto the stack first.
9634 static int
9635 setinputfile(const char *fname, int flags)
9637 int fd;
9638 int fd2;
9640 INT_OFF;
9641 fd = open(fname, O_RDONLY);
9642 if (fd < 0) {
9643 if (flags & INPUT_NOFILE_OK)
9644 goto out;
9645 ash_msg_and_raise_error("can't open '%s'", fname);
9647 if (fd < 10) {
9648 fd2 = copyfd(fd, 10);
9649 close(fd);
9650 if (fd2 < 0)
9651 ash_msg_and_raise_error("out of file descriptors");
9652 fd = fd2;
9654 setinputfd(fd, flags & INPUT_PUSH_FILE);
9655 out:
9656 INT_ON;
9657 return fd;
9661 * Like setinputfile, but takes input from a string.
9663 static void
9664 setinputstring(char *string)
9666 INT_OFF;
9667 pushfile();
9668 g_parsefile->next_to_pgetc = string;
9669 g_parsefile->left_in_line = strlen(string);
9670 g_parsefile->buf = NULL;
9671 g_parsefile->linno = 1;
9672 INT_ON;
9676 /* ============ mail.c
9678 * Routines to check for mail.
9681 #if ENABLE_ASH_MAIL
9683 #define MAXMBOXES 10
9685 /* times of mailboxes */
9686 static time_t mailtime[MAXMBOXES];
9687 /* Set if MAIL or MAILPATH is changed. */
9688 static smallint mail_var_path_changed;
9691 * Print appropriate message(s) if mail has arrived.
9692 * If mail_var_path_changed is set,
9693 * then the value of MAIL has mail_var_path_changed,
9694 * so we just update the values.
9696 static void
9697 chkmail(void)
9699 const char *mpath;
9700 char *p;
9701 char *q;
9702 time_t *mtp;
9703 struct stackmark smark;
9704 struct stat statb;
9706 setstackmark(&smark);
9707 mpath = mpathset() ? mpathval() : mailval();
9708 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
9709 p = padvance(&mpath, nullstr);
9710 if (p == NULL)
9711 break;
9712 if (*p == '\0')
9713 continue;
9714 for (q = p; *q; q++)
9715 continue;
9716 #if DEBUG
9717 if (q[-1] != '/')
9718 abort();
9719 #endif
9720 q[-1] = '\0'; /* delete trailing '/' */
9721 if (stat(p, &statb) < 0) {
9722 *mtp = 0;
9723 continue;
9725 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
9726 fprintf(
9727 stderr, snlfmt,
9728 pathopt ? pathopt : "you have mail"
9731 *mtp = statb.st_mtime;
9733 mail_var_path_changed = 0;
9734 popstackmark(&smark);
9737 static void
9738 changemail(const char *val UNUSED_PARAM)
9740 mail_var_path_changed = 1;
9743 #endif /* ASH_MAIL */
9746 /* ============ ??? */
9749 * Set the shell parameters.
9751 static void
9752 setparam(char **argv)
9754 char **newparam;
9755 char **ap;
9756 int nparam;
9758 for (nparam = 0; argv[nparam]; nparam++)
9759 continue;
9760 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
9761 while (*argv) {
9762 *ap++ = ckstrdup(*argv++);
9764 *ap = NULL;
9765 freeparam(&shellparam);
9766 shellparam.malloced = 1;
9767 shellparam.nparam = nparam;
9768 shellparam.p = newparam;
9769 #if ENABLE_ASH_GETOPTS
9770 shellparam.optind = 1;
9771 shellparam.optoff = -1;
9772 #endif
9776 * Process shell options. The global variable argptr contains a pointer
9777 * to the argument list; we advance it past the options.
9779 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9780 * For a non-interactive shell, an error condition encountered
9781 * by a special built-in ... shall cause the shell to write a diagnostic message
9782 * to standard error and exit as shown in the following table:
9783 * Error Special Built-In
9784 * ...
9785 * Utility syntax error (option or operand error) Shall exit
9786 * ...
9787 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9788 * we see that bash does not do that (set "finishes" with error code 1 instead,
9789 * and shell continues), and people rely on this behavior!
9790 * Testcase:
9791 * set -o barfoo 2>/dev/null
9792 * echo $?
9794 * Oh well. Let's mimic that.
9796 static int
9797 plus_minus_o(char *name, int val)
9799 int i;
9801 if (name) {
9802 for (i = 0; i < NOPTS; i++) {
9803 if (strcmp(name, optnames(i)) == 0) {
9804 optlist[i] = val;
9805 return 0;
9808 ash_msg("illegal option %co %s", val ? '-' : '+', name);
9809 return 1;
9811 for (i = 0; i < NOPTS; i++) {
9812 if (val) {
9813 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
9814 } else {
9815 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
9818 return 0;
9820 static void
9821 setoption(int flag, int val)
9823 int i;
9825 for (i = 0; i < NOPTS; i++) {
9826 if (optletters(i) == flag) {
9827 optlist[i] = val;
9828 return;
9831 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
9832 /* NOTREACHED */
9834 static int
9835 options(int cmdline)
9837 char *p;
9838 int val;
9839 int c;
9841 if (cmdline)
9842 minusc = NULL;
9843 while ((p = *argptr) != NULL) {
9844 c = *p++;
9845 if (c != '-' && c != '+')
9846 break;
9847 argptr++;
9848 val = 0; /* val = 0 if c == '+' */
9849 if (c == '-') {
9850 val = 1;
9851 if (p[0] == '\0' || LONE_DASH(p)) {
9852 if (!cmdline) {
9853 /* "-" means turn off -x and -v */
9854 if (p[0] == '\0')
9855 xflag = vflag = 0;
9856 /* "--" means reset params */
9857 else if (*argptr == NULL)
9858 setparam(argptr);
9860 break; /* "-" or "--" terminates options */
9863 /* first char was + or - */
9864 while ((c = *p++) != '\0') {
9865 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9866 if (c == 'c' && cmdline) {
9867 minusc = p; /* command is after shell args */
9868 } else if (c == 'o') {
9869 if (plus_minus_o(*argptr, val)) {
9870 /* it already printed err message */
9871 return 1; /* error */
9873 if (*argptr)
9874 argptr++;
9875 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
9876 isloginsh = 1;
9877 /* bash does not accept +-login, we also won't */
9878 } else if (cmdline && val && (c == '-')) { /* long options */
9879 if (strcmp(p, "login") == 0)
9880 isloginsh = 1;
9881 break;
9882 } else {
9883 setoption(c, val);
9887 return 0;
9891 * The shift builtin command.
9893 static int
9894 shiftcmd(int argc UNUSED_PARAM, char **argv)
9896 int n;
9897 char **ap1, **ap2;
9899 n = 1;
9900 if (argv[1])
9901 n = number(argv[1]);
9902 if (n > shellparam.nparam)
9903 n = 0; /* bash compat, was = shellparam.nparam; */
9904 INT_OFF;
9905 shellparam.nparam -= n;
9906 for (ap1 = shellparam.p; --n >= 0; ap1++) {
9907 if (shellparam.malloced)
9908 free(*ap1);
9910 ap2 = shellparam.p;
9911 while ((*ap2++ = *ap1++) != NULL)
9912 continue;
9913 #if ENABLE_ASH_GETOPTS
9914 shellparam.optind = 1;
9915 shellparam.optoff = -1;
9916 #endif
9917 INT_ON;
9918 return 0;
9922 * POSIX requires that 'set' (but not export or readonly) output the
9923 * variables in lexicographic order - by the locale's collating order (sigh).
9924 * Maybe we could keep them in an ordered balanced binary tree
9925 * instead of hashed lists.
9926 * For now just roll 'em through qsort for printing...
9928 static int
9929 showvars(const char *sep_prefix, int on, int off)
9931 const char *sep;
9932 char **ep, **epend;
9934 ep = listvars(on, off, &epend);
9935 qsort(ep, epend - ep, sizeof(char *), vpcmp);
9937 sep = *sep_prefix ? " " : sep_prefix;
9939 for (; ep < epend; ep++) {
9940 const char *p;
9941 const char *q;
9943 p = strchrnul(*ep, '=');
9944 q = nullstr;
9945 if (*p)
9946 q = single_quote(++p);
9947 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
9949 return 0;
9953 * The set command builtin.
9955 static int
9956 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9958 int retval;
9960 if (!argv[1])
9961 return showvars(nullstr, 0, VUNSET);
9962 INT_OFF;
9963 retval = 1;
9964 if (!options(0)) { /* if no parse error... */
9965 retval = 0;
9966 optschanged();
9967 if (*argptr != NULL) {
9968 setparam(argptr);
9971 INT_ON;
9972 return retval;
9975 #if ENABLE_ASH_RANDOM_SUPPORT
9976 static void
9977 change_random(const char *value)
9979 /* Galois LFSR parameter */
9980 /* Taps at 32 31 29 1: */
9981 enum { MASK = 0x8000000b };
9982 /* Another example - taps at 32 31 30 10: */
9983 /* MASK = 0x00400007 */
9985 if (value == NULL) {
9986 /* "get", generate */
9987 uint32_t t;
9989 /* LCG has period of 2^32 and alternating lowest bit */
9990 random_LCG = 1664525 * random_LCG + 1013904223;
9991 /* Galois LFSR has period of 2^32-1 = 3 * 5 * 17 * 257 * 65537 */
9992 t = (random_galois_LFSR << 1);
9993 if (random_galois_LFSR < 0) /* if we just shifted 1 out of msb... */
9994 t ^= MASK;
9995 random_galois_LFSR = t;
9996 /* Both are weak, combining them gives better randomness
9997 * and ~2^64 period. & 0x7fff is probably bash compat
9998 * for $RANDOM range. Combining with subtraction is
9999 * just for fun. + and ^ would work equally well. */
10000 t = (t - random_LCG) & 0x7fff;
10001 /* set without recursion */
10002 setvar(vrandom.text, utoa(t), VNOFUNC);
10003 vrandom.flags &= ~VNOFUNC;
10004 } else {
10005 /* set/reset */
10006 random_galois_LFSR = random_LCG = strtoul(value, (char **)NULL, 10);
10009 #endif
10011 #if ENABLE_ASH_GETOPTS
10012 static int
10013 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
10015 char *p, *q;
10016 char c = '?';
10017 int done = 0;
10018 int err = 0;
10019 char s[12];
10020 char **optnext;
10022 if (*param_optind < 1)
10023 return 1;
10024 optnext = optfirst + *param_optind - 1;
10026 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
10027 p = NULL;
10028 else
10029 p = optnext[-1] + *optoff;
10030 if (p == NULL || *p == '\0') {
10031 /* Current word is done, advance */
10032 p = *optnext;
10033 if (p == NULL || *p != '-' || *++p == '\0') {
10034 atend:
10035 p = NULL;
10036 done = 1;
10037 goto out;
10039 optnext++;
10040 if (LONE_DASH(p)) /* check for "--" */
10041 goto atend;
10044 c = *p++;
10045 for (q = optstr; *q != c;) {
10046 if (*q == '\0') {
10047 if (optstr[0] == ':') {
10048 s[0] = c;
10049 s[1] = '\0';
10050 err |= setvarsafe("OPTARG", s, 0);
10051 } else {
10052 fprintf(stderr, "Illegal option -%c\n", c);
10053 unsetvar("OPTARG");
10055 c = '?';
10056 goto out;
10058 if (*++q == ':')
10059 q++;
10062 if (*++q == ':') {
10063 if (*p == '\0' && (p = *optnext) == NULL) {
10064 if (optstr[0] == ':') {
10065 s[0] = c;
10066 s[1] = '\0';
10067 err |= setvarsafe("OPTARG", s, 0);
10068 c = ':';
10069 } else {
10070 fprintf(stderr, "No arg for -%c option\n", c);
10071 unsetvar("OPTARG");
10072 c = '?';
10074 goto out;
10077 if (p == *optnext)
10078 optnext++;
10079 err |= setvarsafe("OPTARG", p, 0);
10080 p = NULL;
10081 } else
10082 err |= setvarsafe("OPTARG", nullstr, 0);
10083 out:
10084 *optoff = p ? p - *(optnext - 1) : -1;
10085 *param_optind = optnext - optfirst + 1;
10086 fmtstr(s, sizeof(s), "%d", *param_optind);
10087 err |= setvarsafe("OPTIND", s, VNOFUNC);
10088 s[0] = c;
10089 s[1] = '\0';
10090 err |= setvarsafe(optvar, s, 0);
10091 if (err) {
10092 *param_optind = 1;
10093 *optoff = -1;
10094 flush_stdout_stderr();
10095 raise_exception(EXERROR);
10097 return done;
10101 * The getopts builtin. Shellparam.optnext points to the next argument
10102 * to be processed. Shellparam.optptr points to the next character to
10103 * be processed in the current argument. If shellparam.optnext is NULL,
10104 * then it's the first time getopts has been called.
10106 static int
10107 getoptscmd(int argc, char **argv)
10109 char **optbase;
10111 if (argc < 3)
10112 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
10113 if (argc == 3) {
10114 optbase = shellparam.p;
10115 if (shellparam.optind > shellparam.nparam + 1) {
10116 shellparam.optind = 1;
10117 shellparam.optoff = -1;
10119 } else {
10120 optbase = &argv[3];
10121 if (shellparam.optind > argc - 2) {
10122 shellparam.optind = 1;
10123 shellparam.optoff = -1;
10127 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
10128 &shellparam.optoff);
10130 #endif /* ASH_GETOPTS */
10133 /* ============ Shell parser */
10135 struct heredoc {
10136 struct heredoc *next; /* next here document in list */
10137 union node *here; /* redirection node */
10138 char *eofmark; /* string indicating end of input */
10139 smallint striptabs; /* if set, strip leading tabs */
10142 static smallint tokpushback; /* last token pushed back */
10143 static smallint parsebackquote; /* nonzero if we are inside backquotes */
10144 static smallint quoteflag; /* set if (part of) last token was quoted */
10145 static token_id_t lasttoken; /* last token read (integer id Txxx) */
10146 static struct heredoc *heredoclist; /* list of here documents to read */
10147 static char *wordtext; /* text of last word returned by readtoken */
10148 static struct nodelist *backquotelist;
10149 static union node *redirnode;
10150 static struct heredoc *heredoc;
10152 * NEOF is returned by parsecmd when it encounters an end of file. It
10153 * must be distinct from NULL, so we use the address of a variable that
10154 * happens to be handy.
10156 #define NEOF ((union node *)&tokpushback)
10159 * Called when an unexpected token is read during the parse. The argument
10160 * is the token that is expected, or -1 if more than one type of token can
10161 * occur at this point.
10163 static void raise_error_unexpected_syntax(int) NORETURN;
10164 static void
10165 raise_error_unexpected_syntax(int token)
10167 char msg[64];
10168 int l;
10170 l = sprintf(msg, "unexpected %s", tokname(lasttoken));
10171 if (token >= 0)
10172 sprintf(msg + l, " (expecting %s)", tokname(token));
10173 raise_error_syntax(msg);
10174 /* NOTREACHED */
10177 #define EOFMARKLEN 79
10179 /* parsing is heavily cross-recursive, need these forward decls */
10180 static union node *andor(void);
10181 static union node *pipeline(void);
10182 static union node *parse_command(void);
10183 static void parseheredoc(void);
10184 static char peektoken(void);
10185 static int readtoken(void);
10187 static union node *
10188 list(int nlflag)
10190 union node *n1, *n2, *n3;
10191 int tok;
10193 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10194 if (nlflag == 2 && peektoken())
10195 return NULL;
10196 n1 = NULL;
10197 for (;;) {
10198 n2 = andor();
10199 tok = readtoken();
10200 if (tok == TBACKGND) {
10201 if (n2->type == NPIPE) {
10202 n2->npipe.pipe_backgnd = 1;
10203 } else {
10204 if (n2->type != NREDIR) {
10205 n3 = stzalloc(sizeof(struct nredir));
10206 n3->nredir.n = n2;
10207 /*n3->nredir.redirect = NULL; - stzalloc did it */
10208 n2 = n3;
10210 n2->type = NBACKGND;
10213 if (n1 == NULL) {
10214 n1 = n2;
10215 } else {
10216 n3 = stzalloc(sizeof(struct nbinary));
10217 n3->type = NSEMI;
10218 n3->nbinary.ch1 = n1;
10219 n3->nbinary.ch2 = n2;
10220 n1 = n3;
10222 switch (tok) {
10223 case TBACKGND:
10224 case TSEMI:
10225 tok = readtoken();
10226 /* fall through */
10227 case TNL:
10228 if (tok == TNL) {
10229 parseheredoc();
10230 if (nlflag == 1)
10231 return n1;
10232 } else {
10233 tokpushback = 1;
10235 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10236 if (peektoken())
10237 return n1;
10238 break;
10239 case TEOF:
10240 if (heredoclist)
10241 parseheredoc();
10242 else
10243 pungetc(); /* push back EOF on input */
10244 return n1;
10245 default:
10246 if (nlflag == 1)
10247 raise_error_unexpected_syntax(-1);
10248 tokpushback = 1;
10249 return n1;
10254 static union node *
10255 andor(void)
10257 union node *n1, *n2, *n3;
10258 int t;
10260 n1 = pipeline();
10261 for (;;) {
10262 t = readtoken();
10263 if (t == TAND) {
10264 t = NAND;
10265 } else if (t == TOR) {
10266 t = NOR;
10267 } else {
10268 tokpushback = 1;
10269 return n1;
10271 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10272 n2 = pipeline();
10273 n3 = stzalloc(sizeof(struct nbinary));
10274 n3->type = t;
10275 n3->nbinary.ch1 = n1;
10276 n3->nbinary.ch2 = n2;
10277 n1 = n3;
10281 static union node *
10282 pipeline(void)
10284 union node *n1, *n2, *pipenode;
10285 struct nodelist *lp, *prev;
10286 int negate;
10288 negate = 0;
10289 TRACE(("pipeline: entered\n"));
10290 if (readtoken() == TNOT) {
10291 negate = !negate;
10292 checkkwd = CHKKWD | CHKALIAS;
10293 } else
10294 tokpushback = 1;
10295 n1 = parse_command();
10296 if (readtoken() == TPIPE) {
10297 pipenode = stzalloc(sizeof(struct npipe));
10298 pipenode->type = NPIPE;
10299 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10300 lp = stzalloc(sizeof(struct nodelist));
10301 pipenode->npipe.cmdlist = lp;
10302 lp->n = n1;
10303 do {
10304 prev = lp;
10305 lp = stzalloc(sizeof(struct nodelist));
10306 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10307 lp->n = parse_command();
10308 prev->next = lp;
10309 } while (readtoken() == TPIPE);
10310 lp->next = NULL;
10311 n1 = pipenode;
10313 tokpushback = 1;
10314 if (negate) {
10315 n2 = stzalloc(sizeof(struct nnot));
10316 n2->type = NNOT;
10317 n2->nnot.com = n1;
10318 return n2;
10320 return n1;
10323 static union node *
10324 makename(void)
10326 union node *n;
10328 n = stzalloc(sizeof(struct narg));
10329 n->type = NARG;
10330 /*n->narg.next = NULL; - stzalloc did it */
10331 n->narg.text = wordtext;
10332 n->narg.backquote = backquotelist;
10333 return n;
10336 static void
10337 fixredir(union node *n, const char *text, int err)
10339 int fd;
10341 TRACE(("Fix redir %s %d\n", text, err));
10342 if (!err)
10343 n->ndup.vname = NULL;
10345 fd = bb_strtou(text, NULL, 10);
10346 if (!errno && fd >= 0)
10347 n->ndup.dupfd = fd;
10348 else if (LONE_DASH(text))
10349 n->ndup.dupfd = -1;
10350 else {
10351 if (err)
10352 raise_error_syntax("bad fd number");
10353 n->ndup.vname = makename();
10358 * Returns true if the text contains nothing to expand (no dollar signs
10359 * or backquotes).
10361 static int
10362 noexpand(const char *text)
10364 const char *p;
10365 char c;
10367 p = text;
10368 while ((c = *p++) != '\0') {
10369 if (c == CTLQUOTEMARK)
10370 continue;
10371 if (c == CTLESC)
10372 p++;
10373 else if (SIT((signed char)c, BASESYNTAX) == CCTL)
10374 return 0;
10376 return 1;
10379 static void
10380 parsefname(void)
10382 union node *n = redirnode;
10384 if (readtoken() != TWORD)
10385 raise_error_unexpected_syntax(-1);
10386 if (n->type == NHERE) {
10387 struct heredoc *here = heredoc;
10388 struct heredoc *p;
10389 int i;
10391 if (quoteflag == 0)
10392 n->type = NXHERE;
10393 TRACE(("Here document %d\n", n->type));
10394 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10395 raise_error_syntax("illegal eof marker for << redirection");
10396 rmescapes(wordtext);
10397 here->eofmark = wordtext;
10398 here->next = NULL;
10399 if (heredoclist == NULL)
10400 heredoclist = here;
10401 else {
10402 for (p = heredoclist; p->next; p = p->next)
10403 continue;
10404 p->next = here;
10406 } else if (n->type == NTOFD || n->type == NFROMFD) {
10407 fixredir(n, wordtext, 0);
10408 } else {
10409 n->nfile.fname = makename();
10413 static union node *
10414 simplecmd(void)
10416 union node *args, **app;
10417 union node *n = NULL;
10418 union node *vars, **vpp;
10419 union node **rpp, *redir;
10420 int savecheckkwd;
10421 #if ENABLE_ASH_BASH_COMPAT
10422 smallint double_brackets_flag = 0;
10423 #endif
10425 args = NULL;
10426 app = &args;
10427 vars = NULL;
10428 vpp = &vars;
10429 redir = NULL;
10430 rpp = &redir;
10432 savecheckkwd = CHKALIAS;
10433 for (;;) {
10434 int t;
10435 checkkwd = savecheckkwd;
10436 t = readtoken();
10437 switch (t) {
10438 #if ENABLE_ASH_BASH_COMPAT
10439 case TAND: /* "&&" */
10440 case TOR: /* "||" */
10441 if (!double_brackets_flag) {
10442 tokpushback = 1;
10443 goto out;
10445 wordtext = (char *) (t == TAND ? "-a" : "-o");
10446 #endif
10447 case TWORD:
10448 n = stzalloc(sizeof(struct narg));
10449 n->type = NARG;
10450 /*n->narg.next = NULL; - stzalloc did it */
10451 n->narg.text = wordtext;
10452 #if ENABLE_ASH_BASH_COMPAT
10453 if (strcmp("[[", wordtext) == 0)
10454 double_brackets_flag = 1;
10455 else if (strcmp("]]", wordtext) == 0)
10456 double_brackets_flag = 0;
10457 #endif
10458 n->narg.backquote = backquotelist;
10459 if (savecheckkwd && isassignment(wordtext)) {
10460 *vpp = n;
10461 vpp = &n->narg.next;
10462 } else {
10463 *app = n;
10464 app = &n->narg.next;
10465 savecheckkwd = 0;
10467 break;
10468 case TREDIR:
10469 *rpp = n = redirnode;
10470 rpp = &n->nfile.next;
10471 parsefname(); /* read name of redirection file */
10472 break;
10473 case TLP:
10474 if (args && app == &args->narg.next
10475 && !vars && !redir
10477 struct builtincmd *bcmd;
10478 const char *name;
10480 /* We have a function */
10481 if (readtoken() != TRP)
10482 raise_error_unexpected_syntax(TRP);
10483 name = n->narg.text;
10484 if (!goodname(name)
10485 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10487 raise_error_syntax("bad function name");
10489 n->type = NDEFUN;
10490 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10491 n->narg.next = parse_command();
10492 return n;
10494 /* fall through */
10495 default:
10496 tokpushback = 1;
10497 goto out;
10500 out:
10501 *app = NULL;
10502 *vpp = NULL;
10503 *rpp = NULL;
10504 n = stzalloc(sizeof(struct ncmd));
10505 n->type = NCMD;
10506 n->ncmd.args = args;
10507 n->ncmd.assign = vars;
10508 n->ncmd.redirect = redir;
10509 return n;
10512 static union node *
10513 parse_command(void)
10515 union node *n1, *n2;
10516 union node *ap, **app;
10517 union node *cp, **cpp;
10518 union node *redir, **rpp;
10519 union node **rpp2;
10520 int t;
10522 redir = NULL;
10523 rpp2 = &redir;
10525 switch (readtoken()) {
10526 default:
10527 raise_error_unexpected_syntax(-1);
10528 /* NOTREACHED */
10529 case TIF:
10530 n1 = stzalloc(sizeof(struct nif));
10531 n1->type = NIF;
10532 n1->nif.test = list(0);
10533 if (readtoken() != TTHEN)
10534 raise_error_unexpected_syntax(TTHEN);
10535 n1->nif.ifpart = list(0);
10536 n2 = n1;
10537 while (readtoken() == TELIF) {
10538 n2->nif.elsepart = stzalloc(sizeof(struct nif));
10539 n2 = n2->nif.elsepart;
10540 n2->type = NIF;
10541 n2->nif.test = list(0);
10542 if (readtoken() != TTHEN)
10543 raise_error_unexpected_syntax(TTHEN);
10544 n2->nif.ifpart = list(0);
10546 if (lasttoken == TELSE)
10547 n2->nif.elsepart = list(0);
10548 else {
10549 n2->nif.elsepart = NULL;
10550 tokpushback = 1;
10552 t = TFI;
10553 break;
10554 case TWHILE:
10555 case TUNTIL: {
10556 int got;
10557 n1 = stzalloc(sizeof(struct nbinary));
10558 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10559 n1->nbinary.ch1 = list(0);
10560 got = readtoken();
10561 if (got != TDO) {
10562 TRACE(("expecting DO got %s %s\n", tokname(got),
10563 got == TWORD ? wordtext : ""));
10564 raise_error_unexpected_syntax(TDO);
10566 n1->nbinary.ch2 = list(0);
10567 t = TDONE;
10568 break;
10570 case TFOR:
10571 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10572 raise_error_syntax("bad for loop variable");
10573 n1 = stzalloc(sizeof(struct nfor));
10574 n1->type = NFOR;
10575 n1->nfor.var = wordtext;
10576 checkkwd = CHKKWD | CHKALIAS;
10577 if (readtoken() == TIN) {
10578 app = &ap;
10579 while (readtoken() == TWORD) {
10580 n2 = stzalloc(sizeof(struct narg));
10581 n2->type = NARG;
10582 /*n2->narg.next = NULL; - stzalloc did it */
10583 n2->narg.text = wordtext;
10584 n2->narg.backquote = backquotelist;
10585 *app = n2;
10586 app = &n2->narg.next;
10588 *app = NULL;
10589 n1->nfor.args = ap;
10590 if (lasttoken != TNL && lasttoken != TSEMI)
10591 raise_error_unexpected_syntax(-1);
10592 } else {
10593 n2 = stzalloc(sizeof(struct narg));
10594 n2->type = NARG;
10595 /*n2->narg.next = NULL; - stzalloc did it */
10596 n2->narg.text = (char *)dolatstr;
10597 /*n2->narg.backquote = NULL;*/
10598 n1->nfor.args = n2;
10600 * Newline or semicolon here is optional (but note
10601 * that the original Bourne shell only allowed NL).
10603 if (lasttoken != TNL && lasttoken != TSEMI)
10604 tokpushback = 1;
10606 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10607 if (readtoken() != TDO)
10608 raise_error_unexpected_syntax(TDO);
10609 n1->nfor.body = list(0);
10610 t = TDONE;
10611 break;
10612 case TCASE:
10613 n1 = stzalloc(sizeof(struct ncase));
10614 n1->type = NCASE;
10615 if (readtoken() != TWORD)
10616 raise_error_unexpected_syntax(TWORD);
10617 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10618 n2->type = NARG;
10619 /*n2->narg.next = NULL; - stzalloc did it */
10620 n2->narg.text = wordtext;
10621 n2->narg.backquote = backquotelist;
10622 do {
10623 checkkwd = CHKKWD | CHKALIAS;
10624 } while (readtoken() == TNL);
10625 if (lasttoken != TIN)
10626 raise_error_unexpected_syntax(TIN);
10627 cpp = &n1->ncase.cases;
10628 next_case:
10629 checkkwd = CHKNL | CHKKWD;
10630 t = readtoken();
10631 while (t != TESAC) {
10632 if (lasttoken == TLP)
10633 readtoken();
10634 *cpp = cp = stzalloc(sizeof(struct nclist));
10635 cp->type = NCLIST;
10636 app = &cp->nclist.pattern;
10637 for (;;) {
10638 *app = ap = stzalloc(sizeof(struct narg));
10639 ap->type = NARG;
10640 /*ap->narg.next = NULL; - stzalloc did it */
10641 ap->narg.text = wordtext;
10642 ap->narg.backquote = backquotelist;
10643 if (readtoken() != TPIPE)
10644 break;
10645 app = &ap->narg.next;
10646 readtoken();
10648 //ap->narg.next = NULL;
10649 if (lasttoken != TRP)
10650 raise_error_unexpected_syntax(TRP);
10651 cp->nclist.body = list(2);
10653 cpp = &cp->nclist.next;
10655 checkkwd = CHKNL | CHKKWD;
10656 t = readtoken();
10657 if (t != TESAC) {
10658 if (t != TENDCASE)
10659 raise_error_unexpected_syntax(TENDCASE);
10660 goto next_case;
10663 *cpp = NULL;
10664 goto redir;
10665 case TLP:
10666 n1 = stzalloc(sizeof(struct nredir));
10667 n1->type = NSUBSHELL;
10668 n1->nredir.n = list(0);
10669 /*n1->nredir.redirect = NULL; - stzalloc did it */
10670 t = TRP;
10671 break;
10672 case TBEGIN:
10673 n1 = list(0);
10674 t = TEND;
10675 break;
10676 case TWORD:
10677 case TREDIR:
10678 tokpushback = 1;
10679 return simplecmd();
10682 if (readtoken() != t)
10683 raise_error_unexpected_syntax(t);
10685 redir:
10686 /* Now check for redirection which may follow command */
10687 checkkwd = CHKKWD | CHKALIAS;
10688 rpp = rpp2;
10689 while (readtoken() == TREDIR) {
10690 *rpp = n2 = redirnode;
10691 rpp = &n2->nfile.next;
10692 parsefname();
10694 tokpushback = 1;
10695 *rpp = NULL;
10696 if (redir) {
10697 if (n1->type != NSUBSHELL) {
10698 n2 = stzalloc(sizeof(struct nredir));
10699 n2->type = NREDIR;
10700 n2->nredir.n = n1;
10701 n1 = n2;
10703 n1->nredir.redirect = redir;
10705 return n1;
10708 #if ENABLE_ASH_BASH_COMPAT
10709 static int decode_dollar_squote(void)
10711 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
10712 int c, cnt;
10713 char *p;
10714 char buf[4];
10716 c = pgetc();
10717 p = strchr(C_escapes, c);
10718 if (p) {
10719 buf[0] = c;
10720 p = buf;
10721 cnt = 3;
10722 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
10723 do {
10724 c = pgetc();
10725 *++p = c;
10726 } while ((unsigned char)(c - '0') <= 7 && --cnt);
10727 pungetc();
10728 } else if (c == 'x') { /* \xHH */
10729 do {
10730 c = pgetc();
10731 *++p = c;
10732 } while (isxdigit(c) && --cnt);
10733 pungetc();
10734 if (cnt == 3) { /* \x but next char is "bad" */
10735 c = 'x';
10736 goto unrecognized;
10738 } else { /* simple seq like \\ or \t */
10739 p++;
10741 *p = '\0';
10742 p = buf;
10743 c = bb_process_escape_sequence((void*)&p);
10744 } else { /* unrecognized "\z": print both chars unless ' or " */
10745 if (c != '\'' && c != '"') {
10746 unrecognized:
10747 c |= 0x100; /* "please encode \, then me" */
10750 return c;
10752 #endif
10755 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10756 * is not NULL, read a here document. In the latter case, eofmark is the
10757 * word which marks the end of the document and striptabs is true if
10758 * leading tabs should be stripped from the document. The argument firstc
10759 * is the first character of the input token or document.
10761 * Because C does not have internal subroutines, I have simulated them
10762 * using goto's to implement the subroutine linkage. The following macros
10763 * will run code that appears at the end of readtoken1.
10765 #define CHECKEND() {goto checkend; checkend_return:;}
10766 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10767 #define PARSESUB() {goto parsesub; parsesub_return:;}
10768 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10769 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10770 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10771 static int
10772 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10774 /* NB: syntax parameter fits into smallint */
10775 int c = firstc;
10776 char *out;
10777 int len;
10778 char line[EOFMARKLEN + 1];
10779 struct nodelist *bqlist;
10780 smallint quotef;
10781 smallint dblquote;
10782 smallint oldstyle;
10783 smallint prevsyntax; /* syntax before arithmetic */
10784 #if ENABLE_ASH_EXPAND_PRMT
10785 smallint pssyntax; /* we are expanding a prompt string */
10786 #endif
10787 int varnest; /* levels of variables expansion */
10788 int arinest; /* levels of arithmetic expansion */
10789 int parenlevel; /* levels of parens in arithmetic */
10790 int dqvarnest; /* levels of variables expansion within double quotes */
10792 USE_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
10794 #if __GNUC__
10795 /* Avoid longjmp clobbering */
10796 (void) &out;
10797 (void) &quotef;
10798 (void) &dblquote;
10799 (void) &varnest;
10800 (void) &arinest;
10801 (void) &parenlevel;
10802 (void) &dqvarnest;
10803 (void) &oldstyle;
10804 (void) &prevsyntax;
10805 (void) &syntax;
10806 #endif
10807 startlinno = g_parsefile->linno;
10808 bqlist = NULL;
10809 quotef = 0;
10810 oldstyle = 0;
10811 prevsyntax = 0;
10812 #if ENABLE_ASH_EXPAND_PRMT
10813 pssyntax = (syntax == PSSYNTAX);
10814 if (pssyntax)
10815 syntax = DQSYNTAX;
10816 #endif
10817 dblquote = (syntax == DQSYNTAX);
10818 varnest = 0;
10819 arinest = 0;
10820 parenlevel = 0;
10821 dqvarnest = 0;
10823 STARTSTACKSTR(out);
10824 loop:
10825 /* For each line, until end of word */
10827 CHECKEND(); /* set c to PEOF if at end of here document */
10828 for (;;) { /* until end of line or end of word */
10829 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10830 switch (SIT(c, syntax)) {
10831 case CNL: /* '\n' */
10832 if (syntax == BASESYNTAX)
10833 goto endword; /* exit outer loop */
10834 USTPUTC(c, out);
10835 g_parsefile->linno++;
10836 if (doprompt)
10837 setprompt(2);
10838 c = pgetc();
10839 goto loop; /* continue outer loop */
10840 case CWORD:
10841 USTPUTC(c, out);
10842 break;
10843 case CCTL:
10844 if (eofmark == NULL || dblquote)
10845 USTPUTC(CTLESC, out);
10846 #if ENABLE_ASH_BASH_COMPAT
10847 if (c == '\\' && bash_dollar_squote) {
10848 c = decode_dollar_squote();
10849 if (c & 0x100) {
10850 USTPUTC('\\', out);
10851 c = (unsigned char)c;
10854 #endif
10855 USTPUTC(c, out);
10856 break;
10857 case CBACK: /* backslash */
10858 c = pgetc2();
10859 if (c == PEOF) {
10860 USTPUTC(CTLESC, out);
10861 USTPUTC('\\', out);
10862 pungetc();
10863 } else if (c == '\n') {
10864 if (doprompt)
10865 setprompt(2);
10866 } else {
10867 #if ENABLE_ASH_EXPAND_PRMT
10868 if (c == '$' && pssyntax) {
10869 USTPUTC(CTLESC, out);
10870 USTPUTC('\\', out);
10872 #endif
10873 if (dblquote && c != '\\'
10874 && c != '`' && c != '$'
10875 && (c != '"' || eofmark != NULL)
10877 USTPUTC(CTLESC, out);
10878 USTPUTC('\\', out);
10880 if (SIT(c, SQSYNTAX) == CCTL)
10881 USTPUTC(CTLESC, out);
10882 USTPUTC(c, out);
10883 quotef = 1;
10885 break;
10886 case CSQUOTE:
10887 syntax = SQSYNTAX;
10888 quotemark:
10889 if (eofmark == NULL) {
10890 USTPUTC(CTLQUOTEMARK, out);
10892 break;
10893 case CDQUOTE:
10894 syntax = DQSYNTAX;
10895 dblquote = 1;
10896 goto quotemark;
10897 case CENDQUOTE:
10898 USE_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
10899 if (eofmark != NULL && arinest == 0
10900 && varnest == 0
10902 USTPUTC(c, out);
10903 } else {
10904 if (dqvarnest == 0) {
10905 syntax = BASESYNTAX;
10906 dblquote = 0;
10908 quotef = 1;
10909 goto quotemark;
10911 break;
10912 case CVAR: /* '$' */
10913 PARSESUB(); /* parse substitution */
10914 break;
10915 case CENDVAR: /* '}' */
10916 if (varnest > 0) {
10917 varnest--;
10918 if (dqvarnest > 0) {
10919 dqvarnest--;
10921 USTPUTC(CTLENDVAR, out);
10922 } else {
10923 USTPUTC(c, out);
10925 break;
10926 #if ENABLE_SH_MATH_SUPPORT
10927 case CLP: /* '(' in arithmetic */
10928 parenlevel++;
10929 USTPUTC(c, out);
10930 break;
10931 case CRP: /* ')' in arithmetic */
10932 if (parenlevel > 0) {
10933 USTPUTC(c, out);
10934 --parenlevel;
10935 } else {
10936 if (pgetc() == ')') {
10937 if (--arinest == 0) {
10938 USTPUTC(CTLENDARI, out);
10939 syntax = prevsyntax;
10940 dblquote = (syntax == DQSYNTAX);
10941 } else
10942 USTPUTC(')', out);
10943 } else {
10945 * unbalanced parens
10946 * (don't 2nd guess - no error)
10948 pungetc();
10949 USTPUTC(')', out);
10952 break;
10953 #endif
10954 case CBQUOTE: /* '`' */
10955 PARSEBACKQOLD();
10956 break;
10957 case CENDFILE:
10958 goto endword; /* exit outer loop */
10959 case CIGN:
10960 break;
10961 default:
10962 if (varnest == 0) {
10963 #if ENABLE_ASH_BASH_COMPAT
10964 if (c == '&') {
10965 if (pgetc() == '>')
10966 c = 0x100 + '>'; /* flag &> */
10967 pungetc();
10969 #endif
10970 goto endword; /* exit outer loop */
10972 #if ENABLE_ASH_ALIAS
10973 if (c != PEOA)
10974 #endif
10975 USTPUTC(c, out);
10978 c = pgetc_fast();
10979 } /* for (;;) */
10981 endword:
10982 #if ENABLE_SH_MATH_SUPPORT
10983 if (syntax == ARISYNTAX)
10984 raise_error_syntax("missing '))'");
10985 #endif
10986 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10987 raise_error_syntax("unterminated quoted string");
10988 if (varnest != 0) {
10989 startlinno = g_parsefile->linno;
10990 /* { */
10991 raise_error_syntax("missing '}'");
10993 USTPUTC('\0', out);
10994 len = out - (char *)stackblock();
10995 out = stackblock();
10996 if (eofmark == NULL) {
10997 if ((c == '>' || c == '<' USE_ASH_BASH_COMPAT( || c == 0x100 + '>'))
10998 && quotef == 0
11000 if (isdigit_str9(out)) {
11001 PARSEREDIR(); /* passed as params: out, c */
11002 lasttoken = TREDIR;
11003 return lasttoken;
11005 /* else: non-number X seen, interpret it
11006 * as "NNNX>file" = "NNNX >file" */
11008 pungetc();
11010 quoteflag = quotef;
11011 backquotelist = bqlist;
11012 grabstackblock(len);
11013 wordtext = out;
11014 lasttoken = TWORD;
11015 return lasttoken;
11016 /* end of readtoken routine */
11019 * Check to see whether we are at the end of the here document. When this
11020 * is called, c is set to the first character of the next input line. If
11021 * we are at the end of the here document, this routine sets the c to PEOF.
11023 checkend: {
11024 if (eofmark) {
11025 #if ENABLE_ASH_ALIAS
11026 if (c == PEOA) {
11027 c = pgetc2();
11029 #endif
11030 if (striptabs) {
11031 while (c == '\t') {
11032 c = pgetc2();
11035 if (c == *eofmark) {
11036 if (pfgets(line, sizeof(line)) != NULL) {
11037 char *p, *q;
11039 p = line;
11040 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11041 continue;
11042 if (*p == '\n' && *q == '\0') {
11043 c = PEOF;
11044 g_parsefile->linno++;
11045 needprompt = doprompt;
11046 } else {
11047 pushstring(line, NULL);
11052 goto checkend_return;
11056 * Parse a redirection operator. The variable "out" points to a string
11057 * specifying the fd to be redirected. The variable "c" contains the
11058 * first character of the redirection operator.
11060 parseredir: {
11061 /* out is already checked to be a valid number or "" */
11062 int fd = (*out == '\0' ? -1 : atoi(out));
11063 union node *np;
11065 np = stzalloc(sizeof(struct nfile));
11066 if (c == '>') {
11067 np->nfile.fd = 1;
11068 c = pgetc();
11069 if (c == '>')
11070 np->type = NAPPEND;
11071 else if (c == '|')
11072 np->type = NCLOBBER;
11073 else if (c == '&')
11074 np->type = NTOFD;
11075 /* it also can be NTO2 (>&file), but we can't figure it out yet */
11076 else {
11077 np->type = NTO;
11078 pungetc();
11081 #if ENABLE_ASH_BASH_COMPAT
11082 else if (c == 0x100 + '>') { /* this flags &> redirection */
11083 np->nfile.fd = 1;
11084 pgetc(); /* this is '>', no need to check */
11085 np->type = NTO2;
11087 #endif
11088 else { /* c == '<' */
11089 /*np->nfile.fd = 0; - stzalloc did it */
11090 c = pgetc();
11091 switch (c) {
11092 case '<':
11093 if (sizeof(struct nfile) != sizeof(struct nhere)) {
11094 np = stzalloc(sizeof(struct nhere));
11095 /*np->nfile.fd = 0; - stzalloc did it */
11097 np->type = NHERE;
11098 heredoc = stzalloc(sizeof(struct heredoc));
11099 heredoc->here = np;
11100 c = pgetc();
11101 if (c == '-') {
11102 heredoc->striptabs = 1;
11103 } else {
11104 /*heredoc->striptabs = 0; - stzalloc did it */
11105 pungetc();
11107 break;
11109 case '&':
11110 np->type = NFROMFD;
11111 break;
11113 case '>':
11114 np->type = NFROMTO;
11115 break;
11117 default:
11118 np->type = NFROM;
11119 pungetc();
11120 break;
11123 if (fd >= 0)
11124 np->nfile.fd = fd;
11125 redirnode = np;
11126 goto parseredir_return;
11130 * Parse a substitution. At this point, we have read the dollar sign
11131 * and nothing else.
11134 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11135 * (assuming ascii char codes, as the original implementation did) */
11136 #define is_special(c) \
11137 (((unsigned)(c) - 33 < 32) \
11138 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
11139 parsesub: {
11140 int subtype;
11141 int typeloc;
11142 int flags;
11143 char *p;
11144 static const char types[] ALIGN1 = "}-+?=";
11146 c = pgetc();
11147 if (c <= PEOA_OR_PEOF
11148 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
11150 #if ENABLE_ASH_BASH_COMPAT
11151 if (c == '\'')
11152 bash_dollar_squote = 1;
11153 else
11154 #endif
11155 USTPUTC('$', out);
11156 pungetc();
11157 } else if (c == '(') { /* $(command) or $((arith)) */
11158 if (pgetc() == '(') {
11159 #if ENABLE_SH_MATH_SUPPORT
11160 PARSEARITH();
11161 #else
11162 raise_error_syntax("you disabled math support for $((arith)) syntax");
11163 #endif
11164 } else {
11165 pungetc();
11166 PARSEBACKQNEW();
11168 } else {
11169 USTPUTC(CTLVAR, out);
11170 typeloc = out - (char *)stackblock();
11171 USTPUTC(VSNORMAL, out);
11172 subtype = VSNORMAL;
11173 if (c == '{') {
11174 c = pgetc();
11175 if (c == '#') {
11176 c = pgetc();
11177 if (c == '}')
11178 c = '#';
11179 else
11180 subtype = VSLENGTH;
11181 } else
11182 subtype = 0;
11184 if (c > PEOA_OR_PEOF && is_name(c)) {
11185 do {
11186 STPUTC(c, out);
11187 c = pgetc();
11188 } while (c > PEOA_OR_PEOF && is_in_name(c));
11189 } else if (isdigit(c)) {
11190 do {
11191 STPUTC(c, out);
11192 c = pgetc();
11193 } while (isdigit(c));
11194 } else if (is_special(c)) {
11195 USTPUTC(c, out);
11196 c = pgetc();
11197 } else {
11198 badsub:
11199 raise_error_syntax("bad substitution");
11202 STPUTC('=', out);
11203 flags = 0;
11204 if (subtype == 0) {
11205 switch (c) {
11206 case ':':
11207 c = pgetc();
11208 #if ENABLE_ASH_BASH_COMPAT
11209 if (c == ':' || c == '$' || isdigit(c)) {
11210 pungetc();
11211 subtype = VSSUBSTR;
11212 break;
11214 #endif
11215 flags = VSNUL;
11216 /*FALLTHROUGH*/
11217 default:
11218 p = strchr(types, c);
11219 if (p == NULL)
11220 goto badsub;
11221 subtype = p - types + VSNORMAL;
11222 break;
11223 case '%':
11224 case '#': {
11225 int cc = c;
11226 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT;
11227 c = pgetc();
11228 if (c == cc)
11229 subtype++;
11230 else
11231 pungetc();
11232 break;
11234 #if ENABLE_ASH_BASH_COMPAT
11235 case '/':
11236 subtype = VSREPLACE;
11237 c = pgetc();
11238 if (c == '/')
11239 subtype++; /* VSREPLACEALL */
11240 else
11241 pungetc();
11242 break;
11243 #endif
11245 } else {
11246 pungetc();
11248 if (dblquote || arinest)
11249 flags |= VSQUOTE;
11250 *((char *)stackblock() + typeloc) = subtype | flags;
11251 if (subtype != VSNORMAL) {
11252 varnest++;
11253 if (dblquote || arinest) {
11254 dqvarnest++;
11258 goto parsesub_return;
11262 * Called to parse command substitutions. Newstyle is set if the command
11263 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11264 * list of commands (passed by reference), and savelen is the number of
11265 * characters on the top of the stack which must be preserved.
11267 parsebackq: {
11268 struct nodelist **nlpp;
11269 smallint savepbq;
11270 union node *n;
11271 char *volatile str;
11272 struct jmploc jmploc;
11273 struct jmploc *volatile savehandler;
11274 size_t savelen;
11275 smallint saveprompt = 0;
11277 #ifdef __GNUC__
11278 (void) &saveprompt;
11279 #endif
11280 savepbq = parsebackquote;
11281 if (setjmp(jmploc.loc)) {
11282 free(str);
11283 parsebackquote = 0;
11284 exception_handler = savehandler;
11285 longjmp(exception_handler->loc, 1);
11287 INT_OFF;
11288 str = NULL;
11289 savelen = out - (char *)stackblock();
11290 if (savelen > 0) {
11291 str = ckmalloc(savelen);
11292 memcpy(str, stackblock(), savelen);
11294 savehandler = exception_handler;
11295 exception_handler = &jmploc;
11296 INT_ON;
11297 if (oldstyle) {
11298 /* We must read until the closing backquote, giving special
11299 treatment to some slashes, and then push the string and
11300 reread it as input, interpreting it normally. */
11301 char *pout;
11302 int pc;
11303 size_t psavelen;
11304 char *pstr;
11307 STARTSTACKSTR(pout);
11308 for (;;) {
11309 if (needprompt) {
11310 setprompt(2);
11312 pc = pgetc();
11313 switch (pc) {
11314 case '`':
11315 goto done;
11317 case '\\':
11318 pc = pgetc();
11319 if (pc == '\n') {
11320 g_parsefile->linno++;
11321 if (doprompt)
11322 setprompt(2);
11324 * If eating a newline, avoid putting
11325 * the newline into the new character
11326 * stream (via the STPUTC after the
11327 * switch).
11329 continue;
11331 if (pc != '\\' && pc != '`' && pc != '$'
11332 && (!dblquote || pc != '"'))
11333 STPUTC('\\', pout);
11334 if (pc > PEOA_OR_PEOF) {
11335 break;
11337 /* fall through */
11339 case PEOF:
11340 #if ENABLE_ASH_ALIAS
11341 case PEOA:
11342 #endif
11343 startlinno = g_parsefile->linno;
11344 raise_error_syntax("EOF in backquote substitution");
11346 case '\n':
11347 g_parsefile->linno++;
11348 needprompt = doprompt;
11349 break;
11351 default:
11352 break;
11354 STPUTC(pc, pout);
11356 done:
11357 STPUTC('\0', pout);
11358 psavelen = pout - (char *)stackblock();
11359 if (psavelen > 0) {
11360 pstr = grabstackstr(pout);
11361 setinputstring(pstr);
11364 nlpp = &bqlist;
11365 while (*nlpp)
11366 nlpp = &(*nlpp)->next;
11367 *nlpp = stzalloc(sizeof(**nlpp));
11368 /* (*nlpp)->next = NULL; - stzalloc did it */
11369 parsebackquote = oldstyle;
11371 if (oldstyle) {
11372 saveprompt = doprompt;
11373 doprompt = 0;
11376 n = list(2);
11378 if (oldstyle)
11379 doprompt = saveprompt;
11380 else if (readtoken() != TRP)
11381 raise_error_unexpected_syntax(TRP);
11383 (*nlpp)->n = n;
11384 if (oldstyle) {
11386 * Start reading from old file again, ignoring any pushed back
11387 * tokens left from the backquote parsing
11389 popfile();
11390 tokpushback = 0;
11392 while (stackblocksize() <= savelen)
11393 growstackblock();
11394 STARTSTACKSTR(out);
11395 if (str) {
11396 memcpy(out, str, savelen);
11397 STADJUST(savelen, out);
11398 INT_OFF;
11399 free(str);
11400 str = NULL;
11401 INT_ON;
11403 parsebackquote = savepbq;
11404 exception_handler = savehandler;
11405 if (arinest || dblquote)
11406 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11407 else
11408 USTPUTC(CTLBACKQ, out);
11409 if (oldstyle)
11410 goto parsebackq_oldreturn;
11411 goto parsebackq_newreturn;
11414 #if ENABLE_SH_MATH_SUPPORT
11416 * Parse an arithmetic expansion (indicate start of one and set state)
11418 parsearith: {
11419 if (++arinest == 1) {
11420 prevsyntax = syntax;
11421 syntax = ARISYNTAX;
11422 USTPUTC(CTLARI, out);
11423 if (dblquote)
11424 USTPUTC('"', out);
11425 else
11426 USTPUTC(' ', out);
11427 } else {
11429 * we collapse embedded arithmetic expansion to
11430 * parenthesis, which should be equivalent
11432 USTPUTC('(', out);
11434 goto parsearith_return;
11436 #endif
11438 } /* end of readtoken */
11441 * Read the next input token.
11442 * If the token is a word, we set backquotelist to the list of cmds in
11443 * backquotes. We set quoteflag to true if any part of the word was
11444 * quoted.
11445 * If the token is TREDIR, then we set redirnode to a structure containing
11446 * the redirection.
11447 * In all cases, the variable startlinno is set to the number of the line
11448 * on which the token starts.
11450 * [Change comment: here documents and internal procedures]
11451 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11452 * word parsing code into a separate routine. In this case, readtoken
11453 * doesn't need to have any internal procedures, but parseword does.
11454 * We could also make parseoperator in essence the main routine, and
11455 * have parseword (readtoken1?) handle both words and redirection.]
11457 #define NEW_xxreadtoken
11458 #ifdef NEW_xxreadtoken
11459 /* singles must be first! */
11460 static const char xxreadtoken_chars[7] ALIGN1 = {
11461 '\n', '(', ')', /* singles */
11462 '&', '|', ';', /* doubles */
11466 #define xxreadtoken_singles 3
11467 #define xxreadtoken_doubles 3
11469 static const char xxreadtoken_tokens[] ALIGN1 = {
11470 TNL, TLP, TRP, /* only single occurrence allowed */
11471 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11472 TEOF, /* corresponds to trailing nul */
11473 TAND, TOR, TENDCASE /* if double occurrence */
11476 static int
11477 xxreadtoken(void)
11479 int c;
11481 if (tokpushback) {
11482 tokpushback = 0;
11483 return lasttoken;
11485 if (needprompt) {
11486 setprompt(2);
11488 startlinno = g_parsefile->linno;
11489 for (;;) { /* until token or start of word found */
11490 c = pgetc_fast();
11491 if (c == ' ' || c == '\t' USE_ASH_ALIAS( || c == PEOA))
11492 continue;
11494 if (c == '#') {
11495 while ((c = pgetc()) != '\n' && c != PEOF)
11496 continue;
11497 pungetc();
11498 } else if (c == '\\') {
11499 if (pgetc() != '\n') {
11500 pungetc();
11501 break; /* return readtoken1(...) */
11503 startlinno = ++g_parsefile->linno;
11504 if (doprompt)
11505 setprompt(2);
11506 } else {
11507 const char *p;
11509 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11510 if (c != PEOF) {
11511 if (c == '\n') {
11512 g_parsefile->linno++;
11513 needprompt = doprompt;
11516 p = strchr(xxreadtoken_chars, c);
11517 if (p == NULL)
11518 break; /* return readtoken1(...) */
11520 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11521 int cc = pgetc();
11522 if (cc == c) { /* double occurrence? */
11523 p += xxreadtoken_doubles + 1;
11524 } else {
11525 pungetc();
11526 #if ENABLE_ASH_BASH_COMPAT
11527 if (c == '&' && cc == '>') /* &> */
11528 break; /* return readtoken1(...) */
11529 #endif
11533 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11534 return lasttoken;
11536 } /* for (;;) */
11538 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11540 #else /* old xxreadtoken */
11541 #define RETURN(token) return lasttoken = token
11542 static int
11543 xxreadtoken(void)
11545 int c;
11547 if (tokpushback) {
11548 tokpushback = 0;
11549 return lasttoken;
11551 if (needprompt) {
11552 setprompt(2);
11554 startlinno = g_parsefile->linno;
11555 for (;;) { /* until token or start of word found */
11556 c = pgetc_fast();
11557 switch (c) {
11558 case ' ': case '\t':
11559 #if ENABLE_ASH_ALIAS
11560 case PEOA:
11561 #endif
11562 continue;
11563 case '#':
11564 while ((c = pgetc()) != '\n' && c != PEOF)
11565 continue;
11566 pungetc();
11567 continue;
11568 case '\\':
11569 if (pgetc() == '\n') {
11570 startlinno = ++g_parsefile->linno;
11571 if (doprompt)
11572 setprompt(2);
11573 continue;
11575 pungetc();
11576 goto breakloop;
11577 case '\n':
11578 g_parsefile->linno++;
11579 needprompt = doprompt;
11580 RETURN(TNL);
11581 case PEOF:
11582 RETURN(TEOF);
11583 case '&':
11584 if (pgetc() == '&')
11585 RETURN(TAND);
11586 pungetc();
11587 RETURN(TBACKGND);
11588 case '|':
11589 if (pgetc() == '|')
11590 RETURN(TOR);
11591 pungetc();
11592 RETURN(TPIPE);
11593 case ';':
11594 if (pgetc() == ';')
11595 RETURN(TENDCASE);
11596 pungetc();
11597 RETURN(TSEMI);
11598 case '(':
11599 RETURN(TLP);
11600 case ')':
11601 RETURN(TRP);
11602 default:
11603 goto breakloop;
11606 breakloop:
11607 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11608 #undef RETURN
11610 #endif /* old xxreadtoken */
11612 static int
11613 readtoken(void)
11615 int t;
11616 #if DEBUG
11617 smallint alreadyseen = tokpushback;
11618 #endif
11620 #if ENABLE_ASH_ALIAS
11621 top:
11622 #endif
11624 t = xxreadtoken();
11627 * eat newlines
11629 if (checkkwd & CHKNL) {
11630 while (t == TNL) {
11631 parseheredoc();
11632 t = xxreadtoken();
11636 if (t != TWORD || quoteflag) {
11637 goto out;
11641 * check for keywords
11643 if (checkkwd & CHKKWD) {
11644 const char *const *pp;
11646 pp = findkwd(wordtext);
11647 if (pp) {
11648 lasttoken = t = pp - tokname_array;
11649 TRACE(("keyword %s recognized\n", tokname(t)));
11650 goto out;
11654 if (checkkwd & CHKALIAS) {
11655 #if ENABLE_ASH_ALIAS
11656 struct alias *ap;
11657 ap = lookupalias(wordtext, 1);
11658 if (ap != NULL) {
11659 if (*ap->val) {
11660 pushstring(ap->val, ap);
11662 goto top;
11664 #endif
11666 out:
11667 checkkwd = 0;
11668 #if DEBUG
11669 if (!alreadyseen)
11670 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11671 else
11672 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
11673 #endif
11674 return t;
11677 static char
11678 peektoken(void)
11680 int t;
11682 t = readtoken();
11683 tokpushback = 1;
11684 return tokname_array[t][0];
11688 * Read and parse a command. Returns NEOF on end of file. (NULL is a
11689 * valid parse tree indicating a blank line.)
11691 static union node *
11692 parsecmd(int interact)
11694 int t;
11696 tokpushback = 0;
11697 doprompt = interact;
11698 if (doprompt)
11699 setprompt(doprompt);
11700 needprompt = 0;
11701 t = readtoken();
11702 if (t == TEOF)
11703 return NEOF;
11704 if (t == TNL)
11705 return NULL;
11706 tokpushback = 1;
11707 return list(1);
11711 * Input any here documents.
11713 static void
11714 parseheredoc(void)
11716 struct heredoc *here;
11717 union node *n;
11719 here = heredoclist;
11720 heredoclist = NULL;
11722 while (here) {
11723 if (needprompt) {
11724 setprompt(2);
11726 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
11727 here->eofmark, here->striptabs);
11728 n = stzalloc(sizeof(struct narg));
11729 n->narg.type = NARG;
11730 /*n->narg.next = NULL; - stzalloc did it */
11731 n->narg.text = wordtext;
11732 n->narg.backquote = backquotelist;
11733 here->here->nhere.doc = n;
11734 here = here->next;
11740 * called by editline -- any expansions to the prompt should be added here.
11742 #if ENABLE_ASH_EXPAND_PRMT
11743 static const char *
11744 expandstr(const char *ps)
11746 union node n;
11748 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
11749 * and token processing _can_ alter it (delete NULs etc). */
11750 setinputstring((char *)ps);
11751 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
11752 popfile();
11754 n.narg.type = NARG;
11755 n.narg.next = NULL;
11756 n.narg.text = wordtext;
11757 n.narg.backquote = backquotelist;
11759 expandarg(&n, NULL, 0);
11760 return stackblock();
11762 #endif
11765 * Execute a command or commands contained in a string.
11767 static int
11768 evalstring(char *s, int mask)
11770 union node *n;
11771 struct stackmark smark;
11772 int skip;
11774 setinputstring(s);
11775 setstackmark(&smark);
11777 skip = 0;
11778 while ((n = parsecmd(0)) != NEOF) {
11779 evaltree(n, 0);
11780 popstackmark(&smark);
11781 skip = evalskip;
11782 if (skip)
11783 break;
11785 popfile();
11787 skip &= mask;
11788 evalskip = skip;
11789 return skip;
11793 * The eval command.
11795 static int
11796 evalcmd(int argc UNUSED_PARAM, char **argv)
11798 char *p;
11799 char *concat;
11801 if (argv[1]) {
11802 p = argv[1];
11803 argv += 2;
11804 if (argv[0]) {
11805 STARTSTACKSTR(concat);
11806 for (;;) {
11807 concat = stack_putstr(p, concat);
11808 p = *argv++;
11809 if (p == NULL)
11810 break;
11811 STPUTC(' ', concat);
11813 STPUTC('\0', concat);
11814 p = grabstackstr(concat);
11816 evalstring(p, ~SKIPEVAL);
11819 return exitstatus;
11823 * Read and execute commands. "Top" is nonzero for the top level command
11824 * loop; it turns on prompting if the shell is interactive.
11826 static int
11827 cmdloop(int top)
11829 union node *n;
11830 struct stackmark smark;
11831 int inter;
11832 int numeof = 0;
11834 TRACE(("cmdloop(%d) called\n", top));
11835 for (;;) {
11836 int skip;
11838 setstackmark(&smark);
11839 #if JOBS
11840 if (doing_jobctl)
11841 showjobs(stderr, SHOW_CHANGED);
11842 #endif
11843 inter = 0;
11844 if (iflag && top) {
11845 inter++;
11846 #if ENABLE_ASH_MAIL
11847 chkmail();
11848 #endif
11850 n = parsecmd(inter);
11851 #if DEBUG
11852 showtree(n);
11853 #endif
11854 if (n == NEOF) {
11855 if (!top || numeof >= 50)
11856 break;
11857 if (!stoppedjobs()) {
11858 if (!Iflag)
11859 break;
11860 out2str("\nUse \"exit\" to leave shell.\n");
11862 numeof++;
11863 } else if (nflag == 0) {
11864 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11865 job_warning >>= 1;
11866 numeof = 0;
11867 evaltree(n, 0);
11869 popstackmark(&smark);
11870 skip = evalskip;
11872 if (skip) {
11873 evalskip = 0;
11874 return skip & SKIPEVAL;
11877 return 0;
11881 * Take commands from a file. To be compatible we should do a path
11882 * search for the file, which is necessary to find sub-commands.
11884 static char *
11885 find_dot_file(char *name)
11887 char *fullname;
11888 const char *path = pathval();
11889 struct stat statb;
11891 /* don't try this for absolute or relative paths */
11892 if (strchr(name, '/'))
11893 return name;
11895 /* IIRC standards do not say whether . is to be searched.
11896 * And it is even smaller this way, making it unconditional for now:
11898 if (1) { /* ENABLE_ASH_BASH_COMPAT */
11899 fullname = name;
11900 goto try_cur_dir;
11903 while ((fullname = padvance(&path, name)) != NULL) {
11904 try_cur_dir:
11905 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
11907 * Don't bother freeing here, since it will
11908 * be freed by the caller.
11910 return fullname;
11912 if (fullname != name)
11913 stunalloc(fullname);
11916 /* not found in the PATH */
11917 ash_msg_and_raise_error("%s: not found", name);
11918 /* NOTREACHED */
11921 static int
11922 dotcmd(int argc, char **argv)
11924 struct strlist *sp;
11925 volatile struct shparam saveparam;
11926 int status = 0;
11928 for (sp = cmdenviron; sp; sp = sp->next)
11929 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
11931 if (argv[1]) { /* That's what SVR2 does */
11932 char *fullname = find_dot_file(argv[1]);
11933 argv += 2;
11934 argc -= 2;
11935 if (argc) { /* argc > 0, argv[0] != NULL */
11936 saveparam = shellparam;
11937 shellparam.malloced = 0;
11938 shellparam.nparam = argc;
11939 shellparam.p = argv;
11942 setinputfile(fullname, INPUT_PUSH_FILE);
11943 commandname = fullname;
11944 cmdloop(0);
11945 popfile();
11947 if (argc) {
11948 freeparam(&shellparam);
11949 shellparam = saveparam;
11951 status = exitstatus;
11953 return status;
11956 static int
11957 exitcmd(int argc UNUSED_PARAM, char **argv)
11959 if (stoppedjobs())
11960 return 0;
11961 if (argv[1])
11962 exitstatus = number(argv[1]);
11963 raise_exception(EXEXIT);
11964 /* NOTREACHED */
11968 * Read a file containing shell functions.
11970 static void
11971 readcmdfile(char *name)
11973 setinputfile(name, INPUT_PUSH_FILE);
11974 cmdloop(0);
11975 popfile();
11979 /* ============ find_command inplementation */
11982 * Resolve a command name. If you change this routine, you may have to
11983 * change the shellexec routine as well.
11985 static void
11986 find_command(char *name, struct cmdentry *entry, int act, const char *path)
11988 struct tblentry *cmdp;
11989 int idx;
11990 int prev;
11991 char *fullname;
11992 struct stat statb;
11993 int e;
11994 int updatetbl;
11995 struct builtincmd *bcmd;
11997 /* If name contains a slash, don't use PATH or hash table */
11998 if (strchr(name, '/') != NULL) {
11999 entry->u.index = -1;
12000 if (act & DO_ABS) {
12001 while (stat(name, &statb) < 0) {
12002 #ifdef SYSV
12003 if (errno == EINTR)
12004 continue;
12005 #endif
12006 entry->cmdtype = CMDUNKNOWN;
12007 return;
12010 entry->cmdtype = CMDNORMAL;
12011 return;
12014 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
12016 updatetbl = (path == pathval());
12017 if (!updatetbl) {
12018 act |= DO_ALTPATH;
12019 if (strstr(path, "%builtin") != NULL)
12020 act |= DO_ALTBLTIN;
12023 /* If name is in the table, check answer will be ok */
12024 cmdp = cmdlookup(name, 0);
12025 if (cmdp != NULL) {
12026 int bit;
12028 switch (cmdp->cmdtype) {
12029 default:
12030 #if DEBUG
12031 abort();
12032 #endif
12033 case CMDNORMAL:
12034 bit = DO_ALTPATH;
12035 break;
12036 case CMDFUNCTION:
12037 bit = DO_NOFUNC;
12038 break;
12039 case CMDBUILTIN:
12040 bit = DO_ALTBLTIN;
12041 break;
12043 if (act & bit) {
12044 updatetbl = 0;
12045 cmdp = NULL;
12046 } else if (cmdp->rehash == 0)
12047 /* if not invalidated by cd, we're done */
12048 goto success;
12051 /* If %builtin not in path, check for builtin next */
12052 bcmd = find_builtin(name);
12053 if (bcmd) {
12054 if (IS_BUILTIN_REGULAR(bcmd))
12055 goto builtin_success;
12056 if (act & DO_ALTPATH) {
12057 if (!(act & DO_ALTBLTIN))
12058 goto builtin_success;
12059 } else if (builtinloc <= 0) {
12060 goto builtin_success;
12064 #if ENABLE_FEATURE_SH_STANDALONE
12066 int applet_no = find_applet_by_name(name);
12067 if (applet_no >= 0) {
12068 entry->cmdtype = CMDNORMAL;
12069 entry->u.index = -2 - applet_no;
12070 return;
12073 #endif
12075 /* We have to search path. */
12076 prev = -1; /* where to start */
12077 if (cmdp && cmdp->rehash) { /* doing a rehash */
12078 if (cmdp->cmdtype == CMDBUILTIN)
12079 prev = builtinloc;
12080 else
12081 prev = cmdp->param.index;
12084 e = ENOENT;
12085 idx = -1;
12086 loop:
12087 while ((fullname = padvance(&path, name)) != NULL) {
12088 stunalloc(fullname);
12089 /* NB: code below will still use fullname
12090 * despite it being "unallocated" */
12091 idx++;
12092 if (pathopt) {
12093 if (prefix(pathopt, "builtin")) {
12094 if (bcmd)
12095 goto builtin_success;
12096 continue;
12098 if ((act & DO_NOFUNC)
12099 || !prefix(pathopt, "func")
12100 ) { /* ignore unimplemented options */
12101 continue;
12104 /* if rehash, don't redo absolute path names */
12105 if (fullname[0] == '/' && idx <= prev) {
12106 if (idx < prev)
12107 continue;
12108 TRACE(("searchexec \"%s\": no change\n", name));
12109 goto success;
12111 while (stat(fullname, &statb) < 0) {
12112 #ifdef SYSV
12113 if (errno == EINTR)
12114 continue;
12115 #endif
12116 if (errno != ENOENT && errno != ENOTDIR)
12117 e = errno;
12118 goto loop;
12120 e = EACCES; /* if we fail, this will be the error */
12121 if (!S_ISREG(statb.st_mode))
12122 continue;
12123 if (pathopt) { /* this is a %func directory */
12124 stalloc(strlen(fullname) + 1);
12125 /* NB: stalloc will return space pointed by fullname
12126 * (because we don't have any intervening allocations
12127 * between stunalloc above and this stalloc) */
12128 readcmdfile(fullname);
12129 cmdp = cmdlookup(name, 0);
12130 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12131 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12132 stunalloc(fullname);
12133 goto success;
12135 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12136 if (!updatetbl) {
12137 entry->cmdtype = CMDNORMAL;
12138 entry->u.index = idx;
12139 return;
12141 INT_OFF;
12142 cmdp = cmdlookup(name, 1);
12143 cmdp->cmdtype = CMDNORMAL;
12144 cmdp->param.index = idx;
12145 INT_ON;
12146 goto success;
12149 /* We failed. If there was an entry for this command, delete it */
12150 if (cmdp && updatetbl)
12151 delete_cmd_entry();
12152 if (act & DO_ERR)
12153 ash_msg("%s: %s", name, errmsg(e, "not found"));
12154 entry->cmdtype = CMDUNKNOWN;
12155 return;
12157 builtin_success:
12158 if (!updatetbl) {
12159 entry->cmdtype = CMDBUILTIN;
12160 entry->u.cmd = bcmd;
12161 return;
12163 INT_OFF;
12164 cmdp = cmdlookup(name, 1);
12165 cmdp->cmdtype = CMDBUILTIN;
12166 cmdp->param.cmd = bcmd;
12167 INT_ON;
12168 success:
12169 cmdp->rehash = 0;
12170 entry->cmdtype = cmdp->cmdtype;
12171 entry->u = cmdp->param;
12175 /* ============ trap.c */
12178 * The trap builtin.
12180 static int
12181 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12183 char *action;
12184 char **ap;
12185 int signo;
12187 nextopt(nullstr);
12188 ap = argptr;
12189 if (!*ap) {
12190 for (signo = 0; signo < NSIG; signo++) {
12191 if (trap[signo] != NULL) {
12192 out1fmt("trap -- %s %s\n",
12193 single_quote(trap[signo]),
12194 get_signame(signo));
12197 return 0;
12199 action = NULL;
12200 if (ap[1])
12201 action = *ap++;
12202 while (*ap) {
12203 signo = get_signum(*ap);
12204 if (signo < 0)
12205 ash_msg_and_raise_error("%s: bad trap", *ap);
12206 INT_OFF;
12207 if (action) {
12208 if (LONE_DASH(action))
12209 action = NULL;
12210 else
12211 action = ckstrdup(action);
12213 free(trap[signo]);
12214 trap[signo] = action;
12215 if (signo != 0)
12216 setsignal(signo);
12217 INT_ON;
12218 ap++;
12220 return 0;
12224 /* ============ Builtins */
12226 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
12228 * Lists available builtins
12230 static int
12231 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12233 unsigned col;
12234 unsigned i;
12236 out1fmt("\n"
12237 "Built-in commands:\n"
12238 "------------------\n");
12239 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12240 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12241 builtintab[i].name + 1);
12242 if (col > 60) {
12243 out1fmt("\n");
12244 col = 0;
12247 #if ENABLE_FEATURE_SH_STANDALONE
12249 const char *a = applet_names;
12250 while (*a) {
12251 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12252 if (col > 60) {
12253 out1fmt("\n");
12254 col = 0;
12256 a += strlen(a) + 1;
12259 #endif
12260 out1fmt("\n\n");
12261 return EXIT_SUCCESS;
12263 #endif /* FEATURE_SH_EXTRA_QUIET */
12266 * The export and readonly commands.
12268 static int
12269 exportcmd(int argc UNUSED_PARAM, char **argv)
12271 struct var *vp;
12272 char *name;
12273 const char *p;
12274 char **aptr;
12275 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT;
12277 if (nextopt("p") != 'p') {
12278 aptr = argptr;
12279 name = *aptr;
12280 if (name) {
12281 do {
12282 p = strchr(name, '=');
12283 if (p != NULL) {
12284 p++;
12285 } else {
12286 vp = *findvar(hashvar(name), name);
12287 if (vp) {
12288 vp->flags |= flag;
12289 continue;
12292 setvar(name, p, flag);
12293 } while ((name = *++aptr) != NULL);
12294 return 0;
12297 showvars(argv[0], flag, 0);
12298 return 0;
12302 * Delete a function if it exists.
12304 static void
12305 unsetfunc(const char *name)
12307 struct tblentry *cmdp;
12309 cmdp = cmdlookup(name, 0);
12310 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
12311 delete_cmd_entry();
12315 * The unset builtin command. We unset the function before we unset the
12316 * variable to allow a function to be unset when there is a readonly variable
12317 * with the same name.
12319 static int
12320 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12322 char **ap;
12323 int i;
12324 int flag = 0;
12325 int ret = 0;
12327 while ((i = nextopt("vf")) != '\0') {
12328 flag = i;
12331 for (ap = argptr; *ap; ap++) {
12332 if (flag != 'f') {
12333 i = unsetvar(*ap);
12334 ret |= i;
12335 if (!(i & 2))
12336 continue;
12338 if (flag != 'v')
12339 unsetfunc(*ap);
12341 return ret & 1;
12345 /* setmode.c */
12347 #include <sys/times.h>
12349 static const unsigned char timescmd_str[] ALIGN1 = {
12350 ' ', offsetof(struct tms, tms_utime),
12351 '\n', offsetof(struct tms, tms_stime),
12352 ' ', offsetof(struct tms, tms_cutime),
12353 '\n', offsetof(struct tms, tms_cstime),
12357 static int
12358 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12360 long clk_tck, s, t;
12361 const unsigned char *p;
12362 struct tms buf;
12364 clk_tck = sysconf(_SC_CLK_TCK);
12365 times(&buf);
12367 p = timescmd_str;
12368 do {
12369 t = *(clock_t *)(((char *) &buf) + p[1]);
12370 s = t / clk_tck;
12371 out1fmt("%ldm%ld.%.3lds%c",
12372 s/60, s%60,
12373 ((t - s * clk_tck) * 1000) / clk_tck,
12374 p[0]);
12375 } while (*(p += 2));
12377 return 0;
12380 #if ENABLE_SH_MATH_SUPPORT
12382 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12383 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12385 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12387 static int
12388 letcmd(int argc UNUSED_PARAM, char **argv)
12390 arith_t i;
12392 argv++;
12393 if (!*argv)
12394 ash_msg_and_raise_error("expression expected");
12395 do {
12396 i = ash_arith(*argv);
12397 } while (*++argv);
12399 return !i;
12401 #endif /* SH_MATH_SUPPORT */
12404 /* ============ miscbltin.c
12406 * Miscellaneous builtins.
12409 #undef rflag
12411 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12412 typedef enum __rlimit_resource rlim_t;
12413 #endif
12416 * The read builtin. Options:
12417 * -r Do not interpret '\' specially
12418 * -s Turn off echo (tty only)
12419 * -n NCHARS Read NCHARS max
12420 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12421 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12422 * -u FD Read from given FD instead of fd 0
12423 * This uses unbuffered input, which may be avoidable in some cases.
12424 * TODO: bash also has:
12425 * -a ARRAY Read into array[0],[1],etc
12426 * -d DELIM End on DELIM char, not newline
12427 * -e Use line editing (tty only)
12429 static int
12430 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12432 static const char *const arg_REPLY[] = { "REPLY", NULL };
12434 char **ap;
12435 int backslash;
12436 char c;
12437 int rflag;
12438 char *prompt;
12439 const char *ifs;
12440 char *p;
12441 int startword;
12442 int status;
12443 int i;
12444 int fd = 0;
12445 #if ENABLE_ASH_READ_NCHARS
12446 int nchars = 0; /* if != 0, -n is in effect */
12447 int silent = 0;
12448 struct termios tty, old_tty;
12449 #endif
12450 #if ENABLE_ASH_READ_TIMEOUT
12451 unsigned end_ms = 0;
12452 unsigned timeout = 0;
12453 #endif
12455 rflag = 0;
12456 prompt = NULL;
12457 while ((i = nextopt("p:u:r"
12458 USE_ASH_READ_TIMEOUT("t:")
12459 USE_ASH_READ_NCHARS("n:s")
12460 )) != '\0') {
12461 switch (i) {
12462 case 'p':
12463 prompt = optionarg;
12464 break;
12465 #if ENABLE_ASH_READ_NCHARS
12466 case 'n':
12467 nchars = bb_strtou(optionarg, NULL, 10);
12468 if (nchars < 0 || errno)
12469 ash_msg_and_raise_error("invalid count");
12470 /* nchars == 0: off (bash 3.2 does this too) */
12471 break;
12472 case 's':
12473 silent = 1;
12474 break;
12475 #endif
12476 #if ENABLE_ASH_READ_TIMEOUT
12477 case 't':
12478 timeout = bb_strtou(optionarg, NULL, 10);
12479 if (errno || timeout > UINT_MAX / 2048)
12480 ash_msg_and_raise_error("invalid timeout");
12481 timeout *= 1000;
12482 #if 0 /* even bash have no -t N.NNN support */
12483 ts.tv_sec = bb_strtou(optionarg, &p, 10);
12484 ts.tv_usec = 0;
12485 /* EINVAL means number is ok, but not terminated by NUL */
12486 if (*p == '.' && errno == EINVAL) {
12487 char *p2;
12488 if (*++p) {
12489 int scale;
12490 ts.tv_usec = bb_strtou(p, &p2, 10);
12491 if (errno)
12492 ash_msg_and_raise_error("invalid timeout");
12493 scale = p2 - p;
12494 /* normalize to usec */
12495 if (scale > 6)
12496 ash_msg_and_raise_error("invalid timeout");
12497 while (scale++ < 6)
12498 ts.tv_usec *= 10;
12500 } else if (ts.tv_sec < 0 || errno) {
12501 ash_msg_and_raise_error("invalid timeout");
12503 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
12504 ash_msg_and_raise_error("invalid timeout");
12506 #endif /* if 0 */
12507 break;
12508 #endif
12509 case 'r':
12510 rflag = 1;
12511 break;
12512 case 'u':
12513 fd = bb_strtou(optionarg, NULL, 10);
12514 if (fd < 0 || errno)
12515 ash_msg_and_raise_error("invalid file descriptor");
12516 break;
12517 default:
12518 break;
12521 if (prompt && isatty(fd)) {
12522 out2str(prompt);
12524 ap = argptr;
12525 if (*ap == NULL)
12526 ap = (char**)arg_REPLY;
12527 ifs = bltinlookup("IFS");
12528 if (ifs == NULL)
12529 ifs = defifs;
12530 #if ENABLE_ASH_READ_NCHARS
12531 tcgetattr(fd, &tty);
12532 old_tty = tty;
12533 if (nchars || silent) {
12534 if (nchars) {
12535 tty.c_lflag &= ~ICANON;
12536 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
12538 if (silent) {
12539 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
12541 /* if tcgetattr failed, tcsetattr will fail too.
12542 * Ignoring, it's harmless. */
12543 tcsetattr(fd, TCSANOW, &tty);
12545 #endif
12547 status = 0;
12548 startword = 2;
12549 backslash = 0;
12550 #if ENABLE_ASH_READ_TIMEOUT
12551 if (timeout) /* NB: ensuring end_ms is nonzero */
12552 end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1;
12553 #endif
12554 STARTSTACKSTR(p);
12555 do {
12556 const char *is_ifs;
12558 #if ENABLE_ASH_READ_TIMEOUT
12559 if (end_ms) {
12560 struct pollfd pfd[1];
12561 pfd[0].fd = fd;
12562 pfd[0].events = POLLIN;
12563 timeout = end_ms - (unsigned)(monotonic_us() / 1000);
12564 if ((int)timeout <= 0 /* already late? */
12565 || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
12566 ) { /* timed out! */
12567 #if ENABLE_ASH_READ_NCHARS
12568 tcsetattr(fd, TCSANOW, &old_tty);
12569 #endif
12570 return 1;
12573 #endif
12574 if (nonblock_safe_read(fd, &c, 1) != 1) {
12575 status = 1;
12576 break;
12578 if (c == '\0')
12579 continue;
12580 if (backslash) {
12581 backslash = 0;
12582 if (c != '\n')
12583 goto put;
12584 continue;
12586 if (!rflag && c == '\\') {
12587 backslash = 1;
12588 continue;
12590 if (c == '\n')
12591 break;
12592 /* $IFS splitting */
12593 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */
12594 is_ifs = strchr(ifs, c);
12595 if (startword && is_ifs) {
12596 if (isspace(c))
12597 continue;
12598 /* it is a non-space ifs char */
12599 startword--;
12600 if (startword == 1) /* first one? */
12601 continue; /* yes, it is not next word yet */
12603 startword = 0;
12604 if (ap[1] != NULL && is_ifs) {
12605 const char *beg;
12606 STACKSTRNUL(p);
12607 beg = stackblock();
12608 setvar(*ap, beg, 0);
12609 ap++;
12610 /* can we skip one non-space ifs char? (2: yes) */
12611 startword = isspace(c) ? 2 : 1;
12612 STARTSTACKSTR(p);
12613 continue;
12615 put:
12616 STPUTC(c, p);
12618 /* end of do {} while: */
12619 #if ENABLE_ASH_READ_NCHARS
12620 while (--nchars);
12621 #else
12622 while (1);
12623 #endif
12625 #if ENABLE_ASH_READ_NCHARS
12626 tcsetattr(fd, TCSANOW, &old_tty);
12627 #endif
12629 STACKSTRNUL(p);
12630 /* Remove trailing space ifs chars */
12631 while ((char *)stackblock() <= --p && isspace(*p) && strchr(ifs, *p) != NULL)
12632 *p = '\0';
12633 setvar(*ap, stackblock(), 0);
12634 while (*++ap != NULL)
12635 setvar(*ap, nullstr, 0);
12636 return status;
12639 static int
12640 umaskcmd(int argc UNUSED_PARAM, char **argv)
12642 static const char permuser[3] ALIGN1 = "ugo";
12643 static const char permmode[3] ALIGN1 = "rwx";
12644 static const short permmask[] ALIGN2 = {
12645 S_IRUSR, S_IWUSR, S_IXUSR,
12646 S_IRGRP, S_IWGRP, S_IXGRP,
12647 S_IROTH, S_IWOTH, S_IXOTH
12650 char *ap;
12651 mode_t mask;
12652 int i;
12653 int symbolic_mode = 0;
12655 while (nextopt("S") != '\0') {
12656 symbolic_mode = 1;
12659 INT_OFF;
12660 mask = umask(0);
12661 umask(mask);
12662 INT_ON;
12664 ap = *argptr;
12665 if (ap == NULL) {
12666 if (symbolic_mode) {
12667 char buf[18];
12668 char *p = buf;
12670 for (i = 0; i < 3; i++) {
12671 int j;
12673 *p++ = permuser[i];
12674 *p++ = '=';
12675 for (j = 0; j < 3; j++) {
12676 if ((mask & permmask[3 * i + j]) == 0) {
12677 *p++ = permmode[j];
12680 *p++ = ',';
12682 *--p = 0;
12683 puts(buf);
12684 } else {
12685 out1fmt("%.4o\n", mask);
12687 } else {
12688 if (isdigit((unsigned char) *ap)) {
12689 mask = 0;
12690 do {
12691 if (*ap >= '8' || *ap < '0')
12692 ash_msg_and_raise_error(illnum, argv[1]);
12693 mask = (mask << 3) + (*ap - '0');
12694 } while (*++ap != '\0');
12695 umask(mask);
12696 } else {
12697 mask = ~mask & 0777;
12698 if (!bb_parse_mode(ap, &mask)) {
12699 ash_msg_and_raise_error("illegal mode: %s", ap);
12701 umask(~mask & 0777);
12704 return 0;
12708 * ulimit builtin
12710 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12711 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12712 * ash by J.T. Conklin.
12714 * Public domain.
12717 struct limits {
12718 uint8_t cmd; /* RLIMIT_xxx fit into it */
12719 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
12720 char option;
12723 static const struct limits limits_tbl[] = {
12724 #ifdef RLIMIT_CPU
12725 { RLIMIT_CPU, 0, 't' },
12726 #endif
12727 #ifdef RLIMIT_FSIZE
12728 { RLIMIT_FSIZE, 9, 'f' },
12729 #endif
12730 #ifdef RLIMIT_DATA
12731 { RLIMIT_DATA, 10, 'd' },
12732 #endif
12733 #ifdef RLIMIT_STACK
12734 { RLIMIT_STACK, 10, 's' },
12735 #endif
12736 #ifdef RLIMIT_CORE
12737 { RLIMIT_CORE, 9, 'c' },
12738 #endif
12739 #ifdef RLIMIT_RSS
12740 { RLIMIT_RSS, 10, 'm' },
12741 #endif
12742 #ifdef RLIMIT_MEMLOCK
12743 { RLIMIT_MEMLOCK, 10, 'l' },
12744 #endif
12745 #ifdef RLIMIT_NPROC
12746 { RLIMIT_NPROC, 0, 'p' },
12747 #endif
12748 #ifdef RLIMIT_NOFILE
12749 { RLIMIT_NOFILE, 0, 'n' },
12750 #endif
12751 #ifdef RLIMIT_AS
12752 { RLIMIT_AS, 10, 'v' },
12753 #endif
12754 #ifdef RLIMIT_LOCKS
12755 { RLIMIT_LOCKS, 0, 'w' },
12756 #endif
12758 static const char limits_name[] =
12759 #ifdef RLIMIT_CPU
12760 "time(seconds)" "\0"
12761 #endif
12762 #ifdef RLIMIT_FSIZE
12763 "file(blocks)" "\0"
12764 #endif
12765 #ifdef RLIMIT_DATA
12766 "data(kb)" "\0"
12767 #endif
12768 #ifdef RLIMIT_STACK
12769 "stack(kb)" "\0"
12770 #endif
12771 #ifdef RLIMIT_CORE
12772 "coredump(blocks)" "\0"
12773 #endif
12774 #ifdef RLIMIT_RSS
12775 "memory(kb)" "\0"
12776 #endif
12777 #ifdef RLIMIT_MEMLOCK
12778 "locked memory(kb)" "\0"
12779 #endif
12780 #ifdef RLIMIT_NPROC
12781 "process" "\0"
12782 #endif
12783 #ifdef RLIMIT_NOFILE
12784 "nofiles" "\0"
12785 #endif
12786 #ifdef RLIMIT_AS
12787 "vmemory(kb)" "\0"
12788 #endif
12789 #ifdef RLIMIT_LOCKS
12790 "locks" "\0"
12791 #endif
12794 enum limtype { SOFT = 0x1, HARD = 0x2 };
12796 static void
12797 printlim(enum limtype how, const struct rlimit *limit,
12798 const struct limits *l)
12800 rlim_t val;
12802 val = limit->rlim_max;
12803 if (how & SOFT)
12804 val = limit->rlim_cur;
12806 if (val == RLIM_INFINITY)
12807 out1fmt("unlimited\n");
12808 else {
12809 val >>= l->factor_shift;
12810 out1fmt("%lld\n", (long long) val);
12814 static int
12815 ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12817 int c;
12818 rlim_t val = 0;
12819 enum limtype how = SOFT | HARD;
12820 const struct limits *l;
12821 int set, all = 0;
12822 int optc, what;
12823 struct rlimit limit;
12825 what = 'f';
12826 while ((optc = nextopt("HSa"
12827 #ifdef RLIMIT_CPU
12829 #endif
12830 #ifdef RLIMIT_FSIZE
12832 #endif
12833 #ifdef RLIMIT_DATA
12835 #endif
12836 #ifdef RLIMIT_STACK
12838 #endif
12839 #ifdef RLIMIT_CORE
12841 #endif
12842 #ifdef RLIMIT_RSS
12844 #endif
12845 #ifdef RLIMIT_MEMLOCK
12847 #endif
12848 #ifdef RLIMIT_NPROC
12850 #endif
12851 #ifdef RLIMIT_NOFILE
12853 #endif
12854 #ifdef RLIMIT_AS
12856 #endif
12857 #ifdef RLIMIT_LOCKS
12859 #endif
12860 )) != '\0')
12861 switch (optc) {
12862 case 'H':
12863 how = HARD;
12864 break;
12865 case 'S':
12866 how = SOFT;
12867 break;
12868 case 'a':
12869 all = 1;
12870 break;
12871 default:
12872 what = optc;
12875 for (l = limits_tbl; l->option != what; l++)
12876 continue;
12878 set = *argptr ? 1 : 0;
12879 if (set) {
12880 char *p = *argptr;
12882 if (all || argptr[1])
12883 ash_msg_and_raise_error("too many arguments");
12884 if (strncmp(p, "unlimited\n", 9) == 0)
12885 val = RLIM_INFINITY;
12886 else {
12887 val = (rlim_t) 0;
12889 while ((c = *p++) >= '0' && c <= '9') {
12890 val = (val * 10) + (long)(c - '0');
12891 // val is actually 'unsigned long int' and can't get < 0
12892 if (val < (rlim_t) 0)
12893 break;
12895 if (c)
12896 ash_msg_and_raise_error("bad number");
12897 val <<= l->factor_shift;
12900 if (all) {
12901 const char *lname = limits_name;
12902 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) {
12903 getrlimit(l->cmd, &limit);
12904 out1fmt("%-20s ", lname);
12905 lname += strlen(lname) + 1;
12906 printlim(how, &limit, l);
12908 return 0;
12911 getrlimit(l->cmd, &limit);
12912 if (set) {
12913 if (how & HARD)
12914 limit.rlim_max = val;
12915 if (how & SOFT)
12916 limit.rlim_cur = val;
12917 if (setrlimit(l->cmd, &limit) < 0)
12918 ash_msg_and_raise_error("error setting limit (%m)");
12919 } else {
12920 printlim(how, &limit, l);
12922 return 0;
12925 /* ============ main() and helpers */
12928 * Called to exit the shell.
12930 static void exitshell(void) NORETURN;
12931 static void
12932 exitshell(void)
12934 struct jmploc loc;
12935 char *p;
12936 int status;
12938 status = exitstatus;
12939 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12940 if (setjmp(loc.loc)) {
12941 if (exception_type == EXEXIT)
12942 /* dash bug: it just does _exit(exitstatus) here
12943 * but we have to do setjobctl(0) first!
12944 * (bug is still not fixed in dash-0.5.3 - if you run dash
12945 * under Midnight Commander, on exit from dash MC is backgrounded) */
12946 status = exitstatus;
12947 goto out;
12949 exception_handler = &loc;
12950 p = trap[0];
12951 if (p) {
12952 trap[0] = NULL;
12953 evalstring(p, 0);
12955 flush_stdout_stderr();
12956 out:
12957 setjobctl(0);
12958 _exit(status);
12959 /* NOTREACHED */
12962 static void
12963 init(void)
12965 /* from input.c: */
12966 basepf.next_to_pgetc = basepf.buf = basebuf;
12968 /* from trap.c: */
12969 signal(SIGCHLD, SIG_DFL);
12971 /* from var.c: */
12973 char **envp;
12974 char ppid[sizeof(int)*3 + 1];
12975 const char *p;
12976 struct stat st1, st2;
12978 initvar();
12979 for (envp = environ; envp && *envp; envp++) {
12980 if (strchr(*envp, '=')) {
12981 setvareq(*envp, VEXPORT|VTEXTFIXED);
12985 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid());
12986 setvar("PPID", ppid, 0);
12988 p = lookupvar("PWD");
12989 if (p)
12990 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
12991 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
12992 p = '\0';
12993 setpwd(p, 0);
12998 * Process the shell command line arguments.
13000 static void
13001 procargs(char **argv)
13003 int i;
13004 const char *xminusc;
13005 char **xargv;
13007 xargv = argv;
13008 arg0 = xargv[0];
13009 /* if (xargv[0]) - mmm, this is always true! */
13010 xargv++;
13011 for (i = 0; i < NOPTS; i++)
13012 optlist[i] = 2;
13013 argptr = xargv;
13014 if (options(1)) {
13015 /* it already printed err message */
13016 raise_exception(EXERROR);
13018 xargv = argptr;
13019 xminusc = minusc;
13020 if (*xargv == NULL) {
13021 if (xminusc)
13022 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13023 sflag = 1;
13025 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13026 iflag = 1;
13027 if (mflag == 2)
13028 mflag = iflag;
13029 for (i = 0; i < NOPTS; i++)
13030 if (optlist[i] == 2)
13031 optlist[i] = 0;
13032 #if DEBUG == 2
13033 debug = 1;
13034 #endif
13035 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13036 if (xminusc) {
13037 minusc = *xargv++;
13038 if (*xargv)
13039 goto setarg0;
13040 } else if (!sflag) {
13041 setinputfile(*xargv, 0);
13042 setarg0:
13043 arg0 = *xargv++;
13044 commandname = arg0;
13047 shellparam.p = xargv;
13048 #if ENABLE_ASH_GETOPTS
13049 shellparam.optind = 1;
13050 shellparam.optoff = -1;
13051 #endif
13052 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13053 while (*xargv) {
13054 shellparam.nparam++;
13055 xargv++;
13057 optschanged();
13061 * Read /etc/profile or .profile.
13063 static void
13064 read_profile(const char *name)
13066 int skip;
13068 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13069 return;
13070 skip = cmdloop(0);
13071 popfile();
13072 if (skip)
13073 exitshell();
13077 * This routine is called when an error or an interrupt occurs in an
13078 * interactive shell and control is returned to the main command loop.
13080 static void
13081 reset(void)
13083 /* from eval.c: */
13084 evalskip = 0;
13085 loopnest = 0;
13086 /* from input.c: */
13087 g_parsefile->left_in_buffer = 0;
13088 g_parsefile->left_in_line = 0; /* clear input buffer */
13089 popallfiles();
13090 /* from parser.c: */
13091 tokpushback = 0;
13092 checkkwd = 0;
13093 /* from redir.c: */
13094 clearredir(/*drop:*/ 0);
13097 #if PROFILE
13098 static short profile_buf[16384];
13099 extern int etext();
13100 #endif
13103 * Main routine. We initialize things, parse the arguments, execute
13104 * profiles if we're a login shell, and then call cmdloop to execute
13105 * commands. The setjmp call sets up the location to jump to when an
13106 * exception occurs. When an exception occurs the variable "state"
13107 * is used to figure out how far we had gotten.
13109 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13110 int ash_main(int argc UNUSED_PARAM, char **argv)
13112 const char *shinit;
13113 volatile smallint state;
13114 struct jmploc jmploc;
13115 struct stackmark smark;
13117 /* Initialize global data */
13118 INIT_G_misc();
13119 INIT_G_memstack();
13120 INIT_G_var();
13121 #if ENABLE_ASH_ALIAS
13122 INIT_G_alias();
13123 #endif
13124 INIT_G_cmdtable();
13126 #if PROFILE
13127 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13128 #endif
13130 #if ENABLE_FEATURE_EDITING
13131 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13132 #endif
13133 state = 0;
13134 if (setjmp(jmploc.loc)) {
13135 smallint e;
13136 smallint s;
13138 reset();
13140 e = exception_type;
13141 if (e == EXERROR)
13142 exitstatus = 2;
13143 s = state;
13144 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13145 exitshell();
13146 if (e == EXINT)
13147 outcslow('\n', stderr);
13149 popstackmark(&smark);
13150 FORCE_INT_ON; /* enable interrupts */
13151 if (s == 1)
13152 goto state1;
13153 if (s == 2)
13154 goto state2;
13155 if (s == 3)
13156 goto state3;
13157 goto state4;
13159 exception_handler = &jmploc;
13160 #if DEBUG
13161 opentrace();
13162 TRACE(("Shell args: "));
13163 trace_puts_args(argv);
13164 #endif
13165 rootpid = getpid();
13167 #if ENABLE_ASH_RANDOM_SUPPORT
13168 /* Can use monotonic_ns() for better randomness but for now it is
13169 * not used anywhere else in busybox... so avoid bloat */
13170 random_galois_LFSR = random_LCG = rootpid + monotonic_us();
13171 #endif
13172 init();
13173 setstackmark(&smark);
13174 procargs(argv);
13176 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13177 if (iflag) {
13178 const char *hp = lookupvar("HISTFILE");
13180 if (hp == NULL) {
13181 hp = lookupvar("HOME");
13182 if (hp != NULL) {
13183 char *defhp = concat_path_file(hp, ".ash_history");
13184 setvar("HISTFILE", defhp, 0);
13185 free(defhp);
13189 #endif
13190 if (/* argv[0] && */ argv[0][0] == '-')
13191 isloginsh = 1;
13192 if (isloginsh) {
13193 state = 1;
13194 read_profile("/etc/profile");
13195 state1:
13196 state = 2;
13197 read_profile(".profile");
13199 state2:
13200 state = 3;
13201 if (
13202 #ifndef linux
13203 getuid() == geteuid() && getgid() == getegid() &&
13204 #endif
13205 iflag
13207 shinit = lookupvar("ENV");
13208 if (shinit != NULL && *shinit != '\0') {
13209 read_profile(shinit);
13212 state3:
13213 state = 4;
13214 if (minusc) {
13215 /* evalstring pushes parsefile stack.
13216 * Ensure we don't falsely claim that 0 (stdin)
13217 * is one of stacked source fds.
13218 * Testcase: ash -c 'exec 1>&0' must not complain. */
13219 if (!sflag)
13220 g_parsefile->fd = -1;
13221 evalstring(minusc, 0);
13224 if (sflag || minusc == NULL) {
13225 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13226 if (iflag) {
13227 const char *hp = lookupvar("HISTFILE");
13228 if (hp)
13229 line_input_state->hist_file = hp;
13231 #endif
13232 state4: /* XXX ??? - why isn't this before the "if" statement */
13233 cmdloop(1);
13235 #if PROFILE
13236 monitor(0);
13237 #endif
13238 #ifdef GPROF
13240 extern void _mcleanup(void);
13241 _mcleanup();
13243 #endif
13244 exitshell();
13245 /* NOTREACHED */
13250 * Copyright (c) 1989, 1991, 1993, 1994
13251 * The Regents of the University of California. All rights reserved.
13253 * This code is derived from software contributed to Berkeley by
13254 * Kenneth Almquist.
13256 * Redistribution and use in source and binary forms, with or without
13257 * modification, are permitted provided that the following conditions
13258 * are met:
13259 * 1. Redistributions of source code must retain the above copyright
13260 * notice, this list of conditions and the following disclaimer.
13261 * 2. Redistributions in binary form must reproduce the above copyright
13262 * notice, this list of conditions and the following disclaimer in the
13263 * documentation and/or other materials provided with the distribution.
13264 * 3. Neither the name of the University nor the names of its contributors
13265 * may be used to endorse or promote products derived from this software
13266 * without specific prior written permission.
13268 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13269 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13270 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13271 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13272 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13273 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13274 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13275 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13276 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13277 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13278 * SUCH DAMAGE.