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