Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / busybox / shell / ash.c
blob31fbc550a62532ecb99a831a71ae7c31b7e2c312
1 /* vi: set sw=4 ts=4: */
2 /*
3 * ash shell port for busybox
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
8 * Original BSD copyright notice is retained at the end of this file.
10 * Copyright (c) 1989, 1991, 1993, 1994
11 * The Regents of the University of California. All rights reserved.
13 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
14 * was re-ported from NetBSD and debianized.
16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
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 (DEBUG is 1 and "set -o debug" was executed),
27 * debugging info will be written to ./trace and a quit signal
28 * will generate a core dump.
30 #define DEBUG 0
31 /* Tweak debug output verbosity here */
32 #define DEBUG_TIME 0
33 #define DEBUG_PID 1
34 #define DEBUG_SIG 1
36 #define PROFILE 0
38 #define JOBS ENABLE_ASH_JOB_CONTROL
40 #include <paths.h>
41 #include <setjmp.h>
42 #include <fnmatch.h>
43 #include <sys/times.h>
45 #include "busybox.h" /* for applet_names */
46 #include "unicode.h"
48 #include "shell_common.h"
49 #if ENABLE_SH_MATH_SUPPORT
50 # include "math.h"
51 #endif
52 #if ENABLE_ASH_RANDOM_SUPPORT
53 # include "random.h"
54 #else
55 # define CLEAR_RANDOM_T(rnd) ((void)0)
56 #endif
58 #include "NUM_APPLETS.h"
59 #if NUM_APPLETS == 1
60 /* STANDALONE does not make sense, and won't compile */
61 # undef CONFIG_FEATURE_SH_STANDALONE
62 # undef ENABLE_FEATURE_SH_STANDALONE
63 # undef IF_FEATURE_SH_STANDALONE
64 # undef IF_NOT_FEATURE_SH_STANDALONE
65 # define ENABLE_FEATURE_SH_STANDALONE 0
66 # define IF_FEATURE_SH_STANDALONE(...)
67 # define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
68 #endif
70 #ifndef PIPE_BUF
71 # define PIPE_BUF 4096 /* amount of buffering in a pipe */
72 #endif
74 #if !BB_MMU
75 # error "Do not even bother, ash will not run on NOMMU machine"
76 #endif
78 //config:config ASH
79 //config: bool "ash"
80 //config: default y
81 //config: depends on !NOMMU
82 //config: help
83 //config: Tha 'ash' shell adds about 60k in the default configuration and is
84 //config: the most complete and most pedantically correct shell included with
85 //config: busybox. This shell is actually a derivative of the Debian 'dash'
86 //config: shell (by Herbert Xu), which was created by porting the 'ash' shell
87 //config: (written by Kenneth Almquist) from NetBSD.
88 //config:
89 //config:config ASH_BASH_COMPAT
90 //config: bool "bash-compatible extensions"
91 //config: default y
92 //config: depends on ASH
93 //config: help
94 //config: Enable bash-compatible extensions.
95 //config:
96 //config:config ASH_IDLE_TIMEOUT
97 //config: bool "Idle timeout variable"
98 //config: default n
99 //config: depends on ASH
100 //config: help
101 //config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
102 //config:
103 //config:config ASH_JOB_CONTROL
104 //config: bool "Job control"
105 //config: default y
106 //config: depends on ASH
107 //config: help
108 //config: Enable job control in the ash shell.
109 //config:
110 //config:config ASH_ALIAS
111 //config: bool "Alias support"
112 //config: default y
113 //config: depends on ASH
114 //config: help
115 //config: Enable alias support in the ash shell.
116 //config:
117 //config:config ASH_GETOPTS
118 //config: bool "Builtin getopt to parse positional parameters"
119 //config: default y
120 //config: depends on ASH
121 //config: help
122 //config: Enable support for getopts builtin in ash.
123 //config:
124 //config:config ASH_BUILTIN_ECHO
125 //config: bool "Builtin version of 'echo'"
126 //config: default y
127 //config: depends on ASH
128 //config: help
129 //config: Enable support for echo builtin in ash.
130 //config:
131 //config:config ASH_BUILTIN_PRINTF
132 //config: bool "Builtin version of 'printf'"
133 //config: default y
134 //config: depends on ASH
135 //config: help
136 //config: Enable support for printf builtin in ash.
137 //config:
138 //config:config ASH_BUILTIN_TEST
139 //config: bool "Builtin version of 'test'"
140 //config: default y
141 //config: depends on ASH
142 //config: help
143 //config: Enable support for test builtin in ash.
144 //config:
145 //config:config ASH_CMDCMD
146 //config: bool "'command' command to override shell builtins"
147 //config: default y
148 //config: depends on ASH
149 //config: help
150 //config: Enable support for the ash 'command' builtin, which allows
151 //config: you to run the specified command with the specified arguments,
152 //config: even when there is an ash builtin command with the same name.
153 //config:
154 //config:config ASH_MAIL
155 //config: bool "Check for new mail on interactive shells"
156 //config: default n
157 //config: depends on ASH
158 //config: help
159 //config: Enable "check for new mail" function in the ash shell.
160 //config:
161 //config:config ASH_OPTIMIZE_FOR_SIZE
162 //config: bool "Optimize for size instead of speed"
163 //config: default y
164 //config: depends on ASH
165 //config: help
166 //config: Compile ash for reduced size at the price of speed.
167 //config:
168 //config:config ASH_RANDOM_SUPPORT
169 //config: bool "Pseudorandom generator and $RANDOM variable"
170 //config: default y
171 //config: depends on ASH
172 //config: help
173 //config: Enable pseudorandom generator and dynamic variable "$RANDOM".
174 //config: Each read of "$RANDOM" will generate a new pseudorandom value.
175 //config: You can reset the generator by using a specified start value.
176 //config: After "unset RANDOM" the generator will switch off and this
177 //config: variable will no longer have special treatment.
178 //config:
179 //config:config ASH_EXPAND_PRMT
180 //config: bool "Expand prompt string"
181 //config: default y
182 //config: depends on ASH
183 //config: help
184 //config: "PS#" may contain volatile content, such as backquote commands.
185 //config: This option recreates the prompt string from the environment
186 //config: variable each time it is displayed.
187 //config:
189 //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
190 //applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh))
191 //applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash))
193 //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
194 //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
197 /* ============ Hash table sizes. Configurable. */
199 #define VTABSIZE 39
200 #define ATABSIZE 39
201 #define CMDTABLESIZE 31 /* should be prime */
204 /* ============ Shell options */
206 static const char *const optletters_optnames[] = {
207 "e" "errexit",
208 "f" "noglob",
209 "I" "ignoreeof",
210 "i" "interactive",
211 "m" "monitor",
212 "n" "noexec",
213 "s" "stdin",
214 "x" "xtrace",
215 "v" "verbose",
216 "C" "noclobber",
217 "a" "allexport",
218 "b" "notify",
219 "u" "nounset",
220 "\0" "vi"
221 #if ENABLE_ASH_BASH_COMPAT
222 ,"\0" "pipefail"
223 #endif
224 #if DEBUG
225 ,"\0" "nolog"
226 ,"\0" "debug"
227 #endif
230 #define optletters(n) optletters_optnames[n][0]
231 #define optnames(n) (optletters_optnames[n] + 1)
233 enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
236 /* ============ Misc data */
238 #define msg_illnum "Illegal number: %s"
241 * We enclose jmp_buf in a structure so that we can declare pointers to
242 * jump locations. The global variable handler contains the location to
243 * jump to when an exception occurs, and the global variable exception_type
244 * contains a code identifying the exception. To implement nested
245 * exception handlers, the user should save the value of handler on entry
246 * to an inner scope, set handler to point to a jmploc structure for the
247 * inner scope, and restore handler on exit from the scope.
249 struct jmploc {
250 jmp_buf loc;
253 struct globals_misc {
254 /* pid of main shell */
255 int rootpid;
256 /* shell level: 0 for the main shell, 1 for its children, and so on */
257 int shlvl;
258 #define rootshell (!shlvl)
259 char *minusc; /* argument to -c option */
261 char *curdir; // = nullstr; /* current working directory */
262 char *physdir; // = nullstr; /* physical working directory */
264 char *arg0; /* value of $0 */
266 struct jmploc *exception_handler;
268 volatile int suppress_int; /* counter */
269 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
270 /* last pending signal */
271 volatile /*sig_atomic_t*/ smallint pending_sig;
272 smallint exception_type; /* kind of exception (0..5) */
273 /* exceptions */
274 #define EXINT 0 /* SIGINT received */
275 #define EXERROR 1 /* a generic error */
276 #define EXSHELLPROC 2 /* execute a shell procedure */
277 #define EXEXEC 3 /* command execution failed */
278 #define EXEXIT 4 /* exit the shell */
279 #define EXSIG 5 /* trapped signal in wait(1) */
281 smallint isloginsh;
282 char nullstr[1]; /* zero length string */
284 char optlist[NOPTS];
285 #define eflag optlist[0]
286 #define fflag optlist[1]
287 #define Iflag optlist[2]
288 #define iflag optlist[3]
289 #define mflag optlist[4]
290 #define nflag optlist[5]
291 #define sflag optlist[6]
292 #define xflag optlist[7]
293 #define vflag optlist[8]
294 #define Cflag optlist[9]
295 #define aflag optlist[10]
296 #define bflag optlist[11]
297 #define uflag optlist[12]
298 #define viflag optlist[13]
299 #if ENABLE_ASH_BASH_COMPAT
300 # define pipefail optlist[14]
301 #else
302 # define pipefail 0
303 #endif
304 #if DEBUG
305 # define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
306 # define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
307 #endif
309 /* trap handler commands */
311 * Sigmode records the current value of the signal handlers for the various
312 * modes. A value of zero means that the current handler is not known.
313 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
315 char sigmode[NSIG - 1];
316 #define S_DFL 1 /* default signal handling (SIG_DFL) */
317 #define S_CATCH 2 /* signal is caught */
318 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
319 #define S_HARD_IGN 4 /* signal is ignored permenantly */
321 /* indicates specified signal received */
322 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
323 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
324 char *trap[NSIG];
325 char **trap_ptr; /* used only by "trap hack" */
327 /* Rarely referenced stuff */
328 #if ENABLE_ASH_RANDOM_SUPPORT
329 random_t random_gen;
330 #endif
331 pid_t backgndpid; /* pid of last background process */
332 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
334 extern struct globals_misc *const ash_ptr_to_globals_misc;
335 #define G_misc (*ash_ptr_to_globals_misc)
336 #define rootpid (G_misc.rootpid )
337 #define shlvl (G_misc.shlvl )
338 #define minusc (G_misc.minusc )
339 #define curdir (G_misc.curdir )
340 #define physdir (G_misc.physdir )
341 #define arg0 (G_misc.arg0 )
342 #define exception_handler (G_misc.exception_handler)
343 #define exception_type (G_misc.exception_type )
344 #define suppress_int (G_misc.suppress_int )
345 #define pending_int (G_misc.pending_int )
346 #define pending_sig (G_misc.pending_sig )
347 #define isloginsh (G_misc.isloginsh )
348 #define nullstr (G_misc.nullstr )
349 #define optlist (G_misc.optlist )
350 #define sigmode (G_misc.sigmode )
351 #define gotsig (G_misc.gotsig )
352 #define may_have_traps (G_misc.may_have_traps )
353 #define trap (G_misc.trap )
354 #define trap_ptr (G_misc.trap_ptr )
355 #define random_gen (G_misc.random_gen )
356 #define backgndpid (G_misc.backgndpid )
357 #define job_warning (G_misc.job_warning)
358 #define INIT_G_misc() do { \
359 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
360 barrier(); \
361 curdir = nullstr; \
362 physdir = nullstr; \
363 trap_ptr = trap; \
364 } while (0)
367 /* ============ DEBUG */
368 #if DEBUG
369 static void trace_printf(const char *fmt, ...);
370 static void trace_vprintf(const char *fmt, va_list va);
371 # define TRACE(param) trace_printf param
372 # define TRACEV(param) trace_vprintf param
373 # define close(fd) do { \
374 int dfd = (fd); \
375 if (close(dfd) < 0) \
376 bb_error_msg("bug on %d: closing %d(0x%x)", \
377 __LINE__, dfd, dfd); \
378 } while (0)
379 #else
380 # define TRACE(param)
381 # define TRACEV(param)
382 #endif
385 /* ============ Utility functions */
386 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
388 static int isdigit_str9(const char *str)
390 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
391 while (--maxlen && isdigit(*str))
392 str++;
393 return (*str == '\0');
396 static const char *var_end(const char *var)
398 while (*var)
399 if (*var++ == '=')
400 break;
401 return var;
405 /* ============ Interrupts / exceptions */
407 static void exitshell(void) NORETURN;
410 * These macros allow the user to suspend the handling of interrupt signals
411 * over a period of time. This is similar to SIGHOLD or to sigblock, but
412 * much more efficient and portable. (But hacking the kernel is so much
413 * more fun than worrying about efficiency and portability. :-))
415 #define INT_OFF do { \
416 suppress_int++; \
417 xbarrier(); \
418 } while (0)
421 * Called to raise an exception. Since C doesn't include exceptions, we
422 * just do a longjmp to the exception handler. The type of exception is
423 * stored in the global variable "exception_type".
425 static void raise_exception(int) NORETURN;
426 static void
427 raise_exception(int e)
429 #if DEBUG
430 if (exception_handler == NULL)
431 abort();
432 #endif
433 INT_OFF;
434 exception_type = e;
435 longjmp(exception_handler->loc, 1);
437 #if DEBUG
438 #define raise_exception(e) do { \
439 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
440 raise_exception(e); \
441 } while (0)
442 #endif
445 * Called from trap.c when a SIGINT is received. (If the user specifies
446 * that SIGINT is to be trapped or ignored using the trap builtin, then
447 * this routine is not called.) Suppressint is nonzero when interrupts
448 * are held using the INT_OFF macro. (The test for iflag is just
449 * defensive programming.)
451 static void raise_interrupt(void) NORETURN;
452 static void
453 raise_interrupt(void)
455 int ex_type;
457 pending_int = 0;
458 /* Signal is not automatically unmasked after it is raised,
459 * do it ourself - unmask all signals */
460 sigprocmask_allsigs(SIG_UNBLOCK);
461 /* pending_sig = 0; - now done in signal_handler() */
463 ex_type = EXSIG;
464 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
465 if (!(rootshell && iflag)) {
466 /* Kill ourself with SIGINT */
467 signal(SIGINT, SIG_DFL);
468 raise(SIGINT);
470 ex_type = EXINT;
472 raise_exception(ex_type);
473 /* NOTREACHED */
475 #if DEBUG
476 #define raise_interrupt() do { \
477 TRACE(("raising interrupt on line %d\n", __LINE__)); \
478 raise_interrupt(); \
479 } while (0)
480 #endif
482 static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
483 int_on(void)
485 xbarrier();
486 if (--suppress_int == 0 && pending_int) {
487 raise_interrupt();
490 #define INT_ON int_on()
491 static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
492 force_int_on(void)
494 xbarrier();
495 suppress_int = 0;
496 if (pending_int)
497 raise_interrupt();
499 #define FORCE_INT_ON force_int_on()
501 #define SAVE_INT(v) ((v) = suppress_int)
503 #define RESTORE_INT(v) do { \
504 xbarrier(); \
505 suppress_int = (v); \
506 if (suppress_int == 0 && pending_int) \
507 raise_interrupt(); \
508 } while (0)
511 /* ============ Stdout/stderr output */
513 static void
514 outstr(const char *p, FILE *file)
516 INT_OFF;
517 fputs(p, file);
518 INT_ON;
521 static void
522 flush_stdout_stderr(void)
524 INT_OFF;
525 fflush_all();
526 INT_ON;
529 static void
530 outcslow(int c, FILE *dest)
532 INT_OFF;
533 putc(c, dest);
534 fflush(dest);
535 INT_ON;
538 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
539 static int
540 out1fmt(const char *fmt, ...)
542 va_list ap;
543 int r;
545 INT_OFF;
546 va_start(ap, fmt);
547 r = vprintf(fmt, ap);
548 va_end(ap);
549 INT_ON;
550 return r;
553 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
554 static int
555 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
557 va_list ap;
558 int ret;
560 va_start(ap, fmt);
561 INT_OFF;
562 ret = vsnprintf(outbuf, length, fmt, ap);
563 va_end(ap);
564 INT_ON;
565 return ret;
568 static void
569 out1str(const char *p)
571 outstr(p, stdout);
574 static void
575 out2str(const char *p)
577 outstr(p, stderr);
578 flush_stdout_stderr();
582 /* ============ Parser structures */
584 /* control characters in argument strings */
585 #define CTL_FIRST CTLESC
586 #define CTLESC ((unsigned char)'\201') /* escape next character */
587 #define CTLVAR ((unsigned char)'\202') /* variable defn */
588 #define CTLENDVAR ((unsigned char)'\203')
589 #define CTLBACKQ ((unsigned char)'\204')
590 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
591 /* CTLBACKQ | CTLQUOTE == '\205' */
592 #define CTLARI ((unsigned char)'\206') /* arithmetic expression */
593 #define CTLENDARI ((unsigned char)'\207')
594 #define CTLQUOTEMARK ((unsigned char)'\210')
595 #define CTL_LAST CTLQUOTEMARK
597 /* variable substitution byte (follows CTLVAR) */
598 #define VSTYPE 0x0f /* type of variable substitution */
599 #define VSNUL 0x10 /* colon--treat the empty string as unset */
600 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
602 /* values of VSTYPE field */
603 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
604 #define VSMINUS 0x2 /* ${var-text} */
605 #define VSPLUS 0x3 /* ${var+text} */
606 #define VSQUESTION 0x4 /* ${var?message} */
607 #define VSASSIGN 0x5 /* ${var=text} */
608 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
609 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
610 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
611 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
612 #define VSLENGTH 0xa /* ${#var} */
613 #if ENABLE_ASH_BASH_COMPAT
614 #define VSSUBSTR 0xc /* ${var:position:length} */
615 #define VSREPLACE 0xd /* ${var/pattern/replacement} */
616 #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
617 #endif
619 static const char dolatstr[] ALIGN1 = {
620 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
623 #define NCMD 0
624 #define NPIPE 1
625 #define NREDIR 2
626 #define NBACKGND 3
627 #define NSUBSHELL 4
628 #define NAND 5
629 #define NOR 6
630 #define NSEMI 7
631 #define NIF 8
632 #define NWHILE 9
633 #define NUNTIL 10
634 #define NFOR 11
635 #define NCASE 12
636 #define NCLIST 13
637 #define NDEFUN 14
638 #define NARG 15
639 #define NTO 16
640 #if ENABLE_ASH_BASH_COMPAT
641 #define NTO2 17
642 #endif
643 #define NCLOBBER 18
644 #define NFROM 19
645 #define NFROMTO 20
646 #define NAPPEND 21
647 #define NTOFD 22
648 #define NFROMFD 23
649 #define NHERE 24
650 #define NXHERE 25
651 #define NNOT 26
652 #define N_NUMBER 27
654 union node;
656 struct ncmd {
657 smallint type; /* Nxxxx */
658 union node *assign;
659 union node *args;
660 union node *redirect;
663 struct npipe {
664 smallint type;
665 smallint pipe_backgnd;
666 struct nodelist *cmdlist;
669 struct nredir {
670 smallint type;
671 union node *n;
672 union node *redirect;
675 struct nbinary {
676 smallint type;
677 union node *ch1;
678 union node *ch2;
681 struct nif {
682 smallint type;
683 union node *test;
684 union node *ifpart;
685 union node *elsepart;
688 struct nfor {
689 smallint type;
690 union node *args;
691 union node *body;
692 char *var;
695 struct ncase {
696 smallint type;
697 union node *expr;
698 union node *cases;
701 struct nclist {
702 smallint type;
703 union node *next;
704 union node *pattern;
705 union node *body;
708 struct narg {
709 smallint type;
710 union node *next;
711 char *text;
712 struct nodelist *backquote;
715 /* nfile and ndup layout must match!
716 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
717 * that it is actually NTO2 (>&file), and change its type.
719 struct nfile {
720 smallint type;
721 union node *next;
722 int fd;
723 int _unused_dupfd;
724 union node *fname;
725 char *expfname;
728 struct ndup {
729 smallint type;
730 union node *next;
731 int fd;
732 int dupfd;
733 union node *vname;
734 char *_unused_expfname;
737 struct nhere {
738 smallint type;
739 union node *next;
740 int fd;
741 union node *doc;
744 struct nnot {
745 smallint type;
746 union node *com;
749 union node {
750 smallint type;
751 struct ncmd ncmd;
752 struct npipe npipe;
753 struct nredir nredir;
754 struct nbinary nbinary;
755 struct nif nif;
756 struct nfor nfor;
757 struct ncase ncase;
758 struct nclist nclist;
759 struct narg narg;
760 struct nfile nfile;
761 struct ndup ndup;
762 struct nhere nhere;
763 struct nnot nnot;
767 * NODE_EOF is returned by parsecmd when it encounters an end of file.
768 * It must be distinct from NULL.
770 #define NODE_EOF ((union node *) -1L)
772 struct nodelist {
773 struct nodelist *next;
774 union node *n;
777 struct funcnode {
778 int count;
779 union node n;
783 * Free a parse tree.
785 static void
786 freefunc(struct funcnode *f)
788 if (f && --f->count < 0)
789 free(f);
793 /* ============ Debugging output */
795 #if DEBUG
797 static FILE *tracefile;
799 static void
800 trace_printf(const char *fmt, ...)
802 va_list va;
804 if (debug != 1)
805 return;
806 if (DEBUG_TIME)
807 fprintf(tracefile, "%u ", (int) time(NULL));
808 if (DEBUG_PID)
809 fprintf(tracefile, "[%u] ", (int) getpid());
810 if (DEBUG_SIG)
811 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
812 va_start(va, fmt);
813 vfprintf(tracefile, fmt, va);
814 va_end(va);
817 static void
818 trace_vprintf(const char *fmt, va_list va)
820 if (debug != 1)
821 return;
822 if (DEBUG_TIME)
823 fprintf(tracefile, "%u ", (int) time(NULL));
824 if (DEBUG_PID)
825 fprintf(tracefile, "[%u] ", (int) getpid());
826 if (DEBUG_SIG)
827 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
828 vfprintf(tracefile, fmt, va);
831 static void
832 trace_puts(const char *s)
834 if (debug != 1)
835 return;
836 fputs(s, tracefile);
839 static void
840 trace_puts_quoted(char *s)
842 char *p;
843 char c;
845 if (debug != 1)
846 return;
847 putc('"', tracefile);
848 for (p = s; *p; p++) {
849 switch ((unsigned char)*p) {
850 case '\n': c = 'n'; goto backslash;
851 case '\t': c = 't'; goto backslash;
852 case '\r': c = 'r'; goto backslash;
853 case '\"': c = '\"'; goto backslash;
854 case '\\': c = '\\'; goto backslash;
855 case CTLESC: c = 'e'; goto backslash;
856 case CTLVAR: c = 'v'; goto backslash;
857 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
858 case CTLBACKQ: c = 'q'; goto backslash;
859 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
860 backslash:
861 putc('\\', tracefile);
862 putc(c, tracefile);
863 break;
864 default:
865 if (*p >= ' ' && *p <= '~')
866 putc(*p, tracefile);
867 else {
868 putc('\\', tracefile);
869 putc((*p >> 6) & 03, tracefile);
870 putc((*p >> 3) & 07, tracefile);
871 putc(*p & 07, tracefile);
873 break;
876 putc('"', tracefile);
879 static void
880 trace_puts_args(char **ap)
882 if (debug != 1)
883 return;
884 if (!*ap)
885 return;
886 while (1) {
887 trace_puts_quoted(*ap);
888 if (!*++ap) {
889 putc('\n', tracefile);
890 break;
892 putc(' ', tracefile);
896 static void
897 opentrace(void)
899 char s[100];
900 #ifdef O_APPEND
901 int flags;
902 #endif
904 if (debug != 1) {
905 if (tracefile)
906 fflush(tracefile);
907 /* leave open because libedit might be using it */
908 return;
910 strcpy(s, "./trace");
911 if (tracefile) {
912 if (!freopen(s, "a", tracefile)) {
913 fprintf(stderr, "Can't re-open %s\n", s);
914 debug = 0;
915 return;
917 } else {
918 tracefile = fopen(s, "a");
919 if (tracefile == NULL) {
920 fprintf(stderr, "Can't open %s\n", s);
921 debug = 0;
922 return;
925 #ifdef O_APPEND
926 flags = fcntl(fileno(tracefile), F_GETFL);
927 if (flags >= 0)
928 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
929 #endif
930 setlinebuf(tracefile);
931 fputs("\nTracing started.\n", tracefile);
934 static void
935 indent(int amount, char *pfx, FILE *fp)
937 int i;
939 for (i = 0; i < amount; i++) {
940 if (pfx && i == amount - 1)
941 fputs(pfx, fp);
942 putc('\t', fp);
946 /* little circular references here... */
947 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
949 static void
950 sharg(union node *arg, FILE *fp)
952 char *p;
953 struct nodelist *bqlist;
954 unsigned char subtype;
956 if (arg->type != NARG) {
957 out1fmt("<node type %d>\n", arg->type);
958 abort();
960 bqlist = arg->narg.backquote;
961 for (p = arg->narg.text; *p; p++) {
962 switch ((unsigned char)*p) {
963 case CTLESC:
964 p++;
965 putc(*p, fp);
966 break;
967 case CTLVAR:
968 putc('$', fp);
969 putc('{', fp);
970 subtype = *++p;
971 if (subtype == VSLENGTH)
972 putc('#', fp);
974 while (*p != '=') {
975 putc(*p, fp);
976 p++;
979 if (subtype & VSNUL)
980 putc(':', fp);
982 switch (subtype & VSTYPE) {
983 case VSNORMAL:
984 putc('}', fp);
985 break;
986 case VSMINUS:
987 putc('-', fp);
988 break;
989 case VSPLUS:
990 putc('+', fp);
991 break;
992 case VSQUESTION:
993 putc('?', fp);
994 break;
995 case VSASSIGN:
996 putc('=', fp);
997 break;
998 case VSTRIMLEFT:
999 putc('#', fp);
1000 break;
1001 case VSTRIMLEFTMAX:
1002 putc('#', fp);
1003 putc('#', fp);
1004 break;
1005 case VSTRIMRIGHT:
1006 putc('%', fp);
1007 break;
1008 case VSTRIMRIGHTMAX:
1009 putc('%', fp);
1010 putc('%', fp);
1011 break;
1012 case VSLENGTH:
1013 break;
1014 default:
1015 out1fmt("<subtype %d>", subtype);
1017 break;
1018 case CTLENDVAR:
1019 putc('}', fp);
1020 break;
1021 case CTLBACKQ:
1022 case CTLBACKQ|CTLQUOTE:
1023 putc('$', fp);
1024 putc('(', fp);
1025 shtree(bqlist->n, -1, NULL, fp);
1026 putc(')', fp);
1027 break;
1028 default:
1029 putc(*p, fp);
1030 break;
1035 static void
1036 shcmd(union node *cmd, FILE *fp)
1038 union node *np;
1039 int first;
1040 const char *s;
1041 int dftfd;
1043 first = 1;
1044 for (np = cmd->ncmd.args; np; np = np->narg.next) {
1045 if (!first)
1046 putc(' ', fp);
1047 sharg(np, fp);
1048 first = 0;
1050 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
1051 if (!first)
1052 putc(' ', fp);
1053 dftfd = 0;
1054 switch (np->nfile.type) {
1055 case NTO: s = ">>"+1; dftfd = 1; break;
1056 case NCLOBBER: s = ">|"; dftfd = 1; break;
1057 case NAPPEND: s = ">>"; dftfd = 1; break;
1058 #if ENABLE_ASH_BASH_COMPAT
1059 case NTO2:
1060 #endif
1061 case NTOFD: s = ">&"; dftfd = 1; break;
1062 case NFROM: s = "<"; break;
1063 case NFROMFD: s = "<&"; break;
1064 case NFROMTO: s = "<>"; break;
1065 default: s = "*error*"; break;
1067 if (np->nfile.fd != dftfd)
1068 fprintf(fp, "%d", np->nfile.fd);
1069 fputs(s, fp);
1070 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1071 fprintf(fp, "%d", np->ndup.dupfd);
1072 } else {
1073 sharg(np->nfile.fname, fp);
1075 first = 0;
1079 static void
1080 shtree(union node *n, int ind, char *pfx, FILE *fp)
1082 struct nodelist *lp;
1083 const char *s;
1085 if (n == NULL)
1086 return;
1088 indent(ind, pfx, fp);
1090 if (n == NODE_EOF) {
1091 fputs("<EOF>", fp);
1092 return;
1095 switch (n->type) {
1096 case NSEMI:
1097 s = "; ";
1098 goto binop;
1099 case NAND:
1100 s = " && ";
1101 goto binop;
1102 case NOR:
1103 s = " || ";
1104 binop:
1105 shtree(n->nbinary.ch1, ind, NULL, fp);
1106 /* if (ind < 0) */
1107 fputs(s, fp);
1108 shtree(n->nbinary.ch2, ind, NULL, fp);
1109 break;
1110 case NCMD:
1111 shcmd(n, fp);
1112 if (ind >= 0)
1113 putc('\n', fp);
1114 break;
1115 case NPIPE:
1116 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
1117 shtree(lp->n, 0, NULL, fp);
1118 if (lp->next)
1119 fputs(" | ", fp);
1121 if (n->npipe.pipe_backgnd)
1122 fputs(" &", fp);
1123 if (ind >= 0)
1124 putc('\n', fp);
1125 break;
1126 default:
1127 fprintf(fp, "<node type %d>", n->type);
1128 if (ind >= 0)
1129 putc('\n', fp);
1130 break;
1134 static void
1135 showtree(union node *n)
1137 trace_puts("showtree called\n");
1138 shtree(n, 1, NULL, stderr);
1141 #endif /* DEBUG */
1144 /* ============ Parser data */
1147 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1149 struct strlist {
1150 struct strlist *next;
1151 char *text;
1154 struct alias;
1156 struct strpush {
1157 struct strpush *prev; /* preceding string on stack */
1158 char *prev_string;
1159 int prev_left_in_line;
1160 #if ENABLE_ASH_ALIAS
1161 struct alias *ap; /* if push was associated with an alias */
1162 #endif
1163 char *string; /* remember the string since it may change */
1166 struct parsefile {
1167 struct parsefile *prev; /* preceding file on stack */
1168 int linno; /* current line */
1169 int pf_fd; /* file descriptor (or -1 if string) */
1170 int left_in_line; /* number of chars left in this line */
1171 int left_in_buffer; /* number of chars left in this buffer past the line */
1172 char *next_to_pgetc; /* next char in buffer */
1173 char *buf; /* input buffer */
1174 struct strpush *strpush; /* for pushing strings at this level */
1175 struct strpush basestrpush; /* so pushing one is fast */
1178 static struct parsefile basepf; /* top level input file */
1179 static struct parsefile *g_parsefile = &basepf; /* current input file */
1180 static int startlinno; /* line # where last token started */
1181 static char *commandname; /* currently executing command */
1182 static struct strlist *cmdenviron; /* environment for builtin command */
1183 static uint8_t exitstatus; /* exit status of last command */
1186 /* ============ Message printing */
1188 static void
1189 ash_vmsg(const char *msg, va_list ap)
1191 fprintf(stderr, "%s: ", arg0);
1192 if (commandname) {
1193 if (strcmp(arg0, commandname))
1194 fprintf(stderr, "%s: ", commandname);
1195 if (!iflag || g_parsefile->pf_fd > 0)
1196 fprintf(stderr, "line %d: ", startlinno);
1198 vfprintf(stderr, msg, ap);
1199 outcslow('\n', stderr);
1203 * Exverror is called to raise the error exception. If the second argument
1204 * is not NULL then error prints an error message using printf style
1205 * formatting. It then raises the error exception.
1207 static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1208 static void
1209 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1211 #if DEBUG
1212 if (msg) {
1213 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1214 TRACEV((msg, ap));
1215 TRACE(("\") pid=%d\n", getpid()));
1216 } else
1217 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1218 if (msg)
1219 #endif
1220 ash_vmsg(msg, ap);
1222 flush_stdout_stderr();
1223 raise_exception(cond);
1224 /* NOTREACHED */
1227 static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1228 static void
1229 ash_msg_and_raise_error(const char *msg, ...)
1231 va_list ap;
1233 va_start(ap, msg);
1234 ash_vmsg_and_raise(EXERROR, msg, ap);
1235 /* NOTREACHED */
1236 va_end(ap);
1239 static void raise_error_syntax(const char *) NORETURN;
1240 static void
1241 raise_error_syntax(const char *msg)
1243 ash_msg_and_raise_error("syntax error: %s", msg);
1244 /* NOTREACHED */
1247 static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1248 static void
1249 ash_msg_and_raise(int cond, const char *msg, ...)
1251 va_list ap;
1253 va_start(ap, msg);
1254 ash_vmsg_and_raise(cond, msg, ap);
1255 /* NOTREACHED */
1256 va_end(ap);
1260 * error/warning routines for external builtins
1262 static void
1263 ash_msg(const char *fmt, ...)
1265 va_list ap;
1267 va_start(ap, fmt);
1268 ash_vmsg(fmt, ap);
1269 va_end(ap);
1273 * Return a string describing an error. The returned string may be a
1274 * pointer to a static buffer that will be overwritten on the next call.
1275 * Action describes the operation that got the error.
1277 static const char *
1278 errmsg(int e, const char *em)
1280 if (e == ENOENT || e == ENOTDIR) {
1281 return em;
1283 return strerror(e);
1287 /* ============ Memory allocation */
1289 #if 0
1290 /* I consider these wrappers nearly useless:
1291 * ok, they return you to nearest exception handler, but
1292 * how much memory do you leak in the process, making
1293 * memory starvation worse?
1295 static void *
1296 ckrealloc(void * p, size_t nbytes)
1298 p = realloc(p, nbytes);
1299 if (!p)
1300 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1301 return p;
1304 static void *
1305 ckmalloc(size_t nbytes)
1307 return ckrealloc(NULL, nbytes);
1310 static void *
1311 ckzalloc(size_t nbytes)
1313 return memset(ckmalloc(nbytes), 0, nbytes);
1316 static char *
1317 ckstrdup(const char *s)
1319 char *p = strdup(s);
1320 if (!p)
1321 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1322 return p;
1324 #else
1325 /* Using bbox equivalents. They exit if out of memory */
1326 # define ckrealloc xrealloc
1327 # define ckmalloc xmalloc
1328 # define ckzalloc xzalloc
1329 # define ckstrdup xstrdup
1330 #endif
1333 * It appears that grabstackstr() will barf with such alignments
1334 * because stalloc() will return a string allocated in a new stackblock.
1336 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1337 enum {
1338 /* Most machines require the value returned from malloc to be aligned
1339 * in some way. The following macro will get this right
1340 * on many machines. */
1341 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1342 /* Minimum size of a block */
1343 MINSIZE = SHELL_ALIGN(504),
1346 struct stack_block {
1347 struct stack_block *prev;
1348 char space[MINSIZE];
1351 struct stackmark {
1352 struct stack_block *stackp;
1353 char *stacknxt;
1354 size_t stacknleft;
1355 struct stackmark *marknext;
1359 struct globals_memstack {
1360 struct stack_block *g_stackp; // = &stackbase;
1361 struct stackmark *markp;
1362 char *g_stacknxt; // = stackbase.space;
1363 char *sstrend; // = stackbase.space + MINSIZE;
1364 size_t g_stacknleft; // = MINSIZE;
1365 int herefd; // = -1;
1366 struct stack_block stackbase;
1368 extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1369 #define G_memstack (*ash_ptr_to_globals_memstack)
1370 #define g_stackp (G_memstack.g_stackp )
1371 #define markp (G_memstack.markp )
1372 #define g_stacknxt (G_memstack.g_stacknxt )
1373 #define sstrend (G_memstack.sstrend )
1374 #define g_stacknleft (G_memstack.g_stacknleft)
1375 #define herefd (G_memstack.herefd )
1376 #define stackbase (G_memstack.stackbase )
1377 #define INIT_G_memstack() do { \
1378 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1379 barrier(); \
1380 g_stackp = &stackbase; \
1381 g_stacknxt = stackbase.space; \
1382 g_stacknleft = MINSIZE; \
1383 sstrend = stackbase.space + MINSIZE; \
1384 herefd = -1; \
1385 } while (0)
1388 #define stackblock() ((void *)g_stacknxt)
1389 #define stackblocksize() g_stacknleft
1392 * Parse trees for commands are allocated in lifo order, so we use a stack
1393 * to make this more efficient, and also to avoid all sorts of exception
1394 * handling code to handle interrupts in the middle of a parse.
1396 * The size 504 was chosen because the Ultrix malloc handles that size
1397 * well.
1399 static void *
1400 stalloc(size_t nbytes)
1402 char *p;
1403 size_t aligned;
1405 aligned = SHELL_ALIGN(nbytes);
1406 if (aligned > g_stacknleft) {
1407 size_t len;
1408 size_t blocksize;
1409 struct stack_block *sp;
1411 blocksize = aligned;
1412 if (blocksize < MINSIZE)
1413 blocksize = MINSIZE;
1414 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1415 if (len < blocksize)
1416 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1417 INT_OFF;
1418 sp = ckmalloc(len);
1419 sp->prev = g_stackp;
1420 g_stacknxt = sp->space;
1421 g_stacknleft = blocksize;
1422 sstrend = g_stacknxt + blocksize;
1423 g_stackp = sp;
1424 INT_ON;
1426 p = g_stacknxt;
1427 g_stacknxt += aligned;
1428 g_stacknleft -= aligned;
1429 return p;
1432 static void *
1433 stzalloc(size_t nbytes)
1435 return memset(stalloc(nbytes), 0, nbytes);
1438 static void
1439 stunalloc(void *p)
1441 #if DEBUG
1442 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1443 write(STDERR_FILENO, "stunalloc\n", 10);
1444 abort();
1446 #endif
1447 g_stacknleft += g_stacknxt - (char *)p;
1448 g_stacknxt = p;
1452 * Like strdup but works with the ash stack.
1454 static char *
1455 ststrdup(const char *p)
1457 size_t len = strlen(p) + 1;
1458 return memcpy(stalloc(len), p, len);
1461 static void
1462 setstackmark(struct stackmark *mark)
1464 mark->stackp = g_stackp;
1465 mark->stacknxt = g_stacknxt;
1466 mark->stacknleft = g_stacknleft;
1467 mark->marknext = markp;
1468 markp = mark;
1471 static void
1472 popstackmark(struct stackmark *mark)
1474 struct stack_block *sp;
1476 if (!mark->stackp)
1477 return;
1479 INT_OFF;
1480 markp = mark->marknext;
1481 while (g_stackp != mark->stackp) {
1482 sp = g_stackp;
1483 g_stackp = sp->prev;
1484 free(sp);
1486 g_stacknxt = mark->stacknxt;
1487 g_stacknleft = mark->stacknleft;
1488 sstrend = mark->stacknxt + mark->stacknleft;
1489 INT_ON;
1493 * When the parser reads in a string, it wants to stick the string on the
1494 * stack and only adjust the stack pointer when it knows how big the
1495 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1496 * of space on top of the stack and stackblocklen returns the length of
1497 * this block. Growstackblock will grow this space by at least one byte,
1498 * possibly moving it (like realloc). Grabstackblock actually allocates the
1499 * part of the block that has been used.
1501 static void
1502 growstackblock(void)
1504 size_t newlen;
1506 newlen = g_stacknleft * 2;
1507 if (newlen < g_stacknleft)
1508 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1509 if (newlen < 128)
1510 newlen += 128;
1512 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1513 struct stack_block *oldstackp;
1514 struct stackmark *xmark;
1515 struct stack_block *sp;
1516 struct stack_block *prevstackp;
1517 size_t grosslen;
1519 INT_OFF;
1520 oldstackp = g_stackp;
1521 sp = g_stackp;
1522 prevstackp = sp->prev;
1523 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1524 sp = ckrealloc(sp, grosslen);
1525 sp->prev = prevstackp;
1526 g_stackp = sp;
1527 g_stacknxt = sp->space;
1528 g_stacknleft = newlen;
1529 sstrend = sp->space + newlen;
1532 * Stack marks pointing to the start of the old block
1533 * must be relocated to point to the new block
1535 xmark = markp;
1536 while (xmark != NULL && xmark->stackp == oldstackp) {
1537 xmark->stackp = g_stackp;
1538 xmark->stacknxt = g_stacknxt;
1539 xmark->stacknleft = g_stacknleft;
1540 xmark = xmark->marknext;
1542 INT_ON;
1543 } else {
1544 char *oldspace = g_stacknxt;
1545 size_t oldlen = g_stacknleft;
1546 char *p = stalloc(newlen);
1548 /* free the space we just allocated */
1549 g_stacknxt = memcpy(p, oldspace, oldlen);
1550 g_stacknleft += newlen;
1554 static void
1555 grabstackblock(size_t len)
1557 len = SHELL_ALIGN(len);
1558 g_stacknxt += len;
1559 g_stacknleft -= len;
1563 * The following routines are somewhat easier to use than the above.
1564 * The user declares a variable of type STACKSTR, which may be declared
1565 * to be a register. The macro STARTSTACKSTR initializes things. Then
1566 * the user uses the macro STPUTC to add characters to the string. In
1567 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1568 * grown as necessary. When the user is done, she can just leave the
1569 * string there and refer to it using stackblock(). Or she can allocate
1570 * the space for it using grabstackstr(). If it is necessary to allow
1571 * someone else to use the stack temporarily and then continue to grow
1572 * the string, the user should use grabstack to allocate the space, and
1573 * then call ungrabstr(p) to return to the previous mode of operation.
1575 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1576 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1577 * is space for at least one character.
1579 static void *
1580 growstackstr(void)
1582 size_t len = stackblocksize();
1583 if (herefd >= 0 && len >= 1024) {
1584 full_write(herefd, stackblock(), len);
1585 return stackblock();
1587 growstackblock();
1588 return (char *)stackblock() + len;
1592 * Called from CHECKSTRSPACE.
1594 static char *
1595 makestrspace(size_t newlen, char *p)
1597 size_t len = p - g_stacknxt;
1598 size_t size = stackblocksize();
1600 for (;;) {
1601 size_t nleft;
1603 size = stackblocksize();
1604 nleft = size - len;
1605 if (nleft >= newlen)
1606 break;
1607 growstackblock();
1609 return (char *)stackblock() + len;
1612 static char *
1613 stack_nputstr(const char *s, size_t n, char *p)
1615 p = makestrspace(n, p);
1616 p = (char *)memcpy(p, s, n) + n;
1617 return p;
1620 static char *
1621 stack_putstr(const char *s, char *p)
1623 return stack_nputstr(s, strlen(s), p);
1626 static char *
1627 _STPUTC(int c, char *p)
1629 if (p == sstrend)
1630 p = growstackstr();
1631 *p++ = c;
1632 return p;
1635 #define STARTSTACKSTR(p) ((p) = stackblock())
1636 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1637 #define CHECKSTRSPACE(n, p) do { \
1638 char *q = (p); \
1639 size_t l = (n); \
1640 size_t m = sstrend - q; \
1641 if (l > m) \
1642 (p) = makestrspace(l, q); \
1643 } while (0)
1644 #define USTPUTC(c, p) (*(p)++ = (c))
1645 #define STACKSTRNUL(p) do { \
1646 if ((p) == sstrend) \
1647 (p) = growstackstr(); \
1648 *(p) = '\0'; \
1649 } while (0)
1650 #define STUNPUTC(p) (--(p))
1651 #define STTOPC(p) ((p)[-1])
1652 #define STADJUST(amount, p) ((p) += (amount))
1654 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1655 #define ungrabstackstr(s, p) stunalloc(s)
1656 #define stackstrend() ((void *)sstrend)
1659 /* ============ String helpers */
1662 * prefix -- see if pfx is a prefix of string.
1664 static char *
1665 prefix(const char *string, const char *pfx)
1667 while (*pfx) {
1668 if (*pfx++ != *string++)
1669 return NULL;
1671 return (char *) string;
1675 * Check for a valid number. This should be elsewhere.
1677 static int
1678 is_number(const char *p)
1680 do {
1681 if (!isdigit(*p))
1682 return 0;
1683 } while (*++p != '\0');
1684 return 1;
1688 * Convert a string of digits to an integer, printing an error message on
1689 * failure.
1691 static int
1692 number(const char *s)
1694 if (!is_number(s))
1695 ash_msg_and_raise_error(msg_illnum, s);
1696 return atoi(s);
1700 * Produce a possibly single quoted string suitable as input to the shell.
1701 * The return string is allocated on the stack.
1703 static char *
1704 single_quote(const char *s)
1706 char *p;
1708 STARTSTACKSTR(p);
1710 do {
1711 char *q;
1712 size_t len;
1714 len = strchrnul(s, '\'') - s;
1716 q = p = makestrspace(len + 3, p);
1718 *q++ = '\'';
1719 q = (char *)memcpy(q, s, len) + len;
1720 *q++ = '\'';
1721 s += len;
1723 STADJUST(q - p, p);
1725 if (*s != '\'')
1726 break;
1727 len = 0;
1728 do len++; while (*++s == '\'');
1730 q = p = makestrspace(len + 3, p);
1732 *q++ = '"';
1733 q = (char *)memcpy(q, s - len, len) + len;
1734 *q++ = '"';
1736 STADJUST(q - p, p);
1737 } while (*s);
1739 USTPUTC('\0', p);
1741 return stackblock();
1745 /* ============ nextopt */
1747 static char **argptr; /* argument list for builtin commands */
1748 static char *optionarg; /* set by nextopt (like getopt) */
1749 static char *optptr; /* used by nextopt */
1752 * XXX - should get rid of. Have all builtins use getopt(3).
1753 * The library getopt must have the BSD extension static variable
1754 * "optreset", otherwise it can't be used within the shell safely.
1756 * Standard option processing (a la getopt) for builtin routines.
1757 * The only argument that is passed to nextopt is the option string;
1758 * the other arguments are unnecessary. It returns the character,
1759 * or '\0' on end of input.
1761 static int
1762 nextopt(const char *optstring)
1764 char *p;
1765 const char *q;
1766 char c;
1768 p = optptr;
1769 if (p == NULL || *p == '\0') {
1770 /* We ate entire "-param", take next one */
1771 p = *argptr;
1772 if (p == NULL)
1773 return '\0';
1774 if (*p != '-')
1775 return '\0';
1776 if (*++p == '\0') /* just "-" ? */
1777 return '\0';
1778 argptr++;
1779 if (LONE_DASH(p)) /* "--" ? */
1780 return '\0';
1781 /* p => next "-param" */
1783 /* p => some option char in the middle of a "-param" */
1784 c = *p++;
1785 for (q = optstring; *q != c;) {
1786 if (*q == '\0')
1787 ash_msg_and_raise_error("illegal option -%c", c);
1788 if (*++q == ':')
1789 q++;
1791 if (*++q == ':') {
1792 if (*p == '\0') {
1793 p = *argptr++;
1794 if (p == NULL)
1795 ash_msg_and_raise_error("no arg for -%c option", c);
1797 optionarg = p;
1798 p = NULL;
1800 optptr = p;
1801 return c;
1805 /* ============ Shell variables */
1808 * The parsefile structure pointed to by the global variable parsefile
1809 * contains information about the current file being read.
1811 struct shparam {
1812 int nparam; /* # of positional parameters (without $0) */
1813 #if ENABLE_ASH_GETOPTS
1814 int optind; /* next parameter to be processed by getopts */
1815 int optoff; /* used by getopts */
1816 #endif
1817 unsigned char malloced; /* if parameter list dynamically allocated */
1818 char **p; /* parameter list */
1822 * Free the list of positional parameters.
1824 static void
1825 freeparam(volatile struct shparam *param)
1827 if (param->malloced) {
1828 char **ap, **ap1;
1829 ap = ap1 = param->p;
1830 while (*ap)
1831 free(*ap++);
1832 free(ap1);
1836 #if ENABLE_ASH_GETOPTS
1837 static void FAST_FUNC getoptsreset(const char *value);
1838 #endif
1840 struct var {
1841 struct var *next; /* next entry in hash list */
1842 int flags; /* flags are defined above */
1843 const char *var_text; /* name=value */
1844 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
1845 /* the variable gets set/unset */
1848 struct localvar {
1849 struct localvar *next; /* next local variable in list */
1850 struct var *vp; /* the variable that was made local */
1851 int flags; /* saved flags */
1852 const char *text; /* saved text */
1855 /* flags */
1856 #define VEXPORT 0x01 /* variable is exported */
1857 #define VREADONLY 0x02 /* variable cannot be modified */
1858 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1859 #define VTEXTFIXED 0x08 /* text is statically allocated */
1860 #define VSTACK 0x10 /* text is allocated on the stack */
1861 #define VUNSET 0x20 /* the variable is not set */
1862 #define VNOFUNC 0x40 /* don't call the callback function */
1863 #define VNOSET 0x80 /* do not set variable - just readonly test */
1864 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1865 #if ENABLE_ASH_RANDOM_SUPPORT
1866 # define VDYNAMIC 0x200 /* dynamic variable */
1867 #else
1868 # define VDYNAMIC 0
1869 #endif
1872 /* Need to be before varinit_data[] */
1873 #if ENABLE_LOCALE_SUPPORT
1874 static void FAST_FUNC
1875 change_lc_all(const char *value)
1877 if (value && *value != '\0')
1878 setlocale(LC_ALL, value);
1880 static void FAST_FUNC
1881 change_lc_ctype(const char *value)
1883 if (value && *value != '\0')
1884 setlocale(LC_CTYPE, value);
1886 #endif
1887 #if ENABLE_ASH_MAIL
1888 static void chkmail(void);
1889 static void changemail(const char *var_value) FAST_FUNC;
1890 #else
1891 # define chkmail() ((void)0)
1892 #endif
1893 static void changepath(const char *) FAST_FUNC;
1894 #if ENABLE_ASH_RANDOM_SUPPORT
1895 static void change_random(const char *) FAST_FUNC;
1896 #endif
1898 static const struct {
1899 int flags;
1900 const char *var_text;
1901 void (*var_func)(const char *) FAST_FUNC;
1902 } varinit_data[] = {
1904 * Note: VEXPORT would not work correctly here for NOFORK applets:
1905 * some environment strings may be constant.
1907 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1908 #if ENABLE_ASH_MAIL
1909 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1910 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
1911 #endif
1912 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1913 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1914 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1915 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1916 #if ENABLE_ASH_GETOPTS
1917 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
1918 #endif
1919 #if ENABLE_ASH_RANDOM_SUPPORT
1920 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
1921 #endif
1922 #if ENABLE_LOCALE_SUPPORT
1923 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1924 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
1925 #endif
1926 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1927 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
1928 #endif
1931 struct redirtab;
1933 struct globals_var {
1934 struct shparam shellparam; /* $@ current positional parameters */
1935 struct redirtab *redirlist;
1936 int g_nullredirs;
1937 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1938 struct var *vartab[VTABSIZE];
1939 struct var varinit[ARRAY_SIZE(varinit_data)];
1941 extern struct globals_var *const ash_ptr_to_globals_var;
1942 #define G_var (*ash_ptr_to_globals_var)
1943 #define shellparam (G_var.shellparam )
1944 //#define redirlist (G_var.redirlist )
1945 #define g_nullredirs (G_var.g_nullredirs )
1946 #define preverrout_fd (G_var.preverrout_fd)
1947 #define vartab (G_var.vartab )
1948 #define varinit (G_var.varinit )
1949 #define INIT_G_var() do { \
1950 unsigned i; \
1951 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1952 barrier(); \
1953 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1954 varinit[i].flags = varinit_data[i].flags; \
1955 varinit[i].var_text = varinit_data[i].var_text; \
1956 varinit[i].var_func = varinit_data[i].var_func; \
1958 } while (0)
1960 #define vifs varinit[0]
1961 #if ENABLE_ASH_MAIL
1962 # define vmail (&vifs)[1]
1963 # define vmpath (&vmail)[1]
1964 # define vpath (&vmpath)[1]
1965 #else
1966 # define vpath (&vifs)[1]
1967 #endif
1968 #define vps1 (&vpath)[1]
1969 #define vps2 (&vps1)[1]
1970 #define vps4 (&vps2)[1]
1971 #if ENABLE_ASH_GETOPTS
1972 # define voptind (&vps4)[1]
1973 # if ENABLE_ASH_RANDOM_SUPPORT
1974 # define vrandom (&voptind)[1]
1975 # endif
1976 #else
1977 # if ENABLE_ASH_RANDOM_SUPPORT
1978 # define vrandom (&vps4)[1]
1979 # endif
1980 #endif
1983 * The following macros access the values of the above variables.
1984 * They have to skip over the name. They return the null string
1985 * for unset variables.
1987 #define ifsval() (vifs.var_text + 4)
1988 #define ifsset() ((vifs.flags & VUNSET) == 0)
1989 #if ENABLE_ASH_MAIL
1990 # define mailval() (vmail.var_text + 5)
1991 # define mpathval() (vmpath.var_text + 9)
1992 # define mpathset() ((vmpath.flags & VUNSET) == 0)
1993 #endif
1994 #define pathval() (vpath.var_text + 5)
1995 #define ps1val() (vps1.var_text + 4)
1996 #define ps2val() (vps2.var_text + 4)
1997 #define ps4val() (vps4.var_text + 4)
1998 #if ENABLE_ASH_GETOPTS
1999 # define optindval() (voptind.var_text + 7)
2000 #endif
2002 #if ENABLE_ASH_GETOPTS
2003 static void FAST_FUNC
2004 getoptsreset(const char *value)
2006 shellparam.optind = number(value);
2007 shellparam.optoff = -1;
2009 #endif
2011 /* math.h has these, otherwise define our private copies */
2012 #if !ENABLE_SH_MATH_SUPPORT
2013 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
2014 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
2016 * Return the pointer to the first char which is not part of a legal variable name
2017 * (a letter or underscore followed by letters, underscores, and digits).
2019 static const char*
2020 endofname(const char *name)
2022 if (!is_name(*name))
2023 return name;
2024 while (*++name) {
2025 if (!is_in_name(*name))
2026 break;
2028 return name;
2030 #endif
2033 * Compares two strings up to the first = or '\0'. The first
2034 * string must be terminated by '='; the second may be terminated by
2035 * either '=' or '\0'.
2037 static int
2038 varcmp(const char *p, const char *q)
2040 int c, d;
2042 while ((c = *p) == (d = *q)) {
2043 if (!c || c == '=')
2044 goto out;
2045 p++;
2046 q++;
2048 if (c == '=')
2049 c = '\0';
2050 if (d == '=')
2051 d = '\0';
2052 out:
2053 return c - d;
2057 * Find the appropriate entry in the hash table from the name.
2059 static struct var **
2060 hashvar(const char *p)
2062 unsigned hashval;
2064 hashval = ((unsigned char) *p) << 4;
2065 while (*p && *p != '=')
2066 hashval += (unsigned char) *p++;
2067 return &vartab[hashval % VTABSIZE];
2070 static int
2071 vpcmp(const void *a, const void *b)
2073 return varcmp(*(const char **)a, *(const char **)b);
2077 * This routine initializes the builtin variables.
2079 static void
2080 initvar(void)
2082 struct var *vp;
2083 struct var *end;
2084 struct var **vpp;
2087 * PS1 depends on uid
2089 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2090 vps1.var_text = "PS1=\\w \\$ ";
2091 #else
2092 if (!geteuid())
2093 vps1.var_text = "PS1=# ";
2094 #endif
2095 vp = varinit;
2096 end = vp + ARRAY_SIZE(varinit);
2097 do {
2098 vpp = hashvar(vp->var_text);
2099 vp->next = *vpp;
2100 *vpp = vp;
2101 } while (++vp < end);
2104 static struct var **
2105 findvar(struct var **vpp, const char *name)
2107 for (; *vpp; vpp = &(*vpp)->next) {
2108 if (varcmp((*vpp)->var_text, name) == 0) {
2109 break;
2112 return vpp;
2116 * Find the value of a variable. Returns NULL if not set.
2118 static const char* FAST_FUNC
2119 lookupvar(const char *name)
2121 struct var *v;
2123 v = *findvar(hashvar(name), name);
2124 if (v) {
2125 #if ENABLE_ASH_RANDOM_SUPPORT
2127 * Dynamic variables are implemented roughly the same way they are
2128 * in bash. Namely, they're "special" so long as they aren't unset.
2129 * As soon as they're unset, they're no longer dynamic, and dynamic
2130 * lookup will no longer happen at that point. -- PFM.
2132 if (v->flags & VDYNAMIC)
2133 v->var_func(NULL);
2134 #endif
2135 if (!(v->flags & VUNSET))
2136 return var_end(v->var_text);
2138 return NULL;
2142 * Search the environment of a builtin command.
2144 static const char *
2145 bltinlookup(const char *name)
2147 struct strlist *sp;
2149 for (sp = cmdenviron; sp; sp = sp->next) {
2150 if (varcmp(sp->text, name) == 0)
2151 return var_end(sp->text);
2153 return lookupvar(name);
2157 * Same as setvar except that the variable and value are passed in
2158 * the first argument as name=value. Since the first argument will
2159 * be actually stored in the table, it should not be a string that
2160 * will go away.
2161 * Called with interrupts off.
2163 static void
2164 setvareq(char *s, int flags)
2166 struct var *vp, **vpp;
2168 vpp = hashvar(s);
2169 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2170 vp = *findvar(vpp, s);
2171 if (vp) {
2172 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2173 const char *n;
2175 if (flags & VNOSAVE)
2176 free(s);
2177 n = vp->var_text;
2178 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2181 if (flags & VNOSET)
2182 return;
2184 if (vp->var_func && !(flags & VNOFUNC))
2185 vp->var_func(var_end(s));
2187 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2188 free((char*)vp->var_text);
2190 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2191 } else {
2192 /* variable s is not found */
2193 if (flags & VNOSET)
2194 return;
2195 vp = ckzalloc(sizeof(*vp));
2196 vp->next = *vpp;
2197 /*vp->func = NULL; - ckzalloc did it */
2198 *vpp = vp;
2200 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2201 s = ckstrdup(s);
2202 vp->var_text = s;
2203 vp->flags = flags;
2207 * Set the value of a variable. The flags argument is ored with the
2208 * flags of the variable. If val is NULL, the variable is unset.
2210 static void
2211 setvar(const char *name, const char *val, int flags)
2213 const char *q;
2214 char *p;
2215 char *nameeq;
2216 size_t namelen;
2217 size_t vallen;
2219 q = endofname(name);
2220 p = strchrnul(q, '=');
2221 namelen = p - name;
2222 if (!namelen || p != q)
2223 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2224 vallen = 0;
2225 if (val == NULL) {
2226 flags |= VUNSET;
2227 } else {
2228 vallen = strlen(val);
2231 INT_OFF;
2232 nameeq = ckmalloc(namelen + vallen + 2);
2233 p = memcpy(nameeq, name, namelen) + namelen;
2234 if (val) {
2235 *p++ = '=';
2236 p = memcpy(p, val, vallen) + vallen;
2238 *p = '\0';
2239 setvareq(nameeq, flags | VNOSAVE);
2240 INT_ON;
2243 static void FAST_FUNC
2244 setvar2(const char *name, const char *val)
2246 setvar(name, val, 0);
2249 #if ENABLE_ASH_GETOPTS
2251 * Safe version of setvar, returns 1 on success 0 on failure.
2253 static int
2254 setvarsafe(const char *name, const char *val, int flags)
2256 int err;
2257 volatile int saveint;
2258 struct jmploc *volatile savehandler = exception_handler;
2259 struct jmploc jmploc;
2261 SAVE_INT(saveint);
2262 if (setjmp(jmploc.loc))
2263 err = 1;
2264 else {
2265 exception_handler = &jmploc;
2266 setvar(name, val, flags);
2267 err = 0;
2269 exception_handler = savehandler;
2270 RESTORE_INT(saveint);
2271 return err;
2273 #endif
2276 * Unset the specified variable.
2278 static int
2279 unsetvar(const char *s)
2281 struct var **vpp;
2282 struct var *vp;
2283 int retval;
2285 vpp = findvar(hashvar(s), s);
2286 vp = *vpp;
2287 retval = 2;
2288 if (vp) {
2289 int flags = vp->flags;
2291 retval = 1;
2292 if (flags & VREADONLY)
2293 goto out;
2294 #if ENABLE_ASH_RANDOM_SUPPORT
2295 vp->flags &= ~VDYNAMIC;
2296 #endif
2297 if (flags & VUNSET)
2298 goto ok;
2299 if ((flags & VSTRFIXED) == 0) {
2300 INT_OFF;
2301 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2302 free((char*)vp->var_text);
2303 *vpp = vp->next;
2304 free(vp);
2305 INT_ON;
2306 } else {
2307 setvar(s, 0, 0);
2308 vp->flags &= ~VEXPORT;
2311 retval = 0;
2313 out:
2314 return retval;
2318 * Process a linked list of variable assignments.
2320 static void
2321 listsetvar(struct strlist *list_set_var, int flags)
2323 struct strlist *lp = list_set_var;
2325 if (!lp)
2326 return;
2327 INT_OFF;
2328 do {
2329 setvareq(lp->text, flags);
2330 lp = lp->next;
2331 } while (lp);
2332 INT_ON;
2336 * Generate a list of variables satisfying the given conditions.
2338 static char **
2339 listvars(int on, int off, char ***end)
2341 struct var **vpp;
2342 struct var *vp;
2343 char **ep;
2344 int mask;
2346 STARTSTACKSTR(ep);
2347 vpp = vartab;
2348 mask = on | off;
2349 do {
2350 for (vp = *vpp; vp; vp = vp->next) {
2351 if ((vp->flags & mask) == on) {
2352 if (ep == stackstrend())
2353 ep = growstackstr();
2354 *ep++ = (char*)vp->var_text;
2357 } while (++vpp < vartab + VTABSIZE);
2358 if (ep == stackstrend())
2359 ep = growstackstr();
2360 if (end)
2361 *end = ep;
2362 *ep++ = NULL;
2363 return grabstackstr(ep);
2367 /* ============ Path search helper
2369 * The variable path (passed by reference) should be set to the start
2370 * of the path before the first call; path_advance will update
2371 * this value as it proceeds. Successive calls to path_advance will return
2372 * the possible path expansions in sequence. If an option (indicated by
2373 * a percent sign) appears in the path entry then the global variable
2374 * pathopt will be set to point to it; otherwise pathopt will be set to
2375 * NULL.
2377 static const char *pathopt; /* set by path_advance */
2379 static char *
2380 path_advance(const char **path, const char *name)
2382 const char *p;
2383 char *q;
2384 const char *start;
2385 size_t len;
2387 if (*path == NULL)
2388 return NULL;
2389 start = *path;
2390 for (p = start; *p && *p != ':' && *p != '%'; p++)
2391 continue;
2392 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2393 while (stackblocksize() < len)
2394 growstackblock();
2395 q = stackblock();
2396 if (p != start) {
2397 memcpy(q, start, p - start);
2398 q += p - start;
2399 *q++ = '/';
2401 strcpy(q, name);
2402 pathopt = NULL;
2403 if (*p == '%') {
2404 pathopt = ++p;
2405 while (*p && *p != ':')
2406 p++;
2408 if (*p == ':')
2409 *path = p + 1;
2410 else
2411 *path = NULL;
2412 return stalloc(len);
2416 /* ============ Prompt */
2418 static smallint doprompt; /* if set, prompt the user */
2419 static smallint needprompt; /* true if interactive and at start of line */
2421 #if ENABLE_FEATURE_EDITING
2422 static line_input_t *line_input_state;
2423 static const char *cmdedit_prompt;
2424 static void
2425 putprompt(const char *s)
2427 if (ENABLE_ASH_EXPAND_PRMT) {
2428 free((char*)cmdedit_prompt);
2429 cmdedit_prompt = ckstrdup(s);
2430 return;
2432 cmdedit_prompt = s;
2434 #else
2435 static void
2436 putprompt(const char *s)
2438 out2str(s);
2440 #endif
2442 #if ENABLE_ASH_EXPAND_PRMT
2443 /* expandstr() needs parsing machinery, so it is far away ahead... */
2444 static const char *expandstr(const char *ps);
2445 #else
2446 #define expandstr(s) s
2447 #endif
2449 static void
2450 setprompt_if(smallint do_set, int whichprompt)
2452 const char *prompt;
2453 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2455 if (!do_set)
2456 return;
2458 needprompt = 0;
2460 switch (whichprompt) {
2461 case 1:
2462 prompt = ps1val();
2463 break;
2464 case 2:
2465 prompt = ps2val();
2466 break;
2467 default: /* 0 */
2468 prompt = nullstr;
2470 #if ENABLE_ASH_EXPAND_PRMT
2471 setstackmark(&smark);
2472 stalloc(stackblocksize());
2473 #endif
2474 putprompt(expandstr(prompt));
2475 #if ENABLE_ASH_EXPAND_PRMT
2476 popstackmark(&smark);
2477 #endif
2481 /* ============ The cd and pwd commands */
2483 #define CD_PHYSICAL 1
2484 #define CD_PRINT 2
2486 static int
2487 cdopt(void)
2489 int flags = 0;
2490 int i, j;
2492 j = 'L';
2493 while ((i = nextopt("LP")) != '\0') {
2494 if (i != j) {
2495 flags ^= CD_PHYSICAL;
2496 j = i;
2500 return flags;
2504 * Update curdir (the name of the current directory) in response to a
2505 * cd command.
2507 static const char *
2508 updatepwd(const char *dir)
2510 char *new;
2511 char *p;
2512 char *cdcomppath;
2513 const char *lim;
2515 cdcomppath = ststrdup(dir);
2516 STARTSTACKSTR(new);
2517 if (*dir != '/') {
2518 if (curdir == nullstr)
2519 return 0;
2520 new = stack_putstr(curdir, new);
2522 new = makestrspace(strlen(dir) + 2, new);
2523 lim = (char *)stackblock() + 1;
2524 if (*dir != '/') {
2525 if (new[-1] != '/')
2526 USTPUTC('/', new);
2527 if (new > lim && *lim == '/')
2528 lim++;
2529 } else {
2530 USTPUTC('/', new);
2531 cdcomppath++;
2532 if (dir[1] == '/' && dir[2] != '/') {
2533 USTPUTC('/', new);
2534 cdcomppath++;
2535 lim++;
2538 p = strtok(cdcomppath, "/");
2539 while (p) {
2540 switch (*p) {
2541 case '.':
2542 if (p[1] == '.' && p[2] == '\0') {
2543 while (new > lim) {
2544 STUNPUTC(new);
2545 if (new[-1] == '/')
2546 break;
2548 break;
2550 if (p[1] == '\0')
2551 break;
2552 /* fall through */
2553 default:
2554 new = stack_putstr(p, new);
2555 USTPUTC('/', new);
2557 p = strtok(0, "/");
2559 if (new > lim)
2560 STUNPUTC(new);
2561 *new = 0;
2562 return stackblock();
2566 * Find out what the current directory is. If we already know the current
2567 * directory, this routine returns immediately.
2569 static char *
2570 getpwd(void)
2572 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2573 return dir ? dir : nullstr;
2576 static void
2577 setpwd(const char *val, int setold)
2579 char *oldcur, *dir;
2581 oldcur = dir = curdir;
2583 if (setold) {
2584 setvar("OLDPWD", oldcur, VEXPORT);
2586 INT_OFF;
2587 if (physdir != nullstr) {
2588 if (physdir != oldcur)
2589 free(physdir);
2590 physdir = nullstr;
2592 if (oldcur == val || !val) {
2593 char *s = getpwd();
2594 physdir = s;
2595 if (!val)
2596 dir = s;
2597 } else
2598 dir = ckstrdup(val);
2599 if (oldcur != dir && oldcur != nullstr) {
2600 free(oldcur);
2602 curdir = dir;
2603 INT_ON;
2604 setvar("PWD", dir, VEXPORT);
2607 static void hashcd(void);
2610 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2611 * know that the current directory has changed.
2613 static int
2614 docd(const char *dest, int flags)
2616 const char *dir = NULL;
2617 int err;
2619 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2621 INT_OFF;
2622 if (!(flags & CD_PHYSICAL)) {
2623 dir = updatepwd(dest);
2624 if (dir)
2625 dest = dir;
2627 err = chdir(dest);
2628 if (err)
2629 goto out;
2630 setpwd(dir, 1);
2631 hashcd();
2632 out:
2633 INT_ON;
2634 return err;
2637 static int FAST_FUNC
2638 cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2640 const char *dest;
2641 const char *path;
2642 const char *p;
2643 char c;
2644 struct stat statb;
2645 int flags;
2647 flags = cdopt();
2648 dest = *argptr;
2649 if (!dest)
2650 dest = bltinlookup("HOME");
2651 else if (LONE_DASH(dest)) {
2652 dest = bltinlookup("OLDPWD");
2653 flags |= CD_PRINT;
2655 if (!dest)
2656 dest = nullstr;
2657 if (*dest == '/')
2658 goto step7;
2659 if (*dest == '.') {
2660 c = dest[1];
2661 dotdot:
2662 switch (c) {
2663 case '\0':
2664 case '/':
2665 goto step6;
2666 case '.':
2667 c = dest[2];
2668 if (c != '.')
2669 goto dotdot;
2672 if (!*dest)
2673 dest = ".";
2674 path = bltinlookup("CDPATH");
2675 if (!path) {
2676 step6:
2677 step7:
2678 p = dest;
2679 goto docd;
2681 do {
2682 c = *path;
2683 p = path_advance(&path, dest);
2684 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2685 if (c && c != ':')
2686 flags |= CD_PRINT;
2687 docd:
2688 if (!docd(p, flags))
2689 goto out;
2690 break;
2692 } while (path);
2693 ash_msg_and_raise_error("can't cd to %s", dest);
2694 /* NOTREACHED */
2695 out:
2696 if (flags & CD_PRINT)
2697 out1fmt("%s\n", curdir);
2698 return 0;
2701 static int FAST_FUNC
2702 pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2704 int flags;
2705 const char *dir = curdir;
2707 flags = cdopt();
2708 if (flags) {
2709 if (physdir == nullstr)
2710 setpwd(dir, 0);
2711 dir = physdir;
2713 out1fmt("%s\n", dir);
2714 return 0;
2718 /* ============ ... */
2721 #define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
2723 /* Syntax classes */
2724 #define CWORD 0 /* character is nothing special */
2725 #define CNL 1 /* newline character */
2726 #define CBACK 2 /* a backslash character */
2727 #define CSQUOTE 3 /* single quote */
2728 #define CDQUOTE 4 /* double quote */
2729 #define CENDQUOTE 5 /* a terminating quote */
2730 #define CBQUOTE 6 /* backwards single quote */
2731 #define CVAR 7 /* a dollar sign */
2732 #define CENDVAR 8 /* a '}' character */
2733 #define CLP 9 /* a left paren in arithmetic */
2734 #define CRP 10 /* a right paren in arithmetic */
2735 #define CENDFILE 11 /* end of file */
2736 #define CCTL 12 /* like CWORD, except it must be escaped */
2737 #define CSPCL 13 /* these terminate a word */
2738 #define CIGN 14 /* character should be ignored */
2740 #define PEOF 256
2741 #if ENABLE_ASH_ALIAS
2742 # define PEOA 257
2743 #endif
2745 #define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
2747 #if ENABLE_SH_MATH_SUPPORT
2748 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
2749 #else
2750 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
2751 #endif
2752 static const uint16_t S_I_T[] = {
2753 #if ENABLE_ASH_ALIAS
2754 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2755 #endif
2756 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2757 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2758 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2759 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2760 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2761 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2762 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2763 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2764 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2765 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2766 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
2767 #if !USE_SIT_FUNCTION
2768 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2769 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2770 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2771 #endif
2772 #undef SIT_ITEM
2774 /* Constants below must match table above */
2775 enum {
2776 #if ENABLE_ASH_ALIAS
2777 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2778 #endif
2779 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2780 CNL_CNL_CNL_CNL , /* 2 */
2781 CWORD_CCTL_CCTL_CWORD , /* 3 */
2782 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2783 CVAR_CVAR_CWORD_CVAR , /* 5 */
2784 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2785 CSPCL_CWORD_CWORD_CLP , /* 7 */
2786 CSPCL_CWORD_CWORD_CRP , /* 8 */
2787 CBACK_CBACK_CCTL_CBACK , /* 9 */
2788 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2789 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2790 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2791 CWORD_CWORD_CWORD_CWORD , /* 13 */
2792 CCTL_CCTL_CCTL_CCTL , /* 14 */
2795 /* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2796 * caller must ensure proper cast on it if c is *char_ptr!
2798 /* Values for syntax param */
2799 #define BASESYNTAX 0 /* not in quotes */
2800 #define DQSYNTAX 1 /* in double quotes */
2801 #define SQSYNTAX 2 /* in single quotes */
2802 #define ARISYNTAX 3 /* in arithmetic */
2803 #define PSSYNTAX 4 /* prompt. never passed to SIT() */
2805 #if USE_SIT_FUNCTION
2807 static int
2808 SIT(int c, int syntax)
2810 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2811 # if ENABLE_ASH_ALIAS
2812 static const uint8_t syntax_index_table[] ALIGN1 = {
2813 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2814 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2815 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2816 11, 3 /* "}~" */
2818 # else
2819 static const uint8_t syntax_index_table[] ALIGN1 = {
2820 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2821 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2822 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2823 10, 2 /* "}~" */
2825 # endif
2826 const char *s;
2827 int indx;
2829 if (c == PEOF)
2830 return CENDFILE;
2831 # if ENABLE_ASH_ALIAS
2832 if (c == PEOA)
2833 indx = 0;
2834 else
2835 # endif
2837 /* Cast is purely for paranoia here,
2838 * just in case someone passed signed char to us */
2839 if ((unsigned char)c >= CTL_FIRST
2840 && (unsigned char)c <= CTL_LAST
2842 return CCTL;
2844 s = strchrnul(spec_symbls, c);
2845 if (*s == '\0')
2846 return CWORD;
2847 indx = syntax_index_table[s - spec_symbls];
2849 return (S_I_T[indx] >> (syntax*4)) & 0xf;
2852 #else /* !USE_SIT_FUNCTION */
2854 static const uint8_t syntax_index_table[] = {
2855 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2856 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2866 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2867 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2889 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2890 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2891 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2892 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2893 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2894 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2895 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2896 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2897 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2898 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2899 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2900 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2901 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2902 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
2903 /* 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2904 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2905 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2906 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2907 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2908 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2909 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2910 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2915 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2916 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2917 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2918 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2919 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2920 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2948 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2949 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2950 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2953 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2981 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2982 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2983 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2984 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2985 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2986 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2987 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2988 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2989 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2990 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2991 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2992 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2993 /* 137 */ CWORD_CWORD_CWORD_CWORD,
2994 /* 138 */ CWORD_CWORD_CWORD_CWORD,
2995 /* 139 */ CWORD_CWORD_CWORD_CWORD,
2996 /* 140 */ CWORD_CWORD_CWORD_CWORD,
2997 /* 141 */ CWORD_CWORD_CWORD_CWORD,
2998 /* 142 */ CWORD_CWORD_CWORD_CWORD,
2999 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3000 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3001 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3002 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 255 */ CWORD_CWORD_CWORD_CWORD,
3112 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
3113 # if ENABLE_ASH_ALIAS
3114 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3115 # endif
3118 # define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
3120 #endif /* !USE_SIT_FUNCTION */
3123 /* ============ Alias handling */
3125 #if ENABLE_ASH_ALIAS
3127 #define ALIASINUSE 1
3128 #define ALIASDEAD 2
3130 struct alias {
3131 struct alias *next;
3132 char *name;
3133 char *val;
3134 int flag;
3138 static struct alias **atab; // [ATABSIZE];
3139 #define INIT_G_alias() do { \
3140 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3141 } while (0)
3144 static struct alias **
3145 __lookupalias(const char *name) {
3146 unsigned int hashval;
3147 struct alias **app;
3148 const char *p;
3149 unsigned int ch;
3151 p = name;
3153 ch = (unsigned char)*p;
3154 hashval = ch << 4;
3155 while (ch) {
3156 hashval += ch;
3157 ch = (unsigned char)*++p;
3159 app = &atab[hashval % ATABSIZE];
3161 for (; *app; app = &(*app)->next) {
3162 if (strcmp(name, (*app)->name) == 0) {
3163 break;
3167 return app;
3170 static struct alias *
3171 lookupalias(const char *name, int check)
3173 struct alias *ap = *__lookupalias(name);
3175 if (check && ap && (ap->flag & ALIASINUSE))
3176 return NULL;
3177 return ap;
3180 static struct alias *
3181 freealias(struct alias *ap)
3183 struct alias *next;
3185 if (ap->flag & ALIASINUSE) {
3186 ap->flag |= ALIASDEAD;
3187 return ap;
3190 next = ap->next;
3191 free(ap->name);
3192 free(ap->val);
3193 free(ap);
3194 return next;
3197 static void
3198 setalias(const char *name, const char *val)
3200 struct alias *ap, **app;
3202 app = __lookupalias(name);
3203 ap = *app;
3204 INT_OFF;
3205 if (ap) {
3206 if (!(ap->flag & ALIASINUSE)) {
3207 free(ap->val);
3209 ap->val = ckstrdup(val);
3210 ap->flag &= ~ALIASDEAD;
3211 } else {
3212 /* not found */
3213 ap = ckzalloc(sizeof(struct alias));
3214 ap->name = ckstrdup(name);
3215 ap->val = ckstrdup(val);
3216 /*ap->flag = 0; - ckzalloc did it */
3217 /*ap->next = NULL;*/
3218 *app = ap;
3220 INT_ON;
3223 static int
3224 unalias(const char *name)
3226 struct alias **app;
3228 app = __lookupalias(name);
3230 if (*app) {
3231 INT_OFF;
3232 *app = freealias(*app);
3233 INT_ON;
3234 return 0;
3237 return 1;
3240 static void
3241 rmaliases(void)
3243 struct alias *ap, **app;
3244 int i;
3246 INT_OFF;
3247 for (i = 0; i < ATABSIZE; i++) {
3248 app = &atab[i];
3249 for (ap = *app; ap; ap = *app) {
3250 *app = freealias(*app);
3251 if (ap == *app) {
3252 app = &ap->next;
3256 INT_ON;
3259 static void
3260 printalias(const struct alias *ap)
3262 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3266 * TODO - sort output
3268 static int FAST_FUNC
3269 aliascmd(int argc UNUSED_PARAM, char **argv)
3271 char *n, *v;
3272 int ret = 0;
3273 struct alias *ap;
3275 if (!argv[1]) {
3276 int i;
3278 for (i = 0; i < ATABSIZE; i++) {
3279 for (ap = atab[i]; ap; ap = ap->next) {
3280 printalias(ap);
3283 return 0;
3285 while ((n = *++argv) != NULL) {
3286 v = strchr(n+1, '=');
3287 if (v == NULL) { /* n+1: funny ksh stuff */
3288 ap = *__lookupalias(n);
3289 if (ap == NULL) {
3290 fprintf(stderr, "%s: %s not found\n", "alias", n);
3291 ret = 1;
3292 } else
3293 printalias(ap);
3294 } else {
3295 *v++ = '\0';
3296 setalias(n, v);
3300 return ret;
3303 static int FAST_FUNC
3304 unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3306 int i;
3308 while ((i = nextopt("a")) != '\0') {
3309 if (i == 'a') {
3310 rmaliases();
3311 return 0;
3314 for (i = 0; *argptr; argptr++) {
3315 if (unalias(*argptr)) {
3316 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3317 i = 1;
3321 return i;
3324 #endif /* ASH_ALIAS */
3327 /* ============ jobs.c */
3329 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3330 #define FORK_FG 0
3331 #define FORK_BG 1
3332 #define FORK_NOJOB 2
3334 /* mode flags for showjob(s) */
3335 #define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3336 #define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3337 #define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
3340 * A job structure contains information about a job. A job is either a
3341 * single process or a set of processes contained in a pipeline. In the
3342 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3343 * array of pids.
3345 struct procstat {
3346 pid_t ps_pid; /* process id */
3347 int ps_status; /* last process status from wait() */
3348 char *ps_cmd; /* text of command being run */
3351 struct job {
3352 struct procstat ps0; /* status of process */
3353 struct procstat *ps; /* status or processes when more than one */
3354 #if JOBS
3355 int stopstatus; /* status of a stopped job */
3356 #endif
3357 uint32_t
3358 nprocs: 16, /* number of processes */
3359 state: 8,
3360 #define JOBRUNNING 0 /* at least one proc running */
3361 #define JOBSTOPPED 1 /* all procs are stopped */
3362 #define JOBDONE 2 /* all procs are completed */
3363 #if JOBS
3364 sigint: 1, /* job was killed by SIGINT */
3365 jobctl: 1, /* job running under job control */
3366 #endif
3367 waited: 1, /* true if this entry has been waited for */
3368 used: 1, /* true if this entry is in used */
3369 changed: 1; /* true if status has changed */
3370 struct job *prev_job; /* previous job */
3373 static struct job *makejob(/*union node *,*/ int);
3374 static int forkshell(struct job *, union node *, int);
3375 static int waitforjob(struct job *);
3377 #if !JOBS
3378 enum { doing_jobctl = 0 };
3379 #define setjobctl(on) do {} while (0)
3380 #else
3381 static smallint doing_jobctl; //references:8
3382 static void setjobctl(int);
3383 #endif
3386 * Ignore a signal.
3388 static void
3389 ignoresig(int signo)
3391 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3392 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3393 /* No, need to do it */
3394 signal(signo, SIG_IGN);
3396 sigmode[signo - 1] = S_HARD_IGN;
3400 * Only one usage site - in setsignal()
3402 static void
3403 signal_handler(int signo)
3405 gotsig[signo - 1] = 1;
3407 if (signo == SIGINT && !trap[SIGINT]) {
3408 if (!suppress_int) {
3409 pending_sig = 0;
3410 raise_interrupt(); /* does not return */
3412 pending_int = 1;
3413 } else {
3414 pending_sig = signo;
3419 * Set the signal handler for the specified signal. The routine figures
3420 * out what it should be set to.
3422 static void
3423 setsignal(int signo)
3425 char *t;
3426 char cur_act, new_act;
3427 struct sigaction act;
3429 t = trap[signo];
3430 new_act = S_DFL;
3431 if (t != NULL) { /* trap for this sig is set */
3432 new_act = S_CATCH;
3433 if (t[0] == '\0') /* trap is "": ignore this sig */
3434 new_act = S_IGN;
3437 if (rootshell && new_act == S_DFL) {
3438 switch (signo) {
3439 case SIGINT:
3440 if (iflag || minusc || sflag == 0)
3441 new_act = S_CATCH;
3442 break;
3443 case SIGQUIT:
3444 #if DEBUG
3445 if (debug)
3446 break;
3447 #endif
3448 /* man bash:
3449 * "In all cases, bash ignores SIGQUIT. Non-builtin
3450 * commands run by bash have signal handlers
3451 * set to the values inherited by the shell
3452 * from its parent". */
3453 new_act = S_IGN;
3454 break;
3455 case SIGTERM:
3456 if (iflag)
3457 new_act = S_IGN;
3458 break;
3459 #if JOBS
3460 case SIGTSTP:
3461 case SIGTTOU:
3462 if (mflag)
3463 new_act = S_IGN;
3464 break;
3465 #endif
3468 //TODO: if !rootshell, we reset SIGQUIT to DFL,
3469 //whereas we have to restore it to what shell got on entry
3470 //from the parent. See comment above
3472 t = &sigmode[signo - 1];
3473 cur_act = *t;
3474 if (cur_act == 0) {
3475 /* current setting is not yet known */
3476 if (sigaction(signo, NULL, &act)) {
3477 /* pretend it worked; maybe we should give a warning,
3478 * but other shells don't. We don't alter sigmode,
3479 * so we retry every time.
3480 * btw, in Linux it never fails. --vda */
3481 return;
3483 if (act.sa_handler == SIG_IGN) {
3484 cur_act = S_HARD_IGN;
3485 if (mflag
3486 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3488 cur_act = S_IGN; /* don't hard ignore these */
3492 if (cur_act == S_HARD_IGN || cur_act == new_act)
3493 return;
3495 act.sa_handler = SIG_DFL;
3496 switch (new_act) {
3497 case S_CATCH:
3498 act.sa_handler = signal_handler;
3499 break;
3500 case S_IGN:
3501 act.sa_handler = SIG_IGN;
3502 break;
3505 /* flags and mask matter only if !DFL and !IGN, but we do it
3506 * for all cases for more deterministic behavior:
3508 act.sa_flags = 0;
3509 sigfillset(&act.sa_mask);
3511 sigaction_set(signo, &act);
3513 *t = new_act;
3516 /* mode flags for set_curjob */
3517 #define CUR_DELETE 2
3518 #define CUR_RUNNING 1
3519 #define CUR_STOPPED 0
3521 /* mode flags for dowait */
3522 #define DOWAIT_NONBLOCK WNOHANG
3523 #define DOWAIT_BLOCK 0
3525 #if JOBS
3526 /* pgrp of shell on invocation */
3527 static int initialpgrp; //references:2
3528 static int ttyfd = -1; //5
3529 #endif
3530 /* array of jobs */
3531 static struct job *jobtab; //5
3532 /* size of array */
3533 static unsigned njobs; //4
3534 /* current job */
3535 static struct job *curjob; //lots
3536 /* number of presumed living untracked jobs */
3537 static int jobless; //4
3539 static void
3540 set_curjob(struct job *jp, unsigned mode)
3542 struct job *jp1;
3543 struct job **jpp, **curp;
3545 /* first remove from list */
3546 jpp = curp = &curjob;
3547 while (1) {
3548 jp1 = *jpp;
3549 if (jp1 == jp)
3550 break;
3551 jpp = &jp1->prev_job;
3553 *jpp = jp1->prev_job;
3555 /* Then re-insert in correct position */
3556 jpp = curp;
3557 switch (mode) {
3558 default:
3559 #if DEBUG
3560 abort();
3561 #endif
3562 case CUR_DELETE:
3563 /* job being deleted */
3564 break;
3565 case CUR_RUNNING:
3566 /* newly created job or backgrounded job,
3567 * put after all stopped jobs.
3569 while (1) {
3570 jp1 = *jpp;
3571 #if JOBS
3572 if (!jp1 || jp1->state != JOBSTOPPED)
3573 #endif
3574 break;
3575 jpp = &jp1->prev_job;
3577 /* FALLTHROUGH */
3578 #if JOBS
3579 case CUR_STOPPED:
3580 #endif
3581 /* newly stopped job - becomes curjob */
3582 jp->prev_job = *jpp;
3583 *jpp = jp;
3584 break;
3588 #if JOBS || DEBUG
3589 static int
3590 jobno(const struct job *jp)
3592 return jp - jobtab + 1;
3594 #endif
3597 * Convert a job name to a job structure.
3599 #if !JOBS
3600 #define getjob(name, getctl) getjob(name)
3601 #endif
3602 static struct job *
3603 getjob(const char *name, int getctl)
3605 struct job *jp;
3606 struct job *found;
3607 const char *err_msg = "%s: no such job";
3608 unsigned num;
3609 int c;
3610 const char *p;
3611 char *(*match)(const char *, const char *);
3613 jp = curjob;
3614 p = name;
3615 if (!p)
3616 goto currentjob;
3618 if (*p != '%')
3619 goto err;
3621 c = *++p;
3622 if (!c)
3623 goto currentjob;
3625 if (!p[1]) {
3626 if (c == '+' || c == '%') {
3627 currentjob:
3628 err_msg = "No current job";
3629 goto check;
3631 if (c == '-') {
3632 if (jp)
3633 jp = jp->prev_job;
3634 err_msg = "No previous job";
3635 check:
3636 if (!jp)
3637 goto err;
3638 goto gotit;
3642 if (is_number(p)) {
3643 num = atoi(p);
3644 if (num < njobs) {
3645 jp = jobtab + num - 1;
3646 if (jp->used)
3647 goto gotit;
3648 goto err;
3652 match = prefix;
3653 if (*p == '?') {
3654 match = strstr;
3655 p++;
3658 found = NULL;
3659 while (jp) {
3660 if (match(jp->ps[0].ps_cmd, p)) {
3661 if (found)
3662 goto err;
3663 found = jp;
3664 err_msg = "%s: ambiguous";
3666 jp = jp->prev_job;
3668 if (!found)
3669 goto err;
3670 jp = found;
3672 gotit:
3673 #if JOBS
3674 err_msg = "job %s not created under job control";
3675 if (getctl && jp->jobctl == 0)
3676 goto err;
3677 #endif
3678 return jp;
3679 err:
3680 ash_msg_and_raise_error(err_msg, name);
3684 * Mark a job structure as unused.
3686 static void
3687 freejob(struct job *jp)
3689 struct procstat *ps;
3690 int i;
3692 INT_OFF;
3693 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3694 if (ps->ps_cmd != nullstr)
3695 free(ps->ps_cmd);
3697 if (jp->ps != &jp->ps0)
3698 free(jp->ps);
3699 jp->used = 0;
3700 set_curjob(jp, CUR_DELETE);
3701 INT_ON;
3704 #if JOBS
3705 static void
3706 xtcsetpgrp(int fd, pid_t pgrp)
3708 if (tcsetpgrp(fd, pgrp))
3709 ash_msg_and_raise_error("can't set tty process group (%m)");
3713 * Turn job control on and off.
3715 * Note: This code assumes that the third arg to ioctl is a character
3716 * pointer, which is true on Berkeley systems but not System V. Since
3717 * System V doesn't have job control yet, this isn't a problem now.
3719 * Called with interrupts off.
3721 static void
3722 setjobctl(int on)
3724 int fd;
3725 int pgrp;
3727 if (on == doing_jobctl || rootshell == 0)
3728 return;
3729 if (on) {
3730 int ofd;
3731 ofd = fd = open(_PATH_TTY, O_RDWR);
3732 if (fd < 0) {
3733 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3734 * That sometimes helps to acquire controlling tty.
3735 * Obviously, a workaround for bugs when someone
3736 * failed to provide a controlling tty to bash! :) */
3737 fd = 2;
3738 while (!isatty(fd))
3739 if (--fd < 0)
3740 goto out;
3742 fd = fcntl(fd, F_DUPFD, 10);
3743 if (ofd >= 0)
3744 close(ofd);
3745 if (fd < 0)
3746 goto out;
3747 /* fd is a tty at this point */
3748 close_on_exec_on(fd);
3749 while (1) { /* while we are in the background */
3750 pgrp = tcgetpgrp(fd);
3751 if (pgrp < 0) {
3752 out:
3753 ash_msg("can't access tty; job control turned off");
3754 mflag = on = 0;
3755 goto close;
3757 if (pgrp == getpgrp())
3758 break;
3759 killpg(0, SIGTTIN);
3761 initialpgrp = pgrp;
3763 setsignal(SIGTSTP);
3764 setsignal(SIGTTOU);
3765 setsignal(SIGTTIN);
3766 pgrp = rootpid;
3767 setpgid(0, pgrp);
3768 xtcsetpgrp(fd, pgrp);
3769 } else {
3770 /* turning job control off */
3771 fd = ttyfd;
3772 pgrp = initialpgrp;
3773 /* was xtcsetpgrp, but this can make exiting ash
3774 * loop forever if pty is already deleted */
3775 tcsetpgrp(fd, pgrp);
3776 setpgid(0, pgrp);
3777 setsignal(SIGTSTP);
3778 setsignal(SIGTTOU);
3779 setsignal(SIGTTIN);
3780 close:
3781 if (fd >= 0)
3782 close(fd);
3783 fd = -1;
3785 ttyfd = fd;
3786 doing_jobctl = on;
3789 static int FAST_FUNC
3790 killcmd(int argc, char **argv)
3792 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3793 int i = 1;
3794 do {
3795 if (argv[i][0] == '%') {
3797 * "kill %N" - job kill
3798 * Converting to pgrp / pid kill
3800 struct job *jp;
3801 char *dst;
3802 int j, n;
3804 jp = getjob(argv[i], 0);
3806 * In jobs started under job control, we signal
3807 * entire process group by kill -PGRP_ID.
3808 * This happens, f.e., in interactive shell.
3810 * Otherwise, we signal each child via
3811 * kill PID1 PID2 PID3.
3812 * Testcases:
3813 * sh -c 'sleep 1|sleep 1 & kill %1'
3814 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3815 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3817 n = jp->nprocs; /* can't be 0 (I hope) */
3818 if (jp->jobctl)
3819 n = 1;
3820 dst = alloca(n * sizeof(int)*4);
3821 argv[i] = dst;
3822 for (j = 0; j < n; j++) {
3823 struct procstat *ps = &jp->ps[j];
3824 /* Skip non-running and not-stopped members
3825 * (i.e. dead members) of the job
3827 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3828 continue;
3830 * kill_main has matching code to expect
3831 * leading space. Needed to not confuse
3832 * negative pids with "kill -SIGNAL_NO" syntax
3834 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3836 *dst = '\0';
3838 } while (argv[++i]);
3840 return kill_main(argc, argv);
3843 static void
3844 showpipe(struct job *jp /*, FILE *out*/)
3846 struct procstat *ps;
3847 struct procstat *psend;
3849 psend = jp->ps + jp->nprocs;
3850 for (ps = jp->ps + 1; ps < psend; ps++)
3851 printf(" | %s", ps->ps_cmd);
3852 outcslow('\n', stdout);
3853 flush_stdout_stderr();
3857 static int
3858 restartjob(struct job *jp, int mode)
3860 struct procstat *ps;
3861 int i;
3862 int status;
3863 pid_t pgid;
3865 INT_OFF;
3866 if (jp->state == JOBDONE)
3867 goto out;
3868 jp->state = JOBRUNNING;
3869 pgid = jp->ps[0].ps_pid;
3870 if (mode == FORK_FG)
3871 xtcsetpgrp(ttyfd, pgid);
3872 killpg(pgid, SIGCONT);
3873 ps = jp->ps;
3874 i = jp->nprocs;
3875 do {
3876 if (WIFSTOPPED(ps->ps_status)) {
3877 ps->ps_status = -1;
3879 ps++;
3880 } while (--i);
3881 out:
3882 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3883 INT_ON;
3884 return status;
3887 static int FAST_FUNC
3888 fg_bgcmd(int argc UNUSED_PARAM, char **argv)
3890 struct job *jp;
3891 int mode;
3892 int retval;
3894 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3895 nextopt(nullstr);
3896 argv = argptr;
3897 do {
3898 jp = getjob(*argv, 1);
3899 if (mode == FORK_BG) {
3900 set_curjob(jp, CUR_RUNNING);
3901 printf("[%d] ", jobno(jp));
3903 out1str(jp->ps[0].ps_cmd);
3904 showpipe(jp /*, stdout*/);
3905 retval = restartjob(jp, mode);
3906 } while (*argv && *++argv);
3907 return retval;
3909 #endif
3911 static int
3912 sprint_status(char *s, int status, int sigonly)
3914 int col;
3915 int st;
3917 col = 0;
3918 if (!WIFEXITED(status)) {
3919 #if JOBS
3920 if (WIFSTOPPED(status))
3921 st = WSTOPSIG(status);
3922 else
3923 #endif
3924 st = WTERMSIG(status);
3925 if (sigonly) {
3926 if (st == SIGINT || st == SIGPIPE)
3927 goto out;
3928 #if JOBS
3929 if (WIFSTOPPED(status))
3930 goto out;
3931 #endif
3933 st &= 0x7f;
3934 //TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
3935 col = fmtstr(s, 32, strsignal(st));
3936 if (WCOREDUMP(status)) {
3937 col += fmtstr(s + col, 16, " (core dumped)");
3939 } else if (!sigonly) {
3940 st = WEXITSTATUS(status);
3941 if (st)
3942 col = fmtstr(s, 16, "Done(%d)", st);
3943 else
3944 col = fmtstr(s, 16, "Done");
3946 out:
3947 return col;
3950 static int
3951 dowait(int wait_flags, struct job *job)
3953 int pid;
3954 int status;
3955 struct job *jp;
3956 struct job *thisjob;
3957 int state;
3959 TRACE(("dowait(0x%x) called\n", wait_flags));
3961 /* Do a wait system call. If job control is compiled in, we accept
3962 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3963 * NB: _not_ safe_waitpid, we need to detect EINTR */
3964 if (doing_jobctl)
3965 wait_flags |= WUNTRACED;
3966 pid = waitpid(-1, &status, wait_flags);
3967 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3968 pid, status, errno, strerror(errno)));
3969 if (pid <= 0)
3970 return pid;
3972 INT_OFF;
3973 thisjob = NULL;
3974 for (jp = curjob; jp; jp = jp->prev_job) {
3975 struct procstat *ps;
3976 struct procstat *psend;
3977 if (jp->state == JOBDONE)
3978 continue;
3979 state = JOBDONE;
3980 ps = jp->ps;
3981 psend = ps + jp->nprocs;
3982 do {
3983 if (ps->ps_pid == pid) {
3984 TRACE(("Job %d: changing status of proc %d "
3985 "from 0x%x to 0x%x\n",
3986 jobno(jp), pid, ps->ps_status, status));
3987 ps->ps_status = status;
3988 thisjob = jp;
3990 if (ps->ps_status == -1)
3991 state = JOBRUNNING;
3992 #if JOBS
3993 if (state == JOBRUNNING)
3994 continue;
3995 if (WIFSTOPPED(ps->ps_status)) {
3996 jp->stopstatus = ps->ps_status;
3997 state = JOBSTOPPED;
3999 #endif
4000 } while (++ps < psend);
4001 if (thisjob)
4002 goto gotjob;
4004 #if JOBS
4005 if (!WIFSTOPPED(status))
4006 #endif
4007 jobless--;
4008 goto out;
4010 gotjob:
4011 if (state != JOBRUNNING) {
4012 thisjob->changed = 1;
4014 if (thisjob->state != state) {
4015 TRACE(("Job %d: changing state from %d to %d\n",
4016 jobno(thisjob), thisjob->state, state));
4017 thisjob->state = state;
4018 #if JOBS
4019 if (state == JOBSTOPPED) {
4020 set_curjob(thisjob, CUR_STOPPED);
4022 #endif
4026 out:
4027 INT_ON;
4029 if (thisjob && thisjob == job) {
4030 char s[48 + 1];
4031 int len;
4033 len = sprint_status(s, status, 1);
4034 if (len) {
4035 s[len] = '\n';
4036 s[len + 1] = '\0';
4037 out2str(s);
4040 return pid;
4043 static int
4044 blocking_wait_with_raise_on_sig(void)
4046 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
4047 if (pid <= 0 && pending_sig)
4048 raise_exception(EXSIG);
4049 return pid;
4052 #if JOBS
4053 static void
4054 showjob(FILE *out, struct job *jp, int mode)
4056 struct procstat *ps;
4057 struct procstat *psend;
4058 int col;
4059 int indent_col;
4060 char s[80];
4062 ps = jp->ps;
4064 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
4065 /* just output process (group) id of pipeline */
4066 fprintf(out, "%d\n", ps->ps_pid);
4067 return;
4070 col = fmtstr(s, 16, "[%d] ", jobno(jp));
4071 indent_col = col;
4073 if (jp == curjob)
4074 s[col - 3] = '+';
4075 else if (curjob && jp == curjob->prev_job)
4076 s[col - 3] = '-';
4078 if (mode & SHOW_PIDS)
4079 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
4081 psend = ps + jp->nprocs;
4083 if (jp->state == JOBRUNNING) {
4084 strcpy(s + col, "Running");
4085 col += sizeof("Running") - 1;
4086 } else {
4087 int status = psend[-1].ps_status;
4088 if (jp->state == JOBSTOPPED)
4089 status = jp->stopstatus;
4090 col += sprint_status(s + col, status, 0);
4092 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
4094 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4095 * or prints several "PID | <cmdN>" lines,
4096 * depending on SHOW_PIDS bit.
4097 * We do not print status of individual processes
4098 * between PID and <cmdN>. bash does it, but not very well:
4099 * first line shows overall job status, not process status,
4100 * making it impossible to know 1st process status.
4102 goto start;
4103 do {
4104 /* for each process */
4105 s[0] = '\0';
4106 col = 33;
4107 if (mode & SHOW_PIDS)
4108 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
4109 start:
4110 fprintf(out, "%s%*c%s%s",
4112 33 - col >= 0 ? 33 - col : 0, ' ',
4113 ps == jp->ps ? "" : "| ",
4114 ps->ps_cmd
4116 } while (++ps != psend);
4117 outcslow('\n', out);
4119 jp->changed = 0;
4121 if (jp->state == JOBDONE) {
4122 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4123 freejob(jp);
4128 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4129 * statuses have changed since the last call to showjobs.
4131 static void
4132 showjobs(FILE *out, int mode)
4134 struct job *jp;
4136 TRACE(("showjobs(0x%x) called\n", mode));
4138 /* Handle all finished jobs */
4139 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
4140 continue;
4142 for (jp = curjob; jp; jp = jp->prev_job) {
4143 if (!(mode & SHOW_CHANGED) || jp->changed) {
4144 showjob(out, jp, mode);
4149 static int FAST_FUNC
4150 jobscmd(int argc UNUSED_PARAM, char **argv)
4152 int mode, m;
4154 mode = 0;
4155 while ((m = nextopt("lp")) != '\0') {
4156 if (m == 'l')
4157 mode |= SHOW_PIDS;
4158 else
4159 mode |= SHOW_ONLY_PGID;
4162 argv = argptr;
4163 if (*argv) {
4165 showjob(stdout, getjob(*argv, 0), mode);
4166 while (*++argv);
4167 } else {
4168 showjobs(stdout, mode);
4171 return 0;
4173 #endif /* JOBS */
4175 /* Called only on finished or stopped jobs (no members are running) */
4176 static int
4177 getstatus(struct job *job)
4179 int status;
4180 int retval;
4181 struct procstat *ps;
4183 /* Fetch last member's status */
4184 ps = job->ps + job->nprocs - 1;
4185 status = ps->ps_status;
4186 if (pipefail) {
4187 /* "set -o pipefail" mode: use last _nonzero_ status */
4188 while (status == 0 && --ps >= job->ps)
4189 status = ps->ps_status;
4192 retval = WEXITSTATUS(status);
4193 if (!WIFEXITED(status)) {
4194 #if JOBS
4195 retval = WSTOPSIG(status);
4196 if (!WIFSTOPPED(status))
4197 #endif
4199 /* XXX: limits number of signals */
4200 retval = WTERMSIG(status);
4201 #if JOBS
4202 if (retval == SIGINT)
4203 job->sigint = 1;
4204 #endif
4206 retval += 128;
4208 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4209 jobno(job), job->nprocs, status, retval));
4210 return retval;
4213 static int FAST_FUNC
4214 waitcmd(int argc UNUSED_PARAM, char **argv)
4216 struct job *job;
4217 int retval;
4218 struct job *jp;
4220 if (pending_sig)
4221 raise_exception(EXSIG);
4223 nextopt(nullstr);
4224 retval = 0;
4226 argv = argptr;
4227 if (!*argv) {
4228 /* wait for all jobs */
4229 for (;;) {
4230 jp = curjob;
4231 while (1) {
4232 if (!jp) /* no running procs */
4233 goto ret;
4234 if (jp->state == JOBRUNNING)
4235 break;
4236 jp->waited = 1;
4237 jp = jp->prev_job;
4239 blocking_wait_with_raise_on_sig();
4240 /* man bash:
4241 * "When bash is waiting for an asynchronous command via
4242 * the wait builtin, the reception of a signal for which a trap
4243 * has been set will cause the wait builtin to return immediately
4244 * with an exit status greater than 128, immediately after which
4245 * the trap is executed."
4247 * blocking_wait_with_raise_on_sig raises signal handlers
4248 * if it gets no pid (pid < 0). However,
4249 * if child sends us a signal *and immediately exits*,
4250 * blocking_wait_with_raise_on_sig gets pid > 0
4251 * and does not handle pending_sig. Check this case: */
4252 if (pending_sig)
4253 raise_exception(EXSIG);
4257 retval = 127;
4258 do {
4259 if (**argv != '%') {
4260 pid_t pid = number(*argv);
4261 job = curjob;
4262 while (1) {
4263 if (!job)
4264 goto repeat;
4265 if (job->ps[job->nprocs - 1].ps_pid == pid)
4266 break;
4267 job = job->prev_job;
4269 } else {
4270 job = getjob(*argv, 0);
4272 /* loop until process terminated or stopped */
4273 while (job->state == JOBRUNNING)
4274 blocking_wait_with_raise_on_sig();
4275 job->waited = 1;
4276 retval = getstatus(job);
4277 repeat: ;
4278 } while (*++argv);
4280 ret:
4281 return retval;
4284 static struct job *
4285 growjobtab(void)
4287 size_t len;
4288 ptrdiff_t offset;
4289 struct job *jp, *jq;
4291 len = njobs * sizeof(*jp);
4292 jq = jobtab;
4293 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4295 offset = (char *)jp - (char *)jq;
4296 if (offset) {
4297 /* Relocate pointers */
4298 size_t l = len;
4300 jq = (struct job *)((char *)jq + l);
4301 while (l) {
4302 l -= sizeof(*jp);
4303 jq--;
4304 #define joff(p) ((struct job *)((char *)(p) + l))
4305 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4306 if (joff(jp)->ps == &jq->ps0)
4307 jmove(joff(jp)->ps);
4308 if (joff(jp)->prev_job)
4309 jmove(joff(jp)->prev_job);
4311 if (curjob)
4312 jmove(curjob);
4313 #undef joff
4314 #undef jmove
4317 njobs += 4;
4318 jobtab = jp;
4319 jp = (struct job *)((char *)jp + len);
4320 jq = jp + 3;
4321 do {
4322 jq->used = 0;
4323 } while (--jq >= jp);
4324 return jp;
4328 * Return a new job structure.
4329 * Called with interrupts off.
4331 static struct job *
4332 makejob(/*union node *node,*/ int nprocs)
4334 int i;
4335 struct job *jp;
4337 for (i = njobs, jp = jobtab; ; jp++) {
4338 if (--i < 0) {
4339 jp = growjobtab();
4340 break;
4342 if (jp->used == 0)
4343 break;
4344 if (jp->state != JOBDONE || !jp->waited)
4345 continue;
4346 #if JOBS
4347 if (doing_jobctl)
4348 continue;
4349 #endif
4350 freejob(jp);
4351 break;
4353 memset(jp, 0, sizeof(*jp));
4354 #if JOBS
4355 /* jp->jobctl is a bitfield.
4356 * "jp->jobctl |= jobctl" likely to give awful code */
4357 if (doing_jobctl)
4358 jp->jobctl = 1;
4359 #endif
4360 jp->prev_job = curjob;
4361 curjob = jp;
4362 jp->used = 1;
4363 jp->ps = &jp->ps0;
4364 if (nprocs > 1) {
4365 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4367 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4368 jobno(jp)));
4369 return jp;
4372 #if JOBS
4374 * Return a string identifying a command (to be printed by the
4375 * jobs command).
4377 static char *cmdnextc;
4379 static void
4380 cmdputs(const char *s)
4382 static const char vstype[VSTYPE + 1][3] = {
4383 "", "}", "-", "+", "?", "=",
4384 "%", "%%", "#", "##"
4385 IF_ASH_BASH_COMPAT(, ":", "/", "//")
4388 const char *p, *str;
4389 char cc[2];
4390 char *nextc;
4391 unsigned char c;
4392 unsigned char subtype = 0;
4393 int quoted = 0;
4395 cc[1] = '\0';
4396 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4397 p = s;
4398 while ((c = *p++) != '\0') {
4399 str = NULL;
4400 switch (c) {
4401 case CTLESC:
4402 c = *p++;
4403 break;
4404 case CTLVAR:
4405 subtype = *p++;
4406 if ((subtype & VSTYPE) == VSLENGTH)
4407 str = "${#";
4408 else
4409 str = "${";
4410 if (!(subtype & VSQUOTE) == !(quoted & 1))
4411 goto dostr;
4412 quoted ^= 1;
4413 c = '"';
4414 break;
4415 case CTLENDVAR:
4416 str = "\"}" + !(quoted & 1);
4417 quoted >>= 1;
4418 subtype = 0;
4419 goto dostr;
4420 case CTLBACKQ:
4421 str = "$(...)";
4422 goto dostr;
4423 case CTLBACKQ+CTLQUOTE:
4424 str = "\"$(...)\"";
4425 goto dostr;
4426 #if ENABLE_SH_MATH_SUPPORT
4427 case CTLARI:
4428 str = "$((";
4429 goto dostr;
4430 case CTLENDARI:
4431 str = "))";
4432 goto dostr;
4433 #endif
4434 case CTLQUOTEMARK:
4435 quoted ^= 1;
4436 c = '"';
4437 break;
4438 case '=':
4439 if (subtype == 0)
4440 break;
4441 if ((subtype & VSTYPE) != VSNORMAL)
4442 quoted <<= 1;
4443 str = vstype[subtype & VSTYPE];
4444 if (subtype & VSNUL)
4445 c = ':';
4446 else
4447 goto checkstr;
4448 break;
4449 case '\'':
4450 case '\\':
4451 case '"':
4452 case '$':
4453 /* These can only happen inside quotes */
4454 cc[0] = c;
4455 str = cc;
4456 c = '\\';
4457 break;
4458 default:
4459 break;
4461 USTPUTC(c, nextc);
4462 checkstr:
4463 if (!str)
4464 continue;
4465 dostr:
4466 while ((c = *str++) != '\0') {
4467 USTPUTC(c, nextc);
4469 } /* while *p++ not NUL */
4471 if (quoted & 1) {
4472 USTPUTC('"', nextc);
4474 *nextc = 0;
4475 cmdnextc = nextc;
4478 /* cmdtxt() and cmdlist() call each other */
4479 static void cmdtxt(union node *n);
4481 static void
4482 cmdlist(union node *np, int sep)
4484 for (; np; np = np->narg.next) {
4485 if (!sep)
4486 cmdputs(" ");
4487 cmdtxt(np);
4488 if (sep && np->narg.next)
4489 cmdputs(" ");
4493 static void
4494 cmdtxt(union node *n)
4496 union node *np;
4497 struct nodelist *lp;
4498 const char *p;
4500 if (!n)
4501 return;
4502 switch (n->type) {
4503 default:
4504 #if DEBUG
4505 abort();
4506 #endif
4507 case NPIPE:
4508 lp = n->npipe.cmdlist;
4509 for (;;) {
4510 cmdtxt(lp->n);
4511 lp = lp->next;
4512 if (!lp)
4513 break;
4514 cmdputs(" | ");
4516 break;
4517 case NSEMI:
4518 p = "; ";
4519 goto binop;
4520 case NAND:
4521 p = " && ";
4522 goto binop;
4523 case NOR:
4524 p = " || ";
4525 binop:
4526 cmdtxt(n->nbinary.ch1);
4527 cmdputs(p);
4528 n = n->nbinary.ch2;
4529 goto donode;
4530 case NREDIR:
4531 case NBACKGND:
4532 n = n->nredir.n;
4533 goto donode;
4534 case NNOT:
4535 cmdputs("!");
4536 n = n->nnot.com;
4537 donode:
4538 cmdtxt(n);
4539 break;
4540 case NIF:
4541 cmdputs("if ");
4542 cmdtxt(n->nif.test);
4543 cmdputs("; then ");
4544 if (n->nif.elsepart) {
4545 cmdtxt(n->nif.ifpart);
4546 cmdputs("; else ");
4547 n = n->nif.elsepart;
4548 } else {
4549 n = n->nif.ifpart;
4551 p = "; fi";
4552 goto dotail;
4553 case NSUBSHELL:
4554 cmdputs("(");
4555 n = n->nredir.n;
4556 p = ")";
4557 goto dotail;
4558 case NWHILE:
4559 p = "while ";
4560 goto until;
4561 case NUNTIL:
4562 p = "until ";
4563 until:
4564 cmdputs(p);
4565 cmdtxt(n->nbinary.ch1);
4566 n = n->nbinary.ch2;
4567 p = "; done";
4568 dodo:
4569 cmdputs("; do ");
4570 dotail:
4571 cmdtxt(n);
4572 goto dotail2;
4573 case NFOR:
4574 cmdputs("for ");
4575 cmdputs(n->nfor.var);
4576 cmdputs(" in ");
4577 cmdlist(n->nfor.args, 1);
4578 n = n->nfor.body;
4579 p = "; done";
4580 goto dodo;
4581 case NDEFUN:
4582 cmdputs(n->narg.text);
4583 p = "() { ... }";
4584 goto dotail2;
4585 case NCMD:
4586 cmdlist(n->ncmd.args, 1);
4587 cmdlist(n->ncmd.redirect, 0);
4588 break;
4589 case NARG:
4590 p = n->narg.text;
4591 dotail2:
4592 cmdputs(p);
4593 break;
4594 case NHERE:
4595 case NXHERE:
4596 p = "<<...";
4597 goto dotail2;
4598 case NCASE:
4599 cmdputs("case ");
4600 cmdputs(n->ncase.expr->narg.text);
4601 cmdputs(" in ");
4602 for (np = n->ncase.cases; np; np = np->nclist.next) {
4603 cmdtxt(np->nclist.pattern);
4604 cmdputs(") ");
4605 cmdtxt(np->nclist.body);
4606 cmdputs(";; ");
4608 p = "esac";
4609 goto dotail2;
4610 case NTO:
4611 p = ">";
4612 goto redir;
4613 case NCLOBBER:
4614 p = ">|";
4615 goto redir;
4616 case NAPPEND:
4617 p = ">>";
4618 goto redir;
4619 #if ENABLE_ASH_BASH_COMPAT
4620 case NTO2:
4621 #endif
4622 case NTOFD:
4623 p = ">&";
4624 goto redir;
4625 case NFROM:
4626 p = "<";
4627 goto redir;
4628 case NFROMFD:
4629 p = "<&";
4630 goto redir;
4631 case NFROMTO:
4632 p = "<>";
4633 redir:
4634 cmdputs(utoa(n->nfile.fd));
4635 cmdputs(p);
4636 if (n->type == NTOFD || n->type == NFROMFD) {
4637 cmdputs(utoa(n->ndup.dupfd));
4638 break;
4640 n = n->nfile.fname;
4641 goto donode;
4645 static char *
4646 commandtext(union node *n)
4648 char *name;
4650 STARTSTACKSTR(cmdnextc);
4651 cmdtxt(n);
4652 name = stackblock();
4653 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4654 name, cmdnextc, cmdnextc));
4655 return ckstrdup(name);
4657 #endif /* JOBS */
4660 * Fork off a subshell. If we are doing job control, give the subshell its
4661 * own process group. Jp is a job structure that the job is to be added to.
4662 * N is the command that will be evaluated by the child. Both jp and n may
4663 * be NULL. The mode parameter can be one of the following:
4664 * FORK_FG - Fork off a foreground process.
4665 * FORK_BG - Fork off a background process.
4666 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4667 * process group even if job control is on.
4669 * When job control is turned off, background processes have their standard
4670 * input redirected to /dev/null (except for the second and later processes
4671 * in a pipeline).
4673 * Called with interrupts off.
4676 * Clear traps on a fork.
4678 static void
4679 clear_traps(void)
4681 char **tp;
4683 for (tp = trap; tp < &trap[NSIG]; tp++) {
4684 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4685 INT_OFF;
4686 if (trap_ptr == trap)
4687 free(*tp);
4688 /* else: it "belongs" to trap_ptr vector, don't free */
4689 *tp = NULL;
4690 if ((tp - trap) != 0)
4691 setsignal(tp - trap);
4692 INT_ON;
4695 may_have_traps = 0;
4698 /* Lives far away from here, needed for forkchild */
4699 static void closescript(void);
4701 /* Called after fork(), in child */
4702 static NOINLINE void
4703 forkchild(struct job *jp, union node *n, int mode)
4705 int oldlvl;
4707 TRACE(("Child shell %d\n", getpid()));
4708 oldlvl = shlvl;
4709 shlvl++;
4711 /* man bash: "Non-builtin commands run by bash have signal handlers
4712 * set to the values inherited by the shell from its parent".
4713 * Do we do it correctly? */
4715 closescript();
4717 if (mode == FORK_NOJOB /* is it `xxx` ? */
4718 && n && n->type == NCMD /* is it single cmd? */
4719 /* && n->ncmd.args->type == NARG - always true? */
4720 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
4721 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4722 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4724 TRACE(("Trap hack\n"));
4725 /* Awful hack for `trap` or $(trap).
4727 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4728 * contains an example where "trap" is executed in a subshell:
4730 * save_traps=$(trap)
4731 * ...
4732 * eval "$save_traps"
4734 * Standard does not say that "trap" in subshell shall print
4735 * parent shell's traps. It only says that its output
4736 * must have suitable form, but then, in the above example
4737 * (which is not supposed to be normative), it implies that.
4739 * bash (and probably other shell) does implement it
4740 * (traps are reset to defaults, but "trap" still shows them),
4741 * but as a result, "trap" logic is hopelessly messed up:
4743 * # trap
4744 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4745 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4746 * # true | trap <--- trap is in subshell - no output (ditto)
4747 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4748 * trap -- 'echo Ho' SIGWINCH
4749 * # echo `(trap)` <--- in subshell in subshell - output
4750 * trap -- 'echo Ho' SIGWINCH
4751 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4752 * trap -- 'echo Ho' SIGWINCH
4754 * The rules when to forget and when to not forget traps
4755 * get really complex and nonsensical.
4757 * Our solution: ONLY bare $(trap) or `trap` is special.
4759 /* Save trap handler strings for trap builtin to print */
4760 trap_ptr = memcpy(xmalloc(sizeof(trap)), trap, sizeof(trap));
4761 /* Fall through into clearing traps */
4763 clear_traps();
4764 #if JOBS
4765 /* do job control only in root shell */
4766 doing_jobctl = 0;
4767 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
4768 pid_t pgrp;
4770 if (jp->nprocs == 0)
4771 pgrp = getpid();
4772 else
4773 pgrp = jp->ps[0].ps_pid;
4774 /* this can fail because we are doing it in the parent also */
4775 setpgid(0, pgrp);
4776 if (mode == FORK_FG)
4777 xtcsetpgrp(ttyfd, pgrp);
4778 setsignal(SIGTSTP);
4779 setsignal(SIGTTOU);
4780 } else
4781 #endif
4782 if (mode == FORK_BG) {
4783 /* man bash: "When job control is not in effect,
4784 * asynchronous commands ignore SIGINT and SIGQUIT" */
4785 ignoresig(SIGINT);
4786 ignoresig(SIGQUIT);
4787 if (jp->nprocs == 0) {
4788 close(0);
4789 if (open(bb_dev_null, O_RDONLY) != 0)
4790 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
4793 if (oldlvl == 0) {
4794 if (iflag) { /* why if iflag only? */
4795 setsignal(SIGINT);
4796 setsignal(SIGTERM);
4798 /* man bash:
4799 * "In all cases, bash ignores SIGQUIT. Non-builtin
4800 * commands run by bash have signal handlers
4801 * set to the values inherited by the shell
4802 * from its parent".
4803 * Take care of the second rule: */
4804 setsignal(SIGQUIT);
4806 #if JOBS
4807 if (n && n->type == NCMD
4808 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
4810 TRACE(("Job hack\n"));
4811 /* "jobs": we do not want to clear job list for it,
4812 * instead we remove only _its_ own_ job from job list.
4813 * This makes "jobs .... | cat" more useful.
4815 freejob(curjob);
4816 return;
4818 #endif
4819 for (jp = curjob; jp; jp = jp->prev_job)
4820 freejob(jp);
4821 jobless = 0;
4824 /* Called after fork(), in parent */
4825 #if !JOBS
4826 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4827 #endif
4828 static void
4829 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4831 TRACE(("In parent shell: child = %d\n", pid));
4832 if (!jp) {
4833 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4834 continue;
4835 jobless++;
4836 return;
4838 #if JOBS
4839 if (mode != FORK_NOJOB && jp->jobctl) {
4840 int pgrp;
4842 if (jp->nprocs == 0)
4843 pgrp = pid;
4844 else
4845 pgrp = jp->ps[0].ps_pid;
4846 /* This can fail because we are doing it in the child also */
4847 setpgid(pid, pgrp);
4849 #endif
4850 if (mode == FORK_BG) {
4851 backgndpid = pid; /* set $! */
4852 set_curjob(jp, CUR_RUNNING);
4854 if (jp) {
4855 struct procstat *ps = &jp->ps[jp->nprocs++];
4856 ps->ps_pid = pid;
4857 ps->ps_status = -1;
4858 ps->ps_cmd = nullstr;
4859 #if JOBS
4860 if (doing_jobctl && n)
4861 ps->ps_cmd = commandtext(n);
4862 #endif
4866 static int
4867 forkshell(struct job *jp, union node *n, int mode)
4869 int pid;
4871 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4872 pid = fork();
4873 if (pid < 0) {
4874 TRACE(("Fork failed, errno=%d", errno));
4875 if (jp)
4876 freejob(jp);
4877 ash_msg_and_raise_error("can't fork");
4879 if (pid == 0) {
4880 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
4881 forkchild(jp, n, mode);
4882 } else {
4883 forkparent(jp, n, mode, pid);
4885 return pid;
4889 * Wait for job to finish.
4891 * Under job control we have the problem that while a child process
4892 * is running interrupts generated by the user are sent to the child
4893 * but not to the shell. This means that an infinite loop started by
4894 * an interactive user may be hard to kill. With job control turned off,
4895 * an interactive user may place an interactive program inside a loop.
4896 * If the interactive program catches interrupts, the user doesn't want
4897 * these interrupts to also abort the loop. The approach we take here
4898 * is to have the shell ignore interrupt signals while waiting for a
4899 * foreground process to terminate, and then send itself an interrupt
4900 * signal if the child process was terminated by an interrupt signal.
4901 * Unfortunately, some programs want to do a bit of cleanup and then
4902 * exit on interrupt; unless these processes terminate themselves by
4903 * sending a signal to themselves (instead of calling exit) they will
4904 * confuse this approach.
4906 * Called with interrupts off.
4908 static int
4909 waitforjob(struct job *jp)
4911 int st;
4913 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4915 INT_OFF;
4916 while (jp->state == JOBRUNNING) {
4917 /* In non-interactive shells, we _can_ get
4918 * a keyboard signal here and be EINTRed,
4919 * but we just loop back, waiting for command to complete.
4921 * man bash:
4922 * "If bash is waiting for a command to complete and receives
4923 * a signal for which a trap has been set, the trap
4924 * will not be executed until the command completes."
4926 * Reality is that even if trap is not set, bash
4927 * will not act on the signal until command completes.
4928 * Try this. sleep5intoff.c:
4929 * #include <signal.h>
4930 * #include <unistd.h>
4931 * int main() {
4932 * sigset_t set;
4933 * sigemptyset(&set);
4934 * sigaddset(&set, SIGINT);
4935 * sigaddset(&set, SIGQUIT);
4936 * sigprocmask(SIG_BLOCK, &set, NULL);
4937 * sleep(5);
4938 * return 0;
4940 * $ bash -c './sleep5intoff; echo hi'
4941 * ^C^C^C^C <--- pressing ^C once a second
4942 * $ _
4943 * $ bash -c './sleep5intoff; echo hi'
4944 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4945 * $ _
4947 dowait(DOWAIT_BLOCK, jp);
4949 INT_ON;
4951 st = getstatus(jp);
4952 #if JOBS
4953 if (jp->jobctl) {
4954 xtcsetpgrp(ttyfd, rootpid);
4956 * This is truly gross.
4957 * If we're doing job control, then we did a TIOCSPGRP which
4958 * caused us (the shell) to no longer be in the controlling
4959 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4960 * intuit from the subprocess exit status whether a SIGINT
4961 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4963 if (jp->sigint) /* TODO: do the same with all signals */
4964 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4966 if (jp->state == JOBDONE)
4967 #endif
4968 freejob(jp);
4969 return st;
4973 * return 1 if there are stopped jobs, otherwise 0
4975 static int
4976 stoppedjobs(void)
4978 struct job *jp;
4979 int retval;
4981 retval = 0;
4982 if (job_warning)
4983 goto out;
4984 jp = curjob;
4985 if (jp && jp->state == JOBSTOPPED) {
4986 out2str("You have stopped jobs.\n");
4987 job_warning = 2;
4988 retval++;
4990 out:
4991 return retval;
4995 /* ============ redir.c
4997 * Code for dealing with input/output redirection.
5000 #undef EMPTY
5001 #undef CLOSED
5002 #define EMPTY -2 /* marks an unused slot in redirtab */
5003 #define CLOSED -3 /* marks a slot of previously-closed fd */
5006 * Open a file in noclobber mode.
5007 * The code was copied from bash.
5009 static int
5010 noclobberopen(const char *fname)
5012 int r, fd;
5013 struct stat finfo, finfo2;
5016 * If the file exists and is a regular file, return an error
5017 * immediately.
5019 r = stat(fname, &finfo);
5020 if (r == 0 && S_ISREG(finfo.st_mode)) {
5021 errno = EEXIST;
5022 return -1;
5026 * If the file was not present (r != 0), make sure we open it
5027 * exclusively so that if it is created before we open it, our open
5028 * will fail. Make sure that we do not truncate an existing file.
5029 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5030 * file was not a regular file, we leave O_EXCL off.
5032 if (r != 0)
5033 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5034 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5036 /* If the open failed, return the file descriptor right away. */
5037 if (fd < 0)
5038 return fd;
5041 * OK, the open succeeded, but the file may have been changed from a
5042 * non-regular file to a regular file between the stat and the open.
5043 * We are assuming that the O_EXCL open handles the case where FILENAME
5044 * did not exist and is symlinked to an existing file between the stat
5045 * and open.
5049 * If we can open it and fstat the file descriptor, and neither check
5050 * revealed that it was a regular file, and the file has not been
5051 * replaced, return the file descriptor.
5053 if (fstat(fd, &finfo2) == 0
5054 && !S_ISREG(finfo2.st_mode)
5055 && finfo.st_dev == finfo2.st_dev
5056 && finfo.st_ino == finfo2.st_ino
5058 return fd;
5061 /* The file has been replaced. badness. */
5062 close(fd);
5063 errno = EEXIST;
5064 return -1;
5068 * Handle here documents. Normally we fork off a process to write the
5069 * data to a pipe. If the document is short, we can stuff the data in
5070 * the pipe without forking.
5072 /* openhere needs this forward reference */
5073 static void expandhere(union node *arg, int fd);
5074 static int
5075 openhere(union node *redir)
5077 int pip[2];
5078 size_t len = 0;
5080 if (pipe(pip) < 0)
5081 ash_msg_and_raise_error("pipe call failed");
5082 if (redir->type == NHERE) {
5083 len = strlen(redir->nhere.doc->narg.text);
5084 if (len <= PIPE_BUF) {
5085 full_write(pip[1], redir->nhere.doc->narg.text, len);
5086 goto out;
5089 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5090 /* child */
5091 close(pip[0]);
5092 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5093 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5094 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5095 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5096 signal(SIGPIPE, SIG_DFL);
5097 if (redir->type == NHERE)
5098 full_write(pip[1], redir->nhere.doc->narg.text, len);
5099 else /* NXHERE */
5100 expandhere(redir->nhere.doc, pip[1]);
5101 _exit(EXIT_SUCCESS);
5103 out:
5104 close(pip[1]);
5105 return pip[0];
5108 static int
5109 openredirect(union node *redir)
5111 char *fname;
5112 int f;
5114 fname = redir->nfile.expfname;
5115 switch (redir->nfile.type) {
5116 case NFROM:
5117 f = open(fname, O_RDONLY);
5118 if (f < 0)
5119 goto eopen;
5120 break;
5121 case NFROMTO:
5122 f = open(fname, O_RDWR|O_CREAT, 0666);
5123 if (f < 0)
5124 goto ecreate;
5125 break;
5126 case NTO:
5127 #if ENABLE_ASH_BASH_COMPAT
5128 case NTO2:
5129 #endif
5130 /* Take care of noclobber mode. */
5131 if (Cflag) {
5132 f = noclobberopen(fname);
5133 if (f < 0)
5134 goto ecreate;
5135 break;
5137 /* FALLTHROUGH */
5138 case NCLOBBER:
5139 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5140 if (f < 0)
5141 goto ecreate;
5142 break;
5143 case NAPPEND:
5144 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5145 if (f < 0)
5146 goto ecreate;
5147 break;
5148 default:
5149 #if DEBUG
5150 abort();
5151 #endif
5152 /* Fall through to eliminate warning. */
5153 /* Our single caller does this itself */
5154 // case NTOFD:
5155 // case NFROMFD:
5156 // f = -1;
5157 // break;
5158 case NHERE:
5159 case NXHERE:
5160 f = openhere(redir);
5161 break;
5164 return f;
5165 ecreate:
5166 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5167 eopen:
5168 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5172 * Copy a file descriptor to be >= to. Returns -1
5173 * if the source file descriptor is closed, EMPTY if there are no unused
5174 * file descriptors left.
5176 /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5177 * old code was doing close(to) prior to copyfd() to achieve the same */
5178 enum {
5179 COPYFD_EXACT = (int)~(INT_MAX),
5180 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5182 static int
5183 copyfd(int from, int to)
5185 int newfd;
5187 if (to & COPYFD_EXACT) {
5188 to &= ~COPYFD_EXACT;
5189 /*if (from != to)*/
5190 newfd = dup2(from, to);
5191 } else {
5192 newfd = fcntl(from, F_DUPFD, to);
5194 if (newfd < 0) {
5195 if (errno == EMFILE)
5196 return EMPTY;
5197 /* Happens when source fd is not open: try "echo >&99" */
5198 ash_msg_and_raise_error("%d: %m", from);
5200 return newfd;
5203 /* Struct def and variable are moved down to the first usage site */
5204 struct two_fd_t {
5205 int orig, copy;
5207 struct redirtab {
5208 struct redirtab *next;
5209 int nullredirs;
5210 int pair_count;
5211 struct two_fd_t two_fd[];
5213 #define redirlist (G_var.redirlist)
5215 static int need_to_remember(struct redirtab *rp, int fd)
5217 int i;
5219 if (!rp) /* remembering was not requested */
5220 return 0;
5222 for (i = 0; i < rp->pair_count; i++) {
5223 if (rp->two_fd[i].orig == fd) {
5224 /* already remembered */
5225 return 0;
5228 return 1;
5231 /* "hidden" fd is a fd used to read scripts, or a copy of such */
5232 static int is_hidden_fd(struct redirtab *rp, int fd)
5234 int i;
5235 struct parsefile *pf;
5237 if (fd == -1)
5238 return 0;
5239 /* Check open scripts' fds */
5240 pf = g_parsefile;
5241 while (pf) {
5242 /* We skip pf_fd == 0 case because of the following case:
5243 * $ ash # running ash interactively
5244 * $ . ./script.sh
5245 * and in script.sh: "exec 9>&0".
5246 * Even though top-level pf_fd _is_ 0,
5247 * it's still ok to use it: "read" builtin uses it,
5248 * why should we cripple "exec" builtin?
5250 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
5251 return 1;
5253 pf = pf->prev;
5256 if (!rp)
5257 return 0;
5258 /* Check saved fds of redirects */
5259 fd |= COPYFD_RESTORE;
5260 for (i = 0; i < rp->pair_count; i++) {
5261 if (rp->two_fd[i].copy == fd) {
5262 return 1;
5265 return 0;
5269 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5270 * old file descriptors are stashed away so that the redirection can be
5271 * undone by calling popredir.
5273 /* flags passed to redirect */
5274 #define REDIR_PUSH 01 /* save previous values of file descriptors */
5275 #define REDIR_SAVEFD2 03 /* set preverrout */
5276 static void
5277 redirect(union node *redir, int flags)
5279 struct redirtab *sv;
5280 int sv_pos;
5281 int i;
5282 int fd;
5283 int newfd;
5284 int copied_fd2 = -1;
5286 g_nullredirs++;
5287 if (!redir) {
5288 return;
5291 sv = NULL;
5292 sv_pos = 0;
5293 INT_OFF;
5294 if (flags & REDIR_PUSH) {
5295 union node *tmp = redir;
5296 do {
5297 sv_pos++;
5298 #if ENABLE_ASH_BASH_COMPAT
5299 if (tmp->nfile.type == NTO2)
5300 sv_pos++;
5301 #endif
5302 tmp = tmp->nfile.next;
5303 } while (tmp);
5304 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
5305 sv->next = redirlist;
5306 sv->pair_count = sv_pos;
5307 redirlist = sv;
5308 sv->nullredirs = g_nullredirs - 1;
5309 g_nullredirs = 0;
5310 while (sv_pos > 0) {
5311 sv_pos--;
5312 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5316 do {
5317 int right_fd = -1;
5318 fd = redir->nfile.fd;
5319 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5320 right_fd = redir->ndup.dupfd;
5321 //bb_error_msg("doing %d > %d", fd, right_fd);
5322 /* redirect from/to same file descriptor? */
5323 if (right_fd == fd)
5324 continue;
5325 /* "echo >&10" and 10 is a fd opened to a sh script? */
5326 if (is_hidden_fd(sv, right_fd)) {
5327 errno = EBADF; /* as if it is closed */
5328 ash_msg_and_raise_error("%d: %m", right_fd);
5330 newfd = -1;
5331 } else {
5332 newfd = openredirect(redir); /* always >= 0 */
5333 if (fd == newfd) {
5334 /* Descriptor wasn't open before redirect.
5335 * Mark it for close in the future */
5336 if (need_to_remember(sv, fd)) {
5337 goto remember_to_close;
5339 continue;
5342 #if ENABLE_ASH_BASH_COMPAT
5343 redirect_more:
5344 #endif
5345 if (need_to_remember(sv, fd)) {
5346 /* Copy old descriptor */
5347 /* Careful to not accidentally "save"
5348 * to the same fd as right side fd in N>&M */
5349 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5350 i = fcntl(fd, F_DUPFD, minfd);
5351 /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5352 * are closed in popredir() in the child, preventing them from leaking
5353 * into child. (popredir() also cleans up the mess in case of failures)
5355 if (i == -1) {
5356 i = errno;
5357 if (i != EBADF) {
5358 /* Strange error (e.g. "too many files" EMFILE?) */
5359 if (newfd >= 0)
5360 close(newfd);
5361 errno = i;
5362 ash_msg_and_raise_error("%d: %m", fd);
5363 /* NOTREACHED */
5365 /* EBADF: it is not open - good, remember to close it */
5366 remember_to_close:
5367 i = CLOSED;
5368 } else { /* fd is open, save its copy */
5369 /* "exec fd>&-" should not close fds
5370 * which point to script file(s).
5371 * Force them to be restored afterwards */
5372 if (is_hidden_fd(sv, fd))
5373 i |= COPYFD_RESTORE;
5375 if (fd == 2)
5376 copied_fd2 = i;
5377 sv->two_fd[sv_pos].orig = fd;
5378 sv->two_fd[sv_pos].copy = i;
5379 sv_pos++;
5381 if (newfd < 0) {
5382 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5383 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5384 /* Don't want to trigger debugging */
5385 if (fd != -1)
5386 close(fd);
5387 } else {
5388 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
5390 } else if (fd != newfd) { /* move newfd to fd */
5391 copyfd(newfd, fd | COPYFD_EXACT);
5392 #if ENABLE_ASH_BASH_COMPAT
5393 if (!(redir->nfile.type == NTO2 && fd == 2))
5394 #endif
5395 close(newfd);
5397 #if ENABLE_ASH_BASH_COMPAT
5398 if (redir->nfile.type == NTO2 && fd == 1) {
5399 /* We already redirected it to fd 1, now copy it to 2 */
5400 newfd = 1;
5401 fd = 2;
5402 goto redirect_more;
5404 #endif
5405 } while ((redir = redir->nfile.next) != NULL);
5407 INT_ON;
5408 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5409 preverrout_fd = copied_fd2;
5413 * Undo the effects of the last redirection.
5415 static void
5416 popredir(int drop, int restore)
5418 struct redirtab *rp;
5419 int i;
5421 if (--g_nullredirs >= 0)
5422 return;
5423 INT_OFF;
5424 rp = redirlist;
5425 for (i = 0; i < rp->pair_count; i++) {
5426 int fd = rp->two_fd[i].orig;
5427 int copy = rp->two_fd[i].copy;
5428 if (copy == CLOSED) {
5429 if (!drop)
5430 close(fd);
5431 continue;
5433 if (copy != EMPTY) {
5434 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5435 copy &= ~COPYFD_RESTORE;
5436 /*close(fd);*/
5437 copyfd(copy, fd | COPYFD_EXACT);
5439 close(copy & ~COPYFD_RESTORE);
5442 redirlist = rp->next;
5443 g_nullredirs = rp->nullredirs;
5444 free(rp);
5445 INT_ON;
5449 * Undo all redirections. Called on error or interrupt.
5453 * Discard all saved file descriptors.
5455 static void
5456 clearredir(int drop)
5458 for (;;) {
5459 g_nullredirs = 0;
5460 if (!redirlist)
5461 break;
5462 popredir(drop, /*restore:*/ 0);
5466 static int
5467 redirectsafe(union node *redir, int flags)
5469 int err;
5470 volatile int saveint;
5471 struct jmploc *volatile savehandler = exception_handler;
5472 struct jmploc jmploc;
5474 SAVE_INT(saveint);
5475 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5476 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5477 if (!err) {
5478 exception_handler = &jmploc;
5479 redirect(redir, flags);
5481 exception_handler = savehandler;
5482 if (err && exception_type != EXERROR)
5483 longjmp(exception_handler->loc, 1);
5484 RESTORE_INT(saveint);
5485 return err;
5489 /* ============ Routines to expand arguments to commands
5491 * We have to deal with backquotes, shell variables, and file metacharacters.
5494 #if ENABLE_SH_MATH_SUPPORT
5495 static arith_t
5496 ash_arith(const char *s)
5498 arith_state_t math_state;
5499 arith_t result;
5501 math_state.lookupvar = lookupvar;
5502 math_state.setvar = setvar2;
5503 //math_state.endofname = endofname;
5505 INT_OFF;
5506 result = arith(&math_state, s);
5507 if (math_state.errmsg)
5508 ash_msg_and_raise_error(math_state.errmsg);
5509 INT_ON;
5511 return result;
5513 #endif
5516 * expandarg flags
5518 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5519 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5520 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5521 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5522 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5523 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5524 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5525 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5526 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5528 * rmescape() flags
5530 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5531 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5532 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5533 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5534 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5537 * Structure specifying which parts of the string should be searched
5538 * for IFS characters.
5540 struct ifsregion {
5541 struct ifsregion *next; /* next region in list */
5542 int begoff; /* offset of start of region */
5543 int endoff; /* offset of end of region */
5544 int nulonly; /* search for nul bytes only */
5547 struct arglist {
5548 struct strlist *list;
5549 struct strlist **lastp;
5552 /* output of current string */
5553 static char *expdest;
5554 /* list of back quote expressions */
5555 static struct nodelist *argbackq;
5556 /* first struct in list of ifs regions */
5557 static struct ifsregion ifsfirst;
5558 /* last struct in list */
5559 static struct ifsregion *ifslastp;
5560 /* holds expanded arg list */
5561 static struct arglist exparg;
5564 * Our own itoa().
5566 #if !ENABLE_SH_MATH_SUPPORT
5567 /* cvtnum() is used even if math support is off (to prepare $? values and such) */
5568 typedef long arith_t;
5569 # define ARITH_FMT "%ld"
5570 #endif
5571 static int
5572 cvtnum(arith_t num)
5574 int len;
5576 expdest = makestrspace(32, expdest);
5577 len = fmtstr(expdest, 32, ARITH_FMT, num);
5578 STADJUST(len, expdest);
5579 return len;
5582 static size_t
5583 esclen(const char *start, const char *p)
5585 size_t esc = 0;
5587 while (p > start && (unsigned char)*--p == CTLESC) {
5588 esc++;
5590 return esc;
5594 * Remove any CTLESC characters from a string.
5596 static char *
5597 rmescapes(char *str, int flag)
5599 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5601 char *p, *q, *r;
5602 unsigned inquotes;
5603 unsigned protect_against_glob;
5604 unsigned globbing;
5606 p = strpbrk(str, qchars);
5607 if (!p)
5608 return str;
5610 q = p;
5611 r = str;
5612 if (flag & RMESCAPE_ALLOC) {
5613 size_t len = p - str;
5614 size_t fulllen = len + strlen(p) + 1;
5616 if (flag & RMESCAPE_GROW) {
5617 int strloc = str - (char *)stackblock();
5618 r = makestrspace(fulllen, expdest);
5619 /* p and str may be invalidated by makestrspace */
5620 str = (char *)stackblock() + strloc;
5621 p = str + len;
5622 } else if (flag & RMESCAPE_HEAP) {
5623 r = ckmalloc(fulllen);
5624 } else {
5625 r = stalloc(fulllen);
5627 q = r;
5628 if (len > 0) {
5629 q = (char *)memcpy(q, str, len) + len;
5633 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5634 globbing = flag & RMESCAPE_GLOB;
5635 protect_against_glob = globbing;
5636 while (*p) {
5637 if ((unsigned char)*p == CTLQUOTEMARK) {
5638 // TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0
5639 // (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok?
5640 // Note: both inquotes and protect_against_glob only affect whether
5641 // CTLESC,<ch> gets converted to <ch> or to \<ch>
5642 inquotes = ~inquotes;
5643 p++;
5644 protect_against_glob = globbing;
5645 continue;
5647 if (*p == '\\') {
5648 /* naked back slash */
5649 protect_against_glob = 0;
5650 goto copy;
5652 if ((unsigned char)*p == CTLESC) {
5653 p++;
5654 if (protect_against_glob && inquotes && *p != '/') {
5655 *q++ = '\\';
5658 protect_against_glob = globbing;
5659 copy:
5660 *q++ = *p++;
5662 *q = '\0';
5663 if (flag & RMESCAPE_GROW) {
5664 expdest = r;
5665 STADJUST(q - r + 1, expdest);
5667 return r;
5669 #define pmatch(a, b) !fnmatch((a), (b), 0)
5672 * Prepare a pattern for a expmeta (internal glob(3)) call.
5674 * Returns an stalloced string.
5676 static char *
5677 preglob(const char *pattern, int quoted, int flag)
5679 flag |= RMESCAPE_GLOB;
5680 if (quoted) {
5681 flag |= RMESCAPE_QUOTED;
5683 return rmescapes((char *)pattern, flag);
5687 * Put a string on the stack.
5689 static void
5690 memtodest(const char *p, size_t len, int syntax, int quotes)
5692 char *q = expdest;
5694 q = makestrspace(quotes ? len * 2 : len, q);
5696 while (len--) {
5697 unsigned char c = *p++;
5698 if (c == '\0')
5699 continue;
5700 if (quotes) {
5701 int n = SIT(c, syntax);
5702 if (n == CCTL || n == CBACK)
5703 USTPUTC(CTLESC, q);
5705 USTPUTC(c, q);
5708 expdest = q;
5711 static void
5712 strtodest(const char *p, int syntax, int quotes)
5714 memtodest(p, strlen(p), syntax, quotes);
5718 * Record the fact that we have to scan this region of the
5719 * string for IFS characters.
5721 static void
5722 recordregion(int start, int end, int nulonly)
5724 struct ifsregion *ifsp;
5726 if (ifslastp == NULL) {
5727 ifsp = &ifsfirst;
5728 } else {
5729 INT_OFF;
5730 ifsp = ckzalloc(sizeof(*ifsp));
5731 /*ifsp->next = NULL; - ckzalloc did it */
5732 ifslastp->next = ifsp;
5733 INT_ON;
5735 ifslastp = ifsp;
5736 ifslastp->begoff = start;
5737 ifslastp->endoff = end;
5738 ifslastp->nulonly = nulonly;
5741 static void
5742 removerecordregions(int endoff)
5744 if (ifslastp == NULL)
5745 return;
5747 if (ifsfirst.endoff > endoff) {
5748 while (ifsfirst.next) {
5749 struct ifsregion *ifsp;
5750 INT_OFF;
5751 ifsp = ifsfirst.next->next;
5752 free(ifsfirst.next);
5753 ifsfirst.next = ifsp;
5754 INT_ON;
5756 if (ifsfirst.begoff > endoff) {
5757 ifslastp = NULL;
5758 } else {
5759 ifslastp = &ifsfirst;
5760 ifsfirst.endoff = endoff;
5762 return;
5765 ifslastp = &ifsfirst;
5766 while (ifslastp->next && ifslastp->next->begoff < endoff)
5767 ifslastp = ifslastp->next;
5768 while (ifslastp->next) {
5769 struct ifsregion *ifsp;
5770 INT_OFF;
5771 ifsp = ifslastp->next->next;
5772 free(ifslastp->next);
5773 ifslastp->next = ifsp;
5774 INT_ON;
5776 if (ifslastp->endoff > endoff)
5777 ifslastp->endoff = endoff;
5780 static char *
5781 exptilde(char *startp, char *p, int flags)
5783 unsigned char c;
5784 char *name;
5785 struct passwd *pw;
5786 const char *home;
5787 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
5788 int startloc;
5790 name = p + 1;
5792 while ((c = *++p) != '\0') {
5793 switch (c) {
5794 case CTLESC:
5795 return startp;
5796 case CTLQUOTEMARK:
5797 return startp;
5798 case ':':
5799 if (flags & EXP_VARTILDE)
5800 goto done;
5801 break;
5802 case '/':
5803 case CTLENDVAR:
5804 goto done;
5807 done:
5808 *p = '\0';
5809 if (*name == '\0') {
5810 home = lookupvar("HOME");
5811 } else {
5812 pw = getpwnam(name);
5813 if (pw == NULL)
5814 goto lose;
5815 home = pw->pw_dir;
5817 if (!home || !*home)
5818 goto lose;
5819 *p = c;
5820 startloc = expdest - (char *)stackblock();
5821 strtodest(home, SQSYNTAX, quotes);
5822 recordregion(startloc, expdest - (char *)stackblock(), 0);
5823 return p;
5824 lose:
5825 *p = c;
5826 return startp;
5830 * Execute a command inside back quotes. If it's a builtin command, we
5831 * want to save its output in a block obtained from malloc. Otherwise
5832 * we fork off a subprocess and get the output of the command via a pipe.
5833 * Should be called with interrupts off.
5835 struct backcmd { /* result of evalbackcmd */
5836 int fd; /* file descriptor to read from */
5837 int nleft; /* number of chars in buffer */
5838 char *buf; /* buffer */
5839 struct job *jp; /* job structure for command */
5842 /* These forward decls are needed to use "eval" code for backticks handling: */
5843 static uint8_t back_exitstatus; /* exit status of backquoted command */
5844 #define EV_EXIT 01 /* exit after evaluating tree */
5845 static void evaltree(union node *, int);
5847 static void FAST_FUNC
5848 evalbackcmd(union node *n, struct backcmd *result)
5850 int saveherefd;
5852 result->fd = -1;
5853 result->buf = NULL;
5854 result->nleft = 0;
5855 result->jp = NULL;
5856 if (n == NULL)
5857 goto out;
5859 saveherefd = herefd;
5860 herefd = -1;
5863 int pip[2];
5864 struct job *jp;
5866 if (pipe(pip) < 0)
5867 ash_msg_and_raise_error("pipe call failed");
5868 jp = makejob(/*n,*/ 1);
5869 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5870 FORCE_INT_ON;
5871 close(pip[0]);
5872 if (pip[1] != 1) {
5873 /*close(1);*/
5874 copyfd(pip[1], 1 | COPYFD_EXACT);
5875 close(pip[1]);
5877 eflag = 0;
5878 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5879 /* NOTREACHED */
5881 close(pip[1]);
5882 result->fd = pip[0];
5883 result->jp = jp;
5885 herefd = saveherefd;
5886 out:
5887 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5888 result->fd, result->buf, result->nleft, result->jp));
5892 * Expand stuff in backwards quotes.
5894 static void
5895 expbackq(union node *cmd, int quoted, int quotes)
5897 struct backcmd in;
5898 int i;
5899 char buf[128];
5900 char *p;
5901 char *dest;
5902 int startloc;
5903 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
5904 struct stackmark smark;
5906 INT_OFF;
5907 setstackmark(&smark);
5908 dest = expdest;
5909 startloc = dest - (char *)stackblock();
5910 grabstackstr(dest);
5911 evalbackcmd(cmd, &in);
5912 popstackmark(&smark);
5914 p = in.buf;
5915 i = in.nleft;
5916 if (i == 0)
5917 goto read;
5918 for (;;) {
5919 memtodest(p, i, syntax, quotes);
5920 read:
5921 if (in.fd < 0)
5922 break;
5923 i = nonblock_immune_read(in.fd, buf, sizeof(buf), /*loop_on_EINTR:*/ 1);
5924 TRACE(("expbackq: read returns %d\n", i));
5925 if (i <= 0)
5926 break;
5927 p = buf;
5930 free(in.buf);
5931 if (in.fd >= 0) {
5932 close(in.fd);
5933 back_exitstatus = waitforjob(in.jp);
5935 INT_ON;
5937 /* Eat all trailing newlines */
5938 dest = expdest;
5939 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5940 STUNPUTC(dest);
5941 expdest = dest;
5943 if (quoted == 0)
5944 recordregion(startloc, dest - (char *)stackblock(), 0);
5945 TRACE(("evalbackq: size:%d:'%.*s'\n",
5946 (int)((dest - (char *)stackblock()) - startloc),
5947 (int)((dest - (char *)stackblock()) - startloc),
5948 stackblock() + startloc));
5951 #if ENABLE_SH_MATH_SUPPORT
5953 * Expand arithmetic expression. Backup to start of expression,
5954 * evaluate, place result in (backed up) result, adjust string position.
5956 static void
5957 expari(int quotes)
5959 char *p, *start;
5960 int begoff;
5961 int flag;
5962 int len;
5964 /* ifsfree(); */
5967 * This routine is slightly over-complicated for
5968 * efficiency. Next we scan backwards looking for the
5969 * start of arithmetic.
5971 start = stackblock();
5972 p = expdest - 1;
5973 *p = '\0';
5974 p--;
5975 while (1) {
5976 int esc;
5978 while ((unsigned char)*p != CTLARI) {
5979 p--;
5980 #if DEBUG
5981 if (p < start) {
5982 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5984 #endif
5987 esc = esclen(start, p);
5988 if (!(esc % 2)) {
5989 break;
5992 p -= esc + 1;
5995 begoff = p - start;
5997 removerecordregions(begoff);
5999 flag = p[1];
6001 expdest = p;
6003 if (quotes)
6004 rmescapes(p + 2, 0);
6006 len = cvtnum(ash_arith(p + 2));
6008 if (flag != '"')
6009 recordregion(begoff, begoff + len, 0);
6011 #endif
6013 /* argstr needs it */
6014 static char *evalvar(char *p, int flags, struct strlist *var_str_list);
6017 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6018 * characters to allow for further processing. Otherwise treat
6019 * $@ like $* since no splitting will be performed.
6021 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6022 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6023 * for correct expansion of "B=$A" word.
6025 static void
6026 argstr(char *p, int flags, struct strlist *var_str_list)
6028 static const char spclchars[] ALIGN1 = {
6029 '=',
6030 ':',
6031 CTLQUOTEMARK,
6032 CTLENDVAR,
6033 CTLESC,
6034 CTLVAR,
6035 CTLBACKQ,
6036 CTLBACKQ | CTLQUOTE,
6037 #if ENABLE_SH_MATH_SUPPORT
6038 CTLENDARI,
6039 #endif
6040 '\0'
6042 const char *reject = spclchars;
6043 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
6044 int breakall = flags & EXP_WORD;
6045 int inquotes;
6046 size_t length;
6047 int startloc;
6049 if (!(flags & EXP_VARTILDE)) {
6050 reject += 2;
6051 } else if (flags & EXP_VARTILDE2) {
6052 reject++;
6054 inquotes = 0;
6055 length = 0;
6056 if (flags & EXP_TILDE) {
6057 char *q;
6059 flags &= ~EXP_TILDE;
6060 tilde:
6061 q = p;
6062 if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD))
6063 q++;
6064 if (*q == '~')
6065 p = exptilde(p, q, flags);
6067 start:
6068 startloc = expdest - (char *)stackblock();
6069 for (;;) {
6070 unsigned char c;
6072 length += strcspn(p + length, reject);
6073 c = p[length];
6074 if (c) {
6075 if (!(c & 0x80)
6076 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
6078 /* c == '=' || c == ':' || c == CTLENDARI */
6079 length++;
6082 if (length > 0) {
6083 int newloc;
6084 expdest = stack_nputstr(p, length, expdest);
6085 newloc = expdest - (char *)stackblock();
6086 if (breakall && !inquotes && newloc > startloc) {
6087 recordregion(startloc, newloc, 0);
6089 startloc = newloc;
6091 p += length + 1;
6092 length = 0;
6094 switch (c) {
6095 case '\0':
6096 goto breakloop;
6097 case '=':
6098 if (flags & EXP_VARTILDE2) {
6099 p--;
6100 continue;
6102 flags |= EXP_VARTILDE2;
6103 reject++;
6104 /* fall through */
6105 case ':':
6107 * sort of a hack - expand tildes in variable
6108 * assignments (after the first '=' and after ':'s).
6110 if (*--p == '~') {
6111 goto tilde;
6113 continue;
6116 switch (c) {
6117 case CTLENDVAR: /* ??? */
6118 goto breakloop;
6119 case CTLQUOTEMARK:
6120 /* "$@" syntax adherence hack */
6121 if (!inquotes
6122 && memcmp(p, dolatstr, 4) == 0
6123 && ( p[4] == (char)CTLQUOTEMARK
6124 || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK)
6127 p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1;
6128 goto start;
6130 inquotes = !inquotes;
6131 addquote:
6132 if (quotes) {
6133 p--;
6134 length++;
6135 startloc++;
6137 break;
6138 case CTLESC:
6139 startloc++;
6140 length++;
6141 goto addquote;
6142 case CTLVAR:
6143 TRACE(("argstr: evalvar('%s')\n", p));
6144 p = evalvar(p, flags, var_str_list);
6145 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6146 goto start;
6147 case CTLBACKQ:
6148 c = '\0';
6149 case CTLBACKQ|CTLQUOTE:
6150 expbackq(argbackq->n, c, quotes);
6151 argbackq = argbackq->next;
6152 goto start;
6153 #if ENABLE_SH_MATH_SUPPORT
6154 case CTLENDARI:
6155 p--;
6156 expari(quotes);
6157 goto start;
6158 #endif
6161 breakloop: ;
6164 static char *
6165 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6166 char *pattern, int quotes, int zero)
6168 char *loc, *loc2;
6169 char c;
6171 loc = startp;
6172 loc2 = rmesc;
6173 do {
6174 int match;
6175 const char *s = loc2;
6177 c = *loc2;
6178 if (zero) {
6179 *loc2 = '\0';
6180 s = rmesc;
6182 match = pmatch(pattern, s);
6184 *loc2 = c;
6185 if (match)
6186 return loc;
6187 if (quotes && (unsigned char)*loc == CTLESC)
6188 loc++;
6189 loc++;
6190 loc2++;
6191 } while (c);
6192 return NULL;
6195 static char *
6196 scanright(char *startp, char *rmesc, char *rmescend,
6197 char *pattern, int quotes, int match_at_start)
6199 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6200 int try2optimize = match_at_start;
6201 #endif
6202 int esc = 0;
6203 char *loc;
6204 char *loc2;
6206 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6207 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6208 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6209 * Logic:
6210 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6211 * and on each iteration they go back two/one char until they reach the beginning.
6212 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6214 /* TODO: document in what other circumstances we are called. */
6216 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6217 int match;
6218 char c = *loc2;
6219 const char *s = loc2;
6220 if (match_at_start) {
6221 *loc2 = '\0';
6222 s = rmesc;
6224 match = pmatch(pattern, s);
6225 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
6226 *loc2 = c;
6227 if (match)
6228 return loc;
6229 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6230 if (try2optimize) {
6231 /* Maybe we can optimize this:
6232 * if pattern ends with unescaped *, we can avoid checking
6233 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6234 * it wont match truncated "raw_value_of_" strings too.
6236 unsigned plen = strlen(pattern);
6237 /* Does it end with "*"? */
6238 if (plen != 0 && pattern[--plen] == '*') {
6239 /* "xxxx*" is not escaped */
6240 /* "xxx\*" is escaped */
6241 /* "xx\\*" is not escaped */
6242 /* "x\\\*" is escaped */
6243 int slashes = 0;
6244 while (plen != 0 && pattern[--plen] == '\\')
6245 slashes++;
6246 if (!(slashes & 1))
6247 break; /* ends with unescaped "*" */
6249 try2optimize = 0;
6251 #endif
6252 loc--;
6253 if (quotes) {
6254 if (--esc < 0) {
6255 esc = esclen(startp, loc);
6257 if (esc % 2) {
6258 esc--;
6259 loc--;
6263 return NULL;
6266 static void varunset(const char *, const char *, const char *, int) NORETURN;
6267 static void
6268 varunset(const char *end, const char *var, const char *umsg, int varflags)
6270 const char *msg;
6271 const char *tail;
6273 tail = nullstr;
6274 msg = "parameter not set";
6275 if (umsg) {
6276 if ((unsigned char)*end == CTLENDVAR) {
6277 if (varflags & VSNUL)
6278 tail = " or null";
6279 } else {
6280 msg = umsg;
6283 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
6286 #if ENABLE_ASH_BASH_COMPAT
6287 static char *
6288 parse_sub_pattern(char *arg, int varflags)
6290 char *idx, *repl = NULL;
6291 unsigned char c;
6293 //char *org_arg = arg;
6294 //bb_error_msg("arg:'%s' varflags:%x", arg, varflags);
6295 idx = arg;
6296 while (1) {
6297 c = *arg;
6298 if (!c)
6299 break;
6300 if (c == '/') {
6301 /* Only the first '/' seen is our separator */
6302 if (!repl) {
6303 repl = idx + 1;
6304 c = '\0';
6307 *idx++ = c;
6308 arg++;
6310 * Example: v='ab\c'; echo ${v/\\b/_\\_\z_}
6311 * The result is a_\_z_c (not a\_\_z_c)!
6313 * Enable debug prints in this function and you'll see:
6314 * ash: arg:'\\b/_\\_z_' varflags:d
6315 * ash: pattern:'\\b' repl:'_\_z_'
6316 * That is, \\b is interpreted as \\b, but \\_ as \_!
6317 * IOW: search pattern and replace string treat backslashes
6318 * differently! That is the reason why we check repl below:
6320 if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE))
6321 arg++; /* skip both '\', not just first one */
6323 *idx = c; /* NUL */
6324 //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl);
6326 return repl;
6328 #endif /* ENABLE_ASH_BASH_COMPAT */
6330 static const char *
6331 subevalvar(char *p, char *varname, int strloc, int subtype,
6332 int startloc, int varflags, int quotes, struct strlist *var_str_list)
6334 struct nodelist *saveargbackq = argbackq;
6335 char *startp;
6336 char *loc;
6337 char *rmesc, *rmescend;
6338 char *str;
6339 IF_ASH_BASH_COMPAT(const char *repl = NULL;)
6340 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
6341 int saveherefd = herefd;
6342 int amount, resetloc;
6343 IF_ASH_BASH_COMPAT(int workloc;)
6344 int zero;
6345 char *(*scan)(char*, char*, char*, char*, int, int);
6347 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6348 // p, varname, strloc, subtype, startloc, varflags, quotes);
6350 herefd = -1;
6351 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
6352 var_str_list);
6353 STPUTC('\0', expdest);
6354 herefd = saveherefd;
6355 argbackq = saveargbackq;
6356 startp = (char *)stackblock() + startloc;
6358 switch (subtype) {
6359 case VSASSIGN:
6360 setvar(varname, startp, 0);
6361 amount = startp - expdest;
6362 STADJUST(amount, expdest);
6363 return startp;
6365 case VSQUESTION:
6366 varunset(p, varname, startp, varflags);
6367 /* NOTREACHED */
6369 #if ENABLE_ASH_BASH_COMPAT
6370 case VSSUBSTR:
6371 loc = str = stackblock() + strloc;
6372 /* Read POS in ${var:POS:LEN} */
6373 pos = atoi(loc); /* number(loc) errors out on "1:4" */
6374 len = str - startp - 1;
6376 /* *loc != '\0', guaranteed by parser */
6377 if (quotes) {
6378 char *ptr;
6380 /* Adjust the length by the number of escapes */
6381 for (ptr = startp; ptr < (str - 1); ptr++) {
6382 if ((unsigned char)*ptr == CTLESC) {
6383 len--;
6384 ptr++;
6388 orig_len = len;
6390 if (*loc++ == ':') {
6391 /* ${var::LEN} */
6392 len = number(loc);
6393 } else {
6394 /* Skip POS in ${var:POS:LEN} */
6395 len = orig_len;
6396 while (*loc && *loc != ':') {
6397 /* TODO?
6398 * bash complains on: var=qwe; echo ${var:1a:123}
6399 if (!isdigit(*loc))
6400 ash_msg_and_raise_error(msg_illnum, str);
6402 loc++;
6404 if (*loc++ == ':') {
6405 len = number(loc);
6408 if (pos >= orig_len) {
6409 pos = 0;
6410 len = 0;
6412 if (len > (orig_len - pos))
6413 len = orig_len - pos;
6415 for (str = startp; pos; str++, pos--) {
6416 if (quotes && (unsigned char)*str == CTLESC)
6417 str++;
6419 for (loc = startp; len; len--) {
6420 if (quotes && (unsigned char)*str == CTLESC)
6421 *loc++ = *str++;
6422 *loc++ = *str++;
6424 *loc = '\0';
6425 amount = loc - expdest;
6426 STADJUST(amount, expdest);
6427 return loc;
6428 #endif
6431 resetloc = expdest - (char *)stackblock();
6433 /* We'll comeback here if we grow the stack while handling
6434 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6435 * stack will need rebasing, and we'll need to remove our work
6436 * areas each time
6438 IF_ASH_BASH_COMPAT(restart:)
6440 amount = expdest - ((char *)stackblock() + resetloc);
6441 STADJUST(-amount, expdest);
6442 startp = (char *)stackblock() + startloc;
6444 rmesc = startp;
6445 rmescend = (char *)stackblock() + strloc;
6446 if (quotes) {
6447 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6448 if (rmesc != startp) {
6449 rmescend = expdest;
6450 startp = (char *)stackblock() + startloc;
6453 rmescend--;
6454 str = (char *)stackblock() + strloc;
6455 preglob(str, varflags & VSQUOTE, 0);
6457 #if ENABLE_ASH_BASH_COMPAT
6458 workloc = expdest - (char *)stackblock();
6459 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6460 char *idx, *end;
6462 if (!repl) {
6463 repl = parse_sub_pattern(str, varflags);
6464 //bb_error_msg("repl:'%s'", repl);
6465 if (!repl)
6466 repl = nullstr;
6469 /* If there's no pattern to match, return the expansion unmolested */
6470 if (str[0] == '\0')
6471 return NULL;
6473 len = 0;
6474 idx = startp;
6475 end = str - 1;
6476 while (idx < end) {
6477 try_to_match:
6478 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6479 //bb_error_msg("scanright('%s'):'%s'", str, loc);
6480 if (!loc) {
6481 /* No match, advance */
6482 char *restart_detect = stackblock();
6483 skip_matching:
6484 STPUTC(*idx, expdest);
6485 if (quotes && (unsigned char)*idx == CTLESC) {
6486 idx++;
6487 len++;
6488 STPUTC(*idx, expdest);
6490 if (stackblock() != restart_detect)
6491 goto restart;
6492 idx++;
6493 len++;
6494 rmesc++;
6495 /* continue; - prone to quadratic behavior, smarter code: */
6496 if (idx >= end)
6497 break;
6498 if (str[0] == '*') {
6499 /* Pattern is "*foo". If "*foo" does not match "long_string",
6500 * it would never match "ong_string" etc, no point in trying.
6502 goto skip_matching;
6504 goto try_to_match;
6507 if (subtype == VSREPLACEALL) {
6508 while (idx < loc) {
6509 if (quotes && (unsigned char)*idx == CTLESC)
6510 idx++;
6511 idx++;
6512 rmesc++;
6514 } else {
6515 idx = loc;
6518 //bb_error_msg("repl:'%s'", repl);
6519 for (loc = (char*)repl; *loc; loc++) {
6520 char *restart_detect = stackblock();
6521 if (quotes && *loc == '\\') {
6522 STPUTC(CTLESC, expdest);
6523 len++;
6525 STPUTC(*loc, expdest);
6526 if (stackblock() != restart_detect)
6527 goto restart;
6528 len++;
6531 if (subtype == VSREPLACE) {
6532 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
6533 while (*idx) {
6534 char *restart_detect = stackblock();
6535 STPUTC(*idx, expdest);
6536 if (stackblock() != restart_detect)
6537 goto restart;
6538 len++;
6539 idx++;
6541 break;
6545 /* We've put the replaced text into a buffer at workloc, now
6546 * move it to the right place and adjust the stack.
6548 STPUTC('\0', expdest);
6549 startp = (char *)stackblock() + startloc;
6550 memmove(startp, (char *)stackblock() + workloc, len + 1);
6551 //bb_error_msg("startp:'%s'", startp);
6552 amount = expdest - (startp + len);
6553 STADJUST(-amount, expdest);
6554 return startp;
6556 #endif /* ENABLE_ASH_BASH_COMPAT */
6558 subtype -= VSTRIMRIGHT;
6559 #if DEBUG
6560 if (subtype < 0 || subtype > 7)
6561 abort();
6562 #endif
6563 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
6564 zero = subtype >> 1;
6565 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6566 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6568 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6569 if (loc) {
6570 if (zero) {
6571 memmove(startp, loc, str - loc);
6572 loc = startp + (str - loc) - 1;
6574 *loc = '\0';
6575 amount = loc - expdest;
6576 STADJUST(amount, expdest);
6578 return loc;
6582 * Add the value of a specialized variable to the stack string.
6583 * name parameter (examples):
6584 * ash -c 'echo $1' name:'1='
6585 * ash -c 'echo $qwe' name:'qwe='
6586 * ash -c 'echo $$' name:'$='
6587 * ash -c 'echo ${$}' name:'$='
6588 * ash -c 'echo ${$##q}' name:'$=q'
6589 * ash -c 'echo ${#$}' name:'$='
6590 * note: examples with bad shell syntax:
6591 * ash -c 'echo ${#$1}' name:'$=1'
6592 * ash -c 'echo ${#1#}' name:'1=#'
6594 static NOINLINE ssize_t
6595 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6597 const char *p;
6598 int num;
6599 int i;
6600 int sepq = 0;
6601 ssize_t len = 0;
6602 int subtype = varflags & VSTYPE;
6603 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
6604 int quoted = varflags & VSQUOTE;
6605 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
6607 switch (*name) {
6608 case '$':
6609 num = rootpid;
6610 goto numvar;
6611 case '?':
6612 num = exitstatus;
6613 goto numvar;
6614 case '#':
6615 num = shellparam.nparam;
6616 goto numvar;
6617 case '!':
6618 num = backgndpid;
6619 if (num == 0)
6620 return -1;
6621 numvar:
6622 len = cvtnum(num);
6623 goto check_1char_name;
6624 case '-':
6625 expdest = makestrspace(NOPTS, expdest);
6626 for (i = NOPTS - 1; i >= 0; i--) {
6627 if (optlist[i]) {
6628 USTPUTC(optletters(i), expdest);
6629 len++;
6632 check_1char_name:
6633 #if 0
6634 /* handles cases similar to ${#$1} */
6635 if (name[2] != '\0')
6636 raise_error_syntax("bad substitution");
6637 #endif
6638 break;
6639 case '@': {
6640 char **ap;
6641 int sep;
6643 if (quoted && (flags & EXP_FULL)) {
6644 /* note: this is not meant as PEOF value */
6645 sep = 1 << CHAR_BIT;
6646 goto param;
6648 /* fall through */
6649 case '*':
6650 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
6651 i = SIT(sep, syntax);
6652 if (quotes && (i == CCTL || i == CBACK))
6653 sepq = 1;
6654 param:
6655 ap = shellparam.p;
6656 if (!ap)
6657 return -1;
6658 while ((p = *ap++) != NULL) {
6659 size_t partlen;
6661 partlen = strlen(p);
6662 len += partlen;
6664 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6665 memtodest(p, partlen, syntax, quotes);
6667 if (*ap && sep) {
6668 char *q;
6670 len++;
6671 if (subtype == VSPLUS || subtype == VSLENGTH) {
6672 continue;
6674 q = expdest;
6675 if (sepq)
6676 STPUTC(CTLESC, q);
6677 /* note: may put NUL despite sep != 0
6678 * (see sep = 1 << CHAR_BIT above) */
6679 STPUTC(sep, q);
6680 expdest = q;
6683 return len;
6684 } /* case '@' and '*' */
6685 case '0':
6686 case '1':
6687 case '2':
6688 case '3':
6689 case '4':
6690 case '5':
6691 case '6':
6692 case '7':
6693 case '8':
6694 case '9':
6695 num = atoi(name); /* number(name) fails on ${N#str} etc */
6696 if (num < 0 || num > shellparam.nparam)
6697 return -1;
6698 p = num ? shellparam.p[num - 1] : arg0;
6699 goto value;
6700 default:
6701 /* NB: name has form "VAR=..." */
6703 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6704 * which should be considered before we check variables. */
6705 if (var_str_list) {
6706 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6707 p = NULL;
6708 do {
6709 char *str, *eq;
6710 str = var_str_list->text;
6711 eq = strchr(str, '=');
6712 if (!eq) /* stop at first non-assignment */
6713 break;
6714 eq++;
6715 if (name_len == (unsigned)(eq - str)
6716 && strncmp(str, name, name_len) == 0
6718 p = eq;
6719 /* goto value; - WRONG! */
6720 /* think "A=1 A=2 B=$A" */
6722 var_str_list = var_str_list->next;
6723 } while (var_str_list);
6724 if (p)
6725 goto value;
6727 p = lookupvar(name);
6728 value:
6729 if (!p)
6730 return -1;
6732 len = strlen(p);
6733 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6734 memtodest(p, len, syntax, quotes);
6735 return len;
6738 if (subtype == VSPLUS || subtype == VSLENGTH)
6739 STADJUST(-len, expdest);
6740 return len;
6744 * Expand a variable, and return a pointer to the next character in the
6745 * input string.
6747 static char *
6748 evalvar(char *p, int flags, struct strlist *var_str_list)
6750 char varflags;
6751 char subtype;
6752 char quoted;
6753 char easy;
6754 char *var;
6755 int patloc;
6756 int startloc;
6757 ssize_t varlen;
6759 varflags = (unsigned char) *p++;
6760 subtype = varflags & VSTYPE;
6761 quoted = varflags & VSQUOTE;
6762 var = p;
6763 easy = (!quoted || (*var == '@' && shellparam.nparam));
6764 startloc = expdest - (char *)stackblock();
6765 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
6767 again:
6768 varlen = varvalue(var, varflags, flags, var_str_list);
6769 if (varflags & VSNUL)
6770 varlen--;
6772 if (subtype == VSPLUS) {
6773 varlen = -1 - varlen;
6774 goto vsplus;
6777 if (subtype == VSMINUS) {
6778 vsplus:
6779 if (varlen < 0) {
6780 argstr(
6782 flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD),
6783 var_str_list
6785 goto end;
6787 if (easy)
6788 goto record;
6789 goto end;
6792 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6793 if (varlen < 0) {
6794 if (subevalvar(p, var, /* strloc: */ 0,
6795 subtype, startloc, varflags,
6796 /* quotes: */ 0,
6797 var_str_list)
6799 varflags &= ~VSNUL;
6801 * Remove any recorded regions beyond
6802 * start of variable
6804 removerecordregions(startloc);
6805 goto again;
6807 goto end;
6809 if (easy)
6810 goto record;
6811 goto end;
6814 if (varlen < 0 && uflag)
6815 varunset(p, var, 0, 0);
6817 if (subtype == VSLENGTH) {
6818 cvtnum(varlen > 0 ? varlen : 0);
6819 goto record;
6822 if (subtype == VSNORMAL) {
6823 if (easy)
6824 goto record;
6825 goto end;
6828 #if DEBUG
6829 switch (subtype) {
6830 case VSTRIMLEFT:
6831 case VSTRIMLEFTMAX:
6832 case VSTRIMRIGHT:
6833 case VSTRIMRIGHTMAX:
6834 #if ENABLE_ASH_BASH_COMPAT
6835 case VSSUBSTR:
6836 case VSREPLACE:
6837 case VSREPLACEALL:
6838 #endif
6839 break;
6840 default:
6841 abort();
6843 #endif
6845 if (varlen >= 0) {
6847 * Terminate the string and start recording the pattern
6848 * right after it
6850 STPUTC('\0', expdest);
6851 patloc = expdest - (char *)stackblock();
6852 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
6853 startloc, varflags,
6854 /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR),
6855 var_str_list)
6857 int amount = expdest - (
6858 (char *)stackblock() + patloc - 1
6860 STADJUST(-amount, expdest);
6862 /* Remove any recorded regions beyond start of variable */
6863 removerecordregions(startloc);
6864 record:
6865 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6868 end:
6869 if (subtype != VSNORMAL) { /* skip to end of alternative */
6870 int nesting = 1;
6871 for (;;) {
6872 unsigned char c = *p++;
6873 if (c == CTLESC)
6874 p++;
6875 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6876 if (varlen >= 0)
6877 argbackq = argbackq->next;
6878 } else if (c == CTLVAR) {
6879 if ((*p++ & VSTYPE) != VSNORMAL)
6880 nesting++;
6881 } else if (c == CTLENDVAR) {
6882 if (--nesting == 0)
6883 break;
6887 return p;
6891 * Break the argument string into pieces based upon IFS and add the
6892 * strings to the argument list. The regions of the string to be
6893 * searched for IFS characters have been stored by recordregion.
6895 static void
6896 ifsbreakup(char *string, struct arglist *arglist)
6898 struct ifsregion *ifsp;
6899 struct strlist *sp;
6900 char *start;
6901 char *p;
6902 char *q;
6903 const char *ifs, *realifs;
6904 int ifsspc;
6905 int nulonly;
6907 start = string;
6908 if (ifslastp != NULL) {
6909 ifsspc = 0;
6910 nulonly = 0;
6911 realifs = ifsset() ? ifsval() : defifs;
6912 ifsp = &ifsfirst;
6913 do {
6914 p = string + ifsp->begoff;
6915 nulonly = ifsp->nulonly;
6916 ifs = nulonly ? nullstr : realifs;
6917 ifsspc = 0;
6918 while (p < string + ifsp->endoff) {
6919 q = p;
6920 if ((unsigned char)*p == CTLESC)
6921 p++;
6922 if (!strchr(ifs, *p)) {
6923 p++;
6924 continue;
6926 if (!nulonly)
6927 ifsspc = (strchr(defifs, *p) != NULL);
6928 /* Ignore IFS whitespace at start */
6929 if (q == start && ifsspc) {
6930 p++;
6931 start = p;
6932 continue;
6934 *q = '\0';
6935 sp = stzalloc(sizeof(*sp));
6936 sp->text = start;
6937 *arglist->lastp = sp;
6938 arglist->lastp = &sp->next;
6939 p++;
6940 if (!nulonly) {
6941 for (;;) {
6942 if (p >= string + ifsp->endoff) {
6943 break;
6945 q = p;
6946 if ((unsigned char)*p == CTLESC)
6947 p++;
6948 if (strchr(ifs, *p) == NULL) {
6949 p = q;
6950 break;
6952 if (strchr(defifs, *p) == NULL) {
6953 if (ifsspc) {
6954 p++;
6955 ifsspc = 0;
6956 } else {
6957 p = q;
6958 break;
6960 } else
6961 p++;
6964 start = p;
6965 } /* while */
6966 ifsp = ifsp->next;
6967 } while (ifsp != NULL);
6968 if (nulonly)
6969 goto add;
6972 if (!*start)
6973 return;
6975 add:
6976 sp = stzalloc(sizeof(*sp));
6977 sp->text = start;
6978 *arglist->lastp = sp;
6979 arglist->lastp = &sp->next;
6982 static void
6983 ifsfree(void)
6985 struct ifsregion *p;
6987 INT_OFF;
6988 p = ifsfirst.next;
6989 do {
6990 struct ifsregion *ifsp;
6991 ifsp = p->next;
6992 free(p);
6993 p = ifsp;
6994 } while (p);
6995 ifslastp = NULL;
6996 ifsfirst.next = NULL;
6997 INT_ON;
7001 * Add a file name to the list.
7003 static void
7004 addfname(const char *name)
7006 struct strlist *sp;
7008 sp = stzalloc(sizeof(*sp));
7009 sp->text = ststrdup(name);
7010 *exparg.lastp = sp;
7011 exparg.lastp = &sp->next;
7015 * Do metacharacter (i.e. *, ?, [...]) expansion.
7017 static void
7018 expmeta(char *expdir, char *enddir, char *name)
7020 char *p;
7021 const char *cp;
7022 char *start;
7023 char *endname;
7024 int metaflag;
7025 struct stat statb;
7026 DIR *dirp;
7027 struct dirent *dp;
7028 int atend;
7029 int matchdot;
7031 metaflag = 0;
7032 start = name;
7033 for (p = name; *p; p++) {
7034 if (*p == '*' || *p == '?')
7035 metaflag = 1;
7036 else if (*p == '[') {
7037 char *q = p + 1;
7038 if (*q == '!')
7039 q++;
7040 for (;;) {
7041 if (*q == '\\')
7042 q++;
7043 if (*q == '/' || *q == '\0')
7044 break;
7045 if (*++q == ']') {
7046 metaflag = 1;
7047 break;
7050 } else if (*p == '\\')
7051 p++;
7052 else if (*p == '/') {
7053 if (metaflag)
7054 goto out;
7055 start = p + 1;
7058 out:
7059 if (metaflag == 0) { /* we've reached the end of the file name */
7060 if (enddir != expdir)
7061 metaflag++;
7062 p = name;
7063 do {
7064 if (*p == '\\')
7065 p++;
7066 *enddir++ = *p;
7067 } while (*p++);
7068 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7069 addfname(expdir);
7070 return;
7072 endname = p;
7073 if (name < start) {
7074 p = name;
7075 do {
7076 if (*p == '\\')
7077 p++;
7078 *enddir++ = *p++;
7079 } while (p < start);
7081 if (enddir == expdir) {
7082 cp = ".";
7083 } else if (enddir == expdir + 1 && *expdir == '/') {
7084 cp = "/";
7085 } else {
7086 cp = expdir;
7087 enddir[-1] = '\0';
7089 dirp = opendir(cp);
7090 if (dirp == NULL)
7091 return;
7092 if (enddir != expdir)
7093 enddir[-1] = '/';
7094 if (*endname == 0) {
7095 atend = 1;
7096 } else {
7097 atend = 0;
7098 *endname++ = '\0';
7100 matchdot = 0;
7101 p = start;
7102 if (*p == '\\')
7103 p++;
7104 if (*p == '.')
7105 matchdot++;
7106 while (!pending_int && (dp = readdir(dirp)) != NULL) {
7107 if (dp->d_name[0] == '.' && !matchdot)
7108 continue;
7109 if (pmatch(start, dp->d_name)) {
7110 if (atend) {
7111 strcpy(enddir, dp->d_name);
7112 addfname(expdir);
7113 } else {
7114 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7115 continue;
7116 p[-1] = '/';
7117 expmeta(expdir, p, endname);
7121 closedir(dirp);
7122 if (!atend)
7123 endname[-1] = '/';
7126 static struct strlist *
7127 msort(struct strlist *list, int len)
7129 struct strlist *p, *q = NULL;
7130 struct strlist **lpp;
7131 int half;
7132 int n;
7134 if (len <= 1)
7135 return list;
7136 half = len >> 1;
7137 p = list;
7138 for (n = half; --n >= 0;) {
7139 q = p;
7140 p = p->next;
7142 q->next = NULL; /* terminate first half of list */
7143 q = msort(list, half); /* sort first half of list */
7144 p = msort(p, len - half); /* sort second half */
7145 lpp = &list;
7146 for (;;) {
7147 #if ENABLE_LOCALE_SUPPORT
7148 if (strcoll(p->text, q->text) < 0)
7149 #else
7150 if (strcmp(p->text, q->text) < 0)
7151 #endif
7153 *lpp = p;
7154 lpp = &p->next;
7155 p = *lpp;
7156 if (p == NULL) {
7157 *lpp = q;
7158 break;
7160 } else {
7161 *lpp = q;
7162 lpp = &q->next;
7163 q = *lpp;
7164 if (q == NULL) {
7165 *lpp = p;
7166 break;
7170 return list;
7174 * Sort the results of file name expansion. It calculates the number of
7175 * strings to sort and then calls msort (short for merge sort) to do the
7176 * work.
7178 static struct strlist *
7179 expsort(struct strlist *str)
7181 int len;
7182 struct strlist *sp;
7184 len = 0;
7185 for (sp = str; sp; sp = sp->next)
7186 len++;
7187 return msort(str, len);
7190 static void
7191 expandmeta(struct strlist *str /*, int flag*/)
7193 static const char metachars[] ALIGN1 = {
7194 '*', '?', '[', 0
7196 /* TODO - EXP_REDIR */
7198 while (str) {
7199 char *expdir;
7200 struct strlist **savelastp;
7201 struct strlist *sp;
7202 char *p;
7204 if (fflag)
7205 goto nometa;
7206 if (!strpbrk(str->text, metachars))
7207 goto nometa;
7208 savelastp = exparg.lastp;
7210 INT_OFF;
7211 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7213 int i = strlen(str->text);
7214 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
7216 expmeta(expdir, expdir, p);
7217 free(expdir);
7218 if (p != str->text)
7219 free(p);
7220 INT_ON;
7221 if (exparg.lastp == savelastp) {
7223 * no matches
7225 nometa:
7226 *exparg.lastp = str;
7227 rmescapes(str->text, 0);
7228 exparg.lastp = &str->next;
7229 } else {
7230 *exparg.lastp = NULL;
7231 *savelastp = sp = expsort(*savelastp);
7232 while (sp->next != NULL)
7233 sp = sp->next;
7234 exparg.lastp = &sp->next;
7236 str = str->next;
7241 * Perform variable substitution and command substitution on an argument,
7242 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7243 * perform splitting and file name expansion. When arglist is NULL, perform
7244 * here document expansion.
7246 static void
7247 expandarg(union node *arg, struct arglist *arglist, int flag)
7249 struct strlist *sp;
7250 char *p;
7252 argbackq = arg->narg.backquote;
7253 STARTSTACKSTR(expdest);
7254 ifsfirst.next = NULL;
7255 ifslastp = NULL;
7256 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
7257 argstr(arg->narg.text, flag,
7258 /* var_str_list: */ arglist ? arglist->list : NULL);
7259 p = _STPUTC('\0', expdest);
7260 expdest = p - 1;
7261 if (arglist == NULL) {
7262 return; /* here document expanded */
7264 p = grabstackstr(p);
7265 TRACE(("expandarg: p:'%s'\n", p));
7266 exparg.lastp = &exparg.list;
7268 * TODO - EXP_REDIR
7270 if (flag & EXP_FULL) {
7271 ifsbreakup(p, &exparg);
7272 *exparg.lastp = NULL;
7273 exparg.lastp = &exparg.list;
7274 expandmeta(exparg.list /*, flag*/);
7275 } else {
7276 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
7277 rmescapes(p, 0);
7278 TRACE(("expandarg: rmescapes:'%s'\n", p));
7280 sp = stzalloc(sizeof(*sp));
7281 sp->text = p;
7282 *exparg.lastp = sp;
7283 exparg.lastp = &sp->next;
7285 if (ifsfirst.next)
7286 ifsfree();
7287 *exparg.lastp = NULL;
7288 if (exparg.list) {
7289 *arglist->lastp = exparg.list;
7290 arglist->lastp = exparg.lastp;
7295 * Expand shell variables and backquotes inside a here document.
7297 static void
7298 expandhere(union node *arg, int fd)
7300 herefd = fd;
7301 expandarg(arg, (struct arglist *)NULL, 0);
7302 full_write(fd, stackblock(), expdest - (char *)stackblock());
7306 * Returns true if the pattern matches the string.
7308 static int
7309 patmatch(char *pattern, const char *string)
7311 return pmatch(preglob(pattern, 0, 0), string);
7315 * See if a pattern matches in a case statement.
7317 static int
7318 casematch(union node *pattern, char *val)
7320 struct stackmark smark;
7321 int result;
7323 setstackmark(&smark);
7324 argbackq = pattern->narg.backquote;
7325 STARTSTACKSTR(expdest);
7326 ifslastp = NULL;
7327 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7328 /* var_str_list: */ NULL);
7329 STACKSTRNUL(expdest);
7330 result = patmatch(stackblock(), val);
7331 popstackmark(&smark);
7332 return result;
7336 /* ============ find_command */
7338 struct builtincmd {
7339 const char *name;
7340 int (*builtin)(int, char **) FAST_FUNC;
7341 /* unsigned flags; */
7343 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
7344 /* "regular" builtins always take precedence over commands,
7345 * regardless of PATH=....%builtin... position */
7346 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
7347 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
7349 struct cmdentry {
7350 smallint cmdtype; /* CMDxxx */
7351 union param {
7352 int index;
7353 /* index >= 0 for commands without path (slashes) */
7354 /* (TODO: what exactly does the value mean? PATH position?) */
7355 /* index == -1 for commands with slashes */
7356 /* index == (-2 - applet_no) for NOFORK applets */
7357 const struct builtincmd *cmd;
7358 struct funcnode *func;
7359 } u;
7361 /* values of cmdtype */
7362 #define CMDUNKNOWN -1 /* no entry in table for command */
7363 #define CMDNORMAL 0 /* command is an executable program */
7364 #define CMDFUNCTION 1 /* command is a shell function */
7365 #define CMDBUILTIN 2 /* command is a shell builtin */
7367 /* action to find_command() */
7368 #define DO_ERR 0x01 /* prints errors */
7369 #define DO_ABS 0x02 /* checks absolute paths */
7370 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7371 #define DO_ALTPATH 0x08 /* using alternate path */
7372 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7374 static void find_command(char *, struct cmdentry *, int, const char *);
7377 /* ============ Hashing commands */
7380 * When commands are first encountered, they are entered in a hash table.
7381 * This ensures that a full path search will not have to be done for them
7382 * on each invocation.
7384 * We should investigate converting to a linear search, even though that
7385 * would make the command name "hash" a misnomer.
7388 struct tblentry {
7389 struct tblentry *next; /* next entry in hash chain */
7390 union param param; /* definition of builtin function */
7391 smallint cmdtype; /* CMDxxx */
7392 char rehash; /* if set, cd done since entry created */
7393 char cmdname[1]; /* name of command */
7396 static struct tblentry **cmdtable;
7397 #define INIT_G_cmdtable() do { \
7398 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7399 } while (0)
7401 static int builtinloc = -1; /* index in path of %builtin, or -1 */
7404 static void
7405 tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
7407 #if ENABLE_FEATURE_SH_STANDALONE
7408 if (applet_no >= 0) {
7409 if (APPLET_IS_NOEXEC(applet_no)) {
7410 clearenv();
7411 while (*envp)
7412 putenv(*envp++);
7413 run_applet_no_and_exit(applet_no, argv);
7415 /* re-exec ourselves with the new arguments */
7416 execve(bb_busybox_exec_path, argv, envp);
7417 /* If they called chroot or otherwise made the binary no longer
7418 * executable, fall through */
7420 #endif
7422 repeat:
7423 #ifdef SYSV
7424 do {
7425 execve(cmd, argv, envp);
7426 } while (errno == EINTR);
7427 #else
7428 execve(cmd, argv, envp);
7429 #endif
7430 if (cmd == (char*) bb_busybox_exec_path) {
7431 /* We already visited ENOEXEC branch below, don't do it again */
7432 //TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
7433 free(argv);
7434 return;
7436 if (errno == ENOEXEC) {
7437 /* Run "cmd" as a shell script:
7438 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7439 * "If the execve() function fails with ENOEXEC, the shell
7440 * shall execute a command equivalent to having a shell invoked
7441 * with the command name as its first operand,
7442 * with any remaining arguments passed to the new shell"
7444 * That is, do not use $SHELL, user's shell, or /bin/sh;
7445 * just call ourselves.
7447 * Note that bash reads ~80 chars of the file, and if it sees
7448 * a zero byte before it sees newline, it doesn't try to
7449 * interpret it, but fails with "cannot execute binary file"
7450 * message and exit code 126. For one, this prevents attempts
7451 * to interpret foreign ELF binaries as shell scripts.
7453 char **ap;
7454 char **new;
7456 for (ap = argv; *ap; ap++)
7457 continue;
7458 new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
7459 new[0] = (char*) "ash";
7460 new[1] = cmd;
7461 ap = new + 2;
7462 while ((*ap++ = *++argv) != NULL)
7463 continue;
7464 cmd = (char*) bb_busybox_exec_path;
7465 argv = new;
7466 goto repeat;
7471 * Exec a program. Never returns. If you change this routine, you may
7472 * have to change the find_command routine as well.
7474 static void shellexec(char **, const char *, int) NORETURN;
7475 static void
7476 shellexec(char **argv, const char *path, int idx)
7478 char *cmdname;
7479 int e;
7480 char **envp;
7481 int exerrno;
7482 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
7484 clearredir(/*drop:*/ 1);
7485 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7486 if (strchr(argv[0], '/') != NULL
7487 #if ENABLE_FEATURE_SH_STANDALONE
7488 || (applet_no = find_applet_by_name(argv[0])) >= 0
7489 #endif
7491 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7492 if (applet_no >= 0) {
7493 /* We tried execing ourself, but it didn't work.
7494 * Maybe /proc/self/exe doesn't exist?
7495 * Try $PATH search.
7497 goto try_PATH;
7499 e = errno;
7500 } else {
7501 try_PATH:
7502 e = ENOENT;
7503 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
7504 if (--idx < 0 && pathopt == NULL) {
7505 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7506 if (errno != ENOENT && errno != ENOTDIR)
7507 e = errno;
7509 stunalloc(cmdname);
7513 /* Map to POSIX errors */
7514 switch (e) {
7515 case EACCES:
7516 exerrno = 126;
7517 break;
7518 case ENOENT:
7519 exerrno = 127;
7520 break;
7521 default:
7522 exerrno = 2;
7523 break;
7525 exitstatus = exerrno;
7526 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7527 argv[0], e, suppress_int));
7528 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7529 /* NOTREACHED */
7532 static void
7533 printentry(struct tblentry *cmdp)
7535 int idx;
7536 const char *path;
7537 char *name;
7539 idx = cmdp->param.index;
7540 path = pathval();
7541 do {
7542 name = path_advance(&path, cmdp->cmdname);
7543 stunalloc(name);
7544 } while (--idx >= 0);
7545 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7549 * Clear out command entries. The argument specifies the first entry in
7550 * PATH which has changed.
7552 static void
7553 clearcmdentry(int firstchange)
7555 struct tblentry **tblp;
7556 struct tblentry **pp;
7557 struct tblentry *cmdp;
7559 INT_OFF;
7560 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7561 pp = tblp;
7562 while ((cmdp = *pp) != NULL) {
7563 if ((cmdp->cmdtype == CMDNORMAL &&
7564 cmdp->param.index >= firstchange)
7565 || (cmdp->cmdtype == CMDBUILTIN &&
7566 builtinloc >= firstchange)
7568 *pp = cmdp->next;
7569 free(cmdp);
7570 } else {
7571 pp = &cmdp->next;
7575 INT_ON;
7579 * Locate a command in the command hash table. If "add" is nonzero,
7580 * add the command to the table if it is not already present. The
7581 * variable "lastcmdentry" is set to point to the address of the link
7582 * pointing to the entry, so that delete_cmd_entry can delete the
7583 * entry.
7585 * Interrupts must be off if called with add != 0.
7587 static struct tblentry **lastcmdentry;
7589 static struct tblentry *
7590 cmdlookup(const char *name, int add)
7592 unsigned int hashval;
7593 const char *p;
7594 struct tblentry *cmdp;
7595 struct tblentry **pp;
7597 p = name;
7598 hashval = (unsigned char)*p << 4;
7599 while (*p)
7600 hashval += (unsigned char)*p++;
7601 hashval &= 0x7FFF;
7602 pp = &cmdtable[hashval % CMDTABLESIZE];
7603 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7604 if (strcmp(cmdp->cmdname, name) == 0)
7605 break;
7606 pp = &cmdp->next;
7608 if (add && cmdp == NULL) {
7609 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7610 + strlen(name)
7611 /* + 1 - already done because
7612 * tblentry::cmdname is char[1] */);
7613 /*cmdp->next = NULL; - ckzalloc did it */
7614 cmdp->cmdtype = CMDUNKNOWN;
7615 strcpy(cmdp->cmdname, name);
7617 lastcmdentry = pp;
7618 return cmdp;
7622 * Delete the command entry returned on the last lookup.
7624 static void
7625 delete_cmd_entry(void)
7627 struct tblentry *cmdp;
7629 INT_OFF;
7630 cmdp = *lastcmdentry;
7631 *lastcmdentry = cmdp->next;
7632 if (cmdp->cmdtype == CMDFUNCTION)
7633 freefunc(cmdp->param.func);
7634 free(cmdp);
7635 INT_ON;
7639 * Add a new command entry, replacing any existing command entry for
7640 * the same name - except special builtins.
7642 static void
7643 addcmdentry(char *name, struct cmdentry *entry)
7645 struct tblentry *cmdp;
7647 cmdp = cmdlookup(name, 1);
7648 if (cmdp->cmdtype == CMDFUNCTION) {
7649 freefunc(cmdp->param.func);
7651 cmdp->cmdtype = entry->cmdtype;
7652 cmdp->param = entry->u;
7653 cmdp->rehash = 0;
7656 static int FAST_FUNC
7657 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7659 struct tblentry **pp;
7660 struct tblentry *cmdp;
7661 int c;
7662 struct cmdentry entry;
7663 char *name;
7665 if (nextopt("r") != '\0') {
7666 clearcmdentry(0);
7667 return 0;
7670 if (*argptr == NULL) {
7671 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7672 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7673 if (cmdp->cmdtype == CMDNORMAL)
7674 printentry(cmdp);
7677 return 0;
7680 c = 0;
7681 while ((name = *argptr) != NULL) {
7682 cmdp = cmdlookup(name, 0);
7683 if (cmdp != NULL
7684 && (cmdp->cmdtype == CMDNORMAL
7685 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7687 delete_cmd_entry();
7689 find_command(name, &entry, DO_ERR, pathval());
7690 if (entry.cmdtype == CMDUNKNOWN)
7691 c = 1;
7692 argptr++;
7694 return c;
7698 * Called when a cd is done. Marks all commands so the next time they
7699 * are executed they will be rehashed.
7701 static void
7702 hashcd(void)
7704 struct tblentry **pp;
7705 struct tblentry *cmdp;
7707 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7708 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7709 if (cmdp->cmdtype == CMDNORMAL
7710 || (cmdp->cmdtype == CMDBUILTIN
7711 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7712 && builtinloc > 0)
7714 cmdp->rehash = 1;
7721 * Fix command hash table when PATH changed.
7722 * Called before PATH is changed. The argument is the new value of PATH;
7723 * pathval() still returns the old value at this point.
7724 * Called with interrupts off.
7726 static void FAST_FUNC
7727 changepath(const char *new)
7729 const char *old;
7730 int firstchange;
7731 int idx;
7732 int idx_bltin;
7734 old = pathval();
7735 firstchange = 9999; /* assume no change */
7736 idx = 0;
7737 idx_bltin = -1;
7738 for (;;) {
7739 if (*old != *new) {
7740 firstchange = idx;
7741 if ((*old == '\0' && *new == ':')
7742 || (*old == ':' && *new == '\0')
7744 firstchange++;
7746 old = new; /* ignore subsequent differences */
7748 if (*new == '\0')
7749 break;
7750 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7751 idx_bltin = idx;
7752 if (*new == ':')
7753 idx++;
7754 new++;
7755 old++;
7757 if (builtinloc < 0 && idx_bltin >= 0)
7758 builtinloc = idx_bltin; /* zap builtins */
7759 if (builtinloc >= 0 && idx_bltin < 0)
7760 firstchange = 0;
7761 clearcmdentry(firstchange);
7762 builtinloc = idx_bltin;
7765 #define TEOF 0
7766 #define TNL 1
7767 #define TREDIR 2
7768 #define TWORD 3
7769 #define TSEMI 4
7770 #define TBACKGND 5
7771 #define TAND 6
7772 #define TOR 7
7773 #define TPIPE 8
7774 #define TLP 9
7775 #define TRP 10
7776 #define TENDCASE 11
7777 #define TENDBQUOTE 12
7778 #define TNOT 13
7779 #define TCASE 14
7780 #define TDO 15
7781 #define TDONE 16
7782 #define TELIF 17
7783 #define TELSE 18
7784 #define TESAC 19
7785 #define TFI 20
7786 #define TFOR 21
7787 #define TIF 22
7788 #define TIN 23
7789 #define TTHEN 24
7790 #define TUNTIL 25
7791 #define TWHILE 26
7792 #define TBEGIN 27
7793 #define TEND 28
7794 typedef smallint token_id_t;
7796 /* first char is indicating which tokens mark the end of a list */
7797 static const char *const tokname_array[] = {
7798 "\1end of file",
7799 "\0newline",
7800 "\0redirection",
7801 "\0word",
7802 "\0;",
7803 "\0&",
7804 "\0&&",
7805 "\0||",
7806 "\0|",
7807 "\0(",
7808 "\1)",
7809 "\1;;",
7810 "\1`",
7811 #define KWDOFFSET 13
7812 /* the following are keywords */
7813 "\0!",
7814 "\0case",
7815 "\1do",
7816 "\1done",
7817 "\1elif",
7818 "\1else",
7819 "\1esac",
7820 "\1fi",
7821 "\0for",
7822 "\0if",
7823 "\0in",
7824 "\1then",
7825 "\0until",
7826 "\0while",
7827 "\0{",
7828 "\1}",
7831 /* Wrapper around strcmp for qsort/bsearch/... */
7832 static int
7833 pstrcmp(const void *a, const void *b)
7835 return strcmp((char*) a, (*(char**) b) + 1);
7838 static const char *const *
7839 findkwd(const char *s)
7841 return bsearch(s, tokname_array + KWDOFFSET,
7842 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7843 sizeof(tokname_array[0]), pstrcmp);
7847 * Locate and print what a word is...
7849 static int
7850 describe_command(char *command, int describe_command_verbose)
7852 struct cmdentry entry;
7853 struct tblentry *cmdp;
7854 #if ENABLE_ASH_ALIAS
7855 const struct alias *ap;
7856 #endif
7857 const char *path = pathval();
7859 if (describe_command_verbose) {
7860 out1str(command);
7863 /* First look at the keywords */
7864 if (findkwd(command)) {
7865 out1str(describe_command_verbose ? " is a shell keyword" : command);
7866 goto out;
7869 #if ENABLE_ASH_ALIAS
7870 /* Then look at the aliases */
7871 ap = lookupalias(command, 0);
7872 if (ap != NULL) {
7873 if (!describe_command_verbose) {
7874 out1str("alias ");
7875 printalias(ap);
7876 return 0;
7878 out1fmt(" is an alias for %s", ap->val);
7879 goto out;
7881 #endif
7882 /* Then check if it is a tracked alias */
7883 cmdp = cmdlookup(command, 0);
7884 if (cmdp != NULL) {
7885 entry.cmdtype = cmdp->cmdtype;
7886 entry.u = cmdp->param;
7887 } else {
7888 /* Finally use brute force */
7889 find_command(command, &entry, DO_ABS, path);
7892 switch (entry.cmdtype) {
7893 case CMDNORMAL: {
7894 int j = entry.u.index;
7895 char *p;
7896 if (j < 0) {
7897 p = command;
7898 } else {
7899 do {
7900 p = path_advance(&path, command);
7901 stunalloc(p);
7902 } while (--j >= 0);
7904 if (describe_command_verbose) {
7905 out1fmt(" is%s %s",
7906 (cmdp ? " a tracked alias for" : nullstr), p
7908 } else {
7909 out1str(p);
7911 break;
7914 case CMDFUNCTION:
7915 if (describe_command_verbose) {
7916 out1str(" is a shell function");
7917 } else {
7918 out1str(command);
7920 break;
7922 case CMDBUILTIN:
7923 if (describe_command_verbose) {
7924 out1fmt(" is a %sshell builtin",
7925 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7926 "special " : nullstr
7928 } else {
7929 out1str(command);
7931 break;
7933 default:
7934 if (describe_command_verbose) {
7935 out1str(": not found\n");
7937 return 127;
7939 out:
7940 out1str("\n");
7941 return 0;
7944 static int FAST_FUNC
7945 typecmd(int argc UNUSED_PARAM, char **argv)
7947 int i = 1;
7948 int err = 0;
7949 int verbose = 1;
7951 /* type -p ... ? (we don't bother checking for 'p') */
7952 if (argv[1] && argv[1][0] == '-') {
7953 i++;
7954 verbose = 0;
7956 while (argv[i]) {
7957 err |= describe_command(argv[i++], verbose);
7959 return err;
7962 #if ENABLE_ASH_CMDCMD
7963 static int FAST_FUNC
7964 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7966 int c;
7967 enum {
7968 VERIFY_BRIEF = 1,
7969 VERIFY_VERBOSE = 2,
7970 } verify = 0;
7972 while ((c = nextopt("pvV")) != '\0')
7973 if (c == 'V')
7974 verify |= VERIFY_VERBOSE;
7975 else if (c == 'v')
7976 verify |= VERIFY_BRIEF;
7977 #if DEBUG
7978 else if (c != 'p')
7979 abort();
7980 #endif
7981 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7982 if (verify && (*argptr != NULL)) {
7983 return describe_command(*argptr, verify - VERIFY_BRIEF);
7986 return 0;
7988 #endif
7991 /* ============ eval.c */
7993 static int funcblocksize; /* size of structures in function */
7994 static int funcstringsize; /* size of strings in node */
7995 static void *funcblock; /* block to allocate function from */
7996 static char *funcstring; /* block to allocate strings from */
7998 /* flags in argument to evaltree */
7999 #define EV_EXIT 01 /* exit after evaluating tree */
8000 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
8001 #define EV_BACKCMD 04 /* command executing within back quotes */
8003 static const uint8_t nodesize[N_NUMBER] = {
8004 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8005 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8006 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8007 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8008 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8009 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8010 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8011 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8012 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8013 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8014 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8015 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8016 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8017 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8018 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8019 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8020 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8021 #if ENABLE_ASH_BASH_COMPAT
8022 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
8023 #endif
8024 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8025 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8026 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8027 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8028 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8029 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8030 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8031 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8032 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
8035 static void calcsize(union node *n);
8037 static void
8038 sizenodelist(struct nodelist *lp)
8040 while (lp) {
8041 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8042 calcsize(lp->n);
8043 lp = lp->next;
8047 static void
8048 calcsize(union node *n)
8050 if (n == NULL)
8051 return;
8052 funcblocksize += nodesize[n->type];
8053 switch (n->type) {
8054 case NCMD:
8055 calcsize(n->ncmd.redirect);
8056 calcsize(n->ncmd.args);
8057 calcsize(n->ncmd.assign);
8058 break;
8059 case NPIPE:
8060 sizenodelist(n->npipe.cmdlist);
8061 break;
8062 case NREDIR:
8063 case NBACKGND:
8064 case NSUBSHELL:
8065 calcsize(n->nredir.redirect);
8066 calcsize(n->nredir.n);
8067 break;
8068 case NAND:
8069 case NOR:
8070 case NSEMI:
8071 case NWHILE:
8072 case NUNTIL:
8073 calcsize(n->nbinary.ch2);
8074 calcsize(n->nbinary.ch1);
8075 break;
8076 case NIF:
8077 calcsize(n->nif.elsepart);
8078 calcsize(n->nif.ifpart);
8079 calcsize(n->nif.test);
8080 break;
8081 case NFOR:
8082 funcstringsize += strlen(n->nfor.var) + 1;
8083 calcsize(n->nfor.body);
8084 calcsize(n->nfor.args);
8085 break;
8086 case NCASE:
8087 calcsize(n->ncase.cases);
8088 calcsize(n->ncase.expr);
8089 break;
8090 case NCLIST:
8091 calcsize(n->nclist.body);
8092 calcsize(n->nclist.pattern);
8093 calcsize(n->nclist.next);
8094 break;
8095 case NDEFUN:
8096 case NARG:
8097 sizenodelist(n->narg.backquote);
8098 funcstringsize += strlen(n->narg.text) + 1;
8099 calcsize(n->narg.next);
8100 break;
8101 case NTO:
8102 #if ENABLE_ASH_BASH_COMPAT
8103 case NTO2:
8104 #endif
8105 case NCLOBBER:
8106 case NFROM:
8107 case NFROMTO:
8108 case NAPPEND:
8109 calcsize(n->nfile.fname);
8110 calcsize(n->nfile.next);
8111 break;
8112 case NTOFD:
8113 case NFROMFD:
8114 calcsize(n->ndup.vname);
8115 calcsize(n->ndup.next);
8116 break;
8117 case NHERE:
8118 case NXHERE:
8119 calcsize(n->nhere.doc);
8120 calcsize(n->nhere.next);
8121 break;
8122 case NNOT:
8123 calcsize(n->nnot.com);
8124 break;
8128 static char *
8129 nodeckstrdup(char *s)
8131 char *rtn = funcstring;
8133 strcpy(funcstring, s);
8134 funcstring += strlen(s) + 1;
8135 return rtn;
8138 static union node *copynode(union node *);
8140 static struct nodelist *
8141 copynodelist(struct nodelist *lp)
8143 struct nodelist *start;
8144 struct nodelist **lpp;
8146 lpp = &start;
8147 while (lp) {
8148 *lpp = funcblock;
8149 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8150 (*lpp)->n = copynode(lp->n);
8151 lp = lp->next;
8152 lpp = &(*lpp)->next;
8154 *lpp = NULL;
8155 return start;
8158 static union node *
8159 copynode(union node *n)
8161 union node *new;
8163 if (n == NULL)
8164 return NULL;
8165 new = funcblock;
8166 funcblock = (char *) funcblock + nodesize[n->type];
8168 switch (n->type) {
8169 case NCMD:
8170 new->ncmd.redirect = copynode(n->ncmd.redirect);
8171 new->ncmd.args = copynode(n->ncmd.args);
8172 new->ncmd.assign = copynode(n->ncmd.assign);
8173 break;
8174 case NPIPE:
8175 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8176 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8177 break;
8178 case NREDIR:
8179 case NBACKGND:
8180 case NSUBSHELL:
8181 new->nredir.redirect = copynode(n->nredir.redirect);
8182 new->nredir.n = copynode(n->nredir.n);
8183 break;
8184 case NAND:
8185 case NOR:
8186 case NSEMI:
8187 case NWHILE:
8188 case NUNTIL:
8189 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8190 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8191 break;
8192 case NIF:
8193 new->nif.elsepart = copynode(n->nif.elsepart);
8194 new->nif.ifpart = copynode(n->nif.ifpart);
8195 new->nif.test = copynode(n->nif.test);
8196 break;
8197 case NFOR:
8198 new->nfor.var = nodeckstrdup(n->nfor.var);
8199 new->nfor.body = copynode(n->nfor.body);
8200 new->nfor.args = copynode(n->nfor.args);
8201 break;
8202 case NCASE:
8203 new->ncase.cases = copynode(n->ncase.cases);
8204 new->ncase.expr = copynode(n->ncase.expr);
8205 break;
8206 case NCLIST:
8207 new->nclist.body = copynode(n->nclist.body);
8208 new->nclist.pattern = copynode(n->nclist.pattern);
8209 new->nclist.next = copynode(n->nclist.next);
8210 break;
8211 case NDEFUN:
8212 case NARG:
8213 new->narg.backquote = copynodelist(n->narg.backquote);
8214 new->narg.text = nodeckstrdup(n->narg.text);
8215 new->narg.next = copynode(n->narg.next);
8216 break;
8217 case NTO:
8218 #if ENABLE_ASH_BASH_COMPAT
8219 case NTO2:
8220 #endif
8221 case NCLOBBER:
8222 case NFROM:
8223 case NFROMTO:
8224 case NAPPEND:
8225 new->nfile.fname = copynode(n->nfile.fname);
8226 new->nfile.fd = n->nfile.fd;
8227 new->nfile.next = copynode(n->nfile.next);
8228 break;
8229 case NTOFD:
8230 case NFROMFD:
8231 new->ndup.vname = copynode(n->ndup.vname);
8232 new->ndup.dupfd = n->ndup.dupfd;
8233 new->ndup.fd = n->ndup.fd;
8234 new->ndup.next = copynode(n->ndup.next);
8235 break;
8236 case NHERE:
8237 case NXHERE:
8238 new->nhere.doc = copynode(n->nhere.doc);
8239 new->nhere.fd = n->nhere.fd;
8240 new->nhere.next = copynode(n->nhere.next);
8241 break;
8242 case NNOT:
8243 new->nnot.com = copynode(n->nnot.com);
8244 break;
8246 new->type = n->type;
8247 return new;
8251 * Make a copy of a parse tree.
8253 static struct funcnode *
8254 copyfunc(union node *n)
8256 struct funcnode *f;
8257 size_t blocksize;
8259 funcblocksize = offsetof(struct funcnode, n);
8260 funcstringsize = 0;
8261 calcsize(n);
8262 blocksize = funcblocksize;
8263 f = ckmalloc(blocksize + funcstringsize);
8264 funcblock = (char *) f + offsetof(struct funcnode, n);
8265 funcstring = (char *) f + blocksize;
8266 copynode(n);
8267 f->count = 0;
8268 return f;
8272 * Define a shell function.
8274 static void
8275 defun(char *name, union node *func)
8277 struct cmdentry entry;
8279 INT_OFF;
8280 entry.cmdtype = CMDFUNCTION;
8281 entry.u.func = copyfunc(func);
8282 addcmdentry(name, &entry);
8283 INT_ON;
8286 /* Reasons for skipping commands (see comment on breakcmd routine) */
8287 #define SKIPBREAK (1 << 0)
8288 #define SKIPCONT (1 << 1)
8289 #define SKIPFUNC (1 << 2)
8290 #define SKIPFILE (1 << 3)
8291 #define SKIPEVAL (1 << 4)
8292 static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
8293 static int skipcount; /* number of levels to skip */
8294 static int funcnest; /* depth of function calls */
8295 static int loopnest; /* current loop nesting level */
8297 /* Forward decl way out to parsing code - dotrap needs it */
8298 static int evalstring(char *s, int mask);
8300 /* Called to execute a trap.
8301 * Single callsite - at the end of evaltree().
8302 * If we return non-zero, evaltree raises EXEXIT exception.
8304 * Perhaps we should avoid entering new trap handlers
8305 * while we are executing a trap handler. [is it a TODO?]
8307 static int
8308 dotrap(void)
8310 uint8_t *g;
8311 int sig;
8312 uint8_t savestatus;
8314 savestatus = exitstatus;
8315 pending_sig = 0;
8316 xbarrier();
8318 TRACE(("dotrap entered\n"));
8319 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8320 int want_exexit;
8321 char *t;
8323 if (*g == 0)
8324 continue;
8325 t = trap[sig];
8326 /* non-trapped SIGINT is handled separately by raise_interrupt,
8327 * don't upset it by resetting gotsig[SIGINT-1] */
8328 if (sig == SIGINT && !t)
8329 continue;
8331 TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
8332 *g = 0;
8333 if (!t)
8334 continue;
8335 want_exexit = evalstring(t, SKIPEVAL);
8336 exitstatus = savestatus;
8337 if (want_exexit) {
8338 TRACE(("dotrap returns %d\n", want_exexit));
8339 return want_exexit;
8343 TRACE(("dotrap returns 0\n"));
8344 return 0;
8347 /* forward declarations - evaluation is fairly recursive business... */
8348 static void evalloop(union node *, int);
8349 static void evalfor(union node *, int);
8350 static void evalcase(union node *, int);
8351 static void evalsubshell(union node *, int);
8352 static void expredir(union node *);
8353 static void evalpipe(union node *, int);
8354 static void evalcommand(union node *, int);
8355 static int evalbltin(const struct builtincmd *, int, char **);
8356 static void prehash(union node *);
8359 * Evaluate a parse tree. The value is left in the global variable
8360 * exitstatus.
8362 static void
8363 evaltree(union node *n, int flags)
8365 struct jmploc *volatile savehandler = exception_handler;
8366 struct jmploc jmploc;
8367 int checkexit = 0;
8368 void (*evalfn)(union node *, int);
8369 int status;
8370 int int_level;
8372 SAVE_INT(int_level);
8374 if (n == NULL) {
8375 TRACE(("evaltree(NULL) called\n"));
8376 goto out1;
8378 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
8380 exception_handler = &jmploc;
8382 int err = setjmp(jmploc.loc);
8383 if (err) {
8384 /* if it was a signal, check for trap handlers */
8385 if (exception_type == EXSIG) {
8386 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8387 exception_type, err));
8388 goto out;
8390 /* continue on the way out */
8391 TRACE(("exception %d in evaltree, propagating err=%d\n",
8392 exception_type, err));
8393 exception_handler = savehandler;
8394 longjmp(exception_handler->loc, err);
8398 switch (n->type) {
8399 default:
8400 #if DEBUG
8401 out1fmt("Node type = %d\n", n->type);
8402 fflush_all();
8403 break;
8404 #endif
8405 case NNOT:
8406 evaltree(n->nnot.com, EV_TESTED);
8407 status = !exitstatus;
8408 goto setstatus;
8409 case NREDIR:
8410 expredir(n->nredir.redirect);
8411 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8412 if (!status) {
8413 evaltree(n->nredir.n, flags & EV_TESTED);
8414 status = exitstatus;
8416 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
8417 goto setstatus;
8418 case NCMD:
8419 evalfn = evalcommand;
8420 checkexit:
8421 if (eflag && !(flags & EV_TESTED))
8422 checkexit = ~0;
8423 goto calleval;
8424 case NFOR:
8425 evalfn = evalfor;
8426 goto calleval;
8427 case NWHILE:
8428 case NUNTIL:
8429 evalfn = evalloop;
8430 goto calleval;
8431 case NSUBSHELL:
8432 case NBACKGND:
8433 evalfn = evalsubshell;
8434 goto calleval;
8435 case NPIPE:
8436 evalfn = evalpipe;
8437 goto checkexit;
8438 case NCASE:
8439 evalfn = evalcase;
8440 goto calleval;
8441 case NAND:
8442 case NOR:
8443 case NSEMI: {
8445 #if NAND + 1 != NOR
8446 #error NAND + 1 != NOR
8447 #endif
8448 #if NOR + 1 != NSEMI
8449 #error NOR + 1 != NSEMI
8450 #endif
8451 unsigned is_or = n->type - NAND;
8452 evaltree(
8453 n->nbinary.ch1,
8454 (flags | ((is_or >> 1) - 1)) & EV_TESTED
8456 if (!exitstatus == is_or)
8457 break;
8458 if (!evalskip) {
8459 n = n->nbinary.ch2;
8460 evaln:
8461 evalfn = evaltree;
8462 calleval:
8463 evalfn(n, flags);
8464 break;
8466 break;
8468 case NIF:
8469 evaltree(n->nif.test, EV_TESTED);
8470 if (evalskip)
8471 break;
8472 if (exitstatus == 0) {
8473 n = n->nif.ifpart;
8474 goto evaln;
8476 if (n->nif.elsepart) {
8477 n = n->nif.elsepart;
8478 goto evaln;
8480 goto success;
8481 case NDEFUN:
8482 defun(n->narg.text, n->narg.next);
8483 success:
8484 status = 0;
8485 setstatus:
8486 exitstatus = status;
8487 break;
8490 out:
8491 exception_handler = savehandler;
8493 out1:
8494 /* Order of checks below is important:
8495 * signal handlers trigger before exit caused by "set -e".
8497 if (pending_sig && dotrap())
8498 goto exexit;
8499 if (checkexit & exitstatus)
8500 evalskip |= SKIPEVAL;
8502 if (flags & EV_EXIT) {
8503 exexit:
8504 raise_exception(EXEXIT);
8507 RESTORE_INT(int_level);
8508 TRACE(("leaving evaltree (no interrupts)\n"));
8511 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8512 static
8513 #endif
8514 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8516 static void
8517 evalloop(union node *n, int flags)
8519 int status;
8521 loopnest++;
8522 status = 0;
8523 flags &= EV_TESTED;
8524 for (;;) {
8525 int i;
8527 evaltree(n->nbinary.ch1, EV_TESTED);
8528 if (evalskip) {
8529 skipping:
8530 if (evalskip == SKIPCONT && --skipcount <= 0) {
8531 evalskip = 0;
8532 continue;
8534 if (evalskip == SKIPBREAK && --skipcount <= 0)
8535 evalskip = 0;
8536 break;
8538 i = exitstatus;
8539 if (n->type != NWHILE)
8540 i = !i;
8541 if (i != 0)
8542 break;
8543 evaltree(n->nbinary.ch2, flags);
8544 status = exitstatus;
8545 if (evalskip)
8546 goto skipping;
8548 loopnest--;
8549 exitstatus = status;
8552 static void
8553 evalfor(union node *n, int flags)
8555 struct arglist arglist;
8556 union node *argp;
8557 struct strlist *sp;
8558 struct stackmark smark;
8560 setstackmark(&smark);
8561 arglist.list = NULL;
8562 arglist.lastp = &arglist.list;
8563 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8564 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
8565 /* XXX */
8566 if (evalskip)
8567 goto out;
8569 *arglist.lastp = NULL;
8571 exitstatus = 0;
8572 loopnest++;
8573 flags &= EV_TESTED;
8574 for (sp = arglist.list; sp; sp = sp->next) {
8575 setvar(n->nfor.var, sp->text, 0);
8576 evaltree(n->nfor.body, flags);
8577 if (evalskip) {
8578 if (evalskip == SKIPCONT && --skipcount <= 0) {
8579 evalskip = 0;
8580 continue;
8582 if (evalskip == SKIPBREAK && --skipcount <= 0)
8583 evalskip = 0;
8584 break;
8587 loopnest--;
8588 out:
8589 popstackmark(&smark);
8592 static void
8593 evalcase(union node *n, int flags)
8595 union node *cp;
8596 union node *patp;
8597 struct arglist arglist;
8598 struct stackmark smark;
8600 setstackmark(&smark);
8601 arglist.list = NULL;
8602 arglist.lastp = &arglist.list;
8603 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8604 exitstatus = 0;
8605 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8606 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8607 if (casematch(patp, arglist.list->text)) {
8608 if (evalskip == 0) {
8609 evaltree(cp->nclist.body, flags);
8611 goto out;
8615 out:
8616 popstackmark(&smark);
8620 * Kick off a subshell to evaluate a tree.
8622 static void
8623 evalsubshell(union node *n, int flags)
8625 struct job *jp;
8626 int backgnd = (n->type == NBACKGND);
8627 int status;
8629 expredir(n->nredir.redirect);
8630 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
8631 goto nofork;
8632 INT_OFF;
8633 jp = makejob(/*n,*/ 1);
8634 if (forkshell(jp, n, backgnd) == 0) {
8635 /* child */
8636 INT_ON;
8637 flags |= EV_EXIT;
8638 if (backgnd)
8639 flags &= ~EV_TESTED;
8640 nofork:
8641 redirect(n->nredir.redirect, 0);
8642 evaltreenr(n->nredir.n, flags);
8643 /* never returns */
8645 status = 0;
8646 if (!backgnd)
8647 status = waitforjob(jp);
8648 exitstatus = status;
8649 INT_ON;
8653 * Compute the names of the files in a redirection list.
8655 static void fixredir(union node *, const char *, int);
8656 static void
8657 expredir(union node *n)
8659 union node *redir;
8661 for (redir = n; redir; redir = redir->nfile.next) {
8662 struct arglist fn;
8664 fn.list = NULL;
8665 fn.lastp = &fn.list;
8666 switch (redir->type) {
8667 case NFROMTO:
8668 case NFROM:
8669 case NTO:
8670 #if ENABLE_ASH_BASH_COMPAT
8671 case NTO2:
8672 #endif
8673 case NCLOBBER:
8674 case NAPPEND:
8675 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8676 TRACE(("expredir expanded to '%s'\n", fn.list->text));
8677 #if ENABLE_ASH_BASH_COMPAT
8678 store_expfname:
8679 #endif
8680 #if 0
8681 // By the design of stack allocator, the loop of this kind:
8682 // while true; do while true; do break; done </dev/null; done
8683 // will look like a memory leak: ash plans to free expfname's
8684 // of "/dev/null" as soon as it finishes running the loop
8685 // (in this case, never).
8686 // This "fix" is wrong:
8687 if (redir->nfile.expfname)
8688 stunalloc(redir->nfile.expfname);
8689 // It results in corrupted state of stacked allocations.
8690 #endif
8691 redir->nfile.expfname = fn.list->text;
8692 break;
8693 case NFROMFD:
8694 case NTOFD: /* >& */
8695 if (redir->ndup.vname) {
8696 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8697 if (fn.list == NULL)
8698 ash_msg_and_raise_error("redir error");
8699 #if ENABLE_ASH_BASH_COMPAT
8700 //FIXME: we used expandarg with different args!
8701 if (!isdigit_str9(fn.list->text)) {
8702 /* >&file, not >&fd */
8703 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8704 ash_msg_and_raise_error("redir error");
8705 redir->type = NTO2;
8706 goto store_expfname;
8708 #endif
8709 fixredir(redir, fn.list->text, 1);
8711 break;
8717 * Evaluate a pipeline. All the processes in the pipeline are children
8718 * of the process creating the pipeline. (This differs from some versions
8719 * of the shell, which make the last process in a pipeline the parent
8720 * of all the rest.)
8722 static void
8723 evalpipe(union node *n, int flags)
8725 struct job *jp;
8726 struct nodelist *lp;
8727 int pipelen;
8728 int prevfd;
8729 int pip[2];
8731 TRACE(("evalpipe(0x%lx) called\n", (long)n));
8732 pipelen = 0;
8733 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8734 pipelen++;
8735 flags |= EV_EXIT;
8736 INT_OFF;
8737 jp = makejob(/*n,*/ pipelen);
8738 prevfd = -1;
8739 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8740 prehash(lp->n);
8741 pip[1] = -1;
8742 if (lp->next) {
8743 if (pipe(pip) < 0) {
8744 close(prevfd);
8745 ash_msg_and_raise_error("pipe call failed");
8748 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8749 INT_ON;
8750 if (pip[1] >= 0) {
8751 close(pip[0]);
8753 if (prevfd > 0) {
8754 dup2(prevfd, 0);
8755 close(prevfd);
8757 if (pip[1] > 1) {
8758 dup2(pip[1], 1);
8759 close(pip[1]);
8761 evaltreenr(lp->n, flags);
8762 /* never returns */
8764 if (prevfd >= 0)
8765 close(prevfd);
8766 prevfd = pip[0];
8767 /* Don't want to trigger debugging */
8768 if (pip[1] != -1)
8769 close(pip[1]);
8771 if (n->npipe.pipe_backgnd == 0) {
8772 exitstatus = waitforjob(jp);
8773 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
8775 INT_ON;
8779 * Controls whether the shell is interactive or not.
8781 static void
8782 setinteractive(int on)
8784 static smallint is_interactive;
8786 if (++on == is_interactive)
8787 return;
8788 is_interactive = on;
8789 setsignal(SIGINT);
8790 setsignal(SIGQUIT);
8791 setsignal(SIGTERM);
8792 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8793 if (is_interactive > 1) {
8794 /* Looks like they want an interactive shell */
8795 static smallint did_banner;
8797 if (!did_banner) {
8798 /* note: ash and hush share this string */
8799 out1fmt("\n\n%s %s\n"
8800 "Enter 'help' for a list of built-in commands."
8801 "\n\n",
8802 bb_banner,
8803 "built-in shell (ash)"
8805 did_banner = 1;
8808 #endif
8811 static void
8812 optschanged(void)
8814 #if DEBUG
8815 opentrace();
8816 #endif
8817 setinteractive(iflag);
8818 setjobctl(mflag);
8819 #if ENABLE_FEATURE_EDITING_VI
8820 if (viflag)
8821 line_input_state->flags |= VI_MODE;
8822 else
8823 line_input_state->flags &= ~VI_MODE;
8824 #else
8825 viflag = 0; /* forcibly keep the option off */
8826 #endif
8829 static struct localvar *localvars;
8832 * Called after a function returns.
8833 * Interrupts must be off.
8835 static void
8836 poplocalvars(void)
8838 struct localvar *lvp;
8839 struct var *vp;
8841 while ((lvp = localvars) != NULL) {
8842 localvars = lvp->next;
8843 vp = lvp->vp;
8844 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
8845 if (vp == NULL) { /* $- saved */
8846 memcpy(optlist, lvp->text, sizeof(optlist));
8847 free((char*)lvp->text);
8848 optschanged();
8849 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8850 unsetvar(vp->var_text);
8851 } else {
8852 if (vp->var_func)
8853 vp->var_func(var_end(lvp->text));
8854 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8855 free((char*)vp->var_text);
8856 vp->flags = lvp->flags;
8857 vp->var_text = lvp->text;
8859 free(lvp);
8863 static int
8864 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8866 volatile struct shparam saveparam;
8867 struct localvar *volatile savelocalvars;
8868 struct jmploc *volatile savehandler;
8869 struct jmploc jmploc;
8870 int e;
8872 saveparam = shellparam;
8873 savelocalvars = localvars;
8874 e = setjmp(jmploc.loc);
8875 if (e) {
8876 goto funcdone;
8878 INT_OFF;
8879 savehandler = exception_handler;
8880 exception_handler = &jmploc;
8881 localvars = NULL;
8882 shellparam.malloced = 0;
8883 func->count++;
8884 funcnest++;
8885 INT_ON;
8886 shellparam.nparam = argc - 1;
8887 shellparam.p = argv + 1;
8888 #if ENABLE_ASH_GETOPTS
8889 shellparam.optind = 1;
8890 shellparam.optoff = -1;
8891 #endif
8892 evaltree(&func->n, flags & EV_TESTED);
8893 funcdone:
8894 INT_OFF;
8895 funcnest--;
8896 freefunc(func);
8897 poplocalvars();
8898 localvars = savelocalvars;
8899 freeparam(&shellparam);
8900 shellparam = saveparam;
8901 exception_handler = savehandler;
8902 INT_ON;
8903 evalskip &= ~SKIPFUNC;
8904 return e;
8907 #if ENABLE_ASH_CMDCMD
8908 static char **
8909 parse_command_args(char **argv, const char **path)
8911 char *cp, c;
8913 for (;;) {
8914 cp = *++argv;
8915 if (!cp)
8916 return 0;
8917 if (*cp++ != '-')
8918 break;
8919 c = *cp++;
8920 if (!c)
8921 break;
8922 if (c == '-' && !*cp) {
8923 argv++;
8924 break;
8926 do {
8927 switch (c) {
8928 case 'p':
8929 *path = bb_default_path;
8930 break;
8931 default:
8932 /* run 'typecmd' for other options */
8933 return 0;
8935 c = *cp++;
8936 } while (c);
8938 return argv;
8940 #endif
8943 * Make a variable a local variable. When a variable is made local, it's
8944 * value and flags are saved in a localvar structure. The saved values
8945 * will be restored when the shell function returns. We handle the name
8946 * "-" as a special case.
8948 static void
8949 mklocal(char *name)
8951 struct localvar *lvp;
8952 struct var **vpp;
8953 struct var *vp;
8955 INT_OFF;
8956 lvp = ckzalloc(sizeof(struct localvar));
8957 if (LONE_DASH(name)) {
8958 char *p;
8959 p = ckmalloc(sizeof(optlist));
8960 lvp->text = memcpy(p, optlist, sizeof(optlist));
8961 vp = NULL;
8962 } else {
8963 char *eq;
8965 vpp = hashvar(name);
8966 vp = *findvar(vpp, name);
8967 eq = strchr(name, '=');
8968 if (vp == NULL) {
8969 if (eq)
8970 setvareq(name, VSTRFIXED);
8971 else
8972 setvar(name, NULL, VSTRFIXED);
8973 vp = *vpp; /* the new variable */
8974 lvp->flags = VUNSET;
8975 } else {
8976 lvp->text = vp->var_text;
8977 lvp->flags = vp->flags;
8978 vp->flags |= VSTRFIXED|VTEXTFIXED;
8979 if (eq)
8980 setvareq(name, 0);
8983 lvp->vp = vp;
8984 lvp->next = localvars;
8985 localvars = lvp;
8986 INT_ON;
8990 * The "local" command.
8992 static int FAST_FUNC
8993 localcmd(int argc UNUSED_PARAM, char **argv)
8995 char *name;
8997 argv = argptr;
8998 while ((name = *argv++) != NULL) {
8999 mklocal(name);
9001 return 0;
9004 static int FAST_FUNC
9005 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9007 return 1;
9010 static int FAST_FUNC
9011 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9013 return 0;
9016 static int FAST_FUNC
9017 execcmd(int argc UNUSED_PARAM, char **argv)
9019 if (argv[1]) {
9020 iflag = 0; /* exit on error */
9021 mflag = 0;
9022 optschanged();
9023 shellexec(argv + 1, pathval(), 0);
9025 return 0;
9029 * The return command.
9031 static int FAST_FUNC
9032 returncmd(int argc UNUSED_PARAM, char **argv)
9035 * If called outside a function, do what ksh does;
9036 * skip the rest of the file.
9038 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
9039 return argv[1] ? number(argv[1]) : exitstatus;
9042 /* Forward declarations for builtintab[] */
9043 static int breakcmd(int, char **) FAST_FUNC;
9044 static int dotcmd(int, char **) FAST_FUNC;
9045 static int evalcmd(int, char **) FAST_FUNC;
9046 static int exitcmd(int, char **) FAST_FUNC;
9047 static int exportcmd(int, char **) FAST_FUNC;
9048 #if ENABLE_ASH_GETOPTS
9049 static int getoptscmd(int, char **) FAST_FUNC;
9050 #endif
9051 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
9052 static int helpcmd(int, char **) FAST_FUNC;
9053 #endif
9054 #if ENABLE_SH_MATH_SUPPORT
9055 static int letcmd(int, char **) FAST_FUNC;
9056 #endif
9057 static int readcmd(int, char **) FAST_FUNC;
9058 static int setcmd(int, char **) FAST_FUNC;
9059 static int shiftcmd(int, char **) FAST_FUNC;
9060 static int timescmd(int, char **) FAST_FUNC;
9061 static int trapcmd(int, char **) FAST_FUNC;
9062 static int umaskcmd(int, char **) FAST_FUNC;
9063 static int unsetcmd(int, char **) FAST_FUNC;
9064 static int ulimitcmd(int, char **) FAST_FUNC;
9066 #define BUILTIN_NOSPEC "0"
9067 #define BUILTIN_SPECIAL "1"
9068 #define BUILTIN_REGULAR "2"
9069 #define BUILTIN_SPEC_REG "3"
9070 #define BUILTIN_ASSIGN "4"
9071 #define BUILTIN_SPEC_ASSG "5"
9072 #define BUILTIN_REG_ASSG "6"
9073 #define BUILTIN_SPEC_REG_ASSG "7"
9075 /* Stubs for calling non-FAST_FUNC's */
9076 #if ENABLE_ASH_BUILTIN_ECHO
9077 static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
9078 #endif
9079 #if ENABLE_ASH_BUILTIN_PRINTF
9080 static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
9081 #endif
9082 #if ENABLE_ASH_BUILTIN_TEST
9083 static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
9084 #endif
9086 /* Keep these in proper order since it is searched via bsearch() */
9087 static const struct builtincmd builtintab[] = {
9088 { BUILTIN_SPEC_REG "." , dotcmd },
9089 { BUILTIN_SPEC_REG ":" , truecmd },
9090 #if ENABLE_ASH_BUILTIN_TEST
9091 { BUILTIN_REGULAR "[" , testcmd },
9092 #if ENABLE_ASH_BASH_COMPAT
9093 { BUILTIN_REGULAR "[[" , testcmd },
9094 #endif
9095 #endif
9096 #if ENABLE_ASH_ALIAS
9097 { BUILTIN_REG_ASSG "alias" , aliascmd },
9098 #endif
9099 #if JOBS
9100 { BUILTIN_REGULAR "bg" , fg_bgcmd },
9101 #endif
9102 { BUILTIN_SPEC_REG "break" , breakcmd },
9103 { BUILTIN_REGULAR "cd" , cdcmd },
9104 { BUILTIN_NOSPEC "chdir" , cdcmd },
9105 #if ENABLE_ASH_CMDCMD
9106 { BUILTIN_REGULAR "command" , commandcmd },
9107 #endif
9108 { BUILTIN_SPEC_REG "continue", breakcmd },
9109 #if ENABLE_ASH_BUILTIN_ECHO
9110 { BUILTIN_REGULAR "echo" , echocmd },
9111 #endif
9112 { BUILTIN_SPEC_REG "eval" , evalcmd },
9113 { BUILTIN_SPEC_REG "exec" , execcmd },
9114 { BUILTIN_SPEC_REG "exit" , exitcmd },
9115 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9116 { BUILTIN_REGULAR "false" , falsecmd },
9117 #if JOBS
9118 { BUILTIN_REGULAR "fg" , fg_bgcmd },
9119 #endif
9120 #if ENABLE_ASH_GETOPTS
9121 { BUILTIN_REGULAR "getopts" , getoptscmd },
9122 #endif
9123 { BUILTIN_NOSPEC "hash" , hashcmd },
9124 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
9125 { BUILTIN_NOSPEC "help" , helpcmd },
9126 #endif
9127 #if JOBS
9128 { BUILTIN_REGULAR "jobs" , jobscmd },
9129 { BUILTIN_REGULAR "kill" , killcmd },
9130 #endif
9131 #if ENABLE_SH_MATH_SUPPORT
9132 { BUILTIN_NOSPEC "let" , letcmd },
9133 #endif
9134 { BUILTIN_ASSIGN "local" , localcmd },
9135 #if ENABLE_ASH_BUILTIN_PRINTF
9136 { BUILTIN_REGULAR "printf" , printfcmd },
9137 #endif
9138 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9139 { BUILTIN_REGULAR "read" , readcmd },
9140 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9141 { BUILTIN_SPEC_REG "return" , returncmd },
9142 { BUILTIN_SPEC_REG "set" , setcmd },
9143 { BUILTIN_SPEC_REG "shift" , shiftcmd },
9144 #if ENABLE_ASH_BASH_COMPAT
9145 { BUILTIN_SPEC_REG "source" , dotcmd },
9146 #endif
9147 #if ENABLE_ASH_BUILTIN_TEST
9148 { BUILTIN_REGULAR "test" , testcmd },
9149 #endif
9150 { BUILTIN_SPEC_REG "times" , timescmd },
9151 { BUILTIN_SPEC_REG "trap" , trapcmd },
9152 { BUILTIN_REGULAR "true" , truecmd },
9153 { BUILTIN_NOSPEC "type" , typecmd },
9154 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9155 { BUILTIN_REGULAR "umask" , umaskcmd },
9156 #if ENABLE_ASH_ALIAS
9157 { BUILTIN_REGULAR "unalias" , unaliascmd },
9158 #endif
9159 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9160 { BUILTIN_REGULAR "wait" , waitcmd },
9163 /* Should match the above table! */
9164 #define COMMANDCMD (builtintab + \
9165 2 + \
9166 1 * ENABLE_ASH_BUILTIN_TEST + \
9167 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9168 1 * ENABLE_ASH_ALIAS + \
9169 1 * ENABLE_ASH_JOB_CONTROL + \
9171 #define EXECCMD (builtintab + \
9172 2 + \
9173 1 * ENABLE_ASH_BUILTIN_TEST + \
9174 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9175 1 * ENABLE_ASH_ALIAS + \
9176 1 * ENABLE_ASH_JOB_CONTROL + \
9177 3 + \
9178 1 * ENABLE_ASH_CMDCMD + \
9179 1 + \
9180 ENABLE_ASH_BUILTIN_ECHO + \
9184 * Search the table of builtin commands.
9186 static struct builtincmd *
9187 find_builtin(const char *name)
9189 struct builtincmd *bp;
9191 bp = bsearch(
9192 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
9193 pstrcmp
9195 return bp;
9199 * Execute a simple command.
9201 static int
9202 isassignment(const char *p)
9204 const char *q = endofname(p);
9205 if (p == q)
9206 return 0;
9207 return *q == '=';
9209 static int FAST_FUNC
9210 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9212 /* Preserve exitstatus of a previous possible redirection
9213 * as POSIX mandates */
9214 return back_exitstatus;
9216 static void
9217 evalcommand(union node *cmd, int flags)
9219 static const struct builtincmd null_bltin = {
9220 "\0\0", bltincmd /* why three NULs? */
9222 struct stackmark smark;
9223 union node *argp;
9224 struct arglist arglist;
9225 struct arglist varlist;
9226 char **argv;
9227 int argc;
9228 const struct strlist *sp;
9229 struct cmdentry cmdentry;
9230 struct job *jp;
9231 char *lastarg;
9232 const char *path;
9233 int spclbltin;
9234 int status;
9235 char **nargv;
9236 struct builtincmd *bcmd;
9237 smallint cmd_is_exec;
9238 smallint pseudovarflag = 0;
9240 /* First expand the arguments. */
9241 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9242 setstackmark(&smark);
9243 back_exitstatus = 0;
9245 cmdentry.cmdtype = CMDBUILTIN;
9246 cmdentry.u.cmd = &null_bltin;
9247 varlist.lastp = &varlist.list;
9248 *varlist.lastp = NULL;
9249 arglist.lastp = &arglist.list;
9250 *arglist.lastp = NULL;
9252 argc = 0;
9253 if (cmd->ncmd.args) {
9254 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9255 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9258 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9259 struct strlist **spp;
9261 spp = arglist.lastp;
9262 if (pseudovarflag && isassignment(argp->narg.text))
9263 expandarg(argp, &arglist, EXP_VARTILDE);
9264 else
9265 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9267 for (sp = *spp; sp; sp = sp->next)
9268 argc++;
9271 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
9272 for (sp = arglist.list; sp; sp = sp->next) {
9273 TRACE(("evalcommand arg: %s\n", sp->text));
9274 *nargv++ = sp->text;
9276 *nargv = NULL;
9278 lastarg = NULL;
9279 if (iflag && funcnest == 0 && argc > 0)
9280 lastarg = nargv[-1];
9282 preverrout_fd = 2;
9283 expredir(cmd->ncmd.redirect);
9284 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
9286 path = vpath.var_text;
9287 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9288 struct strlist **spp;
9289 char *p;
9291 spp = varlist.lastp;
9292 expandarg(argp, &varlist, EXP_VARTILDE);
9295 * Modify the command lookup path, if a PATH= assignment
9296 * is present
9298 p = (*spp)->text;
9299 if (varcmp(p, path) == 0)
9300 path = p;
9303 /* Print the command if xflag is set. */
9304 if (xflag) {
9305 int n;
9306 const char *p = " %s" + 1;
9308 fdprintf(preverrout_fd, p, expandstr(ps4val()));
9309 sp = varlist.list;
9310 for (n = 0; n < 2; n++) {
9311 while (sp) {
9312 fdprintf(preverrout_fd, p, sp->text);
9313 sp = sp->next;
9314 p = " %s";
9316 sp = arglist.list;
9318 safe_write(preverrout_fd, "\n", 1);
9321 cmd_is_exec = 0;
9322 spclbltin = -1;
9324 /* Now locate the command. */
9325 if (argc) {
9326 int cmd_flag = DO_ERR;
9327 #if ENABLE_ASH_CMDCMD
9328 const char *oldpath = path + 5;
9329 #endif
9330 path += 5;
9331 for (;;) {
9332 find_command(argv[0], &cmdentry, cmd_flag, path);
9333 if (cmdentry.cmdtype == CMDUNKNOWN) {
9334 flush_stdout_stderr();
9335 status = 127;
9336 goto bail;
9339 /* implement bltin and command here */
9340 if (cmdentry.cmdtype != CMDBUILTIN)
9341 break;
9342 if (spclbltin < 0)
9343 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9344 if (cmdentry.u.cmd == EXECCMD)
9345 cmd_is_exec = 1;
9346 #if ENABLE_ASH_CMDCMD
9347 if (cmdentry.u.cmd == COMMANDCMD) {
9348 path = oldpath;
9349 nargv = parse_command_args(argv, &path);
9350 if (!nargv)
9351 break;
9352 argc -= nargv - argv;
9353 argv = nargv;
9354 cmd_flag |= DO_NOFUNC;
9355 } else
9356 #endif
9357 break;
9361 if (status) {
9362 /* We have a redirection error. */
9363 if (spclbltin > 0)
9364 raise_exception(EXERROR);
9365 bail:
9366 exitstatus = status;
9367 goto out;
9370 /* Execute the command. */
9371 switch (cmdentry.cmdtype) {
9372 default: {
9374 #if ENABLE_FEATURE_SH_NOFORK
9375 /* (1) BUG: if variables are set, we need to fork, or save/restore them
9376 * around run_nofork_applet() call.
9377 * (2) Should this check also be done in forkshell()?
9378 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9380 /* find_command() encodes applet_no as (-2 - applet_no) */
9381 int applet_no = (- cmdentry.u.index - 2);
9382 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
9383 listsetvar(varlist.list, VEXPORT|VSTACK);
9384 /* run <applet>_main() */
9385 exitstatus = run_nofork_applet(applet_no, argv);
9386 break;
9388 #endif
9389 /* Can we avoid forking off? For example, very last command
9390 * in a script or a subshell does not need forking,
9391 * we can just exec it.
9393 if (!(flags & EV_EXIT) || may_have_traps) {
9394 /* No, forking off a child is necessary */
9395 INT_OFF;
9396 jp = makejob(/*cmd,*/ 1);
9397 if (forkshell(jp, cmd, FORK_FG) != 0) {
9398 /* parent */
9399 exitstatus = waitforjob(jp);
9400 INT_ON;
9401 TRACE(("forked child exited with %d\n", exitstatus));
9402 break;
9404 /* child */
9405 FORCE_INT_ON;
9406 /* fall through to exec'ing external program */
9408 listsetvar(varlist.list, VEXPORT|VSTACK);
9409 shellexec(argv, path, cmdentry.u.index);
9410 /* NOTREACHED */
9411 } /* default */
9412 case CMDBUILTIN:
9413 cmdenviron = varlist.list;
9414 if (cmdenviron) {
9415 struct strlist *list = cmdenviron;
9416 int i = VNOSET;
9417 if (spclbltin > 0 || argc == 0) {
9418 i = 0;
9419 if (cmd_is_exec && argc > 1)
9420 i = VEXPORT;
9422 listsetvar(list, i);
9424 /* Tight loop with builtins only:
9425 * "while kill -0 $child; do true; done"
9426 * will never exit even if $child died, unless we do this
9427 * to reap the zombie and make kill detect that it's gone: */
9428 dowait(DOWAIT_NONBLOCK, NULL);
9430 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9431 int exit_status;
9432 int i = exception_type;
9433 if (i == EXEXIT)
9434 goto raise;
9435 exit_status = 2;
9436 if (i == EXINT)
9437 exit_status = 128 + SIGINT;
9438 if (i == EXSIG)
9439 exit_status = 128 + pending_sig;
9440 exitstatus = exit_status;
9441 if (i == EXINT || spclbltin > 0) {
9442 raise:
9443 longjmp(exception_handler->loc, 1);
9445 FORCE_INT_ON;
9447 break;
9449 case CMDFUNCTION:
9450 listsetvar(varlist.list, 0);
9451 /* See above for the rationale */
9452 dowait(DOWAIT_NONBLOCK, NULL);
9453 if (evalfun(cmdentry.u.func, argc, argv, flags))
9454 goto raise;
9455 break;
9457 } /* switch */
9459 out:
9460 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
9461 if (lastarg) {
9462 /* dsl: I think this is intended to be used to support
9463 * '_' in 'vi' command mode during line editing...
9464 * However I implemented that within libedit itself.
9466 setvar("_", lastarg, 0);
9468 popstackmark(&smark);
9471 static int
9472 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9474 char *volatile savecmdname;
9475 struct jmploc *volatile savehandler;
9476 struct jmploc jmploc;
9477 int i;
9479 savecmdname = commandname;
9480 i = setjmp(jmploc.loc);
9481 if (i)
9482 goto cmddone;
9483 savehandler = exception_handler;
9484 exception_handler = &jmploc;
9485 commandname = argv[0];
9486 argptr = argv + 1;
9487 optptr = NULL; /* initialize nextopt */
9488 exitstatus = (*cmd->builtin)(argc, argv);
9489 flush_stdout_stderr();
9490 cmddone:
9491 exitstatus |= ferror(stdout);
9492 clearerr(stdout);
9493 commandname = savecmdname;
9494 exception_handler = savehandler;
9496 return i;
9499 static int
9500 goodname(const char *p)
9502 return endofname(p)[0] == '\0';
9507 * Search for a command. This is called before we fork so that the
9508 * location of the command will be available in the parent as well as
9509 * the child. The check for "goodname" is an overly conservative
9510 * check that the name will not be subject to expansion.
9512 static void
9513 prehash(union node *n)
9515 struct cmdentry entry;
9517 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9518 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9522 /* ============ Builtin commands
9524 * Builtin commands whose functions are closely tied to evaluation
9525 * are implemented here.
9529 * Handle break and continue commands. Break, continue, and return are
9530 * all handled by setting the evalskip flag. The evaluation routines
9531 * above all check this flag, and if it is set they start skipping
9532 * commands rather than executing them. The variable skipcount is
9533 * the number of loops to break/continue, or the number of function
9534 * levels to return. (The latter is always 1.) It should probably
9535 * be an error to break out of more loops than exist, but it isn't
9536 * in the standard shell so we don't make it one here.
9538 static int FAST_FUNC
9539 breakcmd(int argc UNUSED_PARAM, char **argv)
9541 int n = argv[1] ? number(argv[1]) : 1;
9543 if (n <= 0)
9544 ash_msg_and_raise_error(msg_illnum, argv[1]);
9545 if (n > loopnest)
9546 n = loopnest;
9547 if (n > 0) {
9548 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9549 skipcount = n;
9551 return 0;
9555 /* ============ input.c
9557 * This implements the input routines used by the parser.
9560 enum {
9561 INPUT_PUSH_FILE = 1,
9562 INPUT_NOFILE_OK = 2,
9565 static smallint checkkwd;
9566 /* values of checkkwd variable */
9567 #define CHKALIAS 0x1
9568 #define CHKKWD 0x2
9569 #define CHKNL 0x4
9572 * Push a string back onto the input at this current parsefile level.
9573 * We handle aliases this way.
9575 #if !ENABLE_ASH_ALIAS
9576 #define pushstring(s, ap) pushstring(s)
9577 #endif
9578 static void
9579 pushstring(char *s, struct alias *ap)
9581 struct strpush *sp;
9582 int len;
9584 len = strlen(s);
9585 INT_OFF;
9586 if (g_parsefile->strpush) {
9587 sp = ckzalloc(sizeof(*sp));
9588 sp->prev = g_parsefile->strpush;
9589 } else {
9590 sp = &(g_parsefile->basestrpush);
9592 g_parsefile->strpush = sp;
9593 sp->prev_string = g_parsefile->next_to_pgetc;
9594 sp->prev_left_in_line = g_parsefile->left_in_line;
9595 #if ENABLE_ASH_ALIAS
9596 sp->ap = ap;
9597 if (ap) {
9598 ap->flag |= ALIASINUSE;
9599 sp->string = s;
9601 #endif
9602 g_parsefile->next_to_pgetc = s;
9603 g_parsefile->left_in_line = len;
9604 INT_ON;
9607 static void
9608 popstring(void)
9610 struct strpush *sp = g_parsefile->strpush;
9612 INT_OFF;
9613 #if ENABLE_ASH_ALIAS
9614 if (sp->ap) {
9615 if (g_parsefile->next_to_pgetc[-1] == ' '
9616 || g_parsefile->next_to_pgetc[-1] == '\t'
9618 checkkwd |= CHKALIAS;
9620 if (sp->string != sp->ap->val) {
9621 free(sp->string);
9623 sp->ap->flag &= ~ALIASINUSE;
9624 if (sp->ap->flag & ALIASDEAD) {
9625 unalias(sp->ap->name);
9628 #endif
9629 g_parsefile->next_to_pgetc = sp->prev_string;
9630 g_parsefile->left_in_line = sp->prev_left_in_line;
9631 g_parsefile->strpush = sp->prev;
9632 if (sp != &(g_parsefile->basestrpush))
9633 free(sp);
9634 INT_ON;
9637 //FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9638 //it peeks whether it is &>, and then pushes back both chars.
9639 //This function needs to save last *next_to_pgetc to buf[0]
9640 //to make two pungetc() reliable. Currently,
9641 // pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
9642 static int
9643 preadfd(void)
9645 int nr;
9646 char *buf = g_parsefile->buf;
9648 g_parsefile->next_to_pgetc = buf;
9649 #if ENABLE_FEATURE_EDITING
9650 retry:
9651 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
9652 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
9653 else {
9654 int timeout = -1;
9655 # if ENABLE_ASH_IDLE_TIMEOUT
9656 if (iflag) {
9657 const char *tmout_var = lookupvar("TMOUT");
9658 if (tmout_var) {
9659 timeout = atoi(tmout_var) * 1000;
9660 if (timeout <= 0)
9661 timeout = -1;
9664 # endif
9665 # if ENABLE_FEATURE_TAB_COMPLETION
9666 line_input_state->path_lookup = pathval();
9667 # endif
9668 /* Unicode support should be activated even if LANG is set
9669 * _during_ shell execution, not only if it was set when
9670 * shell was started. Therefore, re-check LANG every time:
9672 reinit_unicode(lookupvar("LANG"));
9673 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
9674 if (nr == 0) {
9675 /* Ctrl+C pressed */
9676 if (trap[SIGINT]) {
9677 buf[0] = '\n';
9678 buf[1] = '\0';
9679 raise(SIGINT);
9680 return 1;
9682 goto retry;
9684 if (nr < 0) {
9685 if (errno == 0) {
9686 /* Ctrl+D pressed */
9687 nr = 0;
9689 # if ENABLE_ASH_IDLE_TIMEOUT
9690 else if (errno == EAGAIN && timeout > 0) {
9691 printf("\007timed out waiting for input: auto-logout\n");
9692 exitshell();
9694 # endif
9697 #else
9698 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
9699 #endif
9701 #if 0 /* disabled: nonblock_immune_read() handles this problem */
9702 if (nr < 0) {
9703 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9704 int flags = fcntl(0, F_GETFL);
9705 if (flags >= 0 && (flags & O_NONBLOCK)) {
9706 flags &= ~O_NONBLOCK;
9707 if (fcntl(0, F_SETFL, flags) >= 0) {
9708 out2str("sh: turning off NDELAY mode\n");
9709 goto retry;
9714 #endif
9715 return nr;
9719 * Refill the input buffer and return the next input character:
9721 * 1) If a string was pushed back on the input, pop it;
9722 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9723 * or we are reading from a string so we can't refill the buffer,
9724 * return EOF.
9725 * 3) If there is more stuff in this buffer, use it else call read to fill it.
9726 * 4) Process input up to the next newline, deleting nul characters.
9728 //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9729 #define pgetc_debug(...) ((void)0)
9730 static int
9731 preadbuffer(void)
9733 char *q;
9734 int more;
9736 while (g_parsefile->strpush) {
9737 #if ENABLE_ASH_ALIAS
9738 if (g_parsefile->left_in_line == -1
9739 && g_parsefile->strpush->ap
9740 && g_parsefile->next_to_pgetc[-1] != ' '
9741 && g_parsefile->next_to_pgetc[-1] != '\t'
9743 pgetc_debug("preadbuffer PEOA");
9744 return PEOA;
9746 #endif
9747 popstring();
9748 /* try "pgetc" now: */
9749 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9750 g_parsefile->left_in_line,
9751 g_parsefile->next_to_pgetc,
9752 g_parsefile->next_to_pgetc);
9753 if (--g_parsefile->left_in_line >= 0)
9754 return (unsigned char)(*g_parsefile->next_to_pgetc++);
9756 /* on both branches above g_parsefile->left_in_line < 0.
9757 * "pgetc" needs refilling.
9760 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
9761 * pungetc() may increment it a few times.
9762 * Assuming it won't increment it to less than -90.
9764 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
9765 pgetc_debug("preadbuffer PEOF1");
9766 /* even in failure keep left_in_line and next_to_pgetc
9767 * in lock step, for correct multi-layer pungetc.
9768 * left_in_line was decremented before preadbuffer(),
9769 * must inc next_to_pgetc: */
9770 g_parsefile->next_to_pgetc++;
9771 return PEOF;
9774 more = g_parsefile->left_in_buffer;
9775 if (more <= 0) {
9776 flush_stdout_stderr();
9777 again:
9778 more = preadfd();
9779 if (more <= 0) {
9780 /* don't try reading again */
9781 g_parsefile->left_in_line = -99;
9782 pgetc_debug("preadbuffer PEOF2");
9783 g_parsefile->next_to_pgetc++;
9784 return PEOF;
9788 /* Find out where's the end of line.
9789 * Set g_parsefile->left_in_line
9790 * and g_parsefile->left_in_buffer acordingly.
9791 * NUL chars are deleted.
9793 q = g_parsefile->next_to_pgetc;
9794 for (;;) {
9795 char c;
9797 more--;
9799 c = *q;
9800 if (c == '\0') {
9801 memmove(q, q + 1, more);
9802 } else {
9803 q++;
9804 if (c == '\n') {
9805 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9806 break;
9810 if (more <= 0) {
9811 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9812 if (g_parsefile->left_in_line < 0)
9813 goto again;
9814 break;
9817 g_parsefile->left_in_buffer = more;
9819 if (vflag) {
9820 char save = *q;
9821 *q = '\0';
9822 out2str(g_parsefile->next_to_pgetc);
9823 *q = save;
9826 pgetc_debug("preadbuffer at %d:%p'%s'",
9827 g_parsefile->left_in_line,
9828 g_parsefile->next_to_pgetc,
9829 g_parsefile->next_to_pgetc);
9830 return (unsigned char)*g_parsefile->next_to_pgetc++;
9833 #define pgetc_as_macro() \
9834 (--g_parsefile->left_in_line >= 0 \
9835 ? (unsigned char)*g_parsefile->next_to_pgetc++ \
9836 : preadbuffer() \
9839 static int
9840 pgetc(void)
9842 pgetc_debug("pgetc_fast at %d:%p'%s'",
9843 g_parsefile->left_in_line,
9844 g_parsefile->next_to_pgetc,
9845 g_parsefile->next_to_pgetc);
9846 return pgetc_as_macro();
9849 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9850 # define pgetc_fast() pgetc()
9851 #else
9852 # define pgetc_fast() pgetc_as_macro()
9853 #endif
9855 #if ENABLE_ASH_ALIAS
9856 static int
9857 pgetc_without_PEOA(void)
9859 int c;
9860 do {
9861 pgetc_debug("pgetc_fast at %d:%p'%s'",
9862 g_parsefile->left_in_line,
9863 g_parsefile->next_to_pgetc,
9864 g_parsefile->next_to_pgetc);
9865 c = pgetc_fast();
9866 } while (c == PEOA);
9867 return c;
9869 #else
9870 # define pgetc_without_PEOA() pgetc()
9871 #endif
9874 * Read a line from the script.
9876 static char *
9877 pfgets(char *line, int len)
9879 char *p = line;
9880 int nleft = len;
9881 int c;
9883 while (--nleft > 0) {
9884 c = pgetc_without_PEOA();
9885 if (c == PEOF) {
9886 if (p == line)
9887 return NULL;
9888 break;
9890 *p++ = c;
9891 if (c == '\n')
9892 break;
9894 *p = '\0';
9895 return line;
9899 * Undo the last call to pgetc. Only one character may be pushed back.
9900 * PEOF may be pushed back.
9902 static void
9903 pungetc(void)
9905 g_parsefile->left_in_line++;
9906 g_parsefile->next_to_pgetc--;
9907 pgetc_debug("pushed back to %d:%p'%s'",
9908 g_parsefile->left_in_line,
9909 g_parsefile->next_to_pgetc,
9910 g_parsefile->next_to_pgetc);
9914 * To handle the "." command, a stack of input files is used. Pushfile
9915 * adds a new entry to the stack and popfile restores the previous level.
9917 static void
9918 pushfile(void)
9920 struct parsefile *pf;
9922 pf = ckzalloc(sizeof(*pf));
9923 pf->prev = g_parsefile;
9924 pf->pf_fd = -1;
9925 /*pf->strpush = NULL; - ckzalloc did it */
9926 /*pf->basestrpush.prev = NULL;*/
9927 g_parsefile = pf;
9930 static void
9931 popfile(void)
9933 struct parsefile *pf = g_parsefile;
9935 INT_OFF;
9936 if (pf->pf_fd >= 0)
9937 close(pf->pf_fd);
9938 free(pf->buf);
9939 while (pf->strpush)
9940 popstring();
9941 g_parsefile = pf->prev;
9942 free(pf);
9943 INT_ON;
9947 * Return to top level.
9949 static void
9950 popallfiles(void)
9952 while (g_parsefile != &basepf)
9953 popfile();
9957 * Close the file(s) that the shell is reading commands from. Called
9958 * after a fork is done.
9960 static void
9961 closescript(void)
9963 popallfiles();
9964 if (g_parsefile->pf_fd > 0) {
9965 close(g_parsefile->pf_fd);
9966 g_parsefile->pf_fd = 0;
9971 * Like setinputfile, but takes an open file descriptor. Call this with
9972 * interrupts off.
9974 static void
9975 setinputfd(int fd, int push)
9977 close_on_exec_on(fd);
9978 if (push) {
9979 pushfile();
9980 g_parsefile->buf = NULL;
9982 g_parsefile->pf_fd = fd;
9983 if (g_parsefile->buf == NULL)
9984 g_parsefile->buf = ckmalloc(IBUFSIZ);
9985 g_parsefile->left_in_buffer = 0;
9986 g_parsefile->left_in_line = 0;
9987 g_parsefile->linno = 1;
9991 * Set the input to take input from a file. If push is set, push the
9992 * old input onto the stack first.
9994 static int
9995 setinputfile(const char *fname, int flags)
9997 int fd;
9998 int fd2;
10000 INT_OFF;
10001 fd = open(fname, O_RDONLY);
10002 if (fd < 0) {
10003 if (flags & INPUT_NOFILE_OK)
10004 goto out;
10005 ash_msg_and_raise_error("can't open '%s'", fname);
10007 if (fd < 10) {
10008 fd2 = copyfd(fd, 10);
10009 close(fd);
10010 if (fd2 < 0)
10011 ash_msg_and_raise_error("out of file descriptors");
10012 fd = fd2;
10014 setinputfd(fd, flags & INPUT_PUSH_FILE);
10015 out:
10016 INT_ON;
10017 return fd;
10021 * Like setinputfile, but takes input from a string.
10023 static void
10024 setinputstring(char *string)
10026 INT_OFF;
10027 pushfile();
10028 g_parsefile->next_to_pgetc = string;
10029 g_parsefile->left_in_line = strlen(string);
10030 g_parsefile->buf = NULL;
10031 g_parsefile->linno = 1;
10032 INT_ON;
10036 /* ============ mail.c
10038 * Routines to check for mail.
10041 #if ENABLE_ASH_MAIL
10043 #define MAXMBOXES 10
10045 /* times of mailboxes */
10046 static time_t mailtime[MAXMBOXES];
10047 /* Set if MAIL or MAILPATH is changed. */
10048 static smallint mail_var_path_changed;
10051 * Print appropriate message(s) if mail has arrived.
10052 * If mail_var_path_changed is set,
10053 * then the value of MAIL has mail_var_path_changed,
10054 * so we just update the values.
10056 static void
10057 chkmail(void)
10059 const char *mpath;
10060 char *p;
10061 char *q;
10062 time_t *mtp;
10063 struct stackmark smark;
10064 struct stat statb;
10066 setstackmark(&smark);
10067 mpath = mpathset() ? mpathval() : mailval();
10068 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
10069 p = path_advance(&mpath, nullstr);
10070 if (p == NULL)
10071 break;
10072 if (*p == '\0')
10073 continue;
10074 for (q = p; *q; q++)
10075 continue;
10076 #if DEBUG
10077 if (q[-1] != '/')
10078 abort();
10079 #endif
10080 q[-1] = '\0'; /* delete trailing '/' */
10081 if (stat(p, &statb) < 0) {
10082 *mtp = 0;
10083 continue;
10085 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
10086 fprintf(
10087 stderr, "%s\n",
10088 pathopt ? pathopt : "you have mail"
10091 *mtp = statb.st_mtime;
10093 mail_var_path_changed = 0;
10094 popstackmark(&smark);
10097 static void FAST_FUNC
10098 changemail(const char *val UNUSED_PARAM)
10100 mail_var_path_changed = 1;
10103 #endif /* ASH_MAIL */
10106 /* ============ ??? */
10109 * Set the shell parameters.
10111 static void
10112 setparam(char **argv)
10114 char **newparam;
10115 char **ap;
10116 int nparam;
10118 for (nparam = 0; argv[nparam]; nparam++)
10119 continue;
10120 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10121 while (*argv) {
10122 *ap++ = ckstrdup(*argv++);
10124 *ap = NULL;
10125 freeparam(&shellparam);
10126 shellparam.malloced = 1;
10127 shellparam.nparam = nparam;
10128 shellparam.p = newparam;
10129 #if ENABLE_ASH_GETOPTS
10130 shellparam.optind = 1;
10131 shellparam.optoff = -1;
10132 #endif
10136 * Process shell options. The global variable argptr contains a pointer
10137 * to the argument list; we advance it past the options.
10139 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10140 * For a non-interactive shell, an error condition encountered
10141 * by a special built-in ... shall cause the shell to write a diagnostic message
10142 * to standard error and exit as shown in the following table:
10143 * Error Special Built-In
10144 * ...
10145 * Utility syntax error (option or operand error) Shall exit
10146 * ...
10147 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10148 * we see that bash does not do that (set "finishes" with error code 1 instead,
10149 * and shell continues), and people rely on this behavior!
10150 * Testcase:
10151 * set -o barfoo 2>/dev/null
10152 * echo $?
10154 * Oh well. Let's mimic that.
10156 static int
10157 plus_minus_o(char *name, int val)
10159 int i;
10161 if (name) {
10162 for (i = 0; i < NOPTS; i++) {
10163 if (strcmp(name, optnames(i)) == 0) {
10164 optlist[i] = val;
10165 return 0;
10168 ash_msg("illegal option %co %s", val ? '-' : '+', name);
10169 return 1;
10171 for (i = 0; i < NOPTS; i++) {
10172 if (val) {
10173 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10174 } else {
10175 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10178 return 0;
10180 static void
10181 setoption(int flag, int val)
10183 int i;
10185 for (i = 0; i < NOPTS; i++) {
10186 if (optletters(i) == flag) {
10187 optlist[i] = val;
10188 return;
10191 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
10192 /* NOTREACHED */
10194 static int
10195 options(int cmdline)
10197 char *p;
10198 int val;
10199 int c;
10201 if (cmdline)
10202 minusc = NULL;
10203 while ((p = *argptr) != NULL) {
10204 c = *p++;
10205 if (c != '-' && c != '+')
10206 break;
10207 argptr++;
10208 val = 0; /* val = 0 if c == '+' */
10209 if (c == '-') {
10210 val = 1;
10211 if (p[0] == '\0' || LONE_DASH(p)) {
10212 if (!cmdline) {
10213 /* "-" means turn off -x and -v */
10214 if (p[0] == '\0')
10215 xflag = vflag = 0;
10216 /* "--" means reset params */
10217 else if (*argptr == NULL)
10218 setparam(argptr);
10220 break; /* "-" or "--" terminates options */
10223 /* first char was + or - */
10224 while ((c = *p++) != '\0') {
10225 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
10226 if (c == 'c' && cmdline) {
10227 minusc = p; /* command is after shell args */
10228 } else if (c == 'o') {
10229 if (plus_minus_o(*argptr, val)) {
10230 /* it already printed err message */
10231 return 1; /* error */
10233 if (*argptr)
10234 argptr++;
10235 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10236 isloginsh = 1;
10237 /* bash does not accept +-login, we also won't */
10238 } else if (cmdline && val && (c == '-')) { /* long options */
10239 if (strcmp(p, "login") == 0)
10240 isloginsh = 1;
10241 break;
10242 } else {
10243 setoption(c, val);
10247 return 0;
10251 * The shift builtin command.
10253 static int FAST_FUNC
10254 shiftcmd(int argc UNUSED_PARAM, char **argv)
10256 int n;
10257 char **ap1, **ap2;
10259 n = 1;
10260 if (argv[1])
10261 n = number(argv[1]);
10262 if (n > shellparam.nparam)
10263 n = 0; /* bash compat, was = shellparam.nparam; */
10264 INT_OFF;
10265 shellparam.nparam -= n;
10266 for (ap1 = shellparam.p; --n >= 0; ap1++) {
10267 if (shellparam.malloced)
10268 free(*ap1);
10270 ap2 = shellparam.p;
10271 while ((*ap2++ = *ap1++) != NULL)
10272 continue;
10273 #if ENABLE_ASH_GETOPTS
10274 shellparam.optind = 1;
10275 shellparam.optoff = -1;
10276 #endif
10277 INT_ON;
10278 return 0;
10282 * POSIX requires that 'set' (but not export or readonly) output the
10283 * variables in lexicographic order - by the locale's collating order (sigh).
10284 * Maybe we could keep them in an ordered balanced binary tree
10285 * instead of hashed lists.
10286 * For now just roll 'em through qsort for printing...
10288 static int
10289 showvars(const char *sep_prefix, int on, int off)
10291 const char *sep;
10292 char **ep, **epend;
10294 ep = listvars(on, off, &epend);
10295 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10297 sep = *sep_prefix ? " " : sep_prefix;
10299 for (; ep < epend; ep++) {
10300 const char *p;
10301 const char *q;
10303 p = strchrnul(*ep, '=');
10304 q = nullstr;
10305 if (*p)
10306 q = single_quote(++p);
10307 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10309 return 0;
10313 * The set command builtin.
10315 static int FAST_FUNC
10316 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10318 int retval;
10320 if (!argv[1])
10321 return showvars(nullstr, 0, VUNSET);
10323 INT_OFF;
10324 retval = options(/*cmdline:*/ 0);
10325 if (retval == 0) { /* if no parse error... */
10326 optschanged();
10327 if (*argptr != NULL) {
10328 setparam(argptr);
10331 INT_ON;
10332 return retval;
10335 #if ENABLE_ASH_RANDOM_SUPPORT
10336 static void FAST_FUNC
10337 change_random(const char *value)
10339 uint32_t t;
10341 if (value == NULL) {
10342 /* "get", generate */
10343 t = next_random(&random_gen);
10344 /* set without recursion */
10345 setvar(vrandom.var_text, utoa(t), VNOFUNC);
10346 vrandom.flags &= ~VNOFUNC;
10347 } else {
10348 /* set/reset */
10349 t = strtoul(value, NULL, 10);
10350 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
10353 #endif
10355 #if ENABLE_ASH_GETOPTS
10356 static int
10357 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
10359 char *p, *q;
10360 char c = '?';
10361 int done = 0;
10362 int err = 0;
10363 char s[12];
10364 char **optnext;
10366 if (*param_optind < 1)
10367 return 1;
10368 optnext = optfirst + *param_optind - 1;
10370 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
10371 p = NULL;
10372 else
10373 p = optnext[-1] + *optoff;
10374 if (p == NULL || *p == '\0') {
10375 /* Current word is done, advance */
10376 p = *optnext;
10377 if (p == NULL || *p != '-' || *++p == '\0') {
10378 atend:
10379 p = NULL;
10380 done = 1;
10381 goto out;
10383 optnext++;
10384 if (LONE_DASH(p)) /* check for "--" */
10385 goto atend;
10388 c = *p++;
10389 for (q = optstr; *q != c;) {
10390 if (*q == '\0') {
10391 if (optstr[0] == ':') {
10392 s[0] = c;
10393 s[1] = '\0';
10394 err |= setvarsafe("OPTARG", s, 0);
10395 } else {
10396 fprintf(stderr, "Illegal option -%c\n", c);
10397 unsetvar("OPTARG");
10399 c = '?';
10400 goto out;
10402 if (*++q == ':')
10403 q++;
10406 if (*++q == ':') {
10407 if (*p == '\0' && (p = *optnext) == NULL) {
10408 if (optstr[0] == ':') {
10409 s[0] = c;
10410 s[1] = '\0';
10411 err |= setvarsafe("OPTARG", s, 0);
10412 c = ':';
10413 } else {
10414 fprintf(stderr, "No arg for -%c option\n", c);
10415 unsetvar("OPTARG");
10416 c = '?';
10418 goto out;
10421 if (p == *optnext)
10422 optnext++;
10423 err |= setvarsafe("OPTARG", p, 0);
10424 p = NULL;
10425 } else
10426 err |= setvarsafe("OPTARG", nullstr, 0);
10427 out:
10428 *optoff = p ? p - *(optnext - 1) : -1;
10429 *param_optind = optnext - optfirst + 1;
10430 fmtstr(s, sizeof(s), "%d", *param_optind);
10431 err |= setvarsafe("OPTIND", s, VNOFUNC);
10432 s[0] = c;
10433 s[1] = '\0';
10434 err |= setvarsafe(optvar, s, 0);
10435 if (err) {
10436 *param_optind = 1;
10437 *optoff = -1;
10438 flush_stdout_stderr();
10439 raise_exception(EXERROR);
10441 return done;
10445 * The getopts builtin. Shellparam.optnext points to the next argument
10446 * to be processed. Shellparam.optptr points to the next character to
10447 * be processed in the current argument. If shellparam.optnext is NULL,
10448 * then it's the first time getopts has been called.
10450 static int FAST_FUNC
10451 getoptscmd(int argc, char **argv)
10453 char **optbase;
10455 if (argc < 3)
10456 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
10457 if (argc == 3) {
10458 optbase = shellparam.p;
10459 if (shellparam.optind > shellparam.nparam + 1) {
10460 shellparam.optind = 1;
10461 shellparam.optoff = -1;
10463 } else {
10464 optbase = &argv[3];
10465 if (shellparam.optind > argc - 2) {
10466 shellparam.optind = 1;
10467 shellparam.optoff = -1;
10471 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
10472 &shellparam.optoff);
10474 #endif /* ASH_GETOPTS */
10477 /* ============ Shell parser */
10479 struct heredoc {
10480 struct heredoc *next; /* next here document in list */
10481 union node *here; /* redirection node */
10482 char *eofmark; /* string indicating end of input */
10483 smallint striptabs; /* if set, strip leading tabs */
10486 static smallint tokpushback; /* last token pushed back */
10487 static smallint parsebackquote; /* nonzero if we are inside backquotes */
10488 static smallint quoteflag; /* set if (part of) last token was quoted */
10489 static token_id_t lasttoken; /* last token read (integer id Txxx) */
10490 static struct heredoc *heredoclist; /* list of here documents to read */
10491 static char *wordtext; /* text of last word returned by readtoken */
10492 static struct nodelist *backquotelist;
10493 static union node *redirnode;
10494 static struct heredoc *heredoc;
10496 static const char *
10497 tokname(char *buf, int tok)
10499 if (tok < TSEMI)
10500 return tokname_array[tok] + 1;
10501 sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
10502 return buf;
10505 /* raise_error_unexpected_syntax:
10506 * Called when an unexpected token is read during the parse. The argument
10507 * is the token that is expected, or -1 if more than one type of token can
10508 * occur at this point.
10510 static void raise_error_unexpected_syntax(int) NORETURN;
10511 static void
10512 raise_error_unexpected_syntax(int token)
10514 char msg[64];
10515 char buf[16];
10516 int l;
10518 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
10519 if (token >= 0)
10520 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
10521 raise_error_syntax(msg);
10522 /* NOTREACHED */
10525 #define EOFMARKLEN 79
10527 /* parsing is heavily cross-recursive, need these forward decls */
10528 static union node *andor(void);
10529 static union node *pipeline(void);
10530 static union node *parse_command(void);
10531 static void parseheredoc(void);
10532 static char peektoken(void);
10533 static int readtoken(void);
10535 static union node *
10536 list(int nlflag)
10538 union node *n1, *n2, *n3;
10539 int tok;
10541 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10542 if (nlflag == 2 && peektoken())
10543 return NULL;
10544 n1 = NULL;
10545 for (;;) {
10546 n2 = andor();
10547 tok = readtoken();
10548 if (tok == TBACKGND) {
10549 if (n2->type == NPIPE) {
10550 n2->npipe.pipe_backgnd = 1;
10551 } else {
10552 if (n2->type != NREDIR) {
10553 n3 = stzalloc(sizeof(struct nredir));
10554 n3->nredir.n = n2;
10555 /*n3->nredir.redirect = NULL; - stzalloc did it */
10556 n2 = n3;
10558 n2->type = NBACKGND;
10561 if (n1 == NULL) {
10562 n1 = n2;
10563 } else {
10564 n3 = stzalloc(sizeof(struct nbinary));
10565 n3->type = NSEMI;
10566 n3->nbinary.ch1 = n1;
10567 n3->nbinary.ch2 = n2;
10568 n1 = n3;
10570 switch (tok) {
10571 case TBACKGND:
10572 case TSEMI:
10573 tok = readtoken();
10574 /* fall through */
10575 case TNL:
10576 if (tok == TNL) {
10577 parseheredoc();
10578 if (nlflag == 1)
10579 return n1;
10580 } else {
10581 tokpushback = 1;
10583 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10584 if (peektoken())
10585 return n1;
10586 break;
10587 case TEOF:
10588 if (heredoclist)
10589 parseheredoc();
10590 else
10591 pungetc(); /* push back EOF on input */
10592 return n1;
10593 default:
10594 if (nlflag == 1)
10595 raise_error_unexpected_syntax(-1);
10596 tokpushback = 1;
10597 return n1;
10602 static union node *
10603 andor(void)
10605 union node *n1, *n2, *n3;
10606 int t;
10608 n1 = pipeline();
10609 for (;;) {
10610 t = readtoken();
10611 if (t == TAND) {
10612 t = NAND;
10613 } else if (t == TOR) {
10614 t = NOR;
10615 } else {
10616 tokpushback = 1;
10617 return n1;
10619 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10620 n2 = pipeline();
10621 n3 = stzalloc(sizeof(struct nbinary));
10622 n3->type = t;
10623 n3->nbinary.ch1 = n1;
10624 n3->nbinary.ch2 = n2;
10625 n1 = n3;
10629 static union node *
10630 pipeline(void)
10632 union node *n1, *n2, *pipenode;
10633 struct nodelist *lp, *prev;
10634 int negate;
10636 negate = 0;
10637 TRACE(("pipeline: entered\n"));
10638 if (readtoken() == TNOT) {
10639 negate = !negate;
10640 checkkwd = CHKKWD | CHKALIAS;
10641 } else
10642 tokpushback = 1;
10643 n1 = parse_command();
10644 if (readtoken() == TPIPE) {
10645 pipenode = stzalloc(sizeof(struct npipe));
10646 pipenode->type = NPIPE;
10647 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10648 lp = stzalloc(sizeof(struct nodelist));
10649 pipenode->npipe.cmdlist = lp;
10650 lp->n = n1;
10651 do {
10652 prev = lp;
10653 lp = stzalloc(sizeof(struct nodelist));
10654 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10655 lp->n = parse_command();
10656 prev->next = lp;
10657 } while (readtoken() == TPIPE);
10658 lp->next = NULL;
10659 n1 = pipenode;
10661 tokpushback = 1;
10662 if (negate) {
10663 n2 = stzalloc(sizeof(struct nnot));
10664 n2->type = NNOT;
10665 n2->nnot.com = n1;
10666 return n2;
10668 return n1;
10671 static union node *
10672 makename(void)
10674 union node *n;
10676 n = stzalloc(sizeof(struct narg));
10677 n->type = NARG;
10678 /*n->narg.next = NULL; - stzalloc did it */
10679 n->narg.text = wordtext;
10680 n->narg.backquote = backquotelist;
10681 return n;
10684 static void
10685 fixredir(union node *n, const char *text, int err)
10687 int fd;
10689 TRACE(("Fix redir %s %d\n", text, err));
10690 if (!err)
10691 n->ndup.vname = NULL;
10693 fd = bb_strtou(text, NULL, 10);
10694 if (!errno && fd >= 0)
10695 n->ndup.dupfd = fd;
10696 else if (LONE_DASH(text))
10697 n->ndup.dupfd = -1;
10698 else {
10699 if (err)
10700 raise_error_syntax("bad fd number");
10701 n->ndup.vname = makename();
10706 * Returns true if the text contains nothing to expand (no dollar signs
10707 * or backquotes).
10709 static int
10710 noexpand(const char *text)
10712 unsigned char c;
10714 while ((c = *text++) != '\0') {
10715 if (c == CTLQUOTEMARK)
10716 continue;
10717 if (c == CTLESC)
10718 text++;
10719 else if (SIT(c, BASESYNTAX) == CCTL)
10720 return 0;
10722 return 1;
10725 static void
10726 parsefname(void)
10728 union node *n = redirnode;
10730 if (readtoken() != TWORD)
10731 raise_error_unexpected_syntax(-1);
10732 if (n->type == NHERE) {
10733 struct heredoc *here = heredoc;
10734 struct heredoc *p;
10735 int i;
10737 if (quoteflag == 0)
10738 n->type = NXHERE;
10739 TRACE(("Here document %d\n", n->type));
10740 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10741 raise_error_syntax("illegal eof marker for << redirection");
10742 rmescapes(wordtext, 0);
10743 here->eofmark = wordtext;
10744 here->next = NULL;
10745 if (heredoclist == NULL)
10746 heredoclist = here;
10747 else {
10748 for (p = heredoclist; p->next; p = p->next)
10749 continue;
10750 p->next = here;
10752 } else if (n->type == NTOFD || n->type == NFROMFD) {
10753 fixredir(n, wordtext, 0);
10754 } else {
10755 n->nfile.fname = makename();
10759 static union node *
10760 simplecmd(void)
10762 union node *args, **app;
10763 union node *n = NULL;
10764 union node *vars, **vpp;
10765 union node **rpp, *redir;
10766 int savecheckkwd;
10767 #if ENABLE_ASH_BASH_COMPAT
10768 smallint double_brackets_flag = 0;
10769 #endif
10771 args = NULL;
10772 app = &args;
10773 vars = NULL;
10774 vpp = &vars;
10775 redir = NULL;
10776 rpp = &redir;
10778 savecheckkwd = CHKALIAS;
10779 for (;;) {
10780 int t;
10781 checkkwd = savecheckkwd;
10782 t = readtoken();
10783 switch (t) {
10784 #if ENABLE_ASH_BASH_COMPAT
10785 case TAND: /* "&&" */
10786 case TOR: /* "||" */
10787 if (!double_brackets_flag) {
10788 tokpushback = 1;
10789 goto out;
10791 wordtext = (char *) (t == TAND ? "-a" : "-o");
10792 #endif
10793 case TWORD:
10794 n = stzalloc(sizeof(struct narg));
10795 n->type = NARG;
10796 /*n->narg.next = NULL; - stzalloc did it */
10797 n->narg.text = wordtext;
10798 #if ENABLE_ASH_BASH_COMPAT
10799 if (strcmp("[[", wordtext) == 0)
10800 double_brackets_flag = 1;
10801 else if (strcmp("]]", wordtext) == 0)
10802 double_brackets_flag = 0;
10803 #endif
10804 n->narg.backquote = backquotelist;
10805 if (savecheckkwd && isassignment(wordtext)) {
10806 *vpp = n;
10807 vpp = &n->narg.next;
10808 } else {
10809 *app = n;
10810 app = &n->narg.next;
10811 savecheckkwd = 0;
10813 break;
10814 case TREDIR:
10815 *rpp = n = redirnode;
10816 rpp = &n->nfile.next;
10817 parsefname(); /* read name of redirection file */
10818 break;
10819 case TLP:
10820 if (args && app == &args->narg.next
10821 && !vars && !redir
10823 struct builtincmd *bcmd;
10824 const char *name;
10826 /* We have a function */
10827 if (readtoken() != TRP)
10828 raise_error_unexpected_syntax(TRP);
10829 name = n->narg.text;
10830 if (!goodname(name)
10831 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10833 raise_error_syntax("bad function name");
10835 n->type = NDEFUN;
10836 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10837 n->narg.next = parse_command();
10838 return n;
10840 /* fall through */
10841 default:
10842 tokpushback = 1;
10843 goto out;
10846 out:
10847 *app = NULL;
10848 *vpp = NULL;
10849 *rpp = NULL;
10850 n = stzalloc(sizeof(struct ncmd));
10851 n->type = NCMD;
10852 n->ncmd.args = args;
10853 n->ncmd.assign = vars;
10854 n->ncmd.redirect = redir;
10855 return n;
10858 static union node *
10859 parse_command(void)
10861 union node *n1, *n2;
10862 union node *ap, **app;
10863 union node *cp, **cpp;
10864 union node *redir, **rpp;
10865 union node **rpp2;
10866 int t;
10868 redir = NULL;
10869 rpp2 = &redir;
10871 switch (readtoken()) {
10872 default:
10873 raise_error_unexpected_syntax(-1);
10874 /* NOTREACHED */
10875 case TIF:
10876 n1 = stzalloc(sizeof(struct nif));
10877 n1->type = NIF;
10878 n1->nif.test = list(0);
10879 if (readtoken() != TTHEN)
10880 raise_error_unexpected_syntax(TTHEN);
10881 n1->nif.ifpart = list(0);
10882 n2 = n1;
10883 while (readtoken() == TELIF) {
10884 n2->nif.elsepart = stzalloc(sizeof(struct nif));
10885 n2 = n2->nif.elsepart;
10886 n2->type = NIF;
10887 n2->nif.test = list(0);
10888 if (readtoken() != TTHEN)
10889 raise_error_unexpected_syntax(TTHEN);
10890 n2->nif.ifpart = list(0);
10892 if (lasttoken == TELSE)
10893 n2->nif.elsepart = list(0);
10894 else {
10895 n2->nif.elsepart = NULL;
10896 tokpushback = 1;
10898 t = TFI;
10899 break;
10900 case TWHILE:
10901 case TUNTIL: {
10902 int got;
10903 n1 = stzalloc(sizeof(struct nbinary));
10904 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10905 n1->nbinary.ch1 = list(0);
10906 got = readtoken();
10907 if (got != TDO) {
10908 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
10909 got == TWORD ? wordtext : ""));
10910 raise_error_unexpected_syntax(TDO);
10912 n1->nbinary.ch2 = list(0);
10913 t = TDONE;
10914 break;
10916 case TFOR:
10917 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10918 raise_error_syntax("bad for loop variable");
10919 n1 = stzalloc(sizeof(struct nfor));
10920 n1->type = NFOR;
10921 n1->nfor.var = wordtext;
10922 checkkwd = CHKKWD | CHKALIAS;
10923 if (readtoken() == TIN) {
10924 app = &ap;
10925 while (readtoken() == TWORD) {
10926 n2 = stzalloc(sizeof(struct narg));
10927 n2->type = NARG;
10928 /*n2->narg.next = NULL; - stzalloc did it */
10929 n2->narg.text = wordtext;
10930 n2->narg.backquote = backquotelist;
10931 *app = n2;
10932 app = &n2->narg.next;
10934 *app = NULL;
10935 n1->nfor.args = ap;
10936 if (lasttoken != TNL && lasttoken != TSEMI)
10937 raise_error_unexpected_syntax(-1);
10938 } else {
10939 n2 = stzalloc(sizeof(struct narg));
10940 n2->type = NARG;
10941 /*n2->narg.next = NULL; - stzalloc did it */
10942 n2->narg.text = (char *)dolatstr;
10943 /*n2->narg.backquote = NULL;*/
10944 n1->nfor.args = n2;
10946 * Newline or semicolon here is optional (but note
10947 * that the original Bourne shell only allowed NL).
10949 if (lasttoken != TNL && lasttoken != TSEMI)
10950 tokpushback = 1;
10952 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10953 if (readtoken() != TDO)
10954 raise_error_unexpected_syntax(TDO);
10955 n1->nfor.body = list(0);
10956 t = TDONE;
10957 break;
10958 case TCASE:
10959 n1 = stzalloc(sizeof(struct ncase));
10960 n1->type = NCASE;
10961 if (readtoken() != TWORD)
10962 raise_error_unexpected_syntax(TWORD);
10963 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10964 n2->type = NARG;
10965 /*n2->narg.next = NULL; - stzalloc did it */
10966 n2->narg.text = wordtext;
10967 n2->narg.backquote = backquotelist;
10968 do {
10969 checkkwd = CHKKWD | CHKALIAS;
10970 } while (readtoken() == TNL);
10971 if (lasttoken != TIN)
10972 raise_error_unexpected_syntax(TIN);
10973 cpp = &n1->ncase.cases;
10974 next_case:
10975 checkkwd = CHKNL | CHKKWD;
10976 t = readtoken();
10977 while (t != TESAC) {
10978 if (lasttoken == TLP)
10979 readtoken();
10980 *cpp = cp = stzalloc(sizeof(struct nclist));
10981 cp->type = NCLIST;
10982 app = &cp->nclist.pattern;
10983 for (;;) {
10984 *app = ap = stzalloc(sizeof(struct narg));
10985 ap->type = NARG;
10986 /*ap->narg.next = NULL; - stzalloc did it */
10987 ap->narg.text = wordtext;
10988 ap->narg.backquote = backquotelist;
10989 if (readtoken() != TPIPE)
10990 break;
10991 app = &ap->narg.next;
10992 readtoken();
10994 //ap->narg.next = NULL;
10995 if (lasttoken != TRP)
10996 raise_error_unexpected_syntax(TRP);
10997 cp->nclist.body = list(2);
10999 cpp = &cp->nclist.next;
11001 checkkwd = CHKNL | CHKKWD;
11002 t = readtoken();
11003 if (t != TESAC) {
11004 if (t != TENDCASE)
11005 raise_error_unexpected_syntax(TENDCASE);
11006 goto next_case;
11009 *cpp = NULL;
11010 goto redir;
11011 case TLP:
11012 n1 = stzalloc(sizeof(struct nredir));
11013 n1->type = NSUBSHELL;
11014 n1->nredir.n = list(0);
11015 /*n1->nredir.redirect = NULL; - stzalloc did it */
11016 t = TRP;
11017 break;
11018 case TBEGIN:
11019 n1 = list(0);
11020 t = TEND;
11021 break;
11022 case TWORD:
11023 case TREDIR:
11024 tokpushback = 1;
11025 return simplecmd();
11028 if (readtoken() != t)
11029 raise_error_unexpected_syntax(t);
11031 redir:
11032 /* Now check for redirection which may follow command */
11033 checkkwd = CHKKWD | CHKALIAS;
11034 rpp = rpp2;
11035 while (readtoken() == TREDIR) {
11036 *rpp = n2 = redirnode;
11037 rpp = &n2->nfile.next;
11038 parsefname();
11040 tokpushback = 1;
11041 *rpp = NULL;
11042 if (redir) {
11043 if (n1->type != NSUBSHELL) {
11044 n2 = stzalloc(sizeof(struct nredir));
11045 n2->type = NREDIR;
11046 n2->nredir.n = n1;
11047 n1 = n2;
11049 n1->nredir.redirect = redir;
11051 return n1;
11054 #if ENABLE_ASH_BASH_COMPAT
11055 static int decode_dollar_squote(void)
11057 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11058 int c, cnt;
11059 char *p;
11060 char buf[4];
11062 c = pgetc();
11063 p = strchr(C_escapes, c);
11064 if (p) {
11065 buf[0] = c;
11066 p = buf;
11067 cnt = 3;
11068 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11069 do {
11070 c = pgetc();
11071 *++p = c;
11072 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11073 pungetc();
11074 } else if (c == 'x') { /* \xHH */
11075 do {
11076 c = pgetc();
11077 *++p = c;
11078 } while (isxdigit(c) && --cnt);
11079 pungetc();
11080 if (cnt == 3) { /* \x but next char is "bad" */
11081 c = 'x';
11082 goto unrecognized;
11084 } else { /* simple seq like \\ or \t */
11085 p++;
11087 *p = '\0';
11088 p = buf;
11089 c = bb_process_escape_sequence((void*)&p);
11090 } else { /* unrecognized "\z": print both chars unless ' or " */
11091 if (c != '\'' && c != '"') {
11092 unrecognized:
11093 c |= 0x100; /* "please encode \, then me" */
11096 return c;
11098 #endif
11101 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11102 * is not NULL, read a here document. In the latter case, eofmark is the
11103 * word which marks the end of the document and striptabs is true if
11104 * leading tabs should be stripped from the document. The argument c
11105 * is the first character of the input token or document.
11107 * Because C does not have internal subroutines, I have simulated them
11108 * using goto's to implement the subroutine linkage. The following macros
11109 * will run code that appears at the end of readtoken1.
11111 #define CHECKEND() {goto checkend; checkend_return:;}
11112 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
11113 #define PARSESUB() {goto parsesub; parsesub_return:;}
11114 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11115 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11116 #define PARSEARITH() {goto parsearith; parsearith_return:;}
11117 static int
11118 readtoken1(int c, int syntax, char *eofmark, int striptabs)
11120 /* NB: syntax parameter fits into smallint */
11121 /* c parameter is an unsigned char or PEOF or PEOA */
11122 char *out;
11123 int len;
11124 char line[EOFMARKLEN + 1];
11125 struct nodelist *bqlist;
11126 smallint quotef;
11127 smallint dblquote;
11128 smallint oldstyle;
11129 smallint prevsyntax; /* syntax before arithmetic */
11130 #if ENABLE_ASH_EXPAND_PRMT
11131 smallint pssyntax; /* we are expanding a prompt string */
11132 #endif
11133 int varnest; /* levels of variables expansion */
11134 int arinest; /* levels of arithmetic expansion */
11135 int parenlevel; /* levels of parens in arithmetic */
11136 int dqvarnest; /* levels of variables expansion within double quotes */
11138 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
11140 #if __GNUC__
11141 /* Avoid longjmp clobbering */
11142 (void) &out;
11143 (void) &quotef;
11144 (void) &dblquote;
11145 (void) &varnest;
11146 (void) &arinest;
11147 (void) &parenlevel;
11148 (void) &dqvarnest;
11149 (void) &oldstyle;
11150 (void) &prevsyntax;
11151 (void) &syntax;
11152 #endif
11153 startlinno = g_parsefile->linno;
11154 bqlist = NULL;
11155 quotef = 0;
11156 prevsyntax = 0;
11157 #if ENABLE_ASH_EXPAND_PRMT
11158 pssyntax = (syntax == PSSYNTAX);
11159 if (pssyntax)
11160 syntax = DQSYNTAX;
11161 #endif
11162 dblquote = (syntax == DQSYNTAX);
11163 varnest = 0;
11164 arinest = 0;
11165 parenlevel = 0;
11166 dqvarnest = 0;
11168 STARTSTACKSTR(out);
11169 loop:
11170 /* For each line, until end of word */
11171 CHECKEND(); /* set c to PEOF if at end of here document */
11172 for (;;) { /* until end of line or end of word */
11173 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11174 switch (SIT(c, syntax)) {
11175 case CNL: /* '\n' */
11176 if (syntax == BASESYNTAX)
11177 goto endword; /* exit outer loop */
11178 USTPUTC(c, out);
11179 g_parsefile->linno++;
11180 setprompt_if(doprompt, 2);
11181 c = pgetc();
11182 goto loop; /* continue outer loop */
11183 case CWORD:
11184 USTPUTC(c, out);
11185 break;
11186 case CCTL:
11187 if (eofmark == NULL || dblquote)
11188 USTPUTC(CTLESC, out);
11189 #if ENABLE_ASH_BASH_COMPAT
11190 if (c == '\\' && bash_dollar_squote) {
11191 c = decode_dollar_squote();
11192 if (c & 0x100) {
11193 USTPUTC('\\', out);
11194 c = (unsigned char)c;
11197 #endif
11198 USTPUTC(c, out);
11199 break;
11200 case CBACK: /* backslash */
11201 c = pgetc_without_PEOA();
11202 if (c == PEOF) {
11203 USTPUTC(CTLESC, out);
11204 USTPUTC('\\', out);
11205 pungetc();
11206 } else if (c == '\n') {
11207 setprompt_if(doprompt, 2);
11208 } else {
11209 #if ENABLE_ASH_EXPAND_PRMT
11210 if (c == '$' && pssyntax) {
11211 USTPUTC(CTLESC, out);
11212 USTPUTC('\\', out);
11214 #endif
11215 /* Backslash is retained if we are in "str" and next char isn't special */
11216 if (dblquote
11217 && c != '\\'
11218 && c != '`'
11219 && c != '$'
11220 && (c != '"' || eofmark != NULL)
11222 USTPUTC(CTLESC, out);
11223 USTPUTC('\\', out);
11225 if (SIT(c, SQSYNTAX) == CCTL)
11226 USTPUTC(CTLESC, out);
11227 USTPUTC(c, out);
11228 quotef = 1;
11230 break;
11231 case CSQUOTE:
11232 syntax = SQSYNTAX;
11233 quotemark:
11234 if (eofmark == NULL) {
11235 USTPUTC(CTLQUOTEMARK, out);
11237 break;
11238 case CDQUOTE:
11239 syntax = DQSYNTAX;
11240 dblquote = 1;
11241 goto quotemark;
11242 case CENDQUOTE:
11243 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
11244 if (eofmark != NULL && arinest == 0
11245 && varnest == 0
11247 USTPUTC(c, out);
11248 } else {
11249 if (dqvarnest == 0) {
11250 syntax = BASESYNTAX;
11251 dblquote = 0;
11253 quotef = 1;
11254 goto quotemark;
11256 break;
11257 case CVAR: /* '$' */
11258 PARSESUB(); /* parse substitution */
11259 break;
11260 case CENDVAR: /* '}' */
11261 if (varnest > 0) {
11262 varnest--;
11263 if (dqvarnest > 0) {
11264 dqvarnest--;
11266 c = CTLENDVAR;
11268 USTPUTC(c, out);
11269 break;
11270 #if ENABLE_SH_MATH_SUPPORT
11271 case CLP: /* '(' in arithmetic */
11272 parenlevel++;
11273 USTPUTC(c, out);
11274 break;
11275 case CRP: /* ')' in arithmetic */
11276 if (parenlevel > 0) {
11277 parenlevel--;
11278 } else {
11279 if (pgetc() == ')') {
11280 if (--arinest == 0) {
11281 syntax = prevsyntax;
11282 dblquote = (syntax == DQSYNTAX);
11283 c = CTLENDARI;
11285 } else {
11287 * unbalanced parens
11288 * (don't 2nd guess - no error)
11290 pungetc();
11293 USTPUTC(c, out);
11294 break;
11295 #endif
11296 case CBQUOTE: /* '`' */
11297 PARSEBACKQOLD();
11298 break;
11299 case CENDFILE:
11300 goto endword; /* exit outer loop */
11301 case CIGN:
11302 break;
11303 default:
11304 if (varnest == 0) {
11305 #if ENABLE_ASH_BASH_COMPAT
11306 if (c == '&') {
11307 if (pgetc() == '>')
11308 c = 0x100 + '>'; /* flag &> */
11309 pungetc();
11311 #endif
11312 goto endword; /* exit outer loop */
11314 IF_ASH_ALIAS(if (c != PEOA))
11315 USTPUTC(c, out);
11317 c = pgetc_fast();
11318 } /* for (;;) */
11319 endword:
11321 #if ENABLE_SH_MATH_SUPPORT
11322 if (syntax == ARISYNTAX)
11323 raise_error_syntax("missing '))'");
11324 #endif
11325 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
11326 raise_error_syntax("unterminated quoted string");
11327 if (varnest != 0) {
11328 startlinno = g_parsefile->linno;
11329 /* { */
11330 raise_error_syntax("missing '}'");
11332 USTPUTC('\0', out);
11333 len = out - (char *)stackblock();
11334 out = stackblock();
11335 if (eofmark == NULL) {
11336 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
11337 && quotef == 0
11339 if (isdigit_str9(out)) {
11340 PARSEREDIR(); /* passed as params: out, c */
11341 lasttoken = TREDIR;
11342 return lasttoken;
11344 /* else: non-number X seen, interpret it
11345 * as "NNNX>file" = "NNNX >file" */
11347 pungetc();
11349 quoteflag = quotef;
11350 backquotelist = bqlist;
11351 grabstackblock(len);
11352 wordtext = out;
11353 lasttoken = TWORD;
11354 return lasttoken;
11355 /* end of readtoken routine */
11358 * Check to see whether we are at the end of the here document. When this
11359 * is called, c is set to the first character of the next input line. If
11360 * we are at the end of the here document, this routine sets the c to PEOF.
11362 checkend: {
11363 if (eofmark) {
11364 #if ENABLE_ASH_ALIAS
11365 if (c == PEOA)
11366 c = pgetc_without_PEOA();
11367 #endif
11368 if (striptabs) {
11369 while (c == '\t') {
11370 c = pgetc_without_PEOA();
11373 if (c == *eofmark) {
11374 if (pfgets(line, sizeof(line)) != NULL) {
11375 char *p, *q;
11377 p = line;
11378 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11379 continue;
11380 if (*p == '\n' && *q == '\0') {
11381 c = PEOF;
11382 g_parsefile->linno++;
11383 needprompt = doprompt;
11384 } else {
11385 pushstring(line, NULL);
11390 goto checkend_return;
11394 * Parse a redirection operator. The variable "out" points to a string
11395 * specifying the fd to be redirected. The variable "c" contains the
11396 * first character of the redirection operator.
11398 parseredir: {
11399 /* out is already checked to be a valid number or "" */
11400 int fd = (*out == '\0' ? -1 : atoi(out));
11401 union node *np;
11403 np = stzalloc(sizeof(struct nfile));
11404 if (c == '>') {
11405 np->nfile.fd = 1;
11406 c = pgetc();
11407 if (c == '>')
11408 np->type = NAPPEND;
11409 else if (c == '|')
11410 np->type = NCLOBBER;
11411 else if (c == '&')
11412 np->type = NTOFD;
11413 /* it also can be NTO2 (>&file), but we can't figure it out yet */
11414 else {
11415 np->type = NTO;
11416 pungetc();
11419 #if ENABLE_ASH_BASH_COMPAT
11420 else if (c == 0x100 + '>') { /* this flags &> redirection */
11421 np->nfile.fd = 1;
11422 pgetc(); /* this is '>', no need to check */
11423 np->type = NTO2;
11425 #endif
11426 else { /* c == '<' */
11427 /*np->nfile.fd = 0; - stzalloc did it */
11428 c = pgetc();
11429 switch (c) {
11430 case '<':
11431 if (sizeof(struct nfile) != sizeof(struct nhere)) {
11432 np = stzalloc(sizeof(struct nhere));
11433 /*np->nfile.fd = 0; - stzalloc did it */
11435 np->type = NHERE;
11436 heredoc = stzalloc(sizeof(struct heredoc));
11437 heredoc->here = np;
11438 c = pgetc();
11439 if (c == '-') {
11440 heredoc->striptabs = 1;
11441 } else {
11442 /*heredoc->striptabs = 0; - stzalloc did it */
11443 pungetc();
11445 break;
11447 case '&':
11448 np->type = NFROMFD;
11449 break;
11451 case '>':
11452 np->type = NFROMTO;
11453 break;
11455 default:
11456 np->type = NFROM;
11457 pungetc();
11458 break;
11461 if (fd >= 0)
11462 np->nfile.fd = fd;
11463 redirnode = np;
11464 goto parseredir_return;
11468 * Parse a substitution. At this point, we have read the dollar sign
11469 * and nothing else.
11472 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11473 * (assuming ascii char codes, as the original implementation did) */
11474 #define is_special(c) \
11475 (((unsigned)(c) - 33 < 32) \
11476 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
11477 parsesub: {
11478 unsigned char subtype;
11479 int typeloc;
11480 int flags;
11482 c = pgetc();
11483 if (c > 255 /* PEOA or PEOF */
11484 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
11486 #if ENABLE_ASH_BASH_COMPAT
11487 if (c == '\'')
11488 bash_dollar_squote = 1;
11489 else
11490 #endif
11491 USTPUTC('$', out);
11492 pungetc();
11493 } else if (c == '(') {
11494 /* $(command) or $((arith)) */
11495 if (pgetc() == '(') {
11496 #if ENABLE_SH_MATH_SUPPORT
11497 PARSEARITH();
11498 #else
11499 raise_error_syntax("you disabled math support for $((arith)) syntax");
11500 #endif
11501 } else {
11502 pungetc();
11503 PARSEBACKQNEW();
11505 } else {
11506 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
11507 USTPUTC(CTLVAR, out);
11508 typeloc = out - (char *)stackblock();
11509 USTPUTC(VSNORMAL, out);
11510 subtype = VSNORMAL;
11511 if (c == '{') {
11512 c = pgetc();
11513 if (c == '#') {
11514 c = pgetc();
11515 if (c == '}')
11516 c = '#'; /* ${#} - same as $# */
11517 else
11518 subtype = VSLENGTH; /* ${#VAR} */
11519 } else {
11520 subtype = 0;
11523 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
11524 /* $[{[#]]NAME[}] */
11525 do {
11526 STPUTC(c, out);
11527 c = pgetc();
11528 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
11529 } else if (isdigit(c)) {
11530 /* $[{[#]]NUM[}] */
11531 do {
11532 STPUTC(c, out);
11533 c = pgetc();
11534 } while (isdigit(c));
11535 } else if (is_special(c)) {
11536 /* $[{[#]]<specialchar>[}] */
11537 USTPUTC(c, out);
11538 c = pgetc();
11539 } else {
11540 badsub:
11541 raise_error_syntax("bad substitution");
11543 if (c != '}' && subtype == VSLENGTH) {
11544 /* ${#VAR didn't end with } */
11545 goto badsub;
11548 STPUTC('=', out);
11549 flags = 0;
11550 if (subtype == 0) {
11551 /* ${VAR...} but not $VAR or ${#VAR} */
11552 /* c == first char after VAR */
11553 switch (c) {
11554 case ':':
11555 c = pgetc();
11556 #if ENABLE_ASH_BASH_COMPAT
11557 if (c == ':' || c == '$' || isdigit(c)) {
11558 //TODO: support more general format ${v:EXPR:EXPR},
11559 // where EXPR follows $(()) rules
11560 subtype = VSSUBSTR;
11561 pungetc();
11562 break; /* "goto do_pungetc" is bigger (!) */
11564 #endif
11565 flags = VSNUL;
11566 /*FALLTHROUGH*/
11567 default: {
11568 static const char types[] ALIGN1 = "}-+?=";
11569 const char *p = strchr(types, c);
11570 if (p == NULL)
11571 goto badsub;
11572 subtype = p - types + VSNORMAL;
11573 break;
11575 case '%':
11576 case '#': {
11577 int cc = c;
11578 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
11579 c = pgetc();
11580 if (c != cc)
11581 goto do_pungetc;
11582 subtype++;
11583 break;
11585 #if ENABLE_ASH_BASH_COMPAT
11586 case '/':
11587 /* ${v/[/]pattern/repl} */
11588 //TODO: encode pattern and repl separately.
11589 // Currently ${v/$var_with_slash/repl} is horribly broken
11590 subtype = VSREPLACE;
11591 c = pgetc();
11592 if (c != '/')
11593 goto do_pungetc;
11594 subtype++; /* VSREPLACEALL */
11595 break;
11596 #endif
11598 } else {
11599 do_pungetc:
11600 pungetc();
11602 if (dblquote || arinest)
11603 flags |= VSQUOTE;
11604 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
11605 if (subtype != VSNORMAL) {
11606 varnest++;
11607 if (dblquote || arinest) {
11608 dqvarnest++;
11612 goto parsesub_return;
11616 * Called to parse command substitutions. Newstyle is set if the command
11617 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11618 * list of commands (passed by reference), and savelen is the number of
11619 * characters on the top of the stack which must be preserved.
11621 parsebackq: {
11622 struct nodelist **nlpp;
11623 smallint savepbq;
11624 union node *n;
11625 char *volatile str;
11626 struct jmploc jmploc;
11627 struct jmploc *volatile savehandler;
11628 size_t savelen;
11629 smallint saveprompt = 0;
11631 #ifdef __GNUC__
11632 (void) &saveprompt;
11633 #endif
11634 savepbq = parsebackquote;
11635 if (setjmp(jmploc.loc)) {
11636 free(str);
11637 parsebackquote = 0;
11638 exception_handler = savehandler;
11639 longjmp(exception_handler->loc, 1);
11641 INT_OFF;
11642 str = NULL;
11643 savelen = out - (char *)stackblock();
11644 if (savelen > 0) {
11645 str = ckmalloc(savelen);
11646 memcpy(str, stackblock(), savelen);
11648 savehandler = exception_handler;
11649 exception_handler = &jmploc;
11650 INT_ON;
11651 if (oldstyle) {
11652 /* We must read until the closing backquote, giving special
11653 * treatment to some slashes, and then push the string and
11654 * reread it as input, interpreting it normally.
11656 char *pout;
11657 size_t psavelen;
11658 char *pstr;
11660 STARTSTACKSTR(pout);
11661 for (;;) {
11662 int pc;
11664 setprompt_if(needprompt, 2);
11665 pc = pgetc();
11666 switch (pc) {
11667 case '`':
11668 goto done;
11670 case '\\':
11671 pc = pgetc();
11672 if (pc == '\n') {
11673 g_parsefile->linno++;
11674 setprompt_if(doprompt, 2);
11676 * If eating a newline, avoid putting
11677 * the newline into the new character
11678 * stream (via the STPUTC after the
11679 * switch).
11681 continue;
11683 if (pc != '\\' && pc != '`' && pc != '$'
11684 && (!dblquote || pc != '"')
11686 STPUTC('\\', pout);
11688 if (pc <= 255 /* not PEOA or PEOF */) {
11689 break;
11691 /* fall through */
11693 case PEOF:
11694 IF_ASH_ALIAS(case PEOA:)
11695 startlinno = g_parsefile->linno;
11696 raise_error_syntax("EOF in backquote substitution");
11698 case '\n':
11699 g_parsefile->linno++;
11700 needprompt = doprompt;
11701 break;
11703 default:
11704 break;
11706 STPUTC(pc, pout);
11708 done:
11709 STPUTC('\0', pout);
11710 psavelen = pout - (char *)stackblock();
11711 if (psavelen > 0) {
11712 pstr = grabstackstr(pout);
11713 setinputstring(pstr);
11716 nlpp = &bqlist;
11717 while (*nlpp)
11718 nlpp = &(*nlpp)->next;
11719 *nlpp = stzalloc(sizeof(**nlpp));
11720 /* (*nlpp)->next = NULL; - stzalloc did it */
11721 parsebackquote = oldstyle;
11723 if (oldstyle) {
11724 saveprompt = doprompt;
11725 doprompt = 0;
11728 n = list(2);
11730 if (oldstyle)
11731 doprompt = saveprompt;
11732 else if (readtoken() != TRP)
11733 raise_error_unexpected_syntax(TRP);
11735 (*nlpp)->n = n;
11736 if (oldstyle) {
11738 * Start reading from old file again, ignoring any pushed back
11739 * tokens left from the backquote parsing
11741 popfile();
11742 tokpushback = 0;
11744 while (stackblocksize() <= savelen)
11745 growstackblock();
11746 STARTSTACKSTR(out);
11747 if (str) {
11748 memcpy(out, str, savelen);
11749 STADJUST(savelen, out);
11750 INT_OFF;
11751 free(str);
11752 str = NULL;
11753 INT_ON;
11755 parsebackquote = savepbq;
11756 exception_handler = savehandler;
11757 if (arinest || dblquote)
11758 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11759 else
11760 USTPUTC(CTLBACKQ, out);
11761 if (oldstyle)
11762 goto parsebackq_oldreturn;
11763 goto parsebackq_newreturn;
11766 #if ENABLE_SH_MATH_SUPPORT
11768 * Parse an arithmetic expansion (indicate start of one and set state)
11770 parsearith: {
11771 if (++arinest == 1) {
11772 prevsyntax = syntax;
11773 syntax = ARISYNTAX;
11774 USTPUTC(CTLARI, out);
11775 if (dblquote)
11776 USTPUTC('"', out);
11777 else
11778 USTPUTC(' ', out);
11779 } else {
11781 * we collapse embedded arithmetic expansion to
11782 * parenthesis, which should be equivalent
11784 USTPUTC('(', out);
11786 goto parsearith_return;
11788 #endif
11790 } /* end of readtoken */
11793 * Read the next input token.
11794 * If the token is a word, we set backquotelist to the list of cmds in
11795 * backquotes. We set quoteflag to true if any part of the word was
11796 * quoted.
11797 * If the token is TREDIR, then we set redirnode to a structure containing
11798 * the redirection.
11799 * In all cases, the variable startlinno is set to the number of the line
11800 * on which the token starts.
11802 * [Change comment: here documents and internal procedures]
11803 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11804 * word parsing code into a separate routine. In this case, readtoken
11805 * doesn't need to have any internal procedures, but parseword does.
11806 * We could also make parseoperator in essence the main routine, and
11807 * have parseword (readtoken1?) handle both words and redirection.]
11809 #define NEW_xxreadtoken
11810 #ifdef NEW_xxreadtoken
11811 /* singles must be first! */
11812 static const char xxreadtoken_chars[7] ALIGN1 = {
11813 '\n', '(', ')', /* singles */
11814 '&', '|', ';', /* doubles */
11818 #define xxreadtoken_singles 3
11819 #define xxreadtoken_doubles 3
11821 static const char xxreadtoken_tokens[] ALIGN1 = {
11822 TNL, TLP, TRP, /* only single occurrence allowed */
11823 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11824 TEOF, /* corresponds to trailing nul */
11825 TAND, TOR, TENDCASE /* if double occurrence */
11828 static int
11829 xxreadtoken(void)
11831 int c;
11833 if (tokpushback) {
11834 tokpushback = 0;
11835 return lasttoken;
11837 setprompt_if(needprompt, 2);
11838 startlinno = g_parsefile->linno;
11839 for (;;) { /* until token or start of word found */
11840 c = pgetc_fast();
11841 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
11842 continue;
11844 if (c == '#') {
11845 while ((c = pgetc()) != '\n' && c != PEOF)
11846 continue;
11847 pungetc();
11848 } else if (c == '\\') {
11849 if (pgetc() != '\n') {
11850 pungetc();
11851 break; /* return readtoken1(...) */
11853 startlinno = ++g_parsefile->linno;
11854 setprompt_if(doprompt, 2);
11855 } else {
11856 const char *p;
11858 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11859 if (c != PEOF) {
11860 if (c == '\n') {
11861 g_parsefile->linno++;
11862 needprompt = doprompt;
11865 p = strchr(xxreadtoken_chars, c);
11866 if (p == NULL)
11867 break; /* return readtoken1(...) */
11869 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11870 int cc = pgetc();
11871 if (cc == c) { /* double occurrence? */
11872 p += xxreadtoken_doubles + 1;
11873 } else {
11874 pungetc();
11875 #if ENABLE_ASH_BASH_COMPAT
11876 if (c == '&' && cc == '>') /* &> */
11877 break; /* return readtoken1(...) */
11878 #endif
11882 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11883 return lasttoken;
11885 } /* for (;;) */
11887 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11889 #else /* old xxreadtoken */
11890 #define RETURN(token) return lasttoken = token
11891 static int
11892 xxreadtoken(void)
11894 int c;
11896 if (tokpushback) {
11897 tokpushback = 0;
11898 return lasttoken;
11900 setprompt_if(needprompt, 2);
11901 startlinno = g_parsefile->linno;
11902 for (;;) { /* until token or start of word found */
11903 c = pgetc_fast();
11904 switch (c) {
11905 case ' ': case '\t':
11906 IF_ASH_ALIAS(case PEOA:)
11907 continue;
11908 case '#':
11909 while ((c = pgetc()) != '\n' && c != PEOF)
11910 continue;
11911 pungetc();
11912 continue;
11913 case '\\':
11914 if (pgetc() == '\n') {
11915 startlinno = ++g_parsefile->linno;
11916 setprompt_if(doprompt, 2);
11917 continue;
11919 pungetc();
11920 goto breakloop;
11921 case '\n':
11922 g_parsefile->linno++;
11923 needprompt = doprompt;
11924 RETURN(TNL);
11925 case PEOF:
11926 RETURN(TEOF);
11927 case '&':
11928 if (pgetc() == '&')
11929 RETURN(TAND);
11930 pungetc();
11931 RETURN(TBACKGND);
11932 case '|':
11933 if (pgetc() == '|')
11934 RETURN(TOR);
11935 pungetc();
11936 RETURN(TPIPE);
11937 case ';':
11938 if (pgetc() == ';')
11939 RETURN(TENDCASE);
11940 pungetc();
11941 RETURN(TSEMI);
11942 case '(':
11943 RETURN(TLP);
11944 case ')':
11945 RETURN(TRP);
11946 default:
11947 goto breakloop;
11950 breakloop:
11951 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11952 #undef RETURN
11954 #endif /* old xxreadtoken */
11956 static int
11957 readtoken(void)
11959 int t;
11960 #if DEBUG
11961 smallint alreadyseen = tokpushback;
11962 #endif
11964 #if ENABLE_ASH_ALIAS
11965 top:
11966 #endif
11968 t = xxreadtoken();
11971 * eat newlines
11973 if (checkkwd & CHKNL) {
11974 while (t == TNL) {
11975 parseheredoc();
11976 t = xxreadtoken();
11980 if (t != TWORD || quoteflag) {
11981 goto out;
11985 * check for keywords
11987 if (checkkwd & CHKKWD) {
11988 const char *const *pp;
11990 pp = findkwd(wordtext);
11991 if (pp) {
11992 lasttoken = t = pp - tokname_array;
11993 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
11994 goto out;
11998 if (checkkwd & CHKALIAS) {
11999 #if ENABLE_ASH_ALIAS
12000 struct alias *ap;
12001 ap = lookupalias(wordtext, 1);
12002 if (ap != NULL) {
12003 if (*ap->val) {
12004 pushstring(ap->val, ap);
12006 goto top;
12008 #endif
12010 out:
12011 checkkwd = 0;
12012 #if DEBUG
12013 if (!alreadyseen)
12014 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
12015 else
12016 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
12017 #endif
12018 return t;
12021 static char
12022 peektoken(void)
12024 int t;
12026 t = readtoken();
12027 tokpushback = 1;
12028 return tokname_array[t][0];
12032 * Read and parse a command. Returns NODE_EOF on end of file.
12033 * (NULL is a valid parse tree indicating a blank line.)
12035 static union node *
12036 parsecmd(int interact)
12038 int t;
12040 tokpushback = 0;
12041 doprompt = interact;
12042 setprompt_if(doprompt, doprompt);
12043 needprompt = 0;
12044 t = readtoken();
12045 if (t == TEOF)
12046 return NODE_EOF;
12047 if (t == TNL)
12048 return NULL;
12049 tokpushback = 1;
12050 return list(1);
12054 * Input any here documents.
12056 static void
12057 parseheredoc(void)
12059 struct heredoc *here;
12060 union node *n;
12062 here = heredoclist;
12063 heredoclist = NULL;
12065 while (here) {
12066 setprompt_if(needprompt, 2);
12067 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
12068 here->eofmark, here->striptabs);
12069 n = stzalloc(sizeof(struct narg));
12070 n->narg.type = NARG;
12071 /*n->narg.next = NULL; - stzalloc did it */
12072 n->narg.text = wordtext;
12073 n->narg.backquote = backquotelist;
12074 here->here->nhere.doc = n;
12075 here = here->next;
12081 * called by editline -- any expansions to the prompt should be added here.
12083 #if ENABLE_ASH_EXPAND_PRMT
12084 static const char *
12085 expandstr(const char *ps)
12087 union node n;
12089 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12090 * and token processing _can_ alter it (delete NULs etc). */
12091 setinputstring((char *)ps);
12092 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
12093 popfile();
12095 n.narg.type = NARG;
12096 n.narg.next = NULL;
12097 n.narg.text = wordtext;
12098 n.narg.backquote = backquotelist;
12100 expandarg(&n, NULL, 0);
12101 return stackblock();
12103 #endif
12106 * Execute a command or commands contained in a string.
12108 static int
12109 evalstring(char *s, int mask)
12111 union node *n;
12112 struct stackmark smark;
12113 int skip;
12115 setinputstring(s);
12116 setstackmark(&smark);
12118 skip = 0;
12119 while ((n = parsecmd(0)) != NODE_EOF) {
12120 evaltree(n, 0);
12121 popstackmark(&smark);
12122 skip = evalskip;
12123 if (skip)
12124 break;
12126 popfile();
12128 skip &= mask;
12129 evalskip = skip;
12130 return skip;
12134 * The eval command.
12136 static int FAST_FUNC
12137 evalcmd(int argc UNUSED_PARAM, char **argv)
12139 char *p;
12140 char *concat;
12142 if (argv[1]) {
12143 p = argv[1];
12144 argv += 2;
12145 if (argv[0]) {
12146 STARTSTACKSTR(concat);
12147 for (;;) {
12148 concat = stack_putstr(p, concat);
12149 p = *argv++;
12150 if (p == NULL)
12151 break;
12152 STPUTC(' ', concat);
12154 STPUTC('\0', concat);
12155 p = grabstackstr(concat);
12157 evalstring(p, ~SKIPEVAL);
12159 return exitstatus;
12163 * Read and execute commands.
12164 * "Top" is nonzero for the top level command loop;
12165 * it turns on prompting if the shell is interactive.
12167 static int
12168 cmdloop(int top)
12170 union node *n;
12171 struct stackmark smark;
12172 int inter;
12173 int numeof = 0;
12175 TRACE(("cmdloop(%d) called\n", top));
12176 for (;;) {
12177 int skip;
12179 setstackmark(&smark);
12180 #if JOBS
12181 if (doing_jobctl)
12182 showjobs(stderr, SHOW_CHANGED);
12183 #endif
12184 inter = 0;
12185 if (iflag && top) {
12186 inter++;
12187 chkmail();
12189 n = parsecmd(inter);
12190 #if DEBUG
12191 if (DEBUG > 2 && debug && (n != NODE_EOF))
12192 showtree(n);
12193 #endif
12194 if (n == NODE_EOF) {
12195 if (!top || numeof >= 50)
12196 break;
12197 if (!stoppedjobs()) {
12198 if (!Iflag)
12199 break;
12200 out2str("\nUse \"exit\" to leave shell.\n");
12202 numeof++;
12203 } else if (nflag == 0) {
12204 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12205 job_warning >>= 1;
12206 numeof = 0;
12207 evaltree(n, 0);
12209 popstackmark(&smark);
12210 skip = evalskip;
12212 if (skip) {
12213 evalskip = 0;
12214 return skip & SKIPEVAL;
12217 return 0;
12221 * Take commands from a file. To be compatible we should do a path
12222 * search for the file, which is necessary to find sub-commands.
12224 static char *
12225 find_dot_file(char *name)
12227 char *fullname;
12228 const char *path = pathval();
12229 struct stat statb;
12231 /* don't try this for absolute or relative paths */
12232 if (strchr(name, '/'))
12233 return name;
12235 /* IIRC standards do not say whether . is to be searched.
12236 * And it is even smaller this way, making it unconditional for now:
12238 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12239 fullname = name;
12240 goto try_cur_dir;
12243 while ((fullname = path_advance(&path, name)) != NULL) {
12244 try_cur_dir:
12245 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12247 * Don't bother freeing here, since it will
12248 * be freed by the caller.
12250 return fullname;
12252 if (fullname != name)
12253 stunalloc(fullname);
12256 /* not found in the PATH */
12257 ash_msg_and_raise_error("%s: not found", name);
12258 /* NOTREACHED */
12261 static int FAST_FUNC
12262 dotcmd(int argc, char **argv)
12264 char *fullname;
12265 struct strlist *sp;
12266 volatile struct shparam saveparam;
12268 for (sp = cmdenviron; sp; sp = sp->next)
12269 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
12271 if (!argv[1]) {
12272 /* bash says: "bash: .: filename argument required" */
12273 return 2; /* bash compat */
12276 /* "false; . empty_file; echo $?" should print 0, not 1: */
12277 exitstatus = 0;
12279 fullname = find_dot_file(argv[1]);
12281 argv += 2;
12282 argc -= 2;
12283 if (argc) { /* argc > 0, argv[0] != NULL */
12284 saveparam = shellparam;
12285 shellparam.malloced = 0;
12286 shellparam.nparam = argc;
12287 shellparam.p = argv;
12290 setinputfile(fullname, INPUT_PUSH_FILE);
12291 commandname = fullname;
12292 cmdloop(0);
12293 popfile();
12295 if (argc) {
12296 freeparam(&shellparam);
12297 shellparam = saveparam;
12300 return exitstatus;
12303 static int FAST_FUNC
12304 exitcmd(int argc UNUSED_PARAM, char **argv)
12306 if (stoppedjobs())
12307 return 0;
12308 if (argv[1])
12309 exitstatus = number(argv[1]);
12310 raise_exception(EXEXIT);
12311 /* NOTREACHED */
12315 * Read a file containing shell functions.
12317 static void
12318 readcmdfile(char *name)
12320 setinputfile(name, INPUT_PUSH_FILE);
12321 cmdloop(0);
12322 popfile();
12326 /* ============ find_command inplementation */
12329 * Resolve a command name. If you change this routine, you may have to
12330 * change the shellexec routine as well.
12332 static void
12333 find_command(char *name, struct cmdentry *entry, int act, const char *path)
12335 struct tblentry *cmdp;
12336 int idx;
12337 int prev;
12338 char *fullname;
12339 struct stat statb;
12340 int e;
12341 int updatetbl;
12342 struct builtincmd *bcmd;
12344 /* If name contains a slash, don't use PATH or hash table */
12345 if (strchr(name, '/') != NULL) {
12346 entry->u.index = -1;
12347 if (act & DO_ABS) {
12348 while (stat(name, &statb) < 0) {
12349 #ifdef SYSV
12350 if (errno == EINTR)
12351 continue;
12352 #endif
12353 entry->cmdtype = CMDUNKNOWN;
12354 return;
12357 entry->cmdtype = CMDNORMAL;
12358 return;
12361 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
12363 updatetbl = (path == pathval());
12364 if (!updatetbl) {
12365 act |= DO_ALTPATH;
12366 if (strstr(path, "%builtin") != NULL)
12367 act |= DO_ALTBLTIN;
12370 /* If name is in the table, check answer will be ok */
12371 cmdp = cmdlookup(name, 0);
12372 if (cmdp != NULL) {
12373 int bit;
12375 switch (cmdp->cmdtype) {
12376 default:
12377 #if DEBUG
12378 abort();
12379 #endif
12380 case CMDNORMAL:
12381 bit = DO_ALTPATH;
12382 break;
12383 case CMDFUNCTION:
12384 bit = DO_NOFUNC;
12385 break;
12386 case CMDBUILTIN:
12387 bit = DO_ALTBLTIN;
12388 break;
12390 if (act & bit) {
12391 updatetbl = 0;
12392 cmdp = NULL;
12393 } else if (cmdp->rehash == 0)
12394 /* if not invalidated by cd, we're done */
12395 goto success;
12398 /* If %builtin not in path, check for builtin next */
12399 bcmd = find_builtin(name);
12400 if (bcmd) {
12401 if (IS_BUILTIN_REGULAR(bcmd))
12402 goto builtin_success;
12403 if (act & DO_ALTPATH) {
12404 if (!(act & DO_ALTBLTIN))
12405 goto builtin_success;
12406 } else if (builtinloc <= 0) {
12407 goto builtin_success;
12411 #if ENABLE_FEATURE_SH_STANDALONE
12413 int applet_no = find_applet_by_name(name);
12414 if (applet_no >= 0) {
12415 entry->cmdtype = CMDNORMAL;
12416 entry->u.index = -2 - applet_no;
12417 return;
12420 #endif
12422 /* We have to search path. */
12423 prev = -1; /* where to start */
12424 if (cmdp && cmdp->rehash) { /* doing a rehash */
12425 if (cmdp->cmdtype == CMDBUILTIN)
12426 prev = builtinloc;
12427 else
12428 prev = cmdp->param.index;
12431 e = ENOENT;
12432 idx = -1;
12433 loop:
12434 while ((fullname = path_advance(&path, name)) != NULL) {
12435 stunalloc(fullname);
12436 /* NB: code below will still use fullname
12437 * despite it being "unallocated" */
12438 idx++;
12439 if (pathopt) {
12440 if (prefix(pathopt, "builtin")) {
12441 if (bcmd)
12442 goto builtin_success;
12443 continue;
12445 if ((act & DO_NOFUNC)
12446 || !prefix(pathopt, "func")
12447 ) { /* ignore unimplemented options */
12448 continue;
12451 /* if rehash, don't redo absolute path names */
12452 if (fullname[0] == '/' && idx <= prev) {
12453 if (idx < prev)
12454 continue;
12455 TRACE(("searchexec \"%s\": no change\n", name));
12456 goto success;
12458 while (stat(fullname, &statb) < 0) {
12459 #ifdef SYSV
12460 if (errno == EINTR)
12461 continue;
12462 #endif
12463 if (errno != ENOENT && errno != ENOTDIR)
12464 e = errno;
12465 goto loop;
12467 e = EACCES; /* if we fail, this will be the error */
12468 if (!S_ISREG(statb.st_mode))
12469 continue;
12470 if (pathopt) { /* this is a %func directory */
12471 stalloc(strlen(fullname) + 1);
12472 /* NB: stalloc will return space pointed by fullname
12473 * (because we don't have any intervening allocations
12474 * between stunalloc above and this stalloc) */
12475 readcmdfile(fullname);
12476 cmdp = cmdlookup(name, 0);
12477 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12478 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12479 stunalloc(fullname);
12480 goto success;
12482 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12483 if (!updatetbl) {
12484 entry->cmdtype = CMDNORMAL;
12485 entry->u.index = idx;
12486 return;
12488 INT_OFF;
12489 cmdp = cmdlookup(name, 1);
12490 cmdp->cmdtype = CMDNORMAL;
12491 cmdp->param.index = idx;
12492 INT_ON;
12493 goto success;
12496 /* We failed. If there was an entry for this command, delete it */
12497 if (cmdp && updatetbl)
12498 delete_cmd_entry();
12499 if (act & DO_ERR)
12500 ash_msg("%s: %s", name, errmsg(e, "not found"));
12501 entry->cmdtype = CMDUNKNOWN;
12502 return;
12504 builtin_success:
12505 if (!updatetbl) {
12506 entry->cmdtype = CMDBUILTIN;
12507 entry->u.cmd = bcmd;
12508 return;
12510 INT_OFF;
12511 cmdp = cmdlookup(name, 1);
12512 cmdp->cmdtype = CMDBUILTIN;
12513 cmdp->param.cmd = bcmd;
12514 INT_ON;
12515 success:
12516 cmdp->rehash = 0;
12517 entry->cmdtype = cmdp->cmdtype;
12518 entry->u = cmdp->param;
12522 /* ============ trap.c */
12525 * The trap builtin.
12527 static int FAST_FUNC
12528 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12530 char *action;
12531 char **ap;
12532 int signo, exitcode;
12534 nextopt(nullstr);
12535 ap = argptr;
12536 if (!*ap) {
12537 for (signo = 0; signo < NSIG; signo++) {
12538 char *tr = trap_ptr[signo];
12539 if (tr) {
12540 /* note: bash adds "SIG", but only if invoked
12541 * as "bash". If called as "sh", or if set -o posix,
12542 * then it prints short signal names.
12543 * We are printing short names: */
12544 out1fmt("trap -- %s %s\n",
12545 single_quote(tr),
12546 get_signame(signo));
12547 /* trap_ptr != trap only if we are in special-cased `trap` code.
12548 * In this case, we will exit very soon, no need to free(). */
12549 /* if (trap_ptr != trap && tp[0]) */
12550 /* free(tr); */
12554 if (trap_ptr != trap) {
12555 free(trap_ptr);
12556 trap_ptr = trap;
12559 return 0;
12562 action = NULL;
12563 if (ap[1])
12564 action = *ap++;
12565 exitcode = 0;
12566 while (*ap) {
12567 signo = get_signum(*ap);
12568 if (signo < 0) {
12569 /* Mimic bash message exactly */
12570 ash_msg("%s: invalid signal specification", *ap);
12571 exitcode = 1;
12572 goto next;
12574 INT_OFF;
12575 if (action) {
12576 if (LONE_DASH(action))
12577 action = NULL;
12578 else
12579 action = ckstrdup(action);
12581 free(trap[signo]);
12582 if (action)
12583 may_have_traps = 1;
12584 trap[signo] = action;
12585 if (signo != 0)
12586 setsignal(signo);
12587 INT_ON;
12588 next:
12589 ap++;
12591 return exitcode;
12595 /* ============ Builtins */
12597 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
12599 * Lists available builtins
12601 static int FAST_FUNC
12602 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12604 unsigned col;
12605 unsigned i;
12607 out1fmt(
12608 "Built-in commands:\n"
12609 "------------------\n");
12610 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12611 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12612 builtintab[i].name + 1);
12613 if (col > 60) {
12614 out1fmt("\n");
12615 col = 0;
12618 #if ENABLE_FEATURE_SH_STANDALONE
12620 const char *a = applet_names;
12621 while (*a) {
12622 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12623 if (col > 60) {
12624 out1fmt("\n");
12625 col = 0;
12627 a += strlen(a) + 1;
12630 #endif
12631 out1fmt("\n\n");
12632 return EXIT_SUCCESS;
12634 #endif /* FEATURE_SH_EXTRA_QUIET */
12637 * The export and readonly commands.
12639 static int FAST_FUNC
12640 exportcmd(int argc UNUSED_PARAM, char **argv)
12642 struct var *vp;
12643 char *name;
12644 const char *p;
12645 char **aptr;
12646 char opt;
12647 int flag;
12648 int flag_off;
12650 /* "readonly" in bash accepts, but ignores -n.
12651 * We do the same: it saves a conditional in nextopt's param.
12653 flag_off = 0;
12654 while ((opt = nextopt("np")) != '\0') {
12655 if (opt == 'n')
12656 flag_off = VEXPORT;
12658 flag = VEXPORT;
12659 if (argv[0][0] == 'r') {
12660 flag = VREADONLY;
12661 flag_off = 0; /* readonly ignores -n */
12663 flag_off = ~flag_off;
12665 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12667 aptr = argptr;
12668 name = *aptr;
12669 if (name) {
12670 do {
12671 p = strchr(name, '=');
12672 if (p != NULL) {
12673 p++;
12674 } else {
12675 vp = *findvar(hashvar(name), name);
12676 if (vp) {
12677 vp->flags = ((vp->flags | flag) & flag_off);
12678 continue;
12681 setvar(name, p, (flag & flag_off));
12682 } while ((name = *++aptr) != NULL);
12683 return 0;
12687 /* No arguments. Show the list of exported or readonly vars.
12688 * -n is ignored.
12690 showvars(argv[0], flag, 0);
12691 return 0;
12695 * Delete a function if it exists.
12697 static void
12698 unsetfunc(const char *name)
12700 struct tblentry *cmdp;
12702 cmdp = cmdlookup(name, 0);
12703 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
12704 delete_cmd_entry();
12708 * The unset builtin command. We unset the function before we unset the
12709 * variable to allow a function to be unset when there is a readonly variable
12710 * with the same name.
12712 static int FAST_FUNC
12713 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12715 char **ap;
12716 int i;
12717 int flag = 0;
12718 int ret = 0;
12720 while ((i = nextopt("vf")) != 0) {
12721 flag = i;
12724 for (ap = argptr; *ap; ap++) {
12725 if (flag != 'f') {
12726 i = unsetvar(*ap);
12727 ret |= i;
12728 if (!(i & 2))
12729 continue;
12731 if (flag != 'v')
12732 unsetfunc(*ap);
12734 return ret & 1;
12737 static const unsigned char timescmd_str[] ALIGN1 = {
12738 ' ', offsetof(struct tms, tms_utime),
12739 '\n', offsetof(struct tms, tms_stime),
12740 ' ', offsetof(struct tms, tms_cutime),
12741 '\n', offsetof(struct tms, tms_cstime),
12744 static int FAST_FUNC
12745 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12747 unsigned long clk_tck, s, t;
12748 const unsigned char *p;
12749 struct tms buf;
12751 clk_tck = sysconf(_SC_CLK_TCK);
12752 times(&buf);
12754 p = timescmd_str;
12755 do {
12756 t = *(clock_t *)(((char *) &buf) + p[1]);
12757 s = t / clk_tck;
12758 t = t % clk_tck;
12759 out1fmt("%lum%lu.%03lus%c",
12760 s / 60, s % 60,
12761 (t * 1000) / clk_tck,
12762 p[0]);
12763 p += 2;
12764 } while (*p);
12766 return 0;
12769 #if ENABLE_SH_MATH_SUPPORT
12771 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
12772 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12774 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12776 static int FAST_FUNC
12777 letcmd(int argc UNUSED_PARAM, char **argv)
12779 arith_t i;
12781 argv++;
12782 if (!*argv)
12783 ash_msg_and_raise_error("expression expected");
12784 do {
12785 i = ash_arith(*argv);
12786 } while (*++argv);
12788 return !i;
12790 #endif
12793 * The read builtin. Options:
12794 * -r Do not interpret '\' specially
12795 * -s Turn off echo (tty only)
12796 * -n NCHARS Read NCHARS max
12797 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12798 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12799 * -u FD Read from given FD instead of fd 0
12800 * This uses unbuffered input, which may be avoidable in some cases.
12801 * TODO: bash also has:
12802 * -a ARRAY Read into array[0],[1],etc
12803 * -d DELIM End on DELIM char, not newline
12804 * -e Use line editing (tty only)
12806 static int FAST_FUNC
12807 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12809 char *opt_n = NULL;
12810 char *opt_p = NULL;
12811 char *opt_t = NULL;
12812 char *opt_u = NULL;
12813 int read_flags = 0;
12814 const char *r;
12815 int i;
12817 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
12818 switch (i) {
12819 case 'p':
12820 opt_p = optionarg;
12821 break;
12822 case 'n':
12823 opt_n = optionarg;
12824 break;
12825 case 's':
12826 read_flags |= BUILTIN_READ_SILENT;
12827 break;
12828 case 't':
12829 opt_t = optionarg;
12830 break;
12831 case 'r':
12832 read_flags |= BUILTIN_READ_RAW;
12833 break;
12834 case 'u':
12835 opt_u = optionarg;
12836 break;
12837 default:
12838 break;
12842 /* "read -s" needs to save/restore termios, can't allow ^C
12843 * to jump out of it.
12845 INT_OFF;
12846 r = shell_builtin_read(setvar2,
12847 argptr,
12848 bltinlookup("IFS"), /* can be NULL */
12849 read_flags,
12850 opt_n,
12851 opt_p,
12852 opt_t,
12853 opt_u
12855 INT_ON;
12857 if ((uintptr_t)r > 1)
12858 ash_msg_and_raise_error(r);
12860 return (uintptr_t)r;
12863 static int FAST_FUNC
12864 umaskcmd(int argc UNUSED_PARAM, char **argv)
12866 static const char permuser[3] ALIGN1 = "ugo";
12867 static const char permmode[3] ALIGN1 = "rwx";
12868 static const short permmask[] ALIGN2 = {
12869 S_IRUSR, S_IWUSR, S_IXUSR,
12870 S_IRGRP, S_IWGRP, S_IXGRP,
12871 S_IROTH, S_IWOTH, S_IXOTH
12874 /* TODO: use bb_parse_mode() instead */
12876 char *ap;
12877 mode_t mask;
12878 int i;
12879 int symbolic_mode = 0;
12881 while (nextopt("S") != '\0') {
12882 symbolic_mode = 1;
12885 INT_OFF;
12886 mask = umask(0);
12887 umask(mask);
12888 INT_ON;
12890 ap = *argptr;
12891 if (ap == NULL) {
12892 if (symbolic_mode) {
12893 char buf[18];
12894 char *p = buf;
12896 for (i = 0; i < 3; i++) {
12897 int j;
12899 *p++ = permuser[i];
12900 *p++ = '=';
12901 for (j = 0; j < 3; j++) {
12902 if ((mask & permmask[3 * i + j]) == 0) {
12903 *p++ = permmode[j];
12906 *p++ = ',';
12908 *--p = 0;
12909 puts(buf);
12910 } else {
12911 out1fmt("%.4o\n", mask);
12913 } else {
12914 if (isdigit((unsigned char) *ap)) {
12915 mask = 0;
12916 do {
12917 if (*ap >= '8' || *ap < '0')
12918 ash_msg_and_raise_error(msg_illnum, argv[1]);
12919 mask = (mask << 3) + (*ap - '0');
12920 } while (*++ap != '\0');
12921 umask(mask);
12922 } else {
12923 mask = ~mask & 0777;
12924 if (!bb_parse_mode(ap, &mask)) {
12925 ash_msg_and_raise_error("illegal mode: %s", ap);
12927 umask(~mask & 0777);
12930 return 0;
12933 static int FAST_FUNC
12934 ulimitcmd(int argc UNUSED_PARAM, char **argv)
12936 return shell_builtin_ulimit(argv);
12939 /* ============ main() and helpers */
12942 * Called to exit the shell.
12944 static void
12945 exitshell(void)
12947 struct jmploc loc;
12948 char *p;
12949 int status;
12951 #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
12952 save_history(line_input_state);
12953 #endif
12955 status = exitstatus;
12956 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12957 if (setjmp(loc.loc)) {
12958 if (exception_type == EXEXIT)
12959 /* dash bug: it just does _exit(exitstatus) here
12960 * but we have to do setjobctl(0) first!
12961 * (bug is still not fixed in dash-0.5.3 - if you run dash
12962 * under Midnight Commander, on exit from dash MC is backgrounded) */
12963 status = exitstatus;
12964 goto out;
12966 exception_handler = &loc;
12967 p = trap[0];
12968 if (p) {
12969 trap[0] = NULL;
12970 evalstring(p, 0);
12971 free(p);
12973 flush_stdout_stderr();
12974 out:
12975 setjobctl(0);
12976 _exit(status);
12977 /* NOTREACHED */
12980 static void
12981 init(void)
12983 /* from input.c: */
12984 /* we will never free this */
12985 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
12987 /* from trap.c: */
12988 signal(SIGCHLD, SIG_DFL);
12989 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
12990 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
12992 signal(SIGHUP, SIG_DFL);
12994 /* from var.c: */
12996 char **envp;
12997 const char *p;
12998 struct stat st1, st2;
13000 initvar();
13001 for (envp = environ; envp && *envp; envp++) {
13002 if (strchr(*envp, '=')) {
13003 setvareq(*envp, VEXPORT|VTEXTFIXED);
13007 setvar("PPID", utoa(getppid()), 0);
13009 p = lookupvar("PWD");
13010 if (p) {
13011 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
13012 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13014 p = '\0';
13017 setpwd(p, 0);
13022 //usage:#define ash_trivial_usage
13023 //usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
13024 //usage:#define ash_full_usage "\n\n"
13025 //usage: "Unix shell interpreter"
13027 //usage:#if ENABLE_FEATURE_SH_IS_ASH
13028 //usage:# define sh_trivial_usage ash_trivial_usage
13029 //usage:# define sh_full_usage ash_full_usage
13030 //usage:#endif
13031 //usage:#if ENABLE_FEATURE_BASH_IS_ASH
13032 //usage:# define bash_trivial_usage ash_trivial_usage
13033 //usage:# define bash_full_usage ash_full_usage
13034 //usage:#endif
13037 * Process the shell command line arguments.
13039 static void
13040 procargs(char **argv)
13042 int i;
13043 const char *xminusc;
13044 char **xargv;
13046 xargv = argv;
13047 arg0 = xargv[0];
13048 /* if (xargv[0]) - mmm, this is always true! */
13049 xargv++;
13050 for (i = 0; i < NOPTS; i++)
13051 optlist[i] = 2;
13052 argptr = xargv;
13053 if (options(/*cmdline:*/ 1)) {
13054 /* it already printed err message */
13055 raise_exception(EXERROR);
13057 xargv = argptr;
13058 xminusc = minusc;
13059 if (*xargv == NULL) {
13060 if (xminusc)
13061 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13062 sflag = 1;
13064 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13065 iflag = 1;
13066 if (mflag == 2)
13067 mflag = iflag;
13068 for (i = 0; i < NOPTS; i++)
13069 if (optlist[i] == 2)
13070 optlist[i] = 0;
13071 #if DEBUG == 2
13072 debug = 1;
13073 #endif
13074 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13075 if (xminusc) {
13076 minusc = *xargv++;
13077 if (*xargv)
13078 goto setarg0;
13079 } else if (!sflag) {
13080 setinputfile(*xargv, 0);
13081 setarg0:
13082 arg0 = *xargv++;
13083 commandname = arg0;
13086 shellparam.p = xargv;
13087 #if ENABLE_ASH_GETOPTS
13088 shellparam.optind = 1;
13089 shellparam.optoff = -1;
13090 #endif
13091 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13092 while (*xargv) {
13093 shellparam.nparam++;
13094 xargv++;
13096 optschanged();
13100 * Read /etc/profile or .profile.
13102 static void
13103 read_profile(const char *name)
13105 int skip;
13107 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13108 return;
13109 skip = cmdloop(0);
13110 popfile();
13111 if (skip)
13112 exitshell();
13116 * This routine is called when an error or an interrupt occurs in an
13117 * interactive shell and control is returned to the main command loop.
13119 static void
13120 reset(void)
13122 /* from eval.c: */
13123 evalskip = 0;
13124 loopnest = 0;
13125 /* from input.c: */
13126 g_parsefile->left_in_buffer = 0;
13127 g_parsefile->left_in_line = 0; /* clear input buffer */
13128 popallfiles();
13129 /* from parser.c: */
13130 tokpushback = 0;
13131 checkkwd = 0;
13132 /* from redir.c: */
13133 clearredir(/*drop:*/ 0);
13136 #if PROFILE
13137 static short profile_buf[16384];
13138 extern int etext();
13139 #endif
13142 * Main routine. We initialize things, parse the arguments, execute
13143 * profiles if we're a login shell, and then call cmdloop to execute
13144 * commands. The setjmp call sets up the location to jump to when an
13145 * exception occurs. When an exception occurs the variable "state"
13146 * is used to figure out how far we had gotten.
13148 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13149 int ash_main(int argc UNUSED_PARAM, char **argv)
13151 const char *shinit;
13152 volatile smallint state;
13153 struct jmploc jmploc;
13154 struct stackmark smark;
13156 /* Initialize global data */
13157 INIT_G_misc();
13158 INIT_G_memstack();
13159 INIT_G_var();
13160 #if ENABLE_ASH_ALIAS
13161 INIT_G_alias();
13162 #endif
13163 INIT_G_cmdtable();
13165 #if PROFILE
13166 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13167 #endif
13169 #if ENABLE_FEATURE_EDITING
13170 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13171 #endif
13172 state = 0;
13173 if (setjmp(jmploc.loc)) {
13174 smallint e;
13175 smallint s;
13177 reset();
13179 e = exception_type;
13180 if (e == EXERROR)
13181 exitstatus = 2;
13182 s = state;
13183 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
13184 exitshell();
13186 if (e == EXINT) {
13187 outcslow('\n', stderr);
13190 popstackmark(&smark);
13191 FORCE_INT_ON; /* enable interrupts */
13192 if (s == 1)
13193 goto state1;
13194 if (s == 2)
13195 goto state2;
13196 if (s == 3)
13197 goto state3;
13198 goto state4;
13200 exception_handler = &jmploc;
13201 #if DEBUG
13202 opentrace();
13203 TRACE(("Shell args: "));
13204 trace_puts_args(argv);
13205 #endif
13206 rootpid = getpid();
13208 init();
13209 setstackmark(&smark);
13210 procargs(argv);
13212 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13213 if (iflag) {
13214 const char *hp = lookupvar("HISTFILE");
13215 if (!hp) {
13216 hp = lookupvar("HOME");
13217 if (hp) {
13218 char *defhp = concat_path_file(hp, ".ash_history");
13219 setvar("HISTFILE", defhp, 0);
13220 free(defhp);
13224 #endif
13225 if (argv[0] && argv[0][0] == '-')
13226 isloginsh = 1;
13227 if (isloginsh) {
13228 state = 1;
13229 read_profile("/etc/profile");
13230 state1:
13231 state = 2;
13232 read_profile(".profile");
13234 state2:
13235 state = 3;
13236 if (
13237 #ifndef linux
13238 getuid() == geteuid() && getgid() == getegid() &&
13239 #endif
13240 iflag
13242 shinit = lookupvar("ENV");
13243 if (shinit != NULL && *shinit != '\0') {
13244 read_profile(shinit);
13247 state3:
13248 state = 4;
13249 if (minusc) {
13250 /* evalstring pushes parsefile stack.
13251 * Ensure we don't falsely claim that 0 (stdin)
13252 * is one of stacked source fds.
13253 * Testcase: ash -c 'exec 1>&0' must not complain. */
13254 // if (!sflag) g_parsefile->pf_fd = -1;
13255 // ^^ not necessary since now we special-case fd 0
13256 // in is_hidden_fd() to not be considered "hidden fd"
13257 evalstring(minusc, 0);
13260 if (sflag || minusc == NULL) {
13261 #if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
13262 if (iflag) {
13263 const char *hp = lookupvar("HISTFILE");
13264 if (hp)
13265 line_input_state->hist_file = hp;
13266 # if ENABLE_FEATURE_SH_HISTFILESIZE
13267 hp = lookupvar("HISTFILESIZE");
13268 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13269 # endif
13271 #endif
13272 state4: /* XXX ??? - why isn't this before the "if" statement */
13273 cmdloop(1);
13275 #if PROFILE
13276 monitor(0);
13277 #endif
13278 #ifdef GPROF
13280 extern void _mcleanup(void);
13281 _mcleanup();
13283 #endif
13284 TRACE(("End of main reached\n"));
13285 exitshell();
13286 /* NOTREACHED */
13291 * Copyright (c) 1989, 1991, 1993, 1994
13292 * The Regents of the University of California. All rights reserved.
13294 * This code is derived from software contributed to Berkeley by
13295 * Kenneth Almquist.
13297 * Redistribution and use in source and binary forms, with or without
13298 * modification, are permitted provided that the following conditions
13299 * are met:
13300 * 1. Redistributions of source code must retain the above copyright
13301 * notice, this list of conditions and the following disclaimer.
13302 * 2. Redistributions in binary form must reproduce the above copyright
13303 * notice, this list of conditions and the following disclaimer in the
13304 * documentation and/or other materials provided with the distribution.
13305 * 3. Neither the name of the University nor the names of its contributors
13306 * may be used to endorse or promote products derived from this software
13307 * without specific prior written permission.
13309 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13310 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13311 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13312 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13313 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13314 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13315 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13316 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13317 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13318 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13319 * SUCH DAMAGE.