busybox: update to 1.25.0
[tomato.git] / release / src / router / busybox / shell / ash.c
blobfaa45a8dc600f9800d866fb0198f09c28c0ad993
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 <setjmp.h>
41 #include <fnmatch.h>
42 #include <sys/times.h>
43 #include <sys/utsname.h> /* for setting $HOSTNAME */
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_HELP
146 //config: bool "help builtin"
147 //config: default y
148 //config: depends on ASH
149 //config: help
150 //config: Enable help builtin in ash.
151 //config:
152 //config:config ASH_CMDCMD
153 //config: bool "'command' command to override shell builtins"
154 //config: default y
155 //config: depends on ASH
156 //config: help
157 //config: Enable support for the ash 'command' builtin, which allows
158 //config: you to run the specified command with the specified arguments,
159 //config: even when there is an ash builtin command with the same name.
160 //config:
161 //config:config ASH_MAIL
162 //config: bool "Check for new mail on interactive shells"
163 //config: default n
164 //config: depends on ASH
165 //config: help
166 //config: Enable "check for new mail" function in the ash shell.
167 //config:
168 //config:config ASH_OPTIMIZE_FOR_SIZE
169 //config: bool "Optimize for size instead of speed"
170 //config: default y
171 //config: depends on ASH
172 //config: help
173 //config: Compile ash for reduced size at the price of speed.
174 //config:
175 //config:config ASH_RANDOM_SUPPORT
176 //config: bool "Pseudorandom generator and $RANDOM variable"
177 //config: default y
178 //config: depends on ASH
179 //config: help
180 //config: Enable pseudorandom generator and dynamic variable "$RANDOM".
181 //config: Each read of "$RANDOM" will generate a new pseudorandom value.
182 //config: You can reset the generator by using a specified start value.
183 //config: After "unset RANDOM" the generator will switch off and this
184 //config: variable will no longer have special treatment.
185 //config:
186 //config:config ASH_EXPAND_PRMT
187 //config: bool "Expand prompt string"
188 //config: default y
189 //config: depends on ASH
190 //config: help
191 //config: "PS#" may contain volatile content, such as backquote commands.
192 //config: This option recreates the prompt string from the environment
193 //config: variable each time it is displayed.
194 //config:
196 //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
197 //applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh))
198 //applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash))
200 //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
201 //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
204 /* ============ Hash table sizes. Configurable. */
206 #define VTABSIZE 39
207 #define ATABSIZE 39
208 #define CMDTABLESIZE 31 /* should be prime */
211 /* ============ Shell options */
213 static const char *const optletters_optnames[] = {
214 "e" "errexit",
215 "f" "noglob",
216 "I" "ignoreeof",
217 "i" "interactive",
218 "m" "monitor",
219 "n" "noexec",
220 "s" "stdin",
221 "x" "xtrace",
222 "v" "verbose",
223 "C" "noclobber",
224 "a" "allexport",
225 "b" "notify",
226 "u" "nounset",
227 "\0" "vi"
228 #if ENABLE_ASH_BASH_COMPAT
229 ,"\0" "pipefail"
230 #endif
231 #if DEBUG
232 ,"\0" "nolog"
233 ,"\0" "debug"
234 #endif
237 #define optletters(n) optletters_optnames[n][0]
238 #define optnames(n) (optletters_optnames[n] + 1)
240 enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
243 /* ============ Misc data */
245 #define msg_illnum "Illegal number: %s"
248 * We enclose jmp_buf in a structure so that we can declare pointers to
249 * jump locations. The global variable handler contains the location to
250 * jump to when an exception occurs, and the global variable exception_type
251 * contains a code identifying the exception. To implement nested
252 * exception handlers, the user should save the value of handler on entry
253 * to an inner scope, set handler to point to a jmploc structure for the
254 * inner scope, and restore handler on exit from the scope.
256 struct jmploc {
257 jmp_buf loc;
260 struct globals_misc {
261 /* pid of main shell */
262 int rootpid;
263 /* shell level: 0 for the main shell, 1 for its children, and so on */
264 int shlvl;
265 #define rootshell (!shlvl)
266 char *minusc; /* argument to -c option */
268 char *curdir; // = nullstr; /* current working directory */
269 char *physdir; // = nullstr; /* physical working directory */
271 char *arg0; /* value of $0 */
273 struct jmploc *exception_handler;
275 volatile int suppress_int; /* counter */
276 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
277 /* last pending signal */
278 volatile /*sig_atomic_t*/ smallint pending_sig;
279 smallint exception_type; /* kind of exception (0..5) */
280 /* exceptions */
281 #define EXINT 0 /* SIGINT received */
282 #define EXERROR 1 /* a generic error */
283 #define EXSHELLPROC 2 /* execute a shell procedure */
284 #define EXEXEC 3 /* command execution failed */
285 #define EXEXIT 4 /* exit the shell */
286 #define EXSIG 5 /* trapped signal in wait(1) */
288 smallint isloginsh;
289 char nullstr[1]; /* zero length string */
291 char optlist[NOPTS];
292 #define eflag optlist[0]
293 #define fflag optlist[1]
294 #define Iflag optlist[2]
295 #define iflag optlist[3]
296 #define mflag optlist[4]
297 #define nflag optlist[5]
298 #define sflag optlist[6]
299 #define xflag optlist[7]
300 #define vflag optlist[8]
301 #define Cflag optlist[9]
302 #define aflag optlist[10]
303 #define bflag optlist[11]
304 #define uflag optlist[12]
305 #define viflag optlist[13]
306 #if ENABLE_ASH_BASH_COMPAT
307 # define pipefail optlist[14]
308 #else
309 # define pipefail 0
310 #endif
311 #if DEBUG
312 # define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
313 # define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
314 #endif
316 /* trap handler commands */
318 * Sigmode records the current value of the signal handlers for the various
319 * modes. A value of zero means that the current handler is not known.
320 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
322 char sigmode[NSIG - 1];
323 #define S_DFL 1 /* default signal handling (SIG_DFL) */
324 #define S_CATCH 2 /* signal is caught */
325 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
326 #define S_HARD_IGN 4 /* signal is ignored permenantly */
328 /* indicates specified signal received */
329 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
330 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
331 char *trap[NSIG];
332 char **trap_ptr; /* used only by "trap hack" */
334 /* Rarely referenced stuff */
335 #if ENABLE_ASH_RANDOM_SUPPORT
336 random_t random_gen;
337 #endif
338 pid_t backgndpid; /* pid of last background process */
339 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
341 extern struct globals_misc *const ash_ptr_to_globals_misc;
342 #define G_misc (*ash_ptr_to_globals_misc)
343 #define rootpid (G_misc.rootpid )
344 #define shlvl (G_misc.shlvl )
345 #define minusc (G_misc.minusc )
346 #define curdir (G_misc.curdir )
347 #define physdir (G_misc.physdir )
348 #define arg0 (G_misc.arg0 )
349 #define exception_handler (G_misc.exception_handler)
350 #define exception_type (G_misc.exception_type )
351 #define suppress_int (G_misc.suppress_int )
352 #define pending_int (G_misc.pending_int )
353 #define pending_sig (G_misc.pending_sig )
354 #define isloginsh (G_misc.isloginsh )
355 #define nullstr (G_misc.nullstr )
356 #define optlist (G_misc.optlist )
357 #define sigmode (G_misc.sigmode )
358 #define gotsig (G_misc.gotsig )
359 #define may_have_traps (G_misc.may_have_traps )
360 #define trap (G_misc.trap )
361 #define trap_ptr (G_misc.trap_ptr )
362 #define random_gen (G_misc.random_gen )
363 #define backgndpid (G_misc.backgndpid )
364 #define job_warning (G_misc.job_warning)
365 #define INIT_G_misc() do { \
366 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
367 barrier(); \
368 curdir = nullstr; \
369 physdir = nullstr; \
370 trap_ptr = trap; \
371 } while (0)
374 /* ============ DEBUG */
375 #if DEBUG
376 static void trace_printf(const char *fmt, ...);
377 static void trace_vprintf(const char *fmt, va_list va);
378 # define TRACE(param) trace_printf param
379 # define TRACEV(param) trace_vprintf param
380 # define close(fd) do { \
381 int dfd = (fd); \
382 if (close(dfd) < 0) \
383 bb_error_msg("bug on %d: closing %d(0x%x)", \
384 __LINE__, dfd, dfd); \
385 } while (0)
386 #else
387 # define TRACE(param)
388 # define TRACEV(param)
389 #endif
392 /* ============ Utility functions */
393 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
395 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
396 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
398 static int isdigit_str9(const char *str)
400 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
401 while (--maxlen && isdigit(*str))
402 str++;
403 return (*str == '\0');
406 static const char *var_end(const char *var)
408 while (*var)
409 if (*var++ == '=')
410 break;
411 return var;
415 /* ============ Interrupts / exceptions */
417 static void exitshell(void) NORETURN;
420 * These macros allow the user to suspend the handling of interrupt signals
421 * over a period of time. This is similar to SIGHOLD or to sigblock, but
422 * much more efficient and portable. (But hacking the kernel is so much
423 * more fun than worrying about efficiency and portability. :-))
425 #define INT_OFF do { \
426 suppress_int++; \
427 xbarrier(); \
428 } while (0)
431 * Called to raise an exception. Since C doesn't include exceptions, we
432 * just do a longjmp to the exception handler. The type of exception is
433 * stored in the global variable "exception_type".
435 static void raise_exception(int) NORETURN;
436 static void
437 raise_exception(int e)
439 #if DEBUG
440 if (exception_handler == NULL)
441 abort();
442 #endif
443 INT_OFF;
444 exception_type = e;
445 longjmp(exception_handler->loc, 1);
447 #if DEBUG
448 #define raise_exception(e) do { \
449 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
450 raise_exception(e); \
451 } while (0)
452 #endif
455 * Called from trap.c when a SIGINT is received. (If the user specifies
456 * that SIGINT is to be trapped or ignored using the trap builtin, then
457 * this routine is not called.) Suppressint is nonzero when interrupts
458 * are held using the INT_OFF macro. (The test for iflag is just
459 * defensive programming.)
461 static void raise_interrupt(void) NORETURN;
462 static void
463 raise_interrupt(void)
465 int ex_type;
467 pending_int = 0;
468 /* Signal is not automatically unmasked after it is raised,
469 * do it ourself - unmask all signals */
470 sigprocmask_allsigs(SIG_UNBLOCK);
471 /* pending_sig = 0; - now done in signal_handler() */
473 ex_type = EXSIG;
474 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
475 if (!(rootshell && iflag)) {
476 /* Kill ourself with SIGINT */
477 signal(SIGINT, SIG_DFL);
478 raise(SIGINT);
480 ex_type = EXINT;
482 raise_exception(ex_type);
483 /* NOTREACHED */
485 #if DEBUG
486 #define raise_interrupt() do { \
487 TRACE(("raising interrupt on line %d\n", __LINE__)); \
488 raise_interrupt(); \
489 } while (0)
490 #endif
492 static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
493 int_on(void)
495 xbarrier();
496 if (--suppress_int == 0 && pending_int) {
497 raise_interrupt();
500 #define INT_ON int_on()
501 static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
502 force_int_on(void)
504 xbarrier();
505 suppress_int = 0;
506 if (pending_int)
507 raise_interrupt();
509 #define FORCE_INT_ON force_int_on()
511 #define SAVE_INT(v) ((v) = suppress_int)
513 #define RESTORE_INT(v) do { \
514 xbarrier(); \
515 suppress_int = (v); \
516 if (suppress_int == 0 && pending_int) \
517 raise_interrupt(); \
518 } while (0)
521 /* ============ Stdout/stderr output */
523 static void
524 outstr(const char *p, FILE *file)
526 INT_OFF;
527 fputs(p, file);
528 INT_ON;
531 static void
532 flush_stdout_stderr(void)
534 INT_OFF;
535 fflush_all();
536 INT_ON;
539 /* Was called outcslow(c,FILE*), but c was always '\n' */
540 static void
541 newline_and_flush(FILE *dest)
543 INT_OFF;
544 putc('\n', dest);
545 fflush(dest);
546 INT_ON;
549 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
550 static int
551 out1fmt(const char *fmt, ...)
553 va_list ap;
554 int r;
556 INT_OFF;
557 va_start(ap, fmt);
558 r = vprintf(fmt, ap);
559 va_end(ap);
560 INT_ON;
561 return r;
564 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
565 static int
566 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
568 va_list ap;
569 int ret;
571 va_start(ap, fmt);
572 INT_OFF;
573 ret = vsnprintf(outbuf, length, fmt, ap);
574 va_end(ap);
575 INT_ON;
576 return ret;
579 static void
580 out1str(const char *p)
582 outstr(p, stdout);
585 static void
586 out2str(const char *p)
588 outstr(p, stderr);
589 flush_stdout_stderr();
593 /* ============ Parser structures */
595 /* control characters in argument strings */
596 #define CTL_FIRST CTLESC
597 #define CTLESC ((unsigned char)'\201') /* escape next character */
598 #define CTLVAR ((unsigned char)'\202') /* variable defn */
599 #define CTLENDVAR ((unsigned char)'\203')
600 #define CTLBACKQ ((unsigned char)'\204')
601 #define CTLARI ((unsigned char)'\206') /* arithmetic expression */
602 #define CTLENDARI ((unsigned char)'\207')
603 #define CTLQUOTEMARK ((unsigned char)'\210')
604 #define CTL_LAST CTLQUOTEMARK
606 /* variable substitution byte (follows CTLVAR) */
607 #define VSTYPE 0x0f /* type of variable substitution */
608 #define VSNUL 0x10 /* colon--treat the empty string as unset */
610 /* values of VSTYPE field */
611 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
612 #define VSMINUS 0x2 /* ${var-text} */
613 #define VSPLUS 0x3 /* ${var+text} */
614 #define VSQUESTION 0x4 /* ${var?message} */
615 #define VSASSIGN 0x5 /* ${var=text} */
616 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
617 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
618 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
619 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
620 #define VSLENGTH 0xa /* ${#var} */
621 #if ENABLE_ASH_BASH_COMPAT
622 #define VSSUBSTR 0xc /* ${var:position:length} */
623 #define VSREPLACE 0xd /* ${var/pattern/replacement} */
624 #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
625 #endif
627 static const char dolatstr[] ALIGN1 = {
628 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
630 #define DOLATSTRLEN 6
632 #define NCMD 0
633 #define NPIPE 1
634 #define NREDIR 2
635 #define NBACKGND 3
636 #define NSUBSHELL 4
637 #define NAND 5
638 #define NOR 6
639 #define NSEMI 7
640 #define NIF 8
641 #define NWHILE 9
642 #define NUNTIL 10
643 #define NFOR 11
644 #define NCASE 12
645 #define NCLIST 13
646 #define NDEFUN 14
647 #define NARG 15
648 #define NTO 16
649 #if ENABLE_ASH_BASH_COMPAT
650 #define NTO2 17
651 #endif
652 #define NCLOBBER 18
653 #define NFROM 19
654 #define NFROMTO 20
655 #define NAPPEND 21
656 #define NTOFD 22
657 #define NFROMFD 23
658 #define NHERE 24
659 #define NXHERE 25
660 #define NNOT 26
661 #define N_NUMBER 27
663 union node;
665 struct ncmd {
666 smallint type; /* Nxxxx */
667 union node *assign;
668 union node *args;
669 union node *redirect;
672 struct npipe {
673 smallint type;
674 smallint pipe_backgnd;
675 struct nodelist *cmdlist;
678 struct nredir {
679 smallint type;
680 union node *n;
681 union node *redirect;
684 struct nbinary {
685 smallint type;
686 union node *ch1;
687 union node *ch2;
690 struct nif {
691 smallint type;
692 union node *test;
693 union node *ifpart;
694 union node *elsepart;
697 struct nfor {
698 smallint type;
699 union node *args;
700 union node *body;
701 char *var;
704 struct ncase {
705 smallint type;
706 union node *expr;
707 union node *cases;
710 struct nclist {
711 smallint type;
712 union node *next;
713 union node *pattern;
714 union node *body;
717 struct narg {
718 smallint type;
719 union node *next;
720 char *text;
721 struct nodelist *backquote;
724 /* nfile and ndup layout must match!
725 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
726 * that it is actually NTO2 (>&file), and change its type.
728 struct nfile {
729 smallint type;
730 union node *next;
731 int fd;
732 int _unused_dupfd;
733 union node *fname;
734 char *expfname;
737 struct ndup {
738 smallint type;
739 union node *next;
740 int fd;
741 int dupfd;
742 union node *vname;
743 char *_unused_expfname;
746 struct nhere {
747 smallint type;
748 union node *next;
749 int fd;
750 union node *doc;
753 struct nnot {
754 smallint type;
755 union node *com;
758 union node {
759 smallint type;
760 struct ncmd ncmd;
761 struct npipe npipe;
762 struct nredir nredir;
763 struct nbinary nbinary;
764 struct nif nif;
765 struct nfor nfor;
766 struct ncase ncase;
767 struct nclist nclist;
768 struct narg narg;
769 struct nfile nfile;
770 struct ndup ndup;
771 struct nhere nhere;
772 struct nnot nnot;
776 * NODE_EOF is returned by parsecmd when it encounters an end of file.
777 * It must be distinct from NULL.
779 #define NODE_EOF ((union node *) -1L)
781 struct nodelist {
782 struct nodelist *next;
783 union node *n;
786 struct funcnode {
787 int count;
788 union node n;
792 * Free a parse tree.
794 static void
795 freefunc(struct funcnode *f)
797 if (f && --f->count < 0)
798 free(f);
802 /* ============ Debugging output */
804 #if DEBUG
806 static FILE *tracefile;
808 static void
809 trace_printf(const char *fmt, ...)
811 va_list va;
813 if (debug != 1)
814 return;
815 if (DEBUG_TIME)
816 fprintf(tracefile, "%u ", (int) time(NULL));
817 if (DEBUG_PID)
818 fprintf(tracefile, "[%u] ", (int) getpid());
819 if (DEBUG_SIG)
820 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
821 va_start(va, fmt);
822 vfprintf(tracefile, fmt, va);
823 va_end(va);
826 static void
827 trace_vprintf(const char *fmt, va_list va)
829 if (debug != 1)
830 return;
831 if (DEBUG_TIME)
832 fprintf(tracefile, "%u ", (int) time(NULL));
833 if (DEBUG_PID)
834 fprintf(tracefile, "[%u] ", (int) getpid());
835 if (DEBUG_SIG)
836 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
837 vfprintf(tracefile, fmt, va);
840 static void
841 trace_puts(const char *s)
843 if (debug != 1)
844 return;
845 fputs(s, tracefile);
848 static void
849 trace_puts_quoted(char *s)
851 char *p;
852 char c;
854 if (debug != 1)
855 return;
856 putc('"', tracefile);
857 for (p = s; *p; p++) {
858 switch ((unsigned char)*p) {
859 case '\n': c = 'n'; goto backslash;
860 case '\t': c = 't'; goto backslash;
861 case '\r': c = 'r'; goto backslash;
862 case '\"': c = '\"'; goto backslash;
863 case '\\': c = '\\'; goto backslash;
864 case CTLESC: c = 'e'; goto backslash;
865 case CTLVAR: c = 'v'; goto backslash;
866 case CTLBACKQ: c = 'q'; goto backslash;
867 backslash:
868 putc('\\', tracefile);
869 putc(c, tracefile);
870 break;
871 default:
872 if (*p >= ' ' && *p <= '~')
873 putc(*p, tracefile);
874 else {
875 putc('\\', tracefile);
876 putc((*p >> 6) & 03, tracefile);
877 putc((*p >> 3) & 07, tracefile);
878 putc(*p & 07, tracefile);
880 break;
883 putc('"', tracefile);
886 static void
887 trace_puts_args(char **ap)
889 if (debug != 1)
890 return;
891 if (!*ap)
892 return;
893 while (1) {
894 trace_puts_quoted(*ap);
895 if (!*++ap) {
896 putc('\n', tracefile);
897 break;
899 putc(' ', tracefile);
903 static void
904 opentrace(void)
906 char s[100];
907 #ifdef O_APPEND
908 int flags;
909 #endif
911 if (debug != 1) {
912 if (tracefile)
913 fflush(tracefile);
914 /* leave open because libedit might be using it */
915 return;
917 strcpy(s, "./trace");
918 if (tracefile) {
919 if (!freopen(s, "a", tracefile)) {
920 fprintf(stderr, "Can't re-open %s\n", s);
921 debug = 0;
922 return;
924 } else {
925 tracefile = fopen(s, "a");
926 if (tracefile == NULL) {
927 fprintf(stderr, "Can't open %s\n", s);
928 debug = 0;
929 return;
932 #ifdef O_APPEND
933 flags = fcntl(fileno(tracefile), F_GETFL);
934 if (flags >= 0)
935 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
936 #endif
937 setlinebuf(tracefile);
938 fputs("\nTracing started.\n", tracefile);
941 static void
942 indent(int amount, char *pfx, FILE *fp)
944 int i;
946 for (i = 0; i < amount; i++) {
947 if (pfx && i == amount - 1)
948 fputs(pfx, fp);
949 putc('\t', fp);
953 /* little circular references here... */
954 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
956 static void
957 sharg(union node *arg, FILE *fp)
959 char *p;
960 struct nodelist *bqlist;
961 unsigned char subtype;
963 if (arg->type != NARG) {
964 out1fmt("<node type %d>\n", arg->type);
965 abort();
967 bqlist = arg->narg.backquote;
968 for (p = arg->narg.text; *p; p++) {
969 switch ((unsigned char)*p) {
970 case CTLESC:
971 p++;
972 putc(*p, fp);
973 break;
974 case CTLVAR:
975 putc('$', fp);
976 putc('{', fp);
977 subtype = *++p;
978 if (subtype == VSLENGTH)
979 putc('#', fp);
981 while (*p != '=') {
982 putc(*p, fp);
983 p++;
986 if (subtype & VSNUL)
987 putc(':', fp);
989 switch (subtype & VSTYPE) {
990 case VSNORMAL:
991 putc('}', fp);
992 break;
993 case VSMINUS:
994 putc('-', fp);
995 break;
996 case VSPLUS:
997 putc('+', fp);
998 break;
999 case VSQUESTION:
1000 putc('?', fp);
1001 break;
1002 case VSASSIGN:
1003 putc('=', fp);
1004 break;
1005 case VSTRIMLEFT:
1006 putc('#', fp);
1007 break;
1008 case VSTRIMLEFTMAX:
1009 putc('#', fp);
1010 putc('#', fp);
1011 break;
1012 case VSTRIMRIGHT:
1013 putc('%', fp);
1014 break;
1015 case VSTRIMRIGHTMAX:
1016 putc('%', fp);
1017 putc('%', fp);
1018 break;
1019 case VSLENGTH:
1020 break;
1021 default:
1022 out1fmt("<subtype %d>", subtype);
1024 break;
1025 case CTLENDVAR:
1026 putc('}', fp);
1027 break;
1028 case CTLBACKQ:
1029 putc('$', fp);
1030 putc('(', fp);
1031 shtree(bqlist->n, -1, NULL, fp);
1032 putc(')', fp);
1033 break;
1034 default:
1035 putc(*p, fp);
1036 break;
1041 static void
1042 shcmd(union node *cmd, FILE *fp)
1044 union node *np;
1045 int first;
1046 const char *s;
1047 int dftfd;
1049 first = 1;
1050 for (np = cmd->ncmd.args; np; np = np->narg.next) {
1051 if (!first)
1052 putc(' ', fp);
1053 sharg(np, fp);
1054 first = 0;
1056 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
1057 if (!first)
1058 putc(' ', fp);
1059 dftfd = 0;
1060 switch (np->nfile.type) {
1061 case NTO: s = ">>"+1; dftfd = 1; break;
1062 case NCLOBBER: s = ">|"; dftfd = 1; break;
1063 case NAPPEND: s = ">>"; dftfd = 1; break;
1064 #if ENABLE_ASH_BASH_COMPAT
1065 case NTO2:
1066 #endif
1067 case NTOFD: s = ">&"; dftfd = 1; break;
1068 case NFROM: s = "<"; break;
1069 case NFROMFD: s = "<&"; break;
1070 case NFROMTO: s = "<>"; break;
1071 default: s = "*error*"; break;
1073 if (np->nfile.fd != dftfd)
1074 fprintf(fp, "%d", np->nfile.fd);
1075 fputs(s, fp);
1076 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1077 fprintf(fp, "%d", np->ndup.dupfd);
1078 } else {
1079 sharg(np->nfile.fname, fp);
1081 first = 0;
1085 static void
1086 shtree(union node *n, int ind, char *pfx, FILE *fp)
1088 struct nodelist *lp;
1089 const char *s;
1091 if (n == NULL)
1092 return;
1094 indent(ind, pfx, fp);
1096 if (n == NODE_EOF) {
1097 fputs("<EOF>", fp);
1098 return;
1101 switch (n->type) {
1102 case NSEMI:
1103 s = "; ";
1104 goto binop;
1105 case NAND:
1106 s = " && ";
1107 goto binop;
1108 case NOR:
1109 s = " || ";
1110 binop:
1111 shtree(n->nbinary.ch1, ind, NULL, fp);
1112 /* if (ind < 0) */
1113 fputs(s, fp);
1114 shtree(n->nbinary.ch2, ind, NULL, fp);
1115 break;
1116 case NCMD:
1117 shcmd(n, fp);
1118 if (ind >= 0)
1119 putc('\n', fp);
1120 break;
1121 case NPIPE:
1122 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
1123 shtree(lp->n, 0, NULL, fp);
1124 if (lp->next)
1125 fputs(" | ", fp);
1127 if (n->npipe.pipe_backgnd)
1128 fputs(" &", fp);
1129 if (ind >= 0)
1130 putc('\n', fp);
1131 break;
1132 default:
1133 fprintf(fp, "<node type %d>", n->type);
1134 if (ind >= 0)
1135 putc('\n', fp);
1136 break;
1140 static void
1141 showtree(union node *n)
1143 trace_puts("showtree called\n");
1144 shtree(n, 1, NULL, stderr);
1147 #endif /* DEBUG */
1150 /* ============ Parser data */
1153 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1155 struct strlist {
1156 struct strlist *next;
1157 char *text;
1160 struct alias;
1162 struct strpush {
1163 struct strpush *prev; /* preceding string on stack */
1164 char *prev_string;
1165 int prev_left_in_line;
1166 #if ENABLE_ASH_ALIAS
1167 struct alias *ap; /* if push was associated with an alias */
1168 #endif
1169 char *string; /* remember the string since it may change */
1172 struct parsefile {
1173 struct parsefile *prev; /* preceding file on stack */
1174 int linno; /* current line */
1175 int pf_fd; /* file descriptor (or -1 if string) */
1176 int left_in_line; /* number of chars left in this line */
1177 int left_in_buffer; /* number of chars left in this buffer past the line */
1178 char *next_to_pgetc; /* next char in buffer */
1179 char *buf; /* input buffer */
1180 struct strpush *strpush; /* for pushing strings at this level */
1181 struct strpush basestrpush; /* so pushing one is fast */
1184 static struct parsefile basepf; /* top level input file */
1185 static struct parsefile *g_parsefile = &basepf; /* current input file */
1186 static int startlinno; /* line # where last token started */
1187 static char *commandname; /* currently executing command */
1188 static struct strlist *cmdenviron; /* environment for builtin command */
1189 static uint8_t exitstatus; /* exit status of last command */
1192 /* ============ Message printing */
1194 static void
1195 ash_vmsg(const char *msg, va_list ap)
1197 fprintf(stderr, "%s: ", arg0);
1198 if (commandname) {
1199 if (strcmp(arg0, commandname))
1200 fprintf(stderr, "%s: ", commandname);
1201 if (!iflag || g_parsefile->pf_fd > 0)
1202 fprintf(stderr, "line %d: ", startlinno);
1204 vfprintf(stderr, msg, ap);
1205 newline_and_flush(stderr);
1209 * Exverror is called to raise the error exception. If the second argument
1210 * is not NULL then error prints an error message using printf style
1211 * formatting. It then raises the error exception.
1213 static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1214 static void
1215 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1217 #if DEBUG
1218 if (msg) {
1219 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1220 TRACEV((msg, ap));
1221 TRACE(("\") pid=%d\n", getpid()));
1222 } else
1223 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1224 if (msg)
1225 #endif
1226 ash_vmsg(msg, ap);
1228 flush_stdout_stderr();
1229 raise_exception(cond);
1230 /* NOTREACHED */
1233 static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1234 static void
1235 ash_msg_and_raise_error(const char *msg, ...)
1237 va_list ap;
1239 va_start(ap, msg);
1240 ash_vmsg_and_raise(EXERROR, msg, ap);
1241 /* NOTREACHED */
1242 va_end(ap);
1245 static void raise_error_syntax(const char *) NORETURN;
1246 static void
1247 raise_error_syntax(const char *msg)
1249 ash_msg_and_raise_error("syntax error: %s", msg);
1250 /* NOTREACHED */
1253 static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1254 static void
1255 ash_msg_and_raise(int cond, const char *msg, ...)
1257 va_list ap;
1259 va_start(ap, msg);
1260 ash_vmsg_and_raise(cond, msg, ap);
1261 /* NOTREACHED */
1262 va_end(ap);
1266 * error/warning routines for external builtins
1268 static void
1269 ash_msg(const char *fmt, ...)
1271 va_list ap;
1273 va_start(ap, fmt);
1274 ash_vmsg(fmt, ap);
1275 va_end(ap);
1279 * Return a string describing an error. The returned string may be a
1280 * pointer to a static buffer that will be overwritten on the next call.
1281 * Action describes the operation that got the error.
1283 static const char *
1284 errmsg(int e, const char *em)
1286 if (e == ENOENT || e == ENOTDIR) {
1287 return em;
1289 return strerror(e);
1293 /* ============ Memory allocation */
1295 #if 0
1296 /* I consider these wrappers nearly useless:
1297 * ok, they return you to nearest exception handler, but
1298 * how much memory do you leak in the process, making
1299 * memory starvation worse?
1301 static void *
1302 ckrealloc(void * p, size_t nbytes)
1304 p = realloc(p, nbytes);
1305 if (!p)
1306 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1307 return p;
1310 static void *
1311 ckmalloc(size_t nbytes)
1313 return ckrealloc(NULL, nbytes);
1316 static void *
1317 ckzalloc(size_t nbytes)
1319 return memset(ckmalloc(nbytes), 0, nbytes);
1322 static char *
1323 ckstrdup(const char *s)
1325 char *p = strdup(s);
1326 if (!p)
1327 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1328 return p;
1330 #else
1331 /* Using bbox equivalents. They exit if out of memory */
1332 # define ckrealloc xrealloc
1333 # define ckmalloc xmalloc
1334 # define ckzalloc xzalloc
1335 # define ckstrdup xstrdup
1336 #endif
1339 * It appears that grabstackstr() will barf with such alignments
1340 * because stalloc() will return a string allocated in a new stackblock.
1342 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1343 enum {
1344 /* Most machines require the value returned from malloc to be aligned
1345 * in some way. The following macro will get this right
1346 * on many machines. */
1347 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1348 /* Minimum size of a block */
1349 MINSIZE = SHELL_ALIGN(504),
1352 struct stack_block {
1353 struct stack_block *prev;
1354 char space[MINSIZE];
1357 struct stackmark {
1358 struct stack_block *stackp;
1359 char *stacknxt;
1360 size_t stacknleft;
1361 struct stackmark *marknext;
1365 struct globals_memstack {
1366 struct stack_block *g_stackp; // = &stackbase;
1367 struct stackmark *markp;
1368 char *g_stacknxt; // = stackbase.space;
1369 char *sstrend; // = stackbase.space + MINSIZE;
1370 size_t g_stacknleft; // = MINSIZE;
1371 int herefd; // = -1;
1372 struct stack_block stackbase;
1374 extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1375 #define G_memstack (*ash_ptr_to_globals_memstack)
1376 #define g_stackp (G_memstack.g_stackp )
1377 #define markp (G_memstack.markp )
1378 #define g_stacknxt (G_memstack.g_stacknxt )
1379 #define sstrend (G_memstack.sstrend )
1380 #define g_stacknleft (G_memstack.g_stacknleft)
1381 #define herefd (G_memstack.herefd )
1382 #define stackbase (G_memstack.stackbase )
1383 #define INIT_G_memstack() do { \
1384 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1385 barrier(); \
1386 g_stackp = &stackbase; \
1387 g_stacknxt = stackbase.space; \
1388 g_stacknleft = MINSIZE; \
1389 sstrend = stackbase.space + MINSIZE; \
1390 herefd = -1; \
1391 } while (0)
1394 #define stackblock() ((void *)g_stacknxt)
1395 #define stackblocksize() g_stacknleft
1398 * Parse trees for commands are allocated in lifo order, so we use a stack
1399 * to make this more efficient, and also to avoid all sorts of exception
1400 * handling code to handle interrupts in the middle of a parse.
1402 * The size 504 was chosen because the Ultrix malloc handles that size
1403 * well.
1405 static void *
1406 stalloc(size_t nbytes)
1408 char *p;
1409 size_t aligned;
1411 aligned = SHELL_ALIGN(nbytes);
1412 if (aligned > g_stacknleft) {
1413 size_t len;
1414 size_t blocksize;
1415 struct stack_block *sp;
1417 blocksize = aligned;
1418 if (blocksize < MINSIZE)
1419 blocksize = MINSIZE;
1420 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1421 if (len < blocksize)
1422 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1423 INT_OFF;
1424 sp = ckmalloc(len);
1425 sp->prev = g_stackp;
1426 g_stacknxt = sp->space;
1427 g_stacknleft = blocksize;
1428 sstrend = g_stacknxt + blocksize;
1429 g_stackp = sp;
1430 INT_ON;
1432 p = g_stacknxt;
1433 g_stacknxt += aligned;
1434 g_stacknleft -= aligned;
1435 return p;
1438 static void *
1439 stzalloc(size_t nbytes)
1441 return memset(stalloc(nbytes), 0, nbytes);
1444 static void
1445 stunalloc(void *p)
1447 #if DEBUG
1448 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1449 write(STDERR_FILENO, "stunalloc\n", 10);
1450 abort();
1452 #endif
1453 g_stacknleft += g_stacknxt - (char *)p;
1454 g_stacknxt = p;
1458 * Like strdup but works with the ash stack.
1460 static char *
1461 ststrdup(const char *p)
1463 size_t len = strlen(p) + 1;
1464 return memcpy(stalloc(len), p, len);
1467 static void
1468 setstackmark(struct stackmark *mark)
1470 mark->stackp = g_stackp;
1471 mark->stacknxt = g_stacknxt;
1472 mark->stacknleft = g_stacknleft;
1473 mark->marknext = markp;
1474 markp = mark;
1477 static void
1478 popstackmark(struct stackmark *mark)
1480 struct stack_block *sp;
1482 if (!mark->stackp)
1483 return;
1485 INT_OFF;
1486 markp = mark->marknext;
1487 while (g_stackp != mark->stackp) {
1488 sp = g_stackp;
1489 g_stackp = sp->prev;
1490 free(sp);
1492 g_stacknxt = mark->stacknxt;
1493 g_stacknleft = mark->stacknleft;
1494 sstrend = mark->stacknxt + mark->stacknleft;
1495 INT_ON;
1499 * When the parser reads in a string, it wants to stick the string on the
1500 * stack and only adjust the stack pointer when it knows how big the
1501 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1502 * of space on top of the stack and stackblocklen returns the length of
1503 * this block. Growstackblock will grow this space by at least one byte,
1504 * possibly moving it (like realloc). Grabstackblock actually allocates the
1505 * part of the block that has been used.
1507 static void
1508 growstackblock(void)
1510 size_t newlen;
1512 newlen = g_stacknleft * 2;
1513 if (newlen < g_stacknleft)
1514 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1515 if (newlen < 128)
1516 newlen += 128;
1518 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1519 struct stack_block *oldstackp;
1520 struct stackmark *xmark;
1521 struct stack_block *sp;
1522 struct stack_block *prevstackp;
1523 size_t grosslen;
1525 INT_OFF;
1526 oldstackp = g_stackp;
1527 sp = g_stackp;
1528 prevstackp = sp->prev;
1529 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1530 sp = ckrealloc(sp, grosslen);
1531 sp->prev = prevstackp;
1532 g_stackp = sp;
1533 g_stacknxt = sp->space;
1534 g_stacknleft = newlen;
1535 sstrend = sp->space + newlen;
1538 * Stack marks pointing to the start of the old block
1539 * must be relocated to point to the new block
1541 xmark = markp;
1542 while (xmark != NULL && xmark->stackp == oldstackp) {
1543 xmark->stackp = g_stackp;
1544 xmark->stacknxt = g_stacknxt;
1545 xmark->stacknleft = g_stacknleft;
1546 xmark = xmark->marknext;
1548 INT_ON;
1549 } else {
1550 char *oldspace = g_stacknxt;
1551 size_t oldlen = g_stacknleft;
1552 char *p = stalloc(newlen);
1554 /* free the space we just allocated */
1555 g_stacknxt = memcpy(p, oldspace, oldlen);
1556 g_stacknleft += newlen;
1560 static void
1561 grabstackblock(size_t len)
1563 len = SHELL_ALIGN(len);
1564 g_stacknxt += len;
1565 g_stacknleft -= len;
1569 * The following routines are somewhat easier to use than the above.
1570 * The user declares a variable of type STACKSTR, which may be declared
1571 * to be a register. The macro STARTSTACKSTR initializes things. Then
1572 * the user uses the macro STPUTC to add characters to the string. In
1573 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1574 * grown as necessary. When the user is done, she can just leave the
1575 * string there and refer to it using stackblock(). Or she can allocate
1576 * the space for it using grabstackstr(). If it is necessary to allow
1577 * someone else to use the stack temporarily and then continue to grow
1578 * the string, the user should use grabstack to allocate the space, and
1579 * then call ungrabstr(p) to return to the previous mode of operation.
1581 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1582 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1583 * is space for at least one character.
1585 static void *
1586 growstackstr(void)
1588 size_t len = stackblocksize();
1589 if (herefd >= 0 && len >= 1024) {
1590 full_write(herefd, stackblock(), len);
1591 return stackblock();
1593 growstackblock();
1594 return (char *)stackblock() + len;
1598 * Called from CHECKSTRSPACE.
1600 static char *
1601 makestrspace(size_t newlen, char *p)
1603 size_t len = p - g_stacknxt;
1604 size_t size = stackblocksize();
1606 for (;;) {
1607 size_t nleft;
1609 size = stackblocksize();
1610 nleft = size - len;
1611 if (nleft >= newlen)
1612 break;
1613 growstackblock();
1615 return (char *)stackblock() + len;
1618 static char *
1619 stack_nputstr(const char *s, size_t n, char *p)
1621 p = makestrspace(n, p);
1622 p = (char *)memcpy(p, s, n) + n;
1623 return p;
1626 static char *
1627 stack_putstr(const char *s, char *p)
1629 return stack_nputstr(s, strlen(s), p);
1632 static char *
1633 _STPUTC(int c, char *p)
1635 if (p == sstrend)
1636 p = growstackstr();
1637 *p++ = c;
1638 return p;
1641 #define STARTSTACKSTR(p) ((p) = stackblock())
1642 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1643 #define CHECKSTRSPACE(n, p) do { \
1644 char *q = (p); \
1645 size_t l = (n); \
1646 size_t m = sstrend - q; \
1647 if (l > m) \
1648 (p) = makestrspace(l, q); \
1649 } while (0)
1650 #define USTPUTC(c, p) (*(p)++ = (c))
1651 #define STACKSTRNUL(p) do { \
1652 if ((p) == sstrend) \
1653 (p) = growstackstr(); \
1654 *(p) = '\0'; \
1655 } while (0)
1656 #define STUNPUTC(p) (--(p))
1657 #define STTOPC(p) ((p)[-1])
1658 #define STADJUST(amount, p) ((p) += (amount))
1660 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1661 #define ungrabstackstr(s, p) stunalloc(s)
1662 #define stackstrend() ((void *)sstrend)
1665 /* ============ String helpers */
1668 * prefix -- see if pfx is a prefix of string.
1670 static char *
1671 prefix(const char *string, const char *pfx)
1673 while (*pfx) {
1674 if (*pfx++ != *string++)
1675 return NULL;
1677 return (char *) string;
1681 * Check for a valid number. This should be elsewhere.
1683 static int
1684 is_number(const char *p)
1686 do {
1687 if (!isdigit(*p))
1688 return 0;
1689 } while (*++p != '\0');
1690 return 1;
1694 * Convert a string of digits to an integer, printing an error message on
1695 * failure.
1697 static int
1698 number(const char *s)
1700 if (!is_number(s))
1701 ash_msg_and_raise_error(msg_illnum, s);
1702 return atoi(s);
1706 * Produce a possibly single quoted string suitable as input to the shell.
1707 * The return string is allocated on the stack.
1709 static char *
1710 single_quote(const char *s)
1712 char *p;
1714 STARTSTACKSTR(p);
1716 do {
1717 char *q;
1718 size_t len;
1720 len = strchrnul(s, '\'') - s;
1722 q = p = makestrspace(len + 3, p);
1724 *q++ = '\'';
1725 q = (char *)memcpy(q, s, len) + len;
1726 *q++ = '\'';
1727 s += len;
1729 STADJUST(q - p, p);
1731 if (*s != '\'')
1732 break;
1733 len = 0;
1734 do len++; while (*++s == '\'');
1736 q = p = makestrspace(len + 3, p);
1738 *q++ = '"';
1739 q = (char *)memcpy(q, s - len, len) + len;
1740 *q++ = '"';
1742 STADJUST(q - p, p);
1743 } while (*s);
1745 USTPUTC('\0', p);
1747 return stackblock();
1751 /* ============ nextopt */
1753 static char **argptr; /* argument list for builtin commands */
1754 static char *optionarg; /* set by nextopt (like getopt) */
1755 static char *optptr; /* used by nextopt */
1758 * XXX - should get rid of. Have all builtins use getopt(3).
1759 * The library getopt must have the BSD extension static variable
1760 * "optreset", otherwise it can't be used within the shell safely.
1762 * Standard option processing (a la getopt) for builtin routines.
1763 * The only argument that is passed to nextopt is the option string;
1764 * the other arguments are unnecessary. It returns the character,
1765 * or '\0' on end of input.
1767 static int
1768 nextopt(const char *optstring)
1770 char *p;
1771 const char *q;
1772 char c;
1774 p = optptr;
1775 if (p == NULL || *p == '\0') {
1776 /* We ate entire "-param", take next one */
1777 p = *argptr;
1778 if (p == NULL)
1779 return '\0';
1780 if (*p != '-')
1781 return '\0';
1782 if (*++p == '\0') /* just "-" ? */
1783 return '\0';
1784 argptr++;
1785 if (LONE_DASH(p)) /* "--" ? */
1786 return '\0';
1787 /* p => next "-param" */
1789 /* p => some option char in the middle of a "-param" */
1790 c = *p++;
1791 for (q = optstring; *q != c;) {
1792 if (*q == '\0')
1793 ash_msg_and_raise_error("illegal option -%c", c);
1794 if (*++q == ':')
1795 q++;
1797 if (*++q == ':') {
1798 if (*p == '\0') {
1799 p = *argptr++;
1800 if (p == NULL)
1801 ash_msg_and_raise_error("no arg for -%c option", c);
1803 optionarg = p;
1804 p = NULL;
1806 optptr = p;
1807 return c;
1811 /* ============ Shell variables */
1814 * The parsefile structure pointed to by the global variable parsefile
1815 * contains information about the current file being read.
1817 struct shparam {
1818 int nparam; /* # of positional parameters (without $0) */
1819 #if ENABLE_ASH_GETOPTS
1820 int optind; /* next parameter to be processed by getopts */
1821 int optoff; /* used by getopts */
1822 #endif
1823 unsigned char malloced; /* if parameter list dynamically allocated */
1824 char **p; /* parameter list */
1828 * Free the list of positional parameters.
1830 static void
1831 freeparam(volatile struct shparam *param)
1833 if (param->malloced) {
1834 char **ap, **ap1;
1835 ap = ap1 = param->p;
1836 while (*ap)
1837 free(*ap++);
1838 free(ap1);
1842 #if ENABLE_ASH_GETOPTS
1843 static void FAST_FUNC getoptsreset(const char *value);
1844 #endif
1846 struct var {
1847 struct var *next; /* next entry in hash list */
1848 int flags; /* flags are defined above */
1849 const char *var_text; /* name=value */
1850 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
1851 /* the variable gets set/unset */
1854 struct localvar {
1855 struct localvar *next; /* next local variable in list */
1856 struct var *vp; /* the variable that was made local */
1857 int flags; /* saved flags */
1858 const char *text; /* saved text */
1861 /* flags */
1862 #define VEXPORT 0x01 /* variable is exported */
1863 #define VREADONLY 0x02 /* variable cannot be modified */
1864 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1865 #define VTEXTFIXED 0x08 /* text is statically allocated */
1866 #define VSTACK 0x10 /* text is allocated on the stack */
1867 #define VUNSET 0x20 /* the variable is not set */
1868 #define VNOFUNC 0x40 /* don't call the callback function */
1869 #define VNOSET 0x80 /* do not set variable - just readonly test */
1870 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1871 #if ENABLE_ASH_RANDOM_SUPPORT
1872 # define VDYNAMIC 0x200 /* dynamic variable */
1873 #else
1874 # define VDYNAMIC 0
1875 #endif
1878 /* Need to be before varinit_data[] */
1879 #if ENABLE_LOCALE_SUPPORT
1880 static void FAST_FUNC
1881 change_lc_all(const char *value)
1883 if (value && *value != '\0')
1884 setlocale(LC_ALL, value);
1886 static void FAST_FUNC
1887 change_lc_ctype(const char *value)
1889 if (value && *value != '\0')
1890 setlocale(LC_CTYPE, value);
1892 #endif
1893 #if ENABLE_ASH_MAIL
1894 static void chkmail(void);
1895 static void changemail(const char *var_value) FAST_FUNC;
1896 #else
1897 # define chkmail() ((void)0)
1898 #endif
1899 static void changepath(const char *) FAST_FUNC;
1900 #if ENABLE_ASH_RANDOM_SUPPORT
1901 static void change_random(const char *) FAST_FUNC;
1902 #endif
1904 static const struct {
1905 int flags;
1906 const char *var_text;
1907 void (*var_func)(const char *) FAST_FUNC;
1908 } varinit_data[] = {
1910 * Note: VEXPORT would not work correctly here for NOFORK applets:
1911 * some environment strings may be constant.
1913 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1914 #if ENABLE_ASH_MAIL
1915 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1916 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
1917 #endif
1918 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1919 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1920 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1921 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1922 #if ENABLE_ASH_GETOPTS
1923 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
1924 #endif
1925 #if ENABLE_ASH_RANDOM_SUPPORT
1926 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
1927 #endif
1928 #if ENABLE_LOCALE_SUPPORT
1929 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1930 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
1931 #endif
1932 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1933 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
1934 #endif
1937 struct redirtab;
1939 struct globals_var {
1940 struct shparam shellparam; /* $@ current positional parameters */
1941 struct redirtab *redirlist;
1942 int g_nullredirs;
1943 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1944 struct var *vartab[VTABSIZE];
1945 struct var varinit[ARRAY_SIZE(varinit_data)];
1947 extern struct globals_var *const ash_ptr_to_globals_var;
1948 #define G_var (*ash_ptr_to_globals_var)
1949 #define shellparam (G_var.shellparam )
1950 //#define redirlist (G_var.redirlist )
1951 #define g_nullredirs (G_var.g_nullredirs )
1952 #define preverrout_fd (G_var.preverrout_fd)
1953 #define vartab (G_var.vartab )
1954 #define varinit (G_var.varinit )
1955 #define INIT_G_var() do { \
1956 unsigned i; \
1957 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1958 barrier(); \
1959 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1960 varinit[i].flags = varinit_data[i].flags; \
1961 varinit[i].var_text = varinit_data[i].var_text; \
1962 varinit[i].var_func = varinit_data[i].var_func; \
1964 } while (0)
1966 #define vifs varinit[0]
1967 #if ENABLE_ASH_MAIL
1968 # define vmail (&vifs)[1]
1969 # define vmpath (&vmail)[1]
1970 # define vpath (&vmpath)[1]
1971 #else
1972 # define vpath (&vifs)[1]
1973 #endif
1974 #define vps1 (&vpath)[1]
1975 #define vps2 (&vps1)[1]
1976 #define vps4 (&vps2)[1]
1977 #if ENABLE_ASH_GETOPTS
1978 # define voptind (&vps4)[1]
1979 # if ENABLE_ASH_RANDOM_SUPPORT
1980 # define vrandom (&voptind)[1]
1981 # endif
1982 #else
1983 # if ENABLE_ASH_RANDOM_SUPPORT
1984 # define vrandom (&vps4)[1]
1985 # endif
1986 #endif
1989 * The following macros access the values of the above variables.
1990 * They have to skip over the name. They return the null string
1991 * for unset variables.
1993 #define ifsval() (vifs.var_text + 4)
1994 #define ifsset() ((vifs.flags & VUNSET) == 0)
1995 #if ENABLE_ASH_MAIL
1996 # define mailval() (vmail.var_text + 5)
1997 # define mpathval() (vmpath.var_text + 9)
1998 # define mpathset() ((vmpath.flags & VUNSET) == 0)
1999 #endif
2000 #define pathval() (vpath.var_text + 5)
2001 #define ps1val() (vps1.var_text + 4)
2002 #define ps2val() (vps2.var_text + 4)
2003 #define ps4val() (vps4.var_text + 4)
2004 #if ENABLE_ASH_GETOPTS
2005 # define optindval() (voptind.var_text + 7)
2006 #endif
2008 #if ENABLE_ASH_GETOPTS
2009 static void FAST_FUNC
2010 getoptsreset(const char *value)
2012 shellparam.optind = number(value);
2013 shellparam.optoff = -1;
2015 #endif
2018 * Compares two strings up to the first = or '\0'. The first
2019 * string must be terminated by '='; the second may be terminated by
2020 * either '=' or '\0'.
2022 static int
2023 varcmp(const char *p, const char *q)
2025 int c, d;
2027 while ((c = *p) == (d = *q)) {
2028 if (c == '\0' || c == '=')
2029 goto out;
2030 p++;
2031 q++;
2033 if (c == '=')
2034 c = '\0';
2035 if (d == '=')
2036 d = '\0';
2037 out:
2038 return c - d;
2042 * Find the appropriate entry in the hash table from the name.
2044 static struct var **
2045 hashvar(const char *p)
2047 unsigned hashval;
2049 hashval = ((unsigned char) *p) << 4;
2050 while (*p && *p != '=')
2051 hashval += (unsigned char) *p++;
2052 return &vartab[hashval % VTABSIZE];
2055 static int
2056 vpcmp(const void *a, const void *b)
2058 return varcmp(*(const char **)a, *(const char **)b);
2062 * This routine initializes the builtin variables.
2064 static void
2065 initvar(void)
2067 struct var *vp;
2068 struct var *end;
2069 struct var **vpp;
2072 * PS1 depends on uid
2074 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2075 vps1.var_text = "PS1=\\w \\$ ";
2076 #else
2077 if (!geteuid())
2078 vps1.var_text = "PS1=# ";
2079 #endif
2080 vp = varinit;
2081 end = vp + ARRAY_SIZE(varinit);
2082 do {
2083 vpp = hashvar(vp->var_text);
2084 vp->next = *vpp;
2085 *vpp = vp;
2086 } while (++vp < end);
2089 static struct var **
2090 findvar(struct var **vpp, const char *name)
2092 for (; *vpp; vpp = &(*vpp)->next) {
2093 if (varcmp((*vpp)->var_text, name) == 0) {
2094 break;
2097 return vpp;
2101 * Find the value of a variable. Returns NULL if not set.
2103 static const char* FAST_FUNC
2104 lookupvar(const char *name)
2106 struct var *v;
2108 v = *findvar(hashvar(name), name);
2109 if (v) {
2110 #if ENABLE_ASH_RANDOM_SUPPORT
2112 * Dynamic variables are implemented roughly the same way they are
2113 * in bash. Namely, they're "special" so long as they aren't unset.
2114 * As soon as they're unset, they're no longer dynamic, and dynamic
2115 * lookup will no longer happen at that point. -- PFM.
2117 if (v->flags & VDYNAMIC)
2118 v->var_func(NULL);
2119 #endif
2120 if (!(v->flags & VUNSET))
2121 return var_end(v->var_text);
2123 return NULL;
2126 static void reinit_unicode_for_ash(void)
2128 /* Unicode support should be activated even if LANG is set
2129 * _during_ shell execution, not only if it was set when
2130 * shell was started. Therefore, re-check LANG every time:
2132 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2133 || ENABLE_UNICODE_USING_LOCALE
2135 const char *s = lookupvar("LC_ALL");
2136 if (!s) s = lookupvar("LC_CTYPE");
2137 if (!s) s = lookupvar("LANG");
2138 reinit_unicode(s);
2143 * Search the environment of a builtin command.
2145 static const char *
2146 bltinlookup(const char *name)
2148 struct strlist *sp;
2150 for (sp = cmdenviron; sp; sp = sp->next) {
2151 if (varcmp(sp->text, name) == 0)
2152 return var_end(sp->text);
2154 return lookupvar(name);
2158 * Same as setvar except that the variable and value are passed in
2159 * the first argument as name=value. Since the first argument will
2160 * be actually stored in the table, it should not be a string that
2161 * will go away.
2162 * Called with interrupts off.
2164 static void
2165 setvareq(char *s, int flags)
2167 struct var *vp, **vpp;
2169 vpp = hashvar(s);
2170 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2171 vp = *findvar(vpp, s);
2172 if (vp) {
2173 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2174 const char *n;
2176 if (flags & VNOSAVE)
2177 free(s);
2178 n = vp->var_text;
2179 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2182 if (flags & VNOSET)
2183 return;
2185 if (vp->var_func && !(flags & VNOFUNC))
2186 vp->var_func(var_end(s));
2188 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2189 free((char*)vp->var_text);
2191 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2192 } else {
2193 /* variable s is not found */
2194 if (flags & VNOSET)
2195 return;
2196 vp = ckzalloc(sizeof(*vp));
2197 vp->next = *vpp;
2198 /*vp->func = NULL; - ckzalloc did it */
2199 *vpp = vp;
2201 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2202 s = ckstrdup(s);
2203 vp->var_text = s;
2204 vp->flags = flags;
2208 * Set the value of a variable. The flags argument is ored with the
2209 * flags of the variable. If val is NULL, the variable is unset.
2211 static void
2212 setvar(const char *name, const char *val, int flags)
2214 const char *q;
2215 char *p;
2216 char *nameeq;
2217 size_t namelen;
2218 size_t vallen;
2220 q = endofname(name);
2221 p = strchrnul(q, '=');
2222 namelen = p - name;
2223 if (!namelen || p != q)
2224 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2225 vallen = 0;
2226 if (val == NULL) {
2227 flags |= VUNSET;
2228 } else {
2229 vallen = strlen(val);
2232 INT_OFF;
2233 nameeq = ckmalloc(namelen + vallen + 2);
2234 p = memcpy(nameeq, name, namelen) + namelen;
2235 if (val) {
2236 *p++ = '=';
2237 p = memcpy(p, val, vallen) + vallen;
2239 *p = '\0';
2240 setvareq(nameeq, flags | VNOSAVE);
2241 INT_ON;
2244 static void FAST_FUNC
2245 setvar0(const char *name, const char *val)
2247 setvar(name, val, 0);
2250 #if ENABLE_ASH_GETOPTS
2252 * Safe version of setvar, returns 1 on success 0 on failure.
2254 static int
2255 setvarsafe(const char *name, const char *val, int flags)
2257 int err;
2258 volatile int saveint;
2259 struct jmploc *volatile savehandler = exception_handler;
2260 struct jmploc jmploc;
2262 SAVE_INT(saveint);
2263 if (setjmp(jmploc.loc))
2264 err = 1;
2265 else {
2266 exception_handler = &jmploc;
2267 setvar(name, val, flags);
2268 err = 0;
2270 exception_handler = savehandler;
2271 RESTORE_INT(saveint);
2272 return err;
2274 #endif
2277 * Unset the specified variable.
2279 static int
2280 unsetvar(const char *s)
2282 struct var **vpp;
2283 struct var *vp;
2284 int retval;
2286 vpp = findvar(hashvar(s), s);
2287 vp = *vpp;
2288 retval = 2;
2289 if (vp) {
2290 int flags = vp->flags;
2292 retval = 1;
2293 if (flags & VREADONLY)
2294 goto out;
2295 #if ENABLE_ASH_RANDOM_SUPPORT
2296 vp->flags &= ~VDYNAMIC;
2297 #endif
2298 if (flags & VUNSET)
2299 goto ok;
2300 if ((flags & VSTRFIXED) == 0) {
2301 INT_OFF;
2302 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2303 free((char*)vp->var_text);
2304 *vpp = vp->next;
2305 free(vp);
2306 INT_ON;
2307 } else {
2308 setvar0(s, NULL);
2309 vp->flags &= ~VEXPORT;
2312 retval = 0;
2314 out:
2315 return retval;
2319 * Process a linked list of variable assignments.
2321 static void
2322 listsetvar(struct strlist *list_set_var, int flags)
2324 struct strlist *lp = list_set_var;
2326 if (!lp)
2327 return;
2328 INT_OFF;
2329 do {
2330 setvareq(lp->text, flags);
2331 lp = lp->next;
2332 } while (lp);
2333 INT_ON;
2337 * Generate a list of variables satisfying the given conditions.
2339 static char **
2340 listvars(int on, int off, char ***end)
2342 struct var **vpp;
2343 struct var *vp;
2344 char **ep;
2345 int mask;
2347 STARTSTACKSTR(ep);
2348 vpp = vartab;
2349 mask = on | off;
2350 do {
2351 for (vp = *vpp; vp; vp = vp->next) {
2352 if ((vp->flags & mask) == on) {
2353 if (ep == stackstrend())
2354 ep = growstackstr();
2355 *ep++ = (char*)vp->var_text;
2358 } while (++vpp < vartab + VTABSIZE);
2359 if (ep == stackstrend())
2360 ep = growstackstr();
2361 if (end)
2362 *end = ep;
2363 *ep++ = NULL;
2364 return grabstackstr(ep);
2368 /* ============ Path search helper
2370 * The variable path (passed by reference) should be set to the start
2371 * of the path before the first call; path_advance will update
2372 * this value as it proceeds. Successive calls to path_advance will return
2373 * the possible path expansions in sequence. If an option (indicated by
2374 * a percent sign) appears in the path entry then the global variable
2375 * pathopt will be set to point to it; otherwise pathopt will be set to
2376 * NULL.
2378 static const char *pathopt; /* set by path_advance */
2380 static char *
2381 path_advance(const char **path, const char *name)
2383 const char *p;
2384 char *q;
2385 const char *start;
2386 size_t len;
2388 if (*path == NULL)
2389 return NULL;
2390 start = *path;
2391 for (p = start; *p && *p != ':' && *p != '%'; p++)
2392 continue;
2393 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2394 while (stackblocksize() < len)
2395 growstackblock();
2396 q = stackblock();
2397 if (p != start) {
2398 memcpy(q, start, p - start);
2399 q += p - start;
2400 *q++ = '/';
2402 strcpy(q, name);
2403 pathopt = NULL;
2404 if (*p == '%') {
2405 pathopt = ++p;
2406 while (*p && *p != ':')
2407 p++;
2409 if (*p == ':')
2410 *path = p + 1;
2411 else
2412 *path = NULL;
2413 return stalloc(len);
2417 /* ============ Prompt */
2419 static smallint doprompt; /* if set, prompt the user */
2420 static smallint needprompt; /* true if interactive and at start of line */
2422 #if ENABLE_FEATURE_EDITING
2423 static line_input_t *line_input_state;
2424 static const char *cmdedit_prompt;
2425 static void
2426 putprompt(const char *s)
2428 if (ENABLE_ASH_EXPAND_PRMT) {
2429 free((char*)cmdedit_prompt);
2430 cmdedit_prompt = ckstrdup(s);
2431 return;
2433 cmdedit_prompt = s;
2435 #else
2436 static void
2437 putprompt(const char *s)
2439 out2str(s);
2441 #endif
2443 #if ENABLE_ASH_EXPAND_PRMT
2444 /* expandstr() needs parsing machinery, so it is far away ahead... */
2445 static const char *expandstr(const char *ps);
2446 #else
2447 #define expandstr(s) s
2448 #endif
2450 static void
2451 setprompt_if(smallint do_set, int whichprompt)
2453 const char *prompt;
2454 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2456 if (!do_set)
2457 return;
2459 needprompt = 0;
2461 switch (whichprompt) {
2462 case 1:
2463 prompt = ps1val();
2464 break;
2465 case 2:
2466 prompt = ps2val();
2467 break;
2468 default: /* 0 */
2469 prompt = nullstr;
2471 #if ENABLE_ASH_EXPAND_PRMT
2472 setstackmark(&smark);
2473 stalloc(stackblocksize());
2474 #endif
2475 putprompt(expandstr(prompt));
2476 #if ENABLE_ASH_EXPAND_PRMT
2477 popstackmark(&smark);
2478 #endif
2482 /* ============ The cd and pwd commands */
2484 #define CD_PHYSICAL 1
2485 #define CD_PRINT 2
2487 static int
2488 cdopt(void)
2490 int flags = 0;
2491 int i, j;
2493 j = 'L';
2494 while ((i = nextopt("LP")) != '\0') {
2495 if (i != j) {
2496 flags ^= CD_PHYSICAL;
2497 j = i;
2501 return flags;
2505 * Update curdir (the name of the current directory) in response to a
2506 * cd command.
2508 static const char *
2509 updatepwd(const char *dir)
2511 char *new;
2512 char *p;
2513 char *cdcomppath;
2514 const char *lim;
2516 cdcomppath = ststrdup(dir);
2517 STARTSTACKSTR(new);
2518 if (*dir != '/') {
2519 if (curdir == nullstr)
2520 return 0;
2521 new = stack_putstr(curdir, new);
2523 new = makestrspace(strlen(dir) + 2, new);
2524 lim = (char *)stackblock() + 1;
2525 if (*dir != '/') {
2526 if (new[-1] != '/')
2527 USTPUTC('/', new);
2528 if (new > lim && *lim == '/')
2529 lim++;
2530 } else {
2531 USTPUTC('/', new);
2532 cdcomppath++;
2533 if (dir[1] == '/' && dir[2] != '/') {
2534 USTPUTC('/', new);
2535 cdcomppath++;
2536 lim++;
2539 p = strtok(cdcomppath, "/");
2540 while (p) {
2541 switch (*p) {
2542 case '.':
2543 if (p[1] == '.' && p[2] == '\0') {
2544 while (new > lim) {
2545 STUNPUTC(new);
2546 if (new[-1] == '/')
2547 break;
2549 break;
2551 if (p[1] == '\0')
2552 break;
2553 /* fall through */
2554 default:
2555 new = stack_putstr(p, new);
2556 USTPUTC('/', new);
2558 p = strtok(NULL, "/");
2560 if (new > lim)
2561 STUNPUTC(new);
2562 *new = 0;
2563 return stackblock();
2567 * Find out what the current directory is. If we already know the current
2568 * directory, this routine returns immediately.
2570 static char *
2571 getpwd(void)
2573 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2574 return dir ? dir : nullstr;
2577 static void
2578 setpwd(const char *val, int setold)
2580 char *oldcur, *dir;
2582 oldcur = dir = curdir;
2584 if (setold) {
2585 setvar("OLDPWD", oldcur, VEXPORT);
2587 INT_OFF;
2588 if (physdir != nullstr) {
2589 if (physdir != oldcur)
2590 free(physdir);
2591 physdir = nullstr;
2593 if (oldcur == val || !val) {
2594 char *s = getpwd();
2595 physdir = s;
2596 if (!val)
2597 dir = s;
2598 } else
2599 dir = ckstrdup(val);
2600 if (oldcur != dir && oldcur != nullstr) {
2601 free(oldcur);
2603 curdir = dir;
2604 INT_ON;
2605 setvar("PWD", dir, VEXPORT);
2608 static void hashcd(void);
2611 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2612 * know that the current directory has changed.
2614 static int
2615 docd(const char *dest, int flags)
2617 const char *dir = NULL;
2618 int err;
2620 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2622 INT_OFF;
2623 if (!(flags & CD_PHYSICAL)) {
2624 dir = updatepwd(dest);
2625 if (dir)
2626 dest = dir;
2628 err = chdir(dest);
2629 if (err)
2630 goto out;
2631 setpwd(dir, 1);
2632 hashcd();
2633 out:
2634 INT_ON;
2635 return err;
2638 static int FAST_FUNC
2639 cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2641 const char *dest;
2642 const char *path;
2643 const char *p;
2644 char c;
2645 struct stat statb;
2646 int flags;
2648 flags = cdopt();
2649 dest = *argptr;
2650 if (!dest)
2651 dest = bltinlookup("HOME");
2652 else if (LONE_DASH(dest)) {
2653 dest = bltinlookup("OLDPWD");
2654 flags |= CD_PRINT;
2656 if (!dest)
2657 dest = nullstr;
2658 if (*dest == '/')
2659 goto step7;
2660 if (*dest == '.') {
2661 c = dest[1];
2662 dotdot:
2663 switch (c) {
2664 case '\0':
2665 case '/':
2666 goto step6;
2667 case '.':
2668 c = dest[2];
2669 if (c != '.')
2670 goto dotdot;
2673 if (!*dest)
2674 dest = ".";
2675 path = bltinlookup("CDPATH");
2676 if (!path) {
2677 step6:
2678 step7:
2679 p = dest;
2680 goto docd;
2682 do {
2683 c = *path;
2684 p = path_advance(&path, dest);
2685 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2686 if (c && c != ':')
2687 flags |= CD_PRINT;
2688 docd:
2689 if (!docd(p, flags))
2690 goto out;
2691 break;
2693 } while (path);
2694 ash_msg_and_raise_error("can't cd to %s", dest);
2695 /* NOTREACHED */
2696 out:
2697 if (flags & CD_PRINT)
2698 out1fmt("%s\n", curdir);
2699 return 0;
2702 static int FAST_FUNC
2703 pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2705 int flags;
2706 const char *dir = curdir;
2708 flags = cdopt();
2709 if (flags) {
2710 if (physdir == nullstr)
2711 setpwd(dir, 0);
2712 dir = physdir;
2714 out1fmt("%s\n", dir);
2715 return 0;
2719 /* ============ ... */
2722 #define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
2724 /* Syntax classes */
2725 #define CWORD 0 /* character is nothing special */
2726 #define CNL 1 /* newline character */
2727 #define CBACK 2 /* a backslash character */
2728 #define CSQUOTE 3 /* single quote */
2729 #define CDQUOTE 4 /* double quote */
2730 #define CENDQUOTE 5 /* a terminating quote */
2731 #define CBQUOTE 6 /* backwards single quote */
2732 #define CVAR 7 /* a dollar sign */
2733 #define CENDVAR 8 /* a '}' character */
2734 #define CLP 9 /* a left paren in arithmetic */
2735 #define CRP 10 /* a right paren in arithmetic */
2736 #define CENDFILE 11 /* end of file */
2737 #define CCTL 12 /* like CWORD, except it must be escaped */
2738 #define CSPCL 13 /* these terminate a word */
2739 #define CIGN 14 /* character should be ignored */
2741 #define PEOF 256
2742 #if ENABLE_ASH_ALIAS
2743 # define PEOA 257
2744 #endif
2746 #define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
2748 #if ENABLE_SH_MATH_SUPPORT
2749 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
2750 #else
2751 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
2752 #endif
2753 static const uint16_t S_I_T[] ALIGN2 = {
2754 #if ENABLE_ASH_ALIAS
2755 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2756 #endif
2757 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2758 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2759 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2760 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2761 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2762 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2763 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2764 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2765 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2766 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2767 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
2768 #if !USE_SIT_FUNCTION
2769 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2770 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2771 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2772 #endif
2773 #undef SIT_ITEM
2775 /* Constants below must match table above */
2776 enum {
2777 #if ENABLE_ASH_ALIAS
2778 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2779 #endif
2780 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2781 CNL_CNL_CNL_CNL , /* 2 */
2782 CWORD_CCTL_CCTL_CWORD , /* 3 */
2783 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2784 CVAR_CVAR_CWORD_CVAR , /* 5 */
2785 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2786 CSPCL_CWORD_CWORD_CLP , /* 7 */
2787 CSPCL_CWORD_CWORD_CRP , /* 8 */
2788 CBACK_CBACK_CCTL_CBACK , /* 9 */
2789 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2790 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2791 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2792 CWORD_CWORD_CWORD_CWORD , /* 13 */
2793 CCTL_CCTL_CCTL_CCTL , /* 14 */
2796 /* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2797 * caller must ensure proper cast on it if c is *char_ptr!
2799 /* Values for syntax param */
2800 #define BASESYNTAX 0 /* not in quotes */
2801 #define DQSYNTAX 1 /* in double quotes */
2802 #define SQSYNTAX 2 /* in single quotes */
2803 #define ARISYNTAX 3 /* in arithmetic */
2804 #define PSSYNTAX 4 /* prompt. never passed to SIT() */
2806 #if USE_SIT_FUNCTION
2808 static int
2809 SIT(int c, int syntax)
2811 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2812 # if ENABLE_ASH_ALIAS
2813 static const uint8_t syntax_index_table[] ALIGN1 = {
2814 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2815 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2816 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2817 11, 3 /* "}~" */
2819 # else
2820 static const uint8_t syntax_index_table[] ALIGN1 = {
2821 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2822 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2823 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2824 10, 2 /* "}~" */
2826 # endif
2827 const char *s;
2828 int indx;
2830 if (c == PEOF)
2831 return CENDFILE;
2832 # if ENABLE_ASH_ALIAS
2833 if (c == PEOA)
2834 indx = 0;
2835 else
2836 # endif
2838 /* Cast is purely for paranoia here,
2839 * just in case someone passed signed char to us */
2840 if ((unsigned char)c >= CTL_FIRST
2841 && (unsigned char)c <= CTL_LAST
2843 return CCTL;
2845 s = strchrnul(spec_symbls, c);
2846 if (*s == '\0')
2847 return CWORD;
2848 indx = syntax_index_table[s - spec_symbls];
2850 return (S_I_T[indx] >> (syntax*4)) & 0xf;
2853 #else /* !USE_SIT_FUNCTION */
2855 static const uint8_t syntax_index_table[] ALIGN1 = {
2856 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2857 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2867 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2868 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2890 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2891 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2892 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2893 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2894 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2895 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2896 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2897 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2898 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2899 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2900 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2901 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2902 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2903 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
2904 /* 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2905 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2906 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2907 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2908 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2909 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2910 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2916 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2917 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2918 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2919 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2920 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2921 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2949 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2950 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2951 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2954 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2982 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2983 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2984 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2985 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2986 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2987 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2988 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2989 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2990 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2991 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2992 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2993 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2994 /* 137 */ CWORD_CWORD_CWORD_CWORD,
2995 /* 138 */ CWORD_CWORD_CWORD_CWORD,
2996 /* 139 */ CWORD_CWORD_CWORD_CWORD,
2997 /* 140 */ CWORD_CWORD_CWORD_CWORD,
2998 /* 141 */ CWORD_CWORD_CWORD_CWORD,
2999 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3000 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3001 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3002 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 255 */ CWORD_CWORD_CWORD_CWORD,
3113 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
3114 # if ENABLE_ASH_ALIAS
3115 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3116 # endif
3119 # define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
3121 #endif /* !USE_SIT_FUNCTION */
3124 /* ============ Alias handling */
3126 #if ENABLE_ASH_ALIAS
3128 #define ALIASINUSE 1
3129 #define ALIASDEAD 2
3131 struct alias {
3132 struct alias *next;
3133 char *name;
3134 char *val;
3135 int flag;
3139 static struct alias **atab; // [ATABSIZE];
3140 #define INIT_G_alias() do { \
3141 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3142 } while (0)
3145 static struct alias **
3146 __lookupalias(const char *name) {
3147 unsigned int hashval;
3148 struct alias **app;
3149 const char *p;
3150 unsigned int ch;
3152 p = name;
3154 ch = (unsigned char)*p;
3155 hashval = ch << 4;
3156 while (ch) {
3157 hashval += ch;
3158 ch = (unsigned char)*++p;
3160 app = &atab[hashval % ATABSIZE];
3162 for (; *app; app = &(*app)->next) {
3163 if (strcmp(name, (*app)->name) == 0) {
3164 break;
3168 return app;
3171 static struct alias *
3172 lookupalias(const char *name, int check)
3174 struct alias *ap = *__lookupalias(name);
3176 if (check && ap && (ap->flag & ALIASINUSE))
3177 return NULL;
3178 return ap;
3181 static struct alias *
3182 freealias(struct alias *ap)
3184 struct alias *next;
3186 if (ap->flag & ALIASINUSE) {
3187 ap->flag |= ALIASDEAD;
3188 return ap;
3191 next = ap->next;
3192 free(ap->name);
3193 free(ap->val);
3194 free(ap);
3195 return next;
3198 static void
3199 setalias(const char *name, const char *val)
3201 struct alias *ap, **app;
3203 app = __lookupalias(name);
3204 ap = *app;
3205 INT_OFF;
3206 if (ap) {
3207 if (!(ap->flag & ALIASINUSE)) {
3208 free(ap->val);
3210 ap->val = ckstrdup(val);
3211 ap->flag &= ~ALIASDEAD;
3212 } else {
3213 /* not found */
3214 ap = ckzalloc(sizeof(struct alias));
3215 ap->name = ckstrdup(name);
3216 ap->val = ckstrdup(val);
3217 /*ap->flag = 0; - ckzalloc did it */
3218 /*ap->next = NULL;*/
3219 *app = ap;
3221 INT_ON;
3224 static int
3225 unalias(const char *name)
3227 struct alias **app;
3229 app = __lookupalias(name);
3231 if (*app) {
3232 INT_OFF;
3233 *app = freealias(*app);
3234 INT_ON;
3235 return 0;
3238 return 1;
3241 static void
3242 rmaliases(void)
3244 struct alias *ap, **app;
3245 int i;
3247 INT_OFF;
3248 for (i = 0; i < ATABSIZE; i++) {
3249 app = &atab[i];
3250 for (ap = *app; ap; ap = *app) {
3251 *app = freealias(*app);
3252 if (ap == *app) {
3253 app = &ap->next;
3257 INT_ON;
3260 static void
3261 printalias(const struct alias *ap)
3263 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3267 * TODO - sort output
3269 static int FAST_FUNC
3270 aliascmd(int argc UNUSED_PARAM, char **argv)
3272 char *n, *v;
3273 int ret = 0;
3274 struct alias *ap;
3276 if (!argv[1]) {
3277 int i;
3279 for (i = 0; i < ATABSIZE; i++) {
3280 for (ap = atab[i]; ap; ap = ap->next) {
3281 printalias(ap);
3284 return 0;
3286 while ((n = *++argv) != NULL) {
3287 v = strchr(n+1, '=');
3288 if (v == NULL) { /* n+1: funny ksh stuff */
3289 ap = *__lookupalias(n);
3290 if (ap == NULL) {
3291 fprintf(stderr, "%s: %s not found\n", "alias", n);
3292 ret = 1;
3293 } else
3294 printalias(ap);
3295 } else {
3296 *v++ = '\0';
3297 setalias(n, v);
3301 return ret;
3304 static int FAST_FUNC
3305 unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3307 int i;
3309 while ((i = nextopt("a")) != '\0') {
3310 if (i == 'a') {
3311 rmaliases();
3312 return 0;
3315 for (i = 0; *argptr; argptr++) {
3316 if (unalias(*argptr)) {
3317 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3318 i = 1;
3322 return i;
3325 #endif /* ASH_ALIAS */
3328 /* ============ jobs.c */
3330 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3331 #define FORK_FG 0
3332 #define FORK_BG 1
3333 #define FORK_NOJOB 2
3335 /* mode flags for showjob(s) */
3336 #define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3337 #define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3338 #define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
3339 #define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
3342 * A job structure contains information about a job. A job is either a
3343 * single process or a set of processes contained in a pipeline. In the
3344 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3345 * array of pids.
3347 struct procstat {
3348 pid_t ps_pid; /* process id */
3349 int ps_status; /* last process status from wait() */
3350 char *ps_cmd; /* text of command being run */
3353 struct job {
3354 struct procstat ps0; /* status of process */
3355 struct procstat *ps; /* status or processes when more than one */
3356 #if JOBS
3357 int stopstatus; /* status of a stopped job */
3358 #endif
3359 uint32_t
3360 nprocs: 16, /* number of processes */
3361 state: 8,
3362 #define JOBRUNNING 0 /* at least one proc running */
3363 #define JOBSTOPPED 1 /* all procs are stopped */
3364 #define JOBDONE 2 /* all procs are completed */
3365 #if JOBS
3366 sigint: 1, /* job was killed by SIGINT */
3367 jobctl: 1, /* job running under job control */
3368 #endif
3369 waited: 1, /* true if this entry has been waited for */
3370 used: 1, /* true if this entry is in used */
3371 changed: 1; /* true if status has changed */
3372 struct job *prev_job; /* previous job */
3375 static struct job *makejob(/*union node *,*/ int);
3376 static int forkshell(struct job *, union node *, int);
3377 static int waitforjob(struct job *);
3379 #if !JOBS
3380 enum { doing_jobctl = 0 };
3381 #define setjobctl(on) do {} while (0)
3382 #else
3383 static smallint doing_jobctl; //references:8
3384 static void setjobctl(int);
3385 #endif
3388 * Ignore a signal.
3390 static void
3391 ignoresig(int signo)
3393 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3394 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3395 /* No, need to do it */
3396 signal(signo, SIG_IGN);
3398 sigmode[signo - 1] = S_HARD_IGN;
3402 * Only one usage site - in setsignal()
3404 static void
3405 signal_handler(int signo)
3407 gotsig[signo - 1] = 1;
3409 if (signo == SIGINT && !trap[SIGINT]) {
3410 if (!suppress_int) {
3411 pending_sig = 0;
3412 raise_interrupt(); /* does not return */
3414 pending_int = 1;
3415 } else {
3416 pending_sig = signo;
3421 * Set the signal handler for the specified signal. The routine figures
3422 * out what it should be set to.
3424 static void
3425 setsignal(int signo)
3427 char *t;
3428 char cur_act, new_act;
3429 struct sigaction act;
3431 t = trap[signo];
3432 new_act = S_DFL;
3433 if (t != NULL) { /* trap for this sig is set */
3434 new_act = S_CATCH;
3435 if (t[0] == '\0') /* trap is "": ignore this sig */
3436 new_act = S_IGN;
3439 if (rootshell && new_act == S_DFL) {
3440 switch (signo) {
3441 case SIGINT:
3442 if (iflag || minusc || sflag == 0)
3443 new_act = S_CATCH;
3444 break;
3445 case SIGQUIT:
3446 #if DEBUG
3447 if (debug)
3448 break;
3449 #endif
3450 /* man bash:
3451 * "In all cases, bash ignores SIGQUIT. Non-builtin
3452 * commands run by bash have signal handlers
3453 * set to the values inherited by the shell
3454 * from its parent". */
3455 new_act = S_IGN;
3456 break;
3457 case SIGTERM:
3458 if (iflag)
3459 new_act = S_IGN;
3460 break;
3461 #if JOBS
3462 case SIGTSTP:
3463 case SIGTTOU:
3464 if (mflag)
3465 new_act = S_IGN;
3466 break;
3467 #endif
3470 //TODO: if !rootshell, we reset SIGQUIT to DFL,
3471 //whereas we have to restore it to what shell got on entry
3472 //from the parent. See comment above
3474 t = &sigmode[signo - 1];
3475 cur_act = *t;
3476 if (cur_act == 0) {
3477 /* current setting is not yet known */
3478 if (sigaction(signo, NULL, &act)) {
3479 /* pretend it worked; maybe we should give a warning,
3480 * but other shells don't. We don't alter sigmode,
3481 * so we retry every time.
3482 * btw, in Linux it never fails. --vda */
3483 return;
3485 if (act.sa_handler == SIG_IGN) {
3486 cur_act = S_HARD_IGN;
3487 if (mflag
3488 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3490 cur_act = S_IGN; /* don't hard ignore these */
3494 if (cur_act == S_HARD_IGN || cur_act == new_act)
3495 return;
3497 act.sa_handler = SIG_DFL;
3498 switch (new_act) {
3499 case S_CATCH:
3500 act.sa_handler = signal_handler;
3501 break;
3502 case S_IGN:
3503 act.sa_handler = SIG_IGN;
3504 break;
3507 /* flags and mask matter only if !DFL and !IGN, but we do it
3508 * for all cases for more deterministic behavior:
3510 act.sa_flags = 0;
3511 sigfillset(&act.sa_mask);
3513 sigaction_set(signo, &act);
3515 *t = new_act;
3518 /* mode flags for set_curjob */
3519 #define CUR_DELETE 2
3520 #define CUR_RUNNING 1
3521 #define CUR_STOPPED 0
3523 /* mode flags for dowait */
3524 #define DOWAIT_NONBLOCK WNOHANG
3525 #define DOWAIT_BLOCK 0
3527 #if JOBS
3528 /* pgrp of shell on invocation */
3529 static int initialpgrp; //references:2
3530 static int ttyfd = -1; //5
3531 #endif
3532 /* array of jobs */
3533 static struct job *jobtab; //5
3534 /* size of array */
3535 static unsigned njobs; //4
3536 /* current job */
3537 static struct job *curjob; //lots
3538 /* number of presumed living untracked jobs */
3539 static int jobless; //4
3541 static void
3542 set_curjob(struct job *jp, unsigned mode)
3544 struct job *jp1;
3545 struct job **jpp, **curp;
3547 /* first remove from list */
3548 jpp = curp = &curjob;
3549 while (1) {
3550 jp1 = *jpp;
3551 if (jp1 == jp)
3552 break;
3553 jpp = &jp1->prev_job;
3555 *jpp = jp1->prev_job;
3557 /* Then re-insert in correct position */
3558 jpp = curp;
3559 switch (mode) {
3560 default:
3561 #if DEBUG
3562 abort();
3563 #endif
3564 case CUR_DELETE:
3565 /* job being deleted */
3566 break;
3567 case CUR_RUNNING:
3568 /* newly created job or backgrounded job,
3569 * put after all stopped jobs.
3571 while (1) {
3572 jp1 = *jpp;
3573 #if JOBS
3574 if (!jp1 || jp1->state != JOBSTOPPED)
3575 #endif
3576 break;
3577 jpp = &jp1->prev_job;
3579 /* FALLTHROUGH */
3580 #if JOBS
3581 case CUR_STOPPED:
3582 #endif
3583 /* newly stopped job - becomes curjob */
3584 jp->prev_job = *jpp;
3585 *jpp = jp;
3586 break;
3590 #if JOBS || DEBUG
3591 static int
3592 jobno(const struct job *jp)
3594 return jp - jobtab + 1;
3596 #endif
3599 * Convert a job name to a job structure.
3601 #if !JOBS
3602 #define getjob(name, getctl) getjob(name)
3603 #endif
3604 static struct job *
3605 getjob(const char *name, int getctl)
3607 struct job *jp;
3608 struct job *found;
3609 const char *err_msg = "%s: no such job";
3610 unsigned num;
3611 int c;
3612 const char *p;
3613 char *(*match)(const char *, const char *);
3615 jp = curjob;
3616 p = name;
3617 if (!p)
3618 goto currentjob;
3620 if (*p != '%')
3621 goto err;
3623 c = *++p;
3624 if (!c)
3625 goto currentjob;
3627 if (!p[1]) {
3628 if (c == '+' || c == '%') {
3629 currentjob:
3630 err_msg = "No current job";
3631 goto check;
3633 if (c == '-') {
3634 if (jp)
3635 jp = jp->prev_job;
3636 err_msg = "No previous job";
3637 check:
3638 if (!jp)
3639 goto err;
3640 goto gotit;
3644 if (is_number(p)) {
3645 num = atoi(p);
3646 if (num <= njobs) {
3647 jp = jobtab + num - 1;
3648 if (jp->used)
3649 goto gotit;
3650 goto err;
3654 match = prefix;
3655 if (*p == '?') {
3656 match = strstr;
3657 p++;
3660 found = NULL;
3661 while (jp) {
3662 if (match(jp->ps[0].ps_cmd, p)) {
3663 if (found)
3664 goto err;
3665 found = jp;
3666 err_msg = "%s: ambiguous";
3668 jp = jp->prev_job;
3670 if (!found)
3671 goto err;
3672 jp = found;
3674 gotit:
3675 #if JOBS
3676 err_msg = "job %s not created under job control";
3677 if (getctl && jp->jobctl == 0)
3678 goto err;
3679 #endif
3680 return jp;
3681 err:
3682 ash_msg_and_raise_error(err_msg, name);
3686 * Mark a job structure as unused.
3688 static void
3689 freejob(struct job *jp)
3691 struct procstat *ps;
3692 int i;
3694 INT_OFF;
3695 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3696 if (ps->ps_cmd != nullstr)
3697 free(ps->ps_cmd);
3699 if (jp->ps != &jp->ps0)
3700 free(jp->ps);
3701 jp->used = 0;
3702 set_curjob(jp, CUR_DELETE);
3703 INT_ON;
3706 #if JOBS
3707 static void
3708 xtcsetpgrp(int fd, pid_t pgrp)
3710 if (tcsetpgrp(fd, pgrp))
3711 ash_msg_and_raise_error("can't set tty process group (%m)");
3715 * Turn job control on and off.
3717 * Note: This code assumes that the third arg to ioctl is a character
3718 * pointer, which is true on Berkeley systems but not System V. Since
3719 * System V doesn't have job control yet, this isn't a problem now.
3721 * Called with interrupts off.
3723 static void
3724 setjobctl(int on)
3726 int fd;
3727 int pgrp;
3729 if (on == doing_jobctl || rootshell == 0)
3730 return;
3731 if (on) {
3732 int ofd;
3733 ofd = fd = open(_PATH_TTY, O_RDWR);
3734 if (fd < 0) {
3735 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3736 * That sometimes helps to acquire controlling tty.
3737 * Obviously, a workaround for bugs when someone
3738 * failed to provide a controlling tty to bash! :) */
3739 fd = 2;
3740 while (!isatty(fd))
3741 if (--fd < 0)
3742 goto out;
3744 fd = fcntl(fd, F_DUPFD, 10);
3745 if (ofd >= 0)
3746 close(ofd);
3747 if (fd < 0)
3748 goto out;
3749 /* fd is a tty at this point */
3750 close_on_exec_on(fd);
3751 while (1) { /* while we are in the background */
3752 pgrp = tcgetpgrp(fd);
3753 if (pgrp < 0) {
3754 out:
3755 ash_msg("can't access tty; job control turned off");
3756 mflag = on = 0;
3757 goto close;
3759 if (pgrp == getpgrp())
3760 break;
3761 killpg(0, SIGTTIN);
3763 initialpgrp = pgrp;
3765 setsignal(SIGTSTP);
3766 setsignal(SIGTTOU);
3767 setsignal(SIGTTIN);
3768 pgrp = rootpid;
3769 setpgid(0, pgrp);
3770 xtcsetpgrp(fd, pgrp);
3771 } else {
3772 /* turning job control off */
3773 fd = ttyfd;
3774 pgrp = initialpgrp;
3775 /* was xtcsetpgrp, but this can make exiting ash
3776 * loop forever if pty is already deleted */
3777 tcsetpgrp(fd, pgrp);
3778 setpgid(0, pgrp);
3779 setsignal(SIGTSTP);
3780 setsignal(SIGTTOU);
3781 setsignal(SIGTTIN);
3782 close:
3783 if (fd >= 0)
3784 close(fd);
3785 fd = -1;
3787 ttyfd = fd;
3788 doing_jobctl = on;
3791 static int FAST_FUNC
3792 killcmd(int argc, char **argv)
3794 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3795 int i = 1;
3796 do {
3797 if (argv[i][0] == '%') {
3799 * "kill %N" - job kill
3800 * Converting to pgrp / pid kill
3802 struct job *jp;
3803 char *dst;
3804 int j, n;
3806 jp = getjob(argv[i], 0);
3808 * In jobs started under job control, we signal
3809 * entire process group by kill -PGRP_ID.
3810 * This happens, f.e., in interactive shell.
3812 * Otherwise, we signal each child via
3813 * kill PID1 PID2 PID3.
3814 * Testcases:
3815 * sh -c 'sleep 1|sleep 1 & kill %1'
3816 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3817 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3819 n = jp->nprocs; /* can't be 0 (I hope) */
3820 if (jp->jobctl)
3821 n = 1;
3822 dst = alloca(n * sizeof(int)*4);
3823 argv[i] = dst;
3824 for (j = 0; j < n; j++) {
3825 struct procstat *ps = &jp->ps[j];
3826 /* Skip non-running and not-stopped members
3827 * (i.e. dead members) of the job
3829 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3830 continue;
3832 * kill_main has matching code to expect
3833 * leading space. Needed to not confuse
3834 * negative pids with "kill -SIGNAL_NO" syntax
3836 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3838 *dst = '\0';
3840 } while (argv[++i]);
3842 return kill_main(argc, argv);
3845 static void
3846 showpipe(struct job *jp /*, FILE *out*/)
3848 struct procstat *ps;
3849 struct procstat *psend;
3851 psend = jp->ps + jp->nprocs;
3852 for (ps = jp->ps + 1; ps < psend; ps++)
3853 printf(" | %s", ps->ps_cmd);
3854 newline_and_flush(stdout);
3855 flush_stdout_stderr();
3859 static int
3860 restartjob(struct job *jp, int mode)
3862 struct procstat *ps;
3863 int i;
3864 int status;
3865 pid_t pgid;
3867 INT_OFF;
3868 if (jp->state == JOBDONE)
3869 goto out;
3870 jp->state = JOBRUNNING;
3871 pgid = jp->ps[0].ps_pid;
3872 if (mode == FORK_FG)
3873 xtcsetpgrp(ttyfd, pgid);
3874 killpg(pgid, SIGCONT);
3875 ps = jp->ps;
3876 i = jp->nprocs;
3877 do {
3878 if (WIFSTOPPED(ps->ps_status)) {
3879 ps->ps_status = -1;
3881 ps++;
3882 } while (--i);
3883 out:
3884 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3885 INT_ON;
3886 return status;
3889 static int FAST_FUNC
3890 fg_bgcmd(int argc UNUSED_PARAM, char **argv)
3892 struct job *jp;
3893 int mode;
3894 int retval;
3896 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3897 nextopt(nullstr);
3898 argv = argptr;
3899 do {
3900 jp = getjob(*argv, 1);
3901 if (mode == FORK_BG) {
3902 set_curjob(jp, CUR_RUNNING);
3903 printf("[%d] ", jobno(jp));
3905 out1str(jp->ps[0].ps_cmd);
3906 showpipe(jp /*, stdout*/);
3907 retval = restartjob(jp, mode);
3908 } while (*argv && *++argv);
3909 return retval;
3911 #endif
3913 static int
3914 sprint_status48(char *s, int status, int sigonly)
3916 int col;
3917 int st;
3919 col = 0;
3920 if (!WIFEXITED(status)) {
3921 if (JOBS && WIFSTOPPED(status))
3922 st = WSTOPSIG(status);
3923 else
3924 st = WTERMSIG(status);
3925 if (sigonly) {
3926 if (st == SIGINT || st == SIGPIPE)
3927 goto out;
3928 if (JOBS && WIFSTOPPED(status))
3929 goto out;
3931 st &= 0x7f;
3932 //TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
3933 col = fmtstr(s, 32, strsignal(st));
3934 if (WCOREDUMP(status)) {
3935 strcpy(s + col, " (core dumped)");
3936 col += sizeof(" (core dumped)")-1;
3938 } else if (!sigonly) {
3939 st = WEXITSTATUS(status);
3940 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
3942 out:
3943 return col;
3946 static int
3947 dowait(int wait_flags, struct job *job)
3949 int pid;
3950 int status;
3951 struct job *jp;
3952 struct job *thisjob;
3954 TRACE(("dowait(0x%x) called\n", wait_flags));
3956 /* Do a wait system call. If job control is compiled in, we accept
3957 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3958 * NB: _not_ safe_waitpid, we need to detect EINTR */
3959 if (doing_jobctl)
3960 wait_flags |= WUNTRACED;
3961 pid = waitpid(-1, &status, wait_flags);
3962 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3963 pid, status, errno, strerror(errno)));
3964 if (pid <= 0)
3965 return pid;
3967 INT_OFF;
3968 thisjob = NULL;
3969 for (jp = curjob; jp; jp = jp->prev_job) {
3970 int jobstate;
3971 struct procstat *ps;
3972 struct procstat *psend;
3973 if (jp->state == JOBDONE)
3974 continue;
3975 jobstate = JOBDONE;
3976 ps = jp->ps;
3977 psend = ps + jp->nprocs;
3978 do {
3979 if (ps->ps_pid == pid) {
3980 TRACE(("Job %d: changing status of proc %d "
3981 "from 0x%x to 0x%x\n",
3982 jobno(jp), pid, ps->ps_status, status));
3983 ps->ps_status = status;
3984 thisjob = jp;
3986 if (ps->ps_status == -1)
3987 jobstate = JOBRUNNING;
3988 #if JOBS
3989 if (jobstate == JOBRUNNING)
3990 continue;
3991 if (WIFSTOPPED(ps->ps_status)) {
3992 jp->stopstatus = ps->ps_status;
3993 jobstate = JOBSTOPPED;
3995 #endif
3996 } while (++ps < psend);
3997 if (!thisjob)
3998 continue;
4000 /* Found the job where one of its processes changed its state.
4001 * Is there at least one live and running process in this job? */
4002 if (jobstate != JOBRUNNING) {
4003 /* No. All live processes in the job are stopped
4004 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4006 thisjob->changed = 1;
4007 if (thisjob->state != jobstate) {
4008 TRACE(("Job %d: changing state from %d to %d\n",
4009 jobno(thisjob), thisjob->state, jobstate));
4010 thisjob->state = jobstate;
4011 #if JOBS
4012 if (jobstate == JOBSTOPPED)
4013 set_curjob(thisjob, CUR_STOPPED);
4014 #endif
4017 goto out;
4019 /* The process wasn't found in job list */
4020 if (JOBS && !WIFSTOPPED(status))
4021 jobless--;
4022 out:
4023 INT_ON;
4025 if (thisjob && thisjob == job) {
4026 char s[48 + 1];
4027 int len;
4029 len = sprint_status48(s, status, 1);
4030 if (len) {
4031 s[len] = '\n';
4032 s[len + 1] = '\0';
4033 out2str(s);
4036 return pid;
4039 static int
4040 blocking_wait_with_raise_on_sig(void)
4042 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
4043 if (pid <= 0 && pending_sig)
4044 raise_exception(EXSIG);
4045 return pid;
4048 #if JOBS
4049 static void
4050 showjob(struct job *jp, int mode)
4052 struct procstat *ps;
4053 struct procstat *psend;
4054 int col;
4055 int indent_col;
4056 char s[16 + 16 + 48];
4057 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
4059 ps = jp->ps;
4061 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
4062 /* just output process (group) id of pipeline */
4063 fprintf(out, "%d\n", ps->ps_pid);
4064 return;
4067 col = fmtstr(s, 16, "[%d] ", jobno(jp));
4068 indent_col = col;
4070 if (jp == curjob)
4071 s[col - 3] = '+';
4072 else if (curjob && jp == curjob->prev_job)
4073 s[col - 3] = '-';
4075 if (mode & SHOW_PIDS)
4076 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
4078 psend = ps + jp->nprocs;
4080 if (jp->state == JOBRUNNING) {
4081 strcpy(s + col, "Running");
4082 col += sizeof("Running") - 1;
4083 } else {
4084 int status = psend[-1].ps_status;
4085 if (jp->state == JOBSTOPPED)
4086 status = jp->stopstatus;
4087 col += sprint_status48(s + col, status, 0);
4089 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
4091 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4092 * or prints several "PID | <cmdN>" lines,
4093 * depending on SHOW_PIDS bit.
4094 * We do not print status of individual processes
4095 * between PID and <cmdN>. bash does it, but not very well:
4096 * first line shows overall job status, not process status,
4097 * making it impossible to know 1st process status.
4099 goto start;
4100 do {
4101 /* for each process */
4102 s[0] = '\0';
4103 col = 33;
4104 if (mode & SHOW_PIDS)
4105 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
4106 start:
4107 fprintf(out, "%s%*c%s%s",
4109 33 - col >= 0 ? 33 - col : 0, ' ',
4110 ps == jp->ps ? "" : "| ",
4111 ps->ps_cmd
4113 } while (++ps != psend);
4114 newline_and_flush(out);
4116 jp->changed = 0;
4118 if (jp->state == JOBDONE) {
4119 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4120 freejob(jp);
4125 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4126 * statuses have changed since the last call to showjobs.
4128 static void
4129 showjobs(int mode)
4131 struct job *jp;
4133 TRACE(("showjobs(0x%x) called\n", mode));
4135 /* Handle all finished jobs */
4136 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
4137 continue;
4139 for (jp = curjob; jp; jp = jp->prev_job) {
4140 if (!(mode & SHOW_CHANGED) || jp->changed) {
4141 showjob(jp, mode);
4146 static int FAST_FUNC
4147 jobscmd(int argc UNUSED_PARAM, char **argv)
4149 int mode, m;
4151 mode = 0;
4152 while ((m = nextopt("lp")) != '\0') {
4153 if (m == 'l')
4154 mode |= SHOW_PIDS;
4155 else
4156 mode |= SHOW_ONLY_PGID;
4159 argv = argptr;
4160 if (*argv) {
4162 showjob(getjob(*argv, 0), mode);
4163 while (*++argv);
4164 } else {
4165 showjobs(mode);
4168 return 0;
4170 #endif /* JOBS */
4172 /* Called only on finished or stopped jobs (no members are running) */
4173 static int
4174 getstatus(struct job *job)
4176 int status;
4177 int retval;
4178 struct procstat *ps;
4180 /* Fetch last member's status */
4181 ps = job->ps + job->nprocs - 1;
4182 status = ps->ps_status;
4183 if (pipefail) {
4184 /* "set -o pipefail" mode: use last _nonzero_ status */
4185 while (status == 0 && --ps >= job->ps)
4186 status = ps->ps_status;
4189 retval = WEXITSTATUS(status);
4190 if (!WIFEXITED(status)) {
4191 #if JOBS
4192 retval = WSTOPSIG(status);
4193 if (!WIFSTOPPED(status))
4194 #endif
4196 /* XXX: limits number of signals */
4197 retval = WTERMSIG(status);
4198 #if JOBS
4199 if (retval == SIGINT)
4200 job->sigint = 1;
4201 #endif
4203 retval += 128;
4205 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4206 jobno(job), job->nprocs, status, retval));
4207 return retval;
4210 static int FAST_FUNC
4211 waitcmd(int argc UNUSED_PARAM, char **argv)
4213 struct job *job;
4214 int retval;
4215 struct job *jp;
4217 if (pending_sig)
4218 raise_exception(EXSIG);
4220 nextopt(nullstr);
4221 retval = 0;
4223 argv = argptr;
4224 if (!*argv) {
4225 /* wait for all jobs */
4226 for (;;) {
4227 jp = curjob;
4228 while (1) {
4229 if (!jp) /* no running procs */
4230 goto ret;
4231 if (jp->state == JOBRUNNING)
4232 break;
4233 jp->waited = 1;
4234 jp = jp->prev_job;
4236 blocking_wait_with_raise_on_sig();
4237 /* man bash:
4238 * "When bash is waiting for an asynchronous command via
4239 * the wait builtin, the reception of a signal for which a trap
4240 * has been set will cause the wait builtin to return immediately
4241 * with an exit status greater than 128, immediately after which
4242 * the trap is executed."
4244 * blocking_wait_with_raise_on_sig raises signal handlers
4245 * if it gets no pid (pid < 0). However,
4246 * if child sends us a signal *and immediately exits*,
4247 * blocking_wait_with_raise_on_sig gets pid > 0
4248 * and does not handle pending_sig. Check this case: */
4249 if (pending_sig)
4250 raise_exception(EXSIG);
4254 retval = 127;
4255 do {
4256 if (**argv != '%') {
4257 pid_t pid = number(*argv);
4258 job = curjob;
4259 while (1) {
4260 if (!job)
4261 goto repeat;
4262 if (job->ps[job->nprocs - 1].ps_pid == pid)
4263 break;
4264 job = job->prev_job;
4266 } else {
4267 job = getjob(*argv, 0);
4269 /* loop until process terminated or stopped */
4270 while (job->state == JOBRUNNING)
4271 blocking_wait_with_raise_on_sig();
4272 job->waited = 1;
4273 retval = getstatus(job);
4274 repeat: ;
4275 } while (*++argv);
4277 ret:
4278 return retval;
4281 static struct job *
4282 growjobtab(void)
4284 size_t len;
4285 ptrdiff_t offset;
4286 struct job *jp, *jq;
4288 len = njobs * sizeof(*jp);
4289 jq = jobtab;
4290 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4292 offset = (char *)jp - (char *)jq;
4293 if (offset) {
4294 /* Relocate pointers */
4295 size_t l = len;
4297 jq = (struct job *)((char *)jq + l);
4298 while (l) {
4299 l -= sizeof(*jp);
4300 jq--;
4301 #define joff(p) ((struct job *)((char *)(p) + l))
4302 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4303 if (joff(jp)->ps == &jq->ps0)
4304 jmove(joff(jp)->ps);
4305 if (joff(jp)->prev_job)
4306 jmove(joff(jp)->prev_job);
4308 if (curjob)
4309 jmove(curjob);
4310 #undef joff
4311 #undef jmove
4314 njobs += 4;
4315 jobtab = jp;
4316 jp = (struct job *)((char *)jp + len);
4317 jq = jp + 3;
4318 do {
4319 jq->used = 0;
4320 } while (--jq >= jp);
4321 return jp;
4325 * Return a new job structure.
4326 * Called with interrupts off.
4328 static struct job *
4329 makejob(/*union node *node,*/ int nprocs)
4331 int i;
4332 struct job *jp;
4334 for (i = njobs, jp = jobtab; ; jp++) {
4335 if (--i < 0) {
4336 jp = growjobtab();
4337 break;
4339 if (jp->used == 0)
4340 break;
4341 if (jp->state != JOBDONE || !jp->waited)
4342 continue;
4343 #if JOBS
4344 if (doing_jobctl)
4345 continue;
4346 #endif
4347 freejob(jp);
4348 break;
4350 memset(jp, 0, sizeof(*jp));
4351 #if JOBS
4352 /* jp->jobctl is a bitfield.
4353 * "jp->jobctl |= jobctl" likely to give awful code */
4354 if (doing_jobctl)
4355 jp->jobctl = 1;
4356 #endif
4357 jp->prev_job = curjob;
4358 curjob = jp;
4359 jp->used = 1;
4360 jp->ps = &jp->ps0;
4361 if (nprocs > 1) {
4362 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4364 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4365 jobno(jp)));
4366 return jp;
4369 #if JOBS
4371 * Return a string identifying a command (to be printed by the
4372 * jobs command).
4374 static char *cmdnextc;
4376 static void
4377 cmdputs(const char *s)
4379 static const char vstype[VSTYPE + 1][3] = {
4380 "", "}", "-", "+", "?", "=",
4381 "%", "%%", "#", "##"
4382 IF_ASH_BASH_COMPAT(, ":", "/", "//")
4385 const char *p, *str;
4386 char cc[2];
4387 char *nextc;
4388 unsigned char c;
4389 unsigned char subtype = 0;
4390 int quoted = 0;
4392 cc[1] = '\0';
4393 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4394 p = s;
4395 while ((c = *p++) != '\0') {
4396 str = NULL;
4397 switch (c) {
4398 case CTLESC:
4399 c = *p++;
4400 break;
4401 case CTLVAR:
4402 subtype = *p++;
4403 if ((subtype & VSTYPE) == VSLENGTH)
4404 str = "${#";
4405 else
4406 str = "${";
4407 goto dostr;
4408 case CTLENDVAR:
4409 str = "\"}" + !(quoted & 1);
4410 quoted >>= 1;
4411 subtype = 0;
4412 goto dostr;
4413 case CTLBACKQ:
4414 str = "$(...)";
4415 goto dostr;
4416 #if ENABLE_SH_MATH_SUPPORT
4417 case CTLARI:
4418 str = "$((";
4419 goto dostr;
4420 case CTLENDARI:
4421 str = "))";
4422 goto dostr;
4423 #endif
4424 case CTLQUOTEMARK:
4425 quoted ^= 1;
4426 c = '"';
4427 break;
4428 case '=':
4429 if (subtype == 0)
4430 break;
4431 if ((subtype & VSTYPE) != VSNORMAL)
4432 quoted <<= 1;
4433 str = vstype[subtype & VSTYPE];
4434 if (subtype & VSNUL)
4435 c = ':';
4436 else
4437 goto checkstr;
4438 break;
4439 case '\'':
4440 case '\\':
4441 case '"':
4442 case '$':
4443 /* These can only happen inside quotes */
4444 cc[0] = c;
4445 str = cc;
4446 c = '\\';
4447 break;
4448 default:
4449 break;
4451 USTPUTC(c, nextc);
4452 checkstr:
4453 if (!str)
4454 continue;
4455 dostr:
4456 while ((c = *str++) != '\0') {
4457 USTPUTC(c, nextc);
4459 } /* while *p++ not NUL */
4461 if (quoted & 1) {
4462 USTPUTC('"', nextc);
4464 *nextc = 0;
4465 cmdnextc = nextc;
4468 /* cmdtxt() and cmdlist() call each other */
4469 static void cmdtxt(union node *n);
4471 static void
4472 cmdlist(union node *np, int sep)
4474 for (; np; np = np->narg.next) {
4475 if (!sep)
4476 cmdputs(" ");
4477 cmdtxt(np);
4478 if (sep && np->narg.next)
4479 cmdputs(" ");
4483 static void
4484 cmdtxt(union node *n)
4486 union node *np;
4487 struct nodelist *lp;
4488 const char *p;
4490 if (!n)
4491 return;
4492 switch (n->type) {
4493 default:
4494 #if DEBUG
4495 abort();
4496 #endif
4497 case NPIPE:
4498 lp = n->npipe.cmdlist;
4499 for (;;) {
4500 cmdtxt(lp->n);
4501 lp = lp->next;
4502 if (!lp)
4503 break;
4504 cmdputs(" | ");
4506 break;
4507 case NSEMI:
4508 p = "; ";
4509 goto binop;
4510 case NAND:
4511 p = " && ";
4512 goto binop;
4513 case NOR:
4514 p = " || ";
4515 binop:
4516 cmdtxt(n->nbinary.ch1);
4517 cmdputs(p);
4518 n = n->nbinary.ch2;
4519 goto donode;
4520 case NREDIR:
4521 case NBACKGND:
4522 n = n->nredir.n;
4523 goto donode;
4524 case NNOT:
4525 cmdputs("!");
4526 n = n->nnot.com;
4527 donode:
4528 cmdtxt(n);
4529 break;
4530 case NIF:
4531 cmdputs("if ");
4532 cmdtxt(n->nif.test);
4533 cmdputs("; then ");
4534 if (n->nif.elsepart) {
4535 cmdtxt(n->nif.ifpart);
4536 cmdputs("; else ");
4537 n = n->nif.elsepart;
4538 } else {
4539 n = n->nif.ifpart;
4541 p = "; fi";
4542 goto dotail;
4543 case NSUBSHELL:
4544 cmdputs("(");
4545 n = n->nredir.n;
4546 p = ")";
4547 goto dotail;
4548 case NWHILE:
4549 p = "while ";
4550 goto until;
4551 case NUNTIL:
4552 p = "until ";
4553 until:
4554 cmdputs(p);
4555 cmdtxt(n->nbinary.ch1);
4556 n = n->nbinary.ch2;
4557 p = "; done";
4558 dodo:
4559 cmdputs("; do ");
4560 dotail:
4561 cmdtxt(n);
4562 goto dotail2;
4563 case NFOR:
4564 cmdputs("for ");
4565 cmdputs(n->nfor.var);
4566 cmdputs(" in ");
4567 cmdlist(n->nfor.args, 1);
4568 n = n->nfor.body;
4569 p = "; done";
4570 goto dodo;
4571 case NDEFUN:
4572 cmdputs(n->narg.text);
4573 p = "() { ... }";
4574 goto dotail2;
4575 case NCMD:
4576 cmdlist(n->ncmd.args, 1);
4577 cmdlist(n->ncmd.redirect, 0);
4578 break;
4579 case NARG:
4580 p = n->narg.text;
4581 dotail2:
4582 cmdputs(p);
4583 break;
4584 case NHERE:
4585 case NXHERE:
4586 p = "<<...";
4587 goto dotail2;
4588 case NCASE:
4589 cmdputs("case ");
4590 cmdputs(n->ncase.expr->narg.text);
4591 cmdputs(" in ");
4592 for (np = n->ncase.cases; np; np = np->nclist.next) {
4593 cmdtxt(np->nclist.pattern);
4594 cmdputs(") ");
4595 cmdtxt(np->nclist.body);
4596 cmdputs(";; ");
4598 p = "esac";
4599 goto dotail2;
4600 case NTO:
4601 p = ">";
4602 goto redir;
4603 case NCLOBBER:
4604 p = ">|";
4605 goto redir;
4606 case NAPPEND:
4607 p = ">>";
4608 goto redir;
4609 #if ENABLE_ASH_BASH_COMPAT
4610 case NTO2:
4611 #endif
4612 case NTOFD:
4613 p = ">&";
4614 goto redir;
4615 case NFROM:
4616 p = "<";
4617 goto redir;
4618 case NFROMFD:
4619 p = "<&";
4620 goto redir;
4621 case NFROMTO:
4622 p = "<>";
4623 redir:
4624 cmdputs(utoa(n->nfile.fd));
4625 cmdputs(p);
4626 if (n->type == NTOFD || n->type == NFROMFD) {
4627 cmdputs(utoa(n->ndup.dupfd));
4628 break;
4630 n = n->nfile.fname;
4631 goto donode;
4635 static char *
4636 commandtext(union node *n)
4638 char *name;
4640 STARTSTACKSTR(cmdnextc);
4641 cmdtxt(n);
4642 name = stackblock();
4643 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4644 name, cmdnextc, cmdnextc));
4645 return ckstrdup(name);
4647 #endif /* JOBS */
4650 * Fork off a subshell. If we are doing job control, give the subshell its
4651 * own process group. Jp is a job structure that the job is to be added to.
4652 * N is the command that will be evaluated by the child. Both jp and n may
4653 * be NULL. The mode parameter can be one of the following:
4654 * FORK_FG - Fork off a foreground process.
4655 * FORK_BG - Fork off a background process.
4656 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4657 * process group even if job control is on.
4659 * When job control is turned off, background processes have their standard
4660 * input redirected to /dev/null (except for the second and later processes
4661 * in a pipeline).
4663 * Called with interrupts off.
4666 * Clear traps on a fork.
4668 static void
4669 clear_traps(void)
4671 char **tp;
4673 for (tp = trap; tp < &trap[NSIG]; tp++) {
4674 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4675 INT_OFF;
4676 if (trap_ptr == trap)
4677 free(*tp);
4678 /* else: it "belongs" to trap_ptr vector, don't free */
4679 *tp = NULL;
4680 if ((tp - trap) != 0)
4681 setsignal(tp - trap);
4682 INT_ON;
4685 may_have_traps = 0;
4688 /* Lives far away from here, needed for forkchild */
4689 static void closescript(void);
4691 /* Called after fork(), in child */
4692 static NOINLINE void
4693 forkchild(struct job *jp, union node *n, int mode)
4695 int oldlvl;
4697 TRACE(("Child shell %d\n", getpid()));
4698 oldlvl = shlvl;
4699 shlvl++;
4701 /* man bash: "Non-builtin commands run by bash have signal handlers
4702 * set to the values inherited by the shell from its parent".
4703 * Do we do it correctly? */
4705 closescript();
4707 if (mode == FORK_NOJOB /* is it `xxx` ? */
4708 && n && n->type == NCMD /* is it single cmd? */
4709 /* && n->ncmd.args->type == NARG - always true? */
4710 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
4711 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4712 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4714 TRACE(("Trap hack\n"));
4715 /* Awful hack for `trap` or $(trap).
4717 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4718 * contains an example where "trap" is executed in a subshell:
4720 * save_traps=$(trap)
4721 * ...
4722 * eval "$save_traps"
4724 * Standard does not say that "trap" in subshell shall print
4725 * parent shell's traps. It only says that its output
4726 * must have suitable form, but then, in the above example
4727 * (which is not supposed to be normative), it implies that.
4729 * bash (and probably other shell) does implement it
4730 * (traps are reset to defaults, but "trap" still shows them),
4731 * but as a result, "trap" logic is hopelessly messed up:
4733 * # trap
4734 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4735 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4736 * # true | trap <--- trap is in subshell - no output (ditto)
4737 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4738 * trap -- 'echo Ho' SIGWINCH
4739 * # echo `(trap)` <--- in subshell in subshell - output
4740 * trap -- 'echo Ho' SIGWINCH
4741 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4742 * trap -- 'echo Ho' SIGWINCH
4744 * The rules when to forget and when to not forget traps
4745 * get really complex and nonsensical.
4747 * Our solution: ONLY bare $(trap) or `trap` is special.
4749 /* Save trap handler strings for trap builtin to print */
4750 trap_ptr = xmemdup(trap, sizeof(trap));
4751 /* Fall through into clearing traps */
4753 clear_traps();
4754 #if JOBS
4755 /* do job control only in root shell */
4756 doing_jobctl = 0;
4757 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
4758 pid_t pgrp;
4760 if (jp->nprocs == 0)
4761 pgrp = getpid();
4762 else
4763 pgrp = jp->ps[0].ps_pid;
4764 /* this can fail because we are doing it in the parent also */
4765 setpgid(0, pgrp);
4766 if (mode == FORK_FG)
4767 xtcsetpgrp(ttyfd, pgrp);
4768 setsignal(SIGTSTP);
4769 setsignal(SIGTTOU);
4770 } else
4771 #endif
4772 if (mode == FORK_BG) {
4773 /* man bash: "When job control is not in effect,
4774 * asynchronous commands ignore SIGINT and SIGQUIT" */
4775 ignoresig(SIGINT);
4776 ignoresig(SIGQUIT);
4777 if (jp->nprocs == 0) {
4778 close(0);
4779 if (open(bb_dev_null, O_RDONLY) != 0)
4780 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
4783 if (oldlvl == 0) {
4784 if (iflag) { /* why if iflag only? */
4785 setsignal(SIGINT);
4786 setsignal(SIGTERM);
4788 /* man bash:
4789 * "In all cases, bash ignores SIGQUIT. Non-builtin
4790 * commands run by bash have signal handlers
4791 * set to the values inherited by the shell
4792 * from its parent".
4793 * Take care of the second rule: */
4794 setsignal(SIGQUIT);
4796 #if JOBS
4797 if (n && n->type == NCMD
4798 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
4800 TRACE(("Job hack\n"));
4801 /* "jobs": we do not want to clear job list for it,
4802 * instead we remove only _its_ own_ job from job list.
4803 * This makes "jobs .... | cat" more useful.
4805 freejob(curjob);
4806 return;
4808 #endif
4809 for (jp = curjob; jp; jp = jp->prev_job)
4810 freejob(jp);
4811 jobless = 0;
4814 /* Called after fork(), in parent */
4815 #if !JOBS
4816 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4817 #endif
4818 static void
4819 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4821 TRACE(("In parent shell: child = %d\n", pid));
4822 if (!jp) {
4823 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4824 continue;
4825 jobless++;
4826 return;
4828 #if JOBS
4829 if (mode != FORK_NOJOB && jp->jobctl) {
4830 int pgrp;
4832 if (jp->nprocs == 0)
4833 pgrp = pid;
4834 else
4835 pgrp = jp->ps[0].ps_pid;
4836 /* This can fail because we are doing it in the child also */
4837 setpgid(pid, pgrp);
4839 #endif
4840 if (mode == FORK_BG) {
4841 backgndpid = pid; /* set $! */
4842 set_curjob(jp, CUR_RUNNING);
4844 if (jp) {
4845 struct procstat *ps = &jp->ps[jp->nprocs++];
4846 ps->ps_pid = pid;
4847 ps->ps_status = -1;
4848 ps->ps_cmd = nullstr;
4849 #if JOBS
4850 if (doing_jobctl && n)
4851 ps->ps_cmd = commandtext(n);
4852 #endif
4856 static int
4857 forkshell(struct job *jp, union node *n, int mode)
4859 int pid;
4861 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4862 pid = fork();
4863 if (pid < 0) {
4864 TRACE(("Fork failed, errno=%d", errno));
4865 if (jp)
4866 freejob(jp);
4867 ash_msg_and_raise_error("can't fork");
4869 if (pid == 0) {
4870 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
4871 forkchild(jp, n, mode);
4872 } else {
4873 forkparent(jp, n, mode, pid);
4875 return pid;
4879 * Wait for job to finish.
4881 * Under job control we have the problem that while a child process
4882 * is running interrupts generated by the user are sent to the child
4883 * but not to the shell. This means that an infinite loop started by
4884 * an interactive user may be hard to kill. With job control turned off,
4885 * an interactive user may place an interactive program inside a loop.
4886 * If the interactive program catches interrupts, the user doesn't want
4887 * these interrupts to also abort the loop. The approach we take here
4888 * is to have the shell ignore interrupt signals while waiting for a
4889 * foreground process to terminate, and then send itself an interrupt
4890 * signal if the child process was terminated by an interrupt signal.
4891 * Unfortunately, some programs want to do a bit of cleanup and then
4892 * exit on interrupt; unless these processes terminate themselves by
4893 * sending a signal to themselves (instead of calling exit) they will
4894 * confuse this approach.
4896 * Called with interrupts off.
4898 static int
4899 waitforjob(struct job *jp)
4901 int st;
4903 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4905 INT_OFF;
4906 while (jp->state == JOBRUNNING) {
4907 /* In non-interactive shells, we _can_ get
4908 * a keyboard signal here and be EINTRed,
4909 * but we just loop back, waiting for command to complete.
4911 * man bash:
4912 * "If bash is waiting for a command to complete and receives
4913 * a signal for which a trap has been set, the trap
4914 * will not be executed until the command completes."
4916 * Reality is that even if trap is not set, bash
4917 * will not act on the signal until command completes.
4918 * Try this. sleep5intoff.c:
4919 * #include <signal.h>
4920 * #include <unistd.h>
4921 * int main() {
4922 * sigset_t set;
4923 * sigemptyset(&set);
4924 * sigaddset(&set, SIGINT);
4925 * sigaddset(&set, SIGQUIT);
4926 * sigprocmask(SIG_BLOCK, &set, NULL);
4927 * sleep(5);
4928 * return 0;
4930 * $ bash -c './sleep5intoff; echo hi'
4931 * ^C^C^C^C <--- pressing ^C once a second
4932 * $ _
4933 * $ bash -c './sleep5intoff; echo hi'
4934 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4935 * $ _
4937 dowait(DOWAIT_BLOCK, jp);
4939 INT_ON;
4941 st = getstatus(jp);
4942 #if JOBS
4943 if (jp->jobctl) {
4944 xtcsetpgrp(ttyfd, rootpid);
4946 * This is truly gross.
4947 * If we're doing job control, then we did a TIOCSPGRP which
4948 * caused us (the shell) to no longer be in the controlling
4949 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4950 * intuit from the subprocess exit status whether a SIGINT
4951 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4953 if (jp->sigint) /* TODO: do the same with all signals */
4954 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4956 if (jp->state == JOBDONE)
4957 #endif
4958 freejob(jp);
4959 return st;
4963 * return 1 if there are stopped jobs, otherwise 0
4965 static int
4966 stoppedjobs(void)
4968 struct job *jp;
4969 int retval;
4971 retval = 0;
4972 if (job_warning)
4973 goto out;
4974 jp = curjob;
4975 if (jp && jp->state == JOBSTOPPED) {
4976 out2str("You have stopped jobs.\n");
4977 job_warning = 2;
4978 retval++;
4980 out:
4981 return retval;
4985 /* ============ redir.c
4987 * Code for dealing with input/output redirection.
4990 #undef EMPTY
4991 #undef CLOSED
4992 #define EMPTY -2 /* marks an unused slot in redirtab */
4993 #define CLOSED -3 /* marks a slot of previously-closed fd */
4996 * Open a file in noclobber mode.
4997 * The code was copied from bash.
4999 static int
5000 noclobberopen(const char *fname)
5002 int r, fd;
5003 struct stat finfo, finfo2;
5006 * If the file exists and is a regular file, return an error
5007 * immediately.
5009 r = stat(fname, &finfo);
5010 if (r == 0 && S_ISREG(finfo.st_mode)) {
5011 errno = EEXIST;
5012 return -1;
5016 * If the file was not present (r != 0), make sure we open it
5017 * exclusively so that if it is created before we open it, our open
5018 * will fail. Make sure that we do not truncate an existing file.
5019 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5020 * file was not a regular file, we leave O_EXCL off.
5022 if (r != 0)
5023 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5024 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5026 /* If the open failed, return the file descriptor right away. */
5027 if (fd < 0)
5028 return fd;
5031 * OK, the open succeeded, but the file may have been changed from a
5032 * non-regular file to a regular file between the stat and the open.
5033 * We are assuming that the O_EXCL open handles the case where FILENAME
5034 * did not exist and is symlinked to an existing file between the stat
5035 * and open.
5039 * If we can open it and fstat the file descriptor, and neither check
5040 * revealed that it was a regular file, and the file has not been
5041 * replaced, return the file descriptor.
5043 if (fstat(fd, &finfo2) == 0
5044 && !S_ISREG(finfo2.st_mode)
5045 && finfo.st_dev == finfo2.st_dev
5046 && finfo.st_ino == finfo2.st_ino
5048 return fd;
5051 /* The file has been replaced. badness. */
5052 close(fd);
5053 errno = EEXIST;
5054 return -1;
5058 * Handle here documents. Normally we fork off a process to write the
5059 * data to a pipe. If the document is short, we can stuff the data in
5060 * the pipe without forking.
5062 /* openhere needs this forward reference */
5063 static void expandhere(union node *arg, int fd);
5064 static int
5065 openhere(union node *redir)
5067 int pip[2];
5068 size_t len = 0;
5070 if (pipe(pip) < 0)
5071 ash_msg_and_raise_error("pipe call failed");
5072 if (redir->type == NHERE) {
5073 len = strlen(redir->nhere.doc->narg.text);
5074 if (len <= PIPE_BUF) {
5075 full_write(pip[1], redir->nhere.doc->narg.text, len);
5076 goto out;
5079 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5080 /* child */
5081 close(pip[0]);
5082 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5083 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5084 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5085 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5086 signal(SIGPIPE, SIG_DFL);
5087 if (redir->type == NHERE)
5088 full_write(pip[1], redir->nhere.doc->narg.text, len);
5089 else /* NXHERE */
5090 expandhere(redir->nhere.doc, pip[1]);
5091 _exit(EXIT_SUCCESS);
5093 out:
5094 close(pip[1]);
5095 return pip[0];
5098 static int
5099 openredirect(union node *redir)
5101 char *fname;
5102 int f;
5104 fname = redir->nfile.expfname;
5105 switch (redir->nfile.type) {
5106 case NFROM:
5107 f = open(fname, O_RDONLY);
5108 if (f < 0)
5109 goto eopen;
5110 break;
5111 case NFROMTO:
5112 f = open(fname, O_RDWR|O_CREAT, 0666);
5113 if (f < 0)
5114 goto ecreate;
5115 break;
5116 case NTO:
5117 #if ENABLE_ASH_BASH_COMPAT
5118 case NTO2:
5119 #endif
5120 /* Take care of noclobber mode. */
5121 if (Cflag) {
5122 f = noclobberopen(fname);
5123 if (f < 0)
5124 goto ecreate;
5125 break;
5127 /* FALLTHROUGH */
5128 case NCLOBBER:
5129 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5130 if (f < 0)
5131 goto ecreate;
5132 break;
5133 case NAPPEND:
5134 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5135 if (f < 0)
5136 goto ecreate;
5137 break;
5138 default:
5139 #if DEBUG
5140 abort();
5141 #endif
5142 /* Fall through to eliminate warning. */
5143 /* Our single caller does this itself */
5144 // case NTOFD:
5145 // case NFROMFD:
5146 // f = -1;
5147 // break;
5148 case NHERE:
5149 case NXHERE:
5150 f = openhere(redir);
5151 break;
5154 return f;
5155 ecreate:
5156 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5157 eopen:
5158 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5162 * Copy a file descriptor to be >= to. Returns -1
5163 * if the source file descriptor is closed, EMPTY if there are no unused
5164 * file descriptors left.
5166 /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5167 * old code was doing close(to) prior to copyfd() to achieve the same */
5168 enum {
5169 COPYFD_EXACT = (int)~(INT_MAX),
5170 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5172 static int
5173 copyfd(int from, int to)
5175 int newfd;
5177 if (to & COPYFD_EXACT) {
5178 to &= ~COPYFD_EXACT;
5179 /*if (from != to)*/
5180 newfd = dup2(from, to);
5181 } else {
5182 newfd = fcntl(from, F_DUPFD, to);
5184 if (newfd < 0) {
5185 if (errno == EMFILE)
5186 return EMPTY;
5187 /* Happens when source fd is not open: try "echo >&99" */
5188 ash_msg_and_raise_error("%d: %m", from);
5190 return newfd;
5193 /* Struct def and variable are moved down to the first usage site */
5194 struct two_fd_t {
5195 int orig, copy;
5197 struct redirtab {
5198 struct redirtab *next;
5199 int nullredirs;
5200 int pair_count;
5201 struct two_fd_t two_fd[];
5203 #define redirlist (G_var.redirlist)
5205 static int need_to_remember(struct redirtab *rp, int fd)
5207 int i;
5209 if (!rp) /* remembering was not requested */
5210 return 0;
5212 for (i = 0; i < rp->pair_count; i++) {
5213 if (rp->two_fd[i].orig == fd) {
5214 /* already remembered */
5215 return 0;
5218 return 1;
5221 /* "hidden" fd is a fd used to read scripts, or a copy of such */
5222 static int is_hidden_fd(struct redirtab *rp, int fd)
5224 int i;
5225 struct parsefile *pf;
5227 if (fd == -1)
5228 return 0;
5229 /* Check open scripts' fds */
5230 pf = g_parsefile;
5231 while (pf) {
5232 /* We skip pf_fd == 0 case because of the following case:
5233 * $ ash # running ash interactively
5234 * $ . ./script.sh
5235 * and in script.sh: "exec 9>&0".
5236 * Even though top-level pf_fd _is_ 0,
5237 * it's still ok to use it: "read" builtin uses it,
5238 * why should we cripple "exec" builtin?
5240 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
5241 return 1;
5243 pf = pf->prev;
5246 if (!rp)
5247 return 0;
5248 /* Check saved fds of redirects */
5249 fd |= COPYFD_RESTORE;
5250 for (i = 0; i < rp->pair_count; i++) {
5251 if (rp->two_fd[i].copy == fd) {
5252 return 1;
5255 return 0;
5259 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5260 * old file descriptors are stashed away so that the redirection can be
5261 * undone by calling popredir.
5263 /* flags passed to redirect */
5264 #define REDIR_PUSH 01 /* save previous values of file descriptors */
5265 #define REDIR_SAVEFD2 03 /* set preverrout */
5266 static void
5267 redirect(union node *redir, int flags)
5269 struct redirtab *sv;
5270 int sv_pos;
5271 int i;
5272 int fd;
5273 int newfd;
5274 int copied_fd2 = -1;
5276 g_nullredirs++;
5277 if (!redir) {
5278 return;
5281 sv = NULL;
5282 sv_pos = 0;
5283 INT_OFF;
5284 if (flags & REDIR_PUSH) {
5285 union node *tmp = redir;
5286 do {
5287 sv_pos++;
5288 #if ENABLE_ASH_BASH_COMPAT
5289 if (tmp->nfile.type == NTO2)
5290 sv_pos++;
5291 #endif
5292 tmp = tmp->nfile.next;
5293 } while (tmp);
5294 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
5295 sv->next = redirlist;
5296 sv->pair_count = sv_pos;
5297 redirlist = sv;
5298 sv->nullredirs = g_nullredirs - 1;
5299 g_nullredirs = 0;
5300 while (sv_pos > 0) {
5301 sv_pos--;
5302 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5306 do {
5307 int right_fd = -1;
5308 fd = redir->nfile.fd;
5309 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5310 right_fd = redir->ndup.dupfd;
5311 //bb_error_msg("doing %d > %d", fd, right_fd);
5312 /* redirect from/to same file descriptor? */
5313 if (right_fd == fd)
5314 continue;
5315 /* "echo >&10" and 10 is a fd opened to a sh script? */
5316 if (is_hidden_fd(sv, right_fd)) {
5317 errno = EBADF; /* as if it is closed */
5318 ash_msg_and_raise_error("%d: %m", right_fd);
5320 newfd = -1;
5321 } else {
5322 newfd = openredirect(redir); /* always >= 0 */
5323 if (fd == newfd) {
5324 /* Descriptor wasn't open before redirect.
5325 * Mark it for close in the future */
5326 if (need_to_remember(sv, fd)) {
5327 goto remember_to_close;
5329 continue;
5332 #if ENABLE_ASH_BASH_COMPAT
5333 redirect_more:
5334 #endif
5335 if (need_to_remember(sv, fd)) {
5336 /* Copy old descriptor */
5337 /* Careful to not accidentally "save"
5338 * to the same fd as right side fd in N>&M */
5339 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5340 i = fcntl(fd, F_DUPFD, minfd);
5341 /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5342 * are closed in popredir() in the child, preventing them from leaking
5343 * into child. (popredir() also cleans up the mess in case of failures)
5345 if (i == -1) {
5346 i = errno;
5347 if (i != EBADF) {
5348 /* Strange error (e.g. "too many files" EMFILE?) */
5349 if (newfd >= 0)
5350 close(newfd);
5351 errno = i;
5352 ash_msg_and_raise_error("%d: %m", fd);
5353 /* NOTREACHED */
5355 /* EBADF: it is not open - good, remember to close it */
5356 remember_to_close:
5357 i = CLOSED;
5358 } else { /* fd is open, save its copy */
5359 /* "exec fd>&-" should not close fds
5360 * which point to script file(s).
5361 * Force them to be restored afterwards */
5362 if (is_hidden_fd(sv, fd))
5363 i |= COPYFD_RESTORE;
5365 if (fd == 2)
5366 copied_fd2 = i;
5367 sv->two_fd[sv_pos].orig = fd;
5368 sv->two_fd[sv_pos].copy = i;
5369 sv_pos++;
5371 if (newfd < 0) {
5372 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5373 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5374 /* Don't want to trigger debugging */
5375 if (fd != -1)
5376 close(fd);
5377 } else {
5378 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
5380 } else if (fd != newfd) { /* move newfd to fd */
5381 copyfd(newfd, fd | COPYFD_EXACT);
5382 #if ENABLE_ASH_BASH_COMPAT
5383 if (!(redir->nfile.type == NTO2 && fd == 2))
5384 #endif
5385 close(newfd);
5387 #if ENABLE_ASH_BASH_COMPAT
5388 if (redir->nfile.type == NTO2 && fd == 1) {
5389 /* We already redirected it to fd 1, now copy it to 2 */
5390 newfd = 1;
5391 fd = 2;
5392 goto redirect_more;
5394 #endif
5395 } while ((redir = redir->nfile.next) != NULL);
5397 INT_ON;
5398 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5399 preverrout_fd = copied_fd2;
5403 * Undo the effects of the last redirection.
5405 static void
5406 popredir(int drop, int restore)
5408 struct redirtab *rp;
5409 int i;
5411 if (--g_nullredirs >= 0 || redirlist == NULL)
5412 return;
5413 INT_OFF;
5414 rp = redirlist;
5415 for (i = 0; i < rp->pair_count; i++) {
5416 int fd = rp->two_fd[i].orig;
5417 int copy = rp->two_fd[i].copy;
5418 if (copy == CLOSED) {
5419 if (!drop)
5420 close(fd);
5421 continue;
5423 if (copy != EMPTY) {
5424 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5425 copy &= ~COPYFD_RESTORE;
5426 /*close(fd);*/
5427 copyfd(copy, fd | COPYFD_EXACT);
5429 close(copy & ~COPYFD_RESTORE);
5432 redirlist = rp->next;
5433 g_nullredirs = rp->nullredirs;
5434 free(rp);
5435 INT_ON;
5439 * Undo all redirections. Called on error or interrupt.
5443 * Discard all saved file descriptors.
5445 static void
5446 clearredir(int drop)
5448 for (;;) {
5449 g_nullredirs = 0;
5450 if (!redirlist)
5451 break;
5452 popredir(drop, /*restore:*/ 0);
5456 static int
5457 redirectsafe(union node *redir, int flags)
5459 int err;
5460 volatile int saveint;
5461 struct jmploc *volatile savehandler = exception_handler;
5462 struct jmploc jmploc;
5464 SAVE_INT(saveint);
5465 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5466 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5467 if (!err) {
5468 exception_handler = &jmploc;
5469 redirect(redir, flags);
5471 exception_handler = savehandler;
5472 if (err && exception_type != EXERROR)
5473 longjmp(exception_handler->loc, 1);
5474 RESTORE_INT(saveint);
5475 return err;
5479 /* ============ Routines to expand arguments to commands
5481 * We have to deal with backquotes, shell variables, and file metacharacters.
5484 #if ENABLE_SH_MATH_SUPPORT
5485 static arith_t
5486 ash_arith(const char *s)
5488 arith_state_t math_state;
5489 arith_t result;
5491 math_state.lookupvar = lookupvar;
5492 math_state.setvar = setvar0;
5493 //math_state.endofname = endofname;
5495 INT_OFF;
5496 result = arith(&math_state, s);
5497 if (math_state.errmsg)
5498 ash_msg_and_raise_error(math_state.errmsg);
5499 INT_ON;
5501 return result;
5503 #endif
5506 * expandarg flags
5508 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5509 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5510 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5511 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5512 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5513 #define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
5514 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5515 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5516 #define EXP_QUOTED 0x100 /* expand word in double quotes */
5518 * rmescape() flags
5520 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5521 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5522 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5523 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5524 #define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
5526 /* Add CTLESC when necessary. */
5527 #define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
5528 /* Do not skip NUL characters. */
5529 #define QUOTES_KEEPNUL EXP_TILDE
5532 * Structure specifying which parts of the string should be searched
5533 * for IFS characters.
5535 struct ifsregion {
5536 struct ifsregion *next; /* next region in list */
5537 int begoff; /* offset of start of region */
5538 int endoff; /* offset of end of region */
5539 int nulonly; /* search for nul bytes only */
5542 struct arglist {
5543 struct strlist *list;
5544 struct strlist **lastp;
5547 /* output of current string */
5548 static char *expdest;
5549 /* list of back quote expressions */
5550 static struct nodelist *argbackq;
5551 /* first struct in list of ifs regions */
5552 static struct ifsregion ifsfirst;
5553 /* last struct in list */
5554 static struct ifsregion *ifslastp;
5555 /* holds expanded arg list */
5556 static struct arglist exparg;
5559 * Our own itoa().
5561 #if !ENABLE_SH_MATH_SUPPORT
5562 /* cvtnum() is used even if math support is off (to prepare $? values and such) */
5563 typedef long arith_t;
5564 # define ARITH_FMT "%ld"
5565 #endif
5566 static int
5567 cvtnum(arith_t num)
5569 int len;
5571 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5572 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
5573 STADJUST(len, expdest);
5574 return len;
5577 static size_t
5578 esclen(const char *start, const char *p)
5580 size_t esc = 0;
5582 while (p > start && (unsigned char)*--p == CTLESC) {
5583 esc++;
5585 return esc;
5589 * Remove any CTLESC characters from a string.
5591 static char *
5592 rmescapes(char *str, int flag)
5594 static const char qchars[] ALIGN1 = {
5595 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
5597 char *p, *q, *r;
5598 unsigned inquotes;
5599 unsigned protect_against_glob;
5600 unsigned globbing;
5601 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
5603 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
5604 if (!p)
5605 return str;
5607 q = p;
5608 r = str;
5609 if (flag & RMESCAPE_ALLOC) {
5610 size_t len = p - str;
5611 size_t fulllen = len + strlen(p) + 1;
5613 if (flag & RMESCAPE_GROW) {
5614 int strloc = str - (char *)stackblock();
5615 r = makestrspace(fulllen, expdest);
5616 /* p and str may be invalidated by makestrspace */
5617 str = (char *)stackblock() + strloc;
5618 p = str + len;
5619 } else if (flag & RMESCAPE_HEAP) {
5620 r = ckmalloc(fulllen);
5621 } else {
5622 r = stalloc(fulllen);
5624 q = r;
5625 if (len > 0) {
5626 q = (char *)memcpy(q, str, len) + len;
5630 inquotes = 0;
5631 globbing = flag & RMESCAPE_GLOB;
5632 protect_against_glob = globbing;
5633 while (*p) {
5634 if ((unsigned char)*p == CTLQUOTEMARK) {
5635 // Note: both inquotes and protect_against_glob only affect whether
5636 // CTLESC,<ch> gets converted to <ch> or to \<ch>
5637 inquotes = ~inquotes;
5638 p++;
5639 protect_against_glob = globbing;
5640 continue;
5642 if ((unsigned char)*p == CTLESC) {
5643 p++;
5644 if (protect_against_glob) {
5645 *q++ = '\\';
5647 } else if (*p == '\\' && !inquotes) {
5648 /* naked back slash */
5649 protect_against_glob = 0;
5650 goto copy;
5652 #if ENABLE_ASH_BASH_COMPAT
5653 else if (*p == '/' && slash) {
5654 /* stop handling globbing and mark location of slash */
5655 globbing = slash = 0;
5656 *p = CTLESC;
5658 #endif
5659 protect_against_glob = globbing;
5660 copy:
5661 *q++ = *p++;
5663 *q = '\0';
5664 if (flag & RMESCAPE_GROW) {
5665 expdest = r;
5666 STADJUST(q - r + 1, expdest);
5668 return r;
5670 #define pmatch(a, b) !fnmatch((a), (b), 0)
5673 * Prepare a pattern for a expmeta (internal glob(3)) call.
5675 * Returns an stalloced string.
5677 static char *
5678 preglob(const char *pattern, int flag)
5680 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
5684 * Put a string on the stack.
5686 static void
5687 memtodest(const char *p, size_t len, int syntax, int quotes)
5689 char *q;
5691 if (!len)
5692 return;
5694 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5696 do {
5697 unsigned char c = *p++;
5698 if (c) {
5699 int n = SIT(c, syntax);
5700 if ((quotes & QUOTES_ESC) &&
5701 ((n == CCTL) ||
5702 (((quotes & EXP_FULL) || syntax != BASESYNTAX) &&
5703 n == CBACK)))
5704 USTPUTC(CTLESC, q);
5705 } else if (!(quotes & QUOTES_KEEPNUL))
5706 continue;
5707 USTPUTC(c, q);
5708 } while (--len);
5710 expdest = q;
5713 static size_t
5714 strtodest(const char *p, int syntax, int quotes)
5716 size_t len = strlen(p);
5717 memtodest(p, len, syntax, quotes);
5718 return len;
5722 * Record the fact that we have to scan this region of the
5723 * string for IFS characters.
5725 static void
5726 recordregion(int start, int end, int nulonly)
5728 struct ifsregion *ifsp;
5730 if (ifslastp == NULL) {
5731 ifsp = &ifsfirst;
5732 } else {
5733 INT_OFF;
5734 ifsp = ckzalloc(sizeof(*ifsp));
5735 /*ifsp->next = NULL; - ckzalloc did it */
5736 ifslastp->next = ifsp;
5737 INT_ON;
5739 ifslastp = ifsp;
5740 ifslastp->begoff = start;
5741 ifslastp->endoff = end;
5742 ifslastp->nulonly = nulonly;
5745 static void
5746 removerecordregions(int endoff)
5748 if (ifslastp == NULL)
5749 return;
5751 if (ifsfirst.endoff > endoff) {
5752 while (ifsfirst.next) {
5753 struct ifsregion *ifsp;
5754 INT_OFF;
5755 ifsp = ifsfirst.next->next;
5756 free(ifsfirst.next);
5757 ifsfirst.next = ifsp;
5758 INT_ON;
5760 if (ifsfirst.begoff > endoff) {
5761 ifslastp = NULL;
5762 } else {
5763 ifslastp = &ifsfirst;
5764 ifsfirst.endoff = endoff;
5766 return;
5769 ifslastp = &ifsfirst;
5770 while (ifslastp->next && ifslastp->next->begoff < endoff)
5771 ifslastp = ifslastp->next;
5772 while (ifslastp->next) {
5773 struct ifsregion *ifsp;
5774 INT_OFF;
5775 ifsp = ifslastp->next->next;
5776 free(ifslastp->next);
5777 ifslastp->next = ifsp;
5778 INT_ON;
5780 if (ifslastp->endoff > endoff)
5781 ifslastp->endoff = endoff;
5784 static char *
5785 exptilde(char *startp, char *p, int flags)
5787 unsigned char c;
5788 char *name;
5789 struct passwd *pw;
5790 const char *home;
5791 int quotes = flags & QUOTES_ESC;
5793 name = p + 1;
5795 while ((c = *++p) != '\0') {
5796 switch (c) {
5797 case CTLESC:
5798 return startp;
5799 case CTLQUOTEMARK:
5800 return startp;
5801 case ':':
5802 if (flags & EXP_VARTILDE)
5803 goto done;
5804 break;
5805 case '/':
5806 case CTLENDVAR:
5807 goto done;
5810 done:
5811 *p = '\0';
5812 if (*name == '\0') {
5813 home = lookupvar("HOME");
5814 } else {
5815 pw = getpwnam(name);
5816 if (pw == NULL)
5817 goto lose;
5818 home = pw->pw_dir;
5820 if (!home || !*home)
5821 goto lose;
5822 *p = c;
5823 strtodest(home, SQSYNTAX, quotes);
5824 return p;
5825 lose:
5826 *p = c;
5827 return startp;
5831 * Execute a command inside back quotes. If it's a builtin command, we
5832 * want to save its output in a block obtained from malloc. Otherwise
5833 * we fork off a subprocess and get the output of the command via a pipe.
5834 * Should be called with interrupts off.
5836 struct backcmd { /* result of evalbackcmd */
5837 int fd; /* file descriptor to read from */
5838 int nleft; /* number of chars in buffer */
5839 char *buf; /* buffer */
5840 struct job *jp; /* job structure for command */
5843 /* These forward decls are needed to use "eval" code for backticks handling: */
5844 static uint8_t back_exitstatus; /* exit status of backquoted command */
5845 #define EV_EXIT 01 /* exit after evaluating tree */
5846 static void evaltree(union node *, int);
5848 static void FAST_FUNC
5849 evalbackcmd(union node *n, struct backcmd *result)
5851 int saveherefd;
5853 result->fd = -1;
5854 result->buf = NULL;
5855 result->nleft = 0;
5856 result->jp = NULL;
5857 if (n == NULL)
5858 goto out;
5860 saveherefd = herefd;
5861 herefd = -1;
5864 int pip[2];
5865 struct job *jp;
5867 if (pipe(pip) < 0)
5868 ash_msg_and_raise_error("pipe call failed");
5869 jp = makejob(/*n,*/ 1);
5870 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5871 FORCE_INT_ON;
5872 close(pip[0]);
5873 if (pip[1] != 1) {
5874 /*close(1);*/
5875 copyfd(pip[1], 1 | COPYFD_EXACT);
5876 close(pip[1]);
5878 eflag = 0;
5879 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5880 /* NOTREACHED */
5882 close(pip[1]);
5883 result->fd = pip[0];
5884 result->jp = jp;
5886 herefd = saveherefd;
5887 out:
5888 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5889 result->fd, result->buf, result->nleft, result->jp));
5893 * Expand stuff in backwards quotes.
5895 static void
5896 expbackq(union node *cmd, int flag)
5898 struct backcmd in;
5899 int i;
5900 char buf[128];
5901 char *p;
5902 char *dest;
5903 int startloc;
5904 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
5905 struct stackmark smark;
5907 INT_OFF;
5908 setstackmark(&smark);
5909 dest = expdest;
5910 startloc = dest - (char *)stackblock();
5911 grabstackstr(dest);
5912 evalbackcmd(cmd, &in);
5913 popstackmark(&smark);
5915 p = in.buf;
5916 i = in.nleft;
5917 if (i == 0)
5918 goto read;
5919 for (;;) {
5920 memtodest(p, i, syntax, flag & QUOTES_ESC);
5921 read:
5922 if (in.fd < 0)
5923 break;
5924 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
5925 TRACE(("expbackq: read returns %d\n", i));
5926 if (i <= 0)
5927 break;
5928 p = buf;
5931 free(in.buf);
5932 if (in.fd >= 0) {
5933 close(in.fd);
5934 back_exitstatus = waitforjob(in.jp);
5936 INT_ON;
5938 /* Eat all trailing newlines */
5939 dest = expdest;
5940 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5941 STUNPUTC(dest);
5942 expdest = dest;
5944 if (!(flag & EXP_QUOTED))
5945 recordregion(startloc, dest - (char *)stackblock(), 0);
5946 TRACE(("evalbackq: size:%d:'%.*s'\n",
5947 (int)((dest - (char *)stackblock()) - startloc),
5948 (int)((dest - (char *)stackblock()) - startloc),
5949 stackblock() + startloc));
5952 #if ENABLE_SH_MATH_SUPPORT
5954 * Expand arithmetic expression. Backup to start of expression,
5955 * evaluate, place result in (backed up) result, adjust string position.
5957 static void
5958 expari(int flag)
5960 char *p, *start;
5961 int begoff;
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 expdest = p;
6001 if (flag & QUOTES_ESC)
6002 rmescapes(p + 1, 0);
6004 len = cvtnum(ash_arith(p + 1));
6006 if (!(flag & EXP_QUOTED))
6007 recordregion(begoff, begoff + len, 0);
6009 #endif
6011 /* argstr needs it */
6012 static char *evalvar(char *p, int flags, struct strlist *var_str_list);
6015 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6016 * characters to allow for further processing. Otherwise treat
6017 * $@ like $* since no splitting will be performed.
6019 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6020 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6021 * for correct expansion of "B=$A" word.
6023 static void
6024 argstr(char *p, int flags, struct strlist *var_str_list)
6026 static const char spclchars[] ALIGN1 = {
6027 '=',
6028 ':',
6029 CTLQUOTEMARK,
6030 CTLENDVAR,
6031 CTLESC,
6032 CTLVAR,
6033 CTLBACKQ,
6034 #if ENABLE_SH_MATH_SUPPORT
6035 CTLENDARI,
6036 #endif
6037 '\0'
6039 const char *reject = spclchars;
6040 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
6041 int inquotes;
6042 size_t length;
6043 int startloc;
6045 if (!(flags & EXP_VARTILDE)) {
6046 reject += 2;
6047 } else if (flags & EXP_VARTILDE2) {
6048 reject++;
6050 inquotes = 0;
6051 length = 0;
6052 if (flags & EXP_TILDE) {
6053 char *q;
6055 flags &= ~EXP_TILDE;
6056 tilde:
6057 q = p;
6058 if (*q == '~')
6059 p = exptilde(p, q, flags);
6061 start:
6062 startloc = expdest - (char *)stackblock();
6063 for (;;) {
6064 unsigned char c;
6066 length += strcspn(p + length, reject);
6067 c = p[length];
6068 if (c) {
6069 if (!(c & 0x80)
6070 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
6072 /* c == '=' || c == ':' || c == CTLENDARI */
6073 length++;
6076 if (length > 0) {
6077 int newloc;
6078 expdest = stack_nputstr(p, length, expdest);
6079 newloc = expdest - (char *)stackblock();
6080 if (breakall && !inquotes && newloc > startloc) {
6081 recordregion(startloc, newloc, 0);
6083 startloc = newloc;
6085 p += length + 1;
6086 length = 0;
6088 switch (c) {
6089 case '\0':
6090 goto breakloop;
6091 case '=':
6092 if (flags & EXP_VARTILDE2) {
6093 p--;
6094 continue;
6096 flags |= EXP_VARTILDE2;
6097 reject++;
6098 /* fall through */
6099 case ':':
6101 * sort of a hack - expand tildes in variable
6102 * assignments (after the first '=' and after ':'s).
6104 if (*--p == '~') {
6105 goto tilde;
6107 continue;
6110 switch (c) {
6111 case CTLENDVAR: /* ??? */
6112 goto breakloop;
6113 case CTLQUOTEMARK:
6114 inquotes ^= EXP_QUOTED;
6115 /* "$@" syntax adherence hack */
6116 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6117 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
6118 goto start;
6120 addquote:
6121 if (flags & QUOTES_ESC) {
6122 p--;
6123 length++;
6124 startloc++;
6126 break;
6127 case CTLESC:
6128 startloc++;
6129 length++;
6132 * Quoted parameter expansion pattern: remove quote
6133 * unless inside inner quotes or we have a literal
6134 * backslash.
6136 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6137 EXP_QPAT && *p != '\\')
6138 break;
6140 goto addquote;
6141 case CTLVAR:
6142 TRACE(("argstr: evalvar('%s')\n", p));
6143 p = evalvar(p, flags | inquotes, var_str_list);
6144 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6145 goto start;
6146 case CTLBACKQ:
6147 expbackq(argbackq->n, flags | inquotes);
6148 argbackq = argbackq->next;
6149 goto start;
6150 #if ENABLE_SH_MATH_SUPPORT
6151 case CTLENDARI:
6152 p--;
6153 expari(flags | inquotes);
6154 goto start;
6155 #endif
6158 breakloop: ;
6161 static char *
6162 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6163 char *pattern, int quotes, int zero)
6165 char *loc, *loc2;
6166 char c;
6168 loc = startp;
6169 loc2 = rmesc;
6170 do {
6171 int match;
6172 const char *s = loc2;
6174 c = *loc2;
6175 if (zero) {
6176 *loc2 = '\0';
6177 s = rmesc;
6179 match = pmatch(pattern, s);
6181 *loc2 = c;
6182 if (match)
6183 return loc;
6184 if (quotes && (unsigned char)*loc == CTLESC)
6185 loc++;
6186 loc++;
6187 loc2++;
6188 } while (c);
6189 return NULL;
6192 static char *
6193 scanright(char *startp, char *rmesc, char *rmescend,
6194 char *pattern, int quotes, int match_at_start)
6196 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6197 int try2optimize = match_at_start;
6198 #endif
6199 int esc = 0;
6200 char *loc;
6201 char *loc2;
6203 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6204 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6205 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6206 * Logic:
6207 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6208 * and on each iteration they go back two/one char until they reach the beginning.
6209 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6211 /* TODO: document in what other circumstances we are called. */
6213 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6214 int match;
6215 char c = *loc2;
6216 const char *s = loc2;
6217 if (match_at_start) {
6218 *loc2 = '\0';
6219 s = rmesc;
6221 match = pmatch(pattern, s);
6222 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
6223 *loc2 = c;
6224 if (match)
6225 return loc;
6226 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6227 if (try2optimize) {
6228 /* Maybe we can optimize this:
6229 * if pattern ends with unescaped *, we can avoid checking
6230 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6231 * it wont match truncated "raw_value_of_" strings too.
6233 unsigned plen = strlen(pattern);
6234 /* Does it end with "*"? */
6235 if (plen != 0 && pattern[--plen] == '*') {
6236 /* "xxxx*" is not escaped */
6237 /* "xxx\*" is escaped */
6238 /* "xx\\*" is not escaped */
6239 /* "x\\\*" is escaped */
6240 int slashes = 0;
6241 while (plen != 0 && pattern[--plen] == '\\')
6242 slashes++;
6243 if (!(slashes & 1))
6244 break; /* ends with unescaped "*" */
6246 try2optimize = 0;
6248 #endif
6249 loc--;
6250 if (quotes) {
6251 if (--esc < 0) {
6252 esc = esclen(startp, loc);
6254 if (esc % 2) {
6255 esc--;
6256 loc--;
6260 return NULL;
6263 static void varunset(const char *, const char *, const char *, int) NORETURN;
6264 static void
6265 varunset(const char *end, const char *var, const char *umsg, int varflags)
6267 const char *msg;
6268 const char *tail;
6270 tail = nullstr;
6271 msg = "parameter not set";
6272 if (umsg) {
6273 if ((unsigned char)*end == CTLENDVAR) {
6274 if (varflags & VSNUL)
6275 tail = " or null";
6276 } else {
6277 msg = umsg;
6280 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
6283 static const char *
6284 subevalvar(char *p, char *varname, int strloc, int subtype,
6285 int startloc, int varflags, int flag, struct strlist *var_str_list)
6287 struct nodelist *saveargbackq = argbackq;
6288 int quotes = flag & QUOTES_ESC;
6289 char *startp;
6290 char *loc;
6291 char *rmesc, *rmescend;
6292 char *str;
6293 IF_ASH_BASH_COMPAT(char *repl = NULL;)
6294 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
6295 int saveherefd = herefd;
6296 int amount, resetloc;
6297 IF_ASH_BASH_COMPAT(int workloc;)
6298 int zero;
6299 char *(*scan)(char*, char*, char*, char*, int, int);
6301 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6302 // p, varname, strloc, subtype, startloc, varflags, quotes);
6304 herefd = -1;
6305 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
6306 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6307 var_str_list);
6308 STPUTC('\0', expdest);
6309 herefd = saveherefd;
6310 argbackq = saveargbackq;
6311 startp = (char *)stackblock() + startloc;
6313 switch (subtype) {
6314 case VSASSIGN:
6315 setvar0(varname, startp);
6316 amount = startp - expdest;
6317 STADJUST(amount, expdest);
6318 return startp;
6320 case VSQUESTION:
6321 varunset(p, varname, startp, varflags);
6322 /* NOTREACHED */
6324 #if ENABLE_ASH_BASH_COMPAT
6325 case VSSUBSTR:
6326 loc = str = stackblock() + strloc;
6327 /* Read POS in ${var:POS:LEN} */
6328 pos = atoi(loc); /* number(loc) errors out on "1:4" */
6329 len = str - startp - 1;
6331 /* *loc != '\0', guaranteed by parser */
6332 if (quotes) {
6333 char *ptr;
6335 /* Adjust the length by the number of escapes */
6336 for (ptr = startp; ptr < (str - 1); ptr++) {
6337 if ((unsigned char)*ptr == CTLESC) {
6338 len--;
6339 ptr++;
6343 orig_len = len;
6345 if (*loc++ == ':') {
6346 /* ${var::LEN} */
6347 len = number(loc);
6348 } else {
6349 /* Skip POS in ${var:POS:LEN} */
6350 len = orig_len;
6351 while (*loc && *loc != ':') {
6352 /* TODO?
6353 * bash complains on: var=qwe; echo ${var:1a:123}
6354 if (!isdigit(*loc))
6355 ash_msg_and_raise_error(msg_illnum, str);
6357 loc++;
6359 if (*loc++ == ':') {
6360 len = number(loc);
6363 if (pos < 0) {
6364 /* ${VAR:$((-n)):l} starts n chars from the end */
6365 pos = orig_len + pos;
6367 if ((unsigned)pos >= orig_len) {
6368 /* apart from obvious ${VAR:999999:l},
6369 * covers ${VAR:$((-9999999)):l} - result is ""
6370 * (bash-compat)
6372 pos = 0;
6373 len = 0;
6375 if (len > (orig_len - pos))
6376 len = orig_len - pos;
6378 for (str = startp; pos; str++, pos--) {
6379 if (quotes && (unsigned char)*str == CTLESC)
6380 str++;
6382 for (loc = startp; len; len--) {
6383 if (quotes && (unsigned char)*str == CTLESC)
6384 *loc++ = *str++;
6385 *loc++ = *str++;
6387 *loc = '\0';
6388 amount = loc - expdest;
6389 STADJUST(amount, expdest);
6390 return loc;
6391 #endif
6394 resetloc = expdest - (char *)stackblock();
6396 /* We'll comeback here if we grow the stack while handling
6397 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6398 * stack will need rebasing, and we'll need to remove our work
6399 * areas each time
6401 IF_ASH_BASH_COMPAT(restart:)
6403 amount = expdest - ((char *)stackblock() + resetloc);
6404 STADJUST(-amount, expdest);
6405 startp = (char *)stackblock() + startloc;
6407 rmesc = startp;
6408 rmescend = (char *)stackblock() + strloc;
6409 if (quotes) {
6410 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6411 if (rmesc != startp) {
6412 rmescend = expdest;
6413 startp = (char *)stackblock() + startloc;
6416 rmescend--;
6417 str = (char *)stackblock() + strloc;
6419 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6420 * The result is a_\_z_c (not a\_\_z_c)!
6422 * The search pattern and replace string treat backslashes differently!
6423 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6424 * and string. It's only used on the first call.
6426 preglob(str, IF_ASH_BASH_COMPAT(
6427 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6428 RMESCAPE_SLASH :) 0);
6430 #if ENABLE_ASH_BASH_COMPAT
6431 workloc = expdest - (char *)stackblock();
6432 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6433 char *idx, *end;
6435 if (!repl) {
6436 if ((repl=strchr(str, CTLESC)))
6437 *repl++ = '\0';
6438 else
6439 repl = nullstr;
6441 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
6443 /* If there's no pattern to match, return the expansion unmolested */
6444 if (str[0] == '\0')
6445 return NULL;
6447 len = 0;
6448 idx = startp;
6449 end = str - 1;
6450 while (idx < end) {
6451 try_to_match:
6452 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6453 //bb_error_msg("scanright('%s'):'%s'", str, loc);
6454 if (!loc) {
6455 /* No match, advance */
6456 char *restart_detect = stackblock();
6457 skip_matching:
6458 STPUTC(*idx, expdest);
6459 if (quotes && (unsigned char)*idx == CTLESC) {
6460 idx++;
6461 len++;
6462 STPUTC(*idx, expdest);
6464 if (stackblock() != restart_detect)
6465 goto restart;
6466 idx++;
6467 len++;
6468 rmesc++;
6469 /* continue; - prone to quadratic behavior, smarter code: */
6470 if (idx >= end)
6471 break;
6472 if (str[0] == '*') {
6473 /* Pattern is "*foo". If "*foo" does not match "long_string",
6474 * it would never match "ong_string" etc, no point in trying.
6476 goto skip_matching;
6478 goto try_to_match;
6481 if (subtype == VSREPLACEALL) {
6482 while (idx < loc) {
6483 if (quotes && (unsigned char)*idx == CTLESC)
6484 idx++;
6485 idx++;
6486 rmesc++;
6488 } else {
6489 idx = loc;
6492 //bb_error_msg("repl:'%s'", repl);
6493 for (loc = (char*)repl; *loc; loc++) {
6494 char *restart_detect = stackblock();
6495 if (quotes && *loc == '\\') {
6496 STPUTC(CTLESC, expdest);
6497 len++;
6499 STPUTC(*loc, expdest);
6500 if (stackblock() != restart_detect)
6501 goto restart;
6502 len++;
6505 if (subtype == VSREPLACE) {
6506 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
6507 while (*idx) {
6508 char *restart_detect = stackblock();
6509 STPUTC(*idx, expdest);
6510 if (stackblock() != restart_detect)
6511 goto restart;
6512 len++;
6513 idx++;
6515 break;
6519 /* We've put the replaced text into a buffer at workloc, now
6520 * move it to the right place and adjust the stack.
6522 STPUTC('\0', expdest);
6523 startp = (char *)stackblock() + startloc;
6524 memmove(startp, (char *)stackblock() + workloc, len + 1);
6525 //bb_error_msg("startp:'%s'", startp);
6526 amount = expdest - (startp + len);
6527 STADJUST(-amount, expdest);
6528 return startp;
6530 #endif /* ENABLE_ASH_BASH_COMPAT */
6532 subtype -= VSTRIMRIGHT;
6533 #if DEBUG
6534 if (subtype < 0 || subtype > 7)
6535 abort();
6536 #endif
6537 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
6538 zero = subtype >> 1;
6539 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6540 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6542 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6543 if (loc) {
6544 if (zero) {
6545 memmove(startp, loc, str - loc);
6546 loc = startp + (str - loc) - 1;
6548 *loc = '\0';
6549 amount = loc - expdest;
6550 STADJUST(amount, expdest);
6552 return loc;
6556 * Add the value of a specialized variable to the stack string.
6557 * name parameter (examples):
6558 * ash -c 'echo $1' name:'1='
6559 * ash -c 'echo $qwe' name:'qwe='
6560 * ash -c 'echo $$' name:'$='
6561 * ash -c 'echo ${$}' name:'$='
6562 * ash -c 'echo ${$##q}' name:'$=q'
6563 * ash -c 'echo ${#$}' name:'$='
6564 * note: examples with bad shell syntax:
6565 * ash -c 'echo ${#$1}' name:'$=1'
6566 * ash -c 'echo ${#1#}' name:'1=#'
6568 static NOINLINE ssize_t
6569 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6571 const char *p;
6572 int num;
6573 int i;
6574 ssize_t len = 0;
6575 int sep;
6576 int quoted = flags & EXP_QUOTED;
6577 int subtype = varflags & VSTYPE;
6578 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6579 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
6580 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
6582 sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
6584 switch (*name) {
6585 case '$':
6586 num = rootpid;
6587 goto numvar;
6588 case '?':
6589 num = exitstatus;
6590 goto numvar;
6591 case '#':
6592 num = shellparam.nparam;
6593 goto numvar;
6594 case '!':
6595 num = backgndpid;
6596 if (num == 0)
6597 return -1;
6598 numvar:
6599 len = cvtnum(num);
6600 goto check_1char_name;
6601 case '-':
6602 expdest = makestrspace(NOPTS, expdest);
6603 for (i = NOPTS - 1; i >= 0; i--) {
6604 if (optlist[i]) {
6605 USTPUTC(optletters(i), expdest);
6606 len++;
6609 check_1char_name:
6610 #if 0
6611 /* handles cases similar to ${#$1} */
6612 if (name[2] != '\0')
6613 raise_error_syntax("bad substitution");
6614 #endif
6615 break;
6616 case '@': {
6617 char **ap;
6618 char sepc;
6620 if (quoted && (flags & EXP_FULL)) {
6621 /* note: this is not meant as PEOF value */
6622 sep = 1 << CHAR_BIT;
6623 goto param;
6625 /* fall through */
6626 case '*':
6627 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
6628 param:
6629 ap = shellparam.p;
6630 sepc = sep;
6631 if (!ap)
6632 return -1;
6633 while ((p = *ap++) != NULL) {
6634 len += strtodest(p, syntax, quotes);
6636 if (*ap && sep) {
6637 len++;
6638 memtodest(&sepc, 1, syntax, quotes);
6641 break;
6642 } /* case '@' and '*' */
6643 case '0':
6644 case '1':
6645 case '2':
6646 case '3':
6647 case '4':
6648 case '5':
6649 case '6':
6650 case '7':
6651 case '8':
6652 case '9':
6653 num = atoi(name); /* number(name) fails on ${N#str} etc */
6654 if (num < 0 || num > shellparam.nparam)
6655 return -1;
6656 p = num ? shellparam.p[num - 1] : arg0;
6657 goto value;
6658 default:
6659 /* NB: name has form "VAR=..." */
6661 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6662 * which should be considered before we check variables. */
6663 if (var_str_list) {
6664 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6665 p = NULL;
6666 do {
6667 char *str, *eq;
6668 str = var_str_list->text;
6669 eq = strchr(str, '=');
6670 if (!eq) /* stop at first non-assignment */
6671 break;
6672 eq++;
6673 if (name_len == (unsigned)(eq - str)
6674 && strncmp(str, name, name_len) == 0
6676 p = eq;
6677 /* goto value; - WRONG! */
6678 /* think "A=1 A=2 B=$A" */
6680 var_str_list = var_str_list->next;
6681 } while (var_str_list);
6682 if (p)
6683 goto value;
6685 p = lookupvar(name);
6686 value:
6687 if (!p)
6688 return -1;
6690 len = strtodest(p, syntax, quotes);
6691 #if ENABLE_UNICODE_SUPPORT
6692 if (subtype == VSLENGTH && len > 0) {
6693 reinit_unicode_for_ash();
6694 if (unicode_status == UNICODE_ON) {
6695 STADJUST(-len, expdest);
6696 discard = 0;
6697 len = unicode_strlen(p);
6700 #endif
6701 break;
6704 if (discard)
6705 STADJUST(-len, expdest);
6706 return len;
6710 * Expand a variable, and return a pointer to the next character in the
6711 * input string.
6713 static char *
6714 evalvar(char *p, int flags, struct strlist *var_str_list)
6716 char varflags;
6717 char subtype;
6718 int quoted;
6719 char easy;
6720 char *var;
6721 int patloc;
6722 int startloc;
6723 ssize_t varlen;
6725 varflags = (unsigned char) *p++;
6726 subtype = varflags & VSTYPE;
6727 quoted = flags & EXP_QUOTED;
6728 var = p;
6729 easy = (!quoted || (*var == '@' && shellparam.nparam));
6730 startloc = expdest - (char *)stackblock();
6731 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
6733 again:
6734 varlen = varvalue(var, varflags, flags, var_str_list);
6735 if (varflags & VSNUL)
6736 varlen--;
6738 if (subtype == VSPLUS) {
6739 varlen = -1 - varlen;
6740 goto vsplus;
6743 if (subtype == VSMINUS) {
6744 vsplus:
6745 if (varlen < 0) {
6746 argstr(
6748 flags | EXP_TILDE | EXP_WORD,
6749 var_str_list
6751 goto end;
6753 if (easy)
6754 goto record;
6755 goto end;
6758 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6759 if (varlen < 0) {
6760 if (subevalvar(p, var, /* strloc: */ 0,
6761 subtype, startloc, varflags,
6762 /* quotes: */ flags & ~QUOTES_ESC,
6763 var_str_list)
6765 varflags &= ~VSNUL;
6767 * Remove any recorded regions beyond
6768 * start of variable
6770 removerecordregions(startloc);
6771 goto again;
6773 goto end;
6775 if (easy)
6776 goto record;
6777 goto end;
6780 if (varlen < 0 && uflag)
6781 varunset(p, var, 0, 0);
6783 if (subtype == VSLENGTH) {
6784 cvtnum(varlen > 0 ? varlen : 0);
6785 goto record;
6788 if (subtype == VSNORMAL) {
6789 if (easy)
6790 goto record;
6791 goto end;
6794 #if DEBUG
6795 switch (subtype) {
6796 case VSTRIMLEFT:
6797 case VSTRIMLEFTMAX:
6798 case VSTRIMRIGHT:
6799 case VSTRIMRIGHTMAX:
6800 #if ENABLE_ASH_BASH_COMPAT
6801 case VSSUBSTR:
6802 case VSREPLACE:
6803 case VSREPLACEALL:
6804 #endif
6805 break;
6806 default:
6807 abort();
6809 #endif
6811 if (varlen >= 0) {
6813 * Terminate the string and start recording the pattern
6814 * right after it
6816 STPUTC('\0', expdest);
6817 patloc = expdest - (char *)stackblock();
6818 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
6819 startloc, varflags, flags, var_str_list)) {
6820 int amount = expdest - (
6821 (char *)stackblock() + patloc - 1
6823 STADJUST(-amount, expdest);
6825 /* Remove any recorded regions beyond start of variable */
6826 removerecordregions(startloc);
6827 record:
6828 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6831 end:
6832 if (subtype != VSNORMAL) { /* skip to end of alternative */
6833 int nesting = 1;
6834 for (;;) {
6835 unsigned char c = *p++;
6836 if (c == CTLESC)
6837 p++;
6838 else if (c == CTLBACKQ) {
6839 if (varlen >= 0)
6840 argbackq = argbackq->next;
6841 } else if (c == CTLVAR) {
6842 if ((*p++ & VSTYPE) != VSNORMAL)
6843 nesting++;
6844 } else if (c == CTLENDVAR) {
6845 if (--nesting == 0)
6846 break;
6850 return p;
6854 * Break the argument string into pieces based upon IFS and add the
6855 * strings to the argument list. The regions of the string to be
6856 * searched for IFS characters have been stored by recordregion.
6858 static void
6859 ifsbreakup(char *string, struct arglist *arglist)
6861 struct ifsregion *ifsp;
6862 struct strlist *sp;
6863 char *start;
6864 char *p;
6865 char *q;
6866 const char *ifs, *realifs;
6867 int ifsspc;
6868 int nulonly;
6870 start = string;
6871 if (ifslastp != NULL) {
6872 ifsspc = 0;
6873 nulonly = 0;
6874 realifs = ifsset() ? ifsval() : defifs;
6875 ifsp = &ifsfirst;
6876 do {
6877 p = string + ifsp->begoff;
6878 nulonly = ifsp->nulonly;
6879 ifs = nulonly ? nullstr : realifs;
6880 ifsspc = 0;
6881 while (p < string + ifsp->endoff) {
6882 q = p;
6883 if ((unsigned char)*p == CTLESC)
6884 p++;
6885 if (!strchr(ifs, *p)) {
6886 p++;
6887 continue;
6889 if (!nulonly)
6890 ifsspc = (strchr(defifs, *p) != NULL);
6891 /* Ignore IFS whitespace at start */
6892 if (q == start && ifsspc) {
6893 p++;
6894 start = p;
6895 continue;
6897 *q = '\0';
6898 sp = stzalloc(sizeof(*sp));
6899 sp->text = start;
6900 *arglist->lastp = sp;
6901 arglist->lastp = &sp->next;
6902 p++;
6903 if (!nulonly) {
6904 for (;;) {
6905 if (p >= string + ifsp->endoff) {
6906 break;
6908 q = p;
6909 if ((unsigned char)*p == CTLESC)
6910 p++;
6911 if (strchr(ifs, *p) == NULL) {
6912 p = q;
6913 break;
6915 if (strchr(defifs, *p) == NULL) {
6916 if (ifsspc) {
6917 p++;
6918 ifsspc = 0;
6919 } else {
6920 p = q;
6921 break;
6923 } else
6924 p++;
6927 start = p;
6928 } /* while */
6929 ifsp = ifsp->next;
6930 } while (ifsp != NULL);
6931 if (nulonly)
6932 goto add;
6935 if (!*start)
6936 return;
6938 add:
6939 sp = stzalloc(sizeof(*sp));
6940 sp->text = start;
6941 *arglist->lastp = sp;
6942 arglist->lastp = &sp->next;
6945 static void
6946 ifsfree(void)
6948 struct ifsregion *p;
6950 INT_OFF;
6951 p = ifsfirst.next;
6952 do {
6953 struct ifsregion *ifsp;
6954 ifsp = p->next;
6955 free(p);
6956 p = ifsp;
6957 } while (p);
6958 ifslastp = NULL;
6959 ifsfirst.next = NULL;
6960 INT_ON;
6964 * Add a file name to the list.
6966 static void
6967 addfname(const char *name)
6969 struct strlist *sp;
6971 sp = stzalloc(sizeof(*sp));
6972 sp->text = ststrdup(name);
6973 *exparg.lastp = sp;
6974 exparg.lastp = &sp->next;
6978 * Do metacharacter (i.e. *, ?, [...]) expansion.
6980 static void
6981 expmeta(char *expdir, char *enddir, char *name)
6983 char *p;
6984 const char *cp;
6985 char *start;
6986 char *endname;
6987 int metaflag;
6988 struct stat statb;
6989 DIR *dirp;
6990 struct dirent *dp;
6991 int atend;
6992 int matchdot;
6993 int esc;
6995 metaflag = 0;
6996 start = name;
6997 for (p = name; esc = 0, *p; p += esc + 1) {
6998 if (*p == '*' || *p == '?')
6999 metaflag = 1;
7000 else if (*p == '[') {
7001 char *q = p + 1;
7002 if (*q == '!')
7003 q++;
7004 for (;;) {
7005 if (*q == '\\')
7006 q++;
7007 if (*q == '/' || *q == '\0')
7008 break;
7009 if (*++q == ']') {
7010 metaflag = 1;
7011 break;
7014 } else {
7015 if (*p == '\\')
7016 esc++;
7017 if (p[esc] == '/') {
7018 if (metaflag)
7019 break;
7020 start = p + esc + 1;
7024 if (metaflag == 0) { /* we've reached the end of the file name */
7025 if (enddir != expdir)
7026 metaflag++;
7027 p = name;
7028 do {
7029 if (*p == '\\')
7030 p++;
7031 *enddir++ = *p;
7032 } while (*p++);
7033 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7034 addfname(expdir);
7035 return;
7037 endname = p;
7038 if (name < start) {
7039 p = name;
7040 do {
7041 if (*p == '\\')
7042 p++;
7043 *enddir++ = *p++;
7044 } while (p < start);
7046 if (enddir == expdir) {
7047 cp = ".";
7048 } else if (enddir == expdir + 1 && *expdir == '/') {
7049 cp = "/";
7050 } else {
7051 cp = expdir;
7052 enddir[-1] = '\0';
7054 dirp = opendir(cp);
7055 if (dirp == NULL)
7056 return;
7057 if (enddir != expdir)
7058 enddir[-1] = '/';
7059 if (*endname == 0) {
7060 atend = 1;
7061 } else {
7062 atend = 0;
7063 *endname = '\0';
7064 endname += esc + 1;
7066 matchdot = 0;
7067 p = start;
7068 if (*p == '\\')
7069 p++;
7070 if (*p == '.')
7071 matchdot++;
7072 while (!pending_int && (dp = readdir(dirp)) != NULL) {
7073 if (dp->d_name[0] == '.' && !matchdot)
7074 continue;
7075 if (pmatch(start, dp->d_name)) {
7076 if (atend) {
7077 strcpy(enddir, dp->d_name);
7078 addfname(expdir);
7079 } else {
7080 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7081 continue;
7082 p[-1] = '/';
7083 expmeta(expdir, p, endname);
7087 closedir(dirp);
7088 if (!atend)
7089 endname[-esc - 1] = esc ? '\\' : '/';
7092 static struct strlist *
7093 msort(struct strlist *list, int len)
7095 struct strlist *p, *q = NULL;
7096 struct strlist **lpp;
7097 int half;
7098 int n;
7100 if (len <= 1)
7101 return list;
7102 half = len >> 1;
7103 p = list;
7104 for (n = half; --n >= 0;) {
7105 q = p;
7106 p = p->next;
7108 q->next = NULL; /* terminate first half of list */
7109 q = msort(list, half); /* sort first half of list */
7110 p = msort(p, len - half); /* sort second half */
7111 lpp = &list;
7112 for (;;) {
7113 #if ENABLE_LOCALE_SUPPORT
7114 if (strcoll(p->text, q->text) < 0)
7115 #else
7116 if (strcmp(p->text, q->text) < 0)
7117 #endif
7119 *lpp = p;
7120 lpp = &p->next;
7121 p = *lpp;
7122 if (p == NULL) {
7123 *lpp = q;
7124 break;
7126 } else {
7127 *lpp = q;
7128 lpp = &q->next;
7129 q = *lpp;
7130 if (q == NULL) {
7131 *lpp = p;
7132 break;
7136 return list;
7140 * Sort the results of file name expansion. It calculates the number of
7141 * strings to sort and then calls msort (short for merge sort) to do the
7142 * work.
7144 static struct strlist *
7145 expsort(struct strlist *str)
7147 int len;
7148 struct strlist *sp;
7150 len = 0;
7151 for (sp = str; sp; sp = sp->next)
7152 len++;
7153 return msort(str, len);
7156 static void
7157 expandmeta(struct strlist *str /*, int flag*/)
7159 static const char metachars[] ALIGN1 = {
7160 '*', '?', '[', 0
7162 /* TODO - EXP_REDIR */
7164 while (str) {
7165 char *expdir;
7166 struct strlist **savelastp;
7167 struct strlist *sp;
7168 char *p;
7170 if (fflag)
7171 goto nometa;
7172 if (!strpbrk(str->text, metachars))
7173 goto nometa;
7174 savelastp = exparg.lastp;
7176 INT_OFF;
7177 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7179 int i = strlen(str->text);
7180 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
7182 expmeta(expdir, expdir, p);
7183 free(expdir);
7184 if (p != str->text)
7185 free(p);
7186 INT_ON;
7187 if (exparg.lastp == savelastp) {
7189 * no matches
7191 nometa:
7192 *exparg.lastp = str;
7193 rmescapes(str->text, 0);
7194 exparg.lastp = &str->next;
7195 } else {
7196 *exparg.lastp = NULL;
7197 *savelastp = sp = expsort(*savelastp);
7198 while (sp->next != NULL)
7199 sp = sp->next;
7200 exparg.lastp = &sp->next;
7202 str = str->next;
7207 * Perform variable substitution and command substitution on an argument,
7208 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7209 * perform splitting and file name expansion. When arglist is NULL, perform
7210 * here document expansion.
7212 static void
7213 expandarg(union node *arg, struct arglist *arglist, int flag)
7215 struct strlist *sp;
7216 char *p;
7218 argbackq = arg->narg.backquote;
7219 STARTSTACKSTR(expdest);
7220 ifsfirst.next = NULL;
7221 ifslastp = NULL;
7222 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
7223 argstr(arg->narg.text, flag,
7224 /* var_str_list: */ arglist ? arglist->list : NULL);
7225 p = _STPUTC('\0', expdest);
7226 expdest = p - 1;
7227 if (arglist == NULL) {
7228 return; /* here document expanded */
7230 p = grabstackstr(p);
7231 TRACE(("expandarg: p:'%s'\n", p));
7232 exparg.lastp = &exparg.list;
7234 * TODO - EXP_REDIR
7236 if (flag & EXP_FULL) {
7237 ifsbreakup(p, &exparg);
7238 *exparg.lastp = NULL;
7239 exparg.lastp = &exparg.list;
7240 expandmeta(exparg.list /*, flag*/);
7241 } else {
7242 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
7243 rmescapes(p, 0);
7244 TRACE(("expandarg: rmescapes:'%s'\n", p));
7246 sp = stzalloc(sizeof(*sp));
7247 sp->text = p;
7248 *exparg.lastp = sp;
7249 exparg.lastp = &sp->next;
7251 if (ifsfirst.next)
7252 ifsfree();
7253 *exparg.lastp = NULL;
7254 if (exparg.list) {
7255 *arglist->lastp = exparg.list;
7256 arglist->lastp = exparg.lastp;
7261 * Expand shell variables and backquotes inside a here document.
7263 static void
7264 expandhere(union node *arg, int fd)
7266 herefd = fd;
7267 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
7268 full_write(fd, stackblock(), expdest - (char *)stackblock());
7272 * Returns true if the pattern matches the string.
7274 static int
7275 patmatch(char *pattern, const char *string)
7277 return pmatch(preglob(pattern, 0), string);
7281 * See if a pattern matches in a case statement.
7283 static int
7284 casematch(union node *pattern, char *val)
7286 struct stackmark smark;
7287 int result;
7289 setstackmark(&smark);
7290 argbackq = pattern->narg.backquote;
7291 STARTSTACKSTR(expdest);
7292 ifslastp = NULL;
7293 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7294 /* var_str_list: */ NULL);
7295 STACKSTRNUL(expdest);
7296 result = patmatch(stackblock(), val);
7297 popstackmark(&smark);
7298 return result;
7302 /* ============ find_command */
7304 struct builtincmd {
7305 const char *name;
7306 int (*builtin)(int, char **) FAST_FUNC;
7307 /* unsigned flags; */
7309 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
7310 /* "regular" builtins always take precedence over commands,
7311 * regardless of PATH=....%builtin... position */
7312 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
7313 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
7315 struct cmdentry {
7316 smallint cmdtype; /* CMDxxx */
7317 union param {
7318 int index;
7319 /* index >= 0 for commands without path (slashes) */
7320 /* (TODO: what exactly does the value mean? PATH position?) */
7321 /* index == -1 for commands with slashes */
7322 /* index == (-2 - applet_no) for NOFORK applets */
7323 const struct builtincmd *cmd;
7324 struct funcnode *func;
7325 } u;
7327 /* values of cmdtype */
7328 #define CMDUNKNOWN -1 /* no entry in table for command */
7329 #define CMDNORMAL 0 /* command is an executable program */
7330 #define CMDFUNCTION 1 /* command is a shell function */
7331 #define CMDBUILTIN 2 /* command is a shell builtin */
7333 /* action to find_command() */
7334 #define DO_ERR 0x01 /* prints errors */
7335 #define DO_ABS 0x02 /* checks absolute paths */
7336 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7337 #define DO_ALTPATH 0x08 /* using alternate path */
7338 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7340 static void find_command(char *, struct cmdentry *, int, const char *);
7343 /* ============ Hashing commands */
7346 * When commands are first encountered, they are entered in a hash table.
7347 * This ensures that a full path search will not have to be done for them
7348 * on each invocation.
7350 * We should investigate converting to a linear search, even though that
7351 * would make the command name "hash" a misnomer.
7354 struct tblentry {
7355 struct tblentry *next; /* next entry in hash chain */
7356 union param param; /* definition of builtin function */
7357 smallint cmdtype; /* CMDxxx */
7358 char rehash; /* if set, cd done since entry created */
7359 char cmdname[1]; /* name of command */
7362 static struct tblentry **cmdtable;
7363 #define INIT_G_cmdtable() do { \
7364 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7365 } while (0)
7367 static int builtinloc = -1; /* index in path of %builtin, or -1 */
7370 static void
7371 tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
7373 #if ENABLE_FEATURE_SH_STANDALONE
7374 if (applet_no >= 0) {
7375 if (APPLET_IS_NOEXEC(applet_no)) {
7376 clearenv();
7377 while (*envp)
7378 putenv(*envp++);
7379 run_applet_no_and_exit(applet_no, argv);
7381 /* re-exec ourselves with the new arguments */
7382 execve(bb_busybox_exec_path, argv, envp);
7383 /* If they called chroot or otherwise made the binary no longer
7384 * executable, fall through */
7386 #endif
7388 repeat:
7389 #ifdef SYSV
7390 do {
7391 execve(cmd, argv, envp);
7392 } while (errno == EINTR);
7393 #else
7394 execve(cmd, argv, envp);
7395 #endif
7396 if (cmd == (char*) bb_busybox_exec_path) {
7397 /* We already visited ENOEXEC branch below, don't do it again */
7398 //TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
7399 free(argv);
7400 return;
7402 if (errno == ENOEXEC) {
7403 /* Run "cmd" as a shell script:
7404 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7405 * "If the execve() function fails with ENOEXEC, the shell
7406 * shall execute a command equivalent to having a shell invoked
7407 * with the command name as its first operand,
7408 * with any remaining arguments passed to the new shell"
7410 * That is, do not use $SHELL, user's shell, or /bin/sh;
7411 * just call ourselves.
7413 * Note that bash reads ~80 chars of the file, and if it sees
7414 * a zero byte before it sees newline, it doesn't try to
7415 * interpret it, but fails with "cannot execute binary file"
7416 * message and exit code 126. For one, this prevents attempts
7417 * to interpret foreign ELF binaries as shell scripts.
7419 char **ap;
7420 char **new;
7422 for (ap = argv; *ap; ap++)
7423 continue;
7424 new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
7425 new[0] = (char*) "ash";
7426 new[1] = cmd;
7427 ap = new + 2;
7428 while ((*ap++ = *++argv) != NULL)
7429 continue;
7430 cmd = (char*) bb_busybox_exec_path;
7431 argv = new;
7432 goto repeat;
7437 * Exec a program. Never returns. If you change this routine, you may
7438 * have to change the find_command routine as well.
7440 static void shellexec(char **, const char *, int) NORETURN;
7441 static void
7442 shellexec(char **argv, const char *path, int idx)
7444 char *cmdname;
7445 int e;
7446 char **envp;
7447 int exerrno;
7448 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
7450 clearredir(/*drop:*/ 1);
7451 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7452 if (strchr(argv[0], '/') != NULL
7453 #if ENABLE_FEATURE_SH_STANDALONE
7454 || (applet_no = find_applet_by_name(argv[0])) >= 0
7455 #endif
7457 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7458 if (applet_no >= 0) {
7459 /* We tried execing ourself, but it didn't work.
7460 * Maybe /proc/self/exe doesn't exist?
7461 * Try $PATH search.
7463 goto try_PATH;
7465 e = errno;
7466 } else {
7467 try_PATH:
7468 e = ENOENT;
7469 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
7470 if (--idx < 0 && pathopt == NULL) {
7471 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7472 if (errno != ENOENT && errno != ENOTDIR)
7473 e = errno;
7475 stunalloc(cmdname);
7479 /* Map to POSIX errors */
7480 switch (e) {
7481 case EACCES:
7482 exerrno = 126;
7483 break;
7484 case ENOENT:
7485 exerrno = 127;
7486 break;
7487 default:
7488 exerrno = 2;
7489 break;
7491 exitstatus = exerrno;
7492 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7493 argv[0], e, suppress_int));
7494 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7495 /* NOTREACHED */
7498 static void
7499 printentry(struct tblentry *cmdp)
7501 int idx;
7502 const char *path;
7503 char *name;
7505 idx = cmdp->param.index;
7506 path = pathval();
7507 do {
7508 name = path_advance(&path, cmdp->cmdname);
7509 stunalloc(name);
7510 } while (--idx >= 0);
7511 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7515 * Clear out command entries. The argument specifies the first entry in
7516 * PATH which has changed.
7518 static void
7519 clearcmdentry(int firstchange)
7521 struct tblentry **tblp;
7522 struct tblentry **pp;
7523 struct tblentry *cmdp;
7525 INT_OFF;
7526 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7527 pp = tblp;
7528 while ((cmdp = *pp) != NULL) {
7529 if ((cmdp->cmdtype == CMDNORMAL &&
7530 cmdp->param.index >= firstchange)
7531 || (cmdp->cmdtype == CMDBUILTIN &&
7532 builtinloc >= firstchange)
7534 *pp = cmdp->next;
7535 free(cmdp);
7536 } else {
7537 pp = &cmdp->next;
7541 INT_ON;
7545 * Locate a command in the command hash table. If "add" is nonzero,
7546 * add the command to the table if it is not already present. The
7547 * variable "lastcmdentry" is set to point to the address of the link
7548 * pointing to the entry, so that delete_cmd_entry can delete the
7549 * entry.
7551 * Interrupts must be off if called with add != 0.
7553 static struct tblentry **lastcmdentry;
7555 static struct tblentry *
7556 cmdlookup(const char *name, int add)
7558 unsigned int hashval;
7559 const char *p;
7560 struct tblentry *cmdp;
7561 struct tblentry **pp;
7563 p = name;
7564 hashval = (unsigned char)*p << 4;
7565 while (*p)
7566 hashval += (unsigned char)*p++;
7567 hashval &= 0x7FFF;
7568 pp = &cmdtable[hashval % CMDTABLESIZE];
7569 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7570 if (strcmp(cmdp->cmdname, name) == 0)
7571 break;
7572 pp = &cmdp->next;
7574 if (add && cmdp == NULL) {
7575 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7576 + strlen(name)
7577 /* + 1 - already done because
7578 * tblentry::cmdname is char[1] */);
7579 /*cmdp->next = NULL; - ckzalloc did it */
7580 cmdp->cmdtype = CMDUNKNOWN;
7581 strcpy(cmdp->cmdname, name);
7583 lastcmdentry = pp;
7584 return cmdp;
7588 * Delete the command entry returned on the last lookup.
7590 static void
7591 delete_cmd_entry(void)
7593 struct tblentry *cmdp;
7595 INT_OFF;
7596 cmdp = *lastcmdentry;
7597 *lastcmdentry = cmdp->next;
7598 if (cmdp->cmdtype == CMDFUNCTION)
7599 freefunc(cmdp->param.func);
7600 free(cmdp);
7601 INT_ON;
7605 * Add a new command entry, replacing any existing command entry for
7606 * the same name - except special builtins.
7608 static void
7609 addcmdentry(char *name, struct cmdentry *entry)
7611 struct tblentry *cmdp;
7613 cmdp = cmdlookup(name, 1);
7614 if (cmdp->cmdtype == CMDFUNCTION) {
7615 freefunc(cmdp->param.func);
7617 cmdp->cmdtype = entry->cmdtype;
7618 cmdp->param = entry->u;
7619 cmdp->rehash = 0;
7622 static int FAST_FUNC
7623 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7625 struct tblentry **pp;
7626 struct tblentry *cmdp;
7627 int c;
7628 struct cmdentry entry;
7629 char *name;
7631 if (nextopt("r") != '\0') {
7632 clearcmdentry(0);
7633 return 0;
7636 if (*argptr == NULL) {
7637 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7638 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7639 if (cmdp->cmdtype == CMDNORMAL)
7640 printentry(cmdp);
7643 return 0;
7646 c = 0;
7647 while ((name = *argptr) != NULL) {
7648 cmdp = cmdlookup(name, 0);
7649 if (cmdp != NULL
7650 && (cmdp->cmdtype == CMDNORMAL
7651 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7653 delete_cmd_entry();
7655 find_command(name, &entry, DO_ERR, pathval());
7656 if (entry.cmdtype == CMDUNKNOWN)
7657 c = 1;
7658 argptr++;
7660 return c;
7664 * Called when a cd is done. Marks all commands so the next time they
7665 * are executed they will be rehashed.
7667 static void
7668 hashcd(void)
7670 struct tblentry **pp;
7671 struct tblentry *cmdp;
7673 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7674 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7675 if (cmdp->cmdtype == CMDNORMAL
7676 || (cmdp->cmdtype == CMDBUILTIN
7677 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7678 && builtinloc > 0)
7680 cmdp->rehash = 1;
7687 * Fix command hash table when PATH changed.
7688 * Called before PATH is changed. The argument is the new value of PATH;
7689 * pathval() still returns the old value at this point.
7690 * Called with interrupts off.
7692 static void FAST_FUNC
7693 changepath(const char *new)
7695 const char *old;
7696 int firstchange;
7697 int idx;
7698 int idx_bltin;
7700 old = pathval();
7701 firstchange = 9999; /* assume no change */
7702 idx = 0;
7703 idx_bltin = -1;
7704 for (;;) {
7705 if (*old != *new) {
7706 firstchange = idx;
7707 if ((*old == '\0' && *new == ':')
7708 || (*old == ':' && *new == '\0')
7710 firstchange++;
7712 old = new; /* ignore subsequent differences */
7714 if (*new == '\0')
7715 break;
7716 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7717 idx_bltin = idx;
7718 if (*new == ':')
7719 idx++;
7720 new++;
7721 old++;
7723 if (builtinloc < 0 && idx_bltin >= 0)
7724 builtinloc = idx_bltin; /* zap builtins */
7725 if (builtinloc >= 0 && idx_bltin < 0)
7726 firstchange = 0;
7727 clearcmdentry(firstchange);
7728 builtinloc = idx_bltin;
7730 enum {
7731 TEOF,
7732 TNL,
7733 TREDIR,
7734 TWORD,
7735 TSEMI,
7736 TBACKGND,
7737 TAND,
7738 TOR,
7739 TPIPE,
7740 TLP,
7741 TRP,
7742 TENDCASE,
7743 TENDBQUOTE,
7744 TNOT,
7745 TCASE,
7746 TDO,
7747 TDONE,
7748 TELIF,
7749 TELSE,
7750 TESAC,
7751 TFI,
7752 TFOR,
7753 #if ENABLE_ASH_BASH_COMPAT
7754 TFUNCTION,
7755 #endif
7756 TIF,
7757 TIN,
7758 TTHEN,
7759 TUNTIL,
7760 TWHILE,
7761 TBEGIN,
7762 TEND
7764 typedef smallint token_id_t;
7766 /* first char is indicating which tokens mark the end of a list */
7767 static const char *const tokname_array[] = {
7768 "\1end of file",
7769 "\0newline",
7770 "\0redirection",
7771 "\0word",
7772 "\0;",
7773 "\0&",
7774 "\0&&",
7775 "\0||",
7776 "\0|",
7777 "\0(",
7778 "\1)",
7779 "\1;;",
7780 "\1`",
7781 #define KWDOFFSET 13
7782 /* the following are keywords */
7783 "\0!",
7784 "\0case",
7785 "\1do",
7786 "\1done",
7787 "\1elif",
7788 "\1else",
7789 "\1esac",
7790 "\1fi",
7791 "\0for",
7792 #if ENABLE_ASH_BASH_COMPAT
7793 "\0function",
7794 #endif
7795 "\0if",
7796 "\0in",
7797 "\1then",
7798 "\0until",
7799 "\0while",
7800 "\0{",
7801 "\1}",
7804 /* Wrapper around strcmp for qsort/bsearch/... */
7805 static int
7806 pstrcmp(const void *a, const void *b)
7808 return strcmp((char*) a, (*(char**) b) + 1);
7811 static const char *const *
7812 findkwd(const char *s)
7814 return bsearch(s, tokname_array + KWDOFFSET,
7815 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7816 sizeof(tokname_array[0]), pstrcmp);
7820 * Locate and print what a word is...
7822 static int
7823 describe_command(char *command, const char *path, int describe_command_verbose)
7825 struct cmdentry entry;
7826 struct tblentry *cmdp;
7827 #if ENABLE_ASH_ALIAS
7828 const struct alias *ap;
7829 #endif
7831 path = path ? path : pathval();
7833 if (describe_command_verbose) {
7834 out1str(command);
7837 /* First look at the keywords */
7838 if (findkwd(command)) {
7839 out1str(describe_command_verbose ? " is a shell keyword" : command);
7840 goto out;
7843 #if ENABLE_ASH_ALIAS
7844 /* Then look at the aliases */
7845 ap = lookupalias(command, 0);
7846 if (ap != NULL) {
7847 if (!describe_command_verbose) {
7848 out1str("alias ");
7849 printalias(ap);
7850 return 0;
7852 out1fmt(" is an alias for %s", ap->val);
7853 goto out;
7855 #endif
7856 /* Then check if it is a tracked alias */
7857 cmdp = cmdlookup(command, 0);
7858 if (cmdp != NULL) {
7859 entry.cmdtype = cmdp->cmdtype;
7860 entry.u = cmdp->param;
7861 } else {
7862 /* Finally use brute force */
7863 find_command(command, &entry, DO_ABS, path);
7866 switch (entry.cmdtype) {
7867 case CMDNORMAL: {
7868 int j = entry.u.index;
7869 char *p;
7870 if (j < 0) {
7871 p = command;
7872 } else {
7873 do {
7874 p = path_advance(&path, command);
7875 stunalloc(p);
7876 } while (--j >= 0);
7878 if (describe_command_verbose) {
7879 out1fmt(" is%s %s",
7880 (cmdp ? " a tracked alias for" : nullstr), p
7882 } else {
7883 out1str(p);
7885 break;
7888 case CMDFUNCTION:
7889 if (describe_command_verbose) {
7890 out1str(" is a shell function");
7891 } else {
7892 out1str(command);
7894 break;
7896 case CMDBUILTIN:
7897 if (describe_command_verbose) {
7898 out1fmt(" is a %sshell builtin",
7899 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7900 "special " : nullstr
7902 } else {
7903 out1str(command);
7905 break;
7907 default:
7908 if (describe_command_verbose) {
7909 out1str(": not found\n");
7911 return 127;
7913 out:
7914 out1str("\n");
7915 return 0;
7918 static int FAST_FUNC
7919 typecmd(int argc UNUSED_PARAM, char **argv)
7921 int i = 1;
7922 int err = 0;
7923 int verbose = 1;
7925 /* type -p ... ? (we don't bother checking for 'p') */
7926 if (argv[1] && argv[1][0] == '-') {
7927 i++;
7928 verbose = 0;
7930 while (argv[i]) {
7931 err |= describe_command(argv[i++], NULL, verbose);
7933 return err;
7936 #if ENABLE_ASH_CMDCMD
7937 static int FAST_FUNC
7938 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7940 int c;
7941 enum {
7942 VERIFY_BRIEF = 1,
7943 VERIFY_VERBOSE = 2,
7944 } verify = 0;
7945 const char *path = NULL;
7947 while ((c = nextopt("pvV")) != '\0')
7948 if (c == 'V')
7949 verify |= VERIFY_VERBOSE;
7950 else if (c == 'v')
7951 verify |= VERIFY_BRIEF;
7952 #if DEBUG
7953 else if (c != 'p')
7954 abort();
7955 #endif
7956 else
7957 path = bb_default_path;
7958 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7959 if (verify && (*argptr != NULL)) {
7960 return describe_command(*argptr, path, verify - VERIFY_BRIEF);
7963 return 0;
7965 #endif
7968 /* ============ eval.c */
7970 static int funcblocksize; /* size of structures in function */
7971 static int funcstringsize; /* size of strings in node */
7972 static void *funcblock; /* block to allocate function from */
7973 static char *funcstring; /* block to allocate strings from */
7975 /* flags in argument to evaltree */
7976 #define EV_EXIT 01 /* exit after evaluating tree */
7977 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7978 #define EV_BACKCMD 04 /* command executing within back quotes */
7980 static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
7981 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
7982 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
7983 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
7984 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
7985 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
7986 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
7987 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
7988 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
7989 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
7990 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
7991 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
7992 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
7993 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
7994 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
7995 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
7996 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
7997 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
7998 #if ENABLE_ASH_BASH_COMPAT
7999 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
8000 #endif
8001 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8002 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8003 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8004 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8005 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8006 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8007 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8008 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8009 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
8012 static void calcsize(union node *n);
8014 static void
8015 sizenodelist(struct nodelist *lp)
8017 while (lp) {
8018 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8019 calcsize(lp->n);
8020 lp = lp->next;
8024 static void
8025 calcsize(union node *n)
8027 if (n == NULL)
8028 return;
8029 funcblocksize += nodesize[n->type];
8030 switch (n->type) {
8031 case NCMD:
8032 calcsize(n->ncmd.redirect);
8033 calcsize(n->ncmd.args);
8034 calcsize(n->ncmd.assign);
8035 break;
8036 case NPIPE:
8037 sizenodelist(n->npipe.cmdlist);
8038 break;
8039 case NREDIR:
8040 case NBACKGND:
8041 case NSUBSHELL:
8042 calcsize(n->nredir.redirect);
8043 calcsize(n->nredir.n);
8044 break;
8045 case NAND:
8046 case NOR:
8047 case NSEMI:
8048 case NWHILE:
8049 case NUNTIL:
8050 calcsize(n->nbinary.ch2);
8051 calcsize(n->nbinary.ch1);
8052 break;
8053 case NIF:
8054 calcsize(n->nif.elsepart);
8055 calcsize(n->nif.ifpart);
8056 calcsize(n->nif.test);
8057 break;
8058 case NFOR:
8059 funcstringsize += strlen(n->nfor.var) + 1;
8060 calcsize(n->nfor.body);
8061 calcsize(n->nfor.args);
8062 break;
8063 case NCASE:
8064 calcsize(n->ncase.cases);
8065 calcsize(n->ncase.expr);
8066 break;
8067 case NCLIST:
8068 calcsize(n->nclist.body);
8069 calcsize(n->nclist.pattern);
8070 calcsize(n->nclist.next);
8071 break;
8072 case NDEFUN:
8073 case NARG:
8074 sizenodelist(n->narg.backquote);
8075 funcstringsize += strlen(n->narg.text) + 1;
8076 calcsize(n->narg.next);
8077 break;
8078 case NTO:
8079 #if ENABLE_ASH_BASH_COMPAT
8080 case NTO2:
8081 #endif
8082 case NCLOBBER:
8083 case NFROM:
8084 case NFROMTO:
8085 case NAPPEND:
8086 calcsize(n->nfile.fname);
8087 calcsize(n->nfile.next);
8088 break;
8089 case NTOFD:
8090 case NFROMFD:
8091 calcsize(n->ndup.vname);
8092 calcsize(n->ndup.next);
8093 break;
8094 case NHERE:
8095 case NXHERE:
8096 calcsize(n->nhere.doc);
8097 calcsize(n->nhere.next);
8098 break;
8099 case NNOT:
8100 calcsize(n->nnot.com);
8101 break;
8105 static char *
8106 nodeckstrdup(char *s)
8108 char *rtn = funcstring;
8110 strcpy(funcstring, s);
8111 funcstring += strlen(s) + 1;
8112 return rtn;
8115 static union node *copynode(union node *);
8117 static struct nodelist *
8118 copynodelist(struct nodelist *lp)
8120 struct nodelist *start;
8121 struct nodelist **lpp;
8123 lpp = &start;
8124 while (lp) {
8125 *lpp = funcblock;
8126 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8127 (*lpp)->n = copynode(lp->n);
8128 lp = lp->next;
8129 lpp = &(*lpp)->next;
8131 *lpp = NULL;
8132 return start;
8135 static union node *
8136 copynode(union node *n)
8138 union node *new;
8140 if (n == NULL)
8141 return NULL;
8142 new = funcblock;
8143 funcblock = (char *) funcblock + nodesize[n->type];
8145 switch (n->type) {
8146 case NCMD:
8147 new->ncmd.redirect = copynode(n->ncmd.redirect);
8148 new->ncmd.args = copynode(n->ncmd.args);
8149 new->ncmd.assign = copynode(n->ncmd.assign);
8150 break;
8151 case NPIPE:
8152 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8153 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8154 break;
8155 case NREDIR:
8156 case NBACKGND:
8157 case NSUBSHELL:
8158 new->nredir.redirect = copynode(n->nredir.redirect);
8159 new->nredir.n = copynode(n->nredir.n);
8160 break;
8161 case NAND:
8162 case NOR:
8163 case NSEMI:
8164 case NWHILE:
8165 case NUNTIL:
8166 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8167 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8168 break;
8169 case NIF:
8170 new->nif.elsepart = copynode(n->nif.elsepart);
8171 new->nif.ifpart = copynode(n->nif.ifpart);
8172 new->nif.test = copynode(n->nif.test);
8173 break;
8174 case NFOR:
8175 new->nfor.var = nodeckstrdup(n->nfor.var);
8176 new->nfor.body = copynode(n->nfor.body);
8177 new->nfor.args = copynode(n->nfor.args);
8178 break;
8179 case NCASE:
8180 new->ncase.cases = copynode(n->ncase.cases);
8181 new->ncase.expr = copynode(n->ncase.expr);
8182 break;
8183 case NCLIST:
8184 new->nclist.body = copynode(n->nclist.body);
8185 new->nclist.pattern = copynode(n->nclist.pattern);
8186 new->nclist.next = copynode(n->nclist.next);
8187 break;
8188 case NDEFUN:
8189 case NARG:
8190 new->narg.backquote = copynodelist(n->narg.backquote);
8191 new->narg.text = nodeckstrdup(n->narg.text);
8192 new->narg.next = copynode(n->narg.next);
8193 break;
8194 case NTO:
8195 #if ENABLE_ASH_BASH_COMPAT
8196 case NTO2:
8197 #endif
8198 case NCLOBBER:
8199 case NFROM:
8200 case NFROMTO:
8201 case NAPPEND:
8202 new->nfile.fname = copynode(n->nfile.fname);
8203 new->nfile.fd = n->nfile.fd;
8204 new->nfile.next = copynode(n->nfile.next);
8205 break;
8206 case NTOFD:
8207 case NFROMFD:
8208 new->ndup.vname = copynode(n->ndup.vname);
8209 new->ndup.dupfd = n->ndup.dupfd;
8210 new->ndup.fd = n->ndup.fd;
8211 new->ndup.next = copynode(n->ndup.next);
8212 break;
8213 case NHERE:
8214 case NXHERE:
8215 new->nhere.doc = copynode(n->nhere.doc);
8216 new->nhere.fd = n->nhere.fd;
8217 new->nhere.next = copynode(n->nhere.next);
8218 break;
8219 case NNOT:
8220 new->nnot.com = copynode(n->nnot.com);
8221 break;
8223 new->type = n->type;
8224 return new;
8228 * Make a copy of a parse tree.
8230 static struct funcnode *
8231 copyfunc(union node *n)
8233 struct funcnode *f;
8234 size_t blocksize;
8236 funcblocksize = offsetof(struct funcnode, n);
8237 funcstringsize = 0;
8238 calcsize(n);
8239 blocksize = funcblocksize;
8240 f = ckmalloc(blocksize + funcstringsize);
8241 funcblock = (char *) f + offsetof(struct funcnode, n);
8242 funcstring = (char *) f + blocksize;
8243 copynode(n);
8244 f->count = 0;
8245 return f;
8249 * Define a shell function.
8251 static void
8252 defun(char *name, union node *func)
8254 struct cmdentry entry;
8256 INT_OFF;
8257 entry.cmdtype = CMDFUNCTION;
8258 entry.u.func = copyfunc(func);
8259 addcmdentry(name, &entry);
8260 INT_ON;
8263 /* Reasons for skipping commands (see comment on breakcmd routine) */
8264 #define SKIPBREAK (1 << 0)
8265 #define SKIPCONT (1 << 1)
8266 #define SKIPFUNC (1 << 2)
8267 #define SKIPFILE (1 << 3)
8268 #define SKIPEVAL (1 << 4)
8269 static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
8270 static int skipcount; /* number of levels to skip */
8271 static int funcnest; /* depth of function calls */
8272 static int loopnest; /* current loop nesting level */
8274 /* Forward decl way out to parsing code - dotrap needs it */
8275 static int evalstring(char *s, int mask);
8277 /* Called to execute a trap.
8278 * Single callsite - at the end of evaltree().
8279 * If we return non-zero, evaltree raises EXEXIT exception.
8281 * Perhaps we should avoid entering new trap handlers
8282 * while we are executing a trap handler. [is it a TODO?]
8284 static int
8285 dotrap(void)
8287 uint8_t *g;
8288 int sig;
8289 uint8_t savestatus;
8291 savestatus = exitstatus;
8292 pending_sig = 0;
8293 xbarrier();
8295 TRACE(("dotrap entered\n"));
8296 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8297 int want_exexit;
8298 char *t;
8300 if (*g == 0)
8301 continue;
8302 t = trap[sig];
8303 /* non-trapped SIGINT is handled separately by raise_interrupt,
8304 * don't upset it by resetting gotsig[SIGINT-1] */
8305 if (sig == SIGINT && !t)
8306 continue;
8308 TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
8309 *g = 0;
8310 if (!t)
8311 continue;
8312 want_exexit = evalstring(t, SKIPEVAL);
8313 exitstatus = savestatus;
8314 if (want_exexit) {
8315 TRACE(("dotrap returns %d\n", want_exexit));
8316 return want_exexit;
8320 TRACE(("dotrap returns 0\n"));
8321 return 0;
8324 /* forward declarations - evaluation is fairly recursive business... */
8325 static void evalloop(union node *, int);
8326 static void evalfor(union node *, int);
8327 static void evalcase(union node *, int);
8328 static void evalsubshell(union node *, int);
8329 static void expredir(union node *);
8330 static void evalpipe(union node *, int);
8331 static void evalcommand(union node *, int);
8332 static int evalbltin(const struct builtincmd *, int, char **);
8333 static void prehash(union node *);
8336 * Evaluate a parse tree. The value is left in the global variable
8337 * exitstatus.
8339 static void
8340 evaltree(union node *n, int flags)
8342 struct jmploc *volatile savehandler = exception_handler;
8343 struct jmploc jmploc;
8344 int checkexit = 0;
8345 void (*evalfn)(union node *, int);
8346 int status;
8347 int int_level;
8349 SAVE_INT(int_level);
8351 if (n == NULL) {
8352 TRACE(("evaltree(NULL) called\n"));
8353 goto out1;
8355 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
8357 exception_handler = &jmploc;
8359 int err = setjmp(jmploc.loc);
8360 if (err) {
8361 /* if it was a signal, check for trap handlers */
8362 if (exception_type == EXSIG) {
8363 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8364 exception_type, err));
8365 goto out;
8367 /* continue on the way out */
8368 TRACE(("exception %d in evaltree, propagating err=%d\n",
8369 exception_type, err));
8370 exception_handler = savehandler;
8371 longjmp(exception_handler->loc, err);
8375 switch (n->type) {
8376 default:
8377 #if DEBUG
8378 out1fmt("Node type = %d\n", n->type);
8379 fflush_all();
8380 break;
8381 #endif
8382 case NNOT:
8383 evaltree(n->nnot.com, EV_TESTED);
8384 status = !exitstatus;
8385 goto setstatus;
8386 case NREDIR:
8387 expredir(n->nredir.redirect);
8388 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8389 if (!status) {
8390 evaltree(n->nredir.n, flags & EV_TESTED);
8391 status = exitstatus;
8393 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
8394 goto setstatus;
8395 case NCMD:
8396 evalfn = evalcommand;
8397 checkexit:
8398 if (eflag && !(flags & EV_TESTED))
8399 checkexit = ~0;
8400 goto calleval;
8401 case NFOR:
8402 evalfn = evalfor;
8403 goto calleval;
8404 case NWHILE:
8405 case NUNTIL:
8406 evalfn = evalloop;
8407 goto calleval;
8408 case NSUBSHELL:
8409 case NBACKGND:
8410 evalfn = evalsubshell;
8411 goto calleval;
8412 case NPIPE:
8413 evalfn = evalpipe;
8414 goto checkexit;
8415 case NCASE:
8416 evalfn = evalcase;
8417 goto calleval;
8418 case NAND:
8419 case NOR:
8420 case NSEMI: {
8422 #if NAND + 1 != NOR
8423 #error NAND + 1 != NOR
8424 #endif
8425 #if NOR + 1 != NSEMI
8426 #error NOR + 1 != NSEMI
8427 #endif
8428 unsigned is_or = n->type - NAND;
8429 evaltree(
8430 n->nbinary.ch1,
8431 (flags | ((is_or >> 1) - 1)) & EV_TESTED
8433 if ((!exitstatus) == is_or)
8434 break;
8435 if (!evalskip) {
8436 n = n->nbinary.ch2;
8437 evaln:
8438 evalfn = evaltree;
8439 calleval:
8440 evalfn(n, flags);
8441 break;
8443 break;
8445 case NIF:
8446 evaltree(n->nif.test, EV_TESTED);
8447 if (evalskip)
8448 break;
8449 if (exitstatus == 0) {
8450 n = n->nif.ifpart;
8451 goto evaln;
8453 if (n->nif.elsepart) {
8454 n = n->nif.elsepart;
8455 goto evaln;
8457 goto success;
8458 case NDEFUN:
8459 defun(n->narg.text, n->narg.next);
8460 success:
8461 status = 0;
8462 setstatus:
8463 exitstatus = status;
8464 break;
8467 out:
8468 exception_handler = savehandler;
8470 out1:
8471 /* Order of checks below is important:
8472 * signal handlers trigger before exit caused by "set -e".
8474 if (pending_sig && dotrap())
8475 goto exexit;
8476 if (checkexit & exitstatus)
8477 evalskip |= SKIPEVAL;
8479 if (flags & EV_EXIT) {
8480 exexit:
8481 raise_exception(EXEXIT);
8484 RESTORE_INT(int_level);
8485 TRACE(("leaving evaltree (no interrupts)\n"));
8488 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8489 static
8490 #endif
8491 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8493 static void
8494 evalloop(union node *n, int flags)
8496 int status;
8498 loopnest++;
8499 status = 0;
8500 flags &= EV_TESTED;
8501 for (;;) {
8502 int i;
8504 evaltree(n->nbinary.ch1, EV_TESTED);
8505 if (evalskip) {
8506 skipping:
8507 if (evalskip == SKIPCONT && --skipcount <= 0) {
8508 evalskip = 0;
8509 continue;
8511 if (evalskip == SKIPBREAK && --skipcount <= 0)
8512 evalskip = 0;
8513 break;
8515 i = exitstatus;
8516 if (n->type != NWHILE)
8517 i = !i;
8518 if (i != 0)
8519 break;
8520 evaltree(n->nbinary.ch2, flags);
8521 status = exitstatus;
8522 if (evalskip)
8523 goto skipping;
8525 loopnest--;
8526 exitstatus = status;
8529 static void
8530 evalfor(union node *n, int flags)
8532 struct arglist arglist;
8533 union node *argp;
8534 struct strlist *sp;
8535 struct stackmark smark;
8537 setstackmark(&smark);
8538 arglist.list = NULL;
8539 arglist.lastp = &arglist.list;
8540 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8541 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8542 /* XXX */
8543 if (evalskip)
8544 goto out;
8546 *arglist.lastp = NULL;
8548 exitstatus = 0;
8549 loopnest++;
8550 flags &= EV_TESTED;
8551 for (sp = arglist.list; sp; sp = sp->next) {
8552 setvar0(n->nfor.var, sp->text);
8553 evaltree(n->nfor.body, flags);
8554 if (evalskip) {
8555 if (evalskip == SKIPCONT && --skipcount <= 0) {
8556 evalskip = 0;
8557 continue;
8559 if (evalskip == SKIPBREAK && --skipcount <= 0)
8560 evalskip = 0;
8561 break;
8564 loopnest--;
8565 out:
8566 popstackmark(&smark);
8569 static void
8570 evalcase(union node *n, int flags)
8572 union node *cp;
8573 union node *patp;
8574 struct arglist arglist;
8575 struct stackmark smark;
8577 setstackmark(&smark);
8578 arglist.list = NULL;
8579 arglist.lastp = &arglist.list;
8580 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8581 exitstatus = 0;
8582 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8583 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8584 if (casematch(patp, arglist.list->text)) {
8585 if (evalskip == 0) {
8586 evaltree(cp->nclist.body, flags);
8588 goto out;
8592 out:
8593 popstackmark(&smark);
8597 * Kick off a subshell to evaluate a tree.
8599 static void
8600 evalsubshell(union node *n, int flags)
8602 struct job *jp;
8603 int backgnd = (n->type == NBACKGND);
8604 int status;
8606 expredir(n->nredir.redirect);
8607 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
8608 goto nofork;
8609 INT_OFF;
8610 jp = makejob(/*n,*/ 1);
8611 if (forkshell(jp, n, backgnd) == 0) {
8612 /* child */
8613 INT_ON;
8614 flags |= EV_EXIT;
8615 if (backgnd)
8616 flags &= ~EV_TESTED;
8617 nofork:
8618 redirect(n->nredir.redirect, 0);
8619 evaltreenr(n->nredir.n, flags);
8620 /* never returns */
8622 status = 0;
8623 if (!backgnd)
8624 status = waitforjob(jp);
8625 exitstatus = status;
8626 INT_ON;
8630 * Compute the names of the files in a redirection list.
8632 static void fixredir(union node *, const char *, int);
8633 static void
8634 expredir(union node *n)
8636 union node *redir;
8638 for (redir = n; redir; redir = redir->nfile.next) {
8639 struct arglist fn;
8641 fn.list = NULL;
8642 fn.lastp = &fn.list;
8643 switch (redir->type) {
8644 case NFROMTO:
8645 case NFROM:
8646 case NTO:
8647 #if ENABLE_ASH_BASH_COMPAT
8648 case NTO2:
8649 #endif
8650 case NCLOBBER:
8651 case NAPPEND:
8652 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8653 TRACE(("expredir expanded to '%s'\n", fn.list->text));
8654 #if ENABLE_ASH_BASH_COMPAT
8655 store_expfname:
8656 #endif
8657 #if 0
8658 // By the design of stack allocator, the loop of this kind:
8659 // while true; do while true; do break; done </dev/null; done
8660 // will look like a memory leak: ash plans to free expfname's
8661 // of "/dev/null" as soon as it finishes running the loop
8662 // (in this case, never).
8663 // This "fix" is wrong:
8664 if (redir->nfile.expfname)
8665 stunalloc(redir->nfile.expfname);
8666 // It results in corrupted state of stacked allocations.
8667 #endif
8668 redir->nfile.expfname = fn.list->text;
8669 break;
8670 case NFROMFD:
8671 case NTOFD: /* >& */
8672 if (redir->ndup.vname) {
8673 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8674 if (fn.list == NULL)
8675 ash_msg_and_raise_error("redir error");
8676 #if ENABLE_ASH_BASH_COMPAT
8677 //FIXME: we used expandarg with different args!
8678 if (!isdigit_str9(fn.list->text)) {
8679 /* >&file, not >&fd */
8680 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8681 ash_msg_and_raise_error("redir error");
8682 redir->type = NTO2;
8683 goto store_expfname;
8685 #endif
8686 fixredir(redir, fn.list->text, 1);
8688 break;
8694 * Evaluate a pipeline. All the processes in the pipeline are children
8695 * of the process creating the pipeline. (This differs from some versions
8696 * of the shell, which make the last process in a pipeline the parent
8697 * of all the rest.)
8699 static void
8700 evalpipe(union node *n, int flags)
8702 struct job *jp;
8703 struct nodelist *lp;
8704 int pipelen;
8705 int prevfd;
8706 int pip[2];
8708 TRACE(("evalpipe(0x%lx) called\n", (long)n));
8709 pipelen = 0;
8710 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8711 pipelen++;
8712 flags |= EV_EXIT;
8713 INT_OFF;
8714 jp = makejob(/*n,*/ pipelen);
8715 prevfd = -1;
8716 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8717 prehash(lp->n);
8718 pip[1] = -1;
8719 if (lp->next) {
8720 if (pipe(pip) < 0) {
8721 close(prevfd);
8722 ash_msg_and_raise_error("pipe call failed");
8725 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8726 INT_ON;
8727 if (pip[1] >= 0) {
8728 close(pip[0]);
8730 if (prevfd > 0) {
8731 dup2(prevfd, 0);
8732 close(prevfd);
8734 if (pip[1] > 1) {
8735 dup2(pip[1], 1);
8736 close(pip[1]);
8738 evaltreenr(lp->n, flags);
8739 /* never returns */
8741 if (prevfd >= 0)
8742 close(prevfd);
8743 prevfd = pip[0];
8744 /* Don't want to trigger debugging */
8745 if (pip[1] != -1)
8746 close(pip[1]);
8748 if (n->npipe.pipe_backgnd == 0) {
8749 exitstatus = waitforjob(jp);
8750 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
8752 INT_ON;
8756 * Controls whether the shell is interactive or not.
8758 static void
8759 setinteractive(int on)
8761 static smallint is_interactive;
8763 if (++on == is_interactive)
8764 return;
8765 is_interactive = on;
8766 setsignal(SIGINT);
8767 setsignal(SIGQUIT);
8768 setsignal(SIGTERM);
8769 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8770 if (is_interactive > 1) {
8771 /* Looks like they want an interactive shell */
8772 static smallint did_banner;
8774 if (!did_banner) {
8775 /* note: ash and hush share this string */
8776 out1fmt("\n\n%s %s\n"
8777 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8778 "\n",
8779 bb_banner,
8780 "built-in shell (ash)"
8782 did_banner = 1;
8785 #endif
8788 static void
8789 optschanged(void)
8791 #if DEBUG
8792 opentrace();
8793 #endif
8794 setinteractive(iflag);
8795 setjobctl(mflag);
8796 #if ENABLE_FEATURE_EDITING_VI
8797 if (viflag)
8798 line_input_state->flags |= VI_MODE;
8799 else
8800 line_input_state->flags &= ~VI_MODE;
8801 #else
8802 viflag = 0; /* forcibly keep the option off */
8803 #endif
8806 static struct localvar *localvars;
8809 * Called after a function returns.
8810 * Interrupts must be off.
8812 static void
8813 poplocalvars(void)
8815 struct localvar *lvp;
8816 struct var *vp;
8818 while ((lvp = localvars) != NULL) {
8819 localvars = lvp->next;
8820 vp = lvp->vp;
8821 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
8822 if (vp == NULL) { /* $- saved */
8823 memcpy(optlist, lvp->text, sizeof(optlist));
8824 free((char*)lvp->text);
8825 optschanged();
8826 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8827 unsetvar(vp->var_text);
8828 } else {
8829 if (vp->var_func)
8830 vp->var_func(var_end(lvp->text));
8831 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8832 free((char*)vp->var_text);
8833 vp->flags = lvp->flags;
8834 vp->var_text = lvp->text;
8836 free(lvp);
8840 static int
8841 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8843 volatile struct shparam saveparam;
8844 struct localvar *volatile savelocalvars;
8845 struct jmploc *volatile savehandler;
8846 struct jmploc jmploc;
8847 int e;
8849 saveparam = shellparam;
8850 savelocalvars = localvars;
8851 e = setjmp(jmploc.loc);
8852 if (e) {
8853 goto funcdone;
8855 INT_OFF;
8856 savehandler = exception_handler;
8857 exception_handler = &jmploc;
8858 localvars = NULL;
8859 shellparam.malloced = 0;
8860 func->count++;
8861 funcnest++;
8862 INT_ON;
8863 shellparam.nparam = argc - 1;
8864 shellparam.p = argv + 1;
8865 #if ENABLE_ASH_GETOPTS
8866 shellparam.optind = 1;
8867 shellparam.optoff = -1;
8868 #endif
8869 evaltree(&func->n, flags & EV_TESTED);
8870 funcdone:
8871 INT_OFF;
8872 funcnest--;
8873 freefunc(func);
8874 poplocalvars();
8875 localvars = savelocalvars;
8876 freeparam(&shellparam);
8877 shellparam = saveparam;
8878 exception_handler = savehandler;
8879 INT_ON;
8880 evalskip &= ~SKIPFUNC;
8881 return e;
8884 #if ENABLE_ASH_CMDCMD
8885 static char **
8886 parse_command_args(char **argv, const char **path)
8888 char *cp, c;
8890 for (;;) {
8891 cp = *++argv;
8892 if (!cp)
8893 return NULL;
8894 if (*cp++ != '-')
8895 break;
8896 c = *cp++;
8897 if (!c)
8898 break;
8899 if (c == '-' && !*cp) {
8900 if (!*++argv)
8901 return NULL;
8902 break;
8904 do {
8905 switch (c) {
8906 case 'p':
8907 *path = bb_default_path;
8908 break;
8909 default:
8910 /* run 'typecmd' for other options */
8911 return NULL;
8913 c = *cp++;
8914 } while (c);
8916 return argv;
8918 #endif
8921 * Make a variable a local variable. When a variable is made local, it's
8922 * value and flags are saved in a localvar structure. The saved values
8923 * will be restored when the shell function returns. We handle the name
8924 * "-" as a special case: it makes changes to "set +-options" local
8925 * (options will be restored on return from the function).
8927 static void
8928 mklocal(char *name)
8930 struct localvar *lvp;
8931 struct var **vpp;
8932 struct var *vp;
8933 char *eq = strchr(name, '=');
8935 INT_OFF;
8936 /* Cater for duplicate "local". Examples:
8937 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
8938 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
8940 lvp = localvars;
8941 while (lvp) {
8942 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
8943 if (eq)
8944 setvareq(name, 0);
8945 /* else:
8946 * it's a duplicate "local VAR" declaration, do nothing
8948 return;
8950 lvp = lvp->next;
8953 lvp = ckzalloc(sizeof(*lvp));
8954 if (LONE_DASH(name)) {
8955 char *p;
8956 p = ckmalloc(sizeof(optlist));
8957 lvp->text = memcpy(p, optlist, sizeof(optlist));
8958 vp = NULL;
8959 } else {
8960 vpp = hashvar(name);
8961 vp = *findvar(vpp, name);
8962 if (vp == NULL) {
8963 /* variable did not exist yet */
8964 if (eq)
8965 setvareq(name, VSTRFIXED);
8966 else
8967 setvar(name, NULL, VSTRFIXED);
8968 vp = *vpp; /* the new variable */
8969 lvp->flags = VUNSET;
8970 } else {
8971 lvp->text = vp->var_text;
8972 lvp->flags = vp->flags;
8973 /* make sure neither "struct var" nor string gets freed
8974 * during (un)setting:
8976 vp->flags |= VSTRFIXED|VTEXTFIXED;
8977 if (eq)
8978 setvareq(name, 0);
8979 else
8980 /* "local VAR" unsets VAR: */
8981 setvar0(name, NULL);
8984 lvp->vp = vp;
8985 lvp->next = localvars;
8986 localvars = lvp;
8987 INT_ON;
8991 * The "local" command.
8993 static int FAST_FUNC
8994 localcmd(int argc UNUSED_PARAM, char **argv)
8996 char *name;
8998 if (!funcnest)
8999 ash_msg_and_raise_error("not in a function");
9001 argv = argptr;
9002 while ((name = *argv++) != NULL) {
9003 mklocal(name);
9005 return 0;
9008 static int FAST_FUNC
9009 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9011 return 1;
9014 static int FAST_FUNC
9015 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9017 return 0;
9020 static int FAST_FUNC
9021 execcmd(int argc UNUSED_PARAM, char **argv)
9023 if (argv[1]) {
9024 iflag = 0; /* exit on error */
9025 mflag = 0;
9026 optschanged();
9027 shellexec(argv + 1, pathval(), 0);
9029 return 0;
9033 * The return command.
9035 static int FAST_FUNC
9036 returncmd(int argc UNUSED_PARAM, char **argv)
9039 * If called outside a function, do what ksh does;
9040 * skip the rest of the file.
9042 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
9043 return argv[1] ? number(argv[1]) : exitstatus;
9046 /* Forward declarations for builtintab[] */
9047 static int breakcmd(int, char **) FAST_FUNC;
9048 static int dotcmd(int, char **) FAST_FUNC;
9049 static int evalcmd(int, char **) FAST_FUNC;
9050 static int exitcmd(int, char **) FAST_FUNC;
9051 static int exportcmd(int, char **) FAST_FUNC;
9052 #if ENABLE_ASH_GETOPTS
9053 static int getoptscmd(int, char **) FAST_FUNC;
9054 #endif
9055 #if ENABLE_ASH_HELP
9056 static int helpcmd(int, char **) FAST_FUNC;
9057 #endif
9058 #if MAX_HISTORY
9059 static int historycmd(int, char **) FAST_FUNC;
9060 #endif
9061 #if ENABLE_SH_MATH_SUPPORT
9062 static int letcmd(int, char **) FAST_FUNC;
9063 #endif
9064 static int readcmd(int, char **) FAST_FUNC;
9065 static int setcmd(int, char **) FAST_FUNC;
9066 static int shiftcmd(int, char **) FAST_FUNC;
9067 static int timescmd(int, char **) FAST_FUNC;
9068 static int trapcmd(int, char **) FAST_FUNC;
9069 static int umaskcmd(int, char **) FAST_FUNC;
9070 static int unsetcmd(int, char **) FAST_FUNC;
9071 static int ulimitcmd(int, char **) FAST_FUNC;
9073 #define BUILTIN_NOSPEC "0"
9074 #define BUILTIN_SPECIAL "1"
9075 #define BUILTIN_REGULAR "2"
9076 #define BUILTIN_SPEC_REG "3"
9077 #define BUILTIN_ASSIGN "4"
9078 #define BUILTIN_SPEC_ASSG "5"
9079 #define BUILTIN_REG_ASSG "6"
9080 #define BUILTIN_SPEC_REG_ASSG "7"
9082 /* Stubs for calling non-FAST_FUNC's */
9083 #if ENABLE_ASH_BUILTIN_ECHO
9084 static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
9085 #endif
9086 #if ENABLE_ASH_BUILTIN_PRINTF
9087 static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
9088 #endif
9089 #if ENABLE_ASH_BUILTIN_TEST
9090 static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
9091 #endif
9093 /* Keep these in proper order since it is searched via bsearch() */
9094 static const struct builtincmd builtintab[] = {
9095 { BUILTIN_SPEC_REG "." , dotcmd },
9096 { BUILTIN_SPEC_REG ":" , truecmd },
9097 #if ENABLE_ASH_BUILTIN_TEST
9098 { BUILTIN_REGULAR "[" , testcmd },
9099 #if ENABLE_ASH_BASH_COMPAT
9100 { BUILTIN_REGULAR "[[" , testcmd },
9101 #endif
9102 #endif
9103 #if ENABLE_ASH_ALIAS
9104 { BUILTIN_REG_ASSG "alias" , aliascmd },
9105 #endif
9106 #if JOBS
9107 { BUILTIN_REGULAR "bg" , fg_bgcmd },
9108 #endif
9109 { BUILTIN_SPEC_REG "break" , breakcmd },
9110 { BUILTIN_REGULAR "cd" , cdcmd },
9111 { BUILTIN_NOSPEC "chdir" , cdcmd },
9112 #if ENABLE_ASH_CMDCMD
9113 { BUILTIN_REGULAR "command" , commandcmd },
9114 #endif
9115 { BUILTIN_SPEC_REG "continue", breakcmd },
9116 #if ENABLE_ASH_BUILTIN_ECHO
9117 { BUILTIN_REGULAR "echo" , echocmd },
9118 #endif
9119 { BUILTIN_SPEC_REG "eval" , evalcmd },
9120 { BUILTIN_SPEC_REG "exec" , execcmd },
9121 { BUILTIN_SPEC_REG "exit" , exitcmd },
9122 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9123 { BUILTIN_REGULAR "false" , falsecmd },
9124 #if JOBS
9125 { BUILTIN_REGULAR "fg" , fg_bgcmd },
9126 #endif
9127 #if ENABLE_ASH_GETOPTS
9128 { BUILTIN_REGULAR "getopts" , getoptscmd },
9129 #endif
9130 { BUILTIN_NOSPEC "hash" , hashcmd },
9131 #if ENABLE_ASH_HELP
9132 { BUILTIN_NOSPEC "help" , helpcmd },
9133 #endif
9134 #if MAX_HISTORY
9135 { BUILTIN_NOSPEC "history" , historycmd },
9136 #endif
9137 #if JOBS
9138 { BUILTIN_REGULAR "jobs" , jobscmd },
9139 { BUILTIN_REGULAR "kill" , killcmd },
9140 #endif
9141 #if ENABLE_SH_MATH_SUPPORT
9142 { BUILTIN_NOSPEC "let" , letcmd },
9143 #endif
9144 { BUILTIN_ASSIGN "local" , localcmd },
9145 #if ENABLE_ASH_BUILTIN_PRINTF
9146 { BUILTIN_REGULAR "printf" , printfcmd },
9147 #endif
9148 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9149 { BUILTIN_REGULAR "read" , readcmd },
9150 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9151 { BUILTIN_SPEC_REG "return" , returncmd },
9152 { BUILTIN_SPEC_REG "set" , setcmd },
9153 { BUILTIN_SPEC_REG "shift" , shiftcmd },
9154 #if ENABLE_ASH_BASH_COMPAT
9155 { BUILTIN_SPEC_REG "source" , dotcmd },
9156 #endif
9157 #if ENABLE_ASH_BUILTIN_TEST
9158 { BUILTIN_REGULAR "test" , testcmd },
9159 #endif
9160 { BUILTIN_SPEC_REG "times" , timescmd },
9161 { BUILTIN_SPEC_REG "trap" , trapcmd },
9162 { BUILTIN_REGULAR "true" , truecmd },
9163 { BUILTIN_NOSPEC "type" , typecmd },
9164 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9165 { BUILTIN_REGULAR "umask" , umaskcmd },
9166 #if ENABLE_ASH_ALIAS
9167 { BUILTIN_REGULAR "unalias" , unaliascmd },
9168 #endif
9169 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9170 { BUILTIN_REGULAR "wait" , waitcmd },
9173 /* Should match the above table! */
9174 #define COMMANDCMD (builtintab + \
9175 2 + \
9176 1 * ENABLE_ASH_BUILTIN_TEST + \
9177 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9178 1 * ENABLE_ASH_ALIAS + \
9179 1 * ENABLE_ASH_JOB_CONTROL + \
9181 #define EXECCMD (builtintab + \
9182 2 + \
9183 1 * ENABLE_ASH_BUILTIN_TEST + \
9184 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9185 1 * ENABLE_ASH_ALIAS + \
9186 1 * ENABLE_ASH_JOB_CONTROL + \
9187 3 + \
9188 1 * ENABLE_ASH_CMDCMD + \
9189 1 + \
9190 ENABLE_ASH_BUILTIN_ECHO + \
9194 * Search the table of builtin commands.
9196 static struct builtincmd *
9197 find_builtin(const char *name)
9199 struct builtincmd *bp;
9201 bp = bsearch(
9202 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
9203 pstrcmp
9205 return bp;
9209 * Execute a simple command.
9211 static int
9212 isassignment(const char *p)
9214 const char *q = endofname(p);
9215 if (p == q)
9216 return 0;
9217 return *q == '=';
9219 static int FAST_FUNC
9220 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9222 /* Preserve exitstatus of a previous possible redirection
9223 * as POSIX mandates */
9224 return back_exitstatus;
9226 static void
9227 evalcommand(union node *cmd, int flags)
9229 static const struct builtincmd null_bltin = {
9230 "\0\0", bltincmd /* why three NULs? */
9232 struct stackmark smark;
9233 union node *argp;
9234 struct arglist arglist;
9235 struct arglist varlist;
9236 char **argv;
9237 int argc;
9238 const struct strlist *sp;
9239 struct cmdentry cmdentry;
9240 struct job *jp;
9241 char *lastarg;
9242 const char *path;
9243 int spclbltin;
9244 int status;
9245 char **nargv;
9246 struct builtincmd *bcmd;
9247 smallint cmd_is_exec;
9248 smallint pseudovarflag = 0;
9250 /* First expand the arguments. */
9251 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9252 setstackmark(&smark);
9253 back_exitstatus = 0;
9255 cmdentry.cmdtype = CMDBUILTIN;
9256 cmdentry.u.cmd = &null_bltin;
9257 varlist.lastp = &varlist.list;
9258 *varlist.lastp = NULL;
9259 arglist.lastp = &arglist.list;
9260 *arglist.lastp = NULL;
9262 argc = 0;
9263 if (cmd->ncmd.args) {
9264 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9265 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9268 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9269 struct strlist **spp;
9271 spp = arglist.lastp;
9272 if (pseudovarflag && isassignment(argp->narg.text))
9273 expandarg(argp, &arglist, EXP_VARTILDE);
9274 else
9275 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9277 for (sp = *spp; sp; sp = sp->next)
9278 argc++;
9281 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
9282 for (sp = arglist.list; sp; sp = sp->next) {
9283 TRACE(("evalcommand arg: %s\n", sp->text));
9284 *nargv++ = sp->text;
9286 *nargv = NULL;
9288 lastarg = NULL;
9289 if (iflag && funcnest == 0 && argc > 0)
9290 lastarg = nargv[-1];
9292 preverrout_fd = 2;
9293 expredir(cmd->ncmd.redirect);
9294 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
9296 path = vpath.var_text;
9297 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9298 struct strlist **spp;
9299 char *p;
9301 spp = varlist.lastp;
9302 expandarg(argp, &varlist, EXP_VARTILDE);
9305 * Modify the command lookup path, if a PATH= assignment
9306 * is present
9308 p = (*spp)->text;
9309 if (varcmp(p, path) == 0)
9310 path = p;
9313 /* Print the command if xflag is set. */
9314 if (xflag) {
9315 int n;
9316 const char *p = " %s" + 1;
9318 fdprintf(preverrout_fd, p, expandstr(ps4val()));
9319 sp = varlist.list;
9320 for (n = 0; n < 2; n++) {
9321 while (sp) {
9322 fdprintf(preverrout_fd, p, sp->text);
9323 sp = sp->next;
9324 p = " %s";
9326 sp = arglist.list;
9328 safe_write(preverrout_fd, "\n", 1);
9331 cmd_is_exec = 0;
9332 spclbltin = -1;
9334 /* Now locate the command. */
9335 if (argc) {
9336 int cmd_flag = DO_ERR;
9337 #if ENABLE_ASH_CMDCMD
9338 const char *oldpath = path + 5;
9339 #endif
9340 path += 5;
9341 for (;;) {
9342 find_command(argv[0], &cmdentry, cmd_flag, path);
9343 if (cmdentry.cmdtype == CMDUNKNOWN) {
9344 flush_stdout_stderr();
9345 status = 127;
9346 goto bail;
9349 /* implement bltin and command here */
9350 if (cmdentry.cmdtype != CMDBUILTIN)
9351 break;
9352 if (spclbltin < 0)
9353 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9354 if (cmdentry.u.cmd == EXECCMD)
9355 cmd_is_exec = 1;
9356 #if ENABLE_ASH_CMDCMD
9357 if (cmdentry.u.cmd == COMMANDCMD) {
9358 path = oldpath;
9359 nargv = parse_command_args(argv, &path);
9360 if (!nargv)
9361 break;
9362 argc -= nargv - argv;
9363 argv = nargv;
9364 cmd_flag |= DO_NOFUNC;
9365 } else
9366 #endif
9367 break;
9371 if (status) {
9372 /* We have a redirection error. */
9373 if (spclbltin > 0)
9374 raise_exception(EXERROR);
9375 bail:
9376 exitstatus = status;
9377 goto out;
9380 /* Execute the command. */
9381 switch (cmdentry.cmdtype) {
9382 default: {
9384 #if ENABLE_FEATURE_SH_NOFORK
9385 /* (1) BUG: if variables are set, we need to fork, or save/restore them
9386 * around run_nofork_applet() call.
9387 * (2) Should this check also be done in forkshell()?
9388 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9390 /* find_command() encodes applet_no as (-2 - applet_no) */
9391 int applet_no = (- cmdentry.u.index - 2);
9392 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
9393 listsetvar(varlist.list, VEXPORT|VSTACK);
9394 /* run <applet>_main() */
9395 exitstatus = run_nofork_applet(applet_no, argv);
9396 break;
9398 #endif
9399 /* Can we avoid forking off? For example, very last command
9400 * in a script or a subshell does not need forking,
9401 * we can just exec it.
9403 if (!(flags & EV_EXIT) || may_have_traps) {
9404 /* No, forking off a child is necessary */
9405 INT_OFF;
9406 jp = makejob(/*cmd,*/ 1);
9407 if (forkshell(jp, cmd, FORK_FG) != 0) {
9408 /* parent */
9409 exitstatus = waitforjob(jp);
9410 INT_ON;
9411 TRACE(("forked child exited with %d\n", exitstatus));
9412 break;
9414 /* child */
9415 FORCE_INT_ON;
9416 /* fall through to exec'ing external program */
9418 listsetvar(varlist.list, VEXPORT|VSTACK);
9419 shellexec(argv, path, cmdentry.u.index);
9420 /* NOTREACHED */
9421 } /* default */
9422 case CMDBUILTIN:
9423 cmdenviron = varlist.list;
9424 if (cmdenviron) {
9425 struct strlist *list = cmdenviron;
9426 int i = VNOSET;
9427 if (spclbltin > 0 || argc == 0) {
9428 i = 0;
9429 if (cmd_is_exec && argc > 1)
9430 i = VEXPORT;
9432 listsetvar(list, i);
9434 /* Tight loop with builtins only:
9435 * "while kill -0 $child; do true; done"
9436 * will never exit even if $child died, unless we do this
9437 * to reap the zombie and make kill detect that it's gone: */
9438 dowait(DOWAIT_NONBLOCK, NULL);
9440 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9441 int exit_status;
9442 int i = exception_type;
9443 if (i == EXEXIT || i == EXEXEC)
9444 goto raise;
9445 exit_status = 2;
9446 if (i == EXINT)
9447 exit_status = 128 + SIGINT;
9448 if (i == EXSIG)
9449 exit_status = 128 + pending_sig;
9450 exitstatus = exit_status;
9451 if (i == EXINT || spclbltin > 0) {
9452 raise:
9453 longjmp(exception_handler->loc, 1);
9455 FORCE_INT_ON;
9457 break;
9459 case CMDFUNCTION:
9460 listsetvar(varlist.list, 0);
9461 /* See above for the rationale */
9462 dowait(DOWAIT_NONBLOCK, NULL);
9463 if (evalfun(cmdentry.u.func, argc, argv, flags))
9464 goto raise;
9465 break;
9466 } /* switch */
9468 out:
9469 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
9470 if (lastarg) {
9471 /* dsl: I think this is intended to be used to support
9472 * '_' in 'vi' command mode during line editing...
9473 * However I implemented that within libedit itself.
9475 setvar0("_", lastarg);
9477 popstackmark(&smark);
9480 static int
9481 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9483 char *volatile savecmdname;
9484 struct jmploc *volatile savehandler;
9485 struct jmploc jmploc;
9486 int i;
9488 savecmdname = commandname;
9489 i = setjmp(jmploc.loc);
9490 if (i)
9491 goto cmddone;
9492 savehandler = exception_handler;
9493 exception_handler = &jmploc;
9494 commandname = argv[0];
9495 argptr = argv + 1;
9496 optptr = NULL; /* initialize nextopt */
9497 exitstatus = (*cmd->builtin)(argc, argv);
9498 flush_stdout_stderr();
9499 cmddone:
9500 exitstatus |= ferror(stdout);
9501 clearerr(stdout);
9502 commandname = savecmdname;
9503 exception_handler = savehandler;
9505 return i;
9508 static int
9509 goodname(const char *p)
9511 return endofname(p)[0] == '\0';
9516 * Search for a command. This is called before we fork so that the
9517 * location of the command will be available in the parent as well as
9518 * the child. The check for "goodname" is an overly conservative
9519 * check that the name will not be subject to expansion.
9521 static void
9522 prehash(union node *n)
9524 struct cmdentry entry;
9526 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9527 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9531 /* ============ Builtin commands
9533 * Builtin commands whose functions are closely tied to evaluation
9534 * are implemented here.
9538 * Handle break and continue commands. Break, continue, and return are
9539 * all handled by setting the evalskip flag. The evaluation routines
9540 * above all check this flag, and if it is set they start skipping
9541 * commands rather than executing them. The variable skipcount is
9542 * the number of loops to break/continue, or the number of function
9543 * levels to return. (The latter is always 1.) It should probably
9544 * be an error to break out of more loops than exist, but it isn't
9545 * in the standard shell so we don't make it one here.
9547 static int FAST_FUNC
9548 breakcmd(int argc UNUSED_PARAM, char **argv)
9550 int n = argv[1] ? number(argv[1]) : 1;
9552 if (n <= 0)
9553 ash_msg_and_raise_error(msg_illnum, argv[1]);
9554 if (n > loopnest)
9555 n = loopnest;
9556 if (n > 0) {
9557 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9558 skipcount = n;
9560 return 0;
9564 /* ============ input.c
9566 * This implements the input routines used by the parser.
9569 enum {
9570 INPUT_PUSH_FILE = 1,
9571 INPUT_NOFILE_OK = 2,
9574 static smallint checkkwd;
9575 /* values of checkkwd variable */
9576 #define CHKALIAS 0x1
9577 #define CHKKWD 0x2
9578 #define CHKNL 0x4
9581 * Push a string back onto the input at this current parsefile level.
9582 * We handle aliases this way.
9584 #if !ENABLE_ASH_ALIAS
9585 #define pushstring(s, ap) pushstring(s)
9586 #endif
9587 static void
9588 pushstring(char *s, struct alias *ap)
9590 struct strpush *sp;
9591 int len;
9593 len = strlen(s);
9594 INT_OFF;
9595 if (g_parsefile->strpush) {
9596 sp = ckzalloc(sizeof(*sp));
9597 sp->prev = g_parsefile->strpush;
9598 } else {
9599 sp = &(g_parsefile->basestrpush);
9601 g_parsefile->strpush = sp;
9602 sp->prev_string = g_parsefile->next_to_pgetc;
9603 sp->prev_left_in_line = g_parsefile->left_in_line;
9604 #if ENABLE_ASH_ALIAS
9605 sp->ap = ap;
9606 if (ap) {
9607 ap->flag |= ALIASINUSE;
9608 sp->string = s;
9610 #endif
9611 g_parsefile->next_to_pgetc = s;
9612 g_parsefile->left_in_line = len;
9613 INT_ON;
9616 static void
9617 popstring(void)
9619 struct strpush *sp = g_parsefile->strpush;
9621 INT_OFF;
9622 #if ENABLE_ASH_ALIAS
9623 if (sp->ap) {
9624 if (g_parsefile->next_to_pgetc[-1] == ' '
9625 || g_parsefile->next_to_pgetc[-1] == '\t'
9627 checkkwd |= CHKALIAS;
9629 if (sp->string != sp->ap->val) {
9630 free(sp->string);
9632 sp->ap->flag &= ~ALIASINUSE;
9633 if (sp->ap->flag & ALIASDEAD) {
9634 unalias(sp->ap->name);
9637 #endif
9638 g_parsefile->next_to_pgetc = sp->prev_string;
9639 g_parsefile->left_in_line = sp->prev_left_in_line;
9640 g_parsefile->strpush = sp->prev;
9641 if (sp != &(g_parsefile->basestrpush))
9642 free(sp);
9643 INT_ON;
9646 //FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9647 //it peeks whether it is &>, and then pushes back both chars.
9648 //This function needs to save last *next_to_pgetc to buf[0]
9649 //to make two pungetc() reliable. Currently,
9650 // pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
9651 static int
9652 preadfd(void)
9654 int nr;
9655 char *buf = g_parsefile->buf;
9657 g_parsefile->next_to_pgetc = buf;
9658 #if ENABLE_FEATURE_EDITING
9659 retry:
9660 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
9661 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
9662 else {
9663 int timeout = -1;
9664 # if ENABLE_ASH_IDLE_TIMEOUT
9665 if (iflag) {
9666 const char *tmout_var = lookupvar("TMOUT");
9667 if (tmout_var) {
9668 timeout = atoi(tmout_var) * 1000;
9669 if (timeout <= 0)
9670 timeout = -1;
9673 # endif
9674 # if ENABLE_FEATURE_TAB_COMPLETION
9675 line_input_state->path_lookup = pathval();
9676 # endif
9677 reinit_unicode_for_ash();
9678 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
9679 if (nr == 0) {
9680 /* Ctrl+C pressed */
9681 if (trap[SIGINT]) {
9682 buf[0] = '\n';
9683 buf[1] = '\0';
9684 raise(SIGINT);
9685 return 1;
9687 goto retry;
9689 if (nr < 0) {
9690 if (errno == 0) {
9691 /* Ctrl+D pressed */
9692 nr = 0;
9694 # if ENABLE_ASH_IDLE_TIMEOUT
9695 else if (errno == EAGAIN && timeout > 0) {
9696 puts("\007timed out waiting for input: auto-logout");
9697 exitshell();
9699 # endif
9702 #else
9703 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
9704 #endif
9706 #if 0 /* disabled: nonblock_immune_read() handles this problem */
9707 if (nr < 0) {
9708 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9709 int flags = fcntl(0, F_GETFL);
9710 if (flags >= 0 && (flags & O_NONBLOCK)) {
9711 flags &= ~O_NONBLOCK;
9712 if (fcntl(0, F_SETFL, flags) >= 0) {
9713 out2str("sh: turning off NDELAY mode\n");
9714 goto retry;
9719 #endif
9720 return nr;
9724 * Refill the input buffer and return the next input character:
9726 * 1) If a string was pushed back on the input, pop it;
9727 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9728 * or we are reading from a string so we can't refill the buffer,
9729 * return EOF.
9730 * 3) If there is more stuff in this buffer, use it else call read to fill it.
9731 * 4) Process input up to the next newline, deleting nul characters.
9733 //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9734 #define pgetc_debug(...) ((void)0)
9735 static int
9736 preadbuffer(void)
9738 char *q;
9739 int more;
9741 while (g_parsefile->strpush) {
9742 #if ENABLE_ASH_ALIAS
9743 if (g_parsefile->left_in_line == -1
9744 && g_parsefile->strpush->ap
9745 && g_parsefile->next_to_pgetc[-1] != ' '
9746 && g_parsefile->next_to_pgetc[-1] != '\t'
9748 pgetc_debug("preadbuffer PEOA");
9749 return PEOA;
9751 #endif
9752 popstring();
9753 /* try "pgetc" now: */
9754 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9755 g_parsefile->left_in_line,
9756 g_parsefile->next_to_pgetc,
9757 g_parsefile->next_to_pgetc);
9758 if (--g_parsefile->left_in_line >= 0)
9759 return (unsigned char)(*g_parsefile->next_to_pgetc++);
9761 /* on both branches above g_parsefile->left_in_line < 0.
9762 * "pgetc" needs refilling.
9765 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
9766 * pungetc() may increment it a few times.
9767 * Assuming it won't increment it to less than -90.
9769 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
9770 pgetc_debug("preadbuffer PEOF1");
9771 /* even in failure keep left_in_line and next_to_pgetc
9772 * in lock step, for correct multi-layer pungetc.
9773 * left_in_line was decremented before preadbuffer(),
9774 * must inc next_to_pgetc: */
9775 g_parsefile->next_to_pgetc++;
9776 return PEOF;
9779 more = g_parsefile->left_in_buffer;
9780 if (more <= 0) {
9781 flush_stdout_stderr();
9782 again:
9783 more = preadfd();
9784 if (more <= 0) {
9785 /* don't try reading again */
9786 g_parsefile->left_in_line = -99;
9787 pgetc_debug("preadbuffer PEOF2");
9788 g_parsefile->next_to_pgetc++;
9789 return PEOF;
9793 /* Find out where's the end of line.
9794 * Set g_parsefile->left_in_line
9795 * and g_parsefile->left_in_buffer acordingly.
9796 * NUL chars are deleted.
9798 q = g_parsefile->next_to_pgetc;
9799 for (;;) {
9800 char c;
9802 more--;
9804 c = *q;
9805 if (c == '\0') {
9806 memmove(q, q + 1, more);
9807 } else {
9808 q++;
9809 if (c == '\n') {
9810 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9811 break;
9815 if (more <= 0) {
9816 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9817 if (g_parsefile->left_in_line < 0)
9818 goto again;
9819 break;
9822 g_parsefile->left_in_buffer = more;
9824 if (vflag) {
9825 char save = *q;
9826 *q = '\0';
9827 out2str(g_parsefile->next_to_pgetc);
9828 *q = save;
9831 pgetc_debug("preadbuffer at %d:%p'%s'",
9832 g_parsefile->left_in_line,
9833 g_parsefile->next_to_pgetc,
9834 g_parsefile->next_to_pgetc);
9835 return (unsigned char)*g_parsefile->next_to_pgetc++;
9838 #define pgetc_as_macro() \
9839 (--g_parsefile->left_in_line >= 0 \
9840 ? (unsigned char)*g_parsefile->next_to_pgetc++ \
9841 : preadbuffer() \
9844 static int
9845 pgetc(void)
9847 pgetc_debug("pgetc_fast at %d:%p'%s'",
9848 g_parsefile->left_in_line,
9849 g_parsefile->next_to_pgetc,
9850 g_parsefile->next_to_pgetc);
9851 return pgetc_as_macro();
9854 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9855 # define pgetc_fast() pgetc()
9856 #else
9857 # define pgetc_fast() pgetc_as_macro()
9858 #endif
9860 #if ENABLE_ASH_ALIAS
9861 static int
9862 pgetc_without_PEOA(void)
9864 int c;
9865 do {
9866 pgetc_debug("pgetc_fast at %d:%p'%s'",
9867 g_parsefile->left_in_line,
9868 g_parsefile->next_to_pgetc,
9869 g_parsefile->next_to_pgetc);
9870 c = pgetc_fast();
9871 } while (c == PEOA);
9872 return c;
9874 #else
9875 # define pgetc_without_PEOA() pgetc()
9876 #endif
9879 * Read a line from the script.
9881 static char *
9882 pfgets(char *line, int len)
9884 char *p = line;
9885 int nleft = len;
9886 int c;
9888 while (--nleft > 0) {
9889 c = pgetc_without_PEOA();
9890 if (c == PEOF) {
9891 if (p == line)
9892 return NULL;
9893 break;
9895 *p++ = c;
9896 if (c == '\n')
9897 break;
9899 *p = '\0';
9900 return line;
9904 * Undo the last call to pgetc. Only one character may be pushed back.
9905 * PEOF may be pushed back.
9907 static void
9908 pungetc(void)
9910 g_parsefile->left_in_line++;
9911 g_parsefile->next_to_pgetc--;
9912 pgetc_debug("pushed back to %d:%p'%s'",
9913 g_parsefile->left_in_line,
9914 g_parsefile->next_to_pgetc,
9915 g_parsefile->next_to_pgetc);
9919 * To handle the "." command, a stack of input files is used. Pushfile
9920 * adds a new entry to the stack and popfile restores the previous level.
9922 static void
9923 pushfile(void)
9925 struct parsefile *pf;
9927 pf = ckzalloc(sizeof(*pf));
9928 pf->prev = g_parsefile;
9929 pf->pf_fd = -1;
9930 /*pf->strpush = NULL; - ckzalloc did it */
9931 /*pf->basestrpush.prev = NULL;*/
9932 g_parsefile = pf;
9935 static void
9936 popfile(void)
9938 struct parsefile *pf = g_parsefile;
9940 INT_OFF;
9941 if (pf->pf_fd >= 0)
9942 close(pf->pf_fd);
9943 free(pf->buf);
9944 while (pf->strpush)
9945 popstring();
9946 g_parsefile = pf->prev;
9947 free(pf);
9948 INT_ON;
9952 * Return to top level.
9954 static void
9955 popallfiles(void)
9957 while (g_parsefile != &basepf)
9958 popfile();
9962 * Close the file(s) that the shell is reading commands from. Called
9963 * after a fork is done.
9965 static void
9966 closescript(void)
9968 popallfiles();
9969 if (g_parsefile->pf_fd > 0) {
9970 close(g_parsefile->pf_fd);
9971 g_parsefile->pf_fd = 0;
9976 * Like setinputfile, but takes an open file descriptor. Call this with
9977 * interrupts off.
9979 static void
9980 setinputfd(int fd, int push)
9982 close_on_exec_on(fd);
9983 if (push) {
9984 pushfile();
9985 g_parsefile->buf = NULL;
9987 g_parsefile->pf_fd = fd;
9988 if (g_parsefile->buf == NULL)
9989 g_parsefile->buf = ckmalloc(IBUFSIZ);
9990 g_parsefile->left_in_buffer = 0;
9991 g_parsefile->left_in_line = 0;
9992 g_parsefile->linno = 1;
9996 * Set the input to take input from a file. If push is set, push the
9997 * old input onto the stack first.
9999 static int
10000 setinputfile(const char *fname, int flags)
10002 int fd;
10003 int fd2;
10005 INT_OFF;
10006 fd = open(fname, O_RDONLY);
10007 if (fd < 0) {
10008 if (flags & INPUT_NOFILE_OK)
10009 goto out;
10010 ash_msg_and_raise_error("can't open '%s'", fname);
10012 if (fd < 10) {
10013 fd2 = copyfd(fd, 10);
10014 close(fd);
10015 if (fd2 < 0)
10016 ash_msg_and_raise_error("out of file descriptors");
10017 fd = fd2;
10019 setinputfd(fd, flags & INPUT_PUSH_FILE);
10020 out:
10021 INT_ON;
10022 return fd;
10026 * Like setinputfile, but takes input from a string.
10028 static void
10029 setinputstring(char *string)
10031 INT_OFF;
10032 pushfile();
10033 g_parsefile->next_to_pgetc = string;
10034 g_parsefile->left_in_line = strlen(string);
10035 g_parsefile->buf = NULL;
10036 g_parsefile->linno = 1;
10037 INT_ON;
10041 /* ============ mail.c
10043 * Routines to check for mail.
10046 #if ENABLE_ASH_MAIL
10048 /* Hash of mtimes of mailboxes */
10049 static unsigned mailtime_hash;
10050 /* Set if MAIL or MAILPATH is changed. */
10051 static smallint mail_var_path_changed;
10054 * Print appropriate message(s) if mail has arrived.
10055 * If mail_var_path_changed is set,
10056 * then the value of MAIL has mail_var_path_changed,
10057 * so we just update the values.
10059 static void
10060 chkmail(void)
10062 const char *mpath;
10063 char *p;
10064 char *q;
10065 unsigned new_hash;
10066 struct stackmark smark;
10067 struct stat statb;
10069 setstackmark(&smark);
10070 mpath = mpathset() ? mpathval() : mailval();
10071 new_hash = 0;
10072 for (;;) {
10073 p = path_advance(&mpath, nullstr);
10074 if (p == NULL)
10075 break;
10076 if (*p == '\0')
10077 continue;
10078 for (q = p; *q; q++)
10079 continue;
10080 #if DEBUG
10081 if (q[-1] != '/')
10082 abort();
10083 #endif
10084 q[-1] = '\0'; /* delete trailing '/' */
10085 if (stat(p, &statb) < 0) {
10086 continue;
10088 /* Very simplistic "hash": just a sum of all mtimes */
10089 new_hash += (unsigned)statb.st_mtime;
10091 if (!mail_var_path_changed && mailtime_hash != new_hash) {
10092 if (mailtime_hash != 0)
10093 out2str("you have mail\n");
10094 mailtime_hash = new_hash;
10096 mail_var_path_changed = 0;
10097 popstackmark(&smark);
10100 static void FAST_FUNC
10101 changemail(const char *val UNUSED_PARAM)
10103 mail_var_path_changed = 1;
10106 #endif /* ASH_MAIL */
10109 /* ============ ??? */
10112 * Set the shell parameters.
10114 static void
10115 setparam(char **argv)
10117 char **newparam;
10118 char **ap;
10119 int nparam;
10121 for (nparam = 0; argv[nparam]; nparam++)
10122 continue;
10123 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10124 while (*argv) {
10125 *ap++ = ckstrdup(*argv++);
10127 *ap = NULL;
10128 freeparam(&shellparam);
10129 shellparam.malloced = 1;
10130 shellparam.nparam = nparam;
10131 shellparam.p = newparam;
10132 #if ENABLE_ASH_GETOPTS
10133 shellparam.optind = 1;
10134 shellparam.optoff = -1;
10135 #endif
10139 * Process shell options. The global variable argptr contains a pointer
10140 * to the argument list; we advance it past the options.
10142 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10143 * For a non-interactive shell, an error condition encountered
10144 * by a special built-in ... shall cause the shell to write a diagnostic message
10145 * to standard error and exit as shown in the following table:
10146 * Error Special Built-In
10147 * ...
10148 * Utility syntax error (option or operand error) Shall exit
10149 * ...
10150 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10151 * we see that bash does not do that (set "finishes" with error code 1 instead,
10152 * and shell continues), and people rely on this behavior!
10153 * Testcase:
10154 * set -o barfoo 2>/dev/null
10155 * echo $?
10157 * Oh well. Let's mimic that.
10159 static int
10160 plus_minus_o(char *name, int val)
10162 int i;
10164 if (name) {
10165 for (i = 0; i < NOPTS; i++) {
10166 if (strcmp(name, optnames(i)) == 0) {
10167 optlist[i] = val;
10168 return 0;
10171 ash_msg("illegal option %co %s", val ? '-' : '+', name);
10172 return 1;
10174 for (i = 0; i < NOPTS; i++) {
10175 if (val) {
10176 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10177 } else {
10178 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10181 return 0;
10183 static void
10184 setoption(int flag, int val)
10186 int i;
10188 for (i = 0; i < NOPTS; i++) {
10189 if (optletters(i) == flag) {
10190 optlist[i] = val;
10191 return;
10194 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
10195 /* NOTREACHED */
10197 static int
10198 options(int cmdline)
10200 char *p;
10201 int val;
10202 int c;
10204 if (cmdline)
10205 minusc = NULL;
10206 while ((p = *argptr) != NULL) {
10207 c = *p++;
10208 if (c != '-' && c != '+')
10209 break;
10210 argptr++;
10211 val = 0; /* val = 0 if c == '+' */
10212 if (c == '-') {
10213 val = 1;
10214 if (p[0] == '\0' || LONE_DASH(p)) {
10215 if (!cmdline) {
10216 /* "-" means turn off -x and -v */
10217 if (p[0] == '\0')
10218 xflag = vflag = 0;
10219 /* "--" means reset params */
10220 else if (*argptr == NULL)
10221 setparam(argptr);
10223 break; /* "-" or "--" terminates options */
10226 /* first char was + or - */
10227 while ((c = *p++) != '\0') {
10228 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
10229 if (c == 'c' && cmdline) {
10230 minusc = p; /* command is after shell args */
10231 } else if (c == 'o') {
10232 if (plus_minus_o(*argptr, val)) {
10233 /* it already printed err message */
10234 return 1; /* error */
10236 if (*argptr)
10237 argptr++;
10238 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10239 isloginsh = 1;
10240 /* bash does not accept +-login, we also won't */
10241 } else if (cmdline && val && (c == '-')) { /* long options */
10242 if (strcmp(p, "login") == 0)
10243 isloginsh = 1;
10244 break;
10245 } else {
10246 setoption(c, val);
10250 return 0;
10254 * The shift builtin command.
10256 static int FAST_FUNC
10257 shiftcmd(int argc UNUSED_PARAM, char **argv)
10259 int n;
10260 char **ap1, **ap2;
10262 n = 1;
10263 if (argv[1])
10264 n = number(argv[1]);
10265 if (n > shellparam.nparam)
10266 n = 0; /* bash compat, was = shellparam.nparam; */
10267 INT_OFF;
10268 shellparam.nparam -= n;
10269 for (ap1 = shellparam.p; --n >= 0; ap1++) {
10270 if (shellparam.malloced)
10271 free(*ap1);
10273 ap2 = shellparam.p;
10274 while ((*ap2++ = *ap1++) != NULL)
10275 continue;
10276 #if ENABLE_ASH_GETOPTS
10277 shellparam.optind = 1;
10278 shellparam.optoff = -1;
10279 #endif
10280 INT_ON;
10281 return 0;
10285 * POSIX requires that 'set' (but not export or readonly) output the
10286 * variables in lexicographic order - by the locale's collating order (sigh).
10287 * Maybe we could keep them in an ordered balanced binary tree
10288 * instead of hashed lists.
10289 * For now just roll 'em through qsort for printing...
10291 static int
10292 showvars(const char *sep_prefix, int on, int off)
10294 const char *sep;
10295 char **ep, **epend;
10297 ep = listvars(on, off, &epend);
10298 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10300 sep = *sep_prefix ? " " : sep_prefix;
10302 for (; ep < epend; ep++) {
10303 const char *p;
10304 const char *q;
10306 p = strchrnul(*ep, '=');
10307 q = nullstr;
10308 if (*p)
10309 q = single_quote(++p);
10310 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10312 return 0;
10316 * The set command builtin.
10318 static int FAST_FUNC
10319 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10321 int retval;
10323 if (!argv[1])
10324 return showvars(nullstr, 0, VUNSET);
10326 INT_OFF;
10327 retval = options(/*cmdline:*/ 0);
10328 if (retval == 0) { /* if no parse error... */
10329 optschanged();
10330 if (*argptr != NULL) {
10331 setparam(argptr);
10334 INT_ON;
10335 return retval;
10338 #if ENABLE_ASH_RANDOM_SUPPORT
10339 static void FAST_FUNC
10340 change_random(const char *value)
10342 uint32_t t;
10344 if (value == NULL) {
10345 /* "get", generate */
10346 t = next_random(&random_gen);
10347 /* set without recursion */
10348 setvar(vrandom.var_text, utoa(t), VNOFUNC);
10349 vrandom.flags &= ~VNOFUNC;
10350 } else {
10351 /* set/reset */
10352 t = strtoul(value, NULL, 10);
10353 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
10356 #endif
10358 #if ENABLE_ASH_GETOPTS
10359 static int
10360 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
10362 char *p, *q;
10363 char c = '?';
10364 int done = 0;
10365 int err = 0;
10366 char sbuf[2];
10367 char **optnext;
10369 sbuf[1] = '\0';
10371 if (*param_optind < 1)
10372 return 1;
10373 optnext = optfirst + *param_optind - 1;
10375 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
10376 p = NULL;
10377 else
10378 p = optnext[-1] + *optoff;
10379 if (p == NULL || *p == '\0') {
10380 /* Current word is done, advance */
10381 p = *optnext;
10382 if (p == NULL || *p != '-' || *++p == '\0') {
10383 atend:
10384 p = NULL;
10385 done = 1;
10386 goto out;
10388 optnext++;
10389 if (LONE_DASH(p)) /* check for "--" */
10390 goto atend;
10393 c = *p++;
10394 for (q = optstr; *q != c;) {
10395 if (*q == '\0') {
10396 if (optstr[0] == ':') {
10397 sbuf[0] = c;
10398 /*sbuf[1] = '\0'; - already is */
10399 err |= setvarsafe("OPTARG", sbuf, 0);
10400 } else {
10401 fprintf(stderr, "Illegal option -%c\n", c);
10402 unsetvar("OPTARG");
10404 c = '?';
10405 goto out;
10407 if (*++q == ':')
10408 q++;
10411 if (*++q == ':') {
10412 if (*p == '\0' && (p = *optnext) == NULL) {
10413 if (optstr[0] == ':') {
10414 sbuf[0] = c;
10415 /*sbuf[1] = '\0'; - already is */
10416 err |= setvarsafe("OPTARG", sbuf, 0);
10417 c = ':';
10418 } else {
10419 fprintf(stderr, "No arg for -%c option\n", c);
10420 unsetvar("OPTARG");
10421 c = '?';
10423 goto out;
10426 if (p == *optnext)
10427 optnext++;
10428 err |= setvarsafe("OPTARG", p, 0);
10429 p = NULL;
10430 } else
10431 err |= setvarsafe("OPTARG", nullstr, 0);
10432 out:
10433 *optoff = p ? p - *(optnext - 1) : -1;
10434 *param_optind = optnext - optfirst + 1;
10435 err |= setvarsafe("OPTIND", itoa(*param_optind), VNOFUNC);
10436 sbuf[0] = c;
10437 /*sbuf[1] = '\0'; - already is */
10438 err |= setvarsafe(optvar, sbuf, 0);
10439 if (err) {
10440 *param_optind = 1;
10441 *optoff = -1;
10442 flush_stdout_stderr();
10443 raise_exception(EXERROR);
10445 return done;
10449 * The getopts builtin. Shellparam.optnext points to the next argument
10450 * to be processed. Shellparam.optptr points to the next character to
10451 * be processed in the current argument. If shellparam.optnext is NULL,
10452 * then it's the first time getopts has been called.
10454 static int FAST_FUNC
10455 getoptscmd(int argc, char **argv)
10457 char **optbase;
10459 if (argc < 3)
10460 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
10461 if (argc == 3) {
10462 optbase = shellparam.p;
10463 if (shellparam.optind > shellparam.nparam + 1) {
10464 shellparam.optind = 1;
10465 shellparam.optoff = -1;
10467 } else {
10468 optbase = &argv[3];
10469 if (shellparam.optind > argc - 2) {
10470 shellparam.optind = 1;
10471 shellparam.optoff = -1;
10475 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
10476 &shellparam.optoff);
10478 #endif /* ASH_GETOPTS */
10481 /* ============ Shell parser */
10483 struct heredoc {
10484 struct heredoc *next; /* next here document in list */
10485 union node *here; /* redirection node */
10486 char *eofmark; /* string indicating end of input */
10487 smallint striptabs; /* if set, strip leading tabs */
10490 static smallint tokpushback; /* last token pushed back */
10491 static smallint quoteflag; /* set if (part of) last token was quoted */
10492 static token_id_t lasttoken; /* last token read (integer id Txxx) */
10493 static struct heredoc *heredoclist; /* list of here documents to read */
10494 static char *wordtext; /* text of last word returned by readtoken */
10495 static struct nodelist *backquotelist;
10496 static union node *redirnode;
10497 static struct heredoc *heredoc;
10499 static const char *
10500 tokname(char *buf, int tok)
10502 if (tok < TSEMI)
10503 return tokname_array[tok] + 1;
10504 sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
10505 return buf;
10508 /* raise_error_unexpected_syntax:
10509 * Called when an unexpected token is read during the parse. The argument
10510 * is the token that is expected, or -1 if more than one type of token can
10511 * occur at this point.
10513 static void raise_error_unexpected_syntax(int) NORETURN;
10514 static void
10515 raise_error_unexpected_syntax(int token)
10517 char msg[64];
10518 char buf[16];
10519 int l;
10521 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
10522 if (token >= 0)
10523 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
10524 raise_error_syntax(msg);
10525 /* NOTREACHED */
10528 #define EOFMARKLEN 79
10530 /* parsing is heavily cross-recursive, need these forward decls */
10531 static union node *andor(void);
10532 static union node *pipeline(void);
10533 static union node *parse_command(void);
10534 static void parseheredoc(void);
10535 static int peektoken(void);
10536 static int readtoken(void);
10538 static union node *
10539 list(int nlflag)
10541 union node *n1, *n2, *n3;
10542 int tok;
10544 n1 = NULL;
10545 for (;;) {
10546 switch (peektoken()) {
10547 case TNL:
10548 if (!(nlflag & 1))
10549 break;
10550 parseheredoc();
10551 return n1;
10553 case TEOF:
10554 if (!n1 && (nlflag & 1))
10555 n1 = NODE_EOF;
10556 parseheredoc();
10557 return n1;
10560 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10561 if (nlflag == 2 && tokname_array[peektoken()][0])
10562 return n1;
10563 nlflag |= 2;
10565 n2 = andor();
10566 tok = readtoken();
10567 if (tok == TBACKGND) {
10568 if (n2->type == NPIPE) {
10569 n2->npipe.pipe_backgnd = 1;
10570 } else {
10571 if (n2->type != NREDIR) {
10572 n3 = stzalloc(sizeof(struct nredir));
10573 n3->nredir.n = n2;
10574 /*n3->nredir.redirect = NULL; - stzalloc did it */
10575 n2 = n3;
10577 n2->type = NBACKGND;
10580 if (n1 == NULL) {
10581 n1 = n2;
10582 } else {
10583 n3 = stzalloc(sizeof(struct nbinary));
10584 n3->type = NSEMI;
10585 n3->nbinary.ch1 = n1;
10586 n3->nbinary.ch2 = n2;
10587 n1 = n3;
10589 switch (tok) {
10590 case TNL:
10591 case TEOF:
10592 tokpushback = 1;
10593 /* fall through */
10594 case TBACKGND:
10595 case TSEMI:
10596 break;
10597 default:
10598 if ((nlflag & 1))
10599 raise_error_unexpected_syntax(-1);
10600 tokpushback = 1;
10601 return n1;
10606 static union node *
10607 andor(void)
10609 union node *n1, *n2, *n3;
10610 int t;
10612 n1 = pipeline();
10613 for (;;) {
10614 t = readtoken();
10615 if (t == TAND) {
10616 t = NAND;
10617 } else if (t == TOR) {
10618 t = NOR;
10619 } else {
10620 tokpushback = 1;
10621 return n1;
10623 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10624 n2 = pipeline();
10625 n3 = stzalloc(sizeof(struct nbinary));
10626 n3->type = t;
10627 n3->nbinary.ch1 = n1;
10628 n3->nbinary.ch2 = n2;
10629 n1 = n3;
10633 static union node *
10634 pipeline(void)
10636 union node *n1, *n2, *pipenode;
10637 struct nodelist *lp, *prev;
10638 int negate;
10640 negate = 0;
10641 TRACE(("pipeline: entered\n"));
10642 if (readtoken() == TNOT) {
10643 negate = !negate;
10644 checkkwd = CHKKWD | CHKALIAS;
10645 } else
10646 tokpushback = 1;
10647 n1 = parse_command();
10648 if (readtoken() == TPIPE) {
10649 pipenode = stzalloc(sizeof(struct npipe));
10650 pipenode->type = NPIPE;
10651 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10652 lp = stzalloc(sizeof(struct nodelist));
10653 pipenode->npipe.cmdlist = lp;
10654 lp->n = n1;
10655 do {
10656 prev = lp;
10657 lp = stzalloc(sizeof(struct nodelist));
10658 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10659 lp->n = parse_command();
10660 prev->next = lp;
10661 } while (readtoken() == TPIPE);
10662 lp->next = NULL;
10663 n1 = pipenode;
10665 tokpushback = 1;
10666 if (negate) {
10667 n2 = stzalloc(sizeof(struct nnot));
10668 n2->type = NNOT;
10669 n2->nnot.com = n1;
10670 return n2;
10672 return n1;
10675 static union node *
10676 makename(void)
10678 union node *n;
10680 n = stzalloc(sizeof(struct narg));
10681 n->type = NARG;
10682 /*n->narg.next = NULL; - stzalloc did it */
10683 n->narg.text = wordtext;
10684 n->narg.backquote = backquotelist;
10685 return n;
10688 static void
10689 fixredir(union node *n, const char *text, int err)
10691 int fd;
10693 TRACE(("Fix redir %s %d\n", text, err));
10694 if (!err)
10695 n->ndup.vname = NULL;
10697 fd = bb_strtou(text, NULL, 10);
10698 if (!errno && fd >= 0)
10699 n->ndup.dupfd = fd;
10700 else if (LONE_DASH(text))
10701 n->ndup.dupfd = -1;
10702 else {
10703 if (err)
10704 raise_error_syntax("bad fd number");
10705 n->ndup.vname = makename();
10710 * Returns true if the text contains nothing to expand (no dollar signs
10711 * or backquotes).
10713 static int
10714 noexpand(const char *text)
10716 unsigned char c;
10718 while ((c = *text++) != '\0') {
10719 if (c == CTLQUOTEMARK)
10720 continue;
10721 if (c == CTLESC)
10722 text++;
10723 else if (SIT(c, BASESYNTAX) == CCTL)
10724 return 0;
10726 return 1;
10729 static void
10730 parsefname(void)
10732 union node *n = redirnode;
10734 if (readtoken() != TWORD)
10735 raise_error_unexpected_syntax(-1);
10736 if (n->type == NHERE) {
10737 struct heredoc *here = heredoc;
10738 struct heredoc *p;
10739 int i;
10741 if (quoteflag == 0)
10742 n->type = NXHERE;
10743 TRACE(("Here document %d\n", n->type));
10744 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10745 raise_error_syntax("illegal eof marker for << redirection");
10746 rmescapes(wordtext, 0);
10747 here->eofmark = wordtext;
10748 here->next = NULL;
10749 if (heredoclist == NULL)
10750 heredoclist = here;
10751 else {
10752 for (p = heredoclist; p->next; p = p->next)
10753 continue;
10754 p->next = here;
10756 } else if (n->type == NTOFD || n->type == NFROMFD) {
10757 fixredir(n, wordtext, 0);
10758 } else {
10759 n->nfile.fname = makename();
10763 static union node *
10764 simplecmd(void)
10766 union node *args, **app;
10767 union node *n = NULL;
10768 union node *vars, **vpp;
10769 union node **rpp, *redir;
10770 int savecheckkwd;
10771 #if ENABLE_ASH_BASH_COMPAT
10772 smallint double_brackets_flag = 0;
10773 smallint function_flag = 0;
10774 #endif
10776 args = NULL;
10777 app = &args;
10778 vars = NULL;
10779 vpp = &vars;
10780 redir = NULL;
10781 rpp = &redir;
10783 savecheckkwd = CHKALIAS;
10784 for (;;) {
10785 int t;
10786 checkkwd = savecheckkwd;
10787 t = readtoken();
10788 switch (t) {
10789 #if ENABLE_ASH_BASH_COMPAT
10790 case TFUNCTION:
10791 if (peektoken() != TWORD)
10792 raise_error_unexpected_syntax(TWORD);
10793 function_flag = 1;
10794 break;
10795 case TAND: /* "&&" */
10796 case TOR: /* "||" */
10797 if (!double_brackets_flag) {
10798 tokpushback = 1;
10799 goto out;
10801 wordtext = (char *) (t == TAND ? "-a" : "-o");
10802 #endif
10803 case TWORD:
10804 n = stzalloc(sizeof(struct narg));
10805 n->type = NARG;
10806 /*n->narg.next = NULL; - stzalloc did it */
10807 n->narg.text = wordtext;
10808 #if ENABLE_ASH_BASH_COMPAT
10809 if (strcmp("[[", wordtext) == 0)
10810 double_brackets_flag = 1;
10811 else if (strcmp("]]", wordtext) == 0)
10812 double_brackets_flag = 0;
10813 #endif
10814 n->narg.backquote = backquotelist;
10815 if (savecheckkwd && isassignment(wordtext)) {
10816 *vpp = n;
10817 vpp = &n->narg.next;
10818 } else {
10819 *app = n;
10820 app = &n->narg.next;
10821 savecheckkwd = 0;
10823 #if ENABLE_ASH_BASH_COMPAT
10824 if (function_flag) {
10825 checkkwd = CHKNL | CHKKWD;
10826 switch (peektoken()) {
10827 case TBEGIN:
10828 case TIF:
10829 case TCASE:
10830 case TUNTIL:
10831 case TWHILE:
10832 case TFOR:
10833 goto do_func;
10834 case TLP:
10835 function_flag = 0;
10836 break;
10837 case TWORD:
10838 if (strcmp("[[", wordtext) == 0)
10839 goto do_func;
10840 /* fall through */
10841 default:
10842 raise_error_unexpected_syntax(-1);
10845 #endif
10846 break;
10847 case TREDIR:
10848 *rpp = n = redirnode;
10849 rpp = &n->nfile.next;
10850 parsefname(); /* read name of redirection file */
10851 break;
10852 case TLP:
10853 IF_ASH_BASH_COMPAT(do_func:)
10854 if (args && app == &args->narg.next
10855 && !vars && !redir
10857 struct builtincmd *bcmd;
10858 const char *name;
10860 /* We have a function */
10861 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
10862 raise_error_unexpected_syntax(TRP);
10863 name = n->narg.text;
10864 if (!goodname(name)
10865 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10867 raise_error_syntax("bad function name");
10869 n->type = NDEFUN;
10870 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10871 n->narg.next = parse_command();
10872 return n;
10874 IF_ASH_BASH_COMPAT(function_flag = 0;)
10875 /* fall through */
10876 default:
10877 tokpushback = 1;
10878 goto out;
10881 out:
10882 *app = NULL;
10883 *vpp = NULL;
10884 *rpp = NULL;
10885 n = stzalloc(sizeof(struct ncmd));
10886 n->type = NCMD;
10887 n->ncmd.args = args;
10888 n->ncmd.assign = vars;
10889 n->ncmd.redirect = redir;
10890 return n;
10893 static union node *
10894 parse_command(void)
10896 union node *n1, *n2;
10897 union node *ap, **app;
10898 union node *cp, **cpp;
10899 union node *redir, **rpp;
10900 union node **rpp2;
10901 int t;
10903 redir = NULL;
10904 rpp2 = &redir;
10906 switch (readtoken()) {
10907 default:
10908 raise_error_unexpected_syntax(-1);
10909 /* NOTREACHED */
10910 case TIF:
10911 n1 = stzalloc(sizeof(struct nif));
10912 n1->type = NIF;
10913 n1->nif.test = list(0);
10914 if (readtoken() != TTHEN)
10915 raise_error_unexpected_syntax(TTHEN);
10916 n1->nif.ifpart = list(0);
10917 n2 = n1;
10918 while (readtoken() == TELIF) {
10919 n2->nif.elsepart = stzalloc(sizeof(struct nif));
10920 n2 = n2->nif.elsepart;
10921 n2->type = NIF;
10922 n2->nif.test = list(0);
10923 if (readtoken() != TTHEN)
10924 raise_error_unexpected_syntax(TTHEN);
10925 n2->nif.ifpart = list(0);
10927 if (lasttoken == TELSE)
10928 n2->nif.elsepart = list(0);
10929 else {
10930 n2->nif.elsepart = NULL;
10931 tokpushback = 1;
10933 t = TFI;
10934 break;
10935 case TWHILE:
10936 case TUNTIL: {
10937 int got;
10938 n1 = stzalloc(sizeof(struct nbinary));
10939 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10940 n1->nbinary.ch1 = list(0);
10941 got = readtoken();
10942 if (got != TDO) {
10943 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
10944 got == TWORD ? wordtext : ""));
10945 raise_error_unexpected_syntax(TDO);
10947 n1->nbinary.ch2 = list(0);
10948 t = TDONE;
10949 break;
10951 case TFOR:
10952 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10953 raise_error_syntax("bad for loop variable");
10954 n1 = stzalloc(sizeof(struct nfor));
10955 n1->type = NFOR;
10956 n1->nfor.var = wordtext;
10957 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10958 if (readtoken() == TIN) {
10959 app = &ap;
10960 while (readtoken() == TWORD) {
10961 n2 = stzalloc(sizeof(struct narg));
10962 n2->type = NARG;
10963 /*n2->narg.next = NULL; - stzalloc did it */
10964 n2->narg.text = wordtext;
10965 n2->narg.backquote = backquotelist;
10966 *app = n2;
10967 app = &n2->narg.next;
10969 *app = NULL;
10970 n1->nfor.args = ap;
10971 if (lasttoken != TNL && lasttoken != TSEMI)
10972 raise_error_unexpected_syntax(-1);
10973 } else {
10974 n2 = stzalloc(sizeof(struct narg));
10975 n2->type = NARG;
10976 /*n2->narg.next = NULL; - stzalloc did it */
10977 n2->narg.text = (char *)dolatstr;
10978 /*n2->narg.backquote = NULL;*/
10979 n1->nfor.args = n2;
10981 * Newline or semicolon here is optional (but note
10982 * that the original Bourne shell only allowed NL).
10984 if (lasttoken != TSEMI)
10985 tokpushback = 1;
10987 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10988 if (readtoken() != TDO)
10989 raise_error_unexpected_syntax(TDO);
10990 n1->nfor.body = list(0);
10991 t = TDONE;
10992 break;
10993 case TCASE:
10994 n1 = stzalloc(sizeof(struct ncase));
10995 n1->type = NCASE;
10996 if (readtoken() != TWORD)
10997 raise_error_unexpected_syntax(TWORD);
10998 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10999 n2->type = NARG;
11000 /*n2->narg.next = NULL; - stzalloc did it */
11001 n2->narg.text = wordtext;
11002 n2->narg.backquote = backquotelist;
11003 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11004 if (readtoken() != TIN)
11005 raise_error_unexpected_syntax(TIN);
11006 cpp = &n1->ncase.cases;
11007 next_case:
11008 checkkwd = CHKNL | CHKKWD;
11009 t = readtoken();
11010 while (t != TESAC) {
11011 if (lasttoken == TLP)
11012 readtoken();
11013 *cpp = cp = stzalloc(sizeof(struct nclist));
11014 cp->type = NCLIST;
11015 app = &cp->nclist.pattern;
11016 for (;;) {
11017 *app = ap = stzalloc(sizeof(struct narg));
11018 ap->type = NARG;
11019 /*ap->narg.next = NULL; - stzalloc did it */
11020 ap->narg.text = wordtext;
11021 ap->narg.backquote = backquotelist;
11022 if (readtoken() != TPIPE)
11023 break;
11024 app = &ap->narg.next;
11025 readtoken();
11027 //ap->narg.next = NULL;
11028 if (lasttoken != TRP)
11029 raise_error_unexpected_syntax(TRP);
11030 cp->nclist.body = list(2);
11032 cpp = &cp->nclist.next;
11034 checkkwd = CHKNL | CHKKWD;
11035 t = readtoken();
11036 if (t != TESAC) {
11037 if (t != TENDCASE)
11038 raise_error_unexpected_syntax(TENDCASE);
11039 goto next_case;
11042 *cpp = NULL;
11043 goto redir;
11044 case TLP:
11045 n1 = stzalloc(sizeof(struct nredir));
11046 n1->type = NSUBSHELL;
11047 n1->nredir.n = list(0);
11048 /*n1->nredir.redirect = NULL; - stzalloc did it */
11049 t = TRP;
11050 break;
11051 case TBEGIN:
11052 n1 = list(0);
11053 t = TEND;
11054 break;
11055 IF_ASH_BASH_COMPAT(case TFUNCTION:)
11056 case TWORD:
11057 case TREDIR:
11058 tokpushback = 1;
11059 return simplecmd();
11062 if (readtoken() != t)
11063 raise_error_unexpected_syntax(t);
11065 redir:
11066 /* Now check for redirection which may follow command */
11067 checkkwd = CHKKWD | CHKALIAS;
11068 rpp = rpp2;
11069 while (readtoken() == TREDIR) {
11070 *rpp = n2 = redirnode;
11071 rpp = &n2->nfile.next;
11072 parsefname();
11074 tokpushback = 1;
11075 *rpp = NULL;
11076 if (redir) {
11077 if (n1->type != NSUBSHELL) {
11078 n2 = stzalloc(sizeof(struct nredir));
11079 n2->type = NREDIR;
11080 n2->nredir.n = n1;
11081 n1 = n2;
11083 n1->nredir.redirect = redir;
11085 return n1;
11088 #if ENABLE_ASH_BASH_COMPAT
11089 static int decode_dollar_squote(void)
11091 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11092 int c, cnt;
11093 char *p;
11094 char buf[4];
11096 c = pgetc();
11097 p = strchr(C_escapes, c);
11098 if (p) {
11099 buf[0] = c;
11100 p = buf;
11101 cnt = 3;
11102 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11103 do {
11104 c = pgetc();
11105 *++p = c;
11106 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11107 pungetc();
11108 } else if (c == 'x') { /* \xHH */
11109 do {
11110 c = pgetc();
11111 *++p = c;
11112 } while (isxdigit(c) && --cnt);
11113 pungetc();
11114 if (cnt == 3) { /* \x but next char is "bad" */
11115 c = 'x';
11116 goto unrecognized;
11118 } else { /* simple seq like \\ or \t */
11119 p++;
11121 *p = '\0';
11122 p = buf;
11123 c = bb_process_escape_sequence((void*)&p);
11124 } else { /* unrecognized "\z": print both chars unless ' or " */
11125 if (c != '\'' && c != '"') {
11126 unrecognized:
11127 c |= 0x100; /* "please encode \, then me" */
11130 return c;
11132 #endif
11135 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11136 * is not NULL, read a here document. In the latter case, eofmark is the
11137 * word which marks the end of the document and striptabs is true if
11138 * leading tabs should be stripped from the document. The argument c
11139 * is the first character of the input token or document.
11141 * Because C does not have internal subroutines, I have simulated them
11142 * using goto's to implement the subroutine linkage. The following macros
11143 * will run code that appears at the end of readtoken1.
11145 #define CHECKEND() {goto checkend; checkend_return:;}
11146 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
11147 #define PARSESUB() {goto parsesub; parsesub_return:;}
11148 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11149 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11150 #define PARSEARITH() {goto parsearith; parsearith_return:;}
11151 static int
11152 readtoken1(int c, int syntax, char *eofmark, int striptabs)
11154 /* NB: syntax parameter fits into smallint */
11155 /* c parameter is an unsigned char or PEOF or PEOA */
11156 char *out;
11157 int len;
11158 char line[EOFMARKLEN + 1];
11159 struct nodelist *bqlist;
11160 smallint quotef;
11161 smallint dblquote;
11162 smallint oldstyle;
11163 smallint prevsyntax; /* syntax before arithmetic */
11164 #if ENABLE_ASH_EXPAND_PRMT
11165 smallint pssyntax; /* we are expanding a prompt string */
11166 #endif
11167 int varnest; /* levels of variables expansion */
11168 int arinest; /* levels of arithmetic expansion */
11169 int parenlevel; /* levels of parens in arithmetic */
11170 int dqvarnest; /* levels of variables expansion within double quotes */
11172 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
11174 startlinno = g_parsefile->linno;
11175 bqlist = NULL;
11176 quotef = 0;
11177 prevsyntax = 0;
11178 #if ENABLE_ASH_EXPAND_PRMT
11179 pssyntax = (syntax == PSSYNTAX);
11180 if (pssyntax)
11181 syntax = DQSYNTAX;
11182 #endif
11183 dblquote = (syntax == DQSYNTAX);
11184 varnest = 0;
11185 arinest = 0;
11186 parenlevel = 0;
11187 dqvarnest = 0;
11189 STARTSTACKSTR(out);
11190 loop:
11191 /* For each line, until end of word */
11192 CHECKEND(); /* set c to PEOF if at end of here document */
11193 for (;;) { /* until end of line or end of word */
11194 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11195 switch (SIT(c, syntax)) {
11196 case CNL: /* '\n' */
11197 if (syntax == BASESYNTAX)
11198 goto endword; /* exit outer loop */
11199 USTPUTC(c, out);
11200 g_parsefile->linno++;
11201 setprompt_if(doprompt, 2);
11202 c = pgetc();
11203 goto loop; /* continue outer loop */
11204 case CWORD:
11205 USTPUTC(c, out);
11206 break;
11207 case CCTL:
11208 if (eofmark == NULL || dblquote)
11209 USTPUTC(CTLESC, out);
11210 #if ENABLE_ASH_BASH_COMPAT
11211 if (c == '\\' && bash_dollar_squote) {
11212 c = decode_dollar_squote();
11213 if (c & 0x100) {
11214 USTPUTC('\\', out);
11215 c = (unsigned char)c;
11218 #endif
11219 USTPUTC(c, out);
11220 break;
11221 case CBACK: /* backslash */
11222 c = pgetc_without_PEOA();
11223 if (c == PEOF) {
11224 USTPUTC(CTLESC, out);
11225 USTPUTC('\\', out);
11226 pungetc();
11227 } else if (c == '\n') {
11228 setprompt_if(doprompt, 2);
11229 } else {
11230 #if ENABLE_ASH_EXPAND_PRMT
11231 if (c == '$' && pssyntax) {
11232 USTPUTC(CTLESC, out);
11233 USTPUTC('\\', out);
11235 #endif
11236 /* Backslash is retained if we are in "str" and next char isn't special */
11237 if (dblquote
11238 && c != '\\'
11239 && c != '`'
11240 && c != '$'
11241 && (c != '"' || eofmark != NULL)
11243 USTPUTC('\\', out);
11245 USTPUTC(CTLESC, out);
11246 USTPUTC(c, out);
11247 quotef = 1;
11249 break;
11250 case CSQUOTE:
11251 syntax = SQSYNTAX;
11252 quotemark:
11253 if (eofmark == NULL) {
11254 USTPUTC(CTLQUOTEMARK, out);
11256 break;
11257 case CDQUOTE:
11258 syntax = DQSYNTAX;
11259 dblquote = 1;
11260 goto quotemark;
11261 case CENDQUOTE:
11262 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
11263 if (eofmark != NULL && varnest == 0) {
11264 USTPUTC(c, out);
11265 } else {
11266 if (dqvarnest == 0) {
11267 syntax = BASESYNTAX;
11268 dblquote = 0;
11270 quotef = 1;
11271 goto quotemark;
11273 break;
11274 case CVAR: /* '$' */
11275 PARSESUB(); /* parse substitution */
11276 break;
11277 case CENDVAR: /* '}' */
11278 if (varnest > 0) {
11279 varnest--;
11280 if (dqvarnest > 0) {
11281 dqvarnest--;
11283 c = CTLENDVAR;
11285 USTPUTC(c, out);
11286 break;
11287 #if ENABLE_SH_MATH_SUPPORT
11288 case CLP: /* '(' in arithmetic */
11289 parenlevel++;
11290 USTPUTC(c, out);
11291 break;
11292 case CRP: /* ')' in arithmetic */
11293 if (parenlevel > 0) {
11294 parenlevel--;
11295 } else {
11296 if (pgetc() == ')') {
11297 c = CTLENDARI;
11298 if (--arinest == 0) {
11299 syntax = prevsyntax;
11301 } else {
11303 * unbalanced parens
11304 * (don't 2nd guess - no error)
11306 pungetc();
11309 USTPUTC(c, out);
11310 break;
11311 #endif
11312 case CBQUOTE: /* '`' */
11313 PARSEBACKQOLD();
11314 break;
11315 case CENDFILE:
11316 goto endword; /* exit outer loop */
11317 case CIGN:
11318 break;
11319 default:
11320 if (varnest == 0) {
11321 #if ENABLE_ASH_BASH_COMPAT
11322 if (c == '&') {
11323 if (pgetc() == '>')
11324 c = 0x100 + '>'; /* flag &> */
11325 pungetc();
11327 #endif
11328 goto endword; /* exit outer loop */
11330 IF_ASH_ALIAS(if (c != PEOA))
11331 USTPUTC(c, out);
11333 c = pgetc_fast();
11334 } /* for (;;) */
11335 endword:
11337 #if ENABLE_SH_MATH_SUPPORT
11338 if (syntax == ARISYNTAX)
11339 raise_error_syntax("missing '))'");
11340 #endif
11341 if (syntax != BASESYNTAX && eofmark == NULL)
11342 raise_error_syntax("unterminated quoted string");
11343 if (varnest != 0) {
11344 startlinno = g_parsefile->linno;
11345 /* { */
11346 raise_error_syntax("missing '}'");
11348 USTPUTC('\0', out);
11349 len = out - (char *)stackblock();
11350 out = stackblock();
11351 if (eofmark == NULL) {
11352 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
11353 && quotef == 0
11355 if (isdigit_str9(out)) {
11356 PARSEREDIR(); /* passed as params: out, c */
11357 lasttoken = TREDIR;
11358 return lasttoken;
11360 /* else: non-number X seen, interpret it
11361 * as "NNNX>file" = "NNNX >file" */
11363 pungetc();
11365 quoteflag = quotef;
11366 backquotelist = bqlist;
11367 grabstackblock(len);
11368 wordtext = out;
11369 lasttoken = TWORD;
11370 return lasttoken;
11371 /* end of readtoken routine */
11374 * Check to see whether we are at the end of the here document. When this
11375 * is called, c is set to the first character of the next input line. If
11376 * we are at the end of the here document, this routine sets the c to PEOF.
11378 checkend: {
11379 if (eofmark) {
11380 #if ENABLE_ASH_ALIAS
11381 if (c == PEOA)
11382 c = pgetc_without_PEOA();
11383 #endif
11384 if (striptabs) {
11385 while (c == '\t') {
11386 c = pgetc_without_PEOA();
11389 if (c == *eofmark) {
11390 if (pfgets(line, sizeof(line)) != NULL) {
11391 char *p, *q;
11393 p = line;
11394 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11395 continue;
11396 if (*p == '\n' && *q == '\0') {
11397 c = PEOF;
11398 g_parsefile->linno++;
11399 needprompt = doprompt;
11400 } else {
11401 pushstring(line, NULL);
11406 goto checkend_return;
11410 * Parse a redirection operator. The variable "out" points to a string
11411 * specifying the fd to be redirected. The variable "c" contains the
11412 * first character of the redirection operator.
11414 parseredir: {
11415 /* out is already checked to be a valid number or "" */
11416 int fd = (*out == '\0' ? -1 : atoi(out));
11417 union node *np;
11419 np = stzalloc(sizeof(struct nfile));
11420 if (c == '>') {
11421 np->nfile.fd = 1;
11422 c = pgetc();
11423 if (c == '>')
11424 np->type = NAPPEND;
11425 else if (c == '|')
11426 np->type = NCLOBBER;
11427 else if (c == '&')
11428 np->type = NTOFD;
11429 /* it also can be NTO2 (>&file), but we can't figure it out yet */
11430 else {
11431 np->type = NTO;
11432 pungetc();
11435 #if ENABLE_ASH_BASH_COMPAT
11436 else if (c == 0x100 + '>') { /* this flags &> redirection */
11437 np->nfile.fd = 1;
11438 pgetc(); /* this is '>', no need to check */
11439 np->type = NTO2;
11441 #endif
11442 else { /* c == '<' */
11443 /*np->nfile.fd = 0; - stzalloc did it */
11444 c = pgetc();
11445 switch (c) {
11446 case '<':
11447 if (sizeof(struct nfile) != sizeof(struct nhere)) {
11448 np = stzalloc(sizeof(struct nhere));
11449 /*np->nfile.fd = 0; - stzalloc did it */
11451 np->type = NHERE;
11452 heredoc = stzalloc(sizeof(struct heredoc));
11453 heredoc->here = np;
11454 c = pgetc();
11455 if (c == '-') {
11456 heredoc->striptabs = 1;
11457 } else {
11458 /*heredoc->striptabs = 0; - stzalloc did it */
11459 pungetc();
11461 break;
11463 case '&':
11464 np->type = NFROMFD;
11465 break;
11467 case '>':
11468 np->type = NFROMTO;
11469 break;
11471 default:
11472 np->type = NFROM;
11473 pungetc();
11474 break;
11477 if (fd >= 0)
11478 np->nfile.fd = fd;
11479 redirnode = np;
11480 goto parseredir_return;
11484 * Parse a substitution. At this point, we have read the dollar sign
11485 * and nothing else.
11488 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11489 * (assuming ascii char codes, as the original implementation did) */
11490 #define is_special(c) \
11491 (((unsigned)(c) - 33 < 32) \
11492 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
11493 parsesub: {
11494 unsigned char subtype;
11495 int typeloc;
11496 int flags;
11498 c = pgetc();
11499 if (c > 255 /* PEOA or PEOF */
11500 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
11502 #if ENABLE_ASH_BASH_COMPAT
11503 if (syntax != DQSYNTAX && c == '\'')
11504 bash_dollar_squote = 1;
11505 else
11506 #endif
11507 USTPUTC('$', out);
11508 pungetc();
11509 } else if (c == '(') {
11510 /* $(command) or $((arith)) */
11511 if (pgetc() == '(') {
11512 #if ENABLE_SH_MATH_SUPPORT
11513 PARSEARITH();
11514 #else
11515 raise_error_syntax("you disabled math support for $((arith)) syntax");
11516 #endif
11517 } else {
11518 pungetc();
11519 PARSEBACKQNEW();
11521 } else {
11522 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
11523 USTPUTC(CTLVAR, out);
11524 typeloc = out - (char *)stackblock();
11525 USTPUTC(VSNORMAL, out);
11526 subtype = VSNORMAL;
11527 if (c == '{') {
11528 c = pgetc();
11529 if (c == '#') {
11530 c = pgetc();
11531 if (c == '}')
11532 c = '#'; /* ${#} - same as $# */
11533 else
11534 subtype = VSLENGTH; /* ${#VAR} */
11535 } else {
11536 subtype = 0;
11539 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
11540 /* $[{[#]]NAME[}] */
11541 do {
11542 STPUTC(c, out);
11543 c = pgetc();
11544 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
11545 } else if (isdigit(c)) {
11546 /* $[{[#]]NUM[}] */
11547 do {
11548 STPUTC(c, out);
11549 c = pgetc();
11550 } while (isdigit(c));
11551 } else if (is_special(c)) {
11552 /* $[{[#]]<specialchar>[}] */
11553 USTPUTC(c, out);
11554 c = pgetc();
11555 } else {
11556 badsub:
11557 raise_error_syntax("bad substitution");
11559 if (c != '}' && subtype == VSLENGTH) {
11560 /* ${#VAR didn't end with } */
11561 goto badsub;
11564 STPUTC('=', out);
11565 flags = 0;
11566 if (subtype == 0) {
11567 /* ${VAR...} but not $VAR or ${#VAR} */
11568 /* c == first char after VAR */
11569 switch (c) {
11570 case ':':
11571 c = pgetc();
11572 #if ENABLE_ASH_BASH_COMPAT
11573 if (c == ':' || c == '$' || isdigit(c)) {
11574 //TODO: support more general format ${v:EXPR:EXPR},
11575 // where EXPR follows $(()) rules
11576 subtype = VSSUBSTR;
11577 pungetc();
11578 break; /* "goto do_pungetc" is bigger (!) */
11580 #endif
11581 flags = VSNUL;
11582 /*FALLTHROUGH*/
11583 default: {
11584 static const char types[] ALIGN1 = "}-+?=";
11585 const char *p = strchr(types, c);
11586 if (p == NULL)
11587 goto badsub;
11588 subtype = p - types + VSNORMAL;
11589 break;
11591 case '%':
11592 case '#': {
11593 int cc = c;
11594 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
11595 c = pgetc();
11596 if (c != cc)
11597 goto do_pungetc;
11598 subtype++;
11599 break;
11601 #if ENABLE_ASH_BASH_COMPAT
11602 case '/':
11603 /* ${v/[/]pattern/repl} */
11604 //TODO: encode pattern and repl separately.
11605 // Currently ${v/$var_with_slash/repl} is horribly broken
11606 subtype = VSREPLACE;
11607 c = pgetc();
11608 if (c != '/')
11609 goto do_pungetc;
11610 subtype++; /* VSREPLACEALL */
11611 break;
11612 #endif
11614 } else {
11615 do_pungetc:
11616 pungetc();
11618 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
11619 if (subtype != VSNORMAL) {
11620 varnest++;
11621 if (dblquote) {
11622 dqvarnest++;
11626 goto parsesub_return;
11630 * Called to parse command substitutions. Newstyle is set if the command
11631 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11632 * list of commands (passed by reference), and savelen is the number of
11633 * characters on the top of the stack which must be preserved.
11635 parsebackq: {
11636 struct nodelist **nlpp;
11637 union node *n;
11638 char *str;
11639 size_t savelen;
11640 smallint saveprompt = 0;
11642 str = NULL;
11643 savelen = out - (char *)stackblock();
11644 if (savelen > 0) {
11645 str = alloca(savelen);
11646 memcpy(str, stackblock(), savelen);
11648 if (oldstyle) {
11649 /* We must read until the closing backquote, giving special
11650 * treatment to some slashes, and then push the string and
11651 * reread it as input, interpreting it normally.
11653 char *pout;
11654 size_t psavelen;
11655 char *pstr;
11657 STARTSTACKSTR(pout);
11658 for (;;) {
11659 int pc;
11661 setprompt_if(needprompt, 2);
11662 pc = pgetc();
11663 switch (pc) {
11664 case '`':
11665 goto done;
11667 case '\\':
11668 pc = pgetc();
11669 if (pc == '\n') {
11670 g_parsefile->linno++;
11671 setprompt_if(doprompt, 2);
11673 * If eating a newline, avoid putting
11674 * the newline into the new character
11675 * stream (via the STPUTC after the
11676 * switch).
11678 continue;
11680 if (pc != '\\' && pc != '`' && pc != '$'
11681 && (!dblquote || pc != '"')
11683 STPUTC('\\', pout);
11685 if (pc <= 255 /* not PEOA or PEOF */) {
11686 break;
11688 /* fall through */
11690 case PEOF:
11691 IF_ASH_ALIAS(case PEOA:)
11692 startlinno = g_parsefile->linno;
11693 raise_error_syntax("EOF in backquote substitution");
11695 case '\n':
11696 g_parsefile->linno++;
11697 needprompt = doprompt;
11698 break;
11700 default:
11701 break;
11703 STPUTC(pc, pout);
11705 done:
11706 STPUTC('\0', pout);
11707 psavelen = pout - (char *)stackblock();
11708 if (psavelen > 0) {
11709 pstr = grabstackstr(pout);
11710 setinputstring(pstr);
11713 nlpp = &bqlist;
11714 while (*nlpp)
11715 nlpp = &(*nlpp)->next;
11716 *nlpp = stzalloc(sizeof(**nlpp));
11717 /* (*nlpp)->next = NULL; - stzalloc did it */
11719 if (oldstyle) {
11720 saveprompt = doprompt;
11721 doprompt = 0;
11724 n = list(2);
11726 if (oldstyle)
11727 doprompt = saveprompt;
11728 else if (readtoken() != TRP)
11729 raise_error_unexpected_syntax(TRP);
11731 (*nlpp)->n = n;
11732 if (oldstyle) {
11734 * Start reading from old file again, ignoring any pushed back
11735 * tokens left from the backquote parsing
11737 popfile();
11738 tokpushback = 0;
11740 while (stackblocksize() <= savelen)
11741 growstackblock();
11742 STARTSTACKSTR(out);
11743 if (str) {
11744 memcpy(out, str, savelen);
11745 STADJUST(savelen, out);
11747 USTPUTC(CTLBACKQ, out);
11748 if (oldstyle)
11749 goto parsebackq_oldreturn;
11750 goto parsebackq_newreturn;
11753 #if ENABLE_SH_MATH_SUPPORT
11755 * Parse an arithmetic expansion (indicate start of one and set state)
11757 parsearith: {
11758 if (++arinest == 1) {
11759 prevsyntax = syntax;
11760 syntax = ARISYNTAX;
11762 USTPUTC(CTLARI, out);
11763 goto parsearith_return;
11765 #endif
11766 } /* end of readtoken */
11769 * Read the next input token.
11770 * If the token is a word, we set backquotelist to the list of cmds in
11771 * backquotes. We set quoteflag to true if any part of the word was
11772 * quoted.
11773 * If the token is TREDIR, then we set redirnode to a structure containing
11774 * the redirection.
11775 * In all cases, the variable startlinno is set to the number of the line
11776 * on which the token starts.
11778 * [Change comment: here documents and internal procedures]
11779 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11780 * word parsing code into a separate routine. In this case, readtoken
11781 * doesn't need to have any internal procedures, but parseword does.
11782 * We could also make parseoperator in essence the main routine, and
11783 * have parseword (readtoken1?) handle both words and redirection.]
11785 #define NEW_xxreadtoken
11786 #ifdef NEW_xxreadtoken
11787 /* singles must be first! */
11788 static const char xxreadtoken_chars[7] ALIGN1 = {
11789 '\n', '(', ')', /* singles */
11790 '&', '|', ';', /* doubles */
11794 #define xxreadtoken_singles 3
11795 #define xxreadtoken_doubles 3
11797 static const char xxreadtoken_tokens[] ALIGN1 = {
11798 TNL, TLP, TRP, /* only single occurrence allowed */
11799 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11800 TEOF, /* corresponds to trailing nul */
11801 TAND, TOR, TENDCASE /* if double occurrence */
11804 static int
11805 xxreadtoken(void)
11807 int c;
11809 if (tokpushback) {
11810 tokpushback = 0;
11811 return lasttoken;
11813 setprompt_if(needprompt, 2);
11814 startlinno = g_parsefile->linno;
11815 for (;;) { /* until token or start of word found */
11816 c = pgetc_fast();
11817 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
11818 continue;
11820 if (c == '#') {
11821 while ((c = pgetc()) != '\n' && c != PEOF)
11822 continue;
11823 pungetc();
11824 } else if (c == '\\') {
11825 if (pgetc() != '\n') {
11826 pungetc();
11827 break; /* return readtoken1(...) */
11829 startlinno = ++g_parsefile->linno;
11830 setprompt_if(doprompt, 2);
11831 } else {
11832 const char *p;
11834 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11835 if (c != PEOF) {
11836 if (c == '\n') {
11837 g_parsefile->linno++;
11838 needprompt = doprompt;
11841 p = strchr(xxreadtoken_chars, c);
11842 if (p == NULL)
11843 break; /* return readtoken1(...) */
11845 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11846 int cc = pgetc();
11847 if (cc == c) { /* double occurrence? */
11848 p += xxreadtoken_doubles + 1;
11849 } else {
11850 pungetc();
11851 #if ENABLE_ASH_BASH_COMPAT
11852 if (c == '&' && cc == '>') /* &> */
11853 break; /* return readtoken1(...) */
11854 #endif
11858 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11859 return lasttoken;
11861 } /* for (;;) */
11863 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11865 #else /* old xxreadtoken */
11866 #define RETURN(token) return lasttoken = token
11867 static int
11868 xxreadtoken(void)
11870 int c;
11872 if (tokpushback) {
11873 tokpushback = 0;
11874 return lasttoken;
11876 setprompt_if(needprompt, 2);
11877 startlinno = g_parsefile->linno;
11878 for (;;) { /* until token or start of word found */
11879 c = pgetc_fast();
11880 switch (c) {
11881 case ' ': case '\t':
11882 IF_ASH_ALIAS(case PEOA:)
11883 continue;
11884 case '#':
11885 while ((c = pgetc()) != '\n' && c != PEOF)
11886 continue;
11887 pungetc();
11888 continue;
11889 case '\\':
11890 if (pgetc() == '\n') {
11891 startlinno = ++g_parsefile->linno;
11892 setprompt_if(doprompt, 2);
11893 continue;
11895 pungetc();
11896 goto breakloop;
11897 case '\n':
11898 g_parsefile->linno++;
11899 needprompt = doprompt;
11900 RETURN(TNL);
11901 case PEOF:
11902 RETURN(TEOF);
11903 case '&':
11904 if (pgetc() == '&')
11905 RETURN(TAND);
11906 pungetc();
11907 RETURN(TBACKGND);
11908 case '|':
11909 if (pgetc() == '|')
11910 RETURN(TOR);
11911 pungetc();
11912 RETURN(TPIPE);
11913 case ';':
11914 if (pgetc() == ';')
11915 RETURN(TENDCASE);
11916 pungetc();
11917 RETURN(TSEMI);
11918 case '(':
11919 RETURN(TLP);
11920 case ')':
11921 RETURN(TRP);
11922 default:
11923 goto breakloop;
11926 breakloop:
11927 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11928 #undef RETURN
11930 #endif /* old xxreadtoken */
11932 static int
11933 readtoken(void)
11935 int t;
11936 int kwd = checkkwd;
11937 #if DEBUG
11938 smallint alreadyseen = tokpushback;
11939 #endif
11941 #if ENABLE_ASH_ALIAS
11942 top:
11943 #endif
11945 t = xxreadtoken();
11948 * eat newlines
11950 if (kwd & CHKNL) {
11951 while (t == TNL) {
11952 parseheredoc();
11953 t = xxreadtoken();
11957 if (t != TWORD || quoteflag) {
11958 goto out;
11962 * check for keywords
11964 if (kwd & CHKKWD) {
11965 const char *const *pp;
11967 pp = findkwd(wordtext);
11968 if (pp) {
11969 lasttoken = t = pp - tokname_array;
11970 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
11971 goto out;
11975 if (checkkwd & CHKALIAS) {
11976 #if ENABLE_ASH_ALIAS
11977 struct alias *ap;
11978 ap = lookupalias(wordtext, 1);
11979 if (ap != NULL) {
11980 if (*ap->val) {
11981 pushstring(ap->val, ap);
11983 goto top;
11985 #endif
11987 out:
11988 checkkwd = 0;
11989 #if DEBUG
11990 if (!alreadyseen)
11991 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
11992 else
11993 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
11994 #endif
11995 return t;
11998 static int
11999 peektoken(void)
12001 int t;
12003 t = readtoken();
12004 tokpushback = 1;
12005 return t;
12009 * Read and parse a command. Returns NODE_EOF on end of file.
12010 * (NULL is a valid parse tree indicating a blank line.)
12012 static union node *
12013 parsecmd(int interact)
12015 tokpushback = 0;
12016 checkkwd = 0;
12017 heredoclist = 0;
12018 doprompt = interact;
12019 setprompt_if(doprompt, doprompt);
12020 needprompt = 0;
12021 return list(1);
12025 * Input any here documents.
12027 static void
12028 parseheredoc(void)
12030 struct heredoc *here;
12031 union node *n;
12033 here = heredoclist;
12034 heredoclist = NULL;
12036 while (here) {
12037 setprompt_if(needprompt, 2);
12038 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
12039 here->eofmark, here->striptabs);
12040 n = stzalloc(sizeof(struct narg));
12041 n->narg.type = NARG;
12042 /*n->narg.next = NULL; - stzalloc did it */
12043 n->narg.text = wordtext;
12044 n->narg.backquote = backquotelist;
12045 here->here->nhere.doc = n;
12046 here = here->next;
12052 * called by editline -- any expansions to the prompt should be added here.
12054 #if ENABLE_ASH_EXPAND_PRMT
12055 static const char *
12056 expandstr(const char *ps)
12058 union node n;
12060 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12061 * and token processing _can_ alter it (delete NULs etc). */
12062 setinputstring((char *)ps);
12063 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
12064 popfile();
12066 n.narg.type = NARG;
12067 n.narg.next = NULL;
12068 n.narg.text = wordtext;
12069 n.narg.backquote = backquotelist;
12071 expandarg(&n, NULL, EXP_QUOTED);
12072 return stackblock();
12074 #endif
12077 * Execute a command or commands contained in a string.
12079 static int
12080 evalstring(char *s, int mask)
12082 union node *n;
12083 struct stackmark smark;
12084 int skip;
12086 setinputstring(s);
12087 setstackmark(&smark);
12089 skip = 0;
12090 while ((n = parsecmd(0)) != NODE_EOF) {
12091 evaltree(n, 0);
12092 popstackmark(&smark);
12093 skip = evalskip;
12094 if (skip)
12095 break;
12097 popfile();
12099 skip &= mask;
12100 evalskip = skip;
12101 return skip;
12105 * The eval command.
12107 static int FAST_FUNC
12108 evalcmd(int argc UNUSED_PARAM, char **argv)
12110 char *p;
12111 char *concat;
12113 if (argv[1]) {
12114 p = argv[1];
12115 argv += 2;
12116 if (argv[0]) {
12117 STARTSTACKSTR(concat);
12118 for (;;) {
12119 concat = stack_putstr(p, concat);
12120 p = *argv++;
12121 if (p == NULL)
12122 break;
12123 STPUTC(' ', concat);
12125 STPUTC('\0', concat);
12126 p = grabstackstr(concat);
12128 evalstring(p, ~SKIPEVAL);
12130 return exitstatus;
12134 * Read and execute commands.
12135 * "Top" is nonzero for the top level command loop;
12136 * it turns on prompting if the shell is interactive.
12138 static int
12139 cmdloop(int top)
12141 union node *n;
12142 struct stackmark smark;
12143 int inter;
12144 int numeof = 0;
12146 TRACE(("cmdloop(%d) called\n", top));
12147 for (;;) {
12148 int skip;
12150 setstackmark(&smark);
12151 #if JOBS
12152 if (doing_jobctl)
12153 showjobs(SHOW_CHANGED|SHOW_STDERR);
12154 #endif
12155 inter = 0;
12156 if (iflag && top) {
12157 inter++;
12158 chkmail();
12160 n = parsecmd(inter);
12161 #if DEBUG
12162 if (DEBUG > 2 && debug && (n != NODE_EOF))
12163 showtree(n);
12164 #endif
12165 if (n == NODE_EOF) {
12166 if (!top || numeof >= 50)
12167 break;
12168 if (!stoppedjobs()) {
12169 if (!Iflag)
12170 break;
12171 out2str("\nUse \"exit\" to leave shell.\n");
12173 numeof++;
12174 } else if (nflag == 0) {
12175 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12176 job_warning >>= 1;
12177 numeof = 0;
12178 evaltree(n, 0);
12180 popstackmark(&smark);
12181 skip = evalskip;
12183 if (skip) {
12184 evalskip = 0;
12185 return skip & SKIPEVAL;
12188 return 0;
12192 * Take commands from a file. To be compatible we should do a path
12193 * search for the file, which is necessary to find sub-commands.
12195 static char *
12196 find_dot_file(char *name)
12198 char *fullname;
12199 const char *path = pathval();
12200 struct stat statb;
12202 /* don't try this for absolute or relative paths */
12203 if (strchr(name, '/'))
12204 return name;
12206 /* IIRC standards do not say whether . is to be searched.
12207 * And it is even smaller this way, making it unconditional for now:
12209 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12210 fullname = name;
12211 goto try_cur_dir;
12214 while ((fullname = path_advance(&path, name)) != NULL) {
12215 try_cur_dir:
12216 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12218 * Don't bother freeing here, since it will
12219 * be freed by the caller.
12221 return fullname;
12223 if (fullname != name)
12224 stunalloc(fullname);
12227 /* not found in the PATH */
12228 ash_msg_and_raise_error("%s: not found", name);
12229 /* NOTREACHED */
12232 static int FAST_FUNC
12233 dotcmd(int argc, char **argv)
12235 char *fullname;
12236 struct strlist *sp;
12237 volatile struct shparam saveparam;
12239 for (sp = cmdenviron; sp; sp = sp->next)
12240 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
12242 if (!argv[1]) {
12243 /* bash says: "bash: .: filename argument required" */
12244 return 2; /* bash compat */
12247 /* "false; . empty_file; echo $?" should print 0, not 1: */
12248 exitstatus = 0;
12250 /* This aborts if file isn't found, which is POSIXly correct.
12251 * bash returns exitcode 1 instead.
12253 fullname = find_dot_file(argv[1]);
12254 argv += 2;
12255 argc -= 2;
12256 if (argc) { /* argc > 0, argv[0] != NULL */
12257 saveparam = shellparam;
12258 shellparam.malloced = 0;
12259 shellparam.nparam = argc;
12260 shellparam.p = argv;
12263 /* This aborts if file can't be opened, which is POSIXly correct.
12264 * bash returns exitcode 1 instead.
12266 setinputfile(fullname, INPUT_PUSH_FILE);
12267 commandname = fullname;
12268 cmdloop(0);
12269 popfile();
12271 if (argc) {
12272 freeparam(&shellparam);
12273 shellparam = saveparam;
12276 return exitstatus;
12279 static int FAST_FUNC
12280 exitcmd(int argc UNUSED_PARAM, char **argv)
12282 if (stoppedjobs())
12283 return 0;
12284 if (argv[1])
12285 exitstatus = number(argv[1]);
12286 raise_exception(EXEXIT);
12287 /* NOTREACHED */
12291 * Read a file containing shell functions.
12293 static void
12294 readcmdfile(char *name)
12296 setinputfile(name, INPUT_PUSH_FILE);
12297 cmdloop(0);
12298 popfile();
12302 /* ============ find_command inplementation */
12305 * Resolve a command name. If you change this routine, you may have to
12306 * change the shellexec routine as well.
12308 static void
12309 find_command(char *name, struct cmdentry *entry, int act, const char *path)
12311 struct tblentry *cmdp;
12312 int idx;
12313 int prev;
12314 char *fullname;
12315 struct stat statb;
12316 int e;
12317 int updatetbl;
12318 struct builtincmd *bcmd;
12320 /* If name contains a slash, don't use PATH or hash table */
12321 if (strchr(name, '/') != NULL) {
12322 entry->u.index = -1;
12323 if (act & DO_ABS) {
12324 while (stat(name, &statb) < 0) {
12325 #ifdef SYSV
12326 if (errno == EINTR)
12327 continue;
12328 #endif
12329 entry->cmdtype = CMDUNKNOWN;
12330 return;
12333 entry->cmdtype = CMDNORMAL;
12334 return;
12337 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
12339 updatetbl = (path == pathval());
12340 if (!updatetbl) {
12341 act |= DO_ALTPATH;
12342 if (strstr(path, "%builtin") != NULL)
12343 act |= DO_ALTBLTIN;
12346 /* If name is in the table, check answer will be ok */
12347 cmdp = cmdlookup(name, 0);
12348 if (cmdp != NULL) {
12349 int bit;
12351 switch (cmdp->cmdtype) {
12352 default:
12353 #if DEBUG
12354 abort();
12355 #endif
12356 case CMDNORMAL:
12357 bit = DO_ALTPATH;
12358 break;
12359 case CMDFUNCTION:
12360 bit = DO_NOFUNC;
12361 break;
12362 case CMDBUILTIN:
12363 bit = DO_ALTBLTIN;
12364 break;
12366 if (act & bit) {
12367 updatetbl = 0;
12368 cmdp = NULL;
12369 } else if (cmdp->rehash == 0)
12370 /* if not invalidated by cd, we're done */
12371 goto success;
12374 /* If %builtin not in path, check for builtin next */
12375 bcmd = find_builtin(name);
12376 if (bcmd) {
12377 if (IS_BUILTIN_REGULAR(bcmd))
12378 goto builtin_success;
12379 if (act & DO_ALTPATH) {
12380 if (!(act & DO_ALTBLTIN))
12381 goto builtin_success;
12382 } else if (builtinloc <= 0) {
12383 goto builtin_success;
12387 #if ENABLE_FEATURE_SH_STANDALONE
12389 int applet_no = find_applet_by_name(name);
12390 if (applet_no >= 0) {
12391 entry->cmdtype = CMDNORMAL;
12392 entry->u.index = -2 - applet_no;
12393 return;
12396 #endif
12398 /* We have to search path. */
12399 prev = -1; /* where to start */
12400 if (cmdp && cmdp->rehash) { /* doing a rehash */
12401 if (cmdp->cmdtype == CMDBUILTIN)
12402 prev = builtinloc;
12403 else
12404 prev = cmdp->param.index;
12407 e = ENOENT;
12408 idx = -1;
12409 loop:
12410 while ((fullname = path_advance(&path, name)) != NULL) {
12411 stunalloc(fullname);
12412 /* NB: code below will still use fullname
12413 * despite it being "unallocated" */
12414 idx++;
12415 if (pathopt) {
12416 if (prefix(pathopt, "builtin")) {
12417 if (bcmd)
12418 goto builtin_success;
12419 continue;
12421 if ((act & DO_NOFUNC)
12422 || !prefix(pathopt, "func")
12423 ) { /* ignore unimplemented options */
12424 continue;
12427 /* if rehash, don't redo absolute path names */
12428 if (fullname[0] == '/' && idx <= prev) {
12429 if (idx < prev)
12430 continue;
12431 TRACE(("searchexec \"%s\": no change\n", name));
12432 goto success;
12434 while (stat(fullname, &statb) < 0) {
12435 #ifdef SYSV
12436 if (errno == EINTR)
12437 continue;
12438 #endif
12439 if (errno != ENOENT && errno != ENOTDIR)
12440 e = errno;
12441 goto loop;
12443 e = EACCES; /* if we fail, this will be the error */
12444 if (!S_ISREG(statb.st_mode))
12445 continue;
12446 if (pathopt) { /* this is a %func directory */
12447 stalloc(strlen(fullname) + 1);
12448 /* NB: stalloc will return space pointed by fullname
12449 * (because we don't have any intervening allocations
12450 * between stunalloc above and this stalloc) */
12451 readcmdfile(fullname);
12452 cmdp = cmdlookup(name, 0);
12453 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12454 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12455 stunalloc(fullname);
12456 goto success;
12458 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12459 if (!updatetbl) {
12460 entry->cmdtype = CMDNORMAL;
12461 entry->u.index = idx;
12462 return;
12464 INT_OFF;
12465 cmdp = cmdlookup(name, 1);
12466 cmdp->cmdtype = CMDNORMAL;
12467 cmdp->param.index = idx;
12468 INT_ON;
12469 goto success;
12472 /* We failed. If there was an entry for this command, delete it */
12473 if (cmdp && updatetbl)
12474 delete_cmd_entry();
12475 if (act & DO_ERR)
12476 ash_msg("%s: %s", name, errmsg(e, "not found"));
12477 entry->cmdtype = CMDUNKNOWN;
12478 return;
12480 builtin_success:
12481 if (!updatetbl) {
12482 entry->cmdtype = CMDBUILTIN;
12483 entry->u.cmd = bcmd;
12484 return;
12486 INT_OFF;
12487 cmdp = cmdlookup(name, 1);
12488 cmdp->cmdtype = CMDBUILTIN;
12489 cmdp->param.cmd = bcmd;
12490 INT_ON;
12491 success:
12492 cmdp->rehash = 0;
12493 entry->cmdtype = cmdp->cmdtype;
12494 entry->u = cmdp->param;
12498 /* ============ trap.c */
12501 * The trap builtin.
12503 static int FAST_FUNC
12504 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12506 char *action;
12507 char **ap;
12508 int signo, exitcode;
12510 nextopt(nullstr);
12511 ap = argptr;
12512 if (!*ap) {
12513 for (signo = 0; signo < NSIG; signo++) {
12514 char *tr = trap_ptr[signo];
12515 if (tr) {
12516 /* note: bash adds "SIG", but only if invoked
12517 * as "bash". If called as "sh", or if set -o posix,
12518 * then it prints short signal names.
12519 * We are printing short names: */
12520 out1fmt("trap -- %s %s\n",
12521 single_quote(tr),
12522 get_signame(signo));
12523 /* trap_ptr != trap only if we are in special-cased `trap` code.
12524 * In this case, we will exit very soon, no need to free(). */
12525 /* if (trap_ptr != trap && tp[0]) */
12526 /* free(tr); */
12530 if (trap_ptr != trap) {
12531 free(trap_ptr);
12532 trap_ptr = trap;
12535 return 0;
12538 action = NULL;
12539 if (ap[1])
12540 action = *ap++;
12541 exitcode = 0;
12542 while (*ap) {
12543 signo = get_signum(*ap);
12544 if (signo < 0) {
12545 /* Mimic bash message exactly */
12546 ash_msg("%s: invalid signal specification", *ap);
12547 exitcode = 1;
12548 goto next;
12550 INT_OFF;
12551 if (action) {
12552 if (LONE_DASH(action))
12553 action = NULL;
12554 else
12555 action = ckstrdup(action);
12557 free(trap[signo]);
12558 if (action)
12559 may_have_traps = 1;
12560 trap[signo] = action;
12561 if (signo != 0)
12562 setsignal(signo);
12563 INT_ON;
12564 next:
12565 ap++;
12567 return exitcode;
12571 /* ============ Builtins */
12573 #if ENABLE_ASH_HELP
12574 static int FAST_FUNC
12575 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12577 unsigned col;
12578 unsigned i;
12580 out1fmt(
12581 "Built-in commands:\n"
12582 "------------------\n");
12583 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12584 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12585 builtintab[i].name + 1);
12586 if (col > 60) {
12587 out1fmt("\n");
12588 col = 0;
12591 # if ENABLE_FEATURE_SH_STANDALONE
12593 const char *a = applet_names;
12594 while (*a) {
12595 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12596 if (col > 60) {
12597 out1fmt("\n");
12598 col = 0;
12600 while (*a++ != '\0')
12601 continue;
12604 # endif
12605 out1fmt("\n\n");
12606 return EXIT_SUCCESS;
12608 #endif
12610 #if MAX_HISTORY
12611 static int FAST_FUNC
12612 historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12614 show_history(line_input_state);
12615 return EXIT_SUCCESS;
12617 #endif
12620 * The export and readonly commands.
12622 static int FAST_FUNC
12623 exportcmd(int argc UNUSED_PARAM, char **argv)
12625 struct var *vp;
12626 char *name;
12627 const char *p;
12628 char **aptr;
12629 char opt;
12630 int flag;
12631 int flag_off;
12633 /* "readonly" in bash accepts, but ignores -n.
12634 * We do the same: it saves a conditional in nextopt's param.
12636 flag_off = 0;
12637 while ((opt = nextopt("np")) != '\0') {
12638 if (opt == 'n')
12639 flag_off = VEXPORT;
12641 flag = VEXPORT;
12642 if (argv[0][0] == 'r') {
12643 flag = VREADONLY;
12644 flag_off = 0; /* readonly ignores -n */
12646 flag_off = ~flag_off;
12648 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12650 aptr = argptr;
12651 name = *aptr;
12652 if (name) {
12653 do {
12654 p = strchr(name, '=');
12655 if (p != NULL) {
12656 p++;
12657 } else {
12658 vp = *findvar(hashvar(name), name);
12659 if (vp) {
12660 vp->flags = ((vp->flags | flag) & flag_off);
12661 continue;
12664 setvar(name, p, (flag & flag_off));
12665 } while ((name = *++aptr) != NULL);
12666 return 0;
12670 /* No arguments. Show the list of exported or readonly vars.
12671 * -n is ignored.
12673 showvars(argv[0], flag, 0);
12674 return 0;
12678 * Delete a function if it exists.
12680 static void
12681 unsetfunc(const char *name)
12683 struct tblentry *cmdp;
12685 cmdp = cmdlookup(name, 0);
12686 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
12687 delete_cmd_entry();
12691 * The unset builtin command. We unset the function before we unset the
12692 * variable to allow a function to be unset when there is a readonly variable
12693 * with the same name.
12695 static int FAST_FUNC
12696 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12698 char **ap;
12699 int i;
12700 int flag = 0;
12701 int ret = 0;
12703 while ((i = nextopt("vf")) != 0) {
12704 flag = i;
12707 for (ap = argptr; *ap; ap++) {
12708 if (flag != 'f') {
12709 i = unsetvar(*ap);
12710 ret |= i;
12711 if (!(i & 2))
12712 continue;
12714 if (flag != 'v')
12715 unsetfunc(*ap);
12717 return ret & 1;
12720 static const unsigned char timescmd_str[] ALIGN1 = {
12721 ' ', offsetof(struct tms, tms_utime),
12722 '\n', offsetof(struct tms, tms_stime),
12723 ' ', offsetof(struct tms, tms_cutime),
12724 '\n', offsetof(struct tms, tms_cstime),
12727 static int FAST_FUNC
12728 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12730 unsigned long clk_tck, s, t;
12731 const unsigned char *p;
12732 struct tms buf;
12734 clk_tck = bb_clk_tck();
12735 times(&buf);
12737 p = timescmd_str;
12738 do {
12739 t = *(clock_t *)(((char *) &buf) + p[1]);
12740 s = t / clk_tck;
12741 t = t % clk_tck;
12742 out1fmt("%lum%lu.%03lus%c",
12743 s / 60, s % 60,
12744 (t * 1000) / clk_tck,
12745 p[0]);
12746 p += 2;
12747 } while (*p);
12749 return 0;
12752 #if ENABLE_SH_MATH_SUPPORT
12754 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
12755 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12757 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12759 static int FAST_FUNC
12760 letcmd(int argc UNUSED_PARAM, char **argv)
12762 arith_t i;
12764 argv++;
12765 if (!*argv)
12766 ash_msg_and_raise_error("expression expected");
12767 do {
12768 i = ash_arith(*argv);
12769 } while (*++argv);
12771 return !i;
12773 #endif
12776 * The read builtin. Options:
12777 * -r Do not interpret '\' specially
12778 * -s Turn off echo (tty only)
12779 * -n NCHARS Read NCHARS max
12780 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12781 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12782 * -u FD Read from given FD instead of fd 0
12783 * This uses unbuffered input, which may be avoidable in some cases.
12784 * TODO: bash also has:
12785 * -a ARRAY Read into array[0],[1],etc
12786 * -d DELIM End on DELIM char, not newline
12787 * -e Use line editing (tty only)
12789 static int FAST_FUNC
12790 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12792 char *opt_n = NULL;
12793 char *opt_p = NULL;
12794 char *opt_t = NULL;
12795 char *opt_u = NULL;
12796 int read_flags = 0;
12797 const char *r;
12798 int i;
12800 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
12801 switch (i) {
12802 case 'p':
12803 opt_p = optionarg;
12804 break;
12805 case 'n':
12806 opt_n = optionarg;
12807 break;
12808 case 's':
12809 read_flags |= BUILTIN_READ_SILENT;
12810 break;
12811 case 't':
12812 opt_t = optionarg;
12813 break;
12814 case 'r':
12815 read_flags |= BUILTIN_READ_RAW;
12816 break;
12817 case 'u':
12818 opt_u = optionarg;
12819 break;
12820 default:
12821 break;
12825 /* "read -s" needs to save/restore termios, can't allow ^C
12826 * to jump out of it.
12828 INT_OFF;
12829 r = shell_builtin_read(setvar0,
12830 argptr,
12831 bltinlookup("IFS"), /* can be NULL */
12832 read_flags,
12833 opt_n,
12834 opt_p,
12835 opt_t,
12836 opt_u
12838 INT_ON;
12840 if ((uintptr_t)r > 1)
12841 ash_msg_and_raise_error(r);
12843 return (uintptr_t)r;
12846 static int FAST_FUNC
12847 umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12849 static const char permuser[3] ALIGN1 = "ogu";
12851 mode_t mask;
12852 int symbolic_mode = 0;
12854 while (nextopt("S") != '\0') {
12855 symbolic_mode = 1;
12858 INT_OFF;
12859 mask = umask(0);
12860 umask(mask);
12861 INT_ON;
12863 if (*argptr == NULL) {
12864 if (symbolic_mode) {
12865 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
12866 char *p = buf;
12867 int i;
12869 i = 2;
12870 for (;;) {
12871 *p++ = ',';
12872 *p++ = permuser[i];
12873 *p++ = '=';
12874 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
12875 if (!(mask & 0400)) *p++ = 'r';
12876 if (!(mask & 0200)) *p++ = 'w';
12877 if (!(mask & 0100)) *p++ = 'x';
12878 mask <<= 3;
12879 if (--i < 0)
12880 break;
12882 *p = '\0';
12883 puts(buf + 1);
12884 } else {
12885 out1fmt("%04o\n", mask);
12887 } else {
12888 char *modestr = *argptr;
12889 /* numeric umasks are taken as-is */
12890 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
12891 if (!isdigit(modestr[0]))
12892 mask ^= 0777;
12893 mask = bb_parse_mode(modestr, mask);
12894 if ((unsigned)mask > 0777) {
12895 ash_msg_and_raise_error("illegal mode: %s", modestr);
12897 if (!isdigit(modestr[0]))
12898 mask ^= 0777;
12899 umask(mask);
12901 return 0;
12904 static int FAST_FUNC
12905 ulimitcmd(int argc UNUSED_PARAM, char **argv)
12907 return shell_builtin_ulimit(argv);
12910 /* ============ main() and helpers */
12913 * Called to exit the shell.
12915 static void
12916 exitshell(void)
12918 struct jmploc loc;
12919 char *p;
12920 int status;
12922 #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
12923 save_history(line_input_state);
12924 #endif
12926 status = exitstatus;
12927 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12928 if (setjmp(loc.loc)) {
12929 if (exception_type == EXEXIT)
12930 /* dash bug: it just does _exit(exitstatus) here
12931 * but we have to do setjobctl(0) first!
12932 * (bug is still not fixed in dash-0.5.3 - if you run dash
12933 * under Midnight Commander, on exit from dash MC is backgrounded) */
12934 status = exitstatus;
12935 goto out;
12937 exception_handler = &loc;
12938 p = trap[0];
12939 if (p) {
12940 trap[0] = NULL;
12941 evalstring(p, 0);
12942 free(p);
12944 flush_stdout_stderr();
12945 out:
12946 setjobctl(0);
12947 _exit(status);
12948 /* NOTREACHED */
12951 static void
12952 init(void)
12954 /* from input.c: */
12955 /* we will never free this */
12956 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
12958 /* from trap.c: */
12959 signal(SIGCHLD, SIG_DFL);
12960 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
12961 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
12963 signal(SIGHUP, SIG_DFL);
12965 /* from var.c: */
12967 char **envp;
12968 const char *p;
12969 struct stat st1, st2;
12971 initvar();
12972 for (envp = environ; envp && *envp; envp++) {
12973 if (strchr(*envp, '=')) {
12974 setvareq(*envp, VEXPORT|VTEXTFIXED);
12978 setvar0("PPID", utoa(getppid()));
12979 #if ENABLE_ASH_BASH_COMPAT
12980 p = lookupvar("SHLVL");
12981 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
12982 if (!lookupvar("HOSTNAME")) {
12983 struct utsname uts;
12984 uname(&uts);
12985 setvar0("HOSTNAME", uts.nodename);
12987 #endif
12988 p = lookupvar("PWD");
12989 if (p) {
12990 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
12991 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
12993 p = '\0';
12996 setpwd(p, 0);
13001 //usage:#define ash_trivial_usage
13002 //usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
13003 //usage:#define ash_full_usage "\n\n"
13004 //usage: "Unix shell interpreter"
13006 //usage:#if ENABLE_FEATURE_SH_IS_ASH
13007 //usage:# define sh_trivial_usage ash_trivial_usage
13008 //usage:# define sh_full_usage ash_full_usage
13009 //usage:#endif
13010 //usage:#if ENABLE_FEATURE_BASH_IS_ASH
13011 //usage:# define bash_trivial_usage ash_trivial_usage
13012 //usage:# define bash_full_usage ash_full_usage
13013 //usage:#endif
13016 * Process the shell command line arguments.
13018 static void
13019 procargs(char **argv)
13021 int i;
13022 const char *xminusc;
13023 char **xargv;
13025 xargv = argv;
13026 arg0 = xargv[0];
13027 /* if (xargv[0]) - mmm, this is always true! */
13028 xargv++;
13029 for (i = 0; i < NOPTS; i++)
13030 optlist[i] = 2;
13031 argptr = xargv;
13032 if (options(/*cmdline:*/ 1)) {
13033 /* it already printed err message */
13034 raise_exception(EXERROR);
13036 xargv = argptr;
13037 xminusc = minusc;
13038 if (*xargv == NULL) {
13039 if (xminusc)
13040 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13041 sflag = 1;
13043 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13044 iflag = 1;
13045 if (mflag == 2)
13046 mflag = iflag;
13047 for (i = 0; i < NOPTS; i++)
13048 if (optlist[i] == 2)
13049 optlist[i] = 0;
13050 #if DEBUG == 2
13051 debug = 1;
13052 #endif
13053 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13054 if (xminusc) {
13055 minusc = *xargv++;
13056 if (*xargv)
13057 goto setarg0;
13058 } else if (!sflag) {
13059 setinputfile(*xargv, 0);
13060 setarg0:
13061 arg0 = *xargv++;
13062 commandname = arg0;
13065 shellparam.p = xargv;
13066 #if ENABLE_ASH_GETOPTS
13067 shellparam.optind = 1;
13068 shellparam.optoff = -1;
13069 #endif
13070 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13071 while (*xargv) {
13072 shellparam.nparam++;
13073 xargv++;
13075 optschanged();
13079 * Read /etc/profile or .profile.
13081 static void
13082 read_profile(const char *name)
13084 int skip;
13086 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13087 return;
13088 skip = cmdloop(0);
13089 popfile();
13090 if (skip)
13091 exitshell();
13095 * This routine is called when an error or an interrupt occurs in an
13096 * interactive shell and control is returned to the main command loop.
13098 static void
13099 reset(void)
13101 /* from eval.c: */
13102 evalskip = 0;
13103 loopnest = 0;
13104 /* from input.c: */
13105 g_parsefile->left_in_buffer = 0;
13106 g_parsefile->left_in_line = 0; /* clear input buffer */
13107 popallfiles();
13108 /* from parser.c: */
13109 tokpushback = 0;
13110 checkkwd = 0;
13111 /* from redir.c: */
13112 clearredir(/*drop:*/ 0);
13115 #if PROFILE
13116 static short profile_buf[16384];
13117 extern int etext();
13118 #endif
13121 * Main routine. We initialize things, parse the arguments, execute
13122 * profiles if we're a login shell, and then call cmdloop to execute
13123 * commands. The setjmp call sets up the location to jump to when an
13124 * exception occurs. When an exception occurs the variable "state"
13125 * is used to figure out how far we had gotten.
13127 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13128 int ash_main(int argc UNUSED_PARAM, char **argv)
13130 const char *shinit;
13131 volatile smallint state;
13132 struct jmploc jmploc;
13133 struct stackmark smark;
13135 /* Initialize global data */
13136 INIT_G_misc();
13137 INIT_G_memstack();
13138 INIT_G_var();
13139 #if ENABLE_ASH_ALIAS
13140 INIT_G_alias();
13141 #endif
13142 INIT_G_cmdtable();
13144 #if PROFILE
13145 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13146 #endif
13148 #if ENABLE_FEATURE_EDITING
13149 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13150 #endif
13151 state = 0;
13152 if (setjmp(jmploc.loc)) {
13153 smallint e;
13154 smallint s;
13156 reset();
13158 e = exception_type;
13159 if (e == EXERROR)
13160 exitstatus = 2;
13161 s = state;
13162 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
13163 exitshell();
13165 if (e == EXINT) {
13166 newline_and_flush(stderr);
13169 popstackmark(&smark);
13170 FORCE_INT_ON; /* enable interrupts */
13171 if (s == 1)
13172 goto state1;
13173 if (s == 2)
13174 goto state2;
13175 if (s == 3)
13176 goto state3;
13177 goto state4;
13179 exception_handler = &jmploc;
13180 #if DEBUG
13181 opentrace();
13182 TRACE(("Shell args: "));
13183 trace_puts_args(argv);
13184 #endif
13185 rootpid = getpid();
13187 init();
13188 setstackmark(&smark);
13189 procargs(argv);
13191 if (argv[0] && argv[0][0] == '-')
13192 isloginsh = 1;
13193 if (isloginsh) {
13194 const char *hp;
13196 state = 1;
13197 read_profile("/etc/profile");
13198 state1:
13199 state = 2;
13200 hp = lookupvar("HOME");
13201 if (hp) {
13202 hp = concat_path_file(hp, ".profile");
13203 read_profile(hp);
13204 free((char*)hp);
13207 state2:
13208 state = 3;
13209 if (
13210 #ifndef linux
13211 getuid() == geteuid() && getgid() == getegid() &&
13212 #endif
13213 iflag
13215 shinit = lookupvar("ENV");
13216 if (shinit != NULL && *shinit != '\0') {
13217 read_profile(shinit);
13220 state3:
13221 state = 4;
13222 if (minusc) {
13223 /* evalstring pushes parsefile stack.
13224 * Ensure we don't falsely claim that 0 (stdin)
13225 * is one of stacked source fds.
13226 * Testcase: ash -c 'exec 1>&0' must not complain. */
13227 // if (!sflag) g_parsefile->pf_fd = -1;
13228 // ^^ not necessary since now we special-case fd 0
13229 // in is_hidden_fd() to not be considered "hidden fd"
13230 evalstring(minusc, 0);
13233 if (sflag || minusc == NULL) {
13234 #if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
13235 if (iflag) {
13236 const char *hp = lookupvar("HISTFILE");
13237 if (!hp) {
13238 hp = lookupvar("HOME");
13239 if (hp) {
13240 hp = concat_path_file(hp, ".ash_history");
13241 setvar0("HISTFILE", hp);
13242 free((char*)hp);
13243 hp = lookupvar("HISTFILE");
13246 if (hp)
13247 line_input_state->hist_file = hp;
13248 # if ENABLE_FEATURE_SH_HISTFILESIZE
13249 hp = lookupvar("HISTFILESIZE");
13250 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13251 # endif
13253 #endif
13254 state4: /* XXX ??? - why isn't this before the "if" statement */
13255 cmdloop(1);
13257 #if PROFILE
13258 monitor(0);
13259 #endif
13260 #ifdef GPROF
13262 extern void _mcleanup(void);
13263 _mcleanup();
13265 #endif
13266 TRACE(("End of main reached\n"));
13267 exitshell();
13268 /* NOTREACHED */
13273 * Copyright (c) 1989, 1991, 1993, 1994
13274 * The Regents of the University of California. All rights reserved.
13276 * This code is derived from software contributed to Berkeley by
13277 * Kenneth Almquist.
13279 * Redistribution and use in source and binary forms, with or without
13280 * modification, are permitted provided that the following conditions
13281 * are met:
13282 * 1. Redistributions of source code must retain the above copyright
13283 * notice, this list of conditions and the following disclaimer.
13284 * 2. Redistributions in binary form must reproduce the above copyright
13285 * notice, this list of conditions and the following disclaimer in the
13286 * documentation and/or other materials provided with the distribution.
13287 * 3. Neither the name of the University nor the names of its contributors
13288 * may be used to endorse or promote products derived from this software
13289 * without specific prior written permission.
13291 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13292 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13293 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13294 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13295 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13296 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13297 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13298 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13299 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13300 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13301 * SUCH DAMAGE.