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