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