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