summaryrefslogtreecommitdiff
path: root/shell/ash_80.c (plain)
blob: c0824f1185cd820285a77b4a3f03df58c2a9ae56
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 col = fmtstr(s, 32, "%s", strsignal(st));
3961//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
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 if (st)
3969 col = fmtstr(s, 16, "Done(%d)", st);
3970 else
3971 col = fmtstr(s, 16, "Done");
3972 }
3973 out:
3974 return col;
3975}
3976
3977static int
3978wait_block_or_sig(int *status)
3979{
3980 int pid;
3981
3982 do {
3983 sigset_t mask;
3984
3985 /* Poll all children for changes in their state */
3986 got_sigchld = 0;
3987 /* if job control is active, accept stopped processes too */
3988 pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
3989 if (pid != 0)
3990 break; /* Error (e.g. EINTR, ECHILD) or pid */
3991
3992 /* Children exist, but none are ready. Sleep until interesting signal */
3993#if 1
3994 sigfillset(&mask);
3995 sigprocmask(SIG_SETMASK, &mask, &mask);
3996 while (!got_sigchld && !pending_sig)
3997 sigsuspend(&mask);
3998 sigprocmask(SIG_SETMASK, &mask, NULL);
3999#else /* unsafe: a signal can set pending_sig after check, but before pause() */
4000 while (!got_sigchld && !pending_sig)
4001 pause();
4002#endif
4003
4004 /* If it was SIGCHLD, poll children again */
4005 } while (got_sigchld);
4006
4007 return pid;
4008}
4009
4010#define DOWAIT_NONBLOCK 0
4011#define DOWAIT_BLOCK 1
4012#define DOWAIT_BLOCK_OR_SIG 2
4013
4014static int
4015dowait(int block, struct job *job)
4016{
4017 int pid;
4018 int status;
4019 struct job *jp;
4020 struct job *thisjob = NULL;
4021
4022 TRACE(("dowait(0x%x) called\n", block));
4023
4024 /* It's wrong to call waitpid() outside of INT_OFF region:
4025 * signal can arrive just after syscall return and handler can
4026 * longjmp away, losing stop/exit notification processing.
4027 * Thus, for "jobs" builtin, and for waiting for a fg job,
4028 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
4029 *
4030 * However, for "wait" builtin it is wrong to simply call waitpid()
4031 * in INT_OFF region: "wait" needs to wait for any running job
4032 * to change state, but should exit on any trap too.
4033 * In INT_OFF region, a signal just before syscall entry can set
4034 * pending_sig variables, but we can't check them, and we would
4035 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
4036 *
4037 * Because of this, we run inside INT_OFF, but use a special routine
4038 * which combines waitpid() and sigsuspend().
4039 * This is the reason why we need to have a handler for SIGCHLD:
4040 * SIG_DFL handler does not wake sigsuspend().
4041 */
4042 INT_OFF;
4043 if (block == DOWAIT_BLOCK_OR_SIG) {
4044 pid = wait_block_or_sig(&status);
4045 } else {
4046 int wait_flags = 0;
4047 if (block == DOWAIT_NONBLOCK)
4048 wait_flags = WNOHANG;
4049 /* if job control is active, accept stopped processes too */
4050 if (doing_jobctl)
4051 wait_flags |= WUNTRACED;
4052 /* NB: _not_ safe_waitpid, we need to detect EINTR */
4053 pid = waitpid(-1, &status, wait_flags);
4054 }
4055 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
4056 pid, status, errno, strerror(errno)));
4057 if (pid <= 0)
4058 goto out;
4059
4060 thisjob = NULL;
4061 for (jp = curjob; jp; jp = jp->prev_job) {
4062 int jobstate;
4063 struct procstat *ps;
4064 struct procstat *psend;
4065 if (jp->state == JOBDONE)
4066 continue;
4067 jobstate = JOBDONE;
4068 ps = jp->ps;
4069 psend = ps + jp->nprocs;
4070 do {
4071 if (ps->ps_pid == pid) {
4072 TRACE(("Job %d: changing status of proc %d "
4073 "from 0x%x to 0x%x\n",
4074 jobno(jp), pid, ps->ps_status, status));
4075 ps->ps_status = status;
4076 thisjob = jp;
4077 }
4078 if (ps->ps_status == -1)
4079 jobstate = JOBRUNNING;
4080#if JOBS
4081 if (jobstate == JOBRUNNING)
4082 continue;
4083 if (WIFSTOPPED(ps->ps_status)) {
4084 jp->stopstatus = ps->ps_status;
4085 jobstate = JOBSTOPPED;
4086 }
4087#endif
4088 } while (++ps < psend);
4089 if (!thisjob)
4090 continue;
4091
4092 /* Found the job where one of its processes changed its state.
4093 * Is there at least one live and running process in this job? */
4094 if (jobstate != JOBRUNNING) {
4095 /* No. All live processes in the job are stopped
4096 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4097 */
4098 thisjob->changed = 1;
4099 if (thisjob->state != jobstate) {
4100 TRACE(("Job %d: changing state from %d to %d\n",
4101 jobno(thisjob), thisjob->state, jobstate));
4102 thisjob->state = jobstate;
4103#if JOBS
4104 if (jobstate == JOBSTOPPED)
4105 set_curjob(thisjob, CUR_STOPPED);
4106#endif
4107 }
4108 }
4109 goto out;
4110 }
4111 /* The process wasn't found in job list */
4112 if (JOBS && !WIFSTOPPED(status))
4113 jobless--;
4114 out:
4115 INT_ON;
4116
4117 if (thisjob && thisjob == job) {
4118 char s[48 + 1];
4119 int len;
4120
4121 len = sprint_status48(s, status, 1);
4122 if (len) {
4123 s[len] = '\n';
4124 s[len + 1] = '\0';
4125 out2str(s);
4126 }
4127 }
4128 return pid;
4129}
4130
4131#if JOBS
4132static void
4133showjob(struct job *jp, int mode)
4134{
4135 struct procstat *ps;
4136 struct procstat *psend;
4137 int col;
4138 int indent_col;
4139 char s[16 + 16 + 48];
4140 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
4141
4142 ps = jp->ps;
4143
4144 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
4145 /* just output process (group) id of pipeline */
4146 fprintf(out, "%d\n", ps->ps_pid);
4147 return;
4148 }
4149
4150 col = fmtstr(s, 16, "[%d] ", jobno(jp));
4151 indent_col = col;
4152
4153 if (jp == curjob)
4154 s[col - 3] = '+';
4155 else if (curjob && jp == curjob->prev_job)
4156 s[col - 3] = '-';
4157
4158 if (mode & SHOW_PIDS)
4159 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
4160
4161 psend = ps + jp->nprocs;
4162
4163 if (jp->state == JOBRUNNING) {
4164 strcpy(s + col, "Running");
4165 col += sizeof("Running") - 1;
4166 } else {
4167 int status = psend[-1].ps_status;
4168 if (jp->state == JOBSTOPPED)
4169 status = jp->stopstatus;
4170 col += sprint_status48(s + col, status, 0);
4171 }
4172 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
4173
4174 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4175 * or prints several "PID | <cmdN>" lines,
4176 * depending on SHOW_PIDS bit.
4177 * We do not print status of individual processes
4178 * between PID and <cmdN>. bash does it, but not very well:
4179 * first line shows overall job status, not process status,
4180 * making it impossible to know 1st process status.
4181 */
4182 goto start;
4183 do {
4184 /* for each process */
4185 s[0] = '\0';
4186 col = 33;
4187 if (mode & SHOW_PIDS)
4188 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
4189 start:
4190 fprintf(out, "%s%*c%s%s",
4191 s,
4192 33 - col >= 0 ? 33 - col : 0, ' ',
4193 ps == jp->ps ? "" : "| ",
4194 ps->ps_cmd
4195 );
4196 } while (++ps != psend);
4197 newline_and_flush(out);
4198
4199 jp->changed = 0;
4200
4201 if (jp->state == JOBDONE) {
4202 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4203 freejob(jp);
4204 }
4205}
4206
4207/*
4208 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4209 * statuses have changed since the last call to showjobs.
4210 */
4211static void
4212showjobs(int mode)
4213{
4214 struct job *jp;
4215
4216 TRACE(("showjobs(0x%x) called\n", mode));
4217
4218 /* Handle all finished jobs */
4219 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
4220 continue;
4221
4222 for (jp = curjob; jp; jp = jp->prev_job) {
4223 if (!(mode & SHOW_CHANGED) || jp->changed) {
4224 showjob(jp, mode);
4225 }
4226 }
4227}
4228
4229static int FAST_FUNC
4230jobscmd(int argc UNUSED_PARAM, char **argv)
4231{
4232 int mode, m;
4233
4234 mode = 0;
4235 while ((m = nextopt("lp")) != '\0') {
4236 if (m == 'l')
4237 mode |= SHOW_PIDS;
4238 else
4239 mode |= SHOW_ONLY_PGID;
4240 }
4241
4242 argv = argptr;
4243 if (*argv) {
4244 do
4245 showjob(getjob(*argv, 0), mode);
4246 while (*++argv);
4247 } else {
4248 showjobs(mode);
4249 }
4250
4251 return 0;
4252}
4253#endif /* JOBS */
4254
4255/* Called only on finished or stopped jobs (no members are running) */
4256static int
4257getstatus(struct job *job)
4258{
4259 int status;
4260 int retval;
4261 struct procstat *ps;
4262
4263 /* Fetch last member's status */
4264 ps = job->ps + job->nprocs - 1;
4265 status = ps->ps_status;
4266 if (pipefail) {
4267 /* "set -o pipefail" mode: use last _nonzero_ status */
4268 while (status == 0 && --ps >= job->ps)
4269 status = ps->ps_status;
4270 }
4271
4272 retval = WEXITSTATUS(status);
4273 if (!WIFEXITED(status)) {
4274#if JOBS
4275 retval = WSTOPSIG(status);
4276 if (!WIFSTOPPED(status))
4277#endif
4278 {
4279 /* XXX: limits number of signals */
4280 retval = WTERMSIG(status);
4281#if JOBS
4282 if (retval == SIGINT)
4283 job->sigint = 1;
4284#endif
4285 }
4286 retval += 128;
4287 }
4288 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
4289 jobno(job), job->nprocs, status, retval));
4290 return retval;
4291}
4292
4293static int FAST_FUNC
4294waitcmd(int argc UNUSED_PARAM, char **argv)
4295{
4296 struct job *job;
4297 int retval;
4298 struct job *jp;
4299
4300 nextopt(nullstr);
4301 retval = 0;
4302
4303 argv = argptr;
4304 if (!*argv) {
4305 /* wait for all jobs */
4306 for (;;) {
4307 jp = curjob;
4308 while (1) {
4309 if (!jp) /* no running procs */
4310 goto ret;
4311 if (jp->state == JOBRUNNING)
4312 break;
4313 jp->waited = 1;
4314 jp = jp->prev_job;
4315 }
4316 /* man bash:
4317 * "When bash is waiting for an asynchronous command via
4318 * the wait builtin, the reception of a signal for which a trap
4319 * has been set will cause the wait builtin to return immediately
4320 * with an exit status greater than 128, immediately after which
4321 * the trap is executed."
4322 */
4323 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4324 /* if child sends us a signal *and immediately exits*,
4325 * dowait() returns pid > 0. Check this case,
4326 * not "if (dowait() < 0)"!
4327 */
4328 if (pending_sig)
4329 goto sigout;
4330 }
4331 }
4332
4333 retval = 127;
4334 do {
4335 if (**argv != '%') {
4336 pid_t pid = number(*argv);
4337 job = curjob;
4338 while (1) {
4339 if (!job)
4340 goto repeat;
4341 if (job->ps[job->nprocs - 1].ps_pid == pid)
4342 break;
4343 job = job->prev_job;
4344 }
4345 } else {
4346 job = getjob(*argv, 0);
4347 }
4348 /* loop until process terminated or stopped */
4349 while (job->state == JOBRUNNING) {
4350 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4351 if (pending_sig)
4352 goto sigout;
4353 }
4354 job->waited = 1;
4355 retval = getstatus(job);
4356 repeat: ;
4357 } while (*++argv);
4358
4359 ret:
4360 return retval;
4361 sigout:
4362 retval = 128 + pending_sig;
4363 return retval;
4364}
4365
4366static struct job *
4367growjobtab(void)
4368{
4369 size_t len;
4370 ptrdiff_t offset;
4371 struct job *jp, *jq;
4372
4373 len = njobs * sizeof(*jp);
4374 jq = jobtab;
4375 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4376
4377 offset = (char *)jp - (char *)jq;
4378 if (offset) {
4379 /* Relocate pointers */
4380 size_t l = len;
4381
4382 jq = (struct job *)((char *)jq + l);
4383 while (l) {
4384 l -= sizeof(*jp);
4385 jq--;
4386#define joff(p) ((struct job *)((char *)(p) + l))
4387#define jmove(p) (p) = (void *)((char *)(p) + offset)
4388 if (joff(jp)->ps == &jq->ps0)
4389 jmove(joff(jp)->ps);
4390 if (joff(jp)->prev_job)
4391 jmove(joff(jp)->prev_job);
4392 }
4393 if (curjob)
4394 jmove(curjob);
4395#undef joff
4396#undef jmove
4397 }
4398
4399 njobs += 4;
4400 jobtab = jp;
4401 jp = (struct job *)((char *)jp + len);
4402 jq = jp + 3;
4403 do {
4404 jq->used = 0;
4405 } while (--jq >= jp);
4406 return jp;
4407}
4408
4409/*
4410 * Return a new job structure.
4411 * Called with interrupts off.
4412 */
4413static struct job *
4414makejob(/*union node *node,*/ int nprocs)
4415{
4416 int i;
4417 struct job *jp;
4418
4419 for (i = njobs, jp = jobtab; ; jp++) {
4420 if (--i < 0) {
4421 jp = growjobtab();
4422 break;
4423 }
4424 if (jp->used == 0)
4425 break;
4426 if (jp->state != JOBDONE || !jp->waited)
4427 continue;
4428#if JOBS
4429 if (doing_jobctl)
4430 continue;
4431#endif
4432 freejob(jp);
4433 break;
4434 }
4435 memset(jp, 0, sizeof(*jp));
4436#if JOBS
4437 /* jp->jobctl is a bitfield.
4438 * "jp->jobctl |= jobctl" likely to give awful code */
4439 if (doing_jobctl)
4440 jp->jobctl = 1;
4441#endif
4442 jp->prev_job = curjob;
4443 curjob = jp;
4444 jp->used = 1;
4445 jp->ps = &jp->ps0;
4446 if (nprocs > 1) {
4447 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4448 }
4449 TRACE(("makejob(%d) returns %%%d\n", nprocs,
4450 jobno(jp)));
4451 return jp;
4452}
4453
4454#if JOBS
4455/*
4456 * Return a string identifying a command (to be printed by the
4457 * jobs command).
4458 */
4459static char *cmdnextc;
4460
4461static void
4462cmdputs(const char *s)
4463{
4464 static const char vstype[VSTYPE + 1][3] = {
4465 "", "}", "-", "+", "?", "=",
4466 "%", "%%", "#", "##"
4467 IF_ASH_BASH_COMPAT(, ":", "/", "//")
4468 };
4469
4470 const char *p, *str;
4471 char cc[2];
4472 char *nextc;
4473 unsigned char c;
4474 unsigned char subtype = 0;
4475 int quoted = 0;
4476
4477 cc[1] = '\0';
4478 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4479 p = s;
4480 while ((c = *p++) != '\0') {
4481 str = NULL;
4482 switch (c) {
4483 case CTLESC:
4484 c = *p++;
4485 break;
4486 case CTLVAR:
4487 subtype = *p++;
4488 if ((subtype & VSTYPE) == VSLENGTH)
4489 str = "${#";
4490 else
4491 str = "${";
4492 goto dostr;
4493 case CTLENDVAR:
4494 str = "\"}" + !(quoted & 1);
4495 quoted >>= 1;
4496 subtype = 0;
4497 goto dostr;
4498 case CTLBACKQ:
4499 str = "$(...)";
4500 goto dostr;
4501#if ENABLE_FEATURE_SH_MATH
4502 case CTLARI:
4503 str = "$((";
4504 goto dostr;
4505 case CTLENDARI:
4506 str = "))";
4507 goto dostr;
4508#endif
4509 case CTLQUOTEMARK:
4510 quoted ^= 1;
4511 c = '"';
4512 break;
4513 case '=':
4514 if (subtype == 0)
4515 break;
4516 if ((subtype & VSTYPE) != VSNORMAL)
4517 quoted <<= 1;
4518 str = vstype[subtype & VSTYPE];
4519 if (subtype & VSNUL)
4520 c = ':';
4521 else
4522 goto checkstr;
4523 break;
4524 case '\'':
4525 case '\\':
4526 case '"':
4527 case '$':
4528 /* These can only happen inside quotes */
4529 cc[0] = c;
4530 str = cc;
4531 c = '\\';
4532 break;
4533 default:
4534 break;
4535 }
4536 USTPUTC(c, nextc);
4537 checkstr:
4538 if (!str)
4539 continue;
4540 dostr:
4541 while ((c = *str++) != '\0') {
4542 USTPUTC(c, nextc);
4543 }
4544 } /* while *p++ not NUL */
4545
4546 if (quoted & 1) {
4547 USTPUTC('"', nextc);
4548 }
4549 *nextc = 0;
4550 cmdnextc = nextc;
4551}
4552
4553/* cmdtxt() and cmdlist() call each other */
4554static void cmdtxt(union node *n);
4555
4556static void
4557cmdlist(union node *np, int sep)
4558{
4559 for (; np; np = np->narg.next) {
4560 if (!sep)
4561 cmdputs(" ");
4562 cmdtxt(np);
4563 if (sep && np->narg.next)
4564 cmdputs(" ");
4565 }
4566}
4567
4568static void
4569cmdtxt(union node *n)
4570{
4571 union node *np;
4572 struct nodelist *lp;
4573 const char *p;
4574
4575 if (!n)
4576 return;
4577 switch (n->type) {
4578 default:
4579#if DEBUG
4580 abort();
4581#endif
4582 case NPIPE:
4583 lp = n->npipe.cmdlist;
4584 for (;;) {
4585 cmdtxt(lp->n);
4586 lp = lp->next;
4587 if (!lp)
4588 break;
4589 cmdputs(" | ");
4590 }
4591 break;
4592 case NSEMI:
4593 p = "; ";
4594 goto binop;
4595 case NAND:
4596 p = " && ";
4597 goto binop;
4598 case NOR:
4599 p = " || ";
4600 binop:
4601 cmdtxt(n->nbinary.ch1);
4602 cmdputs(p);
4603 n = n->nbinary.ch2;
4604 goto donode;
4605 case NREDIR:
4606 case NBACKGND:
4607 n = n->nredir.n;
4608 goto donode;
4609 case NNOT:
4610 cmdputs("!");
4611 n = n->nnot.com;
4612 donode:
4613 cmdtxt(n);
4614 break;
4615 case NIF:
4616 cmdputs("if ");
4617 cmdtxt(n->nif.test);
4618 cmdputs("; then ");
4619 if (n->nif.elsepart) {
4620 cmdtxt(n->nif.ifpart);
4621 cmdputs("; else ");
4622 n = n->nif.elsepart;
4623 } else {
4624 n = n->nif.ifpart;
4625 }
4626 p = "; fi";
4627 goto dotail;
4628 case NSUBSHELL:
4629 cmdputs("(");
4630 n = n->nredir.n;
4631 p = ")";
4632 goto dotail;
4633 case NWHILE:
4634 p = "while ";
4635 goto until;
4636 case NUNTIL:
4637 p = "until ";
4638 until:
4639 cmdputs(p);
4640 cmdtxt(n->nbinary.ch1);
4641 n = n->nbinary.ch2;
4642 p = "; done";
4643 dodo:
4644 cmdputs("; do ");
4645 dotail:
4646 cmdtxt(n);
4647 goto dotail2;
4648 case NFOR:
4649 cmdputs("for ");
4650 cmdputs(n->nfor.var);
4651 cmdputs(" in ");
4652 cmdlist(n->nfor.args, 1);
4653 n = n->nfor.body;
4654 p = "; done";
4655 goto dodo;
4656 case NDEFUN:
4657 cmdputs(n->narg.text);
4658 p = "() { ... }";
4659 goto dotail2;
4660 case NCMD:
4661 cmdlist(n->ncmd.args, 1);
4662 cmdlist(n->ncmd.redirect, 0);
4663 break;
4664 case NARG:
4665 p = n->narg.text;
4666 dotail2:
4667 cmdputs(p);
4668 break;
4669 case NHERE:
4670 case NXHERE:
4671 p = "<<...";
4672 goto dotail2;
4673 case NCASE:
4674 cmdputs("case ");
4675 cmdputs(n->ncase.expr->narg.text);
4676 cmdputs(" in ");
4677 for (np = n->ncase.cases; np; np = np->nclist.next) {
4678 cmdtxt(np->nclist.pattern);
4679 cmdputs(") ");
4680 cmdtxt(np->nclist.body);
4681 cmdputs(";; ");
4682 }
4683 p = "esac";
4684 goto dotail2;
4685 case NTO:
4686 p = ">";
4687 goto redir;
4688 case NCLOBBER:
4689 p = ">|";
4690 goto redir;
4691 case NAPPEND:
4692 p = ">>";
4693 goto redir;
4694#if ENABLE_ASH_BASH_COMPAT
4695 case NTO2:
4696#endif
4697 case NTOFD:
4698 p = ">&";
4699 goto redir;
4700 case NFROM:
4701 p = "<";
4702 goto redir;
4703 case NFROMFD:
4704 p = "<&";
4705 goto redir;
4706 case NFROMTO:
4707 p = "<>";
4708 redir:
4709 cmdputs(utoa(n->nfile.fd));
4710 cmdputs(p);
4711 if (n->type == NTOFD || n->type == NFROMFD) {
4712 cmdputs(utoa(n->ndup.dupfd));
4713 break;
4714 }
4715 n = n->nfile.fname;
4716 goto donode;
4717 }
4718}
4719
4720static char *
4721commandtext(union node *n)
4722{
4723 char *name;
4724
4725 STARTSTACKSTR(cmdnextc);
4726 cmdtxt(n);
4727 name = stackblock();
4728 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
4729 return ckstrdup(name);
4730}
4731#endif /* JOBS */
4732
4733/*
4734 * Fork off a subshell. If we are doing job control, give the subshell its
4735 * own process group. Jp is a job structure that the job is to be added to.
4736 * N is the command that will be evaluated by the child. Both jp and n may
4737 * be NULL. The mode parameter can be one of the following:
4738 * FORK_FG - Fork off a foreground process.
4739 * FORK_BG - Fork off a background process.
4740 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4741 * process group even if job control is on.
4742 *
4743 * When job control is turned off, background processes have their standard
4744 * input redirected to /dev/null (except for the second and later processes
4745 * in a pipeline).
4746 *
4747 * Called with interrupts off.
4748 */
4749/*
4750 * Clear traps on a fork.
4751 */
4752static void
4753clear_traps(void)
4754{
4755 char **tp;
4756
4757 INT_OFF;
4758 for (tp = trap; tp < &trap[NSIG]; tp++) {
4759 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
4760 if (trap_ptr == trap)
4761 free(*tp);
4762 /* else: it "belongs" to trap_ptr vector, don't free */
4763 *tp = NULL;
4764 if ((tp - trap) != 0)
4765 setsignal(tp - trap);
4766 }
4767 }
4768 may_have_traps = 0;
4769 INT_ON;
4770}
4771
4772/* Lives far away from here, needed for forkchild */
4773static void closescript(void);
4774
4775/* Called after fork(), in child */
4776/* jp and n are NULL when called by openhere() for heredoc support */
4777static NOINLINE void
4778forkchild(struct job *jp, union node *n, int mode)
4779{
4780 int oldlvl;
4781
4782 TRACE(("Child shell %d\n", getpid()));
4783 oldlvl = shlvl;
4784 shlvl++;
4785
4786 /* man bash: "Non-builtin commands run by bash have signal handlers
4787 * set to the values inherited by the shell from its parent".
4788 * Do we do it correctly? */
4789
4790 closescript();
4791
4792 if (mode == FORK_NOJOB /* is it `xxx` ? */
4793 && n && n->type == NCMD /* is it single cmd? */
4794 /* && n->ncmd.args->type == NARG - always true? */
4795 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
4796 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4797 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4798 ) {
4799 TRACE(("Trap hack\n"));
4800 /* Awful hack for `trap` or $(trap).
4801 *
4802 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4803 * contains an example where "trap" is executed in a subshell:
4804 *
4805 * save_traps=$(trap)
4806 * ...
4807 * eval "$save_traps"
4808 *
4809 * Standard does not say that "trap" in subshell shall print
4810 * parent shell's traps. It only says that its output
4811 * must have suitable form, but then, in the above example
4812 * (which is not supposed to be normative), it implies that.
4813 *
4814 * bash (and probably other shell) does implement it
4815 * (traps are reset to defaults, but "trap" still shows them),
4816 * but as a result, "trap" logic is hopelessly messed up:
4817 *
4818 * # trap
4819 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4820 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4821 * # true | trap <--- trap is in subshell - no output (ditto)
4822 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4823 * trap -- 'echo Ho' SIGWINCH
4824 * # echo `(trap)` <--- in subshell in subshell - output
4825 * trap -- 'echo Ho' SIGWINCH
4826 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4827 * trap -- 'echo Ho' SIGWINCH
4828 *
4829 * The rules when to forget and when to not forget traps
4830 * get really complex and nonsensical.
4831 *
4832 * Our solution: ONLY bare $(trap) or `trap` is special.
4833 */
4834 /* Save trap handler strings for trap builtin to print */
4835 trap_ptr = xmemdup(trap, sizeof(trap));
4836 /* Fall through into clearing traps */
4837 }
4838 clear_traps();
4839#if JOBS
4840 /* do job control only in root shell */
4841 doing_jobctl = 0;
4842 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
4843 pid_t pgrp;
4844
4845 if (jp->nprocs == 0)
4846 pgrp = getpid();
4847 else
4848 pgrp = jp->ps[0].ps_pid;
4849 /* this can fail because we are doing it in the parent also */
4850 setpgid(0, pgrp);
4851 if (mode == FORK_FG)
4852 xtcsetpgrp(ttyfd, pgrp);
4853 setsignal(SIGTSTP);
4854 setsignal(SIGTTOU);
4855 } else
4856#endif
4857 if (mode == FORK_BG) {
4858 /* man bash: "When job control is not in effect,
4859 * asynchronous commands ignore SIGINT and SIGQUIT" */
4860 ignoresig(SIGINT);
4861 ignoresig(SIGQUIT);
4862 if (jp->nprocs == 0) {
4863 close(0);
4864 if (open(bb_dev_null, O_RDONLY) != 0)
4865 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
4866 }
4867 }
4868 if (oldlvl == 0) {
4869 if (iflag) { /* why if iflag only? */
4870 setsignal(SIGINT);
4871 setsignal(SIGTERM);
4872 }
4873 /* man bash:
4874 * "In all cases, bash ignores SIGQUIT. Non-builtin
4875 * commands run by bash have signal handlers
4876 * set to the values inherited by the shell
4877 * from its parent".
4878 * Take care of the second rule: */
4879 setsignal(SIGQUIT);
4880 }
4881#if JOBS
4882 if (n && n->type == NCMD
4883 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
4884 ) {
4885 TRACE(("Job hack\n"));
4886 /* "jobs": we do not want to clear job list for it,
4887 * instead we remove only _its_ own_ job from job list.
4888 * This makes "jobs .... | cat" more useful.
4889 */
4890 freejob(curjob);
4891 return;
4892 }
4893#endif
4894 for (jp = curjob; jp; jp = jp->prev_job)
4895 freejob(jp);
4896 jobless = 0;
4897}
4898
4899/* Called after fork(), in parent */
4900#if !JOBS
4901#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4902#endif
4903static void
4904forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4905{
4906 TRACE(("In parent shell: child = %d\n", pid));
4907 if (!jp) {
4908 /* jp is NULL when called by openhere() for heredoc support */
4909 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4910 continue;
4911 jobless++;
4912 return;
4913 }
4914#if JOBS
4915 if (mode != FORK_NOJOB && jp->jobctl) {
4916 int pgrp;
4917
4918 if (jp->nprocs == 0)
4919 pgrp = pid;
4920 else
4921 pgrp = jp->ps[0].ps_pid;
4922 /* This can fail because we are doing it in the child also */
4923 setpgid(pid, pgrp);
4924 }
4925#endif
4926 if (mode == FORK_BG) {
4927 backgndpid = pid; /* set $! */
4928 set_curjob(jp, CUR_RUNNING);
4929 }
4930 if (jp) {
4931 struct procstat *ps = &jp->ps[jp->nprocs++];
4932 ps->ps_pid = pid;
4933 ps->ps_status = -1;
4934 ps->ps_cmd = nullstr;
4935#if JOBS
4936 if (doing_jobctl && n)
4937 ps->ps_cmd = commandtext(n);
4938#endif
4939 }
4940}
4941
4942/* jp and n are NULL when called by openhere() for heredoc support */
4943static int
4944forkshell(struct job *jp, union node *n, int mode)
4945{
4946 int pid;
4947
4948 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4949 pid = fork();
4950 if (pid < 0) {
4951 TRACE(("Fork failed, errno=%d", errno));
4952 if (jp)
4953 freejob(jp);
4954 ash_msg_and_raise_error("can't fork");
4955 }
4956 if (pid == 0) {
4957 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
4958 forkchild(jp, n, mode);
4959 } else {
4960 forkparent(jp, n, mode, pid);
4961 }
4962 return pid;
4963}
4964
4965/*
4966 * Wait for job to finish.
4967 *
4968 * Under job control we have the problem that while a child process
4969 * is running interrupts generated by the user are sent to the child
4970 * but not to the shell. This means that an infinite loop started by
4971 * an interactive user may be hard to kill. With job control turned off,
4972 * an interactive user may place an interactive program inside a loop.
4973 * If the interactive program catches interrupts, the user doesn't want
4974 * these interrupts to also abort the loop. The approach we take here
4975 * is to have the shell ignore interrupt signals while waiting for a
4976 * foreground process to terminate, and then send itself an interrupt
4977 * signal if the child process was terminated by an interrupt signal.
4978 * Unfortunately, some programs want to do a bit of cleanup and then
4979 * exit on interrupt; unless these processes terminate themselves by
4980 * sending a signal to themselves (instead of calling exit) they will
4981 * confuse this approach.
4982 *
4983 * Called with interrupts off.
4984 */
4985static int
4986waitforjob(struct job *jp)
4987{
4988 int st;
4989
4990 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
4991
4992 INT_OFF;
4993 while (jp->state == JOBRUNNING) {
4994 /* In non-interactive shells, we _can_ get
4995 * a keyboard signal here and be EINTRed,
4996 * but we just loop back, waiting for command to complete.
4997 *
4998 * man bash:
4999 * "If bash is waiting for a command to complete and receives
5000 * a signal for which a trap has been set, the trap
5001 * will not be executed until the command completes."
5002 *
5003 * Reality is that even if trap is not set, bash
5004 * will not act on the signal until command completes.
5005 * Try this. sleep5intoff.c:
5006 * #include <signal.h>
5007 * #include <unistd.h>
5008 * int main() {
5009 * sigset_t set;
5010 * sigemptyset(&set);
5011 * sigaddset(&set, SIGINT);
5012 * sigaddset(&set, SIGQUIT);
5013 * sigprocmask(SIG_BLOCK, &set, NULL);
5014 * sleep(5);
5015 * return 0;
5016 * }
5017 * $ bash -c './sleep5intoff; echo hi'
5018 * ^C^C^C^C <--- pressing ^C once a second
5019 * $ _
5020 * $ bash -c './sleep5intoff; echo hi'
5021 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
5022 * $ _
5023 */
5024 dowait(DOWAIT_BLOCK, jp);
5025 }
5026 INT_ON;
5027
5028 st = getstatus(jp);
5029#if JOBS
5030 if (jp->jobctl) {
5031 xtcsetpgrp(ttyfd, rootpid);
5032 /*
5033 * This is truly gross.
5034 * If we're doing job control, then we did a TIOCSPGRP which
5035 * caused us (the shell) to no longer be in the controlling
5036 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
5037 * intuit from the subprocess exit status whether a SIGINT
5038 * occurred, and if so interrupt ourselves. Yuck. - mycroft
5039 */
5040 if (jp->sigint) /* TODO: do the same with all signals */
5041 raise(SIGINT); /* ... by raise(jp->sig) instead? */
5042 }
5043 if (jp->state == JOBDONE)
5044#endif
5045 freejob(jp);
5046 return st;
5047}
5048
5049/*
5050 * return 1 if there are stopped jobs, otherwise 0
5051 */
5052static int
5053stoppedjobs(void)
5054{
5055 struct job *jp;
5056 int retval;
5057
5058 retval = 0;
5059 if (job_warning)
5060 goto out;
5061 jp = curjob;
5062 if (jp && jp->state == JOBSTOPPED) {
5063 out2str("You have stopped jobs.\n");
5064 job_warning = 2;
5065 retval++;
5066 }
5067 out:
5068 return retval;
5069}
5070
5071
5072/*
5073 * Code for dealing with input/output redirection.
5074 */
5075
5076#undef EMPTY
5077#undef CLOSED
5078#define EMPTY -2 /* marks an unused slot in redirtab */
5079#define CLOSED -3 /* marks a slot of previously-closed fd */
5080
5081/*
5082 * Open a file in noclobber mode.
5083 * The code was copied from bash.
5084 */
5085static int
5086noclobberopen(const char *fname)
5087{
5088 int r, fd;
5089 struct stat finfo, finfo2;
5090
5091 /*
5092 * If the file exists and is a regular file, return an error
5093 * immediately.
5094 */
5095 r = stat(fname, &finfo);
5096 if (r == 0 && S_ISREG(finfo.st_mode)) {
5097 errno = EEXIST;
5098 return -1;
5099 }
5100
5101 /*
5102 * If the file was not present (r != 0), make sure we open it
5103 * exclusively so that if it is created before we open it, our open
5104 * will fail. Make sure that we do not truncate an existing file.
5105 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5106 * file was not a regular file, we leave O_EXCL off.
5107 */
5108 if (r != 0)
5109 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5110 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5111
5112 /* If the open failed, return the file descriptor right away. */
5113 if (fd < 0)
5114 return fd;
5115
5116 /*
5117 * OK, the open succeeded, but the file may have been changed from a
5118 * non-regular file to a regular file between the stat and the open.
5119 * We are assuming that the O_EXCL open handles the case where FILENAME
5120 * did not exist and is symlinked to an existing file between the stat
5121 * and open.
5122 */
5123
5124 /*
5125 * If we can open it and fstat the file descriptor, and neither check
5126 * revealed that it was a regular file, and the file has not been
5127 * replaced, return the file descriptor.
5128 */
5129 if (fstat(fd, &finfo2) == 0
5130 && !S_ISREG(finfo2.st_mode)
5131 && finfo.st_dev == finfo2.st_dev
5132 && finfo.st_ino == finfo2.st_ino
5133 ) {
5134 return fd;
5135 }
5136
5137 /* The file has been replaced. badness. */
5138 close(fd);
5139 errno = EEXIST;
5140 return -1;
5141}
5142
5143/*
5144 * Handle here documents. Normally we fork off a process to write the
5145 * data to a pipe. If the document is short, we can stuff the data in
5146 * the pipe without forking.
5147 */
5148/* openhere needs this forward reference */
5149static void expandhere(union node *arg, int fd);
5150static int
5151openhere(union node *redir)
5152{
5153 int pip[2];
5154 size_t len = 0;
5155
5156 if (pipe(pip) < 0)
5157 ash_msg_and_raise_error("pipe call failed");
5158 if (redir->type == NHERE) {
5159 len = strlen(redir->nhere.doc->narg.text);
5160 if (len <= PIPE_BUF) {
5161 full_write(pip[1], redir->nhere.doc->narg.text, len);
5162 goto out;
5163 }
5164 }
5165 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5166 /* child */
5167 close(pip[0]);
5168 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5169 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5170 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5171 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
5172 signal(SIGPIPE, SIG_DFL);
5173 if (redir->type == NHERE)
5174 full_write(pip[1], redir->nhere.doc->narg.text, len);
5175 else /* NXHERE */
5176 expandhere(redir->nhere.doc, pip[1]);
5177 _exit(EXIT_SUCCESS);
5178 }
5179 out:
5180 close(pip[1]);
5181 return pip[0];
5182}
5183
5184static int
5185openredirect(union node *redir)
5186{
5187 char *fname;
5188 int f;
5189
5190 switch (redir->nfile.type) {
5191/* Can't happen, our single caller does this itself */
5192// case NTOFD:
5193// case NFROMFD:
5194// return -1;
5195 case NHERE:
5196 case NXHERE:
5197 return openhere(redir);
5198 }
5199
5200 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5201 * allocated space. Do it only when we know it is safe.
5202 */
5203 fname = redir->nfile.expfname;
5204
5205 switch (redir->nfile.type) {
5206 default:
5207#if DEBUG
5208 abort();
5209#endif
5210 case NFROM:
5211 f = open(fname, O_RDONLY);
5212 if (f < 0)
5213 goto eopen;
5214 break;
5215 case NFROMTO:
5216 f = open(fname, O_RDWR|O_CREAT, 0666);
5217 if (f < 0)
5218 goto ecreate;
5219 break;
5220 case NTO:
5221#if ENABLE_ASH_BASH_COMPAT
5222 case NTO2:
5223#endif
5224 /* Take care of noclobber mode. */
5225 if (Cflag) {
5226 f = noclobberopen(fname);
5227 if (f < 0)
5228 goto ecreate;
5229 break;
5230 }
5231 /* FALLTHROUGH */
5232 case NCLOBBER:
5233 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5234 if (f < 0)
5235 goto ecreate;
5236 break;
5237 case NAPPEND:
5238 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5239 if (f < 0)
5240 goto ecreate;
5241 break;
5242 }
5243
5244 return f;
5245 ecreate:
5246 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
5247 eopen:
5248 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
5249}
5250
5251/*
5252 * Copy a file descriptor to be >= 10. Throws exception on error.
5253 */
5254static int
5255savefd(int from)
5256{
5257 int newfd;
5258 int err;
5259
5260 newfd = fcntl(from, F_DUPFD, 10);
5261 err = newfd < 0 ? errno : 0;
5262 if (err != EBADF) {
5263 if (err)
5264 ash_msg_and_raise_error("%d: %m", from);
5265 close(from);
5266 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5267 }
5268
5269 return newfd;
5270}
5271static int
5272dup2_or_raise(int from, int to)
5273{
5274 int newfd;
5275
5276 newfd = (from != to) ? dup2(from, to) : to;
5277 if (newfd < 0) {
5278 /* Happens when source fd is not open: try "echo >&99" */
5279 ash_msg_and_raise_error("%d: %m", from);
5280 }
5281 return newfd;
5282}
5283
5284/* Struct def and variable are moved down to the first usage site */
5285struct two_fd_t {
5286 int orig, copy;
5287};
5288struct redirtab {
5289 struct redirtab *next;
5290 int pair_count;
5291 struct two_fd_t two_fd[];
5292};
5293#define redirlist (G_var.redirlist)
5294enum {
5295 COPYFD_RESTORE = (int)~(INT_MAX),
5296};
5297
5298static int
5299need_to_remember(struct redirtab *rp, int fd)
5300{
5301 int i;
5302
5303 if (!rp) /* remembering was not requested */
5304 return 0;
5305
5306 for (i = 0; i < rp->pair_count; i++) {
5307 if (rp->two_fd[i].orig == fd) {
5308 /* already remembered */
5309 return 0;
5310 }
5311 }
5312 return 1;
5313}
5314
5315/* "hidden" fd is a fd used to read scripts, or a copy of such */
5316static int
5317is_hidden_fd(struct redirtab *rp, int fd)
5318{
5319 int i;
5320 struct parsefile *pf;
5321
5322 if (fd == -1)
5323 return 0;
5324 /* Check open scripts' fds */
5325 pf = g_parsefile;
5326 while (pf) {
5327 /* We skip pf_fd == 0 case because of the following case:
5328 * $ ash # running ash interactively
5329 * $ . ./script.sh
5330 * and in script.sh: "exec 9>&0".
5331 * Even though top-level pf_fd _is_ 0,
5332 * it's still ok to use it: "read" builtin uses it,
5333 * why should we cripple "exec" builtin?
5334 */
5335 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
5336 return 1;
5337 }
5338 pf = pf->prev;
5339 }
5340
5341 if (!rp)
5342 return 0;
5343 /* Check saved fds of redirects */
5344 fd |= COPYFD_RESTORE;
5345 for (i = 0; i < rp->pair_count; i++) {
5346 if (rp->two_fd[i].copy == fd) {
5347 return 1;
5348 }
5349 }
5350 return 0;
5351}
5352
5353/*
5354 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5355 * old file descriptors are stashed away so that the redirection can be
5356 * undone by calling popredir.
5357 */
5358/* flags passed to redirect */
5359#define REDIR_PUSH 01 /* save previous values of file descriptors */
5360#define REDIR_SAVEFD2 03 /* set preverrout */
5361static void
5362redirect(union node *redir, int flags)
5363{
5364 struct redirtab *sv;
5365 int sv_pos;
5366 int i;
5367 int fd;
5368 int newfd;
5369 int copied_fd2 = -1;
5370
5371 if (!redir) {
5372 return;
5373 }
5374
5375 sv = NULL;
5376 sv_pos = 0;
5377 INT_OFF;
5378 if (flags & REDIR_PUSH) {
5379 union node *tmp = redir;
5380 do {
5381 sv_pos++;
5382#if ENABLE_ASH_BASH_COMPAT
5383 if (tmp->nfile.type == NTO2)
5384 sv_pos++;
5385#endif
5386 tmp = tmp->nfile.next;
5387 } while (tmp);
5388 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
5389 sv->next = redirlist;
5390 sv->pair_count = sv_pos;
5391 redirlist = sv;
5392 while (sv_pos > 0) {
5393 sv_pos--;
5394 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5395 }
5396 }
5397
5398 do {
5399 int right_fd = -1;
5400 fd = redir->nfile.fd;
5401 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
5402 right_fd = redir->ndup.dupfd;
5403 //bb_error_msg("doing %d > %d", fd, right_fd);
5404 /* redirect from/to same file descriptor? */
5405 if (right_fd == fd)
5406 continue;
5407 /* "echo >&10" and 10 is a fd opened to a sh script? */
5408 if (is_hidden_fd(sv, right_fd)) {
5409 errno = EBADF; /* as if it is closed */
5410 ash_msg_and_raise_error("%d: %m", right_fd);
5411 }
5412 newfd = -1;
5413 } else {
5414 newfd = openredirect(redir); /* always >= 0 */
5415 if (fd == newfd) {
5416 /* Descriptor wasn't open before redirect.
5417 * Mark it for close in the future */
5418 if (need_to_remember(sv, fd)) {
5419 goto remember_to_close;
5420 }
5421 continue;
5422 }
5423 }
5424#if ENABLE_ASH_BASH_COMPAT
5425 redirect_more:
5426#endif
5427 if (need_to_remember(sv, fd)) {
5428 /* Copy old descriptor */
5429 /* Careful to not accidentally "save"
5430 * to the same fd as right side fd in N>&M */
5431 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5432#if defined(F_DUPFD_CLOEXEC)
5433 i = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
5434#else
5435 i = fcntl(fd, F_DUPFD, minfd);
5436#endif
5437 if (i == -1) {
5438 i = errno;
5439 if (i != EBADF) {
5440 /* Strange error (e.g. "too many files" EMFILE?) */
5441 if (newfd >= 0)
5442 close(newfd);
5443 errno = i;
5444 ash_msg_and_raise_error("%d: %m", fd);
5445 /* NOTREACHED */
5446 }
5447 /* EBADF: it is not open - good, remember to close it */
5448 remember_to_close:
5449 i = CLOSED;
5450 } else { /* fd is open, save its copy */
5451#if !defined(F_DUPFD_CLOEXEC)
5452 fcntl(i, F_SETFD, FD_CLOEXEC);
5453#endif
5454 /* "exec fd>&-" should not close fds
5455 * which point to script file(s).
5456 * Force them to be restored afterwards */
5457 if (is_hidden_fd(sv, fd))
5458 i |= COPYFD_RESTORE;
5459 }
5460 if (fd == 2)
5461 copied_fd2 = i;
5462 sv->two_fd[sv_pos].orig = fd;
5463 sv->two_fd[sv_pos].copy = i;
5464 sv_pos++;
5465 }
5466 if (newfd < 0) {
5467 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5468 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
5469 /* Don't want to trigger debugging */
5470 if (fd != -1)
5471 close(fd);
5472 } else {
5473 dup2_or_raise(redir->ndup.dupfd, fd);
5474 }
5475 } else if (fd != newfd) { /* move newfd to fd */
5476 dup2_or_raise(newfd, fd);
5477#if ENABLE_ASH_BASH_COMPAT
5478 if (!(redir->nfile.type == NTO2 && fd == 2))
5479#endif
5480 close(newfd);
5481 }
5482#if ENABLE_ASH_BASH_COMPAT
5483 if (redir->nfile.type == NTO2 && fd == 1) {
5484 /* We already redirected it to fd 1, now copy it to 2 */
5485 newfd = 1;
5486 fd = 2;
5487 goto redirect_more;
5488 }
5489#endif
5490 } while ((redir = redir->nfile.next) != NULL);
5491
5492 INT_ON;
5493 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5494 preverrout_fd = copied_fd2;
5495}
5496
5497/*
5498 * Undo the effects of the last redirection.
5499 */
5500static void
5501popredir(int drop, int restore)
5502{
5503 struct redirtab *rp;
5504 int i;
5505
5506 if (redirlist == NULL)
5507 return;
5508 INT_OFF;
5509 rp = redirlist;
5510 for (i = 0; i < rp->pair_count; i++) {
5511 int fd = rp->two_fd[i].orig;
5512 int copy = rp->two_fd[i].copy;
5513 if (copy == CLOSED) {
5514 if (!drop)
5515 close(fd);
5516 continue;
5517 }
5518 if (copy != EMPTY) {
5519 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5520 copy &= ~COPYFD_RESTORE;
5521 /*close(fd);*/
5522 dup2_or_raise(copy, fd);
5523 }
5524 close(copy & ~COPYFD_RESTORE);
5525 }
5526 }
5527 redirlist = rp->next;
5528 free(rp);
5529 INT_ON;
5530}
5531
5532/*
5533 * Undo all redirections. Called on error or interrupt.
5534 */
5535
5536static int
5537redirectsafe(union node *redir, int flags)
5538{
5539 int err;
5540 volatile int saveint;
5541 struct jmploc *volatile savehandler = exception_handler;
5542 struct jmploc jmploc;
5543
5544 SAVE_INT(saveint);
5545 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5546 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5547 if (!err) {
5548 exception_handler = &jmploc;
5549 redirect(redir, flags);
5550 }
5551 exception_handler = savehandler;
5552 if (err && exception_type != EXERROR)
5553 longjmp(exception_handler->loc, 1);
5554 RESTORE_INT(saveint);
5555 return err;
5556}
5557
5558
5559/* ============ Routines to expand arguments to commands
5560 *
5561 * We have to deal with backquotes, shell variables, and file metacharacters.
5562 */
5563
5564#if ENABLE_FEATURE_SH_MATH
5565static arith_t
5566ash_arith(const char *s)
5567{
5568 arith_state_t math_state;
5569 arith_t result;
5570
5571 math_state.lookupvar = lookupvar;
5572 math_state.setvar = setvar0;
5573 //math_state.endofname = endofname;
5574
5575 INT_OFF;
5576 result = arith(&math_state, s);
5577 if (math_state.errmsg)
5578 ash_msg_and_raise_error(math_state.errmsg);
5579 INT_ON;
5580
5581 return result;
5582}
5583#endif
5584
5585/*
5586 * expandarg flags
5587 */
5588#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5589#define EXP_TILDE 0x2 /* do normal tilde expansion */
5590#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5591#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5592/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5593 * POSIX says for this case:
5594 * Pathname expansion shall not be performed on the word by a
5595 * non-interactive shell; an interactive shell may perform it, but shall
5596 * do so only when the expansion would result in one word.
5597 * Currently, our code complies to the above rule by never globbing
5598 * redirection filenames.
5599 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5600 * (this means that on a typical Linux distro, bash almost always
5601 * performs globbing, and thus diverges from what we do).
5602 */
5603#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5604#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
5605#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5606#define EXP_WORD 0x80 /* expand word in parameter expansion */
5607#define EXP_QUOTED 0x100 /* expand word in double quotes */
5608/*
5609 * rmescape() flags
5610 */
5611#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5612#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5613#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5614#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5615#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
5616
5617/* Add CTLESC when necessary. */
5618#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
5619/* Do not skip NUL characters. */
5620#define QUOTES_KEEPNUL EXP_TILDE
5621
5622/*
5623 * Structure specifying which parts of the string should be searched
5624 * for IFS characters.
5625 */
5626struct ifsregion {
5627 struct ifsregion *next; /* next region in list */
5628 int begoff; /* offset of start of region */
5629 int endoff; /* offset of end of region */
5630 int nulonly; /* search for nul bytes only */
5631};
5632
5633struct arglist {
5634 struct strlist *list;
5635 struct strlist **lastp;
5636};
5637
5638/* output of current string */
5639static char *expdest;
5640/* list of back quote expressions */
5641static struct nodelist *argbackq;
5642/* first struct in list of ifs regions */
5643static struct ifsregion ifsfirst;
5644/* last struct in list */
5645static struct ifsregion *ifslastp;
5646/* holds expanded arg list */
5647static struct arglist exparg;
5648
5649/*
5650 * Our own itoa().
5651 */
5652#if !ENABLE_FEATURE_SH_MATH
5653/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5654typedef long arith_t;
5655# define ARITH_FMT "%ld"
5656#endif
5657static int
5658cvtnum(arith_t num)
5659{
5660 int len;
5661
5662 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5663 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
5664 STADJUST(len, expdest);
5665 return len;
5666}
5667
5668/*
5669 * Break the argument string into pieces based upon IFS and add the
5670 * strings to the argument list. The regions of the string to be
5671 * searched for IFS characters have been stored by recordregion.
5672 */
5673static void
5674ifsbreakup(char *string, struct arglist *arglist)
5675{
5676 struct ifsregion *ifsp;
5677 struct strlist *sp;
5678 char *start;
5679 char *p;
5680 char *q;
5681 const char *ifs, *realifs;
5682 int ifsspc;
5683 int nulonly;
5684
5685 start = string;
5686 if (ifslastp != NULL) {
5687 ifsspc = 0;
5688 nulonly = 0;
5689 realifs = ifsset() ? ifsval() : defifs;
5690 ifsp = &ifsfirst;
5691 do {
5692 p = string + ifsp->begoff;
5693 nulonly = ifsp->nulonly;
5694 ifs = nulonly ? nullstr : realifs;
5695 ifsspc = 0;
5696 while (p < string + ifsp->endoff) {
5697 q = p;
5698 if ((unsigned char)*p == CTLESC)
5699 p++;
5700 if (!strchr(ifs, *p)) {
5701 p++;
5702 continue;
5703 }
5704 if (!nulonly)
5705 ifsspc = (strchr(defifs, *p) != NULL);
5706 /* Ignore IFS whitespace at start */
5707 if (q == start && ifsspc) {
5708 p++;
5709 start = p;
5710 continue;
5711 }
5712 *q = '\0';
5713 sp = stzalloc(sizeof(*sp));
5714 sp->text = start;
5715 *arglist->lastp = sp;
5716 arglist->lastp = &sp->next;
5717 p++;
5718 if (!nulonly) {
5719 for (;;) {
5720 if (p >= string + ifsp->endoff) {
5721 break;
5722 }
5723 q = p;
5724 if ((unsigned char)*p == CTLESC)
5725 p++;
5726 if (strchr(ifs, *p) == NULL) {
5727 p = q;
5728 break;
5729 }
5730 if (strchr(defifs, *p) == NULL) {
5731 if (ifsspc) {
5732 p++;
5733 ifsspc = 0;
5734 } else {
5735 p = q;
5736 break;
5737 }
5738 } else
5739 p++;
5740 }
5741 }
5742 start = p;
5743 } /* while */
5744 ifsp = ifsp->next;
5745 } while (ifsp != NULL);
5746 if (nulonly)
5747 goto add;
5748 }
5749
5750 if (!*start)
5751 return;
5752
5753 add:
5754 sp = stzalloc(sizeof(*sp));
5755 sp->text = start;
5756 *arglist->lastp = sp;
5757 arglist->lastp = &sp->next;
5758}
5759
5760static void
5761ifsfree(void)
5762{
5763 struct ifsregion *p = ifsfirst.next;
5764
5765 if (!p)
5766 goto out;
5767
5768 INT_OFF;
5769 do {
5770 struct ifsregion *ifsp;
5771 ifsp = p->next;
5772 free(p);
5773 p = ifsp;
5774 } while (p);
5775 ifsfirst.next = NULL;
5776 INT_ON;
5777 out:
5778 ifslastp = NULL;
5779}
5780
5781static size_t
5782esclen(const char *start, const char *p)
5783{
5784 size_t esc = 0;
5785
5786 while (p > start && (unsigned char)*--p == CTLESC) {
5787 esc++;
5788 }
5789 return esc;
5790}
5791
5792/*
5793 * Remove any CTLESC characters from a string.
5794 */
5795static char *
5796rmescapes(char *str, int flag)
5797{
5798 static const char qchars[] ALIGN1 = {
5799 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
5800
5801 char *p, *q, *r;
5802 unsigned inquotes;
5803 unsigned protect_against_glob;
5804 unsigned globbing;
5805 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
5806
5807 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
5808 if (!p)
5809 return str;
5810
5811 q = p;
5812 r = str;
5813 if (flag & RMESCAPE_ALLOC) {
5814 size_t len = p - str;
5815 size_t fulllen = len + strlen(p) + 1;
5816
5817 if (flag & RMESCAPE_GROW) {
5818 int strloc = str - (char *)stackblock();
5819 r = makestrspace(fulllen, expdest);
5820 /* p and str may be invalidated by makestrspace */
5821 str = (char *)stackblock() + strloc;
5822 p = str + len;
5823 } else if (flag & RMESCAPE_HEAP) {
5824 r = ckmalloc(fulllen);
5825 } else {
5826 r = stalloc(fulllen);
5827 }
5828 q = r;
5829 if (len > 0) {
5830 q = (char *)memcpy(q, str, len) + len;
5831 }
5832 }
5833
5834 inquotes = 0;
5835 globbing = flag & RMESCAPE_GLOB;
5836 protect_against_glob = globbing;
5837 while (*p) {
5838 if ((unsigned char)*p == CTLQUOTEMARK) {
5839// Note: both inquotes and protect_against_glob only affect whether
5840 inquotes = ~inquotes;
5841 p++;
5842 protect_against_glob = globbing;
5843 continue;
5844 }
5845 if ((unsigned char)*p == CTLESC) {
5846 p++;
5847#if DEBUG
5848 if (*p == '\0')
5849 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5850#endif
5851 if (protect_against_glob) {
5852 *q++ = '\\';
5853 }
5854 } else if (*p == '\\' && !inquotes) {
5855 /* naked back slash */
5856 protect_against_glob = 0;
5857 goto copy;
5858 }
5859#if ENABLE_ASH_BASH_COMPAT
5860 else if (*p == '/' && slash) {
5861 /* stop handling globbing and mark location of slash */
5862 globbing = slash = 0;
5863 *p = CTLESC;
5864 }
5865#endif
5866 protect_against_glob = globbing;
5867 copy:
5868 *q++ = *p++;
5869 }
5870 *q = '\0';
5871 if (flag & RMESCAPE_GROW) {
5872 expdest = r;
5873 STADJUST(q - r + 1, expdest);
5874 }
5875 return r;
5876}
5877#define pmatch(a, b) !fnmatch((a), (b), 0)
5878
5879/*
5880 * Prepare a pattern for a expmeta (internal glob(3)) call.
5881 *
5882 * Returns an stalloced string.
5883 */
5884static char *
5885preglob(const char *pattern, int flag)
5886{
5887 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
5888}
5889
5890/*
5891 * Put a string on the stack.
5892 */
5893static void
5894memtodest(const char *p, size_t len, int syntax, int quotes)
5895{
5896 char *q;
5897
5898 if (!len)
5899 return;
5900
5901 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5902
5903 do {
5904 unsigned char c = *p++;
5905 if (c) {
5906 if (quotes & QUOTES_ESC) {
5907 int n = SIT(c, syntax);
5908 if (n == CCTL
5909 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5910 && n == CBACK
5911 )
5912 ) {
5913 USTPUTC(CTLESC, q);
5914 }
5915 }
5916 } else if (!(quotes & QUOTES_KEEPNUL))
5917 continue;
5918 USTPUTC(c, q);
5919 } while (--len);
5920
5921 expdest = q;
5922}
5923
5924static size_t
5925strtodest(const char *p, int syntax, int quotes)
5926{
5927 size_t len = strlen(p);
5928 memtodest(p, len, syntax, quotes);
5929 return len;
5930}
5931
5932/*
5933 * Record the fact that we have to scan this region of the
5934 * string for IFS characters.
5935 */
5936static void
5937recordregion(int start, int end, int nulonly)
5938{
5939 struct ifsregion *ifsp;
5940
5941 if (ifslastp == NULL) {
5942 ifsp = &ifsfirst;
5943 } else {
5944 INT_OFF;
5945 ifsp = ckzalloc(sizeof(*ifsp));
5946 /*ifsp->next = NULL; - ckzalloc did it */
5947 ifslastp->next = ifsp;
5948 INT_ON;
5949 }
5950 ifslastp = ifsp;
5951 ifslastp->begoff = start;
5952 ifslastp->endoff = end;
5953 ifslastp->nulonly = nulonly;
5954}
5955
5956static void
5957removerecordregions(int endoff)
5958{
5959 if (ifslastp == NULL)
5960 return;
5961
5962 if (ifsfirst.endoff > endoff) {
5963 while (ifsfirst.next) {
5964 struct ifsregion *ifsp;
5965 INT_OFF;
5966 ifsp = ifsfirst.next->next;
5967 free(ifsfirst.next);
5968 ifsfirst.next = ifsp;
5969 INT_ON;
5970 }
5971 if (ifsfirst.begoff > endoff) {
5972 ifslastp = NULL;
5973 } else {
5974 ifslastp = &ifsfirst;
5975 ifsfirst.endoff = endoff;
5976 }
5977 return;
5978 }
5979
5980 ifslastp = &ifsfirst;
5981 while (ifslastp->next && ifslastp->next->begoff < endoff)
5982 ifslastp = ifslastp->next;
5983 while (ifslastp->next) {
5984 struct ifsregion *ifsp;
5985 INT_OFF;
5986 ifsp = ifslastp->next->next;
5987 free(ifslastp->next);
5988 ifslastp->next = ifsp;
5989 INT_ON;
5990 }
5991 if (ifslastp->endoff > endoff)
5992 ifslastp->endoff = endoff;
5993}
5994
5995static char *
5996exptilde(char *startp, char *p, int flags)
5997{
5998 unsigned char c;
5999 char *name;
6000 struct passwd *pw;
6001 const char *home;
6002 int quotes = flags & QUOTES_ESC;
6003
6004 name = p + 1;
6005
6006 while ((c = *++p) != '\0') {
6007 switch (c) {
6008 case CTLESC:
6009 return startp;
6010 case CTLQUOTEMARK:
6011 return startp;
6012 case ':':
6013 if (flags & EXP_VARTILDE)
6014 goto done;
6015 break;
6016 case '/':
6017 case CTLENDVAR:
6018 goto done;
6019 }
6020 }
6021 done:
6022 *p = '\0';
6023 if (*name == '\0') {
6024 home = lookupvar("HOME");
6025 } else {
6026 pw = getpwnam(name);
6027 if (pw == NULL)
6028 goto lose;
6029 home = pw->pw_dir;
6030 }
6031 if (!home || !*home)
6032 goto lose;
6033 *p = c;
6034 strtodest(home, SQSYNTAX, quotes);
6035 return p;
6036 lose:
6037 *p = c;
6038 return startp;
6039}
6040
6041/*
6042 * Execute a command inside back quotes. If it's a builtin command, we
6043 * want to save its output in a block obtained from malloc. Otherwise
6044 * we fork off a subprocess and get the output of the command via a pipe.
6045 * Should be called with interrupts off.
6046 */
6047struct backcmd { /* result of evalbackcmd */
6048 int fd; /* file descriptor to read from */
6049 int nleft; /* number of chars in buffer */
6050 char *buf; /* buffer */
6051 struct job *jp; /* job structure for command */
6052};
6053
6054/* These forward decls are needed to use "eval" code for backticks handling: */
6055#define EV_EXIT 01 /* exit after evaluating tree */
6056static int evaltree(union node *, int);
6057
6058static void FAST_FUNC
6059evalbackcmd(union node *n, struct backcmd *result)
6060{
6061 int pip[2];
6062 struct job *jp;
6063
6064 result->fd = -1;
6065 result->buf = NULL;
6066 result->nleft = 0;
6067 result->jp = NULL;
6068 if (n == NULL) {
6069 goto out;
6070 }
6071
6072 if (pipe(pip) < 0)
6073 ash_msg_and_raise_error("pipe call failed");
6074 jp = makejob(/*n,*/ 1);
6075 if (forkshell(jp, n, FORK_NOJOB) == 0) {
6076 /* child */
6077 FORCE_INT_ON;
6078 close(pip[0]);
6079 if (pip[1] != 1) {
6080 /*close(1);*/
6081 dup2_or_raise(pip[1], 1);
6082 close(pip[1]);
6083 }
6084/* TODO: eflag clearing makes the following not abort:
6085 * ash -c 'set -e; z=$(false;echo foo); echo $z'
6086 * which is what bash does (unless it is in POSIX mode).
6087 * dash deleted "eflag = 0" line in the commit
6088 * Date: Mon, 28 Jun 2010 17:11:58 +1000
6089 * [EVAL] Don't clear eflag in evalbackcmd
6090 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
6091 */
6092 eflag = 0;
6093 ifsfree();
6094 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6095 /* NOTREACHED */
6096 }
6097 /* parent */
6098 close(pip[1]);
6099 result->fd = pip[0];
6100 result->jp = jp;
6101
6102 out:
6103 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6104 result->fd, result->buf, result->nleft, result->jp));
6105}
6106
6107/*
6108 * Expand stuff in backwards quotes.
6109 */
6110static void
6111expbackq(union node *cmd, int flag)
6112{
6113 struct backcmd in;
6114 int i;
6115 char buf[128];
6116 char *p;
6117 char *dest;
6118 int startloc;
6119 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
6120 struct stackmark smark;
6121
6122 INT_OFF;
6123 startloc = expdest - (char *)stackblock();
6124 pushstackmark(&smark, startloc);
6125 evalbackcmd(cmd, &in);
6126 popstackmark(&smark);
6127
6128 p = in.buf;
6129 i = in.nleft;
6130 if (i == 0)
6131 goto read;
6132 for (;;) {
6133 memtodest(p, i, syntax, flag & QUOTES_ESC);
6134 read:
6135 if (in.fd < 0)
6136 break;
6137 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
6138 TRACE(("expbackq: read returns %d\n", i));
6139 if (i <= 0)
6140 break;
6141 p = buf;
6142 }
6143
6144 free(in.buf);
6145 if (in.fd >= 0) {
6146 close(in.fd);
6147 back_exitstatus = waitforjob(in.jp);
6148 }
6149 INT_ON;
6150
6151 /* Eat all trailing newlines */
6152 dest = expdest;
6153 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6154 STUNPUTC(dest);
6155 expdest = dest;
6156
6157 if (!(flag & EXP_QUOTED))
6158 recordregion(startloc, dest - (char *)stackblock(), 0);
6159 TRACE(("evalbackq: size:%d:'%.*s'\n",
6160 (int)((dest - (char *)stackblock()) - startloc),
6161 (int)((dest - (char *)stackblock()) - startloc),
6162 stackblock() + startloc));
6163}
6164
6165#if ENABLE_FEATURE_SH_MATH
6166/*
6167 * Expand arithmetic expression. Backup to start of expression,
6168 * evaluate, place result in (backed up) result, adjust string position.
6169 */
6170static void
6171expari(int flag)
6172{
6173 char *p, *start;
6174 int begoff;
6175 int len;
6176
6177 /* ifsfree(); */
6178
6179 /*
6180 * This routine is slightly over-complicated for
6181 * efficiency. Next we scan backwards looking for the
6182 * start of arithmetic.
6183 */
6184 start = stackblock();
6185 p = expdest - 1;
6186 *p = '\0';
6187 p--;
6188 while (1) {
6189 int esc;
6190
6191 while ((unsigned char)*p != CTLARI) {
6192 p--;
6193#if DEBUG
6194 if (p < start) {
6195 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6196 }
6197#endif
6198 }
6199
6200 esc = esclen(start, p);
6201 if (!(esc % 2)) {
6202 break;
6203 }
6204
6205 p -= esc + 1;
6206 }
6207
6208 begoff = p - start;
6209
6210 removerecordregions(begoff);
6211
6212 expdest = p;
6213
6214 if (flag & QUOTES_ESC)
6215 rmescapes(p + 1, 0);
6216
6217 len = cvtnum(ash_arith(p + 1));
6218
6219 if (!(flag & EXP_QUOTED))
6220 recordregion(begoff, begoff + len, 0);
6221}
6222#endif
6223
6224/* argstr needs it */
6225static char *evalvar(char *p, int flags, struct strlist *var_str_list);
6226
6227/*
6228 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6229 * characters to allow for further processing. Otherwise treat
6230 * $@ like $* since no splitting will be performed.
6231 *
6232 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6233 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6234 * for correct expansion of "B=$A" word.
6235 */
6236static void
6237argstr(char *p, int flags, struct strlist *var_str_list)
6238{
6239 static const char spclchars[] ALIGN1 = {
6240 '=',
6241 ':',
6242 CTLQUOTEMARK,
6243 CTLENDVAR,
6244 CTLESC,
6245 CTLVAR,
6246 CTLBACKQ,
6247#if ENABLE_FEATURE_SH_MATH
6248 CTLENDARI,
6249#endif
6250 '\0'
6251 };
6252 const char *reject = spclchars;
6253 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
6254 int inquotes;
6255 size_t length;
6256 int startloc;
6257
6258 if (!(flags & EXP_VARTILDE)) {
6259 reject += 2;
6260 } else if (flags & EXP_VARTILDE2) {
6261 reject++;
6262 }
6263 inquotes = 0;
6264 length = 0;
6265 if (flags & EXP_TILDE) {
6266 char *q;
6267
6268 flags &= ~EXP_TILDE;
6269 tilde:
6270 q = p;
6271 if (*q == '~')
6272 p = exptilde(p, q, flags);
6273 }
6274 start:
6275 startloc = expdest - (char *)stackblock();
6276 for (;;) {
6277 unsigned char c;
6278
6279 length += strcspn(p + length, reject);
6280 c = p[length];
6281 if (c) {
6282 if (!(c & 0x80)
6283 IF_FEATURE_SH_MATH(|| c == CTLENDARI)
6284 ) {
6285 /* c == '=' || c == ':' || c == CTLENDARI */
6286 length++;
6287 }
6288 }
6289 if (length > 0) {
6290 int newloc;
6291 expdest = stack_nputstr(p, length, expdest);
6292 newloc = expdest - (char *)stackblock();
6293 if (breakall && !inquotes && newloc > startloc) {
6294 recordregion(startloc, newloc, 0);
6295 }
6296 startloc = newloc;
6297 }
6298 p += length + 1;
6299 length = 0;
6300
6301 switch (c) {
6302 case '\0':
6303 goto breakloop;
6304 case '=':
6305 if (flags & EXP_VARTILDE2) {
6306 p--;
6307 continue;
6308 }
6309 flags |= EXP_VARTILDE2;
6310 reject++;
6311 /* fall through */
6312 case ':':
6313 /*
6314 * sort of a hack - expand tildes in variable
6315 * assignments (after the first '=' and after ':'s).
6316 */
6317 if (*--p == '~') {
6318 goto tilde;
6319 }
6320 continue;
6321 }
6322
6323 switch (c) {
6324 case CTLENDVAR: /* ??? */
6325 goto breakloop;
6326 case CTLQUOTEMARK:
6327 inquotes ^= EXP_QUOTED;
6328 /* "$@" syntax adherence hack */
6329 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6330 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
6331 goto start;
6332 }
6333 addquote:
6334 if (flags & QUOTES_ESC) {
6335 p--;
6336 length++;
6337 startloc++;
6338 }
6339 break;
6340 case CTLESC:
6341 startloc++;
6342 length++;
6343
6344 /*
6345 * Quoted parameter expansion pattern: remove quote
6346 * unless inside inner quotes or we have a literal
6347 * backslash.
6348 */
6349 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6350 EXP_QPAT && *p != '\\')
6351 break;
6352
6353 goto addquote;
6354 case CTLVAR:
6355 TRACE(("argstr: evalvar('%s')\n", p));
6356 p = evalvar(p, flags | inquotes, var_str_list);
6357 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6358 goto start;
6359 case CTLBACKQ:
6360 expbackq(argbackq->n, flags | inquotes);
6361 argbackq = argbackq->next;
6362 goto start;
6363#if ENABLE_FEATURE_SH_MATH
6364 case CTLENDARI:
6365 p--;
6366 expari(flags | inquotes);
6367 goto start;
6368#endif
6369 }
6370 }
6371 breakloop: ;
6372}
6373
6374static char *
6375scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6376 char *pattern, int quotes, int zero)
6377{
6378 char *loc, *loc2;
6379 char c;
6380
6381 loc = startp;
6382 loc2 = rmesc;
6383 do {
6384 int match;
6385 const char *s = loc2;
6386
6387 c = *loc2;
6388 if (zero) {
6389 *loc2 = '\0';
6390 s = rmesc;
6391 }
6392 match = pmatch(pattern, s);
6393
6394 *loc2 = c;
6395 if (match)
6396 return loc;
6397 if (quotes && (unsigned char)*loc == CTLESC)
6398 loc++;
6399 loc++;
6400 loc2++;
6401 } while (c);
6402 return NULL;
6403}
6404
6405static char *
6406scanright(char *startp, char *rmesc, char *rmescend,
6407 char *pattern, int quotes, int match_at_start)
6408{
6409#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6410 int try2optimize = match_at_start;
6411#endif
6412 int esc = 0;
6413 char *loc;
6414 char *loc2;
6415
6416 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6417 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6418 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6419 * Logic:
6420 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6421 * and on each iteration they go back two/one char until they reach the beginning.
6422 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6423 */
6424 /* TODO: document in what other circumstances we are called. */
6425
6426 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
6427 int match;
6428 char c = *loc2;
6429 const char *s = loc2;
6430 if (match_at_start) {
6431 *loc2 = '\0';
6432 s = rmesc;
6433 }
6434 match = pmatch(pattern, s);
6435 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
6436 *loc2 = c;
6437 if (match)
6438 return loc;
6439#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6440 if (try2optimize) {
6441 /* Maybe we can optimize this:
6442 * if pattern ends with unescaped *, we can avoid checking
6443 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6444 * it wont match truncated "raw_value_of_" strings too.
6445 */
6446 unsigned plen = strlen(pattern);
6447 /* Does it end with "*"? */
6448 if (plen != 0 && pattern[--plen] == '*') {
6449 /* "xxxx*" is not escaped */
6450 /* "xxx\*" is escaped */
6451 /* "xx\\*" is not escaped */
6452 /* "x\\\*" is escaped */
6453 int slashes = 0;
6454 while (plen != 0 && pattern[--plen] == '\\')
6455 slashes++;
6456 if (!(slashes & 1))
6457 break; /* ends with unescaped "*" */
6458 }
6459 try2optimize = 0;
6460 }
6461#endif
6462 loc--;
6463 if (quotes) {
6464 if (--esc < 0) {
6465 esc = esclen(startp, loc);
6466 }
6467 if (esc % 2) {
6468 esc--;
6469 loc--;
6470 }
6471 }
6472 }
6473 return NULL;
6474}
6475
6476static void varunset(const char *, const char *, const char *, int) NORETURN;
6477static void
6478varunset(const char *end, const char *var, const char *umsg, int varflags)
6479{
6480 const char *msg;
6481 const char *tail;
6482
6483 tail = nullstr;
6484 msg = "parameter not set";
6485 if (umsg) {
6486 if ((unsigned char)*end == CTLENDVAR) {
6487 if (varflags & VSNUL)
6488 tail = " or null";
6489 } else {
6490 msg = umsg;
6491 }
6492 }
6493 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
6494}
6495
6496static const char *
6497subevalvar(char *p, char *varname, int strloc, int subtype,
6498 int startloc, int varflags, int flag, struct strlist *var_str_list)
6499{
6500 struct nodelist *saveargbackq = argbackq;
6501 int quotes = flag & QUOTES_ESC;
6502 char *startp;
6503 char *loc;
6504 char *rmesc, *rmescend;
6505 char *str;
6506 IF_ASH_BASH_COMPAT(char *repl = NULL;)
6507 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
6508 int amount, resetloc;
6509 IF_ASH_BASH_COMPAT(int workloc;)
6510 int zero;
6511 char *(*scan)(char*, char*, char*, char*, int, int);
6512
6513 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6514 // p, varname, strloc, subtype, startloc, varflags, quotes);
6515
6516 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
6517 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6518 var_str_list);
6519 STPUTC('\0', expdest);
6520 argbackq = saveargbackq;
6521 startp = (char *)stackblock() + startloc;
6522
6523 switch (subtype) {
6524 case VSASSIGN:
6525 setvar0(varname, startp);
6526 amount = startp - expdest;
6527 STADJUST(amount, expdest);
6528 return startp;
6529
6530 case VSQUESTION:
6531 varunset(p, varname, startp, varflags);
6532 /* NOTREACHED */
6533
6534#if ENABLE_ASH_BASH_COMPAT
6535 case VSSUBSTR:
6536//TODO: support more general format ${v:EXPR:EXPR},
6537// where EXPR follows $(()) rules
6538 loc = str = stackblock() + strloc;
6539 /* Read POS in ${var:POS:LEN} */
6540 pos = atoi(loc); /* number(loc) errors out on "1:4" */
6541 len = str - startp - 1;
6542
6543 /* *loc != '\0', guaranteed by parser */
6544 if (quotes) {
6545 char *ptr;
6546
6547 /* Adjust the length by the number of escapes */
6548 for (ptr = startp; ptr < (str - 1); ptr++) {
6549 if ((unsigned char)*ptr == CTLESC) {
6550 len--;
6551 ptr++;
6552 }
6553 }
6554 }
6555 orig_len = len;
6556
6557 if (*loc++ == ':') {
6558 /* ${var::LEN} */
6559 len = number(loc);
6560 } else {
6561 /* Skip POS in ${var:POS:LEN} */
6562 len = orig_len;
6563 while (*loc && *loc != ':') {
6564 /* TODO?
6565 * bash complains on: var=qwe; echo ${var:1a:123}
6566 if (!isdigit(*loc))
6567 ash_msg_and_raise_error(msg_illnum, str);
6568 */
6569 loc++;
6570 }
6571 if (*loc++ == ':') {
6572 len = number(loc);
6573 }
6574 }
6575 if (pos < 0) {
6576 /* ${VAR:$((-n)):l} starts n chars from the end */
6577 pos = orig_len + pos;
6578 }
6579 if ((unsigned)pos >= orig_len) {
6580 /* apart from obvious ${VAR:999999:l},
6581 * covers ${VAR:$((-9999999)):l} - result is ""
6582 * (bash-compat)
6583 */
6584 pos = 0;
6585 len = 0;
6586 }
6587 if (len > (orig_len - pos))
6588 len = orig_len - pos;
6589
6590 for (str = startp; pos; str++, pos--) {
6591 if (quotes && (unsigned char)*str == CTLESC)
6592 str++;
6593 }
6594 for (loc = startp; len; len--) {
6595 if (quotes && (unsigned char)*str == CTLESC)
6596 *loc++ = *str++;
6597 *loc++ = *str++;
6598 }
6599 *loc = '\0';
6600 amount = loc - expdest;
6601 STADJUST(amount, expdest);
6602 return loc;
6603#endif
6604 }
6605
6606 resetloc = expdest - (char *)stackblock();
6607
6608 /* We'll comeback here if we grow the stack while handling
6609 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6610 * stack will need rebasing, and we'll need to remove our work
6611 * areas each time
6612 */
6613 IF_ASH_BASH_COMPAT(restart:)
6614
6615 amount = expdest - ((char *)stackblock() + resetloc);
6616 STADJUST(-amount, expdest);
6617 startp = (char *)stackblock() + startloc;
6618
6619 rmesc = startp;
6620 rmescend = (char *)stackblock() + strloc;
6621 if (quotes) {
6622 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
6623 if (rmesc != startp) {
6624 rmescend = expdest;
6625 startp = (char *)stackblock() + startloc;
6626 }
6627 }
6628 rmescend--;
6629 str = (char *)stackblock() + strloc;
6630 /*
6631 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6632 * The result is a_\_z_c (not a\_\_z_c)!
6633 *
6634 * The search pattern and replace string treat backslashes differently!
6635 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6636 * and string. It's only used on the first call.
6637 */
6638 preglob(str, IF_ASH_BASH_COMPAT(
6639 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6640 RMESCAPE_SLASH :) 0);
6641
6642#if ENABLE_ASH_BASH_COMPAT
6643 workloc = expdest - (char *)stackblock();
6644 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
6645 char *idx, *end;
6646
6647 if (!repl) {
6648 repl = strchr(str, CTLESC);
6649 if (repl)
6650 *repl++ = '\0';
6651 else
6652 repl = nullstr;
6653 }
6654 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
6655
6656 /* If there's no pattern to match, return the expansion unmolested */
6657 if (str[0] == '\0')
6658 return NULL;
6659
6660 len = 0;
6661 idx = startp;
6662 end = str - 1;
6663 while (idx < end) {
6664 try_to_match:
6665 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6666 //bb_error_msg("scanright('%s'):'%s'", str, loc);
6667 if (!loc) {
6668 /* No match, advance */
6669 char *restart_detect = stackblock();
6670 skip_matching:
6671 STPUTC(*idx, expdest);
6672 if (quotes && (unsigned char)*idx == CTLESC) {
6673 idx++;
6674 len++;
6675 STPUTC(*idx, expdest);
6676 }
6677 if (stackblock() != restart_detect)
6678 goto restart;
6679 idx++;
6680 len++;
6681 rmesc++;
6682 /* continue; - prone to quadratic behavior, smarter code: */
6683 if (idx >= end)
6684 break;
6685 if (str[0] == '*') {
6686 /* Pattern is "*foo". If "*foo" does not match "long_string",
6687 * it would never match "ong_string" etc, no point in trying.
6688 */
6689 goto skip_matching;
6690 }
6691 goto try_to_match;
6692 }
6693
6694 if (subtype == VSREPLACEALL) {
6695 while (idx < loc) {
6696 if (quotes && (unsigned char)*idx == CTLESC)
6697 idx++;
6698 idx++;
6699 rmesc++;
6700 }
6701 } else {
6702 idx = loc;
6703 }
6704
6705 //bb_error_msg("repl:'%s'", repl);
6706 for (loc = (char*)repl; *loc; loc++) {
6707 char *restart_detect = stackblock();
6708 if (quotes && *loc == '\\') {
6709 STPUTC(CTLESC, expdest);
6710 len++;
6711 }
6712 STPUTC(*loc, expdest);
6713 if (stackblock() != restart_detect)
6714 goto restart;
6715 len++;
6716 }
6717
6718 if (subtype == VSREPLACE) {
6719 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
6720 while (*idx) {
6721 char *restart_detect = stackblock();
6722 STPUTC(*idx, expdest);
6723 if (stackblock() != restart_detect)
6724 goto restart;
6725 len++;
6726 idx++;
6727 }
6728 break;
6729 }
6730 }
6731
6732 /* We've put the replaced text into a buffer at workloc, now
6733 * move it to the right place and adjust the stack.
6734 */
6735 STPUTC('\0', expdest);
6736 startp = (char *)stackblock() + startloc;
6737 memmove(startp, (char *)stackblock() + workloc, len + 1);
6738 //bb_error_msg("startp:'%s'", startp);
6739 amount = expdest - (startp + len);
6740 STADJUST(-amount, expdest);
6741 return startp;
6742 }
6743#endif /* ENABLE_ASH_BASH_COMPAT */
6744
6745 subtype -= VSTRIMRIGHT;
6746#if DEBUG
6747 if (subtype < 0 || subtype > 7)
6748 abort();
6749#endif
6750 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
6751 zero = subtype >> 1;
6752 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6753 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6754
6755 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6756 if (loc) {
6757 if (zero) {
6758 memmove(startp, loc, str - loc);
6759 loc = startp + (str - loc) - 1;
6760 }
6761 *loc = '\0';
6762 amount = loc - expdest;
6763 STADJUST(amount, expdest);
6764 }
6765 return loc;
6766}
6767
6768/*
6769 * Add the value of a specialized variable to the stack string.
6770 * name parameter (examples):
6771 * ash -c 'echo $1' name:'1='
6772 * ash -c 'echo $qwe' name:'qwe='
6773 * ash -c 'echo $$' name:'$='
6774 * ash -c 'echo ${$}' name:'$='
6775 * ash -c 'echo ${$##q}' name:'$=q'
6776 * ash -c 'echo ${#$}' name:'$='
6777 * note: examples with bad shell syntax:
6778 * ash -c 'echo ${#$1}' name:'$=1'
6779 * ash -c 'echo ${#1#}' name:'1=#'
6780 */
6781static NOINLINE ssize_t
6782varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
6783{
6784 const char *p;
6785 int num;
6786 int i;
6787 ssize_t len = 0;
6788 int sep;
6789 int quoted = *quotedp;
6790 int subtype = varflags & VSTYPE;
6791 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6792 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
6793 int syntax;
6794
6795 sep = (flags & EXP_FULL) << CHAR_BIT;
6796 syntax = quoted ? DQSYNTAX : BASESYNTAX;
6797
6798 switch (*name) {
6799 case '$':
6800 num = rootpid;
6801 goto numvar;
6802 case '?':
6803 num = exitstatus;
6804 goto numvar;
6805 case '#':
6806 num = shellparam.nparam;
6807 goto numvar;
6808 case '!':
6809 num = backgndpid;
6810 if (num == 0)
6811 return -1;
6812 numvar:
6813 len = cvtnum(num);
6814 goto check_1char_name;
6815 case '-':
6816 expdest = makestrspace(NOPTS, expdest);
6817 for (i = NOPTS - 1; i >= 0; i--) {
6818 if (optlist[i]) {
6819 USTPUTC(optletters(i), expdest);
6820 len++;
6821 }
6822 }
6823 check_1char_name:
6824#if 0
6825 /* handles cases similar to ${#$1} */
6826 if (name[2] != '\0')
6827 raise_error_syntax("bad substitution");
6828#endif
6829 break;
6830 case '@':
6831 if (quoted && sep)
6832 goto param;
6833 /* fall through */
6834 case '*': {
6835 char **ap;
6836 char sepc;
6837
6838 if (quoted)
6839 sep = 0;
6840 sep |= ifsset() ? ifsval()[0] : ' ';
6841 param:
6842 sepc = sep;
6843 *quotedp = !sepc;
6844 ap = shellparam.p;
6845 if (!ap)
6846 return -1;
6847 while ((p = *ap++) != NULL) {
6848 len += strtodest(p, syntax, quotes);
6849
6850 if (*ap && sep) {
6851 len++;
6852 memtodest(&sepc, 1, syntax, quotes);
6853 }
6854 }
6855 break;
6856 } /* case '*' */
6857 case '0':
6858 case '1':
6859 case '2':
6860 case '3':
6861 case '4':
6862 case '5':
6863 case '6':
6864 case '7':
6865 case '8':
6866 case '9':
6867 num = atoi(name); /* number(name) fails on ${N#str} etc */
6868 if (num < 0 || num > shellparam.nparam)
6869 return -1;
6870 p = num ? shellparam.p[num - 1] : arg0;
6871 goto value;
6872 default:
6873 /* NB: name has form "VAR=..." */
6874
6875 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6876 * which should be considered before we check variables. */
6877 if (var_str_list) {
6878 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6879 p = NULL;
6880 do {
6881 char *str, *eq;
6882 str = var_str_list->text;
6883 eq = strchr(str, '=');
6884 if (!eq) /* stop at first non-assignment */
6885 break;
6886 eq++;
6887 if (name_len == (unsigned)(eq - str)
6888 && strncmp(str, name, name_len) == 0
6889 ) {
6890 p = eq;
6891 /* goto value; - WRONG! */
6892 /* think "A=1 A=2 B=$A" */
6893 }
6894 var_str_list = var_str_list->next;
6895 } while (var_str_list);
6896 if (p)
6897 goto value;
6898 }
6899 p = lookupvar(name);
6900 value:
6901 if (!p)
6902 return -1;
6903
6904 len = strtodest(p, syntax, quotes);
6905#if ENABLE_UNICODE_SUPPORT
6906 if (subtype == VSLENGTH && len > 0) {
6907 reinit_unicode_for_ash();
6908 if (unicode_status == UNICODE_ON) {
6909 STADJUST(-len, expdest);
6910 discard = 0;
6911 len = unicode_strlen(p);
6912 }
6913 }
6914#endif
6915 break;
6916 }
6917
6918 if (discard)
6919 STADJUST(-len, expdest);
6920 return len;
6921}
6922
6923/*
6924 * Expand a variable, and return a pointer to the next character in the
6925 * input string.
6926 */
6927static char *
6928evalvar(char *p, int flag, struct strlist *var_str_list)
6929{
6930 char varflags;
6931 char subtype;
6932 int quoted;
6933 char easy;
6934 char *var;
6935 int patloc;
6936 int startloc;
6937 ssize_t varlen;
6938
6939 varflags = (unsigned char) *p++;
6940 subtype = varflags & VSTYPE;
6941
6942 if (!subtype)
6943 raise_error_syntax("bad substitution");
6944
6945 quoted = flag & EXP_QUOTED;
6946 var = p;
6947 easy = (!quoted || (*var == '@' && shellparam.nparam));
6948 startloc = expdest - (char *)stackblock();
6949 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
6950
6951 again:
6952 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
6953 if (varflags & VSNUL)
6954 varlen--;
6955
6956 if (subtype == VSPLUS) {
6957 varlen = -1 - varlen;
6958 goto vsplus;
6959 }
6960
6961 if (subtype == VSMINUS) {
6962 vsplus:
6963 if (varlen < 0) {
6964 argstr(
6965 p,
6966 flag | EXP_TILDE | EXP_WORD,
6967 var_str_list
6968 );
6969 goto end;
6970 }
6971 goto record;
6972 }
6973
6974 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6975 if (varlen >= 0)
6976 goto record;
6977
6978 subevalvar(p, var, 0, subtype, startloc, varflags,
6979 flag & ~QUOTES_ESC, var_str_list);
6980 varflags &= ~VSNUL;
6981 /*
6982 * Remove any recorded regions beyond
6983 * start of variable
6984 */
6985 removerecordregions(startloc);
6986 goto again;
6987 }
6988
6989 if (varlen < 0 && uflag)
6990 varunset(p, var, 0, 0);
6991
6992 if (subtype == VSLENGTH) {
6993 cvtnum(varlen > 0 ? varlen : 0);
6994 goto record;
6995 }
6996
6997 if (subtype == VSNORMAL) {
6998 record:
6999 if (!easy)
7000 goto end;
7001 recordregion(startloc, expdest - (char *)stackblock(), quoted);
7002 goto end;
7003 }
7004
7005#if DEBUG
7006 switch (subtype) {
7007 case VSTRIMLEFT:
7008 case VSTRIMLEFTMAX:
7009 case VSTRIMRIGHT:
7010 case VSTRIMRIGHTMAX:
7011#if ENABLE_ASH_BASH_COMPAT
7012 case VSSUBSTR:
7013 case VSREPLACE:
7014 case VSREPLACEALL:
7015#endif
7016 break;
7017 default:
7018 abort();
7019 }
7020#endif
7021
7022 if (varlen >= 0) {
7023 /*
7024 * Terminate the string and start recording the pattern
7025 * right after it
7026 */
7027 STPUTC('\0', expdest);
7028 patloc = expdest - (char *)stackblock();
7029 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
7030 startloc, varflags, flag, var_str_list)) {
7031 int amount = expdest - (
7032 (char *)stackblock() + patloc - 1
7033 );
7034 STADJUST(-amount, expdest);
7035 }
7036 /* Remove any recorded regions beyond start of variable */
7037 removerecordregions(startloc);
7038 goto record;
7039 }
7040
7041 end:
7042 if (subtype != VSNORMAL) { /* skip to end of alternative */
7043 int nesting = 1;
7044 for (;;) {
7045 unsigned char c = *p++;
7046 if (c == CTLESC)
7047 p++;
7048 else if (c == CTLBACKQ) {
7049 if (varlen >= 0)
7050 argbackq = argbackq->next;
7051 } else if (c == CTLVAR) {
7052 if ((*p++ & VSTYPE) != VSNORMAL)
7053 nesting++;
7054 } else if (c == CTLENDVAR) {
7055 if (--nesting == 0)
7056 break;
7057 }
7058 }
7059 }
7060 return p;
7061}
7062
7063/*
7064 * Add a file name to the list.
7065 */
7066static void
7067addfname(const char *name)
7068{
7069 struct strlist *sp;
7070
7071 sp = stzalloc(sizeof(*sp));
7072 sp->text = sstrdup(name);
7073 *exparg.lastp = sp;
7074 exparg.lastp = &sp->next;
7075}
7076
7077/* If we want to use glob() from libc... */
7078#if !ENABLE_ASH_INTERNAL_GLOB
7079
7080/* Add the result of glob() to the list */
7081static void
7082addglob(const glob_t *pglob)
7083{
7084 char **p = pglob->gl_pathv;
7085
7086 do {
7087 addfname(*p);
7088 } while (*++p);
7089}
7090static void
7091expandmeta(struct strlist *str /*, int flag*/)
7092{
7093 /* TODO - EXP_REDIR */
7094
7095 while (str) {
7096 char *p;
7097 glob_t pglob;
7098 int i;
7099
7100 if (fflag)
7101 goto nometa;
7102
7103 /* Avoid glob() (and thus, stat() et al) for words like "echo" */
7104 p = str->text;
7105 while (*p) {
7106 if (*p == '*')
7107 goto need_glob;
7108 if (*p == '?')
7109 goto need_glob;
7110 if (*p == '[')
7111 goto need_glob;
7112 p++;
7113 }
7114 goto nometa;
7115
7116 need_glob:
7117 INT_OFF;
7118 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7119// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7120// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7121//
7122// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7123// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7124// Which means you need to unescape the string, right? Not so fast:
7125// if there _is_ a file named "file\?" (with backslash), it is returned
7126// as "file\?" too (whichever pattern you used to find it, say, "file*").
7127// You DONT KNOW by looking at the result whether you need to unescape it.
7128//
7129// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7130// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7131// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7132// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7133// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7134// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7135 i = glob(p, 0, NULL, &pglob);
7136 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
7137 if (p != str->text)
7138 free(p);
7139 switch (i) {
7140 case 0:
7141#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
7142 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7143 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7144 goto nometa2;
7145#endif
7146 addglob(&pglob);
7147 globfree(&pglob);
7148 INT_ON;
7149 break;
7150 case GLOB_NOMATCH:
7151 //nometa2:
7152 globfree(&pglob);
7153 INT_ON;
7154 nometa:
7155 *exparg.lastp = str;
7156 rmescapes(str->text, 0);
7157 exparg.lastp = &str->next;
7158 break;
7159 default: /* GLOB_NOSPACE */
7160 globfree(&pglob);
7161 INT_ON;
7162 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7163 }
7164 str = str->next;
7165 }
7166}
7167
7168#else
7169/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
7170
7171/*
7172 * Do metacharacter (i.e. *, ?, [...]) expansion.
7173 */
7174static void
7175expmeta(char *expdir, char *enddir, char *name)
7176{
7177 char *p;
7178 const char *cp;
7179 char *start;
7180 char *endname;
7181 int metaflag;
7182 struct stat statb;
7183 DIR *dirp;
7184 struct dirent *dp;
7185 int atend;
7186 int matchdot;
7187 int esc;
7188
7189 metaflag = 0;
7190 start = name;
7191 for (p = name; esc = 0, *p; p += esc + 1) {
7192 if (*p == '*' || *p == '?')
7193 metaflag = 1;
7194 else if (*p == '[') {
7195 char *q = p + 1;
7196 if (*q == '!')
7197 q++;
7198 for (;;) {
7199 if (*q == '\\')
7200 q++;
7201 if (*q == '/' || *q == '\0')
7202 break;
7203 if (*++q == ']') {
7204 metaflag = 1;
7205 break;
7206 }
7207 }
7208 } else {
7209 if (*p == '\\')
7210 esc++;
7211 if (p[esc] == '/') {
7212 if (metaflag)
7213 break;
7214 start = p + esc + 1;
7215 }
7216 }
7217 }
7218 if (metaflag == 0) { /* we've reached the end of the file name */
7219 if (enddir != expdir)
7220 metaflag++;
7221 p = name;
7222 do {
7223 if (*p == '\\')
7224 p++;
7225 *enddir++ = *p;
7226 } while (*p++);
7227 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7228 addfname(expdir);
7229 return;
7230 }
7231 endname = p;
7232 if (name < start) {
7233 p = name;
7234 do {
7235 if (*p == '\\')
7236 p++;
7237 *enddir++ = *p++;
7238 } while (p < start);
7239 }
7240 if (enddir == expdir) {
7241 cp = ".";
7242 } else if (enddir == expdir + 1 && *expdir == '/') {
7243 cp = "/";
7244 } else {
7245 cp = expdir;
7246 enddir[-1] = '\0';
7247 }
7248 dirp = opendir(cp);
7249 if (dirp == NULL)
7250 return;
7251 if (enddir != expdir)
7252 enddir[-1] = '/';
7253 if (*endname == 0) {
7254 atend = 1;
7255 } else {
7256 atend = 0;
7257 *endname = '\0';
7258 endname += esc + 1;
7259 }
7260 matchdot = 0;
7261 p = start;
7262 if (*p == '\\')
7263 p++;
7264 if (*p == '.')
7265 matchdot++;
7266 while (!pending_int && (dp = readdir(dirp)) != NULL) {
7267 if (dp->d_name[0] == '.' && !matchdot)
7268 continue;
7269 if (pmatch(start, dp->d_name)) {
7270 if (atend) {
7271 strcpy(enddir, dp->d_name);
7272 addfname(expdir);
7273 } else {
7274 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7275 continue;
7276 p[-1] = '/';
7277 expmeta(expdir, p, endname);
7278 }
7279 }
7280 }
7281 closedir(dirp);
7282 if (!atend)
7283 endname[-esc - 1] = esc ? '\\' : '/';
7284}
7285
7286static struct strlist *
7287msort(struct strlist *list, int len)
7288{
7289 struct strlist *p, *q = NULL;
7290 struct strlist **lpp;
7291 int half;
7292 int n;
7293
7294 if (len <= 1)
7295 return list;
7296 half = len >> 1;
7297 p = list;
7298 for (n = half; --n >= 0;) {
7299 q = p;
7300 p = p->next;
7301 }
7302 q->next = NULL; /* terminate first half of list */
7303 q = msort(list, half); /* sort first half of list */
7304 p = msort(p, len - half); /* sort second half */
7305 lpp = &list;
7306 for (;;) {
7307#if ENABLE_LOCALE_SUPPORT
7308 if (strcoll(p->text, q->text) < 0)
7309#else
7310 if (strcmp(p->text, q->text) < 0)
7311#endif
7312 {
7313 *lpp = p;
7314 lpp = &p->next;
7315 p = *lpp;
7316 if (p == NULL) {
7317 *lpp = q;
7318 break;
7319 }
7320 } else {
7321 *lpp = q;
7322 lpp = &q->next;
7323 q = *lpp;
7324 if (q == NULL) {
7325 *lpp = p;
7326 break;
7327 }
7328 }
7329 }
7330 return list;
7331}
7332
7333/*
7334 * Sort the results of file name expansion. It calculates the number of
7335 * strings to sort and then calls msort (short for merge sort) to do the
7336 * work.
7337 */
7338static struct strlist *
7339expsort(struct strlist *str)
7340{
7341 int len;
7342 struct strlist *sp;
7343
7344 len = 0;
7345 for (sp = str; sp; sp = sp->next)
7346 len++;
7347 return msort(str, len);
7348}
7349
7350static void
7351expandmeta(struct strlist *str /*, int flag*/)
7352{
7353 static const char metachars[] ALIGN1 = {
7354 '*', '?', '[', 0
7355 };
7356 /* TODO - EXP_REDIR */
7357
7358 while (str) {
7359 char *expdir;
7360 struct strlist **savelastp;
7361 struct strlist *sp;
7362 char *p;
7363
7364 if (fflag)
7365 goto nometa;
7366 if (!strpbrk(str->text, metachars))
7367 goto nometa;
7368 savelastp = exparg.lastp;
7369
7370 INT_OFF;
7371 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7372 {
7373 int i = strlen(str->text);
7374//BUGGY estimation of how long expanded name can be
7375 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
7376 }
7377 expmeta(expdir, expdir, p);
7378 free(expdir);
7379 if (p != str->text)
7380 free(p);
7381 INT_ON;
7382 if (exparg.lastp == savelastp) {
7383 /*
7384 * no matches
7385 */
7386 nometa:
7387 *exparg.lastp = str;
7388 rmescapes(str->text, 0);
7389 exparg.lastp = &str->next;
7390 } else {
7391 *exparg.lastp = NULL;
7392 *savelastp = sp = expsort(*savelastp);
7393 while (sp->next != NULL)
7394 sp = sp->next;
7395 exparg.lastp = &sp->next;
7396 }
7397 str = str->next;
7398 }
7399}
7400#endif /* ENABLE_ASH_INTERNAL_GLOB */
7401
7402/*
7403 * Perform variable substitution and command substitution on an argument,
7404 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7405 * perform splitting and file name expansion. When arglist is NULL, perform
7406 * here document expansion.
7407 */
7408static void
7409expandarg(union node *arg, struct arglist *arglist, int flag)
7410{
7411 struct strlist *sp;
7412 char *p;
7413
7414 argbackq = arg->narg.backquote;
7415 STARTSTACKSTR(expdest);
7416 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
7417 argstr(arg->narg.text, flag,
7418 /* var_str_list: */ arglist ? arglist->list : NULL);
7419 p = _STPUTC('\0', expdest);
7420 expdest = p - 1;
7421 if (arglist == NULL) {
7422 /* here document expanded */
7423 goto out;
7424 }
7425 p = grabstackstr(p);
7426 TRACE(("expandarg: p:'%s'\n", p));
7427 exparg.lastp = &exparg.list;
7428 /*
7429 * TODO - EXP_REDIR
7430 */
7431 if (flag & EXP_FULL) {
7432 ifsbreakup(p, &exparg);
7433 *exparg.lastp = NULL;
7434 exparg.lastp = &exparg.list;
7435 expandmeta(exparg.list /*, flag*/);
7436 } else {
7437 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
7438 rmescapes(p, 0);
7439 TRACE(("expandarg: rmescapes:'%s'\n", p));
7440 }
7441 sp = stzalloc(sizeof(*sp));
7442 sp->text = p;
7443 *exparg.lastp = sp;
7444 exparg.lastp = &sp->next;
7445 }
7446 *exparg.lastp = NULL;
7447 if (exparg.list) {
7448 *arglist->lastp = exparg.list;
7449 arglist->lastp = exparg.lastp;
7450 }
7451
7452 out:
7453 ifsfree();
7454}
7455
7456/*
7457 * Expand shell variables and backquotes inside a here document.
7458 */
7459static void
7460expandhere(union node *arg, int fd)
7461{
7462 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
7463 full_write(fd, stackblock(), expdest - (char *)stackblock());
7464}
7465
7466/*
7467 * Returns true if the pattern matches the string.
7468 */
7469static int
7470patmatch(char *pattern, const char *string)
7471{
7472 return pmatch(preglob(pattern, 0), string);
7473}
7474
7475/*
7476 * See if a pattern matches in a case statement.
7477 */
7478static int
7479casematch(union node *pattern, char *val)
7480{
7481 struct stackmark smark;
7482 int result;
7483
7484 setstackmark(&smark);
7485 argbackq = pattern->narg.backquote;
7486 STARTSTACKSTR(expdest);
7487 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7488 /* var_str_list: */ NULL);
7489 STACKSTRNUL(expdest);
7490 ifsfree();
7491 result = patmatch(stackblock(), val);
7492 popstackmark(&smark);
7493 return result;
7494}
7495
7496
7497/* ============ find_command */
7498
7499struct builtincmd {
7500 const char *name;
7501 int (*builtin)(int, char **) FAST_FUNC;
7502 /* unsigned flags; */
7503};
7504#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
7505/* "regular" builtins always take precedence over commands,
7506 * regardless of PATH=....%builtin... position */
7507#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
7508#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
7509
7510struct cmdentry {
7511 smallint cmdtype; /* CMDxxx */
7512 union param {
7513 int index;
7514 /* index >= 0 for commands without path (slashes) */
7515 /* (TODO: what exactly does the value mean? PATH position?) */
7516 /* index == -1 for commands with slashes */
7517 /* index == (-2 - applet_no) for NOFORK applets */
7518 const struct builtincmd *cmd;
7519 struct funcnode *func;
7520 } u;
7521};
7522/* values of cmdtype */
7523#define CMDUNKNOWN -1 /* no entry in table for command */
7524#define CMDNORMAL 0 /* command is an executable program */
7525#define CMDFUNCTION 1 /* command is a shell function */
7526#define CMDBUILTIN 2 /* command is a shell builtin */
7527
7528/* action to find_command() */
7529#define DO_ERR 0x01 /* prints errors */
7530#define DO_ABS 0x02 /* checks absolute paths */
7531#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7532#define DO_ALTPATH 0x08 /* using alternate path */
7533#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7534
7535static void find_command(char *, struct cmdentry *, int, const char *);
7536
7537
7538/* ============ Hashing commands */
7539
7540/*
7541 * When commands are first encountered, they are entered in a hash table.
7542 * This ensures that a full path search will not have to be done for them
7543 * on each invocation.
7544 *
7545 * We should investigate converting to a linear search, even though that
7546 * would make the command name "hash" a misnomer.
7547 */
7548
7549struct tblentry {
7550 struct tblentry *next; /* next entry in hash chain */
7551 union param param; /* definition of builtin function */
7552 smallint cmdtype; /* CMDxxx */
7553 char rehash; /* if set, cd done since entry created */
7554 char cmdname[1]; /* name of command */
7555};
7556
7557static struct tblentry **cmdtable;
7558#define INIT_G_cmdtable() do { \
7559 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7560} while (0)
7561
7562static int builtinloc = -1; /* index in path of %builtin, or -1 */
7563
7564
7565static void
7566tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
7567{
7568#if ENABLE_FEATURE_SH_STANDALONE
7569 if (applet_no >= 0) {
7570 if (APPLET_IS_NOEXEC(applet_no)) {
7571 clearenv();
7572 while (*envp)
7573 putenv(*envp++);
7574 run_applet_no_and_exit(applet_no, argv);
7575 }
7576 /* re-exec ourselves with the new arguments */
7577 execve(bb_busybox_exec_path, argv, envp);
7578 /* If they called chroot or otherwise made the binary no longer
7579 * executable, fall through */
7580 }
7581#endif
7582
7583 repeat:
7584#ifdef SYSV
7585 do {
7586 execve(cmd, argv, envp);
7587 } while (errno == EINTR);
7588#else
7589 execve(cmd, argv, envp);
7590#endif
7591 if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
7592 /* Run "cmd" as a shell script:
7593 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7594 * "If the execve() function fails with ENOEXEC, the shell
7595 * shall execute a command equivalent to having a shell invoked
7596 * with the command name as its first operand,
7597 * with any remaining arguments passed to the new shell"
7598 *
7599 * That is, do not use $SHELL, user's shell, or /bin/sh;
7600 * just call ourselves.
7601 *
7602 * Note that bash reads ~80 chars of the file, and if it sees
7603 * a zero byte before it sees newline, it doesn't try to
7604 * interpret it, but fails with "cannot execute binary file"
7605 * message and exit code 126. For one, this prevents attempts
7606 * to interpret foreign ELF binaries as shell scripts.
7607 */
7608 argv[0] = cmd;
7609 cmd = (char*) bb_busybox_exec_path;
7610 /* NB: this is only possible because all callers of shellexec()
7611 * ensure that the argv[-1] slot exists!
7612 */
7613 argv--;
7614 argv[0] = (char*) "ash";
7615 goto repeat;
7616 }
7617}
7618
7619/*
7620 * Exec a program. Never returns. If you change this routine, you may
7621 * have to change the find_command routine as well.
7622 * argv[-1] must exist and be writable! See tryexec() for why.
7623 */
7624static void shellexec(char **, const char *, int) NORETURN;
7625static void
7626shellexec(char **argv, const char *path, int idx)
7627{
7628 char *cmdname;
7629 int e;
7630 char **envp;
7631 int exerrno;
7632 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
7633
7634 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7635 if (strchr(argv[0], '/') != NULL
7636#if ENABLE_FEATURE_SH_STANDALONE
7637 || (applet_no = find_applet_by_name(argv[0])) >= 0
7638#endif
7639 ) {
7640 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7641 if (applet_no >= 0) {
7642 /* We tried execing ourself, but it didn't work.
7643 * Maybe /proc/self/exe doesn't exist?
7644 * Try $PATH search.
7645 */
7646 goto try_PATH;
7647 }
7648 e = errno;
7649 } else {
7650 try_PATH:
7651 e = ENOENT;
7652 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
7653 if (--idx < 0 && pathopt == NULL) {
7654 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
7655 if (errno != ENOENT && errno != ENOTDIR)
7656 e = errno;
7657 }
7658 stunalloc(cmdname);
7659 }
7660 }
7661
7662 /* Map to POSIX errors */
7663 switch (e) {
7664 case EACCES:
7665 exerrno = 126;
7666 break;
7667 case ENOENT:
7668 exerrno = 127;
7669 break;
7670 default:
7671 exerrno = 2;
7672 break;
7673 }
7674 exitstatus = exerrno;
7675 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7676 argv[0], e, suppress_int));
7677 ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found"));
7678 /* NOTREACHED */
7679}
7680
7681static void
7682printentry(struct tblentry *cmdp)
7683{
7684 int idx;
7685 const char *path;
7686 char *name;
7687
7688 idx = cmdp->param.index;
7689 path = pathval();
7690 do {
7691 name = path_advance(&path, cmdp->cmdname);
7692 stunalloc(name);
7693 } while (--idx >= 0);
7694 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7695}
7696
7697/*
7698 * Clear out command entries. The argument specifies the first entry in
7699 * PATH which has changed.
7700 */
7701static void
7702clearcmdentry(int firstchange)
7703{
7704 struct tblentry **tblp;
7705 struct tblentry **pp;
7706 struct tblentry *cmdp;
7707
7708 INT_OFF;
7709 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7710 pp = tblp;
7711 while ((cmdp = *pp) != NULL) {
7712 if ((cmdp->cmdtype == CMDNORMAL &&
7713 cmdp->param.index >= firstchange)
7714 || (cmdp->cmdtype == CMDBUILTIN &&
7715 builtinloc >= firstchange)
7716 ) {
7717 *pp = cmdp->next;
7718 free(cmdp);
7719 } else {
7720 pp = &cmdp->next;
7721 }
7722 }
7723 }
7724 INT_ON;
7725}
7726
7727/*
7728 * Locate a command in the command hash table. If "add" is nonzero,
7729 * add the command to the table if it is not already present. The
7730 * variable "lastcmdentry" is set to point to the address of the link
7731 * pointing to the entry, so that delete_cmd_entry can delete the
7732 * entry.
7733 *
7734 * Interrupts must be off if called with add != 0.
7735 */
7736static struct tblentry **lastcmdentry;
7737
7738static struct tblentry *
7739cmdlookup(const char *name, int add)
7740{
7741 unsigned int hashval;
7742 const char *p;
7743 struct tblentry *cmdp;
7744 struct tblentry **pp;
7745
7746 p = name;
7747 hashval = (unsigned char)*p << 4;
7748 while (*p)
7749 hashval += (unsigned char)*p++;
7750 hashval &= 0x7FFF;
7751 pp = &cmdtable[hashval % CMDTABLESIZE];
7752 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7753 if (strcmp(cmdp->cmdname, name) == 0)
7754 break;
7755 pp = &cmdp->next;
7756 }
7757 if (add && cmdp == NULL) {
7758 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7759 + strlen(name)
7760 /* + 1 - already done because
7761 * tblentry::cmdname is char[1] */);
7762 /*cmdp->next = NULL; - ckzalloc did it */
7763 cmdp->cmdtype = CMDUNKNOWN;
7764 strcpy(cmdp->cmdname, name);
7765 }
7766 lastcmdentry = pp;
7767 return cmdp;
7768}
7769
7770/*
7771 * Delete the command entry returned on the last lookup.
7772 */
7773static void
7774delete_cmd_entry(void)
7775{
7776 struct tblentry *cmdp;
7777
7778 INT_OFF;
7779 cmdp = *lastcmdentry;
7780 *lastcmdentry = cmdp->next;
7781 if (cmdp->cmdtype == CMDFUNCTION)
7782 freefunc(cmdp->param.func);
7783 free(cmdp);
7784 INT_ON;
7785}
7786
7787/*
7788 * Add a new command entry, replacing any existing command entry for
7789 * the same name - except special builtins.
7790 */
7791static void
7792addcmdentry(char *name, struct cmdentry *entry)
7793{
7794 struct tblentry *cmdp;
7795
7796 cmdp = cmdlookup(name, 1);
7797 if (cmdp->cmdtype == CMDFUNCTION) {
7798 freefunc(cmdp->param.func);
7799 }
7800 cmdp->cmdtype = entry->cmdtype;
7801 cmdp->param = entry->u;
7802 cmdp->rehash = 0;
7803}
7804
7805static int FAST_FUNC
7806hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
7807{
7808 struct tblentry **pp;
7809 struct tblentry *cmdp;
7810 int c;
7811 struct cmdentry entry;
7812 char *name;
7813
7814 if (nextopt("r") != '\0') {
7815 clearcmdentry(0);
7816 return 0;
7817 }
7818
7819 if (*argptr == NULL) {
7820 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7821 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7822 if (cmdp->cmdtype == CMDNORMAL)
7823 printentry(cmdp);
7824 }
7825 }
7826 return 0;
7827 }
7828
7829 c = 0;
7830 while ((name = *argptr) != NULL) {
7831 cmdp = cmdlookup(name, 0);
7832 if (cmdp != NULL
7833 && (cmdp->cmdtype == CMDNORMAL
7834 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7835 ) {
7836 delete_cmd_entry();
7837 }
7838 find_command(name, &entry, DO_ERR, pathval());
7839 if (entry.cmdtype == CMDUNKNOWN)
7840 c = 1;
7841 argptr++;
7842 }
7843 return c;
7844}
7845
7846/*
7847 * Called when a cd is done. Marks all commands so the next time they
7848 * are executed they will be rehashed.
7849 */
7850static void
7851hashcd(void)
7852{
7853 struct tblentry **pp;
7854 struct tblentry *cmdp;
7855
7856 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7857 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7858 if (cmdp->cmdtype == CMDNORMAL
7859 || (cmdp->cmdtype == CMDBUILTIN
7860 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
7861 && builtinloc > 0)
7862 ) {
7863 cmdp->rehash = 1;
7864 }
7865 }
7866 }
7867}
7868
7869/*
7870 * Fix command hash table when PATH changed.
7871 * Called before PATH is changed. The argument is the new value of PATH;
7872 * pathval() still returns the old value at this point.
7873 * Called with interrupts off.
7874 */
7875static void FAST_FUNC
7876changepath(const char *new)
7877{
7878 const char *old;
7879 int firstchange;
7880 int idx;
7881 int idx_bltin;
7882
7883 old = pathval();
7884 firstchange = 9999; /* assume no change */
7885 idx = 0;
7886 idx_bltin = -1;
7887 for (;;) {
7888 if (*old != *new) {
7889 firstchange = idx;
7890 if ((*old == '\0' && *new == ':')
7891 || (*old == ':' && *new == '\0')
7892 ) {
7893 firstchange++;
7894 }
7895 old = new; /* ignore subsequent differences */
7896 }
7897 if (*new == '\0')
7898 break;
7899 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7900 idx_bltin = idx;
7901 if (*new == ':')
7902 idx++;
7903 new++;
7904 old++;
7905 }
7906 if (builtinloc < 0 && idx_bltin >= 0)
7907 builtinloc = idx_bltin; /* zap builtins */
7908 if (builtinloc >= 0 && idx_bltin < 0)
7909 firstchange = 0;
7910 clearcmdentry(firstchange);
7911 builtinloc = idx_bltin;
7912}
7913enum {
7914 TEOF,
7915 TNL,
7916 TREDIR,
7917 TWORD,
7918 TSEMI,
7919 TBACKGND,
7920 TAND,
7921 TOR,
7922 TPIPE,
7923 TLP,
7924 TRP,
7925 TENDCASE,
7926 TENDBQUOTE,
7927 TNOT,
7928 TCASE,
7929 TDO,
7930 TDONE,
7931 TELIF,
7932 TELSE,
7933 TESAC,
7934 TFI,
7935 TFOR,
7936#if ENABLE_ASH_BASH_COMPAT
7937 TFUNCTION,
7938#endif
7939 TIF,
7940 TIN,
7941 TTHEN,
7942 TUNTIL,
7943 TWHILE,
7944 TBEGIN,
7945 TEND
7946};
7947typedef smallint token_id_t;
7948
7949/* Nth bit indicates if token marks the end of a list */
7950enum {
7951 tokendlist = 0
7952 /* 0 */ | (1u << TEOF)
7953 /* 1 */ | (0u << TNL)
7954 /* 2 */ | (0u << TREDIR)
7955 /* 3 */ | (0u << TWORD)
7956 /* 4 */ | (0u << TSEMI)
7957 /* 5 */ | (0u << TBACKGND)
7958 /* 6 */ | (0u << TAND)
7959 /* 7 */ | (0u << TOR)
7960 /* 8 */ | (0u << TPIPE)
7961 /* 9 */ | (0u << TLP)
7962 /* 10 */ | (1u << TRP)
7963 /* 11 */ | (1u << TENDCASE)
7964 /* 12 */ | (1u << TENDBQUOTE)
7965 /* 13 */ | (0u << TNOT)
7966 /* 14 */ | (0u << TCASE)
7967 /* 15 */ | (1u << TDO)
7968 /* 16 */ | (1u << TDONE)
7969 /* 17 */ | (1u << TELIF)
7970 /* 18 */ | (1u << TELSE)
7971 /* 19 */ | (1u << TESAC)
7972 /* 20 */ | (1u << TFI)
7973 /* 21 */ | (0u << TFOR)
7974#if ENABLE_ASH_BASH_COMPAT
7975 /* 22 */ | (0u << TFUNCTION)
7976#endif
7977 /* 23 */ | (0u << TIF)
7978 /* 24 */ | (0u << TIN)
7979 /* 25 */ | (1u << TTHEN)
7980 /* 26 */ | (0u << TUNTIL)
7981 /* 27 */ | (0u << TWHILE)
7982 /* 28 */ | (0u << TBEGIN)
7983 /* 29 */ | (1u << TEND)
7984 , /* thus far 29 bits used */
7985};
7986
7987static const char *const tokname_array[] = {
7988 "end of file",
7989 "newline",
7990 "redirection",
7991 "word",
7992 ";",
7993 "&",
7994 "&&",
7995 "||",
7996 "|",
7997 "(",
7998 ")",
7999 ";;",
8000 "`",
8001#define KWDOFFSET 13
8002 /* the following are keywords */
8003 "!",
8004 "case",
8005 "do",
8006 "done",
8007 "elif",
8008 "else",
8009 "esac",
8010 "fi",
8011 "for",
8012#if ENABLE_ASH_BASH_COMPAT
8013 "function",
8014#endif
8015 "if",
8016 "in",
8017 "then",
8018 "until",
8019 "while",
8020 "{",
8021 "}",
8022};
8023
8024/* Wrapper around strcmp for qsort/bsearch/... */
8025static int
8026pstrcmp(const void *a, const void *b)
8027{
8028 return strcmp((char*)a, *(char**)b);
8029}
8030
8031static const char *const *
8032findkwd(const char *s)
8033{
8034 return bsearch(s, tokname_array + KWDOFFSET,
8035 ARRAY_SIZE(tokname_array) - KWDOFFSET,
8036 sizeof(tokname_array[0]), pstrcmp);
8037}
8038
8039/*
8040 * Locate and print what a word is...
8041 */
8042static int
8043describe_command(char *command, const char *path, int describe_command_verbose)
8044{
8045 struct cmdentry entry;
8046 struct tblentry *cmdp;
8047#if ENABLE_ASH_ALIAS
8048 const struct alias *ap;
8049#endif
8050
8051 path = path ? path : pathval();
8052
8053 if (describe_command_verbose) {
8054 out1str(command);
8055 }
8056
8057 /* First look at the keywords */
8058 if (findkwd(command)) {
8059 out1str(describe_command_verbose ? " is a shell keyword" : command);
8060 goto out;
8061 }
8062
8063#if ENABLE_ASH_ALIAS
8064 /* Then look at the aliases */
8065 ap = lookupalias(command, 0);
8066 if (ap != NULL) {
8067 if (!describe_command_verbose) {
8068 out1str("alias ");
8069 printalias(ap);
8070 return 0;
8071 }
8072 out1fmt(" is an alias for %s", ap->val);
8073 goto out;
8074 }
8075#endif
8076 /* Then check if it is a tracked alias */
8077 cmdp = cmdlookup(command, 0);
8078 if (cmdp != NULL) {
8079 entry.cmdtype = cmdp->cmdtype;
8080 entry.u = cmdp->param;
8081 } else {
8082 /* Finally use brute force */
8083 find_command(command, &entry, DO_ABS, path);
8084 }
8085
8086 switch (entry.cmdtype) {
8087 case CMDNORMAL: {
8088 int j = entry.u.index;
8089 char *p;
8090 if (j < 0) {
8091 p = command;
8092 } else {
8093 do {
8094 p = path_advance(&path, command);
8095 stunalloc(p);
8096 } while (--j >= 0);
8097 }
8098 if (describe_command_verbose) {
8099 out1fmt(" is%s %s",
8100 (cmdp ? " a tracked alias for" : nullstr), p
8101 );
8102 } else {
8103 out1str(p);
8104 }
8105 break;
8106 }
8107
8108 case CMDFUNCTION:
8109 if (describe_command_verbose) {
8110 out1str(" is a shell function");
8111 } else {
8112 out1str(command);
8113 }
8114 break;
8115
8116 case CMDBUILTIN:
8117 if (describe_command_verbose) {
8118 out1fmt(" is a %sshell builtin",
8119 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8120 "special " : nullstr
8121 );
8122 } else {
8123 out1str(command);
8124 }
8125 break;
8126
8127 default:
8128 if (describe_command_verbose) {
8129 out1str(": not found\n");
8130 }
8131 return 127;
8132 }
8133 out:
8134 out1str("\n");
8135 return 0;
8136}
8137
8138static int FAST_FUNC
8139typecmd(int argc UNUSED_PARAM, char **argv)
8140{
8141 int i = 1;
8142 int err = 0;
8143 int verbose = 1;
8144
8145 /* type -p ... ? (we don't bother checking for 'p') */
8146 if (argv[1] && argv[1][0] == '-') {
8147 i++;
8148 verbose = 0;
8149 }
8150 while (argv[i]) {
8151 err |= describe_command(argv[i++], NULL, verbose);
8152 }
8153 return err;
8154}
8155
8156#if ENABLE_ASH_CMDCMD
8157/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8158static char **
8159parse_command_args(char **argv, const char **path)
8160{
8161 char *cp, c;
8162
8163 for (;;) {
8164 cp = *++argv;
8165 if (!cp)
8166 return NULL;
8167 if (*cp++ != '-')
8168 break;
8169 c = *cp++;
8170 if (!c)
8171 break;
8172 if (c == '-' && !*cp) {
8173 if (!*++argv)
8174 return NULL;
8175 break;
8176 }
8177 do {
8178 switch (c) {
8179 case 'p':
8180 *path = bb_default_path;
8181 break;
8182 default:
8183 /* run 'typecmd' for other options */
8184 return NULL;
8185 }
8186 c = *cp++;
8187 } while (c);
8188 }
8189 return argv;
8190}
8191
8192static int FAST_FUNC
8193commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8194{
8195 char *cmd;
8196 int c;
8197 enum {
8198 VERIFY_BRIEF = 1,
8199 VERIFY_VERBOSE = 2,
8200 } verify = 0;
8201 const char *path = NULL;
8202
8203 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8204 * never reaches this function.
8205 */
8206
8207 while ((c = nextopt("pvV")) != '\0')
8208 if (c == 'V')
8209 verify |= VERIFY_VERBOSE;
8210 else if (c == 'v')
8211 /*verify |= VERIFY_BRIEF*/;
8212#if DEBUG
8213 else if (c != 'p')
8214 abort();
8215#endif
8216 else
8217 path = bb_default_path;
8218
8219 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8220 cmd = *argptr;
8221 if (/*verify && */ cmd)
8222 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
8223
8224 return 0;
8225}
8226#endif
8227
8228
8229/*static int funcblocksize; // size of structures in function */
8230/*static int funcstringsize; // size of strings in node */
8231static void *funcblock; /* block to allocate function from */
8232static char *funcstring_end; /* end of block to allocate strings from */
8233
8234/* flags in argument to evaltree */
8235#define EV_EXIT 01 /* exit after evaluating tree */
8236#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
8237
8238static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8239 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8240 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8241 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8242 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8243 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8244 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8245 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8246 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8247 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8248 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8249 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8250 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8251 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8252 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8253 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8254 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8255 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8256#if ENABLE_ASH_BASH_COMPAT
8257 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
8258#endif
8259 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8260 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8261 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8262 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8263 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8264 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8265 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8266 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8267 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
8268};
8269
8270static int calcsize(int funcblocksize, union node *n);
8271
8272static int
8273sizenodelist(int funcblocksize, struct nodelist *lp)
8274{
8275 while (lp) {
8276 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8277 funcblocksize = calcsize(funcblocksize, lp->n);
8278 lp = lp->next;
8279 }
8280 return funcblocksize;
8281}
8282
8283static int
8284calcsize(int funcblocksize, union node *n)
8285{
8286 if (n == NULL)
8287 return funcblocksize;
8288 funcblocksize += nodesize[n->type];
8289 switch (n->type) {
8290 case NCMD:
8291 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8292 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8293 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
8294 break;
8295 case NPIPE:
8296 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
8297 break;
8298 case NREDIR:
8299 case NBACKGND:
8300 case NSUBSHELL:
8301 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8302 funcblocksize = calcsize(funcblocksize, n->nredir.n);
8303 break;
8304 case NAND:
8305 case NOR:
8306 case NSEMI:
8307 case NWHILE:
8308 case NUNTIL:
8309 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8310 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
8311 break;
8312 case NIF:
8313 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8314 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8315 funcblocksize = calcsize(funcblocksize, n->nif.test);
8316 break;
8317 case NFOR:
8318 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
8319 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8320 funcblocksize = calcsize(funcblocksize, n->nfor.args);
8321 break;
8322 case NCASE:
8323 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8324 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
8325 break;
8326 case NCLIST:
8327 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8328 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8329 funcblocksize = calcsize(funcblocksize, n->nclist.next);
8330 break;
8331 case NDEFUN:
8332 case NARG:
8333 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
8334 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
8335 funcblocksize = calcsize(funcblocksize, n->narg.next);
8336 break;
8337 case NTO:
8338#if ENABLE_ASH_BASH_COMPAT
8339 case NTO2:
8340#endif
8341 case NCLOBBER:
8342 case NFROM:
8343 case NFROMTO:
8344 case NAPPEND:
8345 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8346 funcblocksize = calcsize(funcblocksize, n->nfile.next);
8347 break;
8348 case NTOFD:
8349 case NFROMFD:
8350 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8351 funcblocksize = calcsize(funcblocksize, n->ndup.next);
8352 break;
8353 case NHERE:
8354 case NXHERE:
8355 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8356 funcblocksize = calcsize(funcblocksize, n->nhere.next);
8357 break;
8358 case NNOT:
8359 funcblocksize = calcsize(funcblocksize, n->nnot.com);
8360 break;
8361 };
8362 return funcblocksize;
8363}
8364
8365static char *
8366nodeckstrdup(char *s)
8367{
8368 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
8369 return strcpy(funcstring_end, s);
8370}
8371
8372static union node *copynode(union node *);
8373
8374static struct nodelist *
8375copynodelist(struct nodelist *lp)
8376{
8377 struct nodelist *start;
8378 struct nodelist **lpp;
8379
8380 lpp = &start;
8381 while (lp) {
8382 *lpp = funcblock;
8383 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8384 (*lpp)->n = copynode(lp->n);
8385 lp = lp->next;
8386 lpp = &(*lpp)->next;
8387 }
8388 *lpp = NULL;
8389 return start;
8390}
8391
8392static union node *
8393copynode(union node *n)
8394{
8395 union node *new;
8396
8397 if (n == NULL)
8398 return NULL;
8399 new = funcblock;
8400 funcblock = (char *) funcblock + nodesize[n->type];
8401
8402 switch (n->type) {
8403 case NCMD:
8404 new->ncmd.redirect = copynode(n->ncmd.redirect);
8405 new->ncmd.args = copynode(n->ncmd.args);
8406 new->ncmd.assign = copynode(n->ncmd.assign);
8407 break;
8408 case NPIPE:
8409 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8410 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8411 break;
8412 case NREDIR:
8413 case NBACKGND:
8414 case NSUBSHELL:
8415 new->nredir.redirect = copynode(n->nredir.redirect);
8416 new->nredir.n = copynode(n->nredir.n);
8417 break;
8418 case NAND:
8419 case NOR:
8420 case NSEMI:
8421 case NWHILE:
8422 case NUNTIL:
8423 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8424 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8425 break;
8426 case NIF:
8427 new->nif.elsepart = copynode(n->nif.elsepart);
8428 new->nif.ifpart = copynode(n->nif.ifpart);
8429 new->nif.test = copynode(n->nif.test);
8430 break;
8431 case NFOR:
8432 new->nfor.var = nodeckstrdup(n->nfor.var);
8433 new->nfor.body = copynode(n->nfor.body);
8434 new->nfor.args = copynode(n->nfor.args);
8435 break;
8436 case NCASE:
8437 new->ncase.cases = copynode(n->ncase.cases);
8438 new->ncase.expr = copynode(n->ncase.expr);
8439 break;
8440 case NCLIST:
8441 new->nclist.body = copynode(n->nclist.body);
8442 new->nclist.pattern = copynode(n->nclist.pattern);
8443 new->nclist.next = copynode(n->nclist.next);
8444 break;
8445 case NDEFUN:
8446 case NARG:
8447 new->narg.backquote = copynodelist(n->narg.backquote);
8448 new->narg.text = nodeckstrdup(n->narg.text);
8449 new->narg.next = copynode(n->narg.next);
8450 break;
8451 case NTO:
8452#if ENABLE_ASH_BASH_COMPAT
8453 case NTO2:
8454#endif
8455 case NCLOBBER:
8456 case NFROM:
8457 case NFROMTO:
8458 case NAPPEND:
8459 new->nfile.fname = copynode(n->nfile.fname);
8460 new->nfile.fd = n->nfile.fd;
8461 new->nfile.next = copynode(n->nfile.next);
8462 break;
8463 case NTOFD:
8464 case NFROMFD:
8465 new->ndup.vname = copynode(n->ndup.vname);
8466 new->ndup.dupfd = n->ndup.dupfd;
8467 new->ndup.fd = n->ndup.fd;
8468 new->ndup.next = copynode(n->ndup.next);
8469 break;
8470 case NHERE:
8471 case NXHERE:
8472 new->nhere.doc = copynode(n->nhere.doc);
8473 new->nhere.fd = n->nhere.fd;
8474 new->nhere.next = copynode(n->nhere.next);
8475 break;
8476 case NNOT:
8477 new->nnot.com = copynode(n->nnot.com);
8478 break;
8479 };
8480 new->type = n->type;
8481 return new;
8482}
8483
8484/*
8485 * Make a copy of a parse tree.
8486 */
8487static struct funcnode *
8488copyfunc(union node *n)
8489{
8490 struct funcnode *f;
8491 size_t blocksize;
8492
8493 /*funcstringsize = 0;*/
8494 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8495 f = ckzalloc(blocksize /* + funcstringsize */);
8496 funcblock = (char *) f + offsetof(struct funcnode, n);
8497 funcstring_end = (char *) f + blocksize;
8498 copynode(n);
8499 /* f->count = 0; - ckzalloc did it */
8500 return f;
8501}
8502
8503/*
8504 * Define a shell function.
8505 */
8506static void
8507defun(union node *func)
8508{
8509 struct cmdentry entry;
8510
8511 INT_OFF;
8512 entry.cmdtype = CMDFUNCTION;
8513 entry.u.func = copyfunc(func);
8514 addcmdentry(func->narg.text, &entry);
8515 INT_ON;
8516}
8517
8518/* Reasons for skipping commands (see comment on breakcmd routine) */
8519#define SKIPBREAK (1 << 0)
8520#define SKIPCONT (1 << 1)
8521#define SKIPFUNC (1 << 2)
8522static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
8523static int skipcount; /* number of levels to skip */
8524static int funcnest; /* depth of function calls */
8525static int loopnest; /* current loop nesting level */
8526
8527/* Forward decl way out to parsing code - dotrap needs it */
8528static int evalstring(char *s, int flags);
8529
8530/* Called to execute a trap.
8531 * Single callsite - at the end of evaltree().
8532 * If we return non-zero, evaltree raises EXEXIT exception.
8533 *
8534 * Perhaps we should avoid entering new trap handlers
8535 * while we are executing a trap handler. [is it a TODO?]
8536 */
8537static void
8538dotrap(void)
8539{
8540 uint8_t *g;
8541 int sig;
8542 uint8_t last_status;
8543
8544 if (!pending_sig)
8545 return;
8546
8547 last_status = exitstatus;
8548 pending_sig = 0;
8549 barrier();
8550
8551 TRACE(("dotrap entered\n"));
8552 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8553 char *p;
8554
8555 if (!*g)
8556 continue;
8557
8558 if (evalskip) {
8559 pending_sig = sig;
8560 break;
8561 }
8562
8563 p = trap[sig];
8564 /* non-trapped SIGINT is handled separately by raise_interrupt,
8565 * don't upset it by resetting gotsig[SIGINT-1] */
8566 if (sig == SIGINT && !p)
8567 continue;
8568
8569 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
8570 *g = 0;
8571 if (!p)
8572 continue;
8573 evalstring(p, 0);
8574 }
8575 exitstatus = last_status;
8576 TRACE(("dotrap returns\n"));
8577}
8578
8579/* forward declarations - evaluation is fairly recursive business... */
8580static int evalloop(union node *, int);
8581static int evalfor(union node *, int);
8582static int evalcase(union node *, int);
8583static int evalsubshell(union node *, int);
8584static void expredir(union node *);
8585static int evalpipe(union node *, int);
8586static int evalcommand(union node *, int);
8587static int evalbltin(const struct builtincmd *, int, char **, int);
8588static void prehash(union node *);
8589
8590/*
8591 * Evaluate a parse tree. The value is left in the global variable
8592 * exitstatus.
8593 */
8594static int
8595evaltree(union node *n, int flags)
8596{
8597 int checkexit = 0;
8598 int (*evalfn)(union node *, int);
8599 int status = 0;
8600
8601 if (n == NULL) {
8602 TRACE(("evaltree(NULL) called\n"));
8603 goto out;
8604 }
8605 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
8606
8607 dotrap();
8608
8609 switch (n->type) {
8610 default:
8611#if DEBUG
8612 out1fmt("Node type = %d\n", n->type);
8613 fflush_all();
8614 break;
8615#endif
8616 case NNOT:
8617 status = !evaltree(n->nnot.com, EV_TESTED);
8618 goto setstatus;
8619 case NREDIR:
8620 expredir(n->nredir.redirect);
8621 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8622 if (!status) {
8623 status = evaltree(n->nredir.n, flags & EV_TESTED);
8624 }
8625 if (n->nredir.redirect)
8626 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
8627 goto setstatus;
8628 case NCMD:
8629 evalfn = evalcommand;
8630 checkexit:
8631 if (eflag && !(flags & EV_TESTED))
8632 checkexit = ~0;
8633 goto calleval;
8634 case NFOR:
8635 evalfn = evalfor;
8636 goto calleval;
8637 case NWHILE:
8638 case NUNTIL:
8639 evalfn = evalloop;
8640 goto calleval;
8641 case NSUBSHELL:
8642 case NBACKGND:
8643 evalfn = evalsubshell;
8644 goto checkexit;
8645 case NPIPE:
8646 evalfn = evalpipe;
8647 goto checkexit;
8648 case NCASE:
8649 evalfn = evalcase;
8650 goto calleval;
8651 case NAND:
8652 case NOR:
8653 case NSEMI: {
8654
8655#if NAND + 1 != NOR
8656#error NAND + 1 != NOR
8657#endif
8658#if NOR + 1 != NSEMI
8659#error NOR + 1 != NSEMI
8660#endif
8661 unsigned is_or = n->type - NAND;
8662 status = evaltree(
8663 n->nbinary.ch1,
8664 (flags | ((is_or >> 1) - 1)) & EV_TESTED
8665 );
8666 if ((!status) == is_or || evalskip)
8667 break;
8668 n = n->nbinary.ch2;
8669 evaln:
8670 evalfn = evaltree;
8671 calleval:
8672 status = evalfn(n, flags);
8673 goto setstatus;
8674 }
8675 case NIF:
8676 status = evaltree(n->nif.test, EV_TESTED);
8677 if (evalskip)
8678 break;
8679 if (!status) {
8680 n = n->nif.ifpart;
8681 goto evaln;
8682 }
8683 if (n->nif.elsepart) {
8684 n = n->nif.elsepart;
8685 goto evaln;
8686 }
8687 status = 0;
8688 goto setstatus;
8689 case NDEFUN:
8690 defun(n);
8691 /* Not necessary. To test it:
8692 * "false; f() { qwerty; }; echo $?" should print 0.
8693 */
8694 /* status = 0; */
8695 setstatus:
8696 exitstatus = status;
8697 break;
8698 }
8699 out:
8700 /* Order of checks below is important:
8701 * signal handlers trigger before exit caused by "set -e".
8702 */
8703 dotrap();
8704
8705 if (checkexit & status)
8706 raise_exception(EXEXIT);
8707 if (flags & EV_EXIT)
8708 raise_exception(EXEXIT);
8709
8710 TRACE(("leaving evaltree (no interrupts)\n"));
8711 return exitstatus;
8712}
8713
8714#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8715static
8716#endif
8717int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8718
8719static int
8720skiploop(void)
8721{
8722 int skip = evalskip;
8723
8724 switch (skip) {
8725 case 0:
8726 break;
8727 case SKIPBREAK:
8728 case SKIPCONT:
8729 if (--skipcount <= 0) {
8730 evalskip = 0;
8731 break;
8732 }
8733 skip = SKIPBREAK;
8734 break;
8735 }
8736 return skip;
8737}
8738
8739static int
8740evalloop(union node *n, int flags)
8741{
8742 int skip;
8743 int status;
8744
8745 loopnest++;
8746 status = 0;
8747 flags &= EV_TESTED;
8748 do {
8749 int i;
8750
8751 i = evaltree(n->nbinary.ch1, EV_TESTED);
8752 skip = skiploop();
8753 if (skip == SKIPFUNC)
8754 status = i;
8755 if (skip)
8756 continue;
8757 if (n->type != NWHILE)
8758 i = !i;
8759 if (i != 0)
8760 break;
8761 status = evaltree(n->nbinary.ch2, flags);
8762 skip = skiploop();
8763 } while (!(skip & ~SKIPCONT));
8764 loopnest--;
8765
8766 return status;
8767}
8768
8769static int
8770evalfor(union node *n, int flags)
8771{
8772 struct arglist arglist;
8773 union node *argp;
8774 struct strlist *sp;
8775 struct stackmark smark;
8776 int status = 0;
8777
8778 setstackmark(&smark);
8779 arglist.list = NULL;
8780 arglist.lastp = &arglist.list;
8781 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8782 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8783 }
8784 *arglist.lastp = NULL;
8785
8786 loopnest++;
8787 flags &= EV_TESTED;
8788 for (sp = arglist.list; sp; sp = sp->next) {
8789 setvar0(n->nfor.var, sp->text);
8790 status = evaltree(n->nfor.body, flags);
8791 if (skiploop() & ~SKIPCONT)
8792 break;
8793 }
8794 loopnest--;
8795 popstackmark(&smark);
8796
8797 return status;
8798}
8799
8800static int
8801evalcase(union node *n, int flags)
8802{
8803 union node *cp;
8804 union node *patp;
8805 struct arglist arglist;
8806 struct stackmark smark;
8807 int status = 0;
8808
8809 setstackmark(&smark);
8810 arglist.list = NULL;
8811 arglist.lastp = &arglist.list;
8812 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
8813 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8814 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
8815 if (casematch(patp, arglist.list->text)) {
8816 /* Ensure body is non-empty as otherwise
8817 * EV_EXIT may prevent us from setting the
8818 * exit status.
8819 */
8820 if (evalskip == 0 && cp->nclist.body) {
8821 status = evaltree(cp->nclist.body, flags);
8822 }
8823 goto out;
8824 }
8825 }
8826 }
8827 out:
8828 popstackmark(&smark);
8829
8830 return status;
8831}
8832
8833/*
8834 * Kick off a subshell to evaluate a tree.
8835 */
8836static int
8837evalsubshell(union node *n, int flags)
8838{
8839 struct job *jp;
8840 int backgnd = (n->type == NBACKGND);
8841 int status;
8842
8843 expredir(n->nredir.redirect);
8844 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
8845 goto nofork;
8846 INT_OFF;
8847 jp = makejob(/*n,*/ 1);
8848 if (forkshell(jp, n, backgnd) == 0) {
8849 /* child */
8850 INT_ON;
8851 flags |= EV_EXIT;
8852 if (backgnd)
8853 flags &= ~EV_TESTED;
8854 nofork:
8855 redirect(n->nredir.redirect, 0);
8856 evaltreenr(n->nredir.n, flags);
8857 /* never returns */
8858 }
8859 /* parent */
8860 status = 0;
8861 if (!backgnd)
8862 status = waitforjob(jp);
8863 INT_ON;
8864 return status;
8865}
8866
8867/*
8868 * Compute the names of the files in a redirection list.
8869 */
8870static void fixredir(union node *, const char *, int);
8871static void
8872expredir(union node *n)
8873{
8874 union node *redir;
8875
8876 for (redir = n; redir; redir = redir->nfile.next) {
8877 struct arglist fn;
8878
8879 fn.list = NULL;
8880 fn.lastp = &fn.list;
8881 switch (redir->type) {
8882 case NFROMTO:
8883 case NFROM:
8884 case NTO:
8885#if ENABLE_ASH_BASH_COMPAT
8886 case NTO2:
8887#endif
8888 case NCLOBBER:
8889 case NAPPEND:
8890 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8891 TRACE(("expredir expanded to '%s'\n", fn.list->text));
8892#if ENABLE_ASH_BASH_COMPAT
8893 store_expfname:
8894#endif
8895#if 0
8896// By the design of stack allocator, the loop of this kind:
8897// while true; do while true; do break; done </dev/null; done
8898// will look like a memory leak: ash plans to free expfname's
8899// of "/dev/null" as soon as it finishes running the loop
8900// (in this case, never).
8901// This "fix" is wrong:
8902 if (redir->nfile.expfname)
8903 stunalloc(redir->nfile.expfname);
8904// It results in corrupted state of stacked allocations.
8905#endif
8906 redir->nfile.expfname = fn.list->text;
8907 break;
8908 case NFROMFD:
8909 case NTOFD: /* >& */
8910 if (redir->ndup.vname) {
8911 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8912 if (fn.list == NULL)
8913 ash_msg_and_raise_error("redir error");
8914#if ENABLE_ASH_BASH_COMPAT
8915//FIXME: we used expandarg with different args!
8916 if (!isdigit_str9(fn.list->text)) {
8917 /* >&file, not >&fd */
8918 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8919 ash_msg_and_raise_error("redir error");
8920 redir->type = NTO2;
8921 goto store_expfname;
8922 }
8923#endif
8924 fixredir(redir, fn.list->text, 1);
8925 }
8926 break;
8927 }
8928 }
8929}
8930
8931/*
8932 * Evaluate a pipeline. All the processes in the pipeline are children
8933 * of the process creating the pipeline. (This differs from some versions
8934 * of the shell, which make the last process in a pipeline the parent
8935 * of all the rest.)
8936 */
8937static int
8938evalpipe(union node *n, int flags)
8939{
8940 struct job *jp;
8941 struct nodelist *lp;
8942 int pipelen;
8943 int prevfd;
8944 int pip[2];
8945 int status = 0;
8946
8947 TRACE(("evalpipe(0x%lx) called\n", (long)n));
8948 pipelen = 0;
8949 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
8950 pipelen++;
8951 flags |= EV_EXIT;
8952 INT_OFF;
8953 jp = makejob(/*n,*/ pipelen);
8954 prevfd = -1;
8955 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
8956 prehash(lp->n);
8957 pip[1] = -1;
8958 if (lp->next) {
8959 if (pipe(pip) < 0) {
8960 close(prevfd);
8961 ash_msg_and_raise_error("pipe call failed");
8962 }
8963 }
8964 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8965 /* child */
8966 INT_ON;
8967 if (pip[1] >= 0) {
8968 close(pip[0]);
8969 }
8970 if (prevfd > 0) {
8971 dup2(prevfd, 0);
8972 close(prevfd);
8973 }
8974 if (pip[1] > 1) {
8975 dup2(pip[1], 1);
8976 close(pip[1]);
8977 }
8978 evaltreenr(lp->n, flags);
8979 /* never returns */
8980 }
8981 /* parent */
8982 if (prevfd >= 0)
8983 close(prevfd);
8984 prevfd = pip[0];
8985 /* Don't want to trigger debugging */
8986 if (pip[1] != -1)
8987 close(pip[1]);
8988 }
8989 if (n->npipe.pipe_backgnd == 0) {
8990 status = waitforjob(jp);
8991 TRACE(("evalpipe: job done exit status %d\n", status));
8992 }
8993 INT_ON;
8994
8995 return status;
8996}
8997
8998/*
8999 * Controls whether the shell is interactive or not.
9000 */
9001static void
9002setinteractive(int on)
9003{
9004 static smallint is_interactive;
9005
9006 if (++on == is_interactive)
9007 return;
9008 is_interactive = on;
9009 setsignal(SIGINT);
9010 setsignal(SIGQUIT);
9011 setsignal(SIGTERM);
9012#if !ENABLE_FEATURE_SH_EXTRA_QUIET
9013 if (is_interactive > 1) {
9014 /* Looks like they want an interactive shell */
9015 static smallint did_banner;
9016
9017 if (!did_banner) {
9018 /* note: ash and hush share this string */
9019 out1fmt("\n\n%s %s\n"
9020 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
9021 "\n",
9022 bb_banner,
9023 "built-in shell (ash)"
9024 );
9025 did_banner = 1;
9026 }
9027 }
9028#endif
9029}
9030
9031static void
9032optschanged(void)
9033{
9034#if DEBUG
9035 opentrace();
9036#endif
9037 setinteractive(iflag);
9038 setjobctl(mflag);
9039#if ENABLE_FEATURE_EDITING_VI
9040 if (viflag)
9041 line_input_state->flags |= VI_MODE;
9042 else
9043 line_input_state->flags &= ~VI_MODE;
9044#else
9045 viflag = 0; /* forcibly keep the option off */
9046#endif
9047}
9048
9049static struct localvar *localvars;
9050
9051/*
9052 * Called after a function returns.
9053 * Interrupts must be off.
9054 */
9055static void
9056poplocalvars(void)
9057{
9058 struct localvar *lvp;
9059 struct var *vp;
9060
9061 while ((lvp = localvars) != NULL) {
9062 localvars = lvp->next;
9063 vp = lvp->vp;
9064 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
9065 if (vp == NULL) { /* $- saved */
9066 memcpy(optlist, lvp->text, sizeof(optlist));
9067 free((char*)lvp->text);
9068 optschanged();
9069 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
9070 unsetvar(vp->var_text);
9071 } else {
9072 if (vp->var_func)
9073 vp->var_func(var_end(lvp->text));
9074 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
9075 free((char*)vp->var_text);
9076 vp->flags = lvp->flags;
9077 vp->var_text = lvp->text;
9078 }
9079 free(lvp);
9080 }
9081}
9082
9083static int
9084evalfun(struct funcnode *func, int argc, char **argv, int flags)
9085{
9086 volatile struct shparam saveparam;
9087 struct localvar *volatile savelocalvars;
9088 struct jmploc *volatile savehandler;
9089 struct jmploc jmploc;
9090 int e;
9091
9092 saveparam = shellparam;
9093 savelocalvars = localvars;
9094 savehandler = exception_handler;
9095 e = setjmp(jmploc.loc);
9096 if (e) {
9097 goto funcdone;
9098 }
9099 INT_OFF;
9100 exception_handler = &jmploc;
9101 localvars = NULL;
9102 shellparam.malloced = 0;
9103 func->count++;
9104 funcnest++;
9105 INT_ON;
9106 shellparam.nparam = argc - 1;
9107 shellparam.p = argv + 1;
9108#if ENABLE_ASH_GETOPTS
9109 shellparam.optind = 1;
9110 shellparam.optoff = -1;
9111#endif
9112 evaltree(func->n.narg.next, flags & EV_TESTED);
9113 funcdone:
9114 INT_OFF;
9115 funcnest--;
9116 freefunc(func);
9117 poplocalvars();
9118 localvars = savelocalvars;
9119 freeparam(&shellparam);
9120 shellparam = saveparam;
9121 exception_handler = savehandler;
9122 INT_ON;
9123 evalskip &= ~SKIPFUNC;
9124 return e;
9125}
9126
9127/*
9128 * Make a variable a local variable. When a variable is made local, it's
9129 * value and flags are saved in a localvar structure. The saved values
9130 * will be restored when the shell function returns. We handle the name
9131 * "-" as a special case: it makes changes to "set +-options" local
9132 * (options will be restored on return from the function).
9133 */
9134static void
9135mklocal(char *name)
9136{
9137 struct localvar *lvp;
9138 struct var **vpp;
9139 struct var *vp;
9140 char *eq = strchr(name, '=');
9141
9142 INT_OFF;
9143 /* Cater for duplicate "local". Examples:
9144 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9145 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9146 */
9147 lvp = localvars;
9148 while (lvp) {
9149 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
9150 if (eq)
9151 setvareq(name, 0);
9152 /* else:
9153 * it's a duplicate "local VAR" declaration, do nothing
9154 */
9155 goto ret;
9156 }
9157 lvp = lvp->next;
9158 }
9159
9160 lvp = ckzalloc(sizeof(*lvp));
9161 if (LONE_DASH(name)) {
9162 char *p;
9163 p = ckmalloc(sizeof(optlist));
9164 lvp->text = memcpy(p, optlist, sizeof(optlist));
9165 vp = NULL;
9166 } else {
9167 vpp = hashvar(name);
9168 vp = *findvar(vpp, name);
9169 if (vp == NULL) {
9170 /* variable did not exist yet */
9171 if (eq)
9172 setvareq(name, VSTRFIXED);
9173 else
9174 setvar(name, NULL, VSTRFIXED);
9175 vp = *vpp; /* the new variable */
9176 lvp->flags = VUNSET;
9177 } else {
9178 lvp->text = vp->var_text;
9179 lvp->flags = vp->flags;
9180 /* make sure neither "struct var" nor string gets freed
9181 * during (un)setting:
9182 */
9183 vp->flags |= VSTRFIXED|VTEXTFIXED;
9184 if (eq)
9185 setvareq(name, 0);
9186 else
9187 /* "local VAR" unsets VAR: */
9188 setvar0(name, NULL);
9189 }
9190 }
9191 lvp->vp = vp;
9192 lvp->next = localvars;
9193 localvars = lvp;
9194 ret:
9195 INT_ON;
9196}
9197
9198/*
9199 * The "local" command.
9200 */
9201static int FAST_FUNC
9202localcmd(int argc UNUSED_PARAM, char **argv)
9203{
9204 char *name;
9205
9206 if (!funcnest)
9207 ash_msg_and_raise_error("not in a function");
9208
9209 argv = argptr;
9210 while ((name = *argv++) != NULL) {
9211 mklocal(name);
9212 }
9213 return 0;
9214}
9215
9216static int FAST_FUNC
9217falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9218{
9219 return 1;
9220}
9221
9222static int FAST_FUNC
9223truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9224{
9225 return 0;
9226}
9227
9228static int FAST_FUNC
9229execcmd(int argc UNUSED_PARAM, char **argv)
9230{
9231 if (argv[1]) {
9232 iflag = 0; /* exit on error */
9233 mflag = 0;
9234 optschanged();
9235 /* We should set up signals for "exec CMD"
9236 * the same way as for "CMD" without "exec".
9237 * But optschanged->setinteractive->setsignal
9238 * still thought we are a root shell. Therefore, for example,
9239 * SIGQUIT is still set to IGN. Fix it:
9240 */
9241 shlvl++;
9242 setsignal(SIGQUIT);
9243 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9244 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9245 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9246
9247 shellexec(argv + 1, pathval(), 0);
9248 /* NOTREACHED */
9249 }
9250 return 0;
9251}
9252
9253/*
9254 * The return command.
9255 */
9256static int FAST_FUNC
9257returncmd(int argc UNUSED_PARAM, char **argv)
9258{
9259 /*
9260 * If called outside a function, do what ksh does;
9261 * skip the rest of the file.
9262 */
9263 evalskip = SKIPFUNC;
9264 return argv[1] ? number(argv[1]) : exitstatus;
9265}
9266
9267/* Forward declarations for builtintab[] */
9268static int breakcmd(int, char **) FAST_FUNC;
9269static int dotcmd(int, char **) FAST_FUNC;
9270static int evalcmd(int, char **, int) FAST_FUNC;
9271static int exitcmd(int, char **) FAST_FUNC;
9272static int exportcmd(int, char **) FAST_FUNC;
9273#if ENABLE_ASH_GETOPTS
9274static int getoptscmd(int, char **) FAST_FUNC;
9275#endif
9276#if ENABLE_ASH_HELP
9277static int helpcmd(int, char **) FAST_FUNC;
9278#endif
9279#if MAX_HISTORY
9280static int historycmd(int, char **) FAST_FUNC;
9281#endif
9282#if ENABLE_FEATURE_SH_MATH
9283static int letcmd(int, char **) FAST_FUNC;
9284#endif
9285static int readcmd(int, char **) FAST_FUNC;
9286static int setcmd(int, char **) FAST_FUNC;
9287static int shiftcmd(int, char **) FAST_FUNC;
9288static int timescmd(int, char **) FAST_FUNC;
9289static int trapcmd(int, char **) FAST_FUNC;
9290static int umaskcmd(int, char **) FAST_FUNC;
9291static int unsetcmd(int, char **) FAST_FUNC;
9292static int ulimitcmd(int, char **) FAST_FUNC;
9293
9294#define BUILTIN_NOSPEC "0"
9295#define BUILTIN_SPECIAL "1"
9296#define BUILTIN_REGULAR "2"
9297#define BUILTIN_SPEC_REG "3"
9298#define BUILTIN_ASSIGN "4"
9299#define BUILTIN_SPEC_ASSG "5"
9300#define BUILTIN_REG_ASSG "6"
9301#define BUILTIN_SPEC_REG_ASSG "7"
9302
9303/* Stubs for calling non-FAST_FUNC's */
9304#if ENABLE_ASH_BUILTIN_ECHO
9305static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
9306#endif
9307#if ENABLE_ASH_BUILTIN_PRINTF
9308static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
9309#endif
9310#if ENABLE_ASH_BUILTIN_TEST
9311static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
9312#endif
9313
9314/* Keep these in proper order since it is searched via bsearch() */
9315static const struct builtincmd builtintab[] = {
9316 { BUILTIN_SPEC_REG "." , dotcmd },
9317 { BUILTIN_SPEC_REG ":" , truecmd },
9318#if ENABLE_ASH_BUILTIN_TEST
9319 { BUILTIN_REGULAR "[" , testcmd },
9320# if ENABLE_ASH_BASH_COMPAT
9321 { BUILTIN_REGULAR "[[" , testcmd },
9322# endif
9323#endif
9324#if ENABLE_ASH_ALIAS
9325 { BUILTIN_REG_ASSG "alias" , aliascmd },
9326#endif
9327#if JOBS
9328 { BUILTIN_REGULAR "bg" , fg_bgcmd },
9329#endif
9330 { BUILTIN_SPEC_REG "break" , breakcmd },
9331 { BUILTIN_REGULAR "cd" , cdcmd },
9332 { BUILTIN_NOSPEC "chdir" , cdcmd },
9333#if ENABLE_ASH_CMDCMD
9334 { BUILTIN_REGULAR "command" , commandcmd },
9335#endif
9336 { BUILTIN_SPEC_REG "continue", breakcmd },
9337#if ENABLE_ASH_BUILTIN_ECHO
9338 { BUILTIN_REGULAR "echo" , echocmd },
9339#endif
9340 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
9341 { BUILTIN_SPEC_REG "exec" , execcmd },
9342 { BUILTIN_SPEC_REG "exit" , exitcmd },
9343 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9344 { BUILTIN_REGULAR "false" , falsecmd },
9345#if JOBS
9346 { BUILTIN_REGULAR "fg" , fg_bgcmd },
9347#endif
9348#if ENABLE_ASH_GETOPTS
9349 { BUILTIN_REGULAR "getopts" , getoptscmd },
9350#endif
9351 { BUILTIN_NOSPEC "hash" , hashcmd },
9352#if ENABLE_ASH_HELP
9353 { BUILTIN_NOSPEC "help" , helpcmd },
9354#endif
9355#if MAX_HISTORY
9356 { BUILTIN_NOSPEC "history" , historycmd },
9357#endif
9358#if JOBS
9359 { BUILTIN_REGULAR "jobs" , jobscmd },
9360 { BUILTIN_REGULAR "kill" , killcmd },
9361#endif
9362#if ENABLE_FEATURE_SH_MATH
9363 { BUILTIN_NOSPEC "let" , letcmd },
9364#endif
9365 { BUILTIN_ASSIGN "local" , localcmd },
9366#if ENABLE_ASH_BUILTIN_PRINTF
9367 { BUILTIN_REGULAR "printf" , printfcmd },
9368#endif
9369 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9370 { BUILTIN_REGULAR "read" , readcmd },
9371 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9372 { BUILTIN_SPEC_REG "return" , returncmd },
9373 { BUILTIN_SPEC_REG "set" , setcmd },
9374 { BUILTIN_SPEC_REG "shift" , shiftcmd },
9375#if ENABLE_ASH_BASH_COMPAT
9376 { BUILTIN_SPEC_REG "source" , dotcmd },
9377#endif
9378#if ENABLE_ASH_BUILTIN_TEST
9379 { BUILTIN_REGULAR "test" , testcmd },
9380#endif
9381 { BUILTIN_SPEC_REG "times" , timescmd },
9382 { BUILTIN_SPEC_REG "trap" , trapcmd },
9383 { BUILTIN_REGULAR "true" , truecmd },
9384 { BUILTIN_NOSPEC "type" , typecmd },
9385 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9386 { BUILTIN_REGULAR "umask" , umaskcmd },
9387#if ENABLE_ASH_ALIAS
9388 { BUILTIN_REGULAR "unalias" , unaliascmd },
9389#endif
9390 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9391 { BUILTIN_REGULAR "wait" , waitcmd },
9392};
9393
9394/* Should match the above table! */
9395#define COMMANDCMD (builtintab + \
9396 /* . : */ 2 + \
9397 /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \
9398 /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9399 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9400 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9401 /* break cd cddir */ 3)
9402#define EVALCMD (COMMANDCMD + \
9403 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9404 /* continue */ 1 + \
9405 /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \
9406 0)
9407#define EXECCMD (EVALCMD + \
9408 /* eval */ 1)
9409
9410/*
9411 * Search the table of builtin commands.
9412 */
9413static int
9414pstrcmp1(const void *a, const void *b)
9415{
9416 return strcmp((char*)a, *(char**)b + 1);
9417}
9418static struct builtincmd *
9419find_builtin(const char *name)
9420{
9421 struct builtincmd *bp;
9422
9423 bp = bsearch(
9424 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
9425 pstrcmp1
9426 );
9427 return bp;
9428}
9429
9430/*
9431 * Execute a simple command.
9432 */
9433static int
9434isassignment(const char *p)
9435{
9436 const char *q = endofname(p);
9437 if (p == q)
9438 return 0;
9439 return *q == '=';
9440}
9441static int FAST_FUNC
9442bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9443{
9444 /* Preserve exitstatus of a previous possible redirection
9445 * as POSIX mandates */
9446 return back_exitstatus;
9447}
9448static int
9449evalcommand(union node *cmd, int flags)
9450{
9451 static const struct builtincmd null_bltin = {
9452 "\0\0", bltincmd /* why three NULs? */
9453 };
9454 struct stackmark smark;
9455 union node *argp;
9456 struct arglist arglist;
9457 struct arglist varlist;
9458 char **argv;
9459 int argc;
9460 const struct strlist *sp;
9461 struct cmdentry cmdentry;
9462 struct job *jp;
9463 char *lastarg;
9464 const char *path;
9465 int spclbltin;
9466 int status;
9467 char **nargv;
9468 struct builtincmd *bcmd;
9469 smallint cmd_is_exec;
9470 smallint pseudovarflag = 0;
9471
9472 /* First expand the arguments. */
9473 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9474 setstackmark(&smark);
9475 back_exitstatus = 0;
9476
9477 cmdentry.cmdtype = CMDBUILTIN;
9478 cmdentry.u.cmd = &null_bltin;
9479 varlist.lastp = &varlist.list;
9480 *varlist.lastp = NULL;
9481 arglist.lastp = &arglist.list;
9482 *arglist.lastp = NULL;
9483
9484 argc = 0;
9485 if (cmd->ncmd.args) {
9486 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9487 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9488 }
9489
9490 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9491 struct strlist **spp;
9492
9493 spp = arglist.lastp;
9494 if (pseudovarflag && isassignment(argp->narg.text))
9495 expandarg(argp, &arglist, EXP_VARTILDE);
9496 else
9497 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9498
9499 for (sp = *spp; sp; sp = sp->next)
9500 argc++;
9501 }
9502
9503 /* Reserve one extra spot at the front for shellexec. */
9504 nargv = stalloc(sizeof(char *) * (argc + 2));
9505 argv = ++nargv;
9506 for (sp = arglist.list; sp; sp = sp->next) {
9507 TRACE(("evalcommand arg: %s\n", sp->text));
9508 *nargv++ = sp->text;
9509 }
9510 *nargv = NULL;
9511
9512 lastarg = NULL;
9513 if (iflag && funcnest == 0 && argc > 0)
9514 lastarg = nargv[-1];
9515
9516 preverrout_fd = 2;
9517 expredir(cmd->ncmd.redirect);
9518 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
9519
9520 path = vpath.var_text;
9521 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9522 struct strlist **spp;
9523 char *p;
9524
9525 spp = varlist.lastp;
9526 expandarg(argp, &varlist, EXP_VARTILDE);
9527
9528 /*
9529 * Modify the command lookup path, if a PATH= assignment
9530 * is present
9531 */
9532 p = (*spp)->text;
9533 if (varcmp(p, path) == 0)
9534 path = p;
9535 }
9536
9537 /* Print the command if xflag is set. */
9538 if (xflag) {
9539 int n;
9540 const char *p = " %s" + 1;
9541
9542 fdprintf(preverrout_fd, p, expandstr(ps4val()));
9543 sp = varlist.list;
9544 for (n = 0; n < 2; n++) {
9545 while (sp) {
9546 fdprintf(preverrout_fd, p, sp->text);
9547 sp = sp->next;
9548 p = " %s";
9549 }
9550 sp = arglist.list;
9551 }
9552 safe_write(preverrout_fd, "\n", 1);
9553 }
9554
9555 cmd_is_exec = 0;
9556 spclbltin = -1;
9557
9558 /* Now locate the command. */
9559 if (argc) {
9560 int cmd_flag = DO_ERR;
9561#if ENABLE_ASH_CMDCMD
9562 const char *oldpath = path + 5;
9563#endif
9564 path += 5;
9565 for (;;) {
9566 find_command(argv[0], &cmdentry, cmd_flag, path);
9567 if (cmdentry.cmdtype == CMDUNKNOWN) {
9568 flush_stdout_stderr();
9569 status = 127;
9570 goto bail;
9571 }
9572
9573 /* implement bltin and command here */
9574 if (cmdentry.cmdtype != CMDBUILTIN)
9575 break;
9576 if (spclbltin < 0)
9577 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9578 if (cmdentry.u.cmd == EXECCMD)
9579 cmd_is_exec = 1;
9580#if ENABLE_ASH_CMDCMD
9581 if (cmdentry.u.cmd == COMMANDCMD) {
9582 path = oldpath;
9583 nargv = parse_command_args(argv, &path);
9584 if (!nargv)
9585 break;
9586 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9587 * nargv => "PROG". path is updated if -p.
9588 */
9589 argc -= nargv - argv;
9590 argv = nargv;
9591 cmd_flag |= DO_NOFUNC;
9592 } else
9593#endif
9594 break;
9595 }
9596 }
9597
9598 if (status) {
9599 bail:
9600 exitstatus = status;
9601
9602 /* We have a redirection error. */
9603 if (spclbltin > 0)
9604 raise_exception(EXERROR);
9605
9606 goto out;
9607 }
9608
9609 /* Execute the command. */
9610 switch (cmdentry.cmdtype) {
9611 default: {
9612
9613#if ENABLE_FEATURE_SH_NOFORK
9614/* (1) BUG: if variables are set, we need to fork, or save/restore them
9615 * around run_nofork_applet() call.
9616 * (2) Should this check also be done in forkshell()?
9617 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9618 */
9619 /* find_command() encodes applet_no as (-2 - applet_no) */
9620 int applet_no = (- cmdentry.u.index - 2);
9621 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
9622 listsetvar(varlist.list, VEXPORT|VSTACK);
9623 /* run <applet>_main() */
9624 status = run_nofork_applet(applet_no, argv);
9625 break;
9626 }
9627#endif
9628 /* Can we avoid forking off? For example, very last command
9629 * in a script or a subshell does not need forking,
9630 * we can just exec it.
9631 */
9632 if (!(flags & EV_EXIT) || may_have_traps) {
9633 /* No, forking off a child is necessary */
9634 INT_OFF;
9635 jp = makejob(/*cmd,*/ 1);
9636 if (forkshell(jp, cmd, FORK_FG) != 0) {
9637 /* parent */
9638 status = waitforjob(jp);
9639 INT_ON;
9640 TRACE(("forked child exited with %d\n", status));
9641 break;
9642 }
9643 /* child */
9644 FORCE_INT_ON;
9645 /* fall through to exec'ing external program */
9646 }
9647 listsetvar(varlist.list, VEXPORT|VSTACK);
9648 shellexec(argv, path, cmdentry.u.index);
9649 /* NOTREACHED */
9650 } /* default */
9651 case CMDBUILTIN:
9652 cmdenviron = varlist.list;
9653 if (cmdenviron) {
9654 struct strlist *list = cmdenviron;
9655 int i = VNOSET;
9656 if (spclbltin > 0 || argc == 0) {
9657 i = 0;
9658 if (cmd_is_exec && argc > 1)
9659 i = VEXPORT;
9660 }
9661 listsetvar(list, i);
9662 }
9663 /* Tight loop with builtins only:
9664 * "while kill -0 $child; do true; done"
9665 * will never exit even if $child died, unless we do this
9666 * to reap the zombie and make kill detect that it's gone: */
9667 dowait(DOWAIT_NONBLOCK, NULL);
9668
9669 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
9670 if (exception_type == EXERROR && spclbltin <= 0) {
9671 FORCE_INT_ON;
9672 goto readstatus;
9673 }
9674 raise:
9675 longjmp(exception_handler->loc, 1);
9676 }
9677 goto readstatus;
9678
9679 case CMDFUNCTION:
9680 listsetvar(varlist.list, 0);
9681 /* See above for the rationale */
9682 dowait(DOWAIT_NONBLOCK, NULL);
9683 if (evalfun(cmdentry.u.func, argc, argv, flags))
9684 goto raise;
9685 readstatus:
9686 status = exitstatus;
9687 break;
9688 } /* switch */
9689
9690 out:
9691 if (cmd->ncmd.redirect)
9692 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
9693 if (lastarg) {
9694 /* dsl: I think this is intended to be used to support
9695 * '_' in 'vi' command mode during line editing...
9696 * However I implemented that within libedit itself.
9697 */
9698 setvar0("_", lastarg);
9699 }
9700 popstackmark(&smark);
9701
9702 return status;
9703}
9704
9705static int
9706evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
9707{
9708 char *volatile savecmdname;
9709 struct jmploc *volatile savehandler;
9710 struct jmploc jmploc;
9711 int status;
9712 int i;
9713
9714 savecmdname = commandname;
9715 savehandler = exception_handler;
9716 i = setjmp(jmploc.loc);
9717 if (i)
9718 goto cmddone;
9719 exception_handler = &jmploc;
9720 commandname = argv[0];
9721 argptr = argv + 1;
9722 optptr = NULL; /* initialize nextopt */
9723 if (cmd == EVALCMD)
9724 status = evalcmd(argc, argv, flags);
9725 else
9726 status = (*cmd->builtin)(argc, argv);
9727 flush_stdout_stderr();
9728 status |= ferror(stdout);
9729 exitstatus = status;
9730 cmddone:
9731 clearerr(stdout);
9732 commandname = savecmdname;
9733 exception_handler = savehandler;
9734
9735 return i;
9736}
9737
9738static int
9739goodname(const char *p)
9740{
9741 return endofname(p)[0] == '\0';
9742}
9743
9744
9745/*
9746 * Search for a command. This is called before we fork so that the
9747 * location of the command will be available in the parent as well as
9748 * the child. The check for "goodname" is an overly conservative
9749 * check that the name will not be subject to expansion.
9750 */
9751static void
9752prehash(union node *n)
9753{
9754 struct cmdentry entry;
9755
9756 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9757 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
9758}
9759
9760
9761/* ============ Builtin commands
9762 *
9763 * Builtin commands whose functions are closely tied to evaluation
9764 * are implemented here.
9765 */
9766
9767/*
9768 * Handle break and continue commands. Break, continue, and return are
9769 * all handled by setting the evalskip flag. The evaluation routines
9770 * above all check this flag, and if it is set they start skipping
9771 * commands rather than executing them. The variable skipcount is
9772 * the number of loops to break/continue, or the number of function
9773 * levels to return. (The latter is always 1.) It should probably
9774 * be an error to break out of more loops than exist, but it isn't
9775 * in the standard shell so we don't make it one here.
9776 */
9777static int FAST_FUNC
9778breakcmd(int argc UNUSED_PARAM, char **argv)
9779{
9780 int n = argv[1] ? number(argv[1]) : 1;
9781
9782 if (n <= 0)
9783 ash_msg_and_raise_error(msg_illnum, argv[1]);
9784 if (n > loopnest)
9785 n = loopnest;
9786 if (n > 0) {
9787 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
9788 skipcount = n;
9789 }
9790 return 0;
9791}
9792
9793
9794/*
9795 * This implements the input routines used by the parser.
9796 */
9797
9798enum {
9799 INPUT_PUSH_FILE = 1,
9800 INPUT_NOFILE_OK = 2,
9801};
9802
9803static smallint checkkwd;
9804/* values of checkkwd variable */
9805#define CHKALIAS 0x1
9806#define CHKKWD 0x2
9807#define CHKNL 0x4
9808
9809/*
9810 * Push a string back onto the input at this current parsefile level.
9811 * We handle aliases this way.
9812 */
9813#if !ENABLE_ASH_ALIAS
9814#define pushstring(s, ap) pushstring(s)
9815#endif
9816static void
9817pushstring(char *s, struct alias *ap)
9818{
9819 struct strpush *sp;
9820 int len;
9821
9822 len = strlen(s);
9823 INT_OFF;
9824 if (g_parsefile->strpush) {
9825 sp = ckzalloc(sizeof(*sp));
9826 sp->prev = g_parsefile->strpush;
9827 } else {
9828 sp = &(g_parsefile->basestrpush);
9829 }
9830 g_parsefile->strpush = sp;
9831 sp->prev_string = g_parsefile->next_to_pgetc;
9832 sp->prev_left_in_line = g_parsefile->left_in_line;
9833 sp->unget = g_parsefile->unget;
9834 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
9835#if ENABLE_ASH_ALIAS
9836 sp->ap = ap;
9837 if (ap) {
9838 ap->flag |= ALIASINUSE;
9839 sp->string = s;
9840 }
9841#endif
9842 g_parsefile->next_to_pgetc = s;
9843 g_parsefile->left_in_line = len;
9844 g_parsefile->unget = 0;
9845 INT_ON;
9846}
9847
9848static void
9849popstring(void)
9850{
9851 struct strpush *sp = g_parsefile->strpush;
9852
9853 INT_OFF;
9854#if ENABLE_ASH_ALIAS
9855 if (sp->ap) {
9856 if (g_parsefile->next_to_pgetc[-1] == ' '
9857 || g_parsefile->next_to_pgetc[-1] == '\t'
9858 ) {
9859 checkkwd |= CHKALIAS;
9860 }
9861 if (sp->string != sp->ap->val) {
9862 free(sp->string);
9863 }
9864 sp->ap->flag &= ~ALIASINUSE;
9865 if (sp->ap->flag & ALIASDEAD) {
9866 unalias(sp->ap->name);
9867 }
9868 }
9869#endif
9870 g_parsefile->next_to_pgetc = sp->prev_string;
9871 g_parsefile->left_in_line = sp->prev_left_in_line;
9872 g_parsefile->unget = sp->unget;
9873 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
9874 g_parsefile->strpush = sp->prev;
9875 if (sp != &(g_parsefile->basestrpush))
9876 free(sp);
9877 INT_ON;
9878}
9879
9880static int
9881preadfd(void)
9882{
9883 int nr;
9884 char *buf = g_parsefile->buf;
9885
9886 g_parsefile->next_to_pgetc = buf;
9887#if ENABLE_FEATURE_EDITING
9888 retry:
9889 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
9890 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
9891 else {
9892 int timeout = -1;
9893# if ENABLE_ASH_IDLE_TIMEOUT
9894 if (iflag) {
9895 const char *tmout_var = lookupvar("TMOUT");
9896 if (tmout_var) {
9897 timeout = atoi(tmout_var) * 1000;
9898 if (timeout <= 0)
9899 timeout = -1;
9900 }
9901 }
9902# endif
9903# if ENABLE_FEATURE_TAB_COMPLETION
9904 line_input_state->path_lookup = pathval();
9905# endif
9906 reinit_unicode_for_ash();
9907 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
9908 if (nr == 0) {
9909 /* ^C pressed, "convert" to SIGINT */
9910 write(STDOUT_FILENO, "^C", 2);
9911 if (trap[SIGINT]) {
9912 buf[0] = '\n';
9913 buf[1] = '\0';
9914 raise(SIGINT);
9915 return 1;
9916 }
9917 exitstatus = 128 + SIGINT;
9918 bb_putchar('\n');
9919 goto retry;
9920 }
9921 if (nr < 0) {
9922 if (errno == 0) {
9923 /* Ctrl+D pressed */
9924 nr = 0;
9925 }
9926# if ENABLE_ASH_IDLE_TIMEOUT
9927 else if (errno == EAGAIN && timeout > 0) {
9928 puts("\007timed out waiting for input: auto-logout");
9929 exitshell();
9930 }
9931# endif
9932 }
9933 }
9934#else
9935 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
9936#endif
9937
9938#if 0 /* disabled: nonblock_immune_read() handles this problem */
9939 if (nr < 0) {
9940 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
9941 int flags = fcntl(0, F_GETFL);
9942 if (flags >= 0 && (flags & O_NONBLOCK)) {
9943 flags &= ~O_NONBLOCK;
9944 if (fcntl(0, F_SETFL, flags) >= 0) {
9945 out2str("sh: turning off NDELAY mode\n");
9946 goto retry;
9947 }
9948 }
9949 }
9950 }
9951#endif
9952 return nr;
9953}
9954
9955/*
9956 * Refill the input buffer and return the next input character:
9957 *
9958 * 1) If a string was pushed back on the input, pop it;
9959 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9960 * or we are reading from a string so we can't refill the buffer,
9961 * return EOF.
9962 * 3) If there is more stuff in this buffer, use it else call read to fill it.
9963 * 4) Process input up to the next newline, deleting nul characters.
9964 */
9965//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9966#define pgetc_debug(...) ((void)0)
9967static int pgetc(void);
9968static int
9969preadbuffer(void)
9970{
9971 char *q;
9972 int more;
9973
9974 if (g_parsefile->strpush) {
9975#if ENABLE_ASH_ALIAS
9976 if (g_parsefile->left_in_line == -1
9977 && g_parsefile->strpush->ap
9978 && g_parsefile->next_to_pgetc[-1] != ' '
9979 && g_parsefile->next_to_pgetc[-1] != '\t'
9980 ) {
9981 pgetc_debug("preadbuffer PEOA");
9982 return PEOA;
9983 }
9984#endif
9985 popstring();
9986 return pgetc();
9987 }
9988 /* on both branches above g_parsefile->left_in_line < 0.
9989 * "pgetc" needs refilling.
9990 */
9991
9992 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
9993 * pungetc() may increment it a few times.
9994 * Assuming it won't increment it to less than -90.
9995 */
9996 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
9997 pgetc_debug("preadbuffer PEOF1");
9998 /* even in failure keep left_in_line and next_to_pgetc
9999 * in lock step, for correct multi-layer pungetc.
10000 * left_in_line was decremented before preadbuffer(),
10001 * must inc next_to_pgetc: */
10002 g_parsefile->next_to_pgetc++;
10003 return PEOF;
10004 }
10005
10006 more = g_parsefile->left_in_buffer;
10007 if (more <= 0) {
10008 flush_stdout_stderr();
10009 again:
10010 more = preadfd();
10011 if (more <= 0) {
10012 /* don't try reading again */
10013 g_parsefile->left_in_line = -99;
10014 pgetc_debug("preadbuffer PEOF2");
10015 g_parsefile->next_to_pgetc++;
10016 return PEOF;
10017 }
10018 }
10019
10020 /* Find out where's the end of line.
10021 * Set g_parsefile->left_in_line
10022 * and g_parsefile->left_in_buffer acordingly.
10023 * NUL chars are deleted.
10024 */
10025 q = g_parsefile->next_to_pgetc;
10026 for (;;) {
10027 char c;
10028
10029 more--;
10030
10031 c = *q;
10032 if (c == '\0') {
10033 memmove(q, q + 1, more);
10034 } else {
10035 q++;
10036 if (c == '\n') {
10037 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10038 break;
10039 }
10040 }
10041
10042 if (more <= 0) {
10043 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10044 if (g_parsefile->left_in_line < 0)
10045 goto again;
10046 break;
10047 }
10048 }
10049 g_parsefile->left_in_buffer = more;
10050
10051 if (vflag) {
10052 char save = *q;
10053 *q = '\0';
10054 out2str(g_parsefile->next_to_pgetc);
10055 *q = save;
10056 }
10057
10058 pgetc_debug("preadbuffer at %d:%p'%s'",
10059 g_parsefile->left_in_line,
10060 g_parsefile->next_to_pgetc,
10061 g_parsefile->next_to_pgetc);
10062 return (unsigned char)*g_parsefile->next_to_pgetc++;
10063}
10064
10065static void
10066nlprompt(void)
10067{
10068 g_parsefile->linno++;
10069 setprompt_if(doprompt, 2);
10070}
10071static void
10072nlnoprompt(void)
10073{
10074 g_parsefile->linno++;
10075 needprompt = doprompt;
10076}
10077
10078static int
10079pgetc(void)
10080{
10081 int c;
10082
10083 pgetc_debug("pgetc at %d:%p'%s'",
10084 g_parsefile->left_in_line,
10085 g_parsefile->next_to_pgetc,
10086 g_parsefile->next_to_pgetc);
10087 if (g_parsefile->unget)
10088 return g_parsefile->lastc[--g_parsefile->unget];
10089
10090 if (--g_parsefile->left_in_line >= 0)
10091 c = (unsigned char)*g_parsefile->next_to_pgetc++;
10092 else
10093 c = preadbuffer();
10094
10095 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10096 g_parsefile->lastc[0] = c;
10097
10098 return c;
10099}
10100
10101#if ENABLE_ASH_ALIAS
10102static int
10103pgetc_without_PEOA(void)
10104{
10105 int c;
10106 do {
10107 pgetc_debug("pgetc at %d:%p'%s'",
10108 g_parsefile->left_in_line,
10109 g_parsefile->next_to_pgetc,
10110 g_parsefile->next_to_pgetc);
10111 c = pgetc();
10112 } while (c == PEOA);
10113 return c;
10114}
10115#else
10116# define pgetc_without_PEOA() pgetc()
10117#endif
10118
10119/*
10120 * Read a line from the script.
10121 */
10122static char *
10123pfgets(char *line, int len)
10124{
10125 char *p = line;
10126 int nleft = len;
10127 int c;
10128
10129 while (--nleft > 0) {
10130 c = pgetc_without_PEOA();
10131 if (c == PEOF) {
10132 if (p == line)
10133 return NULL;
10134 break;
10135 }
10136 *p++ = c;
10137 if (c == '\n')
10138 break;
10139 }
10140 *p = '\0';
10141 return line;
10142}
10143
10144/*
10145 * Undo a call to pgetc. Only two characters may be pushed back.
10146 * PEOF may be pushed back.
10147 */
10148static void
10149pungetc(void)
10150{
10151 g_parsefile->unget++;
10152}
10153
10154/* This one eats backslash+newline */
10155static int
10156pgetc_eatbnl(void)
10157{
10158 int c;
10159
10160 while ((c = pgetc()) == '\\') {
10161 if (pgetc() != '\n') {
10162 pungetc();
10163 break;
10164 }
10165
10166 nlprompt();
10167 }
10168
10169 return c;
10170}
10171
10172/*
10173 * To handle the "." command, a stack of input files is used. Pushfile
10174 * adds a new entry to the stack and popfile restores the previous level.
10175 */
10176static void
10177pushfile(void)
10178{
10179 struct parsefile *pf;
10180
10181 pf = ckzalloc(sizeof(*pf));
10182 pf->prev = g_parsefile;
10183 pf->pf_fd = -1;
10184 /*pf->strpush = NULL; - ckzalloc did it */
10185 /*pf->basestrpush.prev = NULL;*/
10186 /*pf->unget = 0;*/
10187 g_parsefile = pf;
10188}
10189
10190static void
10191popfile(void)
10192{
10193 struct parsefile *pf = g_parsefile;
10194
10195 if (pf == &basepf)
10196 return;
10197
10198 INT_OFF;
10199 if (pf->pf_fd >= 0)
10200 close(pf->pf_fd);
10201 free(pf->buf);
10202 while (pf->strpush)
10203 popstring();
10204 g_parsefile = pf->prev;
10205 free(pf);
10206 INT_ON;
10207}
10208
10209/*
10210 * Return to top level.
10211 */
10212static void
10213popallfiles(void)
10214{
10215 while (g_parsefile != &basepf)
10216 popfile();
10217}
10218
10219/*
10220 * Close the file(s) that the shell is reading commands from. Called
10221 * after a fork is done.
10222 */
10223static void
10224closescript(void)
10225{
10226 popallfiles();
10227 if (g_parsefile->pf_fd > 0) {
10228 close(g_parsefile->pf_fd);
10229 g_parsefile->pf_fd = 0;
10230 }
10231}
10232
10233/*
10234 * Like setinputfile, but takes an open file descriptor. Call this with
10235 * interrupts off.
10236 */
10237static void
10238setinputfd(int fd, int push)
10239{
10240 if (push) {
10241 pushfile();
10242 g_parsefile->buf = NULL;
10243 }
10244 g_parsefile->pf_fd = fd;
10245 if (g_parsefile->buf == NULL)
10246 g_parsefile->buf = ckmalloc(IBUFSIZ);
10247 g_parsefile->left_in_buffer = 0;
10248 g_parsefile->left_in_line = 0;
10249 g_parsefile->linno = 1;
10250}
10251
10252/*
10253 * Set the input to take input from a file. If push is set, push the
10254 * old input onto the stack first.
10255 */
10256static int
10257setinputfile(const char *fname, int flags)
10258{
10259 int fd;
10260
10261 INT_OFF;
10262 fd = open(fname, O_RDONLY);
10263 if (fd < 0) {
10264 if (flags & INPUT_NOFILE_OK)
10265 goto out;
10266 exitstatus = 127;
10267 ash_msg_and_raise_error("can't open '%s'", fname);
10268 }
10269 if (fd < 10)
10270 fd = savefd(fd);
10271 else
10272 close_on_exec_on(fd);
10273 setinputfd(fd, flags & INPUT_PUSH_FILE);
10274 out:
10275 INT_ON;
10276 return fd;
10277}
10278
10279/*
10280 * Like setinputfile, but takes input from a string.
10281 */
10282static void
10283setinputstring(char *string)
10284{
10285 INT_OFF;
10286 pushfile();
10287 g_parsefile->next_to_pgetc = string;
10288 g_parsefile->left_in_line = strlen(string);
10289 g_parsefile->buf = NULL;
10290 g_parsefile->linno = 1;
10291 INT_ON;
10292}
10293
10294
10295/*
10296 * Routines to check for mail.
10297 */
10298
10299#if ENABLE_ASH_MAIL
10300
10301/* Hash of mtimes of mailboxes */
10302static unsigned mailtime_hash;
10303/* Set if MAIL or MAILPATH is changed. */
10304static smallint mail_var_path_changed;
10305
10306/*
10307 * Print appropriate message(s) if mail has arrived.
10308 * If mail_var_path_changed is set,
10309 * then the value of MAIL has mail_var_path_changed,
10310 * so we just update the values.
10311 */
10312static void
10313chkmail(void)
10314{
10315 const char *mpath;
10316 char *p;
10317 char *q;
10318 unsigned new_hash;
10319 struct stackmark smark;
10320 struct stat statb;
10321
10322 setstackmark(&smark);
10323 mpath = mpathset() ? mpathval() : mailval();
10324 new_hash = 0;
10325 for (;;) {
10326 p = path_advance(&mpath, nullstr);
10327 if (p == NULL)
10328 break;
10329 if (*p == '\0')
10330 continue;
10331 for (q = p; *q; q++)
10332 continue;
10333#if DEBUG
10334 if (q[-1] != '/')
10335 abort();
10336#endif
10337 q[-1] = '\0'; /* delete trailing '/' */
10338 if (stat(p, &statb) < 0) {
10339 continue;
10340 }
10341 /* Very simplistic "hash": just a sum of all mtimes */
10342 new_hash += (unsigned)statb.st_mtime;
10343 }
10344 if (!mail_var_path_changed && mailtime_hash != new_hash) {
10345 if (mailtime_hash != 0)
10346 out2str("you have mail\n");
10347 mailtime_hash = new_hash;
10348 }
10349 mail_var_path_changed = 0;
10350 popstackmark(&smark);
10351}
10352
10353static void FAST_FUNC
10354changemail(const char *val UNUSED_PARAM)
10355{
10356 mail_var_path_changed = 1;
10357}
10358
10359#endif /* ASH_MAIL */
10360
10361
10362/* ============ ??? */
10363
10364/*
10365 * Set the shell parameters.
10366 */
10367static void
10368setparam(char **argv)
10369{
10370 char **newparam;
10371 char **ap;
10372 int nparam;
10373
10374 for (nparam = 0; argv[nparam]; nparam++)
10375 continue;
10376 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10377 while (*argv) {
10378 *ap++ = ckstrdup(*argv++);
10379 }
10380 *ap = NULL;
10381 freeparam(&shellparam);
10382 shellparam.malloced = 1;
10383 shellparam.nparam = nparam;
10384 shellparam.p = newparam;
10385#if ENABLE_ASH_GETOPTS
10386 shellparam.optind = 1;
10387 shellparam.optoff = -1;
10388#endif
10389}
10390
10391/*
10392 * Process shell options. The global variable argptr contains a pointer
10393 * to the argument list; we advance it past the options.
10394 *
10395 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10396 * For a non-interactive shell, an error condition encountered
10397 * by a special built-in ... shall cause the shell to write a diagnostic message
10398 * to standard error and exit as shown in the following table:
10399 * Error Special Built-In
10400 * ...
10401 * Utility syntax error (option or operand error) Shall exit
10402 * ...
10403 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10404 * we see that bash does not do that (set "finishes" with error code 1 instead,
10405 * and shell continues), and people rely on this behavior!
10406 * Testcase:
10407 * set -o barfoo 2>/dev/null
10408 * echo $?
10409 *
10410 * Oh well. Let's mimic that.
10411 */
10412static int
10413plus_minus_o(char *name, int val)
10414{
10415 int i;
10416
10417 if (name) {
10418 for (i = 0; i < NOPTS; i++) {
10419 if (strcmp(name, optnames(i)) == 0) {
10420 optlist[i] = val;
10421 return 0;
10422 }
10423 }
10424 ash_msg("illegal option %co %s", val ? '-' : '+', name);
10425 return 1;
10426 }
10427 for (i = 0; i < NOPTS; i++) {
10428 if (val) {
10429 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10430 } else {
10431 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10432 }
10433 }
10434 return 0;
10435}
10436static void
10437setoption(int flag, int val)
10438{
10439 int i;
10440
10441 for (i = 0; i < NOPTS; i++) {
10442 if (optletters(i) == flag) {
10443 optlist[i] = val;
10444 return;
10445 }
10446 }
10447 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
10448 /* NOTREACHED */
10449}
10450static int
10451options(int cmdline)
10452{
10453 char *p;
10454 int val;
10455 int c;
10456
10457 if (cmdline)
10458 minusc = NULL;
10459 while ((p = *argptr) != NULL) {
10460 c = *p++;
10461 if (c != '-' && c != '+')
10462 break;
10463 argptr++;
10464 val = 0; /* val = 0 if c == '+' */
10465 if (c == '-') {
10466 val = 1;
10467 if (p[0] == '\0' || LONE_DASH(p)) {
10468 if (!cmdline) {
10469 /* "-" means turn off -x and -v */
10470 if (p[0] == '\0')
10471 xflag = vflag = 0;
10472 /* "--" means reset params */
10473 else if (*argptr == NULL)
10474 setparam(argptr);
10475 }
10476 break; /* "-" or "--" terminates options */
10477 }
10478 }
10479 /* first char was + or - */
10480 while ((c = *p++) != '\0') {
10481 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
10482 if (c == 'c' && cmdline) {
10483 minusc = p; /* command is after shell args */
10484 } else if (c == 'o') {
10485 if (plus_minus_o(*argptr, val)) {
10486 /* it already printed err message */
10487 return 1; /* error */
10488 }
10489 if (*argptr)
10490 argptr++;
10491 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10492 isloginsh = 1;
10493 /* bash does not accept +-login, we also won't */
10494 } else if (cmdline && val && (c == '-')) { /* long options */
10495 if (strcmp(p, "login") == 0)
10496 isloginsh = 1;
10497 break;
10498 } else {
10499 setoption(c, val);
10500 }
10501 }
10502 }
10503 return 0;
10504}
10505
10506/*
10507 * The shift builtin command.
10508 */
10509static int FAST_FUNC
10510shiftcmd(int argc UNUSED_PARAM, char **argv)
10511{
10512 int n;
10513 char **ap1, **ap2;
10514
10515 n = 1;
10516 if (argv[1])
10517 n = number(argv[1]);
10518 if (n > shellparam.nparam)
10519 n = 0; /* bash compat, was = shellparam.nparam; */
10520 INT_OFF;
10521 shellparam.nparam -= n;
10522 for (ap1 = shellparam.p; --n >= 0; ap1++) {
10523 if (shellparam.malloced)
10524 free(*ap1);
10525 }
10526 ap2 = shellparam.p;
10527 while ((*ap2++ = *ap1++) != NULL)
10528 continue;
10529#if ENABLE_ASH_GETOPTS
10530 shellparam.optind = 1;
10531 shellparam.optoff = -1;
10532#endif
10533 INT_ON;
10534 return 0;
10535}
10536
10537/*
10538 * POSIX requires that 'set' (but not export or readonly) output the
10539 * variables in lexicographic order - by the locale's collating order (sigh).
10540 * Maybe we could keep them in an ordered balanced binary tree
10541 * instead of hashed lists.
10542 * For now just roll 'em through qsort for printing...
10543 */
10544static int
10545showvars(const char *sep_prefix, int on, int off)
10546{
10547 const char *sep;
10548 char **ep, **epend;
10549
10550 ep = listvars(on, off, &epend);
10551 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10552
10553 sep = *sep_prefix ? " " : sep_prefix;
10554
10555 for (; ep < epend; ep++) {
10556 const char *p;
10557 const char *q;
10558
10559 p = strchrnul(*ep, '=');
10560 q = nullstr;
10561 if (*p)
10562 q = single_quote(++p);
10563 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10564 }
10565 return 0;
10566}
10567
10568/*
10569 * The set command builtin.
10570 */
10571static int FAST_FUNC
10572setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
10573{
10574 int retval;
10575
10576 if (!argv[1])
10577 return showvars(nullstr, 0, VUNSET);
10578
10579 INT_OFF;
10580 retval = options(/*cmdline:*/ 0);
10581 if (retval == 0) { /* if no parse error... */
10582 optschanged();
10583 if (*argptr != NULL) {
10584 setparam(argptr);
10585 }
10586 }
10587 INT_ON;
10588 return retval;
10589}
10590
10591#if ENABLE_ASH_RANDOM_SUPPORT
10592static void FAST_FUNC
10593change_random(const char *value)
10594{
10595 uint32_t t;
10596
10597 if (value == NULL) {
10598 /* "get", generate */
10599 t = next_random(&random_gen);
10600 /* set without recursion */
10601 setvar(vrandom.var_text, utoa(t), VNOFUNC);
10602 vrandom.flags &= ~VNOFUNC;
10603 } else {
10604 /* set/reset */
10605 t = strtoul(value, NULL, 10);
10606 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
10607 }
10608}
10609#endif
10610
10611#if ENABLE_ASH_GETOPTS
10612static int
10613getopts(char *optstr, char *optvar, char **optfirst)
10614{
10615 char *p, *q;
10616 char c = '?';
10617 int done = 0;
10618 char sbuf[2];
10619 char **optnext;
10620 int ind = shellparam.optind;
10621 int off = shellparam.optoff;
10622
10623 sbuf[1] = '\0';
10624
10625 shellparam.optind = -1;
10626 optnext = optfirst + ind - 1;
10627
10628 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
10629 p = NULL;
10630 else
10631 p = optnext[-1] + off;
10632 if (p == NULL || *p == '\0') {
10633 /* Current word is done, advance */
10634 p = *optnext;
10635 if (p == NULL || *p != '-' || *++p == '\0') {
10636 atend:
10637 p = NULL;
10638 done = 1;
10639 goto out;
10640 }
10641 optnext++;
10642 if (LONE_DASH(p)) /* check for "--" */
10643 goto atend;
10644 }
10645
10646 c = *p++;
10647 for (q = optstr; *q != c;) {
10648 if (*q == '\0') {
10649 if (optstr[0] == ':') {
10650 sbuf[0] = c;
10651 /*sbuf[1] = '\0'; - already is */
10652 setvar0("OPTARG", sbuf);
10653 } else {
10654 fprintf(stderr, "Illegal option -%c\n", c);
10655 unsetvar("OPTARG");
10656 }
10657 c = '?';
10658 goto out;
10659 }
10660 if (*++q == ':')
10661 q++;
10662 }
10663
10664 if (*++q == ':') {
10665 if (*p == '\0' && (p = *optnext) == NULL) {
10666 if (optstr[0] == ':') {
10667 sbuf[0] = c;
10668 /*sbuf[1] = '\0'; - already is */
10669 setvar0("OPTARG", sbuf);
10670 c = ':';
10671 } else {
10672 fprintf(stderr, "No arg for -%c option\n", c);
10673 unsetvar("OPTARG");
10674 c = '?';
10675 }
10676 goto out;
10677 }
10678
10679 if (p == *optnext)
10680 optnext++;
10681 setvar0("OPTARG", p);
10682 p = NULL;
10683 } else
10684 setvar0("OPTARG", nullstr);
10685 out:
10686 ind = optnext - optfirst + 1;
10687 setvar("OPTIND", itoa(ind), VNOFUNC);
10688 sbuf[0] = c;
10689 /*sbuf[1] = '\0'; - already is */
10690 setvar0(optvar, sbuf);
10691
10692 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10693 shellparam.optind = ind;
10694
10695 return done;
10696}
10697
10698/*
10699 * The getopts builtin. Shellparam.optnext points to the next argument
10700 * to be processed. Shellparam.optptr points to the next character to
10701 * be processed in the current argument. If shellparam.optnext is NULL,
10702 * then it's the first time getopts has been called.
10703 */
10704static int FAST_FUNC
10705getoptscmd(int argc, char **argv)
10706{
10707 char **optbase;
10708
10709 if (argc < 3)
10710 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
10711 if (argc == 3) {
10712 optbase = shellparam.p;
10713 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
10714 shellparam.optind = 1;
10715 shellparam.optoff = -1;
10716 }
10717 } else {
10718 optbase = &argv[3];
10719 if ((unsigned)shellparam.optind > argc - 2) {
10720 shellparam.optind = 1;
10721 shellparam.optoff = -1;
10722 }
10723 }
10724
10725 return getopts(argv[1], argv[2], optbase);
10726}
10727#endif /* ASH_GETOPTS */
10728
10729
10730/* ============ Shell parser */
10731
10732struct heredoc {
10733 struct heredoc *next; /* next here document in list */
10734 union node *here; /* redirection node */
10735 char *eofmark; /* string indicating end of input */
10736 smallint striptabs; /* if set, strip leading tabs */
10737};
10738
10739static smallint tokpushback; /* last token pushed back */
10740static smallint quoteflag; /* set if (part of) last token was quoted */
10741static token_id_t lasttoken; /* last token read (integer id Txxx) */
10742static struct heredoc *heredoclist; /* list of here documents to read */
10743static char *wordtext; /* text of last word returned by readtoken */
10744static struct nodelist *backquotelist;
10745static union node *redirnode;
10746static struct heredoc *heredoc;
10747
10748static const char *
10749tokname(char *buf, int tok)
10750{
10751 if (tok < TSEMI)
10752 return tokname_array[tok];
10753 sprintf(buf, "\"%s\"", tokname_array[tok]);
10754 return buf;
10755}
10756
10757/* raise_error_unexpected_syntax:
10758 * Called when an unexpected token is read during the parse. The argument
10759 * is the token that is expected, or -1 if more than one type of token can
10760 * occur at this point.
10761 */
10762static void raise_error_unexpected_syntax(int) NORETURN;
10763static void
10764raise_error_unexpected_syntax(int token)
10765{
10766 char msg[64];
10767 char buf[16];
10768 int l;
10769
10770 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
10771 if (token >= 0)
10772 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
10773 raise_error_syntax(msg);
10774 /* NOTREACHED */
10775}
10776
10777#define EOFMARKLEN 79
10778
10779/* parsing is heavily cross-recursive, need these forward decls */
10780static union node *andor(void);
10781static union node *pipeline(void);
10782static union node *parse_command(void);
10783static void parseheredoc(void);
10784static int peektoken(void);
10785static int readtoken(void);
10786
10787static union node *
10788list(int nlflag)
10789{
10790 union node *n1, *n2, *n3;
10791 int tok;
10792
10793 n1 = NULL;
10794 for (;;) {
10795 switch (peektoken()) {
10796 case TNL:
10797 if (!(nlflag & 1))
10798 break;
10799 parseheredoc();
10800 return n1;
10801
10802 case TEOF:
10803 if (!n1 && (nlflag & 1))
10804 n1 = NODE_EOF;
10805 parseheredoc();
10806 return n1;
10807 }
10808
10809 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10810 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
10811 return n1;
10812 nlflag |= 2;
10813
10814 n2 = andor();
10815 tok = readtoken();
10816 if (tok == TBACKGND) {
10817 if (n2->type == NPIPE) {
10818 n2->npipe.pipe_backgnd = 1;
10819 } else {
10820 if (n2->type != NREDIR) {
10821 n3 = stzalloc(sizeof(struct nredir));
10822 n3->nredir.n = n2;
10823 /*n3->nredir.redirect = NULL; - stzalloc did it */
10824 n2 = n3;
10825 }
10826 n2->type = NBACKGND;
10827 }
10828 }
10829 if (n1 == NULL) {
10830 n1 = n2;
10831 } else {
10832 n3 = stzalloc(sizeof(struct nbinary));
10833 n3->type = NSEMI;
10834 n3->nbinary.ch1 = n1;
10835 n3->nbinary.ch2 = n2;
10836 n1 = n3;
10837 }
10838 switch (tok) {
10839 case TNL:
10840 case TEOF:
10841 tokpushback = 1;
10842 /* fall through */
10843 case TBACKGND:
10844 case TSEMI:
10845 break;
10846 default:
10847 if ((nlflag & 1))
10848 raise_error_unexpected_syntax(-1);
10849 tokpushback = 1;
10850 return n1;
10851 }
10852 }
10853}
10854
10855static union node *
10856andor(void)
10857{
10858 union node *n1, *n2, *n3;
10859 int t;
10860
10861 n1 = pipeline();
10862 for (;;) {
10863 t = readtoken();
10864 if (t == TAND) {
10865 t = NAND;
10866 } else if (t == TOR) {
10867 t = NOR;
10868 } else {
10869 tokpushback = 1;
10870 return n1;
10871 }
10872 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10873 n2 = pipeline();
10874 n3 = stzalloc(sizeof(struct nbinary));
10875 n3->type = t;
10876 n3->nbinary.ch1 = n1;
10877 n3->nbinary.ch2 = n2;
10878 n1 = n3;
10879 }
10880}
10881
10882static union node *
10883pipeline(void)
10884{
10885 union node *n1, *n2, *pipenode;
10886 struct nodelist *lp, *prev;
10887 int negate;
10888
10889 negate = 0;
10890 TRACE(("pipeline: entered\n"));
10891 if (readtoken() == TNOT) {
10892 negate = !negate;
10893 checkkwd = CHKKWD | CHKALIAS;
10894 } else
10895 tokpushback = 1;
10896 n1 = parse_command();
10897 if (readtoken() == TPIPE) {
10898 pipenode = stzalloc(sizeof(struct npipe));
10899 pipenode->type = NPIPE;
10900 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10901 lp = stzalloc(sizeof(struct nodelist));
10902 pipenode->npipe.cmdlist = lp;
10903 lp->n = n1;
10904 do {
10905 prev = lp;
10906 lp = stzalloc(sizeof(struct nodelist));
10907 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10908 lp->n = parse_command();
10909 prev->next = lp;
10910 } while (readtoken() == TPIPE);
10911 lp->next = NULL;
10912 n1 = pipenode;
10913 }
10914 tokpushback = 1;
10915 if (negate) {
10916 n2 = stzalloc(sizeof(struct nnot));
10917 n2->type = NNOT;
10918 n2->nnot.com = n1;
10919 return n2;
10920 }
10921 return n1;
10922}
10923
10924static union node *
10925makename(void)
10926{
10927 union node *n;
10928
10929 n = stzalloc(sizeof(struct narg));
10930 n->type = NARG;
10931 /*n->narg.next = NULL; - stzalloc did it */
10932 n->narg.text = wordtext;
10933 n->narg.backquote = backquotelist;
10934 return n;
10935}
10936
10937static void
10938fixredir(union node *n, const char *text, int err)
10939{
10940 int fd;
10941
10942 TRACE(("Fix redir %s %d\n", text, err));
10943 if (!err)
10944 n->ndup.vname = NULL;
10945
10946 fd = bb_strtou(text, NULL, 10);
10947 if (!errno && fd >= 0)
10948 n->ndup.dupfd = fd;
10949 else if (LONE_DASH(text))
10950 n->ndup.dupfd = -1;
10951 else {
10952 if (err)
10953 raise_error_syntax("bad fd number");
10954 n->ndup.vname = makename();
10955 }
10956}
10957
10958/*
10959 * Returns true if the text contains nothing to expand (no dollar signs
10960 * or backquotes).
10961 */
10962static int
10963noexpand(const char *text)
10964{
10965 unsigned char c;
10966
10967 while ((c = *text++) != '\0') {
10968 if (c == CTLQUOTEMARK)
10969 continue;
10970 if (c == CTLESC)
10971 text++;
10972 else if (SIT(c, BASESYNTAX) == CCTL)
10973 return 0;
10974 }
10975 return 1;
10976}
10977
10978static void
10979parsefname(void)
10980{
10981 union node *n = redirnode;
10982
10983 if (readtoken() != TWORD)
10984 raise_error_unexpected_syntax(-1);
10985 if (n->type == NHERE) {
10986 struct heredoc *here = heredoc;
10987 struct heredoc *p;
10988 int i;
10989
10990 if (quoteflag == 0)
10991 n->type = NXHERE;
10992 TRACE(("Here document %d\n", n->type));
10993 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10994 raise_error_syntax("illegal eof marker for << redirection");
10995 rmescapes(wordtext, 0);
10996 here->eofmark = wordtext;
10997 here->next = NULL;
10998 if (heredoclist == NULL)
10999 heredoclist = here;
11000 else {
11001 for (p = heredoclist; p->next; p = p->next)
11002 continue;
11003 p->next = here;
11004 }
11005 } else if (n->type == NTOFD || n->type == NFROMFD) {
11006 fixredir(n, wordtext, 0);
11007 } else {
11008 n->nfile.fname = makename();
11009 }
11010}
11011
11012static union node *
11013simplecmd(void)
11014{
11015 union node *args, **app;
11016 union node *n = NULL;
11017 union node *vars, **vpp;
11018 union node **rpp, *redir;
11019 int savecheckkwd;
11020#if ENABLE_ASH_BASH_COMPAT
11021 smallint double_brackets_flag = 0;
11022 smallint function_flag = 0;
11023#endif
11024
11025 args = NULL;
11026 app = &args;
11027 vars = NULL;
11028 vpp = &vars;
11029 redir = NULL;
11030 rpp = &redir;
11031
11032 savecheckkwd = CHKALIAS;
11033 for (;;) {
11034 int t;
11035 checkkwd = savecheckkwd;
11036 t = readtoken();
11037 switch (t) {
11038#if ENABLE_ASH_BASH_COMPAT
11039 case TFUNCTION:
11040 if (peektoken() != TWORD)
11041 raise_error_unexpected_syntax(TWORD);
11042 function_flag = 1;
11043 break;
11044 case TAND: /* "&&" */
11045 case TOR: /* "||" */
11046 if (!double_brackets_flag) {
11047 tokpushback = 1;
11048 goto out;
11049 }
11050 wordtext = (char *) (t == TAND ? "-a" : "-o");
11051#endif
11052 case TWORD:
11053 n = stzalloc(sizeof(struct narg));
11054 n->type = NARG;
11055 /*n->narg.next = NULL; - stzalloc did it */
11056 n->narg.text = wordtext;
11057#if ENABLE_ASH_BASH_COMPAT
11058 if (strcmp("[[", wordtext) == 0)
11059 double_brackets_flag = 1;
11060 else if (strcmp("]]", wordtext) == 0)
11061 double_brackets_flag = 0;
11062#endif
11063 n->narg.backquote = backquotelist;
11064 if (savecheckkwd && isassignment(wordtext)) {
11065 *vpp = n;
11066 vpp = &n->narg.next;
11067 } else {
11068 *app = n;
11069 app = &n->narg.next;
11070 savecheckkwd = 0;
11071 }
11072#if ENABLE_ASH_BASH_COMPAT
11073 if (function_flag) {
11074 checkkwd = CHKNL | CHKKWD;
11075 switch (peektoken()) {
11076 case TBEGIN:
11077 case TIF:
11078 case TCASE:
11079 case TUNTIL:
11080 case TWHILE:
11081 case TFOR:
11082 goto do_func;
11083 case TLP:
11084 function_flag = 0;
11085 break;
11086 case TWORD:
11087 if (strcmp("[[", wordtext) == 0)
11088 goto do_func;
11089 /* fall through */
11090 default:
11091 raise_error_unexpected_syntax(-1);
11092 }
11093 }
11094#endif
11095 break;
11096 case TREDIR:
11097 *rpp = n = redirnode;
11098 rpp = &n->nfile.next;
11099 parsefname(); /* read name of redirection file */
11100 break;
11101 case TLP:
11102 IF_ASH_BASH_COMPAT(do_func:)
11103 if (args && app == &args->narg.next
11104 && !vars && !redir
11105 ) {
11106 struct builtincmd *bcmd;
11107 const char *name;
11108
11109 /* We have a function */
11110 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
11111 raise_error_unexpected_syntax(TRP);
11112 name = n->narg.text;
11113 if (!goodname(name)
11114 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11115 ) {
11116 raise_error_syntax("bad function name");
11117 }
11118 n->type = NDEFUN;
11119 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11120 n->narg.next = parse_command();
11121 return n;
11122 }
11123 IF_ASH_BASH_COMPAT(function_flag = 0;)
11124 /* fall through */
11125 default:
11126 tokpushback = 1;
11127 goto out;
11128 }
11129 }
11130 out:
11131 *app = NULL;
11132 *vpp = NULL;
11133 *rpp = NULL;
11134 n = stzalloc(sizeof(struct ncmd));
11135 n->type = NCMD;
11136 n->ncmd.args = args;
11137 n->ncmd.assign = vars;
11138 n->ncmd.redirect = redir;
11139 return n;
11140}
11141
11142static union node *
11143parse_command(void)
11144{
11145 union node *n1, *n2;
11146 union node *ap, **app;
11147 union node *cp, **cpp;
11148 union node *redir, **rpp;
11149 union node **rpp2;
11150 int t;
11151
11152 redir = NULL;
11153 rpp2 = &redir;
11154
11155 switch (readtoken()) {
11156 default:
11157 raise_error_unexpected_syntax(-1);
11158 /* NOTREACHED */
11159 case TIF:
11160 n1 = stzalloc(sizeof(struct nif));
11161 n1->type = NIF;
11162 n1->nif.test = list(0);
11163 if (readtoken() != TTHEN)
11164 raise_error_unexpected_syntax(TTHEN);
11165 n1->nif.ifpart = list(0);
11166 n2 = n1;
11167 while (readtoken() == TELIF) {
11168 n2->nif.elsepart = stzalloc(sizeof(struct nif));
11169 n2 = n2->nif.elsepart;
11170 n2->type = NIF;
11171 n2->nif.test = list(0);
11172 if (readtoken() != TTHEN)
11173 raise_error_unexpected_syntax(TTHEN);
11174 n2->nif.ifpart = list(0);
11175 }
11176 if (lasttoken == TELSE)
11177 n2->nif.elsepart = list(0);
11178 else {
11179 n2->nif.elsepart = NULL;
11180 tokpushback = 1;
11181 }
11182 t = TFI;
11183 break;
11184 case TWHILE:
11185 case TUNTIL: {
11186 int got;
11187 n1 = stzalloc(sizeof(struct nbinary));
11188 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
11189 n1->nbinary.ch1 = list(0);
11190 got = readtoken();
11191 if (got != TDO) {
11192 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
11193 got == TWORD ? wordtext : ""));
11194 raise_error_unexpected_syntax(TDO);
11195 }
11196 n1->nbinary.ch2 = list(0);
11197 t = TDONE;
11198 break;
11199 }
11200 case TFOR:
11201 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
11202 raise_error_syntax("bad for loop variable");
11203 n1 = stzalloc(sizeof(struct nfor));
11204 n1->type = NFOR;
11205 n1->nfor.var = wordtext;
11206 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11207 if (readtoken() == TIN) {
11208 app = &ap;
11209 while (readtoken() == TWORD) {
11210 n2 = stzalloc(sizeof(struct narg));
11211 n2->type = NARG;
11212 /*n2->narg.next = NULL; - stzalloc did it */
11213 n2->narg.text = wordtext;
11214 n2->narg.backquote = backquotelist;
11215 *app = n2;
11216 app = &n2->narg.next;
11217 }
11218 *app = NULL;
11219 n1->nfor.args = ap;
11220 if (lasttoken != TNL && lasttoken != TSEMI)
11221 raise_error_unexpected_syntax(-1);
11222 } else {
11223 n2 = stzalloc(sizeof(struct narg));
11224 n2->type = NARG;
11225 /*n2->narg.next = NULL; - stzalloc did it */
11226 n2->narg.text = (char *)dolatstr;
11227 /*n2->narg.backquote = NULL;*/
11228 n1->nfor.args = n2;
11229 /*
11230 * Newline or semicolon here is optional (but note
11231 * that the original Bourne shell only allowed NL).
11232 */
11233 if (lasttoken != TSEMI)
11234 tokpushback = 1;
11235 }
11236 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11237 if (readtoken() != TDO)
11238 raise_error_unexpected_syntax(TDO);
11239 n1->nfor.body = list(0);
11240 t = TDONE;
11241 break;
11242 case TCASE:
11243 n1 = stzalloc(sizeof(struct ncase));
11244 n1->type = NCASE;
11245 if (readtoken() != TWORD)
11246 raise_error_unexpected_syntax(TWORD);
11247 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
11248 n2->type = NARG;
11249 /*n2->narg.next = NULL; - stzalloc did it */
11250 n2->narg.text = wordtext;
11251 n2->narg.backquote = backquotelist;
11252 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11253 if (readtoken() != TIN)
11254 raise_error_unexpected_syntax(TIN);
11255 cpp = &n1->ncase.cases;
11256 next_case:
11257 checkkwd = CHKNL | CHKKWD;
11258 t = readtoken();
11259 while (t != TESAC) {
11260 if (lasttoken == TLP)
11261 readtoken();
11262 *cpp = cp = stzalloc(sizeof(struct nclist));
11263 cp->type = NCLIST;
11264 app = &cp->nclist.pattern;
11265 for (;;) {
11266 *app = ap = stzalloc(sizeof(struct narg));
11267 ap->type = NARG;
11268 /*ap->narg.next = NULL; - stzalloc did it */
11269 ap->narg.text = wordtext;
11270 ap->narg.backquote = backquotelist;
11271 if (readtoken() != TPIPE)
11272 break;
11273 app = &ap->narg.next;
11274 readtoken();
11275 }
11276 //ap->narg.next = NULL;
11277 if (lasttoken != TRP)
11278 raise_error_unexpected_syntax(TRP);
11279 cp->nclist.body = list(2);
11280
11281 cpp = &cp->nclist.next;
11282
11283 checkkwd = CHKNL | CHKKWD;
11284 t = readtoken();
11285 if (t != TESAC) {
11286 if (t != TENDCASE)
11287 raise_error_unexpected_syntax(TENDCASE);
11288 goto next_case;
11289 }
11290 }
11291 *cpp = NULL;
11292 goto redir;
11293 case TLP:
11294 n1 = stzalloc(sizeof(struct nredir));
11295 n1->type = NSUBSHELL;
11296 n1->nredir.n = list(0);
11297 /*n1->nredir.redirect = NULL; - stzalloc did it */
11298 t = TRP;
11299 break;
11300 case TBEGIN:
11301 n1 = list(0);
11302 t = TEND;
11303 break;
11304 IF_ASH_BASH_COMPAT(case TFUNCTION:)
11305 case TWORD:
11306 case TREDIR:
11307 tokpushback = 1;
11308 return simplecmd();
11309 }
11310
11311 if (readtoken() != t)
11312 raise_error_unexpected_syntax(t);
11313
11314 redir:
11315 /* Now check for redirection which may follow command */
11316 checkkwd = CHKKWD | CHKALIAS;
11317 rpp = rpp2;
11318 while (readtoken() == TREDIR) {
11319 *rpp = n2 = redirnode;
11320 rpp = &n2->nfile.next;
11321 parsefname();
11322 }
11323 tokpushback = 1;
11324 *rpp = NULL;
11325 if (redir) {
11326 if (n1->type != NSUBSHELL) {
11327 n2 = stzalloc(sizeof(struct nredir));
11328 n2->type = NREDIR;
11329 n2->nredir.n = n1;
11330 n1 = n2;
11331 }
11332 n1->nredir.redirect = redir;
11333 }
11334 return n1;
11335}
11336
11337#if ENABLE_ASH_BASH_COMPAT
11338static int
11339decode_dollar_squote(void)
11340{
11341 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11342 int c, cnt;
11343 char *p;
11344 char buf[4];
11345
11346 c = pgetc();
11347 p = strchr(C_escapes, c);
11348 if (p) {
11349 buf[0] = c;
11350 p = buf;
11351 cnt = 3;
11352 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11353 do {
11354 c = pgetc();
11355 *++p = c;
11356 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11357 pungetc();
11358 } else if (c == 'x') { /* \xHH */
11359 do {
11360 c = pgetc();
11361 *++p = c;
11362 } while (isxdigit(c) && --cnt);
11363 pungetc();
11364 if (cnt == 3) { /* \x but next char is "bad" */
11365 c = 'x';
11366 goto unrecognized;
11367 }
11368 } else { /* simple seq like \\ or \t */
11369 p++;
11370 }
11371 *p = '\0';
11372 p = buf;
11373 c = bb_process_escape_sequence((void*)&p);
11374 } else { /* unrecognized "\z": print both chars unless ' or " */
11375 if (c != '\'' && c != '"') {
11376 unrecognized:
11377 c |= 0x100; /* "please encode \, then me" */
11378 }
11379 }
11380 return c;
11381}
11382#endif
11383
11384/*
11385 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11386 * is not NULL, read a here document. In the latter case, eofmark is the
11387 * word which marks the end of the document and striptabs is true if
11388 * leading tabs should be stripped from the document. The argument c
11389 * is the first character of the input token or document.
11390 *
11391 * Because C does not have internal subroutines, I have simulated them
11392 * using goto's to implement the subroutine linkage. The following macros
11393 * will run code that appears at the end of readtoken1.
11394 */
11395#define CHECKEND() {goto checkend; checkend_return:;}
11396#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11397#define PARSESUB() {goto parsesub; parsesub_return:;}
11398#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11399#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11400#define PARSEARITH() {goto parsearith; parsearith_return:;}
11401static int
11402readtoken1(int c, int syntax, char *eofmark, int striptabs)
11403{
11404 /* NB: syntax parameter fits into smallint */
11405 /* c parameter is an unsigned char or PEOF or PEOA */
11406 char *out;
11407 size_t len;
11408 char line[EOFMARKLEN + 1];
11409 struct nodelist *bqlist;
11410 smallint quotef;
11411 smallint dblquote;
11412 smallint oldstyle;
11413 IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
11414#if ENABLE_ASH_EXPAND_PRMT
11415 smallint pssyntax; /* we are expanding a prompt string */
11416#endif
11417 int varnest; /* levels of variables expansion */
11418 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11419 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
11420 int dqvarnest; /* levels of variables expansion within double quotes */
11421
11422 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
11423
11424 startlinno = g_parsefile->linno;
11425 bqlist = NULL;
11426 quotef = 0;
11427 IF_FEATURE_SH_MATH(prevsyntax = 0;)
11428#if ENABLE_ASH_EXPAND_PRMT
11429 pssyntax = (syntax == PSSYNTAX);
11430 if (pssyntax)
11431 syntax = DQSYNTAX;
11432#endif
11433 dblquote = (syntax == DQSYNTAX);
11434 varnest = 0;
11435 IF_FEATURE_SH_MATH(arinest = 0;)
11436 IF_FEATURE_SH_MATH(parenlevel = 0;)
11437 dqvarnest = 0;
11438
11439 STARTSTACKSTR(out);
11440 loop:
11441 /* For each line, until end of word */
11442 CHECKEND(); /* set c to PEOF if at end of here document */
11443 for (;;) { /* until end of line or end of word */
11444 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11445 switch (SIT(c, syntax)) {
11446 case CNL: /* '\n' */
11447 if (syntax == BASESYNTAX)
11448 goto endword; /* exit outer loop */
11449 USTPUTC(c, out);
11450 nlprompt();
11451 c = pgetc();
11452 goto loop; /* continue outer loop */
11453 case CWORD:
11454 USTPUTC(c, out);
11455 break;
11456 case CCTL:
11457#if ENABLE_ASH_BASH_COMPAT
11458 if (c == '\\' && bash_dollar_squote) {
11459 c = decode_dollar_squote();
11460 if (c == '\0') {
11461 /* skip $'\000', $'\x00' (like bash) */
11462 break;
11463 }
11464 if (c & 0x100) {
11465 /* Unknown escape. Encode as '\z' */
11466 c = (unsigned char)c;
11467 if (eofmark == NULL || dblquote)
11468 USTPUTC(CTLESC, out);
11469 USTPUTC('\\', out);
11470 }
11471 }
11472#endif
11473 if (eofmark == NULL || dblquote)
11474 USTPUTC(CTLESC, out);
11475 USTPUTC(c, out);
11476 break;
11477 case CBACK: /* backslash */
11478 c = pgetc_without_PEOA();
11479 if (c == PEOF) {
11480 USTPUTC(CTLESC, out);
11481 USTPUTC('\\', out);
11482 pungetc();
11483 } else if (c == '\n') {
11484 nlprompt();
11485 } else {
11486#if ENABLE_ASH_EXPAND_PRMT
11487 if (c == '$' && pssyntax) {
11488 USTPUTC(CTLESC, out);
11489 USTPUTC('\\', out);
11490 }
11491#endif
11492 /* Backslash is retained if we are in "str" and next char isn't special */
11493 if (dblquote
11494 && c != '\\'
11495 && c != '`'
11496 && c != '$'
11497 && (c != '"' || eofmark != NULL)
11498 ) {
11499 USTPUTC('\\', out);
11500 }
11501 USTPUTC(CTLESC, out);
11502 USTPUTC(c, out);
11503 quotef = 1;
11504 }
11505 break;
11506 case CSQUOTE:
11507 syntax = SQSYNTAX;
11508 quotemark:
11509 if (eofmark == NULL) {
11510 USTPUTC(CTLQUOTEMARK, out);
11511 }
11512 break;
11513 case CDQUOTE:
11514 syntax = DQSYNTAX;
11515 dblquote = 1;
11516 goto quotemark;
11517 case CENDQUOTE:
11518 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
11519 if (eofmark != NULL && varnest == 0) {
11520 USTPUTC(c, out);
11521 } else {
11522 if (dqvarnest == 0) {
11523 syntax = BASESYNTAX;
11524 dblquote = 0;
11525 }
11526 quotef = 1;
11527 goto quotemark;
11528 }
11529 break;
11530 case CVAR: /* '$' */
11531 PARSESUB(); /* parse substitution */
11532 break;
11533 case CENDVAR: /* '}' */
11534 if (varnest > 0) {
11535 varnest--;
11536 if (dqvarnest > 0) {
11537 dqvarnest--;
11538 }
11539 c = CTLENDVAR;
11540 }
11541 USTPUTC(c, out);
11542 break;
11543#if ENABLE_FEATURE_SH_MATH
11544 case CLP: /* '(' in arithmetic */
11545 parenlevel++;
11546 USTPUTC(c, out);
11547 break;
11548 case CRP: /* ')' in arithmetic */
11549 if (parenlevel > 0) {
11550 parenlevel--;
11551 } else {
11552 if (pgetc_eatbnl() == ')') {
11553 c = CTLENDARI;
11554 if (--arinest == 0) {
11555 syntax = prevsyntax;
11556 }
11557 } else {
11558 /*
11559 * unbalanced parens
11560 * (don't 2nd guess - no error)
11561 */
11562 pungetc();
11563 }
11564 }
11565 USTPUTC(c, out);
11566 break;
11567#endif
11568 case CBQUOTE: /* '`' */
11569 PARSEBACKQOLD();
11570 break;
11571 case CENDFILE:
11572 goto endword; /* exit outer loop */
11573 case CIGN:
11574 break;
11575 default:
11576 if (varnest == 0) {
11577#if ENABLE_ASH_BASH_COMPAT
11578 if (c == '&') {
11579//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
11580 if (pgetc() == '>')
11581 c = 0x100 + '>'; /* flag &> */
11582 pungetc();
11583 }
11584#endif
11585 goto endword; /* exit outer loop */
11586 }
11587 IF_ASH_ALIAS(if (c != PEOA))
11588 USTPUTC(c, out);
11589 }
11590 c = pgetc();
11591 } /* for (;;) */
11592 endword:
11593
11594#if ENABLE_FEATURE_SH_MATH
11595 if (syntax == ARISYNTAX)
11596 raise_error_syntax("missing '))'");
11597#endif
11598 if (syntax != BASESYNTAX && eofmark == NULL)
11599 raise_error_syntax("unterminated quoted string");
11600 if (varnest != 0) {
11601 startlinno = g_parsefile->linno;
11602 /* { */
11603 raise_error_syntax("missing '}'");
11604 }
11605 USTPUTC('\0', out);
11606 len = out - (char *)stackblock();
11607 out = stackblock();
11608 if (eofmark == NULL) {
11609 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
11610 && quotef == 0
11611 ) {
11612 if (isdigit_str9(out)) {
11613 PARSEREDIR(); /* passed as params: out, c */
11614 lasttoken = TREDIR;
11615 return lasttoken;
11616 }
11617 /* else: non-number X seen, interpret it
11618 * as "NNNX>file" = "NNNX >file" */
11619 }
11620 pungetc();
11621 }
11622 quoteflag = quotef;
11623 backquotelist = bqlist;
11624 grabstackblock(len);
11625 wordtext = out;
11626 lasttoken = TWORD;
11627 return lasttoken;
11628/* end of readtoken routine */
11629
11630/*
11631 * Check to see whether we are at the end of the here document. When this
11632 * is called, c is set to the first character of the next input line. If
11633 * we are at the end of the here document, this routine sets the c to PEOF.
11634 */
11635checkend: {
11636 if (eofmark) {
11637#if ENABLE_ASH_ALIAS
11638 if (c == PEOA)
11639 c = pgetc_without_PEOA();
11640#endif
11641 if (striptabs) {
11642 while (c == '\t') {
11643 c = pgetc_without_PEOA();
11644 }
11645 }
11646 if (c == *eofmark) {
11647 if (pfgets(line, sizeof(line)) != NULL) {
11648 char *p, *q;
11649 int cc;
11650
11651 p = line;
11652 for (q = eofmark + 1;; p++, q++) {
11653 cc = *p;
11654 if (cc == '\n')
11655 cc = 0;
11656 if (!*q || cc != *q)
11657 break;
11658 }
11659 if (cc == *q) {
11660 c = PEOF;
11661 nlnoprompt();
11662 } else {
11663 pushstring(line, NULL);
11664 }
11665 }
11666 }
11667 }
11668 goto checkend_return;
11669}
11670
11671/*
11672 * Parse a redirection operator. The variable "out" points to a string
11673 * specifying the fd to be redirected. The variable "c" contains the
11674 * first character of the redirection operator.
11675 */
11676parseredir: {
11677 /* out is already checked to be a valid number or "" */
11678 int fd = (*out == '\0' ? -1 : atoi(out));
11679 union node *np;
11680
11681 np = stzalloc(sizeof(struct nfile));
11682 if (c == '>') {
11683 np->nfile.fd = 1;
11684 c = pgetc();
11685 if (c == '>')
11686 np->type = NAPPEND;
11687 else if (c == '|')
11688 np->type = NCLOBBER;
11689 else if (c == '&')
11690 np->type = NTOFD;
11691 /* it also can be NTO2 (>&file), but we can't figure it out yet */
11692 else {
11693 np->type = NTO;
11694 pungetc();
11695 }
11696 }
11697#if ENABLE_ASH_BASH_COMPAT
11698 else if (c == 0x100 + '>') { /* this flags &> redirection */
11699 np->nfile.fd = 1;
11700 pgetc(); /* this is '>', no need to check */
11701 np->type = NTO2;
11702 }
11703#endif
11704 else { /* c == '<' */
11705 /*np->nfile.fd = 0; - stzalloc did it */
11706 c = pgetc();
11707 switch (c) {
11708 case '<':
11709 if (sizeof(struct nfile) != sizeof(struct nhere)) {
11710 np = stzalloc(sizeof(struct nhere));
11711 /*np->nfile.fd = 0; - stzalloc did it */
11712 }
11713 np->type = NHERE;
11714 heredoc = stzalloc(sizeof(struct heredoc));
11715 heredoc->here = np;
11716 c = pgetc();
11717 if (c == '-') {
11718 heredoc->striptabs = 1;
11719 } else {
11720 /*heredoc->striptabs = 0; - stzalloc did it */
11721 pungetc();
11722 }
11723 break;
11724
11725 case '&':
11726 np->type = NFROMFD;
11727 break;
11728
11729 case '>':
11730 np->type = NFROMTO;
11731 break;
11732
11733 default:
11734 np->type = NFROM;
11735 pungetc();
11736 break;
11737 }
11738 }
11739 if (fd >= 0)
11740 np->nfile.fd = fd;
11741 redirnode = np;
11742 goto parseredir_return;
11743}
11744
11745/*
11746 * Parse a substitution. At this point, we have read the dollar sign
11747 * and nothing else.
11748 */
11749
11750/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11751 * (assuming ascii char codes, as the original implementation did) */
11752#define is_special(c) \
11753 (((unsigned)(c) - 33 < 32) \
11754 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
11755parsesub: {
11756 unsigned char subtype;
11757 int typeloc;
11758
11759 c = pgetc_eatbnl();
11760 if (c > 255 /* PEOA or PEOF */
11761 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
11762 ) {
11763#if ENABLE_ASH_BASH_COMPAT
11764 if (syntax != DQSYNTAX && c == '\'')
11765 bash_dollar_squote = 1;
11766 else
11767#endif
11768 USTPUTC('$', out);
11769 pungetc();
11770 } else if (c == '(') {
11771 /* $(command) or $((arith)) */
11772 if (pgetc_eatbnl() == '(') {
11773#if ENABLE_FEATURE_SH_MATH
11774 PARSEARITH();
11775#else
11776 raise_error_syntax("you disabled math support for $((arith)) syntax");
11777#endif
11778 } else {
11779 pungetc();
11780 PARSEBACKQNEW();
11781 }
11782 } else {
11783 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
11784 USTPUTC(CTLVAR, out);
11785 typeloc = out - (char *)stackblock();
11786 STADJUST(1, out);
11787 subtype = VSNORMAL;
11788 if (c == '{') {
11789 c = pgetc_eatbnl();
11790 subtype = 0;
11791 }
11792 varname:
11793 if (is_name(c)) {
11794 /* $[{[#]]NAME[}] */
11795 do {
11796 STPUTC(c, out);
11797 c = pgetc_eatbnl();
11798 } while (is_in_name(c));
11799 } else if (isdigit(c)) {
11800 /* $[{[#]]NUM[}] */
11801 do {
11802 STPUTC(c, out);
11803 c = pgetc_eatbnl();
11804 } while (isdigit(c));
11805 } else if (is_special(c)) {
11806 /* $[{[#]]<specialchar>[}] */
11807 int cc = c;
11808
11809 c = pgetc_eatbnl();
11810 if (!subtype && cc == '#') {
11811 subtype = VSLENGTH;
11812 if (c == '_' || isalnum(c))
11813 goto varname;
11814 cc = c;
11815 c = pgetc_eatbnl();
11816 if (cc == '}' || c != '}') {
11817 pungetc();
11818 subtype = 0;
11819 c = cc;
11820 cc = '#';
11821 }
11822 }
11823 USTPUTC(cc, out);
11824 } else {
11825 goto badsub;
11826 }
11827 if (c != '}' && subtype == VSLENGTH) {
11828 /* ${#VAR didn't end with } */
11829 goto badsub;
11830 }
11831
11832 if (subtype == 0) {
11833 static const char types[] ALIGN1 = "}-+?=";
11834 /* ${VAR...} but not $VAR or ${#VAR} */
11835 /* c == first char after VAR */
11836 switch (c) {
11837 case ':':
11838 c = pgetc_eatbnl();
11839#if ENABLE_ASH_BASH_COMPAT
11840 /* This check is only needed to not misinterpret
11841 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11842 * constructs.
11843 */
11844 if (!strchr(types, c)) {
11845 subtype = VSSUBSTR;
11846 pungetc();
11847 break; /* "goto badsub" is bigger (!) */
11848 }
11849#endif
11850 subtype = VSNUL;
11851 /*FALLTHROUGH*/
11852 default: {
11853 const char *p = strchr(types, c);
11854 if (p == NULL)
11855 break;
11856 subtype |= p - types + VSNORMAL;
11857 break;
11858 }
11859 case '%':
11860 case '#': {
11861 int cc = c;
11862 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
11863 c = pgetc_eatbnl();
11864 if (c != cc)
11865 goto badsub;
11866 subtype++;
11867 break;
11868 }
11869#if ENABLE_ASH_BASH_COMPAT
11870 case '/':
11871 /* ${v/[/]pattern/repl} */
11872//TODO: encode pattern and repl separately.
11873// Currently ${v/$var_with_slash/repl} is horribly broken
11874 subtype = VSREPLACE;
11875 c = pgetc_eatbnl();
11876 if (c != '/')
11877 goto badsub;
11878 subtype++; /* VSREPLACEALL */
11879 break;
11880#endif
11881 }
11882 } else {
11883 badsub:
11884 pungetc();
11885 }
11886 ((unsigned char *)stackblock())[typeloc] = subtype;
11887 if (subtype != VSNORMAL) {
11888 varnest++;
11889 if (dblquote)
11890 dqvarnest++;
11891 }
11892 STPUTC('=', out);
11893 }
11894 goto parsesub_return;
11895}
11896
11897/*
11898 * Called to parse command substitutions. Newstyle is set if the command
11899 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11900 * list of commands (passed by reference), and savelen is the number of
11901 * characters on the top of the stack which must be preserved.
11902 */
11903parsebackq: {
11904 struct nodelist **nlpp;
11905 union node *n;
11906 char *str;
11907 size_t savelen;
11908 smallint saveprompt = 0;
11909
11910 str = NULL;
11911 savelen = out - (char *)stackblock();
11912 if (savelen > 0) {
11913 /*
11914 * FIXME: this can allocate very large block on stack and SEGV.
11915 * Example:
11916 * echo "..<100kbytes>..`true` $(true) `true` ..."
11917 * allocates 100kb for every command subst. With about
11918 * a hundred command substitutions stack overflows.
11919 * With larger prepended string, SEGV happens sooner.
11920 */
11921 str = alloca(savelen);
11922 memcpy(str, stackblock(), savelen);
11923 }
11924
11925 if (oldstyle) {
11926 /* We must read until the closing backquote, giving special
11927 * treatment to some slashes, and then push the string and
11928 * reread it as input, interpreting it normally.
11929 */
11930 char *pout;
11931 size_t psavelen;
11932 char *pstr;
11933
11934 STARTSTACKSTR(pout);
11935 for (;;) {
11936 int pc;
11937
11938 setprompt_if(needprompt, 2);
11939 pc = pgetc();
11940 switch (pc) {
11941 case '`':
11942 goto done;
11943
11944 case '\\':
11945 pc = pgetc();
11946 if (pc == '\n') {
11947 nlprompt();
11948 /*
11949 * If eating a newline, avoid putting
11950 * the newline into the new character
11951 * stream (via the STPUTC after the
11952 * switch).
11953 */
11954 continue;
11955 }
11956 if (pc != '\\' && pc != '`' && pc != '$'
11957 && (!dblquote || pc != '"')
11958 ) {
11959 STPUTC('\\', pout);
11960 }
11961 if (pc <= 255 /* not PEOA or PEOF */) {
11962 break;
11963 }
11964 /* fall through */
11965
11966 case PEOF:
11967 IF_ASH_ALIAS(case PEOA:)
11968 startlinno = g_parsefile->linno;
11969 raise_error_syntax("EOF in backquote substitution");
11970
11971 case '\n':
11972 nlnoprompt();
11973 break;
11974
11975 default:
11976 break;
11977 }
11978 STPUTC(pc, pout);
11979 }
11980 done:
11981 STPUTC('\0', pout);
11982 psavelen = pout - (char *)stackblock();
11983 if (psavelen > 0) {
11984 pstr = grabstackstr(pout);
11985 setinputstring(pstr);
11986 }
11987 }
11988 nlpp = &bqlist;
11989 while (*nlpp)
11990 nlpp = &(*nlpp)->next;
11991 *nlpp = stzalloc(sizeof(**nlpp));
11992 /* (*nlpp)->next = NULL; - stzalloc did it */
11993
11994 if (oldstyle) {
11995 saveprompt = doprompt;
11996 doprompt = 0;
11997 }
11998
11999 n = list(2);
12000
12001 if (oldstyle)
12002 doprompt = saveprompt;
12003 else if (readtoken() != TRP)
12004 raise_error_unexpected_syntax(TRP);
12005
12006 (*nlpp)->n = n;
12007 if (oldstyle) {
12008 /*
12009 * Start reading from old file again, ignoring any pushed back
12010 * tokens left from the backquote parsing
12011 */
12012 popfile();
12013 tokpushback = 0;
12014 }
12015 while (stackblocksize() <= savelen)
12016 growstackblock();
12017 STARTSTACKSTR(out);
12018 if (str) {
12019 memcpy(out, str, savelen);
12020 STADJUST(savelen, out);
12021 }
12022 USTPUTC(CTLBACKQ, out);
12023 if (oldstyle)
12024 goto parsebackq_oldreturn;
12025 goto parsebackq_newreturn;
12026}
12027
12028#if ENABLE_FEATURE_SH_MATH
12029/*
12030 * Parse an arithmetic expansion (indicate start of one and set state)
12031 */
12032parsearith: {
12033 if (++arinest == 1) {
12034 prevsyntax = syntax;
12035 syntax = ARISYNTAX;
12036 }
12037 USTPUTC(CTLARI, out);
12038 goto parsearith_return;
12039}
12040#endif
12041} /* end of readtoken */
12042
12043/*
12044 * Read the next input token.
12045 * If the token is a word, we set backquotelist to the list of cmds in
12046 * backquotes. We set quoteflag to true if any part of the word was
12047 * quoted.
12048 * If the token is TREDIR, then we set redirnode to a structure containing
12049 * the redirection.
12050 * In all cases, the variable startlinno is set to the number of the line
12051 * on which the token starts.
12052 *
12053 * [Change comment: here documents and internal procedures]
12054 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12055 * word parsing code into a separate routine. In this case, readtoken
12056 * doesn't need to have any internal procedures, but parseword does.
12057 * We could also make parseoperator in essence the main routine, and
12058 * have parseword (readtoken1?) handle both words and redirection.]
12059 */
12060#define NEW_xxreadtoken
12061#ifdef NEW_xxreadtoken
12062/* singles must be first! */
12063static const char xxreadtoken_chars[7] ALIGN1 = {
12064 '\n', '(', ')', /* singles */
12065 '&', '|', ';', /* doubles */
12066 0
12067};
12068
12069#define xxreadtoken_singles 3
12070#define xxreadtoken_doubles 3
12071
12072static const char xxreadtoken_tokens[] ALIGN1 = {
12073 TNL, TLP, TRP, /* only single occurrence allowed */
12074 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12075 TEOF, /* corresponds to trailing nul */
12076 TAND, TOR, TENDCASE /* if double occurrence */
12077};
12078
12079static int
12080xxreadtoken(void)
12081{
12082 int c;
12083
12084 if (tokpushback) {
12085 tokpushback = 0;
12086 return lasttoken;
12087 }
12088 setprompt_if(needprompt, 2);
12089 startlinno = g_parsefile->linno;
12090 for (;;) { /* until token or start of word found */
12091 c = pgetc();
12092 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
12093 continue;
12094
12095 if (c == '#') {
12096 while ((c = pgetc()) != '\n' && c != PEOF)
12097 continue;
12098 pungetc();
12099 } else if (c == '\\') {
12100 if (pgetc() != '\n') {
12101 pungetc();
12102 break; /* return readtoken1(...) */
12103 }
12104 nlprompt();
12105 } else {
12106 const char *p;
12107
12108 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12109 if (c != PEOF) {
12110 if (c == '\n') {
12111 nlnoprompt();
12112 }
12113
12114 p = strchr(xxreadtoken_chars, c);
12115 if (p == NULL)
12116 break; /* return readtoken1(...) */
12117
12118 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12119 int cc = pgetc();
12120 if (cc == c) { /* double occurrence? */
12121 p += xxreadtoken_doubles + 1;
12122 } else {
12123 pungetc();
12124#if ENABLE_ASH_BASH_COMPAT
12125 if (c == '&' && cc == '>') /* &> */
12126 break; /* return readtoken1(...) */
12127#endif
12128 }
12129 }
12130 }
12131 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12132 return lasttoken;
12133 }
12134 } /* for (;;) */
12135
12136 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
12137}
12138#else /* old xxreadtoken */
12139#define RETURN(token) return lasttoken = token
12140static int
12141xxreadtoken(void)
12142{
12143 int c;
12144
12145 if (tokpushback) {
12146 tokpushback = 0;
12147 return lasttoken;
12148 }
12149 setprompt_if(needprompt, 2);
12150 startlinno = g_parsefile->linno;
12151 for (;;) { /* until token or start of word found */
12152 c = pgetc();
12153 switch (c) {
12154 case ' ': case '\t':
12155 IF_ASH_ALIAS(case PEOA:)
12156 continue;
12157 case '#':
12158 while ((c = pgetc()) != '\n' && c != PEOF)
12159 continue;
12160 pungetc();
12161 continue;
12162 case '\\':
12163 if (pgetc() == '\n') {
12164 nlprompt();
12165 continue;
12166 }
12167 pungetc();
12168 goto breakloop;
12169 case '\n':
12170 nlnoprompt();
12171 RETURN(TNL);
12172 case PEOF:
12173 RETURN(TEOF);
12174 case '&':
12175 if (pgetc() == '&')
12176 RETURN(TAND);
12177 pungetc();
12178 RETURN(TBACKGND);
12179 case '|':
12180 if (pgetc() == '|')
12181 RETURN(TOR);
12182 pungetc();
12183 RETURN(TPIPE);
12184 case ';':
12185 if (pgetc() == ';')
12186 RETURN(TENDCASE);
12187 pungetc();
12188 RETURN(TSEMI);
12189 case '(':
12190 RETURN(TLP);
12191 case ')':
12192 RETURN(TRP);
12193 default:
12194 goto breakloop;
12195 }
12196 }
12197 breakloop:
12198 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12199#undef RETURN
12200}
12201#endif /* old xxreadtoken */
12202
12203static int
12204readtoken(void)
12205{
12206 int t;
12207 int kwd = checkkwd;
12208#if DEBUG
12209 smallint alreadyseen = tokpushback;
12210#endif
12211
12212#if ENABLE_ASH_ALIAS
12213 top:
12214#endif
12215
12216 t = xxreadtoken();
12217
12218 /*
12219 * eat newlines
12220 */
12221 if (kwd & CHKNL) {
12222 while (t == TNL) {
12223 parseheredoc();
12224 t = xxreadtoken();
12225 }
12226 }
12227
12228 if (t != TWORD || quoteflag) {
12229 goto out;
12230 }
12231
12232 /*
12233 * check for keywords
12234 */
12235 if (kwd & CHKKWD) {
12236 const char *const *pp;
12237
12238 pp = findkwd(wordtext);
12239 if (pp) {
12240 lasttoken = t = pp - tokname_array;
12241 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
12242 goto out;
12243 }
12244 }
12245
12246 if (checkkwd & CHKALIAS) {
12247#if ENABLE_ASH_ALIAS
12248 struct alias *ap;
12249 ap = lookupalias(wordtext, 1);
12250 if (ap != NULL) {
12251 if (*ap->val) {
12252 pushstring(ap->val, ap);
12253 }
12254 goto top;
12255 }
12256#endif
12257 }
12258 out:
12259 checkkwd = 0;
12260#if DEBUG
12261 if (!alreadyseen)
12262 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
12263 else
12264 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
12265#endif
12266 return t;
12267}
12268
12269static int
12270peektoken(void)
12271{
12272 int t;
12273
12274 t = readtoken();
12275 tokpushback = 1;
12276 return t;
12277}
12278
12279/*
12280 * Read and parse a command. Returns NODE_EOF on end of file.
12281 * (NULL is a valid parse tree indicating a blank line.)
12282 */
12283static union node *
12284parsecmd(int interact)
12285{
12286 tokpushback = 0;
12287 checkkwd = 0;
12288 heredoclist = 0;
12289 doprompt = interact;
12290 setprompt_if(doprompt, doprompt);
12291 needprompt = 0;
12292 return list(1);
12293}
12294
12295/*
12296 * Input any here documents.
12297 */
12298static void
12299parseheredoc(void)
12300{
12301 struct heredoc *here;
12302 union node *n;
12303
12304 here = heredoclist;
12305 heredoclist = NULL;
12306
12307 while (here) {
12308 setprompt_if(needprompt, 2);
12309 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
12310 here->eofmark, here->striptabs);
12311 n = stzalloc(sizeof(struct narg));
12312 n->narg.type = NARG;
12313 /*n->narg.next = NULL; - stzalloc did it */
12314 n->narg.text = wordtext;
12315 n->narg.backquote = backquotelist;
12316 here->here->nhere.doc = n;
12317 here = here->next;
12318 }
12319}
12320
12321
12322/*
12323 * called by editline -- any expansions to the prompt should be added here.
12324 */
12325#if ENABLE_ASH_EXPAND_PRMT
12326static const char *
12327expandstr(const char *ps)
12328{
12329 union node n;
12330 int saveprompt;
12331
12332 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12333 * and token processing _can_ alter it (delete NULs etc). */
12334 setinputstring((char *)ps);
12335
12336 saveprompt = doprompt;
12337 doprompt = 0;
12338 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
12339 doprompt = saveprompt;
12340
12341 popfile();
12342
12343 n.narg.type = NARG;
12344 n.narg.next = NULL;
12345 n.narg.text = wordtext;
12346 n.narg.backquote = backquotelist;
12347
12348 expandarg(&n, NULL, EXP_QUOTED);
12349 return stackblock();
12350}
12351#endif
12352
12353/*
12354 * Execute a command or commands contained in a string.
12355 */
12356static int
12357evalstring(char *s, int flags)
12358{
12359 struct jmploc *volatile savehandler;
12360 struct jmploc jmploc;
12361 int ex;
12362
12363 union node *n;
12364 struct stackmark smark;
12365 int status;
12366
12367 s = sstrdup(s);
12368 setinputstring(s);
12369 setstackmark(&smark);
12370
12371 status = 0;
12372 /* On exception inside execution loop, we must popfile().
12373 * Try interactively:
12374 * readonly a=a
12375 * command eval "a=b" # throws "is read only" error
12376 * "command BLTIN" is not supposed to abort (even in non-interactive use).
12377 * But if we skip popfile(), we hit EOF in eval's string, and exit.
12378 */
12379 savehandler = exception_handler;
12380 ex = setjmp(jmploc.loc);
12381 if (ex)
12382 goto out;
12383 exception_handler = &jmploc;
12384
12385 while ((n = parsecmd(0)) != NODE_EOF) {
12386 int i;
12387
12388 i = evaltree(n, flags);
12389 if (n)
12390 status = i;
12391 popstackmark(&smark);
12392 if (evalskip)
12393 break;
12394 }
12395 out:
12396 popstackmark(&smark);
12397 popfile();
12398 stunalloc(s);
12399
12400 exception_handler = savehandler;
12401 if (ex)
12402 longjmp(exception_handler->loc, ex);
12403
12404 return status;
12405}
12406
12407/*
12408 * The eval command.
12409 */
12410static int FAST_FUNC
12411evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
12412{
12413 char *p;
12414 char *concat;
12415
12416 if (argv[1]) {
12417 p = argv[1];
12418 argv += 2;
12419 if (argv[0]) {
12420 STARTSTACKSTR(concat);
12421 for (;;) {
12422 concat = stack_putstr(p, concat);
12423 p = *argv++;
12424 if (p == NULL)
12425 break;
12426 STPUTC(' ', concat);
12427 }
12428 STPUTC('\0', concat);
12429 p = grabstackstr(concat);
12430 }
12431 return evalstring(p, flags & EV_TESTED);
12432 }
12433 return 0;
12434}
12435
12436/*
12437 * Read and execute commands.
12438 * "Top" is nonzero for the top level command loop;
12439 * it turns on prompting if the shell is interactive.
12440 */
12441static int
12442cmdloop(int top)
12443{
12444 union node *n;
12445 struct stackmark smark;
12446 int inter;
12447 int status = 0;
12448 int numeof = 0;
12449
12450 TRACE(("cmdloop(%d) called\n", top));
12451 for (;;) {
12452 int skip;
12453
12454 setstackmark(&smark);
12455#if JOBS
12456 if (doing_jobctl)
12457 showjobs(SHOW_CHANGED|SHOW_STDERR);
12458#endif
12459 inter = 0;
12460 if (iflag && top) {
12461 inter++;
12462 chkmail();
12463 }
12464 n = parsecmd(inter);
12465#if DEBUG
12466 if (DEBUG > 2 && debug && (n != NODE_EOF))
12467 showtree(n);
12468#endif
12469 if (n == NODE_EOF) {
12470 if (!top || numeof >= 50)
12471 break;
12472 if (!stoppedjobs()) {
12473 if (!Iflag)
12474 break;
12475 out2str("\nUse \"exit\" to leave shell.\n");
12476 }
12477 numeof++;
12478 } else if (nflag == 0) {
12479 int i;
12480
12481 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12482 job_warning >>= 1;
12483 numeof = 0;
12484 i = evaltree(n, 0);
12485 if (n)
12486 status = i;
12487 }
12488 popstackmark(&smark);
12489 skip = evalskip;
12490
12491 if (skip) {
12492 evalskip &= ~SKIPFUNC;
12493 break;
12494 }
12495 }
12496 return status;
12497}
12498
12499/*
12500 * Take commands from a file. To be compatible we should do a path
12501 * search for the file, which is necessary to find sub-commands.
12502 */
12503static char *
12504find_dot_file(char *name)
12505{
12506 char *fullname;
12507 const char *path = pathval();
12508 struct stat statb;
12509
12510 /* don't try this for absolute or relative paths */
12511 if (strchr(name, '/'))
12512 return name;
12513
12514 /* IIRC standards do not say whether . is to be searched.
12515 * And it is even smaller this way, making it unconditional for now:
12516 */
12517 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12518 fullname = name;
12519 goto try_cur_dir;
12520 }
12521
12522 while ((fullname = path_advance(&path, name)) != NULL) {
12523 try_cur_dir:
12524 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12525 /*
12526 * Don't bother freeing here, since it will
12527 * be freed by the caller.
12528 */
12529 return fullname;
12530 }
12531 if (fullname != name)
12532 stunalloc(fullname);
12533 }
12534
12535 /* not found in the PATH */
12536 ash_msg_and_raise_error("%s: not found", name);
12537 /* NOTREACHED */
12538}
12539
12540static int FAST_FUNC
12541dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
12542{
12543 /* "false; . empty_file; echo $?" should print 0, not 1: */
12544 int status = 0;
12545 char *fullname;
12546 char **argv;
12547 struct strlist *sp;
12548 volatile struct shparam saveparam;
12549
12550 for (sp = cmdenviron; sp; sp = sp->next)
12551 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
12552
12553 nextopt(nullstr); /* handle possible "--" */
12554 argv = argptr;
12555
12556 if (!argv[0]) {
12557 /* bash says: "bash: .: filename argument required" */
12558 return 2; /* bash compat */
12559 }
12560
12561 /* This aborts if file isn't found, which is POSIXly correct.
12562 * bash returns exitcode 1 instead.
12563 */
12564 fullname = find_dot_file(argv[0]);
12565 argv++;
12566 if (argv[0]) { /* . FILE ARGS, ARGS exist */
12567 int argc;
12568 saveparam = shellparam;
12569 shellparam.malloced = 0;
12570 argc = 1;
12571 while (argv[argc])
12572 argc++;
12573 shellparam.nparam = argc;
12574 shellparam.p = argv;
12575 };
12576
12577 /* This aborts if file can't be opened, which is POSIXly correct.
12578 * bash returns exitcode 1 instead.
12579 */
12580 setinputfile(fullname, INPUT_PUSH_FILE);
12581 commandname = fullname;
12582 status = cmdloop(0);
12583 popfile();
12584
12585 if (argv[0]) {
12586 freeparam(&shellparam);
12587 shellparam = saveparam;
12588 };
12589
12590 return status;
12591}
12592
12593static int FAST_FUNC
12594exitcmd(int argc UNUSED_PARAM, char **argv)
12595{
12596 if (stoppedjobs())
12597 return 0;
12598 if (argv[1])
12599 exitstatus = number(argv[1]);
12600 raise_exception(EXEXIT);
12601 /* NOTREACHED */
12602}
12603
12604/*
12605 * Read a file containing shell functions.
12606 */
12607static void
12608readcmdfile(char *name)
12609{
12610 setinputfile(name, INPUT_PUSH_FILE);
12611 cmdloop(0);
12612 popfile();
12613}
12614
12615
12616/* ============ find_command inplementation */
12617
12618/*
12619 * Resolve a command name. If you change this routine, you may have to
12620 * change the shellexec routine as well.
12621 */
12622static void
12623find_command(char *name, struct cmdentry *entry, int act, const char *path)
12624{
12625 struct tblentry *cmdp;
12626 int idx;
12627 int prev;
12628 char *fullname;
12629 struct stat statb;
12630 int e;
12631 int updatetbl;
12632 struct builtincmd *bcmd;
12633
12634 /* If name contains a slash, don't use PATH or hash table */
12635 if (strchr(name, '/') != NULL) {
12636 entry->u.index = -1;
12637 if (act & DO_ABS) {
12638 while (stat(name, &statb) < 0) {
12639#ifdef SYSV
12640 if (errno == EINTR)
12641 continue;
12642#endif
12643 entry->cmdtype = CMDUNKNOWN;
12644 return;
12645 }
12646 }
12647 entry->cmdtype = CMDNORMAL;
12648 return;
12649 }
12650
12651/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
12652
12653 updatetbl = (path == pathval());
12654 if (!updatetbl) {
12655 act |= DO_ALTPATH;
12656 if (strstr(path, "%builtin") != NULL)
12657 act |= DO_ALTBLTIN;
12658 }
12659
12660 /* If name is in the table, check answer will be ok */
12661 cmdp = cmdlookup(name, 0);
12662 if (cmdp != NULL) {
12663 int bit;
12664
12665 switch (cmdp->cmdtype) {
12666 default:
12667#if DEBUG
12668 abort();
12669#endif
12670 case CMDNORMAL:
12671 bit = DO_ALTPATH;
12672 break;
12673 case CMDFUNCTION:
12674 bit = DO_NOFUNC;
12675 break;
12676 case CMDBUILTIN:
12677 bit = DO_ALTBLTIN;
12678 break;
12679 }
12680 if (act & bit) {
12681 updatetbl = 0;
12682 cmdp = NULL;
12683 } else if (cmdp->rehash == 0)
12684 /* if not invalidated by cd, we're done */
12685 goto success;
12686 }
12687
12688 /* If %builtin not in path, check for builtin next */
12689 bcmd = find_builtin(name);
12690 if (bcmd) {
12691 if (IS_BUILTIN_REGULAR(bcmd))
12692 goto builtin_success;
12693 if (act & DO_ALTPATH) {
12694 if (!(act & DO_ALTBLTIN))
12695 goto builtin_success;
12696 } else if (builtinloc <= 0) {
12697 goto builtin_success;
12698 }
12699 }
12700
12701#if ENABLE_FEATURE_SH_STANDALONE
12702 {
12703 int applet_no = find_applet_by_name(name);
12704 if (applet_no >= 0) {
12705 entry->cmdtype = CMDNORMAL;
12706 entry->u.index = -2 - applet_no;
12707 return;
12708 }
12709 }
12710#endif
12711
12712 /* We have to search path. */
12713 prev = -1; /* where to start */
12714 if (cmdp && cmdp->rehash) { /* doing a rehash */
12715 if (cmdp->cmdtype == CMDBUILTIN)
12716 prev = builtinloc;
12717 else
12718 prev = cmdp->param.index;
12719 }
12720
12721 e = ENOENT;
12722 idx = -1;
12723 loop:
12724 while ((fullname = path_advance(&path, name)) != NULL) {
12725 stunalloc(fullname);
12726 /* NB: code below will still use fullname
12727 * despite it being "unallocated" */
12728 idx++;
12729 if (pathopt) {
12730 if (prefix(pathopt, "builtin")) {
12731 if (bcmd)
12732 goto builtin_success;
12733 continue;
12734 }
12735 if ((act & DO_NOFUNC)
12736 || !prefix(pathopt, "func")
12737 ) { /* ignore unimplemented options */
12738 continue;
12739 }
12740 }
12741 /* if rehash, don't redo absolute path names */
12742 if (fullname[0] == '/' && idx <= prev) {
12743 if (idx < prev)
12744 continue;
12745 TRACE(("searchexec \"%s\": no change\n", name));
12746 goto success;
12747 }
12748 while (stat(fullname, &statb) < 0) {
12749#ifdef SYSV
12750 if (errno == EINTR)
12751 continue;
12752#endif
12753 if (errno != ENOENT && errno != ENOTDIR)
12754 e = errno;
12755 goto loop;
12756 }
12757 e = EACCES; /* if we fail, this will be the error */
12758 if (!S_ISREG(statb.st_mode))
12759 continue;
12760 if (pathopt) { /* this is a %func directory */
12761 stalloc(strlen(fullname) + 1);
12762 /* NB: stalloc will return space pointed by fullname
12763 * (because we don't have any intervening allocations
12764 * between stunalloc above and this stalloc) */
12765 readcmdfile(fullname);
12766 cmdp = cmdlookup(name, 0);
12767 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12768 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12769 stunalloc(fullname);
12770 goto success;
12771 }
12772 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12773 if (!updatetbl) {
12774 entry->cmdtype = CMDNORMAL;
12775 entry->u.index = idx;
12776 return;
12777 }
12778 INT_OFF;
12779 cmdp = cmdlookup(name, 1);
12780 cmdp->cmdtype = CMDNORMAL;
12781 cmdp->param.index = idx;
12782 INT_ON;
12783 goto success;
12784 }
12785
12786 /* We failed. If there was an entry for this command, delete it */
12787 if (cmdp && updatetbl)
12788 delete_cmd_entry();
12789 if (act & DO_ERR)
12790 ash_msg("%s: %s", name, errmsg(e, "not found"));
12791 entry->cmdtype = CMDUNKNOWN;
12792 return;
12793
12794 builtin_success:
12795 if (!updatetbl) {
12796 entry->cmdtype = CMDBUILTIN;
12797 entry->u.cmd = bcmd;
12798 return;
12799 }
12800 INT_OFF;
12801 cmdp = cmdlookup(name, 1);
12802 cmdp->cmdtype = CMDBUILTIN;
12803 cmdp->param.cmd = bcmd;
12804 INT_ON;
12805 success:
12806 cmdp->rehash = 0;
12807 entry->cmdtype = cmdp->cmdtype;
12808 entry->u = cmdp->param;
12809}
12810
12811
12812/*
12813 * The trap builtin.
12814 */
12815static int FAST_FUNC
12816trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12817{
12818 char *action;
12819 char **ap;
12820 int signo, exitcode;
12821
12822 nextopt(nullstr);
12823 ap = argptr;
12824 if (!*ap) {
12825 for (signo = 0; signo < NSIG; signo++) {
12826 char *tr = trap_ptr[signo];
12827 if (tr) {
12828 /* note: bash adds "SIG", but only if invoked
12829 * as "bash". If called as "sh", or if set -o posix,
12830 * then it prints short signal names.
12831 * We are printing short names: */
12832 out1fmt("trap -- %s %s\n",
12833 single_quote(tr),
12834 get_signame(signo));
12835 /* trap_ptr != trap only if we are in special-cased `trap` code.
12836 * In this case, we will exit very soon, no need to free(). */
12837 /* if (trap_ptr != trap && tp[0]) */
12838 /* free(tr); */
12839 }
12840 }
12841 /*
12842 if (trap_ptr != trap) {
12843 free(trap_ptr);
12844 trap_ptr = trap;
12845 }
12846 */
12847 return 0;
12848 }
12849
12850 action = NULL;
12851 if (ap[1])
12852 action = *ap++;
12853 exitcode = 0;
12854 while (*ap) {
12855 signo = get_signum(*ap);
12856 if (signo < 0) {
12857 /* Mimic bash message exactly */
12858 ash_msg("%s: invalid signal specification", *ap);
12859 exitcode = 1;
12860 goto next;
12861 }
12862 INT_OFF;
12863 if (action) {
12864 if (LONE_DASH(action))
12865 action = NULL;
12866 else {
12867 if (action[0]) /* not NULL and not "" and not "-" */
12868 may_have_traps = 1;
12869 action = ckstrdup(action);
12870 }
12871 }
12872 free(trap[signo]);
12873 trap[signo] = action;
12874 if (signo != 0)
12875 setsignal(signo);
12876 INT_ON;
12877 next:
12878 ap++;
12879 }
12880 return exitcode;
12881}
12882
12883
12884/* ============ Builtins */
12885
12886#if ENABLE_ASH_HELP
12887static int FAST_FUNC
12888helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12889{
12890 unsigned col;
12891 unsigned i;
12892
12893 out1fmt(
12894 "Built-in commands:\n"
12895 "------------------\n");
12896 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
12897 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
12898 builtintab[i].name + 1);
12899 if (col > 60) {
12900 out1fmt("\n");
12901 col = 0;
12902 }
12903 }
12904# if ENABLE_FEATURE_SH_STANDALONE
12905 {
12906 const char *a = applet_names;
12907 while (*a) {
12908 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12909 if (col > 60) {
12910 out1fmt("\n");
12911 col = 0;
12912 }
12913 while (*a++ != '\0')
12914 continue;
12915 }
12916 }
12917# endif
12918 newline_and_flush(stdout);
12919 return EXIT_SUCCESS;
12920}
12921#endif
12922
12923#if MAX_HISTORY
12924static int FAST_FUNC
12925historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12926{
12927 show_history(line_input_state);
12928 return EXIT_SUCCESS;
12929}
12930#endif
12931
12932/*
12933 * The export and readonly commands.
12934 */
12935static int FAST_FUNC
12936exportcmd(int argc UNUSED_PARAM, char **argv)
12937{
12938 struct var *vp;
12939 char *name;
12940 const char *p;
12941 char **aptr;
12942 char opt;
12943 int flag;
12944 int flag_off;
12945
12946 /* "readonly" in bash accepts, but ignores -n.
12947 * We do the same: it saves a conditional in nextopt's param.
12948 */
12949 flag_off = 0;
12950 while ((opt = nextopt("np")) != '\0') {
12951 if (opt == 'n')
12952 flag_off = VEXPORT;
12953 }
12954 flag = VEXPORT;
12955 if (argv[0][0] == 'r') {
12956 flag = VREADONLY;
12957 flag_off = 0; /* readonly ignores -n */
12958 }
12959 flag_off = ~flag_off;
12960
12961 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12962 {
12963 aptr = argptr;
12964 name = *aptr;
12965 if (name) {
12966 do {
12967 p = strchr(name, '=');
12968 if (p != NULL) {
12969 p++;
12970 } else {
12971 vp = *findvar(hashvar(name), name);
12972 if (vp) {
12973 vp->flags = ((vp->flags | flag) & flag_off);
12974 continue;
12975 }
12976 }
12977 setvar(name, p, (flag & flag_off));
12978 } while ((name = *++aptr) != NULL);
12979 return 0;
12980 }
12981 }
12982
12983 /* No arguments. Show the list of exported or readonly vars.
12984 * -n is ignored.
12985 */
12986 showvars(argv[0], flag, 0);
12987 return 0;
12988}
12989
12990/*
12991 * Delete a function if it exists.
12992 */
12993static void
12994unsetfunc(const char *name)
12995{
12996 struct tblentry *cmdp;
12997
12998 cmdp = cmdlookup(name, 0);
12999 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
13000 delete_cmd_entry();
13001}
13002
13003/*
13004 * The unset builtin command. We unset the function before we unset the
13005 * variable to allow a function to be unset when there is a readonly variable
13006 * with the same name.
13007 */
13008static int FAST_FUNC
13009unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13010{
13011 char **ap;
13012 int i;
13013 int flag = 0;
13014 int ret = 0;
13015
13016 while ((i = nextopt("vf")) != 0) {
13017 flag = i;
13018 }
13019
13020 for (ap = argptr; *ap; ap++) {
13021 if (flag != 'f') {
13022 i = unsetvar(*ap);
13023 ret |= i;
13024 if (!(i & 2))
13025 continue;
13026 }
13027 if (flag != 'v')
13028 unsetfunc(*ap);
13029 }
13030 return ret & 1;
13031}
13032
13033static const unsigned char timescmd_str[] ALIGN1 = {
13034 ' ', offsetof(struct tms, tms_utime),
13035 '\n', offsetof(struct tms, tms_stime),
13036 ' ', offsetof(struct tms, tms_cutime),
13037 '\n', offsetof(struct tms, tms_cstime),
13038 0
13039};
13040static int FAST_FUNC
13041timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13042{
13043 unsigned long clk_tck, s, t;
13044 const unsigned char *p;
13045 struct tms buf;
13046
13047 clk_tck = bb_clk_tck();
13048 times(&buf);
13049
13050 p = timescmd_str;
13051 do {
13052 t = *(clock_t *)(((char *) &buf) + p[1]);
13053 s = t / clk_tck;
13054 t = t % clk_tck;
13055 out1fmt("%lum%lu.%03lus%c",
13056 s / 60, s % 60,
13057 (t * 1000) / clk_tck,
13058 p[0]);
13059 p += 2;
13060 } while (*p);
13061
13062 return 0;
13063}
13064
13065#if ENABLE_FEATURE_SH_MATH
13066/*
13067 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
13068 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
13069 *
13070 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13071 */
13072static int FAST_FUNC
13073letcmd(int argc UNUSED_PARAM, char **argv)
13074{
13075 arith_t i;
13076
13077 argv++;
13078 if (!*argv)
13079 ash_msg_and_raise_error("expression expected");
13080 do {
13081 i = ash_arith(*argv);
13082 } while (*++argv);
13083
13084 return !i;
13085}
13086#endif
13087
13088/*
13089 * The read builtin. Options:
13090 * -r Do not interpret '\' specially
13091 * -s Turn off echo (tty only)
13092 * -n NCHARS Read NCHARS max
13093 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13094 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13095 * -u FD Read from given FD instead of fd 0
13096 * This uses unbuffered input, which may be avoidable in some cases.
13097 * TODO: bash also has:
13098 * -a ARRAY Read into array[0],[1],etc
13099 * -d DELIM End on DELIM char, not newline
13100 * -e Use line editing (tty only)
13101 */
13102static int FAST_FUNC
13103readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13104{
13105 char *opt_n = NULL;
13106 char *opt_p = NULL;
13107 char *opt_t = NULL;
13108 char *opt_u = NULL;
13109 int read_flags = 0;
13110 const char *r;
13111 int i;
13112
13113 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
13114 switch (i) {
13115 case 'p':
13116 opt_p = optionarg;
13117 break;
13118 case 'n':
13119 opt_n = optionarg;
13120 break;
13121 case 's':
13122 read_flags |= BUILTIN_READ_SILENT;
13123 break;
13124 case 't':
13125 opt_t = optionarg;
13126 break;
13127 case 'r':
13128 read_flags |= BUILTIN_READ_RAW;
13129 break;
13130 case 'u':
13131 opt_u = optionarg;
13132 break;
13133 default:
13134 break;
13135 }
13136 }
13137
13138 /* "read -s" needs to save/restore termios, can't allow ^C
13139 * to jump out of it.
13140 */
13141 INT_OFF;
13142 r = shell_builtin_read(setvar0,
13143 argptr,
13144 bltinlookup("IFS"), /* can be NULL */
13145 read_flags,
13146 opt_n,
13147 opt_p,
13148 opt_t,
13149 opt_u
13150 );
13151 INT_ON;
13152
13153 if ((uintptr_t)r > 1)
13154 ash_msg_and_raise_error(r);
13155
13156 return (uintptr_t)r;
13157}
13158
13159static int FAST_FUNC
13160umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13161{
13162 static const char permuser[3] ALIGN1 = "ogu";
13163
13164 mode_t mask;
13165 int symbolic_mode = 0;
13166
13167 while (nextopt("S") != '\0') {
13168 symbolic_mode = 1;
13169 }
13170
13171 INT_OFF;
13172 mask = umask(0);
13173 umask(mask);
13174 INT_ON;
13175
13176 if (*argptr == NULL) {
13177 if (symbolic_mode) {
13178 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
13179 char *p = buf;
13180 int i;
13181
13182 i = 2;
13183 for (;;) {
13184 *p++ = ',';
13185 *p++ = permuser[i];
13186 *p++ = '=';
13187 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
13188 if (!(mask & 0400)) *p++ = 'r';
13189 if (!(mask & 0200)) *p++ = 'w';
13190 if (!(mask & 0100)) *p++ = 'x';
13191 mask <<= 3;
13192 if (--i < 0)
13193 break;
13194 }
13195 *p = '\0';
13196 puts(buf + 1);
13197 } else {
13198 out1fmt("%04o\n", mask);
13199 }
13200 } else {
13201 char *modestr = *argptr;
13202 /* numeric umasks are taken as-is */
13203 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13204 if (!isdigit(modestr[0]))
13205 mask ^= 0777;
13206 mask = bb_parse_mode(modestr, mask);
13207 if ((unsigned)mask > 0777) {
13208 ash_msg_and_raise_error("illegal mode: %s", modestr);
13209 }
13210 if (!isdigit(modestr[0]))
13211 mask ^= 0777;
13212 umask(mask);
13213 }
13214 return 0;
13215}
13216
13217static int FAST_FUNC
13218ulimitcmd(int argc UNUSED_PARAM, char **argv)
13219{
13220 return shell_builtin_ulimit(argv);
13221}
13222
13223/* ============ main() and helpers */
13224
13225/*
13226 * Called to exit the shell.
13227 */
13228static void
13229exitshell(void)
13230{
13231 struct jmploc loc;
13232 char *p;
13233 int status;
13234
13235#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13236 save_history(line_input_state);
13237#endif
13238 status = exitstatus;
13239 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13240 if (setjmp(loc.loc)) {
13241 if (exception_type == EXEXIT)
13242 status = exitstatus;
13243 goto out;
13244 }
13245 exception_handler = &loc;
13246 p = trap[0];
13247 if (p) {
13248 trap[0] = NULL;
13249 evalskip = 0;
13250 evalstring(p, 0);
13251 /*free(p); - we'll exit soon */
13252 }
13253 out:
13254 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13255 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13256 */
13257 setjobctl(0);
13258 flush_stdout_stderr();
13259 _exit(status);
13260 /* NOTREACHED */
13261}
13262
13263static void
13264init(void)
13265{
13266 /* we will never free this */
13267 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
13268
13269 sigmode[SIGCHLD - 1] = S_DFL;
13270 setsignal(SIGCHLD);
13271
13272 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13273 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13274 */
13275 signal(SIGHUP, SIG_DFL);
13276
13277 {
13278 char **envp;
13279 const char *p;
13280 struct stat st1, st2;
13281
13282 initvar();
13283 for (envp = environ; envp && *envp; envp++) {
13284 p = endofname(*envp);
13285 if (p != *envp && *p == '=') {
13286 setvareq(*envp, VEXPORT|VTEXTFIXED);
13287 }
13288 }
13289
13290 setvareq((char*)defoptindvar, VTEXTFIXED);
13291
13292 setvar0("PPID", utoa(getppid()));
13293#if ENABLE_ASH_BASH_COMPAT
13294 p = lookupvar("SHLVL");
13295 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
13296 if (!lookupvar("HOSTNAME")) {
13297 struct utsname uts;
13298 uname(&uts);
13299 setvar0("HOSTNAME", uts.nodename);
13300 }
13301#endif
13302 p = lookupvar("PWD");
13303 if (p) {
13304 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
13305 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13306 ) {
13307 p = NULL;
13308 }
13309 }
13310 setpwd(p, 0);
13311 }
13312}
13313
13314
13315//usage:#define ash_trivial_usage
13316//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
13317//usage:#define ash_full_usage "\n\n"
13318//usage: "Unix shell interpreter"
13319
13320/*
13321 * Process the shell command line arguments.
13322 */
13323static void
13324procargs(char **argv)
13325{
13326 int i;
13327 const char *xminusc;
13328 char **xargv;
13329
13330 xargv = argv;
13331 arg0 = xargv[0];
13332 /* if (xargv[0]) - mmm, this is always true! */
13333 xargv++;
13334 for (i = 0; i < NOPTS; i++)
13335 optlist[i] = 2;
13336 argptr = xargv;
13337 if (options(/*cmdline:*/ 1)) {
13338 /* it already printed err message */
13339 raise_exception(EXERROR);
13340 }
13341 xargv = argptr;
13342 xminusc = minusc;
13343 if (*xargv == NULL) {
13344 if (xminusc)
13345 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13346 sflag = 1;
13347 }
13348 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13349 iflag = 1;
13350 if (mflag == 2)
13351 mflag = iflag;
13352 for (i = 0; i < NOPTS; i++)
13353 if (optlist[i] == 2)
13354 optlist[i] = 0;
13355#if DEBUG == 2
13356 debug = 1;
13357#endif
13358 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13359 if (xminusc) {
13360 minusc = *xargv++;
13361 if (*xargv)
13362 goto setarg0;
13363 } else if (!sflag) {
13364 setinputfile(*xargv, 0);
13365 setarg0:
13366 arg0 = *xargv++;
13367 commandname = arg0;
13368 }
13369
13370 shellparam.p = xargv;
13371#if ENABLE_ASH_GETOPTS
13372 shellparam.optind = 1;
13373 shellparam.optoff = -1;
13374#endif
13375 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13376 while (*xargv) {
13377 shellparam.nparam++;
13378 xargv++;
13379 }
13380 optschanged();
13381}
13382
13383/*
13384 * Read /etc/profile, ~/.profile, $ENV.
13385 */
13386static void
13387read_profile(const char *name)
13388{
13389 name = expandstr(name);
13390 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13391 return;
13392 cmdloop(0);
13393 popfile();
13394}
13395
13396/*
13397 * This routine is called when an error or an interrupt occurs in an
13398 * interactive shell and control is returned to the main command loop.
13399 * (In dash, this function is auto-generated by build machinery).
13400 */
13401static void
13402reset(void)
13403{
13404 /* from eval.c: */
13405 evalskip = 0;
13406 loopnest = 0;
13407
13408 /* from expand.c: */
13409 ifsfree();
13410
13411 /* from input.c: */
13412 g_parsefile->left_in_buffer = 0;
13413 g_parsefile->left_in_line = 0; /* clear input buffer */
13414 popallfiles();
13415
13416 /* from redir.c: */
13417 while (redirlist)
13418 popredir(/*drop:*/ 0, /*restore:*/ 0);
13419}
13420
13421#if PROFILE
13422static short profile_buf[16384];
13423extern int etext();
13424#endif
13425
13426/*
13427 * Main routine. We initialize things, parse the arguments, execute
13428 * profiles if we're a login shell, and then call cmdloop to execute
13429 * commands. The setjmp call sets up the location to jump to when an
13430 * exception occurs. When an exception occurs the variable "state"
13431 * is used to figure out how far we had gotten.
13432 */
13433int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
13434int ash_main(int argc UNUSED_PARAM, char **argv)
13435{
13436 volatile smallint state;
13437 struct jmploc jmploc;
13438 struct stackmark smark;
13439
13440 /* Initialize global data */
13441 INIT_G_misc();
13442 INIT_G_memstack();
13443 INIT_G_var();
13444#if ENABLE_ASH_ALIAS
13445 INIT_G_alias();
13446#endif
13447 INIT_G_cmdtable();
13448
13449#if PROFILE
13450 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13451#endif
13452
13453#if ENABLE_FEATURE_EDITING
13454 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13455#endif
13456 state = 0;
13457 if (setjmp(jmploc.loc)) {
13458 smallint e;
13459 smallint s;
13460
13461 reset();
13462
13463 e = exception_type;
13464 s = state;
13465 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
13466 exitshell();
13467 }
13468 if (e == EXINT) {
13469 newline_and_flush(stderr);
13470 }
13471
13472 popstackmark(&smark);
13473 FORCE_INT_ON; /* enable interrupts */
13474 if (s == 1)
13475 goto state1;
13476 if (s == 2)
13477 goto state2;
13478 if (s == 3)
13479 goto state3;
13480 goto state4;
13481 }
13482 exception_handler = &jmploc;
13483 rootpid = getpid();
13484
13485 init();
13486 setstackmark(&smark);
13487 procargs(argv);
13488#if DEBUG
13489 TRACE(("Shell args: "));
13490 trace_puts_args(argv);
13491#endif
13492
13493 if (argv[0] && argv[0][0] == '-')
13494 isloginsh = 1;
13495 if (isloginsh) {
13496 const char *hp;
13497
13498 state = 1;
13499 read_profile("/etc/profile");
13500 state1:
13501 state = 2;
13502 hp = lookupvar("HOME");
13503 if (hp)
13504 read_profile("$HOME/.profile");
13505 }
13506 state2:
13507 state = 3;
13508 if (
13509#ifndef linux
13510 getuid() == geteuid() && getgid() == getegid() &&
13511#endif
13512 iflag
13513 ) {
13514 const char *shinit = lookupvar("ENV");
13515 if (shinit != NULL && *shinit != '\0')
13516 read_profile(shinit);
13517 }
13518 popstackmark(&smark);
13519 state3:
13520 state = 4;
13521 if (minusc) {
13522 /* evalstring pushes parsefile stack.
13523 * Ensure we don't falsely claim that 0 (stdin)
13524 * is one of stacked source fds.
13525 * Testcase: ash -c 'exec 1>&0' must not complain. */
13526 // if (!sflag) g_parsefile->pf_fd = -1;
13527 // ^^ not necessary since now we special-case fd 0
13528 // in is_hidden_fd() to not be considered "hidden fd"
13529 evalstring(minusc, 0);
13530 }
13531
13532 if (sflag || minusc == NULL) {
13533#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
13534 if (iflag) {
13535 const char *hp = lookupvar("HISTFILE");
13536 if (!hp) {
13537 hp = lookupvar("HOME");
13538 if (hp) {
13539 hp = concat_path_file(hp, ".ash_history");
13540 setvar0("HISTFILE", hp);
13541 free((char*)hp);
13542 hp = lookupvar("HISTFILE");
13543 }
13544 }
13545 if (hp)
13546 line_input_state->hist_file = hp;
13547# if ENABLE_FEATURE_SH_HISTFILESIZE
13548 hp = lookupvar("HISTFILESIZE");
13549 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13550# endif
13551 }
13552#endif
13553 state4: /* XXX ??? - why isn't this before the "if" statement */
13554 cmdloop(1);
13555 }
13556#if PROFILE
13557 monitor(0);
13558#endif
13559#ifdef GPROF
13560 {
13561 extern void _mcleanup(void);
13562 _mcleanup();
13563 }
13564#endif
13565 TRACE(("End of main reached\n"));
13566 exitshell();
13567 /* NOTREACHED */
13568}
13569
13570
13571/*-
13572 * Copyright (c) 1989, 1991, 1993, 1994
13573 * The Regents of the University of California. All rights reserved.
13574 *
13575 * This code is derived from software contributed to Berkeley by
13576 * Kenneth Almquist.
13577 *
13578 * Redistribution and use in source and binary forms, with or without
13579 * modification, are permitted provided that the following conditions
13580 * are met:
13581 * 1. Redistributions of source code must retain the above copyright
13582 * notice, this list of conditions and the following disclaimer.
13583 * 2. Redistributions in binary form must reproduce the above copyright
13584 * notice, this list of conditions and the following disclaimer in the
13585 * documentation and/or other materials provided with the distribution.
13586 * 3. Neither the name of the University nor the names of its contributors
13587 * may be used to endorse or promote products derived from this software
13588 * without specific prior written permission.
13589 *
13590 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13591 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13592 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13593 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13594 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13595 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13596 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13597 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13598 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13599 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13600 * SUCH DAMAGE.
13601 */
13602