summaryrefslogtreecommitdiff
path: root/shell/ash.c (plain)
blob: 7d45b2cd2c6c4c0ffffdeff8edee1e9f3a2808ce
1/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Original BSD copyright notice is retained at the end of this file.
9 *
10 * Copyright (c) 1989, 1991, 1993, 1994
11 * The Regents of the University of California. All rights reserved.
12 *
13 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
14 * was re-ported from NetBSD and debianized.
15 *
16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
17 */
18
19/*
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.
25 *
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.
29 */
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
35#define DEBUG_INTONOFF 0
36
37#define PROFILE 0
38
39#define JOBS ENABLE_ASH_JOB_CONTROL
40
41#include <setjmp.h>
42#include <fnmatch.h>
43#include <sys/times.h>
44#include <sys/utsname.h> /* for setting $HOSTNAME */
45
46#include "busybox.h" /* for applet_names */
47
48#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
49/* Bionic at least up to version 24 has no glob() */
50# undef ENABLE_ASH_INTERNAL_GLOB
51# define ENABLE_ASH_INTERNAL_GLOB 1
52#endif
53
54#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
55# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
56# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
57# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
58# error glob() should unbackslash them and match. uClibc does not unbackslash,
59# error fails to match dirname, subsequently not expanding <pattern> in it.
60#endif
61
62#if !ENABLE_ASH_INTERNAL_GLOB
63# include <glob.h>
64#endif
65
66#include "unicode.h"
67#include "shell_common.h"
68#if ENABLE_SH_MATH_SUPPORT
69# include "math.h"
70#endif
71#if ENABLE_ASH_RANDOM_SUPPORT
72# include "random.h"
73#else
74# define CLEAR_RANDOM_T(rnd) ((void)0)
75#endif
76
77#include "NUM_APPLETS.h"
78#if NUM_APPLETS == 1
79/* STANDALONE does not make sense, and won't compile */
80# undef CONFIG_FEATURE_SH_STANDALONE
81# undef ENABLE_FEATURE_SH_STANDALONE
82# undef IF_FEATURE_SH_STANDALONE
83# undef IF_NOT_FEATURE_SH_STANDALONE
84# define ENABLE_FEATURE_SH_STANDALONE 0
85# define IF_FEATURE_SH_STANDALONE(...)
86# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
87#endif
88
89#ifndef PIPE_BUF
90# define PIPE_BUF 4096 /* amount of buffering in a pipe */
91#endif
92
93#if !BB_MMU
94# error "Do not even bother, ash will not run on NOMMU machine"
95#endif
96
97//config:config ASH
98//config: bool "ash"
99//config: default y
100//config: depends on !NOMMU
101//config: help
102//config: Tha 'ash' shell adds about 60k in the default configuration and is
103//config: the most complete and most pedantically correct shell included with
104//config: busybox. This shell is actually a derivative of the Debian 'dash'
105//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
106//config: (written by Kenneth Almquist) from NetBSD.
107//config:
108//config:config ASH_OPTIMIZE_FOR_SIZE
109//config: bool "Optimize for size instead of speed"
110//config: default y
111//config: depends on ASH
112//config: help
113//config: Compile ash for reduced size at the price of speed.
114//config:
115//config:config ASH_INTERNAL_GLOB
116//config: bool "Use internal glob() implementation"
117//config: default n
118//config: depends on ASH
119//config: help
120//config: Do not use glob() function from libc, use internal implementation.
121//config: Use this if you are getting "glob.h: No such file or directory"
122//config: or similar build errors.
123//config:
124//config:config ASH_RANDOM_SUPPORT
125//config: bool "Pseudorandom generator and $RANDOM variable"
126//config: default y
127//config: depends on ASH
128//config: help
129//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
130//config: Each read of "$RANDOM" will generate a new pseudorandom value.
131//config: You can reset the generator by using a specified start value.
132//config: After "unset RANDOM" the generator will switch off and this
133//config: variable will no longer have special treatment.
134//config:
135//config:config ASH_EXPAND_PRMT
136//config: bool "Expand prompt string"
137//config: default y
138//config: depends on ASH
139//config: help
140//config: "PS#" may contain volatile content, such as backquote commands.
141//config: This option recreates the prompt string from the environment
142//config: variable each time it is displayed.
143//config:
144//config:config ASH_BASH_COMPAT
145//config: bool "bash-compatible extensions"
146//config: default y
147//config: depends on ASH
148//config: help
149//config: Enable bash-compatible extensions.
150//config:
151//config:config ASH_IDLE_TIMEOUT
152//config: bool "Idle timeout variable"
153//config: default n
154//config: depends on ASH
155//config: help
156//config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
157//config:
158//config:config ASH_JOB_CONTROL
159//config: bool "Job control"
160//config: default y
161//config: depends on ASH
162//config: help
163//config: Enable job control in the ash shell.
164//config:
165//config:config ASH_ALIAS
166//config: bool "Alias support"
167//config: default y
168//config: depends on ASH
169//config: help
170//config: Enable alias support in the ash shell.
171//config:
172//config:config ASH_GETOPTS
173//config: bool "Builtin getopt to parse positional parameters"
174//config: default y
175//config: depends on ASH
176//config: help
177//config: Enable support for getopts builtin in ash.
178//config:
179//config:config ASH_BUILTIN_ECHO
180//config: bool "Builtin version of 'echo'"
181//config: default y
182//config: depends on ASH
183//config: help
184//config: Enable support for echo builtin in ash.
185//config:
186//config:config ASH_BUILTIN_PRINTF
187//config: bool "Builtin version of 'printf'"
188//config: default y
189//config: depends on ASH
190//config: help
191//config: Enable support for printf builtin in ash.
192//config:
193//config:config ASH_BUILTIN_TEST
194//config: bool "Builtin version of 'test'"
195//config: default y
196//config: depends on ASH
197//config: help
198//config: Enable support for test builtin in ash.
199//config:
200//config:config ASH_HELP
201//config: bool "help builtin"
202//config: default y
203//config: depends on ASH
204//config: help
205//config: Enable help builtin in ash.
206//config:
207//config:config ASH_CMDCMD
208//config: bool "'command' command to override shell builtins"
209//config: default y
210//config: depends on ASH
211//config: help
212//config: Enable support for the ash 'command' builtin, which allows
213//config: you to run the specified command with the specified arguments,
214//config: even when there is an ash builtin command with the same name.
215//config:
216//config:config ASH_MAIL
217//config: bool "Check for new mail on interactive shells"
218//config: default n
219//config: depends on ASH
220//config: help
221//config: Enable "check for new mail" function in the ash shell.
222//config:
223
224//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
225//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh))
226//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash))
227
228//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
229//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
230
231
232/* ============ Hash table sizes. Configurable. */
233
234#define VTABSIZE 39
235#define ATABSIZE 39
236#define CMDTABLESIZE 31 /* should be prime */
237
238
239/* ============ Shell options */
240
241static const char *const optletters_optnames[] = {
242 "e" "errexit",
243 "f" "noglob",
244 "I" "ignoreeof",
245 "i" "interactive",
246 "m" "monitor",
247 "n" "noexec",
248 "s" "stdin",
249 "x" "xtrace",
250 "v" "verbose",
251 "C" "noclobber",
252 "a" "allexport",
253 "b" "notify",
254 "u" "nounset",
255 "\0" "vi"
256#if ENABLE_ASH_BASH_COMPAT
257 ,"\0" "pipefail"
258#endif
259#if DEBUG
260 ,"\0" "nolog"
261 ,"\0" "debug"
262#endif
263};
264
265#define optletters(n) optletters_optnames[n][0]
266#define optnames(n) (optletters_optnames[n] + 1)
267
268enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
269
270
271/* ============ Misc data */
272
273#define msg_illnum "Illegal number: %s"
274
275/*
276 * We enclose jmp_buf in a structure so that we can declare pointers to
277 * jump locations. The global variable handler contains the location to
278 * jump to when an exception occurs, and the global variable exception_type
279 * contains a code identifying the exception. To implement nested
280 * exception handlers, the user should save the value of handler on entry
281 * to an inner scope, set handler to point to a jmploc structure for the
282 * inner scope, and restore handler on exit from the scope.
283 */
284struct jmploc {
285 jmp_buf loc;
286};
287
288struct globals_misc {
289 uint8_t exitstatus; /* exit status of last command */
290 uint8_t back_exitstatus;/* exit status of backquoted command */
291 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
292 int rootpid; /* pid of main shell */
293 /* shell level: 0 for the main shell, 1 for its children, and so on */
294 int shlvl;
295#define rootshell (!shlvl)
296 char *minusc; /* argument to -c option */
297
298 char *curdir; // = nullstr; /* current working directory */
299 char *physdir; // = nullstr; /* physical working directory */
300
301 char *arg0; /* value of $0 */
302
303 struct jmploc *exception_handler;
304
305 volatile int suppress_int; /* counter */
306 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
307 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
308 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
309 smallint exception_type; /* kind of exception (0..5) */
310 /* exceptions */
311#define EXINT 0 /* SIGINT received */
312#define EXERROR 1 /* a generic error */
313#define EXEXIT 4 /* exit the shell */
314
315 smallint isloginsh;
316 char nullstr[1]; /* zero length string */
317
318 char optlist[NOPTS];
319#define eflag optlist[0]
320#define fflag optlist[1]
321#define Iflag optlist[2]
322#define iflag optlist[3]
323#define mflag optlist[4]
324#define nflag optlist[5]
325#define sflag optlist[6]
326#define xflag optlist[7]
327#define vflag optlist[8]
328#define Cflag optlist[9]
329#define aflag optlist[10]
330#define bflag optlist[11]
331#define uflag optlist[12]
332#define viflag optlist[13]
333#if ENABLE_ASH_BASH_COMPAT
334# define pipefail optlist[14]
335#else
336# define pipefail 0
337#endif
338#if DEBUG
339# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
340# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
341#endif
342
343 /* trap handler commands */
344 /*
345 * Sigmode records the current value of the signal handlers for the various
346 * modes. A value of zero means that the current handler is not known.
347 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
348 */
349 char sigmode[NSIG - 1];
350#define S_DFL 1 /* default signal handling (SIG_DFL) */
351#define S_CATCH 2 /* signal is caught */
352#define S_IGN 3 /* signal is ignored (SIG_IGN) */
353#define S_HARD_IGN 4 /* signal is ignored permanently */
354
355 /* indicates specified signal received */
356 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
357 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
358 char *trap[NSIG];
359 char **trap_ptr; /* used only by "trap hack" */
360
361 /* Rarely referenced stuff */
362#if ENABLE_ASH_RANDOM_SUPPORT
363 random_t random_gen;
364#endif
365 pid_t backgndpid; /* pid of last background process */
366};
367extern struct globals_misc *const ash_ptr_to_globals_misc;
368#define G_misc (*ash_ptr_to_globals_misc)
369#define exitstatus (G_misc.exitstatus )
370#define back_exitstatus (G_misc.back_exitstatus )
371#define job_warning (G_misc.job_warning)
372#define rootpid (G_misc.rootpid )
373#define shlvl (G_misc.shlvl )
374#define minusc (G_misc.minusc )
375#define curdir (G_misc.curdir )
376#define physdir (G_misc.physdir )
377#define arg0 (G_misc.arg0 )
378#define exception_handler (G_misc.exception_handler)
379#define exception_type (G_misc.exception_type )
380#define suppress_int (G_misc.suppress_int )
381#define pending_int (G_misc.pending_int )
382#define got_sigchld (G_misc.got_sigchld )
383#define pending_sig (G_misc.pending_sig )
384#define isloginsh (G_misc.isloginsh )
385#define nullstr (G_misc.nullstr )
386#define optlist (G_misc.optlist )
387#define sigmode (G_misc.sigmode )
388#define gotsig (G_misc.gotsig )
389#define may_have_traps (G_misc.may_have_traps )
390#define trap (G_misc.trap )
391#define trap_ptr (G_misc.trap_ptr )
392#define random_gen (G_misc.random_gen )
393#define backgndpid (G_misc.backgndpid )
394#define INIT_G_misc() do { \
395 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
396 barrier(); \
397 curdir = nullstr; \
398 physdir = nullstr; \
399 trap_ptr = trap; \
400} while (0)
401
402
403/* ============ DEBUG */
404#if DEBUG
405static void trace_printf(const char *fmt, ...);
406static void trace_vprintf(const char *fmt, va_list va);
407# define TRACE(param) trace_printf param
408# define TRACEV(param) trace_vprintf param
409# define close(fd) do { \
410 int dfd = (fd); \
411 if (close(dfd) < 0) \
412 bb_error_msg("bug on %d: closing %d(0x%x)", \
413 __LINE__, dfd, dfd); \
414} while (0)
415#else
416# define TRACE(param)
417# define TRACEV(param)
418#endif
419
420
421/* ============ Utility functions */
422#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
423#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
424
425static int
426isdigit_str9(const char *str)
427{
428 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
429 while (--maxlen && isdigit(*str))
430 str++;
431 return (*str == '\0');
432}
433
434static const char *
435var_end(const char *var)
436{
437 while (*var)
438 if (*var++ == '=')
439 break;
440 return var;
441}
442
443
444/* ============ Interrupts / exceptions */
445
446static void exitshell(void) NORETURN;
447
448/*
449 * These macros allow the user to suspend the handling of interrupt signals
450 * over a period of time. This is similar to SIGHOLD or to sigblock, but
451 * much more efficient and portable. (But hacking the kernel is so much
452 * more fun than worrying about efficiency and portability. :-))
453 */
454#if DEBUG_INTONOFF
455# define INT_OFF do { \
456 TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
457 suppress_int++; \
458 barrier(); \
459} while (0)
460#else
461# define INT_OFF do { \
462 suppress_int++; \
463 barrier(); \
464} while (0)
465#endif
466
467/*
468 * Called to raise an exception. Since C doesn't include exceptions, we
469 * just do a longjmp to the exception handler. The type of exception is
470 * stored in the global variable "exception_type".
471 */
472static void raise_exception(int) NORETURN;
473static void
474raise_exception(int e)
475{
476#if DEBUG
477 if (exception_handler == NULL)
478 abort();
479#endif
480 INT_OFF;
481 exception_type = e;
482 longjmp(exception_handler->loc, 1);
483}
484#if DEBUG
485#define raise_exception(e) do { \
486 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
487 raise_exception(e); \
488} while (0)
489#endif
490
491/*
492 * Called when a SIGINT is received. (If the user specifies
493 * that SIGINT is to be trapped or ignored using the trap builtin, then
494 * this routine is not called.) Suppressint is nonzero when interrupts
495 * are held using the INT_OFF macro. (The test for iflag is just
496 * defensive programming.)
497 */
498static void raise_interrupt(void) NORETURN;
499static void
500raise_interrupt(void)
501{
502 pending_int = 0;
503 /* Signal is not automatically unmasked after it is raised,
504 * do it ourself - unmask all signals */
505 sigprocmask_allsigs(SIG_UNBLOCK);
506 /* pending_sig = 0; - now done in signal_handler() */
507
508 if (!(rootshell && iflag)) {
509 /* Kill ourself with SIGINT */
510 signal(SIGINT, SIG_DFL);
511 raise(SIGINT);
512 }
513 /* bash: ^C even on empty command line sets $? */
514 exitstatus = SIGINT + 128;
515 raise_exception(EXINT);
516 /* NOTREACHED */
517}
518#if DEBUG
519#define raise_interrupt() do { \
520 TRACE(("raising interrupt on line %d\n", __LINE__)); \
521 raise_interrupt(); \
522} while (0)
523#endif
524
525static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
526int_on(void)
527{
528 barrier();
529 if (--suppress_int == 0 && pending_int) {
530 raise_interrupt();
531 }
532}
533#if DEBUG_INTONOFF
534# define INT_ON do { \
535 TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
536 int_on(); \
537} while (0)
538#else
539# define INT_ON int_on()
540#endif
541static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
542force_int_on(void)
543{
544 barrier();
545 suppress_int = 0;
546 if (pending_int)
547 raise_interrupt();
548}
549#define FORCE_INT_ON force_int_on()
550
551#define SAVE_INT(v) ((v) = suppress_int)
552
553#define RESTORE_INT(v) do { \
554 barrier(); \
555 suppress_int = (v); \
556 if (suppress_int == 0 && pending_int) \
557 raise_interrupt(); \
558} while (0)
559
560
561/* ============ Stdout/stderr output */
562
563static void
564outstr(const char *p, FILE *file)
565{
566 INT_OFF;
567 fputs(p, file);
568 INT_ON;
569}
570
571static void
572flush_stdout_stderr(void)
573{
574 INT_OFF;
575 fflush_all();
576 INT_ON;
577}
578
579/* Was called outcslow(c,FILE*), but c was always '\n' */
580static void
581newline_and_flush(FILE *dest)
582{
583 INT_OFF;
584 putc('\n', dest);
585 fflush(dest);
586 INT_ON;
587}
588
589static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
590static int
591out1fmt(const char *fmt, ...)
592{
593 va_list ap;
594 int r;
595
596 INT_OFF;
597 va_start(ap, fmt);
598 r = vprintf(fmt, ap);
599 va_end(ap);
600 INT_ON;
601 return r;
602}
603
604static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
605static int
606fmtstr(char *outbuf, size_t length, const char *fmt, ...)
607{
608 va_list ap;
609 int ret;
610
611 va_start(ap, fmt);
612 INT_OFF;
613 ret = vsnprintf(outbuf, length, fmt, ap);
614 va_end(ap);
615 INT_ON;
616 return ret;
617}
618
619static void
620out1str(const char *p)
621{
622 outstr(p, stdout);
623}
624
625static void
626out2str(const char *p)
627{
628 outstr(p, stderr);
629 flush_stdout_stderr();
630}
631
632
633/* ============ Parser structures */
634
635/* control characters in argument strings */
636#define CTL_FIRST CTLESC
637#define CTLESC ((unsigned char)'\201') /* escape next character */
638#define CTLVAR ((unsigned char)'\202') /* variable defn */
639#define CTLENDVAR ((unsigned char)'\203')
640#define CTLBACKQ ((unsigned char)'\204')
641#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
642#define CTLENDARI ((unsigned char)'\207')
643#define CTLQUOTEMARK ((unsigned char)'\210')
644#define CTL_LAST CTLQUOTEMARK
645
646/* variable substitution byte (follows CTLVAR) */
647#define VSTYPE 0x0f /* type of variable substitution */
648#define VSNUL 0x10 /* colon--treat the empty string as unset */
649
650/* values of VSTYPE field */
651#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
652#define VSMINUS 0x2 /* ${var-text} */
653#define VSPLUS 0x3 /* ${var+text} */
654#define VSQUESTION 0x4 /* ${var?message} */
655#define VSASSIGN 0x5 /* ${var=text} */
656#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
657#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
658#define VSTRIMLEFT 0x8 /* ${var#pattern} */
659#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
660#define VSLENGTH 0xa /* ${#var} */
661#if ENABLE_ASH_BASH_COMPAT
662#define VSSUBSTR 0xc /* ${var:position:length} */
663#define VSREPLACE 0xd /* ${var/pattern/replacement} */
664#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
665#endif
666
667static const char dolatstr[] ALIGN1 = {
668 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
669};
670#define DOLATSTRLEN 6
671
672#define NCMD 0
673#define NPIPE 1
674#define NREDIR 2
675#define NBACKGND 3
676#define NSUBSHELL 4
677#define NAND 5
678#define NOR 6
679#define NSEMI 7
680#define NIF 8
681#define NWHILE 9
682#define NUNTIL 10
683#define NFOR 11
684#define NCASE 12
685#define NCLIST 13
686#define NDEFUN 14
687#define NARG 15
688#define NTO 16
689#if ENABLE_ASH_BASH_COMPAT
690#define NTO2 17
691#endif
692#define NCLOBBER 18
693#define NFROM 19
694#define NFROMTO 20
695#define NAPPEND 21
696#define NTOFD 22
697#define NFROMFD 23
698#define NHERE 24
699#define NXHERE 25
700#define NNOT 26
701#define N_NUMBER 27
702
703union node;
704
705struct ncmd {
706 smallint type; /* Nxxxx */
707 union node *assign;
708 union node *args;
709 union node *redirect;
710};
711
712struct npipe {
713 smallint type;
714 smallint pipe_backgnd;
715 struct nodelist *cmdlist;
716};
717
718struct nredir {
719 smallint type;
720 union node *n;
721 union node *redirect;
722};
723
724struct nbinary {
725 smallint type;
726 union node *ch1;
727 union node *ch2;
728};
729
730struct nif {
731 smallint type;
732 union node *test;
733 union node *ifpart;
734 union node *elsepart;
735};
736
737struct nfor {
738 smallint type;
739 union node *args;
740 union node *body;
741 char *var;
742};
743
744struct ncase {
745 smallint type;
746 union node *expr;
747 union node *cases;
748};
749
750struct nclist {
751 smallint type;
752 union node *next;
753 union node *pattern;
754 union node *body;
755};
756
757struct narg {
758 smallint type;
759 union node *next;
760 char *text;
761 struct nodelist *backquote;
762};
763
764/* nfile and ndup layout must match!
765 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
766 * that it is actually NTO2 (>&file), and change its type.
767 */
768struct nfile {
769 smallint type;
770 union node *next;
771 int fd;
772 int _unused_dupfd;
773 union node *fname;
774 char *expfname;
775};
776
777struct ndup {
778 smallint type;
779 union node *next;
780 int fd;
781 int dupfd;
782 union node *vname;
783 char *_unused_expfname;
784};
785
786struct nhere {
787 smallint type;
788 union node *next;
789 int fd;
790 union node *doc;
791};
792
793struct nnot {
794 smallint type;
795 union node *com;
796};
797
798union node {
799 smallint type;
800 struct ncmd ncmd;
801 struct npipe npipe;
802 struct nredir nredir;
803 struct nbinary nbinary;
804 struct nif nif;
805 struct nfor nfor;
806 struct ncase ncase;
807 struct nclist nclist;
808 struct narg narg;
809 struct nfile nfile;
810 struct ndup ndup;
811 struct nhere nhere;
812 struct nnot nnot;
813};
814
815/*
816 * NODE_EOF is returned by parsecmd when it encounters an end of file.
817 * It must be distinct from NULL.
818 */
819#define NODE_EOF ((union node *) -1L)
820
821struct nodelist {
822 struct nodelist *next;
823 union node *n;
824};
825
826struct funcnode {
827 int count;
828 union node n;
829};
830
831/*
832 * Free a parse tree.
833 */
834static void
835freefunc(struct funcnode *f)
836{
837 if (f && --f->count < 0)
838 free(f);
839}
840
841
842/* ============ Debugging output */
843
844#if DEBUG
845
846static FILE *tracefile;
847
848static void
849trace_printf(const char *fmt, ...)
850{
851 va_list va;
852
853 if (debug != 1)
854 return;
855 if (DEBUG_TIME)
856 fprintf(tracefile, "%u ", (int) time(NULL));
857 if (DEBUG_PID)
858 fprintf(tracefile, "[%u] ", (int) getpid());
859 if (DEBUG_SIG)
860 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
861 va_start(va, fmt);
862 vfprintf(tracefile, fmt, va);
863 va_end(va);
864}
865
866static void
867trace_vprintf(const char *fmt, va_list va)
868{
869 if (debug != 1)
870 return;
871 vfprintf(tracefile, fmt, va);
872 fprintf(tracefile, "\n");
873}
874
875static void
876trace_puts(const char *s)
877{
878 if (debug != 1)
879 return;
880 fputs(s, tracefile);
881}
882
883static void
884trace_puts_quoted(char *s)
885{
886 char *p;
887 char c;
888
889 if (debug != 1)
890 return;
891 putc('"', tracefile);
892 for (p = s; *p; p++) {
893 switch ((unsigned char)*p) {
894 case '\n': c = 'n'; goto backslash;
895 case '\t': c = 't'; goto backslash;
896 case '\r': c = 'r'; goto backslash;
897 case '\"': c = '\"'; goto backslash;
898 case '\\': c = '\\'; goto backslash;
899 case CTLESC: c = 'e'; goto backslash;
900 case CTLVAR: c = 'v'; goto backslash;
901 case CTLBACKQ: c = 'q'; goto backslash;
902 backslash:
903 putc('\\', tracefile);
904 putc(c, tracefile);
905 break;
906 default:
907 if (*p >= ' ' && *p <= '~')
908 putc(*p, tracefile);
909 else {
910 putc('\\', tracefile);
911 putc((*p >> 6) & 03, tracefile);
912 putc((*p >> 3) & 07, tracefile);
913 putc(*p & 07, tracefile);
914 }
915 break;
916 }
917 }
918 putc('"', tracefile);
919}
920
921static void
922trace_puts_args(char **ap)
923{
924 if (debug != 1)
925 return;
926 if (!*ap)
927 return;
928 while (1) {
929 trace_puts_quoted(*ap);
930 if (!*++ap) {
931 putc('\n', tracefile);
932 break;
933 }
934 putc(' ', tracefile);
935 }
936}
937
938static void
939opentrace(void)
940{
941 char s[100];
942#ifdef O_APPEND
943 int flags;
944#endif
945
946 if (debug != 1) {
947 if (tracefile)
948 fflush(tracefile);
949 /* leave open because libedit might be using it */
950 return;
951 }
952 strcpy(s, "./trace");
953 if (tracefile) {
954 if (!freopen(s, "a", tracefile)) {
955 fprintf(stderr, "Can't re-open %s\n", s);
956 debug = 0;
957 return;
958 }
959 } else {
960 tracefile = fopen(s, "a");
961 if (tracefile == NULL) {
962 fprintf(stderr, "Can't open %s\n", s);
963 debug = 0;
964 return;
965 }
966 }
967#ifdef O_APPEND
968 flags = fcntl(fileno(tracefile), F_GETFL);
969 if (flags >= 0)
970 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
971#endif
972 setlinebuf(tracefile);
973 fputs("\nTracing started.\n", tracefile);
974}
975
976static void
977indent(int amount, char *pfx, FILE *fp)
978{
979 int i;
980
981 for (i = 0; i < amount; i++) {
982 if (pfx && i == amount - 1)
983 fputs(pfx, fp);
984 putc('\t', fp);
985 }
986}
987
988/* little circular references here... */
989static void shtree(union node *n, int ind, char *pfx, FILE *fp);
990
991static void
992sharg(union node *arg, FILE *fp)
993{
994 char *p;
995 struct nodelist *bqlist;
996 unsigned char subtype;
997
998 if (arg->type != NARG) {
999 out1fmt("<node type %d>\n", arg->type);
1000 abort();
1001 }
1002 bqlist = arg->narg.backquote;
1003 for (p = arg->narg.text; *p; p++) {
1004 switch ((unsigned char)*p) {
1005 case CTLESC:
1006 p++;
1007 putc(*p, fp);
1008 break;
1009 case CTLVAR:
1010 putc('$', fp);
1011 putc('{', fp);
1012 subtype = *++p;
1013 if (subtype == VSLENGTH)
1014 putc('#', fp);
1015
1016 while (*p != '=') {
1017 putc(*p, fp);
1018 p++;
1019 }
1020
1021 if (subtype & VSNUL)
1022 putc(':', fp);
1023
1024 switch (subtype & VSTYPE) {
1025 case VSNORMAL:
1026 putc('}', fp);
1027 break;
1028 case VSMINUS:
1029 putc('-', fp);
1030 break;
1031 case VSPLUS:
1032 putc('+', fp);
1033 break;
1034 case VSQUESTION:
1035 putc('?', fp);
1036 break;
1037 case VSASSIGN:
1038 putc('=', fp);
1039 break;
1040 case VSTRIMLEFT:
1041 putc('#', fp);
1042 break;
1043 case VSTRIMLEFTMAX:
1044 putc('#', fp);
1045 putc('#', fp);
1046 break;
1047 case VSTRIMRIGHT:
1048 putc('%', fp);
1049 break;
1050 case VSTRIMRIGHTMAX:
1051 putc('%', fp);
1052 putc('%', fp);
1053 break;
1054 case VSLENGTH:
1055 break;
1056 default:
1057 out1fmt("<subtype %d>", subtype);
1058 }
1059 break;
1060 case CTLENDVAR:
1061 putc('}', fp);
1062 break;
1063 case CTLBACKQ:
1064 putc('$', fp);
1065 putc('(', fp);
1066 shtree(bqlist->n, -1, NULL, fp);
1067 putc(')', fp);
1068 break;
1069 default:
1070 putc(*p, fp);
1071 break;
1072 }
1073 }
1074}
1075
1076static void
1077shcmd(union node *cmd, FILE *fp)
1078{
1079 union node *np;
1080 int first;
1081 const char *s;
1082 int dftfd;
1083
1084 first = 1;
1085 for (np = cmd->ncmd.args; np; np = np->narg.next) {
1086 if (!first)
1087 putc(' ', fp);
1088 sharg(np, fp);
1089 first = 0;
1090 }
1091 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
1092 if (!first)
1093 putc(' ', fp);
1094 dftfd = 0;
1095 switch (np->nfile.type) {
1096 case NTO: s = ">>"+1; dftfd = 1; break;
1097 case NCLOBBER: s = ">|"; dftfd = 1; break;
1098 case NAPPEND: s = ">>"; dftfd = 1; break;
1099#if ENABLE_ASH_BASH_COMPAT
1100 case NTO2:
1101#endif
1102 case NTOFD: s = ">&"; dftfd = 1; break;
1103 case NFROM: s = "<"; break;
1104 case NFROMFD: s = "<&"; break;
1105 case NFROMTO: s = "<>"; break;
1106 default: s = "*error*"; break;
1107 }
1108 if (np->nfile.fd != dftfd)
1109 fprintf(fp, "%d", np->nfile.fd);
1110 fputs(s, fp);
1111 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1112 fprintf(fp, "%d", np->ndup.dupfd);
1113 } else {
1114 sharg(np->nfile.fname, fp);
1115 }
1116 first = 0;
1117 }
1118}
1119
1120static void
1121shtree(union node *n, int ind, char *pfx, FILE *fp)
1122{
1123 struct nodelist *lp;
1124 const char *s;
1125
1126 if (n == NULL)
1127 return;
1128
1129 indent(ind, pfx, fp);
1130
1131 if (n == NODE_EOF) {
1132 fputs("<EOF>", fp);
1133 return;
1134 }
1135
1136 switch (n->type) {
1137 case NSEMI:
1138 s = "; ";
1139 goto binop;
1140 case NAND:
1141 s = " && ";
1142 goto binop;
1143 case NOR:
1144 s = " || ";
1145 binop:
1146 shtree(n->nbinary.ch1, ind, NULL, fp);
1147 /* if (ind < 0) */
1148 fputs(s, fp);
1149 shtree(n->nbinary.ch2, ind, NULL, fp);
1150 break;
1151 case NCMD:
1152 shcmd(n, fp);
1153 if (ind >= 0)
1154 putc('\n', fp);
1155 break;
1156 case NPIPE:
1157 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
1158 shtree(lp->n, 0, NULL, fp);
1159 if (lp->next)
1160 fputs(" | ", fp);
1161 }
1162 if (n->npipe.pipe_backgnd)
1163 fputs(" &", fp);
1164 if (ind >= 0)
1165 putc('\n', fp);
1166 break;
1167 default:
1168 fprintf(fp, "<node type %d>", n->type);
1169 if (ind >= 0)
1170 putc('\n', fp);
1171 break;
1172 }
1173}
1174
1175static void
1176showtree(union node *n)
1177{
1178 trace_puts("showtree called\n");
1179 shtree(n, 1, NULL, stderr);
1180}
1181
1182#endif /* DEBUG */
1183
1184
1185/* ============ Parser data */
1186
1187/*
1188 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1189 */
1190struct strlist {
1191 struct strlist *next;
1192 char *text;
1193};
1194
1195struct alias;
1196
1197struct strpush {
1198 struct strpush *prev; /* preceding string on stack */
1199 char *prev_string;
1200 int prev_left_in_line;
1201#if ENABLE_ASH_ALIAS
1202 struct alias *ap; /* if push was associated with an alias */
1203#endif
1204 char *string; /* remember the string since it may change */
1205
1206 /* Remember last two characters for pungetc. */
1207 int lastc[2];
1208
1209 /* Number of outstanding calls to pungetc. */
1210 int unget;
1211};
1212
1213struct parsefile {
1214 struct parsefile *prev; /* preceding file on stack */
1215 int linno; /* current line */
1216 int pf_fd; /* file descriptor (or -1 if string) */
1217 int left_in_line; /* number of chars left in this line */
1218 int left_in_buffer; /* number of chars left in this buffer past the line */
1219 char *next_to_pgetc; /* next char in buffer */
1220 char *buf; /* input buffer */
1221 struct strpush *strpush; /* for pushing strings at this level */
1222 struct strpush basestrpush; /* so pushing one is fast */
1223
1224 /* Remember last two characters for pungetc. */
1225 int lastc[2];
1226
1227 /* Number of outstanding calls to pungetc. */
1228 int unget;
1229};
1230
1231static struct parsefile basepf; /* top level input file */
1232static struct parsefile *g_parsefile = &basepf; /* current input file */
1233static int startlinno; /* line # where last token started */
1234static char *commandname; /* currently executing command */
1235static struct strlist *cmdenviron; /* environment for builtin command */
1236
1237
1238/* ============ Message printing */
1239
1240static void
1241ash_vmsg(const char *msg, va_list ap)
1242{
1243 fprintf(stderr, "%s: ", arg0);
1244 if (commandname) {
1245 if (strcmp(arg0, commandname))
1246 fprintf(stderr, "%s: ", commandname);
1247 if (!iflag || g_parsefile->pf_fd > 0)
1248 fprintf(stderr, "line %d: ", startlinno);
1249 }
1250 vfprintf(stderr, msg, ap);
1251 newline_and_flush(stderr);
1252}
1253
1254/*
1255 * Exverror is called to raise the error exception. If the second argument
1256 * is not NULL then error prints an error message using printf style
1257 * formatting. It then raises the error exception.
1258 */
1259static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
1260static void
1261ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
1262{
1263#if DEBUG
1264 if (msg) {
1265 TRACE(("ash_vmsg_and_raise(%d):", cond));
1266 TRACEV((msg, ap));
1267 } else
1268 TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
1269 if (msg)
1270#endif
1271 ash_vmsg(msg, ap);
1272
1273 flush_stdout_stderr();
1274 raise_exception(cond);
1275 /* NOTREACHED */
1276}
1277
1278static void ash_msg_and_raise_error(const char *, ...) NORETURN;
1279static void
1280ash_msg_and_raise_error(const char *msg, ...)
1281{
1282 va_list ap;
1283
1284 va_start(ap, msg);
1285 ash_vmsg_and_raise(EXERROR, msg, ap);
1286 /* NOTREACHED */
1287 va_end(ap);
1288}
1289
1290static void raise_error_syntax(const char *) NORETURN;
1291static void
1292raise_error_syntax(const char *msg)
1293{
1294 ash_msg_and_raise_error("syntax error: %s", msg);
1295 /* NOTREACHED */
1296}
1297
1298static void ash_msg_and_raise(int, const char *, ...) NORETURN;
1299static void
1300ash_msg_and_raise(int cond, const char *msg, ...)
1301{
1302 va_list ap;
1303
1304 va_start(ap, msg);
1305 ash_vmsg_and_raise(cond, msg, ap);
1306 /* NOTREACHED */
1307 va_end(ap);
1308}
1309
1310/*
1311 * error/warning routines for external builtins
1312 */
1313static void
1314ash_msg(const char *fmt, ...)
1315{
1316 va_list ap;
1317
1318 va_start(ap, fmt);
1319 ash_vmsg(fmt, ap);
1320 va_end(ap);
1321}
1322
1323/*
1324 * Return a string describing an error. The returned string may be a
1325 * pointer to a static buffer that will be overwritten on the next call.
1326 * Action describes the operation that got the error.
1327 */
1328static const char *
1329errmsg(int e, const char *em)
1330{
1331 if (e == ENOENT || e == ENOTDIR) {
1332 return em;
1333 }
1334 return strerror(e);
1335}
1336
1337
1338/* ============ Memory allocation */
1339
1340#if 0
1341/* I consider these wrappers nearly useless:
1342 * ok, they return you to nearest exception handler, but
1343 * how much memory do you leak in the process, making
1344 * memory starvation worse?
1345 */
1346static void *
1347ckrealloc(void * p, size_t nbytes)
1348{
1349 p = realloc(p, nbytes);
1350 if (!p)
1351 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1352 return p;
1353}
1354
1355static void *
1356ckmalloc(size_t nbytes)
1357{
1358 return ckrealloc(NULL, nbytes);
1359}
1360
1361static void *
1362ckzalloc(size_t nbytes)
1363{
1364 return memset(ckmalloc(nbytes), 0, nbytes);
1365}
1366
1367static char *
1368ckstrdup(const char *s)
1369{
1370 char *p = strdup(s);
1371 if (!p)
1372 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1373 return p;
1374}
1375#else
1376/* Using bbox equivalents. They exit if out of memory */
1377# define ckrealloc xrealloc
1378# define ckmalloc xmalloc
1379# define ckzalloc xzalloc
1380# define ckstrdup xstrdup
1381#endif
1382
1383/*
1384 * It appears that grabstackstr() will barf with such alignments
1385 * because stalloc() will return a string allocated in a new stackblock.
1386 */
1387#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1388enum {
1389 /* Most machines require the value returned from malloc to be aligned
1390 * in some way. The following macro will get this right
1391 * on many machines. */
1392 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
1393 /* Minimum size of a block */
1394 MINSIZE = SHELL_ALIGN(504),
1395};
1396
1397struct stack_block {
1398 struct stack_block *prev;
1399 char space[MINSIZE];
1400};
1401
1402struct stackmark {
1403 struct stack_block *stackp;
1404 char *stacknxt;
1405 size_t stacknleft;
1406};
1407
1408
1409struct globals_memstack {
1410 struct stack_block *g_stackp; // = &stackbase;
1411 char *g_stacknxt; // = stackbase.space;
1412 char *sstrend; // = stackbase.space + MINSIZE;
1413 size_t g_stacknleft; // = MINSIZE;
1414 struct stack_block stackbase;
1415};
1416extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1417#define G_memstack (*ash_ptr_to_globals_memstack)
1418#define g_stackp (G_memstack.g_stackp )
1419#define g_stacknxt (G_memstack.g_stacknxt )
1420#define sstrend (G_memstack.sstrend )
1421#define g_stacknleft (G_memstack.g_stacknleft)
1422#define stackbase (G_memstack.stackbase )
1423#define INIT_G_memstack() do { \
1424 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1425 barrier(); \
1426 g_stackp = &stackbase; \
1427 g_stacknxt = stackbase.space; \
1428 g_stacknleft = MINSIZE; \
1429 sstrend = stackbase.space + MINSIZE; \
1430} while (0)
1431
1432
1433#define stackblock() ((void *)g_stacknxt)
1434#define stackblocksize() g_stacknleft
1435
1436/*
1437 * Parse trees for commands are allocated in lifo order, so we use a stack
1438 * to make this more efficient, and also to avoid all sorts of exception
1439 * handling code to handle interrupts in the middle of a parse.
1440 *
1441 * The size 504 was chosen because the Ultrix malloc handles that size
1442 * well.
1443 */
1444static void *
1445stalloc(size_t nbytes)
1446{
1447 char *p;
1448 size_t aligned;
1449
1450 aligned = SHELL_ALIGN(nbytes);
1451 if (aligned > g_stacknleft) {
1452 size_t len;
1453 size_t blocksize;
1454 struct stack_block *sp;
1455
1456 blocksize = aligned;
1457 if (blocksize < MINSIZE)
1458 blocksize = MINSIZE;
1459 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1460 if (len < blocksize)
1461 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1462 INT_OFF;
1463 sp = ckmalloc(len);
1464 sp->prev = g_stackp;
1465 g_stacknxt = sp->space;
1466 g_stacknleft = blocksize;
1467 sstrend = g_stacknxt + blocksize;
1468 g_stackp = sp;
1469 INT_ON;
1470 }
1471 p = g_stacknxt;
1472 g_stacknxt += aligned;
1473 g_stacknleft -= aligned;
1474 return p;
1475}
1476
1477static void *
1478stzalloc(size_t nbytes)
1479{
1480 return memset(stalloc(nbytes), 0, nbytes);
1481}
1482
1483static void
1484stunalloc(void *p)
1485{
1486#if DEBUG
1487 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
1488 write(STDERR_FILENO, "stunalloc\n", 10);
1489 abort();
1490 }
1491#endif
1492 g_stacknleft += g_stacknxt - (char *)p;
1493 g_stacknxt = p;
1494}
1495
1496/*
1497 * Like strdup but works with the ash stack.
1498 */
1499static char *
1500sstrdup(const char *p)
1501{
1502 size_t len = strlen(p) + 1;
1503 return memcpy(stalloc(len), p, len);
1504}
1505
1506static inline void
1507grabstackblock(size_t len)
1508{
1509 stalloc(len);
1510}
1511
1512static void
1513pushstackmark(struct stackmark *mark, size_t len)
1514{
1515 mark->stackp = g_stackp;
1516 mark->stacknxt = g_stacknxt;
1517 mark->stacknleft = g_stacknleft;
1518 grabstackblock(len);
1519}
1520
1521static void
1522setstackmark(struct stackmark *mark)
1523{
1524 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
1525}
1526
1527static void
1528popstackmark(struct stackmark *mark)
1529{
1530 struct stack_block *sp;
1531
1532 if (!mark->stackp)
1533 return;
1534
1535 INT_OFF;
1536 while (g_stackp != mark->stackp) {
1537 sp = g_stackp;
1538 g_stackp = sp->prev;
1539 free(sp);
1540 }
1541 g_stacknxt = mark->stacknxt;
1542 g_stacknleft = mark->stacknleft;
1543 sstrend = mark->stacknxt + mark->stacknleft;
1544 INT_ON;
1545}
1546
1547/*
1548 * When the parser reads in a string, it wants to stick the string on the
1549 * stack and only adjust the stack pointer when it knows how big the
1550 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1551 * of space on top of the stack and stackblocklen returns the length of
1552 * this block. Growstackblock will grow this space by at least one byte,
1553 * possibly moving it (like realloc). Grabstackblock actually allocates the
1554 * part of the block that has been used.
1555 */
1556static void
1557growstackblock(void)
1558{
1559 size_t newlen;
1560
1561 newlen = g_stacknleft * 2;
1562 if (newlen < g_stacknleft)
1563 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1564 if (newlen < 128)
1565 newlen += 128;
1566
1567 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
1568 struct stack_block *sp;
1569 struct stack_block *prevstackp;
1570 size_t grosslen;
1571
1572 INT_OFF;
1573 sp = g_stackp;
1574 prevstackp = sp->prev;
1575 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1576 sp = ckrealloc(sp, grosslen);
1577 sp->prev = prevstackp;
1578 g_stackp = sp;
1579 g_stacknxt = sp->space;
1580 g_stacknleft = newlen;
1581 sstrend = sp->space + newlen;
1582 INT_ON;
1583 } else {
1584 char *oldspace = g_stacknxt;
1585 size_t oldlen = g_stacknleft;
1586 char *p = stalloc(newlen);
1587
1588 /* free the space we just allocated */
1589 g_stacknxt = memcpy(p, oldspace, oldlen);
1590 g_stacknleft += newlen;
1591 }
1592}
1593
1594/*
1595 * The following routines are somewhat easier to use than the above.
1596 * The user declares a variable of type STACKSTR, which may be declared
1597 * to be a register. The macro STARTSTACKSTR initializes things. Then
1598 * the user uses the macro STPUTC to add characters to the string. In
1599 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1600 * grown as necessary. When the user is done, she can just leave the
1601 * string there and refer to it using stackblock(). Or she can allocate
1602 * the space for it using grabstackstr(). If it is necessary to allow
1603 * someone else to use the stack temporarily and then continue to grow
1604 * the string, the user should use grabstack to allocate the space, and
1605 * then call ungrabstr(p) to return to the previous mode of operation.
1606 *
1607 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1608 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1609 * is space for at least one character.
1610 */
1611static void *
1612growstackstr(void)
1613{
1614 size_t len = stackblocksize();
1615 growstackblock();
1616 return (char *)stackblock() + len;
1617}
1618
1619/*
1620 * Called from CHECKSTRSPACE.
1621 */
1622static char *
1623makestrspace(size_t newlen, char *p)
1624{
1625 size_t len = p - g_stacknxt;
1626 size_t size;
1627
1628 for (;;) {
1629 size_t nleft;
1630
1631 size = stackblocksize();
1632 nleft = size - len;
1633 if (nleft >= newlen)
1634 break;
1635 growstackblock();
1636 }
1637 return (char *)stackblock() + len;
1638}
1639
1640static char *
1641stack_nputstr(const char *s, size_t n, char *p)
1642{
1643 p = makestrspace(n, p);
1644 p = (char *)memcpy(p, s, n) + n;
1645 return p;
1646}
1647
1648static char *
1649stack_putstr(const char *s, char *p)
1650{
1651 return stack_nputstr(s, strlen(s), p);
1652}
1653
1654static char *
1655_STPUTC(int c, char *p)
1656{
1657 if (p == sstrend)
1658 p = growstackstr();
1659 *p++ = c;
1660 return p;
1661}
1662
1663#define STARTSTACKSTR(p) ((p) = stackblock())
1664#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1665#define CHECKSTRSPACE(n, p) do { \
1666 char *q = (p); \
1667 size_t l = (n); \
1668 size_t m = sstrend - q; \
1669 if (l > m) \
1670 (p) = makestrspace(l, q); \
1671} while (0)
1672#define USTPUTC(c, p) (*(p)++ = (c))
1673#define STACKSTRNUL(p) do { \
1674 if ((p) == sstrend) \
1675 (p) = growstackstr(); \
1676 *(p) = '\0'; \
1677} while (0)
1678#define STUNPUTC(p) (--(p))
1679#define STTOPC(p) ((p)[-1])
1680#define STADJUST(amount, p) ((p) += (amount))
1681
1682#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1683#define ungrabstackstr(s, p) stunalloc(s)
1684#define stackstrend() ((void *)sstrend)
1685
1686
1687/* ============ String helpers */
1688
1689/*
1690 * prefix -- see if pfx is a prefix of string.
1691 */
1692static char *
1693prefix(const char *string, const char *pfx)
1694{
1695 while (*pfx) {
1696 if (*pfx++ != *string++)
1697 return NULL;
1698 }
1699 return (char *) string;
1700}
1701
1702/*
1703 * Check for a valid number. This should be elsewhere.
1704 */
1705static int
1706is_number(const char *p)
1707{
1708 do {
1709 if (!isdigit(*p))
1710 return 0;
1711 } while (*++p != '\0');
1712 return 1;
1713}
1714
1715/*
1716 * Convert a string of digits to an integer, printing an error message on
1717 * failure.
1718 */
1719static int
1720number(const char *s)
1721{
1722 if (!is_number(s))
1723 ash_msg_and_raise_error(msg_illnum, s);
1724 return atoi(s);
1725}
1726
1727/*
1728 * Produce a possibly single quoted string suitable as input to the shell.
1729 * The return string is allocated on the stack.
1730 */
1731static char *
1732single_quote(const char *s)
1733{
1734 char *p;
1735
1736 STARTSTACKSTR(p);
1737
1738 do {
1739 char *q;
1740 size_t len;
1741
1742 len = strchrnul(s, '\'') - s;
1743
1744 q = p = makestrspace(len + 3, p);
1745
1746 *q++ = '\'';
1747 q = (char *)memcpy(q, s, len) + len;
1748 *q++ = '\'';
1749 s += len;
1750
1751 STADJUST(q - p, p);
1752
1753 if (*s != '\'')
1754 break;
1755 len = 0;
1756 do len++; while (*++s == '\'');
1757
1758 q = p = makestrspace(len + 3, p);
1759
1760 *q++ = '"';
1761 q = (char *)memcpy(q, s - len, len) + len;
1762 *q++ = '"';
1763
1764 STADJUST(q - p, p);
1765 } while (*s);
1766
1767 USTPUTC('\0', p);
1768
1769 return stackblock();
1770}
1771
1772
1773/* ============ nextopt */
1774
1775static char **argptr; /* argument list for builtin commands */
1776static char *optionarg; /* set by nextopt (like getopt) */
1777static char *optptr; /* used by nextopt */
1778
1779/*
1780 * XXX - should get rid of. Have all builtins use getopt(3).
1781 * The library getopt must have the BSD extension static variable
1782 * "optreset", otherwise it can't be used within the shell safely.
1783 *
1784 * Standard option processing (a la getopt) for builtin routines.
1785 * The only argument that is passed to nextopt is the option string;
1786 * the other arguments are unnecessary. It returns the character,
1787 * or '\0' on end of input.
1788 */
1789static int
1790nextopt(const char *optstring)
1791{
1792 char *p;
1793 const char *q;
1794 char c;
1795
1796 p = optptr;
1797 if (p == NULL || *p == '\0') {
1798 /* We ate entire "-param", take next one */
1799 p = *argptr;
1800 if (p == NULL)
1801 return '\0';
1802 if (*p != '-')
1803 return '\0';
1804 if (*++p == '\0') /* just "-" ? */
1805 return '\0';
1806 argptr++;
1807 if (LONE_DASH(p)) /* "--" ? */
1808 return '\0';
1809 /* p => next "-param" */
1810 }
1811 /* p => some option char in the middle of a "-param" */
1812 c = *p++;
1813 for (q = optstring; *q != c;) {
1814 if (*q == '\0')
1815 ash_msg_and_raise_error("illegal option -%c", c);
1816 if (*++q == ':')
1817 q++;
1818 }
1819 if (*++q == ':') {
1820 if (*p == '\0') {
1821 p = *argptr++;
1822 if (p == NULL)
1823 ash_msg_and_raise_error("no arg for -%c option", c);
1824 }
1825 optionarg = p;
1826 p = NULL;
1827 }
1828 optptr = p;
1829 return c;
1830}
1831
1832
1833/* ============ Shell variables */
1834
1835/*
1836 * The parsefile structure pointed to by the global variable parsefile
1837 * contains information about the current file being read.
1838 */
1839struct shparam {
1840 int nparam; /* # of positional parameters (without $0) */
1841#if ENABLE_ASH_GETOPTS
1842 int optind; /* next parameter to be processed by getopts */
1843 int optoff; /* used by getopts */
1844#endif
1845 unsigned char malloced; /* if parameter list dynamically allocated */
1846 char **p; /* parameter list */
1847};
1848
1849/*
1850 * Free the list of positional parameters.
1851 */
1852static void
1853freeparam(volatile struct shparam *param)
1854{
1855 if (param->malloced) {
1856 char **ap, **ap1;
1857 ap = ap1 = param->p;
1858 while (*ap)
1859 free(*ap++);
1860 free(ap1);
1861 }
1862}
1863
1864#if ENABLE_ASH_GETOPTS
1865static void FAST_FUNC getoptsreset(const char *value);
1866#endif
1867
1868struct var {
1869 struct var *next; /* next entry in hash list */
1870 int flags; /* flags are defined above */
1871 const char *var_text; /* name=value */
1872 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
1873 /* the variable gets set/unset */
1874};
1875
1876struct localvar {
1877 struct localvar *next; /* next local variable in list */
1878 struct var *vp; /* the variable that was made local */
1879 int flags; /* saved flags */
1880 const char *text; /* saved text */
1881};
1882
1883/* flags */
1884#define VEXPORT 0x01 /* variable is exported */
1885#define VREADONLY 0x02 /* variable cannot be modified */
1886#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1887#define VTEXTFIXED 0x08 /* text is statically allocated */
1888#define VSTACK 0x10 /* text is allocated on the stack */
1889#define VUNSET 0x20 /* the variable is not set */
1890#define VNOFUNC 0x40 /* don't call the callback function */
1891#define VNOSET 0x80 /* do not set variable - just readonly test */
1892#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1893#if ENABLE_ASH_RANDOM_SUPPORT
1894# define VDYNAMIC 0x200 /* dynamic variable */
1895#else
1896# define VDYNAMIC 0
1897#endif
1898
1899
1900/* Need to be before varinit_data[] */
1901#if ENABLE_LOCALE_SUPPORT
1902static void FAST_FUNC
1903change_lc_all(const char *value)
1904{
1905 if (value && *value != '\0')
1906 setlocale(LC_ALL, value);
1907}
1908static void FAST_FUNC
1909change_lc_ctype(const char *value)
1910{
1911 if (value && *value != '\0')
1912 setlocale(LC_CTYPE, value);
1913}
1914#endif
1915#if ENABLE_ASH_MAIL
1916static void chkmail(void);
1917static void changemail(const char *var_value) FAST_FUNC;
1918#else
1919# define chkmail() ((void)0)
1920#endif
1921static void changepath(const char *) FAST_FUNC;
1922#if ENABLE_ASH_RANDOM_SUPPORT
1923static void change_random(const char *) FAST_FUNC;
1924#endif
1925
1926static const struct {
1927 int flags;
1928 const char *var_text;
1929 void (*var_func)(const char *) FAST_FUNC;
1930} varinit_data[] = {
1931 /*
1932 * Note: VEXPORT would not work correctly here for NOFORK applets:
1933 * some environment strings may be constant.
1934 */
1935 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
1936#if ENABLE_ASH_MAIL
1937 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1938 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
1939#endif
1940 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1941 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1942 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1943 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
1944#if ENABLE_ASH_GETOPTS
1945 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
1946#endif
1947#if ENABLE_ASH_RANDOM_SUPPORT
1948 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
1949#endif
1950#if ENABLE_LOCALE_SUPPORT
1951 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1952 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
1953#endif
1954#if ENABLE_FEATURE_EDITING_SAVEHISTORY
1955 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
1956#endif
1957};
1958
1959struct redirtab;
1960
1961struct globals_var {
1962 struct shparam shellparam; /* $@ current positional parameters */
1963 struct redirtab *redirlist;
1964 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1965 struct var *vartab[VTABSIZE];
1966 struct var varinit[ARRAY_SIZE(varinit_data)];
1967};
1968extern struct globals_var *const ash_ptr_to_globals_var;
1969#define G_var (*ash_ptr_to_globals_var)
1970#define shellparam (G_var.shellparam )
1971//#define redirlist (G_var.redirlist )
1972#define preverrout_fd (G_var.preverrout_fd)
1973#define vartab (G_var.vartab )
1974#define varinit (G_var.varinit )
1975#define INIT_G_var() do { \
1976 unsigned i; \
1977 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1978 barrier(); \
1979 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1980 varinit[i].flags = varinit_data[i].flags; \
1981 varinit[i].var_text = varinit_data[i].var_text; \
1982 varinit[i].var_func = varinit_data[i].var_func; \
1983 } \
1984} while (0)
1985
1986#define vifs varinit[0]
1987#if ENABLE_ASH_MAIL
1988# define vmail (&vifs)[1]
1989# define vmpath (&vmail)[1]
1990# define vpath (&vmpath)[1]
1991#else
1992# define vpath (&vifs)[1]
1993#endif
1994#define vps1 (&vpath)[1]
1995#define vps2 (&vps1)[1]
1996#define vps4 (&vps2)[1]
1997#if ENABLE_ASH_GETOPTS
1998# define voptind (&vps4)[1]
1999# if ENABLE_ASH_RANDOM_SUPPORT
2000# define vrandom (&voptind)[1]
2001# endif
2002#else
2003# if ENABLE_ASH_RANDOM_SUPPORT
2004# define vrandom (&vps4)[1]
2005# endif
2006#endif
2007
2008/*
2009 * The following macros access the values of the above variables.
2010 * They have to skip over the name. They return the null string
2011 * for unset variables.
2012 */
2013#define ifsval() (vifs.var_text + 4)
2014#define ifsset() ((vifs.flags & VUNSET) == 0)
2015#if ENABLE_ASH_MAIL
2016# define mailval() (vmail.var_text + 5)
2017# define mpathval() (vmpath.var_text + 9)
2018# define mpathset() ((vmpath.flags & VUNSET) == 0)
2019#endif
2020#define pathval() (vpath.var_text + 5)
2021#define ps1val() (vps1.var_text + 4)
2022#define ps2val() (vps2.var_text + 4)
2023#define ps4val() (vps4.var_text + 4)
2024#if ENABLE_ASH_GETOPTS
2025# define optindval() (voptind.var_text + 7)
2026#endif
2027
2028#if ENABLE_ASH_GETOPTS
2029static void FAST_FUNC
2030getoptsreset(const char *value)
2031{
2032 shellparam.optind = number(value) ?: 1;
2033 shellparam.optoff = -1;
2034}
2035#endif
2036
2037/*
2038 * Compares two strings up to the first = or '\0'. The first
2039 * string must be terminated by '='; the second may be terminated by
2040 * either '=' or '\0'.
2041 */
2042static int
2043varcmp(const char *p, const char *q)
2044{
2045 int c, d;
2046
2047 while ((c = *p) == (d = *q)) {
2048 if (c == '\0' || c == '=')
2049 goto out;
2050 p++;
2051 q++;
2052 }
2053 if (c == '=')
2054 c = '\0';
2055 if (d == '=')
2056 d = '\0';
2057 out:
2058 return c - d;
2059}
2060
2061/*
2062 * Find the appropriate entry in the hash table from the name.
2063 */
2064static struct var **
2065hashvar(const char *p)
2066{
2067 unsigned hashval;
2068
2069 hashval = ((unsigned char) *p) << 4;
2070 while (*p && *p != '=')
2071 hashval += (unsigned char) *p++;
2072 return &vartab[hashval % VTABSIZE];
2073}
2074
2075static int
2076vpcmp(const void *a, const void *b)
2077{
2078 return varcmp(*(const char **)a, *(const char **)b);
2079}
2080
2081/*
2082 * This routine initializes the builtin variables.
2083 */
2084static void
2085initvar(void)
2086{
2087 struct var *vp;
2088 struct var *end;
2089 struct var **vpp;
2090
2091 /*
2092 * PS1 depends on uid
2093 */
2094#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
2095 vps1.var_text = "PS1=\\w \\$ ";
2096#else
2097 if (!geteuid())
2098 vps1.var_text = "PS1=# ";
2099#endif
2100 vp = varinit;
2101 end = vp + ARRAY_SIZE(varinit);
2102 do {
2103 vpp = hashvar(vp->var_text);
2104 vp->next = *vpp;
2105 *vpp = vp;
2106 } while (++vp < end);
2107}
2108
2109static struct var **
2110findvar(struct var **vpp, const char *name)
2111{
2112 for (; *vpp; vpp = &(*vpp)->next) {
2113 if (varcmp((*vpp)->var_text, name) == 0) {
2114 break;
2115 }
2116 }
2117 return vpp;
2118}
2119
2120/*
2121 * Find the value of a variable. Returns NULL if not set.
2122 */
2123static const char* FAST_FUNC
2124lookupvar(const char *name)
2125{
2126 struct var *v;
2127
2128 v = *findvar(hashvar(name), name);
2129 if (v) {
2130#if ENABLE_ASH_RANDOM_SUPPORT
2131 /*
2132 * Dynamic variables are implemented roughly the same way they are
2133 * in bash. Namely, they're "special" so long as they aren't unset.
2134 * As soon as they're unset, they're no longer dynamic, and dynamic
2135 * lookup will no longer happen at that point. -- PFM.
2136 */
2137 if (v->flags & VDYNAMIC)
2138 v->var_func(NULL);
2139#endif
2140 if (!(v->flags & VUNSET))
2141 return var_end(v->var_text);
2142 }
2143 return NULL;
2144}
2145
2146static void
2147reinit_unicode_for_ash(void)
2148{
2149 /* Unicode support should be activated even if LANG is set
2150 * _during_ shell execution, not only if it was set when
2151 * shell was started. Therefore, re-check LANG every time:
2152 */
2153 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2154 || ENABLE_UNICODE_USING_LOCALE
2155 ) {
2156 const char *s = lookupvar("LC_ALL");
2157 if (!s) s = lookupvar("LC_CTYPE");
2158 if (!s) s = lookupvar("LANG");
2159 reinit_unicode(s);
2160 }
2161}
2162
2163/*
2164 * Search the environment of a builtin command.
2165 */
2166static const char *
2167bltinlookup(const char *name)
2168{
2169 struct strlist *sp;
2170
2171 for (sp = cmdenviron; sp; sp = sp->next) {
2172 if (varcmp(sp->text, name) == 0)
2173 return var_end(sp->text);
2174 }
2175 return lookupvar(name);
2176}
2177
2178/*
2179 * Same as setvar except that the variable and value are passed in
2180 * the first argument as name=value. Since the first argument will
2181 * be actually stored in the table, it should not be a string that
2182 * will go away.
2183 * Called with interrupts off.
2184 */
2185static void
2186setvareq(char *s, int flags)
2187{
2188 struct var *vp, **vpp;
2189
2190 vpp = hashvar(s);
2191 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2192 vp = *findvar(vpp, s);
2193 if (vp) {
2194 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2195 const char *n;
2196
2197 if (flags & VNOSAVE)
2198 free(s);
2199 n = vp->var_text;
2200 exitstatus = 1;
2201 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2202 }
2203
2204 if (flags & VNOSET)
2205 return;
2206
2207 if (vp->var_func && !(flags & VNOFUNC))
2208 vp->var_func(var_end(s));
2209
2210 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2211 free((char*)vp->var_text);
2212
2213 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2214 } else {
2215 /* variable s is not found */
2216 if (flags & VNOSET)
2217 return;
2218 vp = ckzalloc(sizeof(*vp));
2219 vp->next = *vpp;
2220 /*vp->func = NULL; - ckzalloc did it */
2221 *vpp = vp;
2222 }
2223 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2224 s = ckstrdup(s);
2225 vp->var_text = s;
2226 vp->flags = flags;
2227}
2228
2229/*
2230 * Set the value of a variable. The flags argument is ored with the
2231 * flags of the variable. If val is NULL, the variable is unset.
2232 */
2233static void
2234setvar(const char *name, const char *val, int flags)
2235{
2236 const char *q;
2237 char *p;
2238 char *nameeq;
2239 size_t namelen;
2240 size_t vallen;
2241
2242 q = endofname(name);
2243 p = strchrnul(q, '=');
2244 namelen = p - name;
2245 if (!namelen || p != q)
2246 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2247 vallen = 0;
2248 if (val == NULL) {
2249 flags |= VUNSET;
2250 } else {
2251 vallen = strlen(val);
2252 }
2253
2254 INT_OFF;
2255 nameeq = ckmalloc(namelen + vallen + 2);
2256 p = memcpy(nameeq, name, namelen) + namelen;
2257 if (val) {
2258 *p++ = '=';
2259 p = memcpy(p, val, vallen) + vallen;
2260 }
2261 *p = '\0';
2262 setvareq(nameeq, flags | VNOSAVE);
2263 INT_ON;
2264}
2265
2266static void FAST_FUNC
2267setvar0(const char *name, const char *val)
2268{
2269 setvar(name, val, 0);
2270}
2271
2272/*
2273 * Unset the specified variable.
2274 */
2275static int
2276unsetvar(const char *s)
2277{
2278 struct var **vpp;
2279 struct var *vp;
2280 int retval;
2281
2282 vpp = findvar(hashvar(s), s);
2283 vp = *vpp;
2284 retval = 2;
2285 if (vp) {
2286 int flags = vp->flags;
2287
2288 retval = 1;
2289 if (flags & VREADONLY)
2290 goto out;
2291#if ENABLE_ASH_RANDOM_SUPPORT
2292 vp->flags &= ~VDYNAMIC;
2293#endif
2294 if (flags & VUNSET)
2295 goto ok;
2296 if ((flags & VSTRFIXED) == 0) {
2297 INT_OFF;
2298 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
2299 free((char*)vp->var_text);
2300 *vpp = vp->next;
2301 free(vp);
2302 INT_ON;
2303 } else {
2304 setvar0(s, NULL);
2305 vp->flags &= ~VEXPORT;
2306 }
2307 ok:
2308 retval = 0;
2309 }
2310 out:
2311 return retval;
2312}
2313
2314/*
2315 * Process a linked list of variable assignments.
2316 */
2317static void
2318listsetvar(struct strlist *list_set_var, int flags)
2319{
2320 struct strlist *lp = list_set_var;
2321
2322 if (!lp)
2323 return;
2324 INT_OFF;
2325 do {
2326 setvareq(lp->text, flags);
2327 lp = lp->next;
2328 } while (lp);
2329 INT_ON;
2330}
2331
2332/*
2333 * Generate a list of variables satisfying the given conditions.
2334 */
2335static char **
2336listvars(int on, int off, char ***end)
2337{
2338 struct var **vpp;
2339 struct var *vp;
2340 char **ep;
2341 int mask;
2342
2343 STARTSTACKSTR(ep);
2344 vpp = vartab;
2345 mask = on | off;
2346 do {
2347 for (vp = *vpp; vp; vp = vp->next) {
2348 if ((vp->flags & mask) == on) {
2349 if (ep == stackstrend())
2350 ep = growstackstr();
2351 *ep++ = (char*)vp->var_text;
2352 }
2353 }
2354 } while (++vpp < vartab + VTABSIZE);
2355 if (ep == stackstrend())
2356 ep = growstackstr();
2357 if (end)
2358 *end = ep;
2359 *ep++ = NULL;
2360 return grabstackstr(ep);
2361}
2362
2363
2364/* ============ Path search helper
2365 *
2366 * The variable path (passed by reference) should be set to the start
2367 * of the path before the first call; path_advance will update
2368 * this value as it proceeds. Successive calls to path_advance will return
2369 * the possible path expansions in sequence. If an option (indicated by
2370 * a percent sign) appears in the path entry then the global variable
2371 * pathopt will be set to point to it; otherwise pathopt will be set to
2372 * NULL.
2373 */
2374static const char *pathopt; /* set by path_advance */
2375
2376static char *
2377path_advance(const char **path, const char *name)
2378{
2379 const char *p;
2380 char *q;
2381 const char *start;
2382 size_t len;
2383
2384 if (*path == NULL)
2385 return NULL;
2386 start = *path;
2387 for (p = start; *p && *p != ':' && *p != '%'; p++)
2388 continue;
2389 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2390 while (stackblocksize() < len)
2391 growstackblock();
2392 q = stackblock();
2393 if (p != start) {
2394 memcpy(q, start, p - start);
2395 q += p - start;
2396 *q++ = '/';
2397 }
2398 strcpy(q, name);
2399 pathopt = NULL;
2400 if (*p == '%') {
2401 pathopt = ++p;
2402 while (*p && *p != ':')
2403 p++;
2404 }
2405 if (*p == ':')
2406 *path = p + 1;
2407 else
2408 *path = NULL;
2409 return stalloc(len);
2410}
2411
2412
2413/* ============ Prompt */
2414
2415static smallint doprompt; /* if set, prompt the user */
2416static smallint needprompt; /* true if interactive and at start of line */
2417
2418#if ENABLE_FEATURE_EDITING
2419static line_input_t *line_input_state;
2420static const char *cmdedit_prompt;
2421static void
2422putprompt(const char *s)
2423{
2424 if (ENABLE_ASH_EXPAND_PRMT) {
2425 free((char*)cmdedit_prompt);
2426 cmdedit_prompt = ckstrdup(s);
2427 return;
2428 }
2429 cmdedit_prompt = s;
2430}
2431#else
2432static void
2433putprompt(const char *s)
2434{
2435 out2str(s);
2436}
2437#endif
2438
2439#if ENABLE_ASH_EXPAND_PRMT
2440/* expandstr() needs parsing machinery, so it is far away ahead... */
2441static const char *expandstr(const char *ps);
2442#else
2443#define expandstr(s) s
2444#endif
2445
2446static void
2447setprompt_if(smallint do_set, int whichprompt)
2448{
2449 const char *prompt;
2450 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2451
2452 if (!do_set)
2453 return;
2454
2455 needprompt = 0;
2456
2457 switch (whichprompt) {
2458 case 1:
2459 prompt = ps1val();
2460 break;
2461 case 2:
2462 prompt = ps2val();
2463 break;
2464 default: /* 0 */
2465 prompt = nullstr;
2466 }
2467#if ENABLE_ASH_EXPAND_PRMT
2468 pushstackmark(&smark, stackblocksize());
2469#endif
2470 putprompt(expandstr(prompt));
2471#if ENABLE_ASH_EXPAND_PRMT
2472 popstackmark(&smark);
2473#endif
2474}
2475
2476
2477/* ============ The cd and pwd commands */
2478
2479#define CD_PHYSICAL 1
2480#define CD_PRINT 2
2481
2482static int
2483cdopt(void)
2484{
2485 int flags = 0;
2486 int i, j;
2487
2488 j = 'L';
2489 while ((i = nextopt("LP")) != '\0') {
2490 if (i != j) {
2491 flags ^= CD_PHYSICAL;
2492 j = i;
2493 }
2494 }
2495
2496 return flags;
2497}
2498
2499/*
2500 * Update curdir (the name of the current directory) in response to a
2501 * cd command.
2502 */
2503static const char *
2504updatepwd(const char *dir)
2505{
2506 char *new;
2507 char *p;
2508 char *cdcomppath;
2509 const char *lim;
2510
2511 cdcomppath = sstrdup(dir);
2512 STARTSTACKSTR(new);
2513 if (*dir != '/') {
2514 if (curdir == nullstr)
2515 return 0;
2516 new = stack_putstr(curdir, new);
2517 }
2518 new = makestrspace(strlen(dir) + 2, new);
2519 lim = (char *)stackblock() + 1;
2520 if (*dir != '/') {
2521 if (new[-1] != '/')
2522 USTPUTC('/', new);
2523 if (new > lim && *lim == '/')
2524 lim++;
2525 } else {
2526 USTPUTC('/', new);
2527 cdcomppath++;
2528 if (dir[1] == '/' && dir[2] != '/') {
2529 USTPUTC('/', new);
2530 cdcomppath++;
2531 lim++;
2532 }
2533 }
2534 p = strtok(cdcomppath, "/");
2535 while (p) {
2536 switch (*p) {
2537 case '.':
2538 if (p[1] == '.' && p[2] == '\0') {
2539 while (new > lim) {
2540 STUNPUTC(new);
2541 if (new[-1] == '/')
2542 break;
2543 }
2544 break;
2545 }
2546 if (p[1] == '\0')
2547 break;
2548 /* fall through */
2549 default:
2550 new = stack_putstr(p, new);
2551 USTPUTC('/', new);
2552 }
2553 p = strtok(NULL, "/");
2554 }
2555 if (new > lim)
2556 STUNPUTC(new);
2557 *new = 0;
2558 return stackblock();
2559}
2560
2561/*
2562 * Find out what the current directory is. If we already know the current
2563 * directory, this routine returns immediately.
2564 */
2565static char *
2566getpwd(void)
2567{
2568 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
2569 return dir ? dir : nullstr;
2570}
2571
2572static void
2573setpwd(const char *val, int setold)
2574{
2575 char *oldcur, *dir;
2576
2577 oldcur = dir = curdir;
2578
2579 if (setold) {
2580 setvar("OLDPWD", oldcur, VEXPORT);
2581 }
2582 INT_OFF;
2583 if (physdir != nullstr) {
2584 if (physdir != oldcur)
2585 free(physdir);
2586 physdir = nullstr;
2587 }
2588 if (oldcur == val || !val) {
2589 char *s = getpwd();
2590 physdir = s;
2591 if (!val)
2592 dir = s;
2593 } else
2594 dir = ckstrdup(val);
2595 if (oldcur != dir && oldcur != nullstr) {
2596 free(oldcur);
2597 }
2598 curdir = dir;
2599 INT_ON;
2600 setvar("PWD", dir, VEXPORT);
2601}
2602
2603static void hashcd(void);
2604
2605/*
2606 * Actually do the chdir. We also call hashcd to let other routines
2607 * know that the current directory has changed.
2608 */
2609static int
2610docd(const char *dest, int flags)
2611{
2612 const char *dir = NULL;
2613 int err;
2614
2615 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2616
2617 INT_OFF;
2618 if (!(flags & CD_PHYSICAL)) {
2619 dir = updatepwd(dest);
2620 if (dir)
2621 dest = dir;
2622 }
2623 err = chdir(dest);
2624 if (err)
2625 goto out;
2626 setpwd(dir, 1);
2627 hashcd();
2628 out:
2629 INT_ON;
2630 return err;
2631}
2632
2633static int FAST_FUNC
2634cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2635{
2636 const char *dest;
2637 const char *path;
2638 const char *p;
2639 char c;
2640 struct stat statb;
2641 int flags;
2642
2643 flags = cdopt();
2644 dest = *argptr;
2645 if (!dest)
2646 dest = bltinlookup("HOME");
2647 else if (LONE_DASH(dest)) {
2648 dest = bltinlookup("OLDPWD");
2649 flags |= CD_PRINT;
2650 }
2651 if (!dest)
2652 dest = nullstr;
2653 if (*dest == '/')
2654 goto step6;
2655 if (*dest == '.') {
2656 c = dest[1];
2657 dotdot:
2658 switch (c) {
2659 case '\0':
2660 case '/':
2661 goto step6;
2662 case '.':
2663 c = dest[2];
2664 if (c != '.')
2665 goto dotdot;
2666 }
2667 }
2668 if (!*dest)
2669 dest = ".";
2670 path = bltinlookup("CDPATH");
2671 while (path) {
2672 c = *path;
2673 p = path_advance(&path, dest);
2674 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2675 if (c && c != ':')
2676 flags |= CD_PRINT;
2677 docd:
2678 if (!docd(p, flags))
2679 goto out;
2680 goto err;
2681 }
2682 }
2683
2684 step6:
2685 p = dest;
2686 goto docd;
2687
2688 err:
2689 ash_msg_and_raise_error("can't cd to %s", dest);
2690 /* NOTREACHED */
2691 out:
2692 if (flags & CD_PRINT)
2693 out1fmt("%s\n", curdir);
2694 return 0;
2695}
2696
2697static int FAST_FUNC
2698pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2699{
2700 int flags;
2701 const char *dir = curdir;
2702
2703 flags = cdopt();
2704 if (flags) {
2705 if (physdir == nullstr)
2706 setpwd(dir, 0);
2707 dir = physdir;
2708 }
2709 out1fmt("%s\n", dir);
2710 return 0;
2711}
2712
2713
2714/* ============ ... */
2715
2716
2717#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
2718
2719/* Syntax classes */
2720#define CWORD 0 /* character is nothing special */
2721#define CNL 1 /* newline character */
2722#define CBACK 2 /* a backslash character */
2723#define CSQUOTE 3 /* single quote */
2724#define CDQUOTE 4 /* double quote */
2725#define CENDQUOTE 5 /* a terminating quote */
2726#define CBQUOTE 6 /* backwards single quote */
2727#define CVAR 7 /* a dollar sign */
2728#define CENDVAR 8 /* a '}' character */
2729#define CLP 9 /* a left paren in arithmetic */
2730#define CRP 10 /* a right paren in arithmetic */
2731#define CENDFILE 11 /* end of file */
2732#define CCTL 12 /* like CWORD, except it must be escaped */
2733#define CSPCL 13 /* these terminate a word */
2734#define CIGN 14 /* character should be ignored */
2735
2736#define PEOF 256
2737#if ENABLE_ASH_ALIAS
2738# define PEOA 257
2739#endif
2740
2741#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
2742
2743#if ENABLE_SH_MATH_SUPPORT
2744# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
2745#else
2746# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
2747#endif
2748static const uint16_t S_I_T[] ALIGN2 = {
2749#if ENABLE_ASH_ALIAS
2750 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2751#endif
2752 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2753 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2754 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2755 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2756 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2757 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2758 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2759 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2760 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2761 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2762 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
2763#if !USE_SIT_FUNCTION
2764 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2765 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2766 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2767#endif
2768#undef SIT_ITEM
2769};
2770/* Constants below must match table above */
2771enum {
2772#if ENABLE_ASH_ALIAS
2773 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2774#endif
2775 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2776 CNL_CNL_CNL_CNL , /* 2 */
2777 CWORD_CCTL_CCTL_CWORD , /* 3 */
2778 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2779 CVAR_CVAR_CWORD_CVAR , /* 5 */
2780 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2781 CSPCL_CWORD_CWORD_CLP , /* 7 */
2782 CSPCL_CWORD_CWORD_CRP , /* 8 */
2783 CBACK_CBACK_CCTL_CBACK , /* 9 */
2784 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2785 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2786 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2787 CWORD_CWORD_CWORD_CWORD , /* 13 */
2788 CCTL_CCTL_CCTL_CCTL , /* 14 */
2789};
2790
2791/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2792 * caller must ensure proper cast on it if c is *char_ptr!
2793 */
2794/* Values for syntax param */
2795#define BASESYNTAX 0 /* not in quotes */
2796#define DQSYNTAX 1 /* in double quotes */
2797#define SQSYNTAX 2 /* in single quotes */
2798#define ARISYNTAX 3 /* in arithmetic */
2799#define PSSYNTAX 4 /* prompt. never passed to SIT() */
2800
2801#if USE_SIT_FUNCTION
2802
2803static int
2804SIT(int c, int syntax)
2805{
2806 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2807 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2808 /*
2809 * This causes '/' to be prepended with CTLESC in dquoted string,
2810 * making "./file"* treated incorrectly because we feed
2811 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2812 * The "homegrown" glob implementation is okay with that,
2813 * but glibc one isn't. With '/' always treated as CWORD,
2814 * both work fine.
2815 */
2816# if ENABLE_ASH_ALIAS
2817 static const uint8_t syntax_index_table[] ALIGN1 = {
2818 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2819 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
2820 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2821 11, 3 /* "}~" */
2822 };
2823# else
2824 static const uint8_t syntax_index_table[] ALIGN1 = {
2825 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2826 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
2827 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2828 10, 2 /* "}~" */
2829 };
2830# endif
2831 const char *s;
2832 int indx;
2833
2834 if (c == PEOF)
2835 return CENDFILE;
2836# if ENABLE_ASH_ALIAS
2837 if (c == PEOA)
2838 indx = 0;
2839 else
2840# endif
2841 {
2842 /* Cast is purely for paranoia here,
2843 * just in case someone passed signed char to us */
2844 if ((unsigned char)c >= CTL_FIRST
2845 && (unsigned char)c <= CTL_LAST
2846 ) {
2847 return CCTL;
2848 }
2849 s = strchrnul(spec_symbls, c);
2850 if (*s == '\0')
2851 return CWORD;
2852 indx = syntax_index_table[s - spec_symbls];
2853 }
2854 return (S_I_T[indx] >> (syntax*4)) & 0xf;
2855}
2856
2857#else /* !USE_SIT_FUNCTION */
2858
2859static const uint8_t syntax_index_table[] ALIGN1 = {
2860 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2861 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2871 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2872 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2894 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2895 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2896 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2897 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2898 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2899 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2900 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2901 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2902 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2903 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2904 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2905 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2906 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2907 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
2908/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2909 /* 47 "/" */ CWORD_CWORD_CWORD_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
3122};
3123
3124#if 1
3125# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
3126#else /* debug version, caught one signed char bug */
3127# define SIT(c, syntax) \
3128 ({ \
3129 if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
3130 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3131 if ((syntax) < 0 || (syntax) > (2 + ENABLE_SH_MATH_SUPPORT)) \
3132 bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
3133 ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
3134 })
3135#endif
3136
3137#endif /* !USE_SIT_FUNCTION */
3138
3139
3140/* ============ Alias handling */
3141
3142#if ENABLE_ASH_ALIAS
3143
3144#define ALIASINUSE 1
3145#define ALIASDEAD 2
3146
3147struct alias {
3148 struct alias *next;
3149 char *name;
3150 char *val;
3151 int flag;
3152};
3153
3154
3155static struct alias **atab; // [ATABSIZE];
3156#define INIT_G_alias() do { \
3157 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3158} while (0)
3159
3160
3161static struct alias **
3162__lookupalias(const char *name)
3163{
3164 unsigned int hashval;
3165 struct alias **app;
3166 const char *p;
3167 unsigned int ch;
3168
3169 p = name;
3170
3171 ch = (unsigned char)*p;
3172 hashval = ch << 4;
3173 while (ch) {
3174 hashval += ch;
3175 ch = (unsigned char)*++p;
3176 }
3177 app = &atab[hashval % ATABSIZE];
3178
3179 for (; *app; app = &(*app)->next) {
3180 if (strcmp(name, (*app)->name) == 0) {
3181 break;
3182 }
3183 }
3184
3185 return app;
3186}
3187
3188static struct alias *
3189lookupalias(const char *name, int check)
3190{
3191 struct alias *ap = *__lookupalias(name);
3192
3193 if (check && ap && (ap->flag & ALIASINUSE))
3194 return NULL;
3195 return ap;
3196}
3197
3198static struct alias *
3199freealias(struct alias *ap)
3200{
3201 struct alias *next;
3202
3203 if (ap->flag & ALIASINUSE) {
3204 ap->flag |= ALIASDEAD;
3205 return ap;
3206 }
3207
3208 next = ap->next;
3209 free(ap->name);
3210 free(ap->val);
3211 free(ap);
3212 return next;
3213}
3214
3215static void
3216setalias(const char *name, const char *val)
3217{
3218 struct alias *ap, **app;
3219
3220 app = __lookupalias(name);
3221 ap = *app;
3222 INT_OFF;
3223 if (ap) {
3224 if (!(ap->flag & ALIASINUSE)) {
3225 free(ap->val);
3226 }
3227 ap->val = ckstrdup(val);
3228 ap->flag &= ~ALIASDEAD;
3229 } else {
3230 /* not found */
3231 ap = ckzalloc(sizeof(struct alias));
3232 ap->name = ckstrdup(name);
3233 ap->val = ckstrdup(val);
3234 /*ap->flag = 0; - ckzalloc did it */
3235 /*ap->next = NULL;*/
3236 *app = ap;
3237 }
3238 INT_ON;
3239}
3240
3241static int
3242unalias(const char *name)
3243{
3244 struct alias **app;
3245
3246 app = __lookupalias(name);
3247
3248 if (*app) {
3249 INT_OFF;
3250 *app = freealias(*app);
3251 INT_ON;
3252 return 0;
3253 }
3254
3255 return 1;
3256}
3257
3258static void
3259rmaliases(void)
3260{
3261 struct alias *ap, **app;
3262 int i;
3263
3264 INT_OFF;
3265 for (i = 0; i < ATABSIZE; i++) {
3266 app = &atab[i];
3267 for (ap = *app; ap; ap = *app) {
3268 *app = freealias(*app);
3269 if (ap == *app) {
3270 app = &ap->next;
3271 }
3272 }
3273 }
3274 INT_ON;
3275}
3276
3277static void
3278printalias(const struct alias *ap)
3279{
3280 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3281}
3282
3283/*
3284 * TODO - sort output
3285 */
3286static int FAST_FUNC
3287aliascmd(int argc UNUSED_PARAM, char **argv)
3288{
3289 char *n, *v;
3290 int ret = 0;
3291 struct alias *ap;
3292
3293 if (!argv[1]) {
3294 int i;
3295
3296 for (i = 0; i < ATABSIZE; i++) {
3297 for (ap = atab[i]; ap; ap = ap->next) {
3298 printalias(ap);
3299 }
3300 }
3301 return 0;
3302 }
3303 while ((n = *++argv) != NULL) {
3304 v = strchr(n+1, '=');
3305 if (v == NULL) { /* n+1: funny ksh stuff */
3306 ap = *__lookupalias(n);
3307 if (ap == NULL) {
3308 fprintf(stderr, "%s: %s not found\n", "alias", n);
3309 ret = 1;
3310 } else
3311 printalias(ap);
3312 } else {
3313 *v++ = '\0';
3314 setalias(n, v);
3315 }
3316 }
3317
3318 return ret;
3319}
3320
3321static int FAST_FUNC
3322unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3323{
3324 int i;
3325
3326 while ((i = nextopt("a")) != '\0') {
3327 if (i == 'a') {
3328 rmaliases();
3329 return 0;
3330 }
3331 }
3332 for (i = 0; *argptr; argptr++) {
3333 if (unalias(*argptr)) {
3334 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
3335 i = 1;
3336 }
3337 }
3338
3339 return i;
3340}
3341
3342#endif /* ASH_ALIAS */
3343
3344
3345/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3346#define FORK_FG 0
3347#define FORK_BG 1
3348#define FORK_NOJOB 2
3349
3350/* mode flags for showjob(s) */
3351#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3352#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3353#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
3354#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
3355
3356/*
3357 * A job structure contains information about a job. A job is either a
3358 * single process or a set of processes contained in a pipeline. In the
3359 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3360 * array of pids.
3361 */
3362struct procstat {
3363 pid_t ps_pid; /* process id */
3364 int ps_status; /* last process status from wait() */
3365 char *ps_cmd; /* text of command being run */
3366};
3367
3368struct job {
3369 struct procstat ps0; /* status of process */
3370 struct procstat *ps; /* status or processes when more than one */
3371#if JOBS
3372 int stopstatus; /* status of a stopped job */
3373#endif
3374 uint32_t
3375 nprocs: 16, /* number of processes */
3376 state: 8,
3377#define JOBRUNNING 0 /* at least one proc running */
3378#define JOBSTOPPED 1 /* all procs are stopped */
3379#define JOBDONE 2 /* all procs are completed */
3380#if JOBS
3381 sigint: 1, /* job was killed by SIGINT */
3382 jobctl: 1, /* job running under job control */
3383#endif
3384 waited: 1, /* true if this entry has been waited for */
3385 used: 1, /* true if this entry is in used */
3386 changed: 1; /* true if status has changed */
3387 struct job *prev_job; /* previous job */
3388};
3389
3390static struct job *makejob(/*union node *,*/ int);
3391static int forkshell(struct job *, union node *, int);
3392static int waitforjob(struct job *);
3393
3394#if !JOBS
3395enum { doing_jobctl = 0 };
3396#define setjobctl(on) do {} while (0)
3397#else
3398static smallint doing_jobctl; //references:8
3399static void setjobctl(int);
3400#endif
3401
3402/*
3403 * Ignore a signal.
3404 */
3405static void
3406ignoresig(int signo)
3407{
3408 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3409 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3410 /* No, need to do it */
3411 signal(signo, SIG_IGN);
3412 }
3413 sigmode[signo - 1] = S_HARD_IGN;
3414}
3415
3416/*
3417 * Only one usage site - in setsignal()
3418 */
3419static void
3420signal_handler(int signo)
3421{
3422 if (signo == SIGCHLD) {
3423 got_sigchld = 1;
3424 if (!trap[SIGCHLD])
3425 return;
3426 }
3427
3428 gotsig[signo - 1] = 1;
3429 pending_sig = signo;
3430
3431 if (signo == SIGINT && !trap[SIGINT]) {
3432 if (!suppress_int) {
3433 pending_sig = 0;
3434 raise_interrupt(); /* does not return */
3435 }
3436 pending_int = 1;
3437 }
3438}
3439
3440/*
3441 * Set the signal handler for the specified signal. The routine figures
3442 * out what it should be set to.
3443 */
3444static void
3445setsignal(int signo)
3446{
3447 char *t;
3448 char cur_act, new_act;
3449 struct sigaction act;
3450
3451 t = trap[signo];
3452 new_act = S_DFL;
3453 if (t != NULL) { /* trap for this sig is set */
3454 new_act = S_CATCH;
3455 if (t[0] == '\0') /* trap is "": ignore this sig */
3456 new_act = S_IGN;
3457 }
3458
3459 if (rootshell && new_act == S_DFL) {
3460 switch (signo) {
3461 case SIGINT:
3462 if (iflag || minusc || sflag == 0)
3463 new_act = S_CATCH;
3464 break;
3465 case SIGQUIT:
3466#if DEBUG
3467 if (debug)
3468 break;
3469#endif
3470 /* man bash:
3471 * "In all cases, bash ignores SIGQUIT. Non-builtin
3472 * commands run by bash have signal handlers
3473 * set to the values inherited by the shell
3474 * from its parent". */
3475 new_act = S_IGN;
3476 break;
3477 case SIGTERM:
3478 if (iflag)
3479 new_act = S_IGN;
3480 break;
3481#if JOBS
3482 case SIGTSTP:
3483 case SIGTTOU:
3484 if (mflag)
3485 new_act = S_IGN;
3486 break;
3487#endif
3488 }
3489 }
3490//TODO: if !rootshell, we reset SIGQUIT to DFL,
3491//whereas we have to restore it to what shell got on entry
3492//from the parent. See comment above
3493
3494 if (signo == SIGCHLD)
3495 new_act = S_CATCH;
3496
3497 t = &sigmode[signo - 1];
3498 cur_act = *t;
3499 if (cur_act == 0) {
3500 /* current setting is not yet known */
3501 if (sigaction(signo, NULL, &act)) {
3502 /* pretend it worked; maybe we should give a warning,
3503 * but other shells don't. We don't alter sigmode,
3504 * so we retry every time.
3505 * btw, in Linux it never fails. --vda */
3506 return;
3507 }
3508 if (act.sa_handler == SIG_IGN) {
3509 cur_act = S_HARD_IGN;
3510 if (mflag
3511 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3512 ) {
3513 cur_act = S_IGN; /* don't hard ignore these */
3514 }
3515 }
3516 }
3517 if (cur_act == S_HARD_IGN || cur_act == new_act)
3518 return;
3519
3520 act.sa_handler = SIG_DFL;
3521 switch (new_act) {
3522 case S_CATCH:
3523 act.sa_handler = signal_handler;
3524 break;
3525 case S_IGN:
3526 act.sa_handler = SIG_IGN;
3527 break;
3528 }
3529
3530 /* flags and mask matter only if !DFL and !IGN, but we do it
3531 * for all cases for more deterministic behavior:
3532 */
3533 act.sa_flags = 0;
3534 sigfillset(&act.sa_mask);
3535
3536 sigaction_set(signo, &act);
3537
3538 *t = new_act;
3539}
3540
3541/* mode flags for set_curjob */
3542#define CUR_DELETE 2
3543#define CUR_RUNNING 1
3544#define CUR_STOPPED 0
3545
3546#if JOBS
3547/* pgrp of shell on invocation */
3548static int initialpgrp; //references:2
3549static int ttyfd = -1; //5
3550#endif
3551/* array of jobs */
3552static struct job *jobtab; //5
3553/* size of array */
3554static unsigned njobs; //4
3555/* current job */
3556static struct job *curjob; //lots
3557/* number of presumed living untracked jobs */
3558static int jobless; //4
3559
3560static void
3561set_curjob(struct job *jp, unsigned mode)
3562{
3563 struct job *jp1;
3564 struct job **jpp, **curp;
3565
3566 /* first remove from list */
3567 jpp = curp = &curjob;
3568 while (1) {
3569 jp1 = *jpp;
3570 if (jp1 == jp)
3571 break;
3572 jpp = &jp1->prev_job;
3573 }
3574 *jpp = jp1->prev_job;
3575
3576 /* Then re-insert in correct position */
3577 jpp = curp;
3578 switch (mode) {
3579 default:
3580#if DEBUG
3581 abort();
3582#endif
3583 case CUR_DELETE:
3584 /* job being deleted */
3585 break;
3586 case CUR_RUNNING:
3587 /* newly created job or backgrounded job,
3588 * put after all stopped jobs.
3589 */
3590 while (1) {
3591 jp1 = *jpp;
3592#if JOBS
3593 if (!jp1 || jp1->state != JOBSTOPPED)
3594#endif
3595 break;
3596 jpp = &jp1->prev_job;
3597 }
3598 /* FALLTHROUGH */
3599#if JOBS
3600 case CUR_STOPPED:
3601#endif
3602 /* newly stopped job - becomes curjob */
3603 jp->prev_job = *jpp;
3604 *jpp = jp;
3605 break;
3606 }
3607}
3608
3609#if JOBS || DEBUG
3610static int
3611jobno(const struct job *jp)
3612{
3613 return jp - jobtab + 1;
3614}
3615#endif
3616
3617/*
3618 * Convert a job name to a job structure.
3619 */
3620#if !JOBS
3621#define getjob(name, getctl) getjob(name)
3622#endif
3623static struct job *
3624getjob(const char *name, int getctl)
3625{
3626 struct job *jp;
3627 struct job *found;
3628 const char *err_msg = "%s: no such job";
3629 unsigned num;
3630 int c;
3631 const char *p;
3632 char *(*match)(const char *, const char *);
3633
3634 jp = curjob;
3635 p = name;
3636 if (!p)
3637 goto currentjob;
3638
3639 if (*p != '%')
3640 goto err;
3641
3642 c = *++p;
3643 if (!c)
3644 goto currentjob;
3645
3646 if (!p[1]) {
3647 if (c == '+' || c == '%') {
3648 currentjob:
3649 err_msg = "No current job";
3650 goto check;
3651 }
3652 if (c == '-') {
3653 if (jp)
3654 jp = jp->prev_job;
3655 err_msg = "No previous job";
3656 check:
3657 if (!jp)
3658 goto err;
3659 goto gotit;
3660 }
3661 }
3662
3663 if (is_number(p)) {
3664 num = atoi(p);
3665 if (num > 0 && num <= njobs) {
3666 jp = jobtab + num - 1;
3667 if (jp->used)
3668 goto gotit;
3669 goto err;
3670 }
3671 }
3672
3673 match = prefix;
3674 if (*p == '?') {
3675 match = strstr;
3676 p++;
3677 }
3678
3679 found = NULL;
3680 while (jp) {
3681 if (match(jp->ps[0].ps_cmd, p)) {
3682 if (found)
3683 goto err;
3684 found = jp;
3685 err_msg = "%s: ambiguous";
3686 }
3687 jp = jp->prev_job;
3688 }
3689 if (!found)
3690 goto err;
3691 jp = found;
3692
3693 gotit:
3694#if JOBS
3695 err_msg = "job %s not created under job control";
3696 if (getctl && jp->jobctl == 0)
3697 goto err;
3698#endif
3699 return jp;
3700 err:
3701 ash_msg_and_raise_error(err_msg, name);
3702}
3703
3704/*
3705 * Mark a job structure as unused.
3706 */
3707static void
3708freejob(struct job *jp)
3709{
3710 struct procstat *ps;
3711 int i;
3712
3713 INT_OFF;
3714 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
3715 if (ps->ps_cmd != nullstr)
3716 free(ps->ps_cmd);
3717 }
3718 if (jp->ps != &jp->ps0)
3719 free(jp->ps);
3720 jp->used = 0;
3721 set_curjob(jp, CUR_DELETE);
3722 INT_ON;
3723}
3724
3725#if JOBS
3726static void
3727xtcsetpgrp(int fd, pid_t pgrp)
3728{
3729 if (tcsetpgrp(fd, pgrp))
3730 ash_msg_and_raise_error("can't set tty process group (%m)");
3731}
3732
3733/*
3734 * Turn job control on and off.
3735 *
3736 * Note: This code assumes that the third arg to ioctl is a character
3737 * pointer, which is true on Berkeley systems but not System V. Since
3738 * System V doesn't have job control yet, this isn't a problem now.
3739 *
3740 * Called with interrupts off.
3741 */
3742static void
3743setjobctl(int on)
3744{
3745 int fd;
3746 int pgrp;
3747
3748 if (on == doing_jobctl || rootshell == 0)
3749 return;
3750 if (on) {
3751 int ofd;
3752 ofd = fd = open(_PATH_TTY, O_RDWR);
3753 if (fd < 0) {
3754 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3755 * That sometimes helps to acquire controlling tty.
3756 * Obviously, a workaround for bugs when someone
3757 * failed to provide a controlling tty to bash! :) */
3758 fd = 2;
3759 while (!isatty(fd))
3760 if (--fd < 0)
3761 goto out;
3762 }
3763 /* fd is a tty at this point */
3764 fd = fcntl(fd, F_DUPFD, 10);
3765 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, dont */
3766 close(ofd);
3767 if (fd < 0)
3768 goto out; /* F_DUPFD failed */
3769 close_on_exec_on(fd);
3770 while (1) { /* while we are in the background */
3771 pgrp = tcgetpgrp(fd);
3772 if (pgrp < 0) {
3773 out:
3774 ash_msg("can't access tty; job control turned off");
3775 mflag = on = 0;
3776 goto close;
3777 }
3778 if (pgrp == getpgrp())
3779 break;
3780 killpg(0, SIGTTIN);
3781 }
3782 initialpgrp = pgrp;
3783
3784 setsignal(SIGTSTP);
3785 setsignal(SIGTTOU);
3786 setsignal(SIGTTIN);
3787 pgrp = rootpid;
3788 setpgid(0, pgrp);
3789 xtcsetpgrp(fd, pgrp);
3790 } else {
3791 /* turning job control off */
3792 fd = ttyfd;
3793 pgrp = initialpgrp;
3794 /* was xtcsetpgrp, but this can make exiting ash
3795 * loop forever if pty is already deleted */
3796 tcsetpgrp(fd, pgrp);
3797 setpgid(0, pgrp);
3798 setsignal(SIGTSTP);
3799 setsignal(SIGTTOU);
3800 setsignal(SIGTTIN);
3801 close:
3802 if (fd >= 0)
3803 close(fd);
3804 fd = -1;
3805 }
3806 ttyfd = fd;
3807 doing_jobctl = on;
3808}
3809
3810static int FAST_FUNC
3811killcmd(int argc, char **argv)
3812{
3813 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3814 int i = 1;
3815 do {
3816 if (argv[i][0] == '%') {
3817 /*
3818 * "kill %N" - job kill
3819 * Converting to pgrp / pid kill
3820 */
3821 struct job *jp;
3822 char *dst;
3823 int j, n;
3824
3825 jp = getjob(argv[i], 0);
3826 /*
3827 * In jobs started under job control, we signal
3828 * entire process group by kill -PGRP_ID.
3829 * This happens, f.e., in interactive shell.
3830 *
3831 * Otherwise, we signal each child via
3832 * kill PID1 PID2 PID3.
3833 * Testcases:
3834 * sh -c 'sleep 1|sleep 1 & kill %1'
3835 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3836 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3837 */
3838 n = jp->nprocs; /* can't be 0 (I hope) */
3839 if (jp->jobctl)
3840 n = 1;
3841 dst = alloca(n * sizeof(int)*4);
3842 argv[i] = dst;
3843 for (j = 0; j < n; j++) {
3844 struct procstat *ps = &jp->ps[j];
3845 /* Skip non-running and not-stopped members
3846 * (i.e. dead members) of the job
3847 */
3848 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3849 continue;
3850 /*
3851 * kill_main has matching code to expect
3852 * leading space. Needed to not confuse
3853 * negative pids with "kill -SIGNAL_NO" syntax
3854 */
3855 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3856 }
3857 *dst = '\0';
3858 }
3859 } while (argv[++i]);
3860 }
3861 return kill_main(argc, argv);
3862}
3863
3864static void
3865showpipe(struct job *jp /*, FILE *out*/)
3866{
3867 struct procstat *ps;
3868 struct procstat *psend;
3869
3870 psend = jp->ps + jp->nprocs;
3871 for (ps = jp->ps + 1; ps < psend; ps++)
3872 printf(" | %s", ps->ps_cmd);
3873 newline_and_flush(stdout);
3874 flush_stdout_stderr();
3875}
3876
3877
3878static int
3879restartjob(struct job *jp, int mode)
3880{
3881 struct procstat *ps;
3882 int i;
3883 int status;
3884 pid_t pgid;
3885
3886 INT_OFF;
3887 if (jp->state == JOBDONE)
3888 goto out;
3889 jp->state = JOBRUNNING;
3890 pgid = jp->ps[0].ps_pid;
3891 if (mode == FORK_FG)
3892 xtcsetpgrp(ttyfd, pgid);
3893 killpg(pgid, SIGCONT);
3894 ps = jp->ps;
3895 i = jp->nprocs;
3896 do {
3897 if (WIFSTOPPED(ps->ps_status)) {
3898 ps->ps_status = -1;
3899 }
3900 ps++;
3901 } while (--i);
3902 out:
3903 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3904 INT_ON;
3905 return status;
3906}
3907
3908static int FAST_FUNC
3909fg_bgcmd(int argc UNUSED_PARAM, char **argv)
3910{
3911 struct job *jp;
3912 int mode;
3913 int retval;
3914
3915 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3916 nextopt(nullstr);
3917 argv = argptr;
3918 do {
3919 jp = getjob(*argv, 1);
3920 if (mode == FORK_BG) {
3921 set_curjob(jp, CUR_RUNNING);
3922 printf("[%d] ", jobno(jp));
3923 }
3924 out1str(jp->ps[0].ps_cmd);
3925 showpipe(jp /*, stdout*/);
3926 retval = restartjob(jp, mode);
3927 } while (*argv && *++argv);
3928 return retval;
3929}
3930#endif
3931
3932static int
3933sprint_status48(char *s, int status, int sigonly)
3934{
3935 int col;
3936 int st;
3937
3938 col = 0;
3939 if (!WIFEXITED(status)) {
3940 if (JOBS && WIFSTOPPED(status))
3941 st = WSTOPSIG(status);
3942 else
3943 st = WTERMSIG(status);
3944 if (sigonly) {
3945 if (st == SIGINT || st == SIGPIPE)
3946 goto out;
3947 if (JOBS && WIFSTOPPED(status))
3948 goto out;
3949 }
3950 st &= 0x7f;
3951//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
3952 col = fmtstr(s, 32, strsignal(st));
3953 if (WCOREDUMP(status)) {
3954 strcpy(s + col, " (core dumped)");
3955 col += sizeof(" (core dumped)")-1;
3956 }
3957 } else if (!sigonly) {
3958 st = WEXITSTATUS(status);
3959 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
3960 }
3961 out:
3962 return col;
3963}
3964
3965static int
3966wait_block_or_sig(int *status)
3967{
3968 int pid;
3969
3970 do {
3971 sigset_t mask;
3972
3973 /* Poll all children for changes in their state */
3974 got_sigchld = 0;
3975 /* if job control is active, accept stopped processes too */
3976 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
3977 if (pid != 0)
3978 break; /* Error (e.g. EINTR, ECHILD) or pid */
3979
3980 /* Children exist, but none are ready. Sleep until interesting signal */
3981#if 1
3982 sigfillset(&mask);
3983 sigprocmask(SIG_SETMASK, &mask, &mask);
3984 while (!got_sigchld && !pending_sig)
3985 sigsuspend(&mask);
3986 sigprocmask(SIG_SETMASK, &mask, NULL);
3987#else /* unsafe: a signal can set pending_sig after check, but before pause() */
3988 while (!got_sigchld && !pending_sig)
3989 pause();
3990#endif
3991
3992 /* If it was SIGCHLD, poll children again */
3993 } while (got_sigchld);
3994
3995 return pid;
3996}
3997
3998#define DOWAIT_NONBLOCK 0
3999#define DOWAIT_BLOCK 1
4000#define DOWAIT_BLOCK_OR_SIG 2
4001
4002static int
4003dowait(int block, struct job *job)
4004{
4005 int pid;
4006 int status;
4007 struct job *jp;
4008 struct job *thisjob = NULL;
4009
4010 TRACE(("dowait(0x%x) called\n", block));
4011
4012 /* It's wrong to call waitpid() outside of INT_OFF region:
4013 * signal can arrive just after syscall return and handler can
4014 * longjmp away, losing stop/exit notification processing.
4015 * Thus, for "jobs" builtin, and for waiting for a fg job,
4016 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4017 *
4018 * However, for "wait" builtin it is wrong to simply call waitpid()
4019 * in INT_OFF region: "wait" needs to wait for any running job
4020 * to change state, but should exit on any trap too.
4021 * In INT_OFF region, a signal just before syscall entry can set
4022 * pending_sig variables, but we can't check them, and we would
4023 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
4024 *
4025 * Because of this, we run inside INT_OFF, but use a special routine
4026 * which combines waitpid() and sigsuspend().
4027 * This is the reason why we need to have a handler for SIGCHLD:
4028 * SIG_DFL handler does not wake sigsuspend().
4029 */
4030 INT_OFF;
4031 if (block == DOWAIT_BLOCK_OR_SIG) {
4032 pid = wait_block_or_sig(&status);
4033 } else {
4034 int wait_flags = 0;
4035 if (block == DOWAIT_NONBLOCK)
4036 wait_flags = WNOHANG;
4037 /* if job control is active, accept stopped processes too */
4038 if (doing_jobctl)
4039 wait_flags |= WUNTRACED;
4040 /* NB: _not_ safe_waitpid, we need to detect EINTR */
4041 pid = waitpid(-1, &status, wait_flags);
4042 }
4043 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4044 pid, status, errno, strerror(errno)));
4045 if (pid <= 0)
4046 goto out;
4047
4048 thisjob = NULL;
4049 for (jp = curjob; jp; jp = jp->prev_job) {
4050 int jobstate;
4051 struct procstat *ps;
4052 struct procstat *psend;
4053 if (jp->state == JOBDONE)
4054 continue;
4055 jobstate = JOBDONE;
4056 ps = jp->ps;
4057 psend = ps + jp->nprocs;
4058 do {
4059 if (ps->ps_pid == pid) {
4060 TRACE(("Job %d: changing status of proc %d "
4061 "from 0x%x to 0x%x\n",
4062 jobno(jp), pid, ps->ps_status, status));
4063 ps->ps_status = status;
4064 thisjob = jp;
4065 }
4066 if (ps->ps_status == -1)
4067 jobstate = JOBRUNNING;
4068#if JOBS
4069 if (jobstate == JOBRUNNING)
4070 continue;
4071 if (WIFSTOPPED(ps->ps_status)) {
4072 jp->stopstatus = ps->ps_status;
4073 jobstate = JOBSTOPPED;
4074 }
4075#endif
4076 } while (++ps < psend);
4077 if (!thisjob)
4078 continue;
4079
4080 /* Found the job where one of its processes changed its state.
4081 * Is there at least one live and running process in this job? */
4082 if (jobstate != JOBRUNNING) {
4083 /* No. All live processes in the job are stopped
4084 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4085 */
4086 thisjob->changed = 1;
4087 if (thisjob->state != jobstate) {
4088 TRACE(("Job %d: changing state from %d to %d\n",
4089 jobno(thisjob), thisjob->state, jobstate));
4090 thisjob->state = jobstate;
4091#if JOBS
4092 if (jobstate == JOBSTOPPED)
4093 set_curjob(thisjob, CUR_STOPPED);
4094#endif
4095 }
4096 }
4097 goto out;
4098 }
4099 /* The process wasn't found in job list */
4100 if (JOBS && !WIFSTOPPED(status))
4101 jobless--;
4102 out:
4103 INT_ON;
4104
4105 if (thisjob && thisjob == job) {
4106 char s[48 + 1];
4107 int len;
4108
4109 len = sprint_status48(s, status, 1);
4110 if (len) {
4111 s[len] = '\n';
4112 s[len + 1] = '\0';
4113 out2str(s);
4114 }
4115 }
4116 return pid;
4117}
4118
4119#if JOBS
4120static void
4121showjob(struct job *jp, int mode)
4122{
4123 struct procstat *ps;
4124 struct procstat *psend;
4125 int col;
4126 int indent_col;
4127 char s[16 + 16 + 48];
4128 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
4129
4130 ps = jp->ps;
4131
4132 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
4133 /* just output process (group) id of pipeline */
4134 fprintf(out, "%d\n", ps->ps_pid);
4135 return;
4136 }
4137
4138 col = fmtstr(s, 16, "[%d] ", jobno(jp));
4139 indent_col = col;
4140
4141 if (jp == curjob)
4142 s[col - 3] = '+';
4143 else if (curjob && jp == curjob->prev_job)
4144 s[col - 3] = '-';
4145
4146 if (mode & SHOW_PIDS)
4147 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
4148
4149 psend = ps + jp->nprocs;
4150
4151 if (jp->state == JOBRUNNING) {
4152 strcpy(s + col, "Running");
4153 col += sizeof("Running") - 1;
4154 } else {
4155 int status = psend[-1].ps_status;
4156 if (jp->state == JOBSTOPPED)
4157 status = jp->stopstatus;
4158 col += sprint_status48(s + col, status, 0);
4159 }
4160 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
4161
4162 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4163 * or prints several "PID | <cmdN>" lines,
4164 * depending on SHOW_PIDS bit.
4165 * We do not print status of individual processes
4166 * between PID and <cmdN>. bash does it, but not very well:
4167 * first line shows overall job status, not process status,
4168 * making it impossible to know 1st process status.
4169 */
4170 goto start;
4171 do {
4172 /* for each process */
4173 s[0] = '\0';
4174 col = 33;
4175 if (mode & SHOW_PIDS)
4176 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
4177 start:
4178 fprintf(out, "%s%*c%s%s",
4179 s,
4180 33 - col >= 0 ? 33 - col : 0, ' ',
4181 ps == jp->ps ? "" : "| ",
4182 ps->ps_cmd
4183 );
4184 } while (++ps != psend);
4185 newline_and_flush(out);
4186
4187 jp->changed = 0;
4188
4189 if (jp->state == JOBDONE) {
4190 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4191 freejob(jp);
4192 }
4193}
4194
4195/*
4196 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4197 * statuses have changed since the last call to showjobs.
4198 */
4199static void
4200showjobs(int mode)
4201{
4202 struct job *jp;
4203
4204 TRACE(("showjobs(0x%x) called\n", mode));
4205
4206 /* Handle all finished jobs */
4207 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
4208 continue;
4209
4210 for (jp = curjob; jp; jp = jp->prev_job) {
4211 if (!(mode & SHOW_CHANGED) || jp->changed) {
4212 showjob(jp, mode);
4213 }
4214 }
4215}
4216
4217static int FAST_FUNC
4218jobscmd(int argc UNUSED_PARAM, char **argv)
4219{
4220 int mode, m;
4221
4222 mode = 0;
4223 while ((m = nextopt("lp")) != '\0') {
4224 if (m == 'l')
4225 mode |= SHOW_PIDS;
4226 else
4227 mode |= SHOW_ONLY_PGID;
4228 }
4229
4230 argv = argptr;
4231 if (*argv) {
4232 do
4233 showjob(getjob(*argv, 0), mode);
4234 while (*++argv);
4235 } else {
4236 showjobs(mode);
4237 }
4238
4239 return 0;
4240}
4241#endif /* JOBS */
4242
4243/* Called only on finished or stopped jobs (no members are running) */
4244static int
4245getstatus(struct job *job)
4246{
4247 int status;
4248 int retval;
4249 struct procstat *ps;
4250
4251 /* Fetch last member's status */
4252 ps = job->ps + job->nprocs - 1;
4253 status = ps->ps_status;
4254 if (pipefail) {
4255 /* "set -o pipefail" mode: use last _nonzero_ status */
4256 while (status == 0 && --ps >= job->ps)
4257 status = ps->ps_status;
4258 }
4259
4260 retval = WEXITSTATUS(status);
4261 if (!WIFEXITED(status)) {
4262#if JOBS
4263 retval = WSTOPSIG(status);
4264 if (!WIFSTOPPED(status))
4265#endif
4266 {
4267 /* XXX: limits number of signals */
4268 retval = WTERMSIG(status);
4269#if JOBS
4270 if (retval == SIGINT)
4271 job->sigint = 1;
4272#endif
4273 }
4274 retval += 128;
4275 }
4276 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4277 jobno(job), job->nprocs, status, retval));
4278 return retval;
4279}
4280
4281static int FAST_FUNC
4282waitcmd(int argc UNUSED_PARAM, char **argv)
4283{
4284 struct job *job;
4285 int retval;
4286 struct job *jp;
4287
4288 nextopt(nullstr);
4289 retval = 0;
4290
4291 argv = argptr;
4292 if (!*argv) {
4293 /* wait for all jobs */
4294 for (;;) {
4295 jp = curjob;
4296 while (1) {
4297 if (!jp) /* no running procs */
4298 goto ret;
4299 if (jp->state == JOBRUNNING)
4300 break;
4301 jp->waited = 1;
4302 jp = jp->prev_job;
4303 }
4304 /* man bash:
4305 * "When bash is waiting for an asynchronous command via
4306 * the wait builtin, the reception of a signal for which a trap
4307 * has been set will cause the wait builtin to return immediately
4308 * with an exit status greater than 128, immediately after which
4309 * the trap is executed."
4310 */
4311 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4312 /* if child sends us a signal *and immediately exits*,
4313 * dowait() returns pid > 0. Check this case,
4314 * not "if (dowait() < 0)"!
4315 */
4316 if (pending_sig)
4317 goto sigout;
4318 }
4319 }
4320
4321 retval = 127;
4322 do {
4323 if (**argv != '%') {
4324 pid_t pid = number(*argv);
4325 job = curjob;
4326 while (1) {
4327 if (!job)
4328 goto repeat;
4329 if (job->ps[job->nprocs - 1].ps_pid == pid)
4330 break;
4331 job = job->prev_job;
4332 }
4333 } else {
4334 job = getjob(*argv, 0);
4335 }
4336 /* loop until process terminated or stopped */
4337 while (job->state == JOBRUNNING) {
4338 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4339 if (pending_sig)
4340 goto sigout;
4341 }
4342 job->waited = 1;
4343 retval = getstatus(job);
4344 repeat: ;
4345 } while (*++argv);
4346
4347 ret:
4348 return retval;
4349 sigout:
4350 retval = 128 + pending_sig;
4351 return retval;
4352}
4353
4354static struct job *
4355growjobtab(void)
4356{
4357 size_t len;
4358 ptrdiff_t offset;
4359 struct job *jp, *jq;
4360
4361 len = njobs * sizeof(*jp);
4362 jq = jobtab;
4363 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4364
4365 offset = (char *)jp - (char *)jq;
4366 if (offset) {
4367 /* Relocate pointers */
4368 size_t l = len;
4369
4370 jq = (struct job *)((char *)jq + l);
4371 while (l) {
4372 l -= sizeof(*jp);
4373 jq--;
4374#define joff(p) ((struct job *)((char *)(p) + l))
4375#define jmove(p) (p) = (void *)((char *)(p) + offset)
4376 if (joff(jp)->ps == &jq->ps0)
4377 jmove(joff(jp)->ps);
4378 if (joff(jp)->prev_job)
4379 jmove(joff(jp)->prev_job);
4380 }
4381 if (curjob)
4382 jmove(curjob);
4383#undef joff
4384#undef jmove
4385 }
4386
4387 njobs += 4;
4388 jobtab = jp;
4389 jp = (struct job *)((char *)jp + len);
4390 jq = jp + 3;
4391 do {
4392 jq->used = 0;
4393 } while (--jq >= jp);
4394 return jp;
4395}
4396
4397/*
4398 * Return a new job structure.
4399 * Called with interrupts off.
4400 */
4401static struct job *
4402makejob(/*union node *node,*/ int nprocs)
4403{
4404 int i;
4405 struct job *jp;
4406
4407 for (i = njobs, jp = jobtab; ; jp++) {
4408 if (--i < 0) {
4409 jp = growjobtab();
4410 break;
4411 }
4412 if (jp->used == 0)
4413 break;
4414 if (jp->state != JOBDONE || !jp->waited)
4415 continue;
4416#if JOBS
4417 if (doing_jobctl)
4418 continue;
4419#endif
4420 freejob(jp);
4421 break;
4422 }
4423 memset(jp, 0, sizeof(*jp));
4424#if JOBS
4425 /* jp->jobctl is a bitfield.
4426 * "jp->jobctl |= jobctl" likely to give awful code */
4427 if (doing_jobctl)
4428 jp->jobctl = 1;
4429#endif
4430 jp->prev_job = curjob;
4431 curjob = jp;
4432 jp->used = 1;
4433 jp->ps = &jp->ps0;
4434 if (nprocs > 1) {
4435 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4436 }
4437 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4438 jobno(jp)));
4439 return jp;
4440}
4441
4442#if JOBS
4443/*
4444 * Return a string identifying a command (to be printed by the
4445 * jobs command).
4446 */
4447static char *cmdnextc;
4448
4449static void
4450cmdputs(const char *s)
4451{
4452 static const char vstype[VSTYPE + 1][3] = {
4453 "", "}", "-", "+", "?", "=",
4454 "%", "%%", "#", "##"
4455 IF_ASH_BASH_COMPAT(, ":", "/", "//")
4456 };
4457
4458 const char *p, *str;
4459 char cc[2];
4460 char *nextc;
4461 unsigned char c;
4462 unsigned char subtype = 0;
4463 int quoted = 0;
4464
4465 cc[1] = '\0';
4466 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4467 p = s;
4468 while ((c = *p++) != '\0') {
4469 str = NULL;
4470 switch (c) {
4471 case CTLESC:
4472 c = *p++;
4473 break;
4474 case CTLVAR:
4475 subtype = *p++;
4476 if ((subtype & VSTYPE) == VSLENGTH)
4477 str = "${#";
4478 else
4479 str = "${";
4480 goto dostr;
4481 case CTLENDVAR:
4482 str = "\"}" + !(quoted & 1);
4483 quoted >>= 1;
4484 subtype = 0;
4485 goto dostr;
4486 case CTLBACKQ:
4487 str = "$(...)";
4488 goto dostr;
4489#if ENABLE_SH_MATH_SUPPORT
4490 case CTLARI:
4491 str = "$((";
4492 goto dostr;
4493 case CTLENDARI:
4494 str = "))";
4495 goto dostr;
4496#endif
4497 case CTLQUOTEMARK:
4498 quoted ^= 1;
4499 c = '"';
4500 break;
4501 case '=':
4502 if (subtype == 0)
4503 break;
4504 if ((subtype & VSTYPE) != VSNORMAL)
4505 quoted <<= 1;
4506 str = vstype[subtype & VSTYPE];
4507 if (subtype & VSNUL)
4508 c = ':';
4509 else
4510 goto checkstr;
4511 break;
4512 case '\'':
4513 case '\\':
4514 case '"':
4515 case '$':
4516 /* These can only happen inside quotes */
4517 cc[0] = c;
4518 str = cc;
4519 c = '\\';
4520 break;
4521 default:
4522 break;
4523 }
4524 USTPUTC(c, nextc);
4525 checkstr:
4526 if (!str)
4527 continue;
4528 dostr:
4529 while ((c = *str++) != '\0') {
4530 USTPUTC(c, nextc);
4531 }
4532 } /* while *p++ not NUL */
4533
4534 if (quoted & 1) {
4535 USTPUTC('"', nextc);
4536 }
4537 *nextc = 0;
4538 cmdnextc = nextc;
4539}
4540
4541/* cmdtxt() and cmdlist() call each other */
4542static void cmdtxt(union node *n);
4543
4544static void
4545cmdlist(union node *np, int sep)
4546{
4547 for (; np; np = np->narg.next) {
4548 if (!sep)
4549 cmdputs(" ");
4550 cmdtxt(np);
4551 if (sep && np->narg.next)
4552 cmdputs(" ");
4553 }
4554}
4555
4556static void
4557cmdtxt(union node *n)
4558{
4559 union node *np;
4560 struct nodelist *lp;
4561 const char *p;
4562
4563 if (!n)
4564 return;
4565 switch (n->type) {
4566 default:
4567#if DEBUG
4568 abort();
4569#endif
4570 case NPIPE:
4571 lp = n->npipe.cmdlist;
4572 for (;;) {
4573 cmdtxt(lp->n);
4574 lp = lp->next;
4575 if (!lp)
4576 break;
4577 cmdputs(" | ");
4578 }
4579 break;
4580 case NSEMI:
4581 p = "; ";
4582 goto binop;
4583 case NAND:
4584 p = " && ";
4585 goto binop;
4586 case NOR:
4587 p = " || ";
4588 binop:
4589 cmdtxt(n->nbinary.ch1);
4590 cmdputs(p);
4591 n = n->nbinary.ch2;
4592 goto donode;
4593 case NREDIR:
4594 case NBACKGND:
4595 n = n->nredir.n;
4596 goto donode;
4597 case NNOT:
4598 cmdputs("!");
4599 n = n->nnot.com;
4600 donode:
4601 cmdtxt(n);
4602 break;
4603 case NIF:
4604 cmdputs("if ");
4605 cmdtxt(n->nif.test);
4606 cmdputs("; then ");
4607 if (n->nif.elsepart) {
4608 cmdtxt(n->nif.ifpart);
4609 cmdputs("; else ");
4610 n = n->nif.elsepart;
4611 } else {
4612 n = n->nif.ifpart;
4613 }
4614 p = "; fi";
4615 goto dotail;
4616 case NSUBSHELL:
4617 cmdputs("(");
4618 n = n->nredir.n;
4619 p = ")";
4620 goto dotail;
4621 case NWHILE:
4622 p = "while ";
4623 goto until;
4624 case NUNTIL:
4625 p = "until ";
4626 until:
4627 cmdputs(p);
4628 cmdtxt(n->nbinary.ch1);
4629 n = n->nbinary.ch2;
4630 p = "; done";
4631 dodo:
4632 cmdputs("; do ");
4633 dotail:
4634 cmdtxt(n);
4635 goto dotail2;
4636 case NFOR:
4637 cmdputs("for ");
4638 cmdputs(n->nfor.var);
4639 cmdputs(" in ");
4640 cmdlist(n->nfor.args, 1);
4641 n = n->nfor.body;
4642 p = "; done";
4643 goto dodo;
4644 case NDEFUN:
4645 cmdputs(n->narg.text);
4646 p = "() { ... }";
4647 goto dotail2;
4648 case NCMD:
4649 cmdlist(n->ncmd.args, 1);
4650 cmdlist(n->ncmd.redirect, 0);
4651 break;
4652 case NARG:
4653 p = n->narg.text;
4654 dotail2:
4655 cmdputs(p);
4656 break;
4657 case NHERE:
4658 case NXHERE:
4659 p = "<<...";
4660 goto dotail2;
4661 case NCASE:
4662 cmdputs("case ");
4663 cmdputs(n->ncase.expr->narg.text);
4664 cmdputs(" in ");
4665 for (np = n->ncase.cases; np; np = np->nclist.next) {
4666 cmdtxt(np->nclist.pattern);
4667 cmdputs(") ");
4668 cmdtxt(np->nclist.body);
4669 cmdputs(";; ");
4670 }
4671 p = "esac";
4672 goto dotail2;
4673 case NTO:
4674 p = ">";
4675 goto redir;
4676 case NCLOBBER:
4677 p = ">|";
4678 goto redir;
4679 case NAPPEND:
4680 p = ">>";
4681 goto redir;
4682#if ENABLE_ASH_BASH_COMPAT
4683 case NTO2:
4684#endif
4685 case NTOFD:
4686 p = ">&";
4687 goto redir;
4688 case NFROM:
4689 p = "<";
4690 goto redir;
4691 case NFROMFD:
4692 p = "<&";
4693 goto redir;
4694 case NFROMTO:
4695 p = "<>";
4696 redir:
4697 cmdputs(utoa(n->nfile.fd));
4698 cmdputs(p);
4699 if (n->type == NTOFD || n->type == NFROMFD) {
4700 cmdputs(utoa(n->ndup.dupfd));
4701 break;
4702 }
4703 n = n->nfile.fname;
4704 goto donode;
4705 }
4706}
4707
4708static char *
4709commandtext(union node *n)
4710{
4711 char *name;
4712
4713 STARTSTACKSTR(cmdnextc);
4714 cmdtxt(n);
4715 name = stackblock();
4716 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
4717 return ckstrdup(name);
4718}
4719#endif /* JOBS */
4720
4721/*
4722 * Fork off a subshell. If we are doing job control, give the subshell its
4723 * own process group. Jp is a job structure that the job is to be added to.
4724 * N is the command that will be evaluated by the child. Both jp and n may
4725 * be NULL. The mode parameter can be one of the following:
4726 * FORK_FG - Fork off a foreground process.
4727 * FORK_BG - Fork off a background process.
4728 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4729 * process group even if job control is on.
4730 *
4731 * When job control is turned off, background processes have their standard
4732 * input redirected to /dev/null (except for the second and later processes
4733 * in a pipeline).
4734 *
4735 * Called with interrupts off.
4736 */
4737/*
4738 * Clear traps on a fork.
4739 */
4740static void
4741clear_traps(void)
4742{
4743 char **tp;
4744
4745 INT_OFF;
4746 for (tp = trap; tp < &trap[NSIG]; tp++) {
4747 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4748 if (trap_ptr == trap)
4749 free(*tp);
4750 /* else: it "belongs" to trap_ptr vector, don't free */
4751 *tp = NULL;
4752 if ((tp - trap) != 0)
4753 setsignal(tp - trap);
4754 }
4755 }
4756 may_have_traps = 0;
4757 INT_ON;
4758}
4759
4760/* Lives far away from here, needed for forkchild */
4761static void closescript(void);
4762
4763/* Called after fork(), in child */
4764/* jp and n are NULL when called by openhere() for heredoc support */
4765static NOINLINE void
4766forkchild(struct job *jp, union node *n, int mode)
4767{
4768 int oldlvl;
4769
4770 TRACE(("Child shell %d\n", getpid()));
4771 oldlvl = shlvl;
4772 shlvl++;
4773
4774 /* man bash: "Non-builtin commands run by bash have signal handlers
4775 * set to the values inherited by the shell from its parent".
4776 * Do we do it correctly? */
4777
4778 closescript();
4779
4780 if (mode == FORK_NOJOB /* is it `xxx` ? */
4781 && n && n->type == NCMD /* is it single cmd? */
4782 /* && n->ncmd.args->type == NARG - always true? */
4783 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
4784 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4785 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4786 ) {
4787 TRACE(("Trap hack\n"));
4788 /* Awful hack for `trap` or $(trap).
4789 *
4790 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4791 * contains an example where "trap" is executed in a subshell:
4792 *
4793 * save_traps=$(trap)
4794 * ...
4795 * eval "$save_traps"
4796 *
4797 * Standard does not say that "trap" in subshell shall print
4798 * parent shell's traps. It only says that its output
4799 * must have suitable form, but then, in the above example
4800 * (which is not supposed to be normative), it implies that.
4801 *
4802 * bash (and probably other shell) does implement it
4803 * (traps are reset to defaults, but "trap" still shows them),
4804 * but as a result, "trap" logic is hopelessly messed up:
4805 *
4806 * # trap
4807 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4808 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4809 * # true | trap <--- trap is in subshell - no output (ditto)
4810 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4811 * trap -- 'echo Ho' SIGWINCH
4812 * # echo `(trap)` <--- in subshell in subshell - output
4813 * trap -- 'echo Ho' SIGWINCH
4814 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4815 * trap -- 'echo Ho' SIGWINCH
4816 *
4817 * The rules when to forget and when to not forget traps
4818 * get really complex and nonsensical.
4819 *
4820 * Our solution: ONLY bare $(trap) or `trap` is special.
4821 */
4822 /* Save trap handler strings for trap builtin to print */
4823 trap_ptr = xmemdup(trap, sizeof(trap));
4824 /* Fall through into clearing traps */
4825 }
4826 clear_traps();
4827#if JOBS
4828 /* do job control only in root shell */
4829 doing_jobctl = 0;
4830 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
4831 pid_t pgrp;
4832
4833 if (jp->nprocs == 0)
4834 pgrp = getpid();
4835 else
4836 pgrp = jp->ps[0].ps_pid;
4837 /* this can fail because we are doing it in the parent also */
4838 setpgid(0, pgrp);
4839 if (mode == FORK_FG)
4840 xtcsetpgrp(ttyfd, pgrp);
4841 setsignal(SIGTSTP);
4842 setsignal(SIGTTOU);
4843 } else
4844#endif
4845 if (mode == FORK_BG) {
4846 /* man bash: "When job control is not in effect,
4847 * asynchronous commands ignore SIGINT and SIGQUIT" */
4848 ignoresig(SIGINT);
4849 ignoresig(SIGQUIT);
4850 if (jp->nprocs == 0) {
4851 close(0);
4852 if (open(bb_dev_null, O_RDONLY) != 0)
4853 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
4854 }
4855 }
4856 if (oldlvl == 0) {
4857 if (iflag) { /* why if iflag only? */
4858 setsignal(SIGINT);
4859 setsignal(SIGTERM);
4860 }
4861 /* man bash:
4862 * "In all cases, bash ignores SIGQUIT. Non-builtin
4863 * commands run by bash have signal handlers
4864 * set to the values inherited by the shell
4865 * from its parent".
4866 * Take care of the second rule: */
4867 setsignal(SIGQUIT);
4868 }
4869#if JOBS
4870 if (n && n->type == NCMD
4871 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
4872 ) {
4873 TRACE(("Job hack\n"));
4874 /* "jobs": we do not want to clear job list for it,
4875 * instead we remove only _its_ own_ job from job list.
4876 * This makes "jobs .... | cat" more useful.
4877 */
4878 freejob(curjob);
4879 return;
4880 }
4881#endif
4882 for (jp = curjob; jp; jp = jp->prev_job)
4883 freejob(jp);
4884 jobless = 0;
4885}
4886
4887/* Called after fork(), in parent */
4888#if !JOBS
4889#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4890#endif
4891static void
4892forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4893{
4894 TRACE(("In parent shell: child = %d\n", pid));
4895 if (!jp) {
4896 /* jp is NULL when called by openhere() for heredoc support */
4897 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4898 continue;
4899 jobless++;
4900 return;
4901 }
4902#if JOBS
4903 if (mode != FORK_NOJOB && jp->jobctl) {
4904 int pgrp;
4905
4906 if (jp->nprocs == 0)
4907 pgrp = pid;
4908 else
4909 pgrp = jp->ps[0].ps_pid;
4910 /* This can fail because we are doing it in the child also */
4911 setpgid(pid, pgrp);
4912 }
4913#endif
4914 if (mode == FORK_BG) {
4915 backgndpid = pid; /* set $! */
4916 set_curjob(jp, CUR_RUNNING);
4917 }
4918 if (jp) {
4919 struct procstat *ps = &jp->ps[jp->nprocs++];
4920 ps->ps_pid = pid;
4921 ps->ps_status = -1;
4922 ps->ps_cmd = nullstr;
4923#if JOBS
4924 if (doing_jobctl && n)
4925 ps->ps_cmd = commandtext(n);
4926#endif
4927 }
4928}
4929
4930/* jp and n are NULL when called by openhere() for heredoc support */
4931static int
4932forkshell(struct job *jp, union node *n, int mode)
4933{
4934 int pid;
4935
4936 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4937 pid = fork();
4938 if (pid < 0) {
4939 TRACE(("Fork failed, errno=%d", errno));
4940 if (jp)
4941 freejob(jp);
4942 ash_msg_and_raise_error("can't fork");
4943 }
4944 if (pid == 0) {
4945 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
4946 forkchild(jp, n, mode);
4947 } else {
4948 forkparent(jp, n, mode, pid);
4949 }
4950 return pid;
4951}
4952
4953/*
4954 * Wait for job to finish.
4955 *
4956 * Under job control we have the problem that while a child process
4957 * is running interrupts generated by the user are sent to the child
4958 * but not to the shell. This means that an infinite loop started by
4959 * an interactive user may be hard to kill. With job control turned off,
4960 * an interactive user may place an interactive program inside a loop.
4961 * If the interactive program catches interrupts, the user doesn't want
4962 * these interrupts to also abort the loop. The approach we take here
4963 * is to have the shell ignore interrupt signals while waiting for a
4964 * foreground process to terminate, and then send itself an interrupt
4965 * signal if the child process was terminated by an interrupt signal.
4966 * Unfortunately, some programs want to do a bit of cleanup and then
4967 * exit on interrupt; unless these processes terminate themselves by
4968 * sending a signal to themselves (instead of calling exit) they will
4969 * confuse this approach.
4970 *
4971 * Called with interrupts off.
4972 */
4973static int
4974waitforjob(struct job *jp)
4975{
4976 int st;
4977
4978 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4979
4980 INT_OFF;
4981 while (jp->state == JOBRUNNING) {
4982 /* In non-interactive shells, we _can_ get
4983 * a keyboard signal here and be EINTRed,
4984 * but we just loop back, waiting for command to complete.
4985 *
4986 * man bash:
4987 * "If bash is waiting for a command to complete and receives
4988 * a signal for which a trap has been set, the trap
4989 * will not be executed until the command completes."
4990 *
4991 * Reality is that even if trap is not set, bash
4992 * will not act on the signal until command completes.
4993 * Try this. sleep5intoff.c:
4994 * #include <signal.h>
4995 * #include <unistd.h>
4996 * int main() {
4997 * sigset_t set;
4998 * sigemptyset(&set);
4999 * sigaddset(&set, SIGINT);
5000 * sigaddset(&set, SIGQUIT);
5001 * sigprocmask(SIG_BLOCK, &set, NULL);
5002 * sleep(5);
5003 * return 0;
5004 * }
5005 * $ bash -c './sleep5intoff; echo hi'
5006 * ^C^C^C^C <--- pressing ^C once a second
5007 * $ _
5008 * $ bash -c './sleep5intoff; echo hi'
5009 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5010 * $ _
5011 */
5012 dowait(DOWAIT_BLOCK, jp);
5013 }
5014 INT_ON;
5015
5016 st = getstatus(jp);
5017#if JOBS
5018 if (jp->jobctl) {
5019 xtcsetpgrp(ttyfd, rootpid);
5020 /*
5021 * This is truly gross.
5022 * If we're doing job control, then we did a TIOCSPGRP which
5023 * caused us (the shell) to no longer be in the controlling
5024 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5025 * intuit from the subprocess exit status whether a SIGINT
5026 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5027 */
5028 if (jp->sigint) /* TODO: do the same with all signals */
5029 raise(SIGINT); /* ... by raise(jp->sig) instead? */
5030 }
5031 if (jp->state == JOBDONE)
5032#endif
5033 freejob(jp);
5034 return st;
5035}
5036
5037/*
5038 * return 1 if there are stopped jobs, otherwise 0
5039 */
5040static int
5041stoppedjobs(void)
5042{
5043 struct job *jp;
5044 int retval;
5045
5046 retval = 0;
5047 if (job_warning)
5048 goto out;
5049 jp = curjob;
5050 if (jp && jp->state == JOBSTOPPED) {
5051 out2str("You have stopped jobs.\n");
5052 job_warning = 2;
5053 retval++;
5054 }
5055 out:
5056 return retval;
5057}
5058
5059
5060/*
5061 * Code for dealing with input/output redirection.
5062 */
5063
5064#undef EMPTY
5065#undef CLOSED
5066#define EMPTY -2 /* marks an unused slot in redirtab */
5067#define CLOSED -3 /* marks a slot of previously-closed fd */
5068
5069/*
5070 * Open a file in noclobber mode.
5071 * The code was copied from bash.
5072 */
5073static int
5074noclobberopen(const char *fname)
5075{
5076 int r, fd;
5077 struct stat finfo, finfo2;
5078
5079 /*
5080 * If the file exists and is a regular file, return an error
5081 * immediately.
5082 */
5083 r = stat(fname, &finfo);
5084 if (r == 0 && S_ISREG(finfo.st_mode)) {
5085 errno = EEXIST;
5086 return -1;
5087 }
5088
5089 /*
5090 * If the file was not present (r != 0), make sure we open it
5091 * exclusively so that if it is created before we open it, our open
5092 * will fail. Make sure that we do not truncate an existing file.
5093 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5094 * file was not a regular file, we leave O_EXCL off.
5095 */
5096 if (r != 0)
5097 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5098 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5099
5100 /* If the open failed, return the file descriptor right away. */
5101 if (fd < 0)
5102 return fd;
5103
5104 /*
5105 * OK, the open succeeded, but the file may have been changed from a
5106 * non-regular file to a regular file between the stat and the open.
5107 * We are assuming that the O_EXCL open handles the case where FILENAME
5108 * did not exist and is symlinked to an existing file between the stat
5109 * and open.
5110 */
5111
5112 /*
5113 * If we can open it and fstat the file descriptor, and neither check
5114 * revealed that it was a regular file, and the file has not been
5115 * replaced, return the file descriptor.
5116 */
5117 if (fstat(fd, &finfo2) == 0
5118 && !S_ISREG(finfo2.st_mode)
5119 && finfo.st_dev == finfo2.st_dev
5120 && finfo.st_ino == finfo2.st_ino
5121 ) {
5122 return fd;
5123 }
5124
5125 /* The file has been replaced. badness. */
5126 close(fd);
5127 errno = EEXIST;
5128 return -1;
5129}
5130
5131/*
5132 * Handle here documents. Normally we fork off a process to write the
5133 * data to a pipe. If the document is short, we can stuff the data in
5134 * the pipe without forking.
5135 */
5136/* openhere needs this forward reference */
5137static void expandhere(union node *arg, int fd);
5138static int
5139openhere(union node *redir)
5140{
5141 int pip[2];
5142 size_t len = 0;
5143
5144 if (pipe(pip) < 0)
5145 ash_msg_and_raise_error("pipe call failed");
5146 if (redir->type == NHERE) {
5147 len = strlen(redir->nhere.doc->narg.text);
5148 if (len <= PIPE_BUF) {
5149 full_write(pip[1], redir->nhere.doc->narg.text, len);
5150 goto out;
5151 }
5152 }
5153 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5154 /* child */
5155 close(pip[0]);
5156 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5157 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5158 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5159 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5160 signal(SIGPIPE, SIG_DFL);
5161 if (redir->type == NHERE)
5162 full_write(pip[1], redir->nhere.doc->narg.text, len);
5163 else /* NXHERE */
5164 expandhere(redir->nhere.doc, pip[1]);
5165 _exit(EXIT_SUCCESS);
5166 }
5167 out:
5168 close(pip[1]);
5169 return pip[0];
5170}
5171
5172static int
5173openredirect(union node *redir)
5174{
5175 char *fname;
5176 int f;
5177
5178 switch (redir->nfile.type) {
5179/* Can't happen, our single caller does this itself */
5180// case NTOFD:
5181// case NFROMFD:
5182// return -1;
5183 case NHERE:
5184 case NXHERE:
5185 return openhere(redir);
5186 }
5187
5188 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5189 * allocated space. Do it only when we know it is safe.
5190 */
5191 fname = redir->nfile.expfname;
5192
5193 switch (redir->nfile.type) {
5194 default:
5195#if DEBUG
5196 abort();
5197#endif
5198 case NFROM:
5199 f = open(fname, O_RDONLY);
5200 if (f < 0)
5201 goto eopen;
5202 break;
5203 case NFROMTO:
5204 f = open(fname, O_RDWR|O_CREAT, 0666);
5205 if (f < 0)
5206 goto ecreate;
5207 break;
5208 case NTO:
5209#if ENABLE_ASH_BASH_COMPAT
5210 case NTO2:
5211#endif
5212 /* Take care of noclobber mode. */
5213 if (Cflag) {
5214 f = noclobberopen(fname);
5215 if (f < 0)
5216 goto ecreate;
5217 break;
5218 }
5219 /* FALLTHROUGH */
5220 case NCLOBBER:
5221 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5222 if (f < 0)
5223 goto ecreate;
5224 break;
5225 case NAPPEND:
5226 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5227 if (f < 0)
5228 goto ecreate;
5229 break;
5230 }
5231
5232 return f;
5233 ecreate:
5234 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5235 eopen:
5236 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5237}
5238
5239/*
5240 * Copy a file descriptor to be >= 10. Throws exception on error.
5241 */
5242static int
5243savefd(int from)
5244{
5245 int newfd;
5246 int err;
5247
5248 newfd = fcntl(from, F_DUPFD, 10);
5249 err = newfd < 0 ? errno : 0;
5250 if (err != EBADF) {
5251 if (err)
5252 ash_msg_and_raise_error("%d: %m", from);
5253 close(from);
5254 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5255 }
5256
5257 return newfd;
5258}
5259static int
5260dup2_or_raise(int from, int to)
5261{
5262 int newfd;
5263
5264 newfd = (from != to) ? dup2(from, to) : to;
5265 if (newfd < 0) {
5266 /* Happens when source fd is not open: try "echo >&99" */
5267 ash_msg_and_raise_error("%d: %m", from);
5268 }
5269 return newfd;
5270}
5271
5272/* Struct def and variable are moved down to the first usage site */
5273struct two_fd_t {
5274 int orig, copy;
5275};
5276struct redirtab {
5277 struct redirtab *next;
5278 int pair_count;
5279 struct two_fd_t two_fd[];
5280};
5281#define redirlist (G_var.redirlist)
5282enum {
5283 COPYFD_RESTORE = (int)~(INT_MAX),
5284};
5285
5286static int
5287need_to_remember(struct redirtab *rp, int fd)
5288{
5289 int i;
5290
5291 if (!rp) /* remembering was not requested */
5292 return 0;
5293
5294 for (i = 0; i < rp->pair_count; i++) {
5295 if (rp->two_fd[i].orig == fd) {
5296 /* already remembered */
5297 return 0;
5298 }
5299 }
5300 return 1;
5301}
5302
5303/* "hidden" fd is a fd used to read scripts, or a copy of such */
5304static int
5305is_hidden_fd(struct redirtab *rp, int fd)
5306{
5307 int i;
5308 struct parsefile *pf;
5309
5310 if (fd == -1)
5311 return 0;
5312 /* Check open scripts' fds */
5313 pf = g_parsefile;
5314 while (pf) {
5315 /* We skip pf_fd == 0 case because of the following case:
5316 * $ ash # running ash interactively
5317 * $ . ./script.sh
5318 * and in script.sh: "exec 9>&0".
5319 * Even though top-level pf_fd _is_ 0,
5320 * it's still ok to use it: "read" builtin uses it,
5321 * why should we cripple "exec" builtin?
5322 */
5323 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
5324 return 1;
5325 }
5326 pf = pf->prev;
5327 }
5328
5329 if (!rp)
5330 return 0;
5331 /* Check saved fds of redirects */
5332 fd |= COPYFD_RESTORE;
5333 for (i = 0; i < rp->pair_count; i++) {
5334 if (rp->two_fd[i].copy == fd) {
5335 return 1;
5336 }
5337 }
5338 return 0;
5339}
5340
5341/*
5342 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5343 * old file descriptors are stashed away so that the redirection can be
5344 * undone by calling popredir.
5345 */
5346/* flags passed to redirect */
5347#define REDIR_PUSH 01 /* save previous values of file descriptors */
5348#define REDIR_SAVEFD2 03 /* set preverrout */
5349static void
5350redirect(union node *redir, int flags)
5351{
5352 struct redirtab *sv;
5353 int sv_pos;
5354 int i;
5355 int fd;
5356 int newfd;
5357 int copied_fd2 = -1;
5358
5359 if (!redir) {
5360 return;
5361 }
5362
5363 sv = NULL;
5364 sv_pos = 0;
5365 INT_OFF;
5366 if (flags & REDIR_PUSH) {
5367 union node *tmp = redir;
5368 do {
5369 sv_pos++;
5370#if ENABLE_ASH_BASH_COMPAT
5371 if (tmp->nfile.type == NTO2)
5372 sv_pos++;
5373#endif
5374 tmp = tmp->nfile.next;
5375 } while (tmp);
5376 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
5377 sv->next = redirlist;
5378 sv->pair_count = sv_pos;
5379 redirlist = sv;
5380 while (sv_pos > 0) {
5381 sv_pos--;
5382 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5383 }
5384 }
5385
5386 do {
5387 int right_fd = -1;
5388 fd = redir->nfile.fd;
5389 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5390 right_fd = redir->ndup.dupfd;
5391 //bb_error_msg("doing %d > %d", fd, right_fd);
5392 /* redirect from/to same file descriptor? */
5393 if (right_fd == fd)
5394 continue;
5395 /* "echo >&10" and 10 is a fd opened to a sh script? */
5396 if (is_hidden_fd(sv, right_fd)) {
5397 errno = EBADF; /* as if it is closed */
5398 ash_msg_and_raise_error("%d: %m", right_fd);
5399 }
5400 newfd = -1;
5401 } else {
5402 newfd = openredirect(redir); /* always >= 0 */
5403 if (fd == newfd) {
5404 /* Descriptor wasn't open before redirect.
5405 * Mark it for close in the future */
5406 if (need_to_remember(sv, fd)) {
5407 goto remember_to_close;
5408 }
5409 continue;
5410 }
5411 }
5412#if ENABLE_ASH_BASH_COMPAT
5413 redirect_more:
5414#endif
5415 if (need_to_remember(sv, fd)) {
5416 /* Copy old descriptor */
5417 /* Careful to not accidentally "save"
5418 * to the same fd as right side fd in N>&M */
5419 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5420 i = fcntl(fd, F_DUPFD, minfd);
5421/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5422 * are closed in popredir() in the child, preventing them from leaking
5423 * into child. (popredir() also cleans up the mess in case of failures)
5424 */
5425 if (i == -1) {
5426 i = errno;
5427 if (i != EBADF) {
5428 /* Strange error (e.g. "too many files" EMFILE?) */
5429 if (newfd >= 0)
5430 close(newfd);
5431 errno = i;
5432 ash_msg_and_raise_error("%d: %m", fd);
5433 /* NOTREACHED */
5434 }
5435 /* EBADF: it is not open - good, remember to close it */
5436 remember_to_close:
5437 i = CLOSED;
5438 } else { /* fd is open, save its copy */
5439 /* "exec fd>&-" should not close fds
5440 * which point to script file(s).
5441 * Force them to be restored afterwards */
5442 if (is_hidden_fd(sv, fd))
5443 i |= COPYFD_RESTORE;
5444 }
5445 if (fd == 2)
5446 copied_fd2 = i;
5447 sv->two_fd[sv_pos].orig = fd;
5448 sv->two_fd[sv_pos].copy = i;
5449 sv_pos++;
5450 }
5451 if (newfd < 0) {
5452 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5453 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5454 /* Don't want to trigger debugging */
5455 if (fd != -1)
5456 close(fd);
5457 } else {
5458 dup2_or_raise(redir->ndup.dupfd, fd);
5459 }
5460 } else if (fd != newfd) { /* move newfd to fd */
5461 dup2_or_raise(newfd, fd);
5462#if ENABLE_ASH_BASH_COMPAT
5463 if (!(redir->nfile.type == NTO2 && fd == 2))
5464#endif
5465 close(newfd);
5466 }
5467#if ENABLE_ASH_BASH_COMPAT
5468 if (redir->nfile.type == NTO2 && fd == 1) {
5469 /* We already redirected it to fd 1, now copy it to 2 */
5470 newfd = 1;
5471 fd = 2;
5472 goto redirect_more;
5473 }
5474#endif
5475 } while ((redir = redir->nfile.next) != NULL);
5476
5477 INT_ON;
5478 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5479 preverrout_fd = copied_fd2;
5480}
5481
5482/*
5483 * Undo the effects of the last redirection.
5484 */
5485static void
5486popredir(int drop, int restore)
5487{
5488 struct redirtab *rp;
5489 int i;
5490
5491 if (redirlist == NULL)
5492 return;
5493 INT_OFF;
5494 rp = redirlist;
5495 for (i = 0; i < rp->pair_count; i++) {
5496 int fd = rp->two_fd[i].orig;
5497 int copy = rp->two_fd[i].copy;
5498 if (copy == CLOSED) {
5499 if (!drop)
5500 close(fd);
5501 continue;
5502 }
5503 if (copy != EMPTY) {
5504 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5505 copy &= ~COPYFD_RESTORE;
5506 /*close(fd);*/
5507 dup2_or_raise(copy, fd);
5508 }
5509 close(copy & ~COPYFD_RESTORE);
5510 }
5511 }
5512 redirlist = rp->next;
5513 free(rp);
5514 INT_ON;
5515}
5516
5517/*
5518 * Undo all redirections. Called on error or interrupt.
5519 */
5520
5521static int
5522redirectsafe(union node *redir, int flags)
5523{
5524 int err;
5525 volatile int saveint;
5526 struct jmploc *volatile savehandler = exception_handler;
5527 struct jmploc jmploc;
5528
5529 SAVE_INT(saveint);
5530 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5531 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5532 if (!err) {
5533 exception_handler = &jmploc;
5534 redirect(redir, flags);
5535 }
5536 exception_handler = savehandler;
5537 if (err && exception_type != EXERROR)
5538 longjmp(exception_handler->loc, 1);
5539 RESTORE_INT(saveint);
5540 return err;
5541}
5542
5543
5544/* ============ Routines to expand arguments to commands
5545 *
5546 * We have to deal with backquotes, shell variables, and file metacharacters.
5547 */
5548
5549#if ENABLE_SH_MATH_SUPPORT
5550static arith_t
5551ash_arith(const char *s)
5552{
5553 arith_state_t math_state;
5554 arith_t result;
5555
5556 math_state.lookupvar = lookupvar;
5557 math_state.setvar = setvar0;
5558 //math_state.endofname = endofname;
5559
5560 INT_OFF;
5561 result = arith(&math_state, s);
5562 if (math_state.errmsg)
5563 ash_msg_and_raise_error(math_state.errmsg);
5564 INT_ON;
5565
5566 return result;
5567}
5568#endif
5569
5570/*
5571 * expandarg flags
5572 */
5573#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5574#define EXP_TILDE 0x2 /* do normal tilde expansion */
5575#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5576#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5577/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5578 * POSIX says for this case:
5579 * Pathname expansion shall not be performed on the word by a
5580 * non-interactive shell; an interactive shell may perform it, but shall
5581 * do so only when the expansion would result in one word.
5582 * Currently, our code complies to the above rule by never globbing
5583 * redirection filenames.
5584 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5585 * (this means that on a typical Linux distro, bash almost always
5586 * performs globbing, and thus diverges from what we do).
5587 */
5588#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5589#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
5590#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5591#define EXP_WORD 0x80 /* expand word in parameter expansion */
5592#define EXP_QUOTED 0x100 /* expand word in double quotes */
5593/*
5594 * rmescape() flags
5595 */
5596#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5597#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5598#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5599#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5600#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
5601
5602/* Add CTLESC when necessary. */
5603#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
5604/* Do not skip NUL characters. */
5605#define QUOTES_KEEPNUL EXP_TILDE
5606
5607/*
5608 * Structure specifying which parts of the string should be searched
5609 * for IFS characters.
5610 */
5611struct ifsregion {
5612 struct ifsregion *next; /* next region in list */
5613 int begoff; /* offset of start of region */
5614 int endoff; /* offset of end of region */
5615 int nulonly; /* search for nul bytes only */
5616};
5617
5618struct arglist {
5619 struct strlist *list;
5620 struct strlist **lastp;
5621};
5622
5623/* output of current string */
5624static char *expdest;
5625/* list of back quote expressions */
5626static struct nodelist *argbackq;
5627/* first struct in list of ifs regions */
5628static struct ifsregion ifsfirst;
5629/* last struct in list */
5630static struct ifsregion *ifslastp;
5631/* holds expanded arg list */
5632static struct arglist exparg;
5633
5634/*
5635 * Our own itoa().
5636 */
5637#if !ENABLE_SH_MATH_SUPPORT
5638/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5639typedef long arith_t;
5640# define ARITH_FMT "%ld"
5641#endif
5642static int
5643cvtnum(arith_t num)
5644{
5645 int len;
5646
5647 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5648 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
5649 STADJUST(len, expdest);
5650 return len;
5651}
5652
5653/*
5654 * Break the argument string into pieces based upon IFS and add the
5655 * strings to the argument list. The regions of the string to be
5656 * searched for IFS characters have been stored by recordregion.
5657 */
5658static void
5659ifsbreakup(char *string, struct arglist *arglist)
5660{
5661 struct ifsregion *ifsp;
5662 struct strlist *sp;
5663 char *start;
5664 char *p;
5665 char *q;
5666 const char *ifs, *realifs;
5667 int ifsspc;
5668 int nulonly;
5669
5670 start = string;
5671 if (ifslastp != NULL) {
5672 ifsspc = 0;
5673 nulonly = 0;
5674 realifs = ifsset() ? ifsval() : defifs;
5675 ifsp = &ifsfirst;
5676 do {
5677 p = string + ifsp->begoff;
5678 nulonly = ifsp->nulonly;
5679 ifs = nulonly ? nullstr : realifs;
5680 ifsspc = 0;
5681 while (p < string + ifsp->endoff) {
5682 q = p;
5683 if ((unsigned char)*p == CTLESC)
5684 p++;
5685 if (!strchr(ifs, *p)) {
5686 p++;
5687 continue;
5688 }
5689 if (!nulonly)
5690 ifsspc = (strchr(defifs, *p) != NULL);
5691 /* Ignore IFS whitespace at start */
5692 if (q == start && ifsspc) {
5693 p++;
5694 start = p;
5695 continue;
5696 }
5697 *q = '\0';
5698 sp = stzalloc(sizeof(*sp));
5699 sp->text = start;
5700 *arglist->lastp = sp;
5701 arglist->lastp = &sp->next;
5702 p++;
5703 if (!nulonly) {
5704 for (;;) {
5705 if (p >= string + ifsp->endoff) {
5706 break;
5707 }
5708 q = p;
5709 if ((unsigned char)*p == CTLESC)
5710 p++;
5711 if (strchr(ifs, *p) == NULL) {
5712 p = q;
5713 break;
5714 }
5715 if (strchr(defifs, *p) == NULL) {
5716 if (ifsspc) {
5717 p++;
5718 ifsspc = 0;
5719 } else {
5720 p = q;
5721 break;
5722 }
5723 } else
5724 p++;
5725 }
5726 }
5727 start = p;
5728 } /* while */
5729 ifsp = ifsp->next;
5730 } while (ifsp != NULL);
5731 if (nulonly)
5732 goto add;
5733 }
5734
5735 if (!*start)
5736 return;
5737
5738 add:
5739 sp = stzalloc(sizeof(*sp));
5740 sp->text = start;
5741 *arglist->lastp = sp;
5742 arglist->lastp = &sp->next;
5743}
5744
5745static void
5746ifsfree(void)
5747{
5748 struct ifsregion *p = ifsfirst.next;
5749
5750 if (!p)
5751 goto out;
5752
5753 INT_OFF;
5754 do {
5755 struct ifsregion *ifsp;
5756 ifsp = p->next;
5757 free(p);
5758 p = ifsp;
5759 } while (p);
5760 ifsfirst.next = NULL;
5761 INT_ON;
5762 out:
5763 ifslastp = NULL;
5764}
5765
5766static size_t
5767esclen(const char *start, const char *p)
5768{
5769 size_t esc = 0;
5770
5771 while (p > start && (unsigned char)*--p == CTLESC) {
5772 esc++;
5773 }
5774 return esc;
5775}
5776
5777/*
5778 * Remove any CTLESC characters from a string.
5779 */
5780static char *
5781rmescapes(char *str, int flag)
5782{
5783 static const char qchars[] ALIGN1 = {
5784 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
5785
5786 char *p, *q, *r;
5787 unsigned inquotes;
5788 unsigned protect_against_glob;
5789 unsigned globbing;
5790 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
5791
5792 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
5793 if (!p)
5794 return str;
5795
5796 q = p;
5797 r = str;
5798 if (flag & RMESCAPE_ALLOC) {
5799 size_t len = p - str;
5800 size_t fulllen = len + strlen(p) + 1;
5801
5802 if (flag & RMESCAPE_GROW) {
5803 int strloc = str - (char *)stackblock();
5804 r = makestrspace(fulllen, expdest);
5805 /* p and str may be invalidated by makestrspace */
5806 str = (char *)stackblock() + strloc;
5807 p = str + len;
5808 } else if (flag & RMESCAPE_HEAP) {
5809 r = ckmalloc(fulllen);
5810 } else {
5811 r = stalloc(fulllen);
5812 }
5813 q = r;
5814 if (len > 0) {
5815 q = (char *)memcpy(q, str, len) + len;
5816 }
5817 }
5818
5819 inquotes = 0;
5820 globbing = flag & RMESCAPE_GLOB;
5821 protect_against_glob = globbing;
5822 while (*p) {
5823 if ((unsigned char)*p == CTLQUOTEMARK) {
5824// Note: both inquotes and protect_against_glob only affect whether
5825 inquotes = ~inquotes;
5826 p++;
5827 protect_against_glob = globbing;
5828 continue;
5829 }
5830 if ((unsigned char)*p == CTLESC) {
5831 p++;
5832#if DEBUG
5833 if (*p == '\0')
5834 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5835#endif
5836 if (protect_against_glob) {
5837 *q++ = '\\';
5838 }
5839 } else if (*p == '\\' && !inquotes) {
5840 /* naked back slash */
5841 protect_against_glob = 0;
5842 goto copy;
5843 }
5844#if ENABLE_ASH_BASH_COMPAT
5845 else if (*p == '/' && slash) {
5846 /* stop handling globbing and mark location of slash */
5847 globbing = slash = 0;
5848 *p = CTLESC;
5849 }
5850#endif
5851 protect_against_glob = globbing;
5852 copy:
5853 *q++ = *p++;
5854 }
5855 *q = '\0';
5856 if (flag & RMESCAPE_GROW) {
5857 expdest = r;
5858 STADJUST(q - r + 1, expdest);
5859 }
5860 return r;
5861}
5862#define pmatch(a, b) !fnmatch((a), (b), 0)
5863
5864/*
5865 * Prepare a pattern for a expmeta (internal glob(3)) call.
5866 *
5867 * Returns an stalloced string.
5868 */
5869static char *
5870preglob(const char *pattern, int flag)
5871{
5872 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
5873}
5874
5875/*
5876 * Put a string on the stack.
5877 */
5878static void
5879memtodest(const char *p, size_t len, int syntax, int quotes)
5880{
5881 char *q;
5882
5883 if (!len)
5884 return;
5885
5886 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5887
5888 do {
5889 unsigned char c = *p++;
5890 if (c) {
5891 if (quotes & QUOTES_ESC) {
5892 int n = SIT(c, syntax);
5893 if (n == CCTL
5894 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5895 && n == CBACK
5896 )
5897 ) {
5898 USTPUTC(CTLESC, q);
5899 }
5900 }
5901 } else if (!(quotes & QUOTES_KEEPNUL))
5902 continue;
5903 USTPUTC(c, q);
5904 } while (--len);
5905
5906 expdest = q;
5907}
5908
5909static size_t
5910strtodest(const char *p, int syntax, int quotes)
5911{
5912 size_t len = strlen(p);
5913 memtodest(p, len, syntax, quotes);
5914 return len;
5915}
5916
5917/*
5918 * Record the fact that we have to scan this region of the
5919 * string for IFS characters.
5920 */
5921static void
5922recordregion(int start, int end, int nulonly)
5923{
5924 struct ifsregion *ifsp;
5925
5926 if (ifslastp == NULL) {
5927 ifsp = &ifsfirst;
5928 } else {
5929 INT_OFF;
5930 ifsp = ckzalloc(sizeof(*ifsp));
5931 /*ifsp->next = NULL; - ckzalloc did it */
5932 ifslastp->next = ifsp;
5933 INT_ON;
5934 }
5935 ifslastp = ifsp;
5936 ifslastp->begoff = start;
5937 ifslastp->endoff = end;
5938 ifslastp->nulonly = nulonly;
5939}
5940
5941static void
5942removerecordregions(int endoff)
5943{
5944 if (ifslastp == NULL)
5945 return;
5946
5947 if (ifsfirst.endoff > endoff) {
5948 while (ifsfirst.next) {
5949 struct ifsregion *ifsp;
5950 INT_OFF;
5951 ifsp = ifsfirst.next->next;
5952 free(ifsfirst.next);
5953 ifsfirst.next = ifsp;
5954 INT_ON;
5955 }
5956 if (ifsfirst.begoff > endoff) {
5957 ifslastp = NULL;
5958 } else {
5959 ifslastp = &ifsfirst;
5960 ifsfirst.endoff = endoff;
5961 }
5962 return;
5963 }
5964
5965 ifslastp = &ifsfirst;
5966 while (ifslastp->next && ifslastp->next->begoff < endoff)
5967 ifslastp = ifslastp->next;
5968 while (ifslastp->next) {
5969 struct ifsregion *ifsp;
5970 INT_OFF;
5971 ifsp = ifslastp->next->next;
5972 free(ifslastp->next);
5973 ifslastp->next = ifsp;
5974 INT_ON;
5975 }
5976 if (ifslastp->endoff > endoff)
5977 ifslastp->endoff = endoff;
5978}
5979
5980static char *
5981exptilde(char *startp, char *p, int flags)
5982{
5983 unsigned char c;
5984 char *name;
5985 struct passwd *pw;
5986 const char *home;
5987 int quotes = flags & QUOTES_ESC;
5988
5989 name = p + 1;
5990
5991 while ((c = *++p) != '\0') {
5992 switch (c) {
5993 case CTLESC:
5994 return startp;
5995 case CTLQUOTEMARK:
5996 return startp;
5997 case ':':
5998 if (flags & EXP_VARTILDE)
5999 goto done;
6000 break;
6001 case '/':
6002 case CTLENDVAR:
6003 goto done;
6004 }
6005 }
6006 done:
6007 *p = '\0';
6008 if (*name == '\0') {
6009 home = lookupvar("HOME");
6010 } else {
6011 pw = getpwnam(name);
6012 if (pw == NULL)
6013 goto lose;
6014 home = pw->pw_dir;
6015 }
6016 if (!home || !*home)
6017 goto lose;
6018 *p = c;
6019 strtodest(home, SQSYNTAX, quotes);
6020 return p;
6021 lose:
6022 *p = c;
6023 return startp;
6024}
6025
6026/*
6027 * Execute a command inside back quotes. If it's a builtin command, we
6028 * want to save its output in a block obtained from malloc. Otherwise
6029 * we fork off a subprocess and get the output of the command via a pipe.
6030 * Should be called with interrupts off.
6031 */
6032struct backcmd { /* result of evalbackcmd */
6033 int fd; /* file descriptor to read from */
6034 int nleft; /* number of chars in buffer */
6035 char *buf; /* buffer */
6036 struct job *jp; /* job structure for command */
6037};
6038
6039/* These forward decls are needed to use "eval" code for backticks handling: */
6040#define EV_EXIT 01 /* exit after evaluating tree */
6041static int evaltree(union node *, int);
6042
6043static void FAST_FUNC
6044evalbackcmd(union node *n, struct backcmd *result)
6045{
6046 int pip[2];
6047 struct job *jp;
6048
6049 result->fd = -1;
6050 result->buf = NULL;
6051 result->nleft = 0;
6052 result->jp = NULL;
6053 if (n == NULL) {
6054 goto out;
6055 }
6056
6057 if (pipe(pip) < 0)
6058 ash_msg_and_raise_error("pipe call failed");
6059 jp = makejob(/*n,*/ 1);
6060 if (forkshell(jp, n, FORK_NOJOB) == 0) {
6061 /* child */
6062 FORCE_INT_ON;
6063 close(pip[0]);
6064 if (pip[1] != 1) {
6065 /*close(1);*/
6066 dup2_or_raise(pip[1], 1);
6067 close(pip[1]);
6068 }
6069/* TODO: eflag clearing makes the following not abort:
6070 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6071 * which is what bash does (unless it is in POSIX mode).
6072 * dash deleted "eflag = 0" line in the commit
6073 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6074 * [EVAL] Don't clear eflag in evalbackcmd
6075 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6076 */
6077 eflag = 0;
6078 ifsfree();
6079 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6080 /* NOTREACHED */
6081 }
6082 /* parent */
6083 close(pip[1]);
6084 result->fd = pip[0];
6085 result->jp = jp;
6086
6087 out:
6088 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6089 result->fd, result->buf, result->nleft, result->jp));
6090}
6091
6092/*
6093 * Expand stuff in backwards quotes.
6094 */
6095static void
6096expbackq(union node *cmd, int flag)
6097{
6098 struct backcmd in;
6099 int i;
6100 char buf[128];
6101 char *p;
6102 char *dest;
6103 int startloc;
6104 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
6105 struct stackmark smark;
6106
6107 INT_OFF;
6108 startloc = expdest - (char *)stackblock();
6109 pushstackmark(&smark, startloc);
6110 evalbackcmd(cmd, &in);
6111 popstackmark(&smark);
6112
6113 p = in.buf;
6114 i = in.nleft;
6115 if (i == 0)
6116 goto read;
6117 for (;;) {
6118 memtodest(p, i, syntax, flag & QUOTES_ESC);
6119 read:
6120 if (in.fd < 0)
6121 break;
6122 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
6123 TRACE(("expbackq: read returns %d\n", i));
6124 if (i <= 0)
6125 break;
6126 p = buf;
6127 }
6128
6129 free(in.buf);
6130 if (in.fd >= 0) {
6131 close(in.fd);
6132 back_exitstatus = waitforjob(in.jp);
6133 }
6134 INT_ON;
6135
6136 /* Eat all trailing newlines */
6137 dest = expdest;
6138 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6139 STUNPUTC(dest);
6140 expdest = dest;
6141
6142 if (!(flag & EXP_QUOTED))
6143 recordregion(startloc, dest - (char *)stackblock(), 0);
6144 TRACE(("evalbackq: size:%d:'%.*s'\n",
6145 (int)((dest - (char *)stackblock()) - startloc),
6146 (int)((dest - (char *)stackblock()) - startloc),
6147 stackblock() + startloc));
6148}
6149
6150#if ENABLE_SH_MATH_SUPPORT
6151/*
6152 * Expand arithmetic expression. Backup to start of expression,
6153 * evaluate, place result in (backed up) result, adjust string position.
6154 */
6155static void
6156expari(int flag)
6157{
6158 char *p, *start;
6159 int begoff;
6160 int len;
6161
6162 /* ifsfree(); */
6163
6164 /*
6165 * This routine is slightly over-complicated for
6166 * efficiency. Next we scan backwards looking for the
6167 * start of arithmetic.
6168 */
6169 start = stackblock();
6170 p = expdest - 1;
6171 *p = '\0';
6172 p--;
6173 while (1) {
6174 int esc;
6175
6176 while ((unsigned char)*p != CTLARI) {
6177 p--;
6178#if DEBUG
6179 if (p < start) {
6180 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6181 }
6182#endif
6183 }
6184
6185 esc = esclen(start, p);
6186 if (!(esc % 2)) {
6187 break;
6188 }
6189
6190 p -= esc + 1;
6191 }
6192
6193 begoff = p - start;
6194
6195 removerecordregions(begoff);
6196
6197 expdest = p;
6198
6199 if (flag & QUOTES_ESC)
6200 rmescapes(p + 1, 0);
6201
6202 len = cvtnum(ash_arith(p + 1));
6203
6204 if (!(flag & EXP_QUOTED))
6205 recordregion(begoff, begoff + len, 0);
6206}
6207#endif
6208
6209/* argstr needs it */
6210static char *evalvar(char *p, int flags, struct strlist *var_str_list);
6211
6212/*
6213 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6214 * characters to allow for further processing. Otherwise treat
6215 * $@ like $* since no splitting will be performed.
6216 *
6217 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6218 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6219 * for correct expansion of "B=$A" word.
6220 */
6221static void
6222argstr(char *p, int flags, struct strlist *var_str_list)
6223{
6224 static const char spclchars[] ALIGN1 = {
6225 '=',
6226 ':',
6227 CTLQUOTEMARK,
6228 CTLENDVAR,
6229 CTLESC,
6230 CTLVAR,
6231 CTLBACKQ,
6232#if ENABLE_SH_MATH_SUPPORT
6233 CTLENDARI,
6234#endif
6235 '\0'
6236 };
6237 const char *reject = spclchars;
6238 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
6239 int inquotes;
6240 size_t length;
6241 int startloc;
6242
6243 if (!(flags & EXP_VARTILDE)) {
6244 reject += 2;
6245 } else if (flags & EXP_VARTILDE2) {
6246 reject++;
6247 }
6248 inquotes = 0;
6249 length = 0;
6250 if (flags & EXP_TILDE) {
6251 char *q;
6252
6253 flags &= ~EXP_TILDE;
6254 tilde:
6255 q = p;
6256 if (*q == '~')
6257 p = exptilde(p, q, flags);
6258 }
6259 start:
6260 startloc = expdest - (char *)stackblock();
6261 for (;;) {
6262 unsigned char c;
6263
6264 length += strcspn(p + length, reject);
6265 c = p[length];
6266 if (c) {
6267 if (!(c & 0x80)
6268 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
6269 ) {
6270 /* c == '=' || c == ':' || c == CTLENDARI */
6271 length++;
6272 }
6273 }
6274 if (length > 0) {
6275 int newloc;
6276 expdest = stack_nputstr(p, length, expdest);
6277 newloc = expdest - (char *)stackblock();
6278 if (breakall && !inquotes && newloc > startloc) {
6279 recordregion(startloc, newloc, 0);
6280 }
6281 startloc = newloc;
6282 }
6283 p += length + 1;
6284 length = 0;
6285
6286 switch (c) {
6287 case '\0':
6288 goto breakloop;
6289 case '=':
6290 if (flags & EXP_VARTILDE2) {
6291 p--;
6292 continue;
6293 }
6294 flags |= EXP_VARTILDE2;
6295 reject++;
6296 /* fall through */
6297 case ':':
6298 /*
6299 * sort of a hack - expand tildes in variable
6300 * assignments (after the first '=' and after ':'s).
6301 */
6302 if (*--p == '~') {
6303 goto tilde;
6304 }
6305 continue;
6306 }
6307
6308 switch (c) {
6309 case CTLENDVAR: /* ??? */
6310 goto breakloop;
6311 case CTLQUOTEMARK:
6312 inquotes ^= EXP_QUOTED;
6313 /* "$@" syntax adherence hack */
6314 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6315 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
6316 goto start;
6317 }
6318 addquote:
6319 if (flags & QUOTES_ESC) {
6320 p--;
6321 length++;
6322 startloc++;
6323 }
6324 break;
6325 case CTLESC:
6326 startloc++;
6327 length++;
6328
6329 /*
6330 * Quoted parameter expansion pattern: remove quote
6331 * unless inside inner quotes or we have a literal
6332 * backslash.
6333 */
6334 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6335 EXP_QPAT && *p != '\\')
6336 break;
6337
6338 goto addquote;
6339 case CTLVAR:
6340 TRACE(("argstr: evalvar('%s')\n", p));
6341 p = evalvar(p, flags | inquotes, var_str_list);
6342 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6343 goto start;
6344 case CTLBACKQ:
6345 expbackq(argbackq->n, flags | inquotes);
6346 argbackq = argbackq->next;
6347 goto start;
6348#if ENABLE_SH_MATH_SUPPORT
6349 case CTLENDARI:
6350 p--;
6351 expari(flags | inquotes);
6352 goto start;
6353#endif
6354 }
6355 }
6356 breakloop: ;
6357}
6358
6359static char *
6360scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6361 char *pattern, int quotes, int zero)
6362{
6363 char *loc, *loc2;
6364 char c;
6365
6366 loc = startp;
6367 loc2 = rmesc;
6368 do {
6369 int match;
6370 const char *s = loc2;
6371
6372 c = *loc2;
6373 if (zero) {
6374 *loc2 = '\0';
6375 s = rmesc;
6376 }
6377 match = pmatch(pattern, s);
6378
6379 *loc2 = c;
6380 if (match)
6381 return loc;
6382 if (quotes && (unsigned char)*loc == CTLESC)
6383 loc++;
6384 loc++;
6385 loc2++;
6386 } while (c);
6387 return NULL;
6388}
6389
6390static char *
6391scanright(char *startp, char *rmesc, char *rmescend,
6392 char *pattern, int quotes, int match_at_start)
6393{
6394#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6395 int try2optimize = match_at_start;
6396#endif
6397 int esc = 0;
6398 char *loc;
6399 char *loc2;
6400
6401 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6402 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6403 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6404 * Logic:
6405 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6406 * and on each iteration they go back two/one char until they reach the beginning.
6407 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6408 */
6409 /* TODO: document in what other circumstances we are called. */
6410
6411 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6412 int match;
6413 char c = *loc2;
6414 const char *s = loc2;
6415 if (match_at_start) {
6416 *loc2 = '\0';
6417 s = rmesc;
6418 }
6419 match = pmatch(pattern, s);
6420 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
6421 *loc2 = c;
6422 if (match)
6423 return loc;
6424#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6425 if (try2optimize) {
6426 /* Maybe we can optimize this:
6427 * if pattern ends with unescaped *, we can avoid checking
6428 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6429 * it wont match truncated "raw_value_of_" strings too.
6430 */
6431 unsigned plen = strlen(pattern);
6432 /* Does it end with "*"? */
6433 if (plen != 0 && pattern[--plen] == '*') {
6434 /* "xxxx*" is not escaped */
6435 /* "xxx\*" is escaped */
6436 /* "xx\\*" is not escaped */
6437 /* "x\\\*" is escaped */
6438 int slashes = 0;
6439 while (plen != 0 && pattern[--plen] == '\\')
6440 slashes++;
6441 if (!(slashes & 1))
6442 break; /* ends with unescaped "*" */
6443 }
6444 try2optimize = 0;
6445 }
6446#endif
6447 loc--;
6448 if (quotes) {
6449 if (--esc < 0) {
6450 esc = esclen(startp, loc);
6451 }
6452 if (esc % 2) {
6453 esc--;
6454 loc--;
6455 }
6456 }
6457 }
6458 return NULL;
6459}
6460
6461static void varunset(const char *, const char *, const char *, int) NORETURN;
6462static void
6463varunset(const char *end, const char *var, const char *umsg, int varflags)
6464{
6465 const char *msg;
6466 const char *tail;
6467
6468 tail = nullstr;
6469 msg = "parameter not set";
6470 if (umsg) {
6471 if ((unsigned char)*end == CTLENDVAR) {
6472 if (varflags & VSNUL)
6473 tail = " or null";
6474 } else {
6475 msg = umsg;
6476 }
6477 }
6478 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
6479}
6480
6481static const char *
6482subevalvar(char *p, char *varname, int strloc, int subtype,
6483 int startloc, int varflags, int flag, struct strlist *var_str_list)
6484{
6485 struct nodelist *saveargbackq = argbackq;
6486 int quotes = flag & QUOTES_ESC;
6487 char *startp;
6488 char *loc;
6489 char *rmesc, *rmescend;
6490 char *str;
6491 IF_ASH_BASH_COMPAT(char *repl = NULL;)
6492 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
6493 int amount, resetloc;
6494 IF_ASH_BASH_COMPAT(int workloc;)
6495 int zero;
6496 char *(*scan)(char*, char*, char*, char*, int, int);
6497
6498 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6499 // p, varname, strloc, subtype, startloc, varflags, quotes);
6500
6501 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
6502 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6503 var_str_list);
6504 STPUTC('\0', expdest);
6505 argbackq = saveargbackq;
6506 startp = (char *)stackblock() + startloc;
6507
6508 switch (subtype) {
6509 case VSASSIGN:
6510 setvar0(varname, startp);
6511 amount = startp - expdest;
6512 STADJUST(amount, expdest);
6513 return startp;
6514
6515 case VSQUESTION:
6516 varunset(p, varname, startp, varflags);
6517 /* NOTREACHED */
6518
6519#if ENABLE_ASH_BASH_COMPAT
6520 case VSSUBSTR:
6521//TODO: support more general format ${v:EXPR:EXPR},
6522// where EXPR follows $(()) rules
6523 loc = str = stackblock() + strloc;
6524 /* Read POS in ${var:POS:LEN} */
6525 pos = atoi(loc); /* number(loc) errors out on "1:4" */
6526 len = str - startp - 1;
6527
6528 /* *loc != '\0', guaranteed by parser */
6529 if (quotes) {
6530 char *ptr;
6531
6532 /* Adjust the length by the number of escapes */
6533 for (ptr = startp; ptr < (str - 1); ptr++) {
6534 if ((unsigned char)*ptr == CTLESC) {
6535 len--;
6536 ptr++;
6537 }
6538 }
6539 }
6540 orig_len = len;
6541
6542 if (*loc++ == ':') {
6543 /* ${var::LEN} */
6544 len = number(loc);
6545 } else {
6546 /* Skip POS in ${var:POS:LEN} */
6547 len = orig_len;
6548 while (*loc && *loc != ':') {
6549 /* TODO?
6550 * bash complains on: var=qwe; echo ${var:1a:123}
6551 if (!isdigit(*loc))
6552 ash_msg_and_raise_error(msg_illnum, str);
6553 */
6554 loc++;
6555 }
6556 if (*loc++ == ':') {
6557 len = number(loc);
6558 }
6559 }
6560 if (pos < 0) {
6561 /* ${VAR:$((-n)):l} starts n chars from the end */
6562 pos = orig_len + pos;
6563 }
6564 if ((unsigned)pos >= orig_len) {
6565 /* apart from obvious ${VAR:999999:l},
6566 * covers ${VAR:$((-9999999)):l} - result is ""
6567 * (bash-compat)
6568 */
6569 pos = 0;
6570 len = 0;
6571 }
6572 if (len > (orig_len - pos))
6573 len = orig_len - pos;
6574
6575 for (str = startp; pos; str++, pos--) {
6576 if (quotes && (unsigned char)*str == CTLESC)
6577 str++;
6578 }
6579 for (loc = startp; len; len--) {
6580 if (quotes && (unsigned char)*str == CTLESC)
6581 *loc++ = *str++;
6582 *loc++ = *str++;
6583 }
6584 *loc = '\0';
6585 amount = loc - expdest;
6586 STADJUST(amount, expdest);
6587 return loc;
6588#endif
6589 }
6590
6591 resetloc = expdest - (char *)stackblock();
6592
6593 /* We'll comeback here if we grow the stack while handling
6594 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6595 * stack will need rebasing, and we'll need to remove our work
6596 * areas each time
6597 */
6598 IF_ASH_BASH_COMPAT(restart:)
6599
6600 amount = expdest - ((char *)stackblock() + resetloc);
6601 STADJUST(-amount, expdest);
6602 startp = (char *)stackblock() + startloc;
6603
6604 rmesc = startp;
6605 rmescend = (char *)stackblock() + strloc;
6606 if (quotes) {
6607 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6608 if (rmesc != startp) {
6609 rmescend = expdest;
6610 startp = (char *)stackblock() + startloc;
6611 }
6612 }
6613 rmescend--;
6614 str = (char *)stackblock() + strloc;
6615 /*
6616 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6617 * The result is a_\_z_c (not a\_\_z_c)!
6618 *
6619 * The search pattern and replace string treat backslashes differently!
6620 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6621 * and string. It's only used on the first call.
6622 */
6623 preglob(str, IF_ASH_BASH_COMPAT(
6624 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6625 RMESCAPE_SLASH :) 0);
6626
6627#if ENABLE_ASH_BASH_COMPAT
6628 workloc = expdest - (char *)stackblock();
6629 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6630 char *idx, *end;
6631
6632 if (!repl) {
6633 repl = strchr(str, CTLESC);
6634 if (repl)
6635 *repl++ = '\0';
6636 else
6637 repl = nullstr;
6638 }
6639 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
6640
6641 /* If there's no pattern to match, return the expansion unmolested */
6642 if (str[0] == '\0')
6643 return NULL;
6644
6645 len = 0;
6646 idx = startp;
6647 end = str - 1;
6648 while (idx < end) {
6649 try_to_match:
6650 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6651 //bb_error_msg("scanright('%s'):'%s'", str, loc);
6652 if (!loc) {
6653 /* No match, advance */
6654 char *restart_detect = stackblock();
6655 skip_matching:
6656 STPUTC(*idx, expdest);
6657 if (quotes && (unsigned char)*idx == CTLESC) {
6658 idx++;
6659 len++;
6660 STPUTC(*idx, expdest);
6661 }
6662 if (stackblock() != restart_detect)
6663 goto restart;
6664 idx++;
6665 len++;
6666 rmesc++;
6667 /* continue; - prone to quadratic behavior, smarter code: */
6668 if (idx >= end)
6669 break;
6670 if (str[0] == '*') {
6671 /* Pattern is "*foo". If "*foo" does not match "long_string",
6672 * it would never match "ong_string" etc, no point in trying.
6673 */
6674 goto skip_matching;
6675 }
6676 goto try_to_match;
6677 }
6678
6679 if (subtype == VSREPLACEALL) {
6680 while (idx < loc) {
6681 if (quotes && (unsigned char)*idx == CTLESC)
6682 idx++;
6683 idx++;
6684 rmesc++;
6685 }
6686 } else {
6687 idx = loc;
6688 }
6689
6690 //bb_error_msg("repl:'%s'", repl);
6691 for (loc = (char*)repl; *loc; loc++) {
6692 char *restart_detect = stackblock();
6693 if (quotes && *loc == '\\') {
6694 STPUTC(CTLESC, expdest);
6695 len++;
6696 }
6697 STPUTC(*loc, expdest);
6698 if (stackblock() != restart_detect)
6699 goto restart;
6700 len++;
6701 }
6702
6703 if (subtype == VSREPLACE) {
6704 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
6705 while (*idx) {
6706 char *restart_detect = stackblock();
6707 STPUTC(*idx, expdest);
6708 if (stackblock() != restart_detect)
6709 goto restart;
6710 len++;
6711 idx++;
6712 }
6713 break;
6714 }
6715 }
6716
6717 /* We've put the replaced text into a buffer at workloc, now
6718 * move it to the right place and adjust the stack.
6719 */
6720 STPUTC('\0', expdest);
6721 startp = (char *)stackblock() + startloc;
6722 memmove(startp, (char *)stackblock() + workloc, len + 1);
6723 //bb_error_msg("startp:'%s'", startp);
6724 amount = expdest - (startp + len);
6725 STADJUST(-amount, expdest);
6726 return startp;
6727 }
6728#endif /* ENABLE_ASH_BASH_COMPAT */
6729
6730 subtype -= VSTRIMRIGHT;
6731#if DEBUG
6732 if (subtype < 0 || subtype > 7)
6733 abort();
6734#endif
6735 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
6736 zero = subtype >> 1;
6737 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6738 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6739
6740 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6741 if (loc) {
6742 if (zero) {
6743 memmove(startp, loc, str - loc);
6744 loc = startp + (str - loc) - 1;
6745 }
6746 *loc = '\0';
6747 amount = loc - expdest;
6748 STADJUST(amount, expdest);
6749 }
6750 return loc;
6751}
6752
6753/*
6754 * Add the value of a specialized variable to the stack string.
6755 * name parameter (examples):
6756 * ash -c 'echo $1' name:'1='
6757 * ash -c 'echo $qwe' name:'qwe='
6758 * ash -c 'echo $$' name:'$='
6759 * ash -c 'echo ${$}' name:'$='
6760 * ash -c 'echo ${$##q}' name:'$=q'
6761 * ash -c 'echo ${#$}' name:'$='
6762 * note: examples with bad shell syntax:
6763 * ash -c 'echo ${#$1}' name:'$=1'
6764 * ash -c 'echo ${#1#}' name:'1=#'
6765 */
6766static NOINLINE ssize_t
6767varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
6768{
6769 const char *p;
6770 int num;
6771 int i;
6772 ssize_t len = 0;
6773 int sep;
6774 int quoted = *quotedp;
6775 int subtype = varflags & VSTYPE;
6776 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6777 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
6778 int syntax;
6779
6780 sep = (flags & EXP_FULL) << CHAR_BIT;
6781 syntax = quoted ? DQSYNTAX : BASESYNTAX;
6782
6783 switch (*name) {
6784 case '$':
6785 num = rootpid;
6786 goto numvar;
6787 case '?':
6788 num = exitstatus;
6789 goto numvar;
6790 case '#':
6791 num = shellparam.nparam;
6792 goto numvar;
6793 case '!':
6794 num = backgndpid;
6795 if (num == 0)
6796 return -1;
6797 numvar:
6798 len = cvtnum(num);
6799 goto check_1char_name;
6800 case '-':
6801 expdest = makestrspace(NOPTS, expdest);
6802 for (i = NOPTS - 1; i >= 0; i--) {
6803 if (optlist[i]) {
6804 USTPUTC(optletters(i), expdest);
6805 len++;
6806 }
6807 }
6808 check_1char_name:
6809#if 0
6810 /* handles cases similar to ${#$1} */
6811 if (name[2] != '\0')
6812 raise_error_syntax("bad substitution");
6813#endif
6814 break;
6815 case '@':
6816 if (quoted && sep)
6817 goto param;
6818 /* fall through */
6819 case '*': {
6820 char **ap;
6821 char sepc;
6822
6823 if (quoted)
6824 sep = 0;
6825 sep |= ifsset() ? ifsval()[0] : ' ';
6826 param:
6827 sepc = sep;
6828 *quotedp = !sepc;
6829 ap = shellparam.p;
6830 if (!ap)
6831 return -1;
6832 while ((p = *ap++) != NULL) {
6833 len += strtodest(p, syntax, quotes);
6834
6835 if (*ap && sep) {
6836 len++;
6837 memtodest(&sepc, 1, syntax, quotes);
6838 }
6839 }
6840 break;
6841 } /* case '*' */
6842 case '0':
6843 case '1':
6844 case '2':
6845 case '3':
6846 case '4':
6847 case '5':
6848 case '6':
6849 case '7':
6850 case '8':
6851 case '9':
6852 num = atoi(name); /* number(name) fails on ${N#str} etc */
6853 if (num < 0 || num > shellparam.nparam)
6854 return -1;
6855 p = num ? shellparam.p[num - 1] : arg0;
6856 goto value;
6857 default:
6858 /* NB: name has form "VAR=..." */
6859
6860 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6861 * which should be considered before we check variables. */
6862 if (var_str_list) {
6863 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6864 p = NULL;
6865 do {
6866 char *str, *eq;
6867 str = var_str_list->text;
6868 eq = strchr(str, '=');
6869 if (!eq) /* stop at first non-assignment */
6870 break;
6871 eq++;
6872 if (name_len == (unsigned)(eq - str)
6873 && strncmp(str, name, name_len) == 0
6874 ) {
6875 p = eq;
6876 /* goto value; - WRONG! */
6877 /* think "A=1 A=2 B=$A" */
6878 }
6879 var_str_list = var_str_list->next;
6880 } while (var_str_list);
6881 if (p)
6882 goto value;
6883 }
6884 p = lookupvar(name);
6885 value:
6886 if (!p)
6887 return -1;
6888
6889 len = strtodest(p, syntax, quotes);
6890#if ENABLE_UNICODE_SUPPORT
6891 if (subtype == VSLENGTH && len > 0) {
6892 reinit_unicode_for_ash();
6893 if (unicode_status == UNICODE_ON) {
6894 STADJUST(-len, expdest);
6895 discard = 0;
6896 len = unicode_strlen(p);
6897 }
6898 }
6899#endif
6900 break;
6901 }
6902
6903 if (discard)
6904 STADJUST(-len, expdest);
6905 return len;
6906}
6907
6908/*
6909 * Expand a variable, and return a pointer to the next character in the
6910 * input string.
6911 */
6912static char *
6913evalvar(char *p, int flag, struct strlist *var_str_list)
6914{
6915 char varflags;
6916 char subtype;
6917 int quoted;
6918 char easy;
6919 char *var;
6920 int patloc;
6921 int startloc;
6922 ssize_t varlen;
6923
6924 varflags = (unsigned char) *p++;
6925 subtype = varflags & VSTYPE;
6926
6927 if (!subtype)
6928 raise_error_syntax("bad substitution");
6929
6930 quoted = flag & EXP_QUOTED;
6931 var = p;
6932 easy = (!quoted || (*var == '@' && shellparam.nparam));
6933 startloc = expdest - (char *)stackblock();
6934 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
6935
6936 again:
6937 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
6938 if (varflags & VSNUL)
6939 varlen--;
6940
6941 if (subtype == VSPLUS) {
6942 varlen = -1 - varlen;
6943 goto vsplus;
6944 }
6945
6946 if (subtype == VSMINUS) {
6947 vsplus:
6948 if (varlen < 0) {
6949 argstr(
6950 p,
6951 flag | EXP_TILDE | EXP_WORD,
6952 var_str_list
6953 );
6954 goto end;
6955 }
6956 goto record;
6957 }
6958
6959 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6960 if (varlen >= 0)
6961 goto record;
6962
6963 subevalvar(p, var, 0, subtype, startloc, varflags,
6964 flag & ~QUOTES_ESC, var_str_list);
6965 varflags &= ~VSNUL;
6966 /*
6967 * Remove any recorded regions beyond
6968 * start of variable
6969 */
6970 removerecordregions(startloc);
6971 goto again;
6972 }
6973
6974 if (varlen < 0 && uflag)
6975 varunset(p, var, 0, 0);
6976
6977 if (subtype == VSLENGTH) {
6978 cvtnum(varlen > 0 ? varlen : 0);
6979 goto record;
6980 }
6981
6982 if (subtype == VSNORMAL) {
6983 record:
6984 if (!easy)
6985 goto end;
6986 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6987 goto end;
6988 }
6989
6990#if DEBUG
6991 switch (subtype) {
6992 case VSTRIMLEFT:
6993 case VSTRIMLEFTMAX:
6994 case VSTRIMRIGHT:
6995 case VSTRIMRIGHTMAX:
6996#if ENABLE_ASH_BASH_COMPAT
6997 case VSSUBSTR:
6998 case VSREPLACE:
6999 case VSREPLACEALL:
7000#endif
7001 break;
7002 default:
7003 abort();
7004 }
7005#endif
7006
7007 if (varlen >= 0) {
7008 /*
7009 * Terminate the string and start recording the pattern
7010 * right after it
7011 */
7012 STPUTC('\0', expdest);
7013 patloc = expdest - (char *)stackblock();
7014 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
7015 startloc, varflags, flag, var_str_list)) {
7016 int amount = expdest - (
7017 (char *)stackblock() + patloc - 1
7018 );
7019 STADJUST(-amount, expdest);
7020 }
7021 /* Remove any recorded regions beyond start of variable */
7022 removerecordregions(startloc);
7023 goto record;
7024 }
7025
7026 end:
7027 if (subtype != VSNORMAL) { /* skip to end of alternative */
7028 int nesting = 1;
7029 for (;;) {
7030 unsigned char c = *p++;
7031 if (c == CTLESC)
7032 p++;
7033 else if (c == CTLBACKQ) {
7034 if (varlen >= 0)
7035 argbackq = argbackq->next;
7036 } else if (c == CTLVAR) {
7037 if ((*p++ & VSTYPE) != VSNORMAL)
7038 nesting++;
7039 } else if (c == CTLENDVAR) {
7040 if (--nesting == 0)
7041 break;
7042 }
7043 }
7044 }
7045 return p;
7046}
7047
7048/*
7049 * Add a file name to the list.
7050 */
7051static void
7052addfname(const char *name)
7053{
7054 struct strlist *sp;
7055
7056 sp = stzalloc(sizeof(*sp));
7057 sp->text = sstrdup(name);
7058 *exparg.lastp = sp;
7059 exparg.lastp = &sp->next;
7060}
7061
7062/* If we want to use glob() from libc... */
7063#if !ENABLE_ASH_INTERNAL_GLOB
7064
7065/* Add the result of glob() to the list */
7066static void
7067addglob(const glob_t *pglob)
7068{
7069 char **p = pglob->gl_pathv;
7070
7071 do {
7072 addfname(*p);
7073 } while (*++p);
7074}
7075static void
7076expandmeta(struct strlist *str /*, int flag*/)
7077{
7078 /* TODO - EXP_REDIR */
7079
7080 while (str) {
7081 char *p;
7082 glob_t pglob;
7083 int i;
7084
7085 if (fflag)
7086 goto nometa;
7087
7088 /* Avoid glob() (and thus, stat() et al) for words like "echo" */
7089 p = str->text;
7090 while (*p) {
7091 if (*p == '*')
7092 goto need_glob;
7093 if (*p == '?')
7094 goto need_glob;
7095 if (*p == '[')
7096 goto need_glob;
7097 p++;
7098 }
7099 goto nometa;
7100
7101 need_glob:
7102 INT_OFF;
7103 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7104// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7105// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7106//
7107// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7108// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7109// Which means you need to unescape the string, right? Not so fast:
7110// if there _is_ a file named "file\?" (with backslash), it is returned
7111// as "file\?" too (whichever pattern you used to find it, say, "file*").
7112// You DONT KNOW by looking at the result whether you need to unescape it.
7113//
7114// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7115// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7116// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7117// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7118// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7119// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7120 i = glob(p, 0, NULL, &pglob);
7121 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
7122 if (p != str->text)
7123 free(p);
7124 switch (i) {
7125 case 0:
7126#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
7127 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7128 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7129 goto nometa2;
7130#endif
7131 addglob(&pglob);
7132 globfree(&pglob);
7133 INT_ON;
7134 break;
7135 case GLOB_NOMATCH:
7136 //nometa2:
7137 globfree(&pglob);
7138 INT_ON;
7139 nometa:
7140 *exparg.lastp = str;
7141 rmescapes(str->text, 0);
7142 exparg.lastp = &str->next;
7143 break;
7144 default: /* GLOB_NOSPACE */
7145 globfree(&pglob);
7146 INT_ON;
7147 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7148 }
7149 str = str->next;
7150 }
7151}
7152
7153#else
7154/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
7155
7156/*
7157 * Do metacharacter (i.e. *, ?, [...]) expansion.
7158 */
7159static void
7160expmeta(char *expdir, char *enddir, char *name)
7161{
7162 char *p;
7163 const char *cp;
7164 char *start;
7165 char *endname;
7166 int metaflag;
7167 struct stat statb;
7168 DIR *dirp;
7169 struct dirent *dp;
7170 int atend;
7171 int matchdot;
7172 int esc;
7173
7174 metaflag = 0;
7175 start = name;
7176 for (p = name; esc = 0, *p; p += esc + 1) {
7177 if (*p == '*' || *p == '?')
7178 metaflag = 1;
7179 else if (*p == '[') {
7180 char *q = p + 1;
7181 if (*q == '!')
7182 q++;
7183 for (;;) {
7184 if (*q == '\\')
7185 q++;
7186 if (*q == '/' || *q == '\0')
7187 break;
7188 if (*++q == ']') {
7189 metaflag = 1;
7190 break;
7191 }
7192 }
7193 } else {
7194 if (*p == '\\')
7195 esc++;
7196 if (p[esc] == '/') {
7197 if (metaflag)
7198 break;
7199 start = p + esc + 1;
7200 }
7201 }
7202 }
7203 if (metaflag == 0) { /* we've reached the end of the file name */
7204 if (enddir != expdir)
7205 metaflag++;
7206 p = name;
7207 do {
7208 if (*p == '\\')
7209 p++;
7210 *enddir++ = *p;
7211 } while (*p++);
7212 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7213 addfname(expdir);
7214 return;
7215 }
7216 endname = p;
7217 if (name < start) {
7218 p = name;
7219 do {
7220 if (*p == '\\')
7221 p++;
7222 *enddir++ = *p++;
7223 } while (p < start);
7224 }
7225 if (enddir == expdir) {
7226 cp = ".";
7227 } else if (enddir == expdir + 1 && *expdir == '/') {
7228 cp = "/";
7229 } else {
7230 cp = expdir;
7231 enddir[-1] = '\0';
7232 }
7233 dirp = opendir(cp);
7234 if (dirp == NULL)
7235 return;
7236 if (enddir != expdir)
7237 enddir[-1] = '/';
7238 if (*endname == 0) {
7239 atend = 1;
7240 } else {
7241 atend = 0;
7242 *endname = '\0';
7243 endname += esc + 1;
7244 }
7245 matchdot = 0;
7246 p = start;
7247 if (*p == '\\')
7248 p++;
7249 if (*p == '.')
7250 matchdot++;
7251 while (!pending_int && (dp = readdir(dirp)) != NULL) {
7252 if (dp->d_name[0] == '.' && !matchdot)
7253 continue;
7254 if (pmatch(start, dp->d_name)) {
7255 if (atend) {
7256 strcpy(enddir, dp->d_name);
7257 addfname(expdir);
7258 } else {
7259 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7260 continue;
7261 p[-1] = '/';
7262 expmeta(expdir, p, endname);
7263 }
7264 }
7265 }
7266 closedir(dirp);
7267 if (!atend)
7268 endname[-esc - 1] = esc ? '\\' : '/';
7269}
7270
7271static struct strlist *
7272msort(struct strlist *list, int len)
7273{
7274 struct strlist *p, *q = NULL;
7275 struct strlist **lpp;
7276 int half;
7277 int n;
7278
7279 if (len <= 1)
7280 return list;
7281 half = len >> 1;
7282 p = list;
7283 for (n = half; --n >= 0;) {
7284 q = p;
7285 p = p->next;
7286 }
7287 q->next = NULL; /* terminate first half of list */
7288 q = msort(list, half); /* sort first half of list */
7289 p = msort(p, len - half); /* sort second half */
7290 lpp = &list;
7291 for (;;) {
7292#if ENABLE_LOCALE_SUPPORT
7293 if (strcoll(p->text, q->text) < 0)
7294#else
7295 if (strcmp(p->text, q->text) < 0)
7296#endif
7297 {
7298 *lpp = p;
7299 lpp = &p->next;
7300 p = *lpp;
7301 if (p == NULL) {
7302 *lpp = q;
7303 break;
7304 }
7305 } else {
7306 *lpp = q;
7307 lpp = &q->next;
7308 q = *lpp;
7309 if (q == NULL) {
7310 *lpp = p;
7311 break;
7312 }
7313 }
7314 }
7315 return list;
7316}
7317
7318/*
7319 * Sort the results of file name expansion. It calculates the number of
7320 * strings to sort and then calls msort (short for merge sort) to do the
7321 * work.
7322 */
7323static struct strlist *
7324expsort(struct strlist *str)
7325{
7326 int len;
7327 struct strlist *sp;
7328
7329 len = 0;
7330 for (sp = str; sp; sp = sp->next)
7331 len++;
7332 return msort(str, len);
7333}
7334
7335static void
7336expandmeta(struct strlist *str /*, int flag*/)
7337{
7338 static const char metachars[] ALIGN1 = {
7339 '*', '?', '[', 0
7340 };
7341 /* TODO - EXP_REDIR */
7342
7343 while (str) {
7344 char *expdir;
7345 struct strlist **savelastp;
7346 struct strlist *sp;
7347 char *p;
7348
7349 if (fflag)
7350 goto nometa;
7351 if (!strpbrk(str->text, metachars))
7352 goto nometa;
7353 savelastp = exparg.lastp;
7354
7355 INT_OFF;
7356 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7357 {
7358 int i = strlen(str->text);
7359//BUGGY estimation of how long expanded name can be
7360 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
7361 }
7362 expmeta(expdir, expdir, p);
7363 free(expdir);
7364 if (p != str->text)
7365 free(p);
7366 INT_ON;
7367 if (exparg.lastp == savelastp) {
7368 /*
7369 * no matches
7370 */
7371 nometa:
7372 *exparg.lastp = str;
7373 rmescapes(str->text, 0);
7374 exparg.lastp = &str->next;
7375 } else {
7376 *exparg.lastp = NULL;
7377 *savelastp = sp = expsort(*savelastp);
7378 while (sp->next != NULL)
7379 sp = sp->next;
7380 exparg.lastp = &sp->next;
7381 }
7382 str = str->next;
7383 }
7384}
7385#endif /* ENABLE_ASH_INTERNAL_GLOB */
7386
7387/*
7388 * Perform variable substitution and command substitution on an argument,
7389 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7390 * perform splitting and file name expansion. When arglist is NULL, perform
7391 * here document expansion.
7392 */
7393static void
7394expandarg(union node *arg, struct arglist *arglist, int flag)
7395{
7396 struct strlist *sp;
7397 char *p;
7398
7399 argbackq = arg->narg.backquote;
7400 STARTSTACKSTR(expdest);
7401 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
7402 argstr(arg->narg.text, flag,
7403 /* var_str_list: */ arglist ? arglist->list : NULL);
7404 p = _STPUTC('\0', expdest);
7405 expdest = p - 1;
7406 if (arglist == NULL) {
7407 /* here document expanded */
7408 goto out;
7409 }
7410 p = grabstackstr(p);
7411 TRACE(("expandarg: p:'%s'\n", p));
7412 exparg.lastp = &exparg.list;
7413 /*
7414 * TODO - EXP_REDIR
7415 */
7416 if (flag & EXP_FULL) {
7417 ifsbreakup(p, &exparg);
7418 *exparg.lastp = NULL;
7419 exparg.lastp = &exparg.list;
7420 expandmeta(exparg.list /*, flag*/);
7421 } else {
7422 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
7423 rmescapes(p, 0);
7424 TRACE(("expandarg: rmescapes:'%s'\n", p));
7425 }
7426 sp = stzalloc(sizeof(*sp));
7427 sp->text = p;
7428 *exparg.lastp = sp;
7429 exparg.lastp = &sp->next;
7430 }
7431 *exparg.lastp = NULL;
7432 if (exparg.list) {
7433 *arglist->lastp = exparg.list;
7434 arglist->lastp = exparg.lastp;
7435 }
7436
7437 out:
7438 ifsfree();
7439}
7440
7441/*
7442 * Expand shell variables and backquotes inside a here document.
7443 */
7444static void
7445expandhere(union node *arg, int fd)
7446{
7447 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
7448 full_write(fd, stackblock(), expdest - (char *)stackblock());
7449}
7450
7451/*
7452 * Returns true if the pattern matches the string.
7453 */
7454static int
7455patmatch(char *pattern, const char *string)
7456{
7457 return pmatch(preglob(pattern, 0), string);
7458}
7459
7460/*
7461 * See if a pattern matches in a case statement.
7462 */
7463static int
7464casematch(union node *pattern, char *val)
7465{
7466 struct stackmark smark;
7467 int result;
7468
7469 setstackmark(&smark);
7470 argbackq = pattern->narg.backquote;
7471 STARTSTACKSTR(expdest);
7472 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7473 /* var_str_list: */ NULL);
7474 STACKSTRNUL(expdest);
7475 ifsfree();
7476 result = patmatch(stackblock(), val);
7477 popstackmark(&smark);
7478 return result;
7479}
7480
7481
7482/* ============ find_command */
7483
7484struct builtincmd {
7485 const char *name;
7486 int (*builtin)(int, char **) FAST_FUNC;
7487 /* unsigned flags; */
7488};
7489#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
7490/* "regular" builtins always take precedence over commands,
7491 * regardless of PATH=....%builtin... position */
7492#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
7493#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
7494
7495struct cmdentry {
7496 smallint cmdtype; /* CMDxxx */
7497 union param {
7498 int index;
7499 /* index >= 0 for commands without path (slashes) */
7500 /* (TODO: what exactly does the value mean? PATH position?) */
7501 /* index == -1 for commands with slashes */
7502 /* index == (-2 - applet_no) for NOFORK applets */
7503 const struct builtincmd *cmd;
7504 struct funcnode *func;
7505 } u;
7506};
7507/* values of cmdtype */
7508#define CMDUNKNOWN -1 /* no entry in table for command */
7509#define CMDNORMAL 0 /* command is an executable program */
7510#define CMDFUNCTION 1 /* command is a shell function */
7511#define CMDBUILTIN 2 /* command is a shell builtin */
7512
7513/* action to find_command() */
7514#define DO_ERR 0x01 /* prints errors */
7515#define DO_ABS 0x02 /* checks absolute paths */
7516#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7517#define DO_ALTPATH 0x08 /* using alternate path */
7518#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7519
7520static void find_command(char *, struct cmdentry *, int, const char *);
7521
7522
7523/* ============ Hashing commands */
7524
7525/*
7526 * When commands are first encountered, they are entered in a hash table.
7527 * This ensures that a full path search will not have to be done for them
7528 * on each invocation.
7529 *
7530 * We should investigate converting to a linear search, even though that
7531 * would make the command name "hash" a misnomer.
7532 */
7533
7534struct tblentry {
7535 struct tblentry *next; /* next entry in hash chain */
7536 union param param; /* definition of builtin function */
7537 smallint cmdtype; /* CMDxxx */
7538 char rehash; /* if set, cd done since entry created */
7539 char cmdname[1]; /* name of command */
7540};
7541
7542static struct tblentry **cmdtable;
7543#define INIT_G_cmdtable() do { \
7544 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7545} while (0)
7546
7547static int builtinloc = -1; /* index in path of %builtin, or -1 */
7548
7549
7550static void
7551tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
7552{
7553#if ENABLE_FEATURE_SH_STANDALONE
7554 if (applet_no >= 0) {
7555 if (APPLET_IS_NOEXEC(applet_no)) {
7556 clearenv();
7557 while (*envp)
7558 putenv(*envp++);
7559 run_applet_no_and_exit(applet_no, argv);
7560 }
7561 /* re-exec ourselves with the new arguments */
7562 execve(bb_busybox_exec_path, argv, envp);
7563 /* If they called chroot or otherwise made the binary no longer
7564 * executable, fall through */
7565 }
7566#endif
7567
7568 repeat:
7569#ifdef SYSV
7570 do {
7571 execve(cmd, argv, envp);
7572 } while (errno == EINTR);
7573#else
7574 execve(cmd, argv, envp);
7575#endif
7576 if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
7577 /* Run "cmd" as a shell script:
7578 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7579 * "If the execve() function fails with ENOEXEC, the shell
7580 * shall execute a command equivalent to having a shell invoked
7581 * with the command name as its first operand,
7582 * with any remaining arguments passed to the new shell"
7583 *
7584 * That is, do not use $SHELL, user's shell, or /bin/sh;
7585 * just call ourselves.
7586 *
7587 * Note that bash reads ~80 chars of the file, and if it sees
7588 * a zero byte before it sees newline, it doesn't try to
7589 * interpret it, but fails with "cannot execute binary file"
7590 * message and exit code 126. For one, this prevents attempts
7591 * to interpret foreign ELF binaries as shell scripts.
7592 */
7593 argv[0] = cmd;
7594 cmd = (char*) bb_busybox_exec_path;
7595 /* NB: this is only possible because all callers of shellexec()
7596 * ensure that the argv[-1] slot exists!
7597 */
7598 argv--;
7599 argv[0] = (char*) "ash";
7600 goto repeat;
7601 }
7602}
7603
7604/*
7605 * Exec a program. Never returns. If you change this routine, you may
7606 * have to change the find_command routine as well.
7607 * argv[-1] must exist and be writable! See tryexec() for why.
7608 */
7609static void shellexec(char **, const char *, int) NORETURN;
7610static void
7611shellexec(char **argv, const char *path, int idx)
7612{
7613 char *cmdname;
7614 int e;
7615 char **envp;
7616 int exerrno;
7617 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
7618
7619 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7620 if (strchr(argv[0], '/') != NULL
7621#if ENABLE_FEATURE_SH_STANDALONE
7622 || (applet_no = find_applet_by_name(argv[0])) >= 0
7623#endif
7624 ) {
7625 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7626 if (applet_no >= 0) {
7627 /* We tried execing ourself, but it didn't work.
7628 * Maybe /proc/self/exe doesn't exist?
7629 * Try $PATH search.
7630 */
7631 goto try_PATH;
7632 }
7633 e = errno;
7634 } else {
7635 try_PATH:
7636 e = ENOENT;
7637 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
7638 if (--idx < 0 && pathopt == NULL) {
7639 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7640 if (errno != ENOENT && errno != ENOTDIR)
7641 e = errno;
7642 }
7643 stunalloc(cmdname);
7644 }
7645 }
7646
7647 /* Map to POSIX errors */
7648 switch (e) {
7649 case EACCES:
7650 exerrno = 126;
7651 break;
7652 case ENOENT:
7653 exerrno = 127;
7654 break;
7655 default:
7656 exerrno = 2;
7657 break;
7658 }
7659 exitstatus = exerrno;
7660 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7661 argv[0], e, suppress_int));
7662 ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found"));
7663 /* NOTREACHED */
7664}
7665
7666static void
7667printentry(struct tblentry *cmdp)
7668{
7669 int idx;
7670 const char *path;
7671 char *name;
7672
7673 idx = cmdp->param.index;
7674 path = pathval();
7675 do {
7676 name = path_advance(&path, cmdp->cmdname);
7677 stunalloc(name);
7678 } while (--idx >= 0);
7679 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7680}
7681
7682/*
7683 * Clear out command entries. The argument specifies the first entry in
7684 * PATH which has changed.
7685 */
7686static void
7687clearcmdentry(int firstchange)
7688{
7689 struct tblentry **tblp;
7690 struct tblentry **pp;
7691 struct tblentry *cmdp;
7692
7693 INT_OFF;
7694 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7695 pp = tblp;
7696 while ((cmdp = *pp) != NULL) {
7697 if ((cmdp->cmdtype == CMDNORMAL &&
7698 cmdp->param.index >= firstchange)
7699 || (cmdp->cmdtype == CMDBUILTIN &&
7700 builtinloc >= firstchange)
7701 ) {
7702 *pp = cmdp->next;
7703 free(cmdp);
7704 } else {
7705 pp = &cmdp->next;
7706 }
7707 }
7708 }
7709 INT_ON;
7710}
7711
7712/*
7713 * Locate a command in the command hash table. If "add" is nonzero,
7714 * add the command to the table if it is not already present. The
7715 * variable "lastcmdentry" is set to point to the address of the link
7716 * pointing to the entry, so that delete_cmd_entry can delete the
7717 * entry.
7718 *
7719 * Interrupts must be off if called with add != 0.
7720 */
7721static struct tblentry **lastcmdentry;
7722
7723static struct tblentry *
7724cmdlookup(const char *name, int add)
7725{
7726 unsigned int hashval;
7727 const char *p;
7728 struct tblentry *cmdp;
7729 struct tblentry **pp;
7730
7731 p = name;
7732 hashval = (unsigned char)*p << 4;
7733 while (*p)
7734 hashval += (unsigned char)*p++;
7735 hashval &= 0x7FFF;
7736 pp = &cmdtable[hashval % CMDTABLESIZE];
7737 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7738 if (strcmp(cmdp->cmdname, name) == 0)
7739 break;
7740 pp = &cmdp->next;
7741 }
7742 if (add && cmdp == NULL) {
7743 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7744 + strlen(name)
7745 /* + 1 - already done because
7746 * tblentry::cmdname is char[1] */);
7747 /*cmdp->next = NULL; - ckzalloc did it */
7748 cmdp->cmdtype = CMDUNKNOWN;
7749 strcpy(cmdp->cmdname, name);
7750 }
7751 lastcmdentry = pp;
7752 return cmdp;
7753}
7754
7755/*
7756 * Delete the command entry returned on the last lookup.
7757 */
7758static void
7759delete_cmd_entry(void)
7760{
7761 struct tblentry *cmdp;
7762
7763 INT_OFF;
7764 cmdp = *lastcmdentry;
7765 *lastcmdentry = cmdp->next;
7766 if (cmdp->cmdtype == CMDFUNCTION)
7767 freefunc(cmdp->param.func);
7768 free(cmdp);
7769 INT_ON;
7770}
7771
7772/*
7773 * Add a new command entry, replacing any existing command entry for
7774 * the same name - except special builtins.
7775 */
7776static void
7777addcmdentry(char *name, struct cmdentry *entry)
7778{
7779 struct tblentry *cmdp;
7780
7781 cmdp = cmdlookup(name, 1);
7782 if (cmdp->cmdtype == CMDFUNCTION) {
7783 freefunc(cmdp->param.func);
7784 }
7785 cmdp->cmdtype = entry->cmdtype;
7786 cmdp->param = entry->u;
7787 cmdp->rehash = 0;
7788}
7789
7790static int FAST_FUNC
7791hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7792{
7793 struct tblentry **pp;
7794 struct tblentry *cmdp;
7795 int c;
7796 struct cmdentry entry;
7797 char *name;
7798
7799 if (nextopt("r") != '\0') {
7800 clearcmdentry(0);
7801 return 0;
7802 }
7803
7804 if (*argptr == NULL) {
7805 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7806 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7807 if (cmdp->cmdtype == CMDNORMAL)
7808 printentry(cmdp);
7809 }
7810 }
7811 return 0;
7812 }
7813
7814 c = 0;
7815 while ((name = *argptr) != NULL) {
7816 cmdp = cmdlookup(name, 0);
7817 if (cmdp != NULL
7818 && (cmdp->cmdtype == CMDNORMAL
7819 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7820 ) {
7821 delete_cmd_entry();
7822 }
7823 find_command(name, &entry, DO_ERR, pathval());
7824 if (entry.cmdtype == CMDUNKNOWN)
7825 c = 1;
7826 argptr++;
7827 }
7828 return c;
7829}
7830
7831/*
7832 * Called when a cd is done. Marks all commands so the next time they
7833 * are executed they will be rehashed.
7834 */
7835static void
7836hashcd(void)
7837{
7838 struct tblentry **pp;
7839 struct tblentry *cmdp;
7840
7841 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7842 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7843 if (cmdp->cmdtype == CMDNORMAL
7844 || (cmdp->cmdtype == CMDBUILTIN
7845 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7846 && builtinloc > 0)
7847 ) {
7848 cmdp->rehash = 1;
7849 }
7850 }
7851 }
7852}
7853
7854/*
7855 * Fix command hash table when PATH changed.
7856 * Called before PATH is changed. The argument is the new value of PATH;
7857 * pathval() still returns the old value at this point.
7858 * Called with interrupts off.
7859 */
7860static void FAST_FUNC
7861changepath(const char *new)
7862{
7863 const char *old;
7864 int firstchange;
7865 int idx;
7866 int idx_bltin;
7867
7868 old = pathval();
7869 firstchange = 9999; /* assume no change */
7870 idx = 0;
7871 idx_bltin = -1;
7872 for (;;) {
7873 if (*old != *new) {
7874 firstchange = idx;
7875 if ((*old == '\0' && *new == ':')
7876 || (*old == ':' && *new == '\0')
7877 ) {
7878 firstchange++;
7879 }
7880 old = new; /* ignore subsequent differences */
7881 }
7882 if (*new == '\0')
7883 break;
7884 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7885 idx_bltin = idx;
7886 if (*new == ':')
7887 idx++;
7888 new++;
7889 old++;
7890 }
7891 if (builtinloc < 0 && idx_bltin >= 0)
7892 builtinloc = idx_bltin; /* zap builtins */
7893 if (builtinloc >= 0 && idx_bltin < 0)
7894 firstchange = 0;
7895 clearcmdentry(firstchange);
7896 builtinloc = idx_bltin;
7897}
7898enum {
7899 TEOF,
7900 TNL,
7901 TREDIR,
7902 TWORD,
7903 TSEMI,
7904 TBACKGND,
7905 TAND,
7906 TOR,
7907 TPIPE,
7908 TLP,
7909 TRP,
7910 TENDCASE,
7911 TENDBQUOTE,
7912 TNOT,
7913 TCASE,
7914 TDO,
7915 TDONE,
7916 TELIF,
7917 TELSE,
7918 TESAC,
7919 TFI,
7920 TFOR,
7921#if ENABLE_ASH_BASH_COMPAT
7922 TFUNCTION,
7923#endif
7924 TIF,
7925 TIN,
7926 TTHEN,
7927 TUNTIL,
7928 TWHILE,
7929 TBEGIN,
7930 TEND
7931};
7932typedef smallint token_id_t;
7933
7934/* Nth bit indicates if token marks the end of a list */
7935enum {
7936 tokendlist = 0
7937 /* 0 */ | (1u << TEOF)
7938 /* 1 */ | (0u << TNL)
7939 /* 2 */ | (0u << TREDIR)
7940 /* 3 */ | (0u << TWORD)
7941 /* 4 */ | (0u << TSEMI)
7942 /* 5 */ | (0u << TBACKGND)
7943 /* 6 */ | (0u << TAND)
7944 /* 7 */ | (0u << TOR)
7945 /* 8 */ | (0u << TPIPE)
7946 /* 9 */ | (0u << TLP)
7947 /* 10 */ | (1u << TRP)
7948 /* 11 */ | (1u << TENDCASE)
7949 /* 12 */ | (1u << TENDBQUOTE)
7950 /* 13 */ | (0u << TNOT)
7951 /* 14 */ | (0u << TCASE)
7952 /* 15 */ | (1u << TDO)
7953 /* 16 */ | (1u << TDONE)
7954 /* 17 */ | (1u << TELIF)
7955 /* 18 */ | (1u << TELSE)
7956 /* 19 */ | (1u << TESAC)
7957 /* 20 */ | (1u << TFI)
7958 /* 21 */ | (0u << TFOR)
7959#if ENABLE_ASH_BASH_COMPAT
7960 /* 22 */ | (0u << TFUNCTION)
7961#endif
7962 /* 23 */ | (0u << TIF)
7963 /* 24 */ | (0u << TIN)
7964 /* 25 */ | (1u << TTHEN)
7965 /* 26 */ | (0u << TUNTIL)
7966 /* 27 */ | (0u << TWHILE)
7967 /* 28 */ | (0u << TBEGIN)
7968 /* 29 */ | (1u << TEND)
7969 , /* thus far 29 bits used */
7970};
7971
7972static const char *const tokname_array[] = {
7973 "end of file",
7974 "newline",
7975 "redirection",
7976 "word",
7977 ";",
7978 "&",
7979 "&&",
7980 "||",
7981 "|",
7982 "(",
7983 ")",
7984 ";;",
7985 "`",
7986#define KWDOFFSET 13
7987 /* the following are keywords */
7988 "!",
7989 "case",
7990 "do",
7991 "done",
7992 "elif",
7993 "else",
7994 "esac",
7995 "fi",
7996 "for",
7997#if ENABLE_ASH_BASH_COMPAT
7998 "function",
7999#endif
8000 "if",
8001 "in",
8002 "then",
8003 "until",
8004 "while",
8005 "{",
8006 "}",
8007};
8008
8009/* Wrapper around strcmp for qsort/bsearch/... */
8010static int
8011pstrcmp(const void *a, const void *b)
8012{
8013 return strcmp((char*)a, *(char**)b);
8014}
8015
8016static const char *const *
8017findkwd(const char *s)
8018{
8019 return bsearch(s, tokname_array + KWDOFFSET,
8020 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8021 sizeof(tokname_array[0]), pstrcmp);
8022}
8023
8024/*
8025 * Locate and print what a word is...
8026 */
8027static int
8028describe_command(char *command, const char *path, int describe_command_verbose)
8029{
8030 struct cmdentry entry;
8031 struct tblentry *cmdp;
8032#if ENABLE_ASH_ALIAS
8033 const struct alias *ap;
8034#endif
8035
8036 path = path ? path : pathval();
8037
8038 if (describe_command_verbose) {
8039 out1str(command);
8040 }
8041
8042 /* First look at the keywords */
8043 if (findkwd(command)) {
8044 out1str(describe_command_verbose ? " is a shell keyword" : command);
8045 goto out;
8046 }
8047
8048#if ENABLE_ASH_ALIAS
8049 /* Then look at the aliases */
8050 ap = lookupalias(command, 0);
8051 if (ap != NULL) {
8052 if (!describe_command_verbose) {
8053 out1str("alias ");
8054 printalias(ap);
8055 return 0;
8056 }
8057 out1fmt(" is an alias for %s", ap->val);
8058 goto out;
8059 }
8060#endif
8061 /* Then check if it is a tracked alias */
8062 cmdp = cmdlookup(command, 0);
8063 if (cmdp != NULL) {
8064 entry.cmdtype = cmdp->cmdtype;
8065 entry.u = cmdp->param;
8066 } else {
8067 /* Finally use brute force */
8068 find_command(command, &entry, DO_ABS, path);
8069 }
8070
8071 switch (entry.cmdtype) {
8072 case CMDNORMAL: {
8073 int j = entry.u.index;
8074 char *p;
8075 if (j < 0) {
8076 p = command;
8077 } else {
8078 do {
8079 p = path_advance(&path, command);
8080 stunalloc(p);
8081 } while (--j >= 0);
8082 }
8083 if (describe_command_verbose) {
8084 out1fmt(" is%s %s",
8085 (cmdp ? " a tracked alias for" : nullstr), p
8086 );
8087 } else {
8088 out1str(p);
8089 }
8090 break;
8091 }
8092
8093 case CMDFUNCTION:
8094 if (describe_command_verbose) {
8095 out1str(" is a shell function");
8096 } else {
8097 out1str(command);
8098 }
8099 break;
8100
8101 case CMDBUILTIN:
8102 if (describe_command_verbose) {
8103 out1fmt(" is a %sshell builtin",
8104 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8105 "special " : nullstr
8106 );
8107 } else {
8108 out1str(command);
8109 }
8110 break;
8111
8112 default:
8113 if (describe_command_verbose) {
8114 out1str(": not found\n");
8115 }
8116 return 127;
8117 }
8118 out:
8119 out1str("\n");
8120 return 0;
8121}
8122
8123static int FAST_FUNC
8124typecmd(int argc UNUSED_PARAM, char **argv)
8125{
8126 int i = 1;
8127 int err = 0;
8128 int verbose = 1;
8129
8130 /* type -p ... ? (we don't bother checking for 'p') */
8131 if (argv[1] && argv[1][0] == '-') {
8132 i++;
8133 verbose = 0;
8134 }
8135 while (argv[i]) {
8136 err |= describe_command(argv[i++], NULL, verbose);
8137 }
8138 return err;
8139}
8140
8141#if ENABLE_ASH_CMDCMD
8142/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8143static char **
8144parse_command_args(char **argv, const char **path)
8145{
8146 char *cp, c;
8147
8148 for (;;) {
8149 cp = *++argv;
8150 if (!cp)
8151 return NULL;
8152 if (*cp++ != '-')
8153 break;
8154 c = *cp++;
8155 if (!c)
8156 break;
8157 if (c == '-' && !*cp) {
8158 if (!*++argv)
8159 return NULL;
8160 break;
8161 }
8162 do {
8163 switch (c) {
8164 case 'p':
8165 *path = bb_default_path;
8166 break;
8167 default:
8168 /* run 'typecmd' for other options */
8169 return NULL;
8170 }
8171 c = *cp++;
8172 } while (c);
8173 }
8174 return argv;
8175}
8176
8177static int FAST_FUNC
8178commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8179{
8180 char *cmd;
8181 int c;
8182 enum {
8183 VERIFY_BRIEF = 1,
8184 VERIFY_VERBOSE = 2,
8185 } verify = 0;
8186 const char *path = NULL;
8187
8188 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8189 * never reaches this function.
8190 */
8191
8192 while ((c = nextopt("pvV")) != '\0')
8193 if (c == 'V')
8194 verify |= VERIFY_VERBOSE;
8195 else if (c == 'v')
8196 /*verify |= VERIFY_BRIEF*/;
8197#if DEBUG
8198 else if (c != 'p')
8199 abort();
8200#endif
8201 else
8202 path = bb_default_path;
8203
8204 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8205 cmd = *argptr;
8206 if (/*verify && */ cmd)
8207 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
8208
8209 return 0;
8210}
8211#endif
8212
8213
8214/*static int funcblocksize; // size of structures in function */
8215/*static int funcstringsize; // size of strings in node */
8216static void *funcblock; /* block to allocate function from */
8217static char *funcstring_end; /* end of block to allocate strings from */
8218
8219/* flags in argument to evaltree */
8220#define EV_EXIT 01 /* exit after evaluating tree */
8221#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
8222
8223static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8224 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8225 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8226 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8227 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8228 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8229 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8230 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8231 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8232 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8233 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8234 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8235 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8236 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8237 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8238 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8239 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8240 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8241#if ENABLE_ASH_BASH_COMPAT
8242 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
8243#endif
8244 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8245 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8246 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8247 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8248 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8249 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8250 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8251 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8252 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
8253};
8254
8255static int calcsize(int funcblocksize, union node *n);
8256
8257static int
8258sizenodelist(int funcblocksize, struct nodelist *lp)
8259{
8260 while (lp) {
8261 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8262 funcblocksize = calcsize(funcblocksize, lp->n);
8263 lp = lp->next;
8264 }
8265 return funcblocksize;
8266}
8267
8268static int
8269calcsize(int funcblocksize, union node *n)
8270{
8271 if (n == NULL)
8272 return funcblocksize;
8273 funcblocksize += nodesize[n->type];
8274 switch (n->type) {
8275 case NCMD:
8276 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8277 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8278 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
8279 break;
8280 case NPIPE:
8281 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
8282 break;
8283 case NREDIR:
8284 case NBACKGND:
8285 case NSUBSHELL:
8286 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8287 funcblocksize = calcsize(funcblocksize, n->nredir.n);
8288 break;
8289 case NAND:
8290 case NOR:
8291 case NSEMI:
8292 case NWHILE:
8293 case NUNTIL:
8294 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8295 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
8296 break;
8297 case NIF:
8298 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8299 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8300 funcblocksize = calcsize(funcblocksize, n->nif.test);
8301 break;
8302 case NFOR:
8303 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
8304 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8305 funcblocksize = calcsize(funcblocksize, n->nfor.args);
8306 break;
8307 case NCASE:
8308 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8309 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
8310 break;
8311 case NCLIST:
8312 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8313 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8314 funcblocksize = calcsize(funcblocksize, n->nclist.next);
8315 break;
8316 case NDEFUN:
8317 case NARG:
8318 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
8319 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
8320 funcblocksize = calcsize(funcblocksize, n->narg.next);
8321 break;
8322 case NTO:
8323#if ENABLE_ASH_BASH_COMPAT
8324 case NTO2:
8325#endif
8326 case NCLOBBER:
8327 case NFROM:
8328 case NFROMTO:
8329 case NAPPEND:
8330 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8331 funcblocksize = calcsize(funcblocksize, n->nfile.next);
8332 break;
8333 case NTOFD:
8334 case NFROMFD:
8335 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8336 funcblocksize = calcsize(funcblocksize, n->ndup.next);
8337 break;
8338 case NHERE:
8339 case NXHERE:
8340 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8341 funcblocksize = calcsize(funcblocksize, n->nhere.next);
8342 break;
8343 case NNOT:
8344 funcblocksize = calcsize(funcblocksize, n->nnot.com);
8345 break;
8346 };
8347 return funcblocksize;
8348}
8349
8350static char *
8351nodeckstrdup(char *s)
8352{
8353 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
8354 return strcpy(funcstring_end, s);
8355}
8356
8357static union node *copynode(union node *);
8358
8359static struct nodelist *
8360copynodelist(struct nodelist *lp)
8361{
8362 struct nodelist *start;
8363 struct nodelist **lpp;
8364
8365 lpp = &start;
8366 while (lp) {
8367 *lpp = funcblock;
8368 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8369 (*lpp)->n = copynode(lp->n);
8370 lp = lp->next;
8371 lpp = &(*lpp)->next;
8372 }
8373 *lpp = NULL;
8374 return start;
8375}
8376
8377static union node *
8378copynode(union node *n)
8379{
8380 union node *new;
8381
8382 if (n == NULL)
8383 return NULL;
8384 new = funcblock;
8385 funcblock = (char *) funcblock + nodesize[n->type];
8386
8387 switch (n->type) {
8388 case NCMD:
8389 new->ncmd.redirect = copynode(n->ncmd.redirect);
8390 new->ncmd.args = copynode(n->ncmd.args);
8391 new->ncmd.assign = copynode(n->ncmd.assign);
8392 break;
8393 case NPIPE:
8394 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8395 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8396 break;
8397 case NREDIR:
8398 case NBACKGND:
8399 case NSUBSHELL:
8400 new->nredir.redirect = copynode(n->nredir.redirect);
8401 new->nredir.n = copynode(n->nredir.n);
8402 break;
8403 case NAND:
8404 case NOR:
8405 case NSEMI:
8406 case NWHILE:
8407 case NUNTIL:
8408 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8409 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8410 break;
8411 case NIF:
8412 new->nif.elsepart = copynode(n->nif.elsepart);
8413 new->nif.ifpart = copynode(n->nif.ifpart);
8414 new->nif.test = copynode(n->nif.test);
8415 break;
8416 case NFOR:
8417 new->nfor.var = nodeckstrdup(n->nfor.var);
8418 new->nfor.body = copynode(n->nfor.body);
8419 new->nfor.args = copynode(n->nfor.args);
8420 break;
8421 case NCASE:
8422 new->ncase.cases = copynode(n->ncase.cases);
8423 new->ncase.expr = copynode(n->ncase.expr);
8424 break;
8425 case NCLIST:
8426 new->nclist.body = copynode(n->nclist.body);
8427 new->nclist.pattern = copynode(n->nclist.pattern);
8428 new->nclist.next = copynode(n->nclist.next);
8429 break;
8430 case NDEFUN:
8431 case NARG:
8432 new->narg.backquote = copynodelist(n->narg.backquote);
8433 new->narg.text = nodeckstrdup(n->narg.text);
8434 new->narg.next = copynode(n->narg.next);
8435 break;
8436 case NTO:
8437#if ENABLE_ASH_BASH_COMPAT
8438 case NTO2:
8439#endif
8440 case NCLOBBER:
8441 case NFROM:
8442 case NFROMTO:
8443 case NAPPEND:
8444 new->nfile.fname = copynode(n->nfile.fname);
8445 new->nfile.fd = n->nfile.fd;
8446 new->nfile.next = copynode(n->nfile.next);
8447 break;
8448 case NTOFD:
8449 case NFROMFD:
8450 new->ndup.vname = copynode(n->ndup.vname);
8451 new->ndup.dupfd = n->ndup.dupfd;
8452 new->ndup.fd = n->ndup.fd;
8453 new->ndup.next = copynode(n->ndup.next);
8454 break;
8455 case NHERE:
8456 case NXHERE:
8457 new->nhere.doc = copynode(n->nhere.doc);
8458 new->nhere.fd = n->nhere.fd;
8459 new->nhere.next = copynode(n->nhere.next);
8460 break;
8461 case NNOT:
8462 new->nnot.com = copynode(n->nnot.com);
8463 break;
8464 };
8465 new->type = n->type;
8466 return new;
8467}
8468
8469/*
8470 * Make a copy of a parse tree.
8471 */
8472static struct funcnode *
8473copyfunc(union node *n)
8474{
8475 struct funcnode *f;
8476 size_t blocksize;
8477
8478 /*funcstringsize = 0;*/
8479 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8480 f = ckzalloc(blocksize /* + funcstringsize */);
8481 funcblock = (char *) f + offsetof(struct funcnode, n);
8482 funcstring_end = (char *) f + blocksize;
8483 copynode(n);
8484 /* f->count = 0; - ckzalloc did it */
8485 return f;
8486}
8487
8488/*
8489 * Define a shell function.
8490 */
8491static void
8492defun(union node *func)
8493{
8494 struct cmdentry entry;
8495
8496 INT_OFF;
8497 entry.cmdtype = CMDFUNCTION;
8498 entry.u.func = copyfunc(func);
8499 addcmdentry(func->narg.text, &entry);
8500 INT_ON;
8501}
8502
8503/* Reasons for skipping commands (see comment on breakcmd routine) */
8504#define SKIPBREAK (1 << 0)
8505#define SKIPCONT (1 << 1)
8506#define SKIPFUNC (1 << 2)
8507static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
8508static int skipcount; /* number of levels to skip */
8509static int funcnest; /* depth of function calls */
8510static int loopnest; /* current loop nesting level */
8511
8512/* Forward decl way out to parsing code - dotrap needs it */
8513static int evalstring(char *s, int flags);
8514
8515/* Called to execute a trap.
8516 * Single callsite - at the end of evaltree().
8517 * If we return non-zero, evaltree raises EXEXIT exception.
8518 *
8519 * Perhaps we should avoid entering new trap handlers
8520 * while we are executing a trap handler. [is it a TODO?]
8521 */
8522static void
8523dotrap(void)
8524{
8525 uint8_t *g;
8526 int sig;
8527 uint8_t last_status;
8528
8529 if (!pending_sig)
8530 return;
8531
8532 last_status = exitstatus;
8533 pending_sig = 0;
8534 barrier();
8535
8536 TRACE(("dotrap entered\n"));
8537 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8538 char *p;
8539
8540 if (!*g)
8541 continue;
8542
8543 if (evalskip) {
8544 pending_sig = sig;
8545 break;
8546 }
8547
8548 p = trap[sig];
8549 /* non-trapped SIGINT is handled separately by raise_interrupt,
8550 * don't upset it by resetting gotsig[SIGINT-1] */
8551 if (sig == SIGINT && !p)
8552 continue;
8553
8554 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
8555 *g = 0;
8556 if (!p)
8557 continue;
8558 evalstring(p, 0);
8559 }
8560 exitstatus = last_status;
8561 TRACE(("dotrap returns\n"));
8562}
8563
8564/* forward declarations - evaluation is fairly recursive business... */
8565static int evalloop(union node *, int);
8566static int evalfor(union node *, int);
8567static int evalcase(union node *, int);
8568static int evalsubshell(union node *, int);
8569static void expredir(union node *);
8570static int evalpipe(union node *, int);
8571static int evalcommand(union node *, int);
8572static int evalbltin(const struct builtincmd *, int, char **, int);
8573static void prehash(union node *);
8574
8575/*
8576 * Evaluate a parse tree. The value is left in the global variable
8577 * exitstatus.
8578 */
8579static int
8580evaltree(union node *n, int flags)
8581{
8582 int checkexit = 0;
8583 int (*evalfn)(union node *, int);
8584 int status = 0;
8585
8586 if (n == NULL) {
8587 TRACE(("evaltree(NULL) called\n"));
8588 goto out;
8589 }
8590 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
8591
8592 dotrap();
8593
8594 switch (n->type) {
8595 default:
8596#if DEBUG
8597 out1fmt("Node type = %d\n", n->type);
8598 fflush_all();
8599 break;
8600#endif
8601 case NNOT:
8602 status = !evaltree(n->nnot.com, EV_TESTED);
8603 goto setstatus;
8604 case NREDIR:
8605 expredir(n->nredir.redirect);
8606 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8607 if (!status) {
8608 status = evaltree(n->nredir.n, flags & EV_TESTED);
8609 }
8610 if (n->nredir.redirect)
8611 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
8612 goto setstatus;
8613 case NCMD:
8614 evalfn = evalcommand;
8615 checkexit:
8616 if (eflag && !(flags & EV_TESTED))
8617 checkexit = ~0;
8618 goto calleval;
8619 case NFOR:
8620 evalfn = evalfor;
8621 goto calleval;
8622 case NWHILE:
8623 case NUNTIL:
8624 evalfn = evalloop;
8625 goto calleval;
8626 case NSUBSHELL:
8627 case NBACKGND:
8628 evalfn = evalsubshell;
8629 goto checkexit;
8630 case NPIPE:
8631 evalfn = evalpipe;
8632 goto checkexit;
8633 case NCASE:
8634 evalfn = evalcase;
8635 goto calleval;
8636 case NAND:
8637 case NOR:
8638 case NSEMI: {
8639
8640#if NAND + 1 != NOR
8641#error NAND + 1 != NOR
8642#endif
8643#if NOR + 1 != NSEMI
8644#error NOR + 1 != NSEMI
8645#endif
8646 unsigned is_or = n->type - NAND;
8647 status = evaltree(
8648 n->nbinary.ch1,
8649 (flags | ((is_or >> 1) - 1)) & EV_TESTED
8650 );
8651 if ((!status) == is_or || evalskip)
8652 break;
8653 n = n->nbinary.ch2;
8654 evaln:
8655 evalfn = evaltree;
8656 calleval:
8657 status = evalfn(n, flags);
8658 goto setstatus;
8659 }
8660 case NIF:
8661 status = evaltree(n->nif.test, EV_TESTED);
8662 if (evalskip)
8663 break;
8664 if (!status) {
8665 n = n->nif.ifpart;
8666 goto evaln;
8667 }
8668 if (n->nif.elsepart) {
8669 n = n->nif.elsepart;
8670 goto evaln;
8671 }
8672 status = 0;
8673 goto setstatus;
8674 case NDEFUN:
8675 defun(n);
8676 /* Not necessary. To test it:
8677 * "false; f() { qwerty; }; echo $?" should print 0.
8678 */
8679 /* status = 0; */
8680 setstatus:
8681 exitstatus = status;
8682 break;
8683 }
8684 out:
8685 /* Order of checks below is important:
8686 * signal handlers trigger before exit caused by "set -e".
8687 */
8688 dotrap();
8689
8690 if (checkexit & status)
8691 raise_exception(EXEXIT);
8692 if (flags & EV_EXIT)
8693 raise_exception(EXEXIT);
8694
8695 TRACE(("leaving evaltree (no interrupts)\n"));
8696 return exitstatus;
8697}
8698
8699#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8700static
8701#endif
8702int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8703
8704static int
8705skiploop(void)
8706{
8707 int skip = evalskip;
8708
8709 switch (skip) {
8710 case 0:
8711 break;
8712 case SKIPBREAK:
8713 case SKIPCONT:
8714 if (--skipcount <= 0) {
8715 evalskip = 0;
8716 break;
8717 }
8718 skip = SKIPBREAK;
8719 break;
8720 }
8721 return skip;
8722}
8723
8724static int
8725evalloop(union node *n, int flags)
8726{
8727 int skip;
8728 int status;
8729
8730 loopnest++;
8731 status = 0;
8732 flags &= EV_TESTED;
8733 do {
8734 int i;
8735
8736 i = evaltree(n->nbinary.ch1, EV_TESTED);
8737 skip = skiploop();
8738 if (skip == SKIPFUNC)
8739 status = i;
8740 if (skip)
8741 continue;
8742 if (n->type != NWHILE)
8743 i = !i;
8744 if (i != 0)
8745 break;
8746 status = evaltree(n->nbinary.ch2, flags);
8747 skip = skiploop();
8748 } while (!(skip & ~SKIPCONT));
8749 loopnest--;
8750
8751 return status;
8752}
8753
8754static int
8755evalfor(union node *n, int flags)
8756{
8757 struct arglist arglist;
8758 union node *argp;
8759 struct strlist *sp;
8760 struct stackmark smark;
8761 int status = 0;
8762
8763 setstackmark(&smark);
8764 arglist.list = NULL;
8765 arglist.lastp = &arglist.list;
8766 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8767 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8768 }
8769 *arglist.lastp = NULL;
8770
8771 loopnest++;
8772 flags &= EV_TESTED;
8773 for (sp = arglist.list; sp; sp = sp->next) {
8774 setvar0(n->nfor.var, sp->text);
8775 status = evaltree(n->nfor.body, flags);
8776 if (skiploop() & ~SKIPCONT)
8777 break;
8778 }
8779 loopnest--;
8780 popstackmark(&smark);
8781
8782 return status;
8783}
8784
8785static int
8786evalcase(union node *n, int flags)
8787{
8788 union node *cp;
8789 union node *patp;
8790 struct arglist arglist;
8791 struct stackmark smark;
8792 int status = 0;
8793
8794 setstackmark(&smark);
8795 arglist.list = NULL;
8796 arglist.lastp = &arglist.list;
8797 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8798 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8799 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8800 if (casematch(patp, arglist.list->text)) {
8801 /* Ensure body is non-empty as otherwise
8802 * EV_EXIT may prevent us from setting the
8803 * exit status.
8804 */
8805 if (evalskip == 0 && cp->nclist.body) {
8806 status = evaltree(cp->nclist.body, flags);
8807 }
8808 goto out;
8809 }
8810 }
8811 }
8812 out:
8813 popstackmark(&smark);
8814
8815 return status;
8816}
8817
8818/*
8819 * Kick off a subshell to evaluate a tree.
8820 */
8821static int
8822evalsubshell(union node *n, int flags)
8823{
8824 struct job *jp;
8825 int backgnd = (n->type == NBACKGND);
8826 int status;
8827
8828 expredir(n->nredir.redirect);
8829 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
8830 goto nofork;
8831 INT_OFF;
8832 jp = makejob(/*n,*/ 1);
8833 if (forkshell(jp, n, backgnd) == 0) {
8834 /* child */
8835 INT_ON;
8836 flags |= EV_EXIT;
8837 if (backgnd)
8838 flags &= ~EV_TESTED;
8839 nofork:
8840 redirect(n->nredir.redirect, 0);
8841 evaltreenr(n->nredir.n, flags);
8842 /* never returns */
8843 }
8844 /* parent */
8845 status = 0;
8846 if (!backgnd)
8847 status = waitforjob(jp);
8848 INT_ON;
8849 return status;
8850}
8851
8852/*
8853 * Compute the names of the files in a redirection list.
8854 */
8855static void fixredir(union node *, const char *, int);
8856static void
8857expredir(union node *n)
8858{
8859 union node *redir;
8860
8861 for (redir = n; redir; redir = redir->nfile.next) {
8862 struct arglist fn;
8863
8864 fn.list = NULL;
8865 fn.lastp = &fn.list;
8866 switch (redir->type) {
8867 case NFROMTO:
8868 case NFROM:
8869 case NTO:
8870#if ENABLE_ASH_BASH_COMPAT
8871 case NTO2:
8872#endif
8873 case NCLOBBER:
8874 case NAPPEND:
8875 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8876 TRACE(("expredir expanded to '%s'\n", fn.list->text));
8877#if ENABLE_ASH_BASH_COMPAT
8878 store_expfname:
8879#endif
8880#if 0
8881// By the design of stack allocator, the loop of this kind:
8882// while true; do while true; do break; done </dev/null; done
8883// will look like a memory leak: ash plans to free expfname's
8884// of "/dev/null" as soon as it finishes running the loop
8885// (in this case, never).
8886// This "fix" is wrong:
8887 if (redir->nfile.expfname)
8888 stunalloc(redir->nfile.expfname);
8889// It results in corrupted state of stacked allocations.
8890#endif
8891 redir->nfile.expfname = fn.list->text;
8892 break;
8893 case NFROMFD:
8894 case NTOFD: /* >& */
8895 if (redir->ndup.vname) {
8896 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8897 if (fn.list == NULL)
8898 ash_msg_and_raise_error("redir error");
8899#if ENABLE_ASH_BASH_COMPAT
8900//FIXME: we used expandarg with different args!
8901 if (!isdigit_str9(fn.list->text)) {
8902 /* >&file, not >&fd */
8903 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8904 ash_msg_and_raise_error("redir error");
8905 redir->type = NTO2;
8906 goto store_expfname;
8907 }
8908#endif
8909 fixredir(redir, fn.list->text, 1);
8910 }
8911 break;
8912 }
8913 }
8914}
8915
8916/*
8917 * Evaluate a pipeline. All the processes in the pipeline are children
8918 * of the process creating the pipeline. (This differs from some versions
8919 * of the shell, which make the last process in a pipeline the parent
8920 * of all the rest.)
8921 */
8922static int
8923evalpipe(union node *n, int flags)
8924{
8925 struct job *jp;
8926 struct nodelist *lp;
8927 int pipelen;
8928 int prevfd;
8929 int pip[2];
8930 int status = 0;
8931
8932 TRACE(("evalpipe(0x%lx) called\n", (long)n));
8933 pipelen = 0;
8934 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8935 pipelen++;
8936 flags |= EV_EXIT;
8937 INT_OFF;
8938 jp = makejob(/*n,*/ pipelen);
8939 prevfd = -1;
8940 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8941 prehash(lp->n);
8942 pip[1] = -1;
8943 if (lp->next) {
8944 if (pipe(pip) < 0) {
8945 close(prevfd);
8946 ash_msg_and_raise_error("pipe call failed");
8947 }
8948 }
8949 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8950 /* child */
8951 INT_ON;
8952 if (pip[1] >= 0) {
8953 close(pip[0]);
8954 }
8955 if (prevfd > 0) {
8956 dup2(prevfd, 0);
8957 close(prevfd);
8958 }
8959 if (pip[1] > 1) {
8960 dup2(pip[1], 1);
8961 close(pip[1]);
8962 }
8963 evaltreenr(lp->n, flags);
8964 /* never returns */
8965 }
8966 /* parent */
8967 if (prevfd >= 0)
8968 close(prevfd);
8969 prevfd = pip[0];
8970 /* Don't want to trigger debugging */
8971 if (pip[1] != -1)
8972 close(pip[1]);
8973 }
8974 if (n->npipe.pipe_backgnd == 0) {
8975 status = waitforjob(jp);
8976 TRACE(("evalpipe: job done exit status %d\n", status));
8977 }
8978 INT_ON;
8979
8980 return status;
8981}
8982
8983/*
8984 * Controls whether the shell is interactive or not.
8985 */
8986static void
8987setinteractive(int on)
8988{
8989 static smallint is_interactive;
8990
8991 if (++on == is_interactive)
8992 return;
8993 is_interactive = on;
8994 setsignal(SIGINT);
8995 setsignal(SIGQUIT);
8996 setsignal(SIGTERM);
8997#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8998 if (is_interactive > 1) {
8999 /* Looks like they want an interactive shell */
9000 static smallint did_banner;
9001
9002 if (!did_banner) {
9003 /* note: ash and hush share this string */
9004 out1fmt("\n\n%s %s\n"
9005 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9006 "\n",
9007 bb_banner,
9008 "built-in shell (ash)"
9009 );
9010 did_banner = 1;
9011 }
9012 }
9013#endif
9014}
9015
9016static void
9017optschanged(void)
9018{
9019#if DEBUG
9020 opentrace();
9021#endif
9022 setinteractive(iflag);
9023 setjobctl(mflag);
9024#if ENABLE_FEATURE_EDITING_VI
9025 if (viflag)
9026 line_input_state->flags |= VI_MODE;
9027 else
9028 line_input_state->flags &= ~VI_MODE;
9029#else
9030 viflag = 0; /* forcibly keep the option off */
9031#endif
9032}
9033
9034static struct localvar *localvars;
9035
9036/*
9037 * Called after a function returns.
9038 * Interrupts must be off.
9039 */
9040static void
9041poplocalvars(void)
9042{
9043 struct localvar *lvp;
9044 struct var *vp;
9045
9046 while ((lvp = localvars) != NULL) {
9047 localvars = lvp->next;
9048 vp = lvp->vp;
9049 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
9050 if (vp == NULL) { /* $- saved */
9051 memcpy(optlist, lvp->text, sizeof(optlist));
9052 free((char*)lvp->text);
9053 optschanged();
9054 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
9055 unsetvar(vp->var_text);
9056 } else {
9057 if (vp->var_func)
9058 vp->var_func(var_end(lvp->text));
9059 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
9060 free((char*)vp->var_text);
9061 vp->flags = lvp->flags;
9062 vp->var_text = lvp->text;
9063 }
9064 free(lvp);
9065 }
9066}
9067
9068static int
9069evalfun(struct funcnode *func, int argc, char **argv, int flags)
9070{
9071 volatile struct shparam saveparam;
9072 struct localvar *volatile savelocalvars;
9073 struct jmploc *volatile savehandler;
9074 struct jmploc jmploc;
9075 int e;
9076
9077 saveparam = shellparam;
9078 savelocalvars = localvars;
9079 savehandler = exception_handler;
9080 e = setjmp(jmploc.loc);
9081 if (e) {
9082 goto funcdone;
9083 }
9084 INT_OFF;
9085 exception_handler = &jmploc;
9086 localvars = NULL;
9087 shellparam.malloced = 0;
9088 func->count++;
9089 funcnest++;
9090 INT_ON;
9091 shellparam.nparam = argc - 1;
9092 shellparam.p = argv + 1;
9093#if ENABLE_ASH_GETOPTS
9094 shellparam.optind = 1;
9095 shellparam.optoff = -1;
9096#endif
9097 evaltree(func->n.narg.next, flags & EV_TESTED);
9098 funcdone:
9099 INT_OFF;
9100 funcnest--;
9101 freefunc(func);
9102 poplocalvars();
9103 localvars = savelocalvars;
9104 freeparam(&shellparam);
9105 shellparam = saveparam;
9106 exception_handler = savehandler;
9107 INT_ON;
9108 evalskip &= ~SKIPFUNC;
9109 return e;
9110}
9111
9112/*
9113 * Make a variable a local variable. When a variable is made local, it's
9114 * value and flags are saved in a localvar structure. The saved values
9115 * will be restored when the shell function returns. We handle the name
9116 * "-" as a special case: it makes changes to "set +-options" local
9117 * (options will be restored on return from the function).
9118 */
9119static void
9120mklocal(char *name)
9121{
9122 struct localvar *lvp;
9123 struct var **vpp;
9124 struct var *vp;
9125 char *eq = strchr(name, '=');
9126
9127 INT_OFF;
9128 /* Cater for duplicate "local". Examples:
9129 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9130 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9131 */
9132 lvp = localvars;
9133 while (lvp) {
9134 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
9135 if (eq)
9136 setvareq(name, 0);
9137 /* else:
9138 * it's a duplicate "local VAR" declaration, do nothing
9139 */
9140 goto ret;
9141 }
9142 lvp = lvp->next;
9143 }
9144
9145 lvp = ckzalloc(sizeof(*lvp));
9146 if (LONE_DASH(name)) {
9147 char *p;
9148 p = ckmalloc(sizeof(optlist));
9149 lvp->text = memcpy(p, optlist, sizeof(optlist));
9150 vp = NULL;
9151 } else {
9152 vpp = hashvar(name);
9153 vp = *findvar(vpp, name);
9154 if (vp == NULL) {
9155 /* variable did not exist yet */
9156 if (eq)
9157 setvareq(name, VSTRFIXED);
9158 else
9159 setvar(name, NULL, VSTRFIXED);
9160 vp = *vpp; /* the new variable */
9161 lvp->flags = VUNSET;
9162 } else {
9163 lvp->text = vp->var_text;
9164 lvp->flags = vp->flags;
9165 /* make sure neither "struct var" nor string gets freed
9166 * during (un)setting:
9167 */
9168 vp->flags |= VSTRFIXED|VTEXTFIXED;
9169 if (eq)
9170 setvareq(name, 0);
9171 else
9172 /* "local VAR" unsets VAR: */
9173 setvar0(name, NULL);
9174 }
9175 }
9176 lvp->vp = vp;
9177 lvp->next = localvars;
9178 localvars = lvp;
9179 ret:
9180 INT_ON;
9181}
9182
9183/*
9184 * The "local" command.
9185 */
9186static int FAST_FUNC
9187localcmd(int argc UNUSED_PARAM, char **argv)
9188{
9189 char *name;
9190
9191 if (!funcnest)
9192 ash_msg_and_raise_error("not in a function");
9193
9194 argv = argptr;
9195 while ((name = *argv++) != NULL) {
9196 mklocal(name);
9197 }
9198 return 0;
9199}
9200
9201static int FAST_FUNC
9202falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9203{
9204 return 1;
9205}
9206
9207static int FAST_FUNC
9208truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9209{
9210 return 0;
9211}
9212
9213static int FAST_FUNC
9214execcmd(int argc UNUSED_PARAM, char **argv)
9215{
9216 if (argv[1]) {
9217 iflag = 0; /* exit on error */
9218 mflag = 0;
9219 optschanged();
9220 /* We should set up signals for "exec CMD"
9221 * the same way as for "CMD" without "exec".
9222 * But optschanged->setinteractive->setsignal
9223 * still thought we are a root shell. Therefore, for example,
9224 * SIGQUIT is still set to IGN. Fix it:
9225 */
9226 shlvl++;
9227 setsignal(SIGQUIT);
9228 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9229 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9230 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9231
9232 shellexec(argv + 1, pathval(), 0);
9233 /* NOTREACHED */
9234 }
9235 return 0;
9236}
9237
9238/*
9239 * The return command.
9240 */
9241static int FAST_FUNC
9242returncmd(int argc UNUSED_PARAM, char **argv)
9243{
9244 /*
9245 * If called outside a function, do what ksh does;
9246 * skip the rest of the file.
9247 */
9248 evalskip = SKIPFUNC;
9249 return argv[1] ? number(argv[1]) : exitstatus;
9250}
9251
9252/* Forward declarations for builtintab[] */
9253static int breakcmd(int, char **) FAST_FUNC;
9254static int dotcmd(int, char **) FAST_FUNC;
9255static int evalcmd(int, char **, int) FAST_FUNC;
9256static int exitcmd(int, char **) FAST_FUNC;
9257static int exportcmd(int, char **) FAST_FUNC;
9258#if ENABLE_ASH_GETOPTS
9259static int getoptscmd(int, char **) FAST_FUNC;
9260#endif
9261#if ENABLE_ASH_HELP
9262static int helpcmd(int, char **) FAST_FUNC;
9263#endif
9264#if MAX_HISTORY
9265static int historycmd(int, char **) FAST_FUNC;
9266#endif
9267#if ENABLE_SH_MATH_SUPPORT
9268static int letcmd(int, char **) FAST_FUNC;
9269#endif
9270static int readcmd(int, char **) FAST_FUNC;
9271static int setcmd(int, char **) FAST_FUNC;
9272static int shiftcmd(int, char **) FAST_FUNC;
9273static int timescmd(int, char **) FAST_FUNC;
9274static int trapcmd(int, char **) FAST_FUNC;
9275static int umaskcmd(int, char **) FAST_FUNC;
9276static int unsetcmd(int, char **) FAST_FUNC;
9277static int ulimitcmd(int, char **) FAST_FUNC;
9278
9279#define BUILTIN_NOSPEC "0"
9280#define BUILTIN_SPECIAL "1"
9281#define BUILTIN_REGULAR "2"
9282#define BUILTIN_SPEC_REG "3"
9283#define BUILTIN_ASSIGN "4"
9284#define BUILTIN_SPEC_ASSG "5"
9285#define BUILTIN_REG_ASSG "6"
9286#define BUILTIN_SPEC_REG_ASSG "7"
9287
9288/* Stubs for calling non-FAST_FUNC's */
9289#if ENABLE_ASH_BUILTIN_ECHO
9290static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
9291#endif
9292#if ENABLE_ASH_BUILTIN_PRINTF
9293static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
9294#endif
9295#if ENABLE_ASH_BUILTIN_TEST
9296static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
9297#endif
9298
9299/* Keep these in proper order since it is searched via bsearch() */
9300static const struct builtincmd builtintab[] = {
9301 { BUILTIN_SPEC_REG "." , dotcmd },
9302 { BUILTIN_SPEC_REG ":" , truecmd },
9303#if ENABLE_ASH_BUILTIN_TEST
9304 { BUILTIN_REGULAR "[" , testcmd },
9305# if ENABLE_ASH_BASH_COMPAT
9306 { BUILTIN_REGULAR "[[" , testcmd },
9307# endif
9308#endif
9309#if ENABLE_ASH_ALIAS
9310 { BUILTIN_REG_ASSG "alias" , aliascmd },
9311#endif
9312#if JOBS
9313 { BUILTIN_REGULAR "bg" , fg_bgcmd },
9314#endif
9315 { BUILTIN_SPEC_REG "break" , breakcmd },
9316 { BUILTIN_REGULAR "cd" , cdcmd },
9317 { BUILTIN_NOSPEC "chdir" , cdcmd },
9318#if ENABLE_ASH_CMDCMD
9319 { BUILTIN_REGULAR "command" , commandcmd },
9320#endif
9321 { BUILTIN_SPEC_REG "continue", breakcmd },
9322#if ENABLE_ASH_BUILTIN_ECHO
9323 { BUILTIN_REGULAR "echo" , echocmd },
9324#endif
9325 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
9326 { BUILTIN_SPEC_REG "exec" , execcmd },
9327 { BUILTIN_SPEC_REG "exit" , exitcmd },
9328 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9329 { BUILTIN_REGULAR "false" , falsecmd },
9330#if JOBS
9331 { BUILTIN_REGULAR "fg" , fg_bgcmd },
9332#endif
9333#if ENABLE_ASH_GETOPTS
9334 { BUILTIN_REGULAR "getopts" , getoptscmd },
9335#endif
9336 { BUILTIN_NOSPEC "hash" , hashcmd },
9337#if ENABLE_ASH_HELP
9338 { BUILTIN_NOSPEC "help" , helpcmd },
9339#endif
9340#if MAX_HISTORY
9341 { BUILTIN_NOSPEC "history" , historycmd },
9342#endif
9343#if JOBS
9344 { BUILTIN_REGULAR "jobs" , jobscmd },
9345 { BUILTIN_REGULAR "kill" , killcmd },
9346#endif
9347#if ENABLE_SH_MATH_SUPPORT
9348 { BUILTIN_NOSPEC "let" , letcmd },
9349#endif
9350 { BUILTIN_ASSIGN "local" , localcmd },
9351#if ENABLE_ASH_BUILTIN_PRINTF
9352 { BUILTIN_REGULAR "printf" , printfcmd },
9353#endif
9354 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9355 { BUILTIN_REGULAR "read" , readcmd },
9356 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9357 { BUILTIN_SPEC_REG "return" , returncmd },
9358 { BUILTIN_SPEC_REG "set" , setcmd },
9359 { BUILTIN_SPEC_REG "shift" , shiftcmd },
9360#if ENABLE_ASH_BASH_COMPAT
9361 { BUILTIN_SPEC_REG "source" , dotcmd },
9362#endif
9363#if ENABLE_ASH_BUILTIN_TEST
9364 { BUILTIN_REGULAR "test" , testcmd },
9365#endif
9366 { BUILTIN_SPEC_REG "times" , timescmd },
9367 { BUILTIN_SPEC_REG "trap" , trapcmd },
9368 { BUILTIN_REGULAR "true" , truecmd },
9369 { BUILTIN_NOSPEC "type" , typecmd },
9370 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9371 { BUILTIN_REGULAR "umask" , umaskcmd },
9372#if ENABLE_ASH_ALIAS
9373 { BUILTIN_REGULAR "unalias" , unaliascmd },
9374#endif
9375 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9376 { BUILTIN_REGULAR "wait" , waitcmd },
9377};
9378
9379/* Should match the above table! */
9380#define COMMANDCMD (builtintab + \
9381 /* . : */ 2 + \
9382 /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \
9383 /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9384 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9385 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9386 /* break cd cddir */ 3)
9387#define EVALCMD (COMMANDCMD + \
9388 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9389 /* continue */ 1 + \
9390 /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \
9391 0)
9392#define EXECCMD (EVALCMD + \
9393 /* eval */ 1)
9394
9395/*
9396 * Search the table of builtin commands.
9397 */
9398static int
9399pstrcmp1(const void *a, const void *b)
9400{
9401 return strcmp((char*)a, *(char**)b + 1);
9402}
9403static struct builtincmd *
9404find_builtin(const char *name)
9405{
9406 struct builtincmd *bp;
9407
9408 bp = bsearch(
9409 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
9410 pstrcmp1
9411 );
9412 return bp;
9413}
9414
9415/*
9416 * Execute a simple command.
9417 */
9418static int
9419isassignment(const char *p)
9420{
9421 const char *q = endofname(p);
9422 if (p == q)
9423 return 0;
9424 return *q == '=';
9425}
9426static int FAST_FUNC
9427bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9428{
9429 /* Preserve exitstatus of a previous possible redirection
9430 * as POSIX mandates */
9431 return back_exitstatus;
9432}
9433static int
9434evalcommand(union node *cmd, int flags)
9435{
9436 static const struct builtincmd null_bltin = {
9437 "\0\0", bltincmd /* why three NULs? */
9438 };
9439 struct stackmark smark;
9440 union node *argp;
9441 struct arglist arglist;
9442 struct arglist varlist;
9443 char **argv;
9444 int argc;
9445 const struct strlist *sp;
9446 struct cmdentry cmdentry;
9447 struct job *jp;
9448 char *lastarg;
9449 const char *path;
9450 int spclbltin;
9451 int status;
9452 char **nargv;
9453 struct builtincmd *bcmd;
9454 smallint cmd_is_exec;
9455 smallint pseudovarflag = 0;
9456
9457 /* First expand the arguments. */
9458 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9459 setstackmark(&smark);
9460 back_exitstatus = 0;
9461
9462 cmdentry.cmdtype = CMDBUILTIN;
9463 cmdentry.u.cmd = &null_bltin;
9464 varlist.lastp = &varlist.list;
9465 *varlist.lastp = NULL;
9466 arglist.lastp = &arglist.list;
9467 *arglist.lastp = NULL;
9468
9469 argc = 0;
9470 if (cmd->ncmd.args) {
9471 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9472 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9473 }
9474
9475 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9476 struct strlist **spp;
9477
9478 spp = arglist.lastp;
9479 if (pseudovarflag && isassignment(argp->narg.text))
9480 expandarg(argp, &arglist, EXP_VARTILDE);
9481 else
9482 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9483
9484 for (sp = *spp; sp; sp = sp->next)
9485 argc++;
9486 }
9487
9488 /* Reserve one extra spot at the front for shellexec. */
9489 nargv = stalloc(sizeof(char *) * (argc + 2));
9490 argv = ++nargv;
9491 for (sp = arglist.list; sp; sp = sp->next) {
9492 TRACE(("evalcommand arg: %s\n", sp->text));
9493 *nargv++ = sp->text;
9494 }
9495 *nargv = NULL;
9496
9497 lastarg = NULL;
9498 if (iflag && funcnest == 0 && argc > 0)
9499 lastarg = nargv[-1];
9500
9501 preverrout_fd = 2;
9502 expredir(cmd->ncmd.redirect);
9503 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
9504
9505 path = vpath.var_text;
9506 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9507 struct strlist **spp;
9508 char *p;
9509
9510 spp = varlist.lastp;
9511 expandarg(argp, &varlist, EXP_VARTILDE);
9512
9513 /*
9514 * Modify the command lookup path, if a PATH= assignment
9515 * is present
9516 */
9517 p = (*spp)->text;
9518 if (varcmp(p, path) == 0)
9519 path = p;
9520 }
9521
9522 /* Print the command if xflag is set. */
9523 if (xflag) {
9524 int n;
9525 const char *p = " %s" + 1;
9526
9527 fdprintf(preverrout_fd, p, expandstr(ps4val()));
9528 sp = varlist.list;
9529 for (n = 0; n < 2; n++) {
9530 while (sp) {
9531 fdprintf(preverrout_fd, p, sp->text);
9532 sp = sp->next;
9533 p = " %s";
9534 }
9535 sp = arglist.list;
9536 }
9537 safe_write(preverrout_fd, "\n", 1);
9538 }
9539
9540 cmd_is_exec = 0;
9541 spclbltin = -1;
9542
9543 /* Now locate the command. */
9544 if (argc) {
9545 int cmd_flag = DO_ERR;
9546#if ENABLE_ASH_CMDCMD
9547 const char *oldpath = path + 5;
9548#endif
9549 path += 5;
9550 for (;;) {
9551 find_command(argv[0], &cmdentry, cmd_flag, path);
9552 if (cmdentry.cmdtype == CMDUNKNOWN) {
9553 flush_stdout_stderr();
9554 status = 127;
9555 goto bail;
9556 }
9557
9558 /* implement bltin and command here */
9559 if (cmdentry.cmdtype != CMDBUILTIN)
9560 break;
9561 if (spclbltin < 0)
9562 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9563 if (cmdentry.u.cmd == EXECCMD)
9564 cmd_is_exec = 1;
9565#if ENABLE_ASH_CMDCMD
9566 if (cmdentry.u.cmd == COMMANDCMD) {
9567 path = oldpath;
9568 nargv = parse_command_args(argv, &path);
9569 if (!nargv)
9570 break;
9571 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9572 * nargv => "PROG". path is updated if -p.
9573 */
9574 argc -= nargv - argv;
9575 argv = nargv;
9576 cmd_flag |= DO_NOFUNC;
9577 } else
9578#endif
9579 break;
9580 }
9581 }
9582
9583 if (status) {
9584 /* We have a redirection error. */
9585 if (spclbltin > 0)
9586 raise_exception(EXERROR);
9587 bail:
9588 exitstatus = status;
9589 goto out;
9590 }
9591
9592 /* Execute the command. */
9593 switch (cmdentry.cmdtype) {
9594 default: {
9595
9596#if ENABLE_FEATURE_SH_NOFORK
9597/* (1) BUG: if variables are set, we need to fork, or save/restore them
9598 * around run_nofork_applet() call.
9599 * (2) Should this check also be done in forkshell()?
9600 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9601 */
9602 /* find_command() encodes applet_no as (-2 - applet_no) */
9603 int applet_no = (- cmdentry.u.index - 2);
9604 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
9605 listsetvar(varlist.list, VEXPORT|VSTACK);
9606 /* run <applet>_main() */
9607 status = run_nofork_applet(applet_no, argv);
9608 break;
9609 }
9610#endif
9611 /* Can we avoid forking off? For example, very last command
9612 * in a script or a subshell does not need forking,
9613 * we can just exec it.
9614 */
9615 if (!(flags & EV_EXIT) || may_have_traps) {
9616 /* No, forking off a child is necessary */
9617 INT_OFF;
9618 jp = makejob(/*cmd,*/ 1);
9619 if (forkshell(jp, cmd, FORK_FG) != 0) {
9620 /* parent */
9621 status = waitforjob(jp);
9622 INT_ON;
9623 TRACE(("forked child exited with %d\n", status));
9624 break;
9625 }
9626 /* child */
9627 FORCE_INT_ON;
9628 /* fall through to exec'ing external program */
9629 }
9630 listsetvar(varlist.list, VEXPORT|VSTACK);
9631 shellexec(argv, path, cmdentry.u.index);
9632 /* NOTREACHED */
9633 } /* default */
9634 case CMDBUILTIN:
9635 cmdenviron = varlist.list;
9636 if (cmdenviron) {
9637 struct strlist *list = cmdenviron;
9638 int i = VNOSET;
9639 if (spclbltin > 0 || argc == 0) {
9640 i = 0;
9641 if (cmd_is_exec && argc > 1)
9642 i = VEXPORT;
9643 }
9644 listsetvar(list, i);
9645 }
9646 /* Tight loop with builtins only:
9647 * "while kill -0 $child; do true; done"
9648 * will never exit even if $child died, unless we do this
9649 * to reap the zombie and make kill detect that it's gone: */
9650 dowait(DOWAIT_NONBLOCK, NULL);
9651
9652 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
9653 if (exception_type == EXERROR && spclbltin <= 0) {
9654 FORCE_INT_ON;
9655 goto readstatus;
9656 }
9657 raise:
9658 longjmp(exception_handler->loc, 1);
9659 }
9660 goto readstatus;
9661
9662 case CMDFUNCTION:
9663 listsetvar(varlist.list, 0);
9664 /* See above for the rationale */
9665 dowait(DOWAIT_NONBLOCK, NULL);
9666 if (evalfun(cmdentry.u.func, argc, argv, flags))
9667 goto raise;
9668 readstatus:
9669 status = exitstatus;
9670 break;
9671 } /* switch */
9672
9673 out:
9674 if (cmd->ncmd.redirect)
9675 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
9676 if (lastarg) {
9677 /* dsl: I think this is intended to be used to support
9678 * '_' in 'vi' command mode during line editing...
9679 * However I implemented that within libedit itself.
9680 */
9681 setvar0("_", lastarg);
9682 }
9683 popstackmark(&smark);
9684
9685 return status;
9686}
9687
9688static int
9689evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
9690{
9691 char *volatile savecmdname;
9692 struct jmploc *volatile savehandler;
9693 struct jmploc jmploc;
9694 int status;
9695 int i;
9696
9697 savecmdname = commandname;
9698 savehandler = exception_handler;
9699 i = setjmp(jmploc.loc);
9700 if (i)
9701 goto cmddone;
9702 exception_handler = &jmploc;
9703 commandname = argv[0];
9704 argptr = argv + 1;
9705 optptr = NULL; /* initialize nextopt */
9706 if (cmd == EVALCMD)
9707 status = evalcmd(argc, argv, flags);
9708 else
9709 status = (*cmd->builtin)(argc, argv);
9710 flush_stdout_stderr();
9711 status |= ferror(stdout);
9712 exitstatus = status;
9713 cmddone:
9714 clearerr(stdout);
9715 commandname = savecmdname;
9716 exception_handler = savehandler;
9717
9718 return i;
9719}
9720
9721static int
9722goodname(const char *p)
9723{
9724 return endofname(p)[0] == '\0';
9725}
9726
9727
9728/*
9729 * Search for a command. This is called before we fork so that the
9730 * location of the command will be available in the parent as well as
9731 * the child. The check for "goodname" is an overly conservative
9732 * check that the name will not be subject to expansion.
9733 */
9734static void
9735prehash(union node *n)
9736{
9737 struct cmdentry entry;
9738
9739 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9740 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9741}
9742
9743
9744/* ============ Builtin commands
9745 *
9746 * Builtin commands whose functions are closely tied to evaluation
9747 * are implemented here.
9748 */
9749
9750/*
9751 * Handle break and continue commands. Break, continue, and return are
9752 * all handled by setting the evalskip flag. The evaluation routines
9753 * above all check this flag, and if it is set they start skipping
9754 * commands rather than executing them. The variable skipcount is
9755 * the number of loops to break/continue, or the number of function
9756 * levels to return. (The latter is always 1.) It should probably
9757 * be an error to break out of more loops than exist, but it isn't
9758 * in the standard shell so we don't make it one here.
9759 */
9760static int FAST_FUNC
9761breakcmd(int argc UNUSED_PARAM, char **argv)
9762{
9763 int n = argv[1] ? number(argv[1]) : 1;
9764
9765 if (n <= 0)
9766 ash_msg_and_raise_error(msg_illnum, argv[1]);
9767 if (n > loopnest)
9768 n = loopnest;
9769 if (n > 0) {
9770 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9771 skipcount = n;
9772 }
9773 return 0;
9774}
9775
9776
9777/*
9778 * This implements the input routines used by the parser.
9779 */
9780
9781enum {
9782 INPUT_PUSH_FILE = 1,
9783 INPUT_NOFILE_OK = 2,
9784};
9785
9786static smallint checkkwd;
9787/* values of checkkwd variable */
9788#define CHKALIAS 0x1
9789#define CHKKWD 0x2
9790#define CHKNL 0x4
9791
9792/*
9793 * Push a string back onto the input at this current parsefile level.
9794 * We handle aliases this way.
9795 */
9796#if !ENABLE_ASH_ALIAS
9797#define pushstring(s, ap) pushstring(s)
9798#endif
9799static void
9800pushstring(char *s, struct alias *ap)
9801{
9802 struct strpush *sp;
9803 int len;
9804
9805 len = strlen(s);
9806 INT_OFF;
9807 if (g_parsefile->strpush) {
9808 sp = ckzalloc(sizeof(*sp));
9809 sp->prev = g_parsefile->strpush;
9810 } else {
9811 sp = &(g_parsefile->basestrpush);
9812 }
9813 g_parsefile->strpush = sp;
9814 sp->prev_string = g_parsefile->next_to_pgetc;
9815 sp->prev_left_in_line = g_parsefile->left_in_line;
9816 sp->unget = g_parsefile->unget;
9817 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
9818#if ENABLE_ASH_ALIAS
9819 sp->ap = ap;
9820 if (ap) {
9821 ap->flag |= ALIASINUSE;
9822 sp->string = s;
9823 }
9824#endif
9825 g_parsefile->next_to_pgetc = s;
9826 g_parsefile->left_in_line = len;
9827 g_parsefile->unget = 0;
9828 INT_ON;
9829}
9830
9831static void
9832popstring(void)
9833{
9834 struct strpush *sp = g_parsefile->strpush;
9835
9836 INT_OFF;
9837#if ENABLE_ASH_ALIAS
9838 if (sp->ap) {
9839 if (g_parsefile->next_to_pgetc[-1] == ' '
9840 || g_parsefile->next_to_pgetc[-1] == '\t'
9841 ) {
9842 checkkwd |= CHKALIAS;
9843 }
9844 if (sp->string != sp->ap->val) {
9845 free(sp->string);
9846 }
9847 sp->ap->flag &= ~ALIASINUSE;
9848 if (sp->ap->flag & ALIASDEAD) {
9849 unalias(sp->ap->name);
9850 }
9851 }
9852#endif
9853 g_parsefile->next_to_pgetc = sp->prev_string;
9854 g_parsefile->left_in_line = sp->prev_left_in_line;
9855 g_parsefile->unget = sp->unget;
9856 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
9857 g_parsefile->strpush = sp->prev;
9858 if (sp != &(g_parsefile->basestrpush))
9859 free(sp);
9860 INT_ON;
9861}
9862
9863static int
9864preadfd(void)
9865{
9866 int nr;
9867 char *buf = g_parsefile->buf;
9868
9869 g_parsefile->next_to_pgetc = buf;
9870#if ENABLE_FEATURE_EDITING
9871 retry:
9872 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
9873 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
9874 else {
9875 int timeout = -1;
9876# if ENABLE_ASH_IDLE_TIMEOUT
9877 if (iflag) {
9878 const char *tmout_var = lookupvar("TMOUT");
9879 if (tmout_var) {
9880 timeout = atoi(tmout_var) * 1000;
9881 if (timeout <= 0)
9882 timeout = -1;
9883 }
9884 }
9885# endif
9886# if ENABLE_FEATURE_TAB_COMPLETION
9887 line_input_state->path_lookup = pathval();
9888# endif
9889 reinit_unicode_for_ash();
9890 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
9891 if (nr == 0) {
9892 /* ^C pressed, "convert" to SIGINT */
9893 write(STDOUT_FILENO, "^C", 2);
9894 if (trap[SIGINT]) {
9895 buf[0] = '\n';
9896 buf[1] = '\0';
9897 raise(SIGINT);
9898 return 1;
9899 }
9900 exitstatus = 128 + SIGINT;
9901 bb_putchar('\n');
9902 goto retry;
9903 }
9904 if (nr < 0) {
9905 if (errno == 0) {
9906 /* Ctrl+D pressed */
9907 nr = 0;
9908 }
9909# if ENABLE_ASH_IDLE_TIMEOUT
9910 else if (errno == EAGAIN && timeout > 0) {
9911 puts("\007timed out waiting for input: auto-logout");
9912 exitshell();
9913 }
9914# endif
9915 }
9916 }
9917#else
9918 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
9919#endif
9920
9921#if 0 /* disabled: nonblock_immune_read() handles this problem */
9922 if (nr < 0) {
9923 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9924 int flags = fcntl(0, F_GETFL);
9925 if (flags >= 0 && (flags & O_NONBLOCK)) {
9926 flags &= ~O_NONBLOCK;
9927 if (fcntl(0, F_SETFL, flags) >= 0) {
9928 out2str("sh: turning off NDELAY mode\n");
9929 goto retry;
9930 }
9931 }
9932 }
9933 }
9934#endif
9935 return nr;
9936}
9937
9938/*
9939 * Refill the input buffer and return the next input character:
9940 *
9941 * 1) If a string was pushed back on the input, pop it;
9942 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9943 * or we are reading from a string so we can't refill the buffer,
9944 * return EOF.
9945 * 3) If there is more stuff in this buffer, use it else call read to fill it.
9946 * 4) Process input up to the next newline, deleting nul characters.
9947 */
9948//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9949#define pgetc_debug(...) ((void)0)
9950static int pgetc(void);
9951static int
9952preadbuffer(void)
9953{
9954 char *q;
9955 int more;
9956
9957 if (g_parsefile->strpush) {
9958#if ENABLE_ASH_ALIAS
9959 if (g_parsefile->left_in_line == -1
9960 && g_parsefile->strpush->ap
9961 && g_parsefile->next_to_pgetc[-1] != ' '
9962 && g_parsefile->next_to_pgetc[-1] != '\t'
9963 ) {
9964 pgetc_debug("preadbuffer PEOA");
9965 return PEOA;
9966 }
9967#endif
9968 popstring();
9969 return pgetc();
9970 }
9971 /* on both branches above g_parsefile->left_in_line < 0.
9972 * "pgetc" needs refilling.
9973 */
9974
9975 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
9976 * pungetc() may increment it a few times.
9977 * Assuming it won't increment it to less than -90.
9978 */
9979 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
9980 pgetc_debug("preadbuffer PEOF1");
9981 /* even in failure keep left_in_line and next_to_pgetc
9982 * in lock step, for correct multi-layer pungetc.
9983 * left_in_line was decremented before preadbuffer(),
9984 * must inc next_to_pgetc: */
9985 g_parsefile->next_to_pgetc++;
9986 return PEOF;
9987 }
9988
9989 more = g_parsefile->left_in_buffer;
9990 if (more <= 0) {
9991 flush_stdout_stderr();
9992 again:
9993 more = preadfd();
9994 if (more <= 0) {
9995 /* don't try reading again */
9996 g_parsefile->left_in_line = -99;
9997 pgetc_debug("preadbuffer PEOF2");
9998 g_parsefile->next_to_pgetc++;
9999 return PEOF;
10000 }
10001 }
10002
10003 /* Find out where's the end of line.
10004 * Set g_parsefile->left_in_line
10005 * and g_parsefile->left_in_buffer acordingly.
10006 * NUL chars are deleted.
10007 */
10008 q = g_parsefile->next_to_pgetc;
10009 for (;;) {
10010 char c;
10011
10012 more--;
10013
10014 c = *q;
10015 if (c == '\0') {
10016 memmove(q, q + 1, more);
10017 } else {
10018 q++;
10019 if (c == '\n') {
10020 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10021 break;
10022 }
10023 }
10024
10025 if (more <= 0) {
10026 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10027 if (g_parsefile->left_in_line < 0)
10028 goto again;
10029 break;
10030 }
10031 }
10032 g_parsefile->left_in_buffer = more;
10033
10034 if (vflag) {
10035 char save = *q;
10036 *q = '\0';
10037 out2str(g_parsefile->next_to_pgetc);
10038 *q = save;
10039 }
10040
10041 pgetc_debug("preadbuffer at %d:%p'%s'",
10042 g_parsefile->left_in_line,
10043 g_parsefile->next_to_pgetc,
10044 g_parsefile->next_to_pgetc);
10045 return (unsigned char)*g_parsefile->next_to_pgetc++;
10046}
10047
10048static void
10049nlprompt(void)
10050{
10051 g_parsefile->linno++;
10052 setprompt_if(doprompt, 2);
10053}
10054static void
10055nlnoprompt(void)
10056{
10057 g_parsefile->linno++;
10058 needprompt = doprompt;
10059}
10060
10061static int
10062pgetc(void)
10063{
10064 int c;
10065
10066 pgetc_debug("pgetc at %d:%p'%s'",
10067 g_parsefile->left_in_line,
10068 g_parsefile->next_to_pgetc,
10069 g_parsefile->next_to_pgetc);
10070 if (g_parsefile->unget)
10071 return g_parsefile->lastc[--g_parsefile->unget];
10072
10073 if (--g_parsefile->left_in_line >= 0)
10074 c = (unsigned char)*g_parsefile->next_to_pgetc++;
10075 else
10076 c = preadbuffer();
10077
10078 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10079 g_parsefile->lastc[0] = c;
10080
10081 return c;
10082}
10083
10084#if ENABLE_ASH_ALIAS
10085static int
10086pgetc_without_PEOA(void)
10087{
10088 int c;
10089 do {
10090 pgetc_debug("pgetc at %d:%p'%s'",
10091 g_parsefile->left_in_line,
10092 g_parsefile->next_to_pgetc,
10093 g_parsefile->next_to_pgetc);
10094 c = pgetc();
10095 } while (c == PEOA);
10096 return c;
10097}
10098#else
10099# define pgetc_without_PEOA() pgetc()
10100#endif
10101
10102/*
10103 * Read a line from the script.
10104 */
10105static char *
10106pfgets(char *line, int len)
10107{
10108 char *p = line;
10109 int nleft = len;
10110 int c;
10111
10112 while (--nleft > 0) {
10113 c = pgetc_without_PEOA();
10114 if (c == PEOF) {
10115 if (p == line)
10116 return NULL;
10117 break;
10118 }
10119 *p++ = c;
10120 if (c == '\n')
10121 break;
10122 }
10123 *p = '\0';
10124 return line;
10125}
10126
10127/*
10128 * Undo a call to pgetc. Only two characters may be pushed back.
10129 * PEOF may be pushed back.
10130 */
10131static void
10132pungetc(void)
10133{
10134 g_parsefile->unget++;
10135}
10136
10137/* This one eats backslash+newline */
10138static int
10139pgetc_eatbnl(void)
10140{
10141 int c;
10142
10143 while ((c = pgetc()) == '\\') {
10144 if (pgetc() != '\n') {
10145 pungetc();
10146 break;
10147 }
10148
10149 nlprompt();
10150 }
10151
10152 return c;
10153}
10154
10155/*
10156 * To handle the "." command, a stack of input files is used. Pushfile
10157 * adds a new entry to the stack and popfile restores the previous level.
10158 */
10159static void
10160pushfile(void)
10161{
10162 struct parsefile *pf;
10163
10164 pf = ckzalloc(sizeof(*pf));
10165 pf->prev = g_parsefile;
10166 pf->pf_fd = -1;
10167 /*pf->strpush = NULL; - ckzalloc did it */
10168 /*pf->basestrpush.prev = NULL;*/
10169 /*pf->unget = 0;*/
10170 g_parsefile = pf;
10171}
10172
10173static void
10174popfile(void)
10175{
10176 struct parsefile *pf = g_parsefile;
10177
10178 if (pf == &basepf)
10179 return;
10180
10181 INT_OFF;
10182 if (pf->pf_fd >= 0)
10183 close(pf->pf_fd);
10184 free(pf->buf);
10185 while (pf->strpush)
10186 popstring();
10187 g_parsefile = pf->prev;
10188 free(pf);
10189 INT_ON;
10190}
10191
10192/*
10193 * Return to top level.
10194 */
10195static void
10196popallfiles(void)
10197{
10198 while (g_parsefile != &basepf)
10199 popfile();
10200}
10201
10202/*
10203 * Close the file(s) that the shell is reading commands from. Called
10204 * after a fork is done.
10205 */
10206static void
10207closescript(void)
10208{
10209 popallfiles();
10210 if (g_parsefile->pf_fd > 0) {
10211 close(g_parsefile->pf_fd);
10212 g_parsefile->pf_fd = 0;
10213 }
10214}
10215
10216/*
10217 * Like setinputfile, but takes an open file descriptor. Call this with
10218 * interrupts off.
10219 */
10220static void
10221setinputfd(int fd, int push)
10222{
10223 if (push) {
10224 pushfile();
10225 g_parsefile->buf = NULL;
10226 }
10227 g_parsefile->pf_fd = fd;
10228 if (g_parsefile->buf == NULL)
10229 g_parsefile->buf = ckmalloc(IBUFSIZ);
10230 g_parsefile->left_in_buffer = 0;
10231 g_parsefile->left_in_line = 0;
10232 g_parsefile->linno = 1;
10233}
10234
10235/*
10236 * Set the input to take input from a file. If push is set, push the
10237 * old input onto the stack first.
10238 */
10239static int
10240setinputfile(const char *fname, int flags)
10241{
10242 int fd;
10243
10244 INT_OFF;
10245 fd = open(fname, O_RDONLY);
10246 if (fd < 0) {
10247 if (flags & INPUT_NOFILE_OK)
10248 goto out;
10249 exitstatus = 127;
10250 ash_msg_and_raise_error("can't open '%s'", fname);
10251 }
10252 if (fd < 10)
10253 fd = savefd(fd);
10254 else
10255 close_on_exec_on(fd);
10256 setinputfd(fd, flags & INPUT_PUSH_FILE);
10257 out:
10258 INT_ON;
10259 return fd;
10260}
10261
10262/*
10263 * Like setinputfile, but takes input from a string.
10264 */
10265static void
10266setinputstring(char *string)
10267{
10268 INT_OFF;
10269 pushfile();
10270 g_parsefile->next_to_pgetc = string;
10271 g_parsefile->left_in_line = strlen(string);
10272 g_parsefile->buf = NULL;
10273 g_parsefile->linno = 1;
10274 INT_ON;
10275}
10276
10277
10278/*
10279 * Routines to check for mail.
10280 */
10281
10282#if ENABLE_ASH_MAIL
10283
10284/* Hash of mtimes of mailboxes */
10285static unsigned mailtime_hash;
10286/* Set if MAIL or MAILPATH is changed. */
10287static smallint mail_var_path_changed;
10288
10289/*
10290 * Print appropriate message(s) if mail has arrived.
10291 * If mail_var_path_changed is set,
10292 * then the value of MAIL has mail_var_path_changed,
10293 * so we just update the values.
10294 */
10295static void
10296chkmail(void)
10297{
10298 const char *mpath;
10299 char *p;
10300 char *q;
10301 unsigned new_hash;
10302 struct stackmark smark;
10303 struct stat statb;
10304
10305 setstackmark(&smark);
10306 mpath = mpathset() ? mpathval() : mailval();
10307 new_hash = 0;
10308 for (;;) {
10309 p = path_advance(&mpath, nullstr);
10310 if (p == NULL)
10311 break;
10312 if (*p == '\0')
10313 continue;
10314 for (q = p; *q; q++)
10315 continue;
10316#if DEBUG
10317 if (q[-1] != '/')
10318 abort();
10319#endif
10320 q[-1] = '\0'; /* delete trailing '/' */
10321 if (stat(p, &statb) < 0) {
10322 continue;
10323 }
10324 /* Very simplistic "hash": just a sum of all mtimes */
10325 new_hash += (unsigned)statb.st_mtime;
10326 }
10327 if (!mail_var_path_changed && mailtime_hash != new_hash) {
10328 if (mailtime_hash != 0)
10329 out2str("you have mail\n");
10330 mailtime_hash = new_hash;
10331 }
10332 mail_var_path_changed = 0;
10333 popstackmark(&smark);
10334}
10335
10336static void FAST_FUNC
10337changemail(const char *val UNUSED_PARAM)
10338{
10339 mail_var_path_changed = 1;
10340}
10341
10342#endif /* ASH_MAIL */
10343
10344
10345/* ============ ??? */
10346
10347/*
10348 * Set the shell parameters.
10349 */
10350static void
10351setparam(char **argv)
10352{
10353 char **newparam;
10354 char **ap;
10355 int nparam;
10356
10357 for (nparam = 0; argv[nparam]; nparam++)
10358 continue;
10359 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10360 while (*argv) {
10361 *ap++ = ckstrdup(*argv++);
10362 }
10363 *ap = NULL;
10364 freeparam(&shellparam);
10365 shellparam.malloced = 1;
10366 shellparam.nparam = nparam;
10367 shellparam.p = newparam;
10368#if ENABLE_ASH_GETOPTS
10369 shellparam.optind = 1;
10370 shellparam.optoff = -1;
10371#endif
10372}
10373
10374/*
10375 * Process shell options. The global variable argptr contains a pointer
10376 * to the argument list; we advance it past the options.
10377 *
10378 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10379 * For a non-interactive shell, an error condition encountered
10380 * by a special built-in ... shall cause the shell to write a diagnostic message
10381 * to standard error and exit as shown in the following table:
10382 * Error Special Built-In
10383 * ...
10384 * Utility syntax error (option or operand error) Shall exit
10385 * ...
10386 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10387 * we see that bash does not do that (set "finishes" with error code 1 instead,
10388 * and shell continues), and people rely on this behavior!
10389 * Testcase:
10390 * set -o barfoo 2>/dev/null
10391 * echo $?
10392 *
10393 * Oh well. Let's mimic that.
10394 */
10395static int
10396plus_minus_o(char *name, int val)
10397{
10398 int i;
10399
10400 if (name) {
10401 for (i = 0; i < NOPTS; i++) {
10402 if (strcmp(name, optnames(i)) == 0) {
10403 optlist[i] = val;
10404 return 0;
10405 }
10406 }
10407 ash_msg("illegal option %co %s", val ? '-' : '+', name);
10408 return 1;
10409 }
10410 for (i = 0; i < NOPTS; i++) {
10411 if (val) {
10412 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10413 } else {
10414 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10415 }
10416 }
10417 return 0;
10418}
10419static void
10420setoption(int flag, int val)
10421{
10422 int i;
10423
10424 for (i = 0; i < NOPTS; i++) {
10425 if (optletters(i) == flag) {
10426 optlist[i] = val;
10427 return;
10428 }
10429 }
10430 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
10431 /* NOTREACHED */
10432}
10433static int
10434options(int cmdline)
10435{
10436 char *p;
10437 int val;
10438 int c;
10439
10440 if (cmdline)
10441 minusc = NULL;
10442 while ((p = *argptr) != NULL) {
10443 c = *p++;
10444 if (c != '-' && c != '+')
10445 break;
10446 argptr++;
10447 val = 0; /* val = 0 if c == '+' */
10448 if (c == '-') {
10449 val = 1;
10450 if (p[0] == '\0' || LONE_DASH(p)) {
10451 if (!cmdline) {
10452 /* "-" means turn off -x and -v */
10453 if (p[0] == '\0')
10454 xflag = vflag = 0;
10455 /* "--" means reset params */
10456 else if (*argptr == NULL)
10457 setparam(argptr);
10458 }
10459 break; /* "-" or "--" terminates options */
10460 }
10461 }
10462 /* first char was + or - */
10463 while ((c = *p++) != '\0') {
10464 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
10465 if (c == 'c' && cmdline) {
10466 minusc = p; /* command is after shell args */
10467 } else if (c == 'o') {
10468 if (plus_minus_o(*argptr, val)) {
10469 /* it already printed err message */
10470 return 1; /* error */
10471 }
10472 if (*argptr)
10473 argptr++;
10474 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10475 isloginsh = 1;
10476 /* bash does not accept +-login, we also won't */
10477 } else if (cmdline && val && (c == '-')) { /* long options */
10478 if (strcmp(p, "login") == 0)
10479 isloginsh = 1;
10480 break;
10481 } else {
10482 setoption(c, val);
10483 }
10484 }
10485 }
10486 return 0;
10487}
10488
10489/*
10490 * The shift builtin command.
10491 */
10492static int FAST_FUNC
10493shiftcmd(int argc UNUSED_PARAM, char **argv)
10494{
10495 int n;
10496 char **ap1, **ap2;
10497
10498 n = 1;
10499 if (argv[1])
10500 n = number(argv[1]);
10501 if (n > shellparam.nparam)
10502 n = 0; /* bash compat, was = shellparam.nparam; */
10503 INT_OFF;
10504 shellparam.nparam -= n;
10505 for (ap1 = shellparam.p; --n >= 0; ap1++) {
10506 if (shellparam.malloced)
10507 free(*ap1);
10508 }
10509 ap2 = shellparam.p;
10510 while ((*ap2++ = *ap1++) != NULL)
10511 continue;
10512#if ENABLE_ASH_GETOPTS
10513 shellparam.optind = 1;
10514 shellparam.optoff = -1;
10515#endif
10516 INT_ON;
10517 return 0;
10518}
10519
10520/*
10521 * POSIX requires that 'set' (but not export or readonly) output the
10522 * variables in lexicographic order - by the locale's collating order (sigh).
10523 * Maybe we could keep them in an ordered balanced binary tree
10524 * instead of hashed lists.
10525 * For now just roll 'em through qsort for printing...
10526 */
10527static int
10528showvars(const char *sep_prefix, int on, int off)
10529{
10530 const char *sep;
10531 char **ep, **epend;
10532
10533 ep = listvars(on, off, &epend);
10534 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10535
10536 sep = *sep_prefix ? " " : sep_prefix;
10537
10538 for (; ep < epend; ep++) {
10539 const char *p;
10540 const char *q;
10541
10542 p = strchrnul(*ep, '=');
10543 q = nullstr;
10544 if (*p)
10545 q = single_quote(++p);
10546 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10547 }
10548 return 0;
10549}
10550
10551/*
10552 * The set command builtin.
10553 */
10554static int FAST_FUNC
10555setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10556{
10557 int retval;
10558
10559 if (!argv[1])
10560 return showvars(nullstr, 0, VUNSET);
10561
10562 INT_OFF;
10563 retval = options(/*cmdline:*/ 0);
10564 if (retval == 0) { /* if no parse error... */
10565 optschanged();
10566 if (*argptr != NULL) {
10567 setparam(argptr);
10568 }
10569 }
10570 INT_ON;
10571 return retval;
10572}
10573
10574#if ENABLE_ASH_RANDOM_SUPPORT
10575static void FAST_FUNC
10576change_random(const char *value)
10577{
10578 uint32_t t;
10579
10580 if (value == NULL) {
10581 /* "get", generate */
10582 t = next_random(&random_gen);
10583 /* set without recursion */
10584 setvar(vrandom.var_text, utoa(t), VNOFUNC);
10585 vrandom.flags &= ~VNOFUNC;
10586 } else {
10587 /* set/reset */
10588 t = strtoul(value, NULL, 10);
10589 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
10590 }
10591}
10592#endif
10593
10594#if ENABLE_ASH_GETOPTS
10595static int
10596getopts(char *optstr, char *optvar, char **optfirst)
10597{
10598 char *p, *q;
10599 char c = '?';
10600 int done = 0;
10601 char sbuf[2];
10602 char **optnext;
10603 int ind = shellparam.optind;
10604 int off = shellparam.optoff;
10605
10606 sbuf[1] = '\0';
10607
10608 shellparam.optind = -1;
10609 optnext = optfirst + ind - 1;
10610
10611 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
10612 p = NULL;
10613 else
10614 p = optnext[-1] + off;
10615 if (p == NULL || *p == '\0') {
10616 /* Current word is done, advance */
10617 p = *optnext;
10618 if (p == NULL || *p != '-' || *++p == '\0') {
10619 atend:
10620 p = NULL;
10621 done = 1;
10622 goto out;
10623 }
10624 optnext++;
10625 if (LONE_DASH(p)) /* check for "--" */
10626 goto atend;
10627 }
10628
10629 c = *p++;
10630 for (q = optstr; *q != c;) {
10631 if (*q == '\0') {
10632 if (optstr[0] == ':') {
10633 sbuf[0] = c;
10634 /*sbuf[1] = '\0'; - already is */
10635 setvar0("OPTARG", sbuf);
10636 } else {
10637 fprintf(stderr, "Illegal option -%c\n", c);
10638 unsetvar("OPTARG");
10639 }
10640 c = '?';
10641 goto out;
10642 }
10643 if (*++q == ':')
10644 q++;
10645 }
10646
10647 if (*++q == ':') {
10648 if (*p == '\0' && (p = *optnext) == NULL) {
10649 if (optstr[0] == ':') {
10650 sbuf[0] = c;
10651 /*sbuf[1] = '\0'; - already is */
10652 setvar0("OPTARG", sbuf);
10653 c = ':';
10654 } else {
10655 fprintf(stderr, "No arg for -%c option\n", c);
10656 unsetvar("OPTARG");
10657 c = '?';
10658 }
10659 goto out;
10660 }
10661
10662 if (p == *optnext)
10663 optnext++;
10664 setvar0("OPTARG", p);
10665 p = NULL;
10666 } else
10667 setvar0("OPTARG", nullstr);
10668 out:
10669 ind = optnext - optfirst + 1;
10670 setvar("OPTIND", itoa(ind), VNOFUNC);
10671 sbuf[0] = c;
10672 /*sbuf[1] = '\0'; - already is */
10673 setvar0(optvar, sbuf);
10674
10675 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10676 shellparam.optind = ind;
10677
10678 return done;
10679}
10680
10681/*
10682 * The getopts builtin. Shellparam.optnext points to the next argument
10683 * to be processed. Shellparam.optptr points to the next character to
10684 * be processed in the current argument. If shellparam.optnext is NULL,
10685 * then it's the first time getopts has been called.
10686 */
10687static int FAST_FUNC
10688getoptscmd(int argc, char **argv)
10689{
10690 char **optbase;
10691
10692 if (argc < 3)
10693 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
10694 if (argc == 3) {
10695 optbase = shellparam.p;
10696 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
10697 shellparam.optind = 1;
10698 shellparam.optoff = -1;
10699 }
10700 } else {
10701 optbase = &argv[3];
10702 if ((unsigned)shellparam.optind > argc - 2) {
10703 shellparam.optind = 1;
10704 shellparam.optoff = -1;
10705 }
10706 }
10707
10708 return getopts(argv[1], argv[2], optbase);
10709}
10710#endif /* ASH_GETOPTS */
10711
10712
10713/* ============ Shell parser */
10714
10715struct heredoc {
10716 struct heredoc *next; /* next here document in list */
10717 union node *here; /* redirection node */
10718 char *eofmark; /* string indicating end of input */
10719 smallint striptabs; /* if set, strip leading tabs */
10720};
10721
10722static smallint tokpushback; /* last token pushed back */
10723static smallint quoteflag; /* set if (part of) last token was quoted */
10724static token_id_t lasttoken; /* last token read (integer id Txxx) */
10725static struct heredoc *heredoclist; /* list of here documents to read */
10726static char *wordtext; /* text of last word returned by readtoken */
10727static struct nodelist *backquotelist;
10728static union node *redirnode;
10729static struct heredoc *heredoc;
10730
10731static const char *
10732tokname(char *buf, int tok)
10733{
10734 if (tok < TSEMI)
10735 return tokname_array[tok];
10736 sprintf(buf, "\"%s\"", tokname_array[tok]);
10737 return buf;
10738}
10739
10740/* raise_error_unexpected_syntax:
10741 * Called when an unexpected token is read during the parse. The argument
10742 * is the token that is expected, or -1 if more than one type of token can
10743 * occur at this point.
10744 */
10745static void raise_error_unexpected_syntax(int) NORETURN;
10746static void
10747raise_error_unexpected_syntax(int token)
10748{
10749 char msg[64];
10750 char buf[16];
10751 int l;
10752
10753 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
10754 if (token >= 0)
10755 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
10756 raise_error_syntax(msg);
10757 /* NOTREACHED */
10758}
10759
10760#define EOFMARKLEN 79
10761
10762/* parsing is heavily cross-recursive, need these forward decls */
10763static union node *andor(void);
10764static union node *pipeline(void);
10765static union node *parse_command(void);
10766static void parseheredoc(void);
10767static int peektoken(void);
10768static int readtoken(void);
10769
10770static union node *
10771list(int nlflag)
10772{
10773 union node *n1, *n2, *n3;
10774 int tok;
10775
10776 n1 = NULL;
10777 for (;;) {
10778 switch (peektoken()) {
10779 case TNL:
10780 if (!(nlflag & 1))
10781 break;
10782 parseheredoc();
10783 return n1;
10784
10785 case TEOF:
10786 if (!n1 && (nlflag & 1))
10787 n1 = NODE_EOF;
10788 parseheredoc();
10789 return n1;
10790 }
10791
10792 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10793 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
10794 return n1;
10795 nlflag |= 2;
10796
10797 n2 = andor();
10798 tok = readtoken();
10799 if (tok == TBACKGND) {
10800 if (n2->type == NPIPE) {
10801 n2->npipe.pipe_backgnd = 1;
10802 } else {
10803 if (n2->type != NREDIR) {
10804 n3 = stzalloc(sizeof(struct nredir));
10805 n3->nredir.n = n2;
10806 /*n3->nredir.redirect = NULL; - stzalloc did it */
10807 n2 = n3;
10808 }
10809 n2->type = NBACKGND;
10810 }
10811 }
10812 if (n1 == NULL) {
10813 n1 = n2;
10814 } else {
10815 n3 = stzalloc(sizeof(struct nbinary));
10816 n3->type = NSEMI;
10817 n3->nbinary.ch1 = n1;
10818 n3->nbinary.ch2 = n2;
10819 n1 = n3;
10820 }
10821 switch (tok) {
10822 case TNL:
10823 case TEOF:
10824 tokpushback = 1;
10825 /* fall through */
10826 case TBACKGND:
10827 case TSEMI:
10828 break;
10829 default:
10830 if ((nlflag & 1))
10831 raise_error_unexpected_syntax(-1);
10832 tokpushback = 1;
10833 return n1;
10834 }
10835 }
10836}
10837
10838static union node *
10839andor(void)
10840{
10841 union node *n1, *n2, *n3;
10842 int t;
10843
10844 n1 = pipeline();
10845 for (;;) {
10846 t = readtoken();
10847 if (t == TAND) {
10848 t = NAND;
10849 } else if (t == TOR) {
10850 t = NOR;
10851 } else {
10852 tokpushback = 1;
10853 return n1;
10854 }
10855 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10856 n2 = pipeline();
10857 n3 = stzalloc(sizeof(struct nbinary));
10858 n3->type = t;
10859 n3->nbinary.ch1 = n1;
10860 n3->nbinary.ch2 = n2;
10861 n1 = n3;
10862 }
10863}
10864
10865static union node *
10866pipeline(void)
10867{
10868 union node *n1, *n2, *pipenode;
10869 struct nodelist *lp, *prev;
10870 int negate;
10871
10872 negate = 0;
10873 TRACE(("pipeline: entered\n"));
10874 if (readtoken() == TNOT) {
10875 negate = !negate;
10876 checkkwd = CHKKWD | CHKALIAS;
10877 } else
10878 tokpushback = 1;
10879 n1 = parse_command();
10880 if (readtoken() == TPIPE) {
10881 pipenode = stzalloc(sizeof(struct npipe));
10882 pipenode->type = NPIPE;
10883 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10884 lp = stzalloc(sizeof(struct nodelist));
10885 pipenode->npipe.cmdlist = lp;
10886 lp->n = n1;
10887 do {
10888 prev = lp;
10889 lp = stzalloc(sizeof(struct nodelist));
10890 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10891 lp->n = parse_command();
10892 prev->next = lp;
10893 } while (readtoken() == TPIPE);
10894 lp->next = NULL;
10895 n1 = pipenode;
10896 }
10897 tokpushback = 1;
10898 if (negate) {
10899 n2 = stzalloc(sizeof(struct nnot));
10900 n2->type = NNOT;
10901 n2->nnot.com = n1;
10902 return n2;
10903 }
10904 return n1;
10905}
10906
10907static union node *
10908makename(void)
10909{
10910 union node *n;
10911
10912 n = stzalloc(sizeof(struct narg));
10913 n->type = NARG;
10914 /*n->narg.next = NULL; - stzalloc did it */
10915 n->narg.text = wordtext;
10916 n->narg.backquote = backquotelist;
10917 return n;
10918}
10919
10920static void
10921fixredir(union node *n, const char *text, int err)
10922{
10923 int fd;
10924
10925 TRACE(("Fix redir %s %d\n", text, err));
10926 if (!err)
10927 n->ndup.vname = NULL;
10928
10929 fd = bb_strtou(text, NULL, 10);
10930 if (!errno && fd >= 0)
10931 n->ndup.dupfd = fd;
10932 else if (LONE_DASH(text))
10933 n->ndup.dupfd = -1;
10934 else {
10935 if (err)
10936 raise_error_syntax("bad fd number");
10937 n->ndup.vname = makename();
10938 }
10939}
10940
10941/*
10942 * Returns true if the text contains nothing to expand (no dollar signs
10943 * or backquotes).
10944 */
10945static int
10946noexpand(const char *text)
10947{
10948 unsigned char c;
10949
10950 while ((c = *text++) != '\0') {
10951 if (c == CTLQUOTEMARK)
10952 continue;
10953 if (c == CTLESC)
10954 text++;
10955 else if (SIT(c, BASESYNTAX) == CCTL)
10956 return 0;
10957 }
10958 return 1;
10959}
10960
10961static void
10962parsefname(void)
10963{
10964 union node *n = redirnode;
10965
10966 if (readtoken() != TWORD)
10967 raise_error_unexpected_syntax(-1);
10968 if (n->type == NHERE) {
10969 struct heredoc *here = heredoc;
10970 struct heredoc *p;
10971 int i;
10972
10973 if (quoteflag == 0)
10974 n->type = NXHERE;
10975 TRACE(("Here document %d\n", n->type));
10976 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10977 raise_error_syntax("illegal eof marker for << redirection");
10978 rmescapes(wordtext, 0);
10979 here->eofmark = wordtext;
10980 here->next = NULL;
10981 if (heredoclist == NULL)
10982 heredoclist = here;
10983 else {
10984 for (p = heredoclist; p->next; p = p->next)
10985 continue;
10986 p->next = here;
10987 }
10988 } else if (n->type == NTOFD || n->type == NFROMFD) {
10989 fixredir(n, wordtext, 0);
10990 } else {
10991 n->nfile.fname = makename();
10992 }
10993}
10994
10995static union node *
10996simplecmd(void)
10997{
10998 union node *args, **app;
10999 union node *n = NULL;
11000 union node *vars, **vpp;
11001 union node **rpp, *redir;
11002 int savecheckkwd;
11003#if ENABLE_ASH_BASH_COMPAT
11004 smallint double_brackets_flag = 0;
11005 smallint function_flag = 0;
11006#endif
11007
11008 args = NULL;
11009 app = &args;
11010 vars = NULL;
11011 vpp = &vars;
11012 redir = NULL;
11013 rpp = &redir;
11014
11015 savecheckkwd = CHKALIAS;
11016 for (;;) {
11017 int t;
11018 checkkwd = savecheckkwd;
11019 t = readtoken();
11020 switch (t) {
11021#if ENABLE_ASH_BASH_COMPAT
11022 case TFUNCTION:
11023 if (peektoken() != TWORD)
11024 raise_error_unexpected_syntax(TWORD);
11025 function_flag = 1;
11026 break;
11027 case TAND: /* "&&" */
11028 case TOR: /* "||" */
11029 if (!double_brackets_flag) {
11030 tokpushback = 1;
11031 goto out;
11032 }
11033 wordtext = (char *) (t == TAND ? "-a" : "-o");
11034#endif
11035 case TWORD:
11036 n = stzalloc(sizeof(struct narg));
11037 n->type = NARG;
11038 /*n->narg.next = NULL; - stzalloc did it */
11039 n->narg.text = wordtext;
11040#if ENABLE_ASH_BASH_COMPAT
11041 if (strcmp("[[", wordtext) == 0)
11042 double_brackets_flag = 1;
11043 else if (strcmp("]]", wordtext) == 0)
11044 double_brackets_flag = 0;
11045#endif
11046 n->narg.backquote = backquotelist;
11047 if (savecheckkwd && isassignment(wordtext)) {
11048 *vpp = n;
11049 vpp = &n->narg.next;
11050 } else {
11051 *app = n;
11052 app = &n->narg.next;
11053 savecheckkwd = 0;
11054 }
11055#if ENABLE_ASH_BASH_COMPAT
11056 if (function_flag) {
11057 checkkwd = CHKNL | CHKKWD;
11058 switch (peektoken()) {
11059 case TBEGIN:
11060 case TIF:
11061 case TCASE:
11062 case TUNTIL:
11063 case TWHILE:
11064 case TFOR:
11065 goto do_func;
11066 case TLP:
11067 function_flag = 0;
11068 break;
11069 case TWORD:
11070 if (strcmp("[[", wordtext) == 0)
11071 goto do_func;
11072 /* fall through */
11073 default:
11074 raise_error_unexpected_syntax(-1);
11075 }
11076 }
11077#endif
11078 break;
11079 case TREDIR:
11080 *rpp = n = redirnode;
11081 rpp = &n->nfile.next;
11082 parsefname(); /* read name of redirection file */
11083 break;
11084 case TLP:
11085 IF_ASH_BASH_COMPAT(do_func:)
11086 if (args && app == &args->narg.next
11087 && !vars && !redir
11088 ) {
11089 struct builtincmd *bcmd;
11090 const char *name;
11091
11092 /* We have a function */
11093 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
11094 raise_error_unexpected_syntax(TRP);
11095 name = n->narg.text;
11096 if (!goodname(name)
11097 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11098 ) {
11099 raise_error_syntax("bad function name");
11100 }
11101 n->type = NDEFUN;
11102 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11103 n->narg.next = parse_command();
11104 return n;
11105 }
11106 IF_ASH_BASH_COMPAT(function_flag = 0;)
11107 /* fall through */
11108 default:
11109 tokpushback = 1;
11110 goto out;
11111 }
11112 }
11113 out:
11114 *app = NULL;
11115 *vpp = NULL;
11116 *rpp = NULL;
11117 n = stzalloc(sizeof(struct ncmd));
11118 n->type = NCMD;
11119 n->ncmd.args = args;
11120 n->ncmd.assign = vars;
11121 n->ncmd.redirect = redir;
11122 return n;
11123}
11124
11125static union node *
11126parse_command(void)
11127{
11128 union node *n1, *n2;
11129 union node *ap, **app;
11130 union node *cp, **cpp;
11131 union node *redir, **rpp;
11132 union node **rpp2;
11133 int t;
11134
11135 redir = NULL;
11136 rpp2 = &redir;
11137
11138 switch (readtoken()) {
11139 default:
11140 raise_error_unexpected_syntax(-1);
11141 /* NOTREACHED */
11142 case TIF:
11143 n1 = stzalloc(sizeof(struct nif));
11144 n1->type = NIF;
11145 n1->nif.test = list(0);
11146 if (readtoken() != TTHEN)
11147 raise_error_unexpected_syntax(TTHEN);
11148 n1->nif.ifpart = list(0);
11149 n2 = n1;
11150 while (readtoken() == TELIF) {
11151 n2->nif.elsepart = stzalloc(sizeof(struct nif));
11152 n2 = n2->nif.elsepart;
11153 n2->type = NIF;
11154 n2->nif.test = list(0);
11155 if (readtoken() != TTHEN)
11156 raise_error_unexpected_syntax(TTHEN);
11157 n2->nif.ifpart = list(0);
11158 }
11159 if (lasttoken == TELSE)
11160 n2->nif.elsepart = list(0);
11161 else {
11162 n2->nif.elsepart = NULL;
11163 tokpushback = 1;
11164 }
11165 t = TFI;
11166 break;
11167 case TWHILE:
11168 case TUNTIL: {
11169 int got;
11170 n1 = stzalloc(sizeof(struct nbinary));
11171 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
11172 n1->nbinary.ch1 = list(0);
11173 got = readtoken();
11174 if (got != TDO) {
11175 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
11176 got == TWORD ? wordtext : ""));
11177 raise_error_unexpected_syntax(TDO);
11178 }
11179 n1->nbinary.ch2 = list(0);
11180 t = TDONE;
11181 break;
11182 }
11183 case TFOR:
11184 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
11185 raise_error_syntax("bad for loop variable");
11186 n1 = stzalloc(sizeof(struct nfor));
11187 n1->type = NFOR;
11188 n1->nfor.var = wordtext;
11189 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11190 if (readtoken() == TIN) {
11191 app = &ap;
11192 while (readtoken() == TWORD) {
11193 n2 = stzalloc(sizeof(struct narg));
11194 n2->type = NARG;
11195 /*n2->narg.next = NULL; - stzalloc did it */
11196 n2->narg.text = wordtext;
11197 n2->narg.backquote = backquotelist;
11198 *app = n2;
11199 app = &n2->narg.next;
11200 }
11201 *app = NULL;
11202 n1->nfor.args = ap;
11203 if (lasttoken != TNL && lasttoken != TSEMI)
11204 raise_error_unexpected_syntax(-1);
11205 } else {
11206 n2 = stzalloc(sizeof(struct narg));
11207 n2->type = NARG;
11208 /*n2->narg.next = NULL; - stzalloc did it */
11209 n2->narg.text = (char *)dolatstr;
11210 /*n2->narg.backquote = NULL;*/
11211 n1->nfor.args = n2;
11212 /*
11213 * Newline or semicolon here is optional (but note
11214 * that the original Bourne shell only allowed NL).
11215 */
11216 if (lasttoken != TSEMI)
11217 tokpushback = 1;
11218 }
11219 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11220 if (readtoken() != TDO)
11221 raise_error_unexpected_syntax(TDO);
11222 n1->nfor.body = list(0);
11223 t = TDONE;
11224 break;
11225 case TCASE:
11226 n1 = stzalloc(sizeof(struct ncase));
11227 n1->type = NCASE;
11228 if (readtoken() != TWORD)
11229 raise_error_unexpected_syntax(TWORD);
11230 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
11231 n2->type = NARG;
11232 /*n2->narg.next = NULL; - stzalloc did it */
11233 n2->narg.text = wordtext;
11234 n2->narg.backquote = backquotelist;
11235 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11236 if (readtoken() != TIN)
11237 raise_error_unexpected_syntax(TIN);
11238 cpp = &n1->ncase.cases;
11239 next_case:
11240 checkkwd = CHKNL | CHKKWD;
11241 t = readtoken();
11242 while (t != TESAC) {
11243 if (lasttoken == TLP)
11244 readtoken();
11245 *cpp = cp = stzalloc(sizeof(struct nclist));
11246 cp->type = NCLIST;
11247 app = &cp->nclist.pattern;
11248 for (;;) {
11249 *app = ap = stzalloc(sizeof(struct narg));
11250 ap->type = NARG;
11251 /*ap->narg.next = NULL; - stzalloc did it */
11252 ap->narg.text = wordtext;
11253 ap->narg.backquote = backquotelist;
11254 if (readtoken() != TPIPE)
11255 break;
11256 app = &ap->narg.next;
11257 readtoken();
11258 }
11259 //ap->narg.next = NULL;
11260 if (lasttoken != TRP)
11261 raise_error_unexpected_syntax(TRP);
11262 cp->nclist.body = list(2);
11263
11264 cpp = &cp->nclist.next;
11265
11266 checkkwd = CHKNL | CHKKWD;
11267 t = readtoken();
11268 if (t != TESAC) {
11269 if (t != TENDCASE)
11270 raise_error_unexpected_syntax(TENDCASE);
11271 goto next_case;
11272 }
11273 }
11274 *cpp = NULL;
11275 goto redir;
11276 case TLP:
11277 n1 = stzalloc(sizeof(struct nredir));
11278 n1->type = NSUBSHELL;
11279 n1->nredir.n = list(0);
11280 /*n1->nredir.redirect = NULL; - stzalloc did it */
11281 t = TRP;
11282 break;
11283 case TBEGIN:
11284 n1 = list(0);
11285 t = TEND;
11286 break;
11287 IF_ASH_BASH_COMPAT(case TFUNCTION:)
11288 case TWORD:
11289 case TREDIR:
11290 tokpushback = 1;
11291 return simplecmd();
11292 }
11293
11294 if (readtoken() != t)
11295 raise_error_unexpected_syntax(t);
11296
11297 redir:
11298 /* Now check for redirection which may follow command */
11299 checkkwd = CHKKWD | CHKALIAS;
11300 rpp = rpp2;
11301 while (readtoken() == TREDIR) {
11302 *rpp = n2 = redirnode;
11303 rpp = &n2->nfile.next;
11304 parsefname();
11305 }
11306 tokpushback = 1;
11307 *rpp = NULL;
11308 if (redir) {
11309 if (n1->type != NSUBSHELL) {
11310 n2 = stzalloc(sizeof(struct nredir));
11311 n2->type = NREDIR;
11312 n2->nredir.n = n1;
11313 n1 = n2;
11314 }
11315 n1->nredir.redirect = redir;
11316 }
11317 return n1;
11318}
11319
11320#if ENABLE_ASH_BASH_COMPAT
11321static int
11322decode_dollar_squote(void)
11323{
11324 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11325 int c, cnt;
11326 char *p;
11327 char buf[4];
11328
11329 c = pgetc();
11330 p = strchr(C_escapes, c);
11331 if (p) {
11332 buf[0] = c;
11333 p = buf;
11334 cnt = 3;
11335 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11336 do {
11337 c = pgetc();
11338 *++p = c;
11339 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11340 pungetc();
11341 } else if (c == 'x') { /* \xHH */
11342 do {
11343 c = pgetc();
11344 *++p = c;
11345 } while (isxdigit(c) && --cnt);
11346 pungetc();
11347 if (cnt == 3) { /* \x but next char is "bad" */
11348 c = 'x';
11349 goto unrecognized;
11350 }
11351 } else { /* simple seq like \\ or \t */
11352 p++;
11353 }
11354 *p = '\0';
11355 p = buf;
11356 c = bb_process_escape_sequence((void*)&p);
11357 } else { /* unrecognized "\z": print both chars unless ' or " */
11358 if (c != '\'' && c != '"') {
11359 unrecognized:
11360 c |= 0x100; /* "please encode \, then me" */
11361 }
11362 }
11363 return c;
11364}
11365#endif
11366
11367/*
11368 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11369 * is not NULL, read a here document. In the latter case, eofmark is the
11370 * word which marks the end of the document and striptabs is true if
11371 * leading tabs should be stripped from the document. The argument c
11372 * is the first character of the input token or document.
11373 *
11374 * Because C does not have internal subroutines, I have simulated them
11375 * using goto's to implement the subroutine linkage. The following macros
11376 * will run code that appears at the end of readtoken1.
11377 */
11378#define CHECKEND() {goto checkend; checkend_return:;}
11379#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11380#define PARSESUB() {goto parsesub; parsesub_return:;}
11381#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11382#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11383#define PARSEARITH() {goto parsearith; parsearith_return:;}
11384static int
11385readtoken1(int c, int syntax, char *eofmark, int striptabs)
11386{
11387 /* NB: syntax parameter fits into smallint */
11388 /* c parameter is an unsigned char or PEOF or PEOA */
11389 char *out;
11390 size_t len;
11391 char line[EOFMARKLEN + 1];
11392 struct nodelist *bqlist;
11393 smallint quotef;
11394 smallint dblquote;
11395 smallint oldstyle;
11396 IF_SH_MATH_SUPPORT(smallint prevsyntax;) /* syntax before arithmetic */
11397#if ENABLE_ASH_EXPAND_PRMT
11398 smallint pssyntax; /* we are expanding a prompt string */
11399#endif
11400 int varnest; /* levels of variables expansion */
11401 IF_SH_MATH_SUPPORT(int arinest;) /* levels of arithmetic expansion */
11402 IF_SH_MATH_SUPPORT(int parenlevel;) /* levels of parens in arithmetic */
11403 int dqvarnest; /* levels of variables expansion within double quotes */
11404
11405 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
11406
11407 startlinno = g_parsefile->linno;
11408 bqlist = NULL;
11409 quotef = 0;
11410 IF_SH_MATH_SUPPORT(prevsyntax = 0;)
11411#if ENABLE_ASH_EXPAND_PRMT
11412 pssyntax = (syntax == PSSYNTAX);
11413 if (pssyntax)
11414 syntax = DQSYNTAX;
11415#endif
11416 dblquote = (syntax == DQSYNTAX);
11417 varnest = 0;
11418 IF_SH_MATH_SUPPORT(arinest = 0;)
11419 IF_SH_MATH_SUPPORT(parenlevel = 0;)
11420 dqvarnest = 0;
11421
11422 STARTSTACKSTR(out);
11423 loop:
11424 /* For each line, until end of word */
11425 CHECKEND(); /* set c to PEOF if at end of here document */
11426 for (;;) { /* until end of line or end of word */
11427 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11428 switch (SIT(c, syntax)) {
11429 case CNL: /* '\n' */
11430 if (syntax == BASESYNTAX)
11431 goto endword; /* exit outer loop */
11432 USTPUTC(c, out);
11433 nlprompt();
11434 c = pgetc();
11435 goto loop; /* continue outer loop */
11436 case CWORD:
11437 USTPUTC(c, out);
11438 break;
11439 case CCTL:
11440#if ENABLE_ASH_BASH_COMPAT
11441 if (c == '\\' && bash_dollar_squote) {
11442 c = decode_dollar_squote();
11443 if (c == '\0') {
11444 /* skip $'\000', $'\x00' (like bash) */
11445 break;
11446 }
11447 if (c & 0x100) {
11448 /* Unknown escape. Encode as '\z' */
11449 c = (unsigned char)c;
11450 if (eofmark == NULL || dblquote)
11451 USTPUTC(CTLESC, out);
11452 USTPUTC('\\', out);
11453 }
11454 }
11455#endif
11456 if (eofmark == NULL || dblquote)
11457 USTPUTC(CTLESC, out);
11458 USTPUTC(c, out);
11459 break;
11460 case CBACK: /* backslash */
11461 c = pgetc_without_PEOA();
11462 if (c == PEOF) {
11463 USTPUTC(CTLESC, out);
11464 USTPUTC('\\', out);
11465 pungetc();
11466 } else if (c == '\n') {
11467 nlprompt();
11468 } else {
11469#if ENABLE_ASH_EXPAND_PRMT
11470 if (c == '$' && pssyntax) {
11471 USTPUTC(CTLESC, out);
11472 USTPUTC('\\', out);
11473 }
11474#endif
11475 /* Backslash is retained if we are in "str" and next char isn't special */
11476 if (dblquote
11477 && c != '\\'
11478 && c != '`'
11479 && c != '$'
11480 && (c != '"' || eofmark != NULL)
11481 ) {
11482 USTPUTC('\\', out);
11483 }
11484 USTPUTC(CTLESC, out);
11485 USTPUTC(c, out);
11486 quotef = 1;
11487 }
11488 break;
11489 case CSQUOTE:
11490 syntax = SQSYNTAX;
11491 quotemark:
11492 if (eofmark == NULL) {
11493 USTPUTC(CTLQUOTEMARK, out);
11494 }
11495 break;
11496 case CDQUOTE:
11497 syntax = DQSYNTAX;
11498 dblquote = 1;
11499 goto quotemark;
11500 case CENDQUOTE:
11501 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
11502 if (eofmark != NULL && varnest == 0) {
11503 USTPUTC(c, out);
11504 } else {
11505 if (dqvarnest == 0) {
11506 syntax = BASESYNTAX;
11507 dblquote = 0;
11508 }
11509 quotef = 1;
11510 goto quotemark;
11511 }
11512 break;
11513 case CVAR: /* '$' */
11514 PARSESUB(); /* parse substitution */
11515 break;
11516 case CENDVAR: /* '}' */
11517 if (varnest > 0) {
11518 varnest--;
11519 if (dqvarnest > 0) {
11520 dqvarnest--;
11521 }
11522 c = CTLENDVAR;
11523 }
11524 USTPUTC(c, out);
11525 break;
11526#if ENABLE_SH_MATH_SUPPORT
11527 case CLP: /* '(' in arithmetic */
11528 parenlevel++;
11529 USTPUTC(c, out);
11530 break;
11531 case CRP: /* ')' in arithmetic */
11532 if (parenlevel > 0) {
11533 parenlevel--;
11534 } else {
11535 if (pgetc_eatbnl() == ')') {
11536 c = CTLENDARI;
11537 if (--arinest == 0) {
11538 syntax = prevsyntax;
11539 }
11540 } else {
11541 /*
11542 * unbalanced parens
11543 * (don't 2nd guess - no error)
11544 */
11545 pungetc();
11546 }
11547 }
11548 USTPUTC(c, out);
11549 break;
11550#endif
11551 case CBQUOTE: /* '`' */
11552 PARSEBACKQOLD();
11553 break;
11554 case CENDFILE:
11555 goto endword; /* exit outer loop */
11556 case CIGN:
11557 break;
11558 default:
11559 if (varnest == 0) {
11560#if ENABLE_ASH_BASH_COMPAT
11561 if (c == '&') {
11562//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
11563 if (pgetc() == '>')
11564 c = 0x100 + '>'; /* flag &> */
11565 pungetc();
11566 }
11567#endif
11568 goto endword; /* exit outer loop */
11569 }
11570 IF_ASH_ALIAS(if (c != PEOA))
11571 USTPUTC(c, out);
11572 }
11573 c = pgetc();
11574 } /* for (;;) */
11575 endword:
11576
11577#if ENABLE_SH_MATH_SUPPORT
11578 if (syntax == ARISYNTAX)
11579 raise_error_syntax("missing '))'");
11580#endif
11581 if (syntax != BASESYNTAX && eofmark == NULL)
11582 raise_error_syntax("unterminated quoted string");
11583 if (varnest != 0) {
11584 startlinno = g_parsefile->linno;
11585 /* { */
11586 raise_error_syntax("missing '}'");
11587 }
11588 USTPUTC('\0', out);
11589 len = out - (char *)stackblock();
11590 out = stackblock();
11591 if (eofmark == NULL) {
11592 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
11593 && quotef == 0
11594 ) {
11595 if (isdigit_str9(out)) {
11596 PARSEREDIR(); /* passed as params: out, c */
11597 lasttoken = TREDIR;
11598 return lasttoken;
11599 }
11600 /* else: non-number X seen, interpret it
11601 * as "NNNX>file" = "NNNX >file" */
11602 }
11603 pungetc();
11604 }
11605 quoteflag = quotef;
11606 backquotelist = bqlist;
11607 grabstackblock(len);
11608 wordtext = out;
11609 lasttoken = TWORD;
11610 return lasttoken;
11611/* end of readtoken routine */
11612
11613/*
11614 * Check to see whether we are at the end of the here document. When this
11615 * is called, c is set to the first character of the next input line. If
11616 * we are at the end of the here document, this routine sets the c to PEOF.
11617 */
11618checkend: {
11619 if (eofmark) {
11620#if ENABLE_ASH_ALIAS
11621 if (c == PEOA)
11622 c = pgetc_without_PEOA();
11623#endif
11624 if (striptabs) {
11625 while (c == '\t') {
11626 c = pgetc_without_PEOA();
11627 }
11628 }
11629 if (c == *eofmark) {
11630 if (pfgets(line, sizeof(line)) != NULL) {
11631 char *p, *q;
11632 int cc;
11633
11634 p = line;
11635 for (q = eofmark + 1;; p++, q++) {
11636 cc = *p;
11637 if (cc == '\n')
11638 cc = 0;
11639 if (!*q || cc != *q)
11640 break;
11641 }
11642 if (cc == *q) {
11643 c = PEOF;
11644 nlnoprompt();
11645 } else {
11646 pushstring(line, NULL);
11647 }
11648 }
11649 }
11650 }
11651 goto checkend_return;
11652}
11653
11654/*
11655 * Parse a redirection operator. The variable "out" points to a string
11656 * specifying the fd to be redirected. The variable "c" contains the
11657 * first character of the redirection operator.
11658 */
11659parseredir: {
11660 /* out is already checked to be a valid number or "" */
11661 int fd = (*out == '\0' ? -1 : atoi(out));
11662 union node *np;
11663
11664 np = stzalloc(sizeof(struct nfile));
11665 if (c == '>') {
11666 np->nfile.fd = 1;
11667 c = pgetc();
11668 if (c == '>')
11669 np->type = NAPPEND;
11670 else if (c == '|')
11671 np->type = NCLOBBER;
11672 else if (c == '&')
11673 np->type = NTOFD;
11674 /* it also can be NTO2 (>&file), but we can't figure it out yet */
11675 else {
11676 np->type = NTO;
11677 pungetc();
11678 }
11679 }
11680#if ENABLE_ASH_BASH_COMPAT
11681 else if (c == 0x100 + '>') { /* this flags &> redirection */
11682 np->nfile.fd = 1;
11683 pgetc(); /* this is '>', no need to check */
11684 np->type = NTO2;
11685 }
11686#endif
11687 else { /* c == '<' */
11688 /*np->nfile.fd = 0; - stzalloc did it */
11689 c = pgetc();
11690 switch (c) {
11691 case '<':
11692 if (sizeof(struct nfile) != sizeof(struct nhere)) {
11693 np = stzalloc(sizeof(struct nhere));
11694 /*np->nfile.fd = 0; - stzalloc did it */
11695 }
11696 np->type = NHERE;
11697 heredoc = stzalloc(sizeof(struct heredoc));
11698 heredoc->here = np;
11699 c = pgetc();
11700 if (c == '-') {
11701 heredoc->striptabs = 1;
11702 } else {
11703 /*heredoc->striptabs = 0; - stzalloc did it */
11704 pungetc();
11705 }
11706 break;
11707
11708 case '&':
11709 np->type = NFROMFD;
11710 break;
11711
11712 case '>':
11713 np->type = NFROMTO;
11714 break;
11715
11716 default:
11717 np->type = NFROM;
11718 pungetc();
11719 break;
11720 }
11721 }
11722 if (fd >= 0)
11723 np->nfile.fd = fd;
11724 redirnode = np;
11725 goto parseredir_return;
11726}
11727
11728/*
11729 * Parse a substitution. At this point, we have read the dollar sign
11730 * and nothing else.
11731 */
11732
11733/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11734 * (assuming ascii char codes, as the original implementation did) */
11735#define is_special(c) \
11736 (((unsigned)(c) - 33 < 32) \
11737 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
11738parsesub: {
11739 unsigned char subtype;
11740 int typeloc;
11741
11742 c = pgetc_eatbnl();
11743 if (c > 255 /* PEOA or PEOF */
11744 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
11745 ) {
11746#if ENABLE_ASH_BASH_COMPAT
11747 if (syntax != DQSYNTAX && c == '\'')
11748 bash_dollar_squote = 1;
11749 else
11750#endif
11751 USTPUTC('$', out);
11752 pungetc();
11753 } else if (c == '(') {
11754 /* $(command) or $((arith)) */
11755 if (pgetc_eatbnl() == '(') {
11756#if ENABLE_SH_MATH_SUPPORT
11757 PARSEARITH();
11758#else
11759 raise_error_syntax("you disabled math support for $((arith)) syntax");
11760#endif
11761 } else {
11762 pungetc();
11763 PARSEBACKQNEW();
11764 }
11765 } else {
11766 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
11767 USTPUTC(CTLVAR, out);
11768 typeloc = out - (char *)stackblock();
11769 STADJUST(1, out);
11770 subtype = VSNORMAL;
11771 if (c == '{') {
11772 c = pgetc_eatbnl();
11773 subtype = 0;
11774 }
11775 varname:
11776 if (is_name(c)) {
11777 /* $[{[#]]NAME[}] */
11778 do {
11779 STPUTC(c, out);
11780 c = pgetc_eatbnl();
11781 } while (is_in_name(c));
11782 } else if (isdigit(c)) {
11783 /* $[{[#]]NUM[}] */
11784 do {
11785 STPUTC(c, out);
11786 c = pgetc_eatbnl();
11787 } while (isdigit(c));
11788 } else if (is_special(c)) {
11789 /* $[{[#]]<specialchar>[}] */
11790 int cc = c;
11791
11792 c = pgetc_eatbnl();
11793 if (!subtype && cc == '#') {
11794 subtype = VSLENGTH;
11795 if (c == '_' || isalnum(c))
11796 goto varname;
11797 cc = c;
11798 c = pgetc_eatbnl();
11799 if (cc == '}' || c != '}') {
11800 pungetc();
11801 subtype = 0;
11802 c = cc;
11803 cc = '#';
11804 }
11805 }
11806 USTPUTC(cc, out);
11807 } else {
11808 goto badsub;
11809 }
11810 if (c != '}' && subtype == VSLENGTH) {
11811 /* ${#VAR didn't end with } */
11812 goto badsub;
11813 }
11814
11815 if (subtype == 0) {
11816 static const char types[] ALIGN1 = "}-+?=";
11817 /* ${VAR...} but not $VAR or ${#VAR} */
11818 /* c == first char after VAR */
11819 switch (c) {
11820 case ':':
11821 c = pgetc_eatbnl();
11822#if ENABLE_ASH_BASH_COMPAT
11823 /* This check is only needed to not misinterpret
11824 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11825 * constructs.
11826 */
11827 if (!strchr(types, c)) {
11828 subtype = VSSUBSTR;
11829 pungetc();
11830 break; /* "goto badsub" is bigger (!) */
11831 }
11832#endif
11833 subtype = VSNUL;
11834 /*FALLTHROUGH*/
11835 default: {
11836 const char *p = strchr(types, c);
11837 if (p == NULL)
11838 break;
11839 subtype |= p - types + VSNORMAL;
11840 break;
11841 }
11842 case '%':
11843 case '#': {
11844 int cc = c;
11845 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
11846 c = pgetc_eatbnl();
11847 if (c != cc)
11848 goto badsub;
11849 subtype++;
11850 break;
11851 }
11852#if ENABLE_ASH_BASH_COMPAT
11853 case '/':
11854 /* ${v/[/]pattern/repl} */
11855//TODO: encode pattern and repl separately.
11856// Currently ${v/$var_with_slash/repl} is horribly broken
11857 subtype = VSREPLACE;
11858 c = pgetc_eatbnl();
11859 if (c != '/')
11860 goto badsub;
11861 subtype++; /* VSREPLACEALL */
11862 break;
11863#endif
11864 }
11865 } else {
11866 badsub:
11867 pungetc();
11868 }
11869 ((unsigned char *)stackblock())[typeloc] = subtype;
11870 if (subtype != VSNORMAL) {
11871 varnest++;
11872 if (dblquote)
11873 dqvarnest++;
11874 }
11875 STPUTC('=', out);
11876 }
11877 goto parsesub_return;
11878}
11879
11880/*
11881 * Called to parse command substitutions. Newstyle is set if the command
11882 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11883 * list of commands (passed by reference), and savelen is the number of
11884 * characters on the top of the stack which must be preserved.
11885 */
11886parsebackq: {
11887 struct nodelist **nlpp;
11888 union node *n;
11889 char *str;
11890 size_t savelen;
11891 smallint saveprompt = 0;
11892
11893 str = NULL;
11894 savelen = out - (char *)stackblock();
11895 if (savelen > 0) {
11896 /*
11897 * FIXME: this can allocate very large block on stack and SEGV.
11898 * Example:
11899 * echo "..<100kbytes>..`true` $(true) `true` ..."
11900 * allocates 100kb for every command subst. With about
11901 * a hundred command substitutions stack overflows.
11902 * With larger prepended string, SEGV happens sooner.
11903 */
11904 str = alloca(savelen);
11905 memcpy(str, stackblock(), savelen);
11906 }
11907
11908 if (oldstyle) {
11909 /* We must read until the closing backquote, giving special
11910 * treatment to some slashes, and then push the string and
11911 * reread it as input, interpreting it normally.
11912 */
11913 char *pout;
11914 size_t psavelen;
11915 char *pstr;
11916
11917 STARTSTACKSTR(pout);
11918 for (;;) {
11919 int pc;
11920
11921 setprompt_if(needprompt, 2);
11922 pc = pgetc();
11923 switch (pc) {
11924 case '`':
11925 goto done;
11926
11927 case '\\':
11928 pc = pgetc();
11929 if (pc == '\n') {
11930 nlprompt();
11931 /*
11932 * If eating a newline, avoid putting
11933 * the newline into the new character
11934 * stream (via the STPUTC after the
11935 * switch).
11936 */
11937 continue;
11938 }
11939 if (pc != '\\' && pc != '`' && pc != '$'
11940 && (!dblquote || pc != '"')
11941 ) {
11942 STPUTC('\\', pout);
11943 }
11944 if (pc <= 255 /* not PEOA or PEOF */) {
11945 break;
11946 }
11947 /* fall through */
11948
11949 case PEOF:
11950 IF_ASH_ALIAS(case PEOA:)
11951 startlinno = g_parsefile->linno;
11952 raise_error_syntax("EOF in backquote substitution");
11953
11954 case '\n':
11955 nlnoprompt();
11956 break;
11957
11958 default:
11959 break;
11960 }
11961 STPUTC(pc, pout);
11962 }
11963 done:
11964 STPUTC('\0', pout);
11965 psavelen = pout - (char *)stackblock();
11966 if (psavelen > 0) {
11967 pstr = grabstackstr(pout);
11968 setinputstring(pstr);
11969 }
11970 }
11971 nlpp = &bqlist;
11972 while (*nlpp)
11973 nlpp = &(*nlpp)->next;
11974 *nlpp = stzalloc(sizeof(**nlpp));
11975 /* (*nlpp)->next = NULL; - stzalloc did it */
11976
11977 if (oldstyle) {
11978 saveprompt = doprompt;
11979 doprompt = 0;
11980 }
11981
11982 n = list(2);
11983
11984 if (oldstyle)
11985 doprompt = saveprompt;
11986 else if (readtoken() != TRP)
11987 raise_error_unexpected_syntax(TRP);
11988
11989 (*nlpp)->n = n;
11990 if (oldstyle) {
11991 /*
11992 * Start reading from old file again, ignoring any pushed back
11993 * tokens left from the backquote parsing
11994 */
11995 popfile();
11996 tokpushback = 0;
11997 }
11998 while (stackblocksize() <= savelen)
11999 growstackblock();
12000 STARTSTACKSTR(out);
12001 if (str) {
12002 memcpy(out, str, savelen);
12003 STADJUST(savelen, out);
12004 }
12005 USTPUTC(CTLBACKQ, out);
12006 if (oldstyle)
12007 goto parsebackq_oldreturn;
12008 goto parsebackq_newreturn;
12009}
12010
12011#if ENABLE_SH_MATH_SUPPORT
12012/*
12013 * Parse an arithmetic expansion (indicate start of one and set state)
12014 */
12015parsearith: {
12016 if (++arinest == 1) {
12017 prevsyntax = syntax;
12018 syntax = ARISYNTAX;
12019 }
12020 USTPUTC(CTLARI, out);
12021 goto parsearith_return;
12022}
12023#endif
12024} /* end of readtoken */
12025
12026/*
12027 * Read the next input token.
12028 * If the token is a word, we set backquotelist to the list of cmds in
12029 * backquotes. We set quoteflag to true if any part of the word was
12030 * quoted.
12031 * If the token is TREDIR, then we set redirnode to a structure containing
12032 * the redirection.
12033 * In all cases, the variable startlinno is set to the number of the line
12034 * on which the token starts.
12035 *
12036 * [Change comment: here documents and internal procedures]
12037 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12038 * word parsing code into a separate routine. In this case, readtoken
12039 * doesn't need to have any internal procedures, but parseword does.
12040 * We could also make parseoperator in essence the main routine, and
12041 * have parseword (readtoken1?) handle both words and redirection.]
12042 */
12043#define NEW_xxreadtoken
12044#ifdef NEW_xxreadtoken
12045/* singles must be first! */
12046static const char xxreadtoken_chars[7] ALIGN1 = {
12047 '\n', '(', ')', /* singles */
12048 '&', '|', ';', /* doubles */
12049 0
12050};
12051
12052#define xxreadtoken_singles 3
12053#define xxreadtoken_doubles 3
12054
12055static const char xxreadtoken_tokens[] ALIGN1 = {
12056 TNL, TLP, TRP, /* only single occurrence allowed */
12057 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12058 TEOF, /* corresponds to trailing nul */
12059 TAND, TOR, TENDCASE /* if double occurrence */
12060};
12061
12062static int
12063xxreadtoken(void)
12064{
12065 int c;
12066
12067 if (tokpushback) {
12068 tokpushback = 0;
12069 return lasttoken;
12070 }
12071 setprompt_if(needprompt, 2);
12072 startlinno = g_parsefile->linno;
12073 for (;;) { /* until token or start of word found */
12074 c = pgetc();
12075 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
12076 continue;
12077
12078 if (c == '#') {
12079 while ((c = pgetc()) != '\n' && c != PEOF)
12080 continue;
12081 pungetc();
12082 } else if (c == '\\') {
12083 if (pgetc() != '\n') {
12084 pungetc();
12085 break; /* return readtoken1(...) */
12086 }
12087 nlprompt();
12088 } else {
12089 const char *p;
12090
12091 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12092 if (c != PEOF) {
12093 if (c == '\n') {
12094 nlnoprompt();
12095 }
12096
12097 p = strchr(xxreadtoken_chars, c);
12098 if (p == NULL)
12099 break; /* return readtoken1(...) */
12100
12101 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12102 int cc = pgetc();
12103 if (cc == c) { /* double occurrence? */
12104 p += xxreadtoken_doubles + 1;
12105 } else {
12106 pungetc();
12107#if ENABLE_ASH_BASH_COMPAT
12108 if (c == '&' && cc == '>') /* &> */
12109 break; /* return readtoken1(...) */
12110#endif
12111 }
12112 }
12113 }
12114 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12115 return lasttoken;
12116 }
12117 } /* for (;;) */
12118
12119 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
12120}
12121#else /* old xxreadtoken */
12122#define RETURN(token) return lasttoken = token
12123static int
12124xxreadtoken(void)
12125{
12126 int c;
12127
12128 if (tokpushback) {
12129 tokpushback = 0;
12130 return lasttoken;
12131 }
12132 setprompt_if(needprompt, 2);
12133 startlinno = g_parsefile->linno;
12134 for (;;) { /* until token or start of word found */
12135 c = pgetc();
12136 switch (c) {
12137 case ' ': case '\t':
12138 IF_ASH_ALIAS(case PEOA:)
12139 continue;
12140 case '#':
12141 while ((c = pgetc()) != '\n' && c != PEOF)
12142 continue;
12143 pungetc();
12144 continue;
12145 case '\\':
12146 if (pgetc() == '\n') {
12147 nlprompt();
12148 continue;
12149 }
12150 pungetc();
12151 goto breakloop;
12152 case '\n':
12153 nlnoprompt();
12154 RETURN(TNL);
12155 case PEOF:
12156 RETURN(TEOF);
12157 case '&':
12158 if (pgetc() == '&')
12159 RETURN(TAND);
12160 pungetc();
12161 RETURN(TBACKGND);
12162 case '|':
12163 if (pgetc() == '|')
12164 RETURN(TOR);
12165 pungetc();
12166 RETURN(TPIPE);
12167 case ';':
12168 if (pgetc() == ';')
12169 RETURN(TENDCASE);
12170 pungetc();
12171 RETURN(TSEMI);
12172 case '(':
12173 RETURN(TLP);
12174 case ')':
12175 RETURN(TRP);
12176 default:
12177 goto breakloop;
12178 }
12179 }
12180 breakloop:
12181 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12182#undef RETURN
12183}
12184#endif /* old xxreadtoken */
12185
12186static int
12187readtoken(void)
12188{
12189 int t;
12190 int kwd = checkkwd;
12191#if DEBUG
12192 smallint alreadyseen = tokpushback;
12193#endif
12194
12195#if ENABLE_ASH_ALIAS
12196 top:
12197#endif
12198
12199 t = xxreadtoken();
12200
12201 /*
12202 * eat newlines
12203 */
12204 if (kwd & CHKNL) {
12205 while (t == TNL) {
12206 parseheredoc();
12207 t = xxreadtoken();
12208 }
12209 }
12210
12211 if (t != TWORD || quoteflag) {
12212 goto out;
12213 }
12214
12215 /*
12216 * check for keywords
12217 */
12218 if (kwd & CHKKWD) {
12219 const char *const *pp;
12220
12221 pp = findkwd(wordtext);
12222 if (pp) {
12223 lasttoken = t = pp - tokname_array;
12224 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
12225 goto out;
12226 }
12227 }
12228
12229 if (checkkwd & CHKALIAS) {
12230#if ENABLE_ASH_ALIAS
12231 struct alias *ap;
12232 ap = lookupalias(wordtext, 1);
12233 if (ap != NULL) {
12234 if (*ap->val) {
12235 pushstring(ap->val, ap);
12236 }
12237 goto top;
12238 }
12239#endif
12240 }
12241 out:
12242 checkkwd = 0;
12243#if DEBUG
12244 if (!alreadyseen)
12245 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
12246 else
12247 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
12248#endif
12249 return t;
12250}
12251
12252static int
12253peektoken(void)
12254{
12255 int t;
12256
12257 t = readtoken();
12258 tokpushback = 1;
12259 return t;
12260}
12261
12262/*
12263 * Read and parse a command. Returns NODE_EOF on end of file.
12264 * (NULL is a valid parse tree indicating a blank line.)
12265 */
12266static union node *
12267parsecmd(int interact)
12268{
12269 tokpushback = 0;
12270 checkkwd = 0;
12271 heredoclist = 0;
12272 doprompt = interact;
12273 setprompt_if(doprompt, doprompt);
12274 needprompt = 0;
12275 return list(1);
12276}
12277
12278/*
12279 * Input any here documents.
12280 */
12281static void
12282parseheredoc(void)
12283{
12284 struct heredoc *here;
12285 union node *n;
12286
12287 here = heredoclist;
12288 heredoclist = NULL;
12289
12290 while (here) {
12291 setprompt_if(needprompt, 2);
12292 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
12293 here->eofmark, here->striptabs);
12294 n = stzalloc(sizeof(struct narg));
12295 n->narg.type = NARG;
12296 /*n->narg.next = NULL; - stzalloc did it */
12297 n->narg.text = wordtext;
12298 n->narg.backquote = backquotelist;
12299 here->here->nhere.doc = n;
12300 here = here->next;
12301 }
12302}
12303
12304
12305/*
12306 * called by editline -- any expansions to the prompt should be added here.
12307 */
12308#if ENABLE_ASH_EXPAND_PRMT
12309static const char *
12310expandstr(const char *ps)
12311{
12312 union node n;
12313 int saveprompt;
12314
12315 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12316 * and token processing _can_ alter it (delete NULs etc). */
12317 setinputstring((char *)ps);
12318
12319 saveprompt = doprompt;
12320 doprompt = 0;
12321 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
12322 doprompt = saveprompt;
12323
12324 popfile();
12325
12326 n.narg.type = NARG;
12327 n.narg.next = NULL;
12328 n.narg.text = wordtext;
12329 n.narg.backquote = backquotelist;
12330
12331 expandarg(&n, NULL, EXP_QUOTED);
12332 return stackblock();
12333}
12334#endif
12335
12336/*
12337 * Execute a command or commands contained in a string.
12338 */
12339static int
12340evalstring(char *s, int flags)
12341{
12342 struct jmploc *volatile savehandler;
12343 struct jmploc jmploc;
12344 int ex;
12345
12346 union node *n;
12347 struct stackmark smark;
12348 int status;
12349
12350 s = sstrdup(s);
12351 setinputstring(s);
12352 setstackmark(&smark);
12353
12354 status = 0;
12355 /* On exception inside execution loop, we must popfile().
12356 * Try interactively:
12357 * readonly a=a
12358 * command eval "a=b" # throws "is read only" error
12359 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12360 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12361 */
12362 savehandler = exception_handler;
12363 ex = setjmp(jmploc.loc);
12364 if (ex)
12365 goto out;
12366 exception_handler = &jmploc;
12367
12368 while ((n = parsecmd(0)) != NODE_EOF) {
12369 int i;
12370
12371 i = evaltree(n, flags);
12372 if (n)
12373 status = i;
12374 popstackmark(&smark);
12375 if (evalskip)
12376 break;
12377 }
12378 out:
12379 popstackmark(&smark);
12380 popfile();
12381 stunalloc(s);
12382
12383 exception_handler = savehandler;
12384 if (ex)
12385 longjmp(exception_handler->loc, ex);
12386
12387 return status;
12388}
12389
12390/*
12391 * The eval command.
12392 */
12393static int FAST_FUNC
12394evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
12395{
12396 char *p;
12397 char *concat;
12398
12399 if (argv[1]) {
12400 p = argv[1];
12401 argv += 2;
12402 if (argv[0]) {
12403 STARTSTACKSTR(concat);
12404 for (;;) {
12405 concat = stack_putstr(p, concat);
12406 p = *argv++;
12407 if (p == NULL)
12408 break;
12409 STPUTC(' ', concat);
12410 }
12411 STPUTC('\0', concat);
12412 p = grabstackstr(concat);
12413 }
12414 return evalstring(p, flags & EV_TESTED);
12415 }
12416 return 0;
12417}
12418
12419/*
12420 * Read and execute commands.
12421 * "Top" is nonzero for the top level command loop;
12422 * it turns on prompting if the shell is interactive.
12423 */
12424static int
12425cmdloop(int top)
12426{
12427 union node *n;
12428 struct stackmark smark;
12429 int inter;
12430 int status = 0;
12431 int numeof = 0;
12432
12433 TRACE(("cmdloop(%d) called\n", top));
12434 for (;;) {
12435 int skip;
12436
12437 setstackmark(&smark);
12438#if JOBS
12439 if (doing_jobctl)
12440 showjobs(SHOW_CHANGED|SHOW_STDERR);
12441#endif
12442 inter = 0;
12443 if (iflag && top) {
12444 inter++;
12445 chkmail();
12446 }
12447 n = parsecmd(inter);
12448#if DEBUG
12449 if (DEBUG > 2 && debug && (n != NODE_EOF))
12450 showtree(n);
12451#endif
12452 if (n == NODE_EOF) {
12453 if (!top || numeof >= 50)
12454 break;
12455 if (!stoppedjobs()) {
12456 if (!Iflag)
12457 break;
12458 out2str("\nUse \"exit\" to leave shell.\n");
12459 }
12460 numeof++;
12461 } else if (nflag == 0) {
12462 int i;
12463
12464 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12465 job_warning >>= 1;
12466 numeof = 0;
12467 i = evaltree(n, 0);
12468 if (n)
12469 status = i;
12470 }
12471 popstackmark(&smark);
12472 skip = evalskip;
12473
12474 if (skip) {
12475 evalskip &= ~SKIPFUNC;
12476 break;
12477 }
12478 }
12479 return status;
12480}
12481
12482/*
12483 * Take commands from a file. To be compatible we should do a path
12484 * search for the file, which is necessary to find sub-commands.
12485 */
12486static char *
12487find_dot_file(char *name)
12488{
12489 char *fullname;
12490 const char *path = pathval();
12491 struct stat statb;
12492
12493 /* don't try this for absolute or relative paths */
12494 if (strchr(name, '/'))
12495 return name;
12496
12497 /* IIRC standards do not say whether . is to be searched.
12498 * And it is even smaller this way, making it unconditional for now:
12499 */
12500 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12501 fullname = name;
12502 goto try_cur_dir;
12503 }
12504
12505 while ((fullname = path_advance(&path, name)) != NULL) {
12506 try_cur_dir:
12507 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12508 /*
12509 * Don't bother freeing here, since it will
12510 * be freed by the caller.
12511 */
12512 return fullname;
12513 }
12514 if (fullname != name)
12515 stunalloc(fullname);
12516 }
12517
12518 /* not found in the PATH */
12519 ash_msg_and_raise_error("%s: not found", name);
12520 /* NOTREACHED */
12521}
12522
12523static int FAST_FUNC
12524dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
12525{
12526 /* "false; . empty_file; echo $?" should print 0, not 1: */
12527 int status = 0;
12528 char *fullname;
12529 char **argv;
12530 struct strlist *sp;
12531 volatile struct shparam saveparam;
12532
12533 for (sp = cmdenviron; sp; sp = sp->next)
12534 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
12535
12536 nextopt(nullstr); /* handle possible "--" */
12537 argv = argptr;
12538
12539 if (!argv[0]) {
12540 /* bash says: "bash: .: filename argument required" */
12541 return 2; /* bash compat */
12542 }
12543
12544 /* This aborts if file isn't found, which is POSIXly correct.
12545 * bash returns exitcode 1 instead.
12546 */
12547 fullname = find_dot_file(argv[0]);
12548 argv++;
12549 if (argv[0]) { /* . FILE ARGS, ARGS exist */
12550 int argc;
12551 saveparam = shellparam;
12552 shellparam.malloced = 0;
12553 argc = 1;
12554 while (argv[argc])
12555 argc++;
12556 shellparam.nparam = argc;
12557 shellparam.p = argv;
12558 };
12559
12560 /* This aborts if file can't be opened, which is POSIXly correct.
12561 * bash returns exitcode 1 instead.
12562 */
12563 setinputfile(fullname, INPUT_PUSH_FILE);
12564 commandname = fullname;
12565 status = cmdloop(0);
12566 popfile();
12567
12568 if (argv[0]) {
12569 freeparam(&shellparam);
12570 shellparam = saveparam;
12571 };
12572
12573 return status;
12574}
12575
12576static int FAST_FUNC
12577exitcmd(int argc UNUSED_PARAM, char **argv)
12578{
12579 if (stoppedjobs())
12580 return 0;
12581 if (argv[1])
12582 exitstatus = number(argv[1]);
12583 raise_exception(EXEXIT);
12584 /* NOTREACHED */
12585}
12586
12587/*
12588 * Read a file containing shell functions.
12589 */
12590static void
12591readcmdfile(char *name)
12592{
12593 setinputfile(name, INPUT_PUSH_FILE);
12594 cmdloop(0);
12595 popfile();
12596}
12597
12598
12599/* ============ find_command inplementation */
12600
12601/*
12602 * Resolve a command name. If you change this routine, you may have to
12603 * change the shellexec routine as well.
12604 */
12605static void
12606find_command(char *name, struct cmdentry *entry, int act, const char *path)
12607{
12608 struct tblentry *cmdp;
12609 int idx;
12610 int prev;
12611 char *fullname;
12612 struct stat statb;
12613 int e;
12614 int updatetbl;
12615 struct builtincmd *bcmd;
12616
12617 /* If name contains a slash, don't use PATH or hash table */
12618 if (strchr(name, '/') != NULL) {
12619 entry->u.index = -1;
12620 if (act & DO_ABS) {
12621 while (stat(name, &statb) < 0) {
12622#ifdef SYSV
12623 if (errno == EINTR)
12624 continue;
12625#endif
12626 entry->cmdtype = CMDUNKNOWN;
12627 return;
12628 }
12629 }
12630 entry->cmdtype = CMDNORMAL;
12631 return;
12632 }
12633
12634/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
12635
12636 updatetbl = (path == pathval());
12637 if (!updatetbl) {
12638 act |= DO_ALTPATH;
12639 if (strstr(path, "%builtin") != NULL)
12640 act |= DO_ALTBLTIN;
12641 }
12642
12643 /* If name is in the table, check answer will be ok */
12644 cmdp = cmdlookup(name, 0);
12645 if (cmdp != NULL) {
12646 int bit;
12647
12648 switch (cmdp->cmdtype) {
12649 default:
12650#if DEBUG
12651 abort();
12652#endif
12653 case CMDNORMAL:
12654 bit = DO_ALTPATH;
12655 break;
12656 case CMDFUNCTION:
12657 bit = DO_NOFUNC;
12658 break;
12659 case CMDBUILTIN:
12660 bit = DO_ALTBLTIN;
12661 break;
12662 }
12663 if (act & bit) {
12664 updatetbl = 0;
12665 cmdp = NULL;
12666 } else if (cmdp->rehash == 0)
12667 /* if not invalidated by cd, we're done */
12668 goto success;
12669 }
12670
12671 /* If %builtin not in path, check for builtin next */
12672 bcmd = find_builtin(name);
12673 if (bcmd) {
12674 if (IS_BUILTIN_REGULAR(bcmd))
12675 goto builtin_success;
12676 if (act & DO_ALTPATH) {
12677 if (!(act & DO_ALTBLTIN))
12678 goto builtin_success;
12679 } else if (builtinloc <= 0) {
12680 goto builtin_success;
12681 }
12682 }
12683
12684#if ENABLE_FEATURE_SH_STANDALONE
12685 {
12686 int applet_no = find_applet_by_name(name);
12687 if (applet_no >= 0) {
12688 entry->cmdtype = CMDNORMAL;
12689 entry->u.index = -2 - applet_no;
12690 return;
12691 }
12692 }
12693#endif
12694
12695 /* We have to search path. */
12696 prev = -1; /* where to start */
12697 if (cmdp && cmdp->rehash) { /* doing a rehash */
12698 if (cmdp->cmdtype == CMDBUILTIN)
12699 prev = builtinloc;
12700 else
12701 prev = cmdp->param.index;
12702 }
12703
12704 e = ENOENT;
12705 idx = -1;
12706 loop:
12707 while ((fullname = path_advance(&path, name)) != NULL) {
12708 stunalloc(fullname);
12709 /* NB: code below will still use fullname
12710 * despite it being "unallocated" */
12711 idx++;
12712 if (pathopt) {
12713 if (prefix(pathopt, "builtin")) {
12714 if (bcmd)
12715 goto builtin_success;
12716 continue;
12717 }
12718 if ((act & DO_NOFUNC)
12719 || !prefix(pathopt, "func")
12720 ) { /* ignore unimplemented options */
12721 continue;
12722 }
12723 }
12724 /* if rehash, don't redo absolute path names */
12725 if (fullname[0] == '/' && idx <= prev) {
12726 if (idx < prev)
12727 continue;
12728 TRACE(("searchexec \"%s\": no change\n", name));
12729 goto success;
12730 }
12731 while (stat(fullname, &statb) < 0) {
12732#ifdef SYSV
12733 if (errno == EINTR)
12734 continue;
12735#endif
12736 if (errno != ENOENT && errno != ENOTDIR)
12737 e = errno;
12738 goto loop;
12739 }
12740 e = EACCES; /* if we fail, this will be the error */
12741 if (!S_ISREG(statb.st_mode))
12742 continue;
12743 if (pathopt) { /* this is a %func directory */
12744 stalloc(strlen(fullname) + 1);
12745 /* NB: stalloc will return space pointed by fullname
12746 * (because we don't have any intervening allocations
12747 * between stunalloc above and this stalloc) */
12748 readcmdfile(fullname);
12749 cmdp = cmdlookup(name, 0);
12750 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12751 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12752 stunalloc(fullname);
12753 goto success;
12754 }
12755 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12756 if (!updatetbl) {
12757 entry->cmdtype = CMDNORMAL;
12758 entry->u.index = idx;
12759 return;
12760 }
12761 INT_OFF;
12762 cmdp = cmdlookup(name, 1);
12763 cmdp->cmdtype = CMDNORMAL;
12764 cmdp->param.index = idx;
12765 INT_ON;
12766 goto success;
12767 }
12768
12769 /* We failed. If there was an entry for this command, delete it */
12770 if (cmdp && updatetbl)
12771 delete_cmd_entry();
12772 if (act & DO_ERR)
12773 ash_msg("%s: %s", name, errmsg(e, "not found"));
12774 entry->cmdtype = CMDUNKNOWN;
12775 return;
12776
12777 builtin_success:
12778 if (!updatetbl) {
12779 entry->cmdtype = CMDBUILTIN;
12780 entry->u.cmd = bcmd;
12781 return;
12782 }
12783 INT_OFF;
12784 cmdp = cmdlookup(name, 1);
12785 cmdp->cmdtype = CMDBUILTIN;
12786 cmdp->param.cmd = bcmd;
12787 INT_ON;
12788 success:
12789 cmdp->rehash = 0;
12790 entry->cmdtype = cmdp->cmdtype;
12791 entry->u = cmdp->param;
12792}
12793
12794
12795/*
12796 * The trap builtin.
12797 */
12798static int FAST_FUNC
12799trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12800{
12801 char *action;
12802 char **ap;
12803 int signo, exitcode;
12804
12805 nextopt(nullstr);
12806 ap = argptr;
12807 if (!*ap) {
12808 for (signo = 0; signo < NSIG; signo++) {
12809 char *tr = trap_ptr[signo];
12810 if (tr) {
12811 /* note: bash adds "SIG", but only if invoked
12812 * as "bash". If called as "sh", or if set -o posix,
12813 * then it prints short signal names.
12814 * We are printing short names: */
12815 out1fmt("trap -- %s %s\n",
12816 single_quote(tr),
12817 get_signame(signo));
12818 /* trap_ptr != trap only if we are in special-cased `trap` code.
12819 * In this case, we will exit very soon, no need to free(). */
12820 /* if (trap_ptr != trap && tp[0]) */
12821 /* free(tr); */
12822 }
12823 }
12824 /*
12825 if (trap_ptr != trap) {
12826 free(trap_ptr);
12827 trap_ptr = trap;
12828 }
12829 */
12830 return 0;
12831 }
12832
12833 action = NULL;
12834 if (ap[1])
12835 action = *ap++;
12836 exitcode = 0;
12837 while (*ap) {
12838 signo = get_signum(*ap);
12839 if (signo < 0) {
12840 /* Mimic bash message exactly */
12841 ash_msg("%s: invalid signal specification", *ap);
12842 exitcode = 1;
12843 goto next;
12844 }
12845 INT_OFF;
12846 if (action) {
12847 if (LONE_DASH(action))
12848 action = NULL;
12849 else {
12850 if (action[0]) /* not NULL and not "" and not "-" */
12851 may_have_traps = 1;
12852 action = ckstrdup(action);
12853 }
12854 }
12855 free(trap[signo]);
12856 trap[signo] = action;
12857 if (signo != 0)
12858 setsignal(signo);
12859 INT_ON;
12860 next:
12861 ap++;
12862 }
12863 return exitcode;
12864}
12865
12866
12867/* ============ Builtins */
12868
12869#if ENABLE_ASH_HELP
12870static int FAST_FUNC
12871helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12872{
12873 unsigned col;
12874 unsigned i;
12875
12876 out1fmt(
12877 "Built-in commands:\n"
12878 "------------------\n");
12879 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12880 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12881 builtintab[i].name + 1);
12882 if (col > 60) {
12883 out1fmt("\n");
12884 col = 0;
12885 }
12886 }
12887# if ENABLE_FEATURE_SH_STANDALONE
12888 {
12889 const char *a = applet_names;
12890 while (*a) {
12891 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12892 if (col > 60) {
12893 out1fmt("\n");
12894 col = 0;
12895 }
12896 while (*a++ != '\0')
12897 continue;
12898 }
12899 }
12900# endif
12901 newline_and_flush(stdout);
12902 return EXIT_SUCCESS;
12903}
12904#endif
12905
12906#if MAX_HISTORY
12907static int FAST_FUNC
12908historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12909{
12910 show_history(line_input_state);
12911 return EXIT_SUCCESS;
12912}
12913#endif
12914
12915/*
12916 * The export and readonly commands.
12917 */
12918static int FAST_FUNC
12919exportcmd(int argc UNUSED_PARAM, char **argv)
12920{
12921 struct var *vp;
12922 char *name;
12923 const char *p;
12924 char **aptr;
12925 char opt;
12926 int flag;
12927 int flag_off;
12928
12929 /* "readonly" in bash accepts, but ignores -n.
12930 * We do the same: it saves a conditional in nextopt's param.
12931 */
12932 flag_off = 0;
12933 while ((opt = nextopt("np")) != '\0') {
12934 if (opt == 'n')
12935 flag_off = VEXPORT;
12936 }
12937 flag = VEXPORT;
12938 if (argv[0][0] == 'r') {
12939 flag = VREADONLY;
12940 flag_off = 0; /* readonly ignores -n */
12941 }
12942 flag_off = ~flag_off;
12943
12944 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12945 {
12946 aptr = argptr;
12947 name = *aptr;
12948 if (name) {
12949 do {
12950 p = strchr(name, '=');
12951 if (p != NULL) {
12952 p++;
12953 } else {
12954 vp = *findvar(hashvar(name), name);
12955 if (vp) {
12956 vp->flags = ((vp->flags | flag) & flag_off);
12957 continue;
12958 }
12959 }
12960 setvar(name, p, (flag & flag_off));
12961 } while ((name = *++aptr) != NULL);
12962 return 0;
12963 }
12964 }
12965
12966 /* No arguments. Show the list of exported or readonly vars.
12967 * -n is ignored.
12968 */
12969 showvars(argv[0], flag, 0);
12970 return 0;
12971}
12972
12973/*
12974 * Delete a function if it exists.
12975 */
12976static void
12977unsetfunc(const char *name)
12978{
12979 struct tblentry *cmdp;
12980
12981 cmdp = cmdlookup(name, 0);
12982 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
12983 delete_cmd_entry();
12984}
12985
12986/*
12987 * The unset builtin command. We unset the function before we unset the
12988 * variable to allow a function to be unset when there is a readonly variable
12989 * with the same name.
12990 */
12991static int FAST_FUNC
12992unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12993{
12994 char **ap;
12995 int i;
12996 int flag = 0;
12997 int ret = 0;
12998
12999 while ((i = nextopt("vf")) != 0) {
13000 flag = i;
13001 }
13002
13003 for (ap = argptr; *ap; ap++) {
13004 if (flag != 'f') {
13005 i = unsetvar(*ap);
13006 ret |= i;
13007 if (!(i & 2))
13008 continue;
13009 }
13010 if (flag != 'v')
13011 unsetfunc(*ap);
13012 }
13013 return ret & 1;
13014}
13015
13016static const unsigned char timescmd_str[] ALIGN1 = {
13017 ' ', offsetof(struct tms, tms_utime),
13018 '\n', offsetof(struct tms, tms_stime),
13019 ' ', offsetof(struct tms, tms_cutime),
13020 '\n', offsetof(struct tms, tms_cstime),
13021 0
13022};
13023static int FAST_FUNC
13024timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13025{
13026 unsigned long clk_tck, s, t;
13027 const unsigned char *p;
13028 struct tms buf;
13029
13030 clk_tck = bb_clk_tck();
13031 times(&buf);
13032
13033 p = timescmd_str;
13034 do {
13035 t = *(clock_t *)(((char *) &buf) + p[1]);
13036 s = t / clk_tck;
13037 t = t % clk_tck;
13038 out1fmt("%lum%lu.%03lus%c",
13039 s / 60, s % 60,
13040 (t * 1000) / clk_tck,
13041 p[0]);
13042 p += 2;
13043 } while (*p);
13044
13045 return 0;
13046}
13047
13048#if ENABLE_SH_MATH_SUPPORT
13049/*
13050 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
13051 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
13052 *
13053 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13054 */
13055static int FAST_FUNC
13056letcmd(int argc UNUSED_PARAM, char **argv)
13057{
13058 arith_t i;
13059
13060 argv++;
13061 if (!*argv)
13062 ash_msg_and_raise_error("expression expected");
13063 do {
13064 i = ash_arith(*argv);
13065 } while (*++argv);
13066
13067 return !i;
13068}
13069#endif
13070
13071/*
13072 * The read builtin. Options:
13073 * -r Do not interpret '\' specially
13074 * -s Turn off echo (tty only)
13075 * -n NCHARS Read NCHARS max
13076 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13077 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13078 * -u FD Read from given FD instead of fd 0
13079 * This uses unbuffered input, which may be avoidable in some cases.
13080 * TODO: bash also has:
13081 * -a ARRAY Read into array[0],[1],etc
13082 * -d DELIM End on DELIM char, not newline
13083 * -e Use line editing (tty only)
13084 */
13085static int FAST_FUNC
13086readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13087{
13088 char *opt_n = NULL;
13089 char *opt_p = NULL;
13090 char *opt_t = NULL;
13091 char *opt_u = NULL;
13092 int read_flags = 0;
13093 const char *r;
13094 int i;
13095
13096 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
13097 switch (i) {
13098 case 'p':
13099 opt_p = optionarg;
13100 break;
13101 case 'n':
13102 opt_n = optionarg;
13103 break;
13104 case 's':
13105 read_flags |= BUILTIN_READ_SILENT;
13106 break;
13107 case 't':
13108 opt_t = optionarg;
13109 break;
13110 case 'r':
13111 read_flags |= BUILTIN_READ_RAW;
13112 break;
13113 case 'u':
13114 opt_u = optionarg;
13115 break;
13116 default:
13117 break;
13118 }
13119 }
13120
13121 /* "read -s" needs to save/restore termios, can't allow ^C
13122 * to jump out of it.
13123 */
13124 INT_OFF;
13125 r = shell_builtin_read(setvar0,
13126 argptr,
13127 bltinlookup("IFS"), /* can be NULL */
13128 read_flags,
13129 opt_n,
13130 opt_p,
13131 opt_t,
13132 opt_u
13133 );
13134 INT_ON;
13135
13136 if ((uintptr_t)r > 1)
13137 ash_msg_and_raise_error(r);
13138
13139 return (uintptr_t)r;
13140}
13141
13142static int FAST_FUNC
13143umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13144{
13145 static const char permuser[3] ALIGN1 = "ogu";
13146
13147 mode_t mask;
13148 int symbolic_mode = 0;
13149
13150 while (nextopt("S") != '\0') {
13151 symbolic_mode = 1;
13152 }
13153
13154 INT_OFF;
13155 mask = umask(0);
13156 umask(mask);
13157 INT_ON;
13158
13159 if (*argptr == NULL) {
13160 if (symbolic_mode) {
13161 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
13162 char *p = buf;
13163 int i;
13164
13165 i = 2;
13166 for (;;) {
13167 *p++ = ',';
13168 *p++ = permuser[i];
13169 *p++ = '=';
13170 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
13171 if (!(mask & 0400)) *p++ = 'r';
13172 if (!(mask & 0200)) *p++ = 'w';
13173 if (!(mask & 0100)) *p++ = 'x';
13174 mask <<= 3;
13175 if (--i < 0)
13176 break;
13177 }
13178 *p = '\0';
13179 puts(buf + 1);
13180 } else {
13181 out1fmt("%04o\n", mask);
13182 }
13183 } else {
13184 char *modestr = *argptr;
13185 /* numeric umasks are taken as-is */
13186 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13187 if (!isdigit(modestr[0]))
13188 mask ^= 0777;
13189 mask = bb_parse_mode(modestr, mask);
13190 if ((unsigned)mask > 0777) {
13191 ash_msg_and_raise_error("illegal mode: %s", modestr);
13192 }
13193 if (!isdigit(modestr[0]))
13194 mask ^= 0777;
13195 umask(mask);
13196 }
13197 return 0;
13198}
13199
13200static int FAST_FUNC
13201ulimitcmd(int argc UNUSED_PARAM, char **argv)
13202{
13203 return shell_builtin_ulimit(argv);
13204}
13205
13206/* ============ main() and helpers */
13207
13208/*
13209 * Called to exit the shell.
13210 */
13211static void
13212exitshell(void)
13213{
13214 struct jmploc loc;
13215 char *p;
13216 int status;
13217
13218#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13219 save_history(line_input_state);
13220#endif
13221 status = exitstatus;
13222 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13223 if (setjmp(loc.loc)) {
13224 if (exception_type == EXEXIT)
13225 status = exitstatus;
13226 goto out;
13227 }
13228 exception_handler = &loc;
13229 p = trap[0];
13230 if (p) {
13231 trap[0] = NULL;
13232 evalskip = 0;
13233 evalstring(p, 0);
13234 /*free(p); - we'll exit soon */
13235 }
13236 out:
13237 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13238 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13239 */
13240 setjobctl(0);
13241 flush_stdout_stderr();
13242 _exit(status);
13243 /* NOTREACHED */
13244}
13245
13246static void
13247init(void)
13248{
13249 /* we will never free this */
13250 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
13251
13252 sigmode[SIGCHLD - 1] = S_DFL;
13253 setsignal(SIGCHLD);
13254
13255 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13256 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13257 */
13258 signal(SIGHUP, SIG_DFL);
13259
13260 {
13261 char **envp;
13262 const char *p;
13263 struct stat st1, st2;
13264
13265 initvar();
13266 for (envp = environ; envp && *envp; envp++) {
13267 p = endofname(*envp);
13268 if (p != *envp && *p == '=') {
13269 setvareq(*envp, VEXPORT|VTEXTFIXED);
13270 }
13271 }
13272
13273 setvareq((char*)defoptindvar, VTEXTFIXED);
13274
13275 setvar0("PPID", utoa(getppid()));
13276#if ENABLE_ASH_BASH_COMPAT
13277 p = lookupvar("SHLVL");
13278 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
13279 if (!lookupvar("HOSTNAME")) {
13280 struct utsname uts;
13281 uname(&uts);
13282 setvar0("HOSTNAME", uts.nodename);
13283 }
13284#endif
13285 p = lookupvar("PWD");
13286 if (p) {
13287 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
13288 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13289 ) {
13290 p = NULL;
13291 }
13292 }
13293 setpwd(p, 0);
13294 }
13295}
13296
13297
13298//usage:#define ash_trivial_usage
13299//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
13300//usage:#define ash_full_usage "\n\n"
13301//usage: "Unix shell interpreter"
13302
13303//usage:#if ENABLE_FEATURE_SH_IS_ASH
13304//usage:# define sh_trivial_usage ash_trivial_usage
13305//usage:# define sh_full_usage ash_full_usage
13306//usage:#endif
13307//usage:#if ENABLE_FEATURE_BASH_IS_ASH
13308//usage:# define bash_trivial_usage ash_trivial_usage
13309//usage:# define bash_full_usage ash_full_usage
13310//usage:#endif
13311
13312/*
13313 * Process the shell command line arguments.
13314 */
13315static void
13316procargs(char **argv)
13317{
13318 int i;
13319 const char *xminusc;
13320 char **xargv;
13321
13322 xargv = argv;
13323 arg0 = xargv[0];
13324 /* if (xargv[0]) - mmm, this is always true! */
13325 xargv++;
13326 for (i = 0; i < NOPTS; i++)
13327 optlist[i] = 2;
13328 argptr = xargv;
13329 if (options(/*cmdline:*/ 1)) {
13330 /* it already printed err message */
13331 raise_exception(EXERROR);
13332 }
13333 xargv = argptr;
13334 xminusc = minusc;
13335 if (*xargv == NULL) {
13336 if (xminusc)
13337 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13338 sflag = 1;
13339 }
13340 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13341 iflag = 1;
13342 if (mflag == 2)
13343 mflag = iflag;
13344 for (i = 0; i < NOPTS; i++)
13345 if (optlist[i] == 2)
13346 optlist[i] = 0;
13347#if DEBUG == 2
13348 debug = 1;
13349#endif
13350 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13351 if (xminusc) {
13352 minusc = *xargv++;
13353 if (*xargv)
13354 goto setarg0;
13355 } else if (!sflag) {
13356 setinputfile(*xargv, 0);
13357 setarg0:
13358 arg0 = *xargv++;
13359 commandname = arg0;
13360 }
13361
13362 shellparam.p = xargv;
13363#if ENABLE_ASH_GETOPTS
13364 shellparam.optind = 1;
13365 shellparam.optoff = -1;
13366#endif
13367 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13368 while (*xargv) {
13369 shellparam.nparam++;
13370 xargv++;
13371 }
13372 optschanged();
13373}
13374
13375/*
13376 * Read /etc/profile, ~/.profile, $ENV.
13377 */
13378static void
13379read_profile(const char *name)
13380{
13381 name = expandstr(name);
13382 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13383 return;
13384 cmdloop(0);
13385 popfile();
13386}
13387
13388/*
13389 * This routine is called when an error or an interrupt occurs in an
13390 * interactive shell and control is returned to the main command loop.
13391 * (In dash, this function is auto-generated by build machinery).
13392 */
13393static void
13394reset(void)
13395{
13396 /* from eval.c: */
13397 evalskip = 0;
13398 loopnest = 0;
13399
13400 /* from expand.c: */
13401 ifsfree();
13402
13403 /* from input.c: */
13404 g_parsefile->left_in_buffer = 0;
13405 g_parsefile->left_in_line = 0; /* clear input buffer */
13406 popallfiles();
13407
13408 /* from redir.c: */
13409 while (redirlist)
13410 popredir(/*drop:*/ 0, /*restore:*/ 0);
13411}
13412
13413#if PROFILE
13414static short profile_buf[16384];
13415extern int etext();
13416#endif
13417
13418/*
13419 * Main routine. We initialize things, parse the arguments, execute
13420 * profiles if we're a login shell, and then call cmdloop to execute
13421 * commands. The setjmp call sets up the location to jump to when an
13422 * exception occurs. When an exception occurs the variable "state"
13423 * is used to figure out how far we had gotten.
13424 */
13425int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13426int ash_main(int argc UNUSED_PARAM, char **argv)
13427{
13428 volatile smallint state;
13429 struct jmploc jmploc;
13430 struct stackmark smark;
13431
13432 /* Initialize global data */
13433 INIT_G_misc();
13434 INIT_G_memstack();
13435 INIT_G_var();
13436#if ENABLE_ASH_ALIAS
13437 INIT_G_alias();
13438#endif
13439 INIT_G_cmdtable();
13440
13441#if PROFILE
13442 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13443#endif
13444
13445#if ENABLE_FEATURE_EDITING
13446 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13447#endif
13448 state = 0;
13449 if (setjmp(jmploc.loc)) {
13450 smallint e;
13451 smallint s;
13452
13453 reset();
13454
13455 e = exception_type;
13456 s = state;
13457 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
13458 exitshell();
13459 }
13460 if (e == EXINT) {
13461 newline_and_flush(stderr);
13462 }
13463
13464 popstackmark(&smark);
13465 FORCE_INT_ON; /* enable interrupts */
13466 if (s == 1)
13467 goto state1;
13468 if (s == 2)
13469 goto state2;
13470 if (s == 3)
13471 goto state3;
13472 goto state4;
13473 }
13474 exception_handler = &jmploc;
13475 rootpid = getpid();
13476
13477 init();
13478 setstackmark(&smark);
13479 procargs(argv);
13480#if DEBUG
13481 TRACE(("Shell args: "));
13482 trace_puts_args(argv);
13483#endif
13484
13485 if (argv[0] && argv[0][0] == '-')
13486 isloginsh = 1;
13487 if (isloginsh) {
13488 const char *hp;
13489
13490 state = 1;
13491 read_profile("/etc/profile");
13492 state1:
13493 state = 2;
13494 hp = lookupvar("HOME");
13495 if (hp)
13496 read_profile("$HOME/.profile");
13497 }
13498 state2:
13499 state = 3;
13500 if (
13501#ifndef linux
13502 getuid() == geteuid() && getgid() == getegid() &&
13503#endif
13504 iflag
13505 ) {
13506 const char *shinit = lookupvar("ENV");
13507 if (shinit != NULL && *shinit != '\0')
13508 read_profile(shinit);
13509 }
13510 popstackmark(&smark);
13511 state3:
13512 state = 4;
13513 if (minusc) {
13514 /* evalstring pushes parsefile stack.
13515 * Ensure we don't falsely claim that 0 (stdin)
13516 * is one of stacked source fds.
13517 * Testcase: ash -c 'exec 1>&0' must not complain. */
13518 // if (!sflag) g_parsefile->pf_fd = -1;
13519 // ^^ not necessary since now we special-case fd 0
13520 // in is_hidden_fd() to not be considered "hidden fd"
13521 evalstring(minusc, 0);
13522 }
13523
13524 if (sflag || minusc == NULL) {
13525#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
13526 if (iflag) {
13527 const char *hp = lookupvar("HISTFILE");
13528 if (!hp) {
13529 hp = lookupvar("HOME");
13530 if (hp) {
13531 hp = concat_path_file(hp, ".ash_history");
13532 setvar0("HISTFILE", hp);
13533 free((char*)hp);
13534 hp = lookupvar("HISTFILE");
13535 }
13536 }
13537 if (hp)
13538 line_input_state->hist_file = hp;
13539# if ENABLE_FEATURE_SH_HISTFILESIZE
13540 hp = lookupvar("HISTFILESIZE");
13541 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13542# endif
13543 }
13544#endif
13545 state4: /* XXX ??? - why isn't this before the "if" statement */
13546 cmdloop(1);
13547 }
13548#if PROFILE
13549 monitor(0);
13550#endif
13551#ifdef GPROF
13552 {
13553 extern void _mcleanup(void);
13554 _mcleanup();
13555 }
13556#endif
13557 TRACE(("End of main reached\n"));
13558 exitshell();
13559 /* NOTREACHED */
13560}
13561
13562
13563/*-
13564 * Copyright (c) 1989, 1991, 1993, 1994
13565 * The Regents of the University of California. All rights reserved.
13566 *
13567 * This code is derived from software contributed to Berkeley by
13568 * Kenneth Almquist.
13569 *
13570 * Redistribution and use in source and binary forms, with or without
13571 * modification, are permitted provided that the following conditions
13572 * are met:
13573 * 1. Redistributions of source code must retain the above copyright
13574 * notice, this list of conditions and the following disclaimer.
13575 * 2. Redistributions in binary form must reproduce the above copyright
13576 * notice, this list of conditions and the following disclaimer in the
13577 * documentation and/or other materials provided with the distribution.
13578 * 3. Neither the name of the University nor the names of its contributors
13579 * may be used to endorse or promote products derived from this software
13580 * without specific prior written permission.
13581 *
13582 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13583 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13584 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13585 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13586 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13587 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13588 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13589 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13590 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13591 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13592 * SUCH DAMAGE.
13593 */
13594