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