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