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