1 /* vi: set sw=4 ts=4: */
3 * ash shell port for busybox
5 * Copyright (c) 1989, 1991, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
8 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
9 * was re-ported from NetBSD and debianized.
11 * This code is derived from software contributed to Berkeley by
14 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
16 * Original BSD copyright notice is retained at the end of this file.
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.
30 /* Tweak debug output verbosity here */
39 #define JOBS ENABLE_ASH_JOB_CONTROL
47 #include "busybox.h" /* for applet_names */
48 //TODO: pull in some .h and find out do we have SINGLE_APPLET_MAIN?
49 //#include "applet_tables.h" doesn't work
55 #if defined SINGLE_APPLET_MAIN
56 /* STANDALONE does not make sense, and won't compile */
57 #undef CONFIG_FEATURE_SH_STANDALONE
58 #undef ENABLE_FEATURE_SH_STANDALONE
59 #undef USE_FEATURE_SH_STANDALONE
60 #undef SKIP_FEATURE_SH_STANDALONE(...)
61 #define ENABLE_FEATURE_SH_STANDALONE 0
62 #define USE_FEATURE_SH_STANDALONE(...)
63 #define SKIP_FEATURE_SH_STANDALONE(...) __VA_ARGS__
67 # define PIPE_BUF 4096 /* amount of buffering in a pipe */
70 #if defined(__uClinux__)
71 # error "Do not even bother, ash will not run on NOMMU machine"
75 /* ============ Hash table sizes. Configurable. */
79 #define CMDTABLESIZE 31 /* should be prime */
82 /* ============ Shell options */
84 static const char *const optletters_optnames
[] = {
105 #define optletters(n) optletters_optnames[(n)][0]
106 #define optnames(n) (&optletters_optnames[(n)][1])
108 enum { NOPTS
= ARRAY_SIZE(optletters_optnames
) };
111 /* ============ Misc data */
113 static const char homestr
[] ALIGN1
= "HOME";
114 static const char snlfmt
[] ALIGN1
= "%s\n";
115 static const char illnum
[] ALIGN1
= "Illegal number: %s";
118 * We enclose jmp_buf in a structure so that we can declare pointers to
119 * jump locations. The global variable handler contains the location to
120 * jump to when an exception occurs, and the global variable exception_type
121 * contains a code identifying the exception. To implement nested
122 * exception handlers, the user should save the value of handler on entry
123 * to an inner scope, set handler to point to a jmploc structure for the
124 * inner scope, and restore handler on exit from the scope.
130 struct globals_misc
{
131 /* pid of main shell */
133 /* shell level: 0 for the main shell, 1 for its children, and so on */
135 #define rootshell (!shlvl)
136 char *minusc
; /* argument to -c option */
138 char *curdir
; // = nullstr; /* current working directory */
139 char *physdir
; // = nullstr; /* physical working directory */
141 char *arg0
; /* value of $0 */
143 struct jmploc
*exception_handler
;
145 // disabled by vda: cannot understand how it was supposed to work -
146 // cannot fix bugs. That's why you have to explain your non-trivial designs!
147 // /* do we generate EXSIG events */
148 // int exsig; /* counter */
149 volatile int suppressint
; /* counter */
151 // pendingsig -> pending_sig
152 // intpending -> pending_int
153 volatile /*sig_atomic_t*/ smallint intpending
; /* 1 = got SIGINT */
154 /* last pending signal */
155 volatile /*sig_atomic_t*/ smallint pendingsig
;
156 smallint exception_type
; /* kind of exception (0..5) */
158 #define EXINT 0 /* SIGINT received */
159 #define EXERROR 1 /* a generic error */
160 #define EXSHELLPROC 2 /* execute a shell procedure */
161 #define EXEXEC 3 /* command execution failed */
162 #define EXEXIT 4 /* exit the shell */
163 #define EXSIG 5 /* trapped signal in wait(1) */
166 char nullstr
[1]; /* zero length string */
169 #define eflag optlist[0]
170 #define fflag optlist[1]
171 #define Iflag optlist[2]
172 #define iflag optlist[3]
173 #define mflag optlist[4]
174 #define nflag optlist[5]
175 #define sflag optlist[6]
176 #define xflag optlist[7]
177 #define vflag optlist[8]
178 #define Cflag optlist[9]
179 #define aflag optlist[10]
180 #define bflag optlist[11]
181 #define uflag optlist[12]
182 #define viflag optlist[13]
184 #define nolog optlist[14]
185 #define debug optlist[15]
188 /* trap handler commands */
190 * Sigmode records the current value of the signal handlers for the various
191 * modes. A value of zero means that the current handler is not known.
192 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
194 char sigmode
[NSIG
- 1];
195 #define S_DFL 1 /* default signal handling (SIG_DFL) */
196 #define S_CATCH 2 /* signal is caught */
197 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
198 #define S_HARD_IGN 4 /* signal is ignored permenantly */
200 /* indicates specified signal received */
201 uint8_t gotsig
[NSIG
- 1]; /* offset by 1: "signal" 0 is meaningless */
204 /* Rarely referenced stuff */
205 #if ENABLE_ASH_RANDOM_SUPPORT
206 /* Random number generators */
207 int32_t random_galois_LFSR
; /* Galois LFSR (fast but weak). signed! */
208 uint32_t random_LCG
; /* LCG (fast but weak) */
210 pid_t backgndpid
; /* pid of last background process */
211 smallint job_warning
; /* user was warned about stopped jobs (can be 2, 1 or 0). */
213 extern struct globals_misc
*const ash_ptr_to_globals_misc
;
214 #define G_misc (*ash_ptr_to_globals_misc)
215 #define rootpid (G_misc.rootpid )
216 #define shlvl (G_misc.shlvl )
217 #define minusc (G_misc.minusc )
218 #define curdir (G_misc.curdir )
219 #define physdir (G_misc.physdir )
220 #define arg0 (G_misc.arg0 )
221 #define exception_handler (G_misc.exception_handler)
222 #define exception_type (G_misc.exception_type )
223 #define suppressint (G_misc.suppressint )
224 #define intpending (G_misc.intpending )
225 //#define exsig (G_misc.exsig )
226 #define pendingsig (G_misc.pendingsig )
227 #define isloginsh (G_misc.isloginsh )
228 #define nullstr (G_misc.nullstr )
229 #define optlist (G_misc.optlist )
230 #define sigmode (G_misc.sigmode )
231 #define gotsig (G_misc.gotsig )
232 #define trap (G_misc.trap )
233 #define random_galois_LFSR (G_misc.random_galois_LFSR)
234 #define random_LCG (G_misc.random_LCG )
235 #define backgndpid (G_misc.backgndpid )
236 #define job_warning (G_misc.job_warning)
237 #define INIT_G_misc() do { \
238 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
245 /* ============ DEBUG */
247 static void trace_printf(const char *fmt
, ...);
248 static void trace_vprintf(const char *fmt
, va_list va
);
249 # define TRACE(param) trace_printf param
250 # define TRACEV(param) trace_vprintf param
251 # define close(fd) do { \
253 if (close(dfd) < 0) \
254 bb_error_msg("bug on %d: closing %d(%x)", \
255 __LINE__, dfd, dfd); \
258 # define TRACE(param)
259 # define TRACEV(param)
263 /* ============ Utility functions */
264 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
266 /* C99 say: "char" declaration may be signed or unsigned by default */
267 #define signed_char2int(sc) ((int)(signed char)(sc))
269 static int isdigit_str9(const char *str
)
271 int maxlen
= 9 + 1; /* max 9 digits: 999999999 */
272 while (--maxlen
&& isdigit(*str
))
274 return (*str
== '\0');
278 /* ============ Interrupts / exceptions */
280 * These macros allow the user to suspend the handling of interrupt signals
281 * over a period of time. This is similar to SIGHOLD or to sigblock, but
282 * much more efficient and portable. (But hacking the kernel is so much
283 * more fun than worrying about efficiency and portability. :-))
285 #define INT_OFF do { \
291 * Called to raise an exception. Since C doesn't include exceptions, we
292 * just do a longjmp to the exception handler. The type of exception is
293 * stored in the global variable "exception_type".
295 static void raise_exception(int) NORETURN
;
297 raise_exception(int e
)
300 if (exception_handler
== NULL
)
305 longjmp(exception_handler
->loc
, 1);
308 #define raise_exception(e) do { \
309 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
310 raise_exception(e); \
315 * Called from trap.c when a SIGINT is received. (If the user specifies
316 * that SIGINT is to be trapped or ignored using the trap builtin, then
317 * this routine is not called.) Suppressint is nonzero when interrupts
318 * are held using the INT_OFF macro. (The test for iflag is just
319 * defensive programming.)
321 static void raise_interrupt(void) NORETURN
;
323 raise_interrupt(void)
328 /* Signal is not automatically unmasked after it is raised,
329 * do it ourself - unmask all signals */
330 sigprocmask_allsigs(SIG_UNBLOCK
);
331 /* pendingsig = 0; - now done in onsig() */
334 if (gotsig
[SIGINT
- 1] && !trap
[SIGINT
]) {
335 if (!(rootshell
&& iflag
)) {
336 /* Kill ourself with SIGINT */
337 signal(SIGINT
, SIG_DFL
);
342 raise_exception(ex_type
);
346 #define raise_interrupt() do { \
347 TRACE(("raising interrupt on line %d\n", __LINE__)); \
352 static USE_ASH_OPTIMIZE_FOR_SIZE(inline) void
356 if (--suppressint
== 0 && intpending
) {
360 #define INT_ON int_on()
361 static USE_ASH_OPTIMIZE_FOR_SIZE(inline) void
369 #define FORCE_INT_ON force_int_on()
371 #define SAVE_INT(v) ((v) = suppressint)
373 #define RESTORE_INT(v) do { \
376 if (suppressint == 0 && intpending) \
381 /* ============ Stdout/stderr output */
384 outstr(const char *p
, FILE *file
)
392 flush_stdout_stderr(void)
409 outcslow(int c
, FILE *dest
)
417 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__
,1,2)));
419 out1fmt(const char *fmt
, ...)
426 r
= vprintf(fmt
, ap
);
432 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__
,3,4)));
434 fmtstr(char *outbuf
, size_t length
, const char *fmt
, ...)
441 ret
= vsnprintf(outbuf
, length
, fmt
, ap
);
448 out1str(const char *p
)
454 out2str(const char *p
)
461 /* ============ Parser structures */
463 /* control characters in argument strings */
464 #define CTLESC '\201' /* escape next character */
465 #define CTLVAR '\202' /* variable defn */
466 #define CTLENDVAR '\203'
467 #define CTLBACKQ '\204'
468 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
469 /* CTLBACKQ | CTLQUOTE == '\205' */
470 #define CTLARI '\206' /* arithmetic expression */
471 #define CTLENDARI '\207'
472 #define CTLQUOTEMARK '\210'
474 /* variable substitution byte (follows CTLVAR) */
475 #define VSTYPE 0x0f /* type of variable substitution */
476 #define VSNUL 0x10 /* colon--treat the empty string as unset */
477 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
479 /* values of VSTYPE field */
480 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
481 #define VSMINUS 0x2 /* ${var-text} */
482 #define VSPLUS 0x3 /* ${var+text} */
483 #define VSQUESTION 0x4 /* ${var?message} */
484 #define VSASSIGN 0x5 /* ${var=text} */
485 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
486 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
487 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
488 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
489 #define VSLENGTH 0xa /* ${#var} */
490 #if ENABLE_ASH_BASH_COMPAT
491 #define VSSUBSTR 0xc /* ${var:position:length} */
492 #define VSREPLACE 0xd /* ${var/pattern/replacement} */
493 #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
496 static const char dolatstr
[] ALIGN1
= {
497 CTLVAR
, VSNORMAL
|VSQUOTE
, '@', '=', '\0'
517 #if ENABLE_ASH_BASH_COMPAT
534 smallint type
; /* Nxxxx */
537 union node
*redirect
;
542 smallint pipe_backgnd
;
543 struct nodelist
*cmdlist
;
549 union node
*redirect
;
562 union node
*elsepart
;
589 struct nodelist
*backquote
;
592 /* nfile and ndup layout must match!
593 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
594 * that it is actually NTO2 (>&file), and change its type.
611 char *_unused_expfname
;
630 struct nredir nredir
;
631 struct nbinary nbinary
;
635 struct nclist nclist
;
644 struct nodelist
*next
;
657 freefunc(struct funcnode
*f
)
659 if (f
&& --f
->count
< 0)
664 /* ============ Debugging output */
668 static FILE *tracefile
;
671 trace_printf(const char *fmt
, ...)
678 fprintf(tracefile
, "%u ", (int) time(NULL
));
680 fprintf(tracefile
, "[%u] ", (int) getpid());
682 fprintf(tracefile
, "pending s:%d i:%d(supp:%d) ", pendingsig
, intpending
, suppressint
);
684 vfprintf(tracefile
, fmt
, va
);
689 trace_vprintf(const char *fmt
, va_list va
)
694 fprintf(tracefile
, "%u ", (int) time(NULL
));
696 fprintf(tracefile
, "[%u] ", (int) getpid());
698 fprintf(tracefile
, "pending s:%d i:%d(supp:%d) ", pendingsig
, intpending
, suppressint
);
699 vfprintf(tracefile
, fmt
, va
);
703 trace_puts(const char *s
)
711 trace_puts_quoted(char *s
)
718 putc('"', tracefile
);
719 for (p
= s
; *p
; p
++) {
721 case '\n': c
= 'n'; goto backslash
;
722 case '\t': c
= 't'; goto backslash
;
723 case '\r': c
= 'r'; goto backslash
;
724 case '"': c
= '"'; goto backslash
;
725 case '\\': c
= '\\'; goto backslash
;
726 case CTLESC
: c
= 'e'; goto backslash
;
727 case CTLVAR
: c
= 'v'; goto backslash
;
728 case CTLVAR
+CTLQUOTE
: c
= 'V'; goto backslash
;
729 case CTLBACKQ
: c
= 'q'; goto backslash
;
730 case CTLBACKQ
+CTLQUOTE
: c
= 'Q'; goto backslash
;
732 putc('\\', tracefile
);
736 if (*p
>= ' ' && *p
<= '~')
739 putc('\\', tracefile
);
740 putc(*p
>> 6 & 03, tracefile
);
741 putc(*p
>> 3 & 07, tracefile
);
742 putc(*p
& 07, tracefile
);
747 putc('"', tracefile
);
751 trace_puts_args(char **ap
)
758 trace_puts_quoted(*ap
);
760 putc('\n', tracefile
);
763 putc(' ', tracefile
);
778 /* leave open because libedit might be using it */
781 strcpy(s
, "./trace");
783 if (!freopen(s
, "a", tracefile
)) {
784 fprintf(stderr
, "Can't re-open %s\n", s
);
789 tracefile
= fopen(s
, "a");
790 if (tracefile
== NULL
) {
791 fprintf(stderr
, "Can't open %s\n", s
);
797 flags
= fcntl(fileno(tracefile
), F_GETFL
);
799 fcntl(fileno(tracefile
), F_SETFL
, flags
| O_APPEND
);
801 setlinebuf(tracefile
);
802 fputs("\nTracing started.\n", tracefile
);
806 indent(int amount
, char *pfx
, FILE *fp
)
810 for (i
= 0; i
< amount
; i
++) {
811 if (pfx
&& i
== amount
- 1)
817 /* little circular references here... */
818 static void shtree(union node
*n
, int ind
, char *pfx
, FILE *fp
);
821 sharg(union node
*arg
, FILE *fp
)
824 struct nodelist
*bqlist
;
827 if (arg
->type
!= NARG
) {
828 out1fmt("<node type %d>\n", arg
->type
);
831 bqlist
= arg
->narg
.backquote
;
832 for (p
= arg
->narg
.text
; *p
; p
++) {
841 if (subtype
== VSLENGTH
)
850 switch (subtype
& VSTYPE
) {
883 out1fmt("<subtype %d>", subtype
);
890 case CTLBACKQ
|CTLQUOTE
:
893 shtree(bqlist
->n
, -1, NULL
, fp
);
904 shcmd(union node
*cmd
, FILE *fp
)
912 for (np
= cmd
->ncmd
.args
; np
; np
= np
->narg
.next
) {
918 for (np
= cmd
->ncmd
.redirect
; np
; np
= np
->nfile
.next
) {
922 switch (np
->nfile
.type
) {
923 case NTO
: s
= ">>"+1; dftfd
= 1; break;
924 case NCLOBBER
: s
= ">|"; dftfd
= 1; break;
925 case NAPPEND
: s
= ">>"; dftfd
= 1; break;
926 #if ENABLE_ASH_BASH_COMPAT
929 case NTOFD
: s
= ">&"; dftfd
= 1; break;
930 case NFROM
: s
= "<"; break;
931 case NFROMFD
: s
= "<&"; break;
932 case NFROMTO
: s
= "<>"; break;
933 default: s
= "*error*"; break;
935 if (np
->nfile
.fd
!= dftfd
)
936 fprintf(fp
, "%d", np
->nfile
.fd
);
938 if (np
->nfile
.type
== NTOFD
|| np
->nfile
.type
== NFROMFD
) {
939 fprintf(fp
, "%d", np
->ndup
.dupfd
);
941 sharg(np
->nfile
.fname
, fp
);
948 shtree(union node
*n
, int ind
, char *pfx
, FILE *fp
)
956 indent(ind
, pfx
, fp
);
967 shtree(n
->nbinary
.ch1
, ind
, NULL
, fp
);
970 shtree(n
->nbinary
.ch2
, ind
, NULL
, fp
);
978 for (lp
= n
->npipe
.cmdlist
; lp
; lp
= lp
->next
) {
983 if (n
->npipe
.pipe_backgnd
)
989 fprintf(fp
, "<node type %d>", n
->type
);
997 showtree(union node
*n
)
999 trace_puts("showtree called\n");
1000 shtree(n
, 1, NULL
, stdout
);
1006 /* ============ Parser data */
1009 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1012 struct strlist
*next
;
1019 struct strpush
*prev
; /* preceding string on stack */
1021 int prev_left_in_line
;
1022 #if ENABLE_ASH_ALIAS
1023 struct alias
*ap
; /* if push was associated with an alias */
1025 char *string
; /* remember the string since it may change */
1029 struct parsefile
*prev
; /* preceding file on stack */
1030 int linno
; /* current line */
1031 int fd
; /* file descriptor (or -1 if string) */
1032 int left_in_line
; /* number of chars left in this line */
1033 int left_in_buffer
; /* number of chars left in this buffer past the line */
1034 char *next_to_pgetc
; /* next char in buffer */
1035 char *buf
; /* input buffer */
1036 struct strpush
*strpush
; /* for pushing strings at this level */
1037 struct strpush basestrpush
; /* so pushing one is fast */
1040 static struct parsefile basepf
; /* top level input file */
1041 static struct parsefile
*g_parsefile
= &basepf
; /* current input file */
1042 static int startlinno
; /* line # where last token started */
1043 static char *commandname
; /* currently executing command */
1044 static struct strlist
*cmdenviron
; /* environment for builtin command */
1045 static uint8_t exitstatus
; /* exit status of last command */
1048 /* ============ Message printing */
1051 ash_vmsg(const char *msg
, va_list ap
)
1053 fprintf(stderr
, "%s: ", arg0
);
1055 if (strcmp(arg0
, commandname
))
1056 fprintf(stderr
, "%s: ", commandname
);
1057 if (!iflag
|| g_parsefile
->fd
)
1058 fprintf(stderr
, "line %d: ", startlinno
);
1060 vfprintf(stderr
, msg
, ap
);
1061 outcslow('\n', stderr
);
1065 * Exverror is called to raise the error exception. If the second argument
1066 * is not NULL then error prints an error message using printf style
1067 * formatting. It then raises the error exception.
1069 static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN
;
1071 ash_vmsg_and_raise(int cond
, const char *msg
, va_list ap
)
1075 TRACE(("ash_vmsg_and_raise(%d, \"", cond
));
1077 TRACE(("\") pid=%d\n", getpid()));
1079 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond
, getpid()));
1084 flush_stdout_stderr();
1085 raise_exception(cond
);
1089 static void ash_msg_and_raise_error(const char *, ...) NORETURN
;
1091 ash_msg_and_raise_error(const char *msg
, ...)
1096 ash_vmsg_and_raise(EXERROR
, msg
, ap
);
1101 static void raise_error_syntax(const char *) NORETURN
;
1103 raise_error_syntax(const char *msg
)
1105 ash_msg_and_raise_error("syntax error: %s", msg
);
1109 static void ash_msg_and_raise(int, const char *, ...) NORETURN
;
1111 ash_msg_and_raise(int cond
, const char *msg
, ...)
1116 ash_vmsg_and_raise(cond
, msg
, ap
);
1122 * error/warning routines for external builtins
1125 ash_msg(const char *fmt
, ...)
1135 * Return a string describing an error. The returned string may be a
1136 * pointer to a static buffer that will be overwritten on the next call.
1137 * Action describes the operation that got the error.
1140 errmsg(int e
, const char *em
)
1142 if (e
== ENOENT
|| e
== ENOTDIR
) {
1149 /* ============ Memory allocation */
1152 * It appears that grabstackstr() will barf with such alignments
1153 * because stalloc() will return a string allocated in a new stackblock.
1155 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1157 /* Most machines require the value returned from malloc to be aligned
1158 * in some way. The following macro will get this right
1159 * on many machines. */
1160 SHELL_SIZE
= sizeof(union {int i
; char *cp
; double d
; }) - 1,
1161 /* Minimum size of a block */
1162 MINSIZE
= SHELL_ALIGN(504),
1165 struct stack_block
{
1166 struct stack_block
*prev
;
1167 char space
[MINSIZE
];
1171 struct stack_block
*stackp
;
1174 struct stackmark
*marknext
;
1178 struct globals_memstack
{
1179 struct stack_block
*g_stackp
; // = &stackbase;
1180 struct stackmark
*markp
;
1181 char *g_stacknxt
; // = stackbase.space;
1182 char *sstrend
; // = stackbase.space + MINSIZE;
1183 size_t g_stacknleft
; // = MINSIZE;
1184 int herefd
; // = -1;
1185 struct stack_block stackbase
;
1187 extern struct globals_memstack
*const ash_ptr_to_globals_memstack
;
1188 #define G_memstack (*ash_ptr_to_globals_memstack)
1189 #define g_stackp (G_memstack.g_stackp )
1190 #define markp (G_memstack.markp )
1191 #define g_stacknxt (G_memstack.g_stacknxt )
1192 #define sstrend (G_memstack.sstrend )
1193 #define g_stacknleft (G_memstack.g_stacknleft)
1194 #define herefd (G_memstack.herefd )
1195 #define stackbase (G_memstack.stackbase )
1196 #define INIT_G_memstack() do { \
1197 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1199 g_stackp = &stackbase; \
1200 g_stacknxt = stackbase.space; \
1201 g_stacknleft = MINSIZE; \
1202 sstrend = stackbase.space + MINSIZE; \
1206 #define stackblock() ((void *)g_stacknxt)
1207 #define stackblocksize() g_stacknleft
1211 ckrealloc(void * p
, size_t nbytes
)
1213 p
= realloc(p
, nbytes
);
1215 ash_msg_and_raise_error(bb_msg_memory_exhausted
);
1220 ckmalloc(size_t nbytes
)
1222 return ckrealloc(NULL
, nbytes
);
1226 ckzalloc(size_t nbytes
)
1228 return memset(ckmalloc(nbytes
), 0, nbytes
);
1232 * Make a copy of a string in safe storage.
1235 ckstrdup(const char *s
)
1237 char *p
= strdup(s
);
1239 ash_msg_and_raise_error(bb_msg_memory_exhausted
);
1244 * Parse trees for commands are allocated in lifo order, so we use a stack
1245 * to make this more efficient, and also to avoid all sorts of exception
1246 * handling code to handle interrupts in the middle of a parse.
1248 * The size 504 was chosen because the Ultrix malloc handles that size
1252 stalloc(size_t nbytes
)
1257 aligned
= SHELL_ALIGN(nbytes
);
1258 if (aligned
> g_stacknleft
) {
1261 struct stack_block
*sp
;
1263 blocksize
= aligned
;
1264 if (blocksize
< MINSIZE
)
1265 blocksize
= MINSIZE
;
1266 len
= sizeof(struct stack_block
) - MINSIZE
+ blocksize
;
1267 if (len
< blocksize
)
1268 ash_msg_and_raise_error(bb_msg_memory_exhausted
);
1271 sp
->prev
= g_stackp
;
1272 g_stacknxt
= sp
->space
;
1273 g_stacknleft
= blocksize
;
1274 sstrend
= g_stacknxt
+ blocksize
;
1279 g_stacknxt
+= aligned
;
1280 g_stacknleft
-= aligned
;
1285 stzalloc(size_t nbytes
)
1287 return memset(stalloc(nbytes
), 0, nbytes
);
1294 if (!p
|| (g_stacknxt
< (char *)p
) || ((char *)p
< g_stackp
->space
)) {
1295 write(STDERR_FILENO
, "stunalloc\n", 10);
1299 g_stacknleft
+= g_stacknxt
- (char *)p
;
1304 * Like strdup but works with the ash stack.
1307 ststrdup(const char *p
)
1309 size_t len
= strlen(p
) + 1;
1310 return memcpy(stalloc(len
), p
, len
);
1314 setstackmark(struct stackmark
*mark
)
1316 mark
->stackp
= g_stackp
;
1317 mark
->stacknxt
= g_stacknxt
;
1318 mark
->stacknleft
= g_stacknleft
;
1319 mark
->marknext
= markp
;
1324 popstackmark(struct stackmark
*mark
)
1326 struct stack_block
*sp
;
1332 markp
= mark
->marknext
;
1333 while (g_stackp
!= mark
->stackp
) {
1335 g_stackp
= sp
->prev
;
1338 g_stacknxt
= mark
->stacknxt
;
1339 g_stacknleft
= mark
->stacknleft
;
1340 sstrend
= mark
->stacknxt
+ mark
->stacknleft
;
1345 * When the parser reads in a string, it wants to stick the string on the
1346 * stack and only adjust the stack pointer when it knows how big the
1347 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1348 * of space on top of the stack and stackblocklen returns the length of
1349 * this block. Growstackblock will grow this space by at least one byte,
1350 * possibly moving it (like realloc). Grabstackblock actually allocates the
1351 * part of the block that has been used.
1354 growstackblock(void)
1358 newlen
= g_stacknleft
* 2;
1359 if (newlen
< g_stacknleft
)
1360 ash_msg_and_raise_error(bb_msg_memory_exhausted
);
1364 if (g_stacknxt
== g_stackp
->space
&& g_stackp
!= &stackbase
) {
1365 struct stack_block
*oldstackp
;
1366 struct stackmark
*xmark
;
1367 struct stack_block
*sp
;
1368 struct stack_block
*prevstackp
;
1372 oldstackp
= g_stackp
;
1374 prevstackp
= sp
->prev
;
1375 grosslen
= newlen
+ sizeof(struct stack_block
) - MINSIZE
;
1376 sp
= ckrealloc(sp
, grosslen
);
1377 sp
->prev
= prevstackp
;
1379 g_stacknxt
= sp
->space
;
1380 g_stacknleft
= newlen
;
1381 sstrend
= sp
->space
+ newlen
;
1384 * Stack marks pointing to the start of the old block
1385 * must be relocated to point to the new block
1388 while (xmark
!= NULL
&& xmark
->stackp
== oldstackp
) {
1389 xmark
->stackp
= g_stackp
;
1390 xmark
->stacknxt
= g_stacknxt
;
1391 xmark
->stacknleft
= g_stacknleft
;
1392 xmark
= xmark
->marknext
;
1396 char *oldspace
= g_stacknxt
;
1397 size_t oldlen
= g_stacknleft
;
1398 char *p
= stalloc(newlen
);
1400 /* free the space we just allocated */
1401 g_stacknxt
= memcpy(p
, oldspace
, oldlen
);
1402 g_stacknleft
+= newlen
;
1407 grabstackblock(size_t len
)
1409 len
= SHELL_ALIGN(len
);
1411 g_stacknleft
-= len
;
1415 * The following routines are somewhat easier to use than the above.
1416 * The user declares a variable of type STACKSTR, which may be declared
1417 * to be a register. The macro STARTSTACKSTR initializes things. Then
1418 * the user uses the macro STPUTC to add characters to the string. In
1419 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1420 * grown as necessary. When the user is done, she can just leave the
1421 * string there and refer to it using stackblock(). Or she can allocate
1422 * the space for it using grabstackstr(). If it is necessary to allow
1423 * someone else to use the stack temporarily and then continue to grow
1424 * the string, the user should use grabstack to allocate the space, and
1425 * then call ungrabstr(p) to return to the previous mode of operation.
1427 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1428 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1429 * is space for at least one character.
1434 size_t len
= stackblocksize();
1435 if (herefd
>= 0 && len
>= 1024) {
1436 full_write(herefd
, stackblock(), len
);
1437 return stackblock();
1440 return (char *)stackblock() + len
;
1444 * Called from CHECKSTRSPACE.
1447 makestrspace(size_t newlen
, char *p
)
1449 size_t len
= p
- g_stacknxt
;
1450 size_t size
= stackblocksize();
1455 size
= stackblocksize();
1457 if (nleft
>= newlen
)
1461 return (char *)stackblock() + len
;
1465 stack_nputstr(const char *s
, size_t n
, char *p
)
1467 p
= makestrspace(n
, p
);
1468 p
= (char *)memcpy(p
, s
, n
) + n
;
1473 stack_putstr(const char *s
, char *p
)
1475 return stack_nputstr(s
, strlen(s
), p
);
1479 _STPUTC(int c
, char *p
)
1487 #define STARTSTACKSTR(p) ((p) = stackblock())
1488 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1489 #define CHECKSTRSPACE(n, p) do { \
1492 size_t m = sstrend - q; \
1494 (p) = makestrspace(l, q); \
1496 #define USTPUTC(c, p) (*(p)++ = (c))
1497 #define STACKSTRNUL(p) do { \
1498 if ((p) == sstrend) \
1499 (p) = growstackstr(); \
1502 #define STUNPUTC(p) (--(p))
1503 #define STTOPC(p) ((p)[-1])
1504 #define STADJUST(amount, p) ((p) += (amount))
1506 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1507 #define ungrabstackstr(s, p) stunalloc(s)
1508 #define stackstrend() ((void *)sstrend)
1511 /* ============ String helpers */
1514 * prefix -- see if pfx is a prefix of string.
1517 prefix(const char *string
, const char *pfx
)
1520 if (*pfx
++ != *string
++)
1523 return (char *) string
;
1527 * Check for a valid number. This should be elsewhere.
1530 is_number(const char *p
)
1535 } while (*++p
!= '\0');
1540 * Convert a string of digits to an integer, printing an error message on
1544 number(const char *s
)
1547 ash_msg_and_raise_error(illnum
, s
);
1552 * Produce a possibly single quoted string suitable as input to the shell.
1553 * The return string is allocated on the stack.
1556 single_quote(const char *s
)
1566 len
= strchrnul(s
, '\'') - s
;
1568 q
= p
= makestrspace(len
+ 3, p
);
1571 q
= (char *)memcpy(q
, s
, len
) + len
;
1577 len
= strspn(s
, "'");
1581 q
= p
= makestrspace(len
+ 3, p
);
1584 q
= (char *)memcpy(q
, s
, len
) + len
;
1593 return stackblock();
1597 /* ============ nextopt */
1599 static char **argptr
; /* argument list for builtin commands */
1600 static char *optionarg
; /* set by nextopt (like getopt) */
1601 static char *optptr
; /* used by nextopt */
1604 * XXX - should get rid of. Have all builtins use getopt(3).
1605 * The library getopt must have the BSD extension static variable
1606 * "optreset", otherwise it can't be used within the shell safely.
1608 * Standard option processing (a la getopt) for builtin routines.
1609 * The only argument that is passed to nextopt is the option string;
1610 * the other arguments are unnecessary. It returns the character,
1611 * or '\0' on end of input.
1614 nextopt(const char *optstring
)
1621 if (p
== NULL
|| *p
== '\0') {
1622 /* We ate entire "-param", take next one */
1628 if (*++p
== '\0') /* just "-" ? */
1631 if (LONE_DASH(p
)) /* "--" ? */
1633 /* p => next "-param" */
1635 /* p => some option char in the middle of a "-param" */
1637 for (q
= optstring
; *q
!= c
;) {
1639 ash_msg_and_raise_error("illegal option -%c", c
);
1647 ash_msg_and_raise_error("no arg for -%c option", c
);
1657 /* ============ Shell variables */
1660 * The parsefile structure pointed to by the global variable parsefile
1661 * contains information about the current file being read.
1664 int nparam
; /* # of positional parameters (without $0) */
1665 #if ENABLE_ASH_GETOPTS
1666 int optind
; /* next parameter to be processed by getopts */
1667 int optoff
; /* used by getopts */
1669 unsigned char malloced
; /* if parameter list dynamically allocated */
1670 char **p
; /* parameter list */
1674 * Free the list of positional parameters.
1677 freeparam(volatile struct shparam
*param
)
1679 if (param
->malloced
) {
1681 ap
= ap1
= param
->p
;
1688 #if ENABLE_ASH_GETOPTS
1689 static void getoptsreset(const char *value
);
1693 struct var
*next
; /* next entry in hash list */
1694 int flags
; /* flags are defined above */
1695 const char *text
; /* name=value */
1696 void (*func
)(const char *); /* function to be called when */
1697 /* the variable gets set/unset */
1701 struct localvar
*next
; /* next local variable in list */
1702 struct var
*vp
; /* the variable that was made local */
1703 int flags
; /* saved flags */
1704 const char *text
; /* saved text */
1708 #define VEXPORT 0x01 /* variable is exported */
1709 #define VREADONLY 0x02 /* variable cannot be modified */
1710 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1711 #define VTEXTFIXED 0x08 /* text is statically allocated */
1712 #define VSTACK 0x10 /* text is allocated on the stack */
1713 #define VUNSET 0x20 /* the variable is not set */
1714 #define VNOFUNC 0x40 /* don't call the callback function */
1715 #define VNOSET 0x80 /* do not set variable - just readonly test */
1716 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1717 #if ENABLE_ASH_RANDOM_SUPPORT
1718 # define VDYNAMIC 0x200 /* dynamic variable */
1724 static const char defifsvar
[] ALIGN1
= "IFS= \t\n";
1725 #define defifs (defifsvar + 4)
1727 static const char defifs
[] ALIGN1
= " \t\n";
1731 /* Need to be before varinit_data[] */
1732 #if ENABLE_LOCALE_SUPPORT
1734 change_lc_all(const char *value
)
1736 if (value
&& *value
!= '\0')
1737 setlocale(LC_ALL
, value
);
1740 change_lc_ctype(const char *value
)
1742 if (value
&& *value
!= '\0')
1743 setlocale(LC_CTYPE
, value
);
1747 static void chkmail(void);
1748 static void changemail(const char *);
1750 static void changepath(const char *);
1751 #if ENABLE_ASH_RANDOM_SUPPORT
1752 static void change_random(const char *);
1755 static const struct {
1758 void (*func
)(const char *);
1759 } varinit_data
[] = {
1761 { VSTRFIXED
|VTEXTFIXED
, defifsvar
, NULL
},
1763 { VSTRFIXED
|VTEXTFIXED
|VUNSET
, "IFS\0" , NULL
},
1766 { VSTRFIXED
|VTEXTFIXED
|VUNSET
, "MAIL\0" , changemail
},
1767 { VSTRFIXED
|VTEXTFIXED
|VUNSET
, "MAILPATH\0", changemail
},
1769 { VSTRFIXED
|VTEXTFIXED
, bb_PATH_root_path
, changepath
},
1770 { VSTRFIXED
|VTEXTFIXED
, "PS1=$ " , NULL
},
1771 { VSTRFIXED
|VTEXTFIXED
, "PS2=> " , NULL
},
1772 { VSTRFIXED
|VTEXTFIXED
, "PS4=+ " , NULL
},
1773 #if ENABLE_ASH_GETOPTS
1774 { VSTRFIXED
|VTEXTFIXED
, "OPTIND=1" , getoptsreset
},
1776 #if ENABLE_ASH_RANDOM_SUPPORT
1777 { VSTRFIXED
|VTEXTFIXED
|VUNSET
|VDYNAMIC
, "RANDOM\0", change_random
},
1779 #if ENABLE_LOCALE_SUPPORT
1780 { VSTRFIXED
|VTEXTFIXED
|VUNSET
, "LC_ALL\0" , change_lc_all
},
1781 { VSTRFIXED
|VTEXTFIXED
|VUNSET
, "LC_CTYPE\0", change_lc_ctype
},
1783 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1784 { VSTRFIXED
|VTEXTFIXED
|VUNSET
, "HISTFILE\0", NULL
},
1790 struct globals_var
{
1791 struct shparam shellparam
; /* $@ current positional parameters */
1792 struct redirtab
*redirlist
;
1794 int preverrout_fd
; /* save fd2 before print debug if xflag is set. */
1795 struct var
*vartab
[VTABSIZE
];
1796 struct var varinit
[ARRAY_SIZE(varinit_data
)];
1798 extern struct globals_var
*const ash_ptr_to_globals_var
;
1799 #define G_var (*ash_ptr_to_globals_var)
1800 #define shellparam (G_var.shellparam )
1801 //#define redirlist (G_var.redirlist )
1802 #define g_nullredirs (G_var.g_nullredirs )
1803 #define preverrout_fd (G_var.preverrout_fd)
1804 #define vartab (G_var.vartab )
1805 #define varinit (G_var.varinit )
1806 #define INIT_G_var() do { \
1808 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1810 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
1811 varinit[i].flags = varinit_data[i].flags; \
1812 varinit[i].text = varinit_data[i].text; \
1813 varinit[i].func = varinit_data[i].func; \
1817 #define vifs varinit[0]
1819 # define vmail (&vifs)[1]
1820 # define vmpath (&vmail)[1]
1821 # define vpath (&vmpath)[1]
1823 # define vpath (&vifs)[1]
1825 #define vps1 (&vpath)[1]
1826 #define vps2 (&vps1)[1]
1827 #define vps4 (&vps2)[1]
1828 #if ENABLE_ASH_GETOPTS
1829 # define voptind (&vps4)[1]
1830 # if ENABLE_ASH_RANDOM_SUPPORT
1831 # define vrandom (&voptind)[1]
1834 # if ENABLE_ASH_RANDOM_SUPPORT
1835 # define vrandom (&vps4)[1]
1840 * The following macros access the values of the above variables.
1841 * They have to skip over the name. They return the null string
1842 * for unset variables.
1844 #define ifsval() (vifs.text + 4)
1845 #define ifsset() ((vifs.flags & VUNSET) == 0)
1847 # define mailval() (vmail.text + 5)
1848 # define mpathval() (vmpath.text + 9)
1849 # define mpathset() ((vmpath.flags & VUNSET) == 0)
1851 #define pathval() (vpath.text + 5)
1852 #define ps1val() (vps1.text + 4)
1853 #define ps2val() (vps2.text + 4)
1854 #define ps4val() (vps4.text + 4)
1855 #if ENABLE_ASH_GETOPTS
1856 # define optindval() (voptind.text + 7)
1860 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
1861 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
1863 #if ENABLE_ASH_GETOPTS
1865 getoptsreset(const char *value
)
1867 shellparam
.optind
= number(value
);
1868 shellparam
.optoff
= -1;
1873 * Return of a legal variable name (a letter or underscore followed by zero or
1874 * more letters, underscores, and digits).
1877 endofname(const char *name
)
1885 if (!is_in_name(*p
))
1892 * Compares two strings up to the first = or '\0'. The first
1893 * string must be terminated by '='; the second may be terminated by
1894 * either '=' or '\0'.
1897 varcmp(const char *p
, const char *q
)
1901 while ((c
= *p
) == (d
= *q
)) {
1916 varequal(const char *a
, const char *b
)
1918 return !varcmp(a
, b
);
1922 * Find the appropriate entry in the hash table from the name.
1924 static struct var
**
1925 hashvar(const char *p
)
1929 hashval
= ((unsigned char) *p
) << 4;
1930 while (*p
&& *p
!= '=')
1931 hashval
+= (unsigned char) *p
++;
1932 return &vartab
[hashval
% VTABSIZE
];
1936 vpcmp(const void *a
, const void *b
)
1938 return varcmp(*(const char **)a
, *(const char **)b
);
1942 * This routine initializes the builtin variables.
1952 * PS1 depends on uid
1954 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1955 vps1
.text
= "PS1=\\w \\$ ";
1958 vps1
.text
= "PS1=# ";
1961 end
= vp
+ ARRAY_SIZE(varinit
);
1963 vpp
= hashvar(vp
->text
);
1966 } while (++vp
< end
);
1969 static struct var
**
1970 findvar(struct var
**vpp
, const char *name
)
1972 for (; *vpp
; vpp
= &(*vpp
)->next
) {
1973 if (varequal((*vpp
)->text
, name
)) {
1981 * Find the value of a variable. Returns NULL if not set.
1984 lookupvar(const char *name
)
1988 v
= *findvar(hashvar(name
), name
);
1990 #if ENABLE_ASH_RANDOM_SUPPORT
1992 * Dynamic variables are implemented roughly the same way they are
1993 * in bash. Namely, they're "special" so long as they aren't unset.
1994 * As soon as they're unset, they're no longer dynamic, and dynamic
1995 * lookup will no longer happen at that point. -- PFM.
1997 if ((v
->flags
& VDYNAMIC
))
2000 if (!(v
->flags
& VUNSET
))
2001 return strchrnul(v
->text
, '=') + 1;
2007 * Search the environment of a builtin command.
2010 bltinlookup(const char *name
)
2014 for (sp
= cmdenviron
; sp
; sp
= sp
->next
) {
2015 if (varequal(sp
->text
, name
))
2016 return strchrnul(sp
->text
, '=') + 1;
2018 return lookupvar(name
);
2022 * Same as setvar except that the variable and value are passed in
2023 * the first argument as name=value. Since the first argument will
2024 * be actually stored in the table, it should not be a string that
2026 * Called with interrupts off.
2029 setvareq(char *s
, int flags
)
2031 struct var
*vp
, **vpp
;
2034 flags
|= (VEXPORT
& (((unsigned) (1 - aflag
)) - 1));
2035 vp
= *findvar(vpp
, s
);
2037 if ((vp
->flags
& (VREADONLY
|VDYNAMIC
)) == VREADONLY
) {
2040 if (flags
& VNOSAVE
)
2043 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n
, '=') - n
, n
);
2049 if (vp
->func
&& (flags
& VNOFUNC
) == 0)
2050 (*vp
->func
)(strchrnul(s
, '=') + 1);
2052 if ((vp
->flags
& (VTEXTFIXED
|VSTACK
)) == 0)
2053 free((char*)vp
->text
);
2055 flags
|= vp
->flags
& ~(VTEXTFIXED
|VSTACK
|VNOSAVE
|VUNSET
);
2060 vp
= ckzalloc(sizeof(*vp
));
2062 /*vp->func = NULL; - ckzalloc did it */
2065 if (!(flags
& (VTEXTFIXED
|VSTACK
|VNOSAVE
)))
2072 * Set the value of a variable. The flags argument is ored with the
2073 * flags of the variable. If val is NULL, the variable is unset.
2076 setvar(const char *name
, const char *val
, int flags
)
2083 q
= endofname(name
);
2084 p
= strchrnul(q
, '=');
2086 if (!namelen
|| p
!= q
)
2087 ash_msg_and_raise_error("%.*s: bad variable name", namelen
, name
);
2092 vallen
= strlen(val
);
2095 nameeq
= ckmalloc(namelen
+ vallen
+ 2);
2096 p
= (char *)memcpy(nameeq
, name
, namelen
) + namelen
;
2099 p
= (char *)memcpy(p
, val
, vallen
) + vallen
;
2102 setvareq(nameeq
, flags
| VNOSAVE
);
2106 #if ENABLE_ASH_GETOPTS
2108 * Safe version of setvar, returns 1 on success 0 on failure.
2111 setvarsafe(const char *name
, const char *val
, int flags
)
2114 volatile int saveint
;
2115 struct jmploc
*volatile savehandler
= exception_handler
;
2116 struct jmploc jmploc
;
2119 if (setjmp(jmploc
.loc
))
2122 exception_handler
= &jmploc
;
2123 setvar(name
, val
, flags
);
2126 exception_handler
= savehandler
;
2127 RESTORE_INT(saveint
);
2133 * Unset the specified variable.
2136 unsetvar(const char *s
)
2142 vpp
= findvar(hashvar(s
), s
);
2146 int flags
= vp
->flags
;
2149 if (flags
& VREADONLY
)
2151 #if ENABLE_ASH_RANDOM_SUPPORT
2152 vp
->flags
&= ~VDYNAMIC
;
2156 if ((flags
& VSTRFIXED
) == 0) {
2158 if ((flags
& (VTEXTFIXED
|VSTACK
)) == 0)
2159 free((char*)vp
->text
);
2165 vp
->flags
&= ~VEXPORT
;
2175 * Process a linked list of variable assignments.
2178 listsetvar(struct strlist
*list_set_var
, int flags
)
2180 struct strlist
*lp
= list_set_var
;
2186 setvareq(lp
->text
, flags
);
2193 * Generate a list of variables satisfying the given conditions.
2196 listvars(int on
, int off
, char ***end
)
2207 for (vp
= *vpp
; vp
; vp
= vp
->next
) {
2208 if ((vp
->flags
& mask
) == on
) {
2209 if (ep
== stackstrend())
2210 ep
= growstackstr();
2211 *ep
++ = (char *) vp
->text
;
2214 } while (++vpp
< vartab
+ VTABSIZE
);
2215 if (ep
== stackstrend())
2216 ep
= growstackstr();
2220 return grabstackstr(ep
);
2224 /* ============ Path search helper
2226 * The variable path (passed by reference) should be set to the start
2227 * of the path before the first call; padvance will update
2228 * this value as it proceeds. Successive calls to padvance will return
2229 * the possible path expansions in sequence. If an option (indicated by
2230 * a percent sign) appears in the path entry then the global variable
2231 * pathopt will be set to point to it; otherwise pathopt will be set to
2234 static const char *pathopt
; /* set by padvance */
2237 padvance(const char **path
, const char *name
)
2247 for (p
= start
; *p
&& *p
!= ':' && *p
!= '%'; p
++)
2249 len
= p
- start
+ strlen(name
) + 2; /* "2" is for '/' and '\0' */
2250 while (stackblocksize() < len
)
2254 memcpy(q
, start
, p
- start
);
2262 while (*p
&& *p
!= ':')
2269 return stalloc(len
);
2273 /* ============ Prompt */
2275 static smallint doprompt
; /* if set, prompt the user */
2276 static smallint needprompt
; /* true if interactive and at start of line */
2278 #if ENABLE_FEATURE_EDITING
2279 static line_input_t
*line_input_state
;
2280 static const char *cmdedit_prompt
;
2282 putprompt(const char *s
)
2284 if (ENABLE_ASH_EXPAND_PRMT
) {
2285 free((char*)cmdedit_prompt
);
2286 cmdedit_prompt
= ckstrdup(s
);
2293 putprompt(const char *s
)
2299 #if ENABLE_ASH_EXPAND_PRMT
2300 /* expandstr() needs parsing machinery, so it is far away ahead... */
2301 static const char *expandstr(const char *ps
);
2303 #define expandstr(s) s
2307 setprompt(int whichprompt
)
2310 #if ENABLE_ASH_EXPAND_PRMT
2311 struct stackmark smark
;
2316 switch (whichprompt
) {
2326 #if ENABLE_ASH_EXPAND_PRMT
2327 setstackmark(&smark
);
2328 stalloc(stackblocksize());
2330 putprompt(expandstr(prompt
));
2331 #if ENABLE_ASH_EXPAND_PRMT
2332 popstackmark(&smark
);
2337 /* ============ The cd and pwd commands */
2339 #define CD_PHYSICAL 1
2342 static int docd(const char *, int);
2351 while ((i
= nextopt("LP"))) {
2353 flags
^= CD_PHYSICAL
;
2362 * Update curdir (the name of the current directory) in response to a
2366 updatepwd(const char *dir
)
2373 cdcomppath
= ststrdup(dir
);
2376 if (curdir
== nullstr
)
2378 new = stack_putstr(curdir
, new);
2380 new = makestrspace(strlen(dir
) + 2, new);
2381 lim
= (char *)stackblock() + 1;
2385 if (new > lim
&& *lim
== '/')
2390 if (dir
[1] == '/' && dir
[2] != '/') {
2396 p
= strtok(cdcomppath
, "/");
2400 if (p
[1] == '.' && p
[2] == '\0') {
2412 new = stack_putstr(p
, new);
2420 return stackblock();
2424 * Find out what the current directory is. If we already know the current
2425 * directory, this routine returns immediately.
2430 char *dir
= getcwd(NULL
, 0); /* huh, using glibc extension? */
2431 return dir
? dir
: nullstr
;
2435 setpwd(const char *val
, int setold
)
2439 oldcur
= dir
= curdir
;
2442 setvar("OLDPWD", oldcur
, VEXPORT
);
2445 if (physdir
!= nullstr
) {
2446 if (physdir
!= oldcur
)
2450 if (oldcur
== val
|| !val
) {
2456 dir
= ckstrdup(val
);
2457 if (oldcur
!= dir
&& oldcur
!= nullstr
) {
2462 setvar("PWD", dir
, VEXPORT
);
2465 static void hashcd(void);
2468 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2469 * know that the current directory has changed.
2472 docd(const char *dest
, int flags
)
2474 const char *dir
= 0;
2477 TRACE(("docd(\"%s\", %d) called\n", dest
, flags
));
2480 if (!(flags
& CD_PHYSICAL
)) {
2481 dir
= updatepwd(dest
);
2496 cdcmd(int argc UNUSED_PARAM
, char **argv UNUSED_PARAM
)
2508 dest
= bltinlookup(homestr
);
2509 else if (LONE_DASH(dest
)) {
2510 dest
= bltinlookup("OLDPWD");
2532 path
= bltinlookup("CDPATH");
2541 p
= padvance(&path
, dest
);
2542 if (stat(p
, &statb
) >= 0 && S_ISDIR(statb
.st_mode
)) {
2546 if (!docd(p
, flags
))
2551 ash_msg_and_raise_error("can't cd to %s", dest
);
2554 if (flags
& CD_PRINT
)
2555 out1fmt(snlfmt
, curdir
);
2560 pwdcmd(int argc UNUSED_PARAM
, char **argv UNUSED_PARAM
)
2563 const char *dir
= curdir
;
2567 if (physdir
== nullstr
)
2571 out1fmt(snlfmt
, dir
);
2576 /* ============ ... */
2579 #define IBUFSIZ COMMON_BUFSIZE
2580 /* buffer for top level input file */
2581 #define basebuf bb_common_bufsiz1
2583 /* Syntax classes */
2584 #define CWORD 0 /* character is nothing special */
2585 #define CNL 1 /* newline character */
2586 #define CBACK 2 /* a backslash character */
2587 #define CSQUOTE 3 /* single quote */
2588 #define CDQUOTE 4 /* double quote */
2589 #define CENDQUOTE 5 /* a terminating quote */
2590 #define CBQUOTE 6 /* backwards single quote */
2591 #define CVAR 7 /* a dollar sign */
2592 #define CENDVAR 8 /* a '}' character */
2593 #define CLP 9 /* a left paren in arithmetic */
2594 #define CRP 10 /* a right paren in arithmetic */
2595 #define CENDFILE 11 /* end of file */
2596 #define CCTL 12 /* like CWORD, except it must be escaped */
2597 #define CSPCL 13 /* these terminate a word */
2598 #define CIGN 14 /* character should be ignored */
2600 #if ENABLE_ASH_ALIAS
2604 #define PEOA_OR_PEOF PEOA
2608 #define PEOA_OR_PEOF PEOF
2611 /* number syntax index */
2612 #define BASESYNTAX 0 /* not in quotes */
2613 #define DQSYNTAX 1 /* in double quotes */
2614 #define SQSYNTAX 2 /* in single quotes */
2615 #define ARISYNTAX 3 /* in arithmetic */
2616 #define PSSYNTAX 4 /* prompt */
2618 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
2619 #define USE_SIT_FUNCTION
2622 #if ENABLE_SH_MATH_SUPPORT
2623 static const char S_I_T
[][4] = {
2624 #if ENABLE_ASH_ALIAS
2625 { CSPCL
, CIGN
, CIGN
, CIGN
}, /* 0, PEOA */
2627 { CSPCL
, CWORD
, CWORD
, CWORD
}, /* 1, ' ' */
2628 { CNL
, CNL
, CNL
, CNL
}, /* 2, \n */
2629 { CWORD
, CCTL
, CCTL
, CWORD
}, /* 3, !*-/:=?[]~ */
2630 { CDQUOTE
, CENDQUOTE
, CWORD
, CWORD
}, /* 4, '"' */
2631 { CVAR
, CVAR
, CWORD
, CVAR
}, /* 5, $ */
2632 { CSQUOTE
, CWORD
, CENDQUOTE
, CWORD
}, /* 6, "'" */
2633 { CSPCL
, CWORD
, CWORD
, CLP
}, /* 7, ( */
2634 { CSPCL
, CWORD
, CWORD
, CRP
}, /* 8, ) */
2635 { CBACK
, CBACK
, CCTL
, CBACK
}, /* 9, \ */
2636 { CBQUOTE
, CBQUOTE
, CWORD
, CBQUOTE
}, /* 10, ` */
2637 { CENDVAR
, CENDVAR
, CWORD
, CENDVAR
}, /* 11, } */
2638 #ifndef USE_SIT_FUNCTION
2639 { CENDFILE
, CENDFILE
, CENDFILE
, CENDFILE
}, /* 12, PEOF */
2640 { CWORD
, CWORD
, CWORD
, CWORD
}, /* 13, 0-9A-Za-z */
2641 { CCTL
, CCTL
, CCTL
, CCTL
} /* 14, CTLESC ... */
2645 static const char S_I_T
[][3] = {
2646 #if ENABLE_ASH_ALIAS
2647 { CSPCL
, CIGN
, CIGN
}, /* 0, PEOA */
2649 { CSPCL
, CWORD
, CWORD
}, /* 1, ' ' */
2650 { CNL
, CNL
, CNL
}, /* 2, \n */
2651 { CWORD
, CCTL
, CCTL
}, /* 3, !*-/:=?[]~ */
2652 { CDQUOTE
, CENDQUOTE
, CWORD
}, /* 4, '"' */
2653 { CVAR
, CVAR
, CWORD
}, /* 5, $ */
2654 { CSQUOTE
, CWORD
, CENDQUOTE
}, /* 6, "'" */
2655 { CSPCL
, CWORD
, CWORD
}, /* 7, ( */
2656 { CSPCL
, CWORD
, CWORD
}, /* 8, ) */
2657 { CBACK
, CBACK
, CCTL
}, /* 9, \ */
2658 { CBQUOTE
, CBQUOTE
, CWORD
}, /* 10, ` */
2659 { CENDVAR
, CENDVAR
, CWORD
}, /* 11, } */
2660 #ifndef USE_SIT_FUNCTION
2661 { CENDFILE
, CENDFILE
, CENDFILE
}, /* 12, PEOF */
2662 { CWORD
, CWORD
, CWORD
}, /* 13, 0-9A-Za-z */
2663 { CCTL
, CCTL
, CCTL
} /* 14, CTLESC ... */
2666 #endif /* SH_MATH_SUPPORT */
2668 #ifdef USE_SIT_FUNCTION
2671 SIT(int c
, int syntax
)
2673 static const char spec_symbls
[] ALIGN1
= "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
2674 #if ENABLE_ASH_ALIAS
2675 static const char syntax_index_table
[] ALIGN1
= {
2676 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2677 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2678 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2682 static const char syntax_index_table
[] ALIGN1
= {
2683 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2684 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2685 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2692 if (c
== PEOF
) { /* 2^8+2 */
2695 #if ENABLE_ASH_ALIAS
2696 if (c
== PEOA
) { /* 2^8+1 */
2701 if ((unsigned char)c
>= (unsigned char)(CTLESC
)
2702 && (unsigned char)c
<= (unsigned char)(CTLQUOTEMARK
)
2706 s
= strchrnul(spec_symbls
, c
);
2710 indx
= syntax_index_table
[s
- spec_symbls
];
2712 return S_I_T
[indx
][syntax
];
2715 #else /* !USE_SIT_FUNCTION */
2717 #if ENABLE_ASH_ALIAS
2718 #define CSPCL_CIGN_CIGN_CIGN 0
2719 #define CSPCL_CWORD_CWORD_CWORD 1
2720 #define CNL_CNL_CNL_CNL 2
2721 #define CWORD_CCTL_CCTL_CWORD 3
2722 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
2723 #define CVAR_CVAR_CWORD_CVAR 5
2724 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
2725 #define CSPCL_CWORD_CWORD_CLP 7
2726 #define CSPCL_CWORD_CWORD_CRP 8
2727 #define CBACK_CBACK_CCTL_CBACK 9
2728 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
2729 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
2730 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
2731 #define CWORD_CWORD_CWORD_CWORD 13
2732 #define CCTL_CCTL_CCTL_CCTL 14
2734 #define CSPCL_CWORD_CWORD_CWORD 0
2735 #define CNL_CNL_CNL_CNL 1
2736 #define CWORD_CCTL_CCTL_CWORD 2
2737 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
2738 #define CVAR_CVAR_CWORD_CVAR 4
2739 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
2740 #define CSPCL_CWORD_CWORD_CLP 6
2741 #define CSPCL_CWORD_CWORD_CRP 7
2742 #define CBACK_CBACK_CCTL_CBACK 8
2743 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
2744 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
2745 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
2746 #define CWORD_CWORD_CWORD_CWORD 12
2747 #define CCTL_CCTL_CCTL_CCTL 13
2750 static const char syntax_index_table
[258] = {
2751 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
2752 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE
,
2753 #if ENABLE_ASH_ALIAS
2754 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN
,
2756 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD
,
2757 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL
,
2758 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL
,
2759 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL
,
2760 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL
,
2761 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL
,
2762 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL
,
2763 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL
,
2764 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL
,
2765 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD
,
2766 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD
,
2767 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD
,
2768 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD
,
2769 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD
,
2770 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD
,
2771 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD
,
2772 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD
,
2773 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD
,
2774 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD
,
2775 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD
,
2776 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD
,
2777 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD
,
2778 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD
,
2779 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD
,
2780 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD
,
2781 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD
,
2782 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD
,
2783 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD
,
2784 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD
,
2785 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD
,
2786 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD
,
2787 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD
,
2788 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD
,
2789 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD
,
2790 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD
,
2791 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD
,
2792 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD
,
2793 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD
,
2794 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD
,
2795 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD
,
2796 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD
,
2797 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD
,
2798 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD
,
2799 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD
,
2800 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD
,
2801 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD
,
2802 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD
,
2803 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD
,
2804 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD
,
2805 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD
,
2806 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD
,
2807 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD
,
2808 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD
,
2809 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD
,
2810 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD
,
2811 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD
,
2812 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD
,
2813 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD
,
2814 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD
,
2815 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD
,
2816 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD
,
2817 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD
,
2818 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD
,
2819 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD
,
2820 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD
,
2821 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD
,
2822 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD
,
2823 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD
,
2824 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD
,
2825 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD
,
2826 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD
,
2827 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD
,
2828 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD
,
2829 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD
,
2830 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD
,
2831 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD
,
2832 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD
,
2833 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD
,
2834 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD
,
2835 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD
,
2836 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD
,
2837 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD
,
2838 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD
,
2839 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD
,
2840 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD
,
2841 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD
,
2842 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD
,
2843 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD
,
2844 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD
,
2845 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD
,
2846 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD
,
2847 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD
,
2848 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD
,
2849 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD
,
2850 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD
,
2851 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD
,
2852 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD
,
2853 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD
,
2854 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD
,
2855 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD
,
2856 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD
,
2857 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD
,
2858 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD
,
2859 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD
,
2860 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD
,
2861 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD
,
2862 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD
,
2863 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD
,
2864 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD
,
2865 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD
,
2866 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD
,
2867 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD
,
2868 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD
,
2869 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD
,
2870 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD
,
2871 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD
,
2872 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD
,
2873 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD
,
2874 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD
,
2875 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD
,
2876 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD
,
2877 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD
,
2878 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD
,
2879 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD
,
2880 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD
,
2881 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD
,
2882 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD
,
2883 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD
,
2884 /* 130 0 */ CWORD_CWORD_CWORD_CWORD
,
2885 /* 131 1 */ CWORD_CWORD_CWORD_CWORD
,
2886 /* 132 2 */ CWORD_CWORD_CWORD_CWORD
,
2887 /* 133 3 */ CWORD_CWORD_CWORD_CWORD
,
2888 /* 134 4 */ CWORD_CWORD_CWORD_CWORD
,
2889 /* 135 5 */ CWORD_CWORD_CWORD_CWORD
,
2890 /* 136 6 */ CWORD_CWORD_CWORD_CWORD
,
2891 /* 137 7 */ CWORD_CWORD_CWORD_CWORD
,
2892 /* 138 8 */ CWORD_CWORD_CWORD_CWORD
,
2893 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD
,
2894 /* 140 10 "\n" */ CNL_CNL_CNL_CNL
,
2895 /* 141 11 */ CWORD_CWORD_CWORD_CWORD
,
2896 /* 142 12 */ CWORD_CWORD_CWORD_CWORD
,
2897 /* 143 13 */ CWORD_CWORD_CWORD_CWORD
,
2898 /* 144 14 */ CWORD_CWORD_CWORD_CWORD
,
2899 /* 145 15 */ CWORD_CWORD_CWORD_CWORD
,
2900 /* 146 16 */ CWORD_CWORD_CWORD_CWORD
,
2901 /* 147 17 */ CWORD_CWORD_CWORD_CWORD
,
2902 /* 148 18 */ CWORD_CWORD_CWORD_CWORD
,
2903 /* 149 19 */ CWORD_CWORD_CWORD_CWORD
,
2904 /* 150 20 */ CWORD_CWORD_CWORD_CWORD
,
2905 /* 151 21 */ CWORD_CWORD_CWORD_CWORD
,
2906 /* 152 22 */ CWORD_CWORD_CWORD_CWORD
,
2907 /* 153 23 */ CWORD_CWORD_CWORD_CWORD
,
2908 /* 154 24 */ CWORD_CWORD_CWORD_CWORD
,
2909 /* 155 25 */ CWORD_CWORD_CWORD_CWORD
,
2910 /* 156 26 */ CWORD_CWORD_CWORD_CWORD
,
2911 /* 157 27 */ CWORD_CWORD_CWORD_CWORD
,
2912 /* 158 28 */ CWORD_CWORD_CWORD_CWORD
,
2913 /* 159 29 */ CWORD_CWORD_CWORD_CWORD
,
2914 /* 160 30 */ CWORD_CWORD_CWORD_CWORD
,
2915 /* 161 31 */ CWORD_CWORD_CWORD_CWORD
,
2916 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD
,
2917 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD
,
2918 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD
,
2919 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD
,
2920 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR
,
2921 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD
,
2922 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD
,
2923 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD
,
2924 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP
,
2925 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP
,
2926 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD
,
2927 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD
,
2928 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD
,
2929 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD
,
2930 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD
,
2931 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD
,
2932 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD
,
2933 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD
,
2934 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD
,
2935 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD
,
2936 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD
,
2937 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD
,
2938 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD
,
2939 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD
,
2940 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD
,
2941 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD
,
2942 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD
,
2943 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD
,
2944 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD
,
2945 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD
,
2946 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD
,
2947 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD
,
2948 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD
,
2949 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD
,
2950 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD
,
2951 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD
,
2952 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD
,
2953 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD
,
2954 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD
,
2955 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD
,
2956 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD
,
2957 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD
,
2958 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD
,
2959 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD
,
2960 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD
,
2961 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD
,
2962 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD
,
2963 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD
,
2964 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD
,
2965 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD
,
2966 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD
,
2967 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD
,
2968 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD
,
2969 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD
,
2970 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD
,
2971 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD
,
2972 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD
,
2973 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD
,
2974 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD
,
2975 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD
,
2976 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK
,
2977 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD
,
2978 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD
,
2979 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD
,
2980 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE
,
2981 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD
,
2982 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD
,
2983 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD
,
2984 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD
,
2985 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD
,
2986 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD
,
2987 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD
,
2988 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD
,
2989 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD
,
2990 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD
,
2991 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD
,
2992 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD
,
2993 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD
,
2994 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD
,
2995 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD
,
2996 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD
,
2997 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD
,
2998 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD
,
2999 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD
,
3000 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD
,
3001 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD
,
3002 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD
,
3003 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD
,
3004 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD
,
3005 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD
,
3006 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD
,
3007 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD
,
3008 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD
,
3009 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR
,
3010 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD
,
3011 /* 257 127 */ CWORD_CWORD_CWORD_CWORD
,
3014 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[(int)(c) + SYNBASE]][syntax])
3016 #endif /* USE_SIT_FUNCTION */
3019 /* ============ Alias handling */
3021 #if ENABLE_ASH_ALIAS
3023 #define ALIASINUSE 1
3034 static struct alias
**atab
; // [ATABSIZE];
3035 #define INIT_G_alias() do { \
3036 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3040 static struct alias
**
3041 __lookupalias(const char *name
) {
3042 unsigned int hashval
;
3049 ch
= (unsigned char)*p
;
3053 ch
= (unsigned char)*++p
;
3055 app
= &atab
[hashval
% ATABSIZE
];
3057 for (; *app
; app
= &(*app
)->next
) {
3058 if (strcmp(name
, (*app
)->name
) == 0) {
3066 static struct alias
*
3067 lookupalias(const char *name
, int check
)
3069 struct alias
*ap
= *__lookupalias(name
);
3071 if (check
&& ap
&& (ap
->flag
& ALIASINUSE
))
3076 static struct alias
*
3077 freealias(struct alias
*ap
)
3081 if (ap
->flag
& ALIASINUSE
) {
3082 ap
->flag
|= ALIASDEAD
;
3094 setalias(const char *name
, const char *val
)
3096 struct alias
*ap
, **app
;
3098 app
= __lookupalias(name
);
3102 if (!(ap
->flag
& ALIASINUSE
)) {
3105 ap
->val
= ckstrdup(val
);
3106 ap
->flag
&= ~ALIASDEAD
;
3109 ap
= ckzalloc(sizeof(struct alias
));
3110 ap
->name
= ckstrdup(name
);
3111 ap
->val
= ckstrdup(val
);
3112 /*ap->flag = 0; - ckzalloc did it */
3113 /*ap->next = NULL;*/
3120 unalias(const char *name
)
3124 app
= __lookupalias(name
);
3128 *app
= freealias(*app
);
3139 struct alias
*ap
, **app
;
3143 for (i
= 0; i
< ATABSIZE
; i
++) {
3145 for (ap
= *app
; ap
; ap
= *app
) {
3146 *app
= freealias(*app
);
3156 printalias(const struct alias
*ap
)
3158 out1fmt("%s=%s\n", ap
->name
, single_quote(ap
->val
));
3162 * TODO - sort output
3165 aliascmd(int argc UNUSED_PARAM
, char **argv
)
3174 for (i
= 0; i
< ATABSIZE
; i
++) {
3175 for (ap
= atab
[i
]; ap
; ap
= ap
->next
) {
3181 while ((n
= *++argv
) != NULL
) {
3182 v
= strchr(n
+1, '=');
3183 if (v
== NULL
) { /* n+1: funny ksh stuff */
3184 ap
= *__lookupalias(n
);
3186 fprintf(stderr
, "%s: %s not found\n", "alias", n
);
3200 unaliascmd(int argc UNUSED_PARAM
, char **argv UNUSED_PARAM
)
3204 while ((i
= nextopt("a")) != '\0') {
3210 for (i
= 0; *argptr
; argptr
++) {
3211 if (unalias(*argptr
)) {
3212 fprintf(stderr
, "%s: %s not found\n", "unalias", *argptr
);
3220 #endif /* ASH_ALIAS */
3223 /* ============ jobs.c */
3225 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
3228 #define FORK_NOJOB 2
3230 /* mode flags for showjob(s) */
3231 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
3232 #define SHOW_PID 0x04 /* include process pid */
3233 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
3236 * A job structure contains information about a job. A job is either a
3237 * single process or a set of processes contained in a pipeline. In the
3238 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3243 pid_t pid
; /* process id */
3244 int status
; /* last process status from wait() */
3245 char *cmd
; /* text of command being run */
3249 struct procstat ps0
; /* status of process */
3250 struct procstat
*ps
; /* status or processes when more than one */
3252 int stopstatus
; /* status of a stopped job */
3255 nprocs
: 16, /* number of processes */
3257 #define JOBRUNNING 0 /* at least one proc running */
3258 #define JOBSTOPPED 1 /* all procs are stopped */
3259 #define JOBDONE 2 /* all procs are completed */
3261 sigint
: 1, /* job was killed by SIGINT */
3262 jobctl
: 1, /* job running under job control */
3264 waited
: 1, /* true if this entry has been waited for */
3265 used
: 1, /* true if this entry is in used */
3266 changed
: 1; /* true if status has changed */
3267 struct job
*prev_job
; /* previous job */
3270 static struct job
*makejob(/*union node *,*/ int);
3272 #define forkshell(job, node, mode) forkshell(job, mode)
3274 static int forkshell(struct job
*, union node
*, int);
3275 static int waitforjob(struct job
*);
3278 enum { doing_jobctl
= 0 };
3279 #define setjobctl(on) do {} while (0)
3281 static smallint doing_jobctl
; //references:8
3282 static void setjobctl(int);
3289 ignoresig(int signo
)
3291 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3292 if (sigmode
[signo
- 1] != S_IGN
&& sigmode
[signo
- 1] != S_HARD_IGN
) {
3293 /* No, need to do it */
3294 signal(signo
, SIG_IGN
);
3296 sigmode
[signo
- 1] = S_HARD_IGN
;
3300 * Signal handler. Only one usage site - in setsignal()
3305 gotsig
[signo
- 1] = 1;
3307 if (/* exsig || */ (signo
== SIGINT
&& !trap
[SIGINT
])) {
3310 raise_interrupt(); /* does not return */
3319 * Set the signal handler for the specified signal. The routine figures
3320 * out what it should be set to.
3323 setsignal(int signo
)
3326 char cur_act
, new_act
;
3327 struct sigaction act
;
3331 if (t
!= NULL
) { /* trap for this sig is set */
3333 if (t
[0] == '\0') /* trap is "": ignore this sig */
3337 if (rootshell
&& new_act
== S_DFL
) {
3340 if (iflag
|| minusc
|| sflag
== 0)
3349 * "In all cases, bash ignores SIGQUIT. Non-builtin
3350 * commands run by bash have signal handlers
3351 * set to the values inherited by the shell
3352 * from its parent". */
3368 //TODO: if !rootshell, we reset SIGQUIT to DFL,
3369 //whereas we have to restore it to what shell got on entry
3370 //from the parent. See comment above
3372 t
= &sigmode
[signo
- 1];
3375 /* current setting is not yet known */
3376 if (sigaction(signo
, NULL
, &act
)) {
3377 /* pretend it worked; maybe we should give a warning,
3378 * but other shells don't. We don't alter sigmode,
3379 * so we retry every time.
3380 * btw, in Linux it never fails. --vda */
3383 if (act
.sa_handler
== SIG_IGN
) {
3384 cur_act
= S_HARD_IGN
;
3386 && (signo
== SIGTSTP
|| signo
== SIGTTIN
|| signo
== SIGTTOU
)
3388 cur_act
= S_IGN
; /* don't hard ignore these */
3392 if (cur_act
== S_HARD_IGN
|| cur_act
== new_act
)
3395 act
.sa_handler
= SIG_DFL
;
3398 act
.sa_handler
= onsig
;
3399 act
.sa_flags
= 0; /* matters only if !DFL and !IGN */
3400 sigfillset(&act
.sa_mask
); /* ditto */
3403 act
.sa_handler
= SIG_IGN
;
3406 sigaction_set(signo
, &act
);
3411 /* mode flags for set_curjob */
3412 #define CUR_DELETE 2
3413 #define CUR_RUNNING 1
3414 #define CUR_STOPPED 0
3416 /* mode flags for dowait */
3417 #define DOWAIT_NONBLOCK WNOHANG
3418 #define DOWAIT_BLOCK 0
3421 /* pgrp of shell on invocation */
3422 static int initialpgrp
; //references:2
3423 static int ttyfd
= -1; //5
3426 static struct job
*jobtab
; //5
3428 static unsigned njobs
; //4
3430 static struct job
*curjob
; //lots
3431 /* number of presumed living untracked jobs */
3432 static int jobless
; //4
3435 set_curjob(struct job
*jp
, unsigned mode
)
3438 struct job
**jpp
, **curp
;
3440 /* first remove from list */
3441 jpp
= curp
= &curjob
;
3446 jpp
= &jp1
->prev_job
;
3448 *jpp
= jp1
->prev_job
;
3450 /* Then re-insert in correct position */
3458 /* job being deleted */
3461 /* newly created job or backgrounded job,
3462 put after all stopped jobs. */
3466 if (!jp1
|| jp1
->state
!= JOBSTOPPED
)
3469 jpp
= &jp1
->prev_job
;
3475 /* newly stopped job - becomes curjob */
3476 jp
->prev_job
= *jpp
;
3484 jobno(const struct job
*jp
)
3486 return jp
- jobtab
+ 1;
3491 * Convert a job name to a job structure.
3494 #define getjob(name, getctl) getjob(name)
3497 getjob(const char *name
, int getctl
)
3501 const char *err_msg
= "No such job: %s";
3505 char *(*match
)(const char *, const char *);
3520 if (c
== '+' || c
== '%') {
3522 err_msg
= "No current job";
3528 err_msg
= "No previous job";
3537 // TODO: number() instead? It does error checking...
3540 jp
= jobtab
+ num
- 1;
3557 if (match(jp
->ps
[0].cmd
, p
)) {
3561 err_msg
= "%s: ambiguous";
3568 err_msg
= "job %s not created under job control";
3569 if (getctl
&& jp
->jobctl
== 0)
3574 ash_msg_and_raise_error(err_msg
, name
);
3578 * Mark a job structure as unused.
3581 freejob(struct job
*jp
)
3583 struct procstat
*ps
;
3587 for (i
= jp
->nprocs
, ps
= jp
->ps
; --i
>= 0; ps
++) {
3588 if (ps
->cmd
!= nullstr
)
3591 if (jp
->ps
!= &jp
->ps0
)
3594 set_curjob(jp
, CUR_DELETE
);
3600 xtcsetpgrp(int fd
, pid_t pgrp
)
3602 if (tcsetpgrp(fd
, pgrp
))
3603 ash_msg_and_raise_error("can't set tty process group (%m)");
3607 * Turn job control on and off.
3609 * Note: This code assumes that the third arg to ioctl is a character
3610 * pointer, which is true on Berkeley systems but not System V. Since
3611 * System V doesn't have job control yet, this isn't a problem now.
3613 * Called with interrupts off.
3621 if (on
== doing_jobctl
|| rootshell
== 0)
3625 ofd
= fd
= open(_PATH_TTY
, O_RDWR
);
3627 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3628 * That sometimes helps to acquire controlling tty.
3629 * Obviously, a workaround for bugs when someone
3630 * failed to provide a controlling tty to bash! :) */
3636 fd
= fcntl(fd
, F_DUPFD
, 10);
3641 /* fd is a tty at this point */
3642 close_on_exec_on(fd
);
3643 do { /* while we are in the background */
3644 pgrp
= tcgetpgrp(fd
);
3647 ash_msg("can't access tty; job control turned off");
3651 if (pgrp
== getpgrp())
3662 xtcsetpgrp(fd
, pgrp
);
3664 /* turning job control off */
3667 /* was xtcsetpgrp, but this can make exiting ash
3668 * loop forever if pty is already deleted */
3669 tcsetpgrp(fd
, pgrp
);
3684 killcmd(int argc
, char **argv
)
3687 if (argv
[1] && strcmp(argv
[1], "-l") != 0) {
3689 if (argv
[i
][0] == '%') {
3690 struct job
*jp
= getjob(argv
[i
], 0);
3691 unsigned pid
= jp
->ps
[0].pid
;
3692 /* Enough space for ' -NNN<nul>' */
3693 argv
[i
] = alloca(sizeof(int)*3 + 3);
3694 /* kill_main has matching code to expect
3695 * leading space. Needed to not confuse
3696 * negative pids with "kill -SIGNAL_NO" syntax */
3697 sprintf(argv
[i
], " -%u", pid
);
3699 } while (argv
[++i
]);
3701 return kill_main(argc
, argv
);
3705 showpipe(struct job
*jp
, FILE *out
)
3707 struct procstat
*sp
;
3708 struct procstat
*spend
;
3710 spend
= jp
->ps
+ jp
->nprocs
;
3711 for (sp
= jp
->ps
+ 1; sp
< spend
; sp
++)
3712 fprintf(out
, " | %s", sp
->cmd
);
3713 outcslow('\n', out
);
3714 flush_stdout_stderr();
3719 restartjob(struct job
*jp
, int mode
)
3721 struct procstat
*ps
;
3727 if (jp
->state
== JOBDONE
)
3729 jp
->state
= JOBRUNNING
;
3731 if (mode
== FORK_FG
)
3732 xtcsetpgrp(ttyfd
, pgid
);
3733 killpg(pgid
, SIGCONT
);
3737 if (WIFSTOPPED(ps
->status
)) {
3743 status
= (mode
== FORK_FG
) ? waitforjob(jp
) : 0;
3749 fg_bgcmd(int argc UNUSED_PARAM
, char **argv
)
3756 mode
= (**argv
== 'f') ? FORK_FG
: FORK_BG
;
3761 jp
= getjob(*argv
, 1);
3762 if (mode
== FORK_BG
) {
3763 set_curjob(jp
, CUR_RUNNING
);
3764 fprintf(out
, "[%d] ", jobno(jp
));
3766 outstr(jp
->ps
->cmd
, out
);
3768 retval
= restartjob(jp
, mode
);
3769 } while (*argv
&& *++argv
);
3775 sprint_status(char *s
, int status
, int sigonly
)
3781 if (!WIFEXITED(status
)) {
3783 if (WIFSTOPPED(status
))
3784 st
= WSTOPSIG(status
);
3787 st
= WTERMSIG(status
);
3789 if (st
== SIGINT
|| st
== SIGPIPE
)
3792 if (WIFSTOPPED(status
))
3797 col
= fmtstr(s
, 32, strsignal(st
));
3798 if (WCOREDUMP(status
)) {
3799 col
+= fmtstr(s
+ col
, 16, " (core dumped)");
3801 } else if (!sigonly
) {
3802 st
= WEXITSTATUS(status
);
3804 col
= fmtstr(s
, 16, "Done(%d)", st
);
3806 col
= fmtstr(s
, 16, "Done");
3813 dowait(int wait_flags
, struct job
*job
)
3818 struct job
*thisjob
;
3821 TRACE(("dowait(0x%x) called\n", wait_flags
));
3823 /* Do a wait system call. If job control is compiled in, we accept
3824 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3825 * NB: _not_ safe_waitpid, we need to detect EINTR */
3826 pid
= waitpid(-1, &status
,
3827 (doing_jobctl
? (wait_flags
| WUNTRACED
) : wait_flags
));
3828 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3829 pid
, status
, errno
, strerror(errno
)));
3835 for (jp
= curjob
; jp
; jp
= jp
->prev_job
) {
3836 struct procstat
*sp
;
3837 struct procstat
*spend
;
3838 if (jp
->state
== JOBDONE
)
3841 spend
= jp
->ps
+ jp
->nprocs
;
3844 if (sp
->pid
== pid
) {
3845 TRACE(("Job %d: changing status of proc %d "
3846 "from 0x%x to 0x%x\n",
3847 jobno(jp
), pid
, sp
->status
, status
));
3848 sp
->status
= status
;
3851 if (sp
->status
== -1)
3854 if (state
== JOBRUNNING
)
3856 if (WIFSTOPPED(sp
->status
)) {
3857 jp
->stopstatus
= sp
->status
;
3861 } while (++sp
< spend
);
3866 if (!WIFSTOPPED(status
))
3872 if (state
!= JOBRUNNING
) {
3873 thisjob
->changed
= 1;
3875 if (thisjob
->state
!= state
) {
3876 TRACE(("Job %d: changing state from %d to %d\n",
3877 jobno(thisjob
), thisjob
->state
, state
));
3878 thisjob
->state
= state
;
3880 if (state
== JOBSTOPPED
) {
3881 set_curjob(thisjob
, CUR_STOPPED
);
3890 if (thisjob
&& thisjob
== job
) {
3894 len
= sprint_status(s
, status
, 1);
3905 blocking_wait_with_raise_on_sig(struct job
*job
)
3907 pid_t pid
= dowait(DOWAIT_BLOCK
, job
);
3908 if (pid
<= 0 && pendingsig
)
3909 raise_exception(EXSIG
);
3915 showjob(FILE *out
, struct job
*jp
, int mode
)
3917 struct procstat
*ps
;
3918 struct procstat
*psend
;
3925 if (mode
& SHOW_PGID
) {
3926 /* just output process (group) id of pipeline */
3927 fprintf(out
, "%d\n", ps
->pid
);
3931 col
= fmtstr(s
, 16, "[%d] ", jobno(jp
));
3936 else if (curjob
&& jp
== curjob
->prev_job
)
3939 if (mode
& SHOW_PID
)
3940 col
+= fmtstr(s
+ col
, 16, "%d ", ps
->pid
);
3942 psend
= ps
+ jp
->nprocs
;
3944 if (jp
->state
== JOBRUNNING
) {
3945 strcpy(s
+ col
, "Running");
3946 col
+= sizeof("Running") - 1;
3948 int status
= psend
[-1].status
;
3949 if (jp
->state
== JOBSTOPPED
)
3950 status
= jp
->stopstatus
;
3951 col
+= sprint_status(s
+ col
, status
, 0);
3957 /* for each process */
3958 col
= fmtstr(s
, 48, " |\n%*c%d ", indent_col
, ' ', ps
->pid
) - 3;
3960 fprintf(out
, "%s%*c%s",
3961 s
, 33 - col
>= 0 ? 33 - col
: 0, ' ', ps
->cmd
3963 if (!(mode
& SHOW_PID
)) {
3967 if (++ps
== psend
) {
3968 outcslow('\n', out
);
3975 if (jp
->state
== JOBDONE
) {
3976 TRACE(("showjob: freeing job %d\n", jobno(jp
)));
3982 * Print a list of jobs. If "change" is nonzero, only print jobs whose
3983 * statuses have changed since the last call to showjobs.
3986 showjobs(FILE *out
, int mode
)
3990 TRACE(("showjobs(%x) called\n", mode
));
3992 /* Handle all finished jobs */
3993 while (dowait(DOWAIT_NONBLOCK
, NULL
) > 0)
3996 for (jp
= curjob
; jp
; jp
= jp
->prev_job
) {
3997 if (!(mode
& SHOW_CHANGED
) || jp
->changed
) {
3998 showjob(out
, jp
, mode
);
4004 jobscmd(int argc UNUSED_PARAM
, char **argv
)
4009 while ((m
= nextopt("lp"))) {
4019 showjob(stdout
, getjob(*argv
,0), mode
);
4022 showjobs(stdout
, mode
);
4029 getstatus(struct job
*job
)
4034 status
= job
->ps
[job
->nprocs
- 1].status
;
4035 retval
= WEXITSTATUS(status
);
4036 if (!WIFEXITED(status
)) {
4038 retval
= WSTOPSIG(status
);
4039 if (!WIFSTOPPED(status
))
4042 /* XXX: limits number of signals */
4043 retval
= WTERMSIG(status
);
4045 if (retval
== SIGINT
)
4051 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
4052 jobno(job
), job
->nprocs
, status
, retval
));
4057 waitcmd(int argc UNUSED_PARAM
, char **argv
)
4066 raise_exception(EXSIG
);
4073 /* wait for all jobs */
4077 if (!jp
) /* no running procs */
4079 if (jp
->state
== JOBRUNNING
)
4085 * "When bash is waiting for an asynchronous command via
4086 * the wait builtin, the reception of a signal for which a trap
4087 * has been set will cause the wait builtin to return immediately
4088 * with an exit status greater than 128, immediately after which
4089 * the trap is executed."
4090 * Do we do it that way? */
4091 blocking_wait_with_raise_on_sig(NULL
);
4097 if (**argv
!= '%') {
4098 pid_t pid
= number(*argv
);
4103 if (job
->ps
[job
->nprocs
- 1].pid
== pid
)
4105 job
= job
->prev_job
;
4108 job
= getjob(*argv
, 0);
4109 /* loop until process terminated or stopped */
4110 while (job
->state
== JOBRUNNING
)
4111 blocking_wait_with_raise_on_sig(NULL
);
4113 retval
= getstatus(job
);
4126 struct job
*jp
, *jq
;
4128 len
= njobs
* sizeof(*jp
);
4130 jp
= ckrealloc(jq
, len
+ 4 * sizeof(*jp
));
4132 offset
= (char *)jp
- (char *)jq
;
4134 /* Relocate pointers */
4137 jq
= (struct job
*)((char *)jq
+ l
);
4141 #define joff(p) ((struct job *)((char *)(p) + l))
4142 #define jmove(p) (p) = (void *)((char *)(p) + offset)
4143 if (joff(jp
)->ps
== &jq
->ps0
)
4144 jmove(joff(jp
)->ps
);
4145 if (joff(jp
)->prev_job
)
4146 jmove(joff(jp
)->prev_job
);
4156 jp
= (struct job
*)((char *)jp
+ len
);
4160 } while (--jq
>= jp
);
4165 * Return a new job structure.
4166 * Called with interrupts off.
4169 makejob(/*union node *node,*/ int nprocs
)
4174 for (i
= njobs
, jp
= jobtab
; ; jp
++) {
4181 if (jp
->state
!= JOBDONE
|| !jp
->waited
)
4190 memset(jp
, 0, sizeof(*jp
));
4192 /* jp->jobctl is a bitfield.
4193 * "jp->jobctl |= jobctl" likely to give awful code */
4197 jp
->prev_job
= curjob
;
4202 jp
->ps
= ckmalloc(nprocs
* sizeof(struct procstat
));
4204 TRACE(("makejob(%d) returns %%%d\n", nprocs
,
4211 * Return a string identifying a command (to be printed by the
4214 static char *cmdnextc
;
4217 cmdputs(const char *s
)
4219 static const char vstype
[VSTYPE
+ 1][3] = {
4220 "", "}", "-", "+", "?", "=",
4221 "%", "%%", "#", "##"
4222 USE_ASH_BASH_COMPAT(, ":", "/", "//")
4225 const char *p
, *str
;
4226 char c
, cc
[2] = " ";
4231 nextc
= makestrspace((strlen(s
) + 1) * 8, cmdnextc
);
4233 while ((c
= *p
++) != 0) {
4241 if ((subtype
& VSTYPE
) == VSLENGTH
)
4245 if (!(subtype
& VSQUOTE
) == !(quoted
& 1))
4251 str
= "\"}" + !(quoted
& 1);
4258 case CTLBACKQ
+CTLQUOTE
:
4261 #if ENABLE_SH_MATH_SUPPORT
4276 if ((subtype
& VSTYPE
) != VSNORMAL
)
4278 str
= vstype
[subtype
& VSTYPE
];
4279 if (subtype
& VSNUL
)
4288 /* These can only happen inside quotes */
4301 while ((c
= *str
++)) {
4306 USTPUTC('"', nextc
);
4312 /* cmdtxt() and cmdlist() call each other */
4313 static void cmdtxt(union node
*n
);
4316 cmdlist(union node
*np
, int sep
)
4318 for (; np
; np
= np
->narg
.next
) {
4322 if (sep
&& np
->narg
.next
)
4328 cmdtxt(union node
*n
)
4331 struct nodelist
*lp
;
4342 lp
= n
->npipe
.cmdlist
;
4360 cmdtxt(n
->nbinary
.ch1
);
4376 cmdtxt(n
->nif
.test
);
4379 if (n
->nif
.elsepart
) {
4382 n
= n
->nif
.elsepart
;
4398 cmdtxt(n
->nbinary
.ch1
);
4408 cmdputs(n
->nfor
.var
);
4410 cmdlist(n
->nfor
.args
, 1);
4415 cmdputs(n
->narg
.text
);
4419 cmdlist(n
->ncmd
.args
, 1);
4420 cmdlist(n
->ncmd
.redirect
, 0);
4433 cmdputs(n
->ncase
.expr
->narg
.text
);
4435 for (np
= n
->ncase
.cases
; np
; np
= np
->nclist
.next
) {
4436 cmdtxt(np
->nclist
.pattern
);
4438 cmdtxt(np
->nclist
.body
);
4452 #if ENABLE_ASH_BASH_COMPAT
4467 cmdputs(utoa(n
->nfile
.fd
));
4469 if (n
->type
== NTOFD
|| n
->type
== NFROMFD
) {
4470 cmdputs(utoa(n
->ndup
.dupfd
));
4479 commandtext(union node
*n
)
4483 STARTSTACKSTR(cmdnextc
);
4485 name
= stackblock();
4486 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4487 name
, cmdnextc
, cmdnextc
));
4488 return ckstrdup(name
);
4493 * Fork off a subshell. If we are doing job control, give the subshell its
4494 * own process group. Jp is a job structure that the job is to be added to.
4495 * N is the command that will be evaluated by the child. Both jp and n may
4496 * be NULL. The mode parameter can be one of the following:
4497 * FORK_FG - Fork off a foreground process.
4498 * FORK_BG - Fork off a background process.
4499 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4500 * process group even if job control is on.
4502 * When job control is turned off, background processes have their standard
4503 * input redirected to /dev/null (except for the second and later processes
4506 * Called with interrupts off.
4509 * Clear traps on a fork.
4516 for (tp
= trap
; tp
< &trap
[NSIG
]; tp
++) {
4517 if (*tp
&& **tp
) { /* trap not NULL or "" (SIG_IGN) */
4522 setsignal(tp
- trap
);
4528 /* Lives far away from here, needed for forkchild */
4529 static void closescript(void);
4531 /* Called after fork(), in child */
4533 forkchild(struct job
*jp
, /*union node *n,*/ int mode
)
4537 TRACE(("Child shell %d\n", getpid()));
4541 /* man bash: "Non-builtin commands run by bash have signal handlers
4542 * set to the values inherited by the shell from its parent".
4543 * Do we do it correctly? */
4548 /* do job control only in root shell */
4550 if (mode
!= FORK_NOJOB
&& jp
->jobctl
&& !oldlvl
) {
4553 if (jp
->nprocs
== 0)
4556 pgrp
= jp
->ps
[0].pid
;
4557 /* this can fail because we are doing it in the parent also */
4559 if (mode
== FORK_FG
)
4560 xtcsetpgrp(ttyfd
, pgrp
);
4565 if (mode
== FORK_BG
) {
4566 /* man bash: "When job control is not in effect,
4567 * asynchronous commands ignore SIGINT and SIGQUIT" */
4570 if (jp
->nprocs
== 0) {
4572 if (open(bb_dev_null
, O_RDONLY
) != 0)
4573 ash_msg_and_raise_error("can't open '%s'", bb_dev_null
);
4577 if (iflag
) { /* why if iflag only? */
4582 * "In all cases, bash ignores SIGQUIT. Non-builtin
4583 * commands run by bash have signal handlers
4584 * set to the values inherited by the shell
4586 * Take care of the second rule: */
4589 for (jp
= curjob
; jp
; jp
= jp
->prev_job
)
4594 /* Called after fork(), in parent */
4596 #define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4599 forkparent(struct job
*jp
, union node
*n
, int mode
, pid_t pid
)
4601 TRACE(("In parent shell: child = %d\n", pid
));
4603 while (jobless
&& dowait(DOWAIT_NONBLOCK
, NULL
) > 0)
4609 if (mode
!= FORK_NOJOB
&& jp
->jobctl
) {
4612 if (jp
->nprocs
== 0)
4615 pgrp
= jp
->ps
[0].pid
;
4616 /* This can fail because we are doing it in the child also */
4620 if (mode
== FORK_BG
) {
4621 backgndpid
= pid
; /* set $! */
4622 set_curjob(jp
, CUR_RUNNING
);
4625 struct procstat
*ps
= &jp
->ps
[jp
->nprocs
++];
4630 if (doing_jobctl
&& n
)
4631 ps
->cmd
= commandtext(n
);
4637 forkshell(struct job
*jp
, union node
*n
, int mode
)
4641 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp
), n
, mode
));
4644 TRACE(("Fork failed, errno=%d", errno
));
4647 ash_msg_and_raise_error("can't fork");
4650 forkchild(jp
, /*n,*/ mode
);
4652 forkparent(jp
, n
, mode
, pid
);
4657 * Wait for job to finish.
4659 * Under job control we have the problem that while a child process
4660 * is running interrupts generated by the user are sent to the child
4661 * but not to the shell. This means that an infinite loop started by
4662 * an interactive user may be hard to kill. With job control turned off,
4663 * an interactive user may place an interactive program inside a loop.
4664 * If the interactive program catches interrupts, the user doesn't want
4665 * these interrupts to also abort the loop. The approach we take here
4666 * is to have the shell ignore interrupt signals while waiting for a
4667 * foreground process to terminate, and then send itself an interrupt
4668 * signal if the child process was terminated by an interrupt signal.
4669 * Unfortunately, some programs want to do a bit of cleanup and then
4670 * exit on interrupt; unless these processes terminate themselves by
4671 * sending a signal to themselves (instead of calling exit) they will
4672 * confuse this approach.
4674 * Called with interrupts off.
4677 waitforjob(struct job
*jp
)
4681 TRACE(("waitforjob(%%%d) called\n", jobno(jp
)));
4684 while (jp
->state
== JOBRUNNING
) {
4685 /* In non-interactive shells, we _can_ get
4686 * a keyboard signal here and be EINTRed,
4687 * but we just loop back, waiting for command to complete.
4690 * "If bash is waiting for a command to complete and receives
4691 * a signal for which a trap has been set, the trap
4692 * will not be executed until the command completes."
4694 * Reality is that even if trap is not set, bash
4695 * will not act on the signal until command completes.
4696 * Try this. sleep5intoff.c:
4697 * #include <signal.h>
4698 * #include <unistd.h>
4701 * sigemptyset(&set);
4702 * sigaddset(&set, SIGINT);
4703 * sigaddset(&set, SIGQUIT);
4704 * sigprocmask(SIG_BLOCK, &set, NULL);
4708 * $ bash -c './sleep5intoff; echo hi'
4709 * ^C^C^C^C <--- pressing ^C once a second
4711 * $ bash -c './sleep5intoff; echo hi'
4712 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4715 dowait(DOWAIT_BLOCK
, jp
);
4722 xtcsetpgrp(ttyfd
, rootpid
);
4724 * This is truly gross.
4725 * If we're doing job control, then we did a TIOCSPGRP which
4726 * caused us (the shell) to no longer be in the controlling
4727 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4728 * intuit from the subprocess exit status whether a SIGINT
4729 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4731 if (jp
->sigint
) /* TODO: do the same with all signals */
4732 raise(SIGINT
); /* ... by raise(jp->sig) instead? */
4734 if (jp
->state
== JOBDONE
)
4741 * return 1 if there are stopped jobs, otherwise 0
4753 if (jp
&& jp
->state
== JOBSTOPPED
) {
4754 out2str("You have stopped jobs.\n");
4763 /* ============ redir.c
4765 * Code for dealing with input/output redirection.
4768 #define EMPTY -2 /* marks an unused slot in redirtab */
4769 #define CLOSED -3 /* marks a slot of previously-closed fd */
4772 * Open a file in noclobber mode.
4773 * The code was copied from bash.
4776 noclobberopen(const char *fname
)
4779 struct stat finfo
, finfo2
;
4782 * If the file exists and is a regular file, return an error
4785 r
= stat(fname
, &finfo
);
4786 if (r
== 0 && S_ISREG(finfo
.st_mode
)) {
4792 * If the file was not present (r != 0), make sure we open it
4793 * exclusively so that if it is created before we open it, our open
4794 * will fail. Make sure that we do not truncate an existing file.
4795 * Note that we don't turn on O_EXCL unless the stat failed -- if the
4796 * file was not a regular file, we leave O_EXCL off.
4799 return open(fname
, O_WRONLY
|O_CREAT
|O_EXCL
, 0666);
4800 fd
= open(fname
, O_WRONLY
|O_CREAT
, 0666);
4802 /* If the open failed, return the file descriptor right away. */
4807 * OK, the open succeeded, but the file may have been changed from a
4808 * non-regular file to a regular file between the stat and the open.
4809 * We are assuming that the O_EXCL open handles the case where FILENAME
4810 * did not exist and is symlinked to an existing file between the stat
4815 * If we can open it and fstat the file descriptor, and neither check
4816 * revealed that it was a regular file, and the file has not been
4817 * replaced, return the file descriptor.
4819 if (fstat(fd
, &finfo2
) == 0 && !S_ISREG(finfo2
.st_mode
)
4820 && finfo
.st_dev
== finfo2
.st_dev
&& finfo
.st_ino
== finfo2
.st_ino
)
4823 /* The file has been replaced. badness. */
4830 * Handle here documents. Normally we fork off a process to write the
4831 * data to a pipe. If the document is short, we can stuff the data in
4832 * the pipe without forking.
4834 /* openhere needs this forward reference */
4835 static void expandhere(union node
*arg
, int fd
);
4837 openhere(union node
*redir
)
4843 ash_msg_and_raise_error("pipe call failed");
4844 if (redir
->type
== NHERE
) {
4845 len
= strlen(redir
->nhere
.doc
->narg
.text
);
4846 if (len
<= PIPE_BUF
) {
4847 full_write(pip
[1], redir
->nhere
.doc
->narg
.text
, len
);
4851 if (forkshell((struct job
*)NULL
, (union node
*)NULL
, FORK_NOJOB
) == 0) {
4854 ignoresig(SIGINT
); //signal(SIGINT, SIG_IGN);
4855 ignoresig(SIGQUIT
); //signal(SIGQUIT, SIG_IGN);
4856 ignoresig(SIGHUP
); //signal(SIGHUP, SIG_IGN);
4857 ignoresig(SIGTSTP
); //signal(SIGTSTP, SIG_IGN);
4858 signal(SIGPIPE
, SIG_DFL
);
4859 if (redir
->type
== NHERE
)
4860 full_write(pip
[1], redir
->nhere
.doc
->narg
.text
, len
);
4862 expandhere(redir
->nhere
.doc
, pip
[1]);
4863 _exit(EXIT_SUCCESS
);
4871 openredirect(union node
*redir
)
4876 switch (redir
->nfile
.type
) {
4878 fname
= redir
->nfile
.expfname
;
4879 f
= open(fname
, O_RDONLY
);
4884 fname
= redir
->nfile
.expfname
;
4885 f
= open(fname
, O_RDWR
|O_CREAT
|O_TRUNC
, 0666);
4890 #if ENABLE_ASH_BASH_COMPAT
4893 /* Take care of noclobber mode. */
4895 fname
= redir
->nfile
.expfname
;
4896 f
= noclobberopen(fname
);
4903 fname
= redir
->nfile
.expfname
;
4904 f
= open(fname
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0666);
4909 fname
= redir
->nfile
.expfname
;
4910 f
= open(fname
, O_WRONLY
|O_CREAT
|O_APPEND
, 0666);
4918 /* Fall through to eliminate warning. */
4919 /* Our single caller does this itself */
4926 f
= openhere(redir
);
4932 ash_msg_and_raise_error("can't create %s: %s", fname
, errmsg(errno
, "nonexistent directory"));
4934 ash_msg_and_raise_error("can't open %s: %s", fname
, errmsg(errno
, "no such file"));
4938 * Copy a file descriptor to be >= to. Returns -1
4939 * if the source file descriptor is closed, EMPTY if there are no unused
4940 * file descriptors left.
4942 /* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
4943 * old code was doing close(to) prior to copyfd() to achieve the same */
4945 COPYFD_EXACT
= (int)~(INT_MAX
),
4946 COPYFD_RESTORE
= (int)((unsigned)COPYFD_EXACT
>> 1),
4949 copyfd(int from
, int to
)
4953 if (to
& COPYFD_EXACT
) {
4954 to
&= ~COPYFD_EXACT
;
4956 newfd
= dup2(from
, to
);
4958 newfd
= fcntl(from
, F_DUPFD
, to
);
4961 if (errno
== EMFILE
)
4963 /* Happens when source fd is not open: try "echo >&99" */
4964 ash_msg_and_raise_error("%d: %m", from
);
4969 /* Struct def and variable are moved down to the first usage site */
4974 struct redirtab
*next
;
4977 struct two_fd_t two_fd
[0];
4979 #define redirlist (G_var.redirlist)
4981 static int need_to_remember(struct redirtab
*rp
, int fd
)
4985 if (!rp
) /* remembering was not requested */
4988 for (i
= 0; i
< rp
->pair_count
; i
++) {
4989 if (rp
->two_fd
[i
].orig
== fd
) {
4990 /* already remembered */
4997 /* "hidden" fd is a fd used to read scripts, or a copy of such */
4998 static int is_hidden_fd(struct redirtab
*rp
, int fd
)
5001 struct parsefile
*pf
;
5014 fd
|= COPYFD_RESTORE
;
5015 for (i
= 0; i
< rp
->pair_count
; i
++) {
5016 if (rp
->two_fd
[i
].copy
== fd
) {
5024 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5025 * old file descriptors are stashed away so that the redirection can be
5026 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
5027 * standard output, and the standard error if it becomes a duplicate of
5028 * stdout, is saved in memory.
5030 /* flags passed to redirect */
5031 #define REDIR_PUSH 01 /* save previous values of file descriptors */
5032 #define REDIR_SAVEFD2 03 /* set preverrout */
5034 redirect(union node
*redir
, int flags
)
5036 struct redirtab
*sv
;
5041 int copied_fd2
= -1;
5051 if (flags
& REDIR_PUSH
) {
5052 union node
*tmp
= redir
;
5055 #if ENABLE_ASH_BASH_COMPAT
5056 if (redir
->nfile
.type
== NTO2
)
5059 tmp
= tmp
->nfile
.next
;
5061 sv
= ckmalloc(sizeof(*sv
) + sv_pos
* sizeof(sv
->two_fd
[0]));
5062 sv
->next
= redirlist
;
5063 sv
->pair_count
= sv_pos
;
5065 sv
->nullredirs
= g_nullredirs
- 1;
5067 while (sv_pos
> 0) {
5069 sv
->two_fd
[sv_pos
].orig
= sv
->two_fd
[sv_pos
].copy
= EMPTY
;
5074 fd
= redir
->nfile
.fd
;
5075 if (redir
->nfile
.type
== NTOFD
|| redir
->nfile
.type
== NFROMFD
) {
5076 int right_fd
= redir
->ndup
.dupfd
;
5077 /* redirect from/to same file descriptor? */
5080 /* echo >&10 and 10 is a fd opened to the sh script? */
5081 if (is_hidden_fd(sv
, right_fd
)) {
5082 errno
= EBADF
; /* as if it is closed */
5083 ash_msg_and_raise_error("%d: %m", right_fd
);
5087 newfd
= openredirect(redir
); /* always >= 0 */
5089 /* Descriptor wasn't open before redirect.
5090 * Mark it for close in the future */
5091 if (need_to_remember(sv
, fd
)) {
5092 goto remember_to_close
;
5097 #if ENABLE_ASH_BASH_COMPAT
5100 if (need_to_remember(sv
, fd
)) {
5101 /* Copy old descriptor */
5102 i
= fcntl(fd
, F_DUPFD
, 10);
5103 /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5104 * are closed in popredir() in the child, preventing them from leaking
5105 * into child. (popredir() also cleans up the mess in case of failures)
5110 /* Strange error (e.g. "too many files" EMFILE?) */
5114 ash_msg_and_raise_error("%d: %m", fd
);
5117 /* EBADF: it is not open - good, remember to close it */
5120 } else { /* fd is open, save its copy */
5121 /* "exec fd>&-" should not close fds
5122 * which point to script file(s).
5123 * Force them to be restored afterwards */
5124 if (is_hidden_fd(sv
, fd
))
5125 i
|= COPYFD_RESTORE
;
5129 sv
->two_fd
[sv_pos
].orig
= fd
;
5130 sv
->two_fd
[sv_pos
].copy
= i
;
5134 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
5135 if (redir
->ndup
.dupfd
< 0) { /* "fd>&-" */
5136 /* Don't want to trigger debugging */
5140 copyfd(redir
->ndup
.dupfd
, fd
| COPYFD_EXACT
);
5142 } else if (fd
!= newfd
) { /* move newfd to fd */
5143 copyfd(newfd
, fd
| COPYFD_EXACT
);
5144 #if ENABLE_ASH_BASH_COMPAT
5145 if (!(redir
->nfile
.type
== NTO2
&& fd
== 2))
5149 #if ENABLE_ASH_BASH_COMPAT
5150 if (redir
->nfile
.type
== NTO2
&& fd
== 1) {
5151 /* We already redirected it to fd 1, now copy it to 2 */
5157 } while ((redir
= redir
->nfile
.next
) != NULL
);
5160 if ((flags
& REDIR_SAVEFD2
) && copied_fd2
>= 0)
5161 preverrout_fd
= copied_fd2
;
5165 * Undo the effects of the last redirection.
5168 popredir(int drop
, int restore
)
5170 struct redirtab
*rp
;
5173 if (--g_nullredirs
>= 0)
5177 for (i
= 0; i
< rp
->pair_count
; i
++) {
5178 int fd
= rp
->two_fd
[i
].orig
;
5179 int copy
= rp
->two_fd
[i
].copy
;
5180 if (copy
== CLOSED
) {
5185 if (copy
!= EMPTY
) {
5186 if (!drop
|| (restore
&& (copy
& COPYFD_RESTORE
))) {
5187 copy
&= ~COPYFD_RESTORE
;
5189 copyfd(copy
, fd
| COPYFD_EXACT
);
5191 close(copy
& ~COPYFD_RESTORE
);
5194 redirlist
= rp
->next
;
5195 g_nullredirs
= rp
->nullredirs
;
5201 * Undo all redirections. Called on error or interrupt.
5205 * Discard all saved file descriptors.
5208 clearredir(int drop
)
5214 popredir(drop
, /*restore:*/ 0);
5219 redirectsafe(union node
*redir
, int flags
)
5222 volatile int saveint
;
5223 struct jmploc
*volatile savehandler
= exception_handler
;
5224 struct jmploc jmploc
;
5227 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5228 err
= setjmp(jmploc
.loc
); // huh?? was = setjmp(jmploc.loc) * 2;
5230 exception_handler
= &jmploc
;
5231 redirect(redir
, flags
);
5233 exception_handler
= savehandler
;
5234 if (err
&& exception_type
!= EXERROR
)
5235 longjmp(exception_handler
->loc
, 1);
5236 RESTORE_INT(saveint
);
5241 /* ============ Routines to expand arguments to commands
5243 * We have to deal with backquotes, shell variables, and file metacharacters.
5246 #if ENABLE_SH_MATH_SUPPORT
5248 ash_arith(const char *s
)
5250 arith_eval_hooks_t math_hooks
;
5254 math_hooks
.lookupvar
= lookupvar
;
5255 math_hooks
.setvar
= setvar
;
5256 math_hooks
.endofname
= endofname
;
5259 result
= arith(s
, &errcode
, &math_hooks
);
5262 ash_msg_and_raise_error("exponent less than 0");
5264 ash_msg_and_raise_error("divide by zero");
5266 ash_msg_and_raise_error("expression recursion loop detected");
5267 raise_error_syntax(s
);
5278 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
5279 #define EXP_TILDE 0x2 /* do normal tilde expansion */
5280 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5281 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5282 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5283 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5284 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5285 #define EXP_WORD 0x80 /* expand word in parameter expansion */
5286 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5290 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5291 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5292 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5293 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5294 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5297 * Structure specifying which parts of the string should be searched
5298 * for IFS characters.
5301 struct ifsregion
*next
; /* next region in list */
5302 int begoff
; /* offset of start of region */
5303 int endoff
; /* offset of end of region */
5304 int nulonly
; /* search for nul bytes only */
5308 struct strlist
*list
;
5309 struct strlist
**lastp
;
5312 /* output of current string */
5313 static char *expdest
;
5314 /* list of back quote expressions */
5315 static struct nodelist
*argbackq
;
5316 /* first struct in list of ifs regions */
5317 static struct ifsregion ifsfirst
;
5318 /* last struct in list */
5319 static struct ifsregion
*ifslastp
;
5320 /* holds expanded arg list */
5321 static struct arglist exparg
;
5331 expdest
= makestrspace(32, expdest
);
5332 len
= fmtstr(expdest
, 32, arith_t_fmt
, num
);
5333 STADJUST(len
, expdest
);
5338 esclen(const char *start
, const char *p
)
5342 while (p
> start
&& *--p
== CTLESC
) {
5349 * Remove any CTLESC characters from a string.
5352 _rmescapes(char *str
, int flag
)
5354 static const char qchars
[] ALIGN1
= { CTLESC
, CTLQUOTEMARK
, '\0' };
5361 p
= strpbrk(str
, qchars
);
5367 if (flag
& RMESCAPE_ALLOC
) {
5368 size_t len
= p
- str
;
5369 size_t fulllen
= len
+ strlen(p
) + 1;
5371 if (flag
& RMESCAPE_GROW
) {
5372 r
= makestrspace(fulllen
, expdest
);
5373 } else if (flag
& RMESCAPE_HEAP
) {
5374 r
= ckmalloc(fulllen
);
5376 r
= stalloc(fulllen
);
5380 q
= (char *)memcpy(q
, str
, len
) + len
;
5383 inquotes
= (flag
& RMESCAPE_QUOTED
) ^ RMESCAPE_QUOTED
;
5384 globbing
= flag
& RMESCAPE_GLOB
;
5385 notescaped
= globbing
;
5387 if (*p
== CTLQUOTEMARK
) {
5388 inquotes
= ~inquotes
;
5390 notescaped
= globbing
;
5394 /* naked back slash */
5400 if (notescaped
&& inquotes
&& *p
!= '/') {
5404 notescaped
= globbing
;
5409 if (flag
& RMESCAPE_GROW
) {
5411 STADJUST(q
- r
+ 1, expdest
);
5415 #define rmescapes(p) _rmescapes((p), 0)
5417 #define pmatch(a, b) !fnmatch((a), (b), 0)
5420 * Prepare a pattern for a expmeta (internal glob(3)) call.
5422 * Returns an stalloced string.
5425 preglob(const char *pattern
, int quoted
, int flag
)
5427 flag
|= RMESCAPE_GLOB
;
5429 flag
|= RMESCAPE_QUOTED
;
5431 return _rmescapes((char *)pattern
, flag
);
5435 * Put a string on the stack.
5438 memtodest(const char *p
, size_t len
, int syntax
, int quotes
)
5442 q
= makestrspace(len
* 2, q
);
5445 int c
= signed_char2int(*p
++);
5448 if (quotes
&& (SIT(c
, syntax
) == CCTL
|| SIT(c
, syntax
) == CBACK
))
5457 strtodest(const char *p
, int syntax
, int quotes
)
5459 memtodest(p
, strlen(p
), syntax
, quotes
);
5463 * Record the fact that we have to scan this region of the
5464 * string for IFS characters.
5467 recordregion(int start
, int end
, int nulonly
)
5469 struct ifsregion
*ifsp
;
5471 if (ifslastp
== NULL
) {
5475 ifsp
= ckzalloc(sizeof(*ifsp
));
5476 /*ifsp->next = NULL; - ckzalloc did it */
5477 ifslastp
->next
= ifsp
;
5481 ifslastp
->begoff
= start
;
5482 ifslastp
->endoff
= end
;
5483 ifslastp
->nulonly
= nulonly
;
5487 removerecordregions(int endoff
)
5489 if (ifslastp
== NULL
)
5492 if (ifsfirst
.endoff
> endoff
) {
5493 while (ifsfirst
.next
!= NULL
) {
5494 struct ifsregion
*ifsp
;
5496 ifsp
= ifsfirst
.next
->next
;
5497 free(ifsfirst
.next
);
5498 ifsfirst
.next
= ifsp
;
5501 if (ifsfirst
.begoff
> endoff
)
5504 ifslastp
= &ifsfirst
;
5505 ifsfirst
.endoff
= endoff
;
5510 ifslastp
= &ifsfirst
;
5511 while (ifslastp
->next
&& ifslastp
->next
->begoff
< endoff
)
5512 ifslastp
=ifslastp
->next
;
5513 while (ifslastp
->next
!= NULL
) {
5514 struct ifsregion
*ifsp
;
5516 ifsp
= ifslastp
->next
->next
;
5517 free(ifslastp
->next
);
5518 ifslastp
->next
= ifsp
;
5521 if (ifslastp
->endoff
> endoff
)
5522 ifslastp
->endoff
= endoff
;
5526 exptilde(char *startp
, char *p
, int flag
)
5532 int quotes
= flag
& (EXP_FULL
| EXP_CASE
);
5537 while ((c
= *++p
) != '\0') {
5544 if (flag
& EXP_VARTILDE
)
5554 if (*name
== '\0') {
5555 home
= lookupvar(homestr
);
5557 pw
= getpwnam(name
);
5562 if (!home
|| !*home
)
5565 startloc
= expdest
- (char *)stackblock();
5566 strtodest(home
, SQSYNTAX
, quotes
);
5567 recordregion(startloc
, expdest
- (char *)stackblock(), 0);
5575 * Execute a command inside back quotes. If it's a builtin command, we
5576 * want to save its output in a block obtained from malloc. Otherwise
5577 * we fork off a subprocess and get the output of the command via a pipe.
5578 * Should be called with interrupts off.
5580 struct backcmd
{ /* result of evalbackcmd */
5581 int fd
; /* file descriptor to read from */
5582 int nleft
; /* number of chars in buffer */
5583 char *buf
; /* buffer */
5584 struct job
*jp
; /* job structure for command */
5587 /* These forward decls are needed to use "eval" code for backticks handling: */
5588 static uint8_t back_exitstatus
; /* exit status of backquoted command */
5589 #define EV_EXIT 01 /* exit after evaluating tree */
5590 static void evaltree(union node
*, int);
5593 evalbackcmd(union node
*n
, struct backcmd
*result
)
5604 saveherefd
= herefd
;
5612 ash_msg_and_raise_error("pipe call failed");
5613 jp
= makejob(/*n,*/ 1);
5614 if (forkshell(jp
, n
, FORK_NOJOB
) == 0) {
5619 copyfd(pip
[1], 1 | COPYFD_EXACT
);
5623 evaltree(n
, EV_EXIT
); /* actually evaltreenr... */
5627 result
->fd
= pip
[0];
5630 herefd
= saveherefd
;
5632 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5633 result
->fd
, result
->buf
, result
->nleft
, result
->jp
));
5637 * Expand stuff in backwards quotes.
5640 expbackq(union node
*cmd
, int quoted
, int quotes
)
5648 int syntax
= quoted
? DQSYNTAX
: BASESYNTAX
;
5649 struct stackmark smark
;
5652 setstackmark(&smark
);
5654 startloc
= dest
- (char *)stackblock();
5656 evalbackcmd(cmd
, &in
);
5657 popstackmark(&smark
);
5664 memtodest(p
, i
, syntax
, quotes
);
5668 i
= nonblock_safe_read(in
.fd
, buf
, sizeof(buf
));
5669 TRACE(("expbackq: read returns %d\n", i
));
5678 back_exitstatus
= waitforjob(in
.jp
);
5682 /* Eat all trailing newlines */
5684 for (; dest
> (char *)stackblock() && dest
[-1] == '\n';)
5689 recordregion(startloc
, dest
- (char *)stackblock(), 0);
5690 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5691 (dest
- (char *)stackblock()) - startloc
,
5692 (dest
- (char *)stackblock()) - startloc
,
5693 stackblock() + startloc
));
5696 #if ENABLE_SH_MATH_SUPPORT
5698 * Expand arithmetic expression. Backup to start of expression,
5699 * evaluate, place result in (backed up) result, adjust string position.
5712 * This routine is slightly over-complicated for
5713 * efficiency. Next we scan backwards looking for the
5714 * start of arithmetic.
5716 start
= stackblock();
5723 while (*p
!= CTLARI
) {
5727 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5732 esc
= esclen(start
, p
);
5742 removerecordregions(begoff
);
5751 len
= cvtnum(ash_arith(p
+ 2));
5754 recordregion(begoff
, begoff
+ len
, 0);
5758 /* argstr needs it */
5759 static char *evalvar(char *p
, int flag
, struct strlist
*var_str_list
);
5762 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5763 * characters to allow for further processing. Otherwise treat
5764 * $@ like $* since no splitting will be performed.
5766 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5767 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5768 * for correct expansion of "B=$A" word.
5771 argstr(char *p
, int flag
, struct strlist
*var_str_list
)
5773 static const char spclchars
[] ALIGN1
= {
5781 CTLBACKQ
| CTLQUOTE
,
5782 #if ENABLE_SH_MATH_SUPPORT
5787 const char *reject
= spclchars
;
5789 int quotes
= flag
& (EXP_FULL
| EXP_CASE
| EXP_REDIR
); /* do CTLESC */
5790 int breakall
= flag
& EXP_WORD
;
5795 if (!(flag
& EXP_VARTILDE
)) {
5797 } else if (flag
& EXP_VARTILDE2
) {
5802 if (flag
& EXP_TILDE
) {
5808 if (*q
== CTLESC
&& (flag
& EXP_QWORD
))
5811 p
= exptilde(p
, q
, flag
);
5814 startloc
= expdest
- (char *)stackblock();
5816 length
+= strcspn(p
+ length
, reject
);
5818 if (c
&& (!(c
& 0x80)
5819 #if ENABLE_SH_MATH_SUPPORT
5823 /* c == '=' || c == ':' || c == CTLENDARI */
5828 expdest
= stack_nputstr(p
, length
, expdest
);
5829 newloc
= expdest
- (char *)stackblock();
5830 if (breakall
&& !inquotes
&& newloc
> startloc
) {
5831 recordregion(startloc
, newloc
, 0);
5842 if (flag
& EXP_VARTILDE2
) {
5846 flag
|= EXP_VARTILDE2
;
5851 * sort of a hack - expand tildes in variable
5852 * assignments (after the first '=' and after ':'s).
5861 case CTLENDVAR
: /* ??? */
5864 /* "$@" syntax adherence hack */
5867 !memcmp(p
, dolatstr
, 4) &&
5868 (p
[4] == CTLQUOTEMARK
|| (
5869 p
[4] == CTLENDVAR
&&
5870 p
[5] == CTLQUOTEMARK
5873 p
= evalvar(p
+ 1, flag
, /* var_str_list: */ NULL
) + 1;
5876 inquotes
= !inquotes
;
5889 p
= evalvar(p
, flag
, var_str_list
);
5893 case CTLBACKQ
|CTLQUOTE
:
5894 expbackq(argbackq
->n
, c
, quotes
);
5895 argbackq
= argbackq
->next
;
5897 #if ENABLE_SH_MATH_SUPPORT
5910 scanleft(char *startp
, char *rmesc
, char *rmescend UNUSED_PARAM
, char *str
, int quotes
,
5913 // This commented out code was added by James Simmons <jsimmons@infradead.org>
5914 // as part of a larger change when he added support for ${var/a/b}.
5915 // However, it broke # and % operators:
5919 //echo ${var#ab} abcdcd abcdcd
5920 //echo ${var##ab} abcdcd abcdcd
5921 //echo ${var#a*b} abcdcd ababcdcd (!)
5922 //echo ${var##a*b} cdcd cdcd
5923 //echo ${var#?} babcdcd ababcdcd (!)
5924 //echo ${var##?} babcdcd babcdcd
5925 //echo ${var#*} ababcdcd babcdcd (!)
5927 //echo ${var%cd} ababcd ababcd
5928 //echo ${var%%cd} ababcd abab (!)
5929 //echo ${var%c*d} ababcd ababcd
5930 //echo ${var%%c*d} abab ababcdcd (!)
5931 //echo ${var%?} ababcdc ababcdc
5932 //echo ${var%%?} ababcdc ababcdcd (!)
5933 //echo ${var%*} ababcdcd ababcdcd
5936 // Commenting it back out helped. Remove it completely if it really
5939 char *loc
, *loc2
; //, *full;
5945 int match
; // = strlen(str);
5946 const char *s
= loc2
;
5953 match
= pmatch(str
, s
); // this line was deleted
5955 // // chop off end if its '*'
5956 // full = strrchr(str, '*');
5957 // if (full && full != str)
5960 // // If str starts with '*' replace with s.
5961 // if ((*str == '*') && strlen(s) >= match) {
5962 // full = xstrdup(s);
5963 // strncpy(full+strlen(s)-match+1, str+1, match-1);
5965 // full = xstrndup(str, match);
5966 // match = strncmp(s, full, strlen(full));
5970 if (match
) // if (!match)
5972 if (quotes
&& *loc
== CTLESC
)
5981 scanright(char *startp
, char *rmesc
, char *rmescend
, char *str
, int quotes
,
5988 for (loc
= str
- 1, loc2
= rmescend
; loc
>= startp
; loc2
--) {
5991 const char *s
= loc2
;
5996 match
= pmatch(str
, s
);
6003 esc
= esclen(startp
, loc
);
6014 static void varunset(const char *, const char *, const char *, int) NORETURN
;
6016 varunset(const char *end
, const char *var
, const char *umsg
, int varflags
)
6022 msg
= "parameter not set";
6024 if (*end
== CTLENDVAR
) {
6025 if (varflags
& VSNUL
)
6031 ash_msg_and_raise_error("%.*s: %s%s", end
- var
- 1, var
, msg
, tail
);
6034 #if ENABLE_ASH_BASH_COMPAT
6036 parse_sub_pattern(char *arg
, int inquotes
)
6038 char *idx
, *repl
= NULL
;
6047 /* Only the first '/' seen is our separator */
6054 if (!inquotes
&& c
== '\\' && arg
[1] == '\\')
6055 arg
++; /* skip both \\, not just first one */
6062 #endif /* ENABLE_ASH_BASH_COMPAT */
6065 subevalvar(char *p
, char *str
, int strloc
, int subtype
,
6066 int startloc
, int varflags
, int quotes
, struct strlist
*var_str_list
)
6068 struct nodelist
*saveargbackq
= argbackq
;
6071 char *rmesc
, *rmescend
;
6072 USE_ASH_BASH_COMPAT(char *repl
= NULL
;)
6073 USE_ASH_BASH_COMPAT(char null
= '\0';)
6074 USE_ASH_BASH_COMPAT(int pos
, len
, orig_len
;)
6075 int saveherefd
= herefd
;
6076 int amount
, workloc
, resetloc
;
6078 char *(*scan
)(char*, char*, char*, char*, int, int);
6081 argstr(p
, (subtype
!= VSASSIGN
&& subtype
!= VSQUESTION
) ? EXP_CASE
: 0,
6083 STPUTC('\0', expdest
);
6084 herefd
= saveherefd
;
6085 argbackq
= saveargbackq
;
6086 startp
= (char *)stackblock() + startloc
;
6090 setvar(str
, startp
, 0);
6091 amount
= startp
- expdest
;
6092 STADJUST(amount
, expdest
);
6095 #if ENABLE_ASH_BASH_COMPAT
6097 loc
= str
= stackblock() + strloc
;
6098 // TODO: number() instead? It does error checking...
6100 len
= str
- startp
- 1;
6102 /* *loc != '\0', guaranteed by parser */
6106 /* We must adjust the length by the number of escapes we find. */
6107 for (ptr
= startp
; ptr
< (str
- 1); ptr
++) {
6108 if (*ptr
== CTLESC
) {
6116 if (*loc
++ == ':') {
6117 // TODO: number() instead? It does error checking...
6121 while (*loc
&& *loc
!= ':')
6124 // TODO: number() instead? It does error checking...
6127 if (pos
>= orig_len
) {
6131 if (len
> (orig_len
- pos
))
6132 len
= orig_len
- pos
;
6134 for (str
= startp
; pos
; str
++, pos
--) {
6135 if (quotes
&& *str
== CTLESC
)
6138 for (loc
= startp
; len
; len
--) {
6139 if (quotes
&& *str
== CTLESC
)
6144 amount
= loc
- expdest
;
6145 STADJUST(amount
, expdest
);
6150 varunset(p
, str
, startp
, varflags
);
6153 resetloc
= expdest
- (char *)stackblock();
6155 /* We'll comeback here if we grow the stack while handling
6156 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6157 * stack will need rebasing, and we'll need to remove our work
6160 USE_ASH_BASH_COMPAT(restart
:)
6162 amount
= expdest
- ((char *)stackblock() + resetloc
);
6163 STADJUST(-amount
, expdest
);
6164 startp
= (char *)stackblock() + startloc
;
6167 rmescend
= (char *)stackblock() + strloc
;
6169 rmesc
= _rmescapes(startp
, RMESCAPE_ALLOC
| RMESCAPE_GROW
);
6170 if (rmesc
!= startp
) {
6172 startp
= (char *)stackblock() + startloc
;
6176 str
= (char *)stackblock() + strloc
;
6177 preglob(str
, varflags
& VSQUOTE
, 0);
6178 workloc
= expdest
- (char *)stackblock();
6180 #if ENABLE_ASH_BASH_COMPAT
6181 if (subtype
== VSREPLACE
|| subtype
== VSREPLACEALL
) {
6182 char *idx
, *end
, *restart_detect
;
6185 repl
= parse_sub_pattern(str
, varflags
& VSQUOTE
);
6190 /* If there's no pattern to match, return the expansion unmolested */
6198 loc
= scanright(idx
, rmesc
, rmescend
, str
, quotes
, 1);
6200 /* No match, advance */
6201 restart_detect
= stackblock();
6202 STPUTC(*idx
, expdest
);
6203 if (quotes
&& *idx
== CTLESC
) {
6206 STPUTC(*idx
, expdest
);
6208 if (stackblock() != restart_detect
)
6216 if (subtype
== VSREPLACEALL
) {
6218 if (quotes
&& *idx
== CTLESC
)
6227 for (loc
= repl
; *loc
; loc
++) {
6228 restart_detect
= stackblock();
6229 STPUTC(*loc
, expdest
);
6230 if (stackblock() != restart_detect
)
6235 if (subtype
== VSREPLACE
) {
6237 restart_detect
= stackblock();
6238 STPUTC(*idx
, expdest
);
6239 if (stackblock() != restart_detect
)
6248 /* We've put the replaced text into a buffer at workloc, now
6249 * move it to the right place and adjust the stack.
6251 startp
= stackblock() + startloc
;
6252 STPUTC('\0', expdest
);
6253 memmove(startp
, stackblock() + workloc
, len
);
6254 startp
[len
++] = '\0';
6255 amount
= expdest
- ((char *)stackblock() + startloc
+ len
- 1);
6256 STADJUST(-amount
, expdest
);
6259 #endif /* ENABLE_ASH_BASH_COMPAT */
6261 subtype
-= VSTRIMRIGHT
;
6263 if (subtype
< 0 || subtype
> 7)
6266 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
6267 zero
= subtype
>> 1;
6268 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6269 scan
= (subtype
& 1) ^ zero
? scanleft
: scanright
;
6271 loc
= scan(startp
, rmesc
, rmescend
, str
, quotes
, zero
);
6274 memmove(startp
, loc
, str
- loc
);
6275 loc
= startp
+ (str
- loc
) - 1;
6278 amount
= loc
- expdest
;
6279 STADJUST(amount
, expdest
);
6285 * Add the value of a specialized variable to the stack string.
6288 varvalue(char *name
, int varflags
, int flags
, struct strlist
*var_str_list
)
6298 int quoted
= varflags
& VSQUOTE
;
6299 int subtype
= varflags
& VSTYPE
;
6300 int quotes
= flags
& (EXP_FULL
| EXP_CASE
);
6302 if (quoted
&& (flags
& EXP_FULL
))
6303 sep
= 1 << CHAR_BIT
;
6305 syntax
= quoted
? DQSYNTAX
: BASESYNTAX
;
6314 num
= shellparam
.nparam
;
6324 expdest
= makestrspace(NOPTS
, expdest
);
6325 for (i
= NOPTS
- 1; i
>= 0; i
--) {
6327 USTPUTC(optletters(i
), expdest
);
6337 sep
= ifsset() ? signed_char2int(ifsval()[0]) : ' ';
6338 if (quotes
&& (SIT(sep
, syntax
) == CCTL
|| SIT(sep
, syntax
) == CBACK
))
6344 while ((p
= *ap
++)) {
6347 partlen
= strlen(p
);
6350 if (!(subtype
== VSPLUS
|| subtype
== VSLENGTH
))
6351 memtodest(p
, partlen
, syntax
, quotes
);
6357 if (subtype
== VSPLUS
|| subtype
== VSLENGTH
) {
6378 // TODO: number() instead? It does error checking...
6380 if (num
< 0 || num
> shellparam
.nparam
)
6382 p
= num
? shellparam
.p
[num
- 1] : arg0
;
6385 /* NB: name has form "VAR=..." */
6387 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6388 * which should be considered before we check variables. */
6390 unsigned name_len
= (strchrnul(name
, '=') - name
) + 1;
6394 str
= var_str_list
->text
;
6395 eq
= strchr(str
, '=');
6396 if (!eq
) /* stop at first non-assignment */
6399 if (name_len
== (unsigned)(eq
- str
)
6400 && strncmp(str
, name
, name_len
) == 0) {
6402 /* goto value; - WRONG! */
6403 /* think "A=1 A=2 B=$A" */
6405 var_str_list
= var_str_list
->next
;
6406 } while (var_str_list
);
6410 p
= lookupvar(name
);
6416 if (!(subtype
== VSPLUS
|| subtype
== VSLENGTH
))
6417 memtodest(p
, len
, syntax
, quotes
);
6421 if (subtype
== VSPLUS
|| subtype
== VSLENGTH
)
6422 STADJUST(-len
, expdest
);
6427 * Expand a variable, and return a pointer to the next character in the
6431 evalvar(char *p
, int flag
, struct strlist
*var_str_list
)
6443 subtype
= varflags
& VSTYPE
;
6444 quoted
= varflags
& VSQUOTE
;
6446 easy
= (!quoted
|| (*var
== '@' && shellparam
.nparam
));
6447 startloc
= expdest
- (char *)stackblock();
6448 p
= strchr(p
, '=') + 1;
6451 varlen
= varvalue(var
, varflags
, flag
, var_str_list
);
6452 if (varflags
& VSNUL
)
6455 if (subtype
== VSPLUS
) {
6456 varlen
= -1 - varlen
;
6460 if (subtype
== VSMINUS
) {
6464 p
, flag
| EXP_TILDE
|
6465 (quoted
? EXP_QWORD
: EXP_WORD
),
6475 if (subtype
== VSASSIGN
|| subtype
== VSQUESTION
) {
6477 if (subevalvar(p
, var
, /* strloc: */ 0,
6478 subtype
, startloc
, varflags
,
6484 * Remove any recorded regions beyond
6487 removerecordregions(startloc
);
6497 if (varlen
< 0 && uflag
)
6498 varunset(p
, var
, 0, 0);
6500 if (subtype
== VSLENGTH
) {
6501 cvtnum(varlen
> 0 ? varlen
: 0);
6505 if (subtype
== VSNORMAL
) {
6516 case VSTRIMRIGHTMAX
:
6517 #if ENABLE_ASH_BASH_COMPAT
6530 * Terminate the string and start recording the pattern
6533 STPUTC('\0', expdest
);
6534 patloc
= expdest
- (char *)stackblock();
6535 if (0 == subevalvar(p
, /* str: */ NULL
, patloc
, subtype
,
6537 /* quotes: */ flag
& (EXP_FULL
| EXP_CASE
),
6540 int amount
= expdest
- (
6541 (char *)stackblock() + patloc
- 1
6543 STADJUST(-amount
, expdest
);
6545 /* Remove any recorded regions beyond start of variable */
6546 removerecordregions(startloc
);
6548 recordregion(startloc
, expdest
- (char *)stackblock(), quoted
);
6552 if (subtype
!= VSNORMAL
) { /* skip to end of alternative */
6558 else if (c
== CTLBACKQ
|| c
== (CTLBACKQ
|CTLQUOTE
)) {
6560 argbackq
= argbackq
->next
;
6561 } else if (c
== CTLVAR
) {
6562 if ((*p
++ & VSTYPE
) != VSNORMAL
)
6564 } else if (c
== CTLENDVAR
) {
6574 * Break the argument string into pieces based upon IFS and add the
6575 * strings to the argument list. The regions of the string to be
6576 * searched for IFS characters have been stored by recordregion.
6579 ifsbreakup(char *string
, struct arglist
*arglist
)
6581 struct ifsregion
*ifsp
;
6586 const char *ifs
, *realifs
;
6591 if (ifslastp
!= NULL
) {
6594 realifs
= ifsset() ? ifsval() : defifs
;
6597 p
= string
+ ifsp
->begoff
;
6598 nulonly
= ifsp
->nulonly
;
6599 ifs
= nulonly
? nullstr
: realifs
;
6601 while (p
< string
+ ifsp
->endoff
) {
6605 if (!strchr(ifs
, *p
)) {
6610 ifsspc
= (strchr(defifs
, *p
) != NULL
);
6611 /* Ignore IFS whitespace at start */
6612 if (q
== start
&& ifsspc
) {
6618 sp
= stzalloc(sizeof(*sp
));
6620 *arglist
->lastp
= sp
;
6621 arglist
->lastp
= &sp
->next
;
6625 if (p
>= string
+ ifsp
->endoff
) {
6631 if (strchr(ifs
, *p
) == NULL
) {
6635 if (strchr(defifs
, *p
) == NULL
) {
6650 } while (ifsp
!= NULL
);
6659 sp
= stzalloc(sizeof(*sp
));
6661 *arglist
->lastp
= sp
;
6662 arglist
->lastp
= &sp
->next
;
6668 struct ifsregion
*p
;
6673 struct ifsregion
*ifsp
;
6679 ifsfirst
.next
= NULL
;
6684 * Add a file name to the list.
6687 addfname(const char *name
)
6691 sp
= stzalloc(sizeof(*sp
));
6692 sp
->text
= ststrdup(name
);
6694 exparg
.lastp
= &sp
->next
;
6697 static char *expdir
;
6700 * Do metacharacter (i.e. *, ?, [...]) expansion.
6703 expmeta(char *enddir
, char *name
)
6718 for (p
= name
; *p
; p
++) {
6719 if (*p
== '*' || *p
== '?')
6721 else if (*p
== '[') {
6728 if (*q
== '/' || *q
== '\0')
6735 } else if (*p
== '\\')
6737 else if (*p
== '/') {
6744 if (metaflag
== 0) { /* we've reached the end of the file name */
6745 if (enddir
!= expdir
)
6753 if (metaflag
== 0 || lstat(expdir
, &statb
) >= 0)
6764 } while (p
< start
);
6766 if (enddir
== expdir
) {
6768 } else if (enddir
== expdir
+ 1 && *expdir
== '/') {
6777 if (enddir
!= expdir
)
6779 if (*endname
== 0) {
6791 while (!intpending
&& (dp
= readdir(dirp
)) != NULL
) {
6792 if (dp
->d_name
[0] == '.' && !matchdot
)
6794 if (pmatch(start
, dp
->d_name
)) {
6796 strcpy(enddir
, dp
->d_name
);
6799 for (p
= enddir
, cp
= dp
->d_name
; (*p
++ = *cp
++) != '\0';)
6802 expmeta(p
, endname
);
6811 static struct strlist
*
6812 msort(struct strlist
*list
, int len
)
6814 struct strlist
*p
, *q
= NULL
;
6815 struct strlist
**lpp
;
6823 for (n
= half
; --n
>= 0;) {
6827 q
->next
= NULL
; /* terminate first half of list */
6828 q
= msort(list
, half
); /* sort first half of list */
6829 p
= msort(p
, len
- half
); /* sort second half */
6832 #if ENABLE_LOCALE_SUPPORT
6833 if (strcoll(p
->text
, q
->text
) < 0)
6835 if (strcmp(p
->text
, q
->text
) < 0)
6859 * Sort the results of file name expansion. It calculates the number of
6860 * strings to sort and then calls msort (short for merge sort) to do the
6863 static struct strlist
*
6864 expsort(struct strlist
*str
)
6870 for (sp
= str
; sp
; sp
= sp
->next
)
6872 return msort(str
, len
);
6876 expandmeta(struct strlist
*str
/*, int flag*/)
6878 static const char metachars
[] ALIGN1
= {
6881 /* TODO - EXP_REDIR */
6884 struct strlist
**savelastp
;
6890 if (!strpbrk(str
->text
, metachars
))
6892 savelastp
= exparg
.lastp
;
6895 p
= preglob(str
->text
, 0, RMESCAPE_ALLOC
| RMESCAPE_HEAP
);
6897 int i
= strlen(str
->text
);
6898 expdir
= ckmalloc(i
< 2048 ? 2048 : i
); /* XXX */
6906 if (exparg
.lastp
== savelastp
) {
6911 *exparg
.lastp
= str
;
6912 rmescapes(str
->text
);
6913 exparg
.lastp
= &str
->next
;
6915 *exparg
.lastp
= NULL
;
6916 *savelastp
= sp
= expsort(*savelastp
);
6917 while (sp
->next
!= NULL
)
6919 exparg
.lastp
= &sp
->next
;
6926 * Perform variable substitution and command substitution on an argument,
6927 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
6928 * perform splitting and file name expansion. When arglist is NULL, perform
6929 * here document expansion.
6932 expandarg(union node
*arg
, struct arglist
*arglist
, int flag
)
6937 argbackq
= arg
->narg
.backquote
;
6938 STARTSTACKSTR(expdest
);
6939 ifsfirst
.next
= NULL
;
6941 argstr(arg
->narg
.text
, flag
,
6942 /* var_str_list: */ arglist
? arglist
->list
: NULL
);
6943 p
= _STPUTC('\0', expdest
);
6945 if (arglist
== NULL
) {
6946 return; /* here document expanded */
6948 p
= grabstackstr(p
);
6949 exparg
.lastp
= &exparg
.list
;
6953 if (flag
& EXP_FULL
) {
6954 ifsbreakup(p
, &exparg
);
6955 *exparg
.lastp
= NULL
;
6956 exparg
.lastp
= &exparg
.list
;
6957 expandmeta(exparg
.list
/*, flag*/);
6959 if (flag
& EXP_REDIR
) /*XXX - for now, just remove escapes */
6961 sp
= stzalloc(sizeof(*sp
));
6964 exparg
.lastp
= &sp
->next
;
6968 *exparg
.lastp
= NULL
;
6970 *arglist
->lastp
= exparg
.list
;
6971 arglist
->lastp
= exparg
.lastp
;
6976 * Expand shell variables and backquotes inside a here document.
6979 expandhere(union node
*arg
, int fd
)
6982 expandarg(arg
, (struct arglist
*)NULL
, 0);
6983 full_write(fd
, stackblock(), expdest
- (char *)stackblock());
6987 * Returns true if the pattern matches the string.
6990 patmatch(char *pattern
, const char *string
)
6992 return pmatch(preglob(pattern
, 0, 0), string
);
6996 * See if a pattern matches in a case statement.
6999 casematch(union node
*pattern
, char *val
)
7001 struct stackmark smark
;
7004 setstackmark(&smark
);
7005 argbackq
= pattern
->narg
.backquote
;
7006 STARTSTACKSTR(expdest
);
7008 argstr(pattern
->narg
.text
, EXP_TILDE
| EXP_CASE
,
7009 /* var_str_list: */ NULL
);
7010 STACKSTRNUL(expdest
);
7011 result
= patmatch(stackblock(), val
);
7012 popstackmark(&smark
);
7017 /* ============ find_command */
7021 int (*builtin
)(int, char **);
7022 /* unsigned flags; */
7024 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
7025 /* "regular" builtins always take precedence over commands,
7026 * regardless of PATH=....%builtin... position */
7027 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
7028 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
7031 smallint cmdtype
; /* CMDxxx */
7034 /* index >= 0 for commands without path (slashes) */
7035 /* (TODO: what exactly does the value mean? PATH position?) */
7036 /* index == -1 for commands with slashes */
7037 /* index == (-2 - applet_no) for NOFORK applets */
7038 const struct builtincmd
*cmd
;
7039 struct funcnode
*func
;
7042 /* values of cmdtype */
7043 #define CMDUNKNOWN -1 /* no entry in table for command */
7044 #define CMDNORMAL 0 /* command is an executable program */
7045 #define CMDFUNCTION 1 /* command is a shell function */
7046 #define CMDBUILTIN 2 /* command is a shell builtin */
7048 /* action to find_command() */
7049 #define DO_ERR 0x01 /* prints errors */
7050 #define DO_ABS 0x02 /* checks absolute paths */
7051 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7052 #define DO_ALTPATH 0x08 /* using alternate path */
7053 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7055 static void find_command(char *, struct cmdentry
*, int, const char *);
7058 /* ============ Hashing commands */
7061 * When commands are first encountered, they are entered in a hash table.
7062 * This ensures that a full path search will not have to be done for them
7063 * on each invocation.
7065 * We should investigate converting to a linear search, even though that
7066 * would make the command name "hash" a misnomer.
7070 struct tblentry
*next
; /* next entry in hash chain */
7071 union param param
; /* definition of builtin function */
7072 smallint cmdtype
; /* CMDxxx */
7073 char rehash
; /* if set, cd done since entry created */
7074 char cmdname
[1]; /* name of command */
7077 static struct tblentry
**cmdtable
;
7078 #define INIT_G_cmdtable() do { \
7079 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7082 static int builtinloc
= -1; /* index in path of %builtin, or -1 */
7086 tryexec(USE_FEATURE_SH_STANDALONE(int applet_no
,) char *cmd
, char **argv
, char **envp
)
7090 #if ENABLE_FEATURE_SH_STANDALONE
7091 if (applet_no
>= 0) {
7092 if (APPLET_IS_NOEXEC(applet_no
)) {
7095 run_applet_no_and_exit(applet_no
, argv
);
7097 /* re-exec ourselves with the new arguments */
7098 execve(bb_busybox_exec_path
, argv
, envp
);
7099 /* If they called chroot or otherwise made the binary no longer
7100 * executable, fall through */
7107 execve(cmd
, argv
, envp
);
7108 } while (errno
== EINTR
);
7110 execve(cmd
, argv
, envp
);
7116 if (errno
== ENOEXEC
) {
7120 for (ap
= argv
; *ap
; ap
++)
7122 ap
= new = ckmalloc((ap
- argv
+ 2) * sizeof(ap
[0]));
7124 ap
[0] = cmd
= (char *)DEFAULT_SHELL
;
7127 while ((*ap
++ = *argv
++) != NULL
)
7136 * Exec a program. Never returns. If you change this routine, you may
7137 * have to change the find_command routine as well.
7139 static void shellexec(char **, const char *, int) NORETURN
;
7141 shellexec(char **argv
, const char *path
, int idx
)
7147 #if ENABLE_FEATURE_SH_STANDALONE
7151 clearredir(/*drop:*/ 1);
7152 envp
= listvars(VEXPORT
, VUNSET
, 0);
7153 if (strchr(argv
[0], '/') != NULL
7154 #if ENABLE_FEATURE_SH_STANDALONE
7155 || (applet_no
= find_applet_by_name(argv
[0])) >= 0
7158 tryexec(USE_FEATURE_SH_STANDALONE(applet_no
,) argv
[0], argv
, envp
);
7162 while ((cmdname
= padvance(&path
, argv
[0])) != NULL
) {
7163 if (--idx
< 0 && pathopt
== NULL
) {
7164 tryexec(USE_FEATURE_SH_STANDALONE(-1,) cmdname
, argv
, envp
);
7165 if (errno
!= ENOENT
&& errno
!= ENOTDIR
)
7172 /* Map to POSIX errors */
7184 exitstatus
= exerrno
;
7185 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
7186 argv
[0], e
, suppressint
));
7187 ash_msg_and_raise(EXEXEC
, "%s: %s", argv
[0], errmsg(e
, "not found"));
7192 printentry(struct tblentry
*cmdp
)
7198 idx
= cmdp
->param
.index
;
7201 name
= padvance(&path
, cmdp
->cmdname
);
7203 } while (--idx
>= 0);
7204 out1fmt("%s%s\n", name
, (cmdp
->rehash
? "*" : nullstr
));
7208 * Clear out command entries. The argument specifies the first entry in
7209 * PATH which has changed.
7212 clearcmdentry(int firstchange
)
7214 struct tblentry
**tblp
;
7215 struct tblentry
**pp
;
7216 struct tblentry
*cmdp
;
7219 for (tblp
= cmdtable
; tblp
< &cmdtable
[CMDTABLESIZE
]; tblp
++) {
7221 while ((cmdp
= *pp
) != NULL
) {
7222 if ((cmdp
->cmdtype
== CMDNORMAL
&&
7223 cmdp
->param
.index
>= firstchange
)
7224 || (cmdp
->cmdtype
== CMDBUILTIN
&&
7225 builtinloc
>= firstchange
)
7238 * Locate a command in the command hash table. If "add" is nonzero,
7239 * add the command to the table if it is not already present. The
7240 * variable "lastcmdentry" is set to point to the address of the link
7241 * pointing to the entry, so that delete_cmd_entry can delete the
7244 * Interrupts must be off if called with add != 0.
7246 static struct tblentry
**lastcmdentry
;
7248 static struct tblentry
*
7249 cmdlookup(const char *name
, int add
)
7251 unsigned int hashval
;
7253 struct tblentry
*cmdp
;
7254 struct tblentry
**pp
;
7257 hashval
= (unsigned char)*p
<< 4;
7259 hashval
+= (unsigned char)*p
++;
7261 pp
= &cmdtable
[hashval
% CMDTABLESIZE
];
7262 for (cmdp
= *pp
; cmdp
; cmdp
= cmdp
->next
) {
7263 if (strcmp(cmdp
->cmdname
, name
) == 0)
7267 if (add
&& cmdp
== NULL
) {
7268 cmdp
= *pp
= ckzalloc(sizeof(struct tblentry
)
7270 /* + 1 - already done because
7271 * tblentry::cmdname is char[1] */);
7272 /*cmdp->next = NULL; - ckzalloc did it */
7273 cmdp
->cmdtype
= CMDUNKNOWN
;
7274 strcpy(cmdp
->cmdname
, name
);
7281 * Delete the command entry returned on the last lookup.
7284 delete_cmd_entry(void)
7286 struct tblentry
*cmdp
;
7289 cmdp
= *lastcmdentry
;
7290 *lastcmdentry
= cmdp
->next
;
7291 if (cmdp
->cmdtype
== CMDFUNCTION
)
7292 freefunc(cmdp
->param
.func
);
7298 * Add a new command entry, replacing any existing command entry for
7299 * the same name - except special builtins.
7302 addcmdentry(char *name
, struct cmdentry
*entry
)
7304 struct tblentry
*cmdp
;
7306 cmdp
= cmdlookup(name
, 1);
7307 if (cmdp
->cmdtype
== CMDFUNCTION
) {
7308 freefunc(cmdp
->param
.func
);
7310 cmdp
->cmdtype
= entry
->cmdtype
;
7311 cmdp
->param
= entry
->u
;
7316 hashcmd(int argc UNUSED_PARAM
, char **argv UNUSED_PARAM
)
7318 struct tblentry
**pp
;
7319 struct tblentry
*cmdp
;
7321 struct cmdentry entry
;
7324 if (nextopt("r") != '\0') {
7329 if (*argptr
== NULL
) {
7330 for (pp
= cmdtable
; pp
< &cmdtable
[CMDTABLESIZE
]; pp
++) {
7331 for (cmdp
= *pp
; cmdp
; cmdp
= cmdp
->next
) {
7332 if (cmdp
->cmdtype
== CMDNORMAL
)
7340 while ((name
= *argptr
) != NULL
) {
7341 cmdp
= cmdlookup(name
, 0);
7343 && (cmdp
->cmdtype
== CMDNORMAL
7344 || (cmdp
->cmdtype
== CMDBUILTIN
&& builtinloc
>= 0))
7348 find_command(name
, &entry
, DO_ERR
, pathval());
7349 if (entry
.cmdtype
== CMDUNKNOWN
)
7357 * Called when a cd is done. Marks all commands so the next time they
7358 * are executed they will be rehashed.
7363 struct tblentry
**pp
;
7364 struct tblentry
*cmdp
;
7366 for (pp
= cmdtable
; pp
< &cmdtable
[CMDTABLESIZE
]; pp
++) {
7367 for (cmdp
= *pp
; cmdp
; cmdp
= cmdp
->next
) {
7368 if (cmdp
->cmdtype
== CMDNORMAL
7369 || (cmdp
->cmdtype
== CMDBUILTIN
7370 && !IS_BUILTIN_REGULAR(cmdp
->param
.cmd
)
7380 * Fix command hash table when PATH changed.
7381 * Called before PATH is changed. The argument is the new value of PATH;
7382 * pathval() still returns the old value at this point.
7383 * Called with interrupts off.
7386 changepath(const char *new)
7394 firstchange
= 9999; /* assume no change */
7400 if ((*old
== '\0' && *new == ':')
7401 || (*old
== ':' && *new == '\0'))
7403 old
= new; /* ignore subsequent differences */
7407 if (*new == '%' && idx_bltin
< 0 && prefix(new + 1, "builtin"))
7413 if (builtinloc
< 0 && idx_bltin
>= 0)
7414 builtinloc
= idx_bltin
; /* zap builtins */
7415 if (builtinloc
>= 0 && idx_bltin
< 0)
7417 clearcmdentry(firstchange
);
7418 builtinloc
= idx_bltin
;
7433 #define TENDBQUOTE 12
7450 typedef smallint token_id_t
;
7452 /* first char is indicating which tokens mark the end of a list */
7453 static const char *const tokname_array
[] = {
7467 #define KWDOFFSET 13
7468 /* the following are keywords */
7490 static char buf
[16];
7493 //if (tok < TSEMI) return tokname_array[tok] + 1;
7494 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
7499 sprintf(buf
+ (tok
>= TSEMI
), "%s%c",
7500 tokname_array
[tok
] + 1, (tok
>= TSEMI
? '"' : 0));
7504 /* Wrapper around strcmp for qsort/bsearch/... */
7506 pstrcmp(const void *a
, const void *b
)
7508 return strcmp((char*) a
, (*(char**) b
) + 1);
7511 static const char *const *
7512 findkwd(const char *s
)
7514 return bsearch(s
, tokname_array
+ KWDOFFSET
,
7515 ARRAY_SIZE(tokname_array
) - KWDOFFSET
,
7516 sizeof(tokname_array
[0]), pstrcmp
);
7520 * Locate and print what a word is...
7523 describe_command(char *command
, int describe_command_verbose
)
7525 struct cmdentry entry
;
7526 struct tblentry
*cmdp
;
7527 #if ENABLE_ASH_ALIAS
7528 const struct alias
*ap
;
7530 const char *path
= pathval();
7532 if (describe_command_verbose
) {
7536 /* First look at the keywords */
7537 if (findkwd(command
)) {
7538 out1str(describe_command_verbose
? " is a shell keyword" : command
);
7542 #if ENABLE_ASH_ALIAS
7543 /* Then look at the aliases */
7544 ap
= lookupalias(command
, 0);
7546 if (!describe_command_verbose
) {
7551 out1fmt(" is an alias for %s", ap
->val
);
7555 /* Then check if it is a tracked alias */
7556 cmdp
= cmdlookup(command
, 0);
7558 entry
.cmdtype
= cmdp
->cmdtype
;
7559 entry
.u
= cmdp
->param
;
7561 /* Finally use brute force */
7562 find_command(command
, &entry
, DO_ABS
, path
);
7565 switch (entry
.cmdtype
) {
7567 int j
= entry
.u
.index
;
7573 p
= padvance(&path
, command
);
7577 if (describe_command_verbose
) {
7579 (cmdp
? " a tracked alias for" : nullstr
), p
7588 if (describe_command_verbose
) {
7589 out1str(" is a shell function");
7596 if (describe_command_verbose
) {
7597 out1fmt(" is a %sshell builtin",
7598 IS_BUILTIN_SPECIAL(entry
.u
.cmd
) ?
7599 "special " : nullstr
7607 if (describe_command_verbose
) {
7608 out1str(": not found\n");
7613 outstr("\n", stdout
);
7618 typecmd(int argc UNUSED_PARAM
, char **argv
)
7624 /* type -p ... ? (we don't bother checking for 'p') */
7625 if (argv
[1] && argv
[1][0] == '-') {
7630 err
|= describe_command(argv
[i
++], verbose
);
7635 #if ENABLE_ASH_CMDCMD
7637 commandcmd(int argc UNUSED_PARAM
, char **argv UNUSED_PARAM
)
7645 while ((c
= nextopt("pvV")) != '\0')
7647 verify
|= VERIFY_VERBOSE
;
7649 verify
|= VERIFY_BRIEF
;
7654 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7655 if (verify
&& (*argptr
!= NULL
)) {
7656 return describe_command(*argptr
, verify
- VERIFY_BRIEF
);
7664 /* ============ eval.c */
7666 static int funcblocksize
; /* size of structures in function */
7667 static int funcstringsize
; /* size of strings in node */
7668 static void *funcblock
; /* block to allocate function from */
7669 static char *funcstring
; /* block to allocate strings from */
7671 /* flags in argument to evaltree */
7672 #define EV_EXIT 01 /* exit after evaluating tree */
7673 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
7674 #define EV_BACKCMD 04 /* command executing within back quotes */
7676 static const short nodesize
[N_NUMBER
] = {
7677 [NCMD
] = SHELL_ALIGN(sizeof(struct ncmd
)),
7678 [NPIPE
] = SHELL_ALIGN(sizeof(struct npipe
)),
7679 [NREDIR
] = SHELL_ALIGN(sizeof(struct nredir
)),
7680 [NBACKGND
] = SHELL_ALIGN(sizeof(struct nredir
)),
7681 [NSUBSHELL
] = SHELL_ALIGN(sizeof(struct nredir
)),
7682 [NAND
] = SHELL_ALIGN(sizeof(struct nbinary
)),
7683 [NOR
] = SHELL_ALIGN(sizeof(struct nbinary
)),
7684 [NSEMI
] = SHELL_ALIGN(sizeof(struct nbinary
)),
7685 [NIF
] = SHELL_ALIGN(sizeof(struct nif
)),
7686 [NWHILE
] = SHELL_ALIGN(sizeof(struct nbinary
)),
7687 [NUNTIL
] = SHELL_ALIGN(sizeof(struct nbinary
)),
7688 [NFOR
] = SHELL_ALIGN(sizeof(struct nfor
)),
7689 [NCASE
] = SHELL_ALIGN(sizeof(struct ncase
)),
7690 [NCLIST
] = SHELL_ALIGN(sizeof(struct nclist
)),
7691 [NDEFUN
] = SHELL_ALIGN(sizeof(struct narg
)),
7692 [NARG
] = SHELL_ALIGN(sizeof(struct narg
)),
7693 [NTO
] = SHELL_ALIGN(sizeof(struct nfile
)),
7694 #if ENABLE_ASH_BASH_COMPAT
7695 [NTO2
] = SHELL_ALIGN(sizeof(struct nfile
)),
7697 [NCLOBBER
] = SHELL_ALIGN(sizeof(struct nfile
)),
7698 [NFROM
] = SHELL_ALIGN(sizeof(struct nfile
)),
7699 [NFROMTO
] = SHELL_ALIGN(sizeof(struct nfile
)),
7700 [NAPPEND
] = SHELL_ALIGN(sizeof(struct nfile
)),
7701 [NTOFD
] = SHELL_ALIGN(sizeof(struct ndup
)),
7702 [NFROMFD
] = SHELL_ALIGN(sizeof(struct ndup
)),
7703 [NHERE
] = SHELL_ALIGN(sizeof(struct nhere
)),
7704 [NXHERE
] = SHELL_ALIGN(sizeof(struct nhere
)),
7705 [NNOT
] = SHELL_ALIGN(sizeof(struct nnot
)),
7708 static void calcsize(union node
*n
);
7711 sizenodelist(struct nodelist
*lp
)
7714 funcblocksize
+= SHELL_ALIGN(sizeof(struct nodelist
));
7721 calcsize(union node
*n
)
7725 funcblocksize
+= nodesize
[n
->type
];
7728 calcsize(n
->ncmd
.redirect
);
7729 calcsize(n
->ncmd
.args
);
7730 calcsize(n
->ncmd
.assign
);
7733 sizenodelist(n
->npipe
.cmdlist
);
7738 calcsize(n
->nredir
.redirect
);
7739 calcsize(n
->nredir
.n
);
7746 calcsize(n
->nbinary
.ch2
);
7747 calcsize(n
->nbinary
.ch1
);
7750 calcsize(n
->nif
.elsepart
);
7751 calcsize(n
->nif
.ifpart
);
7752 calcsize(n
->nif
.test
);
7755 funcstringsize
+= strlen(n
->nfor
.var
) + 1;
7756 calcsize(n
->nfor
.body
);
7757 calcsize(n
->nfor
.args
);
7760 calcsize(n
->ncase
.cases
);
7761 calcsize(n
->ncase
.expr
);
7764 calcsize(n
->nclist
.body
);
7765 calcsize(n
->nclist
.pattern
);
7766 calcsize(n
->nclist
.next
);
7770 sizenodelist(n
->narg
.backquote
);
7771 funcstringsize
+= strlen(n
->narg
.text
) + 1;
7772 calcsize(n
->narg
.next
);
7775 #if ENABLE_ASH_BASH_COMPAT
7782 calcsize(n
->nfile
.fname
);
7783 calcsize(n
->nfile
.next
);
7787 calcsize(n
->ndup
.vname
);
7788 calcsize(n
->ndup
.next
);
7792 calcsize(n
->nhere
.doc
);
7793 calcsize(n
->nhere
.next
);
7796 calcsize(n
->nnot
.com
);
7802 nodeckstrdup(char *s
)
7804 char *rtn
= funcstring
;
7806 strcpy(funcstring
, s
);
7807 funcstring
+= strlen(s
) + 1;
7811 static union node
*copynode(union node
*);
7813 static struct nodelist
*
7814 copynodelist(struct nodelist
*lp
)
7816 struct nodelist
*start
;
7817 struct nodelist
**lpp
;
7822 funcblock
= (char *) funcblock
+ SHELL_ALIGN(sizeof(struct nodelist
));
7823 (*lpp
)->n
= copynode(lp
->n
);
7825 lpp
= &(*lpp
)->next
;
7832 copynode(union node
*n
)
7839 funcblock
= (char *) funcblock
+ nodesize
[n
->type
];
7843 new->ncmd
.redirect
= copynode(n
->ncmd
.redirect
);
7844 new->ncmd
.args
= copynode(n
->ncmd
.args
);
7845 new->ncmd
.assign
= copynode(n
->ncmd
.assign
);
7848 new->npipe
.cmdlist
= copynodelist(n
->npipe
.cmdlist
);
7849 new->npipe
.pipe_backgnd
= n
->npipe
.pipe_backgnd
;
7854 new->nredir
.redirect
= copynode(n
->nredir
.redirect
);
7855 new->nredir
.n
= copynode(n
->nredir
.n
);
7862 new->nbinary
.ch2
= copynode(n
->nbinary
.ch2
);
7863 new->nbinary
.ch1
= copynode(n
->nbinary
.ch1
);
7866 new->nif
.elsepart
= copynode(n
->nif
.elsepart
);
7867 new->nif
.ifpart
= copynode(n
->nif
.ifpart
);
7868 new->nif
.test
= copynode(n
->nif
.test
);
7871 new->nfor
.var
= nodeckstrdup(n
->nfor
.var
);
7872 new->nfor
.body
= copynode(n
->nfor
.body
);
7873 new->nfor
.args
= copynode(n
->nfor
.args
);
7876 new->ncase
.cases
= copynode(n
->ncase
.cases
);
7877 new->ncase
.expr
= copynode(n
->ncase
.expr
);
7880 new->nclist
.body
= copynode(n
->nclist
.body
);
7881 new->nclist
.pattern
= copynode(n
->nclist
.pattern
);
7882 new->nclist
.next
= copynode(n
->nclist
.next
);
7886 new->narg
.backquote
= copynodelist(n
->narg
.backquote
);
7887 new->narg
.text
= nodeckstrdup(n
->narg
.text
);
7888 new->narg
.next
= copynode(n
->narg
.next
);
7891 #if ENABLE_ASH_BASH_COMPAT
7898 new->nfile
.fname
= copynode(n
->nfile
.fname
);
7899 new->nfile
.fd
= n
->nfile
.fd
;
7900 new->nfile
.next
= copynode(n
->nfile
.next
);
7904 new->ndup
.vname
= copynode(n
->ndup
.vname
);
7905 new->ndup
.dupfd
= n
->ndup
.dupfd
;
7906 new->ndup
.fd
= n
->ndup
.fd
;
7907 new->ndup
.next
= copynode(n
->ndup
.next
);
7911 new->nhere
.doc
= copynode(n
->nhere
.doc
);
7912 new->nhere
.fd
= n
->nhere
.fd
;
7913 new->nhere
.next
= copynode(n
->nhere
.next
);
7916 new->nnot
.com
= copynode(n
->nnot
.com
);
7919 new->type
= n
->type
;
7924 * Make a copy of a parse tree.
7926 static struct funcnode
*
7927 copyfunc(union node
*n
)
7932 funcblocksize
= offsetof(struct funcnode
, n
);
7935 blocksize
= funcblocksize
;
7936 f
= ckmalloc(blocksize
+ funcstringsize
);
7937 funcblock
= (char *) f
+ offsetof(struct funcnode
, n
);
7938 funcstring
= (char *) f
+ blocksize
;
7945 * Define a shell function.
7948 defun(char *name
, union node
*func
)
7950 struct cmdentry entry
;
7953 entry
.cmdtype
= CMDFUNCTION
;
7954 entry
.u
.func
= copyfunc(func
);
7955 addcmdentry(name
, &entry
);
7959 /* Reasons for skipping commands (see comment on breakcmd routine) */
7960 #define SKIPBREAK (1 << 0)
7961 #define SKIPCONT (1 << 1)
7962 #define SKIPFUNC (1 << 2)
7963 #define SKIPFILE (1 << 3)
7964 #define SKIPEVAL (1 << 4)
7965 static smallint evalskip
; /* set to SKIPxxx if we are skipping commands */
7966 static int skipcount
; /* number of levels to skip */
7967 static int funcnest
; /* depth of function calls */
7968 static int loopnest
; /* current loop nesting level */
7970 /* Forward decl way out to parsing code - dotrap needs it */
7971 static int evalstring(char *s
, int mask
);
7973 /* Called to execute a trap.
7974 * Single callsite - at the end of evaltree().
7975 * If we return non-zero, exaltree raises EXEXIT exception.
7977 * Perhaps we should avoid entering new trap handlers
7978 * while we are executing a trap handler. [is it a TODO?]
7987 savestatus
= exitstatus
;
7991 TRACE(("dotrap entered\n"));
7992 for (sig
= 1, g
= gotsig
; sig
< NSIG
; sig
++, g
++) {
7999 /* non-trapped SIGINT is handled separately by raise_interrupt,
8000 * don't upset it by resetting gotsig[SIGINT-1] */
8001 if (sig
== SIGINT
&& !t
)
8004 TRACE(("sig %d is active, will run handler '%s'\n", sig
, t
));
8008 want_exexit
= evalstring(t
, SKIPEVAL
);
8009 exitstatus
= savestatus
;
8011 TRACE(("dotrap returns %d\n", want_exexit
));
8016 TRACE(("dotrap returns 0\n"));
8020 /* forward declarations - evaluation is fairly recursive business... */
8021 static void evalloop(union node
*, int);
8022 static void evalfor(union node
*, int);
8023 static void evalcase(union node
*, int);
8024 static void evalsubshell(union node
*, int);
8025 static void expredir(union node
*);
8026 static void evalpipe(union node
*, int);
8027 static void evalcommand(union node
*, int);
8028 static int evalbltin(const struct builtincmd
*, int, char **);
8029 static void prehash(union node
*);
8032 * Evaluate a parse tree. The value is left in the global variable
8036 evaltree(union node
*n
, int flags
)
8038 struct jmploc
*volatile savehandler
= exception_handler
;
8039 struct jmploc jmploc
;
8041 void (*evalfn
)(union node
*, int);
8045 SAVE_INT(int_level
);
8048 TRACE(("evaltree(NULL) called\n"));
8051 TRACE(("evaltree(%p: %d, %d) called\n", n
, n
->type
, flags
));
8053 exception_handler
= &jmploc
;
8055 int err
= setjmp(jmploc
.loc
);
8057 /* if it was a signal, check for trap handlers */
8058 if (exception_type
== EXSIG
) {
8059 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8060 exception_type
, err
));
8063 /* continue on the way out */
8064 TRACE(("exception %d in evaltree, propagating err=%d\n",
8065 exception_type
, err
));
8066 exception_handler
= savehandler
;
8067 longjmp(exception_handler
->loc
, err
);
8074 out1fmt("Node type = %d\n", n
->type
);
8079 evaltree(n
->nnot
.com
, EV_TESTED
);
8080 status
= !exitstatus
;
8083 expredir(n
->nredir
.redirect
);
8084 status
= redirectsafe(n
->nredir
.redirect
, REDIR_PUSH
);
8086 evaltree(n
->nredir
.n
, flags
& EV_TESTED
);
8087 status
= exitstatus
;
8089 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
8092 evalfn
= evalcommand
;
8094 if (eflag
&& !(flags
& EV_TESTED
))
8106 evalfn
= evalsubshell
;
8119 #error NAND + 1 != NOR
8121 #if NOR + 1 != NSEMI
8122 #error NOR + 1 != NSEMI
8124 unsigned is_or
= n
->type
- NAND
;
8127 (flags
| ((is_or
>> 1) - 1)) & EV_TESTED
8129 if (!exitstatus
== is_or
)
8142 evaltree(n
->nif
.test
, EV_TESTED
);
8145 if (exitstatus
== 0) {
8149 if (n
->nif
.elsepart
) {
8150 n
= n
->nif
.elsepart
;
8155 defun(n
->narg
.text
, n
->narg
.next
);
8159 exitstatus
= status
;
8164 exception_handler
= savehandler
;
8166 if (checkexit
& exitstatus
)
8167 evalskip
|= SKIPEVAL
;
8168 else if (pendingsig
&& dotrap())
8171 if (flags
& EV_EXIT
) {
8173 raise_exception(EXEXIT
);
8176 RESTORE_INT(int_level
);
8177 TRACE(("leaving evaltree (no interrupts)\n"));
8180 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8183 void evaltreenr(union node
*, int) __attribute__ ((alias("evaltree"),__noreturn__
));
8186 evalloop(union node
*n
, int flags
)
8196 evaltree(n
->nbinary
.ch1
, EV_TESTED
);
8199 if (evalskip
== SKIPCONT
&& --skipcount
<= 0) {
8203 if (evalskip
== SKIPBREAK
&& --skipcount
<= 0)
8208 if (n
->type
!= NWHILE
)
8212 evaltree(n
->nbinary
.ch2
, flags
);
8213 status
= exitstatus
;
8218 exitstatus
= status
;
8222 evalfor(union node
*n
, int flags
)
8224 struct arglist arglist
;
8227 struct stackmark smark
;
8229 setstackmark(&smark
);
8230 arglist
.list
= NULL
;
8231 arglist
.lastp
= &arglist
.list
;
8232 for (argp
= n
->nfor
.args
; argp
; argp
= argp
->narg
.next
) {
8233 expandarg(argp
, &arglist
, EXP_FULL
| EXP_TILDE
| EXP_RECORD
);
8238 *arglist
.lastp
= NULL
;
8243 for (sp
= arglist
.list
; sp
; sp
= sp
->next
) {
8244 setvar(n
->nfor
.var
, sp
->text
, 0);
8245 evaltree(n
->nfor
.body
, flags
);
8247 if (evalskip
== SKIPCONT
&& --skipcount
<= 0) {
8251 if (evalskip
== SKIPBREAK
&& --skipcount
<= 0)
8258 popstackmark(&smark
);
8262 evalcase(union node
*n
, int flags
)
8266 struct arglist arglist
;
8267 struct stackmark smark
;
8269 setstackmark(&smark
);
8270 arglist
.list
= NULL
;
8271 arglist
.lastp
= &arglist
.list
;
8272 expandarg(n
->ncase
.expr
, &arglist
, EXP_TILDE
);
8274 for (cp
= n
->ncase
.cases
; cp
&& evalskip
== 0; cp
= cp
->nclist
.next
) {
8275 for (patp
= cp
->nclist
.pattern
; patp
; patp
= patp
->narg
.next
) {
8276 if (casematch(patp
, arglist
.list
->text
)) {
8277 if (evalskip
== 0) {
8278 evaltree(cp
->nclist
.body
, flags
);
8285 popstackmark(&smark
);
8289 * Kick off a subshell to evaluate a tree.
8292 evalsubshell(union node
*n
, int flags
)
8295 int backgnd
= (n
->type
== NBACKGND
);
8298 expredir(n
->nredir
.redirect
);
8299 if (!backgnd
&& flags
& EV_EXIT
&& !trap
[0])
8302 jp
= makejob(/*n,*/ 1);
8303 if (forkshell(jp
, n
, backgnd
) == 0) {
8307 flags
&=~ EV_TESTED
;
8309 redirect(n
->nredir
.redirect
, 0);
8310 evaltreenr(n
->nredir
.n
, flags
);
8315 status
= waitforjob(jp
);
8316 exitstatus
= status
;
8321 * Compute the names of the files in a redirection list.
8323 static void fixredir(union node
*, const char *, int);
8325 expredir(union node
*n
)
8329 for (redir
= n
; redir
; redir
= redir
->nfile
.next
) {
8333 fn
.lastp
= &fn
.list
;
8334 switch (redir
->type
) {
8338 #if ENABLE_ASH_BASH_COMPAT
8343 expandarg(redir
->nfile
.fname
, &fn
, EXP_TILDE
| EXP_REDIR
);
8344 #if ENABLE_ASH_BASH_COMPAT
8347 redir
->nfile
.expfname
= fn
.list
->text
;
8350 case NTOFD
: /* >& */
8351 if (redir
->ndup
.vname
) {
8352 expandarg(redir
->ndup
.vname
, &fn
, EXP_FULL
| EXP_TILDE
);
8353 if (fn
.list
== NULL
)
8354 ash_msg_and_raise_error("redir error");
8355 #if ENABLE_ASH_BASH_COMPAT
8356 //FIXME: we used expandarg with different args!
8357 if (!isdigit_str9(fn
.list
->text
)) {
8358 /* >&file, not >&fd */
8359 if (redir
->nfile
.fd
!= 1) /* 123>&file - BAD */
8360 ash_msg_and_raise_error("redir error");
8362 goto store_expfname
;
8365 fixredir(redir
, fn
.list
->text
, 1);
8373 * Evaluate a pipeline. All the processes in the pipeline are children
8374 * of the process creating the pipeline. (This differs from some versions
8375 * of the shell, which make the last process in a pipeline the parent
8379 evalpipe(union node
*n
, int flags
)
8382 struct nodelist
*lp
;
8387 TRACE(("evalpipe(0x%lx) called\n", (long)n
));
8389 for (lp
= n
->npipe
.cmdlist
; lp
; lp
= lp
->next
)
8393 jp
= makejob(/*n,*/ pipelen
);
8395 for (lp
= n
->npipe
.cmdlist
; lp
; lp
= lp
->next
) {
8399 if (pipe(pip
) < 0) {
8401 ash_msg_and_raise_error("pipe call failed");
8404 if (forkshell(jp
, lp
->n
, n
->npipe
.pipe_backgnd
) == 0) {
8417 evaltreenr(lp
->n
, flags
);
8423 /* Don't want to trigger debugging */
8427 if (n
->npipe
.pipe_backgnd
== 0) {
8428 exitstatus
= waitforjob(jp
);
8429 TRACE(("evalpipe: job done exit status %d\n", exitstatus
));
8435 * Controls whether the shell is interactive or not.
8438 setinteractive(int on
)
8440 static smallint is_interactive
;
8442 if (++on
== is_interactive
)
8444 is_interactive
= on
;
8448 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8449 if (is_interactive
> 1) {
8450 /* Looks like they want an interactive shell */
8451 static smallint did_banner
;
8456 "%s built-in shell (ash)\n"
8457 "Enter 'help' for a list of built-in commands."
8472 setinteractive(iflag
);
8474 #if ENABLE_FEATURE_EDITING_VI
8476 line_input_state
->flags
|= VI_MODE
;
8478 line_input_state
->flags
&= ~VI_MODE
;
8480 viflag
= 0; /* forcibly keep the option off */
8484 static struct localvar
*localvars
;
8487 * Called after a function returns.
8488 * Interrupts must be off.
8493 struct localvar
*lvp
;
8496 while ((lvp
= localvars
) != NULL
) {
8497 localvars
= lvp
->next
;
8499 TRACE(("poplocalvar %s", vp
? vp
->text
: "-"));
8500 if (vp
== NULL
) { /* $- saved */
8501 memcpy(optlist
, lvp
->text
, sizeof(optlist
));
8502 free((char*)lvp
->text
);
8504 } else if ((lvp
->flags
& (VUNSET
|VSTRFIXED
)) == VUNSET
) {
8508 (*vp
->func
)(strchrnul(lvp
->text
, '=') + 1);
8509 if ((vp
->flags
& (VTEXTFIXED
|VSTACK
)) == 0)
8510 free((char*)vp
->text
);
8511 vp
->flags
= lvp
->flags
;
8512 vp
->text
= lvp
->text
;
8519 evalfun(struct funcnode
*func
, int argc
, char **argv
, int flags
)
8521 volatile struct shparam saveparam
;
8522 struct localvar
*volatile savelocalvars
;
8523 struct jmploc
*volatile savehandler
;
8524 struct jmploc jmploc
;
8527 saveparam
= shellparam
;
8528 savelocalvars
= localvars
;
8529 e
= setjmp(jmploc
.loc
);
8534 savehandler
= exception_handler
;
8535 exception_handler
= &jmploc
;
8537 shellparam
.malloced
= 0;
8541 shellparam
.nparam
= argc
- 1;
8542 shellparam
.p
= argv
+ 1;
8543 #if ENABLE_ASH_GETOPTS
8544 shellparam
.optind
= 1;
8545 shellparam
.optoff
= -1;
8547 evaltree(&func
->n
, flags
& EV_TESTED
);
8553 localvars
= savelocalvars
;
8554 freeparam(&shellparam
);
8555 shellparam
= saveparam
;
8556 exception_handler
= savehandler
;
8558 evalskip
&= ~SKIPFUNC
;
8562 #if ENABLE_ASH_CMDCMD
8564 parse_command_args(char **argv
, const char **path
)
8577 if (c
== '-' && !*cp
) {
8584 *path
= bb_default_path
;
8587 /* run 'typecmd' for other options */
8598 * Make a variable a local variable. When a variable is made local, it's
8599 * value and flags are saved in a localvar structure. The saved values
8600 * will be restored when the shell function returns. We handle the name
8601 * "-" as a special case.
8606 struct localvar
*lvp
;
8611 lvp
= ckzalloc(sizeof(struct localvar
));
8612 if (LONE_DASH(name
)) {
8614 p
= ckmalloc(sizeof(optlist
));
8615 lvp
->text
= memcpy(p
, optlist
, sizeof(optlist
));
8620 vpp
= hashvar(name
);
8621 vp
= *findvar(vpp
, name
);
8622 eq
= strchr(name
, '=');
8625 setvareq(name
, VSTRFIXED
);
8627 setvar(name
, NULL
, VSTRFIXED
);
8628 vp
= *vpp
; /* the new variable */
8629 lvp
->flags
= VUNSET
;
8631 lvp
->text
= vp
->text
;
8632 lvp
->flags
= vp
->flags
;
8633 vp
->flags
|= VSTRFIXED
|VTEXTFIXED
;
8639 lvp
->next
= localvars
;
8645 * The "local" command.
8648 localcmd(int argc UNUSED_PARAM
, char **argv
)
8653 while ((name
= *argv
++) != NULL
) {
8660 falsecmd(int argc UNUSED_PARAM
, char **argv UNUSED_PARAM
)
8666 truecmd(int argc UNUSED_PARAM
, char **argv UNUSED_PARAM
)
8672 execcmd(int argc UNUSED_PARAM
, char **argv
)
8675 iflag
= 0; /* exit on error */
8678 shellexec(argv
+ 1, pathval(), 0);
8684 * The return command.
8687 returncmd(int argc UNUSED_PARAM
, char **argv
)
8690 * If called outside a function, do what ksh does;
8691 * skip the rest of the file.
8693 evalskip
= funcnest
? SKIPFUNC
: SKIPFILE
;
8694 return argv
[1] ? number(argv
[1]) : exitstatus
;
8697 /* Forward declarations for builtintab[] */
8698 static int breakcmd(int, char **);
8699 static int dotcmd(int, char **);
8700 static int evalcmd(int, char **);
8701 static int exitcmd(int, char **);
8702 static int exportcmd(int, char **);
8703 #if ENABLE_ASH_GETOPTS
8704 static int getoptscmd(int, char **);
8706 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8707 static int helpcmd(int, char **);
8709 #if ENABLE_SH_MATH_SUPPORT
8710 static int letcmd(int, char **);
8712 static int readcmd(int, char **);
8713 static int setcmd(int, char **);
8714 static int shiftcmd(int, char **);
8715 static int timescmd(int, char **);
8716 static int trapcmd(int, char **);
8717 static int umaskcmd(int, char **);
8718 static int unsetcmd(int, char **);
8719 static int ulimitcmd(int, char **);
8721 #define BUILTIN_NOSPEC "0"
8722 #define BUILTIN_SPECIAL "1"
8723 #define BUILTIN_REGULAR "2"
8724 #define BUILTIN_SPEC_REG "3"
8725 #define BUILTIN_ASSIGN "4"
8726 #define BUILTIN_SPEC_ASSG "5"
8727 #define BUILTIN_REG_ASSG "6"
8728 #define BUILTIN_SPEC_REG_ASSG "7"
8730 /* We do not handle [[ expr ]] bashism bash-compatibly,
8731 * we make it a synonym of [ expr ].
8732 * Basically, word splitting and pathname expansion should NOT be performed
8734 * no word splitting: a="a b"; [[ $a = "a b" ]]; echo $? should print "0"
8735 * no pathname expansion: [[ /bin/m* = "/bin/m*" ]]; echo $? should print "0"
8736 * Additional operators:
8737 * || and && should work as -o and -a
8739 * Apart from the above, [[ expr ]] should work as [ expr ]
8742 #define echocmd echo_main
8743 #define printfcmd printf_main
8744 #define testcmd test_main
8746 /* Keep these in proper order since it is searched via bsearch() */
8747 static const struct builtincmd builtintab
[] = {
8748 { BUILTIN_SPEC_REG
".", dotcmd
},
8749 { BUILTIN_SPEC_REG
":", truecmd
},
8750 #if ENABLE_ASH_BUILTIN_TEST
8751 { BUILTIN_REGULAR
"[", testcmd
},
8752 #if ENABLE_ASH_BASH_COMPAT
8753 { BUILTIN_REGULAR
"[[", testcmd
},
8756 #if ENABLE_ASH_ALIAS
8757 { BUILTIN_REG_ASSG
"alias", aliascmd
},
8760 { BUILTIN_REGULAR
"bg", fg_bgcmd
},
8762 { BUILTIN_SPEC_REG
"break", breakcmd
},
8763 { BUILTIN_REGULAR
"cd", cdcmd
},
8764 { BUILTIN_NOSPEC
"chdir", cdcmd
},
8765 #if ENABLE_ASH_CMDCMD
8766 { BUILTIN_REGULAR
"command", commandcmd
},
8768 { BUILTIN_SPEC_REG
"continue", breakcmd
},
8769 #if ENABLE_ASH_BUILTIN_ECHO
8770 { BUILTIN_REGULAR
"echo", echocmd
},
8772 { BUILTIN_SPEC_REG
"eval", evalcmd
},
8773 { BUILTIN_SPEC_REG
"exec", execcmd
},
8774 { BUILTIN_SPEC_REG
"exit", exitcmd
},
8775 { BUILTIN_SPEC_REG_ASSG
"export", exportcmd
},
8776 { BUILTIN_REGULAR
"false", falsecmd
},
8778 { BUILTIN_REGULAR
"fg", fg_bgcmd
},
8780 #if ENABLE_ASH_GETOPTS
8781 { BUILTIN_REGULAR
"getopts", getoptscmd
},
8783 { BUILTIN_NOSPEC
"hash", hashcmd
},
8784 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
8785 { BUILTIN_NOSPEC
"help", helpcmd
},
8788 { BUILTIN_REGULAR
"jobs", jobscmd
},
8789 { BUILTIN_REGULAR
"kill", killcmd
},
8791 #if ENABLE_SH_MATH_SUPPORT
8792 { BUILTIN_NOSPEC
"let", letcmd
},
8794 { BUILTIN_ASSIGN
"local", localcmd
},
8795 #if ENABLE_ASH_BUILTIN_PRINTF
8796 { BUILTIN_REGULAR
"printf", printfcmd
},
8798 { BUILTIN_NOSPEC
"pwd", pwdcmd
},
8799 { BUILTIN_REGULAR
"read", readcmd
},
8800 { BUILTIN_SPEC_REG_ASSG
"readonly", exportcmd
},
8801 { BUILTIN_SPEC_REG
"return", returncmd
},
8802 { BUILTIN_SPEC_REG
"set", setcmd
},
8803 { BUILTIN_SPEC_REG
"shift", shiftcmd
},
8804 { BUILTIN_SPEC_REG
"source", dotcmd
},
8805 #if ENABLE_ASH_BUILTIN_TEST
8806 { BUILTIN_REGULAR
"test", testcmd
},
8808 { BUILTIN_SPEC_REG
"times", timescmd
},
8809 { BUILTIN_SPEC_REG
"trap", trapcmd
},
8810 { BUILTIN_REGULAR
"true", truecmd
},
8811 { BUILTIN_NOSPEC
"type", typecmd
},
8812 { BUILTIN_NOSPEC
"ulimit", ulimitcmd
},
8813 { BUILTIN_REGULAR
"umask", umaskcmd
},
8814 #if ENABLE_ASH_ALIAS
8815 { BUILTIN_REGULAR
"unalias", unaliascmd
},
8817 { BUILTIN_SPEC_REG
"unset", unsetcmd
},
8818 { BUILTIN_REGULAR
"wait", waitcmd
},
8821 /* Should match the above table! */
8822 #define COMMANDCMD (builtintab + \
8824 1 * ENABLE_ASH_BUILTIN_TEST + \
8825 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8826 1 * ENABLE_ASH_ALIAS + \
8827 1 * ENABLE_ASH_JOB_CONTROL + \
8829 #define EXECCMD (builtintab + \
8831 1 * ENABLE_ASH_BUILTIN_TEST + \
8832 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
8833 1 * ENABLE_ASH_ALIAS + \
8834 1 * ENABLE_ASH_JOB_CONTROL + \
8836 1 * ENABLE_ASH_CMDCMD + \
8838 ENABLE_ASH_BUILTIN_ECHO + \
8842 * Search the table of builtin commands.
8844 static struct builtincmd
*
8845 find_builtin(const char *name
)
8847 struct builtincmd
*bp
;
8850 name
, builtintab
, ARRAY_SIZE(builtintab
), sizeof(builtintab
[0]),
8857 * Execute a simple command.
8860 isassignment(const char *p
)
8862 const char *q
= endofname(p
);
8868 bltincmd(int argc UNUSED_PARAM
, char **argv UNUSED_PARAM
)
8870 /* Preserve exitstatus of a previous possible redirection
8871 * as POSIX mandates */
8872 return back_exitstatus
;
8875 evalcommand(union node
*cmd
, int flags
)
8877 static const struct builtincmd null_bltin
= {
8878 "\0\0", bltincmd
/* why three NULs? */
8880 struct stackmark smark
;
8882 struct arglist arglist
;
8883 struct arglist varlist
;
8886 const struct strlist
*sp
;
8887 struct cmdentry cmdentry
;
8894 struct builtincmd
*bcmd
;
8895 smallint cmd_is_exec
;
8896 smallint pseudovarflag
= 0;
8898 /* First expand the arguments. */
8899 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd
, flags
));
8900 setstackmark(&smark
);
8901 back_exitstatus
= 0;
8903 cmdentry
.cmdtype
= CMDBUILTIN
;
8904 cmdentry
.u
.cmd
= &null_bltin
;
8905 varlist
.lastp
= &varlist
.list
;
8906 *varlist
.lastp
= NULL
;
8907 arglist
.lastp
= &arglist
.list
;
8908 *arglist
.lastp
= NULL
;
8911 if (cmd
->ncmd
.args
) {
8912 bcmd
= find_builtin(cmd
->ncmd
.args
->narg
.text
);
8913 pseudovarflag
= bcmd
&& IS_BUILTIN_ASSIGN(bcmd
);
8916 for (argp
= cmd
->ncmd
.args
; argp
; argp
= argp
->narg
.next
) {
8917 struct strlist
**spp
;
8919 spp
= arglist
.lastp
;
8920 if (pseudovarflag
&& isassignment(argp
->narg
.text
))
8921 expandarg(argp
, &arglist
, EXP_VARTILDE
);
8923 expandarg(argp
, &arglist
, EXP_FULL
| EXP_TILDE
);
8925 for (sp
= *spp
; sp
; sp
= sp
->next
)
8929 argv
= nargv
= stalloc(sizeof(char *) * (argc
+ 1));
8930 for (sp
= arglist
.list
; sp
; sp
= sp
->next
) {
8931 TRACE(("evalcommand arg: %s\n", sp
->text
));
8932 *nargv
++ = sp
->text
;
8937 if (iflag
&& funcnest
== 0 && argc
> 0)
8938 lastarg
= nargv
[-1];
8941 expredir(cmd
->ncmd
.redirect
);
8942 status
= redirectsafe(cmd
->ncmd
.redirect
, REDIR_PUSH
| REDIR_SAVEFD2
);
8945 for (argp
= cmd
->ncmd
.assign
; argp
; argp
= argp
->narg
.next
) {
8946 struct strlist
**spp
;
8949 spp
= varlist
.lastp
;
8950 expandarg(argp
, &varlist
, EXP_VARTILDE
);
8953 * Modify the command lookup path, if a PATH= assignment
8957 if (varequal(p
, path
))
8961 /* Print the command if xflag is set. */
8964 const char *p
= " %s";
8967 fdprintf(preverrout_fd
, p
, expandstr(ps4val()));
8970 for (n
= 0; n
< 2; n
++) {
8972 fdprintf(preverrout_fd
, p
, sp
->text
);
8980 safe_write(preverrout_fd
, "\n", 1);
8986 /* Now locate the command. */
8988 const char *oldpath
;
8989 int cmd_flag
= DO_ERR
;
8994 find_command(argv
[0], &cmdentry
, cmd_flag
, path
);
8995 if (cmdentry
.cmdtype
== CMDUNKNOWN
) {
9001 /* implement bltin and command here */
9002 if (cmdentry
.cmdtype
!= CMDBUILTIN
)
9005 spclbltin
= IS_BUILTIN_SPECIAL(cmdentry
.u
.cmd
);
9006 if (cmdentry
.u
.cmd
== EXECCMD
)
9008 #if ENABLE_ASH_CMDCMD
9009 if (cmdentry
.u
.cmd
== COMMANDCMD
) {
9011 nargv
= parse_command_args(argv
, &path
);
9014 argc
-= nargv
- argv
;
9016 cmd_flag
|= DO_NOFUNC
;
9024 /* We have a redirection error. */
9026 raise_exception(EXERROR
);
9028 exitstatus
= status
;
9032 /* Execute the command. */
9033 switch (cmdentry
.cmdtype
) {
9036 #if ENABLE_FEATURE_SH_NOFORK
9037 /* Hmmm... shouldn't it happen somewhere in forkshell() instead?
9038 * Why "fork off a child process if necessary" doesn't apply to NOFORK? */
9040 /* find_command() encodes applet_no as (-2 - applet_no) */
9041 int applet_no
= (- cmdentry
.u
.index
- 2);
9042 if (applet_no
>= 0 && APPLET_IS_NOFORK(applet_no
)) {
9043 listsetvar(varlist
.list
, VEXPORT
|VSTACK
);
9044 /* run <applet>_main() */
9045 exitstatus
= run_nofork_applet(applet_no
, argv
);
9050 /* Fork off a child process if necessary. */
9051 if (!(flags
& EV_EXIT
) || trap
[0]) {
9053 jp
= makejob(/*cmd,*/ 1);
9054 if (forkshell(jp
, cmd
, FORK_FG
) != 0) {
9055 exitstatus
= waitforjob(jp
);
9057 TRACE(("forked child exited with %d\n", exitstatus
));
9062 listsetvar(varlist
.list
, VEXPORT
|VSTACK
);
9063 shellexec(argv
, path
, cmdentry
.u
.index
);
9067 cmdenviron
= varlist
.list
;
9069 struct strlist
*list
= cmdenviron
;
9071 if (spclbltin
> 0 || argc
== 0) {
9073 if (cmd_is_exec
&& argc
> 1)
9076 listsetvar(list
, i
);
9078 /* Tight loop with builtins only:
9079 * "while kill -0 $child; do true; done"
9080 * will never exit even if $child died, unless we do this
9081 * to reap the zombie and make kill detect that it's gone: */
9082 dowait(DOWAIT_NONBLOCK
, NULL
);
9084 if (evalbltin(cmdentry
.u
.cmd
, argc
, argv
)) {
9086 int i
= exception_type
;
9091 exit_status
= 128 + SIGINT
;
9093 exit_status
= 128 + pendingsig
;
9094 exitstatus
= exit_status
;
9095 if (i
== EXINT
|| spclbltin
> 0) {
9097 longjmp(exception_handler
->loc
, 1);
9104 listsetvar(varlist
.list
, 0);
9105 /* See above for the rationale */
9106 dowait(DOWAIT_NONBLOCK
, NULL
);
9107 if (evalfun(cmdentry
.u
.func
, argc
, argv
, flags
))
9113 popredir(/*drop:*/ cmd_is_exec
, /*restore:*/ cmd_is_exec
);
9115 /* dsl: I think this is intended to be used to support
9116 * '_' in 'vi' command mode during line editing...
9117 * However I implemented that within libedit itself.
9119 setvar("_", lastarg
, 0);
9121 popstackmark(&smark
);
9125 evalbltin(const struct builtincmd
*cmd
, int argc
, char **argv
)
9127 char *volatile savecmdname
;
9128 struct jmploc
*volatile savehandler
;
9129 struct jmploc jmploc
;
9132 savecmdname
= commandname
;
9133 i
= setjmp(jmploc
.loc
);
9136 savehandler
= exception_handler
;
9137 exception_handler
= &jmploc
;
9138 commandname
= argv
[0];
9140 optptr
= NULL
; /* initialize nextopt */
9141 exitstatus
= (*cmd
->builtin
)(argc
, argv
);
9142 flush_stdout_stderr();
9144 exitstatus
|= ferror(stdout
);
9146 commandname
= savecmdname
;
9148 exception_handler
= savehandler
;
9154 goodname(const char *p
)
9156 return !*endofname(p
);
9161 * Search for a command. This is called before we fork so that the
9162 * location of the command will be available in the parent as well as
9163 * the child. The check for "goodname" is an overly conservative
9164 * check that the name will not be subject to expansion.
9167 prehash(union node
*n
)
9169 struct cmdentry entry
;
9171 if (n
->type
== NCMD
&& n
->ncmd
.args
&& goodname(n
->ncmd
.args
->narg
.text
))
9172 find_command(n
->ncmd
.args
->narg
.text
, &entry
, 0, pathval());
9176 /* ============ Builtin commands
9178 * Builtin commands whose functions are closely tied to evaluation
9179 * are implemented here.
9183 * Handle break and continue commands. Break, continue, and return are
9184 * all handled by setting the evalskip flag. The evaluation routines
9185 * above all check this flag, and if it is set they start skipping
9186 * commands rather than executing them. The variable skipcount is
9187 * the number of loops to break/continue, or the number of function
9188 * levels to return. (The latter is always 1.) It should probably
9189 * be an error to break out of more loops than exist, but it isn't
9190 * in the standard shell so we don't make it one here.
9193 breakcmd(int argc UNUSED_PARAM
, char **argv
)
9195 int n
= argv
[1] ? number(argv
[1]) : 1;
9198 ash_msg_and_raise_error(illnum
, argv
[1]);
9202 evalskip
= (**argv
== 'c') ? SKIPCONT
: SKIPBREAK
;
9209 /* ============ input.c
9211 * This implements the input routines used by the parser.
9215 INPUT_PUSH_FILE
= 1,
9216 INPUT_NOFILE_OK
= 2,
9219 static smallint checkkwd
;
9220 /* values of checkkwd variable */
9221 #define CHKALIAS 0x1
9226 * Push a string back onto the input at this current parsefile level.
9227 * We handle aliases this way.
9229 #if !ENABLE_ASH_ALIAS
9230 #define pushstring(s, ap) pushstring(s)
9233 pushstring(char *s
, struct alias
*ap
)
9240 if (g_parsefile
->strpush
) {
9241 sp
= ckzalloc(sizeof(*sp
));
9242 sp
->prev
= g_parsefile
->strpush
;
9244 sp
= &(g_parsefile
->basestrpush
);
9246 g_parsefile
->strpush
= sp
;
9247 sp
->prev_string
= g_parsefile
->next_to_pgetc
;
9248 sp
->prev_left_in_line
= g_parsefile
->left_in_line
;
9249 #if ENABLE_ASH_ALIAS
9252 ap
->flag
|= ALIASINUSE
;
9256 g_parsefile
->next_to_pgetc
= s
;
9257 g_parsefile
->left_in_line
= len
;
9264 struct strpush
*sp
= g_parsefile
->strpush
;
9267 #if ENABLE_ASH_ALIAS
9269 if (g_parsefile
->next_to_pgetc
[-1] == ' '
9270 || g_parsefile
->next_to_pgetc
[-1] == '\t'
9272 checkkwd
|= CHKALIAS
;
9274 if (sp
->string
!= sp
->ap
->val
) {
9277 sp
->ap
->flag
&= ~ALIASINUSE
;
9278 if (sp
->ap
->flag
& ALIASDEAD
) {
9279 unalias(sp
->ap
->name
);
9283 g_parsefile
->next_to_pgetc
= sp
->prev_string
;
9284 g_parsefile
->left_in_line
= sp
->prev_left_in_line
;
9285 g_parsefile
->strpush
= sp
->prev
;
9286 if (sp
!= &(g_parsefile
->basestrpush
))
9291 //FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9292 //it peeks whether it is &>, and then pushes back both chars.
9293 //This function needs to save last *next_to_pgetc to buf[0]
9294 //to make two pungetc() reliable. Currently,
9295 // pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
9300 char *buf
= g_parsefile
->buf
;
9302 g_parsefile
->next_to_pgetc
= buf
;
9303 #if ENABLE_FEATURE_EDITING
9305 if (!iflag
|| g_parsefile
->fd
!= STDIN_FILENO
)
9306 nr
= nonblock_safe_read(g_parsefile
->fd
, buf
, BUFSIZ
- 1);
9308 #if ENABLE_FEATURE_TAB_COMPLETION
9309 line_input_state
->path_lookup
= pathval();
9311 nr
= read_line_input(cmdedit_prompt
, buf
, BUFSIZ
, line_input_state
);
9313 /* Ctrl+C pressed */
9322 if (nr
< 0 && errno
== 0) {
9323 /* Ctrl+D pressed */
9328 nr
= nonblock_safe_read(g_parsefile
->fd
, buf
, BUFSIZ
- 1);
9332 /* nonblock_safe_read() handles this problem */
9334 if (parsefile
->fd
== 0 && errno
== EWOULDBLOCK
) {
9335 int flags
= fcntl(0, F_GETFL
);
9336 if (flags
>= 0 && (flags
& O_NONBLOCK
)) {
9337 flags
&= ~O_NONBLOCK
;
9338 if (fcntl(0, F_SETFL
, flags
) >= 0) {
9339 out2str("sh: turning off NDELAY mode\n");
9350 * Refill the input buffer and return the next input character:
9352 * 1) If a string was pushed back on the input, pop it;
9353 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9354 * or we are reading from a string so we can't refill the buffer,
9356 * 3) If the is more stuff in this buffer, use it else call read to fill it.
9357 * 4) Process input up to the next newline, deleting nul characters.
9359 //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9360 #define pgetc_debug(...) ((void)0)
9362 * NB: due to SIT(c) internals (syntax_index_table[] vector),
9363 * pgetc() and related functions must return chars SIGN-EXTENDED into ints,
9364 * not zero-extended. Seems fragile to me. Affects only !USE_SIT_FUNCTION case,
9365 * so we can fix it by ditching !USE_SIT_FUNCTION if Unicode requires that.
9373 while (g_parsefile
->strpush
) {
9374 #if ENABLE_ASH_ALIAS
9375 if (g_parsefile
->left_in_line
== -1
9376 && g_parsefile
->strpush
->ap
9377 && g_parsefile
->next_to_pgetc
[-1] != ' '
9378 && g_parsefile
->next_to_pgetc
[-1] != '\t'
9380 pgetc_debug("preadbuffer PEOA");
9385 /* try "pgetc" now: */
9386 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9387 g_parsefile
->left_in_line
,
9388 g_parsefile
->next_to_pgetc
,
9389 g_parsefile
->next_to_pgetc
);
9390 if (--g_parsefile
->left_in_line
>= 0)
9391 return (unsigned char)(*g_parsefile
->next_to_pgetc
++);
9393 /* on both branches above g_parsefile->left_in_line < 0.
9394 * "pgetc" needs refilling.
9397 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
9398 * pungetc() may increment it a few times.
9399 * Assuming it won't increment it to less than -90.
9401 if (g_parsefile
->left_in_line
< -90 || g_parsefile
->buf
== NULL
) {
9402 pgetc_debug("preadbuffer PEOF1");
9403 /* even in failure keep left_in_line and next_to_pgetc
9404 * in lock step, for correct multi-layer pungetc.
9405 * left_in_line was decremented before preadbuffer(),
9406 * must inc next_to_pgetc: */
9407 g_parsefile
->next_to_pgetc
++;
9411 more
= g_parsefile
->left_in_buffer
;
9413 flush_stdout_stderr();
9417 /* don't try reading again */
9418 g_parsefile
->left_in_line
= -99;
9419 pgetc_debug("preadbuffer PEOF2");
9420 g_parsefile
->next_to_pgetc
++;
9425 /* Find out where's the end of line.
9426 * Set g_parsefile->left_in_line
9427 * and g_parsefile->left_in_buffer acordingly.
9428 * NUL chars are deleted.
9430 q
= g_parsefile
->next_to_pgetc
;
9438 memmove(q
, q
+ 1, more
);
9442 g_parsefile
->left_in_line
= q
- g_parsefile
->next_to_pgetc
- 1;
9448 g_parsefile
->left_in_line
= q
- g_parsefile
->next_to_pgetc
- 1;
9449 if (g_parsefile
->left_in_line
< 0)
9454 g_parsefile
->left_in_buffer
= more
;
9459 out2str(g_parsefile
->next_to_pgetc
);
9463 pgetc_debug("preadbuffer at %d:%p'%s'",
9464 g_parsefile
->left_in_line
,
9465 g_parsefile
->next_to_pgetc
,
9466 g_parsefile
->next_to_pgetc
);
9467 return signed_char2int(*g_parsefile
->next_to_pgetc
++);
9470 #define pgetc_as_macro() \
9471 (--g_parsefile->left_in_line >= 0 \
9472 ? signed_char2int(*g_parsefile->next_to_pgetc++) \
9479 pgetc_debug("pgetc_fast at %d:%p'%s'",
9480 g_parsefile
->left_in_line
,
9481 g_parsefile
->next_to_pgetc
,
9482 g_parsefile
->next_to_pgetc
);
9483 return pgetc_as_macro();
9486 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
9487 #define pgetc_fast() pgetc()
9489 #define pgetc_fast() pgetc_as_macro()
9493 * Same as pgetc(), but ignores PEOA.
9495 #if ENABLE_ASH_ALIAS
9501 pgetc_debug("pgetc_fast at %d:%p'%s'",
9502 g_parsefile
->left_in_line
,
9503 g_parsefile
->next_to_pgetc
,
9504 g_parsefile
->next_to_pgetc
);
9506 } while (c
== PEOA
);
9510 #define pgetc2() pgetc()
9514 * Read a line from the script.
9517 pfgets(char *line
, int len
)
9523 while (--nleft
> 0) {
9539 * Undo the last call to pgetc. Only one character may be pushed back.
9540 * PEOF may be pushed back.
9545 g_parsefile
->left_in_line
++;
9546 g_parsefile
->next_to_pgetc
--;
9547 pgetc_debug("pushed back to %d:%p'%s'",
9548 g_parsefile
->left_in_line
,
9549 g_parsefile
->next_to_pgetc
,
9550 g_parsefile
->next_to_pgetc
);
9554 * To handle the "." command, a stack of input files is used. Pushfile
9555 * adds a new entry to the stack and popfile restores the previous level.
9560 struct parsefile
*pf
;
9562 pf
= ckzalloc(sizeof(*pf
));
9563 pf
->prev
= g_parsefile
;
9565 /*pf->strpush = NULL; - ckzalloc did it */
9566 /*pf->basestrpush.prev = NULL;*/
9573 struct parsefile
*pf
= g_parsefile
;
9581 g_parsefile
= pf
->prev
;
9587 * Return to top level.
9592 while (g_parsefile
!= &basepf
)
9597 * Close the file(s) that the shell is reading commands from. Called
9598 * after a fork is done.
9604 if (g_parsefile
->fd
> 0) {
9605 close(g_parsefile
->fd
);
9606 g_parsefile
->fd
= 0;
9611 * Like setinputfile, but takes an open file descriptor. Call this with
9615 setinputfd(int fd
, int push
)
9617 close_on_exec_on(fd
);
9620 g_parsefile
->buf
= NULL
;
9622 g_parsefile
->fd
= fd
;
9623 if (g_parsefile
->buf
== NULL
)
9624 g_parsefile
->buf
= ckmalloc(IBUFSIZ
);
9625 g_parsefile
->left_in_buffer
= 0;
9626 g_parsefile
->left_in_line
= 0;
9627 g_parsefile
->linno
= 1;
9631 * Set the input to take input from a file. If push is set, push the
9632 * old input onto the stack first.
9635 setinputfile(const char *fname
, int flags
)
9641 fd
= open(fname
, O_RDONLY
);
9643 if (flags
& INPUT_NOFILE_OK
)
9645 ash_msg_and_raise_error("can't open '%s'", fname
);
9648 fd2
= copyfd(fd
, 10);
9651 ash_msg_and_raise_error("out of file descriptors");
9654 setinputfd(fd
, flags
& INPUT_PUSH_FILE
);
9661 * Like setinputfile, but takes input from a string.
9664 setinputstring(char *string
)
9668 g_parsefile
->next_to_pgetc
= string
;
9669 g_parsefile
->left_in_line
= strlen(string
);
9670 g_parsefile
->buf
= NULL
;
9671 g_parsefile
->linno
= 1;
9676 /* ============ mail.c
9678 * Routines to check for mail.
9683 #define MAXMBOXES 10
9685 /* times of mailboxes */
9686 static time_t mailtime
[MAXMBOXES
];
9687 /* Set if MAIL or MAILPATH is changed. */
9688 static smallint mail_var_path_changed
;
9691 * Print appropriate message(s) if mail has arrived.
9692 * If mail_var_path_changed is set,
9693 * then the value of MAIL has mail_var_path_changed,
9694 * so we just update the values.
9703 struct stackmark smark
;
9706 setstackmark(&smark
);
9707 mpath
= mpathset() ? mpathval() : mailval();
9708 for (mtp
= mailtime
; mtp
< mailtime
+ MAXMBOXES
; mtp
++) {
9709 p
= padvance(&mpath
, nullstr
);
9714 for (q
= p
; *q
; q
++)
9720 q
[-1] = '\0'; /* delete trailing '/' */
9721 if (stat(p
, &statb
) < 0) {
9725 if (!mail_var_path_changed
&& statb
.st_mtime
!= *mtp
) {
9728 pathopt
? pathopt
: "you have mail"
9731 *mtp
= statb
.st_mtime
;
9733 mail_var_path_changed
= 0;
9734 popstackmark(&smark
);
9738 changemail(const char *val UNUSED_PARAM
)
9740 mail_var_path_changed
= 1;
9743 #endif /* ASH_MAIL */
9746 /* ============ ??? */
9749 * Set the shell parameters.
9752 setparam(char **argv
)
9758 for (nparam
= 0; argv
[nparam
]; nparam
++)
9760 ap
= newparam
= ckmalloc((nparam
+ 1) * sizeof(*ap
));
9762 *ap
++ = ckstrdup(*argv
++);
9765 freeparam(&shellparam
);
9766 shellparam
.malloced
= 1;
9767 shellparam
.nparam
= nparam
;
9768 shellparam
.p
= newparam
;
9769 #if ENABLE_ASH_GETOPTS
9770 shellparam
.optind
= 1;
9771 shellparam
.optoff
= -1;
9776 * Process shell options. The global variable argptr contains a pointer
9777 * to the argument list; we advance it past the options.
9779 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
9780 * For a non-interactive shell, an error condition encountered
9781 * by a special built-in ... shall cause the shell to write a diagnostic message
9782 * to standard error and exit as shown in the following table:
9783 * Error Special Built-In
9785 * Utility syntax error (option or operand error) Shall exit
9787 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
9788 * we see that bash does not do that (set "finishes" with error code 1 instead,
9789 * and shell continues), and people rely on this behavior!
9791 * set -o barfoo 2>/dev/null
9794 * Oh well. Let's mimic that.
9797 plus_minus_o(char *name
, int val
)
9802 for (i
= 0; i
< NOPTS
; i
++) {
9803 if (strcmp(name
, optnames(i
)) == 0) {
9808 ash_msg("illegal option %co %s", val
? '-' : '+', name
);
9811 for (i
= 0; i
< NOPTS
; i
++) {
9813 out1fmt("%-16s%s\n", optnames(i
), optlist
[i
] ? "on" : "off");
9815 out1fmt("set %co %s\n", optlist
[i
] ? '-' : '+', optnames(i
));
9821 setoption(int flag
, int val
)
9825 for (i
= 0; i
< NOPTS
; i
++) {
9826 if (optletters(i
) == flag
) {
9831 ash_msg_and_raise_error("illegal option %c%c", val
? '-' : '+', flag
);
9835 options(int cmdline
)
9843 while ((p
= *argptr
) != NULL
) {
9845 if (c
!= '-' && c
!= '+')
9848 val
= 0; /* val = 0 if c == '+' */
9851 if (p
[0] == '\0' || LONE_DASH(p
)) {
9853 /* "-" means turn off -x and -v */
9856 /* "--" means reset params */
9857 else if (*argptr
== NULL
)
9860 break; /* "-" or "--" terminates options */
9863 /* first char was + or - */
9864 while ((c
= *p
++) != '\0') {
9865 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
9866 if (c
== 'c' && cmdline
) {
9867 minusc
= p
; /* command is after shell args */
9868 } else if (c
== 'o') {
9869 if (plus_minus_o(*argptr
, val
)) {
9870 /* it already printed err message */
9871 return 1; /* error */
9875 } else if (cmdline
&& (c
== 'l')) { /* -l or +l == --login */
9877 /* bash does not accept +-login, we also won't */
9878 } else if (cmdline
&& val
&& (c
== '-')) { /* long options */
9879 if (strcmp(p
, "login") == 0)
9891 * The shift builtin command.
9894 shiftcmd(int argc UNUSED_PARAM
, char **argv
)
9901 n
= number(argv
[1]);
9902 if (n
> shellparam
.nparam
)
9903 n
= 0; /* bash compat, was = shellparam.nparam; */
9905 shellparam
.nparam
-= n
;
9906 for (ap1
= shellparam
.p
; --n
>= 0; ap1
++) {
9907 if (shellparam
.malloced
)
9911 while ((*ap2
++ = *ap1
++) != NULL
)
9913 #if ENABLE_ASH_GETOPTS
9914 shellparam
.optind
= 1;
9915 shellparam
.optoff
= -1;
9922 * POSIX requires that 'set' (but not export or readonly) output the
9923 * variables in lexicographic order - by the locale's collating order (sigh).
9924 * Maybe we could keep them in an ordered balanced binary tree
9925 * instead of hashed lists.
9926 * For now just roll 'em through qsort for printing...
9929 showvars(const char *sep_prefix
, int on
, int off
)
9934 ep
= listvars(on
, off
, &epend
);
9935 qsort(ep
, epend
- ep
, sizeof(char *), vpcmp
);
9937 sep
= *sep_prefix
? " " : sep_prefix
;
9939 for (; ep
< epend
; ep
++) {
9943 p
= strchrnul(*ep
, '=');
9946 q
= single_quote(++p
);
9947 out1fmt("%s%s%.*s%s\n", sep_prefix
, sep
, (int)(p
- *ep
), *ep
, q
);
9953 * The set command builtin.
9956 setcmd(int argc UNUSED_PARAM
, char **argv UNUSED_PARAM
)
9961 return showvars(nullstr
, 0, VUNSET
);
9964 if (!options(0)) { /* if no parse error... */
9967 if (*argptr
!= NULL
) {
9975 #if ENABLE_ASH_RANDOM_SUPPORT
9977 change_random(const char *value
)
9979 /* Galois LFSR parameter */
9980 /* Taps at 32 31 29 1: */
9981 enum { MASK
= 0x8000000b };
9982 /* Another example - taps at 32 31 30 10: */
9983 /* MASK = 0x00400007 */
9985 if (value
== NULL
) {
9986 /* "get", generate */
9989 /* LCG has period of 2^32 and alternating lowest bit */
9990 random_LCG
= 1664525 * random_LCG
+ 1013904223;
9991 /* Galois LFSR has period of 2^32-1 = 3 * 5 * 17 * 257 * 65537 */
9992 t
= (random_galois_LFSR
<< 1);
9993 if (random_galois_LFSR
< 0) /* if we just shifted 1 out of msb... */
9995 random_galois_LFSR
= t
;
9996 /* Both are weak, combining them gives better randomness
9997 * and ~2^64 period. & 0x7fff is probably bash compat
9998 * for $RANDOM range. Combining with subtraction is
9999 * just for fun. + and ^ would work equally well. */
10000 t
= (t
- random_LCG
) & 0x7fff;
10001 /* set without recursion */
10002 setvar(vrandom
.text
, utoa(t
), VNOFUNC
);
10003 vrandom
.flags
&= ~VNOFUNC
;
10006 random_galois_LFSR
= random_LCG
= strtoul(value
, (char **)NULL
, 10);
10011 #if ENABLE_ASH_GETOPTS
10013 getopts(char *optstr
, char *optvar
, char **optfirst
, int *param_optind
, int *optoff
)
10022 if (*param_optind
< 1)
10024 optnext
= optfirst
+ *param_optind
- 1;
10026 if (*param_optind
<= 1 || *optoff
< 0 || (int)strlen(optnext
[-1]) < *optoff
)
10029 p
= optnext
[-1] + *optoff
;
10030 if (p
== NULL
|| *p
== '\0') {
10031 /* Current word is done, advance */
10033 if (p
== NULL
|| *p
!= '-' || *++p
== '\0') {
10040 if (LONE_DASH(p
)) /* check for "--" */
10045 for (q
= optstr
; *q
!= c
;) {
10047 if (optstr
[0] == ':') {
10050 err
|= setvarsafe("OPTARG", s
, 0);
10052 fprintf(stderr
, "Illegal option -%c\n", c
);
10053 unsetvar("OPTARG");
10063 if (*p
== '\0' && (p
= *optnext
) == NULL
) {
10064 if (optstr
[0] == ':') {
10067 err
|= setvarsafe("OPTARG", s
, 0);
10070 fprintf(stderr
, "No arg for -%c option\n", c
);
10071 unsetvar("OPTARG");
10079 err
|= setvarsafe("OPTARG", p
, 0);
10082 err
|= setvarsafe("OPTARG", nullstr
, 0);
10084 *optoff
= p
? p
- *(optnext
- 1) : -1;
10085 *param_optind
= optnext
- optfirst
+ 1;
10086 fmtstr(s
, sizeof(s
), "%d", *param_optind
);
10087 err
|= setvarsafe("OPTIND", s
, VNOFUNC
);
10090 err
|= setvarsafe(optvar
, s
, 0);
10094 flush_stdout_stderr();
10095 raise_exception(EXERROR
);
10101 * The getopts builtin. Shellparam.optnext points to the next argument
10102 * to be processed. Shellparam.optptr points to the next character to
10103 * be processed in the current argument. If shellparam.optnext is NULL,
10104 * then it's the first time getopts has been called.
10107 getoptscmd(int argc
, char **argv
)
10112 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
10114 optbase
= shellparam
.p
;
10115 if (shellparam
.optind
> shellparam
.nparam
+ 1) {
10116 shellparam
.optind
= 1;
10117 shellparam
.optoff
= -1;
10120 optbase
= &argv
[3];
10121 if (shellparam
.optind
> argc
- 2) {
10122 shellparam
.optind
= 1;
10123 shellparam
.optoff
= -1;
10127 return getopts(argv
[1], argv
[2], optbase
, &shellparam
.optind
,
10128 &shellparam
.optoff
);
10130 #endif /* ASH_GETOPTS */
10133 /* ============ Shell parser */
10136 struct heredoc
*next
; /* next here document in list */
10137 union node
*here
; /* redirection node */
10138 char *eofmark
; /* string indicating end of input */
10139 smallint striptabs
; /* if set, strip leading tabs */
10142 static smallint tokpushback
; /* last token pushed back */
10143 static smallint parsebackquote
; /* nonzero if we are inside backquotes */
10144 static smallint quoteflag
; /* set if (part of) last token was quoted */
10145 static token_id_t lasttoken
; /* last token read (integer id Txxx) */
10146 static struct heredoc
*heredoclist
; /* list of here documents to read */
10147 static char *wordtext
; /* text of last word returned by readtoken */
10148 static struct nodelist
*backquotelist
;
10149 static union node
*redirnode
;
10150 static struct heredoc
*heredoc
;
10152 * NEOF is returned by parsecmd when it encounters an end of file. It
10153 * must be distinct from NULL, so we use the address of a variable that
10154 * happens to be handy.
10156 #define NEOF ((union node *)&tokpushback)
10159 * Called when an unexpected token is read during the parse. The argument
10160 * is the token that is expected, or -1 if more than one type of token can
10161 * occur at this point.
10163 static void raise_error_unexpected_syntax(int) NORETURN
;
10165 raise_error_unexpected_syntax(int token
)
10170 l
= sprintf(msg
, "unexpected %s", tokname(lasttoken
));
10172 sprintf(msg
+ l
, " (expecting %s)", tokname(token
));
10173 raise_error_syntax(msg
);
10177 #define EOFMARKLEN 79
10179 /* parsing is heavily cross-recursive, need these forward decls */
10180 static union node
*andor(void);
10181 static union node
*pipeline(void);
10182 static union node
*parse_command(void);
10183 static void parseheredoc(void);
10184 static char peektoken(void);
10185 static int readtoken(void);
10187 static union node
*
10190 union node
*n1
, *n2
, *n3
;
10193 checkkwd
= CHKNL
| CHKKWD
| CHKALIAS
;
10194 if (nlflag
== 2 && peektoken())
10200 if (tok
== TBACKGND
) {
10201 if (n2
->type
== NPIPE
) {
10202 n2
->npipe
.pipe_backgnd
= 1;
10204 if (n2
->type
!= NREDIR
) {
10205 n3
= stzalloc(sizeof(struct nredir
));
10207 /*n3->nredir.redirect = NULL; - stzalloc did it */
10210 n2
->type
= NBACKGND
;
10216 n3
= stzalloc(sizeof(struct nbinary
));
10218 n3
->nbinary
.ch1
= n1
;
10219 n3
->nbinary
.ch2
= n2
;
10235 checkkwd
= CHKNL
| CHKKWD
| CHKALIAS
;
10243 pungetc(); /* push back EOF on input */
10247 raise_error_unexpected_syntax(-1);
10254 static union node
*
10257 union node
*n1
, *n2
, *n3
;
10265 } else if (t
== TOR
) {
10271 checkkwd
= CHKNL
| CHKKWD
| CHKALIAS
;
10273 n3
= stzalloc(sizeof(struct nbinary
));
10275 n3
->nbinary
.ch1
= n1
;
10276 n3
->nbinary
.ch2
= n2
;
10281 static union node
*
10284 union node
*n1
, *n2
, *pipenode
;
10285 struct nodelist
*lp
, *prev
;
10289 TRACE(("pipeline: entered\n"));
10290 if (readtoken() == TNOT
) {
10292 checkkwd
= CHKKWD
| CHKALIAS
;
10295 n1
= parse_command();
10296 if (readtoken() == TPIPE
) {
10297 pipenode
= stzalloc(sizeof(struct npipe
));
10298 pipenode
->type
= NPIPE
;
10299 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
10300 lp
= stzalloc(sizeof(struct nodelist
));
10301 pipenode
->npipe
.cmdlist
= lp
;
10305 lp
= stzalloc(sizeof(struct nodelist
));
10306 checkkwd
= CHKNL
| CHKKWD
| CHKALIAS
;
10307 lp
->n
= parse_command();
10309 } while (readtoken() == TPIPE
);
10315 n2
= stzalloc(sizeof(struct nnot
));
10323 static union node
*
10328 n
= stzalloc(sizeof(struct narg
));
10330 /*n->narg.next = NULL; - stzalloc did it */
10331 n
->narg
.text
= wordtext
;
10332 n
->narg
.backquote
= backquotelist
;
10337 fixredir(union node
*n
, const char *text
, int err
)
10341 TRACE(("Fix redir %s %d\n", text
, err
));
10343 n
->ndup
.vname
= NULL
;
10345 fd
= bb_strtou(text
, NULL
, 10);
10346 if (!errno
&& fd
>= 0)
10347 n
->ndup
.dupfd
= fd
;
10348 else if (LONE_DASH(text
))
10349 n
->ndup
.dupfd
= -1;
10352 raise_error_syntax("bad fd number");
10353 n
->ndup
.vname
= makename();
10358 * Returns true if the text contains nothing to expand (no dollar signs
10362 noexpand(const char *text
)
10368 while ((c
= *p
++) != '\0') {
10369 if (c
== CTLQUOTEMARK
)
10373 else if (SIT((signed char)c
, BASESYNTAX
) == CCTL
)
10382 union node
*n
= redirnode
;
10384 if (readtoken() != TWORD
)
10385 raise_error_unexpected_syntax(-1);
10386 if (n
->type
== NHERE
) {
10387 struct heredoc
*here
= heredoc
;
10391 if (quoteflag
== 0)
10393 TRACE(("Here document %d\n", n
->type
));
10394 if (!noexpand(wordtext
) || (i
= strlen(wordtext
)) == 0 || i
> EOFMARKLEN
)
10395 raise_error_syntax("illegal eof marker for << redirection");
10396 rmescapes(wordtext
);
10397 here
->eofmark
= wordtext
;
10399 if (heredoclist
== NULL
)
10400 heredoclist
= here
;
10402 for (p
= heredoclist
; p
->next
; p
= p
->next
)
10406 } else if (n
->type
== NTOFD
|| n
->type
== NFROMFD
) {
10407 fixredir(n
, wordtext
, 0);
10409 n
->nfile
.fname
= makename();
10413 static union node
*
10416 union node
*args
, **app
;
10417 union node
*n
= NULL
;
10418 union node
*vars
, **vpp
;
10419 union node
**rpp
, *redir
;
10421 #if ENABLE_ASH_BASH_COMPAT
10422 smallint double_brackets_flag
= 0;
10432 savecheckkwd
= CHKALIAS
;
10435 checkkwd
= savecheckkwd
;
10438 #if ENABLE_ASH_BASH_COMPAT
10439 case TAND
: /* "&&" */
10440 case TOR
: /* "||" */
10441 if (!double_brackets_flag
) {
10445 wordtext
= (char *) (t
== TAND
? "-a" : "-o");
10448 n
= stzalloc(sizeof(struct narg
));
10450 /*n->narg.next = NULL; - stzalloc did it */
10451 n
->narg
.text
= wordtext
;
10452 #if ENABLE_ASH_BASH_COMPAT
10453 if (strcmp("[[", wordtext
) == 0)
10454 double_brackets_flag
= 1;
10455 else if (strcmp("]]", wordtext
) == 0)
10456 double_brackets_flag
= 0;
10458 n
->narg
.backquote
= backquotelist
;
10459 if (savecheckkwd
&& isassignment(wordtext
)) {
10461 vpp
= &n
->narg
.next
;
10464 app
= &n
->narg
.next
;
10469 *rpp
= n
= redirnode
;
10470 rpp
= &n
->nfile
.next
;
10471 parsefname(); /* read name of redirection file */
10474 if (args
&& app
== &args
->narg
.next
10477 struct builtincmd
*bcmd
;
10480 /* We have a function */
10481 if (readtoken() != TRP
)
10482 raise_error_unexpected_syntax(TRP
);
10483 name
= n
->narg
.text
;
10484 if (!goodname(name
)
10485 || ((bcmd
= find_builtin(name
)) && IS_BUILTIN_SPECIAL(bcmd
))
10487 raise_error_syntax("bad function name");
10490 checkkwd
= CHKNL
| CHKKWD
| CHKALIAS
;
10491 n
->narg
.next
= parse_command();
10504 n
= stzalloc(sizeof(struct ncmd
));
10506 n
->ncmd
.args
= args
;
10507 n
->ncmd
.assign
= vars
;
10508 n
->ncmd
.redirect
= redir
;
10512 static union node
*
10513 parse_command(void)
10515 union node
*n1
, *n2
;
10516 union node
*ap
, **app
;
10517 union node
*cp
, **cpp
;
10518 union node
*redir
, **rpp
;
10525 switch (readtoken()) {
10527 raise_error_unexpected_syntax(-1);
10530 n1
= stzalloc(sizeof(struct nif
));
10532 n1
->nif
.test
= list(0);
10533 if (readtoken() != TTHEN
)
10534 raise_error_unexpected_syntax(TTHEN
);
10535 n1
->nif
.ifpart
= list(0);
10537 while (readtoken() == TELIF
) {
10538 n2
->nif
.elsepart
= stzalloc(sizeof(struct nif
));
10539 n2
= n2
->nif
.elsepart
;
10541 n2
->nif
.test
= list(0);
10542 if (readtoken() != TTHEN
)
10543 raise_error_unexpected_syntax(TTHEN
);
10544 n2
->nif
.ifpart
= list(0);
10546 if (lasttoken
== TELSE
)
10547 n2
->nif
.elsepart
= list(0);
10549 n2
->nif
.elsepart
= NULL
;
10557 n1
= stzalloc(sizeof(struct nbinary
));
10558 n1
->type
= (lasttoken
== TWHILE
) ? NWHILE
: NUNTIL
;
10559 n1
->nbinary
.ch1
= list(0);
10562 TRACE(("expecting DO got %s %s\n", tokname(got
),
10563 got
== TWORD
? wordtext
: ""));
10564 raise_error_unexpected_syntax(TDO
);
10566 n1
->nbinary
.ch2
= list(0);
10571 if (readtoken() != TWORD
|| quoteflag
|| !goodname(wordtext
))
10572 raise_error_syntax("bad for loop variable");
10573 n1
= stzalloc(sizeof(struct nfor
));
10575 n1
->nfor
.var
= wordtext
;
10576 checkkwd
= CHKKWD
| CHKALIAS
;
10577 if (readtoken() == TIN
) {
10579 while (readtoken() == TWORD
) {
10580 n2
= stzalloc(sizeof(struct narg
));
10582 /*n2->narg.next = NULL; - stzalloc did it */
10583 n2
->narg
.text
= wordtext
;
10584 n2
->narg
.backquote
= backquotelist
;
10586 app
= &n2
->narg
.next
;
10589 n1
->nfor
.args
= ap
;
10590 if (lasttoken
!= TNL
&& lasttoken
!= TSEMI
)
10591 raise_error_unexpected_syntax(-1);
10593 n2
= stzalloc(sizeof(struct narg
));
10595 /*n2->narg.next = NULL; - stzalloc did it */
10596 n2
->narg
.text
= (char *)dolatstr
;
10597 /*n2->narg.backquote = NULL;*/
10598 n1
->nfor
.args
= n2
;
10600 * Newline or semicolon here is optional (but note
10601 * that the original Bourne shell only allowed NL).
10603 if (lasttoken
!= TNL
&& lasttoken
!= TSEMI
)
10606 checkkwd
= CHKNL
| CHKKWD
| CHKALIAS
;
10607 if (readtoken() != TDO
)
10608 raise_error_unexpected_syntax(TDO
);
10609 n1
->nfor
.body
= list(0);
10613 n1
= stzalloc(sizeof(struct ncase
));
10615 if (readtoken() != TWORD
)
10616 raise_error_unexpected_syntax(TWORD
);
10617 n1
->ncase
.expr
= n2
= stzalloc(sizeof(struct narg
));
10619 /*n2->narg.next = NULL; - stzalloc did it */
10620 n2
->narg
.text
= wordtext
;
10621 n2
->narg
.backquote
= backquotelist
;
10623 checkkwd
= CHKKWD
| CHKALIAS
;
10624 } while (readtoken() == TNL
);
10625 if (lasttoken
!= TIN
)
10626 raise_error_unexpected_syntax(TIN
);
10627 cpp
= &n1
->ncase
.cases
;
10629 checkkwd
= CHKNL
| CHKKWD
;
10631 while (t
!= TESAC
) {
10632 if (lasttoken
== TLP
)
10634 *cpp
= cp
= stzalloc(sizeof(struct nclist
));
10636 app
= &cp
->nclist
.pattern
;
10638 *app
= ap
= stzalloc(sizeof(struct narg
));
10640 /*ap->narg.next = NULL; - stzalloc did it */
10641 ap
->narg
.text
= wordtext
;
10642 ap
->narg
.backquote
= backquotelist
;
10643 if (readtoken() != TPIPE
)
10645 app
= &ap
->narg
.next
;
10648 //ap->narg.next = NULL;
10649 if (lasttoken
!= TRP
)
10650 raise_error_unexpected_syntax(TRP
);
10651 cp
->nclist
.body
= list(2);
10653 cpp
= &cp
->nclist
.next
;
10655 checkkwd
= CHKNL
| CHKKWD
;
10659 raise_error_unexpected_syntax(TENDCASE
);
10666 n1
= stzalloc(sizeof(struct nredir
));
10667 n1
->type
= NSUBSHELL
;
10668 n1
->nredir
.n
= list(0);
10669 /*n1->nredir.redirect = NULL; - stzalloc did it */
10679 return simplecmd();
10682 if (readtoken() != t
)
10683 raise_error_unexpected_syntax(t
);
10686 /* Now check for redirection which may follow command */
10687 checkkwd
= CHKKWD
| CHKALIAS
;
10689 while (readtoken() == TREDIR
) {
10690 *rpp
= n2
= redirnode
;
10691 rpp
= &n2
->nfile
.next
;
10697 if (n1
->type
!= NSUBSHELL
) {
10698 n2
= stzalloc(sizeof(struct nredir
));
10703 n1
->nredir
.redirect
= redir
;
10708 #if ENABLE_ASH_BASH_COMPAT
10709 static int decode_dollar_squote(void)
10711 static const char C_escapes
[] ALIGN1
= "nrbtfav""x\\01234567";
10717 p
= strchr(C_escapes
, c
);
10722 if ((unsigned char)(c
- '0') <= 7) { /* \ooo */
10726 } while ((unsigned char)(c
- '0') <= 7 && --cnt
);
10728 } else if (c
== 'x') { /* \xHH */
10732 } while (isxdigit(c
) && --cnt
);
10734 if (cnt
== 3) { /* \x but next char is "bad" */
10738 } else { /* simple seq like \\ or \t */
10743 c
= bb_process_escape_sequence((void*)&p
);
10744 } else { /* unrecognized "\z": print both chars unless ' or " */
10745 if (c
!= '\'' && c
!= '"') {
10747 c
|= 0x100; /* "please encode \, then me" */
10755 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10756 * is not NULL, read a here document. In the latter case, eofmark is the
10757 * word which marks the end of the document and striptabs is true if
10758 * leading tabs should be stripped from the document. The argument firstc
10759 * is the first character of the input token or document.
10761 * Because C does not have internal subroutines, I have simulated them
10762 * using goto's to implement the subroutine linkage. The following macros
10763 * will run code that appears at the end of readtoken1.
10765 #define CHECKEND() {goto checkend; checkend_return:;}
10766 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10767 #define PARSESUB() {goto parsesub; parsesub_return:;}
10768 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10769 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10770 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10772 readtoken1(int firstc
, int syntax
, char *eofmark
, int striptabs
)
10774 /* NB: syntax parameter fits into smallint */
10778 char line
[EOFMARKLEN
+ 1];
10779 struct nodelist
*bqlist
;
10783 smallint prevsyntax
; /* syntax before arithmetic */
10784 #if ENABLE_ASH_EXPAND_PRMT
10785 smallint pssyntax
; /* we are expanding a prompt string */
10787 int varnest
; /* levels of variables expansion */
10788 int arinest
; /* levels of arithmetic expansion */
10789 int parenlevel
; /* levels of parens in arithmetic */
10790 int dqvarnest
; /* levels of variables expansion within double quotes */
10792 USE_ASH_BASH_COMPAT(smallint bash_dollar_squote
= 0;)
10795 /* Avoid longjmp clobbering */
10801 (void) &parenlevel
;
10804 (void) &prevsyntax
;
10807 startlinno
= g_parsefile
->linno
;
10812 #if ENABLE_ASH_EXPAND_PRMT
10813 pssyntax
= (syntax
== PSSYNTAX
);
10817 dblquote
= (syntax
== DQSYNTAX
);
10823 STARTSTACKSTR(out
);
10825 /* For each line, until end of word */
10827 CHECKEND(); /* set c to PEOF if at end of here document */
10828 for (;;) { /* until end of line or end of word */
10829 CHECKSTRSPACE(4, out
); /* permit 4 calls to USTPUTC */
10830 switch (SIT(c
, syntax
)) {
10831 case CNL
: /* '\n' */
10832 if (syntax
== BASESYNTAX
)
10833 goto endword
; /* exit outer loop */
10835 g_parsefile
->linno
++;
10839 goto loop
; /* continue outer loop */
10844 if (eofmark
== NULL
|| dblquote
)
10845 USTPUTC(CTLESC
, out
);
10846 #if ENABLE_ASH_BASH_COMPAT
10847 if (c
== '\\' && bash_dollar_squote
) {
10848 c
= decode_dollar_squote();
10850 USTPUTC('\\', out
);
10851 c
= (unsigned char)c
;
10857 case CBACK
: /* backslash */
10860 USTPUTC(CTLESC
, out
);
10861 USTPUTC('\\', out
);
10863 } else if (c
== '\n') {
10867 #if ENABLE_ASH_EXPAND_PRMT
10868 if (c
== '$' && pssyntax
) {
10869 USTPUTC(CTLESC
, out
);
10870 USTPUTC('\\', out
);
10873 if (dblquote
&& c
!= '\\'
10874 && c
!= '`' && c
!= '$'
10875 && (c
!= '"' || eofmark
!= NULL
)
10877 USTPUTC(CTLESC
, out
);
10878 USTPUTC('\\', out
);
10880 if (SIT(c
, SQSYNTAX
) == CCTL
)
10881 USTPUTC(CTLESC
, out
);
10889 if (eofmark
== NULL
) {
10890 USTPUTC(CTLQUOTEMARK
, out
);
10898 USE_ASH_BASH_COMPAT(bash_dollar_squote
= 0;)
10899 if (eofmark
!= NULL
&& arinest
== 0
10904 if (dqvarnest
== 0) {
10905 syntax
= BASESYNTAX
;
10912 case CVAR
: /* '$' */
10913 PARSESUB(); /* parse substitution */
10915 case CENDVAR
: /* '}' */
10918 if (dqvarnest
> 0) {
10921 USTPUTC(CTLENDVAR
, out
);
10926 #if ENABLE_SH_MATH_SUPPORT
10927 case CLP
: /* '(' in arithmetic */
10931 case CRP
: /* ')' in arithmetic */
10932 if (parenlevel
> 0) {
10936 if (pgetc() == ')') {
10937 if (--arinest
== 0) {
10938 USTPUTC(CTLENDARI
, out
);
10939 syntax
= prevsyntax
;
10940 dblquote
= (syntax
== DQSYNTAX
);
10945 * unbalanced parens
10946 * (don't 2nd guess - no error)
10954 case CBQUOTE
: /* '`' */
10958 goto endword
; /* exit outer loop */
10962 if (varnest
== 0) {
10963 #if ENABLE_ASH_BASH_COMPAT
10965 if (pgetc() == '>')
10966 c
= 0x100 + '>'; /* flag &> */
10970 goto endword
; /* exit outer loop */
10972 #if ENABLE_ASH_ALIAS
10982 #if ENABLE_SH_MATH_SUPPORT
10983 if (syntax
== ARISYNTAX
)
10984 raise_error_syntax("missing '))'");
10986 if (syntax
!= BASESYNTAX
&& !parsebackquote
&& eofmark
== NULL
)
10987 raise_error_syntax("unterminated quoted string");
10988 if (varnest
!= 0) {
10989 startlinno
= g_parsefile
->linno
;
10991 raise_error_syntax("missing '}'");
10993 USTPUTC('\0', out
);
10994 len
= out
- (char *)stackblock();
10995 out
= stackblock();
10996 if (eofmark
== NULL
) {
10997 if ((c
== '>' || c
== '<' USE_ASH_BASH_COMPAT( || c
== 0x100 + '>'))
11000 if (isdigit_str9(out
)) {
11001 PARSEREDIR(); /* passed as params: out, c */
11002 lasttoken
= TREDIR
;
11005 /* else: non-number X seen, interpret it
11006 * as "NNNX>file" = "NNNX >file" */
11010 quoteflag
= quotef
;
11011 backquotelist
= bqlist
;
11012 grabstackblock(len
);
11016 /* end of readtoken routine */
11019 * Check to see whether we are at the end of the here document. When this
11020 * is called, c is set to the first character of the next input line. If
11021 * we are at the end of the here document, this routine sets the c to PEOF.
11025 #if ENABLE_ASH_ALIAS
11031 while (c
== '\t') {
11035 if (c
== *eofmark
) {
11036 if (pfgets(line
, sizeof(line
)) != NULL
) {
11040 for (q
= eofmark
+ 1; *q
&& *p
== *q
; p
++, q
++)
11042 if (*p
== '\n' && *q
== '\0') {
11044 g_parsefile
->linno
++;
11045 needprompt
= doprompt
;
11047 pushstring(line
, NULL
);
11052 goto checkend_return
;
11056 * Parse a redirection operator. The variable "out" points to a string
11057 * specifying the fd to be redirected. The variable "c" contains the
11058 * first character of the redirection operator.
11061 /* out is already checked to be a valid number or "" */
11062 int fd
= (*out
== '\0' ? -1 : atoi(out
));
11065 np
= stzalloc(sizeof(struct nfile
));
11070 np
->type
= NAPPEND
;
11072 np
->type
= NCLOBBER
;
11075 /* it also can be NTO2 (>&file), but we can't figure it out yet */
11081 #if ENABLE_ASH_BASH_COMPAT
11082 else if (c
== 0x100 + '>') { /* this flags &> redirection */
11084 pgetc(); /* this is '>', no need to check */
11088 else { /* c == '<' */
11089 /*np->nfile.fd = 0; - stzalloc did it */
11093 if (sizeof(struct nfile
) != sizeof(struct nhere
)) {
11094 np
= stzalloc(sizeof(struct nhere
));
11095 /*np->nfile.fd = 0; - stzalloc did it */
11098 heredoc
= stzalloc(sizeof(struct heredoc
));
11099 heredoc
->here
= np
;
11102 heredoc
->striptabs
= 1;
11104 /*heredoc->striptabs = 0; - stzalloc did it */
11110 np
->type
= NFROMFD
;
11114 np
->type
= NFROMTO
;
11126 goto parseredir_return
;
11130 * Parse a substitution. At this point, we have read the dollar sign
11131 * and nothing else.
11134 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11135 * (assuming ascii char codes, as the original implementation did) */
11136 #define is_special(c) \
11137 (((unsigned)(c) - 33 < 32) \
11138 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
11144 static const char types
[] ALIGN1
= "}-+?=";
11147 if (c
<= PEOA_OR_PEOF
11148 || (c
!= '(' && c
!= '{' && !is_name(c
) && !is_special(c
))
11150 #if ENABLE_ASH_BASH_COMPAT
11152 bash_dollar_squote
= 1;
11157 } else if (c
== '(') { /* $(command) or $((arith)) */
11158 if (pgetc() == '(') {
11159 #if ENABLE_SH_MATH_SUPPORT
11162 raise_error_syntax("you disabled math support for $((arith)) syntax");
11169 USTPUTC(CTLVAR
, out
);
11170 typeloc
= out
- (char *)stackblock();
11171 USTPUTC(VSNORMAL
, out
);
11172 subtype
= VSNORMAL
;
11180 subtype
= VSLENGTH
;
11184 if (c
> PEOA_OR_PEOF
&& is_name(c
)) {
11188 } while (c
> PEOA_OR_PEOF
&& is_in_name(c
));
11189 } else if (isdigit(c
)) {
11193 } while (isdigit(c
));
11194 } else if (is_special(c
)) {
11199 raise_error_syntax("bad substitution");
11204 if (subtype
== 0) {
11208 #if ENABLE_ASH_BASH_COMPAT
11209 if (c
== ':' || c
== '$' || isdigit(c
)) {
11211 subtype
= VSSUBSTR
;
11218 p
= strchr(types
, c
);
11221 subtype
= p
- types
+ VSNORMAL
;
11226 subtype
= c
== '#' ? VSTRIMLEFT
: VSTRIMRIGHT
;
11234 #if ENABLE_ASH_BASH_COMPAT
11236 subtype
= VSREPLACE
;
11239 subtype
++; /* VSREPLACEALL */
11248 if (dblquote
|| arinest
)
11250 *((char *)stackblock() + typeloc
) = subtype
| flags
;
11251 if (subtype
!= VSNORMAL
) {
11253 if (dblquote
|| arinest
) {
11258 goto parsesub_return
;
11262 * Called to parse command substitutions. Newstyle is set if the command
11263 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11264 * list of commands (passed by reference), and savelen is the number of
11265 * characters on the top of the stack which must be preserved.
11268 struct nodelist
**nlpp
;
11271 char *volatile str
;
11272 struct jmploc jmploc
;
11273 struct jmploc
*volatile savehandler
;
11275 smallint saveprompt
= 0;
11278 (void) &saveprompt
;
11280 savepbq
= parsebackquote
;
11281 if (setjmp(jmploc
.loc
)) {
11283 parsebackquote
= 0;
11284 exception_handler
= savehandler
;
11285 longjmp(exception_handler
->loc
, 1);
11289 savelen
= out
- (char *)stackblock();
11291 str
= ckmalloc(savelen
);
11292 memcpy(str
, stackblock(), savelen
);
11294 savehandler
= exception_handler
;
11295 exception_handler
= &jmploc
;
11298 /* We must read until the closing backquote, giving special
11299 treatment to some slashes, and then push the string and
11300 reread it as input, interpreting it normally. */
11307 STARTSTACKSTR(pout
);
11320 g_parsefile
->linno
++;
11324 * If eating a newline, avoid putting
11325 * the newline into the new character
11326 * stream (via the STPUTC after the
11331 if (pc
!= '\\' && pc
!= '`' && pc
!= '$'
11332 && (!dblquote
|| pc
!= '"'))
11333 STPUTC('\\', pout
);
11334 if (pc
> PEOA_OR_PEOF
) {
11340 #if ENABLE_ASH_ALIAS
11343 startlinno
= g_parsefile
->linno
;
11344 raise_error_syntax("EOF in backquote substitution");
11347 g_parsefile
->linno
++;
11348 needprompt
= doprompt
;
11357 STPUTC('\0', pout
);
11358 psavelen
= pout
- (char *)stackblock();
11359 if (psavelen
> 0) {
11360 pstr
= grabstackstr(pout
);
11361 setinputstring(pstr
);
11366 nlpp
= &(*nlpp
)->next
;
11367 *nlpp
= stzalloc(sizeof(**nlpp
));
11368 /* (*nlpp)->next = NULL; - stzalloc did it */
11369 parsebackquote
= oldstyle
;
11372 saveprompt
= doprompt
;
11379 doprompt
= saveprompt
;
11380 else if (readtoken() != TRP
)
11381 raise_error_unexpected_syntax(TRP
);
11386 * Start reading from old file again, ignoring any pushed back
11387 * tokens left from the backquote parsing
11392 while (stackblocksize() <= savelen
)
11394 STARTSTACKSTR(out
);
11396 memcpy(out
, str
, savelen
);
11397 STADJUST(savelen
, out
);
11403 parsebackquote
= savepbq
;
11404 exception_handler
= savehandler
;
11405 if (arinest
|| dblquote
)
11406 USTPUTC(CTLBACKQ
| CTLQUOTE
, out
);
11408 USTPUTC(CTLBACKQ
, out
);
11410 goto parsebackq_oldreturn
;
11411 goto parsebackq_newreturn
;
11414 #if ENABLE_SH_MATH_SUPPORT
11416 * Parse an arithmetic expansion (indicate start of one and set state)
11419 if (++arinest
== 1) {
11420 prevsyntax
= syntax
;
11421 syntax
= ARISYNTAX
;
11422 USTPUTC(CTLARI
, out
);
11429 * we collapse embedded arithmetic expansion to
11430 * parenthesis, which should be equivalent
11434 goto parsearith_return
;
11438 } /* end of readtoken */
11441 * Read the next input token.
11442 * If the token is a word, we set backquotelist to the list of cmds in
11443 * backquotes. We set quoteflag to true if any part of the word was
11445 * If the token is TREDIR, then we set redirnode to a structure containing
11447 * In all cases, the variable startlinno is set to the number of the line
11448 * on which the token starts.
11450 * [Change comment: here documents and internal procedures]
11451 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11452 * word parsing code into a separate routine. In this case, readtoken
11453 * doesn't need to have any internal procedures, but parseword does.
11454 * We could also make parseoperator in essence the main routine, and
11455 * have parseword (readtoken1?) handle both words and redirection.]
11457 #define NEW_xxreadtoken
11458 #ifdef NEW_xxreadtoken
11459 /* singles must be first! */
11460 static const char xxreadtoken_chars
[7] ALIGN1
= {
11461 '\n', '(', ')', /* singles */
11462 '&', '|', ';', /* doubles */
11466 #define xxreadtoken_singles 3
11467 #define xxreadtoken_doubles 3
11469 static const char xxreadtoken_tokens
[] ALIGN1
= {
11470 TNL
, TLP
, TRP
, /* only single occurrence allowed */
11471 TBACKGND
, TPIPE
, TSEMI
, /* if single occurrence */
11472 TEOF
, /* corresponds to trailing nul */
11473 TAND
, TOR
, TENDCASE
/* if double occurrence */
11488 startlinno
= g_parsefile
->linno
;
11489 for (;;) { /* until token or start of word found */
11491 if (c
== ' ' || c
== '\t' USE_ASH_ALIAS( || c
== PEOA
))
11495 while ((c
= pgetc()) != '\n' && c
!= PEOF
)
11498 } else if (c
== '\\') {
11499 if (pgetc() != '\n') {
11501 break; /* return readtoken1(...) */
11503 startlinno
= ++g_parsefile
->linno
;
11509 p
= xxreadtoken_chars
+ sizeof(xxreadtoken_chars
) - 1;
11512 g_parsefile
->linno
++;
11513 needprompt
= doprompt
;
11516 p
= strchr(xxreadtoken_chars
, c
);
11518 break; /* return readtoken1(...) */
11520 if ((int)(p
- xxreadtoken_chars
) >= xxreadtoken_singles
) {
11522 if (cc
== c
) { /* double occurrence? */
11523 p
+= xxreadtoken_doubles
+ 1;
11526 #if ENABLE_ASH_BASH_COMPAT
11527 if (c
== '&' && cc
== '>') /* &> */
11528 break; /* return readtoken1(...) */
11533 lasttoken
= xxreadtoken_tokens
[p
- xxreadtoken_chars
];
11538 return readtoken1(c
, BASESYNTAX
, (char *) NULL
, 0);
11540 #else /* old xxreadtoken */
11541 #define RETURN(token) return lasttoken = token
11554 startlinno
= g_parsefile
->linno
;
11555 for (;;) { /* until token or start of word found */
11558 case ' ': case '\t':
11559 #if ENABLE_ASH_ALIAS
11564 while ((c
= pgetc()) != '\n' && c
!= PEOF
)
11569 if (pgetc() == '\n') {
11570 startlinno
= ++g_parsefile
->linno
;
11578 g_parsefile
->linno
++;
11579 needprompt
= doprompt
;
11584 if (pgetc() == '&')
11589 if (pgetc() == '|')
11594 if (pgetc() == ';')
11607 return readtoken1(c
, BASESYNTAX
, (char *)NULL
, 0);
11610 #endif /* old xxreadtoken */
11617 smallint alreadyseen
= tokpushback
;
11620 #if ENABLE_ASH_ALIAS
11629 if (checkkwd
& CHKNL
) {
11636 if (t
!= TWORD
|| quoteflag
) {
11641 * check for keywords
11643 if (checkkwd
& CHKKWD
) {
11644 const char *const *pp
;
11646 pp
= findkwd(wordtext
);
11648 lasttoken
= t
= pp
- tokname_array
;
11649 TRACE(("keyword %s recognized\n", tokname(t
)));
11654 if (checkkwd
& CHKALIAS
) {
11655 #if ENABLE_ASH_ALIAS
11657 ap
= lookupalias(wordtext
, 1);
11660 pushstring(ap
->val
, ap
);
11670 TRACE(("token %s %s\n", tokname(t
), t
== TWORD
? wordtext
: ""));
11672 TRACE(("reread token %s %s\n", tokname(t
), t
== TWORD
? wordtext
: ""));
11684 return tokname_array
[t
][0];
11688 * Read and parse a command. Returns NEOF on end of file. (NULL is a
11689 * valid parse tree indicating a blank line.)
11691 static union node
*
11692 parsecmd(int interact
)
11697 doprompt
= interact
;
11699 setprompt(doprompt
);
11711 * Input any here documents.
11716 struct heredoc
*here
;
11719 here
= heredoclist
;
11720 heredoclist
= NULL
;
11726 readtoken1(pgetc(), here
->here
->type
== NHERE
? SQSYNTAX
: DQSYNTAX
,
11727 here
->eofmark
, here
->striptabs
);
11728 n
= stzalloc(sizeof(struct narg
));
11729 n
->narg
.type
= NARG
;
11730 /*n->narg.next = NULL; - stzalloc did it */
11731 n
->narg
.text
= wordtext
;
11732 n
->narg
.backquote
= backquotelist
;
11733 here
->here
->nhere
.doc
= n
;
11740 * called by editline -- any expansions to the prompt should be added here.
11742 #if ENABLE_ASH_EXPAND_PRMT
11743 static const char *
11744 expandstr(const char *ps
)
11748 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
11749 * and token processing _can_ alter it (delete NULs etc). */
11750 setinputstring((char *)ps
);
11751 readtoken1(pgetc(), PSSYNTAX
, nullstr
, 0);
11754 n
.narg
.type
= NARG
;
11755 n
.narg
.next
= NULL
;
11756 n
.narg
.text
= wordtext
;
11757 n
.narg
.backquote
= backquotelist
;
11759 expandarg(&n
, NULL
, 0);
11760 return stackblock();
11765 * Execute a command or commands contained in a string.
11768 evalstring(char *s
, int mask
)
11771 struct stackmark smark
;
11775 setstackmark(&smark
);
11778 while ((n
= parsecmd(0)) != NEOF
) {
11780 popstackmark(&smark
);
11793 * The eval command.
11796 evalcmd(int argc UNUSED_PARAM
, char **argv
)
11805 STARTSTACKSTR(concat
);
11807 concat
= stack_putstr(p
, concat
);
11811 STPUTC(' ', concat
);
11813 STPUTC('\0', concat
);
11814 p
= grabstackstr(concat
);
11816 evalstring(p
, ~SKIPEVAL
);
11823 * Read and execute commands. "Top" is nonzero for the top level command
11824 * loop; it turns on prompting if the shell is interactive.
11830 struct stackmark smark
;
11834 TRACE(("cmdloop(%d) called\n", top
));
11838 setstackmark(&smark
);
11841 showjobs(stderr
, SHOW_CHANGED
);
11844 if (iflag
&& top
) {
11846 #if ENABLE_ASH_MAIL
11850 n
= parsecmd(inter
);
11855 if (!top
|| numeof
>= 50)
11857 if (!stoppedjobs()) {
11860 out2str("\nUse \"exit\" to leave shell.\n");
11863 } else if (nflag
== 0) {
11864 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
11869 popstackmark(&smark
);
11874 return skip
& SKIPEVAL
;
11881 * Take commands from a file. To be compatible we should do a path
11882 * search for the file, which is necessary to find sub-commands.
11885 find_dot_file(char *name
)
11888 const char *path
= pathval();
11891 /* don't try this for absolute or relative paths */
11892 if (strchr(name
, '/'))
11895 /* IIRC standards do not say whether . is to be searched.
11896 * And it is even smaller this way, making it unconditional for now:
11898 if (1) { /* ENABLE_ASH_BASH_COMPAT */
11903 while ((fullname
= padvance(&path
, name
)) != NULL
) {
11905 if ((stat(fullname
, &statb
) == 0) && S_ISREG(statb
.st_mode
)) {
11907 * Don't bother freeing here, since it will
11908 * be freed by the caller.
11912 if (fullname
!= name
)
11913 stunalloc(fullname
);
11916 /* not found in the PATH */
11917 ash_msg_and_raise_error("%s: not found", name
);
11922 dotcmd(int argc
, char **argv
)
11924 struct strlist
*sp
;
11925 volatile struct shparam saveparam
;
11928 for (sp
= cmdenviron
; sp
; sp
= sp
->next
)
11929 setvareq(ckstrdup(sp
->text
), VSTRFIXED
| VTEXTFIXED
);
11931 if (argv
[1]) { /* That's what SVR2 does */
11932 char *fullname
= find_dot_file(argv
[1]);
11935 if (argc
) { /* argc > 0, argv[0] != NULL */
11936 saveparam
= shellparam
;
11937 shellparam
.malloced
= 0;
11938 shellparam
.nparam
= argc
;
11939 shellparam
.p
= argv
;
11942 setinputfile(fullname
, INPUT_PUSH_FILE
);
11943 commandname
= fullname
;
11948 freeparam(&shellparam
);
11949 shellparam
= saveparam
;
11951 status
= exitstatus
;
11957 exitcmd(int argc UNUSED_PARAM
, char **argv
)
11962 exitstatus
= number(argv
[1]);
11963 raise_exception(EXEXIT
);
11968 * Read a file containing shell functions.
11971 readcmdfile(char *name
)
11973 setinputfile(name
, INPUT_PUSH_FILE
);
11979 /* ============ find_command inplementation */
11982 * Resolve a command name. If you change this routine, you may have to
11983 * change the shellexec routine as well.
11986 find_command(char *name
, struct cmdentry
*entry
, int act
, const char *path
)
11988 struct tblentry
*cmdp
;
11995 struct builtincmd
*bcmd
;
11997 /* If name contains a slash, don't use PATH or hash table */
11998 if (strchr(name
, '/') != NULL
) {
11999 entry
->u
.index
= -1;
12000 if (act
& DO_ABS
) {
12001 while (stat(name
, &statb
) < 0) {
12003 if (errno
== EINTR
)
12006 entry
->cmdtype
= CMDUNKNOWN
;
12010 entry
->cmdtype
= CMDNORMAL
;
12014 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
12016 updatetbl
= (path
== pathval());
12019 if (strstr(path
, "%builtin") != NULL
)
12020 act
|= DO_ALTBLTIN
;
12023 /* If name is in the table, check answer will be ok */
12024 cmdp
= cmdlookup(name
, 0);
12025 if (cmdp
!= NULL
) {
12028 switch (cmdp
->cmdtype
) {
12046 } else if (cmdp
->rehash
== 0)
12047 /* if not invalidated by cd, we're done */
12051 /* If %builtin not in path, check for builtin next */
12052 bcmd
= find_builtin(name
);
12054 if (IS_BUILTIN_REGULAR(bcmd
))
12055 goto builtin_success
;
12056 if (act
& DO_ALTPATH
) {
12057 if (!(act
& DO_ALTBLTIN
))
12058 goto builtin_success
;
12059 } else if (builtinloc
<= 0) {
12060 goto builtin_success
;
12064 #if ENABLE_FEATURE_SH_STANDALONE
12066 int applet_no
= find_applet_by_name(name
);
12067 if (applet_no
>= 0) {
12068 entry
->cmdtype
= CMDNORMAL
;
12069 entry
->u
.index
= -2 - applet_no
;
12075 /* We have to search path. */
12076 prev
= -1; /* where to start */
12077 if (cmdp
&& cmdp
->rehash
) { /* doing a rehash */
12078 if (cmdp
->cmdtype
== CMDBUILTIN
)
12081 prev
= cmdp
->param
.index
;
12087 while ((fullname
= padvance(&path
, name
)) != NULL
) {
12088 stunalloc(fullname
);
12089 /* NB: code below will still use fullname
12090 * despite it being "unallocated" */
12093 if (prefix(pathopt
, "builtin")) {
12095 goto builtin_success
;
12098 if ((act
& DO_NOFUNC
)
12099 || !prefix(pathopt
, "func")
12100 ) { /* ignore unimplemented options */
12104 /* if rehash, don't redo absolute path names */
12105 if (fullname
[0] == '/' && idx
<= prev
) {
12108 TRACE(("searchexec \"%s\": no change\n", name
));
12111 while (stat(fullname
, &statb
) < 0) {
12113 if (errno
== EINTR
)
12116 if (errno
!= ENOENT
&& errno
!= ENOTDIR
)
12120 e
= EACCES
; /* if we fail, this will be the error */
12121 if (!S_ISREG(statb
.st_mode
))
12123 if (pathopt
) { /* this is a %func directory */
12124 stalloc(strlen(fullname
) + 1);
12125 /* NB: stalloc will return space pointed by fullname
12126 * (because we don't have any intervening allocations
12127 * between stunalloc above and this stalloc) */
12128 readcmdfile(fullname
);
12129 cmdp
= cmdlookup(name
, 0);
12130 if (cmdp
== NULL
|| cmdp
->cmdtype
!= CMDFUNCTION
)
12131 ash_msg_and_raise_error("%s not defined in %s", name
, fullname
);
12132 stunalloc(fullname
);
12135 TRACE(("searchexec \"%s\" returns \"%s\"\n", name
, fullname
));
12137 entry
->cmdtype
= CMDNORMAL
;
12138 entry
->u
.index
= idx
;
12142 cmdp
= cmdlookup(name
, 1);
12143 cmdp
->cmdtype
= CMDNORMAL
;
12144 cmdp
->param
.index
= idx
;
12149 /* We failed. If there was an entry for this command, delete it */
12150 if (cmdp
&& updatetbl
)
12151 delete_cmd_entry();
12153 ash_msg("%s: %s", name
, errmsg(e
, "not found"));
12154 entry
->cmdtype
= CMDUNKNOWN
;
12159 entry
->cmdtype
= CMDBUILTIN
;
12160 entry
->u
.cmd
= bcmd
;
12164 cmdp
= cmdlookup(name
, 1);
12165 cmdp
->cmdtype
= CMDBUILTIN
;
12166 cmdp
->param
.cmd
= bcmd
;
12170 entry
->cmdtype
= cmdp
->cmdtype
;
12171 entry
->u
= cmdp
->param
;
12175 /* ============ trap.c */
12178 * The trap builtin.
12181 trapcmd(int argc UNUSED_PARAM
, char **argv UNUSED_PARAM
)
12190 for (signo
= 0; signo
< NSIG
; signo
++) {
12191 if (trap
[signo
] != NULL
) {
12192 out1fmt("trap -- %s %s\n",
12193 single_quote(trap
[signo
]),
12194 get_signame(signo
));
12203 signo
= get_signum(*ap
);
12205 ash_msg_and_raise_error("%s: bad trap", *ap
);
12208 if (LONE_DASH(action
))
12211 action
= ckstrdup(action
);
12214 trap
[signo
] = action
;
12224 /* ============ Builtins */
12226 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
12228 * Lists available builtins
12231 helpcmd(int argc UNUSED_PARAM
, char **argv UNUSED_PARAM
)
12237 "Built-in commands:\n"
12238 "------------------\n");
12239 for (col
= 0, i
= 0; i
< ARRAY_SIZE(builtintab
); i
++) {
12240 col
+= out1fmt("%c%s", ((col
== 0) ? '\t' : ' '),
12241 builtintab
[i
].name
+ 1);
12247 #if ENABLE_FEATURE_SH_STANDALONE
12249 const char *a
= applet_names
;
12251 col
+= out1fmt("%c%s", ((col
== 0) ? '\t' : ' '), a
);
12256 a
+= strlen(a
) + 1;
12261 return EXIT_SUCCESS
;
12263 #endif /* FEATURE_SH_EXTRA_QUIET */
12266 * The export and readonly commands.
12269 exportcmd(int argc UNUSED_PARAM
, char **argv
)
12275 int flag
= argv
[0][0] == 'r' ? VREADONLY
: VEXPORT
;
12277 if (nextopt("p") != 'p') {
12282 p
= strchr(name
, '=');
12286 vp
= *findvar(hashvar(name
), name
);
12292 setvar(name
, p
, flag
);
12293 } while ((name
= *++aptr
) != NULL
);
12297 showvars(argv
[0], flag
, 0);
12302 * Delete a function if it exists.
12305 unsetfunc(const char *name
)
12307 struct tblentry
*cmdp
;
12309 cmdp
= cmdlookup(name
, 0);
12310 if (cmdp
!= NULL
&& cmdp
->cmdtype
== CMDFUNCTION
)
12311 delete_cmd_entry();
12315 * The unset builtin command. We unset the function before we unset the
12316 * variable to allow a function to be unset when there is a readonly variable
12317 * with the same name.
12320 unsetcmd(int argc UNUSED_PARAM
, char **argv UNUSED_PARAM
)
12327 while ((i
= nextopt("vf")) != '\0') {
12331 for (ap
= argptr
; *ap
; ap
++) {
12347 #include <sys/times.h>
12349 static const unsigned char timescmd_str
[] ALIGN1
= {
12350 ' ', offsetof(struct tms
, tms_utime
),
12351 '\n', offsetof(struct tms
, tms_stime
),
12352 ' ', offsetof(struct tms
, tms_cutime
),
12353 '\n', offsetof(struct tms
, tms_cstime
),
12358 timescmd(int argc UNUSED_PARAM
, char **argv UNUSED_PARAM
)
12360 long clk_tck
, s
, t
;
12361 const unsigned char *p
;
12364 clk_tck
= sysconf(_SC_CLK_TCK
);
12369 t
= *(clock_t *)(((char *) &buf
) + p
[1]);
12371 out1fmt("%ldm%ld.%.3lds%c",
12373 ((t
- s
* clk_tck
) * 1000) / clk_tck
,
12375 } while (*(p
+= 2));
12380 #if ENABLE_SH_MATH_SUPPORT
12382 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12383 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12385 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12388 letcmd(int argc UNUSED_PARAM
, char **argv
)
12394 ash_msg_and_raise_error("expression expected");
12396 i
= ash_arith(*argv
);
12401 #endif /* SH_MATH_SUPPORT */
12404 /* ============ miscbltin.c
12406 * Miscellaneous builtins.
12411 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12412 typedef enum __rlimit_resource rlim_t
;
12416 * The read builtin. Options:
12417 * -r Do not interpret '\' specially
12418 * -s Turn off echo (tty only)
12419 * -n NCHARS Read NCHARS max
12420 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12421 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12422 * -u FD Read from given FD instead of fd 0
12423 * This uses unbuffered input, which may be avoidable in some cases.
12424 * TODO: bash also has:
12425 * -a ARRAY Read into array[0],[1],etc
12426 * -d DELIM End on DELIM char, not newline
12427 * -e Use line editing (tty only)
12430 readcmd(int argc UNUSED_PARAM
, char **argv UNUSED_PARAM
)
12432 static const char *const arg_REPLY
[] = { "REPLY", NULL
};
12445 #if ENABLE_ASH_READ_NCHARS
12446 int nchars
= 0; /* if != 0, -n is in effect */
12448 struct termios tty
, old_tty
;
12450 #if ENABLE_ASH_READ_TIMEOUT
12451 unsigned end_ms
= 0;
12452 unsigned timeout
= 0;
12457 while ((i
= nextopt("p:u:r"
12458 USE_ASH_READ_TIMEOUT("t:")
12459 USE_ASH_READ_NCHARS("n:s")
12463 prompt
= optionarg
;
12465 #if ENABLE_ASH_READ_NCHARS
12467 nchars
= bb_strtou(optionarg
, NULL
, 10);
12468 if (nchars
< 0 || errno
)
12469 ash_msg_and_raise_error("invalid count");
12470 /* nchars == 0: off (bash 3.2 does this too) */
12476 #if ENABLE_ASH_READ_TIMEOUT
12478 timeout
= bb_strtou(optionarg
, NULL
, 10);
12479 if (errno
|| timeout
> UINT_MAX
/ 2048)
12480 ash_msg_and_raise_error("invalid timeout");
12482 #if 0 /* even bash have no -t N.NNN support */
12483 ts
.tv_sec
= bb_strtou(optionarg
, &p
, 10);
12485 /* EINVAL means number is ok, but not terminated by NUL */
12486 if (*p
== '.' && errno
== EINVAL
) {
12490 ts
.tv_usec
= bb_strtou(p
, &p2
, 10);
12492 ash_msg_and_raise_error("invalid timeout");
12494 /* normalize to usec */
12496 ash_msg_and_raise_error("invalid timeout");
12497 while (scale
++ < 6)
12500 } else if (ts
.tv_sec
< 0 || errno
) {
12501 ash_msg_and_raise_error("invalid timeout");
12503 if (!(ts
.tv_sec
| ts
.tv_usec
)) { /* both are 0? */
12504 ash_msg_and_raise_error("invalid timeout");
12513 fd
= bb_strtou(optionarg
, NULL
, 10);
12514 if (fd
< 0 || errno
)
12515 ash_msg_and_raise_error("invalid file descriptor");
12521 if (prompt
&& isatty(fd
)) {
12526 ap
= (char**)arg_REPLY
;
12527 ifs
= bltinlookup("IFS");
12530 #if ENABLE_ASH_READ_NCHARS
12531 tcgetattr(fd
, &tty
);
12533 if (nchars
|| silent
) {
12535 tty
.c_lflag
&= ~ICANON
;
12536 tty
.c_cc
[VMIN
] = nchars
< 256 ? nchars
: 255;
12539 tty
.c_lflag
&= ~(ECHO
| ECHOK
| ECHONL
);
12541 /* if tcgetattr failed, tcsetattr will fail too.
12542 * Ignoring, it's harmless. */
12543 tcsetattr(fd
, TCSANOW
, &tty
);
12550 #if ENABLE_ASH_READ_TIMEOUT
12551 if (timeout
) /* NB: ensuring end_ms is nonzero */
12552 end_ms
= ((unsigned)(monotonic_us() / 1000) + timeout
) | 1;
12556 const char *is_ifs
;
12558 #if ENABLE_ASH_READ_TIMEOUT
12560 struct pollfd pfd
[1];
12562 pfd
[0].events
= POLLIN
;
12563 timeout
= end_ms
- (unsigned)(monotonic_us() / 1000);
12564 if ((int)timeout
<= 0 /* already late? */
12565 || safe_poll(pfd
, 1, timeout
) != 1 /* no? wait... */
12566 ) { /* timed out! */
12567 #if ENABLE_ASH_READ_NCHARS
12568 tcsetattr(fd
, TCSANOW
, &old_tty
);
12574 if (nonblock_safe_read(fd
, &c
, 1) != 1) {
12586 if (!rflag
&& c
== '\\') {
12592 /* $IFS splitting */
12593 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */
12594 is_ifs
= strchr(ifs
, c
);
12595 if (startword
&& is_ifs
) {
12598 /* it is a non-space ifs char */
12600 if (startword
== 1) /* first one? */
12601 continue; /* yes, it is not next word yet */
12604 if (ap
[1] != NULL
&& is_ifs
) {
12607 beg
= stackblock();
12608 setvar(*ap
, beg
, 0);
12610 /* can we skip one non-space ifs char? (2: yes) */
12611 startword
= isspace(c
) ? 2 : 1;
12618 /* end of do {} while: */
12619 #if ENABLE_ASH_READ_NCHARS
12625 #if ENABLE_ASH_READ_NCHARS
12626 tcsetattr(fd
, TCSANOW
, &old_tty
);
12630 /* Remove trailing space ifs chars */
12631 while ((char *)stackblock() <= --p
&& isspace(*p
) && strchr(ifs
, *p
) != NULL
)
12633 setvar(*ap
, stackblock(), 0);
12634 while (*++ap
!= NULL
)
12635 setvar(*ap
, nullstr
, 0);
12640 umaskcmd(int argc UNUSED_PARAM
, char **argv
)
12642 static const char permuser
[3] ALIGN1
= "ugo";
12643 static const char permmode
[3] ALIGN1
= "rwx";
12644 static const short permmask
[] ALIGN2
= {
12645 S_IRUSR
, S_IWUSR
, S_IXUSR
,
12646 S_IRGRP
, S_IWGRP
, S_IXGRP
,
12647 S_IROTH
, S_IWOTH
, S_IXOTH
12653 int symbolic_mode
= 0;
12655 while (nextopt("S") != '\0') {
12666 if (symbolic_mode
) {
12670 for (i
= 0; i
< 3; i
++) {
12673 *p
++ = permuser
[i
];
12675 for (j
= 0; j
< 3; j
++) {
12676 if ((mask
& permmask
[3 * i
+ j
]) == 0) {
12677 *p
++ = permmode
[j
];
12685 out1fmt("%.4o\n", mask
);
12688 if (isdigit((unsigned char) *ap
)) {
12691 if (*ap
>= '8' || *ap
< '0')
12692 ash_msg_and_raise_error(illnum
, argv
[1]);
12693 mask
= (mask
<< 3) + (*ap
- '0');
12694 } while (*++ap
!= '\0');
12697 mask
= ~mask
& 0777;
12698 if (!bb_parse_mode(ap
, &mask
)) {
12699 ash_msg_and_raise_error("illegal mode: %s", ap
);
12701 umask(~mask
& 0777);
12710 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12711 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12712 * ash by J.T. Conklin.
12718 uint8_t cmd
; /* RLIMIT_xxx fit into it */
12719 uint8_t factor_shift
; /* shift by to get rlim_{cur,max} values */
12723 static const struct limits limits_tbl
[] = {
12725 { RLIMIT_CPU
, 0, 't' },
12727 #ifdef RLIMIT_FSIZE
12728 { RLIMIT_FSIZE
, 9, 'f' },
12731 { RLIMIT_DATA
, 10, 'd' },
12733 #ifdef RLIMIT_STACK
12734 { RLIMIT_STACK
, 10, 's' },
12737 { RLIMIT_CORE
, 9, 'c' },
12740 { RLIMIT_RSS
, 10, 'm' },
12742 #ifdef RLIMIT_MEMLOCK
12743 { RLIMIT_MEMLOCK
, 10, 'l' },
12745 #ifdef RLIMIT_NPROC
12746 { RLIMIT_NPROC
, 0, 'p' },
12748 #ifdef RLIMIT_NOFILE
12749 { RLIMIT_NOFILE
, 0, 'n' },
12752 { RLIMIT_AS
, 10, 'v' },
12754 #ifdef RLIMIT_LOCKS
12755 { RLIMIT_LOCKS
, 0, 'w' },
12758 static const char limits_name
[] =
12760 "time(seconds)" "\0"
12762 #ifdef RLIMIT_FSIZE
12763 "file(blocks)" "\0"
12768 #ifdef RLIMIT_STACK
12772 "coredump(blocks)" "\0"
12777 #ifdef RLIMIT_MEMLOCK
12778 "locked memory(kb)" "\0"
12780 #ifdef RLIMIT_NPROC
12783 #ifdef RLIMIT_NOFILE
12789 #ifdef RLIMIT_LOCKS
12794 enum limtype
{ SOFT
= 0x1, HARD
= 0x2 };
12797 printlim(enum limtype how
, const struct rlimit
*limit
,
12798 const struct limits
*l
)
12802 val
= limit
->rlim_max
;
12804 val
= limit
->rlim_cur
;
12806 if (val
== RLIM_INFINITY
)
12807 out1fmt("unlimited\n");
12809 val
>>= l
->factor_shift
;
12810 out1fmt("%lld\n", (long long) val
);
12815 ulimitcmd(int argc UNUSED_PARAM
, char **argv UNUSED_PARAM
)
12819 enum limtype how
= SOFT
| HARD
;
12820 const struct limits
*l
;
12823 struct rlimit limit
;
12826 while ((optc
= nextopt("HSa"
12830 #ifdef RLIMIT_FSIZE
12836 #ifdef RLIMIT_STACK
12845 #ifdef RLIMIT_MEMLOCK
12848 #ifdef RLIMIT_NPROC
12851 #ifdef RLIMIT_NOFILE
12857 #ifdef RLIMIT_LOCKS
12875 for (l
= limits_tbl
; l
->option
!= what
; l
++)
12878 set
= *argptr
? 1 : 0;
12882 if (all
|| argptr
[1])
12883 ash_msg_and_raise_error("too many arguments");
12884 if (strncmp(p
, "unlimited\n", 9) == 0)
12885 val
= RLIM_INFINITY
;
12889 while ((c
= *p
++) >= '0' && c
<= '9') {
12890 val
= (val
* 10) + (long)(c
- '0');
12891 // val is actually 'unsigned long int' and can't get < 0
12892 if (val
< (rlim_t
) 0)
12896 ash_msg_and_raise_error("bad number");
12897 val
<<= l
->factor_shift
;
12901 const char *lname
= limits_name
;
12902 for (l
= limits_tbl
; l
!= &limits_tbl
[ARRAY_SIZE(limits_tbl
)]; l
++) {
12903 getrlimit(l
->cmd
, &limit
);
12904 out1fmt("%-20s ", lname
);
12905 lname
+= strlen(lname
) + 1;
12906 printlim(how
, &limit
, l
);
12911 getrlimit(l
->cmd
, &limit
);
12914 limit
.rlim_max
= val
;
12916 limit
.rlim_cur
= val
;
12917 if (setrlimit(l
->cmd
, &limit
) < 0)
12918 ash_msg_and_raise_error("error setting limit (%m)");
12920 printlim(how
, &limit
, l
);
12925 /* ============ main() and helpers */
12928 * Called to exit the shell.
12930 static void exitshell(void) NORETURN
;
12938 status
= exitstatus
;
12939 TRACE(("pid %d, exitshell(%d)\n", getpid(), status
));
12940 if (setjmp(loc
.loc
)) {
12941 if (exception_type
== EXEXIT
)
12942 /* dash bug: it just does _exit(exitstatus) here
12943 * but we have to do setjobctl(0) first!
12944 * (bug is still not fixed in dash-0.5.3 - if you run dash
12945 * under Midnight Commander, on exit from dash MC is backgrounded) */
12946 status
= exitstatus
;
12949 exception_handler
= &loc
;
12955 flush_stdout_stderr();
12965 /* from input.c: */
12966 basepf
.next_to_pgetc
= basepf
.buf
= basebuf
;
12969 signal(SIGCHLD
, SIG_DFL
);
12974 char ppid
[sizeof(int)*3 + 1];
12976 struct stat st1
, st2
;
12979 for (envp
= environ
; envp
&& *envp
; envp
++) {
12980 if (strchr(*envp
, '=')) {
12981 setvareq(*envp
, VEXPORT
|VTEXTFIXED
);
12985 snprintf(ppid
, sizeof(ppid
), "%u", (unsigned) getppid());
12986 setvar("PPID", ppid
, 0);
12988 p
= lookupvar("PWD");
12990 if (*p
!= '/' || stat(p
, &st1
) || stat(".", &st2
)
12991 || st1
.st_dev
!= st2
.st_dev
|| st1
.st_ino
!= st2
.st_ino
)
12998 * Process the shell command line arguments.
13001 procargs(char **argv
)
13004 const char *xminusc
;
13009 /* if (xargv[0]) - mmm, this is always true! */
13011 for (i
= 0; i
< NOPTS
; i
++)
13015 /* it already printed err message */
13016 raise_exception(EXERROR
);
13020 if (*xargv
== NULL
) {
13022 ash_msg_and_raise_error(bb_msg_requires_arg
, "-c");
13025 if (iflag
== 2 && sflag
== 1 && isatty(0) && isatty(1))
13029 for (i
= 0; i
< NOPTS
; i
++)
13030 if (optlist
[i
] == 2)
13035 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13040 } else if (!sflag
) {
13041 setinputfile(*xargv
, 0);
13044 commandname
= arg0
;
13047 shellparam
.p
= xargv
;
13048 #if ENABLE_ASH_GETOPTS
13049 shellparam
.optind
= 1;
13050 shellparam
.optoff
= -1;
13052 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
13054 shellparam
.nparam
++;
13061 * Read /etc/profile or .profile.
13064 read_profile(const char *name
)
13068 if (setinputfile(name
, INPUT_PUSH_FILE
| INPUT_NOFILE_OK
) < 0)
13077 * This routine is called when an error or an interrupt occurs in an
13078 * interactive shell and control is returned to the main command loop.
13086 /* from input.c: */
13087 g_parsefile
->left_in_buffer
= 0;
13088 g_parsefile
->left_in_line
= 0; /* clear input buffer */
13090 /* from parser.c: */
13093 /* from redir.c: */
13094 clearredir(/*drop:*/ 0);
13098 static short profile_buf
[16384];
13099 extern int etext();
13103 * Main routine. We initialize things, parse the arguments, execute
13104 * profiles if we're a login shell, and then call cmdloop to execute
13105 * commands. The setjmp call sets up the location to jump to when an
13106 * exception occurs. When an exception occurs the variable "state"
13107 * is used to figure out how far we had gotten.
13109 int ash_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
13110 int ash_main(int argc UNUSED_PARAM
, char **argv
)
13112 const char *shinit
;
13113 volatile smallint state
;
13114 struct jmploc jmploc
;
13115 struct stackmark smark
;
13117 /* Initialize global data */
13121 #if ENABLE_ASH_ALIAS
13127 monitor(4, etext
, profile_buf
, sizeof(profile_buf
), 50);
13130 #if ENABLE_FEATURE_EDITING
13131 line_input_state
= new_line_input_t(FOR_SHELL
| WITH_PATH_LOOKUP
);
13134 if (setjmp(jmploc
.loc
)) {
13140 e
= exception_type
;
13144 if (e
== EXEXIT
|| s
== 0 || iflag
== 0 || shlvl
)
13147 outcslow('\n', stderr
);
13149 popstackmark(&smark
);
13150 FORCE_INT_ON
; /* enable interrupts */
13159 exception_handler
= &jmploc
;
13162 TRACE(("Shell args: "));
13163 trace_puts_args(argv
);
13165 rootpid
= getpid();
13167 #if ENABLE_ASH_RANDOM_SUPPORT
13168 /* Can use monotonic_ns() for better randomness but for now it is
13169 * not used anywhere else in busybox... so avoid bloat */
13170 random_galois_LFSR
= random_LCG
= rootpid
+ monotonic_us();
13173 setstackmark(&smark
);
13176 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13178 const char *hp
= lookupvar("HISTFILE");
13181 hp
= lookupvar("HOME");
13183 char *defhp
= concat_path_file(hp
, ".ash_history");
13184 setvar("HISTFILE", defhp
, 0);
13190 if (/* argv[0] && */ argv
[0][0] == '-')
13194 read_profile("/etc/profile");
13197 read_profile(".profile");
13203 getuid() == geteuid() && getgid() == getegid() &&
13207 shinit
= lookupvar("ENV");
13208 if (shinit
!= NULL
&& *shinit
!= '\0') {
13209 read_profile(shinit
);
13215 /* evalstring pushes parsefile stack.
13216 * Ensure we don't falsely claim that 0 (stdin)
13217 * is one of stacked source fds.
13218 * Testcase: ash -c 'exec 1>&0' must not complain. */
13220 g_parsefile
->fd
= -1;
13221 evalstring(minusc
, 0);
13224 if (sflag
|| minusc
== NULL
) {
13225 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13227 const char *hp
= lookupvar("HISTFILE");
13229 line_input_state
->hist_file
= hp
;
13232 state4
: /* XXX ??? - why isn't this before the "if" statement */
13240 extern void _mcleanup(void);
13250 * Copyright (c) 1989, 1991, 1993, 1994
13251 * The Regents of the University of California. All rights reserved.
13253 * This code is derived from software contributed to Berkeley by
13254 * Kenneth Almquist.
13256 * Redistribution and use in source and binary forms, with or without
13257 * modification, are permitted provided that the following conditions
13259 * 1. Redistributions of source code must retain the above copyright
13260 * notice, this list of conditions and the following disclaimer.
13261 * 2. Redistributions in binary form must reproduce the above copyright
13262 * notice, this list of conditions and the following disclaimer in the
13263 * documentation and/or other materials provided with the distribution.
13264 * 3. Neither the name of the University nor the names of its contributors
13265 * may be used to endorse or promote products derived from this software
13266 * without specific prior written permission.
13268 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13269 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13270 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13271 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13272 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13273 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13274 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13275 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13276 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13277 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF