busybox: update to 1.23.2
[tomato.git] / release / src / router / busybox / shell / ash.c
blobc5ad96909f3387cdeb840fad49e2b1e5c5b6fa9d
1 /* vi: set sw=4 ts=4: */
2 /*
3 * ash shell port for busybox
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
8 * Original BSD copyright notice is retained at the end of this file.
10 * Copyright (c) 1989, 1991, 1993, 1994
11 * The Regents of the University of California. All rights reserved.
13 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
14 * was re-ported from NetBSD and debianized.
16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
20 * The following should be set to reflect the type of system you have:
21 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
22 * define SYSV if you are running under System V.
23 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
24 * define DEBUG=2 to compile in and turn on debugging.
26 * When debugging is on (DEBUG is 1 and "set -o debug" was executed),
27 * debugging info will be written to ./trace and a quit signal
28 * will generate a core dump.
30 #define DEBUG 0
31 /* Tweak debug output verbosity here */
32 #define DEBUG_TIME 0
33 #define DEBUG_PID 1
34 #define DEBUG_SIG 1
36 #define PROFILE 0
38 #define JOBS ENABLE_ASH_JOB_CONTROL
40 #include <paths.h>
41 #include <setjmp.h>
42 #include <fnmatch.h>
43 #include <sys/times.h>
44 #include <sys/utsname.h> /* for setting $HOSTNAME */
46 #include "busybox.h" /* for applet_names */
47 #include "unicode.h"
49 #include "shell_common.h"
50 #if ENABLE_SH_MATH_SUPPORT
51 # include "math.h"
52 #endif
53 #if ENABLE_ASH_RANDOM_SUPPORT
54 # include "random.h"
55 #else
56 # define CLEAR_RANDOM_T(rnd) ((void)0)
57 #endif
59 #include "NUM_APPLETS.h"
60 #if NUM_APPLETS == 1
61 /* STANDALONE does not make sense, and won't compile */
62 # undef CONFIG_FEATURE_SH_STANDALONE
63 # undef ENABLE_FEATURE_SH_STANDALONE
64 # undef IF_FEATURE_SH_STANDALONE
65 # undef IF_NOT_FEATURE_SH_STANDALONE
66 # define ENABLE_FEATURE_SH_STANDALONE 0
67 # define IF_FEATURE_SH_STANDALONE(...)
68 # define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
69 #endif
71 #ifndef PIPE_BUF
72 # define PIPE_BUF 4096 /* amount of buffering in a pipe */
73 #endif
75 #if !BB_MMU
76 # error "Do not even bother, ash will not run on NOMMU machine"
77 #endif
79 //config:config ASH
80 //config: bool "ash"
81 //config: default y
82 //config: depends on !NOMMU
83 //config: help
84 //config: Tha 'ash' shell adds about 60k in the default configuration and is
85 //config: the most complete and most pedantically correct shell included with
86 //config: busybox. This shell is actually a derivative of the Debian 'dash'
87 //config: shell (by Herbert Xu), which was created by porting the 'ash' shell
88 //config: (written by Kenneth Almquist) from NetBSD.
89 //config:
90 //config:config ASH_BASH_COMPAT
91 //config: bool "bash-compatible extensions"
92 //config: default y
93 //config: depends on ASH
94 //config: help
95 //config: Enable bash-compatible extensions.
96 //config:
97 //config:config ASH_IDLE_TIMEOUT
98 //config: bool "Idle timeout variable"
99 //config: default n
100 //config: depends on ASH
101 //config: help
102 //config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
103 //config:
104 //config:config ASH_JOB_CONTROL
105 //config: bool "Job control"
106 //config: default y
107 //config: depends on ASH
108 //config: help
109 //config: Enable job control in the ash shell.
110 //config:
111 //config:config ASH_ALIAS
112 //config: bool "Alias support"
113 //config: default y
114 //config: depends on ASH
115 //config: help
116 //config: Enable alias support in the ash shell.
117 //config:
118 //config:config ASH_GETOPTS
119 //config: bool "Builtin getopt to parse positional parameters"
120 //config: default y
121 //config: depends on ASH
122 //config: help
123 //config: Enable support for getopts builtin in ash.
124 //config:
125 //config:config ASH_BUILTIN_ECHO
126 //config: bool "Builtin version of 'echo'"
127 //config: default y
128 //config: depends on ASH
129 //config: help
130 //config: Enable support for echo builtin in ash.
131 //config:
132 //config:config ASH_BUILTIN_PRINTF
133 //config: bool "Builtin version of 'printf'"
134 //config: default y
135 //config: depends on ASH
136 //config: help
137 //config: Enable support for printf builtin in ash.
138 //config:
139 //config:config ASH_BUILTIN_TEST
140 //config: bool "Builtin version of 'test'"
141 //config: default y
142 //config: depends on ASH
143 //config: help
144 //config: Enable support for test builtin in ash.
145 //config:
146 //config:config ASH_HELP
147 //config: bool "help builtin"
148 //config: default y
149 //config: depends on ASH
150 //config: help
151 //config: Enable help builtin in ash.
152 //config:
153 //config:config ASH_CMDCMD
154 //config: bool "'command' command to override shell builtins"
155 //config: default y
156 //config: depends on ASH
157 //config: help
158 //config: Enable support for the ash 'command' builtin, which allows
159 //config: you to run the specified command with the specified arguments,
160 //config: even when there is an ash builtin command with the same name.
161 //config:
162 //config:config ASH_MAIL
163 //config: bool "Check for new mail on interactive shells"
164 //config: default n
165 //config: depends on ASH
166 //config: help
167 //config: Enable "check for new mail" function in the ash shell.
168 //config:
169 //config:config ASH_OPTIMIZE_FOR_SIZE
170 //config: bool "Optimize for size instead of speed"
171 //config: default y
172 //config: depends on ASH
173 //config: help
174 //config: Compile ash for reduced size at the price of speed.
175 //config:
176 //config:config ASH_RANDOM_SUPPORT
177 //config: bool "Pseudorandom generator and $RANDOM variable"
178 //config: default y
179 //config: depends on ASH
180 //config: help
181 //config: Enable pseudorandom generator and dynamic variable "$RANDOM".
182 //config: Each read of "$RANDOM" will generate a new pseudorandom value.
183 //config: You can reset the generator by using a specified start value.
184 //config: After "unset RANDOM" the generator will switch off and this
185 //config: variable will no longer have special treatment.
186 //config:
187 //config:config ASH_EXPAND_PRMT
188 //config: bool "Expand prompt string"
189 //config: default y
190 //config: depends on ASH
191 //config: help
192 //config: "PS#" may contain volatile content, such as backquote commands.
193 //config: This option recreates the prompt string from the environment
194 //config: variable each time it is displayed.
195 //config:
197 //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
198 //applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh))
199 //applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash))
201 //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
202 //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
205 /* ============ Hash table sizes. Configurable. */
207 #define VTABSIZE 39
208 #define ATABSIZE 39
209 #define CMDTABLESIZE 31 /* should be prime */
212 /* ============ Shell options */
214 static const char *const optletters_optnames[] = {
215 "e" "errexit",
216 "f" "noglob",
217 "I" "ignoreeof",
218 "i" "interactive",
219 "m" "monitor",
220 "n" "noexec",
221 "s" "stdin",
222 "x" "xtrace",
223 "v" "verbose",
224 "C" "noclobber",
225 "a" "allexport",
226 "b" "notify",
227 "u" "nounset",
228 "\0" "vi"
229 #if ENABLE_ASH_BASH_COMPAT
230 ,"\0" "pipefail"
231 #endif
232 #if DEBUG
233 ,"\0" "nolog"
234 ,"\0" "debug"
235 #endif
238 #define optletters(n) optletters_optnames[n][0]
239 #define optnames(n) (optletters_optnames[n] + 1)
241 enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
244 /* ============ Misc data */
246 #define msg_illnum "Illegal number: %s"
249 * We enclose jmp_buf in a structure so that we can declare pointers to
250 * jump locations. The global variable handler contains the location to
251 * jump to when an exception occurs, and the global variable exception_type
252 * contains a code identifying the exception. To implement nested
253 * exception handlers, the user should save the value of handler on entry
254 * to an inner scope, set handler to point to a jmploc structure for the
255 * inner scope, and restore handler on exit from the scope.
257 struct jmploc {
258 jmp_buf loc;
261 struct globals_misc {
262 /* pid of main shell */
263 int rootpid;
264 /* shell level: 0 for the main shell, 1 for its children, and so on */
265 int shlvl;
266 #define rootshell (!shlvl)
267 char *minusc; /* argument to -c option */
269 char *curdir; // = nullstr; /* current working directory */
270 char *physdir; // = nullstr; /* physical working directory */
272 char *arg0; /* value of $0 */
274 struct jmploc *exception_handler;
276 volatile int suppress_int; /* counter */
277 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
278 /* last pending signal */
279 volatile /*sig_atomic_t*/ smallint pending_sig;
280 smallint exception_type; /* kind of exception (0..5) */
281 /* exceptions */
282 #define EXINT 0 /* SIGINT received */
283 #define EXERROR 1 /* a generic error */
284 #define EXSHELLPROC 2 /* execute a shell procedure */
285 #define EXEXEC 3 /* command execution failed */
286 #define EXEXIT 4 /* exit the shell */
287 #define EXSIG 5 /* trapped signal in wait(1) */
289 smallint isloginsh;
290 char nullstr[1]; /* zero length string */
292 char optlist[NOPTS];
293 #define eflag optlist[0]
294 #define fflag optlist[1]
295 #define Iflag optlist[2]
296 #define iflag optlist[3]
297 #define mflag optlist[4]
298 #define nflag optlist[5]
299 #define sflag optlist[6]
300 #define xflag optlist[7]
301 #define vflag optlist[8]
302 #define Cflag optlist[9]
303 #define aflag optlist[10]
304 #define bflag optlist[11]
305 #define uflag optlist[12]
306 #define viflag optlist[13]
307 #if ENABLE_ASH_BASH_COMPAT
308 # define pipefail optlist[14]
309 #else
310 # define pipefail 0
311 #endif
312 #if DEBUG
313 # define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
314 # define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
315 #endif
317 /* trap handler commands */
319 * Sigmode records the current value of the signal handlers for the various
320 * modes. A value of zero means that the current handler is not known.
321 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
323 char sigmode[NSIG - 1];
324 #define S_DFL 1 /* default signal handling (SIG_DFL) */
325 #define S_CATCH 2 /* signal is caught */
326 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
327 #define S_HARD_IGN 4 /* signal is ignored permenantly */
329 /* indicates specified signal received */
330 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
331 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
332 char *trap[NSIG];
333 char **trap_ptr; /* used only by "trap hack" */
335 /* Rarely referenced stuff */
336 #if ENABLE_ASH_RANDOM_SUPPORT
337 random_t random_gen;
338 #endif
339 pid_t backgndpid; /* pid of last background process */
340 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
342 extern struct globals_misc *const ash_ptr_to_globals_misc;
343 #define G_misc (*ash_ptr_to_globals_misc)
344 #define rootpid (G_misc.rootpid )
345 #define shlvl (G_misc.shlvl )
346 #define minusc (G_misc.minusc )
347 #define curdir (G_misc.curdir )
348 #define physdir (G_misc.physdir )
349 #define arg0 (G_misc.arg0 )
350 #define exception_handler (G_misc.exception_handler)
351 #define exception_type (G_misc.exception_type )
352 #define suppress_int (G_misc.suppress_int )
353 #define pending_int (G_misc.pending_int )
354 #define pending_sig (G_misc.pending_sig )
355 #define isloginsh (G_misc.isloginsh )
356 #define nullstr (G_misc.nullstr )
357 #define optlist (G_misc.optlist )
358 #define sigmode (G_misc.sigmode )
359 #define gotsig (G_misc.gotsig )
360 #define may_have_traps (G_misc.may_have_traps )
361 #define trap (G_misc.trap )
362 #define trap_ptr (G_misc.trap_ptr )
363 #define random_gen (G_misc.random_gen )
364 #define backgndpid (G_misc.backgndpid )
365 #define job_warning (G_misc.job_warning)
366 #define INIT_G_misc() do { \
367 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
368 barrier(); \
369 curdir = nullstr; \
370 physdir = nullstr; \
371 trap_ptr = trap; \
372 } while (0)
375 /* ============ DEBUG */
376 #if DEBUG
377 static void trace_printf(const char *fmt, ...);
378 static void trace_vprintf(const char *fmt, va_list va);
379 # define TRACE(param) trace_printf param
380 # define TRACEV(param) trace_vprintf param
381 # define close(fd) do { \
382 int dfd = (fd); \
383 if (close(dfd) < 0) \
384 bb_error_msg("bug on %d: closing %d(0x%x)", \
385 __LINE__, dfd, dfd); \
386 } while (0)
387 #else
388 # define TRACE(param)
389 # define TRACEV(param)
390 #endif
393 /* ============ Utility functions */
394 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
396 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
397 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
399 static int isdigit_str9(const char *str)
401 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
402 while (--maxlen && isdigit(*str))
403 str++;
404 return (*str == '\0');
407 static const char *var_end(const char *var)
409 while (*var)
410 if (*var++ == '=')
411 break;
412 return var;
416 /* ============ Interrupts / exceptions */
418 static void exitshell(void) NORETURN;
421 * These macros allow the user to suspend the handling of interrupt signals
422 * over a period of time. This is similar to SIGHOLD or to sigblock, but
423 * much more efficient and portable. (But hacking the kernel is so much
424 * more fun than worrying about efficiency and portability. :-))
426 #define INT_OFF do { \
427 suppress_int++; \
428 xbarrier(); \
429 } while (0)
432 * Called to raise an exception. Since C doesn't include exceptions, we
433 * just do a longjmp to the exception handler. The type of exception is
434 * stored in the global variable "exception_type".
436 static void raise_exception(int) NORETURN;
437 static void
438 raise_exception(int e)
440 #if DEBUG
441 if (exception_handler == NULL)
442 abort();
443 #endif
444 INT_OFF;
445 exception_type = e;
446 longjmp(exception_handler->loc, 1);
448 #if DEBUG
449 #define raise_exception(e) do { \
450 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
451 raise_exception(e); \
452 } while (0)
453 #endif
456 * Called from trap.c when a SIGINT is received. (If the user specifies
457 * that SIGINT is to be trapped or ignored using the trap builtin, then
458 * this routine is not called.) Suppressint is nonzero when interrupts
459 * are held using the INT_OFF macro. (The test for iflag is just
460 * defensive programming.)
462 static void raise_interrupt(void) NORETURN;
463 static void
464 raise_interrupt(void)
466 int ex_type;
468 pending_int = 0;
469 /* Signal is not automatically unmasked after it is raised,
470 * do it ourself - unmask all signals */
471 sigprocmask_allsigs(SIG_UNBLOCK);
472 /* pending_sig = 0; - now done in signal_handler() */
474 ex_type = EXSIG;
475 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
476 if (!(rootshell && iflag)) {
477 /* Kill ourself with SIGINT */
478 signal(SIGINT, SIG_DFL);
479 raise(SIGINT);
481 ex_type = EXINT;
483 raise_exception(ex_type);
484 /* NOTREACHED */
486 #if DEBUG
487 #define raise_interrupt() do { \
488 TRACE(("raising interrupt on line %d\n", __LINE__)); \
489 raise_interrupt(); \
490 } while (0)
491 #endif
493 static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
494 int_on(void)
496 xbarrier();
497 if (--suppress_int == 0 && pending_int) {
498 raise_interrupt();
501 #define INT_ON int_on()
502 static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
503 force_int_on(void)
505 xbarrier();
506 suppress_int = 0;
507 if (pending_int)
508 raise_interrupt();
510 #define FORCE_INT_ON force_int_on()
512 #define SAVE_INT(v) ((v) = suppress_int)
514 #define RESTORE_INT(v) do { \
515 xbarrier(); \
516 suppress_int = (v); \
517 if (suppress_int == 0 && pending_int) \
518 raise_interrupt(); \
519 } while (0)
522 /* ============ Stdout/stderr output */
524 static void
525 outstr(const char *p, FILE *file)
527 INT_OFF;
528 fputs(p, file);
529 INT_ON;
532 static void
533 flush_stdout_stderr(void)
535 INT_OFF;
536 fflush_all();
537 INT_ON;
540 static void
541 outcslow(int c, FILE *dest)
543 INT_OFF;
544 putc(c, 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 CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
602 /* CTLBACKQ | CTLQUOTE == '\205' */
603 #define CTLARI ((unsigned char)'\206') /* arithmetic expression */
604 #define CTLENDARI ((unsigned char)'\207')
605 #define CTLQUOTEMARK ((unsigned char)'\210')
606 #define CTL_LAST CTLQUOTEMARK
608 /* variable substitution byte (follows CTLVAR) */
609 #define VSTYPE 0x0f /* type of variable substitution */
610 #define VSNUL 0x10 /* colon--treat the empty string as unset */
611 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
613 /* values of VSTYPE field */
614 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
615 #define VSMINUS 0x2 /* ${var-text} */
616 #define VSPLUS 0x3 /* ${var+text} */
617 #define VSQUESTION 0x4 /* ${var?message} */
618 #define VSASSIGN 0x5 /* ${var=text} */
619 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
620 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
621 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
622 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
623 #define VSLENGTH 0xa /* ${#var} */
624 #if ENABLE_ASH_BASH_COMPAT
625 #define VSSUBSTR 0xc /* ${var:position:length} */
626 #define VSREPLACE 0xd /* ${var/pattern/replacement} */
627 #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
628 #endif
630 static const char dolatstr[] ALIGN1 = {
631 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
634 #define NCMD 0
635 #define NPIPE 1
636 #define NREDIR 2
637 #define NBACKGND 3
638 #define NSUBSHELL 4
639 #define NAND 5
640 #define NOR 6
641 #define NSEMI 7
642 #define NIF 8
643 #define NWHILE 9
644 #define NUNTIL 10
645 #define NFOR 11
646 #define NCASE 12
647 #define NCLIST 13
648 #define NDEFUN 14
649 #define NARG 15
650 #define NTO 16
651 #if ENABLE_ASH_BASH_COMPAT
652 #define NTO2 17
653 #endif
654 #define NCLOBBER 18
655 #define NFROM 19
656 #define NFROMTO 20
657 #define NAPPEND 21
658 #define NTOFD 22
659 #define NFROMFD 23
660 #define NHERE 24
661 #define NXHERE 25
662 #define NNOT 26
663 #define N_NUMBER 27
665 union node;
667 struct ncmd {
668 smallint type; /* Nxxxx */
669 union node *assign;
670 union node *args;
671 union node *redirect;
674 struct npipe {
675 smallint type;
676 smallint pipe_backgnd;
677 struct nodelist *cmdlist;
680 struct nredir {
681 smallint type;
682 union node *n;
683 union node *redirect;
686 struct nbinary {
687 smallint type;
688 union node *ch1;
689 union node *ch2;
692 struct nif {
693 smallint type;
694 union node *test;
695 union node *ifpart;
696 union node *elsepart;
699 struct nfor {
700 smallint type;
701 union node *args;
702 union node *body;
703 char *var;
706 struct ncase {
707 smallint type;
708 union node *expr;
709 union node *cases;
712 struct nclist {
713 smallint type;
714 union node *next;
715 union node *pattern;
716 union node *body;
719 struct narg {
720 smallint type;
721 union node *next;
722 char *text;
723 struct nodelist *backquote;
726 /* nfile and ndup layout must match!
727 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
728 * that it is actually NTO2 (>&file), and change its type.
730 struct nfile {
731 smallint type;
732 union node *next;
733 int fd;
734 int _unused_dupfd;
735 union node *fname;
736 char *expfname;
739 struct ndup {
740 smallint type;
741 union node *next;
742 int fd;
743 int dupfd;
744 union node *vname;
745 char *_unused_expfname;
748 struct nhere {
749 smallint type;
750 union node *next;
751 int fd;
752 union node *doc;
755 struct nnot {
756 smallint type;
757 union node *com;
760 union node {
761 smallint type;
762 struct ncmd ncmd;
763 struct npipe npipe;
764 struct nredir nredir;
765 struct nbinary nbinary;
766 struct nif nif;
767 struct nfor nfor;
768 struct ncase ncase;
769 struct nclist nclist;
770 struct narg narg;
771 struct nfile nfile;
772 struct ndup ndup;
773 struct nhere nhere;
774 struct nnot nnot;
778 * NODE_EOF is returned by parsecmd when it encounters an end of file.
779 * It must be distinct from NULL.
781 #define NODE_EOF ((union node *) -1L)
783 struct nodelist {
784 struct nodelist *next;
785 union node *n;
788 struct funcnode {
789 int count;
790 union node n;
794 * Free a parse tree.
796 static void
797 freefunc(struct funcnode *f)
799 if (f && --f->count < 0)
800 free(f);
804 /* ============ Debugging output */
806 #if DEBUG
808 static FILE *tracefile;
810 static void
811 trace_printf(const char *fmt, ...)
813 va_list va;
815 if (debug != 1)
816 return;
817 if (DEBUG_TIME)
818 fprintf(tracefile, "%u ", (int) time(NULL));
819 if (DEBUG_PID)
820 fprintf(tracefile, "[%u] ", (int) getpid());
821 if (DEBUG_SIG)
822 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
823 va_start(va, fmt);
824 vfprintf(tracefile, fmt, va);
825 va_end(va);
828 static void
829 trace_vprintf(const char *fmt, va_list va)
831 if (debug != 1)
832 return;
833 if (DEBUG_TIME)
834 fprintf(tracefile, "%u ", (int) time(NULL));
835 if (DEBUG_PID)
836 fprintf(tracefile, "[%u] ", (int) getpid());
837 if (DEBUG_SIG)
838 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
839 vfprintf(tracefile, fmt, va);
842 static void
843 trace_puts(const char *s)
845 if (debug != 1)
846 return;
847 fputs(s, tracefile);
850 static void
851 trace_puts_quoted(char *s)
853 char *p;
854 char c;
856 if (debug != 1)
857 return;
858 putc('"', tracefile);
859 for (p = s; *p; p++) {
860 switch ((unsigned char)*p) {
861 case '\n': c = 'n'; goto backslash;
862 case '\t': c = 't'; goto backslash;
863 case '\r': c = 'r'; goto backslash;
864 case '\"': c = '\"'; goto backslash;
865 case '\\': c = '\\'; goto backslash;
866 case CTLESC: c = 'e'; goto backslash;
867 case CTLVAR: c = 'v'; goto backslash;
868 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
869 case CTLBACKQ: c = 'q'; goto backslash;
870 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
871 backslash:
872 putc('\\', tracefile);
873 putc(c, tracefile);
874 break;
875 default:
876 if (*p >= ' ' && *p <= '~')
877 putc(*p, tracefile);
878 else {
879 putc('\\', tracefile);
880 putc((*p >> 6) & 03, tracefile);
881 putc((*p >> 3) & 07, tracefile);
882 putc(*p & 07, tracefile);
884 break;
887 putc('"', tracefile);
890 static void
891 trace_puts_args(char **ap)
893 if (debug != 1)
894 return;
895 if (!*ap)
896 return;
897 while (1) {
898 trace_puts_quoted(*ap);
899 if (!*++ap) {
900 putc('\n', tracefile);
901 break;
903 putc(' ', tracefile);
907 static void
908 opentrace(void)
910 char s[100];
911 #ifdef O_APPEND
912 int flags;
913 #endif
915 if (debug != 1) {
916 if (tracefile)
917 fflush(tracefile);
918 /* leave open because libedit might be using it */
919 return;
921 strcpy(s, "./trace");
922 if (tracefile) {
923 if (!freopen(s, "a", tracefile)) {
924 fprintf(stderr, "Can't re-open %s\n", s);
925 debug = 0;
926 return;
928 } else {
929 tracefile = fopen(s, "a");
930 if (tracefile == NULL) {
931 fprintf(stderr, "Can't open %s\n", s);
932 debug = 0;
933 return;
936 #ifdef O_APPEND
937 flags = fcntl(fileno(tracefile), F_GETFL);
938 if (flags >= 0)
939 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
940 #endif
941 setlinebuf(tracefile);
942 fputs("\nTracing started.\n", tracefile);
945 static void
946 indent(int amount, char *pfx, FILE *fp)
948 int i;
950 for (i = 0; i < amount; i++) {
951 if (pfx && i == amount - 1)
952 fputs(pfx, fp);
953 putc('\t', fp);
957 /* little circular references here... */
958 static void shtree(union node *n, int ind, char *pfx, FILE *fp);
960 static void
961 sharg(union node *arg, FILE *fp)
963 char *p;
964 struct nodelist *bqlist;
965 unsigned char subtype;
967 if (arg->type != NARG) {
968 out1fmt("<node type %d>\n", arg->type);
969 abort();
971 bqlist = arg->narg.backquote;
972 for (p = arg->narg.text; *p; p++) {
973 switch ((unsigned char)*p) {
974 case CTLESC:
975 p++;
976 putc(*p, fp);
977 break;
978 case CTLVAR:
979 putc('$', fp);
980 putc('{', fp);
981 subtype = *++p;
982 if (subtype == VSLENGTH)
983 putc('#', fp);
985 while (*p != '=') {
986 putc(*p, fp);
987 p++;
990 if (subtype & VSNUL)
991 putc(':', fp);
993 switch (subtype & VSTYPE) {
994 case VSNORMAL:
995 putc('}', fp);
996 break;
997 case VSMINUS:
998 putc('-', fp);
999 break;
1000 case VSPLUS:
1001 putc('+', fp);
1002 break;
1003 case VSQUESTION:
1004 putc('?', fp);
1005 break;
1006 case VSASSIGN:
1007 putc('=', fp);
1008 break;
1009 case VSTRIMLEFT:
1010 putc('#', fp);
1011 break;
1012 case VSTRIMLEFTMAX:
1013 putc('#', fp);
1014 putc('#', fp);
1015 break;
1016 case VSTRIMRIGHT:
1017 putc('%', fp);
1018 break;
1019 case VSTRIMRIGHTMAX:
1020 putc('%', fp);
1021 putc('%', fp);
1022 break;
1023 case VSLENGTH:
1024 break;
1025 default:
1026 out1fmt("<subtype %d>", subtype);
1028 break;
1029 case CTLENDVAR:
1030 putc('}', fp);
1031 break;
1032 case CTLBACKQ:
1033 case CTLBACKQ|CTLQUOTE:
1034 putc('$', fp);
1035 putc('(', fp);
1036 shtree(bqlist->n, -1, NULL, fp);
1037 putc(')', fp);
1038 break;
1039 default:
1040 putc(*p, fp);
1041 break;
1046 static void
1047 shcmd(union node *cmd, FILE *fp)
1049 union node *np;
1050 int first;
1051 const char *s;
1052 int dftfd;
1054 first = 1;
1055 for (np = cmd->ncmd.args; np; np = np->narg.next) {
1056 if (!first)
1057 putc(' ', fp);
1058 sharg(np, fp);
1059 first = 0;
1061 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
1062 if (!first)
1063 putc(' ', fp);
1064 dftfd = 0;
1065 switch (np->nfile.type) {
1066 case NTO: s = ">>"+1; dftfd = 1; break;
1067 case NCLOBBER: s = ">|"; dftfd = 1; break;
1068 case NAPPEND: s = ">>"; dftfd = 1; break;
1069 #if ENABLE_ASH_BASH_COMPAT
1070 case NTO2:
1071 #endif
1072 case NTOFD: s = ">&"; dftfd = 1; break;
1073 case NFROM: s = "<"; break;
1074 case NFROMFD: s = "<&"; break;
1075 case NFROMTO: s = "<>"; break;
1076 default: s = "*error*"; break;
1078 if (np->nfile.fd != dftfd)
1079 fprintf(fp, "%d", np->nfile.fd);
1080 fputs(s, fp);
1081 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1082 fprintf(fp, "%d", np->ndup.dupfd);
1083 } else {
1084 sharg(np->nfile.fname, fp);
1086 first = 0;
1090 static void
1091 shtree(union node *n, int ind, char *pfx, FILE *fp)
1093 struct nodelist *lp;
1094 const char *s;
1096 if (n == NULL)
1097 return;
1099 indent(ind, pfx, fp);
1101 if (n == NODE_EOF) {
1102 fputs("<EOF>", fp);
1103 return;
1106 switch (n->type) {
1107 case NSEMI:
1108 s = "; ";
1109 goto binop;
1110 case NAND:
1111 s = " && ";
1112 goto binop;
1113 case NOR:
1114 s = " || ";
1115 binop:
1116 shtree(n->nbinary.ch1, ind, NULL, fp);
1117 /* if (ind < 0) */
1118 fputs(s, fp);
1119 shtree(n->nbinary.ch2, ind, NULL, fp);
1120 break;
1121 case NCMD:
1122 shcmd(n, fp);
1123 if (ind >= 0)
1124 putc('\n', fp);
1125 break;
1126 case NPIPE:
1127 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
1128 shtree(lp->n, 0, NULL, fp);
1129 if (lp->next)
1130 fputs(" | ", fp);
1132 if (n->npipe.pipe_backgnd)
1133 fputs(" &", fp);
1134 if (ind >= 0)
1135 putc('\n', fp);
1136 break;
1137 default:
1138 fprintf(fp, "<node type %d>", n->type);
1139 if (ind >= 0)
1140 putc('\n', fp);
1141 break;
1145 static void
1146 showtree(union node *n)
1148 trace_puts("showtree called\n");
1149 shtree(n, 1, NULL, stderr);
1152 #endif /* DEBUG */
1155 /* ============ Parser data */
1158 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1160 struct strlist {
1161 struct strlist *next;
1162 char *text;
1165 struct alias;
1167 struct strpush {
1168 struct strpush *prev; /* preceding string on stack */
1169 char *prev_string;
1170 int prev_left_in_line;
1171 #if ENABLE_ASH_ALIAS
1172 struct alias *ap; /* if push was associated with an alias */
1173 #endif
1174 char *string; /* remember the string since it may change */
1177 struct parsefile {
1178 struct parsefile *prev; /* preceding file on stack */
1179 int linno; /* current line */
1180 int pf_fd; /* file descriptor (or -1 if string) */
1181 int left_in_line; /* number of chars left in this line */
1182 int left_in_buffer; /* number of chars left in this buffer past the line */
1183 char *next_to_pgetc; /* next char in buffer */
1184 char *buf; /* input buffer */
1185 struct strpush *strpush; /* for pushing strings at this level */
1186 struct strpush basestrpush; /* so pushing one is fast */
1189 static struct parsefile basepf; /* top level input file */
1190 static struct parsefile *g_parsefile = &basepf; /* current input file */
1191 static int startlinno; /* line # where last token started */
1192 static char *commandname; /* currently executing command */
1193 static struct strlist *cmdenviron; /* environment for builtin command */
1194 static uint8_t exitstatus; /* exit status of last command */
1197 /* ============ Message printing */
1199 static void
1200 ash_vmsg(const char *msg, va_list ap)
1202 fprintf(stderr, "%s: ", arg0);
1203 if (commandname) {
1204 if (strcmp(arg0, commandname))
1205 fprintf(stderr, "%s: ", commandname);
1206 if (!iflag || g_parsefile->pf_fd > 0)
1207 fprintf(stderr, "line %d: ", startlinno);
1209 vfprintf(stderr, msg, ap);
1210 outcslow('\n', stderr);
1214 * Exverror is called to raise the error exception. If the second argument
1215 * is not NULL then error prints an error message using printf style
1216 * formatting. It then raises the error exception.
1218 static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1219 static void
1220 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1222 #if DEBUG
1223 if (msg) {
1224 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1225 TRACEV((msg, ap));
1226 TRACE(("\") pid=%d\n", getpid()));
1227 } else
1228 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1229 if (msg)
1230 #endif
1231 ash_vmsg(msg, ap);
1233 flush_stdout_stderr();
1234 raise_exception(cond);
1235 /* NOTREACHED */
1238 static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1239 static void
1240 ash_msg_and_raise_error(const char *msg, ...)
1242 va_list ap;
1244 va_start(ap, msg);
1245 ash_vmsg_and_raise(EXERROR, msg, ap);
1246 /* NOTREACHED */
1247 va_end(ap);
1250 static void raise_error_syntax(const char *) NORETURN;
1251 static void
1252 raise_error_syntax(const char *msg)
1254 ash_msg_and_raise_error("syntax error: %s", msg);
1255 /* NOTREACHED */
1258 static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1259 static void
1260 ash_msg_and_raise(int cond, const char *msg, ...)
1262 va_list ap;
1264 va_start(ap, msg);
1265 ash_vmsg_and_raise(cond, msg, ap);
1266 /* NOTREACHED */
1267 va_end(ap);
1271 * error/warning routines for external builtins
1273 static void
1274 ash_msg(const char *fmt, ...)
1276 va_list ap;
1278 va_start(ap, fmt);
1279 ash_vmsg(fmt, ap);
1280 va_end(ap);
1284 * Return a string describing an error. The returned string may be a
1285 * pointer to a static buffer that will be overwritten on the next call.
1286 * Action describes the operation that got the error.
1288 static const char *
1289 errmsg(int e, const char *em)
1291 if (e == ENOENT || e == ENOTDIR) {
1292 return em;
1294 return strerror(e);
1298 /* ============ Memory allocation */
1300 #if 0
1301 /* I consider these wrappers nearly useless:
1302 * ok, they return you to nearest exception handler, but
1303 * how much memory do you leak in the process, making
1304 * memory starvation worse?
1306 static void *
1307 ckrealloc(void * p, size_t nbytes)
1309 p = realloc(p, nbytes);
1310 if (!p)
1311 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1312 return p;
1315 static void *
1316 ckmalloc(size_t nbytes)
1318 return ckrealloc(NULL, nbytes);
1321 static void *
1322 ckzalloc(size_t nbytes)
1324 return memset(ckmalloc(nbytes), 0, nbytes);
1327 static char *
1328 ckstrdup(const char *s)
1330 char *p = strdup(s);
1331 if (!p)
1332 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1333 return p;
1335 #else
1336 /* Using bbox equivalents. They exit if out of memory */
1337 # define ckrealloc xrealloc
1338 # define ckmalloc xmalloc
1339 # define ckzalloc xzalloc
1340 # define ckstrdup xstrdup
1341 #endif
1344 * It appears that grabstackstr() will barf with such alignments
1345 * because stalloc() will return a string allocated in a new stackblock.
1347 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1348 enum {
1349 /* Most machines require the value returned from malloc to be aligned
1350 * in some way. The following macro will get this right
1351 * on many machines. */
1352 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1353 /* Minimum size of a block */
1354 MINSIZE = SHELL_ALIGN(504),
1357 struct stack_block {
1358 struct stack_block *prev;
1359 char space[MINSIZE];
1362 struct stackmark {
1363 struct stack_block *stackp;
1364 char *stacknxt;
1365 size_t stacknleft;
1366 struct stackmark *marknext;
1370 struct globals_memstack {
1371 struct stack_block *g_stackp; // = &stackbase;
1372 struct stackmark *markp;
1373 char *g_stacknxt; // = stackbase.space;
1374 char *sstrend; // = stackbase.space + MINSIZE;
1375 size_t g_stacknleft; // = MINSIZE;
1376 int herefd; // = -1;
1377 struct stack_block stackbase;
1379 extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1380 #define G_memstack (*ash_ptr_to_globals_memstack)
1381 #define g_stackp (G_memstack.g_stackp )
1382 #define markp (G_memstack.markp )
1383 #define g_stacknxt (G_memstack.g_stacknxt )
1384 #define sstrend (G_memstack.sstrend )
1385 #define g_stacknleft (G_memstack.g_stacknleft)
1386 #define herefd (G_memstack.herefd )
1387 #define stackbase (G_memstack.stackbase )
1388 #define INIT_G_memstack() do { \
1389 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1390 barrier(); \
1391 g_stackp = &stackbase; \
1392 g_stacknxt = stackbase.space; \
1393 g_stacknleft = MINSIZE; \
1394 sstrend = stackbase.space + MINSIZE; \
1395 herefd = -1; \
1396 } while (0)
1399 #define stackblock() ((void *)g_stacknxt)
1400 #define stackblocksize() g_stacknleft
1403 * Parse trees for commands are allocated in lifo order, so we use a stack
1404 * to make this more efficient, and also to avoid all sorts of exception
1405 * handling code to handle interrupts in the middle of a parse.
1407 * The size 504 was chosen because the Ultrix malloc handles that size
1408 * well.
1410 static void *
1411 stalloc(size_t nbytes)
1413 char *p;
1414 size_t aligned;
1416 aligned = SHELL_ALIGN(nbytes);
1417 if (aligned > g_stacknleft) {
1418 size_t len;
1419 size_t blocksize;
1420 struct stack_block *sp;
1422 blocksize = aligned;
1423 if (blocksize < MINSIZE)
1424 blocksize = MINSIZE;
1425 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1426 if (len < blocksize)
1427 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1428 INT_OFF;
1429 sp = ckmalloc(len);
1430 sp->prev = g_stackp;
1431 g_stacknxt = sp->space;
1432 g_stacknleft = blocksize;
1433 sstrend = g_stacknxt + blocksize;
1434 g_stackp = sp;
1435 INT_ON;
1437 p = g_stacknxt;
1438 g_stacknxt += aligned;
1439 g_stacknleft -= aligned;
1440 return p;
1443 static void *
1444 stzalloc(size_t nbytes)
1446 return memset(stalloc(nbytes), 0, nbytes);
1449 static void
1450 stunalloc(void *p)
1452 #if DEBUG
1453 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1454 write(STDERR_FILENO, "stunalloc\n", 10);
1455 abort();
1457 #endif
1458 g_stacknleft += g_stacknxt - (char *)p;
1459 g_stacknxt = p;
1463 * Like strdup but works with the ash stack.
1465 static char *
1466 ststrdup(const char *p)
1468 size_t len = strlen(p) + 1;
1469 return memcpy(stalloc(len), p, len);
1472 static void
1473 setstackmark(struct stackmark *mark)
1475 mark->stackp = g_stackp;
1476 mark->stacknxt = g_stacknxt;
1477 mark->stacknleft = g_stacknleft;
1478 mark->marknext = markp;
1479 markp = mark;
1482 static void
1483 popstackmark(struct stackmark *mark)
1485 struct stack_block *sp;
1487 if (!mark->stackp)
1488 return;
1490 INT_OFF;
1491 markp = mark->marknext;
1492 while (g_stackp != mark->stackp) {
1493 sp = g_stackp;
1494 g_stackp = sp->prev;
1495 free(sp);
1497 g_stacknxt = mark->stacknxt;
1498 g_stacknleft = mark->stacknleft;
1499 sstrend = mark->stacknxt + mark->stacknleft;
1500 INT_ON;
1504 * When the parser reads in a string, it wants to stick the string on the
1505 * stack and only adjust the stack pointer when it knows how big the
1506 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1507 * of space on top of the stack and stackblocklen returns the length of
1508 * this block. Growstackblock will grow this space by at least one byte,
1509 * possibly moving it (like realloc). Grabstackblock actually allocates the
1510 * part of the block that has been used.
1512 static void
1513 growstackblock(void)
1515 size_t newlen;
1517 newlen = g_stacknleft * 2;
1518 if (newlen < g_stacknleft)
1519 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1520 if (newlen < 128)
1521 newlen += 128;
1523 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1524 struct stack_block *oldstackp;
1525 struct stackmark *xmark;
1526 struct stack_block *sp;
1527 struct stack_block *prevstackp;
1528 size_t grosslen;
1530 INT_OFF;
1531 oldstackp = g_stackp;
1532 sp = g_stackp;
1533 prevstackp = sp->prev;
1534 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1535 sp = ckrealloc(sp, grosslen);
1536 sp->prev = prevstackp;
1537 g_stackp = sp;
1538 g_stacknxt = sp->space;
1539 g_stacknleft = newlen;
1540 sstrend = sp->space + newlen;
1543 * Stack marks pointing to the start of the old block
1544 * must be relocated to point to the new block
1546 xmark = markp;
1547 while (xmark != NULL && xmark->stackp == oldstackp) {
1548 xmark->stackp = g_stackp;
1549 xmark->stacknxt = g_stacknxt;
1550 xmark->stacknleft = g_stacknleft;
1551 xmark = xmark->marknext;
1553 INT_ON;
1554 } else {
1555 char *oldspace = g_stacknxt;
1556 size_t oldlen = g_stacknleft;
1557 char *p = stalloc(newlen);
1559 /* free the space we just allocated */
1560 g_stacknxt = memcpy(p, oldspace, oldlen);
1561 g_stacknleft += newlen;
1565 static void
1566 grabstackblock(size_t len)
1568 len = SHELL_ALIGN(len);
1569 g_stacknxt += len;
1570 g_stacknleft -= len;
1574 * The following routines are somewhat easier to use than the above.
1575 * The user declares a variable of type STACKSTR, which may be declared
1576 * to be a register. The macro STARTSTACKSTR initializes things. Then
1577 * the user uses the macro STPUTC to add characters to the string. In
1578 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1579 * grown as necessary. When the user is done, she can just leave the
1580 * string there and refer to it using stackblock(). Or she can allocate
1581 * the space for it using grabstackstr(). If it is necessary to allow
1582 * someone else to use the stack temporarily and then continue to grow
1583 * the string, the user should use grabstack to allocate the space, and
1584 * then call ungrabstr(p) to return to the previous mode of operation.
1586 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1587 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1588 * is space for at least one character.
1590 static void *
1591 growstackstr(void)
1593 size_t len = stackblocksize();
1594 if (herefd >= 0 && len >= 1024) {
1595 full_write(herefd, stackblock(), len);
1596 return stackblock();
1598 growstackblock();
1599 return (char *)stackblock() + len;
1603 * Called from CHECKSTRSPACE.
1605 static char *
1606 makestrspace(size_t newlen, char *p)
1608 size_t len = p - g_stacknxt;
1609 size_t size = stackblocksize();
1611 for (;;) {
1612 size_t nleft;
1614 size = stackblocksize();
1615 nleft = size - len;
1616 if (nleft >= newlen)
1617 break;
1618 growstackblock();
1620 return (char *)stackblock() + len;
1623 static char *
1624 stack_nputstr(const char *s, size_t n, char *p)
1626 p = makestrspace(n, p);
1627 p = (char *)memcpy(p, s, n) + n;
1628 return p;
1631 static char *
1632 stack_putstr(const char *s, char *p)
1634 return stack_nputstr(s, strlen(s), p);
1637 static char *
1638 _STPUTC(int c, char *p)
1640 if (p == sstrend)
1641 p = growstackstr();
1642 *p++ = c;
1643 return p;
1646 #define STARTSTACKSTR(p) ((p) = stackblock())
1647 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1648 #define CHECKSTRSPACE(n, p) do { \
1649 char *q = (p); \
1650 size_t l = (n); \
1651 size_t m = sstrend - q; \
1652 if (l > m) \
1653 (p) = makestrspace(l, q); \
1654 } while (0)
1655 #define USTPUTC(c, p) (*(p)++ = (c))
1656 #define STACKSTRNUL(p) do { \
1657 if ((p) == sstrend) \
1658 (p) = growstackstr(); \
1659 *(p) = '\0'; \
1660 } while (0)
1661 #define STUNPUTC(p) (--(p))
1662 #define STTOPC(p) ((p)[-1])
1663 #define STADJUST(amount, p) ((p) += (amount))
1665 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1666 #define ungrabstackstr(s, p) stunalloc(s)
1667 #define stackstrend() ((void *)sstrend)
1670 /* ============ String helpers */
1673 * prefix -- see if pfx is a prefix of string.
1675 static char *
1676 prefix(const char *string, const char *pfx)
1678 while (*pfx) {
1679 if (*pfx++ != *string++)
1680 return NULL;
1682 return (char *) string;
1686 * Check for a valid number. This should be elsewhere.
1688 static int
1689 is_number(const char *p)
1691 do {
1692 if (!isdigit(*p))
1693 return 0;
1694 } while (*++p != '\0');
1695 return 1;
1699 * Convert a string of digits to an integer, printing an error message on
1700 * failure.
1702 static int
1703 number(const char *s)
1705 if (!is_number(s))
1706 ash_msg_and_raise_error(msg_illnum, s);
1707 return atoi(s);
1711 * Produce a possibly single quoted string suitable as input to the shell.
1712 * The return string is allocated on the stack.
1714 static char *
1715 single_quote(const char *s)
1717 char *p;
1719 STARTSTACKSTR(p);
1721 do {
1722 char *q;
1723 size_t len;
1725 len = strchrnul(s, '\'') - s;
1727 q = p = makestrspace(len + 3, p);
1729 *q++ = '\'';
1730 q = (char *)memcpy(q, s, len) + len;
1731 *q++ = '\'';
1732 s += len;
1734 STADJUST(q - p, p);
1736 if (*s != '\'')
1737 break;
1738 len = 0;
1739 do len++; while (*++s == '\'');
1741 q = p = makestrspace(len + 3, p);
1743 *q++ = '"';
1744 q = (char *)memcpy(q, s - len, len) + len;
1745 *q++ = '"';
1747 STADJUST(q - p, p);
1748 } while (*s);
1750 USTPUTC('\0', p);
1752 return stackblock();
1756 /* ============ nextopt */
1758 static char **argptr; /* argument list for builtin commands */
1759 static char *optionarg; /* set by nextopt (like getopt) */
1760 static char *optptr; /* used by nextopt */
1763 * XXX - should get rid of. Have all builtins use getopt(3).
1764 * The library getopt must have the BSD extension static variable
1765 * "optreset", otherwise it can't be used within the shell safely.
1767 * Standard option processing (a la getopt) for builtin routines.
1768 * The only argument that is passed to nextopt is the option string;
1769 * the other arguments are unnecessary. It returns the character,
1770 * or '\0' on end of input.
1772 static int
1773 nextopt(const char *optstring)
1775 char *p;
1776 const char *q;
1777 char c;
1779 p = optptr;
1780 if (p == NULL || *p == '\0') {
1781 /* We ate entire "-param", take next one */
1782 p = *argptr;
1783 if (p == NULL)
1784 return '\0';
1785 if (*p != '-')
1786 return '\0';
1787 if (*++p == '\0') /* just "-" ? */
1788 return '\0';
1789 argptr++;
1790 if (LONE_DASH(p)) /* "--" ? */
1791 return '\0';
1792 /* p => next "-param" */
1794 /* p => some option char in the middle of a "-param" */
1795 c = *p++;
1796 for (q = optstring; *q != c;) {
1797 if (*q == '\0')
1798 ash_msg_and_raise_error("illegal option -%c", c);
1799 if (*++q == ':')
1800 q++;
1802 if (*++q == ':') {
1803 if (*p == '\0') {
1804 p = *argptr++;
1805 if (p == NULL)
1806 ash_msg_and_raise_error("no arg for -%c option", c);
1808 optionarg = p;
1809 p = NULL;
1811 optptr = p;
1812 return c;
1816 /* ============ Shell variables */
1819 * The parsefile structure pointed to by the global variable parsefile
1820 * contains information about the current file being read.
1822 struct shparam {
1823 int nparam; /* # of positional parameters (without $0) */
1824 #if ENABLE_ASH_GETOPTS
1825 int optind; /* next parameter to be processed by getopts */
1826 int optoff; /* used by getopts */
1827 #endif
1828 unsigned char malloced; /* if parameter list dynamically allocated */
1829 char **p; /* parameter list */
1833 * Free the list of positional parameters.
1835 static void
1836 freeparam(volatile struct shparam *param)
1838 if (param->malloced) {
1839 char **ap, **ap1;
1840 ap = ap1 = param->p;
1841 while (*ap)
1842 free(*ap++);
1843 free(ap1);
1847 #if ENABLE_ASH_GETOPTS
1848 static void FAST_FUNC getoptsreset(const char *value);
1849 #endif
1851 struct var {
1852 struct var *next; /* next entry in hash list */
1853 int flags; /* flags are defined above */
1854 const char *var_text; /* name=value */
1855 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
1856 /* the variable gets set/unset */
1859 struct localvar {
1860 struct localvar *next; /* next local variable in list */
1861 struct var *vp; /* the variable that was made local */
1862 int flags; /* saved flags */
1863 const char *text; /* saved text */
1866 /* flags */
1867 #define VEXPORT 0x01 /* variable is exported */
1868 #define VREADONLY 0x02 /* variable cannot be modified */
1869 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1870 #define VTEXTFIXED 0x08 /* text is statically allocated */
1871 #define VSTACK 0x10 /* text is allocated on the stack */
1872 #define VUNSET 0x20 /* the variable is not set */
1873 #define VNOFUNC 0x40 /* don't call the callback function */
1874 #define VNOSET 0x80 /* do not set variable - just readonly test */
1875 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1876 #if ENABLE_ASH_RANDOM_SUPPORT
1877 # define VDYNAMIC 0x200 /* dynamic variable */
1878 #else
1879 # define VDYNAMIC 0
1880 #endif
1883 /* Need to be before varinit_data[] */
1884 #if ENABLE_LOCALE_SUPPORT
1885 static void FAST_FUNC
1886 change_lc_all(const char *value)
1888 if (value && *value != '\0')
1889 setlocale(LC_ALL, value);
1891 static void FAST_FUNC
1892 change_lc_ctype(const char *value)
1894 if (value && *value != '\0')
1895 setlocale(LC_CTYPE, value);
1897 #endif
1898 #if ENABLE_ASH_MAIL
1899 static void chkmail(void);
1900 static void changemail(const char *var_value) FAST_FUNC;
1901 #else
1902 # define chkmail() ((void)0)
1903 #endif
1904 static void changepath(const char *) FAST_FUNC;
1905 #if ENABLE_ASH_RANDOM_SUPPORT
1906 static void change_random(const char *) FAST_FUNC;
1907 #endif
1909 static const struct {
1910 int flags;
1911 const char *var_text;
1912 void (*var_func)(const char *) FAST_FUNC;
1913 } varinit_data[] = {
1915 * Note: VEXPORT would not work correctly here for NOFORK applets:
1916 * some environment strings may be constant.
1918 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1919 #if ENABLE_ASH_MAIL
1920 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1921 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
1922 #endif
1923 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1924 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1925 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1926 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1927 #if ENABLE_ASH_GETOPTS
1928 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
1929 #endif
1930 #if ENABLE_ASH_RANDOM_SUPPORT
1931 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
1932 #endif
1933 #if ENABLE_LOCALE_SUPPORT
1934 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1935 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
1936 #endif
1937 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1938 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
1939 #endif
1942 struct redirtab;
1944 struct globals_var {
1945 struct shparam shellparam; /* $@ current positional parameters */
1946 struct redirtab *redirlist;
1947 int g_nullredirs;
1948 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1949 struct var *vartab[VTABSIZE];
1950 struct var varinit[ARRAY_SIZE(varinit_data)];
1952 extern struct globals_var *const ash_ptr_to_globals_var;
1953 #define G_var (*ash_ptr_to_globals_var)
1954 #define shellparam (G_var.shellparam )
1955 //#define redirlist (G_var.redirlist )
1956 #define g_nullredirs (G_var.g_nullredirs )
1957 #define preverrout_fd (G_var.preverrout_fd)
1958 #define vartab (G_var.vartab )
1959 #define varinit (G_var.varinit )
1960 #define INIT_G_var() do { \
1961 unsigned i; \
1962 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1963 barrier(); \
1964 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1965 varinit[i].flags = varinit_data[i].flags; \
1966 varinit[i].var_text = varinit_data[i].var_text; \
1967 varinit[i].var_func = varinit_data[i].var_func; \
1969 } while (0)
1971 #define vifs varinit[0]
1972 #if ENABLE_ASH_MAIL
1973 # define vmail (&vifs)[1]
1974 # define vmpath (&vmail)[1]
1975 # define vpath (&vmpath)[1]
1976 #else
1977 # define vpath (&vifs)[1]
1978 #endif
1979 #define vps1 (&vpath)[1]
1980 #define vps2 (&vps1)[1]
1981 #define vps4 (&vps2)[1]
1982 #if ENABLE_ASH_GETOPTS
1983 # define voptind (&vps4)[1]
1984 # if ENABLE_ASH_RANDOM_SUPPORT
1985 # define vrandom (&voptind)[1]
1986 # endif
1987 #else
1988 # if ENABLE_ASH_RANDOM_SUPPORT
1989 # define vrandom (&vps4)[1]
1990 # endif
1991 #endif
1994 * The following macros access the values of the above variables.
1995 * They have to skip over the name. They return the null string
1996 * for unset variables.
1998 #define ifsval() (vifs.var_text + 4)
1999 #define ifsset() ((vifs.flags & VUNSET) == 0)
2000 #if ENABLE_ASH_MAIL
2001 # define mailval() (vmail.var_text + 5)
2002 # define mpathval() (vmpath.var_text + 9)
2003 # define mpathset() ((vmpath.flags & VUNSET) == 0)
2004 #endif
2005 #define pathval() (vpath.var_text + 5)
2006 #define ps1val() (vps1.var_text + 4)
2007 #define ps2val() (vps2.var_text + 4)
2008 #define ps4val() (vps4.var_text + 4)
2009 #if ENABLE_ASH_GETOPTS
2010 # define optindval() (voptind.var_text + 7)
2011 #endif
2013 #if ENABLE_ASH_GETOPTS
2014 static void FAST_FUNC
2015 getoptsreset(const char *value)
2017 shellparam.optind = number(value);
2018 shellparam.optoff = -1;
2020 #endif
2023 * Compares two strings up to the first = or '\0'. The first
2024 * string must be terminated by '='; the second may be terminated by
2025 * either '=' or '\0'.
2027 static int
2028 varcmp(const char *p, const char *q)
2030 int c, d;
2032 while ((c = *p) == (d = *q)) {
2033 if (!c || c == '=')
2034 goto out;
2035 p++;
2036 q++;
2038 if (c == '=')
2039 c = '\0';
2040 if (d == '=')
2041 d = '\0';
2042 out:
2043 return c - d;
2047 * Find the appropriate entry in the hash table from the name.
2049 static struct var **
2050 hashvar(const char *p)
2052 unsigned hashval;
2054 hashval = ((unsigned char) *p) << 4;
2055 while (*p && *p != '=')
2056 hashval += (unsigned char) *p++;
2057 return &vartab[hashval % VTABSIZE];
2060 static int
2061 vpcmp(const void *a, const void *b)
2063 return varcmp(*(const char **)a, *(const char **)b);
2067 * This routine initializes the builtin variables.
2069 static void
2070 initvar(void)
2072 struct var *vp;
2073 struct var *end;
2074 struct var **vpp;
2077 * PS1 depends on uid
2079 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2080 vps1.var_text = "PS1=\\w \\$ ";
2081 #else
2082 if (!geteuid())
2083 vps1.var_text = "PS1=# ";
2084 #endif
2085 vp = varinit;
2086 end = vp + ARRAY_SIZE(varinit);
2087 do {
2088 vpp = hashvar(vp->var_text);
2089 vp->next = *vpp;
2090 *vpp = vp;
2091 } while (++vp < end);
2094 static struct var **
2095 findvar(struct var **vpp, const char *name)
2097 for (; *vpp; vpp = &(*vpp)->next) {
2098 if (varcmp((*vpp)->var_text, name) == 0) {
2099 break;
2102 return vpp;
2106 * Find the value of a variable. Returns NULL if not set.
2108 static const char* FAST_FUNC
2109 lookupvar(const char *name)
2111 struct var *v;
2113 v = *findvar(hashvar(name), name);
2114 if (v) {
2115 #if ENABLE_ASH_RANDOM_SUPPORT
2117 * Dynamic variables are implemented roughly the same way they are
2118 * in bash. Namely, they're "special" so long as they aren't unset.
2119 * As soon as they're unset, they're no longer dynamic, and dynamic
2120 * lookup will no longer happen at that point. -- PFM.
2122 if (v->flags & VDYNAMIC)
2123 v->var_func(NULL);
2124 #endif
2125 if (!(v->flags & VUNSET))
2126 return var_end(v->var_text);
2128 return NULL;
2131 static void reinit_unicode_for_ash(void)
2133 /* Unicode support should be activated even if LANG is set
2134 * _during_ shell execution, not only if it was set when
2135 * shell was started. Therefore, re-check LANG every time:
2137 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2138 || ENABLE_UNICODE_USING_LOCALE
2140 const char *s = lookupvar("LC_ALL");
2141 if (!s) s = lookupvar("LC_CTYPE");
2142 if (!s) s = lookupvar("LANG");
2143 reinit_unicode(s);
2148 * Search the environment of a builtin command.
2150 static const char *
2151 bltinlookup(const char *name)
2153 struct strlist *sp;
2155 for (sp = cmdenviron; sp; sp = sp->next) {
2156 if (varcmp(sp->text, name) == 0)
2157 return var_end(sp->text);
2159 return lookupvar(name);
2163 * Same as setvar except that the variable and value are passed in
2164 * the first argument as name=value. Since the first argument will
2165 * be actually stored in the table, it should not be a string that
2166 * will go away.
2167 * Called with interrupts off.
2169 static void
2170 setvareq(char *s, int flags)
2172 struct var *vp, **vpp;
2174 vpp = hashvar(s);
2175 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2176 vp = *findvar(vpp, s);
2177 if (vp) {
2178 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2179 const char *n;
2181 if (flags & VNOSAVE)
2182 free(s);
2183 n = vp->var_text;
2184 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2187 if (flags & VNOSET)
2188 return;
2190 if (vp->var_func && !(flags & VNOFUNC))
2191 vp->var_func(var_end(s));
2193 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2194 free((char*)vp->var_text);
2196 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2197 } else {
2198 /* variable s is not found */
2199 if (flags & VNOSET)
2200 return;
2201 vp = ckzalloc(sizeof(*vp));
2202 vp->next = *vpp;
2203 /*vp->func = NULL; - ckzalloc did it */
2204 *vpp = vp;
2206 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2207 s = ckstrdup(s);
2208 vp->var_text = s;
2209 vp->flags = flags;
2213 * Set the value of a variable. The flags argument is ored with the
2214 * flags of the variable. If val is NULL, the variable is unset.
2216 static void
2217 setvar(const char *name, const char *val, int flags)
2219 const char *q;
2220 char *p;
2221 char *nameeq;
2222 size_t namelen;
2223 size_t vallen;
2225 q = endofname(name);
2226 p = strchrnul(q, '=');
2227 namelen = p - name;
2228 if (!namelen || p != q)
2229 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2230 vallen = 0;
2231 if (val == NULL) {
2232 flags |= VUNSET;
2233 } else {
2234 vallen = strlen(val);
2237 INT_OFF;
2238 nameeq = ckmalloc(namelen + vallen + 2);
2239 p = memcpy(nameeq, name, namelen) + namelen;
2240 if (val) {
2241 *p++ = '=';
2242 p = memcpy(p, val, vallen) + vallen;
2244 *p = '\0';
2245 setvareq(nameeq, flags | VNOSAVE);
2246 INT_ON;
2249 static void FAST_FUNC
2250 setvar2(const char *name, const char *val)
2252 setvar(name, val, 0);
2255 #if ENABLE_ASH_GETOPTS
2257 * Safe version of setvar, returns 1 on success 0 on failure.
2259 static int
2260 setvarsafe(const char *name, const char *val, int flags)
2262 int err;
2263 volatile int saveint;
2264 struct jmploc *volatile savehandler = exception_handler;
2265 struct jmploc jmploc;
2267 SAVE_INT(saveint);
2268 if (setjmp(jmploc.loc))
2269 err = 1;
2270 else {
2271 exception_handler = &jmploc;
2272 setvar(name, val, flags);
2273 err = 0;
2275 exception_handler = savehandler;
2276 RESTORE_INT(saveint);
2277 return err;
2279 #endif
2282 * Unset the specified variable.
2284 static int
2285 unsetvar(const char *s)
2287 struct var **vpp;
2288 struct var *vp;
2289 int retval;
2291 vpp = findvar(hashvar(s), s);
2292 vp = *vpp;
2293 retval = 2;
2294 if (vp) {
2295 int flags = vp->flags;
2297 retval = 1;
2298 if (flags & VREADONLY)
2299 goto out;
2300 #if ENABLE_ASH_RANDOM_SUPPORT
2301 vp->flags &= ~VDYNAMIC;
2302 #endif
2303 if (flags & VUNSET)
2304 goto ok;
2305 if ((flags & VSTRFIXED) == 0) {
2306 INT_OFF;
2307 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2308 free((char*)vp->var_text);
2309 *vpp = vp->next;
2310 free(vp);
2311 INT_ON;
2312 } else {
2313 setvar2(s, 0);
2314 vp->flags &= ~VEXPORT;
2317 retval = 0;
2319 out:
2320 return retval;
2324 * Process a linked list of variable assignments.
2326 static void
2327 listsetvar(struct strlist *list_set_var, int flags)
2329 struct strlist *lp = list_set_var;
2331 if (!lp)
2332 return;
2333 INT_OFF;
2334 do {
2335 setvareq(lp->text, flags);
2336 lp = lp->next;
2337 } while (lp);
2338 INT_ON;
2342 * Generate a list of variables satisfying the given conditions.
2344 static char **
2345 listvars(int on, int off, char ***end)
2347 struct var **vpp;
2348 struct var *vp;
2349 char **ep;
2350 int mask;
2352 STARTSTACKSTR(ep);
2353 vpp = vartab;
2354 mask = on | off;
2355 do {
2356 for (vp = *vpp; vp; vp = vp->next) {
2357 if ((vp->flags & mask) == on) {
2358 if (ep == stackstrend())
2359 ep = growstackstr();
2360 *ep++ = (char*)vp->var_text;
2363 } while (++vpp < vartab + VTABSIZE);
2364 if (ep == stackstrend())
2365 ep = growstackstr();
2366 if (end)
2367 *end = ep;
2368 *ep++ = NULL;
2369 return grabstackstr(ep);
2373 /* ============ Path search helper
2375 * The variable path (passed by reference) should be set to the start
2376 * of the path before the first call; path_advance will update
2377 * this value as it proceeds. Successive calls to path_advance will return
2378 * the possible path expansions in sequence. If an option (indicated by
2379 * a percent sign) appears in the path entry then the global variable
2380 * pathopt will be set to point to it; otherwise pathopt will be set to
2381 * NULL.
2383 static const char *pathopt; /* set by path_advance */
2385 static char *
2386 path_advance(const char **path, const char *name)
2388 const char *p;
2389 char *q;
2390 const char *start;
2391 size_t len;
2393 if (*path == NULL)
2394 return NULL;
2395 start = *path;
2396 for (p = start; *p && *p != ':' && *p != '%'; p++)
2397 continue;
2398 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2399 while (stackblocksize() < len)
2400 growstackblock();
2401 q = stackblock();
2402 if (p != start) {
2403 memcpy(q, start, p - start);
2404 q += p - start;
2405 *q++ = '/';
2407 strcpy(q, name);
2408 pathopt = NULL;
2409 if (*p == '%') {
2410 pathopt = ++p;
2411 while (*p && *p != ':')
2412 p++;
2414 if (*p == ':')
2415 *path = p + 1;
2416 else
2417 *path = NULL;
2418 return stalloc(len);
2422 /* ============ Prompt */
2424 static smallint doprompt; /* if set, prompt the user */
2425 static smallint needprompt; /* true if interactive and at start of line */
2427 #if ENABLE_FEATURE_EDITING
2428 static line_input_t *line_input_state;
2429 static const char *cmdedit_prompt;
2430 static void
2431 putprompt(const char *s)
2433 if (ENABLE_ASH_EXPAND_PRMT) {
2434 free((char*)cmdedit_prompt);
2435 cmdedit_prompt = ckstrdup(s);
2436 return;
2438 cmdedit_prompt = s;
2440 #else
2441 static void
2442 putprompt(const char *s)
2444 out2str(s);
2446 #endif
2448 #if ENABLE_ASH_EXPAND_PRMT
2449 /* expandstr() needs parsing machinery, so it is far away ahead... */
2450 static const char *expandstr(const char *ps);
2451 #else
2452 #define expandstr(s) s
2453 #endif
2455 static void
2456 setprompt_if(smallint do_set, int whichprompt)
2458 const char *prompt;
2459 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2461 if (!do_set)
2462 return;
2464 needprompt = 0;
2466 switch (whichprompt) {
2467 case 1:
2468 prompt = ps1val();
2469 break;
2470 case 2:
2471 prompt = ps2val();
2472 break;
2473 default: /* 0 */
2474 prompt = nullstr;
2476 #if ENABLE_ASH_EXPAND_PRMT
2477 setstackmark(&smark);
2478 stalloc(stackblocksize());
2479 #endif
2480 putprompt(expandstr(prompt));
2481 #if ENABLE_ASH_EXPAND_PRMT
2482 popstackmark(&smark);
2483 #endif
2487 /* ============ The cd and pwd commands */
2489 #define CD_PHYSICAL 1
2490 #define CD_PRINT 2
2492 static int
2493 cdopt(void)
2495 int flags = 0;
2496 int i, j;
2498 j = 'L';
2499 while ((i = nextopt("LP")) != '\0') {
2500 if (i != j) {
2501 flags ^= CD_PHYSICAL;
2502 j = i;
2506 return flags;
2510 * Update curdir (the name of the current directory) in response to a
2511 * cd command.
2513 static const char *
2514 updatepwd(const char *dir)
2516 char *new;
2517 char *p;
2518 char *cdcomppath;
2519 const char *lim;
2521 cdcomppath = ststrdup(dir);
2522 STARTSTACKSTR(new);
2523 if (*dir != '/') {
2524 if (curdir == nullstr)
2525 return 0;
2526 new = stack_putstr(curdir, new);
2528 new = makestrspace(strlen(dir) + 2, new);
2529 lim = (char *)stackblock() + 1;
2530 if (*dir != '/') {
2531 if (new[-1] != '/')
2532 USTPUTC('/', new);
2533 if (new > lim && *lim == '/')
2534 lim++;
2535 } else {
2536 USTPUTC('/', new);
2537 cdcomppath++;
2538 if (dir[1] == '/' && dir[2] != '/') {
2539 USTPUTC('/', new);
2540 cdcomppath++;
2541 lim++;
2544 p = strtok(cdcomppath, "/");
2545 while (p) {
2546 switch (*p) {
2547 case '.':
2548 if (p[1] == '.' && p[2] == '\0') {
2549 while (new > lim) {
2550 STUNPUTC(new);
2551 if (new[-1] == '/')
2552 break;
2554 break;
2556 if (p[1] == '\0')
2557 break;
2558 /* fall through */
2559 default:
2560 new = stack_putstr(p, new);
2561 USTPUTC('/', new);
2563 p = strtok(0, "/");
2565 if (new > lim)
2566 STUNPUTC(new);
2567 *new = 0;
2568 return stackblock();
2572 * Find out what the current directory is. If we already know the current
2573 * directory, this routine returns immediately.
2575 static char *
2576 getpwd(void)
2578 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2579 return dir ? dir : nullstr;
2582 static void
2583 setpwd(const char *val, int setold)
2585 char *oldcur, *dir;
2587 oldcur = dir = curdir;
2589 if (setold) {
2590 setvar("OLDPWD", oldcur, VEXPORT);
2592 INT_OFF;
2593 if (physdir != nullstr) {
2594 if (physdir != oldcur)
2595 free(physdir);
2596 physdir = nullstr;
2598 if (oldcur == val || !val) {
2599 char *s = getpwd();
2600 physdir = s;
2601 if (!val)
2602 dir = s;
2603 } else
2604 dir = ckstrdup(val);
2605 if (oldcur != dir && oldcur != nullstr) {
2606 free(oldcur);
2608 curdir = dir;
2609 INT_ON;
2610 setvar("PWD", dir, VEXPORT);
2613 static void hashcd(void);
2616 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2617 * know that the current directory has changed.
2619 static int
2620 docd(const char *dest, int flags)
2622 const char *dir = NULL;
2623 int err;
2625 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2627 INT_OFF;
2628 if (!(flags & CD_PHYSICAL)) {
2629 dir = updatepwd(dest);
2630 if (dir)
2631 dest = dir;
2633 err = chdir(dest);
2634 if (err)
2635 goto out;
2636 setpwd(dir, 1);
2637 hashcd();
2638 out:
2639 INT_ON;
2640 return err;
2643 static int FAST_FUNC
2644 cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2646 const char *dest;
2647 const char *path;
2648 const char *p;
2649 char c;
2650 struct stat statb;
2651 int flags;
2653 flags = cdopt();
2654 dest = *argptr;
2655 if (!dest)
2656 dest = bltinlookup("HOME");
2657 else if (LONE_DASH(dest)) {
2658 dest = bltinlookup("OLDPWD");
2659 flags |= CD_PRINT;
2661 if (!dest)
2662 dest = nullstr;
2663 if (*dest == '/')
2664 goto step7;
2665 if (*dest == '.') {
2666 c = dest[1];
2667 dotdot:
2668 switch (c) {
2669 case '\0':
2670 case '/':
2671 goto step6;
2672 case '.':
2673 c = dest[2];
2674 if (c != '.')
2675 goto dotdot;
2678 if (!*dest)
2679 dest = ".";
2680 path = bltinlookup("CDPATH");
2681 if (!path) {
2682 step6:
2683 step7:
2684 p = dest;
2685 goto docd;
2687 do {
2688 c = *path;
2689 p = path_advance(&path, dest);
2690 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2691 if (c && c != ':')
2692 flags |= CD_PRINT;
2693 docd:
2694 if (!docd(p, flags))
2695 goto out;
2696 break;
2698 } while (path);
2699 ash_msg_and_raise_error("can't cd to %s", dest);
2700 /* NOTREACHED */
2701 out:
2702 if (flags & CD_PRINT)
2703 out1fmt("%s\n", curdir);
2704 return 0;
2707 static int FAST_FUNC
2708 pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2710 int flags;
2711 const char *dir = curdir;
2713 flags = cdopt();
2714 if (flags) {
2715 if (physdir == nullstr)
2716 setpwd(dir, 0);
2717 dir = physdir;
2719 out1fmt("%s\n", dir);
2720 return 0;
2724 /* ============ ... */
2727 #define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
2729 /* Syntax classes */
2730 #define CWORD 0 /* character is nothing special */
2731 #define CNL 1 /* newline character */
2732 #define CBACK 2 /* a backslash character */
2733 #define CSQUOTE 3 /* single quote */
2734 #define CDQUOTE 4 /* double quote */
2735 #define CENDQUOTE 5 /* a terminating quote */
2736 #define CBQUOTE 6 /* backwards single quote */
2737 #define CVAR 7 /* a dollar sign */
2738 #define CENDVAR 8 /* a '}' character */
2739 #define CLP 9 /* a left paren in arithmetic */
2740 #define CRP 10 /* a right paren in arithmetic */
2741 #define CENDFILE 11 /* end of file */
2742 #define CCTL 12 /* like CWORD, except it must be escaped */
2743 #define CSPCL 13 /* these terminate a word */
2744 #define CIGN 14 /* character should be ignored */
2746 #define PEOF 256
2747 #if ENABLE_ASH_ALIAS
2748 # define PEOA 257
2749 #endif
2751 #define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
2753 #if ENABLE_SH_MATH_SUPPORT
2754 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
2755 #else
2756 # define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
2757 #endif
2758 static const uint16_t S_I_T[] = {
2759 #if ENABLE_ASH_ALIAS
2760 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2761 #endif
2762 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2763 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2764 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2765 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2766 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2767 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2768 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2769 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2770 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2771 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2772 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
2773 #if !USE_SIT_FUNCTION
2774 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2775 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2776 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2777 #endif
2778 #undef SIT_ITEM
2780 /* Constants below must match table above */
2781 enum {
2782 #if ENABLE_ASH_ALIAS
2783 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2784 #endif
2785 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2786 CNL_CNL_CNL_CNL , /* 2 */
2787 CWORD_CCTL_CCTL_CWORD , /* 3 */
2788 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2789 CVAR_CVAR_CWORD_CVAR , /* 5 */
2790 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2791 CSPCL_CWORD_CWORD_CLP , /* 7 */
2792 CSPCL_CWORD_CWORD_CRP , /* 8 */
2793 CBACK_CBACK_CCTL_CBACK , /* 9 */
2794 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2795 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2796 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2797 CWORD_CWORD_CWORD_CWORD , /* 13 */
2798 CCTL_CCTL_CCTL_CCTL , /* 14 */
2801 /* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2802 * caller must ensure proper cast on it if c is *char_ptr!
2804 /* Values for syntax param */
2805 #define BASESYNTAX 0 /* not in quotes */
2806 #define DQSYNTAX 1 /* in double quotes */
2807 #define SQSYNTAX 2 /* in single quotes */
2808 #define ARISYNTAX 3 /* in arithmetic */
2809 #define PSSYNTAX 4 /* prompt. never passed to SIT() */
2811 #if USE_SIT_FUNCTION
2813 static int
2814 SIT(int c, int syntax)
2816 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2817 # if ENABLE_ASH_ALIAS
2818 static const uint8_t syntax_index_table[] ALIGN1 = {
2819 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2820 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2821 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2822 11, 3 /* "}~" */
2824 # else
2825 static const uint8_t syntax_index_table[] ALIGN1 = {
2826 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2827 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2828 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2829 10, 2 /* "}~" */
2831 # endif
2832 const char *s;
2833 int indx;
2835 if (c == PEOF)
2836 return CENDFILE;
2837 # if ENABLE_ASH_ALIAS
2838 if (c == PEOA)
2839 indx = 0;
2840 else
2841 # endif
2843 /* Cast is purely for paranoia here,
2844 * just in case someone passed signed char to us */
2845 if ((unsigned char)c >= CTL_FIRST
2846 && (unsigned char)c <= CTL_LAST
2848 return CCTL;
2850 s = strchrnul(spec_symbls, c);
2851 if (*s == '\0')
2852 return CWORD;
2853 indx = syntax_index_table[s - spec_symbls];
2855 return (S_I_T[indx] >> (syntax*4)) & 0xf;
2858 #else /* !USE_SIT_FUNCTION */
2860 static const uint8_t syntax_index_table[] = {
2861 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2862 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2872 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2873 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2895 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2896 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2897 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2898 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2899 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2900 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2901 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2902 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2903 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2904 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2905 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2906 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2907 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2908 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
2909 /* 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2910 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2921 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2922 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2923 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2924 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2925 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2926 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2954 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2955 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2956 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2959 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2987 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2988 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2989 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2990 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2991 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2992 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2993 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2994 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2995 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2996 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2997 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2998 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2999 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3000 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3001 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3002 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 255 */ CWORD_CWORD_CWORD_CWORD,
3118 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
3119 # if ENABLE_ASH_ALIAS
3120 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3121 # endif
3124 # define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
3126 #endif /* !USE_SIT_FUNCTION */
3129 /* ============ Alias handling */
3131 #if ENABLE_ASH_ALIAS
3133 #define ALIASINUSE 1
3134 #define ALIASDEAD 2
3136 struct alias {
3137 struct alias *next;
3138 char *name;
3139 char *val;
3140 int flag;
3144 static struct alias **atab; // [ATABSIZE];
3145 #define INIT_G_alias() do { \
3146 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3147 } while (0)
3150 static struct alias **
3151 __lookupalias(const char *name) {
3152 unsigned int hashval;
3153 struct alias **app;
3154 const char *p;
3155 unsigned int ch;
3157 p = name;
3159 ch = (unsigned char)*p;
3160 hashval = ch << 4;
3161 while (ch) {
3162 hashval += ch;
3163 ch = (unsigned char)*++p;
3165 app = &atab[hashval % ATABSIZE];
3167 for (; *app; app = &(*app)->next) {
3168 if (strcmp(name, (*app)->name) == 0) {
3169 break;
3173 return app;
3176 static struct alias *
3177 lookupalias(const char *name, int check)
3179 struct alias *ap = *__lookupalias(name);
3181 if (check && ap && (ap->flag & ALIASINUSE))
3182 return NULL;
3183 return ap;
3186 static struct alias *
3187 freealias(struct alias *ap)
3189 struct alias *next;
3191 if (ap->flag & ALIASINUSE) {
3192 ap->flag |= ALIASDEAD;
3193 return ap;
3196 next = ap->next;
3197 free(ap->name);
3198 free(ap->val);
3199 free(ap);
3200 return next;
3203 static void
3204 setalias(const char *name, const char *val)
3206 struct alias *ap, **app;
3208 app = __lookupalias(name);
3209 ap = *app;
3210 INT_OFF;
3211 if (ap) {
3212 if (!(ap->flag & ALIASINUSE)) {
3213 free(ap->val);
3215 ap->val = ckstrdup(val);
3216 ap->flag &= ~ALIASDEAD;
3217 } else {
3218 /* not found */
3219 ap = ckzalloc(sizeof(struct alias));
3220 ap->name = ckstrdup(name);
3221 ap->val = ckstrdup(val);
3222 /*ap->flag = 0; - ckzalloc did it */
3223 /*ap->next = NULL;*/
3224 *app = ap;
3226 INT_ON;
3229 static int
3230 unalias(const char *name)
3232 struct alias **app;
3234 app = __lookupalias(name);
3236 if (*app) {
3237 INT_OFF;
3238 *app = freealias(*app);
3239 INT_ON;
3240 return 0;
3243 return 1;
3246 static void
3247 rmaliases(void)
3249 struct alias *ap, **app;
3250 int i;
3252 INT_OFF;
3253 for (i = 0; i < ATABSIZE; i++) {
3254 app = &atab[i];
3255 for (ap = *app; ap; ap = *app) {
3256 *app = freealias(*app);
3257 if (ap == *app) {
3258 app = &ap->next;
3262 INT_ON;
3265 static void
3266 printalias(const struct alias *ap)
3268 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3272 * TODO - sort output
3274 static int FAST_FUNC
3275 aliascmd(int argc UNUSED_PARAM, char **argv)
3277 char *n, *v;
3278 int ret = 0;
3279 struct alias *ap;
3281 if (!argv[1]) {
3282 int i;
3284 for (i = 0; i < ATABSIZE; i++) {
3285 for (ap = atab[i]; ap; ap = ap->next) {
3286 printalias(ap);
3289 return 0;
3291 while ((n = *++argv) != NULL) {
3292 v = strchr(n+1, '=');
3293 if (v == NULL) { /* n+1: funny ksh stuff */
3294 ap = *__lookupalias(n);
3295 if (ap == NULL) {
3296 fprintf(stderr, "%s: %s not found\n", "alias", n);
3297 ret = 1;
3298 } else
3299 printalias(ap);
3300 } else {
3301 *v++ = '\0';
3302 setalias(n, v);
3306 return ret;
3309 static int FAST_FUNC
3310 unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3312 int i;
3314 while ((i = nextopt("a")) != '\0') {
3315 if (i == 'a') {
3316 rmaliases();
3317 return 0;
3320 for (i = 0; *argptr; argptr++) {
3321 if (unalias(*argptr)) {
3322 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3323 i = 1;
3327 return i;
3330 #endif /* ASH_ALIAS */
3333 /* ============ jobs.c */
3335 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3336 #define FORK_FG 0
3337 #define FORK_BG 1
3338 #define FORK_NOJOB 2
3340 /* mode flags for showjob(s) */
3341 #define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3342 #define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3343 #define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
3346 * A job structure contains information about a job. A job is either a
3347 * single process or a set of processes contained in a pipeline. In the
3348 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3349 * array of pids.
3351 struct procstat {
3352 pid_t ps_pid; /* process id */
3353 int ps_status; /* last process status from wait() */
3354 char *ps_cmd; /* text of command being run */
3357 struct job {
3358 struct procstat ps0; /* status of process */
3359 struct procstat *ps; /* status or processes when more than one */
3360 #if JOBS
3361 int stopstatus; /* status of a stopped job */
3362 #endif
3363 uint32_t
3364 nprocs: 16, /* number of processes */
3365 state: 8,
3366 #define JOBRUNNING 0 /* at least one proc running */
3367 #define JOBSTOPPED 1 /* all procs are stopped */
3368 #define JOBDONE 2 /* all procs are completed */
3369 #if JOBS
3370 sigint: 1, /* job was killed by SIGINT */
3371 jobctl: 1, /* job running under job control */
3372 #endif
3373 waited: 1, /* true if this entry has been waited for */
3374 used: 1, /* true if this entry is in used */
3375 changed: 1; /* true if status has changed */
3376 struct job *prev_job; /* previous job */
3379 static struct job *makejob(/*union node *,*/ int);
3380 static int forkshell(struct job *, union node *, int);
3381 static int waitforjob(struct job *);
3383 #if !JOBS
3384 enum { doing_jobctl = 0 };
3385 #define setjobctl(on) do {} while (0)
3386 #else
3387 static smallint doing_jobctl; //references:8
3388 static void setjobctl(int);
3389 #endif
3392 * Ignore a signal.
3394 static void
3395 ignoresig(int signo)
3397 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3398 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3399 /* No, need to do it */
3400 signal(signo, SIG_IGN);
3402 sigmode[signo - 1] = S_HARD_IGN;
3406 * Only one usage site - in setsignal()
3408 static void
3409 signal_handler(int signo)
3411 gotsig[signo - 1] = 1;
3413 if (signo == SIGINT && !trap[SIGINT]) {
3414 if (!suppress_int) {
3415 pending_sig = 0;
3416 raise_interrupt(); /* does not return */
3418 pending_int = 1;
3419 } else {
3420 pending_sig = signo;
3425 * Set the signal handler for the specified signal. The routine figures
3426 * out what it should be set to.
3428 static void
3429 setsignal(int signo)
3431 char *t;
3432 char cur_act, new_act;
3433 struct sigaction act;
3435 t = trap[signo];
3436 new_act = S_DFL;
3437 if (t != NULL) { /* trap for this sig is set */
3438 new_act = S_CATCH;
3439 if (t[0] == '\0') /* trap is "": ignore this sig */
3440 new_act = S_IGN;
3443 if (rootshell && new_act == S_DFL) {
3444 switch (signo) {
3445 case SIGINT:
3446 if (iflag || minusc || sflag == 0)
3447 new_act = S_CATCH;
3448 break;
3449 case SIGQUIT:
3450 #if DEBUG
3451 if (debug)
3452 break;
3453 #endif
3454 /* man bash:
3455 * "In all cases, bash ignores SIGQUIT. Non-builtin
3456 * commands run by bash have signal handlers
3457 * set to the values inherited by the shell
3458 * from its parent". */
3459 new_act = S_IGN;
3460 break;
3461 case SIGTERM:
3462 if (iflag)
3463 new_act = S_IGN;
3464 break;
3465 #if JOBS
3466 case SIGTSTP:
3467 case SIGTTOU:
3468 if (mflag)
3469 new_act = S_IGN;
3470 break;
3471 #endif
3474 //TODO: if !rootshell, we reset SIGQUIT to DFL,
3475 //whereas we have to restore it to what shell got on entry
3476 //from the parent. See comment above
3478 t = &sigmode[signo - 1];
3479 cur_act = *t;
3480 if (cur_act == 0) {
3481 /* current setting is not yet known */
3482 if (sigaction(signo, NULL, &act)) {
3483 /* pretend it worked; maybe we should give a warning,
3484 * but other shells don't. We don't alter sigmode,
3485 * so we retry every time.
3486 * btw, in Linux it never fails. --vda */
3487 return;
3489 if (act.sa_handler == SIG_IGN) {
3490 cur_act = S_HARD_IGN;
3491 if (mflag
3492 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3494 cur_act = S_IGN; /* don't hard ignore these */
3498 if (cur_act == S_HARD_IGN || cur_act == new_act)
3499 return;
3501 act.sa_handler = SIG_DFL;
3502 switch (new_act) {
3503 case S_CATCH:
3504 act.sa_handler = signal_handler;
3505 break;
3506 case S_IGN:
3507 act.sa_handler = SIG_IGN;
3508 break;
3511 /* flags and mask matter only if !DFL and !IGN, but we do it
3512 * for all cases for more deterministic behavior:
3514 act.sa_flags = 0;
3515 sigfillset(&act.sa_mask);
3517 sigaction_set(signo, &act);
3519 *t = new_act;
3522 /* mode flags for set_curjob */
3523 #define CUR_DELETE 2
3524 #define CUR_RUNNING 1
3525 #define CUR_STOPPED 0
3527 /* mode flags for dowait */
3528 #define DOWAIT_NONBLOCK WNOHANG
3529 #define DOWAIT_BLOCK 0
3531 #if JOBS
3532 /* pgrp of shell on invocation */
3533 static int initialpgrp; //references:2
3534 static int ttyfd = -1; //5
3535 #endif
3536 /* array of jobs */
3537 static struct job *jobtab; //5
3538 /* size of array */
3539 static unsigned njobs; //4
3540 /* current job */
3541 static struct job *curjob; //lots
3542 /* number of presumed living untracked jobs */
3543 static int jobless; //4
3545 static void
3546 set_curjob(struct job *jp, unsigned mode)
3548 struct job *jp1;
3549 struct job **jpp, **curp;
3551 /* first remove from list */
3552 jpp = curp = &curjob;
3553 while (1) {
3554 jp1 = *jpp;
3555 if (jp1 == jp)
3556 break;
3557 jpp = &jp1->prev_job;
3559 *jpp = jp1->prev_job;
3561 /* Then re-insert in correct position */
3562 jpp = curp;
3563 switch (mode) {
3564 default:
3565 #if DEBUG
3566 abort();
3567 #endif
3568 case CUR_DELETE:
3569 /* job being deleted */
3570 break;
3571 case CUR_RUNNING:
3572 /* newly created job or backgrounded job,
3573 * put after all stopped jobs.
3575 while (1) {
3576 jp1 = *jpp;
3577 #if JOBS
3578 if (!jp1 || jp1->state != JOBSTOPPED)
3579 #endif
3580 break;
3581 jpp = &jp1->prev_job;
3583 /* FALLTHROUGH */
3584 #if JOBS
3585 case CUR_STOPPED:
3586 #endif
3587 /* newly stopped job - becomes curjob */
3588 jp->prev_job = *jpp;
3589 *jpp = jp;
3590 break;
3594 #if JOBS || DEBUG
3595 static int
3596 jobno(const struct job *jp)
3598 return jp - jobtab + 1;
3600 #endif
3603 * Convert a job name to a job structure.
3605 #if !JOBS
3606 #define getjob(name, getctl) getjob(name)
3607 #endif
3608 static struct job *
3609 getjob(const char *name, int getctl)
3611 struct job *jp;
3612 struct job *found;
3613 const char *err_msg = "%s: no such job";
3614 unsigned num;
3615 int c;
3616 const char *p;
3617 char *(*match)(const char *, const char *);
3619 jp = curjob;
3620 p = name;
3621 if (!p)
3622 goto currentjob;
3624 if (*p != '%')
3625 goto err;
3627 c = *++p;
3628 if (!c)
3629 goto currentjob;
3631 if (!p[1]) {
3632 if (c == '+' || c == '%') {
3633 currentjob:
3634 err_msg = "No current job";
3635 goto check;
3637 if (c == '-') {
3638 if (jp)
3639 jp = jp->prev_job;
3640 err_msg = "No previous job";
3641 check:
3642 if (!jp)
3643 goto err;
3644 goto gotit;
3648 if (is_number(p)) {
3649 num = atoi(p);
3650 if (num <= njobs) {
3651 jp = jobtab + num - 1;
3652 if (jp->used)
3653 goto gotit;
3654 goto err;
3658 match = prefix;
3659 if (*p == '?') {
3660 match = strstr;
3661 p++;
3664 found = NULL;
3665 while (jp) {
3666 if (match(jp->ps[0].ps_cmd, p)) {
3667 if (found)
3668 goto err;
3669 found = jp;
3670 err_msg = "%s: ambiguous";
3672 jp = jp->prev_job;
3674 if (!found)
3675 goto err;
3676 jp = found;
3678 gotit:
3679 #if JOBS
3680 err_msg = "job %s not created under job control";
3681 if (getctl && jp->jobctl == 0)
3682 goto err;
3683 #endif
3684 return jp;
3685 err:
3686 ash_msg_and_raise_error(err_msg, name);
3690 * Mark a job structure as unused.
3692 static void
3693 freejob(struct job *jp)
3695 struct procstat *ps;
3696 int i;
3698 INT_OFF;
3699 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3700 if (ps->ps_cmd != nullstr)
3701 free(ps->ps_cmd);
3703 if (jp->ps != &jp->ps0)
3704 free(jp->ps);
3705 jp->used = 0;
3706 set_curjob(jp, CUR_DELETE);
3707 INT_ON;
3710 #if JOBS
3711 static void
3712 xtcsetpgrp(int fd, pid_t pgrp)
3714 if (tcsetpgrp(fd, pgrp))
3715 ash_msg_and_raise_error("can't set tty process group (%m)");
3719 * Turn job control on and off.
3721 * Note: This code assumes that the third arg to ioctl is a character
3722 * pointer, which is true on Berkeley systems but not System V. Since
3723 * System V doesn't have job control yet, this isn't a problem now.
3725 * Called with interrupts off.
3727 static void
3728 setjobctl(int on)
3730 int fd;
3731 int pgrp;
3733 if (on == doing_jobctl || rootshell == 0)
3734 return;
3735 if (on) {
3736 int ofd;
3737 ofd = fd = open(_PATH_TTY, O_RDWR);
3738 if (fd < 0) {
3739 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3740 * That sometimes helps to acquire controlling tty.
3741 * Obviously, a workaround for bugs when someone
3742 * failed to provide a controlling tty to bash! :) */
3743 fd = 2;
3744 while (!isatty(fd))
3745 if (--fd < 0)
3746 goto out;
3748 fd = fcntl(fd, F_DUPFD, 10);
3749 if (ofd >= 0)
3750 close(ofd);
3751 if (fd < 0)
3752 goto out;
3753 /* fd is a tty at this point */
3754 close_on_exec_on(fd);
3755 while (1) { /* while we are in the background */
3756 pgrp = tcgetpgrp(fd);
3757 if (pgrp < 0) {
3758 out:
3759 ash_msg("can't access tty; job control turned off");
3760 mflag = on = 0;
3761 goto close;
3763 if (pgrp == getpgrp())
3764 break;
3765 killpg(0, SIGTTIN);
3767 initialpgrp = pgrp;
3769 setsignal(SIGTSTP);
3770 setsignal(SIGTTOU);
3771 setsignal(SIGTTIN);
3772 pgrp = rootpid;
3773 setpgid(0, pgrp);
3774 xtcsetpgrp(fd, pgrp);
3775 } else {
3776 /* turning job control off */
3777 fd = ttyfd;
3778 pgrp = initialpgrp;
3779 /* was xtcsetpgrp, but this can make exiting ash
3780 * loop forever if pty is already deleted */
3781 tcsetpgrp(fd, pgrp);
3782 setpgid(0, pgrp);
3783 setsignal(SIGTSTP);
3784 setsignal(SIGTTOU);
3785 setsignal(SIGTTIN);
3786 close:
3787 if (fd >= 0)
3788 close(fd);
3789 fd = -1;
3791 ttyfd = fd;
3792 doing_jobctl = on;
3795 static int FAST_FUNC
3796 killcmd(int argc, char **argv)
3798 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3799 int i = 1;
3800 do {
3801 if (argv[i][0] == '%') {
3803 * "kill %N" - job kill
3804 * Converting to pgrp / pid kill
3806 struct job *jp;
3807 char *dst;
3808 int j, n;
3810 jp = getjob(argv[i], 0);
3812 * In jobs started under job control, we signal
3813 * entire process group by kill -PGRP_ID.
3814 * This happens, f.e., in interactive shell.
3816 * Otherwise, we signal each child via
3817 * kill PID1 PID2 PID3.
3818 * Testcases:
3819 * sh -c 'sleep 1|sleep 1 & kill %1'
3820 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3821 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3823 n = jp->nprocs; /* can't be 0 (I hope) */
3824 if (jp->jobctl)
3825 n = 1;
3826 dst = alloca(n * sizeof(int)*4);
3827 argv[i] = dst;
3828 for (j = 0; j < n; j++) {
3829 struct procstat *ps = &jp->ps[j];
3830 /* Skip non-running and not-stopped members
3831 * (i.e. dead members) of the job
3833 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3834 continue;
3836 * kill_main has matching code to expect
3837 * leading space. Needed to not confuse
3838 * negative pids with "kill -SIGNAL_NO" syntax
3840 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3842 *dst = '\0';
3844 } while (argv[++i]);
3846 return kill_main(argc, argv);
3849 static void
3850 showpipe(struct job *jp /*, FILE *out*/)
3852 struct procstat *ps;
3853 struct procstat *psend;
3855 psend = jp->ps + jp->nprocs;
3856 for (ps = jp->ps + 1; ps < psend; ps++)
3857 printf(" | %s", ps->ps_cmd);
3858 outcslow('\n', stdout);
3859 flush_stdout_stderr();
3863 static int
3864 restartjob(struct job *jp, int mode)
3866 struct procstat *ps;
3867 int i;
3868 int status;
3869 pid_t pgid;
3871 INT_OFF;
3872 if (jp->state == JOBDONE)
3873 goto out;
3874 jp->state = JOBRUNNING;
3875 pgid = jp->ps[0].ps_pid;
3876 if (mode == FORK_FG)
3877 xtcsetpgrp(ttyfd, pgid);
3878 killpg(pgid, SIGCONT);
3879 ps = jp->ps;
3880 i = jp->nprocs;
3881 do {
3882 if (WIFSTOPPED(ps->ps_status)) {
3883 ps->ps_status = -1;
3885 ps++;
3886 } while (--i);
3887 out:
3888 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3889 INT_ON;
3890 return status;
3893 static int FAST_FUNC
3894 fg_bgcmd(int argc UNUSED_PARAM, char **argv)
3896 struct job *jp;
3897 int mode;
3898 int retval;
3900 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3901 nextopt(nullstr);
3902 argv = argptr;
3903 do {
3904 jp = getjob(*argv, 1);
3905 if (mode == FORK_BG) {
3906 set_curjob(jp, CUR_RUNNING);
3907 printf("[%d] ", jobno(jp));
3909 out1str(jp->ps[0].ps_cmd);
3910 showpipe(jp /*, stdout*/);
3911 retval = restartjob(jp, mode);
3912 } while (*argv && *++argv);
3913 return retval;
3915 #endif
3917 static int
3918 sprint_status(char *s, int status, int sigonly)
3920 int col;
3921 int st;
3923 col = 0;
3924 if (!WIFEXITED(status)) {
3925 #if JOBS
3926 if (WIFSTOPPED(status))
3927 st = WSTOPSIG(status);
3928 else
3929 #endif
3930 st = WTERMSIG(status);
3931 if (sigonly) {
3932 if (st == SIGINT || st == SIGPIPE)
3933 goto out;
3934 #if JOBS
3935 if (WIFSTOPPED(status))
3936 goto out;
3937 #endif
3939 st &= 0x7f;
3940 //TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
3941 col = fmtstr(s, 32, strsignal(st));
3942 if (WCOREDUMP(status)) {
3943 col += fmtstr(s + col, 16, " (core dumped)");
3945 } else if (!sigonly) {
3946 st = WEXITSTATUS(status);
3947 if (st)
3948 col = fmtstr(s, 16, "Done(%d)", st);
3949 else
3950 col = fmtstr(s, 16, "Done");
3952 out:
3953 return col;
3956 static int
3957 dowait(int wait_flags, struct job *job)
3959 int pid;
3960 int status;
3961 struct job *jp;
3962 struct job *thisjob;
3963 int state;
3965 TRACE(("dowait(0x%x) called\n", wait_flags));
3967 /* Do a wait system call. If job control is compiled in, we accept
3968 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3969 * NB: _not_ safe_waitpid, we need to detect EINTR */
3970 if (doing_jobctl)
3971 wait_flags |= WUNTRACED;
3972 pid = waitpid(-1, &status, wait_flags);
3973 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3974 pid, status, errno, strerror(errno)));
3975 if (pid <= 0)
3976 return pid;
3978 INT_OFF;
3979 thisjob = NULL;
3980 for (jp = curjob; jp; jp = jp->prev_job) {
3981 struct procstat *ps;
3982 struct procstat *psend;
3983 if (jp->state == JOBDONE)
3984 continue;
3985 state = JOBDONE;
3986 ps = jp->ps;
3987 psend = ps + jp->nprocs;
3988 do {
3989 if (ps->ps_pid == pid) {
3990 TRACE(("Job %d: changing status of proc %d "
3991 "from 0x%x to 0x%x\n",
3992 jobno(jp), pid, ps->ps_status, status));
3993 ps->ps_status = status;
3994 thisjob = jp;
3996 if (ps->ps_status == -1)
3997 state = JOBRUNNING;
3998 #if JOBS
3999 if (state == JOBRUNNING)
4000 continue;
4001 if (WIFSTOPPED(ps->ps_status)) {
4002 jp->stopstatus = ps->ps_status;
4003 state = JOBSTOPPED;
4005 #endif
4006 } while (++ps < psend);
4007 if (thisjob)
4008 goto gotjob;
4010 #if JOBS
4011 if (!WIFSTOPPED(status))
4012 #endif
4013 jobless--;
4014 goto out;
4016 gotjob:
4017 if (state != JOBRUNNING) {
4018 thisjob->changed = 1;
4020 if (thisjob->state != state) {
4021 TRACE(("Job %d: changing state from %d to %d\n",
4022 jobno(thisjob), thisjob->state, state));
4023 thisjob->state = state;
4024 #if JOBS
4025 if (state == JOBSTOPPED) {
4026 set_curjob(thisjob, CUR_STOPPED);
4028 #endif
4032 out:
4033 INT_ON;
4035 if (thisjob && thisjob == job) {
4036 char s[48 + 1];
4037 int len;
4039 len = sprint_status(s, status, 1);
4040 if (len) {
4041 s[len] = '\n';
4042 s[len + 1] = '\0';
4043 out2str(s);
4046 return pid;
4049 static int
4050 blocking_wait_with_raise_on_sig(void)
4052 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
4053 if (pid <= 0 && pending_sig)
4054 raise_exception(EXSIG);
4055 return pid;
4058 #if JOBS
4059 static void
4060 showjob(FILE *out, struct job *jp, int mode)
4062 struct procstat *ps;
4063 struct procstat *psend;
4064 int col;
4065 int indent_col;
4066 char s[80];
4068 ps = jp->ps;
4070 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
4071 /* just output process (group) id of pipeline */
4072 fprintf(out, "%d\n", ps->ps_pid);
4073 return;
4076 col = fmtstr(s, 16, "[%d] ", jobno(jp));
4077 indent_col = col;
4079 if (jp == curjob)
4080 s[col - 3] = '+';
4081 else if (curjob && jp == curjob->prev_job)
4082 s[col - 3] = '-';
4084 if (mode & SHOW_PIDS)
4085 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
4087 psend = ps + jp->nprocs;
4089 if (jp->state == JOBRUNNING) {
4090 strcpy(s + col, "Running");
4091 col += sizeof("Running") - 1;
4092 } else {
4093 int status = psend[-1].ps_status;
4094 if (jp->state == JOBSTOPPED)
4095 status = jp->stopstatus;
4096 col += sprint_status(s + col, status, 0);
4098 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
4100 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4101 * or prints several "PID | <cmdN>" lines,
4102 * depending on SHOW_PIDS bit.
4103 * We do not print status of individual processes
4104 * between PID and <cmdN>. bash does it, but not very well:
4105 * first line shows overall job status, not process status,
4106 * making it impossible to know 1st process status.
4108 goto start;
4109 do {
4110 /* for each process */
4111 s[0] = '\0';
4112 col = 33;
4113 if (mode & SHOW_PIDS)
4114 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
4115 start:
4116 fprintf(out, "%s%*c%s%s",
4118 33 - col >= 0 ? 33 - col : 0, ' ',
4119 ps == jp->ps ? "" : "| ",
4120 ps->ps_cmd
4122 } while (++ps != psend);
4123 outcslow('\n', out);
4125 jp->changed = 0;
4127 if (jp->state == JOBDONE) {
4128 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4129 freejob(jp);
4134 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4135 * statuses have changed since the last call to showjobs.
4137 static void
4138 showjobs(FILE *out, int mode)
4140 struct job *jp;
4142 TRACE(("showjobs(0x%x) called\n", mode));
4144 /* Handle all finished jobs */
4145 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
4146 continue;
4148 for (jp = curjob; jp; jp = jp->prev_job) {
4149 if (!(mode & SHOW_CHANGED) || jp->changed) {
4150 showjob(out, jp, mode);
4155 static int FAST_FUNC
4156 jobscmd(int argc UNUSED_PARAM, char **argv)
4158 int mode, m;
4160 mode = 0;
4161 while ((m = nextopt("lp")) != '\0') {
4162 if (m == 'l')
4163 mode |= SHOW_PIDS;
4164 else
4165 mode |= SHOW_ONLY_PGID;
4168 argv = argptr;
4169 if (*argv) {
4171 showjob(stdout, getjob(*argv, 0), mode);
4172 while (*++argv);
4173 } else {
4174 showjobs(stdout, mode);
4177 return 0;
4179 #endif /* JOBS */
4181 /* Called only on finished or stopped jobs (no members are running) */
4182 static int
4183 getstatus(struct job *job)
4185 int status;
4186 int retval;
4187 struct procstat *ps;
4189 /* Fetch last member's status */
4190 ps = job->ps + job->nprocs - 1;
4191 status = ps->ps_status;
4192 if (pipefail) {
4193 /* "set -o pipefail" mode: use last _nonzero_ status */
4194 while (status == 0 && --ps >= job->ps)
4195 status = ps->ps_status;
4198 retval = WEXITSTATUS(status);
4199 if (!WIFEXITED(status)) {
4200 #if JOBS
4201 retval = WSTOPSIG(status);
4202 if (!WIFSTOPPED(status))
4203 #endif
4205 /* XXX: limits number of signals */
4206 retval = WTERMSIG(status);
4207 #if JOBS
4208 if (retval == SIGINT)
4209 job->sigint = 1;
4210 #endif
4212 retval += 128;
4214 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4215 jobno(job), job->nprocs, status, retval));
4216 return retval;
4219 static int FAST_FUNC
4220 waitcmd(int argc UNUSED_PARAM, char **argv)
4222 struct job *job;
4223 int retval;
4224 struct job *jp;
4226 if (pending_sig)
4227 raise_exception(EXSIG);
4229 nextopt(nullstr);
4230 retval = 0;
4232 argv = argptr;
4233 if (!*argv) {
4234 /* wait for all jobs */
4235 for (;;) {
4236 jp = curjob;
4237 while (1) {
4238 if (!jp) /* no running procs */
4239 goto ret;
4240 if (jp->state == JOBRUNNING)
4241 break;
4242 jp->waited = 1;
4243 jp = jp->prev_job;
4245 blocking_wait_with_raise_on_sig();
4246 /* man bash:
4247 * "When bash is waiting for an asynchronous command via
4248 * the wait builtin, the reception of a signal for which a trap
4249 * has been set will cause the wait builtin to return immediately
4250 * with an exit status greater than 128, immediately after which
4251 * the trap is executed."
4253 * blocking_wait_with_raise_on_sig raises signal handlers
4254 * if it gets no pid (pid < 0). However,
4255 * if child sends us a signal *and immediately exits*,
4256 * blocking_wait_with_raise_on_sig gets pid > 0
4257 * and does not handle pending_sig. Check this case: */
4258 if (pending_sig)
4259 raise_exception(EXSIG);
4263 retval = 127;
4264 do {
4265 if (**argv != '%') {
4266 pid_t pid = number(*argv);
4267 job = curjob;
4268 while (1) {
4269 if (!job)
4270 goto repeat;
4271 if (job->ps[job->nprocs - 1].ps_pid == pid)
4272 break;
4273 job = job->prev_job;
4275 } else {
4276 job = getjob(*argv, 0);
4278 /* loop until process terminated or stopped */
4279 while (job->state == JOBRUNNING)
4280 blocking_wait_with_raise_on_sig();
4281 job->waited = 1;
4282 retval = getstatus(job);
4283 repeat: ;
4284 } while (*++argv);
4286 ret:
4287 return retval;
4290 static struct job *
4291 growjobtab(void)
4293 size_t len;
4294 ptrdiff_t offset;
4295 struct job *jp, *jq;
4297 len = njobs * sizeof(*jp);
4298 jq = jobtab;
4299 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4301 offset = (char *)jp - (char *)jq;
4302 if (offset) {
4303 /* Relocate pointers */
4304 size_t l = len;
4306 jq = (struct job *)((char *)jq + l);
4307 while (l) {
4308 l -= sizeof(*jp);
4309 jq--;
4310 #define joff(p) ((struct job *)((char *)(p) + l))
4311 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4312 if (joff(jp)->ps == &jq->ps0)
4313 jmove(joff(jp)->ps);
4314 if (joff(jp)->prev_job)
4315 jmove(joff(jp)->prev_job);
4317 if (curjob)
4318 jmove(curjob);
4319 #undef joff
4320 #undef jmove
4323 njobs += 4;
4324 jobtab = jp;
4325 jp = (struct job *)((char *)jp + len);
4326 jq = jp + 3;
4327 do {
4328 jq->used = 0;
4329 } while (--jq >= jp);
4330 return jp;
4334 * Return a new job structure.
4335 * Called with interrupts off.
4337 static struct job *
4338 makejob(/*union node *node,*/ int nprocs)
4340 int i;
4341 struct job *jp;
4343 for (i = njobs, jp = jobtab; ; jp++) {
4344 if (--i < 0) {
4345 jp = growjobtab();
4346 break;
4348 if (jp->used == 0)
4349 break;
4350 if (jp->state != JOBDONE || !jp->waited)
4351 continue;
4352 #if JOBS
4353 if (doing_jobctl)
4354 continue;
4355 #endif
4356 freejob(jp);
4357 break;
4359 memset(jp, 0, sizeof(*jp));
4360 #if JOBS
4361 /* jp->jobctl is a bitfield.
4362 * "jp->jobctl |= jobctl" likely to give awful code */
4363 if (doing_jobctl)
4364 jp->jobctl = 1;
4365 #endif
4366 jp->prev_job = curjob;
4367 curjob = jp;
4368 jp->used = 1;
4369 jp->ps = &jp->ps0;
4370 if (nprocs > 1) {
4371 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4373 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4374 jobno(jp)));
4375 return jp;
4378 #if JOBS
4380 * Return a string identifying a command (to be printed by the
4381 * jobs command).
4383 static char *cmdnextc;
4385 static void
4386 cmdputs(const char *s)
4388 static const char vstype[VSTYPE + 1][3] = {
4389 "", "}", "-", "+", "?", "=",
4390 "%", "%%", "#", "##"
4391 IF_ASH_BASH_COMPAT(, ":", "/", "//")
4394 const char *p, *str;
4395 char cc[2];
4396 char *nextc;
4397 unsigned char c;
4398 unsigned char subtype = 0;
4399 int quoted = 0;
4401 cc[1] = '\0';
4402 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4403 p = s;
4404 while ((c = *p++) != '\0') {
4405 str = NULL;
4406 switch (c) {
4407 case CTLESC:
4408 c = *p++;
4409 break;
4410 case CTLVAR:
4411 subtype = *p++;
4412 if ((subtype & VSTYPE) == VSLENGTH)
4413 str = "${#";
4414 else
4415 str = "${";
4416 if (!(subtype & VSQUOTE) == !(quoted & 1))
4417 goto dostr;
4418 quoted ^= 1;
4419 c = '"';
4420 break;
4421 case CTLENDVAR:
4422 str = "\"}" + !(quoted & 1);
4423 quoted >>= 1;
4424 subtype = 0;
4425 goto dostr;
4426 case CTLBACKQ:
4427 str = "$(...)";
4428 goto dostr;
4429 case CTLBACKQ+CTLQUOTE:
4430 str = "\"$(...)\"";
4431 goto dostr;
4432 #if ENABLE_SH_MATH_SUPPORT
4433 case CTLARI:
4434 str = "$((";
4435 goto dostr;
4436 case CTLENDARI:
4437 str = "))";
4438 goto dostr;
4439 #endif
4440 case CTLQUOTEMARK:
4441 quoted ^= 1;
4442 c = '"';
4443 break;
4444 case '=':
4445 if (subtype == 0)
4446 break;
4447 if ((subtype & VSTYPE) != VSNORMAL)
4448 quoted <<= 1;
4449 str = vstype[subtype & VSTYPE];
4450 if (subtype & VSNUL)
4451 c = ':';
4452 else
4453 goto checkstr;
4454 break;
4455 case '\'':
4456 case '\\':
4457 case '"':
4458 case '$':
4459 /* These can only happen inside quotes */
4460 cc[0] = c;
4461 str = cc;
4462 c = '\\';
4463 break;
4464 default:
4465 break;
4467 USTPUTC(c, nextc);
4468 checkstr:
4469 if (!str)
4470 continue;
4471 dostr:
4472 while ((c = *str++) != '\0') {
4473 USTPUTC(c, nextc);
4475 } /* while *p++ not NUL */
4477 if (quoted & 1) {
4478 USTPUTC('"', nextc);
4480 *nextc = 0;
4481 cmdnextc = nextc;
4484 /* cmdtxt() and cmdlist() call each other */
4485 static void cmdtxt(union node *n);
4487 static void
4488 cmdlist(union node *np, int sep)
4490 for (; np; np = np->narg.next) {
4491 if (!sep)
4492 cmdputs(" ");
4493 cmdtxt(np);
4494 if (sep && np->narg.next)
4495 cmdputs(" ");
4499 static void
4500 cmdtxt(union node *n)
4502 union node *np;
4503 struct nodelist *lp;
4504 const char *p;
4506 if (!n)
4507 return;
4508 switch (n->type) {
4509 default:
4510 #if DEBUG
4511 abort();
4512 #endif
4513 case NPIPE:
4514 lp = n->npipe.cmdlist;
4515 for (;;) {
4516 cmdtxt(lp->n);
4517 lp = lp->next;
4518 if (!lp)
4519 break;
4520 cmdputs(" | ");
4522 break;
4523 case NSEMI:
4524 p = "; ";
4525 goto binop;
4526 case NAND:
4527 p = " && ";
4528 goto binop;
4529 case NOR:
4530 p = " || ";
4531 binop:
4532 cmdtxt(n->nbinary.ch1);
4533 cmdputs(p);
4534 n = n->nbinary.ch2;
4535 goto donode;
4536 case NREDIR:
4537 case NBACKGND:
4538 n = n->nredir.n;
4539 goto donode;
4540 case NNOT:
4541 cmdputs("!");
4542 n = n->nnot.com;
4543 donode:
4544 cmdtxt(n);
4545 break;
4546 case NIF:
4547 cmdputs("if ");
4548 cmdtxt(n->nif.test);
4549 cmdputs("; then ");
4550 if (n->nif.elsepart) {
4551 cmdtxt(n->nif.ifpart);
4552 cmdputs("; else ");
4553 n = n->nif.elsepart;
4554 } else {
4555 n = n->nif.ifpart;
4557 p = "; fi";
4558 goto dotail;
4559 case NSUBSHELL:
4560 cmdputs("(");
4561 n = n->nredir.n;
4562 p = ")";
4563 goto dotail;
4564 case NWHILE:
4565 p = "while ";
4566 goto until;
4567 case NUNTIL:
4568 p = "until ";
4569 until:
4570 cmdputs(p);
4571 cmdtxt(n->nbinary.ch1);
4572 n = n->nbinary.ch2;
4573 p = "; done";
4574 dodo:
4575 cmdputs("; do ");
4576 dotail:
4577 cmdtxt(n);
4578 goto dotail2;
4579 case NFOR:
4580 cmdputs("for ");
4581 cmdputs(n->nfor.var);
4582 cmdputs(" in ");
4583 cmdlist(n->nfor.args, 1);
4584 n = n->nfor.body;
4585 p = "; done";
4586 goto dodo;
4587 case NDEFUN:
4588 cmdputs(n->narg.text);
4589 p = "() { ... }";
4590 goto dotail2;
4591 case NCMD:
4592 cmdlist(n->ncmd.args, 1);
4593 cmdlist(n->ncmd.redirect, 0);
4594 break;
4595 case NARG:
4596 p = n->narg.text;
4597 dotail2:
4598 cmdputs(p);
4599 break;
4600 case NHERE:
4601 case NXHERE:
4602 p = "<<...";
4603 goto dotail2;
4604 case NCASE:
4605 cmdputs("case ");
4606 cmdputs(n->ncase.expr->narg.text);
4607 cmdputs(" in ");
4608 for (np = n->ncase.cases; np; np = np->nclist.next) {
4609 cmdtxt(np->nclist.pattern);
4610 cmdputs(") ");
4611 cmdtxt(np->nclist.body);
4612 cmdputs(";; ");
4614 p = "esac";
4615 goto dotail2;
4616 case NTO:
4617 p = ">";
4618 goto redir;
4619 case NCLOBBER:
4620 p = ">|";
4621 goto redir;
4622 case NAPPEND:
4623 p = ">>";
4624 goto redir;
4625 #if ENABLE_ASH_BASH_COMPAT
4626 case NTO2:
4627 #endif
4628 case NTOFD:
4629 p = ">&";
4630 goto redir;
4631 case NFROM:
4632 p = "<";
4633 goto redir;
4634 case NFROMFD:
4635 p = "<&";
4636 goto redir;
4637 case NFROMTO:
4638 p = "<>";
4639 redir:
4640 cmdputs(utoa(n->nfile.fd));
4641 cmdputs(p);
4642 if (n->type == NTOFD || n->type == NFROMFD) {
4643 cmdputs(utoa(n->ndup.dupfd));
4644 break;
4646 n = n->nfile.fname;
4647 goto donode;
4651 static char *
4652 commandtext(union node *n)
4654 char *name;
4656 STARTSTACKSTR(cmdnextc);
4657 cmdtxt(n);
4658 name = stackblock();
4659 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4660 name, cmdnextc, cmdnextc));
4661 return ckstrdup(name);
4663 #endif /* JOBS */
4666 * Fork off a subshell. If we are doing job control, give the subshell its
4667 * own process group. Jp is a job structure that the job is to be added to.
4668 * N is the command that will be evaluated by the child. Both jp and n may
4669 * be NULL. The mode parameter can be one of the following:
4670 * FORK_FG - Fork off a foreground process.
4671 * FORK_BG - Fork off a background process.
4672 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4673 * process group even if job control is on.
4675 * When job control is turned off, background processes have their standard
4676 * input redirected to /dev/null (except for the second and later processes
4677 * in a pipeline).
4679 * Called with interrupts off.
4682 * Clear traps on a fork.
4684 static void
4685 clear_traps(void)
4687 char **tp;
4689 for (tp = trap; tp < &trap[NSIG]; tp++) {
4690 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4691 INT_OFF;
4692 if (trap_ptr == trap)
4693 free(*tp);
4694 /* else: it "belongs" to trap_ptr vector, don't free */
4695 *tp = NULL;
4696 if ((tp - trap) != 0)
4697 setsignal(tp - trap);
4698 INT_ON;
4701 may_have_traps = 0;
4704 /* Lives far away from here, needed for forkchild */
4705 static void closescript(void);
4707 /* Called after fork(), in child */
4708 static NOINLINE void
4709 forkchild(struct job *jp, union node *n, int mode)
4711 int oldlvl;
4713 TRACE(("Child shell %d\n", getpid()));
4714 oldlvl = shlvl;
4715 shlvl++;
4717 /* man bash: "Non-builtin commands run by bash have signal handlers
4718 * set to the values inherited by the shell from its parent".
4719 * Do we do it correctly? */
4721 closescript();
4723 if (mode == FORK_NOJOB /* is it `xxx` ? */
4724 && n && n->type == NCMD /* is it single cmd? */
4725 /* && n->ncmd.args->type == NARG - always true? */
4726 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
4727 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4728 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4730 TRACE(("Trap hack\n"));
4731 /* Awful hack for `trap` or $(trap).
4733 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4734 * contains an example where "trap" is executed in a subshell:
4736 * save_traps=$(trap)
4737 * ...
4738 * eval "$save_traps"
4740 * Standard does not say that "trap" in subshell shall print
4741 * parent shell's traps. It only says that its output
4742 * must have suitable form, but then, in the above example
4743 * (which is not supposed to be normative), it implies that.
4745 * bash (and probably other shell) does implement it
4746 * (traps are reset to defaults, but "trap" still shows them),
4747 * but as a result, "trap" logic is hopelessly messed up:
4749 * # trap
4750 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4751 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4752 * # true | trap <--- trap is in subshell - no output (ditto)
4753 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4754 * trap -- 'echo Ho' SIGWINCH
4755 * # echo `(trap)` <--- in subshell in subshell - output
4756 * trap -- 'echo Ho' SIGWINCH
4757 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4758 * trap -- 'echo Ho' SIGWINCH
4760 * The rules when to forget and when to not forget traps
4761 * get really complex and nonsensical.
4763 * Our solution: ONLY bare $(trap) or `trap` is special.
4765 /* Save trap handler strings for trap builtin to print */
4766 trap_ptr = memcpy(xmalloc(sizeof(trap)), trap, sizeof(trap));
4767 /* Fall through into clearing traps */
4769 clear_traps();
4770 #if JOBS
4771 /* do job control only in root shell */
4772 doing_jobctl = 0;
4773 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
4774 pid_t pgrp;
4776 if (jp->nprocs == 0)
4777 pgrp = getpid();
4778 else
4779 pgrp = jp->ps[0].ps_pid;
4780 /* this can fail because we are doing it in the parent also */
4781 setpgid(0, pgrp);
4782 if (mode == FORK_FG)
4783 xtcsetpgrp(ttyfd, pgrp);
4784 setsignal(SIGTSTP);
4785 setsignal(SIGTTOU);
4786 } else
4787 #endif
4788 if (mode == FORK_BG) {
4789 /* man bash: "When job control is not in effect,
4790 * asynchronous commands ignore SIGINT and SIGQUIT" */
4791 ignoresig(SIGINT);
4792 ignoresig(SIGQUIT);
4793 if (jp->nprocs == 0) {
4794 close(0);
4795 if (open(bb_dev_null, O_RDONLY) != 0)
4796 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
4799 if (oldlvl == 0) {
4800 if (iflag) { /* why if iflag only? */
4801 setsignal(SIGINT);
4802 setsignal(SIGTERM);
4804 /* man bash:
4805 * "In all cases, bash ignores SIGQUIT. Non-builtin
4806 * commands run by bash have signal handlers
4807 * set to the values inherited by the shell
4808 * from its parent".
4809 * Take care of the second rule: */
4810 setsignal(SIGQUIT);
4812 #if JOBS
4813 if (n && n->type == NCMD
4814 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
4816 TRACE(("Job hack\n"));
4817 /* "jobs": we do not want to clear job list for it,
4818 * instead we remove only _its_ own_ job from job list.
4819 * This makes "jobs .... | cat" more useful.
4821 freejob(curjob);
4822 return;
4824 #endif
4825 for (jp = curjob; jp; jp = jp->prev_job)
4826 freejob(jp);
4827 jobless = 0;
4830 /* Called after fork(), in parent */
4831 #if !JOBS
4832 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4833 #endif
4834 static void
4835 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4837 TRACE(("In parent shell: child = %d\n", pid));
4838 if (!jp) {
4839 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4840 continue;
4841 jobless++;
4842 return;
4844 #if JOBS
4845 if (mode != FORK_NOJOB && jp->jobctl) {
4846 int pgrp;
4848 if (jp->nprocs == 0)
4849 pgrp = pid;
4850 else
4851 pgrp = jp->ps[0].ps_pid;
4852 /* This can fail because we are doing it in the child also */
4853 setpgid(pid, pgrp);
4855 #endif
4856 if (mode == FORK_BG) {
4857 backgndpid = pid; /* set $! */
4858 set_curjob(jp, CUR_RUNNING);
4860 if (jp) {
4861 struct procstat *ps = &jp->ps[jp->nprocs++];
4862 ps->ps_pid = pid;
4863 ps->ps_status = -1;
4864 ps->ps_cmd = nullstr;
4865 #if JOBS
4866 if (doing_jobctl && n)
4867 ps->ps_cmd = commandtext(n);
4868 #endif
4872 static int
4873 forkshell(struct job *jp, union node *n, int mode)
4875 int pid;
4877 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4878 pid = fork();
4879 if (pid < 0) {
4880 TRACE(("Fork failed, errno=%d", errno));
4881 if (jp)
4882 freejob(jp);
4883 ash_msg_and_raise_error("can't fork");
4885 if (pid == 0) {
4886 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
4887 forkchild(jp, n, mode);
4888 } else {
4889 forkparent(jp, n, mode, pid);
4891 return pid;
4895 * Wait for job to finish.
4897 * Under job control we have the problem that while a child process
4898 * is running interrupts generated by the user are sent to the child
4899 * but not to the shell. This means that an infinite loop started by
4900 * an interactive user may be hard to kill. With job control turned off,
4901 * an interactive user may place an interactive program inside a loop.
4902 * If the interactive program catches interrupts, the user doesn't want
4903 * these interrupts to also abort the loop. The approach we take here
4904 * is to have the shell ignore interrupt signals while waiting for a
4905 * foreground process to terminate, and then send itself an interrupt
4906 * signal if the child process was terminated by an interrupt signal.
4907 * Unfortunately, some programs want to do a bit of cleanup and then
4908 * exit on interrupt; unless these processes terminate themselves by
4909 * sending a signal to themselves (instead of calling exit) they will
4910 * confuse this approach.
4912 * Called with interrupts off.
4914 static int
4915 waitforjob(struct job *jp)
4917 int st;
4919 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4921 INT_OFF;
4922 while (jp->state == JOBRUNNING) {
4923 /* In non-interactive shells, we _can_ get
4924 * a keyboard signal here and be EINTRed,
4925 * but we just loop back, waiting for command to complete.
4927 * man bash:
4928 * "If bash is waiting for a command to complete and receives
4929 * a signal for which a trap has been set, the trap
4930 * will not be executed until the command completes."
4932 * Reality is that even if trap is not set, bash
4933 * will not act on the signal until command completes.
4934 * Try this. sleep5intoff.c:
4935 * #include <signal.h>
4936 * #include <unistd.h>
4937 * int main() {
4938 * sigset_t set;
4939 * sigemptyset(&set);
4940 * sigaddset(&set, SIGINT);
4941 * sigaddset(&set, SIGQUIT);
4942 * sigprocmask(SIG_BLOCK, &set, NULL);
4943 * sleep(5);
4944 * return 0;
4946 * $ bash -c './sleep5intoff; echo hi'
4947 * ^C^C^C^C <--- pressing ^C once a second
4948 * $ _
4949 * $ bash -c './sleep5intoff; echo hi'
4950 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4951 * $ _
4953 dowait(DOWAIT_BLOCK, jp);
4955 INT_ON;
4957 st = getstatus(jp);
4958 #if JOBS
4959 if (jp->jobctl) {
4960 xtcsetpgrp(ttyfd, rootpid);
4962 * This is truly gross.
4963 * If we're doing job control, then we did a TIOCSPGRP which
4964 * caused us (the shell) to no longer be in the controlling
4965 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4966 * intuit from the subprocess exit status whether a SIGINT
4967 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4969 if (jp->sigint) /* TODO: do the same with all signals */
4970 raise(SIGINT); /* ... by raise(jp->sig) instead? */
4972 if (jp->state == JOBDONE)
4973 #endif
4974 freejob(jp);
4975 return st;
4979 * return 1 if there are stopped jobs, otherwise 0
4981 static int
4982 stoppedjobs(void)
4984 struct job *jp;
4985 int retval;
4987 retval = 0;
4988 if (job_warning)
4989 goto out;
4990 jp = curjob;
4991 if (jp && jp->state == JOBSTOPPED) {
4992 out2str("You have stopped jobs.\n");
4993 job_warning = 2;
4994 retval++;
4996 out:
4997 return retval;
5001 /* ============ redir.c
5003 * Code for dealing with input/output redirection.
5006 #undef EMPTY
5007 #undef CLOSED
5008 #define EMPTY -2 /* marks an unused slot in redirtab */
5009 #define CLOSED -3 /* marks a slot of previously-closed fd */
5012 * Open a file in noclobber mode.
5013 * The code was copied from bash.
5015 static int
5016 noclobberopen(const char *fname)
5018 int r, fd;
5019 struct stat finfo, finfo2;
5022 * If the file exists and is a regular file, return an error
5023 * immediately.
5025 r = stat(fname, &finfo);
5026 if (r == 0 && S_ISREG(finfo.st_mode)) {
5027 errno = EEXIST;
5028 return -1;
5032 * If the file was not present (r != 0), make sure we open it
5033 * exclusively so that if it is created before we open it, our open
5034 * will fail. Make sure that we do not truncate an existing file.
5035 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5036 * file was not a regular file, we leave O_EXCL off.
5038 if (r != 0)
5039 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5040 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5042 /* If the open failed, return the file descriptor right away. */
5043 if (fd < 0)
5044 return fd;
5047 * OK, the open succeeded, but the file may have been changed from a
5048 * non-regular file to a regular file between the stat and the open.
5049 * We are assuming that the O_EXCL open handles the case where FILENAME
5050 * did not exist and is symlinked to an existing file between the stat
5051 * and open.
5055 * If we can open it and fstat the file descriptor, and neither check
5056 * revealed that it was a regular file, and the file has not been
5057 * replaced, return the file descriptor.
5059 if (fstat(fd, &finfo2) == 0
5060 && !S_ISREG(finfo2.st_mode)
5061 && finfo.st_dev == finfo2.st_dev
5062 && finfo.st_ino == finfo2.st_ino
5064 return fd;
5067 /* The file has been replaced. badness. */
5068 close(fd);
5069 errno = EEXIST;
5070 return -1;
5074 * Handle here documents. Normally we fork off a process to write the
5075 * data to a pipe. If the document is short, we can stuff the data in
5076 * the pipe without forking.
5078 /* openhere needs this forward reference */
5079 static void expandhere(union node *arg, int fd);
5080 static int
5081 openhere(union node *redir)
5083 int pip[2];
5084 size_t len = 0;
5086 if (pipe(pip) < 0)
5087 ash_msg_and_raise_error("pipe call failed");
5088 if (redir->type == NHERE) {
5089 len = strlen(redir->nhere.doc->narg.text);
5090 if (len <= PIPE_BUF) {
5091 full_write(pip[1], redir->nhere.doc->narg.text, len);
5092 goto out;
5095 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5096 /* child */
5097 close(pip[0]);
5098 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5099 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5100 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5101 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5102 signal(SIGPIPE, SIG_DFL);
5103 if (redir->type == NHERE)
5104 full_write(pip[1], redir->nhere.doc->narg.text, len);
5105 else /* NXHERE */
5106 expandhere(redir->nhere.doc, pip[1]);
5107 _exit(EXIT_SUCCESS);
5109 out:
5110 close(pip[1]);
5111 return pip[0];
5114 static int
5115 openredirect(union node *redir)
5117 char *fname;
5118 int f;
5120 fname = redir->nfile.expfname;
5121 switch (redir->nfile.type) {
5122 case NFROM:
5123 f = open(fname, O_RDONLY);
5124 if (f < 0)
5125 goto eopen;
5126 break;
5127 case NFROMTO:
5128 f = open(fname, O_RDWR|O_CREAT, 0666);
5129 if (f < 0)
5130 goto ecreate;
5131 break;
5132 case NTO:
5133 #if ENABLE_ASH_BASH_COMPAT
5134 case NTO2:
5135 #endif
5136 /* Take care of noclobber mode. */
5137 if (Cflag) {
5138 f = noclobberopen(fname);
5139 if (f < 0)
5140 goto ecreate;
5141 break;
5143 /* FALLTHROUGH */
5144 case NCLOBBER:
5145 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5146 if (f < 0)
5147 goto ecreate;
5148 break;
5149 case NAPPEND:
5150 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5151 if (f < 0)
5152 goto ecreate;
5153 break;
5154 default:
5155 #if DEBUG
5156 abort();
5157 #endif
5158 /* Fall through to eliminate warning. */
5159 /* Our single caller does this itself */
5160 // case NTOFD:
5161 // case NFROMFD:
5162 // f = -1;
5163 // break;
5164 case NHERE:
5165 case NXHERE:
5166 f = openhere(redir);
5167 break;
5170 return f;
5171 ecreate:
5172 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5173 eopen:
5174 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5178 * Copy a file descriptor to be >= to. Returns -1
5179 * if the source file descriptor is closed, EMPTY if there are no unused
5180 * file descriptors left.
5182 /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5183 * old code was doing close(to) prior to copyfd() to achieve the same */
5184 enum {
5185 COPYFD_EXACT = (int)~(INT_MAX),
5186 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5188 static int
5189 copyfd(int from, int to)
5191 int newfd;
5193 if (to & COPYFD_EXACT) {
5194 to &= ~COPYFD_EXACT;
5195 /*if (from != to)*/
5196 newfd = dup2(from, to);
5197 } else {
5198 newfd = fcntl(from, F_DUPFD, to);
5200 if (newfd < 0) {
5201 if (errno == EMFILE)
5202 return EMPTY;
5203 /* Happens when source fd is not open: try "echo >&99" */
5204 ash_msg_and_raise_error("%d: %m", from);
5206 return newfd;
5209 /* Struct def and variable are moved down to the first usage site */
5210 struct two_fd_t {
5211 int orig, copy;
5213 struct redirtab {
5214 struct redirtab *next;
5215 int nullredirs;
5216 int pair_count;
5217 struct two_fd_t two_fd[];
5219 #define redirlist (G_var.redirlist)
5221 static int need_to_remember(struct redirtab *rp, int fd)
5223 int i;
5225 if (!rp) /* remembering was not requested */
5226 return 0;
5228 for (i = 0; i < rp->pair_count; i++) {
5229 if (rp->two_fd[i].orig == fd) {
5230 /* already remembered */
5231 return 0;
5234 return 1;
5237 /* "hidden" fd is a fd used to read scripts, or a copy of such */
5238 static int is_hidden_fd(struct redirtab *rp, int fd)
5240 int i;
5241 struct parsefile *pf;
5243 if (fd == -1)
5244 return 0;
5245 /* Check open scripts' fds */
5246 pf = g_parsefile;
5247 while (pf) {
5248 /* We skip pf_fd == 0 case because of the following case:
5249 * $ ash # running ash interactively
5250 * $ . ./script.sh
5251 * and in script.sh: "exec 9>&0".
5252 * Even though top-level pf_fd _is_ 0,
5253 * it's still ok to use it: "read" builtin uses it,
5254 * why should we cripple "exec" builtin?
5256 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
5257 return 1;
5259 pf = pf->prev;
5262 if (!rp)
5263 return 0;
5264 /* Check saved fds of redirects */
5265 fd |= COPYFD_RESTORE;
5266 for (i = 0; i < rp->pair_count; i++) {
5267 if (rp->two_fd[i].copy == fd) {
5268 return 1;
5271 return 0;
5275 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5276 * old file descriptors are stashed away so that the redirection can be
5277 * undone by calling popredir.
5279 /* flags passed to redirect */
5280 #define REDIR_PUSH 01 /* save previous values of file descriptors */
5281 #define REDIR_SAVEFD2 03 /* set preverrout */
5282 static void
5283 redirect(union node *redir, int flags)
5285 struct redirtab *sv;
5286 int sv_pos;
5287 int i;
5288 int fd;
5289 int newfd;
5290 int copied_fd2 = -1;
5292 g_nullredirs++;
5293 if (!redir) {
5294 return;
5297 sv = NULL;
5298 sv_pos = 0;
5299 INT_OFF;
5300 if (flags & REDIR_PUSH) {
5301 union node *tmp = redir;
5302 do {
5303 sv_pos++;
5304 #if ENABLE_ASH_BASH_COMPAT
5305 if (tmp->nfile.type == NTO2)
5306 sv_pos++;
5307 #endif
5308 tmp = tmp->nfile.next;
5309 } while (tmp);
5310 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
5311 sv->next = redirlist;
5312 sv->pair_count = sv_pos;
5313 redirlist = sv;
5314 sv->nullredirs = g_nullredirs - 1;
5315 g_nullredirs = 0;
5316 while (sv_pos > 0) {
5317 sv_pos--;
5318 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5322 do {
5323 int right_fd = -1;
5324 fd = redir->nfile.fd;
5325 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5326 right_fd = redir->ndup.dupfd;
5327 //bb_error_msg("doing %d > %d", fd, right_fd);
5328 /* redirect from/to same file descriptor? */
5329 if (right_fd == fd)
5330 continue;
5331 /* "echo >&10" and 10 is a fd opened to a sh script? */
5332 if (is_hidden_fd(sv, right_fd)) {
5333 errno = EBADF; /* as if it is closed */
5334 ash_msg_and_raise_error("%d: %m", right_fd);
5336 newfd = -1;
5337 } else {
5338 newfd = openredirect(redir); /* always >= 0 */
5339 if (fd == newfd) {
5340 /* Descriptor wasn't open before redirect.
5341 * Mark it for close in the future */
5342 if (need_to_remember(sv, fd)) {
5343 goto remember_to_close;
5345 continue;
5348 #if ENABLE_ASH_BASH_COMPAT
5349 redirect_more:
5350 #endif
5351 if (need_to_remember(sv, fd)) {
5352 /* Copy old descriptor */
5353 /* Careful to not accidentally "save"
5354 * to the same fd as right side fd in N>&M */
5355 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5356 i = fcntl(fd, F_DUPFD, minfd);
5357 /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5358 * are closed in popredir() in the child, preventing them from leaking
5359 * into child. (popredir() also cleans up the mess in case of failures)
5361 if (i == -1) {
5362 i = errno;
5363 if (i != EBADF) {
5364 /* Strange error (e.g. "too many files" EMFILE?) */
5365 if (newfd >= 0)
5366 close(newfd);
5367 errno = i;
5368 ash_msg_and_raise_error("%d: %m", fd);
5369 /* NOTREACHED */
5371 /* EBADF: it is not open - good, remember to close it */
5372 remember_to_close:
5373 i = CLOSED;
5374 } else { /* fd is open, save its copy */
5375 /* "exec fd>&-" should not close fds
5376 * which point to script file(s).
5377 * Force them to be restored afterwards */
5378 if (is_hidden_fd(sv, fd))
5379 i |= COPYFD_RESTORE;
5381 if (fd == 2)
5382 copied_fd2 = i;
5383 sv->two_fd[sv_pos].orig = fd;
5384 sv->two_fd[sv_pos].copy = i;
5385 sv_pos++;
5387 if (newfd < 0) {
5388 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5389 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5390 /* Don't want to trigger debugging */
5391 if (fd != -1)
5392 close(fd);
5393 } else {
5394 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
5396 } else if (fd != newfd) { /* move newfd to fd */
5397 copyfd(newfd, fd | COPYFD_EXACT);
5398 #if ENABLE_ASH_BASH_COMPAT
5399 if (!(redir->nfile.type == NTO2 && fd == 2))
5400 #endif
5401 close(newfd);
5403 #if ENABLE_ASH_BASH_COMPAT
5404 if (redir->nfile.type == NTO2 && fd == 1) {
5405 /* We already redirected it to fd 1, now copy it to 2 */
5406 newfd = 1;
5407 fd = 2;
5408 goto redirect_more;
5410 #endif
5411 } while ((redir = redir->nfile.next) != NULL);
5413 INT_ON;
5414 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5415 preverrout_fd = copied_fd2;
5419 * Undo the effects of the last redirection.
5421 static void
5422 popredir(int drop, int restore)
5424 struct redirtab *rp;
5425 int i;
5427 if (--g_nullredirs >= 0)
5428 return;
5429 INT_OFF;
5430 rp = redirlist;
5431 for (i = 0; i < rp->pair_count; i++) {
5432 int fd = rp->two_fd[i].orig;
5433 int copy = rp->two_fd[i].copy;
5434 if (copy == CLOSED) {
5435 if (!drop)
5436 close(fd);
5437 continue;
5439 if (copy != EMPTY) {
5440 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5441 copy &= ~COPYFD_RESTORE;
5442 /*close(fd);*/
5443 copyfd(copy, fd | COPYFD_EXACT);
5445 close(copy & ~COPYFD_RESTORE);
5448 redirlist = rp->next;
5449 g_nullredirs = rp->nullredirs;
5450 free(rp);
5451 INT_ON;
5455 * Undo all redirections. Called on error or interrupt.
5459 * Discard all saved file descriptors.
5461 static void
5462 clearredir(int drop)
5464 for (;;) {
5465 g_nullredirs = 0;
5466 if (!redirlist)
5467 break;
5468 popredir(drop, /*restore:*/ 0);
5472 static int
5473 redirectsafe(union node *redir, int flags)
5475 int err;
5476 volatile int saveint;
5477 struct jmploc *volatile savehandler = exception_handler;
5478 struct jmploc jmploc;
5480 SAVE_INT(saveint);
5481 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5482 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5483 if (!err) {
5484 exception_handler = &jmploc;
5485 redirect(redir, flags);
5487 exception_handler = savehandler;
5488 if (err && exception_type != EXERROR)
5489 longjmp(exception_handler->loc, 1);
5490 RESTORE_INT(saveint);
5491 return err;
5495 /* ============ Routines to expand arguments to commands
5497 * We have to deal with backquotes, shell variables, and file metacharacters.
5500 #if ENABLE_SH_MATH_SUPPORT
5501 static arith_t
5502 ash_arith(const char *s)
5504 arith_state_t math_state;
5505 arith_t result;
5507 math_state.lookupvar = lookupvar;
5508 math_state.setvar = setvar2;
5509 //math_state.endofname = endofname;
5511 INT_OFF;
5512 result = arith(&math_state, s);
5513 if (math_state.errmsg)
5514 ash_msg_and_raise_error(math_state.errmsg);
5515 INT_ON;
5517 return result;
5519 #endif
5522 * expandarg flags
5524 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5525 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5526 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5527 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5528 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5529 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5530 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5531 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5532 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5534 * rmescape() flags
5536 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5537 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5538 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5539 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5540 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5543 * Structure specifying which parts of the string should be searched
5544 * for IFS characters.
5546 struct ifsregion {
5547 struct ifsregion *next; /* next region in list */
5548 int begoff; /* offset of start of region */
5549 int endoff; /* offset of end of region */
5550 int nulonly; /* search for nul bytes only */
5553 struct arglist {
5554 struct strlist *list;
5555 struct strlist **lastp;
5558 /* output of current string */
5559 static char *expdest;
5560 /* list of back quote expressions */
5561 static struct nodelist *argbackq;
5562 /* first struct in list of ifs regions */
5563 static struct ifsregion ifsfirst;
5564 /* last struct in list */
5565 static struct ifsregion *ifslastp;
5566 /* holds expanded arg list */
5567 static struct arglist exparg;
5570 * Our own itoa().
5572 #if !ENABLE_SH_MATH_SUPPORT
5573 /* cvtnum() is used even if math support is off (to prepare $? values and such) */
5574 typedef long arith_t;
5575 # define ARITH_FMT "%ld"
5576 #endif
5577 static int
5578 cvtnum(arith_t num)
5580 int len;
5582 expdest = makestrspace(32, expdest);
5583 len = fmtstr(expdest, 32, ARITH_FMT, num);
5584 STADJUST(len, expdest);
5585 return len;
5588 static size_t
5589 esclen(const char *start, const char *p)
5591 size_t esc = 0;
5593 while (p > start && (unsigned char)*--p == CTLESC) {
5594 esc++;
5596 return esc;
5600 * Remove any CTLESC characters from a string.
5602 static char *
5603 rmescapes(char *str, int flag)
5605 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
5607 char *p, *q, *r;
5608 unsigned inquotes;
5609 unsigned protect_against_glob;
5610 unsigned globbing;
5612 p = strpbrk(str, qchars);
5613 if (!p)
5614 return str;
5616 q = p;
5617 r = str;
5618 if (flag & RMESCAPE_ALLOC) {
5619 size_t len = p - str;
5620 size_t fulllen = len + strlen(p) + 1;
5622 if (flag & RMESCAPE_GROW) {
5623 int strloc = str - (char *)stackblock();
5624 r = makestrspace(fulllen, expdest);
5625 /* p and str may be invalidated by makestrspace */
5626 str = (char *)stackblock() + strloc;
5627 p = str + len;
5628 } else if (flag & RMESCAPE_HEAP) {
5629 r = ckmalloc(fulllen);
5630 } else {
5631 r = stalloc(fulllen);
5633 q = r;
5634 if (len > 0) {
5635 q = (char *)memcpy(q, str, len) + len;
5639 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5640 globbing = flag & RMESCAPE_GLOB;
5641 protect_against_glob = globbing;
5642 while (*p) {
5643 if ((unsigned char)*p == CTLQUOTEMARK) {
5644 // TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0
5645 // (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok?
5646 // Note: both inquotes and protect_against_glob only affect whether
5647 // CTLESC,<ch> gets converted to <ch> or to \<ch>
5648 inquotes = ~inquotes;
5649 p++;
5650 protect_against_glob = globbing;
5651 continue;
5653 if (*p == '\\') {
5654 /* naked back slash */
5655 protect_against_glob = 0;
5656 goto copy;
5658 if ((unsigned char)*p == CTLESC) {
5659 p++;
5660 if (protect_against_glob && inquotes && *p != '/') {
5661 *q++ = '\\';
5664 protect_against_glob = globbing;
5665 copy:
5666 *q++ = *p++;
5668 *q = '\0';
5669 if (flag & RMESCAPE_GROW) {
5670 expdest = r;
5671 STADJUST(q - r + 1, expdest);
5673 return r;
5675 #define pmatch(a, b) !fnmatch((a), (b), 0)
5678 * Prepare a pattern for a expmeta (internal glob(3)) call.
5680 * Returns an stalloced string.
5682 static char *
5683 preglob(const char *pattern, int quoted, int flag)
5685 flag |= RMESCAPE_GLOB;
5686 if (quoted) {
5687 flag |= RMESCAPE_QUOTED;
5689 return rmescapes((char *)pattern, flag);
5693 * Put a string on the stack.
5695 static void
5696 memtodest(const char *p, size_t len, int syntax, int quotes)
5698 char *q = expdest;
5700 q = makestrspace(quotes ? len * 2 : len, q);
5702 while (len--) {
5703 unsigned char c = *p++;
5704 if (c == '\0')
5705 continue;
5706 if (quotes) {
5707 int n = SIT(c, syntax);
5708 if (n == CCTL || n == CBACK)
5709 USTPUTC(CTLESC, q);
5711 USTPUTC(c, q);
5714 expdest = q;
5717 static void
5718 strtodest(const char *p, int syntax, int quotes)
5720 memtodest(p, strlen(p), syntax, quotes);
5724 * Record the fact that we have to scan this region of the
5725 * string for IFS characters.
5727 static void
5728 recordregion(int start, int end, int nulonly)
5730 struct ifsregion *ifsp;
5732 if (ifslastp == NULL) {
5733 ifsp = &ifsfirst;
5734 } else {
5735 INT_OFF;
5736 ifsp = ckzalloc(sizeof(*ifsp));
5737 /*ifsp->next = NULL; - ckzalloc did it */
5738 ifslastp->next = ifsp;
5739 INT_ON;
5741 ifslastp = ifsp;
5742 ifslastp->begoff = start;
5743 ifslastp->endoff = end;
5744 ifslastp->nulonly = nulonly;
5747 static void
5748 removerecordregions(int endoff)
5750 if (ifslastp == NULL)
5751 return;
5753 if (ifsfirst.endoff > endoff) {
5754 while (ifsfirst.next) {
5755 struct ifsregion *ifsp;
5756 INT_OFF;
5757 ifsp = ifsfirst.next->next;
5758 free(ifsfirst.next);
5759 ifsfirst.next = ifsp;
5760 INT_ON;
5762 if (ifsfirst.begoff > endoff) {
5763 ifslastp = NULL;
5764 } else {
5765 ifslastp = &ifsfirst;
5766 ifsfirst.endoff = endoff;
5768 return;
5771 ifslastp = &ifsfirst;
5772 while (ifslastp->next && ifslastp->next->begoff < endoff)
5773 ifslastp = ifslastp->next;
5774 while (ifslastp->next) {
5775 struct ifsregion *ifsp;
5776 INT_OFF;
5777 ifsp = ifslastp->next->next;
5778 free(ifslastp->next);
5779 ifslastp->next = ifsp;
5780 INT_ON;
5782 if (ifslastp->endoff > endoff)
5783 ifslastp->endoff = endoff;
5786 static char *
5787 exptilde(char *startp, char *p, int flags)
5789 unsigned char c;
5790 char *name;
5791 struct passwd *pw;
5792 const char *home;
5793 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
5794 int startloc;
5796 name = p + 1;
5798 while ((c = *++p) != '\0') {
5799 switch (c) {
5800 case CTLESC:
5801 return startp;
5802 case CTLQUOTEMARK:
5803 return startp;
5804 case ':':
5805 if (flags & EXP_VARTILDE)
5806 goto done;
5807 break;
5808 case '/':
5809 case CTLENDVAR:
5810 goto done;
5813 done:
5814 *p = '\0';
5815 if (*name == '\0') {
5816 home = lookupvar("HOME");
5817 } else {
5818 pw = getpwnam(name);
5819 if (pw == NULL)
5820 goto lose;
5821 home = pw->pw_dir;
5823 if (!home || !*home)
5824 goto lose;
5825 *p = c;
5826 startloc = expdest - (char *)stackblock();
5827 strtodest(home, SQSYNTAX, quotes);
5828 recordregion(startloc, expdest - (char *)stackblock(), 0);
5829 return p;
5830 lose:
5831 *p = c;
5832 return startp;
5836 * Execute a command inside back quotes. If it's a builtin command, we
5837 * want to save its output in a block obtained from malloc. Otherwise
5838 * we fork off a subprocess and get the output of the command via a pipe.
5839 * Should be called with interrupts off.
5841 struct backcmd { /* result of evalbackcmd */
5842 int fd; /* file descriptor to read from */
5843 int nleft; /* number of chars in buffer */
5844 char *buf; /* buffer */
5845 struct job *jp; /* job structure for command */
5848 /* These forward decls are needed to use "eval" code for backticks handling: */
5849 static uint8_t back_exitstatus; /* exit status of backquoted command */
5850 #define EV_EXIT 01 /* exit after evaluating tree */
5851 static void evaltree(union node *, int);
5853 static void FAST_FUNC
5854 evalbackcmd(union node *n, struct backcmd *result)
5856 int saveherefd;
5858 result->fd = -1;
5859 result->buf = NULL;
5860 result->nleft = 0;
5861 result->jp = NULL;
5862 if (n == NULL)
5863 goto out;
5865 saveherefd = herefd;
5866 herefd = -1;
5869 int pip[2];
5870 struct job *jp;
5872 if (pipe(pip) < 0)
5873 ash_msg_and_raise_error("pipe call failed");
5874 jp = makejob(/*n,*/ 1);
5875 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5876 FORCE_INT_ON;
5877 close(pip[0]);
5878 if (pip[1] != 1) {
5879 /*close(1);*/
5880 copyfd(pip[1], 1 | COPYFD_EXACT);
5881 close(pip[1]);
5883 eflag = 0;
5884 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5885 /* NOTREACHED */
5887 close(pip[1]);
5888 result->fd = pip[0];
5889 result->jp = jp;
5891 herefd = saveherefd;
5892 out:
5893 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5894 result->fd, result->buf, result->nleft, result->jp));
5898 * Expand stuff in backwards quotes.
5900 static void
5901 expbackq(union node *cmd, int quoted, int quotes)
5903 struct backcmd in;
5904 int i;
5905 char buf[128];
5906 char *p;
5907 char *dest;
5908 int startloc;
5909 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
5910 struct stackmark smark;
5912 INT_OFF;
5913 setstackmark(&smark);
5914 dest = expdest;
5915 startloc = dest - (char *)stackblock();
5916 grabstackstr(dest);
5917 evalbackcmd(cmd, &in);
5918 popstackmark(&smark);
5920 p = in.buf;
5921 i = in.nleft;
5922 if (i == 0)
5923 goto read;
5924 for (;;) {
5925 memtodest(p, i, syntax, quotes);
5926 read:
5927 if (in.fd < 0)
5928 break;
5929 i = nonblock_immune_read(in.fd, buf, sizeof(buf), /*loop_on_EINTR:*/ 1);
5930 TRACE(("expbackq: read returns %d\n", i));
5931 if (i <= 0)
5932 break;
5933 p = buf;
5936 free(in.buf);
5937 if (in.fd >= 0) {
5938 close(in.fd);
5939 back_exitstatus = waitforjob(in.jp);
5941 INT_ON;
5943 /* Eat all trailing newlines */
5944 dest = expdest;
5945 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5946 STUNPUTC(dest);
5947 expdest = dest;
5949 if (quoted == 0)
5950 recordregion(startloc, dest - (char *)stackblock(), 0);
5951 TRACE(("evalbackq: size:%d:'%.*s'\n",
5952 (int)((dest - (char *)stackblock()) - startloc),
5953 (int)((dest - (char *)stackblock()) - startloc),
5954 stackblock() + startloc));
5957 #if ENABLE_SH_MATH_SUPPORT
5959 * Expand arithmetic expression. Backup to start of expression,
5960 * evaluate, place result in (backed up) result, adjust string position.
5962 static void
5963 expari(int quotes)
5965 char *p, *start;
5966 int begoff;
5967 int flag;
5968 int len;
5970 /* ifsfree(); */
5973 * This routine is slightly over-complicated for
5974 * efficiency. Next we scan backwards looking for the
5975 * start of arithmetic.
5977 start = stackblock();
5978 p = expdest - 1;
5979 *p = '\0';
5980 p--;
5981 while (1) {
5982 int esc;
5984 while ((unsigned char)*p != CTLARI) {
5985 p--;
5986 #if DEBUG
5987 if (p < start) {
5988 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5990 #endif
5993 esc = esclen(start, p);
5994 if (!(esc % 2)) {
5995 break;
5998 p -= esc + 1;
6001 begoff = p - start;
6003 removerecordregions(begoff);
6005 flag = p[1];
6007 expdest = p;
6009 if (quotes)
6010 rmescapes(p + 2, 0);
6012 len = cvtnum(ash_arith(p + 2));
6014 if (flag != '"')
6015 recordregion(begoff, begoff + len, 0);
6017 #endif
6019 /* argstr needs it */
6020 static char *evalvar(char *p, int flags, struct strlist *var_str_list);
6023 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6024 * characters to allow for further processing. Otherwise treat
6025 * $@ like $* since no splitting will be performed.
6027 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6028 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6029 * for correct expansion of "B=$A" word.
6031 static void
6032 argstr(char *p, int flags, struct strlist *var_str_list)
6034 static const char spclchars[] ALIGN1 = {
6035 '=',
6036 ':',
6037 CTLQUOTEMARK,
6038 CTLENDVAR,
6039 CTLESC,
6040 CTLVAR,
6041 CTLBACKQ,
6042 CTLBACKQ | CTLQUOTE,
6043 #if ENABLE_SH_MATH_SUPPORT
6044 CTLENDARI,
6045 #endif
6046 '\0'
6048 const char *reject = spclchars;
6049 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
6050 int breakall = flags & EXP_WORD;
6051 int inquotes;
6052 size_t length;
6053 int startloc;
6055 if (!(flags & EXP_VARTILDE)) {
6056 reject += 2;
6057 } else if (flags & EXP_VARTILDE2) {
6058 reject++;
6060 inquotes = 0;
6061 length = 0;
6062 if (flags & EXP_TILDE) {
6063 char *q;
6065 flags &= ~EXP_TILDE;
6066 tilde:
6067 q = p;
6068 if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD))
6069 q++;
6070 if (*q == '~')
6071 p = exptilde(p, q, flags);
6073 start:
6074 startloc = expdest - (char *)stackblock();
6075 for (;;) {
6076 unsigned char c;
6078 length += strcspn(p + length, reject);
6079 c = p[length];
6080 if (c) {
6081 if (!(c & 0x80)
6082 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
6084 /* c == '=' || c == ':' || c == CTLENDARI */
6085 length++;
6088 if (length > 0) {
6089 int newloc;
6090 expdest = stack_nputstr(p, length, expdest);
6091 newloc = expdest - (char *)stackblock();
6092 if (breakall && !inquotes && newloc > startloc) {
6093 recordregion(startloc, newloc, 0);
6095 startloc = newloc;
6097 p += length + 1;
6098 length = 0;
6100 switch (c) {
6101 case '\0':
6102 goto breakloop;
6103 case '=':
6104 if (flags & EXP_VARTILDE2) {
6105 p--;
6106 continue;
6108 flags |= EXP_VARTILDE2;
6109 reject++;
6110 /* fall through */
6111 case ':':
6113 * sort of a hack - expand tildes in variable
6114 * assignments (after the first '=' and after ':'s).
6116 if (*--p == '~') {
6117 goto tilde;
6119 continue;
6122 switch (c) {
6123 case CTLENDVAR: /* ??? */
6124 goto breakloop;
6125 case CTLQUOTEMARK:
6126 /* "$@" syntax adherence hack */
6127 if (!inquotes
6128 && memcmp(p, dolatstr, 4) == 0
6129 && ( p[4] == (char)CTLQUOTEMARK
6130 || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK)
6133 p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1;
6134 goto start;
6136 inquotes = !inquotes;
6137 addquote:
6138 if (quotes) {
6139 p--;
6140 length++;
6141 startloc++;
6143 break;
6144 case CTLESC:
6145 startloc++;
6146 length++;
6147 goto addquote;
6148 case CTLVAR:
6149 TRACE(("argstr: evalvar('%s')\n", p));
6150 p = evalvar(p, flags, var_str_list);
6151 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6152 goto start;
6153 case CTLBACKQ:
6154 c = '\0';
6155 case CTLBACKQ|CTLQUOTE:
6156 expbackq(argbackq->n, c, quotes);
6157 argbackq = argbackq->next;
6158 goto start;
6159 #if ENABLE_SH_MATH_SUPPORT
6160 case CTLENDARI:
6161 p--;
6162 expari(quotes);
6163 goto start;
6164 #endif
6167 breakloop: ;
6170 static char *
6171 scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6172 char *pattern, int quotes, int zero)
6174 char *loc, *loc2;
6175 char c;
6177 loc = startp;
6178 loc2 = rmesc;
6179 do {
6180 int match;
6181 const char *s = loc2;
6183 c = *loc2;
6184 if (zero) {
6185 *loc2 = '\0';
6186 s = rmesc;
6188 match = pmatch(pattern, s);
6190 *loc2 = c;
6191 if (match)
6192 return loc;
6193 if (quotes && (unsigned char)*loc == CTLESC)
6194 loc++;
6195 loc++;
6196 loc2++;
6197 } while (c);
6198 return NULL;
6201 static char *
6202 scanright(char *startp, char *rmesc, char *rmescend,
6203 char *pattern, int quotes, int match_at_start)
6205 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6206 int try2optimize = match_at_start;
6207 #endif
6208 int esc = 0;
6209 char *loc;
6210 char *loc2;
6212 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6213 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6214 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6215 * Logic:
6216 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6217 * and on each iteration they go back two/one char until they reach the beginning.
6218 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6220 /* TODO: document in what other circumstances we are called. */
6222 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6223 int match;
6224 char c = *loc2;
6225 const char *s = loc2;
6226 if (match_at_start) {
6227 *loc2 = '\0';
6228 s = rmesc;
6230 match = pmatch(pattern, s);
6231 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
6232 *loc2 = c;
6233 if (match)
6234 return loc;
6235 #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6236 if (try2optimize) {
6237 /* Maybe we can optimize this:
6238 * if pattern ends with unescaped *, we can avoid checking
6239 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6240 * it wont match truncated "raw_value_of_" strings too.
6242 unsigned plen = strlen(pattern);
6243 /* Does it end with "*"? */
6244 if (plen != 0 && pattern[--plen] == '*') {
6245 /* "xxxx*" is not escaped */
6246 /* "xxx\*" is escaped */
6247 /* "xx\\*" is not escaped */
6248 /* "x\\\*" is escaped */
6249 int slashes = 0;
6250 while (plen != 0 && pattern[--plen] == '\\')
6251 slashes++;
6252 if (!(slashes & 1))
6253 break; /* ends with unescaped "*" */
6255 try2optimize = 0;
6257 #endif
6258 loc--;
6259 if (quotes) {
6260 if (--esc < 0) {
6261 esc = esclen(startp, loc);
6263 if (esc % 2) {
6264 esc--;
6265 loc--;
6269 return NULL;
6272 static void varunset(const char *, const char *, const char *, int) NORETURN;
6273 static void
6274 varunset(const char *end, const char *var, const char *umsg, int varflags)
6276 const char *msg;
6277 const char *tail;
6279 tail = nullstr;
6280 msg = "parameter not set";
6281 if (umsg) {
6282 if ((unsigned char)*end == CTLENDVAR) {
6283 if (varflags & VSNUL)
6284 tail = " or null";
6285 } else {
6286 msg = umsg;
6289 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
6292 #if ENABLE_ASH_BASH_COMPAT
6293 static char *
6294 parse_sub_pattern(char *arg, int varflags)
6296 char *idx, *repl = NULL;
6297 unsigned char c;
6299 //char *org_arg = arg;
6300 //bb_error_msg("arg:'%s' varflags:%x", arg, varflags);
6301 idx = arg;
6302 while (1) {
6303 c = *arg;
6304 if (!c)
6305 break;
6306 if (c == '/') {
6307 /* Only the first '/' seen is our separator */
6308 if (!repl) {
6309 repl = idx + 1;
6310 c = '\0';
6313 *idx++ = c;
6314 arg++;
6316 * Example: v='ab\c'; echo ${v/\\b/_\\_\z_}
6317 * The result is a_\_z_c (not a\_\_z_c)!
6319 * Enable debug prints in this function and you'll see:
6320 * ash: arg:'\\b/_\\_z_' varflags:d
6321 * ash: pattern:'\\b' repl:'_\_z_'
6322 * That is, \\b is interpreted as \\b, but \\_ as \_!
6323 * IOW: search pattern and replace string treat backslashes
6324 * differently! That is the reason why we check repl below:
6326 if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE))
6327 arg++; /* skip both '\', not just first one */
6329 *idx = c; /* NUL */
6330 //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl);
6332 return repl;
6334 #endif /* ENABLE_ASH_BASH_COMPAT */
6336 static const char *
6337 subevalvar(char *p, char *varname, int strloc, int subtype,
6338 int startloc, int varflags, int quotes, struct strlist *var_str_list)
6340 struct nodelist *saveargbackq = argbackq;
6341 char *startp;
6342 char *loc;
6343 char *rmesc, *rmescend;
6344 char *str;
6345 IF_ASH_BASH_COMPAT(const char *repl = NULL;)
6346 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
6347 int saveherefd = herefd;
6348 int amount, resetloc;
6349 IF_ASH_BASH_COMPAT(int workloc;)
6350 int zero;
6351 char *(*scan)(char*, char*, char*, char*, int, int);
6353 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6354 // p, varname, strloc, subtype, startloc, varflags, quotes);
6356 herefd = -1;
6357 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
6358 var_str_list);
6359 STPUTC('\0', expdest);
6360 herefd = saveherefd;
6361 argbackq = saveargbackq;
6362 startp = (char *)stackblock() + startloc;
6364 switch (subtype) {
6365 case VSASSIGN:
6366 setvar2(varname, startp);
6367 amount = startp - expdest;
6368 STADJUST(amount, expdest);
6369 return startp;
6371 case VSQUESTION:
6372 varunset(p, varname, startp, varflags);
6373 /* NOTREACHED */
6375 #if ENABLE_ASH_BASH_COMPAT
6376 case VSSUBSTR:
6377 loc = str = stackblock() + strloc;
6378 /* Read POS in ${var:POS:LEN} */
6379 pos = atoi(loc); /* number(loc) errors out on "1:4" */
6380 len = str - startp - 1;
6382 /* *loc != '\0', guaranteed by parser */
6383 if (quotes) {
6384 char *ptr;
6386 /* Adjust the length by the number of escapes */
6387 for (ptr = startp; ptr < (str - 1); ptr++) {
6388 if ((unsigned char)*ptr == CTLESC) {
6389 len--;
6390 ptr++;
6394 orig_len = len;
6396 if (*loc++ == ':') {
6397 /* ${var::LEN} */
6398 len = number(loc);
6399 } else {
6400 /* Skip POS in ${var:POS:LEN} */
6401 len = orig_len;
6402 while (*loc && *loc != ':') {
6403 /* TODO?
6404 * bash complains on: var=qwe; echo ${var:1a:123}
6405 if (!isdigit(*loc))
6406 ash_msg_and_raise_error(msg_illnum, str);
6408 loc++;
6410 if (*loc++ == ':') {
6411 len = number(loc);
6414 if (pos < 0) {
6415 /* ${VAR:$((-n)):l} starts n chars from the end */
6416 pos = orig_len + pos;
6418 if ((unsigned)pos >= orig_len) {
6419 /* apart from obvious ${VAR:999999:l},
6420 * covers ${VAR:$((-9999999)):l} - result is ""
6421 * (bash-compat)
6423 pos = 0;
6424 len = 0;
6426 if (len > (orig_len - pos))
6427 len = orig_len - pos;
6429 for (str = startp; pos; str++, pos--) {
6430 if (quotes && (unsigned char)*str == CTLESC)
6431 str++;
6433 for (loc = startp; len; len--) {
6434 if (quotes && (unsigned char)*str == CTLESC)
6435 *loc++ = *str++;
6436 *loc++ = *str++;
6438 *loc = '\0';
6439 amount = loc - expdest;
6440 STADJUST(amount, expdest);
6441 return loc;
6442 #endif
6445 resetloc = expdest - (char *)stackblock();
6447 /* We'll comeback here if we grow the stack while handling
6448 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6449 * stack will need rebasing, and we'll need to remove our work
6450 * areas each time
6452 IF_ASH_BASH_COMPAT(restart:)
6454 amount = expdest - ((char *)stackblock() + resetloc);
6455 STADJUST(-amount, expdest);
6456 startp = (char *)stackblock() + startloc;
6458 rmesc = startp;
6459 rmescend = (char *)stackblock() + strloc;
6460 if (quotes) {
6461 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6462 if (rmesc != startp) {
6463 rmescend = expdest;
6464 startp = (char *)stackblock() + startloc;
6467 rmescend--;
6468 str = (char *)stackblock() + strloc;
6469 preglob(str, varflags & VSQUOTE, 0);
6471 #if ENABLE_ASH_BASH_COMPAT
6472 workloc = expdest - (char *)stackblock();
6473 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6474 char *idx, *end;
6476 if (!repl) {
6477 repl = parse_sub_pattern(str, varflags);
6478 //bb_error_msg("repl:'%s'", repl);
6479 if (!repl)
6480 repl = nullstr;
6483 /* If there's no pattern to match, return the expansion unmolested */
6484 if (str[0] == '\0')
6485 return NULL;
6487 len = 0;
6488 idx = startp;
6489 end = str - 1;
6490 while (idx < end) {
6491 try_to_match:
6492 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6493 //bb_error_msg("scanright('%s'):'%s'", str, loc);
6494 if (!loc) {
6495 /* No match, advance */
6496 char *restart_detect = stackblock();
6497 skip_matching:
6498 STPUTC(*idx, expdest);
6499 if (quotes && (unsigned char)*idx == CTLESC) {
6500 idx++;
6501 len++;
6502 STPUTC(*idx, expdest);
6504 if (stackblock() != restart_detect)
6505 goto restart;
6506 idx++;
6507 len++;
6508 rmesc++;
6509 /* continue; - prone to quadratic behavior, smarter code: */
6510 if (idx >= end)
6511 break;
6512 if (str[0] == '*') {
6513 /* Pattern is "*foo". If "*foo" does not match "long_string",
6514 * it would never match "ong_string" etc, no point in trying.
6516 goto skip_matching;
6518 goto try_to_match;
6521 if (subtype == VSREPLACEALL) {
6522 while (idx < loc) {
6523 if (quotes && (unsigned char)*idx == CTLESC)
6524 idx++;
6525 idx++;
6526 rmesc++;
6528 } else {
6529 idx = loc;
6532 //bb_error_msg("repl:'%s'", repl);
6533 for (loc = (char*)repl; *loc; loc++) {
6534 char *restart_detect = stackblock();
6535 if (quotes && *loc == '\\') {
6536 STPUTC(CTLESC, expdest);
6537 len++;
6539 STPUTC(*loc, expdest);
6540 if (stackblock() != restart_detect)
6541 goto restart;
6542 len++;
6545 if (subtype == VSREPLACE) {
6546 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
6547 while (*idx) {
6548 char *restart_detect = stackblock();
6549 STPUTC(*idx, expdest);
6550 if (stackblock() != restart_detect)
6551 goto restart;
6552 len++;
6553 idx++;
6555 break;
6559 /* We've put the replaced text into a buffer at workloc, now
6560 * move it to the right place and adjust the stack.
6562 STPUTC('\0', expdest);
6563 startp = (char *)stackblock() + startloc;
6564 memmove(startp, (char *)stackblock() + workloc, len + 1);
6565 //bb_error_msg("startp:'%s'", startp);
6566 amount = expdest - (startp + len);
6567 STADJUST(-amount, expdest);
6568 return startp;
6570 #endif /* ENABLE_ASH_BASH_COMPAT */
6572 subtype -= VSTRIMRIGHT;
6573 #if DEBUG
6574 if (subtype < 0 || subtype > 7)
6575 abort();
6576 #endif
6577 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
6578 zero = subtype >> 1;
6579 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6580 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6582 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6583 if (loc) {
6584 if (zero) {
6585 memmove(startp, loc, str - loc);
6586 loc = startp + (str - loc) - 1;
6588 *loc = '\0';
6589 amount = loc - expdest;
6590 STADJUST(amount, expdest);
6592 return loc;
6596 * Add the value of a specialized variable to the stack string.
6597 * name parameter (examples):
6598 * ash -c 'echo $1' name:'1='
6599 * ash -c 'echo $qwe' name:'qwe='
6600 * ash -c 'echo $$' name:'$='
6601 * ash -c 'echo ${$}' name:'$='
6602 * ash -c 'echo ${$##q}' name:'$=q'
6603 * ash -c 'echo ${#$}' name:'$='
6604 * note: examples with bad shell syntax:
6605 * ash -c 'echo ${#$1}' name:'$=1'
6606 * ash -c 'echo ${#1#}' name:'1=#'
6608 static NOINLINE ssize_t
6609 varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6611 const char *p;
6612 int num;
6613 int i;
6614 int sepq = 0;
6615 ssize_t len = 0;
6616 int subtype = varflags & VSTYPE;
6617 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
6618 int quoted = varflags & VSQUOTE;
6619 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
6621 switch (*name) {
6622 case '$':
6623 num = rootpid;
6624 goto numvar;
6625 case '?':
6626 num = exitstatus;
6627 goto numvar;
6628 case '#':
6629 num = shellparam.nparam;
6630 goto numvar;
6631 case '!':
6632 num = backgndpid;
6633 if (num == 0)
6634 return -1;
6635 numvar:
6636 len = cvtnum(num);
6637 goto check_1char_name;
6638 case '-':
6639 expdest = makestrspace(NOPTS, expdest);
6640 for (i = NOPTS - 1; i >= 0; i--) {
6641 if (optlist[i]) {
6642 USTPUTC(optletters(i), expdest);
6643 len++;
6646 check_1char_name:
6647 #if 0
6648 /* handles cases similar to ${#$1} */
6649 if (name[2] != '\0')
6650 raise_error_syntax("bad substitution");
6651 #endif
6652 break;
6653 case '@': {
6654 char **ap;
6655 int sep;
6657 if (quoted && (flags & EXP_FULL)) {
6658 /* note: this is not meant as PEOF value */
6659 sep = 1 << CHAR_BIT;
6660 goto param;
6662 /* fall through */
6663 case '*':
6664 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
6665 i = SIT(sep, syntax);
6666 if (quotes && (i == CCTL || i == CBACK))
6667 sepq = 1;
6668 param:
6669 ap = shellparam.p;
6670 if (!ap)
6671 return -1;
6672 while ((p = *ap++) != NULL) {
6673 size_t partlen;
6675 partlen = strlen(p);
6676 len += partlen;
6678 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6679 memtodest(p, partlen, syntax, quotes);
6681 if (*ap && sep) {
6682 char *q;
6684 len++;
6685 if (subtype == VSPLUS || subtype == VSLENGTH) {
6686 continue;
6688 q = expdest;
6689 if (sepq)
6690 STPUTC(CTLESC, q);
6691 /* note: may put NUL despite sep != 0
6692 * (see sep = 1 << CHAR_BIT above) */
6693 STPUTC(sep, q);
6694 expdest = q;
6697 return len;
6698 } /* case '@' and '*' */
6699 case '0':
6700 case '1':
6701 case '2':
6702 case '3':
6703 case '4':
6704 case '5':
6705 case '6':
6706 case '7':
6707 case '8':
6708 case '9':
6709 num = atoi(name); /* number(name) fails on ${N#str} etc */
6710 if (num < 0 || num > shellparam.nparam)
6711 return -1;
6712 p = num ? shellparam.p[num - 1] : arg0;
6713 goto value;
6714 default:
6715 /* NB: name has form "VAR=..." */
6717 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6718 * which should be considered before we check variables. */
6719 if (var_str_list) {
6720 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6721 p = NULL;
6722 do {
6723 char *str, *eq;
6724 str = var_str_list->text;
6725 eq = strchr(str, '=');
6726 if (!eq) /* stop at first non-assignment */
6727 break;
6728 eq++;
6729 if (name_len == (unsigned)(eq - str)
6730 && strncmp(str, name, name_len) == 0
6732 p = eq;
6733 /* goto value; - WRONG! */
6734 /* think "A=1 A=2 B=$A" */
6736 var_str_list = var_str_list->next;
6737 } while (var_str_list);
6738 if (p)
6739 goto value;
6741 p = lookupvar(name);
6742 value:
6743 if (!p)
6744 return -1;
6746 len = strlen(p);
6747 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6748 memtodest(p, len, syntax, quotes);
6749 #if ENABLE_UNICODE_SUPPORT
6750 if (subtype == VSLENGTH && len > 0) {
6751 reinit_unicode_for_ash();
6752 if (unicode_status == UNICODE_ON) {
6753 len = unicode_strlen(p);
6756 #endif
6757 return len;
6760 if (subtype == VSPLUS || subtype == VSLENGTH)
6761 STADJUST(-len, expdest);
6762 return len;
6766 * Expand a variable, and return a pointer to the next character in the
6767 * input string.
6769 static char *
6770 evalvar(char *p, int flags, struct strlist *var_str_list)
6772 char varflags;
6773 char subtype;
6774 char quoted;
6775 char easy;
6776 char *var;
6777 int patloc;
6778 int startloc;
6779 ssize_t varlen;
6781 varflags = (unsigned char) *p++;
6782 subtype = varflags & VSTYPE;
6783 quoted = varflags & VSQUOTE;
6784 var = p;
6785 easy = (!quoted || (*var == '@' && shellparam.nparam));
6786 startloc = expdest - (char *)stackblock();
6787 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
6789 again:
6790 varlen = varvalue(var, varflags, flags, var_str_list);
6791 if (varflags & VSNUL)
6792 varlen--;
6794 if (subtype == VSPLUS) {
6795 varlen = -1 - varlen;
6796 goto vsplus;
6799 if (subtype == VSMINUS) {
6800 vsplus:
6801 if (varlen < 0) {
6802 argstr(
6804 flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD),
6805 var_str_list
6807 goto end;
6809 if (easy)
6810 goto record;
6811 goto end;
6814 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6815 if (varlen < 0) {
6816 if (subevalvar(p, var, /* strloc: */ 0,
6817 subtype, startloc, varflags,
6818 /* quotes: */ 0,
6819 var_str_list)
6821 varflags &= ~VSNUL;
6823 * Remove any recorded regions beyond
6824 * start of variable
6826 removerecordregions(startloc);
6827 goto again;
6829 goto end;
6831 if (easy)
6832 goto record;
6833 goto end;
6836 if (varlen < 0 && uflag)
6837 varunset(p, var, 0, 0);
6839 if (subtype == VSLENGTH) {
6840 cvtnum(varlen > 0 ? varlen : 0);
6841 goto record;
6844 if (subtype == VSNORMAL) {
6845 if (easy)
6846 goto record;
6847 goto end;
6850 #if DEBUG
6851 switch (subtype) {
6852 case VSTRIMLEFT:
6853 case VSTRIMLEFTMAX:
6854 case VSTRIMRIGHT:
6855 case VSTRIMRIGHTMAX:
6856 #if ENABLE_ASH_BASH_COMPAT
6857 case VSSUBSTR:
6858 case VSREPLACE:
6859 case VSREPLACEALL:
6860 #endif
6861 break;
6862 default:
6863 abort();
6865 #endif
6867 if (varlen >= 0) {
6869 * Terminate the string and start recording the pattern
6870 * right after it
6872 STPUTC('\0', expdest);
6873 patloc = expdest - (char *)stackblock();
6874 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
6875 startloc, varflags,
6876 /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR),
6877 var_str_list)
6879 int amount = expdest - (
6880 (char *)stackblock() + patloc - 1
6882 STADJUST(-amount, expdest);
6884 /* Remove any recorded regions beyond start of variable */
6885 removerecordregions(startloc);
6886 record:
6887 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6890 end:
6891 if (subtype != VSNORMAL) { /* skip to end of alternative */
6892 int nesting = 1;
6893 for (;;) {
6894 unsigned char c = *p++;
6895 if (c == CTLESC)
6896 p++;
6897 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6898 if (varlen >= 0)
6899 argbackq = argbackq->next;
6900 } else if (c == CTLVAR) {
6901 if ((*p++ & VSTYPE) != VSNORMAL)
6902 nesting++;
6903 } else if (c == CTLENDVAR) {
6904 if (--nesting == 0)
6905 break;
6909 return p;
6913 * Break the argument string into pieces based upon IFS and add the
6914 * strings to the argument list. The regions of the string to be
6915 * searched for IFS characters have been stored by recordregion.
6917 static void
6918 ifsbreakup(char *string, struct arglist *arglist)
6920 struct ifsregion *ifsp;
6921 struct strlist *sp;
6922 char *start;
6923 char *p;
6924 char *q;
6925 const char *ifs, *realifs;
6926 int ifsspc;
6927 int nulonly;
6929 start = string;
6930 if (ifslastp != NULL) {
6931 ifsspc = 0;
6932 nulonly = 0;
6933 realifs = ifsset() ? ifsval() : defifs;
6934 ifsp = &ifsfirst;
6935 do {
6936 p = string + ifsp->begoff;
6937 nulonly = ifsp->nulonly;
6938 ifs = nulonly ? nullstr : realifs;
6939 ifsspc = 0;
6940 while (p < string + ifsp->endoff) {
6941 q = p;
6942 if ((unsigned char)*p == CTLESC)
6943 p++;
6944 if (!strchr(ifs, *p)) {
6945 p++;
6946 continue;
6948 if (!nulonly)
6949 ifsspc = (strchr(defifs, *p) != NULL);
6950 /* Ignore IFS whitespace at start */
6951 if (q == start && ifsspc) {
6952 p++;
6953 start = p;
6954 continue;
6956 *q = '\0';
6957 sp = stzalloc(sizeof(*sp));
6958 sp->text = start;
6959 *arglist->lastp = sp;
6960 arglist->lastp = &sp->next;
6961 p++;
6962 if (!nulonly) {
6963 for (;;) {
6964 if (p >= string + ifsp->endoff) {
6965 break;
6967 q = p;
6968 if ((unsigned char)*p == CTLESC)
6969 p++;
6970 if (strchr(ifs, *p) == NULL) {
6971 p = q;
6972 break;
6974 if (strchr(defifs, *p) == NULL) {
6975 if (ifsspc) {
6976 p++;
6977 ifsspc = 0;
6978 } else {
6979 p = q;
6980 break;
6982 } else
6983 p++;
6986 start = p;
6987 } /* while */
6988 ifsp = ifsp->next;
6989 } while (ifsp != NULL);
6990 if (nulonly)
6991 goto add;
6994 if (!*start)
6995 return;
6997 add:
6998 sp = stzalloc(sizeof(*sp));
6999 sp->text = start;
7000 *arglist->lastp = sp;
7001 arglist->lastp = &sp->next;
7004 static void
7005 ifsfree(void)
7007 struct ifsregion *p;
7009 INT_OFF;
7010 p = ifsfirst.next;
7011 do {
7012 struct ifsregion *ifsp;
7013 ifsp = p->next;
7014 free(p);
7015 p = ifsp;
7016 } while (p);
7017 ifslastp = NULL;
7018 ifsfirst.next = NULL;
7019 INT_ON;
7023 * Add a file name to the list.
7025 static void
7026 addfname(const char *name)
7028 struct strlist *sp;
7030 sp = stzalloc(sizeof(*sp));
7031 sp->text = ststrdup(name);
7032 *exparg.lastp = sp;
7033 exparg.lastp = &sp->next;
7037 * Do metacharacter (i.e. *, ?, [...]) expansion.
7039 static void
7040 expmeta(char *expdir, char *enddir, char *name)
7042 char *p;
7043 const char *cp;
7044 char *start;
7045 char *endname;
7046 int metaflag;
7047 struct stat statb;
7048 DIR *dirp;
7049 struct dirent *dp;
7050 int atend;
7051 int matchdot;
7053 metaflag = 0;
7054 start = name;
7055 for (p = name; *p; p++) {
7056 if (*p == '*' || *p == '?')
7057 metaflag = 1;
7058 else if (*p == '[') {
7059 char *q = p + 1;
7060 if (*q == '!')
7061 q++;
7062 for (;;) {
7063 if (*q == '\\')
7064 q++;
7065 if (*q == '/' || *q == '\0')
7066 break;
7067 if (*++q == ']') {
7068 metaflag = 1;
7069 break;
7072 } else if (*p == '\\')
7073 p++;
7074 else if (*p == '/') {
7075 if (metaflag)
7076 goto out;
7077 start = p + 1;
7080 out:
7081 if (metaflag == 0) { /* we've reached the end of the file name */
7082 if (enddir != expdir)
7083 metaflag++;
7084 p = name;
7085 do {
7086 if (*p == '\\')
7087 p++;
7088 *enddir++ = *p;
7089 } while (*p++);
7090 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7091 addfname(expdir);
7092 return;
7094 endname = p;
7095 if (name < start) {
7096 p = name;
7097 do {
7098 if (*p == '\\')
7099 p++;
7100 *enddir++ = *p++;
7101 } while (p < start);
7103 if (enddir == expdir) {
7104 cp = ".";
7105 } else if (enddir == expdir + 1 && *expdir == '/') {
7106 cp = "/";
7107 } else {
7108 cp = expdir;
7109 enddir[-1] = '\0';
7111 dirp = opendir(cp);
7112 if (dirp == NULL)
7113 return;
7114 if (enddir != expdir)
7115 enddir[-1] = '/';
7116 if (*endname == 0) {
7117 atend = 1;
7118 } else {
7119 atend = 0;
7120 *endname++ = '\0';
7122 matchdot = 0;
7123 p = start;
7124 if (*p == '\\')
7125 p++;
7126 if (*p == '.')
7127 matchdot++;
7128 while (!pending_int && (dp = readdir(dirp)) != NULL) {
7129 if (dp->d_name[0] == '.' && !matchdot)
7130 continue;
7131 if (pmatch(start, dp->d_name)) {
7132 if (atend) {
7133 strcpy(enddir, dp->d_name);
7134 addfname(expdir);
7135 } else {
7136 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7137 continue;
7138 p[-1] = '/';
7139 expmeta(expdir, p, endname);
7143 closedir(dirp);
7144 if (!atend)
7145 endname[-1] = '/';
7148 static struct strlist *
7149 msort(struct strlist *list, int len)
7151 struct strlist *p, *q = NULL;
7152 struct strlist **lpp;
7153 int half;
7154 int n;
7156 if (len <= 1)
7157 return list;
7158 half = len >> 1;
7159 p = list;
7160 for (n = half; --n >= 0;) {
7161 q = p;
7162 p = p->next;
7164 q->next = NULL; /* terminate first half of list */
7165 q = msort(list, half); /* sort first half of list */
7166 p = msort(p, len - half); /* sort second half */
7167 lpp = &list;
7168 for (;;) {
7169 #if ENABLE_LOCALE_SUPPORT
7170 if (strcoll(p->text, q->text) < 0)
7171 #else
7172 if (strcmp(p->text, q->text) < 0)
7173 #endif
7175 *lpp = p;
7176 lpp = &p->next;
7177 p = *lpp;
7178 if (p == NULL) {
7179 *lpp = q;
7180 break;
7182 } else {
7183 *lpp = q;
7184 lpp = &q->next;
7185 q = *lpp;
7186 if (q == NULL) {
7187 *lpp = p;
7188 break;
7192 return list;
7196 * Sort the results of file name expansion. It calculates the number of
7197 * strings to sort and then calls msort (short for merge sort) to do the
7198 * work.
7200 static struct strlist *
7201 expsort(struct strlist *str)
7203 int len;
7204 struct strlist *sp;
7206 len = 0;
7207 for (sp = str; sp; sp = sp->next)
7208 len++;
7209 return msort(str, len);
7212 static void
7213 expandmeta(struct strlist *str /*, int flag*/)
7215 static const char metachars[] ALIGN1 = {
7216 '*', '?', '[', 0
7218 /* TODO - EXP_REDIR */
7220 while (str) {
7221 char *expdir;
7222 struct strlist **savelastp;
7223 struct strlist *sp;
7224 char *p;
7226 if (fflag)
7227 goto nometa;
7228 if (!strpbrk(str->text, metachars))
7229 goto nometa;
7230 savelastp = exparg.lastp;
7232 INT_OFF;
7233 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7235 int i = strlen(str->text);
7236 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
7238 expmeta(expdir, expdir, p);
7239 free(expdir);
7240 if (p != str->text)
7241 free(p);
7242 INT_ON;
7243 if (exparg.lastp == savelastp) {
7245 * no matches
7247 nometa:
7248 *exparg.lastp = str;
7249 rmescapes(str->text, 0);
7250 exparg.lastp = &str->next;
7251 } else {
7252 *exparg.lastp = NULL;
7253 *savelastp = sp = expsort(*savelastp);
7254 while (sp->next != NULL)
7255 sp = sp->next;
7256 exparg.lastp = &sp->next;
7258 str = str->next;
7263 * Perform variable substitution and command substitution on an argument,
7264 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7265 * perform splitting and file name expansion. When arglist is NULL, perform
7266 * here document expansion.
7268 static void
7269 expandarg(union node *arg, struct arglist *arglist, int flag)
7271 struct strlist *sp;
7272 char *p;
7274 argbackq = arg->narg.backquote;
7275 STARTSTACKSTR(expdest);
7276 ifsfirst.next = NULL;
7277 ifslastp = NULL;
7278 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
7279 argstr(arg->narg.text, flag,
7280 /* var_str_list: */ arglist ? arglist->list : NULL);
7281 p = _STPUTC('\0', expdest);
7282 expdest = p - 1;
7283 if (arglist == NULL) {
7284 return; /* here document expanded */
7286 p = grabstackstr(p);
7287 TRACE(("expandarg: p:'%s'\n", p));
7288 exparg.lastp = &exparg.list;
7290 * TODO - EXP_REDIR
7292 if (flag & EXP_FULL) {
7293 ifsbreakup(p, &exparg);
7294 *exparg.lastp = NULL;
7295 exparg.lastp = &exparg.list;
7296 expandmeta(exparg.list /*, flag*/);
7297 } else {
7298 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
7299 rmescapes(p, 0);
7300 TRACE(("expandarg: rmescapes:'%s'\n", p));
7302 sp = stzalloc(sizeof(*sp));
7303 sp->text = p;
7304 *exparg.lastp = sp;
7305 exparg.lastp = &sp->next;
7307 if (ifsfirst.next)
7308 ifsfree();
7309 *exparg.lastp = NULL;
7310 if (exparg.list) {
7311 *arglist->lastp = exparg.list;
7312 arglist->lastp = exparg.lastp;
7317 * Expand shell variables and backquotes inside a here document.
7319 static void
7320 expandhere(union node *arg, int fd)
7322 herefd = fd;
7323 expandarg(arg, (struct arglist *)NULL, 0);
7324 full_write(fd, stackblock(), expdest - (char *)stackblock());
7328 * Returns true if the pattern matches the string.
7330 static int
7331 patmatch(char *pattern, const char *string)
7333 return pmatch(preglob(pattern, 0, 0), string);
7337 * See if a pattern matches in a case statement.
7339 static int
7340 casematch(union node *pattern, char *val)
7342 struct stackmark smark;
7343 int result;
7345 setstackmark(&smark);
7346 argbackq = pattern->narg.backquote;
7347 STARTSTACKSTR(expdest);
7348 ifslastp = NULL;
7349 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7350 /* var_str_list: */ NULL);
7351 STACKSTRNUL(expdest);
7352 result = patmatch(stackblock(), val);
7353 popstackmark(&smark);
7354 return result;
7358 /* ============ find_command */
7360 struct builtincmd {
7361 const char *name;
7362 int (*builtin)(int, char **) FAST_FUNC;
7363 /* unsigned flags; */
7365 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
7366 /* "regular" builtins always take precedence over commands,
7367 * regardless of PATH=....%builtin... position */
7368 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
7369 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
7371 struct cmdentry {
7372 smallint cmdtype; /* CMDxxx */
7373 union param {
7374 int index;
7375 /* index >= 0 for commands without path (slashes) */
7376 /* (TODO: what exactly does the value mean? PATH position?) */
7377 /* index == -1 for commands with slashes */
7378 /* index == (-2 - applet_no) for NOFORK applets */
7379 const struct builtincmd *cmd;
7380 struct funcnode *func;
7381 } u;
7383 /* values of cmdtype */
7384 #define CMDUNKNOWN -1 /* no entry in table for command */
7385 #define CMDNORMAL 0 /* command is an executable program */
7386 #define CMDFUNCTION 1 /* command is a shell function */
7387 #define CMDBUILTIN 2 /* command is a shell builtin */
7389 /* action to find_command() */
7390 #define DO_ERR 0x01 /* prints errors */
7391 #define DO_ABS 0x02 /* checks absolute paths */
7392 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7393 #define DO_ALTPATH 0x08 /* using alternate path */
7394 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7396 static void find_command(char *, struct cmdentry *, int, const char *);
7399 /* ============ Hashing commands */
7402 * When commands are first encountered, they are entered in a hash table.
7403 * This ensures that a full path search will not have to be done for them
7404 * on each invocation.
7406 * We should investigate converting to a linear search, even though that
7407 * would make the command name "hash" a misnomer.
7410 struct tblentry {
7411 struct tblentry *next; /* next entry in hash chain */
7412 union param param; /* definition of builtin function */
7413 smallint cmdtype; /* CMDxxx */
7414 char rehash; /* if set, cd done since entry created */
7415 char cmdname[1]; /* name of command */
7418 static struct tblentry **cmdtable;
7419 #define INIT_G_cmdtable() do { \
7420 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7421 } while (0)
7423 static int builtinloc = -1; /* index in path of %builtin, or -1 */
7426 static void
7427 tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
7429 #if ENABLE_FEATURE_SH_STANDALONE
7430 if (applet_no >= 0) {
7431 if (APPLET_IS_NOEXEC(applet_no)) {
7432 clearenv();
7433 while (*envp)
7434 putenv(*envp++);
7435 run_applet_no_and_exit(applet_no, argv);
7437 /* re-exec ourselves with the new arguments */
7438 execve(bb_busybox_exec_path, argv, envp);
7439 /* If they called chroot or otherwise made the binary no longer
7440 * executable, fall through */
7442 #endif
7444 repeat:
7445 #ifdef SYSV
7446 do {
7447 execve(cmd, argv, envp);
7448 } while (errno == EINTR);
7449 #else
7450 execve(cmd, argv, envp);
7451 #endif
7452 if (cmd == (char*) bb_busybox_exec_path) {
7453 /* We already visited ENOEXEC branch below, don't do it again */
7454 //TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
7455 free(argv);
7456 return;
7458 if (errno == ENOEXEC) {
7459 /* Run "cmd" as a shell script:
7460 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7461 * "If the execve() function fails with ENOEXEC, the shell
7462 * shall execute a command equivalent to having a shell invoked
7463 * with the command name as its first operand,
7464 * with any remaining arguments passed to the new shell"
7466 * That is, do not use $SHELL, user's shell, or /bin/sh;
7467 * just call ourselves.
7469 * Note that bash reads ~80 chars of the file, and if it sees
7470 * a zero byte before it sees newline, it doesn't try to
7471 * interpret it, but fails with "cannot execute binary file"
7472 * message and exit code 126. For one, this prevents attempts
7473 * to interpret foreign ELF binaries as shell scripts.
7475 char **ap;
7476 char **new;
7478 for (ap = argv; *ap; ap++)
7479 continue;
7480 new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
7481 new[0] = (char*) "ash";
7482 new[1] = cmd;
7483 ap = new + 2;
7484 while ((*ap++ = *++argv) != NULL)
7485 continue;
7486 cmd = (char*) bb_busybox_exec_path;
7487 argv = new;
7488 goto repeat;
7493 * Exec a program. Never returns. If you change this routine, you may
7494 * have to change the find_command routine as well.
7496 static void shellexec(char **, const char *, int) NORETURN;
7497 static void
7498 shellexec(char **argv, const char *path, int idx)
7500 char *cmdname;
7501 int e;
7502 char **envp;
7503 int exerrno;
7504 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
7506 clearredir(/*drop:*/ 1);
7507 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7508 if (strchr(argv[0], '/') != NULL
7509 #if ENABLE_FEATURE_SH_STANDALONE
7510 || (applet_no = find_applet_by_name(argv[0])) >= 0
7511 #endif
7513 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7514 if (applet_no >= 0) {
7515 /* We tried execing ourself, but it didn't work.
7516 * Maybe /proc/self/exe doesn't exist?
7517 * Try $PATH search.
7519 goto try_PATH;
7521 e = errno;
7522 } else {
7523 try_PATH:
7524 e = ENOENT;
7525 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
7526 if (--idx < 0 && pathopt == NULL) {
7527 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7528 if (errno != ENOENT && errno != ENOTDIR)
7529 e = errno;
7531 stunalloc(cmdname);
7535 /* Map to POSIX errors */
7536 switch (e) {
7537 case EACCES:
7538 exerrno = 126;
7539 break;
7540 case ENOENT:
7541 exerrno = 127;
7542 break;
7543 default:
7544 exerrno = 2;
7545 break;
7547 exitstatus = exerrno;
7548 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7549 argv[0], e, suppress_int));
7550 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7551 /* NOTREACHED */
7554 static void
7555 printentry(struct tblentry *cmdp)
7557 int idx;
7558 const char *path;
7559 char *name;
7561 idx = cmdp->param.index;
7562 path = pathval();
7563 do {
7564 name = path_advance(&path, cmdp->cmdname);
7565 stunalloc(name);
7566 } while (--idx >= 0);
7567 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7571 * Clear out command entries. The argument specifies the first entry in
7572 * PATH which has changed.
7574 static void
7575 clearcmdentry(int firstchange)
7577 struct tblentry **tblp;
7578 struct tblentry **pp;
7579 struct tblentry *cmdp;
7581 INT_OFF;
7582 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7583 pp = tblp;
7584 while ((cmdp = *pp) != NULL) {
7585 if ((cmdp->cmdtype == CMDNORMAL &&
7586 cmdp->param.index >= firstchange)
7587 || (cmdp->cmdtype == CMDBUILTIN &&
7588 builtinloc >= firstchange)
7590 *pp = cmdp->next;
7591 free(cmdp);
7592 } else {
7593 pp = &cmdp->next;
7597 INT_ON;
7601 * Locate a command in the command hash table. If "add" is nonzero,
7602 * add the command to the table if it is not already present. The
7603 * variable "lastcmdentry" is set to point to the address of the link
7604 * pointing to the entry, so that delete_cmd_entry can delete the
7605 * entry.
7607 * Interrupts must be off if called with add != 0.
7609 static struct tblentry **lastcmdentry;
7611 static struct tblentry *
7612 cmdlookup(const char *name, int add)
7614 unsigned int hashval;
7615 const char *p;
7616 struct tblentry *cmdp;
7617 struct tblentry **pp;
7619 p = name;
7620 hashval = (unsigned char)*p << 4;
7621 while (*p)
7622 hashval += (unsigned char)*p++;
7623 hashval &= 0x7FFF;
7624 pp = &cmdtable[hashval % CMDTABLESIZE];
7625 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7626 if (strcmp(cmdp->cmdname, name) == 0)
7627 break;
7628 pp = &cmdp->next;
7630 if (add && cmdp == NULL) {
7631 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7632 + strlen(name)
7633 /* + 1 - already done because
7634 * tblentry::cmdname is char[1] */);
7635 /*cmdp->next = NULL; - ckzalloc did it */
7636 cmdp->cmdtype = CMDUNKNOWN;
7637 strcpy(cmdp->cmdname, name);
7639 lastcmdentry = pp;
7640 return cmdp;
7644 * Delete the command entry returned on the last lookup.
7646 static void
7647 delete_cmd_entry(void)
7649 struct tblentry *cmdp;
7651 INT_OFF;
7652 cmdp = *lastcmdentry;
7653 *lastcmdentry = cmdp->next;
7654 if (cmdp->cmdtype == CMDFUNCTION)
7655 freefunc(cmdp->param.func);
7656 free(cmdp);
7657 INT_ON;
7661 * Add a new command entry, replacing any existing command entry for
7662 * the same name - except special builtins.
7664 static void
7665 addcmdentry(char *name, struct cmdentry *entry)
7667 struct tblentry *cmdp;
7669 cmdp = cmdlookup(name, 1);
7670 if (cmdp->cmdtype == CMDFUNCTION) {
7671 freefunc(cmdp->param.func);
7673 cmdp->cmdtype = entry->cmdtype;
7674 cmdp->param = entry->u;
7675 cmdp->rehash = 0;
7678 static int FAST_FUNC
7679 hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7681 struct tblentry **pp;
7682 struct tblentry *cmdp;
7683 int c;
7684 struct cmdentry entry;
7685 char *name;
7687 if (nextopt("r") != '\0') {
7688 clearcmdentry(0);
7689 return 0;
7692 if (*argptr == NULL) {
7693 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7694 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7695 if (cmdp->cmdtype == CMDNORMAL)
7696 printentry(cmdp);
7699 return 0;
7702 c = 0;
7703 while ((name = *argptr) != NULL) {
7704 cmdp = cmdlookup(name, 0);
7705 if (cmdp != NULL
7706 && (cmdp->cmdtype == CMDNORMAL
7707 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7709 delete_cmd_entry();
7711 find_command(name, &entry, DO_ERR, pathval());
7712 if (entry.cmdtype == CMDUNKNOWN)
7713 c = 1;
7714 argptr++;
7716 return c;
7720 * Called when a cd is done. Marks all commands so the next time they
7721 * are executed they will be rehashed.
7723 static void
7724 hashcd(void)
7726 struct tblentry **pp;
7727 struct tblentry *cmdp;
7729 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7730 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7731 if (cmdp->cmdtype == CMDNORMAL
7732 || (cmdp->cmdtype == CMDBUILTIN
7733 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7734 && builtinloc > 0)
7736 cmdp->rehash = 1;
7743 * Fix command hash table when PATH changed.
7744 * Called before PATH is changed. The argument is the new value of PATH;
7745 * pathval() still returns the old value at this point.
7746 * Called with interrupts off.
7748 static void FAST_FUNC
7749 changepath(const char *new)
7751 const char *old;
7752 int firstchange;
7753 int idx;
7754 int idx_bltin;
7756 old = pathval();
7757 firstchange = 9999; /* assume no change */
7758 idx = 0;
7759 idx_bltin = -1;
7760 for (;;) {
7761 if (*old != *new) {
7762 firstchange = idx;
7763 if ((*old == '\0' && *new == ':')
7764 || (*old == ':' && *new == '\0')
7766 firstchange++;
7768 old = new; /* ignore subsequent differences */
7770 if (*new == '\0')
7771 break;
7772 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7773 idx_bltin = idx;
7774 if (*new == ':')
7775 idx++;
7776 new++;
7777 old++;
7779 if (builtinloc < 0 && idx_bltin >= 0)
7780 builtinloc = idx_bltin; /* zap builtins */
7781 if (builtinloc >= 0 && idx_bltin < 0)
7782 firstchange = 0;
7783 clearcmdentry(firstchange);
7784 builtinloc = idx_bltin;
7787 #define TEOF 0
7788 #define TNL 1
7789 #define TREDIR 2
7790 #define TWORD 3
7791 #define TSEMI 4
7792 #define TBACKGND 5
7793 #define TAND 6
7794 #define TOR 7
7795 #define TPIPE 8
7796 #define TLP 9
7797 #define TRP 10
7798 #define TENDCASE 11
7799 #define TENDBQUOTE 12
7800 #define TNOT 13
7801 #define TCASE 14
7802 #define TDO 15
7803 #define TDONE 16
7804 #define TELIF 17
7805 #define TELSE 18
7806 #define TESAC 19
7807 #define TFI 20
7808 #define TFOR 21
7809 #define TIF 22
7810 #define TIN 23
7811 #define TTHEN 24
7812 #define TUNTIL 25
7813 #define TWHILE 26
7814 #define TBEGIN 27
7815 #define TEND 28
7816 typedef smallint token_id_t;
7818 /* first char is indicating which tokens mark the end of a list */
7819 static const char *const tokname_array[] = {
7820 "\1end of file",
7821 "\0newline",
7822 "\0redirection",
7823 "\0word",
7824 "\0;",
7825 "\0&",
7826 "\0&&",
7827 "\0||",
7828 "\0|",
7829 "\0(",
7830 "\1)",
7831 "\1;;",
7832 "\1`",
7833 #define KWDOFFSET 13
7834 /* the following are keywords */
7835 "\0!",
7836 "\0case",
7837 "\1do",
7838 "\1done",
7839 "\1elif",
7840 "\1else",
7841 "\1esac",
7842 "\1fi",
7843 "\0for",
7844 "\0if",
7845 "\0in",
7846 "\1then",
7847 "\0until",
7848 "\0while",
7849 "\0{",
7850 "\1}",
7853 /* Wrapper around strcmp for qsort/bsearch/... */
7854 static int
7855 pstrcmp(const void *a, const void *b)
7857 return strcmp((char*) a, (*(char**) b) + 1);
7860 static const char *const *
7861 findkwd(const char *s)
7863 return bsearch(s, tokname_array + KWDOFFSET,
7864 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7865 sizeof(tokname_array[0]), pstrcmp);
7869 * Locate and print what a word is...
7871 static int
7872 describe_command(char *command, int describe_command_verbose)
7874 struct cmdentry entry;
7875 struct tblentry *cmdp;
7876 #if ENABLE_ASH_ALIAS
7877 const struct alias *ap;
7878 #endif
7879 const char *path = pathval();
7881 if (describe_command_verbose) {
7882 out1str(command);
7885 /* First look at the keywords */
7886 if (findkwd(command)) {
7887 out1str(describe_command_verbose ? " is a shell keyword" : command);
7888 goto out;
7891 #if ENABLE_ASH_ALIAS
7892 /* Then look at the aliases */
7893 ap = lookupalias(command, 0);
7894 if (ap != NULL) {
7895 if (!describe_command_verbose) {
7896 out1str("alias ");
7897 printalias(ap);
7898 return 0;
7900 out1fmt(" is an alias for %s", ap->val);
7901 goto out;
7903 #endif
7904 /* Then check if it is a tracked alias */
7905 cmdp = cmdlookup(command, 0);
7906 if (cmdp != NULL) {
7907 entry.cmdtype = cmdp->cmdtype;
7908 entry.u = cmdp->param;
7909 } else {
7910 /* Finally use brute force */
7911 find_command(command, &entry, DO_ABS, path);
7914 switch (entry.cmdtype) {
7915 case CMDNORMAL: {
7916 int j = entry.u.index;
7917 char *p;
7918 if (j < 0) {
7919 p = command;
7920 } else {
7921 do {
7922 p = path_advance(&path, command);
7923 stunalloc(p);
7924 } while (--j >= 0);
7926 if (describe_command_verbose) {
7927 out1fmt(" is%s %s",
7928 (cmdp ? " a tracked alias for" : nullstr), p
7930 } else {
7931 out1str(p);
7933 break;
7936 case CMDFUNCTION:
7937 if (describe_command_verbose) {
7938 out1str(" is a shell function");
7939 } else {
7940 out1str(command);
7942 break;
7944 case CMDBUILTIN:
7945 if (describe_command_verbose) {
7946 out1fmt(" is a %sshell builtin",
7947 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7948 "special " : nullstr
7950 } else {
7951 out1str(command);
7953 break;
7955 default:
7956 if (describe_command_verbose) {
7957 out1str(": not found\n");
7959 return 127;
7961 out:
7962 out1str("\n");
7963 return 0;
7966 static int FAST_FUNC
7967 typecmd(int argc UNUSED_PARAM, char **argv)
7969 int i = 1;
7970 int err = 0;
7971 int verbose = 1;
7973 /* type -p ... ? (we don't bother checking for 'p') */
7974 if (argv[1] && argv[1][0] == '-') {
7975 i++;
7976 verbose = 0;
7978 while (argv[i]) {
7979 err |= describe_command(argv[i++], verbose);
7981 return err;
7984 #if ENABLE_ASH_CMDCMD
7985 static int FAST_FUNC
7986 commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7988 int c;
7989 enum {
7990 VERIFY_BRIEF = 1,
7991 VERIFY_VERBOSE = 2,
7992 } verify = 0;
7994 while ((c = nextopt("pvV")) != '\0')
7995 if (c == 'V')
7996 verify |= VERIFY_VERBOSE;
7997 else if (c == 'v')
7998 verify |= VERIFY_BRIEF;
7999 #if DEBUG
8000 else if (c != 'p')
8001 abort();
8002 #endif
8003 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8004 if (verify && (*argptr != NULL)) {
8005 return describe_command(*argptr, verify - VERIFY_BRIEF);
8008 return 0;
8010 #endif
8013 /* ============ eval.c */
8015 static int funcblocksize; /* size of structures in function */
8016 static int funcstringsize; /* size of strings in node */
8017 static void *funcblock; /* block to allocate function from */
8018 static char *funcstring; /* block to allocate strings from */
8020 /* flags in argument to evaltree */
8021 #define EV_EXIT 01 /* exit after evaluating tree */
8022 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
8023 #define EV_BACKCMD 04 /* command executing within back quotes */
8025 static const uint8_t nodesize[N_NUMBER] = {
8026 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8027 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8028 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8029 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8030 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8031 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8032 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8033 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8034 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8035 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8036 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8037 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8038 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8039 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8040 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8041 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8042 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8043 #if ENABLE_ASH_BASH_COMPAT
8044 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
8045 #endif
8046 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8047 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8048 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8049 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8050 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8051 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8052 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8053 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8054 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
8057 static void calcsize(union node *n);
8059 static void
8060 sizenodelist(struct nodelist *lp)
8062 while (lp) {
8063 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8064 calcsize(lp->n);
8065 lp = lp->next;
8069 static void
8070 calcsize(union node *n)
8072 if (n == NULL)
8073 return;
8074 funcblocksize += nodesize[n->type];
8075 switch (n->type) {
8076 case NCMD:
8077 calcsize(n->ncmd.redirect);
8078 calcsize(n->ncmd.args);
8079 calcsize(n->ncmd.assign);
8080 break;
8081 case NPIPE:
8082 sizenodelist(n->npipe.cmdlist);
8083 break;
8084 case NREDIR:
8085 case NBACKGND:
8086 case NSUBSHELL:
8087 calcsize(n->nredir.redirect);
8088 calcsize(n->nredir.n);
8089 break;
8090 case NAND:
8091 case NOR:
8092 case NSEMI:
8093 case NWHILE:
8094 case NUNTIL:
8095 calcsize(n->nbinary.ch2);
8096 calcsize(n->nbinary.ch1);
8097 break;
8098 case NIF:
8099 calcsize(n->nif.elsepart);
8100 calcsize(n->nif.ifpart);
8101 calcsize(n->nif.test);
8102 break;
8103 case NFOR:
8104 funcstringsize += strlen(n->nfor.var) + 1;
8105 calcsize(n->nfor.body);
8106 calcsize(n->nfor.args);
8107 break;
8108 case NCASE:
8109 calcsize(n->ncase.cases);
8110 calcsize(n->ncase.expr);
8111 break;
8112 case NCLIST:
8113 calcsize(n->nclist.body);
8114 calcsize(n->nclist.pattern);
8115 calcsize(n->nclist.next);
8116 break;
8117 case NDEFUN:
8118 case NARG:
8119 sizenodelist(n->narg.backquote);
8120 funcstringsize += strlen(n->narg.text) + 1;
8121 calcsize(n->narg.next);
8122 break;
8123 case NTO:
8124 #if ENABLE_ASH_BASH_COMPAT
8125 case NTO2:
8126 #endif
8127 case NCLOBBER:
8128 case NFROM:
8129 case NFROMTO:
8130 case NAPPEND:
8131 calcsize(n->nfile.fname);
8132 calcsize(n->nfile.next);
8133 break;
8134 case NTOFD:
8135 case NFROMFD:
8136 calcsize(n->ndup.vname);
8137 calcsize(n->ndup.next);
8138 break;
8139 case NHERE:
8140 case NXHERE:
8141 calcsize(n->nhere.doc);
8142 calcsize(n->nhere.next);
8143 break;
8144 case NNOT:
8145 calcsize(n->nnot.com);
8146 break;
8150 static char *
8151 nodeckstrdup(char *s)
8153 char *rtn = funcstring;
8155 strcpy(funcstring, s);
8156 funcstring += strlen(s) + 1;
8157 return rtn;
8160 static union node *copynode(union node *);
8162 static struct nodelist *
8163 copynodelist(struct nodelist *lp)
8165 struct nodelist *start;
8166 struct nodelist **lpp;
8168 lpp = &start;
8169 while (lp) {
8170 *lpp = funcblock;
8171 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8172 (*lpp)->n = copynode(lp->n);
8173 lp = lp->next;
8174 lpp = &(*lpp)->next;
8176 *lpp = NULL;
8177 return start;
8180 static union node *
8181 copynode(union node *n)
8183 union node *new;
8185 if (n == NULL)
8186 return NULL;
8187 new = funcblock;
8188 funcblock = (char *) funcblock + nodesize[n->type];
8190 switch (n->type) {
8191 case NCMD:
8192 new->ncmd.redirect = copynode(n->ncmd.redirect);
8193 new->ncmd.args = copynode(n->ncmd.args);
8194 new->ncmd.assign = copynode(n->ncmd.assign);
8195 break;
8196 case NPIPE:
8197 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8198 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8199 break;
8200 case NREDIR:
8201 case NBACKGND:
8202 case NSUBSHELL:
8203 new->nredir.redirect = copynode(n->nredir.redirect);
8204 new->nredir.n = copynode(n->nredir.n);
8205 break;
8206 case NAND:
8207 case NOR:
8208 case NSEMI:
8209 case NWHILE:
8210 case NUNTIL:
8211 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8212 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8213 break;
8214 case NIF:
8215 new->nif.elsepart = copynode(n->nif.elsepart);
8216 new->nif.ifpart = copynode(n->nif.ifpart);
8217 new->nif.test = copynode(n->nif.test);
8218 break;
8219 case NFOR:
8220 new->nfor.var = nodeckstrdup(n->nfor.var);
8221 new->nfor.body = copynode(n->nfor.body);
8222 new->nfor.args = copynode(n->nfor.args);
8223 break;
8224 case NCASE:
8225 new->ncase.cases = copynode(n->ncase.cases);
8226 new->ncase.expr = copynode(n->ncase.expr);
8227 break;
8228 case NCLIST:
8229 new->nclist.body = copynode(n->nclist.body);
8230 new->nclist.pattern = copynode(n->nclist.pattern);
8231 new->nclist.next = copynode(n->nclist.next);
8232 break;
8233 case NDEFUN:
8234 case NARG:
8235 new->narg.backquote = copynodelist(n->narg.backquote);
8236 new->narg.text = nodeckstrdup(n->narg.text);
8237 new->narg.next = copynode(n->narg.next);
8238 break;
8239 case NTO:
8240 #if ENABLE_ASH_BASH_COMPAT
8241 case NTO2:
8242 #endif
8243 case NCLOBBER:
8244 case NFROM:
8245 case NFROMTO:
8246 case NAPPEND:
8247 new->nfile.fname = copynode(n->nfile.fname);
8248 new->nfile.fd = n->nfile.fd;
8249 new->nfile.next = copynode(n->nfile.next);
8250 break;
8251 case NTOFD:
8252 case NFROMFD:
8253 new->ndup.vname = copynode(n->ndup.vname);
8254 new->ndup.dupfd = n->ndup.dupfd;
8255 new->ndup.fd = n->ndup.fd;
8256 new->ndup.next = copynode(n->ndup.next);
8257 break;
8258 case NHERE:
8259 case NXHERE:
8260 new->nhere.doc = copynode(n->nhere.doc);
8261 new->nhere.fd = n->nhere.fd;
8262 new->nhere.next = copynode(n->nhere.next);
8263 break;
8264 case NNOT:
8265 new->nnot.com = copynode(n->nnot.com);
8266 break;
8268 new->type = n->type;
8269 return new;
8273 * Make a copy of a parse tree.
8275 static struct funcnode *
8276 copyfunc(union node *n)
8278 struct funcnode *f;
8279 size_t blocksize;
8281 funcblocksize = offsetof(struct funcnode, n);
8282 funcstringsize = 0;
8283 calcsize(n);
8284 blocksize = funcblocksize;
8285 f = ckmalloc(blocksize + funcstringsize);
8286 funcblock = (char *) f + offsetof(struct funcnode, n);
8287 funcstring = (char *) f + blocksize;
8288 copynode(n);
8289 f->count = 0;
8290 return f;
8294 * Define a shell function.
8296 static void
8297 defun(char *name, union node *func)
8299 struct cmdentry entry;
8301 INT_OFF;
8302 entry.cmdtype = CMDFUNCTION;
8303 entry.u.func = copyfunc(func);
8304 addcmdentry(name, &entry);
8305 INT_ON;
8308 /* Reasons for skipping commands (see comment on breakcmd routine) */
8309 #define SKIPBREAK (1 << 0)
8310 #define SKIPCONT (1 << 1)
8311 #define SKIPFUNC (1 << 2)
8312 #define SKIPFILE (1 << 3)
8313 #define SKIPEVAL (1 << 4)
8314 static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
8315 static int skipcount; /* number of levels to skip */
8316 static int funcnest; /* depth of function calls */
8317 static int loopnest; /* current loop nesting level */
8319 /* Forward decl way out to parsing code - dotrap needs it */
8320 static int evalstring(char *s, int mask);
8322 /* Called to execute a trap.
8323 * Single callsite - at the end of evaltree().
8324 * If we return non-zero, evaltree raises EXEXIT exception.
8326 * Perhaps we should avoid entering new trap handlers
8327 * while we are executing a trap handler. [is it a TODO?]
8329 static int
8330 dotrap(void)
8332 uint8_t *g;
8333 int sig;
8334 uint8_t savestatus;
8336 savestatus = exitstatus;
8337 pending_sig = 0;
8338 xbarrier();
8340 TRACE(("dotrap entered\n"));
8341 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8342 int want_exexit;
8343 char *t;
8345 if (*g == 0)
8346 continue;
8347 t = trap[sig];
8348 /* non-trapped SIGINT is handled separately by raise_interrupt,
8349 * don't upset it by resetting gotsig[SIGINT-1] */
8350 if (sig == SIGINT && !t)
8351 continue;
8353 TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
8354 *g = 0;
8355 if (!t)
8356 continue;
8357 want_exexit = evalstring(t, SKIPEVAL);
8358 exitstatus = savestatus;
8359 if (want_exexit) {
8360 TRACE(("dotrap returns %d\n", want_exexit));
8361 return want_exexit;
8365 TRACE(("dotrap returns 0\n"));
8366 return 0;
8369 /* forward declarations - evaluation is fairly recursive business... */
8370 static void evalloop(union node *, int);
8371 static void evalfor(union node *, int);
8372 static void evalcase(union node *, int);
8373 static void evalsubshell(union node *, int);
8374 static void expredir(union node *);
8375 static void evalpipe(union node *, int);
8376 static void evalcommand(union node *, int);
8377 static int evalbltin(const struct builtincmd *, int, char **);
8378 static void prehash(union node *);
8381 * Evaluate a parse tree. The value is left in the global variable
8382 * exitstatus.
8384 static void
8385 evaltree(union node *n, int flags)
8387 struct jmploc *volatile savehandler = exception_handler;
8388 struct jmploc jmploc;
8389 int checkexit = 0;
8390 void (*evalfn)(union node *, int);
8391 int status;
8392 int int_level;
8394 SAVE_INT(int_level);
8396 if (n == NULL) {
8397 TRACE(("evaltree(NULL) called\n"));
8398 goto out1;
8400 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
8402 exception_handler = &jmploc;
8404 int err = setjmp(jmploc.loc);
8405 if (err) {
8406 /* if it was a signal, check for trap handlers */
8407 if (exception_type == EXSIG) {
8408 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8409 exception_type, err));
8410 goto out;
8412 /* continue on the way out */
8413 TRACE(("exception %d in evaltree, propagating err=%d\n",
8414 exception_type, err));
8415 exception_handler = savehandler;
8416 longjmp(exception_handler->loc, err);
8420 switch (n->type) {
8421 default:
8422 #if DEBUG
8423 out1fmt("Node type = %d\n", n->type);
8424 fflush_all();
8425 break;
8426 #endif
8427 case NNOT:
8428 evaltree(n->nnot.com, EV_TESTED);
8429 status = !exitstatus;
8430 goto setstatus;
8431 case NREDIR:
8432 expredir(n->nredir.redirect);
8433 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8434 if (!status) {
8435 evaltree(n->nredir.n, flags & EV_TESTED);
8436 status = exitstatus;
8438 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
8439 goto setstatus;
8440 case NCMD:
8441 evalfn = evalcommand;
8442 checkexit:
8443 if (eflag && !(flags & EV_TESTED))
8444 checkexit = ~0;
8445 goto calleval;
8446 case NFOR:
8447 evalfn = evalfor;
8448 goto calleval;
8449 case NWHILE:
8450 case NUNTIL:
8451 evalfn = evalloop;
8452 goto calleval;
8453 case NSUBSHELL:
8454 case NBACKGND:
8455 evalfn = evalsubshell;
8456 goto calleval;
8457 case NPIPE:
8458 evalfn = evalpipe;
8459 goto checkexit;
8460 case NCASE:
8461 evalfn = evalcase;
8462 goto calleval;
8463 case NAND:
8464 case NOR:
8465 case NSEMI: {
8467 #if NAND + 1 != NOR
8468 #error NAND + 1 != NOR
8469 #endif
8470 #if NOR + 1 != NSEMI
8471 #error NOR + 1 != NSEMI
8472 #endif
8473 unsigned is_or = n->type - NAND;
8474 evaltree(
8475 n->nbinary.ch1,
8476 (flags | ((is_or >> 1) - 1)) & EV_TESTED
8478 if (!exitstatus == is_or)
8479 break;
8480 if (!evalskip) {
8481 n = n->nbinary.ch2;
8482 evaln:
8483 evalfn = evaltree;
8484 calleval:
8485 evalfn(n, flags);
8486 break;
8488 break;
8490 case NIF:
8491 evaltree(n->nif.test, EV_TESTED);
8492 if (evalskip)
8493 break;
8494 if (exitstatus == 0) {
8495 n = n->nif.ifpart;
8496 goto evaln;
8498 if (n->nif.elsepart) {
8499 n = n->nif.elsepart;
8500 goto evaln;
8502 goto success;
8503 case NDEFUN:
8504 defun(n->narg.text, n->narg.next);
8505 success:
8506 status = 0;
8507 setstatus:
8508 exitstatus = status;
8509 break;
8512 out:
8513 exception_handler = savehandler;
8515 out1:
8516 /* Order of checks below is important:
8517 * signal handlers trigger before exit caused by "set -e".
8519 if (pending_sig && dotrap())
8520 goto exexit;
8521 if (checkexit & exitstatus)
8522 evalskip |= SKIPEVAL;
8524 if (flags & EV_EXIT) {
8525 exexit:
8526 raise_exception(EXEXIT);
8529 RESTORE_INT(int_level);
8530 TRACE(("leaving evaltree (no interrupts)\n"));
8533 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8534 static
8535 #endif
8536 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8538 static void
8539 evalloop(union node *n, int flags)
8541 int status;
8543 loopnest++;
8544 status = 0;
8545 flags &= EV_TESTED;
8546 for (;;) {
8547 int i;
8549 evaltree(n->nbinary.ch1, EV_TESTED);
8550 if (evalskip) {
8551 skipping:
8552 if (evalskip == SKIPCONT && --skipcount <= 0) {
8553 evalskip = 0;
8554 continue;
8556 if (evalskip == SKIPBREAK && --skipcount <= 0)
8557 evalskip = 0;
8558 break;
8560 i = exitstatus;
8561 if (n->type != NWHILE)
8562 i = !i;
8563 if (i != 0)
8564 break;
8565 evaltree(n->nbinary.ch2, flags);
8566 status = exitstatus;
8567 if (evalskip)
8568 goto skipping;
8570 loopnest--;
8571 exitstatus = status;
8574 static void
8575 evalfor(union node *n, int flags)
8577 struct arglist arglist;
8578 union node *argp;
8579 struct strlist *sp;
8580 struct stackmark smark;
8582 setstackmark(&smark);
8583 arglist.list = NULL;
8584 arglist.lastp = &arglist.list;
8585 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8586 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
8587 /* XXX */
8588 if (evalskip)
8589 goto out;
8591 *arglist.lastp = NULL;
8593 exitstatus = 0;
8594 loopnest++;
8595 flags &= EV_TESTED;
8596 for (sp = arglist.list; sp; sp = sp->next) {
8597 setvar2(n->nfor.var, sp->text);
8598 evaltree(n->nfor.body, flags);
8599 if (evalskip) {
8600 if (evalskip == SKIPCONT && --skipcount <= 0) {
8601 evalskip = 0;
8602 continue;
8604 if (evalskip == SKIPBREAK && --skipcount <= 0)
8605 evalskip = 0;
8606 break;
8609 loopnest--;
8610 out:
8611 popstackmark(&smark);
8614 static void
8615 evalcase(union node *n, int flags)
8617 union node *cp;
8618 union node *patp;
8619 struct arglist arglist;
8620 struct stackmark smark;
8622 setstackmark(&smark);
8623 arglist.list = NULL;
8624 arglist.lastp = &arglist.list;
8625 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8626 exitstatus = 0;
8627 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8628 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8629 if (casematch(patp, arglist.list->text)) {
8630 if (evalskip == 0) {
8631 evaltree(cp->nclist.body, flags);
8633 goto out;
8637 out:
8638 popstackmark(&smark);
8642 * Kick off a subshell to evaluate a tree.
8644 static void
8645 evalsubshell(union node *n, int flags)
8647 struct job *jp;
8648 int backgnd = (n->type == NBACKGND);
8649 int status;
8651 expredir(n->nredir.redirect);
8652 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
8653 goto nofork;
8654 INT_OFF;
8655 jp = makejob(/*n,*/ 1);
8656 if (forkshell(jp, n, backgnd) == 0) {
8657 /* child */
8658 INT_ON;
8659 flags |= EV_EXIT;
8660 if (backgnd)
8661 flags &= ~EV_TESTED;
8662 nofork:
8663 redirect(n->nredir.redirect, 0);
8664 evaltreenr(n->nredir.n, flags);
8665 /* never returns */
8667 status = 0;
8668 if (!backgnd)
8669 status = waitforjob(jp);
8670 exitstatus = status;
8671 INT_ON;
8675 * Compute the names of the files in a redirection list.
8677 static void fixredir(union node *, const char *, int);
8678 static void
8679 expredir(union node *n)
8681 union node *redir;
8683 for (redir = n; redir; redir = redir->nfile.next) {
8684 struct arglist fn;
8686 fn.list = NULL;
8687 fn.lastp = &fn.list;
8688 switch (redir->type) {
8689 case NFROMTO:
8690 case NFROM:
8691 case NTO:
8692 #if ENABLE_ASH_BASH_COMPAT
8693 case NTO2:
8694 #endif
8695 case NCLOBBER:
8696 case NAPPEND:
8697 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8698 TRACE(("expredir expanded to '%s'\n", fn.list->text));
8699 #if ENABLE_ASH_BASH_COMPAT
8700 store_expfname:
8701 #endif
8702 #if 0
8703 // By the design of stack allocator, the loop of this kind:
8704 // while true; do while true; do break; done </dev/null; done
8705 // will look like a memory leak: ash plans to free expfname's
8706 // of "/dev/null" as soon as it finishes running the loop
8707 // (in this case, never).
8708 // This "fix" is wrong:
8709 if (redir->nfile.expfname)
8710 stunalloc(redir->nfile.expfname);
8711 // It results in corrupted state of stacked allocations.
8712 #endif
8713 redir->nfile.expfname = fn.list->text;
8714 break;
8715 case NFROMFD:
8716 case NTOFD: /* >& */
8717 if (redir->ndup.vname) {
8718 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8719 if (fn.list == NULL)
8720 ash_msg_and_raise_error("redir error");
8721 #if ENABLE_ASH_BASH_COMPAT
8722 //FIXME: we used expandarg with different args!
8723 if (!isdigit_str9(fn.list->text)) {
8724 /* >&file, not >&fd */
8725 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8726 ash_msg_and_raise_error("redir error");
8727 redir->type = NTO2;
8728 goto store_expfname;
8730 #endif
8731 fixredir(redir, fn.list->text, 1);
8733 break;
8739 * Evaluate a pipeline. All the processes in the pipeline are children
8740 * of the process creating the pipeline. (This differs from some versions
8741 * of the shell, which make the last process in a pipeline the parent
8742 * of all the rest.)
8744 static void
8745 evalpipe(union node *n, int flags)
8747 struct job *jp;
8748 struct nodelist *lp;
8749 int pipelen;
8750 int prevfd;
8751 int pip[2];
8753 TRACE(("evalpipe(0x%lx) called\n", (long)n));
8754 pipelen = 0;
8755 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8756 pipelen++;
8757 flags |= EV_EXIT;
8758 INT_OFF;
8759 jp = makejob(/*n,*/ pipelen);
8760 prevfd = -1;
8761 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8762 prehash(lp->n);
8763 pip[1] = -1;
8764 if (lp->next) {
8765 if (pipe(pip) < 0) {
8766 close(prevfd);
8767 ash_msg_and_raise_error("pipe call failed");
8770 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8771 INT_ON;
8772 if (pip[1] >= 0) {
8773 close(pip[0]);
8775 if (prevfd > 0) {
8776 dup2(prevfd, 0);
8777 close(prevfd);
8779 if (pip[1] > 1) {
8780 dup2(pip[1], 1);
8781 close(pip[1]);
8783 evaltreenr(lp->n, flags);
8784 /* never returns */
8786 if (prevfd >= 0)
8787 close(prevfd);
8788 prevfd = pip[0];
8789 /* Don't want to trigger debugging */
8790 if (pip[1] != -1)
8791 close(pip[1]);
8793 if (n->npipe.pipe_backgnd == 0) {
8794 exitstatus = waitforjob(jp);
8795 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
8797 INT_ON;
8801 * Controls whether the shell is interactive or not.
8803 static void
8804 setinteractive(int on)
8806 static smallint is_interactive;
8808 if (++on == is_interactive)
8809 return;
8810 is_interactive = on;
8811 setsignal(SIGINT);
8812 setsignal(SIGQUIT);
8813 setsignal(SIGTERM);
8814 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8815 if (is_interactive > 1) {
8816 /* Looks like they want an interactive shell */
8817 static smallint did_banner;
8819 if (!did_banner) {
8820 /* note: ash and hush share this string */
8821 out1fmt("\n\n%s %s\n"
8822 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8823 "\n",
8824 bb_banner,
8825 "built-in shell (ash)"
8827 did_banner = 1;
8830 #endif
8833 static void
8834 optschanged(void)
8836 #if DEBUG
8837 opentrace();
8838 #endif
8839 setinteractive(iflag);
8840 setjobctl(mflag);
8841 #if ENABLE_FEATURE_EDITING_VI
8842 if (viflag)
8843 line_input_state->flags |= VI_MODE;
8844 else
8845 line_input_state->flags &= ~VI_MODE;
8846 #else
8847 viflag = 0; /* forcibly keep the option off */
8848 #endif
8851 static struct localvar *localvars;
8854 * Called after a function returns.
8855 * Interrupts must be off.
8857 static void
8858 poplocalvars(void)
8860 struct localvar *lvp;
8861 struct var *vp;
8863 while ((lvp = localvars) != NULL) {
8864 localvars = lvp->next;
8865 vp = lvp->vp;
8866 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
8867 if (vp == NULL) { /* $- saved */
8868 memcpy(optlist, lvp->text, sizeof(optlist));
8869 free((char*)lvp->text);
8870 optschanged();
8871 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
8872 unsetvar(vp->var_text);
8873 } else {
8874 if (vp->var_func)
8875 vp->var_func(var_end(lvp->text));
8876 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
8877 free((char*)vp->var_text);
8878 vp->flags = lvp->flags;
8879 vp->var_text = lvp->text;
8881 free(lvp);
8885 static int
8886 evalfun(struct funcnode *func, int argc, char **argv, int flags)
8888 volatile struct shparam saveparam;
8889 struct localvar *volatile savelocalvars;
8890 struct jmploc *volatile savehandler;
8891 struct jmploc jmploc;
8892 int e;
8894 saveparam = shellparam;
8895 savelocalvars = localvars;
8896 e = setjmp(jmploc.loc);
8897 if (e) {
8898 goto funcdone;
8900 INT_OFF;
8901 savehandler = exception_handler;
8902 exception_handler = &jmploc;
8903 localvars = NULL;
8904 shellparam.malloced = 0;
8905 func->count++;
8906 funcnest++;
8907 INT_ON;
8908 shellparam.nparam = argc - 1;
8909 shellparam.p = argv + 1;
8910 #if ENABLE_ASH_GETOPTS
8911 shellparam.optind = 1;
8912 shellparam.optoff = -1;
8913 #endif
8914 evaltree(&func->n, flags & EV_TESTED);
8915 funcdone:
8916 INT_OFF;
8917 funcnest--;
8918 freefunc(func);
8919 poplocalvars();
8920 localvars = savelocalvars;
8921 freeparam(&shellparam);
8922 shellparam = saveparam;
8923 exception_handler = savehandler;
8924 INT_ON;
8925 evalskip &= ~SKIPFUNC;
8926 return e;
8929 #if ENABLE_ASH_CMDCMD
8930 static char **
8931 parse_command_args(char **argv, const char **path)
8933 char *cp, c;
8935 for (;;) {
8936 cp = *++argv;
8937 if (!cp)
8938 return 0;
8939 if (*cp++ != '-')
8940 break;
8941 c = *cp++;
8942 if (!c)
8943 break;
8944 if (c == '-' && !*cp) {
8945 argv++;
8946 break;
8948 do {
8949 switch (c) {
8950 case 'p':
8951 *path = bb_default_path;
8952 break;
8953 default:
8954 /* run 'typecmd' for other options */
8955 return 0;
8957 c = *cp++;
8958 } while (c);
8960 return argv;
8962 #endif
8965 * Make a variable a local variable. When a variable is made local, it's
8966 * value and flags are saved in a localvar structure. The saved values
8967 * will be restored when the shell function returns. We handle the name
8968 * "-" as a special case.
8970 static void
8971 mklocal(char *name)
8973 struct localvar *lvp;
8974 struct var **vpp;
8975 struct var *vp;
8977 INT_OFF;
8978 lvp = ckzalloc(sizeof(struct localvar));
8979 if (LONE_DASH(name)) {
8980 char *p;
8981 p = ckmalloc(sizeof(optlist));
8982 lvp->text = memcpy(p, optlist, sizeof(optlist));
8983 vp = NULL;
8984 } else {
8985 char *eq;
8987 vpp = hashvar(name);
8988 vp = *findvar(vpp, name);
8989 eq = strchr(name, '=');
8990 if (vp == NULL) {
8991 if (eq)
8992 setvareq(name, VSTRFIXED);
8993 else
8994 setvar(name, NULL, VSTRFIXED);
8995 vp = *vpp; /* the new variable */
8996 lvp->flags = VUNSET;
8997 } else {
8998 lvp->text = vp->var_text;
8999 lvp->flags = vp->flags;
9000 vp->flags |= VSTRFIXED|VTEXTFIXED;
9001 if (eq)
9002 setvareq(name, 0);
9003 else
9004 /* "local VAR" unsets VAR: */
9005 setvar(name, NULL, 0);
9008 lvp->vp = vp;
9009 lvp->next = localvars;
9010 localvars = lvp;
9011 INT_ON;
9015 * The "local" command.
9017 static int FAST_FUNC
9018 localcmd(int argc UNUSED_PARAM, char **argv)
9020 char *name;
9022 argv = argptr;
9023 while ((name = *argv++) != NULL) {
9024 mklocal(name);
9026 return 0;
9029 static int FAST_FUNC
9030 falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9032 return 1;
9035 static int FAST_FUNC
9036 truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9038 return 0;
9041 static int FAST_FUNC
9042 execcmd(int argc UNUSED_PARAM, char **argv)
9044 if (argv[1]) {
9045 iflag = 0; /* exit on error */
9046 mflag = 0;
9047 optschanged();
9048 shellexec(argv + 1, pathval(), 0);
9050 return 0;
9054 * The return command.
9056 static int FAST_FUNC
9057 returncmd(int argc UNUSED_PARAM, char **argv)
9060 * If called outside a function, do what ksh does;
9061 * skip the rest of the file.
9063 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
9064 return argv[1] ? number(argv[1]) : exitstatus;
9067 /* Forward declarations for builtintab[] */
9068 static int breakcmd(int, char **) FAST_FUNC;
9069 static int dotcmd(int, char **) FAST_FUNC;
9070 static int evalcmd(int, char **) FAST_FUNC;
9071 static int exitcmd(int, char **) FAST_FUNC;
9072 static int exportcmd(int, char **) FAST_FUNC;
9073 #if ENABLE_ASH_GETOPTS
9074 static int getoptscmd(int, char **) FAST_FUNC;
9075 #endif
9076 #if ENABLE_ASH_HELP
9077 static int helpcmd(int, char **) FAST_FUNC;
9078 #endif
9079 #if MAX_HISTORY
9080 static int historycmd(int, char **) FAST_FUNC;
9081 #endif
9082 #if ENABLE_SH_MATH_SUPPORT
9083 static int letcmd(int, char **) FAST_FUNC;
9084 #endif
9085 static int readcmd(int, char **) FAST_FUNC;
9086 static int setcmd(int, char **) FAST_FUNC;
9087 static int shiftcmd(int, char **) FAST_FUNC;
9088 static int timescmd(int, char **) FAST_FUNC;
9089 static int trapcmd(int, char **) FAST_FUNC;
9090 static int umaskcmd(int, char **) FAST_FUNC;
9091 static int unsetcmd(int, char **) FAST_FUNC;
9092 static int ulimitcmd(int, char **) FAST_FUNC;
9094 #define BUILTIN_NOSPEC "0"
9095 #define BUILTIN_SPECIAL "1"
9096 #define BUILTIN_REGULAR "2"
9097 #define BUILTIN_SPEC_REG "3"
9098 #define BUILTIN_ASSIGN "4"
9099 #define BUILTIN_SPEC_ASSG "5"
9100 #define BUILTIN_REG_ASSG "6"
9101 #define BUILTIN_SPEC_REG_ASSG "7"
9103 /* Stubs for calling non-FAST_FUNC's */
9104 #if ENABLE_ASH_BUILTIN_ECHO
9105 static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
9106 #endif
9107 #if ENABLE_ASH_BUILTIN_PRINTF
9108 static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
9109 #endif
9110 #if ENABLE_ASH_BUILTIN_TEST
9111 static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
9112 #endif
9114 /* Keep these in proper order since it is searched via bsearch() */
9115 static const struct builtincmd builtintab[] = {
9116 { BUILTIN_SPEC_REG "." , dotcmd },
9117 { BUILTIN_SPEC_REG ":" , truecmd },
9118 #if ENABLE_ASH_BUILTIN_TEST
9119 { BUILTIN_REGULAR "[" , testcmd },
9120 #if ENABLE_ASH_BASH_COMPAT
9121 { BUILTIN_REGULAR "[[" , testcmd },
9122 #endif
9123 #endif
9124 #if ENABLE_ASH_ALIAS
9125 { BUILTIN_REG_ASSG "alias" , aliascmd },
9126 #endif
9127 #if JOBS
9128 { BUILTIN_REGULAR "bg" , fg_bgcmd },
9129 #endif
9130 { BUILTIN_SPEC_REG "break" , breakcmd },
9131 { BUILTIN_REGULAR "cd" , cdcmd },
9132 { BUILTIN_NOSPEC "chdir" , cdcmd },
9133 #if ENABLE_ASH_CMDCMD
9134 { BUILTIN_REGULAR "command" , commandcmd },
9135 #endif
9136 { BUILTIN_SPEC_REG "continue", breakcmd },
9137 #if ENABLE_ASH_BUILTIN_ECHO
9138 { BUILTIN_REGULAR "echo" , echocmd },
9139 #endif
9140 { BUILTIN_SPEC_REG "eval" , evalcmd },
9141 { BUILTIN_SPEC_REG "exec" , execcmd },
9142 { BUILTIN_SPEC_REG "exit" , exitcmd },
9143 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9144 { BUILTIN_REGULAR "false" , falsecmd },
9145 #if JOBS
9146 { BUILTIN_REGULAR "fg" , fg_bgcmd },
9147 #endif
9148 #if ENABLE_ASH_GETOPTS
9149 { BUILTIN_REGULAR "getopts" , getoptscmd },
9150 #endif
9151 { BUILTIN_NOSPEC "hash" , hashcmd },
9152 #if ENABLE_ASH_HELP
9153 { BUILTIN_NOSPEC "help" , helpcmd },
9154 #endif
9155 #if MAX_HISTORY
9156 { BUILTIN_NOSPEC "history" , historycmd },
9157 #endif
9158 #if JOBS
9159 { BUILTIN_REGULAR "jobs" , jobscmd },
9160 { BUILTIN_REGULAR "kill" , killcmd },
9161 #endif
9162 #if ENABLE_SH_MATH_SUPPORT
9163 { BUILTIN_NOSPEC "let" , letcmd },
9164 #endif
9165 { BUILTIN_ASSIGN "local" , localcmd },
9166 #if ENABLE_ASH_BUILTIN_PRINTF
9167 { BUILTIN_REGULAR "printf" , printfcmd },
9168 #endif
9169 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9170 { BUILTIN_REGULAR "read" , readcmd },
9171 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9172 { BUILTIN_SPEC_REG "return" , returncmd },
9173 { BUILTIN_SPEC_REG "set" , setcmd },
9174 { BUILTIN_SPEC_REG "shift" , shiftcmd },
9175 #if ENABLE_ASH_BASH_COMPAT
9176 { BUILTIN_SPEC_REG "source" , dotcmd },
9177 #endif
9178 #if ENABLE_ASH_BUILTIN_TEST
9179 { BUILTIN_REGULAR "test" , testcmd },
9180 #endif
9181 { BUILTIN_SPEC_REG "times" , timescmd },
9182 { BUILTIN_SPEC_REG "trap" , trapcmd },
9183 { BUILTIN_REGULAR "true" , truecmd },
9184 { BUILTIN_NOSPEC "type" , typecmd },
9185 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9186 { BUILTIN_REGULAR "umask" , umaskcmd },
9187 #if ENABLE_ASH_ALIAS
9188 { BUILTIN_REGULAR "unalias" , unaliascmd },
9189 #endif
9190 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9191 { BUILTIN_REGULAR "wait" , waitcmd },
9194 /* Should match the above table! */
9195 #define COMMANDCMD (builtintab + \
9196 2 + \
9197 1 * ENABLE_ASH_BUILTIN_TEST + \
9198 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9199 1 * ENABLE_ASH_ALIAS + \
9200 1 * ENABLE_ASH_JOB_CONTROL + \
9202 #define EXECCMD (builtintab + \
9203 2 + \
9204 1 * ENABLE_ASH_BUILTIN_TEST + \
9205 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9206 1 * ENABLE_ASH_ALIAS + \
9207 1 * ENABLE_ASH_JOB_CONTROL + \
9208 3 + \
9209 1 * ENABLE_ASH_CMDCMD + \
9210 1 + \
9211 ENABLE_ASH_BUILTIN_ECHO + \
9215 * Search the table of builtin commands.
9217 static struct builtincmd *
9218 find_builtin(const char *name)
9220 struct builtincmd *bp;
9222 bp = bsearch(
9223 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
9224 pstrcmp
9226 return bp;
9230 * Execute a simple command.
9232 static int
9233 isassignment(const char *p)
9235 const char *q = endofname(p);
9236 if (p == q)
9237 return 0;
9238 return *q == '=';
9240 static int FAST_FUNC
9241 bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9243 /* Preserve exitstatus of a previous possible redirection
9244 * as POSIX mandates */
9245 return back_exitstatus;
9247 static void
9248 evalcommand(union node *cmd, int flags)
9250 static const struct builtincmd null_bltin = {
9251 "\0\0", bltincmd /* why three NULs? */
9253 struct stackmark smark;
9254 union node *argp;
9255 struct arglist arglist;
9256 struct arglist varlist;
9257 char **argv;
9258 int argc;
9259 const struct strlist *sp;
9260 struct cmdentry cmdentry;
9261 struct job *jp;
9262 char *lastarg;
9263 const char *path;
9264 int spclbltin;
9265 int status;
9266 char **nargv;
9267 struct builtincmd *bcmd;
9268 smallint cmd_is_exec;
9269 smallint pseudovarflag = 0;
9271 /* First expand the arguments. */
9272 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9273 setstackmark(&smark);
9274 back_exitstatus = 0;
9276 cmdentry.cmdtype = CMDBUILTIN;
9277 cmdentry.u.cmd = &null_bltin;
9278 varlist.lastp = &varlist.list;
9279 *varlist.lastp = NULL;
9280 arglist.lastp = &arglist.list;
9281 *arglist.lastp = NULL;
9283 argc = 0;
9284 if (cmd->ncmd.args) {
9285 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9286 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9289 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9290 struct strlist **spp;
9292 spp = arglist.lastp;
9293 if (pseudovarflag && isassignment(argp->narg.text))
9294 expandarg(argp, &arglist, EXP_VARTILDE);
9295 else
9296 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9298 for (sp = *spp; sp; sp = sp->next)
9299 argc++;
9302 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
9303 for (sp = arglist.list; sp; sp = sp->next) {
9304 TRACE(("evalcommand arg: %s\n", sp->text));
9305 *nargv++ = sp->text;
9307 *nargv = NULL;
9309 lastarg = NULL;
9310 if (iflag && funcnest == 0 && argc > 0)
9311 lastarg = nargv[-1];
9313 preverrout_fd = 2;
9314 expredir(cmd->ncmd.redirect);
9315 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
9317 path = vpath.var_text;
9318 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9319 struct strlist **spp;
9320 char *p;
9322 spp = varlist.lastp;
9323 expandarg(argp, &varlist, EXP_VARTILDE);
9326 * Modify the command lookup path, if a PATH= assignment
9327 * is present
9329 p = (*spp)->text;
9330 if (varcmp(p, path) == 0)
9331 path = p;
9334 /* Print the command if xflag is set. */
9335 if (xflag) {
9336 int n;
9337 const char *p = " %s" + 1;
9339 fdprintf(preverrout_fd, p, expandstr(ps4val()));
9340 sp = varlist.list;
9341 for (n = 0; n < 2; n++) {
9342 while (sp) {
9343 fdprintf(preverrout_fd, p, sp->text);
9344 sp = sp->next;
9345 p = " %s";
9347 sp = arglist.list;
9349 safe_write(preverrout_fd, "\n", 1);
9352 cmd_is_exec = 0;
9353 spclbltin = -1;
9355 /* Now locate the command. */
9356 if (argc) {
9357 int cmd_flag = DO_ERR;
9358 #if ENABLE_ASH_CMDCMD
9359 const char *oldpath = path + 5;
9360 #endif
9361 path += 5;
9362 for (;;) {
9363 find_command(argv[0], &cmdentry, cmd_flag, path);
9364 if (cmdentry.cmdtype == CMDUNKNOWN) {
9365 flush_stdout_stderr();
9366 status = 127;
9367 goto bail;
9370 /* implement bltin and command here */
9371 if (cmdentry.cmdtype != CMDBUILTIN)
9372 break;
9373 if (spclbltin < 0)
9374 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9375 if (cmdentry.u.cmd == EXECCMD)
9376 cmd_is_exec = 1;
9377 #if ENABLE_ASH_CMDCMD
9378 if (cmdentry.u.cmd == COMMANDCMD) {
9379 path = oldpath;
9380 nargv = parse_command_args(argv, &path);
9381 if (!nargv)
9382 break;
9383 argc -= nargv - argv;
9384 argv = nargv;
9385 cmd_flag |= DO_NOFUNC;
9386 } else
9387 #endif
9388 break;
9392 if (status) {
9393 /* We have a redirection error. */
9394 if (spclbltin > 0)
9395 raise_exception(EXERROR);
9396 bail:
9397 exitstatus = status;
9398 goto out;
9401 /* Execute the command. */
9402 switch (cmdentry.cmdtype) {
9403 default: {
9405 #if ENABLE_FEATURE_SH_NOFORK
9406 /* (1) BUG: if variables are set, we need to fork, or save/restore them
9407 * around run_nofork_applet() call.
9408 * (2) Should this check also be done in forkshell()?
9409 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9411 /* find_command() encodes applet_no as (-2 - applet_no) */
9412 int applet_no = (- cmdentry.u.index - 2);
9413 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
9414 listsetvar(varlist.list, VEXPORT|VSTACK);
9415 /* run <applet>_main() */
9416 exitstatus = run_nofork_applet(applet_no, argv);
9417 break;
9419 #endif
9420 /* Can we avoid forking off? For example, very last command
9421 * in a script or a subshell does not need forking,
9422 * we can just exec it.
9424 if (!(flags & EV_EXIT) || may_have_traps) {
9425 /* No, forking off a child is necessary */
9426 INT_OFF;
9427 jp = makejob(/*cmd,*/ 1);
9428 if (forkshell(jp, cmd, FORK_FG) != 0) {
9429 /* parent */
9430 exitstatus = waitforjob(jp);
9431 INT_ON;
9432 TRACE(("forked child exited with %d\n", exitstatus));
9433 break;
9435 /* child */
9436 FORCE_INT_ON;
9437 /* fall through to exec'ing external program */
9439 listsetvar(varlist.list, VEXPORT|VSTACK);
9440 shellexec(argv, path, cmdentry.u.index);
9441 /* NOTREACHED */
9442 } /* default */
9443 case CMDBUILTIN:
9444 cmdenviron = varlist.list;
9445 if (cmdenviron) {
9446 struct strlist *list = cmdenviron;
9447 int i = VNOSET;
9448 if (spclbltin > 0 || argc == 0) {
9449 i = 0;
9450 if (cmd_is_exec && argc > 1)
9451 i = VEXPORT;
9453 listsetvar(list, i);
9455 /* Tight loop with builtins only:
9456 * "while kill -0 $child; do true; done"
9457 * will never exit even if $child died, unless we do this
9458 * to reap the zombie and make kill detect that it's gone: */
9459 dowait(DOWAIT_NONBLOCK, NULL);
9461 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9462 int exit_status;
9463 int i = exception_type;
9464 if (i == EXEXIT)
9465 goto raise;
9466 exit_status = 2;
9467 if (i == EXINT)
9468 exit_status = 128 + SIGINT;
9469 if (i == EXSIG)
9470 exit_status = 128 + pending_sig;
9471 exitstatus = exit_status;
9472 if (i == EXINT || spclbltin > 0) {
9473 raise:
9474 longjmp(exception_handler->loc, 1);
9476 FORCE_INT_ON;
9478 break;
9480 case CMDFUNCTION:
9481 listsetvar(varlist.list, 0);
9482 /* See above for the rationale */
9483 dowait(DOWAIT_NONBLOCK, NULL);
9484 if (evalfun(cmdentry.u.func, argc, argv, flags))
9485 goto raise;
9486 break;
9488 } /* switch */
9490 out:
9491 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
9492 if (lastarg) {
9493 /* dsl: I think this is intended to be used to support
9494 * '_' in 'vi' command mode during line editing...
9495 * However I implemented that within libedit itself.
9497 setvar2("_", lastarg);
9499 popstackmark(&smark);
9502 static int
9503 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9505 char *volatile savecmdname;
9506 struct jmploc *volatile savehandler;
9507 struct jmploc jmploc;
9508 int i;
9510 savecmdname = commandname;
9511 i = setjmp(jmploc.loc);
9512 if (i)
9513 goto cmddone;
9514 savehandler = exception_handler;
9515 exception_handler = &jmploc;
9516 commandname = argv[0];
9517 argptr = argv + 1;
9518 optptr = NULL; /* initialize nextopt */
9519 exitstatus = (*cmd->builtin)(argc, argv);
9520 flush_stdout_stderr();
9521 cmddone:
9522 exitstatus |= ferror(stdout);
9523 clearerr(stdout);
9524 commandname = savecmdname;
9525 exception_handler = savehandler;
9527 return i;
9530 static int
9531 goodname(const char *p)
9533 return endofname(p)[0] == '\0';
9538 * Search for a command. This is called before we fork so that the
9539 * location of the command will be available in the parent as well as
9540 * the child. The check for "goodname" is an overly conservative
9541 * check that the name will not be subject to expansion.
9543 static void
9544 prehash(union node *n)
9546 struct cmdentry entry;
9548 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9549 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9553 /* ============ Builtin commands
9555 * Builtin commands whose functions are closely tied to evaluation
9556 * are implemented here.
9560 * Handle break and continue commands. Break, continue, and return are
9561 * all handled by setting the evalskip flag. The evaluation routines
9562 * above all check this flag, and if it is set they start skipping
9563 * commands rather than executing them. The variable skipcount is
9564 * the number of loops to break/continue, or the number of function
9565 * levels to return. (The latter is always 1.) It should probably
9566 * be an error to break out of more loops than exist, but it isn't
9567 * in the standard shell so we don't make it one here.
9569 static int FAST_FUNC
9570 breakcmd(int argc UNUSED_PARAM, char **argv)
9572 int n = argv[1] ? number(argv[1]) : 1;
9574 if (n <= 0)
9575 ash_msg_and_raise_error(msg_illnum, argv[1]);
9576 if (n > loopnest)
9577 n = loopnest;
9578 if (n > 0) {
9579 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9580 skipcount = n;
9582 return 0;
9586 /* ============ input.c
9588 * This implements the input routines used by the parser.
9591 enum {
9592 INPUT_PUSH_FILE = 1,
9593 INPUT_NOFILE_OK = 2,
9596 static smallint checkkwd;
9597 /* values of checkkwd variable */
9598 #define CHKALIAS 0x1
9599 #define CHKKWD 0x2
9600 #define CHKNL 0x4
9603 * Push a string back onto the input at this current parsefile level.
9604 * We handle aliases this way.
9606 #if !ENABLE_ASH_ALIAS
9607 #define pushstring(s, ap) pushstring(s)
9608 #endif
9609 static void
9610 pushstring(char *s, struct alias *ap)
9612 struct strpush *sp;
9613 int len;
9615 len = strlen(s);
9616 INT_OFF;
9617 if (g_parsefile->strpush) {
9618 sp = ckzalloc(sizeof(*sp));
9619 sp->prev = g_parsefile->strpush;
9620 } else {
9621 sp = &(g_parsefile->basestrpush);
9623 g_parsefile->strpush = sp;
9624 sp->prev_string = g_parsefile->next_to_pgetc;
9625 sp->prev_left_in_line = g_parsefile->left_in_line;
9626 #if ENABLE_ASH_ALIAS
9627 sp->ap = ap;
9628 if (ap) {
9629 ap->flag |= ALIASINUSE;
9630 sp->string = s;
9632 #endif
9633 g_parsefile->next_to_pgetc = s;
9634 g_parsefile->left_in_line = len;
9635 INT_ON;
9638 static void
9639 popstring(void)
9641 struct strpush *sp = g_parsefile->strpush;
9643 INT_OFF;
9644 #if ENABLE_ASH_ALIAS
9645 if (sp->ap) {
9646 if (g_parsefile->next_to_pgetc[-1] == ' '
9647 || g_parsefile->next_to_pgetc[-1] == '\t'
9649 checkkwd |= CHKALIAS;
9651 if (sp->string != sp->ap->val) {
9652 free(sp->string);
9654 sp->ap->flag &= ~ALIASINUSE;
9655 if (sp->ap->flag & ALIASDEAD) {
9656 unalias(sp->ap->name);
9659 #endif
9660 g_parsefile->next_to_pgetc = sp->prev_string;
9661 g_parsefile->left_in_line = sp->prev_left_in_line;
9662 g_parsefile->strpush = sp->prev;
9663 if (sp != &(g_parsefile->basestrpush))
9664 free(sp);
9665 INT_ON;
9668 //FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9669 //it peeks whether it is &>, and then pushes back both chars.
9670 //This function needs to save last *next_to_pgetc to buf[0]
9671 //to make two pungetc() reliable. Currently,
9672 // pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
9673 static int
9674 preadfd(void)
9676 int nr;
9677 char *buf = g_parsefile->buf;
9679 g_parsefile->next_to_pgetc = buf;
9680 #if ENABLE_FEATURE_EDITING
9681 retry:
9682 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
9683 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
9684 else {
9685 int timeout = -1;
9686 # if ENABLE_ASH_IDLE_TIMEOUT
9687 if (iflag) {
9688 const char *tmout_var = lookupvar("TMOUT");
9689 if (tmout_var) {
9690 timeout = atoi(tmout_var) * 1000;
9691 if (timeout <= 0)
9692 timeout = -1;
9695 # endif
9696 # if ENABLE_FEATURE_TAB_COMPLETION
9697 line_input_state->path_lookup = pathval();
9698 # endif
9699 reinit_unicode_for_ash();
9700 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
9701 if (nr == 0) {
9702 /* Ctrl+C pressed */
9703 if (trap[SIGINT]) {
9704 buf[0] = '\n';
9705 buf[1] = '\0';
9706 raise(SIGINT);
9707 return 1;
9709 goto retry;
9711 if (nr < 0) {
9712 if (errno == 0) {
9713 /* Ctrl+D pressed */
9714 nr = 0;
9716 # if ENABLE_ASH_IDLE_TIMEOUT
9717 else if (errno == EAGAIN && timeout > 0) {
9718 printf("\007timed out waiting for input: auto-logout\n");
9719 exitshell();
9721 # endif
9724 #else
9725 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
9726 #endif
9728 #if 0 /* disabled: nonblock_immune_read() handles this problem */
9729 if (nr < 0) {
9730 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9731 int flags = fcntl(0, F_GETFL);
9732 if (flags >= 0 && (flags & O_NONBLOCK)) {
9733 flags &= ~O_NONBLOCK;
9734 if (fcntl(0, F_SETFL, flags) >= 0) {
9735 out2str("sh: turning off NDELAY mode\n");
9736 goto retry;
9741 #endif
9742 return nr;
9746 * Refill the input buffer and return the next input character:
9748 * 1) If a string was pushed back on the input, pop it;
9749 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9750 * or we are reading from a string so we can't refill the buffer,
9751 * return EOF.
9752 * 3) If there is more stuff in this buffer, use it else call read to fill it.
9753 * 4) Process input up to the next newline, deleting nul characters.
9755 //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9756 #define pgetc_debug(...) ((void)0)
9757 static int
9758 preadbuffer(void)
9760 char *q;
9761 int more;
9763 while (g_parsefile->strpush) {
9764 #if ENABLE_ASH_ALIAS
9765 if (g_parsefile->left_in_line == -1
9766 && g_parsefile->strpush->ap
9767 && g_parsefile->next_to_pgetc[-1] != ' '
9768 && g_parsefile->next_to_pgetc[-1] != '\t'
9770 pgetc_debug("preadbuffer PEOA");
9771 return PEOA;
9773 #endif
9774 popstring();
9775 /* try "pgetc" now: */
9776 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9777 g_parsefile->left_in_line,
9778 g_parsefile->next_to_pgetc,
9779 g_parsefile->next_to_pgetc);
9780 if (--g_parsefile->left_in_line >= 0)
9781 return (unsigned char)(*g_parsefile->next_to_pgetc++);
9783 /* on both branches above g_parsefile->left_in_line < 0.
9784 * "pgetc" needs refilling.
9787 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
9788 * pungetc() may increment it a few times.
9789 * Assuming it won't increment it to less than -90.
9791 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
9792 pgetc_debug("preadbuffer PEOF1");
9793 /* even in failure keep left_in_line and next_to_pgetc
9794 * in lock step, for correct multi-layer pungetc.
9795 * left_in_line was decremented before preadbuffer(),
9796 * must inc next_to_pgetc: */
9797 g_parsefile->next_to_pgetc++;
9798 return PEOF;
9801 more = g_parsefile->left_in_buffer;
9802 if (more <= 0) {
9803 flush_stdout_stderr();
9804 again:
9805 more = preadfd();
9806 if (more <= 0) {
9807 /* don't try reading again */
9808 g_parsefile->left_in_line = -99;
9809 pgetc_debug("preadbuffer PEOF2");
9810 g_parsefile->next_to_pgetc++;
9811 return PEOF;
9815 /* Find out where's the end of line.
9816 * Set g_parsefile->left_in_line
9817 * and g_parsefile->left_in_buffer acordingly.
9818 * NUL chars are deleted.
9820 q = g_parsefile->next_to_pgetc;
9821 for (;;) {
9822 char c;
9824 more--;
9826 c = *q;
9827 if (c == '\0') {
9828 memmove(q, q + 1, more);
9829 } else {
9830 q++;
9831 if (c == '\n') {
9832 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9833 break;
9837 if (more <= 0) {
9838 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9839 if (g_parsefile->left_in_line < 0)
9840 goto again;
9841 break;
9844 g_parsefile->left_in_buffer = more;
9846 if (vflag) {
9847 char save = *q;
9848 *q = '\0';
9849 out2str(g_parsefile->next_to_pgetc);
9850 *q = save;
9853 pgetc_debug("preadbuffer at %d:%p'%s'",
9854 g_parsefile->left_in_line,
9855 g_parsefile->next_to_pgetc,
9856 g_parsefile->next_to_pgetc);
9857 return (unsigned char)*g_parsefile->next_to_pgetc++;
9860 #define pgetc_as_macro() \
9861 (--g_parsefile->left_in_line >= 0 \
9862 ? (unsigned char)*g_parsefile->next_to_pgetc++ \
9863 : preadbuffer() \
9866 static int
9867 pgetc(void)
9869 pgetc_debug("pgetc_fast at %d:%p'%s'",
9870 g_parsefile->left_in_line,
9871 g_parsefile->next_to_pgetc,
9872 g_parsefile->next_to_pgetc);
9873 return pgetc_as_macro();
9876 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9877 # define pgetc_fast() pgetc()
9878 #else
9879 # define pgetc_fast() pgetc_as_macro()
9880 #endif
9882 #if ENABLE_ASH_ALIAS
9883 static int
9884 pgetc_without_PEOA(void)
9886 int c;
9887 do {
9888 pgetc_debug("pgetc_fast at %d:%p'%s'",
9889 g_parsefile->left_in_line,
9890 g_parsefile->next_to_pgetc,
9891 g_parsefile->next_to_pgetc);
9892 c = pgetc_fast();
9893 } while (c == PEOA);
9894 return c;
9896 #else
9897 # define pgetc_without_PEOA() pgetc()
9898 #endif
9901 * Read a line from the script.
9903 static char *
9904 pfgets(char *line, int len)
9906 char *p = line;
9907 int nleft = len;
9908 int c;
9910 while (--nleft > 0) {
9911 c = pgetc_without_PEOA();
9912 if (c == PEOF) {
9913 if (p == line)
9914 return NULL;
9915 break;
9917 *p++ = c;
9918 if (c == '\n')
9919 break;
9921 *p = '\0';
9922 return line;
9926 * Undo the last call to pgetc. Only one character may be pushed back.
9927 * PEOF may be pushed back.
9929 static void
9930 pungetc(void)
9932 g_parsefile->left_in_line++;
9933 g_parsefile->next_to_pgetc--;
9934 pgetc_debug("pushed back to %d:%p'%s'",
9935 g_parsefile->left_in_line,
9936 g_parsefile->next_to_pgetc,
9937 g_parsefile->next_to_pgetc);
9941 * To handle the "." command, a stack of input files is used. Pushfile
9942 * adds a new entry to the stack and popfile restores the previous level.
9944 static void
9945 pushfile(void)
9947 struct parsefile *pf;
9949 pf = ckzalloc(sizeof(*pf));
9950 pf->prev = g_parsefile;
9951 pf->pf_fd = -1;
9952 /*pf->strpush = NULL; - ckzalloc did it */
9953 /*pf->basestrpush.prev = NULL;*/
9954 g_parsefile = pf;
9957 static void
9958 popfile(void)
9960 struct parsefile *pf = g_parsefile;
9962 INT_OFF;
9963 if (pf->pf_fd >= 0)
9964 close(pf->pf_fd);
9965 free(pf->buf);
9966 while (pf->strpush)
9967 popstring();
9968 g_parsefile = pf->prev;
9969 free(pf);
9970 INT_ON;
9974 * Return to top level.
9976 static void
9977 popallfiles(void)
9979 while (g_parsefile != &basepf)
9980 popfile();
9984 * Close the file(s) that the shell is reading commands from. Called
9985 * after a fork is done.
9987 static void
9988 closescript(void)
9990 popallfiles();
9991 if (g_parsefile->pf_fd > 0) {
9992 close(g_parsefile->pf_fd);
9993 g_parsefile->pf_fd = 0;
9998 * Like setinputfile, but takes an open file descriptor. Call this with
9999 * interrupts off.
10001 static void
10002 setinputfd(int fd, int push)
10004 close_on_exec_on(fd);
10005 if (push) {
10006 pushfile();
10007 g_parsefile->buf = NULL;
10009 g_parsefile->pf_fd = fd;
10010 if (g_parsefile->buf == NULL)
10011 g_parsefile->buf = ckmalloc(IBUFSIZ);
10012 g_parsefile->left_in_buffer = 0;
10013 g_parsefile->left_in_line = 0;
10014 g_parsefile->linno = 1;
10018 * Set the input to take input from a file. If push is set, push the
10019 * old input onto the stack first.
10021 static int
10022 setinputfile(const char *fname, int flags)
10024 int fd;
10025 int fd2;
10027 INT_OFF;
10028 fd = open(fname, O_RDONLY);
10029 if (fd < 0) {
10030 if (flags & INPUT_NOFILE_OK)
10031 goto out;
10032 ash_msg_and_raise_error("can't open '%s'", fname);
10034 if (fd < 10) {
10035 fd2 = copyfd(fd, 10);
10036 close(fd);
10037 if (fd2 < 0)
10038 ash_msg_and_raise_error("out of file descriptors");
10039 fd = fd2;
10041 setinputfd(fd, flags & INPUT_PUSH_FILE);
10042 out:
10043 INT_ON;
10044 return fd;
10048 * Like setinputfile, but takes input from a string.
10050 static void
10051 setinputstring(char *string)
10053 INT_OFF;
10054 pushfile();
10055 g_parsefile->next_to_pgetc = string;
10056 g_parsefile->left_in_line = strlen(string);
10057 g_parsefile->buf = NULL;
10058 g_parsefile->linno = 1;
10059 INT_ON;
10063 /* ============ mail.c
10065 * Routines to check for mail.
10068 #if ENABLE_ASH_MAIL
10070 #define MAXMBOXES 10
10072 /* times of mailboxes */
10073 static time_t mailtime[MAXMBOXES];
10074 /* Set if MAIL or MAILPATH is changed. */
10075 static smallint mail_var_path_changed;
10078 * Print appropriate message(s) if mail has arrived.
10079 * If mail_var_path_changed is set,
10080 * then the value of MAIL has mail_var_path_changed,
10081 * so we just update the values.
10083 static void
10084 chkmail(void)
10086 const char *mpath;
10087 char *p;
10088 char *q;
10089 time_t *mtp;
10090 struct stackmark smark;
10091 struct stat statb;
10093 setstackmark(&smark);
10094 mpath = mpathset() ? mpathval() : mailval();
10095 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
10096 p = path_advance(&mpath, nullstr);
10097 if (p == NULL)
10098 break;
10099 if (*p == '\0')
10100 continue;
10101 for (q = p; *q; q++)
10102 continue;
10103 #if DEBUG
10104 if (q[-1] != '/')
10105 abort();
10106 #endif
10107 q[-1] = '\0'; /* delete trailing '/' */
10108 if (stat(p, &statb) < 0) {
10109 *mtp = 0;
10110 continue;
10112 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
10113 fprintf(
10114 stderr, "%s\n",
10115 pathopt ? pathopt : "you have mail"
10118 *mtp = statb.st_mtime;
10120 mail_var_path_changed = 0;
10121 popstackmark(&smark);
10124 static void FAST_FUNC
10125 changemail(const char *val UNUSED_PARAM)
10127 mail_var_path_changed = 1;
10130 #endif /* ASH_MAIL */
10133 /* ============ ??? */
10136 * Set the shell parameters.
10138 static void
10139 setparam(char **argv)
10141 char **newparam;
10142 char **ap;
10143 int nparam;
10145 for (nparam = 0; argv[nparam]; nparam++)
10146 continue;
10147 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10148 while (*argv) {
10149 *ap++ = ckstrdup(*argv++);
10151 *ap = NULL;
10152 freeparam(&shellparam);
10153 shellparam.malloced = 1;
10154 shellparam.nparam = nparam;
10155 shellparam.p = newparam;
10156 #if ENABLE_ASH_GETOPTS
10157 shellparam.optind = 1;
10158 shellparam.optoff = -1;
10159 #endif
10163 * Process shell options. The global variable argptr contains a pointer
10164 * to the argument list; we advance it past the options.
10166 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10167 * For a non-interactive shell, an error condition encountered
10168 * by a special built-in ... shall cause the shell to write a diagnostic message
10169 * to standard error and exit as shown in the following table:
10170 * Error Special Built-In
10171 * ...
10172 * Utility syntax error (option or operand error) Shall exit
10173 * ...
10174 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10175 * we see that bash does not do that (set "finishes" with error code 1 instead,
10176 * and shell continues), and people rely on this behavior!
10177 * Testcase:
10178 * set -o barfoo 2>/dev/null
10179 * echo $?
10181 * Oh well. Let's mimic that.
10183 static int
10184 plus_minus_o(char *name, int val)
10186 int i;
10188 if (name) {
10189 for (i = 0; i < NOPTS; i++) {
10190 if (strcmp(name, optnames(i)) == 0) {
10191 optlist[i] = val;
10192 return 0;
10195 ash_msg("illegal option %co %s", val ? '-' : '+', name);
10196 return 1;
10198 for (i = 0; i < NOPTS; i++) {
10199 if (val) {
10200 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10201 } else {
10202 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10205 return 0;
10207 static void
10208 setoption(int flag, int val)
10210 int i;
10212 for (i = 0; i < NOPTS; i++) {
10213 if (optletters(i) == flag) {
10214 optlist[i] = val;
10215 return;
10218 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
10219 /* NOTREACHED */
10221 static int
10222 options(int cmdline)
10224 char *p;
10225 int val;
10226 int c;
10228 if (cmdline)
10229 minusc = NULL;
10230 while ((p = *argptr) != NULL) {
10231 c = *p++;
10232 if (c != '-' && c != '+')
10233 break;
10234 argptr++;
10235 val = 0; /* val = 0 if c == '+' */
10236 if (c == '-') {
10237 val = 1;
10238 if (p[0] == '\0' || LONE_DASH(p)) {
10239 if (!cmdline) {
10240 /* "-" means turn off -x and -v */
10241 if (p[0] == '\0')
10242 xflag = vflag = 0;
10243 /* "--" means reset params */
10244 else if (*argptr == NULL)
10245 setparam(argptr);
10247 break; /* "-" or "--" terminates options */
10250 /* first char was + or - */
10251 while ((c = *p++) != '\0') {
10252 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
10253 if (c == 'c' && cmdline) {
10254 minusc = p; /* command is after shell args */
10255 } else if (c == 'o') {
10256 if (plus_minus_o(*argptr, val)) {
10257 /* it already printed err message */
10258 return 1; /* error */
10260 if (*argptr)
10261 argptr++;
10262 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10263 isloginsh = 1;
10264 /* bash does not accept +-login, we also won't */
10265 } else if (cmdline && val && (c == '-')) { /* long options */
10266 if (strcmp(p, "login") == 0)
10267 isloginsh = 1;
10268 break;
10269 } else {
10270 setoption(c, val);
10274 return 0;
10278 * The shift builtin command.
10280 static int FAST_FUNC
10281 shiftcmd(int argc UNUSED_PARAM, char **argv)
10283 int n;
10284 char **ap1, **ap2;
10286 n = 1;
10287 if (argv[1])
10288 n = number(argv[1]);
10289 if (n > shellparam.nparam)
10290 n = 0; /* bash compat, was = shellparam.nparam; */
10291 INT_OFF;
10292 shellparam.nparam -= n;
10293 for (ap1 = shellparam.p; --n >= 0; ap1++) {
10294 if (shellparam.malloced)
10295 free(*ap1);
10297 ap2 = shellparam.p;
10298 while ((*ap2++ = *ap1++) != NULL)
10299 continue;
10300 #if ENABLE_ASH_GETOPTS
10301 shellparam.optind = 1;
10302 shellparam.optoff = -1;
10303 #endif
10304 INT_ON;
10305 return 0;
10309 * POSIX requires that 'set' (but not export or readonly) output the
10310 * variables in lexicographic order - by the locale's collating order (sigh).
10311 * Maybe we could keep them in an ordered balanced binary tree
10312 * instead of hashed lists.
10313 * For now just roll 'em through qsort for printing...
10315 static int
10316 showvars(const char *sep_prefix, int on, int off)
10318 const char *sep;
10319 char **ep, **epend;
10321 ep = listvars(on, off, &epend);
10322 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10324 sep = *sep_prefix ? " " : sep_prefix;
10326 for (; ep < epend; ep++) {
10327 const char *p;
10328 const char *q;
10330 p = strchrnul(*ep, '=');
10331 q = nullstr;
10332 if (*p)
10333 q = single_quote(++p);
10334 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10336 return 0;
10340 * The set command builtin.
10342 static int FAST_FUNC
10343 setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10345 int retval;
10347 if (!argv[1])
10348 return showvars(nullstr, 0, VUNSET);
10350 INT_OFF;
10351 retval = options(/*cmdline:*/ 0);
10352 if (retval == 0) { /* if no parse error... */
10353 optschanged();
10354 if (*argptr != NULL) {
10355 setparam(argptr);
10358 INT_ON;
10359 return retval;
10362 #if ENABLE_ASH_RANDOM_SUPPORT
10363 static void FAST_FUNC
10364 change_random(const char *value)
10366 uint32_t t;
10368 if (value == NULL) {
10369 /* "get", generate */
10370 t = next_random(&random_gen);
10371 /* set without recursion */
10372 setvar(vrandom.var_text, utoa(t), VNOFUNC);
10373 vrandom.flags &= ~VNOFUNC;
10374 } else {
10375 /* set/reset */
10376 t = strtoul(value, NULL, 10);
10377 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
10380 #endif
10382 #if ENABLE_ASH_GETOPTS
10383 static int
10384 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
10386 char *p, *q;
10387 char c = '?';
10388 int done = 0;
10389 int err = 0;
10390 char s[12];
10391 char **optnext;
10393 if (*param_optind < 1)
10394 return 1;
10395 optnext = optfirst + *param_optind - 1;
10397 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
10398 p = NULL;
10399 else
10400 p = optnext[-1] + *optoff;
10401 if (p == NULL || *p == '\0') {
10402 /* Current word is done, advance */
10403 p = *optnext;
10404 if (p == NULL || *p != '-' || *++p == '\0') {
10405 atend:
10406 p = NULL;
10407 done = 1;
10408 goto out;
10410 optnext++;
10411 if (LONE_DASH(p)) /* check for "--" */
10412 goto atend;
10415 c = *p++;
10416 for (q = optstr; *q != c;) {
10417 if (*q == '\0') {
10418 if (optstr[0] == ':') {
10419 s[0] = c;
10420 s[1] = '\0';
10421 err |= setvarsafe("OPTARG", s, 0);
10422 } else {
10423 fprintf(stderr, "Illegal option -%c\n", c);
10424 unsetvar("OPTARG");
10426 c = '?';
10427 goto out;
10429 if (*++q == ':')
10430 q++;
10433 if (*++q == ':') {
10434 if (*p == '\0' && (p = *optnext) == NULL) {
10435 if (optstr[0] == ':') {
10436 s[0] = c;
10437 s[1] = '\0';
10438 err |= setvarsafe("OPTARG", s, 0);
10439 c = ':';
10440 } else {
10441 fprintf(stderr, "No arg for -%c option\n", c);
10442 unsetvar("OPTARG");
10443 c = '?';
10445 goto out;
10448 if (p == *optnext)
10449 optnext++;
10450 err |= setvarsafe("OPTARG", p, 0);
10451 p = NULL;
10452 } else
10453 err |= setvarsafe("OPTARG", nullstr, 0);
10454 out:
10455 *optoff = p ? p - *(optnext - 1) : -1;
10456 *param_optind = optnext - optfirst + 1;
10457 fmtstr(s, sizeof(s), "%d", *param_optind);
10458 err |= setvarsafe("OPTIND", s, VNOFUNC);
10459 s[0] = c;
10460 s[1] = '\0';
10461 err |= setvarsafe(optvar, s, 0);
10462 if (err) {
10463 *param_optind = 1;
10464 *optoff = -1;
10465 flush_stdout_stderr();
10466 raise_exception(EXERROR);
10468 return done;
10472 * The getopts builtin. Shellparam.optnext points to the next argument
10473 * to be processed. Shellparam.optptr points to the next character to
10474 * be processed in the current argument. If shellparam.optnext is NULL,
10475 * then it's the first time getopts has been called.
10477 static int FAST_FUNC
10478 getoptscmd(int argc, char **argv)
10480 char **optbase;
10482 if (argc < 3)
10483 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
10484 if (argc == 3) {
10485 optbase = shellparam.p;
10486 if (shellparam.optind > shellparam.nparam + 1) {
10487 shellparam.optind = 1;
10488 shellparam.optoff = -1;
10490 } else {
10491 optbase = &argv[3];
10492 if (shellparam.optind > argc - 2) {
10493 shellparam.optind = 1;
10494 shellparam.optoff = -1;
10498 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
10499 &shellparam.optoff);
10501 #endif /* ASH_GETOPTS */
10504 /* ============ Shell parser */
10506 struct heredoc {
10507 struct heredoc *next; /* next here document in list */
10508 union node *here; /* redirection node */
10509 char *eofmark; /* string indicating end of input */
10510 smallint striptabs; /* if set, strip leading tabs */
10513 static smallint tokpushback; /* last token pushed back */
10514 static smallint parsebackquote; /* nonzero if we are inside backquotes */
10515 static smallint quoteflag; /* set if (part of) last token was quoted */
10516 static token_id_t lasttoken; /* last token read (integer id Txxx) */
10517 static struct heredoc *heredoclist; /* list of here documents to read */
10518 static char *wordtext; /* text of last word returned by readtoken */
10519 static struct nodelist *backquotelist;
10520 static union node *redirnode;
10521 static struct heredoc *heredoc;
10523 static const char *
10524 tokname(char *buf, int tok)
10526 if (tok < TSEMI)
10527 return tokname_array[tok] + 1;
10528 sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
10529 return buf;
10532 /* raise_error_unexpected_syntax:
10533 * Called when an unexpected token is read during the parse. The argument
10534 * is the token that is expected, or -1 if more than one type of token can
10535 * occur at this point.
10537 static void raise_error_unexpected_syntax(int) NORETURN;
10538 static void
10539 raise_error_unexpected_syntax(int token)
10541 char msg[64];
10542 char buf[16];
10543 int l;
10545 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
10546 if (token >= 0)
10547 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
10548 raise_error_syntax(msg);
10549 /* NOTREACHED */
10552 #define EOFMARKLEN 79
10554 /* parsing is heavily cross-recursive, need these forward decls */
10555 static union node *andor(void);
10556 static union node *pipeline(void);
10557 static union node *parse_command(void);
10558 static void parseheredoc(void);
10559 static char peektoken(void);
10560 static int readtoken(void);
10562 static union node *
10563 list(int nlflag)
10565 union node *n1, *n2, *n3;
10566 int tok;
10568 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10569 if (nlflag == 2 && peektoken())
10570 return NULL;
10571 n1 = NULL;
10572 for (;;) {
10573 n2 = andor();
10574 tok = readtoken();
10575 if (tok == TBACKGND) {
10576 if (n2->type == NPIPE) {
10577 n2->npipe.pipe_backgnd = 1;
10578 } else {
10579 if (n2->type != NREDIR) {
10580 n3 = stzalloc(sizeof(struct nredir));
10581 n3->nredir.n = n2;
10582 /*n3->nredir.redirect = NULL; - stzalloc did it */
10583 n2 = n3;
10585 n2->type = NBACKGND;
10588 if (n1 == NULL) {
10589 n1 = n2;
10590 } else {
10591 n3 = stzalloc(sizeof(struct nbinary));
10592 n3->type = NSEMI;
10593 n3->nbinary.ch1 = n1;
10594 n3->nbinary.ch2 = n2;
10595 n1 = n3;
10597 switch (tok) {
10598 case TBACKGND:
10599 case TSEMI:
10600 tok = readtoken();
10601 /* fall through */
10602 case TNL:
10603 if (tok == TNL) {
10604 parseheredoc();
10605 if (nlflag == 1)
10606 return n1;
10607 } else {
10608 tokpushback = 1;
10610 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10611 if (peektoken())
10612 return n1;
10613 break;
10614 case TEOF:
10615 if (heredoclist)
10616 parseheredoc();
10617 else
10618 pungetc(); /* push back EOF on input */
10619 return n1;
10620 default:
10621 if (nlflag == 1)
10622 raise_error_unexpected_syntax(-1);
10623 tokpushback = 1;
10624 return n1;
10629 static union node *
10630 andor(void)
10632 union node *n1, *n2, *n3;
10633 int t;
10635 n1 = pipeline();
10636 for (;;) {
10637 t = readtoken();
10638 if (t == TAND) {
10639 t = NAND;
10640 } else if (t == TOR) {
10641 t = NOR;
10642 } else {
10643 tokpushback = 1;
10644 return n1;
10646 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10647 n2 = pipeline();
10648 n3 = stzalloc(sizeof(struct nbinary));
10649 n3->type = t;
10650 n3->nbinary.ch1 = n1;
10651 n3->nbinary.ch2 = n2;
10652 n1 = n3;
10656 static union node *
10657 pipeline(void)
10659 union node *n1, *n2, *pipenode;
10660 struct nodelist *lp, *prev;
10661 int negate;
10663 negate = 0;
10664 TRACE(("pipeline: entered\n"));
10665 if (readtoken() == TNOT) {
10666 negate = !negate;
10667 checkkwd = CHKKWD | CHKALIAS;
10668 } else
10669 tokpushback = 1;
10670 n1 = parse_command();
10671 if (readtoken() == TPIPE) {
10672 pipenode = stzalloc(sizeof(struct npipe));
10673 pipenode->type = NPIPE;
10674 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10675 lp = stzalloc(sizeof(struct nodelist));
10676 pipenode->npipe.cmdlist = lp;
10677 lp->n = n1;
10678 do {
10679 prev = lp;
10680 lp = stzalloc(sizeof(struct nodelist));
10681 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10682 lp->n = parse_command();
10683 prev->next = lp;
10684 } while (readtoken() == TPIPE);
10685 lp->next = NULL;
10686 n1 = pipenode;
10688 tokpushback = 1;
10689 if (negate) {
10690 n2 = stzalloc(sizeof(struct nnot));
10691 n2->type = NNOT;
10692 n2->nnot.com = n1;
10693 return n2;
10695 return n1;
10698 static union node *
10699 makename(void)
10701 union node *n;
10703 n = stzalloc(sizeof(struct narg));
10704 n->type = NARG;
10705 /*n->narg.next = NULL; - stzalloc did it */
10706 n->narg.text = wordtext;
10707 n->narg.backquote = backquotelist;
10708 return n;
10711 static void
10712 fixredir(union node *n, const char *text, int err)
10714 int fd;
10716 TRACE(("Fix redir %s %d\n", text, err));
10717 if (!err)
10718 n->ndup.vname = NULL;
10720 fd = bb_strtou(text, NULL, 10);
10721 if (!errno && fd >= 0)
10722 n->ndup.dupfd = fd;
10723 else if (LONE_DASH(text))
10724 n->ndup.dupfd = -1;
10725 else {
10726 if (err)
10727 raise_error_syntax("bad fd number");
10728 n->ndup.vname = makename();
10733 * Returns true if the text contains nothing to expand (no dollar signs
10734 * or backquotes).
10736 static int
10737 noexpand(const char *text)
10739 unsigned char c;
10741 while ((c = *text++) != '\0') {
10742 if (c == CTLQUOTEMARK)
10743 continue;
10744 if (c == CTLESC)
10745 text++;
10746 else if (SIT(c, BASESYNTAX) == CCTL)
10747 return 0;
10749 return 1;
10752 static void
10753 parsefname(void)
10755 union node *n = redirnode;
10757 if (readtoken() != TWORD)
10758 raise_error_unexpected_syntax(-1);
10759 if (n->type == NHERE) {
10760 struct heredoc *here = heredoc;
10761 struct heredoc *p;
10762 int i;
10764 if (quoteflag == 0)
10765 n->type = NXHERE;
10766 TRACE(("Here document %d\n", n->type));
10767 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10768 raise_error_syntax("illegal eof marker for << redirection");
10769 rmescapes(wordtext, 0);
10770 here->eofmark = wordtext;
10771 here->next = NULL;
10772 if (heredoclist == NULL)
10773 heredoclist = here;
10774 else {
10775 for (p = heredoclist; p->next; p = p->next)
10776 continue;
10777 p->next = here;
10779 } else if (n->type == NTOFD || n->type == NFROMFD) {
10780 fixredir(n, wordtext, 0);
10781 } else {
10782 n->nfile.fname = makename();
10786 static union node *
10787 simplecmd(void)
10789 union node *args, **app;
10790 union node *n = NULL;
10791 union node *vars, **vpp;
10792 union node **rpp, *redir;
10793 int savecheckkwd;
10794 #if ENABLE_ASH_BASH_COMPAT
10795 smallint double_brackets_flag = 0;
10796 #endif
10798 args = NULL;
10799 app = &args;
10800 vars = NULL;
10801 vpp = &vars;
10802 redir = NULL;
10803 rpp = &redir;
10805 savecheckkwd = CHKALIAS;
10806 for (;;) {
10807 int t;
10808 checkkwd = savecheckkwd;
10809 t = readtoken();
10810 switch (t) {
10811 #if ENABLE_ASH_BASH_COMPAT
10812 case TAND: /* "&&" */
10813 case TOR: /* "||" */
10814 if (!double_brackets_flag) {
10815 tokpushback = 1;
10816 goto out;
10818 wordtext = (char *) (t == TAND ? "-a" : "-o");
10819 #endif
10820 case TWORD:
10821 n = stzalloc(sizeof(struct narg));
10822 n->type = NARG;
10823 /*n->narg.next = NULL; - stzalloc did it */
10824 n->narg.text = wordtext;
10825 #if ENABLE_ASH_BASH_COMPAT
10826 if (strcmp("[[", wordtext) == 0)
10827 double_brackets_flag = 1;
10828 else if (strcmp("]]", wordtext) == 0)
10829 double_brackets_flag = 0;
10830 #endif
10831 n->narg.backquote = backquotelist;
10832 if (savecheckkwd && isassignment(wordtext)) {
10833 *vpp = n;
10834 vpp = &n->narg.next;
10835 } else {
10836 *app = n;
10837 app = &n->narg.next;
10838 savecheckkwd = 0;
10840 break;
10841 case TREDIR:
10842 *rpp = n = redirnode;
10843 rpp = &n->nfile.next;
10844 parsefname(); /* read name of redirection file */
10845 break;
10846 case TLP:
10847 if (args && app == &args->narg.next
10848 && !vars && !redir
10850 struct builtincmd *bcmd;
10851 const char *name;
10853 /* We have a function */
10854 if (readtoken() != TRP)
10855 raise_error_unexpected_syntax(TRP);
10856 name = n->narg.text;
10857 if (!goodname(name)
10858 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10860 raise_error_syntax("bad function name");
10862 n->type = NDEFUN;
10863 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10864 n->narg.next = parse_command();
10865 return n;
10867 /* fall through */
10868 default:
10869 tokpushback = 1;
10870 goto out;
10873 out:
10874 *app = NULL;
10875 *vpp = NULL;
10876 *rpp = NULL;
10877 n = stzalloc(sizeof(struct ncmd));
10878 n->type = NCMD;
10879 n->ncmd.args = args;
10880 n->ncmd.assign = vars;
10881 n->ncmd.redirect = redir;
10882 return n;
10885 static union node *
10886 parse_command(void)
10888 union node *n1, *n2;
10889 union node *ap, **app;
10890 union node *cp, **cpp;
10891 union node *redir, **rpp;
10892 union node **rpp2;
10893 int t;
10895 redir = NULL;
10896 rpp2 = &redir;
10898 switch (readtoken()) {
10899 default:
10900 raise_error_unexpected_syntax(-1);
10901 /* NOTREACHED */
10902 case TIF:
10903 n1 = stzalloc(sizeof(struct nif));
10904 n1->type = NIF;
10905 n1->nif.test = list(0);
10906 if (readtoken() != TTHEN)
10907 raise_error_unexpected_syntax(TTHEN);
10908 n1->nif.ifpart = list(0);
10909 n2 = n1;
10910 while (readtoken() == TELIF) {
10911 n2->nif.elsepart = stzalloc(sizeof(struct nif));
10912 n2 = n2->nif.elsepart;
10913 n2->type = NIF;
10914 n2->nif.test = list(0);
10915 if (readtoken() != TTHEN)
10916 raise_error_unexpected_syntax(TTHEN);
10917 n2->nif.ifpart = list(0);
10919 if (lasttoken == TELSE)
10920 n2->nif.elsepart = list(0);
10921 else {
10922 n2->nif.elsepart = NULL;
10923 tokpushback = 1;
10925 t = TFI;
10926 break;
10927 case TWHILE:
10928 case TUNTIL: {
10929 int got;
10930 n1 = stzalloc(sizeof(struct nbinary));
10931 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
10932 n1->nbinary.ch1 = list(0);
10933 got = readtoken();
10934 if (got != TDO) {
10935 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
10936 got == TWORD ? wordtext : ""));
10937 raise_error_unexpected_syntax(TDO);
10939 n1->nbinary.ch2 = list(0);
10940 t = TDONE;
10941 break;
10943 case TFOR:
10944 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10945 raise_error_syntax("bad for loop variable");
10946 n1 = stzalloc(sizeof(struct nfor));
10947 n1->type = NFOR;
10948 n1->nfor.var = wordtext;
10949 checkkwd = CHKKWD | CHKALIAS;
10950 if (readtoken() == TIN) {
10951 app = &ap;
10952 while (readtoken() == TWORD) {
10953 n2 = stzalloc(sizeof(struct narg));
10954 n2->type = NARG;
10955 /*n2->narg.next = NULL; - stzalloc did it */
10956 n2->narg.text = wordtext;
10957 n2->narg.backquote = backquotelist;
10958 *app = n2;
10959 app = &n2->narg.next;
10961 *app = NULL;
10962 n1->nfor.args = ap;
10963 if (lasttoken != TNL && lasttoken != TSEMI)
10964 raise_error_unexpected_syntax(-1);
10965 } else {
10966 n2 = stzalloc(sizeof(struct narg));
10967 n2->type = NARG;
10968 /*n2->narg.next = NULL; - stzalloc did it */
10969 n2->narg.text = (char *)dolatstr;
10970 /*n2->narg.backquote = NULL;*/
10971 n1->nfor.args = n2;
10973 * Newline or semicolon here is optional (but note
10974 * that the original Bourne shell only allowed NL).
10976 if (lasttoken != TNL && lasttoken != TSEMI)
10977 tokpushback = 1;
10979 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10980 if (readtoken() != TDO)
10981 raise_error_unexpected_syntax(TDO);
10982 n1->nfor.body = list(0);
10983 t = TDONE;
10984 break;
10985 case TCASE:
10986 n1 = stzalloc(sizeof(struct ncase));
10987 n1->type = NCASE;
10988 if (readtoken() != TWORD)
10989 raise_error_unexpected_syntax(TWORD);
10990 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
10991 n2->type = NARG;
10992 /*n2->narg.next = NULL; - stzalloc did it */
10993 n2->narg.text = wordtext;
10994 n2->narg.backquote = backquotelist;
10995 do {
10996 checkkwd = CHKKWD | CHKALIAS;
10997 } while (readtoken() == TNL);
10998 if (lasttoken != TIN)
10999 raise_error_unexpected_syntax(TIN);
11000 cpp = &n1->ncase.cases;
11001 next_case:
11002 checkkwd = CHKNL | CHKKWD;
11003 t = readtoken();
11004 while (t != TESAC) {
11005 if (lasttoken == TLP)
11006 readtoken();
11007 *cpp = cp = stzalloc(sizeof(struct nclist));
11008 cp->type = NCLIST;
11009 app = &cp->nclist.pattern;
11010 for (;;) {
11011 *app = ap = stzalloc(sizeof(struct narg));
11012 ap->type = NARG;
11013 /*ap->narg.next = NULL; - stzalloc did it */
11014 ap->narg.text = wordtext;
11015 ap->narg.backquote = backquotelist;
11016 if (readtoken() != TPIPE)
11017 break;
11018 app = &ap->narg.next;
11019 readtoken();
11021 //ap->narg.next = NULL;
11022 if (lasttoken != TRP)
11023 raise_error_unexpected_syntax(TRP);
11024 cp->nclist.body = list(2);
11026 cpp = &cp->nclist.next;
11028 checkkwd = CHKNL | CHKKWD;
11029 t = readtoken();
11030 if (t != TESAC) {
11031 if (t != TENDCASE)
11032 raise_error_unexpected_syntax(TENDCASE);
11033 goto next_case;
11036 *cpp = NULL;
11037 goto redir;
11038 case TLP:
11039 n1 = stzalloc(sizeof(struct nredir));
11040 n1->type = NSUBSHELL;
11041 n1->nredir.n = list(0);
11042 /*n1->nredir.redirect = NULL; - stzalloc did it */
11043 t = TRP;
11044 break;
11045 case TBEGIN:
11046 n1 = list(0);
11047 t = TEND;
11048 break;
11049 case TWORD:
11050 case TREDIR:
11051 tokpushback = 1;
11052 return simplecmd();
11055 if (readtoken() != t)
11056 raise_error_unexpected_syntax(t);
11058 redir:
11059 /* Now check for redirection which may follow command */
11060 checkkwd = CHKKWD | CHKALIAS;
11061 rpp = rpp2;
11062 while (readtoken() == TREDIR) {
11063 *rpp = n2 = redirnode;
11064 rpp = &n2->nfile.next;
11065 parsefname();
11067 tokpushback = 1;
11068 *rpp = NULL;
11069 if (redir) {
11070 if (n1->type != NSUBSHELL) {
11071 n2 = stzalloc(sizeof(struct nredir));
11072 n2->type = NREDIR;
11073 n2->nredir.n = n1;
11074 n1 = n2;
11076 n1->nredir.redirect = redir;
11078 return n1;
11081 #if ENABLE_ASH_BASH_COMPAT
11082 static int decode_dollar_squote(void)
11084 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11085 int c, cnt;
11086 char *p;
11087 char buf[4];
11089 c = pgetc();
11090 p = strchr(C_escapes, c);
11091 if (p) {
11092 buf[0] = c;
11093 p = buf;
11094 cnt = 3;
11095 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11096 do {
11097 c = pgetc();
11098 *++p = c;
11099 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11100 pungetc();
11101 } else if (c == 'x') { /* \xHH */
11102 do {
11103 c = pgetc();
11104 *++p = c;
11105 } while (isxdigit(c) && --cnt);
11106 pungetc();
11107 if (cnt == 3) { /* \x but next char is "bad" */
11108 c = 'x';
11109 goto unrecognized;
11111 } else { /* simple seq like \\ or \t */
11112 p++;
11114 *p = '\0';
11115 p = buf;
11116 c = bb_process_escape_sequence((void*)&p);
11117 } else { /* unrecognized "\z": print both chars unless ' or " */
11118 if (c != '\'' && c != '"') {
11119 unrecognized:
11120 c |= 0x100; /* "please encode \, then me" */
11123 return c;
11125 #endif
11128 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11129 * is not NULL, read a here document. In the latter case, eofmark is the
11130 * word which marks the end of the document and striptabs is true if
11131 * leading tabs should be stripped from the document. The argument c
11132 * is the first character of the input token or document.
11134 * Because C does not have internal subroutines, I have simulated them
11135 * using goto's to implement the subroutine linkage. The following macros
11136 * will run code that appears at the end of readtoken1.
11138 #define CHECKEND() {goto checkend; checkend_return:;}
11139 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
11140 #define PARSESUB() {goto parsesub; parsesub_return:;}
11141 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11142 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11143 #define PARSEARITH() {goto parsearith; parsearith_return:;}
11144 static int
11145 readtoken1(int c, int syntax, char *eofmark, int striptabs)
11147 /* NB: syntax parameter fits into smallint */
11148 /* c parameter is an unsigned char or PEOF or PEOA */
11149 char *out;
11150 int len;
11151 char line[EOFMARKLEN + 1];
11152 struct nodelist *bqlist;
11153 smallint quotef;
11154 smallint dblquote;
11155 smallint oldstyle;
11156 smallint prevsyntax; /* syntax before arithmetic */
11157 #if ENABLE_ASH_EXPAND_PRMT
11158 smallint pssyntax; /* we are expanding a prompt string */
11159 #endif
11160 int varnest; /* levels of variables expansion */
11161 int arinest; /* levels of arithmetic expansion */
11162 int parenlevel; /* levels of parens in arithmetic */
11163 int dqvarnest; /* levels of variables expansion within double quotes */
11165 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
11167 #if __GNUC__
11168 /* Avoid longjmp clobbering */
11169 (void) &out;
11170 (void) &quotef;
11171 (void) &dblquote;
11172 (void) &varnest;
11173 (void) &arinest;
11174 (void) &parenlevel;
11175 (void) &dqvarnest;
11176 (void) &oldstyle;
11177 (void) &prevsyntax;
11178 (void) &syntax;
11179 #endif
11180 startlinno = g_parsefile->linno;
11181 bqlist = NULL;
11182 quotef = 0;
11183 prevsyntax = 0;
11184 #if ENABLE_ASH_EXPAND_PRMT
11185 pssyntax = (syntax == PSSYNTAX);
11186 if (pssyntax)
11187 syntax = DQSYNTAX;
11188 #endif
11189 dblquote = (syntax == DQSYNTAX);
11190 varnest = 0;
11191 arinest = 0;
11192 parenlevel = 0;
11193 dqvarnest = 0;
11195 STARTSTACKSTR(out);
11196 loop:
11197 /* For each line, until end of word */
11198 CHECKEND(); /* set c to PEOF if at end of here document */
11199 for (;;) { /* until end of line or end of word */
11200 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11201 switch (SIT(c, syntax)) {
11202 case CNL: /* '\n' */
11203 if (syntax == BASESYNTAX)
11204 goto endword; /* exit outer loop */
11205 USTPUTC(c, out);
11206 g_parsefile->linno++;
11207 setprompt_if(doprompt, 2);
11208 c = pgetc();
11209 goto loop; /* continue outer loop */
11210 case CWORD:
11211 USTPUTC(c, out);
11212 break;
11213 case CCTL:
11214 if (eofmark == NULL || dblquote)
11215 USTPUTC(CTLESC, out);
11216 #if ENABLE_ASH_BASH_COMPAT
11217 if (c == '\\' && bash_dollar_squote) {
11218 c = decode_dollar_squote();
11219 if (c & 0x100) {
11220 USTPUTC('\\', out);
11221 c = (unsigned char)c;
11224 #endif
11225 USTPUTC(c, out);
11226 break;
11227 case CBACK: /* backslash */
11228 c = pgetc_without_PEOA();
11229 if (c == PEOF) {
11230 USTPUTC(CTLESC, out);
11231 USTPUTC('\\', out);
11232 pungetc();
11233 } else if (c == '\n') {
11234 setprompt_if(doprompt, 2);
11235 } else {
11236 #if ENABLE_ASH_EXPAND_PRMT
11237 if (c == '$' && pssyntax) {
11238 USTPUTC(CTLESC, out);
11239 USTPUTC('\\', out);
11241 #endif
11242 /* Backslash is retained if we are in "str" and next char isn't special */
11243 if (dblquote
11244 && c != '\\'
11245 && c != '`'
11246 && c != '$'
11247 && (c != '"' || eofmark != NULL)
11249 USTPUTC(CTLESC, out);
11250 USTPUTC('\\', out);
11252 if (SIT(c, SQSYNTAX) == CCTL)
11253 USTPUTC(CTLESC, out);
11254 USTPUTC(c, out);
11255 quotef = 1;
11257 break;
11258 case CSQUOTE:
11259 syntax = SQSYNTAX;
11260 quotemark:
11261 if (eofmark == NULL) {
11262 USTPUTC(CTLQUOTEMARK, out);
11264 break;
11265 case CDQUOTE:
11266 syntax = DQSYNTAX;
11267 dblquote = 1;
11268 goto quotemark;
11269 case CENDQUOTE:
11270 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
11271 if (eofmark != NULL && arinest == 0
11272 && varnest == 0
11274 USTPUTC(c, out);
11275 } else {
11276 if (dqvarnest == 0) {
11277 syntax = BASESYNTAX;
11278 dblquote = 0;
11280 quotef = 1;
11281 goto quotemark;
11283 break;
11284 case CVAR: /* '$' */
11285 PARSESUB(); /* parse substitution */
11286 break;
11287 case CENDVAR: /* '}' */
11288 if (varnest > 0) {
11289 varnest--;
11290 if (dqvarnest > 0) {
11291 dqvarnest--;
11293 c = CTLENDVAR;
11295 USTPUTC(c, out);
11296 break;
11297 #if ENABLE_SH_MATH_SUPPORT
11298 case CLP: /* '(' in arithmetic */
11299 parenlevel++;
11300 USTPUTC(c, out);
11301 break;
11302 case CRP: /* ')' in arithmetic */
11303 if (parenlevel > 0) {
11304 parenlevel--;
11305 } else {
11306 if (pgetc() == ')') {
11307 if (--arinest == 0) {
11308 syntax = prevsyntax;
11309 dblquote = (syntax == DQSYNTAX);
11310 c = CTLENDARI;
11312 } else {
11314 * unbalanced parens
11315 * (don't 2nd guess - no error)
11317 pungetc();
11320 USTPUTC(c, out);
11321 break;
11322 #endif
11323 case CBQUOTE: /* '`' */
11324 PARSEBACKQOLD();
11325 break;
11326 case CENDFILE:
11327 goto endword; /* exit outer loop */
11328 case CIGN:
11329 break;
11330 default:
11331 if (varnest == 0) {
11332 #if ENABLE_ASH_BASH_COMPAT
11333 if (c == '&') {
11334 if (pgetc() == '>')
11335 c = 0x100 + '>'; /* flag &> */
11336 pungetc();
11338 #endif
11339 goto endword; /* exit outer loop */
11341 IF_ASH_ALIAS(if (c != PEOA))
11342 USTPUTC(c, out);
11344 c = pgetc_fast();
11345 } /* for (;;) */
11346 endword:
11348 #if ENABLE_SH_MATH_SUPPORT
11349 if (syntax == ARISYNTAX)
11350 raise_error_syntax("missing '))'");
11351 #endif
11352 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
11353 raise_error_syntax("unterminated quoted string");
11354 if (varnest != 0) {
11355 startlinno = g_parsefile->linno;
11356 /* { */
11357 raise_error_syntax("missing '}'");
11359 USTPUTC('\0', out);
11360 len = out - (char *)stackblock();
11361 out = stackblock();
11362 if (eofmark == NULL) {
11363 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
11364 && quotef == 0
11366 if (isdigit_str9(out)) {
11367 PARSEREDIR(); /* passed as params: out, c */
11368 lasttoken = TREDIR;
11369 return lasttoken;
11371 /* else: non-number X seen, interpret it
11372 * as "NNNX>file" = "NNNX >file" */
11374 pungetc();
11376 quoteflag = quotef;
11377 backquotelist = bqlist;
11378 grabstackblock(len);
11379 wordtext = out;
11380 lasttoken = TWORD;
11381 return lasttoken;
11382 /* end of readtoken routine */
11385 * Check to see whether we are at the end of the here document. When this
11386 * is called, c is set to the first character of the next input line. If
11387 * we are at the end of the here document, this routine sets the c to PEOF.
11389 checkend: {
11390 if (eofmark) {
11391 #if ENABLE_ASH_ALIAS
11392 if (c == PEOA)
11393 c = pgetc_without_PEOA();
11394 #endif
11395 if (striptabs) {
11396 while (c == '\t') {
11397 c = pgetc_without_PEOA();
11400 if (c == *eofmark) {
11401 if (pfgets(line, sizeof(line)) != NULL) {
11402 char *p, *q;
11404 p = line;
11405 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11406 continue;
11407 if (*p == '\n' && *q == '\0') {
11408 c = PEOF;
11409 g_parsefile->linno++;
11410 needprompt = doprompt;
11411 } else {
11412 pushstring(line, NULL);
11417 goto checkend_return;
11421 * Parse a redirection operator. The variable "out" points to a string
11422 * specifying the fd to be redirected. The variable "c" contains the
11423 * first character of the redirection operator.
11425 parseredir: {
11426 /* out is already checked to be a valid number or "" */
11427 int fd = (*out == '\0' ? -1 : atoi(out));
11428 union node *np;
11430 np = stzalloc(sizeof(struct nfile));
11431 if (c == '>') {
11432 np->nfile.fd = 1;
11433 c = pgetc();
11434 if (c == '>')
11435 np->type = NAPPEND;
11436 else if (c == '|')
11437 np->type = NCLOBBER;
11438 else if (c == '&')
11439 np->type = NTOFD;
11440 /* it also can be NTO2 (>&file), but we can't figure it out yet */
11441 else {
11442 np->type = NTO;
11443 pungetc();
11446 #if ENABLE_ASH_BASH_COMPAT
11447 else if (c == 0x100 + '>') { /* this flags &> redirection */
11448 np->nfile.fd = 1;
11449 pgetc(); /* this is '>', no need to check */
11450 np->type = NTO2;
11452 #endif
11453 else { /* c == '<' */
11454 /*np->nfile.fd = 0; - stzalloc did it */
11455 c = pgetc();
11456 switch (c) {
11457 case '<':
11458 if (sizeof(struct nfile) != sizeof(struct nhere)) {
11459 np = stzalloc(sizeof(struct nhere));
11460 /*np->nfile.fd = 0; - stzalloc did it */
11462 np->type = NHERE;
11463 heredoc = stzalloc(sizeof(struct heredoc));
11464 heredoc->here = np;
11465 c = pgetc();
11466 if (c == '-') {
11467 heredoc->striptabs = 1;
11468 } else {
11469 /*heredoc->striptabs = 0; - stzalloc did it */
11470 pungetc();
11472 break;
11474 case '&':
11475 np->type = NFROMFD;
11476 break;
11478 case '>':
11479 np->type = NFROMTO;
11480 break;
11482 default:
11483 np->type = NFROM;
11484 pungetc();
11485 break;
11488 if (fd >= 0)
11489 np->nfile.fd = fd;
11490 redirnode = np;
11491 goto parseredir_return;
11495 * Parse a substitution. At this point, we have read the dollar sign
11496 * and nothing else.
11499 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11500 * (assuming ascii char codes, as the original implementation did) */
11501 #define is_special(c) \
11502 (((unsigned)(c) - 33 < 32) \
11503 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
11504 parsesub: {
11505 unsigned char subtype;
11506 int typeloc;
11507 int flags;
11509 c = pgetc();
11510 if (c > 255 /* PEOA or PEOF */
11511 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
11513 #if ENABLE_ASH_BASH_COMPAT
11514 if (c == '\'')
11515 bash_dollar_squote = 1;
11516 else
11517 #endif
11518 USTPUTC('$', out);
11519 pungetc();
11520 } else if (c == '(') {
11521 /* $(command) or $((arith)) */
11522 if (pgetc() == '(') {
11523 #if ENABLE_SH_MATH_SUPPORT
11524 PARSEARITH();
11525 #else
11526 raise_error_syntax("you disabled math support for $((arith)) syntax");
11527 #endif
11528 } else {
11529 pungetc();
11530 PARSEBACKQNEW();
11532 } else {
11533 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
11534 USTPUTC(CTLVAR, out);
11535 typeloc = out - (char *)stackblock();
11536 USTPUTC(VSNORMAL, out);
11537 subtype = VSNORMAL;
11538 if (c == '{') {
11539 c = pgetc();
11540 if (c == '#') {
11541 c = pgetc();
11542 if (c == '}')
11543 c = '#'; /* ${#} - same as $# */
11544 else
11545 subtype = VSLENGTH; /* ${#VAR} */
11546 } else {
11547 subtype = 0;
11550 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
11551 /* $[{[#]]NAME[}] */
11552 do {
11553 STPUTC(c, out);
11554 c = pgetc();
11555 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
11556 } else if (isdigit(c)) {
11557 /* $[{[#]]NUM[}] */
11558 do {
11559 STPUTC(c, out);
11560 c = pgetc();
11561 } while (isdigit(c));
11562 } else if (is_special(c)) {
11563 /* $[{[#]]<specialchar>[}] */
11564 USTPUTC(c, out);
11565 c = pgetc();
11566 } else {
11567 badsub:
11568 raise_error_syntax("bad substitution");
11570 if (c != '}' && subtype == VSLENGTH) {
11571 /* ${#VAR didn't end with } */
11572 goto badsub;
11575 STPUTC('=', out);
11576 flags = 0;
11577 if (subtype == 0) {
11578 /* ${VAR...} but not $VAR or ${#VAR} */
11579 /* c == first char after VAR */
11580 switch (c) {
11581 case ':':
11582 c = pgetc();
11583 #if ENABLE_ASH_BASH_COMPAT
11584 if (c == ':' || c == '$' || isdigit(c)) {
11585 //TODO: support more general format ${v:EXPR:EXPR},
11586 // where EXPR follows $(()) rules
11587 subtype = VSSUBSTR;
11588 pungetc();
11589 break; /* "goto do_pungetc" is bigger (!) */
11591 #endif
11592 flags = VSNUL;
11593 /*FALLTHROUGH*/
11594 default: {
11595 static const char types[] ALIGN1 = "}-+?=";
11596 const char *p = strchr(types, c);
11597 if (p == NULL)
11598 goto badsub;
11599 subtype = p - types + VSNORMAL;
11600 break;
11602 case '%':
11603 case '#': {
11604 int cc = c;
11605 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
11606 c = pgetc();
11607 if (c != cc)
11608 goto do_pungetc;
11609 subtype++;
11610 break;
11612 #if ENABLE_ASH_BASH_COMPAT
11613 case '/':
11614 /* ${v/[/]pattern/repl} */
11615 //TODO: encode pattern and repl separately.
11616 // Currently ${v/$var_with_slash/repl} is horribly broken
11617 subtype = VSREPLACE;
11618 c = pgetc();
11619 if (c != '/')
11620 goto do_pungetc;
11621 subtype++; /* VSREPLACEALL */
11622 break;
11623 #endif
11625 } else {
11626 do_pungetc:
11627 pungetc();
11629 if (dblquote || arinest)
11630 flags |= VSQUOTE;
11631 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
11632 if (subtype != VSNORMAL) {
11633 varnest++;
11634 if (dblquote || arinest) {
11635 dqvarnest++;
11639 goto parsesub_return;
11643 * Called to parse command substitutions. Newstyle is set if the command
11644 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11645 * list of commands (passed by reference), and savelen is the number of
11646 * characters on the top of the stack which must be preserved.
11648 parsebackq: {
11649 struct nodelist **nlpp;
11650 smallint savepbq;
11651 union node *n;
11652 char *volatile str;
11653 struct jmploc jmploc;
11654 struct jmploc *volatile savehandler;
11655 size_t savelen;
11656 smallint saveprompt = 0;
11658 #ifdef __GNUC__
11659 (void) &saveprompt;
11660 #endif
11661 savepbq = parsebackquote;
11662 if (setjmp(jmploc.loc)) {
11663 free(str);
11664 parsebackquote = 0;
11665 exception_handler = savehandler;
11666 longjmp(exception_handler->loc, 1);
11668 INT_OFF;
11669 str = NULL;
11670 savelen = out - (char *)stackblock();
11671 if (savelen > 0) {
11672 str = ckmalloc(savelen);
11673 memcpy(str, stackblock(), savelen);
11675 savehandler = exception_handler;
11676 exception_handler = &jmploc;
11677 INT_ON;
11678 if (oldstyle) {
11679 /* We must read until the closing backquote, giving special
11680 * treatment to some slashes, and then push the string and
11681 * reread it as input, interpreting it normally.
11683 char *pout;
11684 size_t psavelen;
11685 char *pstr;
11687 STARTSTACKSTR(pout);
11688 for (;;) {
11689 int pc;
11691 setprompt_if(needprompt, 2);
11692 pc = pgetc();
11693 switch (pc) {
11694 case '`':
11695 goto done;
11697 case '\\':
11698 pc = pgetc();
11699 if (pc == '\n') {
11700 g_parsefile->linno++;
11701 setprompt_if(doprompt, 2);
11703 * If eating a newline, avoid putting
11704 * the newline into the new character
11705 * stream (via the STPUTC after the
11706 * switch).
11708 continue;
11710 if (pc != '\\' && pc != '`' && pc != '$'
11711 && (!dblquote || pc != '"')
11713 STPUTC('\\', pout);
11715 if (pc <= 255 /* not PEOA or PEOF */) {
11716 break;
11718 /* fall through */
11720 case PEOF:
11721 IF_ASH_ALIAS(case PEOA:)
11722 startlinno = g_parsefile->linno;
11723 raise_error_syntax("EOF in backquote substitution");
11725 case '\n':
11726 g_parsefile->linno++;
11727 needprompt = doprompt;
11728 break;
11730 default:
11731 break;
11733 STPUTC(pc, pout);
11735 done:
11736 STPUTC('\0', pout);
11737 psavelen = pout - (char *)stackblock();
11738 if (psavelen > 0) {
11739 pstr = grabstackstr(pout);
11740 setinputstring(pstr);
11743 nlpp = &bqlist;
11744 while (*nlpp)
11745 nlpp = &(*nlpp)->next;
11746 *nlpp = stzalloc(sizeof(**nlpp));
11747 /* (*nlpp)->next = NULL; - stzalloc did it */
11748 parsebackquote = oldstyle;
11750 if (oldstyle) {
11751 saveprompt = doprompt;
11752 doprompt = 0;
11755 n = list(2);
11757 if (oldstyle)
11758 doprompt = saveprompt;
11759 else if (readtoken() != TRP)
11760 raise_error_unexpected_syntax(TRP);
11762 (*nlpp)->n = n;
11763 if (oldstyle) {
11765 * Start reading from old file again, ignoring any pushed back
11766 * tokens left from the backquote parsing
11768 popfile();
11769 tokpushback = 0;
11771 while (stackblocksize() <= savelen)
11772 growstackblock();
11773 STARTSTACKSTR(out);
11774 if (str) {
11775 memcpy(out, str, savelen);
11776 STADJUST(savelen, out);
11777 INT_OFF;
11778 free(str);
11779 str = NULL;
11780 INT_ON;
11782 parsebackquote = savepbq;
11783 exception_handler = savehandler;
11784 if (arinest || dblquote)
11785 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11786 else
11787 USTPUTC(CTLBACKQ, out);
11788 if (oldstyle)
11789 goto parsebackq_oldreturn;
11790 goto parsebackq_newreturn;
11793 #if ENABLE_SH_MATH_SUPPORT
11795 * Parse an arithmetic expansion (indicate start of one and set state)
11797 parsearith: {
11798 if (++arinest == 1) {
11799 prevsyntax = syntax;
11800 syntax = ARISYNTAX;
11801 USTPUTC(CTLARI, out);
11802 if (dblquote)
11803 USTPUTC('"', out);
11804 else
11805 USTPUTC(' ', out);
11806 } else {
11808 * we collapse embedded arithmetic expansion to
11809 * parenthesis, which should be equivalent
11811 USTPUTC('(', out);
11813 goto parsearith_return;
11815 #endif
11817 } /* end of readtoken */
11820 * Read the next input token.
11821 * If the token is a word, we set backquotelist to the list of cmds in
11822 * backquotes. We set quoteflag to true if any part of the word was
11823 * quoted.
11824 * If the token is TREDIR, then we set redirnode to a structure containing
11825 * the redirection.
11826 * In all cases, the variable startlinno is set to the number of the line
11827 * on which the token starts.
11829 * [Change comment: here documents and internal procedures]
11830 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11831 * word parsing code into a separate routine. In this case, readtoken
11832 * doesn't need to have any internal procedures, but parseword does.
11833 * We could also make parseoperator in essence the main routine, and
11834 * have parseword (readtoken1?) handle both words and redirection.]
11836 #define NEW_xxreadtoken
11837 #ifdef NEW_xxreadtoken
11838 /* singles must be first! */
11839 static const char xxreadtoken_chars[7] ALIGN1 = {
11840 '\n', '(', ')', /* singles */
11841 '&', '|', ';', /* doubles */
11845 #define xxreadtoken_singles 3
11846 #define xxreadtoken_doubles 3
11848 static const char xxreadtoken_tokens[] ALIGN1 = {
11849 TNL, TLP, TRP, /* only single occurrence allowed */
11850 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11851 TEOF, /* corresponds to trailing nul */
11852 TAND, TOR, TENDCASE /* if double occurrence */
11855 static int
11856 xxreadtoken(void)
11858 int c;
11860 if (tokpushback) {
11861 tokpushback = 0;
11862 return lasttoken;
11864 setprompt_if(needprompt, 2);
11865 startlinno = g_parsefile->linno;
11866 for (;;) { /* until token or start of word found */
11867 c = pgetc_fast();
11868 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
11869 continue;
11871 if (c == '#') {
11872 while ((c = pgetc()) != '\n' && c != PEOF)
11873 continue;
11874 pungetc();
11875 } else if (c == '\\') {
11876 if (pgetc() != '\n') {
11877 pungetc();
11878 break; /* return readtoken1(...) */
11880 startlinno = ++g_parsefile->linno;
11881 setprompt_if(doprompt, 2);
11882 } else {
11883 const char *p;
11885 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11886 if (c != PEOF) {
11887 if (c == '\n') {
11888 g_parsefile->linno++;
11889 needprompt = doprompt;
11892 p = strchr(xxreadtoken_chars, c);
11893 if (p == NULL)
11894 break; /* return readtoken1(...) */
11896 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11897 int cc = pgetc();
11898 if (cc == c) { /* double occurrence? */
11899 p += xxreadtoken_doubles + 1;
11900 } else {
11901 pungetc();
11902 #if ENABLE_ASH_BASH_COMPAT
11903 if (c == '&' && cc == '>') /* &> */
11904 break; /* return readtoken1(...) */
11905 #endif
11909 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11910 return lasttoken;
11912 } /* for (;;) */
11914 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
11916 #else /* old xxreadtoken */
11917 #define RETURN(token) return lasttoken = token
11918 static int
11919 xxreadtoken(void)
11921 int c;
11923 if (tokpushback) {
11924 tokpushback = 0;
11925 return lasttoken;
11927 setprompt_if(needprompt, 2);
11928 startlinno = g_parsefile->linno;
11929 for (;;) { /* until token or start of word found */
11930 c = pgetc_fast();
11931 switch (c) {
11932 case ' ': case '\t':
11933 IF_ASH_ALIAS(case PEOA:)
11934 continue;
11935 case '#':
11936 while ((c = pgetc()) != '\n' && c != PEOF)
11937 continue;
11938 pungetc();
11939 continue;
11940 case '\\':
11941 if (pgetc() == '\n') {
11942 startlinno = ++g_parsefile->linno;
11943 setprompt_if(doprompt, 2);
11944 continue;
11946 pungetc();
11947 goto breakloop;
11948 case '\n':
11949 g_parsefile->linno++;
11950 needprompt = doprompt;
11951 RETURN(TNL);
11952 case PEOF:
11953 RETURN(TEOF);
11954 case '&':
11955 if (pgetc() == '&')
11956 RETURN(TAND);
11957 pungetc();
11958 RETURN(TBACKGND);
11959 case '|':
11960 if (pgetc() == '|')
11961 RETURN(TOR);
11962 pungetc();
11963 RETURN(TPIPE);
11964 case ';':
11965 if (pgetc() == ';')
11966 RETURN(TENDCASE);
11967 pungetc();
11968 RETURN(TSEMI);
11969 case '(':
11970 RETURN(TLP);
11971 case ')':
11972 RETURN(TRP);
11973 default:
11974 goto breakloop;
11977 breakloop:
11978 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11979 #undef RETURN
11981 #endif /* old xxreadtoken */
11983 static int
11984 readtoken(void)
11986 int t;
11987 #if DEBUG
11988 smallint alreadyseen = tokpushback;
11989 #endif
11991 #if ENABLE_ASH_ALIAS
11992 top:
11993 #endif
11995 t = xxreadtoken();
11998 * eat newlines
12000 if (checkkwd & CHKNL) {
12001 while (t == TNL) {
12002 parseheredoc();
12003 t = xxreadtoken();
12007 if (t != TWORD || quoteflag) {
12008 goto out;
12012 * check for keywords
12014 if (checkkwd & CHKKWD) {
12015 const char *const *pp;
12017 pp = findkwd(wordtext);
12018 if (pp) {
12019 lasttoken = t = pp - tokname_array;
12020 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
12021 goto out;
12025 if (checkkwd & CHKALIAS) {
12026 #if ENABLE_ASH_ALIAS
12027 struct alias *ap;
12028 ap = lookupalias(wordtext, 1);
12029 if (ap != NULL) {
12030 if (*ap->val) {
12031 pushstring(ap->val, ap);
12033 goto top;
12035 #endif
12037 out:
12038 checkkwd = 0;
12039 #if DEBUG
12040 if (!alreadyseen)
12041 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
12042 else
12043 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
12044 #endif
12045 return t;
12048 static char
12049 peektoken(void)
12051 int t;
12053 t = readtoken();
12054 tokpushback = 1;
12055 return tokname_array[t][0];
12059 * Read and parse a command. Returns NODE_EOF on end of file.
12060 * (NULL is a valid parse tree indicating a blank line.)
12062 static union node *
12063 parsecmd(int interact)
12065 int t;
12067 tokpushback = 0;
12068 doprompt = interact;
12069 setprompt_if(doprompt, doprompt);
12070 needprompt = 0;
12071 t = readtoken();
12072 if (t == TEOF)
12073 return NODE_EOF;
12074 if (t == TNL)
12075 return NULL;
12076 tokpushback = 1;
12077 return list(1);
12081 * Input any here documents.
12083 static void
12084 parseheredoc(void)
12086 struct heredoc *here;
12087 union node *n;
12089 here = heredoclist;
12090 heredoclist = NULL;
12092 while (here) {
12093 setprompt_if(needprompt, 2);
12094 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
12095 here->eofmark, here->striptabs);
12096 n = stzalloc(sizeof(struct narg));
12097 n->narg.type = NARG;
12098 /*n->narg.next = NULL; - stzalloc did it */
12099 n->narg.text = wordtext;
12100 n->narg.backquote = backquotelist;
12101 here->here->nhere.doc = n;
12102 here = here->next;
12108 * called by editline -- any expansions to the prompt should be added here.
12110 #if ENABLE_ASH_EXPAND_PRMT
12111 static const char *
12112 expandstr(const char *ps)
12114 union node n;
12116 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12117 * and token processing _can_ alter it (delete NULs etc). */
12118 setinputstring((char *)ps);
12119 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
12120 popfile();
12122 n.narg.type = NARG;
12123 n.narg.next = NULL;
12124 n.narg.text = wordtext;
12125 n.narg.backquote = backquotelist;
12127 expandarg(&n, NULL, 0);
12128 return stackblock();
12130 #endif
12133 * Execute a command or commands contained in a string.
12135 static int
12136 evalstring(char *s, int mask)
12138 union node *n;
12139 struct stackmark smark;
12140 int skip;
12142 setinputstring(s);
12143 setstackmark(&smark);
12145 skip = 0;
12146 while ((n = parsecmd(0)) != NODE_EOF) {
12147 evaltree(n, 0);
12148 popstackmark(&smark);
12149 skip = evalskip;
12150 if (skip)
12151 break;
12153 popfile();
12155 skip &= mask;
12156 evalskip = skip;
12157 return skip;
12161 * The eval command.
12163 static int FAST_FUNC
12164 evalcmd(int argc UNUSED_PARAM, char **argv)
12166 char *p;
12167 char *concat;
12169 if (argv[1]) {
12170 p = argv[1];
12171 argv += 2;
12172 if (argv[0]) {
12173 STARTSTACKSTR(concat);
12174 for (;;) {
12175 concat = stack_putstr(p, concat);
12176 p = *argv++;
12177 if (p == NULL)
12178 break;
12179 STPUTC(' ', concat);
12181 STPUTC('\0', concat);
12182 p = grabstackstr(concat);
12184 evalstring(p, ~SKIPEVAL);
12186 return exitstatus;
12190 * Read and execute commands.
12191 * "Top" is nonzero for the top level command loop;
12192 * it turns on prompting if the shell is interactive.
12194 static int
12195 cmdloop(int top)
12197 union node *n;
12198 struct stackmark smark;
12199 int inter;
12200 int numeof = 0;
12202 TRACE(("cmdloop(%d) called\n", top));
12203 for (;;) {
12204 int skip;
12206 setstackmark(&smark);
12207 #if JOBS
12208 if (doing_jobctl)
12209 showjobs(stderr, SHOW_CHANGED);
12210 #endif
12211 inter = 0;
12212 if (iflag && top) {
12213 inter++;
12214 chkmail();
12216 n = parsecmd(inter);
12217 #if DEBUG
12218 if (DEBUG > 2 && debug && (n != NODE_EOF))
12219 showtree(n);
12220 #endif
12221 if (n == NODE_EOF) {
12222 if (!top || numeof >= 50)
12223 break;
12224 if (!stoppedjobs()) {
12225 if (!Iflag)
12226 break;
12227 out2str("\nUse \"exit\" to leave shell.\n");
12229 numeof++;
12230 } else if (nflag == 0) {
12231 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12232 job_warning >>= 1;
12233 numeof = 0;
12234 evaltree(n, 0);
12236 popstackmark(&smark);
12237 skip = evalskip;
12239 if (skip) {
12240 evalskip = 0;
12241 return skip & SKIPEVAL;
12244 return 0;
12248 * Take commands from a file. To be compatible we should do a path
12249 * search for the file, which is necessary to find sub-commands.
12251 static char *
12252 find_dot_file(char *name)
12254 char *fullname;
12255 const char *path = pathval();
12256 struct stat statb;
12258 /* don't try this for absolute or relative paths */
12259 if (strchr(name, '/'))
12260 return name;
12262 /* IIRC standards do not say whether . is to be searched.
12263 * And it is even smaller this way, making it unconditional for now:
12265 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12266 fullname = name;
12267 goto try_cur_dir;
12270 while ((fullname = path_advance(&path, name)) != NULL) {
12271 try_cur_dir:
12272 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12274 * Don't bother freeing here, since it will
12275 * be freed by the caller.
12277 return fullname;
12279 if (fullname != name)
12280 stunalloc(fullname);
12283 /* not found in the PATH */
12284 ash_msg_and_raise_error("%s: not found", name);
12285 /* NOTREACHED */
12288 static int FAST_FUNC
12289 dotcmd(int argc, char **argv)
12291 char *fullname;
12292 struct strlist *sp;
12293 volatile struct shparam saveparam;
12295 for (sp = cmdenviron; sp; sp = sp->next)
12296 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
12298 if (!argv[1]) {
12299 /* bash says: "bash: .: filename argument required" */
12300 return 2; /* bash compat */
12303 /* "false; . empty_file; echo $?" should print 0, not 1: */
12304 exitstatus = 0;
12306 /* This aborts if file isn't found, which is POSIXly correct.
12307 * bash returns exitcode 1 instead.
12309 fullname = find_dot_file(argv[1]);
12310 argv += 2;
12311 argc -= 2;
12312 if (argc) { /* argc > 0, argv[0] != NULL */
12313 saveparam = shellparam;
12314 shellparam.malloced = 0;
12315 shellparam.nparam = argc;
12316 shellparam.p = argv;
12319 /* This aborts if file can't be opened, which is POSIXly correct.
12320 * bash returns exitcode 1 instead.
12322 setinputfile(fullname, INPUT_PUSH_FILE);
12323 commandname = fullname;
12324 cmdloop(0);
12325 popfile();
12327 if (argc) {
12328 freeparam(&shellparam);
12329 shellparam = saveparam;
12332 return exitstatus;
12335 static int FAST_FUNC
12336 exitcmd(int argc UNUSED_PARAM, char **argv)
12338 if (stoppedjobs())
12339 return 0;
12340 if (argv[1])
12341 exitstatus = number(argv[1]);
12342 raise_exception(EXEXIT);
12343 /* NOTREACHED */
12347 * Read a file containing shell functions.
12349 static void
12350 readcmdfile(char *name)
12352 setinputfile(name, INPUT_PUSH_FILE);
12353 cmdloop(0);
12354 popfile();
12358 /* ============ find_command inplementation */
12361 * Resolve a command name. If you change this routine, you may have to
12362 * change the shellexec routine as well.
12364 static void
12365 find_command(char *name, struct cmdentry *entry, int act, const char *path)
12367 struct tblentry *cmdp;
12368 int idx;
12369 int prev;
12370 char *fullname;
12371 struct stat statb;
12372 int e;
12373 int updatetbl;
12374 struct builtincmd *bcmd;
12376 /* If name contains a slash, don't use PATH or hash table */
12377 if (strchr(name, '/') != NULL) {
12378 entry->u.index = -1;
12379 if (act & DO_ABS) {
12380 while (stat(name, &statb) < 0) {
12381 #ifdef SYSV
12382 if (errno == EINTR)
12383 continue;
12384 #endif
12385 entry->cmdtype = CMDUNKNOWN;
12386 return;
12389 entry->cmdtype = CMDNORMAL;
12390 return;
12393 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
12395 updatetbl = (path == pathval());
12396 if (!updatetbl) {
12397 act |= DO_ALTPATH;
12398 if (strstr(path, "%builtin") != NULL)
12399 act |= DO_ALTBLTIN;
12402 /* If name is in the table, check answer will be ok */
12403 cmdp = cmdlookup(name, 0);
12404 if (cmdp != NULL) {
12405 int bit;
12407 switch (cmdp->cmdtype) {
12408 default:
12409 #if DEBUG
12410 abort();
12411 #endif
12412 case CMDNORMAL:
12413 bit = DO_ALTPATH;
12414 break;
12415 case CMDFUNCTION:
12416 bit = DO_NOFUNC;
12417 break;
12418 case CMDBUILTIN:
12419 bit = DO_ALTBLTIN;
12420 break;
12422 if (act & bit) {
12423 updatetbl = 0;
12424 cmdp = NULL;
12425 } else if (cmdp->rehash == 0)
12426 /* if not invalidated by cd, we're done */
12427 goto success;
12430 /* If %builtin not in path, check for builtin next */
12431 bcmd = find_builtin(name);
12432 if (bcmd) {
12433 if (IS_BUILTIN_REGULAR(bcmd))
12434 goto builtin_success;
12435 if (act & DO_ALTPATH) {
12436 if (!(act & DO_ALTBLTIN))
12437 goto builtin_success;
12438 } else if (builtinloc <= 0) {
12439 goto builtin_success;
12443 #if ENABLE_FEATURE_SH_STANDALONE
12445 int applet_no = find_applet_by_name(name);
12446 if (applet_no >= 0) {
12447 entry->cmdtype = CMDNORMAL;
12448 entry->u.index = -2 - applet_no;
12449 return;
12452 #endif
12454 /* We have to search path. */
12455 prev = -1; /* where to start */
12456 if (cmdp && cmdp->rehash) { /* doing a rehash */
12457 if (cmdp->cmdtype == CMDBUILTIN)
12458 prev = builtinloc;
12459 else
12460 prev = cmdp->param.index;
12463 e = ENOENT;
12464 idx = -1;
12465 loop:
12466 while ((fullname = path_advance(&path, name)) != NULL) {
12467 stunalloc(fullname);
12468 /* NB: code below will still use fullname
12469 * despite it being "unallocated" */
12470 idx++;
12471 if (pathopt) {
12472 if (prefix(pathopt, "builtin")) {
12473 if (bcmd)
12474 goto builtin_success;
12475 continue;
12477 if ((act & DO_NOFUNC)
12478 || !prefix(pathopt, "func")
12479 ) { /* ignore unimplemented options */
12480 continue;
12483 /* if rehash, don't redo absolute path names */
12484 if (fullname[0] == '/' && idx <= prev) {
12485 if (idx < prev)
12486 continue;
12487 TRACE(("searchexec \"%s\": no change\n", name));
12488 goto success;
12490 while (stat(fullname, &statb) < 0) {
12491 #ifdef SYSV
12492 if (errno == EINTR)
12493 continue;
12494 #endif
12495 if (errno != ENOENT && errno != ENOTDIR)
12496 e = errno;
12497 goto loop;
12499 e = EACCES; /* if we fail, this will be the error */
12500 if (!S_ISREG(statb.st_mode))
12501 continue;
12502 if (pathopt) { /* this is a %func directory */
12503 stalloc(strlen(fullname) + 1);
12504 /* NB: stalloc will return space pointed by fullname
12505 * (because we don't have any intervening allocations
12506 * between stunalloc above and this stalloc) */
12507 readcmdfile(fullname);
12508 cmdp = cmdlookup(name, 0);
12509 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12510 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12511 stunalloc(fullname);
12512 goto success;
12514 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12515 if (!updatetbl) {
12516 entry->cmdtype = CMDNORMAL;
12517 entry->u.index = idx;
12518 return;
12520 INT_OFF;
12521 cmdp = cmdlookup(name, 1);
12522 cmdp->cmdtype = CMDNORMAL;
12523 cmdp->param.index = idx;
12524 INT_ON;
12525 goto success;
12528 /* We failed. If there was an entry for this command, delete it */
12529 if (cmdp && updatetbl)
12530 delete_cmd_entry();
12531 if (act & DO_ERR)
12532 ash_msg("%s: %s", name, errmsg(e, "not found"));
12533 entry->cmdtype = CMDUNKNOWN;
12534 return;
12536 builtin_success:
12537 if (!updatetbl) {
12538 entry->cmdtype = CMDBUILTIN;
12539 entry->u.cmd = bcmd;
12540 return;
12542 INT_OFF;
12543 cmdp = cmdlookup(name, 1);
12544 cmdp->cmdtype = CMDBUILTIN;
12545 cmdp->param.cmd = bcmd;
12546 INT_ON;
12547 success:
12548 cmdp->rehash = 0;
12549 entry->cmdtype = cmdp->cmdtype;
12550 entry->u = cmdp->param;
12554 /* ============ trap.c */
12557 * The trap builtin.
12559 static int FAST_FUNC
12560 trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12562 char *action;
12563 char **ap;
12564 int signo, exitcode;
12566 nextopt(nullstr);
12567 ap = argptr;
12568 if (!*ap) {
12569 for (signo = 0; signo < NSIG; signo++) {
12570 char *tr = trap_ptr[signo];
12571 if (tr) {
12572 /* note: bash adds "SIG", but only if invoked
12573 * as "bash". If called as "sh", or if set -o posix,
12574 * then it prints short signal names.
12575 * We are printing short names: */
12576 out1fmt("trap -- %s %s\n",
12577 single_quote(tr),
12578 get_signame(signo));
12579 /* trap_ptr != trap only if we are in special-cased `trap` code.
12580 * In this case, we will exit very soon, no need to free(). */
12581 /* if (trap_ptr != trap && tp[0]) */
12582 /* free(tr); */
12586 if (trap_ptr != trap) {
12587 free(trap_ptr);
12588 trap_ptr = trap;
12591 return 0;
12594 action = NULL;
12595 if (ap[1])
12596 action = *ap++;
12597 exitcode = 0;
12598 while (*ap) {
12599 signo = get_signum(*ap);
12600 if (signo < 0) {
12601 /* Mimic bash message exactly */
12602 ash_msg("%s: invalid signal specification", *ap);
12603 exitcode = 1;
12604 goto next;
12606 INT_OFF;
12607 if (action) {
12608 if (LONE_DASH(action))
12609 action = NULL;
12610 else
12611 action = ckstrdup(action);
12613 free(trap[signo]);
12614 if (action)
12615 may_have_traps = 1;
12616 trap[signo] = action;
12617 if (signo != 0)
12618 setsignal(signo);
12619 INT_ON;
12620 next:
12621 ap++;
12623 return exitcode;
12627 /* ============ Builtins */
12629 #if ENABLE_ASH_HELP
12630 static int FAST_FUNC
12631 helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12633 unsigned col;
12634 unsigned i;
12636 out1fmt(
12637 "Built-in commands:\n"
12638 "------------------\n");
12639 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12640 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12641 builtintab[i].name + 1);
12642 if (col > 60) {
12643 out1fmt("\n");
12644 col = 0;
12647 # if ENABLE_FEATURE_SH_STANDALONE
12649 const char *a = applet_names;
12650 while (*a) {
12651 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12652 if (col > 60) {
12653 out1fmt("\n");
12654 col = 0;
12656 a += strlen(a) + 1;
12659 # endif
12660 out1fmt("\n\n");
12661 return EXIT_SUCCESS;
12663 #endif
12665 #if MAX_HISTORY
12666 static int FAST_FUNC
12667 historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12669 show_history(line_input_state);
12670 return EXIT_SUCCESS;
12672 #endif
12675 * The export and readonly commands.
12677 static int FAST_FUNC
12678 exportcmd(int argc UNUSED_PARAM, char **argv)
12680 struct var *vp;
12681 char *name;
12682 const char *p;
12683 char **aptr;
12684 char opt;
12685 int flag;
12686 int flag_off;
12688 /* "readonly" in bash accepts, but ignores -n.
12689 * We do the same: it saves a conditional in nextopt's param.
12691 flag_off = 0;
12692 while ((opt = nextopt("np")) != '\0') {
12693 if (opt == 'n')
12694 flag_off = VEXPORT;
12696 flag = VEXPORT;
12697 if (argv[0][0] == 'r') {
12698 flag = VREADONLY;
12699 flag_off = 0; /* readonly ignores -n */
12701 flag_off = ~flag_off;
12703 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12705 aptr = argptr;
12706 name = *aptr;
12707 if (name) {
12708 do {
12709 p = strchr(name, '=');
12710 if (p != NULL) {
12711 p++;
12712 } else {
12713 vp = *findvar(hashvar(name), name);
12714 if (vp) {
12715 vp->flags = ((vp->flags | flag) & flag_off);
12716 continue;
12719 setvar(name, p, (flag & flag_off));
12720 } while ((name = *++aptr) != NULL);
12721 return 0;
12725 /* No arguments. Show the list of exported or readonly vars.
12726 * -n is ignored.
12728 showvars(argv[0], flag, 0);
12729 return 0;
12733 * Delete a function if it exists.
12735 static void
12736 unsetfunc(const char *name)
12738 struct tblentry *cmdp;
12740 cmdp = cmdlookup(name, 0);
12741 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
12742 delete_cmd_entry();
12746 * The unset builtin command. We unset the function before we unset the
12747 * variable to allow a function to be unset when there is a readonly variable
12748 * with the same name.
12750 static int FAST_FUNC
12751 unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12753 char **ap;
12754 int i;
12755 int flag = 0;
12756 int ret = 0;
12758 while ((i = nextopt("vf")) != 0) {
12759 flag = i;
12762 for (ap = argptr; *ap; ap++) {
12763 if (flag != 'f') {
12764 i = unsetvar(*ap);
12765 ret |= i;
12766 if (!(i & 2))
12767 continue;
12769 if (flag != 'v')
12770 unsetfunc(*ap);
12772 return ret & 1;
12775 static const unsigned char timescmd_str[] ALIGN1 = {
12776 ' ', offsetof(struct tms, tms_utime),
12777 '\n', offsetof(struct tms, tms_stime),
12778 ' ', offsetof(struct tms, tms_cutime),
12779 '\n', offsetof(struct tms, tms_cstime),
12782 static int FAST_FUNC
12783 timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12785 unsigned long clk_tck, s, t;
12786 const unsigned char *p;
12787 struct tms buf;
12789 clk_tck = bb_clk_tck();
12790 times(&buf);
12792 p = timescmd_str;
12793 do {
12794 t = *(clock_t *)(((char *) &buf) + p[1]);
12795 s = t / clk_tck;
12796 t = t % clk_tck;
12797 out1fmt("%lum%lu.%03lus%c",
12798 s / 60, s % 60,
12799 (t * 1000) / clk_tck,
12800 p[0]);
12801 p += 2;
12802 } while (*p);
12804 return 0;
12807 #if ENABLE_SH_MATH_SUPPORT
12809 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
12810 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12812 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12814 static int FAST_FUNC
12815 letcmd(int argc UNUSED_PARAM, char **argv)
12817 arith_t i;
12819 argv++;
12820 if (!*argv)
12821 ash_msg_and_raise_error("expression expected");
12822 do {
12823 i = ash_arith(*argv);
12824 } while (*++argv);
12826 return !i;
12828 #endif
12831 * The read builtin. Options:
12832 * -r Do not interpret '\' specially
12833 * -s Turn off echo (tty only)
12834 * -n NCHARS Read NCHARS max
12835 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12836 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12837 * -u FD Read from given FD instead of fd 0
12838 * This uses unbuffered input, which may be avoidable in some cases.
12839 * TODO: bash also has:
12840 * -a ARRAY Read into array[0],[1],etc
12841 * -d DELIM End on DELIM char, not newline
12842 * -e Use line editing (tty only)
12844 static int FAST_FUNC
12845 readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12847 char *opt_n = NULL;
12848 char *opt_p = NULL;
12849 char *opt_t = NULL;
12850 char *opt_u = NULL;
12851 int read_flags = 0;
12852 const char *r;
12853 int i;
12855 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
12856 switch (i) {
12857 case 'p':
12858 opt_p = optionarg;
12859 break;
12860 case 'n':
12861 opt_n = optionarg;
12862 break;
12863 case 's':
12864 read_flags |= BUILTIN_READ_SILENT;
12865 break;
12866 case 't':
12867 opt_t = optionarg;
12868 break;
12869 case 'r':
12870 read_flags |= BUILTIN_READ_RAW;
12871 break;
12872 case 'u':
12873 opt_u = optionarg;
12874 break;
12875 default:
12876 break;
12880 /* "read -s" needs to save/restore termios, can't allow ^C
12881 * to jump out of it.
12883 INT_OFF;
12884 r = shell_builtin_read(setvar2,
12885 argptr,
12886 bltinlookup("IFS"), /* can be NULL */
12887 read_flags,
12888 opt_n,
12889 opt_p,
12890 opt_t,
12891 opt_u
12893 INT_ON;
12895 if ((uintptr_t)r > 1)
12896 ash_msg_and_raise_error(r);
12898 return (uintptr_t)r;
12901 static int FAST_FUNC
12902 umaskcmd(int argc UNUSED_PARAM, char **argv)
12904 static const char permuser[3] ALIGN1 = "ugo";
12905 static const char permmode[3] ALIGN1 = "rwx";
12906 static const short permmask[] ALIGN2 = {
12907 S_IRUSR, S_IWUSR, S_IXUSR,
12908 S_IRGRP, S_IWGRP, S_IXGRP,
12909 S_IROTH, S_IWOTH, S_IXOTH
12912 /* TODO: use bb_parse_mode() instead */
12914 char *ap;
12915 mode_t mask;
12916 int i;
12917 int symbolic_mode = 0;
12919 while (nextopt("S") != '\0') {
12920 symbolic_mode = 1;
12923 INT_OFF;
12924 mask = umask(0);
12925 umask(mask);
12926 INT_ON;
12928 ap = *argptr;
12929 if (ap == NULL) {
12930 if (symbolic_mode) {
12931 char buf[18];
12932 char *p = buf;
12934 for (i = 0; i < 3; i++) {
12935 int j;
12937 *p++ = permuser[i];
12938 *p++ = '=';
12939 for (j = 0; j < 3; j++) {
12940 if ((mask & permmask[3 * i + j]) == 0) {
12941 *p++ = permmode[j];
12944 *p++ = ',';
12946 *--p = 0;
12947 puts(buf);
12948 } else {
12949 out1fmt("%.4o\n", mask);
12951 } else {
12952 if (isdigit((unsigned char) *ap)) {
12953 mask = 0;
12954 do {
12955 if (*ap >= '8' || *ap < '0')
12956 ash_msg_and_raise_error(msg_illnum, argv[1]);
12957 mask = (mask << 3) + (*ap - '0');
12958 } while (*++ap != '\0');
12959 umask(mask);
12960 } else {
12961 mask = ~mask & 0777;
12962 if (!bb_parse_mode(ap, &mask)) {
12963 ash_msg_and_raise_error("illegal mode: %s", ap);
12965 umask(~mask & 0777);
12968 return 0;
12971 static int FAST_FUNC
12972 ulimitcmd(int argc UNUSED_PARAM, char **argv)
12974 return shell_builtin_ulimit(argv);
12977 /* ============ main() and helpers */
12980 * Called to exit the shell.
12982 static void
12983 exitshell(void)
12985 struct jmploc loc;
12986 char *p;
12987 int status;
12989 #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
12990 save_history(line_input_state);
12991 #endif
12993 status = exitstatus;
12994 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12995 if (setjmp(loc.loc)) {
12996 if (exception_type == EXEXIT)
12997 /* dash bug: it just does _exit(exitstatus) here
12998 * but we have to do setjobctl(0) first!
12999 * (bug is still not fixed in dash-0.5.3 - if you run dash
13000 * under Midnight Commander, on exit from dash MC is backgrounded) */
13001 status = exitstatus;
13002 goto out;
13004 exception_handler = &loc;
13005 p = trap[0];
13006 if (p) {
13007 trap[0] = NULL;
13008 evalstring(p, 0);
13009 free(p);
13011 flush_stdout_stderr();
13012 out:
13013 setjobctl(0);
13014 _exit(status);
13015 /* NOTREACHED */
13018 static void
13019 init(void)
13021 /* from input.c: */
13022 /* we will never free this */
13023 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
13025 /* from trap.c: */
13026 signal(SIGCHLD, SIG_DFL);
13027 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13028 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13030 signal(SIGHUP, SIG_DFL);
13032 /* from var.c: */
13034 char **envp;
13035 const char *p;
13036 struct stat st1, st2;
13038 initvar();
13039 for (envp = environ; envp && *envp; envp++) {
13040 if (strchr(*envp, '=')) {
13041 setvareq(*envp, VEXPORT|VTEXTFIXED);
13045 setvar2("PPID", utoa(getppid()));
13046 #if ENABLE_ASH_BASH_COMPAT
13047 p = lookupvar("SHLVL");
13048 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
13049 if (!lookupvar("HOSTNAME")) {
13050 struct utsname uts;
13051 uname(&uts);
13052 setvar2("HOSTNAME", uts.nodename);
13054 #endif
13055 p = lookupvar("PWD");
13056 if (p) {
13057 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
13058 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13060 p = '\0';
13063 setpwd(p, 0);
13068 //usage:#define ash_trivial_usage
13069 //usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
13070 //usage:#define ash_full_usage "\n\n"
13071 //usage: "Unix shell interpreter"
13073 //usage:#if ENABLE_FEATURE_SH_IS_ASH
13074 //usage:# define sh_trivial_usage ash_trivial_usage
13075 //usage:# define sh_full_usage ash_full_usage
13076 //usage:#endif
13077 //usage:#if ENABLE_FEATURE_BASH_IS_ASH
13078 //usage:# define bash_trivial_usage ash_trivial_usage
13079 //usage:# define bash_full_usage ash_full_usage
13080 //usage:#endif
13083 * Process the shell command line arguments.
13085 static void
13086 procargs(char **argv)
13088 int i;
13089 const char *xminusc;
13090 char **xargv;
13092 xargv = argv;
13093 arg0 = xargv[0];
13094 /* if (xargv[0]) - mmm, this is always true! */
13095 xargv++;
13096 for (i = 0; i < NOPTS; i++)
13097 optlist[i] = 2;
13098 argptr = xargv;
13099 if (options(/*cmdline:*/ 1)) {
13100 /* it already printed err message */
13101 raise_exception(EXERROR);
13103 xargv = argptr;
13104 xminusc = minusc;
13105 if (*xargv == NULL) {
13106 if (xminusc)
13107 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13108 sflag = 1;
13110 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13111 iflag = 1;
13112 if (mflag == 2)
13113 mflag = iflag;
13114 for (i = 0; i < NOPTS; i++)
13115 if (optlist[i] == 2)
13116 optlist[i] = 0;
13117 #if DEBUG == 2
13118 debug = 1;
13119 #endif
13120 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13121 if (xminusc) {
13122 minusc = *xargv++;
13123 if (*xargv)
13124 goto setarg0;
13125 } else if (!sflag) {
13126 setinputfile(*xargv, 0);
13127 setarg0:
13128 arg0 = *xargv++;
13129 commandname = arg0;
13132 shellparam.p = xargv;
13133 #if ENABLE_ASH_GETOPTS
13134 shellparam.optind = 1;
13135 shellparam.optoff = -1;
13136 #endif
13137 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13138 while (*xargv) {
13139 shellparam.nparam++;
13140 xargv++;
13142 optschanged();
13146 * Read /etc/profile or .profile.
13148 static void
13149 read_profile(const char *name)
13151 int skip;
13153 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13154 return;
13155 skip = cmdloop(0);
13156 popfile();
13157 if (skip)
13158 exitshell();
13162 * This routine is called when an error or an interrupt occurs in an
13163 * interactive shell and control is returned to the main command loop.
13165 static void
13166 reset(void)
13168 /* from eval.c: */
13169 evalskip = 0;
13170 loopnest = 0;
13171 /* from input.c: */
13172 g_parsefile->left_in_buffer = 0;
13173 g_parsefile->left_in_line = 0; /* clear input buffer */
13174 popallfiles();
13175 /* from parser.c: */
13176 tokpushback = 0;
13177 checkkwd = 0;
13178 /* from redir.c: */
13179 clearredir(/*drop:*/ 0);
13182 #if PROFILE
13183 static short profile_buf[16384];
13184 extern int etext();
13185 #endif
13188 * Main routine. We initialize things, parse the arguments, execute
13189 * profiles if we're a login shell, and then call cmdloop to execute
13190 * commands. The setjmp call sets up the location to jump to when an
13191 * exception occurs. When an exception occurs the variable "state"
13192 * is used to figure out how far we had gotten.
13194 int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13195 int ash_main(int argc UNUSED_PARAM, char **argv)
13197 const char *shinit;
13198 volatile smallint state;
13199 struct jmploc jmploc;
13200 struct stackmark smark;
13202 /* Initialize global data */
13203 INIT_G_misc();
13204 INIT_G_memstack();
13205 INIT_G_var();
13206 #if ENABLE_ASH_ALIAS
13207 INIT_G_alias();
13208 #endif
13209 INIT_G_cmdtable();
13211 #if PROFILE
13212 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13213 #endif
13215 #if ENABLE_FEATURE_EDITING
13216 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13217 #endif
13218 state = 0;
13219 if (setjmp(jmploc.loc)) {
13220 smallint e;
13221 smallint s;
13223 reset();
13225 e = exception_type;
13226 if (e == EXERROR)
13227 exitstatus = 2;
13228 s = state;
13229 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
13230 exitshell();
13232 if (e == EXINT) {
13233 outcslow('\n', stderr);
13236 popstackmark(&smark);
13237 FORCE_INT_ON; /* enable interrupts */
13238 if (s == 1)
13239 goto state1;
13240 if (s == 2)
13241 goto state2;
13242 if (s == 3)
13243 goto state3;
13244 goto state4;
13246 exception_handler = &jmploc;
13247 #if DEBUG
13248 opentrace();
13249 TRACE(("Shell args: "));
13250 trace_puts_args(argv);
13251 #endif
13252 rootpid = getpid();
13254 init();
13255 setstackmark(&smark);
13256 procargs(argv);
13258 if (argv[0] && argv[0][0] == '-')
13259 isloginsh = 1;
13260 if (isloginsh) {
13261 const char *hp;
13263 state = 1;
13264 read_profile("/etc/profile");
13265 state1:
13266 state = 2;
13267 hp = lookupvar("HOME");
13268 if (hp) {
13269 hp = concat_path_file(hp, ".profile");
13270 read_profile(hp);
13271 free((char*)hp);
13274 state2:
13275 state = 3;
13276 if (
13277 #ifndef linux
13278 getuid() == geteuid() && getgid() == getegid() &&
13279 #endif
13280 iflag
13282 shinit = lookupvar("ENV");
13283 if (shinit != NULL && *shinit != '\0') {
13284 read_profile(shinit);
13287 state3:
13288 state = 4;
13289 if (minusc) {
13290 /* evalstring pushes parsefile stack.
13291 * Ensure we don't falsely claim that 0 (stdin)
13292 * is one of stacked source fds.
13293 * Testcase: ash -c 'exec 1>&0' must not complain. */
13294 // if (!sflag) g_parsefile->pf_fd = -1;
13295 // ^^ not necessary since now we special-case fd 0
13296 // in is_hidden_fd() to not be considered "hidden fd"
13297 evalstring(minusc, 0);
13300 if (sflag || minusc == NULL) {
13301 #if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
13302 if (iflag) {
13303 const char *hp = lookupvar("HISTFILE");
13304 if (!hp) {
13305 hp = lookupvar("HOME");
13306 if (hp) {
13307 hp = concat_path_file(hp, ".ash_history");
13308 setvar2("HISTFILE", hp);
13309 free((char*)hp);
13310 hp = lookupvar("HISTFILE");
13313 if (hp)
13314 line_input_state->hist_file = hp;
13315 # if ENABLE_FEATURE_SH_HISTFILESIZE
13316 hp = lookupvar("HISTFILESIZE");
13317 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13318 # endif
13320 #endif
13321 state4: /* XXX ??? - why isn't this before the "if" statement */
13322 cmdloop(1);
13324 #if PROFILE
13325 monitor(0);
13326 #endif
13327 #ifdef GPROF
13329 extern void _mcleanup(void);
13330 _mcleanup();
13332 #endif
13333 TRACE(("End of main reached\n"));
13334 exitshell();
13335 /* NOTREACHED */
13340 * Copyright (c) 1989, 1991, 1993, 1994
13341 * The Regents of the University of California. All rights reserved.
13343 * This code is derived from software contributed to Berkeley by
13344 * Kenneth Almquist.
13346 * Redistribution and use in source and binary forms, with or without
13347 * modification, are permitted provided that the following conditions
13348 * are met:
13349 * 1. Redistributions of source code must retain the above copyright
13350 * notice, this list of conditions and the following disclaimer.
13351 * 2. Redistributions in binary form must reproduce the above copyright
13352 * notice, this list of conditions and the following disclaimer in the
13353 * documentation and/or other materials provided with the distribution.
13354 * 3. Neither the name of the University nor the names of its contributors
13355 * may be used to endorse or promote products derived from this software
13356 * without specific prior written permission.
13358 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13359 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13360 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13361 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13362 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13363 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13364 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13365 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13366 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13367 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13368 * SUCH DAMAGE.