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