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