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.
12 * This code is derived from software contributed to Berkeley by
15 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
17 * Original BSD copyright notice is retained at the end of this file.
21 * rewrite arith.y to micro stack based cryptic algorithm by
22 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
24 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
27 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be
28 * used in busybox and size optimizations,
29 * rewrote arith (see notes to this), added locale support,
30 * rewrote dynamic variables.
35 * The follow should be set to reflect the type of system you have:
36 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
37 * define SYSV if you are running under System V.
38 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
39 * define DEBUG=2 to compile in and turn on debugging.
41 * When debugging is on, debugging info will be written to ./trace and
42 * a quit signal will generate a core dump.
47 #if ENABLE_ASH_JOB_CONTROL
60 #if JOBS || ENABLE_ASH_READ_NCHARS
64 #if defined(__uClinux__)
65 #error "Do not even bother, ash will not run on uClinux"
71 static int *dash_errno;
73 #define errno (*dash_errno)
86 static int aliascmd(int, char **);
87 static int unaliascmd(int, char **);
88 static void printalias(const struct alias *);
92 /* ============ Shell options */
94 static const char *const optletters_optnames[] = {
115 #define optletters(n) optletters_optnames[(n)][0]
116 #define optnames(n) (&optletters_optnames[(n)][1])
118 #define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
120 static char optlist[NOPTS];
122 #define eflag optlist[0]
123 #define fflag optlist[1]
124 #define Iflag optlist[2]
125 #define iflag optlist[3]
126 #define mflag optlist[4]
127 #define nflag optlist[5]
128 #define sflag optlist[6]
129 #define xflag optlist[7]
130 #define vflag optlist[8]
131 #define Cflag optlist[9]
132 #define aflag optlist[10]
133 #define bflag optlist[11]
134 #define uflag optlist[12]
135 #define viflag optlist[13]
137 #define nolog optlist[14]
138 #define debug optlist[15]
142 /* ============ Misc data */
144 static int isloginsh;
145 /* pid of main shell */
147 /* shell level: 0 for the main shell, 1 for its children, and so on */
149 #define rootshell (!shlvl)
150 /* trap handler commands */
151 static char *trap[NSIG];
152 /* current value of signal */
153 static char sigmode[NSIG - 1];
154 /* indicates specified signal received */
155 static char gotsig[NSIG - 1];
156 static char *arg0; /* value of $0 */
159 /* ============ Interrupts / exceptions
161 * We enclose jmp_buf in a structure so that we can declare pointers to
162 * jump locations. The global variable handler contains the location to
163 * jump to when an exception occurs, and the global variable exception
164 * contains a code identifying the exception. To implement nested
165 * exception handlers, the user should save the value of handler on entry
166 * to an inner scope, set handler to point to a jmploc structure for the
167 * inner scope, and restore handler on exit from the scope.
172 static struct jmploc *exception_handler;
173 static int exception;
175 #define EXINT 0 /* SIGINT received */
176 #define EXERROR 1 /* a generic error */
177 #define EXSHELLPROC 2 /* execute a shell procedure */
178 #define EXEXEC 3 /* command execution failed */
179 #define EXEXIT 4 /* exit the shell */
180 #define EXSIG 5 /* trapped signal in wait(1) */
181 static volatile int suppressint;
182 static volatile sig_atomic_t intpending;
183 /* do we generate EXSIG events */
185 /* last pending signal */
186 static volatile sig_atomic_t pendingsigs;
189 * These macros allow the user to suspend the handling of interrupt signals
190 * over a period of time. This is similar to SIGHOLD to or sigblock, but
191 * much more efficient and portable. (But hacking the kernel is so much
192 * more fun than worrying about efficiency and portability. :-))
194 #define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
203 * Called to raise an exception. Since C doesn't include exceptions, we
204 * just do a longjmp to the exception handler. The type of exception is
205 * stored in the global variable "exception".
207 static void raise_exception(int) ATTRIBUTE_NORETURN;
209 raise_exception(int e)
212 if (exception_handler == NULL)
217 longjmp(exception_handler->loc, 1);
221 * Called from trap.c when a SIGINT is received. (If the user specifies
222 * that SIGINT is to be trapped or ignored using the trap builtin, then
223 * this routine is not called.) Suppressint is nonzero when interrupts
224 * are held using the INT_OFF macro. (The test for iflag is just
225 * defensive programming.)
227 static void raise_interrupt(void) ATTRIBUTE_NORETURN;
229 raise_interrupt(void)
235 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
236 if (!(rootshell && iflag)) {
237 signal(SIGINT, SIG_DFL);
246 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
247 static void int_on(void)
249 if (--suppressint == 0 && intpending) {
253 #define INT_ON int_on()
254 static void force_int_on(void)
260 #define FORCE_INT_ON force_int_on()
265 if (--suppressint == 0 && intpending) raise_interrupt(); \
268 #define FORCE_INT_ON \
272 if (intpending) raise_interrupt(); \
275 #endif /* ASH_OPTIMIZE_FOR_SIZE */
277 #define SAVE_INT(v) ((v) = suppressint)
279 #define RESTORE_INT(v) \
283 if (suppressint == 0 && intpending) raise_interrupt(); \
292 raise_exception(EXSIG); \
295 /* EXSIG is turned off by evalbltin(). */
298 /* ============ stdout/stderr output */
301 outstr(const char *p, FILE *file)
309 flush_stdout_stderr(void)
326 outcslow(int c, FILE *dest)
334 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
336 out1fmt(const char *fmt, ...)
343 r = vprintf(fmt, ap);
349 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
351 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
358 ret = vsnprintf(outbuf, length, fmt, ap);
365 out1str(const char *p)
371 out2str(const char *p)
378 /* ============ Parser data
380 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
384 struct strpush *prev; /* preceding string on stack */
388 struct alias *ap; /* if push was associated with an alias */
390 char *string; /* remember the string since it may change */
394 struct parsefile *prev; /* preceding file on stack */
395 int linno; /* current line */
396 int fd; /* file descriptor (or -1 if string) */
397 int nleft; /* number of chars left in this line */
398 int lleft; /* number of chars left in this buffer */
399 char *nextc; /* next char in buffer */
400 char *buf; /* input buffer */
401 struct strpush *strpush; /* for pushing strings at this level */
402 struct strpush basestrpush; /* so pushing one is fast */
405 static struct parsefile basepf; /* top level input file */
406 static struct parsefile *parsefile = &basepf; /* current input file */
407 static int startlinno; /* line # where last token started */
408 static char *commandname; /* currently executing command */
409 static struct strlist *cmdenviron; /* environment for builtin command */
410 static int exitstatus; /* exit status of last command */
411 static int back_exitstatus; /* exit status of backquoted command */
414 /* ============ Message printing */
417 ash_vmsg(const char *msg, va_list ap)
419 fprintf(stderr, "%s: ", arg0);
421 const char *fmt = (!iflag || parsefile->fd) ?
423 fprintf(stderr, fmt, commandname, startlinno);
425 vfprintf(stderr, msg, ap);
426 outcslow('\n', stderr);
430 * Exverror is called to raise the error exception. If the second argument
431 * is not NULL then error prints an error message using printf style
432 * formatting. It then raises the error exception.
434 static void ash_vmsg_and_raise(int, const char *, va_list) ATTRIBUTE_NORETURN;
436 ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
440 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
442 TRACE(("\") pid=%d\n", getpid()));
444 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
449 flush_stdout_stderr();
450 raise_exception(cond);
454 static void ash_msg_and_raise_error(const char *, ...) ATTRIBUTE_NORETURN;
456 ash_msg_and_raise_error(const char *msg, ...)
461 ash_vmsg_and_raise(EXERROR, msg, ap);
466 static void ash_msg_and_raise(int, const char *, ...) ATTRIBUTE_NORETURN;
468 ash_msg_and_raise(int cond, const char *msg, ...)
473 ash_vmsg_and_raise(cond, msg, ap);
479 * error/warning routines for external builtins
482 ash_msg(const char *fmt, ...)
492 * Return a string describing an error. The returned string may be a
493 * pointer to a static buffer that will be overwritten on the next call.
494 * Action describes the operation that got the error.
497 errmsg(int e, const char *em)
499 if (e == ENOENT || e == ENOTDIR) {
506 /* ============ Unsorted yet */
509 static void setpwd(const char *, int);
514 struct strlist *next;
520 struct strlist *list;
521 struct strlist **lastp;
527 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
528 #define EXP_TILDE 0x2 /* do normal tilde expansion */
529 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
530 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
531 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
532 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
533 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
534 #define EXP_WORD 0x80 /* expand word in parameter expansion */
535 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
539 static void expandarg(union node *, struct arglist *, int);
540 #define rmescapes(p) _rmescapes((p), 0)
541 static char *_rmescapes(char *, int);
542 static int casematch(union node *, char *);
544 #if ENABLE_ASH_MATH_SUPPORT
545 static void expari(int);
552 struct backcmd { /* result of evalbackcmd */
553 int fd; /* file descriptor to read from */
554 char *buf; /* buffer */
555 int nleft; /* number of chars in buffer */
556 struct job *jp; /* job structure for command */
560 * This file was generated by the mknodes program.
595 union node *redirect;
601 struct nodelist *cmdlist;
607 union node *redirect;
620 union node *elsepart;
647 struct nodelist *backquote;
682 struct nredir nredir;
683 struct nbinary nbinary;
687 struct nclist nclist;
696 struct nodelist *next;
706 static void freefunc(struct funcnode *);
709 /* control characters in argument strings */
710 #define CTL_FIRST '\201' /* first 'special' character */
711 #define CTLESC '\201' /* escape next character */
712 #define CTLVAR '\202' /* variable defn */
713 #define CTLENDVAR '\203'
714 #define CTLBACKQ '\204'
715 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
716 /* CTLBACKQ | CTLQUOTE == '\205' */
717 #define CTLARI '\206' /* arithmetic expression */
718 #define CTLENDARI '\207'
719 #define CTLQUOTEMARK '\210'
720 #define CTL_LAST '\210' /* last 'special' character */
722 /* variable substitution byte (follows CTLVAR) */
723 #define VSTYPE 0x0f /* type of variable substitution */
724 #define VSNUL 0x10 /* colon--treat the empty string as unset */
725 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
727 /* values of VSTYPE field */
728 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
729 #define VSMINUS 0x2 /* ${var-text} */
730 #define VSPLUS 0x3 /* ${var+text} */
731 #define VSQUESTION 0x4 /* ${var?message} */
732 #define VSASSIGN 0x5 /* ${var=text} */
733 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
734 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
735 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
736 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
737 #define VSLENGTH 0xa /* ${#var} */
739 /* values of checkkwd variable */
744 #define IBUFSIZ (BUFSIZ + 1)
747 * NEOF is returned by parsecmd when it encounters an end of file. It
748 * must be distinct from NULL, so we use the address of a variable that
749 * happens to be handy.
751 static int plinno = 1; /* input line number */
753 /* number of characters left in input buffer */
754 static int parsenleft; /* copy of parsefile->nleft */
755 static int parselleft; /* copy of parsefile->lleft */
757 /* next character in input buffer */
758 static char *parsenextc; /* copy of parsefile->nextc */
760 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */
763 static int tokpushback; /* last token pushed back */
764 #define NEOF ((union node *)&tokpushback)
765 static int parsebackquote; /* nonzero if we are inside backquotes */
766 static int doprompt; /* if set, prompt the user */
767 static int needprompt; /* true if interactive and at start of line */
768 static int lasttoken; /* last token read */
769 static char *wordtext; /* text of last word returned by readtoken */
771 static struct nodelist *backquotelist;
772 static union node *redirnode;
773 static struct heredoc *heredoc;
774 static int quoteflag; /* set if (part of) last token was quoted */
776 static union node *parsecmd(int);
777 static void fixredir(union node *, const char *, int);
778 static const char *const *findkwd(const char *);
779 static char *endofname(const char *);
783 static char nullstr[1]; /* zero length string */
784 static const char spcstr[] = " ";
785 static const char snlfmt[] = "%s\n";
786 static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
787 static const char illnum[] = "Illegal number: %s";
788 static const char homestr[] = "HOME";
791 #define TRACE(param) trace param
792 #define TRACEV(param) tracev param
795 #define TRACEV(param)
798 #if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
799 #define __builtin_expect(x, expected_value) (x)
802 #define xlikely(x) __builtin_expect((x),1)
817 #define TENDBQUOTE 12
835 /* first char is indicating which tokens mark the end of a list */
836 static const char *const tokname_array[] = {
851 /* the following are keywords */
870 static const char *tokname(int tok)
876 sprintf(buf + (tok >= TSEMI), "%s%c",
877 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
884 * Most machines require the value returned from malloc to be aligned
885 * in some way. The following macro will get this right on many machines.
888 #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
890 * It appears that grabstackstr() will barf with such alignments
891 * because stalloc() will return a string allocated in a new stackblock.
893 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
896 * This file was generated by the mksyntax program.
901 #define CWORD 0 /* character is nothing special */
902 #define CNL 1 /* newline character */
903 #define CBACK 2 /* a backslash character */
904 #define CSQUOTE 3 /* single quote */
905 #define CDQUOTE 4 /* double quote */
906 #define CENDQUOTE 5 /* a terminating quote */
907 #define CBQUOTE 6 /* backwards single quote */
908 #define CVAR 7 /* a dollar sign */
909 #define CENDVAR 8 /* a '}' character */
910 #define CLP 9 /* a left paren in arithmetic */
911 #define CRP 10 /* a right paren in arithmetic */
912 #define CENDFILE 11 /* end of file */
913 #define CCTL 12 /* like CWORD, except it must be escaped */
914 #define CSPCL 13 /* these terminate a word */
915 #define CIGN 14 /* character should be ignored */
921 #define PEOA_OR_PEOF PEOA
925 #define PEOA_OR_PEOF PEOF
928 #define is_digit(c) ((unsigned)((c) - '0') <= 9)
929 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
930 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
932 /* C99 say: "char" declaration may be signed or unsigned default */
933 #define SC2INT(chr2may_be_negative_int) (int)((signed char)chr2may_be_negative_int)
936 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
937 * (assuming ascii char codes, as the original implementation did)
939 #define is_special(c) \
940 ( (((unsigned int)c) - 33 < 32) \
941 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
943 #define digit_val(c) ((c) - '0')
946 * This file was generated by the mksyntax program.
949 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
950 #define USE_SIT_FUNCTION
953 /* number syntax index */
954 #define BASESYNTAX 0 /* not in quotes */
955 #define DQSYNTAX 1 /* in double quotes */
956 #define SQSYNTAX 2 /* in single quotes */
957 #define ARISYNTAX 3 /* in arithmetic */
959 #if ENABLE_ASH_MATH_SUPPORT
960 static const char S_I_T[][4] = {
962 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
964 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
965 {CNL, CNL, CNL, CNL}, /* 2, \n */
966 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
967 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
968 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
969 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
970 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
971 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
972 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
973 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
974 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
975 #ifndef USE_SIT_FUNCTION
976 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
977 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
978 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
982 static const char S_I_T[][3] = {
984 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
986 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
987 {CNL, CNL, CNL}, /* 2, \n */
988 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
989 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
990 {CVAR, CVAR, CWORD}, /* 5, $ */
991 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
992 {CSPCL, CWORD, CWORD}, /* 7, ( */
993 {CSPCL, CWORD, CWORD}, /* 8, ) */
994 {CBACK, CBACK, CCTL}, /* 9, \ */
995 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
996 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
997 #ifndef USE_SIT_FUNCTION
998 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
999 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
1000 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
1003 #endif /* ASH_MATH_SUPPORT */
1005 #ifdef USE_SIT_FUNCTION
1007 #define U_C(c) ((unsigned char)(c))
1009 static int SIT(int c, int syntax)
1011 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
1012 #if ENABLE_ASH_ALIAS
1013 static const char syntax_index_table[] = {
1014 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
1015 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
1016 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
1020 static const char syntax_index_table[] = {
1021 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
1022 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
1023 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
1030 if (c == PEOF) /* 2^8+2 */
1032 #if ENABLE_ASH_ALIAS
1033 if (c == PEOA) /* 2^8+1 */
1037 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
1040 s = strchr(spec_symbls, c);
1041 if (s == NULL || *s == '\0')
1043 indx = syntax_index_table[(s - spec_symbls)];
1045 return S_I_T[indx][syntax];
1048 #else /* USE_SIT_FUNCTION */
1050 #define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
1052 #if ENABLE_ASH_ALIAS
1053 #define CSPCL_CIGN_CIGN_CIGN 0
1054 #define CSPCL_CWORD_CWORD_CWORD 1
1055 #define CNL_CNL_CNL_CNL 2
1056 #define CWORD_CCTL_CCTL_CWORD 3
1057 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
1058 #define CVAR_CVAR_CWORD_CVAR 5
1059 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
1060 #define CSPCL_CWORD_CWORD_CLP 7
1061 #define CSPCL_CWORD_CWORD_CRP 8
1062 #define CBACK_CBACK_CCTL_CBACK 9
1063 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
1064 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
1065 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
1066 #define CWORD_CWORD_CWORD_CWORD 13
1067 #define CCTL_CCTL_CCTL_CCTL 14
1069 #define CSPCL_CWORD_CWORD_CWORD 0
1070 #define CNL_CNL_CNL_CNL 1
1071 #define CWORD_CCTL_CCTL_CWORD 2
1072 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
1073 #define CVAR_CVAR_CWORD_CVAR 4
1074 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
1075 #define CSPCL_CWORD_CWORD_CLP 6
1076 #define CSPCL_CWORD_CWORD_CRP 7
1077 #define CBACK_CBACK_CCTL_CBACK 8
1078 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
1079 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
1080 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
1081 #define CWORD_CWORD_CWORD_CWORD 12
1082 #define CCTL_CCTL_CCTL_CCTL 13
1085 static const char syntax_index_table[258] = {
1086 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
1087 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
1088 #if ENABLE_ASH_ALIAS
1089 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
1091 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
1092 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
1093 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
1094 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
1095 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
1096 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
1097 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
1098 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
1099 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
1100 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
1101 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
1102 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
1103 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
1104 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
1105 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
1106 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
1107 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
1108 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
1109 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
1110 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
1111 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
1112 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
1113 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
1114 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
1115 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
1116 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
1117 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
1118 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
1119 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
1120 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
1121 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
1122 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
1123 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
1124 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
1125 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
1126 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
1127 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
1128 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
1129 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
1130 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
1131 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
1132 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
1133 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
1134 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
1135 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
1136 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
1137 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
1138 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
1139 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
1140 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
1141 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
1142 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
1143 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
1144 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
1145 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
1146 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
1147 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
1148 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
1149 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
1150 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
1151 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
1152 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
1153 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
1154 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
1155 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
1156 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
1157 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
1158 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
1159 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
1160 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
1161 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
1162 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
1163 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
1164 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
1165 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
1166 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
1167 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
1168 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
1169 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
1170 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
1171 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
1172 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
1173 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
1174 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
1175 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
1176 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
1177 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
1178 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
1179 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
1180 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
1181 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
1182 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
1183 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
1184 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
1185 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
1186 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
1187 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
1188 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
1189 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
1190 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
1191 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
1192 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
1193 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
1194 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
1195 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
1196 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
1197 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
1198 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
1199 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
1200 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
1201 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
1202 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
1203 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
1204 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1205 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1206 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1207 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1208 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1209 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1210 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1211 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1212 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1213 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1214 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1215 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1216 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1217 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1218 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1219 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1220 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1221 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1222 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1223 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1224 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1225 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1226 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1227 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1228 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1229 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1230 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1231 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1232 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1233 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1234 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1235 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1236 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1237 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1238 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1239 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1240 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1241 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1242 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1243 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1244 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1245 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1246 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1247 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1248 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1249 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1250 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1251 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1252 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
1253 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
1254 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1255 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1256 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1257 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
1258 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
1259 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1260 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1261 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1262 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1263 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1264 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1265 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1266 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1267 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1268 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1269 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1270 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1271 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1272 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1273 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1274 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1275 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1276 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1277 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1278 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1279 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1280 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1281 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1282 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1283 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1284 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1285 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1286 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1287 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1288 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1289 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1290 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1291 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1292 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1293 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1294 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1295 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1296 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1297 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1298 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1299 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1300 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1301 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1302 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1303 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1304 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1305 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1306 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1307 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1308 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1309 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1310 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1311 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1312 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1313 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1314 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1315 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1316 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1317 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1318 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1319 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1320 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1321 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1322 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1323 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1324 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1325 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1326 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1327 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1328 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1329 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1330 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1331 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1332 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1333 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1334 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1335 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1336 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1337 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1338 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1339 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1340 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1341 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1342 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1343 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1344 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1345 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1346 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
1349 #endif /* USE_SIT_FUNCTION */
1356 static int funcblocksize; /* size of structures in function */
1357 static int funcstringsize; /* size of strings in node */
1358 static void *funcblock; /* block to allocate function from */
1359 static char *funcstring; /* block to allocate strings from */
1361 static const short nodesize[26] = {
1362 SHELL_ALIGN(sizeof(struct ncmd)),
1363 SHELL_ALIGN(sizeof(struct npipe)),
1364 SHELL_ALIGN(sizeof(struct nredir)),
1365 SHELL_ALIGN(sizeof(struct nredir)),
1366 SHELL_ALIGN(sizeof(struct nredir)),
1367 SHELL_ALIGN(sizeof(struct nbinary)),
1368 SHELL_ALIGN(sizeof(struct nbinary)),
1369 SHELL_ALIGN(sizeof(struct nbinary)),
1370 SHELL_ALIGN(sizeof(struct nif)),
1371 SHELL_ALIGN(sizeof(struct nbinary)),
1372 SHELL_ALIGN(sizeof(struct nbinary)),
1373 SHELL_ALIGN(sizeof(struct nfor)),
1374 SHELL_ALIGN(sizeof(struct ncase)),
1375 SHELL_ALIGN(sizeof(struct nclist)),
1376 SHELL_ALIGN(sizeof(struct narg)),
1377 SHELL_ALIGN(sizeof(struct narg)),
1378 SHELL_ALIGN(sizeof(struct nfile)),
1379 SHELL_ALIGN(sizeof(struct nfile)),
1380 SHELL_ALIGN(sizeof(struct nfile)),
1381 SHELL_ALIGN(sizeof(struct nfile)),
1382 SHELL_ALIGN(sizeof(struct nfile)),
1383 SHELL_ALIGN(sizeof(struct ndup)),
1384 SHELL_ALIGN(sizeof(struct ndup)),
1385 SHELL_ALIGN(sizeof(struct nhere)),
1386 SHELL_ALIGN(sizeof(struct nhere)),
1387 SHELL_ALIGN(sizeof(struct nnot)),
1391 static void calcsize(union node *);
1392 static void sizenodelist(struct nodelist *);
1393 static union node *copynode(union node *);
1394 static struct nodelist *copynodelist(struct nodelist *);
1395 static char *nodesavestr(char *);
1398 static int evalstring(char *, int mask);
1399 union node; /* BLETCH for ansi C */
1400 static void evaltree(union node *, int);
1401 static void evalbackcmd(union node *, struct backcmd *);
1403 static int evalskip; /* set if we are skipping commands */
1404 static int skipcount; /* number of levels to skip */
1405 static int funcnest; /* depth of function calls */
1407 /* reasons for skipping commands (see comment on breakcmd routine) */
1408 #define SKIPBREAK (1 << 0)
1409 #define SKIPCONT (1 << 1)
1410 #define SKIPFUNC (1 << 2)
1411 #define SKIPFILE (1 << 3)
1412 #define SKIPEVAL (1 << 4)
1415 * This file was generated by the mkbuiltins program.
1419 static int bgcmd(int, char **);
1421 static int breakcmd(int, char **);
1422 static int cdcmd(int, char **);
1423 #if ENABLE_ASH_CMDCMD
1424 static int commandcmd(int, char **);
1426 static int dotcmd(int, char **);
1427 static int evalcmd(int, char **);
1428 #if ENABLE_ASH_BUILTIN_ECHO
1429 static int echocmd(int, char **);
1431 #if ENABLE_ASH_BUILTIN_TEST
1432 static int testcmd(int, char **);
1434 static int execcmd(int, char **);
1435 static int exitcmd(int, char **);
1436 static int exportcmd(int, char **);
1437 static int falsecmd(int, char **);
1439 static int fgcmd(int, char **);
1441 #if ENABLE_ASH_GETOPTS
1442 static int getoptscmd(int, char **);
1444 static int hashcmd(int, char **);
1445 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
1446 static int helpcmd(int argc, char **argv);
1449 static int jobscmd(int, char **);
1451 #if ENABLE_ASH_MATH_SUPPORT
1452 static int letcmd(int, char **);
1454 static int localcmd(int, char **);
1455 static int pwdcmd(int, char **);
1456 static int readcmd(int, char **);
1457 static int returncmd(int, char **);
1458 static int setcmd(int, char **);
1459 static int shiftcmd(int, char **);
1460 static int timescmd(int, char **);
1461 static int trapcmd(int, char **);
1462 static int truecmd(int, char **);
1463 static int typecmd(int, char **);
1464 static int umaskcmd(int, char **);
1465 static int unsetcmd(int, char **);
1466 static int waitcmd(int, char **);
1467 static int ulimitcmd(int, char **);
1469 static int killcmd(int, char **);
1475 static void chkmail(void);
1476 static void changemail(const char *);
1481 /* values of cmdtype */
1482 #define CMDUNKNOWN -1 /* no entry in table for command */
1483 #define CMDNORMAL 0 /* command is an executable program */
1484 #define CMDFUNCTION 1 /* command is a shell function */
1485 #define CMDBUILTIN 2 /* command is a shell builtin */
1489 int (*builtin)(int, char **);
1490 /* unsigned flags; */
1494 #define COMMANDCMD (builtincmd + 5 + \
1495 2 * ENABLE_ASH_BUILTIN_TEST + \
1496 ENABLE_ASH_ALIAS + \
1497 ENABLE_ASH_JOB_CONTROL)
1498 #define EXECCMD (builtincmd + 7 + \
1499 2 * ENABLE_ASH_BUILTIN_TEST + \
1500 ENABLE_ASH_ALIAS + \
1501 ENABLE_ASH_JOB_CONTROL + \
1502 ENABLE_ASH_CMDCMD + \
1503 ENABLE_ASH_BUILTIN_ECHO)
1505 #define BUILTIN_NOSPEC "0"
1506 #define BUILTIN_SPECIAL "1"
1507 #define BUILTIN_REGULAR "2"
1508 #define BUILTIN_SPEC_REG "3"
1509 #define BUILTIN_ASSIGN "4"
1510 #define BUILTIN_SPEC_ASSG "5"
1511 #define BUILTIN_REG_ASSG "6"
1512 #define BUILTIN_SPEC_REG_ASSG "7"
1514 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1515 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1516 #define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1518 /* make sure to keep these in proper order since it is searched via bsearch() */
1519 static const struct builtincmd builtincmd[] = {
1520 { BUILTIN_SPEC_REG ".", dotcmd },
1521 { BUILTIN_SPEC_REG ":", truecmd },
1522 #if ENABLE_ASH_BUILTIN_TEST
1523 { BUILTIN_REGULAR "[", testcmd },
1524 { BUILTIN_REGULAR "[[", testcmd },
1526 #if ENABLE_ASH_ALIAS
1527 { BUILTIN_REG_ASSG "alias", aliascmd },
1530 { BUILTIN_REGULAR "bg", bgcmd },
1532 { BUILTIN_SPEC_REG "break", breakcmd },
1533 { BUILTIN_REGULAR "cd", cdcmd },
1534 { BUILTIN_NOSPEC "chdir", cdcmd },
1535 #if ENABLE_ASH_CMDCMD
1536 { BUILTIN_REGULAR "command", commandcmd },
1538 { BUILTIN_SPEC_REG "continue", breakcmd },
1539 #if ENABLE_ASH_BUILTIN_ECHO
1540 { BUILTIN_REGULAR "echo", echocmd },
1542 { BUILTIN_SPEC_REG "eval", evalcmd },
1543 { BUILTIN_SPEC_REG "exec", execcmd },
1544 { BUILTIN_SPEC_REG "exit", exitcmd },
1545 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1546 { BUILTIN_REGULAR "false", falsecmd },
1548 { BUILTIN_REGULAR "fg", fgcmd },
1550 #if ENABLE_ASH_GETOPTS
1551 { BUILTIN_REGULAR "getopts", getoptscmd },
1553 { BUILTIN_NOSPEC "hash", hashcmd },
1554 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
1555 { BUILTIN_NOSPEC "help", helpcmd },
1558 { BUILTIN_REGULAR "jobs", jobscmd },
1559 { BUILTIN_REGULAR "kill", killcmd },
1561 #if ENABLE_ASH_MATH_SUPPORT
1562 { BUILTIN_NOSPEC "let", letcmd },
1564 { BUILTIN_ASSIGN "local", localcmd },
1565 { BUILTIN_NOSPEC "pwd", pwdcmd },
1566 { BUILTIN_REGULAR "read", readcmd },
1567 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1568 { BUILTIN_SPEC_REG "return", returncmd },
1569 { BUILTIN_SPEC_REG "set", setcmd },
1570 { BUILTIN_SPEC_REG "shift", shiftcmd },
1571 { BUILTIN_SPEC_REG "source", dotcmd },
1572 #if ENABLE_ASH_BUILTIN_TEST
1573 { BUILTIN_REGULAR "test", testcmd },
1575 { BUILTIN_SPEC_REG "times", timescmd },
1576 { BUILTIN_SPEC_REG "trap", trapcmd },
1577 { BUILTIN_REGULAR "true", truecmd },
1578 { BUILTIN_NOSPEC "type", typecmd },
1579 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1580 { BUILTIN_REGULAR "umask", umaskcmd },
1581 #if ENABLE_ASH_ALIAS
1582 { BUILTIN_REGULAR "unalias", unaliascmd },
1584 { BUILTIN_SPEC_REG "unset", unsetcmd },
1585 { BUILTIN_REGULAR "wait", waitcmd },
1588 #define NUMBUILTINS (sizeof(builtincmd) / sizeof(builtincmd[0]))
1595 const struct builtincmd *cmd;
1596 struct funcnode *func;
1601 /* action to find_command() */
1602 #define DO_ERR 0x01 /* prints errors */
1603 #define DO_ABS 0x02 /* checks absolute paths */
1604 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1605 #define DO_ALTPATH 0x08 /* using alternate path */
1606 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1608 static const char *pathopt; /* set by padvance */
1610 static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
1611 static char *padvance(const char **, const char *);
1612 static void find_command(char *, struct cmdentry *, int, const char *);
1613 static struct builtincmd *find_builtin(const char *);
1614 static void hashcd(void);
1615 static void changepath(const char *);
1616 static void defun(char *, union node *);
1617 static void unsetfunc(const char *);
1619 #if ENABLE_ASH_MATH_SUPPORT_64
1620 typedef int64_t arith_t;
1621 #define arith_t_type (long long)
1623 typedef long arith_t;
1624 #define arith_t_type (long)
1627 #if ENABLE_ASH_MATH_SUPPORT
1628 static arith_t dash_arith(const char *);
1629 static arith_t arith(const char *expr, int *perrcode);
1632 #if ENABLE_ASH_RANDOM_SUPPORT
1633 static unsigned long rseed;
1634 static void change_random(const char *);
1635 # ifndef DYNAMIC_VAR
1636 # define DYNAMIC_VAR
1642 static void reset(void);
1651 #define VEXPORT 0x01 /* variable is exported */
1652 #define VREADONLY 0x02 /* variable cannot be modified */
1653 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1654 #define VTEXTFIXED 0x08 /* text is statically allocated */
1655 #define VSTACK 0x10 /* text is allocated on the stack */
1656 #define VUNSET 0x20 /* the variable is not set */
1657 #define VNOFUNC 0x40 /* don't call the callback function */
1658 #define VNOSET 0x80 /* do not set variable - just readonly test */
1659 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1661 # define VDYNAMIC 0x200 /* dynamic variable */
1667 struct var *next; /* next entry in hash list */
1668 int flags; /* flags are defined above */
1669 const char *text; /* name=value */
1670 void (*func)(const char *); /* function to be called when */
1671 /* the variable gets set/unset */
1675 struct localvar *next; /* next local variable in list */
1676 struct var *vp; /* the variable that was made local */
1677 int flags; /* saved flags */
1678 const char *text; /* saved text */
1682 static struct localvar *localvars;
1688 #if ENABLE_ASH_GETOPTS
1689 static void getoptsreset(const char *);
1692 #if ENABLE_LOCALE_SUPPORT
1693 static void change_lc_all(const char *value);
1694 static void change_lc_ctype(const char *value);
1700 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1702 static const char defifsvar[] = "IFS= \t\n";
1703 #define defifs (defifsvar + 4)
1705 static const char defifs[] = " \t\n";
1709 static struct var varinit[] = {
1711 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1713 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1717 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1718 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1721 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1722 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1723 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1724 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1725 #if ENABLE_ASH_GETOPTS
1726 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1728 #if ENABLE_ASH_RANDOM_SUPPORT
1729 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1731 #if ENABLE_LOCALE_SUPPORT
1732 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1733 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
1735 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
1736 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
1740 #define vifs varinit[0]
1742 #define vmail (&vifs)[1]
1743 #define vmpath (&vmail)[1]
1747 #define vpath (&vmpath)[1]
1748 #define vps1 (&vpath)[1]
1749 #define vps2 (&vps1)[1]
1750 #define vps4 (&vps2)[1]
1751 #define voptind (&vps4)[1]
1752 #if ENABLE_ASH_GETOPTS
1753 #define vrandom (&voptind)[1]
1755 #define vrandom (&vps4)[1]
1757 #define defpath (defpathvar + 5)
1760 * The following macros access the values of the above variables.
1761 * They have to skip over the name. They return the null string
1762 * for unset variables.
1765 #define ifsval() (vifs.text + 4)
1766 #define ifsset() ((vifs.flags & VUNSET) == 0)
1767 #define mailval() (vmail.text + 5)
1768 #define mpathval() (vmpath.text + 9)
1769 #define pathval() (vpath.text + 5)
1770 #define ps1val() (vps1.text + 4)
1771 #define ps2val() (vps2.text + 4)
1772 #define ps4val() (vps4.text + 4)
1773 #define optindval() (voptind.text + 7)
1775 #define mpathset() ((vmpath.flags & VUNSET) == 0)
1777 static void setvar(const char *, const char *, int);
1778 static void setvareq(char *, int);
1779 static void listsetvar(struct strlist *, int);
1780 static char *lookupvar(const char *);
1781 static char *bltinlookup(const char *);
1782 static char **listvars(int, int, char ***);
1783 #define environment() listvars(VEXPORT, VUNSET, 0)
1784 static int showvars(const char *, int, int);
1785 static void poplocalvars(void);
1786 static int unsetvar(const char *);
1787 #if ENABLE_ASH_GETOPTS
1788 static int setvarsafe(const char *, const char *, int);
1790 static int varcmp(const char *, const char *);
1791 static struct var **hashvar(const char *);
1794 static int varequal(const char *a, const char *b)
1796 return !varcmp(a, b);
1800 static int loopnest; /* current loop nesting level */
1803 * The parsefile structure pointed to by the global variable parsefile
1804 * contains information about the current file being read.
1809 struct redirtab *next;
1814 static struct redirtab *redirlist;
1815 static int nullredirs;
1817 extern char **environ;
1820 static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1824 * Initialization code.
1828 * This routine initializes the builtin variables.
1831 static void initvar(void)
1838 * PS1 depends on uid
1840 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1841 vps1.text = "PS1=\\w \\$ ";
1844 vps1.text = "PS1=# ";
1847 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1849 vpp = hashvar(vp->text);
1852 } while (++vp < end);
1855 /* PEOF (the end of file marker) */
1858 INPUT_PUSH_FILE = 1,
1859 INPUT_NOFILE_OK = 2,
1863 * The input line number. Input.c just defines this variable, and saves
1864 * and restores it when files are pushed and popped. The user of this
1865 * package must set its value.
1868 static int pgetc(void);
1869 static int pgetc2(void);
1870 static int preadbuffer(void);
1871 static void pungetc(void);
1872 static void pushstring(char *, void *);
1873 static void popstring(void);
1874 static void setinputfd(int, int);
1875 static void setinputstring(char *);
1876 static void popfile(void);
1877 static void popallfiles(void);
1878 static void closescript(void);
1884 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1887 #define FORK_NOJOB 2
1889 /* mode flags for showjob(s) */
1890 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1891 #define SHOW_PID 0x04 /* include process pid */
1892 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1896 * A job structure contains information about a job. A job is either a
1897 * single process or a set of processes contained in a pipeline. In the
1898 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1903 pid_t pid; /* process id */
1904 int status; /* last process status from wait() */
1905 char *cmd; /* text of command being run */
1909 struct procstat ps0; /* status of process */
1910 struct procstat *ps; /* status or processes when more than one */
1912 int stopstatus; /* status of a stopped job */
1915 nprocs: 16, /* number of processes */
1917 #define JOBRUNNING 0 /* at least one proc running */
1918 #define JOBSTOPPED 1 /* all procs are stopped */
1919 #define JOBDONE 2 /* all procs are completed */
1921 sigint: 1, /* job was killed by SIGINT */
1922 jobctl: 1, /* job running under job control */
1924 waited: 1, /* true if this entry has been waited for */
1925 used: 1, /* true if this entry is in used */
1926 changed: 1; /* true if status has changed */
1927 struct job *prev_job; /* previous job */
1930 static pid_t backgndpid; /* pid of last background process */
1931 static int job_warning; /* user was warned about stopped jobs */
1933 static int jobctl; /* true if doing job control */
1936 static struct job *makejob(union node *, int);
1937 static int forkshell(struct job *, union node *, int);
1938 static int waitforjob(struct job *);
1939 static int stoppedjobs(void);
1942 #define setjobctl(on) /* do nothing */
1944 static void setjobctl(int);
1945 static void showjobs(FILE *, int);
1951 static void readcmdfile(char *);
1957 struct stack_block *stackp;
1960 struct stackmark *marknext;
1963 /* minimum size of a block */
1964 #define MINSIZE SHELL_ALIGN(504)
1966 struct stack_block {
1967 struct stack_block *prev;
1968 char space[MINSIZE];
1971 static struct stack_block stackbase;
1972 static struct stack_block *stackp = &stackbase;
1973 static struct stackmark *markp;
1974 static char *stacknxt = stackbase.space;
1975 static size_t stacknleft = MINSIZE;
1976 static char *sstrend = stackbase.space + MINSIZE;
1977 static int herefd = -1;
1980 static void *ckmalloc(size_t);
1981 static void *ckrealloc(void *, size_t);
1982 static char *savestr(const char *);
1983 static void *stalloc(size_t);
1984 static void stunalloc(void *);
1985 static void setstackmark(struct stackmark *);
1986 static void popstackmark(struct stackmark *);
1987 static void growstackblock(void);
1988 static void *growstackstr(void);
1989 static char *makestrspace(size_t, char *);
1990 static char *stnputs(const char *, size_t, char *);
1991 static char *stputs(const char *, char *);
1994 static char *_STPUTC(int c, char *p)
2002 #define stackblock() ((void *)stacknxt)
2003 #define stackblocksize() stacknleft
2004 #define STARTSTACKSTR(p) ((p) = stackblock())
2005 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
2006 #define CHECKSTRSPACE(n, p) \
2010 size_t m = sstrend - q; \
2012 (p) = makestrspace(l, q); \
2015 #define USTPUTC(c, p) (*p++ = (c))
2016 #define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
2017 #define STUNPUTC(p) (--p)
2018 #define STTOPC(p) p[-1]
2019 #define STADJUST(amount, p) (p += (amount))
2021 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
2022 #define ungrabstackstr(s, p) stunalloc((s))
2023 #define stackstrend() ((void *)sstrend)
2028 #define DOLATSTRLEN 4
2030 static char *prefix(const char *, const char *);
2031 static int number(const char *);
2032 static int is_number(const char *);
2033 static char *single_quote(const char *);
2034 static char *sstrdup(const char *);
2036 #define equal(s1, s2) (strcmp(s1, s2) == 0)
2037 #define scopy(s1, s2) ((void)strcpy(s2, s1))
2042 int nparam; /* # of positional parameters (without $0) */
2043 unsigned char malloc; /* if parameter list dynamically allocated */
2044 char **p; /* parameter list */
2045 #if ENABLE_ASH_GETOPTS
2046 int optind; /* next parameter to be processed by getopts */
2047 int optoff; /* used by getopts */
2052 static struct shparam shellparam; /* $@ current positional parameters */
2053 static char **argptr; /* argument list for builtin commands */
2054 static char *optionarg; /* set by nextopt (like getopt) */
2055 static char *optptr; /* used by nextopt */
2057 static char *minusc; /* argument to -c option */
2060 static void optschanged(void);
2061 static void setparam(char **);
2062 static void freeparam(volatile struct shparam *);
2063 static int shiftcmd(int, char **);
2064 static int setcmd(int, char **);
2065 static int nextopt(const char *);
2069 /* flags passed to redirect */
2070 #define REDIR_PUSH 01 /* save previous values of file descriptors */
2071 #define REDIR_SAVEFD2 03 /* set preverrout */
2074 static void redirect(union node *, int);
2075 static void popredir(int);
2076 static void clearredir(int);
2077 static int copyfd(int, int);
2078 static int redirectsafe(union node *, int);
2084 static void showtree(union node *);
2085 static void trace(const char *, ...);
2086 static void tracev(const char *, va_list);
2087 static void trargs(char **);
2088 static void trputc(int);
2089 static void trputs(const char *);
2090 static void opentrace(void);
2096 static void clear_traps(void);
2097 static void setsignal(int);
2098 static void ignoresig(int);
2099 static void onsig(int);
2100 static int dotrap(void);
2101 static void setinteractive(int);
2102 static void exitshell(void) ATTRIBUTE_NORETURN;
2105 static int is_safe_applet(char *name)
2107 /* It isn't a bug to have non-existent applet here... */
2108 /* ...just a waste of space... */
2109 static const char safe_applets[][8] = {
2113 USE_CHMOD (, "chmod" )
2114 USE_CHOWN (, "chown" )
2118 USE_ECHO (, "echo" )
2119 USE_FIND (, "find" )
2120 USE_HEXDUMP(, "hexdump")
2123 USE_MKDIR (, "mkdir" )
2125 USE_SORT (, "sort" )
2126 USE_TEST (, "test" )
2127 USE_TOUCH (, "touch" )
2128 USE_XARGS (, "xargs" )
2130 int n = sizeof(safe_applets) / sizeof(safe_applets[0]);
2132 for (i = 0; i < n; i++)
2133 if (strcmp(safe_applets[i], name) == 0)
2141 * This routine is called when an error or an interrupt occurs in an
2142 * interactive shell and control is returned to the main command loop.
2152 parselleft = parsenleft = 0; /* clear input buffer */
2155 /* from parser.c: */
2163 #if ENABLE_ASH_ALIAS
2164 static struct alias *atab[ATABSIZE];
2166 static void setalias(const char *, const char *);
2167 static struct alias *freealias(struct alias *);
2168 static struct alias **__lookupalias(const char *);
2171 setalias(const char *name, const char *val)
2173 struct alias *ap, **app;
2175 app = __lookupalias(name);
2179 if (!(ap->flag & ALIASINUSE)) {
2182 ap->val = savestr(val);
2183 ap->flag &= ~ALIASDEAD;
2186 ap = ckmalloc(sizeof(struct alias));
2187 ap->name = savestr(name);
2188 ap->val = savestr(val);
2197 unalias(const char *name)
2201 app = __lookupalias(name);
2205 *app = freealias(*app);
2216 struct alias *ap, **app;
2220 for (i = 0; i < ATABSIZE; i++) {
2222 for (ap = *app; ap; ap = *app) {
2223 *app = freealias(*app);
2232 static struct alias *
2233 lookupalias(const char *name, int check)
2235 struct alias *ap = *__lookupalias(name);
2237 if (check && ap && (ap->flag & ALIASINUSE))
2243 * TODO - sort output
2246 aliascmd(int argc, char **argv)
2255 for (i = 0; i < ATABSIZE; i++)
2256 for (ap = atab[i]; ap; ap = ap->next) {
2261 while ((n = *++argv) != NULL) {
2262 v = strchr(n+1, '=');
2263 if (v == NULL) { /* n+1: funny ksh stuff */
2264 ap = *__lookupalias(n);
2266 fprintf(stderr, "%s: %s not found\n", "alias", n);
2280 unaliascmd(int argc, char **argv)
2284 while ((i = nextopt("a")) != '\0') {
2290 for (i = 0; *argptr; argptr++) {
2291 if (unalias(*argptr)) {
2292 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
2300 static struct alias *
2301 freealias(struct alias *ap)
2305 if (ap->flag & ALIASINUSE) {
2306 ap->flag |= ALIASDEAD;
2318 printalias(const struct alias *ap)
2320 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2323 static struct alias **
2324 __lookupalias(const char *name) {
2325 unsigned int hashval;
2332 ch = (unsigned char)*p;
2336 ch = (unsigned char)*++p;
2338 app = &atab[hashval % ATABSIZE];
2340 for (; *app; app = &(*app)->next) {
2341 if (equal(name, (*app)->name)) {
2348 #endif /* ASH_ALIAS */
2354 * The cd and pwd commands.
2357 #define CD_PHYSICAL 1
2360 static int docd(const char *, int);
2361 static int cdopt(void);
2363 static char *curdir = nullstr; /* current working directory */
2364 static char *physdir = nullstr; /* physical working directory */
2373 while ((i = nextopt("LP"))) {
2375 flags ^= CD_PHYSICAL;
2384 cdcmd(int argc, char **argv)
2396 dest = bltinlookup(homestr);
2397 else if (LONE_DASH(dest)) {
2398 dest = bltinlookup("OLDPWD");
2420 path = bltinlookup("CDPATH");
2429 p = padvance(&path, dest);
2430 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2434 if (!docd(p, flags))
2439 ash_msg_and_raise_error("can't cd to %s", dest);
2442 if (flags & CD_PRINT)
2443 out1fmt(snlfmt, curdir);
2449 * Update curdir (the name of the current directory) in response to a
2452 static const char * updatepwd(const char *dir)
2459 cdcomppath = sstrdup(dir);
2462 if (curdir == nullstr)
2464 new = stputs(curdir, new);
2466 new = makestrspace(strlen(dir) + 2, new);
2467 lim = stackblock() + 1;
2471 if (new > lim && *lim == '/')
2476 if (dir[1] == '/' && dir[2] != '/') {
2482 p = strtok(cdcomppath, "/");
2486 if (p[1] == '.' && p[2] == '\0') {
2493 } else if (p[1] == '\0')
2497 new = stputs(p, new);
2505 return stackblock();
2510 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2511 * know that the current directory has changed.
2514 docd(const char *dest, int flags)
2516 const char *dir = 0;
2519 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2522 if (!(flags & CD_PHYSICAL)) {
2523 dir = updatepwd(dest);
2538 * Find out what the current directory is. If we already know the current
2539 * directory, this routine returns immediately.
2541 static char * getpwd(void)
2543 char *dir = getcwd(0, 0);
2544 return dir ? dir : nullstr;
2548 pwdcmd(int argc, char **argv)
2551 const char *dir = curdir;
2555 if (physdir == nullstr)
2559 out1fmt(snlfmt, dir);
2564 setpwd(const char *val, int setold)
2568 oldcur = dir = curdir;
2571 setvar("OLDPWD", oldcur, VEXPORT);
2574 if (physdir != nullstr) {
2575 if (physdir != oldcur)
2579 if (oldcur == val || !val) {
2586 if (oldcur != dir && oldcur != nullstr) {
2591 setvar("PWD", dir, VEXPORT);
2597 * Evaluate a command.
2600 /* flags in argument to evaltree */
2601 #define EV_EXIT 01 /* exit after evaluating tree */
2602 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2603 #define EV_BACKCMD 04 /* command executing within back quotes */
2606 static void evalloop(union node *, int);
2607 static void evalfor(union node *, int);
2608 static void evalcase(union node *, int);
2609 static void evalsubshell(union node *, int);
2610 static void expredir(union node *);
2611 static void evalpipe(union node *, int);
2612 static void evalcommand(union node *, int);
2613 static int evalbltin(const struct builtincmd *, int, char **);
2614 static int evalfun(struct funcnode *, int, char **, int);
2615 static void prehash(union node *);
2616 static int bltincmd(int, char **);
2619 static const struct builtincmd bltin = {
2625 * Called to reset things after an exception.
2632 evalcmd(int argc, char **argv)
2641 STARTSTACKSTR(concat);
2644 concat = stputs(p, concat);
2648 STPUTC(' ', concat);
2650 STPUTC('\0', concat);
2651 p = grabstackstr(concat);
2653 evalstring(p, ~SKIPEVAL);
2661 * Execute a command or commands contained in a string.
2664 evalstring(char *s, int mask)
2667 struct stackmark smark;
2671 setstackmark(&smark);
2674 while ((n = parsecmd(0)) != NEOF) {
2676 popstackmark(&smark);
2690 * Evaluate a parse tree. The value is left in the global variable
2694 evaltree(union node *n, int flags)
2697 void (*evalfn)(union node *, int);
2701 TRACE(("evaltree(NULL) called\n"));
2704 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2705 getpid(), n, n->type, flags));
2709 out1fmt("Node type = %d\n", n->type);
2714 evaltree(n->nnot.com, EV_TESTED);
2715 status = !exitstatus;
2718 expredir(n->nredir.redirect);
2719 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2721 evaltree(n->nredir.n, flags & EV_TESTED);
2722 status = exitstatus;
2727 evalfn = evalcommand;
2729 if (eflag && !(flags & EV_TESTED))
2741 evalfn = evalsubshell;
2753 #error NAND + 1 != NOR
2755 #if NOR + 1 != NSEMI
2756 #error NOR + 1 != NSEMI
2758 isor = n->type - NAND;
2761 (flags | ((isor >> 1) - 1)) & EV_TESTED
2763 if (!exitstatus == isor)
2775 evaltree(n->nif.test, EV_TESTED);
2778 if (exitstatus == 0) {
2781 } else if (n->nif.elsepart) {
2782 n = n->nif.elsepart;
2787 defun(n->narg.text, n->narg.next);
2791 exitstatus = status;
2795 if ((checkexit & exitstatus))
2796 evalskip |= SKIPEVAL;
2797 else if (pendingsigs && dotrap())
2800 if (flags & EV_EXIT) {
2802 raise_exception(EXEXIT);
2807 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2810 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2814 evalloop(union node *n, int flags)
2824 evaltree(n->nbinary.ch1, EV_TESTED);
2827 if (evalskip == SKIPCONT && --skipcount <= 0) {
2831 if (evalskip == SKIPBREAK && --skipcount <= 0)
2836 if (n->type != NWHILE)
2840 evaltree(n->nbinary.ch2, flags);
2841 status = exitstatus;
2846 exitstatus = status;
2851 evalfor(union node *n, int flags)
2853 struct arglist arglist;
2856 struct stackmark smark;
2858 setstackmark(&smark);
2859 arglist.lastp = &arglist.list;
2860 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
2861 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2866 *arglist.lastp = NULL;
2871 for (sp = arglist.list; sp; sp = sp->next) {
2872 setvar(n->nfor.var, sp->text, 0);
2873 evaltree(n->nfor.body, flags);
2875 if (evalskip == SKIPCONT && --skipcount <= 0) {
2879 if (evalskip == SKIPBREAK && --skipcount <= 0)
2886 popstackmark(&smark);
2891 evalcase(union node *n, int flags)
2895 struct arglist arglist;
2896 struct stackmark smark;
2898 setstackmark(&smark);
2899 arglist.lastp = &arglist.list;
2900 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2902 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
2903 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
2904 if (casematch(patp, arglist.list->text)) {
2905 if (evalskip == 0) {
2906 evaltree(cp->nclist.body, flags);
2913 popstackmark(&smark);
2918 * Kick off a subshell to evaluate a tree.
2921 evalsubshell(union node *n, int flags)
2924 int backgnd = (n->type == NBACKGND);
2927 expredir(n->nredir.redirect);
2928 if (!backgnd && flags & EV_EXIT && !trap[0])
2932 if (forkshell(jp, n, backgnd) == 0) {
2936 flags &=~ EV_TESTED;
2938 redirect(n->nredir.redirect, 0);
2939 evaltreenr(n->nredir.n, flags);
2944 status = waitforjob(jp);
2945 exitstatus = status;
2951 * Compute the names of the files in a redirection list.
2954 expredir(union node *n)
2958 for (redir = n; redir; redir = redir->nfile.next) {
2961 memset(&fn, 0, sizeof(fn));
2962 fn.lastp = &fn.list;
2963 switch (redir->type) {
2969 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2970 redir->nfile.expfname = fn.list->text;
2974 if (redir->ndup.vname) {
2975 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2976 if (fn.list == NULL)
2977 ash_msg_and_raise_error("redir error");
2978 fixredir(redir, fn.list->text, 1);
2987 * Evaluate a pipeline. All the processes in the pipeline are children
2988 * of the process creating the pipeline. (This differs from some versions
2989 * of the shell, which make the last process in a pipeline the parent
2993 evalpipe(union node *n, int flags)
2996 struct nodelist *lp;
3001 TRACE(("evalpipe(0x%lx) called\n", (long)n));
3003 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
3007 jp = makejob(n, pipelen);
3009 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
3013 if (pipe(pip) < 0) {
3015 ash_msg_and_raise_error("Pipe call failed");
3018 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3031 evaltreenr(lp->n, flags);
3039 if (n->npipe.backgnd == 0) {
3040 exitstatus = waitforjob(jp);
3041 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
3048 * Execute a command inside back quotes. If it's a builtin command, we
3049 * want to save its output in a block obtained from malloc. Otherwise
3050 * we fork off a subprocess and get the output of the command via a pipe.
3051 * Should be called with interrupts off.
3054 evalbackcmd(union node *n, struct backcmd *result)
3066 saveherefd = herefd;
3074 ash_msg_and_raise_error("Pipe call failed");
3076 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3085 evaltreenr(n, EV_EXIT);
3089 result->fd = pip[0];
3092 herefd = saveherefd;
3094 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3095 result->fd, result->buf, result->nleft, result->jp));
3098 #if ENABLE_ASH_CMDCMD
3099 static char ** parse_command_args(char **argv, const char **path)
3112 if (c == '-' && !*cp) {
3122 /* run 'typecmd' for other options */
3125 } while ((c = *cp++));
3131 static int isassignment(const char *p)
3133 const char *q = endofname(p);
3139 #if ENABLE_ASH_EXPAND_PRMT
3140 static const char *expandstr(const char *ps);
3142 #define expandstr(s) s
3146 * Execute a simple command.
3149 evalcommand(union node *cmd, int flags)
3151 struct stackmark smark;
3153 struct arglist arglist;
3154 struct arglist varlist;
3157 const struct strlist *sp;
3158 struct cmdentry cmdentry;
3166 struct builtincmd *bcmd;
3167 int pseudovarflag = 0;
3169 /* First expand the arguments. */
3170 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3171 setstackmark(&smark);
3172 back_exitstatus = 0;
3174 cmdentry.cmdtype = CMDBUILTIN;
3175 cmdentry.u.cmd = &bltin;
3176 varlist.lastp = &varlist.list;
3177 *varlist.lastp = NULL;
3178 arglist.lastp = &arglist.list;
3179 *arglist.lastp = NULL;
3182 if (cmd->ncmd.args) {
3183 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3184 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3187 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3188 struct strlist **spp;
3190 spp = arglist.lastp;
3191 if (pseudovarflag && isassignment(argp->narg.text))
3192 expandarg(argp, &arglist, EXP_VARTILDE);
3194 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3196 for (sp = *spp; sp; sp = sp->next)
3200 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
3201 for (sp = arglist.list; sp; sp = sp->next) {
3202 TRACE(("evalcommand arg: %s\n", sp->text));
3203 *nargv++ = sp->text;
3208 if (iflag && funcnest == 0 && argc > 0)
3209 lastarg = nargv[-1];
3212 expredir(cmd->ncmd.redirect);
3213 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
3216 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3217 struct strlist **spp;
3220 spp = varlist.lastp;
3221 expandarg(argp, &varlist, EXP_VARTILDE);
3224 * Modify the command lookup path, if a PATH= assignment
3228 if (varequal(p, path))
3232 /* Print the command if xflag is set. */
3235 const char *p = " %s";
3238 dprintf(preverrout_fd, p, expandstr(ps4val()));
3241 for (n = 0; n < 2; n++) {
3243 dprintf(preverrout_fd, p, sp->text);
3251 full_write(preverrout_fd, "\n", 1);
3257 /* Now locate the command. */
3259 const char *oldpath;
3260 int cmd_flag = DO_ERR;
3265 find_command(argv[0], &cmdentry, cmd_flag, path);
3266 if (cmdentry.cmdtype == CMDUNKNOWN) {
3272 /* implement bltin and command here */
3273 if (cmdentry.cmdtype != CMDBUILTIN)
3276 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3277 if (cmdentry.u.cmd == EXECCMD)
3279 #if ENABLE_ASH_CMDCMD
3280 if (cmdentry.u.cmd == COMMANDCMD) {
3283 nargv = parse_command_args(argv, &path);
3286 argc -= nargv - argv;
3288 cmd_flag |= DO_NOFUNC;
3296 /* We have a redirection error. */
3298 raise_exception(EXERROR);
3300 exitstatus = status;
3304 /* Execute the command. */
3305 switch (cmdentry.cmdtype) {
3307 /* Fork off a child process if necessary. */
3308 if (!(flags & EV_EXIT) || trap[0]) {
3310 jp = makejob(cmd, 1);
3311 if (forkshell(jp, cmd, FORK_FG) != 0) {
3312 exitstatus = waitforjob(jp);
3318 listsetvar(varlist.list, VEXPORT|VSTACK);
3319 shellexec(argv, path, cmdentry.u.index);
3323 cmdenviron = varlist.list;
3325 struct strlist *list = cmdenviron;
3327 if (spclbltin > 0 || argc == 0) {
3329 if (cmd_is_exec && argc > 1)
3332 listsetvar(list, i);
3334 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3349 exit_status = j + 128;
3350 exitstatus = exit_status;
3352 if (i == EXINT || spclbltin > 0) {
3354 longjmp(exception_handler->loc, 1);
3361 listsetvar(varlist.list, 0);
3362 if (evalfun(cmdentry.u.func, argc, argv, flags))
3368 popredir(cmd_is_exec);
3370 /* dsl: I think this is intended to be used to support
3371 * '_' in 'vi' command mode during line editing...
3372 * However I implemented that within libedit itself.
3374 setvar("_", lastarg, 0);
3375 popstackmark(&smark);
3379 evalbltin(const struct builtincmd *cmd, int argc, char **argv)
3381 char *volatile savecmdname;
3382 struct jmploc *volatile savehandler;
3383 struct jmploc jmploc;
3386 savecmdname = commandname;
3387 i = setjmp(jmploc.loc);
3390 savehandler = exception_handler;
3391 exception_handler = &jmploc;
3392 commandname = argv[0];
3394 optptr = NULL; /* initialize nextopt */
3395 exitstatus = (*cmd->builtin)(argc, argv);
3396 flush_stdout_stderr();
3398 exitstatus |= ferror(stdout);
3400 commandname = savecmdname;
3402 exception_handler = savehandler;
3408 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3410 volatile struct shparam saveparam;
3411 struct localvar *volatile savelocalvars;
3412 struct jmploc *volatile savehandler;
3413 struct jmploc jmploc;
3416 saveparam = shellparam;
3417 savelocalvars = localvars;
3418 e = setjmp(jmploc.loc);
3423 savehandler = exception_handler;
3424 exception_handler = &jmploc;
3426 shellparam.malloc = 0;
3430 shellparam.nparam = argc - 1;
3431 shellparam.p = argv + 1;
3432 #if ENABLE_ASH_GETOPTS
3433 shellparam.optind = 1;
3434 shellparam.optoff = -1;
3436 evaltree(&func->n, flags & EV_TESTED);
3442 localvars = savelocalvars;
3443 freeparam(&shellparam);
3444 shellparam = saveparam;
3445 exception_handler = savehandler;
3447 evalskip &= ~SKIPFUNC;
3452 static int goodname(const char *p)
3454 return !*endofname(p);
3459 * Search for a command. This is called before we fork so that the
3460 * location of the command will be available in the parent as well as
3461 * the child. The check for "goodname" is an overly conservative
3462 * check that the name will not be subject to expansion.
3465 prehash(union node *n)
3467 struct cmdentry entry;
3469 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
3470 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
3476 * Builtin commands. Builtin commands whose functions are closely
3477 * tied to evaluation are implemented here.
3484 bltincmd(int argc, char **argv)
3487 * Preserve exitstatus of a previous possible redirection
3490 return back_exitstatus;
3495 * Handle break and continue commands. Break, continue, and return are
3496 * all handled by setting the evalskip flag. The evaluation routines
3497 * above all check this flag, and if it is set they start skipping
3498 * commands rather than executing them. The variable skipcount is
3499 * the number of loops to break/continue, or the number of function
3500 * levels to return. (The latter is always 1.) It should probably
3501 * be an error to break out of more loops than exist, but it isn't
3502 * in the standard shell so we don't make it one here.
3506 breakcmd(int argc, char **argv)
3508 int n = argc > 1 ? number(argv[1]) : 1;
3511 ash_msg_and_raise_error(illnum, argv[1]);
3515 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3523 * The return command.
3526 returncmd(int argc, char **argv)
3529 * If called outside a function, do what ksh does;
3530 * skip the rest of the file.
3532 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
3533 return argv[1] ? number(argv[1]) : exitstatus;
3538 falsecmd(int argc, char **argv)
3545 truecmd(int argc, char **argv)
3552 execcmd(int argc, char **argv)
3555 iflag = 0; /* exit on error */
3558 shellexec(argv + 1, pathval(), 0);
3567 * When commands are first encountered, they are entered in a hash table.
3568 * This ensures that a full path search will not have to be done for them
3569 * on each invocation.
3571 * We should investigate converting to a linear search, even though that
3572 * would make the command name "hash" a misnomer.
3575 #define CMDTABLESIZE 31 /* should be prime */
3576 #define ARB 1 /* actual size determined at run time */
3580 struct tblentry *next; /* next entry in hash chain */
3581 union param param; /* definition of builtin function */
3582 short cmdtype; /* index identifying command */
3583 char rehash; /* if set, cd done since entry created */
3584 char cmdname[ARB]; /* name of command */
3588 static struct tblentry *cmdtable[CMDTABLESIZE];
3589 static int builtinloc = -1; /* index in path of %builtin, or -1 */
3592 static void tryexec(char *, char **, char **);
3593 static void clearcmdentry(int);
3594 static struct tblentry *cmdlookup(const char *, int);
3595 static void delete_cmd_entry(void);
3599 * Exec a program. Never returns. If you change this routine, you may
3600 * have to change the find_command routine as well.
3602 static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN;
3604 shellexec(char **argv, const char *path, int idx)
3612 envp = environment();
3613 if (strchr(argv[0], '/') || is_safe_applet(argv[0])
3614 #if ENABLE_FEATURE_SH_STANDALONE_SHELL
3615 || find_applet_by_name(argv[0])
3618 tryexec(argv[0], argv, envp);
3622 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3623 if (--idx < 0 && pathopt == NULL) {
3624 tryexec(cmdname, argv, envp);
3625 if (errno != ENOENT && errno != ENOTDIR)
3632 /* Map to POSIX errors */
3644 exitstatus = exerrno;
3645 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3646 argv[0], e, suppressint ));
3647 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
3653 tryexec(char *cmd, char **argv, char **envp)
3656 struct BB_applet *a;
3660 if (strchr(cmd, '/') == NULL
3661 && (a = find_applet_by_name(cmd)) != NULL
3662 && is_safe_applet(cmd)
3665 while (*c != NULL) {
3669 exit(a->main(argc, argv));
3671 #if ENABLE_FEATURE_SH_STANDALONE_SHELL
3672 if (find_applet_by_name(cmd) != NULL) {
3673 /* re-exec ourselves with the new arguments */
3674 execve(CONFIG_BUSYBOX_EXEC_PATH, argv, envp);
3675 /* If they called chroot or otherwise made the binary no longer
3676 * executable, fall through */
3683 execve(cmd, argv, envp);
3684 } while (errno == EINTR);
3686 execve(cmd, argv, envp);
3690 } else if (errno == ENOEXEC) {
3694 for (ap = argv; *ap; ap++)
3696 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3698 *ap = cmd = (char *)DEFAULT_SHELL;
3701 while ((*ap++ = *argv++))
3710 * Do a path search. The variable path (passed by reference) should be
3711 * set to the start of the path before the first call; padvance will update
3712 * this value as it proceeds. Successive calls to padvance will return
3713 * the possible path expansions in sequence. If an option (indicated by
3714 * a percent sign) appears in the path entry then the global variable
3715 * pathopt will be set to point to it; otherwise pathopt will be set to
3719 padvance(const char **path, const char *name)
3729 for (p = start; *p && *p != ':' && *p != '%'; p++);
3730 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3731 while (stackblocksize() < len)
3735 memcpy(q, start, p - start);
3743 while (*p && *p != ':') p++;
3749 return stalloc(len);
3753 /*** Command hashing code ***/
3756 printentry(struct tblentry *cmdp)
3762 idx = cmdp->param.index;
3765 name = padvance(&path, cmdp->cmdname);
3767 } while (--idx >= 0);
3768 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3773 hashcmd(int argc, char **argv)
3775 struct tblentry **pp;
3776 struct tblentry *cmdp;
3778 struct cmdentry entry;
3781 while ((c = nextopt("r")) != '\0') {
3785 if (*argptr == NULL) {
3786 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
3787 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
3788 if (cmdp->cmdtype == CMDNORMAL)
3795 while ((name = *argptr) != NULL) {
3796 cmdp = cmdlookup(name, 0);
3798 && (cmdp->cmdtype == CMDNORMAL
3799 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3801 find_command(name, &entry, DO_ERR, pathval());
3802 if (entry.cmdtype == CMDUNKNOWN)
3811 * Resolve a command name. If you change this routine, you may have to
3812 * change the shellexec routine as well.
3815 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3817 struct tblentry *cmdp;
3824 struct builtincmd *bcmd;
3826 /* If name contains a slash, don't use PATH or hash table */
3827 if (strchr(name, '/') != NULL) {
3828 entry->u.index = -1;
3830 while (stat(name, &statb) < 0) {
3835 entry->cmdtype = CMDUNKNOWN;
3839 entry->cmdtype = CMDNORMAL;
3843 #if ENABLE_FEATURE_SH_STANDALONE_SHELL
3844 if (find_applet_by_name(name)) {
3845 entry->cmdtype = CMDNORMAL;
3846 entry->u.index = -1;
3851 if (is_safe_applet(name)) {
3852 entry->cmdtype = CMDNORMAL;
3853 entry->u.index = -1;
3857 updatetbl = (path == pathval());
3860 if (strstr(path, "%builtin") != NULL)
3864 /* If name is in the table, check answer will be ok */
3865 cmdp = cmdlookup(name, 0);
3869 switch (cmdp->cmdtype) {
3887 } else if (cmdp->rehash == 0)
3888 /* if not invalidated by cd, we're done */
3892 /* If %builtin not in path, check for builtin next */
3893 bcmd = find_builtin(name);
3894 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3895 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3897 goto builtin_success;
3899 /* We have to search path. */
3900 prev = -1; /* where to start */
3901 if (cmdp && cmdp->rehash) { /* doing a rehash */
3902 if (cmdp->cmdtype == CMDBUILTIN)
3905 prev = cmdp->param.index;
3911 while ((fullname = padvance(&path, name)) != NULL) {
3912 stunalloc(fullname);
3915 if (prefix(pathopt, "builtin")) {
3917 goto builtin_success;
3919 } else if (!(act & DO_NOFUNC) &&
3920 prefix(pathopt, "func")) {
3923 /* ignore unimplemented options */
3927 /* if rehash, don't redo absolute path names */
3928 if (fullname[0] == '/' && idx <= prev) {
3931 TRACE(("searchexec \"%s\": no change\n", name));
3934 while (stat(fullname, &statb) < 0) {
3939 if (errno != ENOENT && errno != ENOTDIR)
3943 e = EACCES; /* if we fail, this will be the error */
3944 if (!S_ISREG(statb.st_mode))
3946 if (pathopt) { /* this is a %func directory */
3947 stalloc(strlen(fullname) + 1);
3948 readcmdfile(fullname);
3949 cmdp = cmdlookup(name, 0);
3950 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
3951 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
3952 stunalloc(fullname);
3955 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3957 entry->cmdtype = CMDNORMAL;
3958 entry->u.index = idx;
3962 cmdp = cmdlookup(name, 1);
3963 cmdp->cmdtype = CMDNORMAL;
3964 cmdp->param.index = idx;
3969 /* We failed. If there was an entry for this command, delete it */
3970 if (cmdp && updatetbl)
3973 ash_msg("%s: %s", name, errmsg(e, "not found"));
3974 entry->cmdtype = CMDUNKNOWN;
3979 entry->cmdtype = CMDBUILTIN;
3980 entry->u.cmd = bcmd;
3984 cmdp = cmdlookup(name, 1);
3985 cmdp->cmdtype = CMDBUILTIN;
3986 cmdp->param.cmd = bcmd;
3990 entry->cmdtype = cmdp->cmdtype;
3991 entry->u = cmdp->param;
3996 * Wrapper around strcmp for qsort/bsearch/...
3998 static int pstrcmp(const void *a, const void *b)
4000 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4005 * Search the table of builtin commands.
4007 static struct builtincmd *
4008 find_builtin(const char *name)
4010 struct builtincmd *bp;
4013 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4021 * Called when a cd is done. Marks all commands so the next time they
4022 * are executed they will be rehashed.
4027 struct tblentry **pp;
4028 struct tblentry *cmdp;
4030 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
4031 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
4032 if (cmdp->cmdtype == CMDNORMAL || (
4033 cmdp->cmdtype == CMDBUILTIN &&
4034 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4044 * Fix command hash table when PATH changed.
4045 * Called before PATH is changed. The argument is the new value of PATH;
4046 * pathval() still returns the old value at this point.
4047 * Called with interrupts off.
4050 changepath(const char *newval)
4052 const char *old, *new;
4059 firstchange = 9999; /* assume no change */
4065 if ((*old == '\0' && *new == ':')
4066 || (*old == ':' && *new == '\0'))
4068 old = new; /* ignore subsequent differences */
4072 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4079 if (builtinloc < 0 && idx_bltin >= 0)
4080 builtinloc = idx_bltin; /* zap builtins */
4081 if (builtinloc >= 0 && idx_bltin < 0)
4083 clearcmdentry(firstchange);
4084 builtinloc = idx_bltin;
4089 * Clear out command entries. The argument specifies the first entry in
4090 * PATH which has changed.
4093 clearcmdentry(int firstchange)
4095 struct tblentry **tblp;
4096 struct tblentry **pp;
4097 struct tblentry *cmdp;
4100 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
4102 while ((cmdp = *pp) != NULL) {
4103 if ((cmdp->cmdtype == CMDNORMAL &&
4104 cmdp->param.index >= firstchange)
4105 || (cmdp->cmdtype == CMDBUILTIN &&
4106 builtinloc >= firstchange)
4120 * Locate a command in the command hash table. If "add" is nonzero,
4121 * add the command to the table if it is not already present. The
4122 * variable "lastcmdentry" is set to point to the address of the link
4123 * pointing to the entry, so that delete_cmd_entry can delete the
4126 * Interrupts must be off if called with add != 0.
4128 static struct tblentry **lastcmdentry;
4130 static struct tblentry *
4131 cmdlookup(const char *name, int add)
4133 unsigned int hashval;
4135 struct tblentry *cmdp;
4136 struct tblentry **pp;
4139 hashval = (unsigned char)*p << 4;
4141 hashval += (unsigned char)*p++;
4143 pp = &cmdtable[hashval % CMDTABLESIZE];
4144 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
4145 if (equal(cmdp->cmdname, name))
4149 if (add && cmdp == NULL) {
4150 cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB
4151 + strlen(name) + 1);
4153 cmdp->cmdtype = CMDUNKNOWN;
4154 strcpy(cmdp->cmdname, name);
4162 * Delete the command entry returned on the last lookup.
4165 delete_cmd_entry(void)
4167 struct tblentry *cmdp;
4170 cmdp = *lastcmdentry;
4171 *lastcmdentry = cmdp->next;
4172 if (cmdp->cmdtype == CMDFUNCTION)
4173 freefunc(cmdp->param.func);
4180 * Add a new command entry, replacing any existing command entry for
4181 * the same name - except special builtins.
4183 static void addcmdentry(char *name, struct cmdentry *entry)
4185 struct tblentry *cmdp;
4187 cmdp = cmdlookup(name, 1);
4188 if (cmdp->cmdtype == CMDFUNCTION) {
4189 freefunc(cmdp->param.func);
4191 cmdp->cmdtype = entry->cmdtype;
4192 cmdp->param = entry->u;
4198 * Make a copy of a parse tree.
4200 static struct funcnode * copyfunc(union node *n)
4205 funcblocksize = offsetof(struct funcnode, n);
4208 blocksize = funcblocksize;
4209 f = ckmalloc(blocksize + funcstringsize);
4210 funcblock = (char *) f + offsetof(struct funcnode, n);
4211 funcstring = (char *) f + blocksize;
4219 * Define a shell function.
4222 defun(char *name, union node *func)
4224 struct cmdentry entry;
4227 entry.cmdtype = CMDFUNCTION;
4228 entry.u.func = copyfunc(func);
4229 addcmdentry(name, &entry);
4235 * Delete a function if it exists.
4238 unsetfunc(const char *name)
4240 struct tblentry *cmdp;
4242 cmdp = cmdlookup(name, 0);
4243 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION)
4248 * Locate and print what a word is...
4250 #if ENABLE_ASH_CMDCMD
4252 describe_command(char *command, int describe_command_verbose)
4254 #define describe_command_verbose 1
4256 describe_command(char *command)
4259 struct cmdentry entry;
4260 struct tblentry *cmdp;
4261 #if ENABLE_ASH_ALIAS
4262 const struct alias *ap;
4264 const char *path = pathval();
4266 if (describe_command_verbose) {
4270 /* First look at the keywords */
4271 if (findkwd(command)) {
4272 out1str(describe_command_verbose ? " is a shell keyword" : command);
4276 #if ENABLE_ASH_ALIAS
4277 /* Then look at the aliases */
4278 ap = lookupalias(command, 0);
4280 if (describe_command_verbose) {
4281 out1fmt(" is an alias for %s", ap->val);
4290 /* Then check if it is a tracked alias */
4291 cmdp = cmdlookup(command, 0);
4293 entry.cmdtype = cmdp->cmdtype;
4294 entry.u = cmdp->param;
4296 /* Finally use brute force */
4297 find_command(command, &entry, DO_ABS, path);
4300 switch (entry.cmdtype) {
4302 int j = entry.u.index;
4308 p = padvance(&path, command);
4312 if (describe_command_verbose) {
4314 (cmdp ? " a tracked alias for" : nullstr), p
4323 if (describe_command_verbose) {
4324 out1str(" is a shell function");
4331 if (describe_command_verbose) {
4332 out1fmt(" is a %sshell builtin",
4333 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4334 "special " : nullstr
4342 if (describe_command_verbose) {
4343 out1str(": not found\n");
4348 outstr("\n", stdout);
4353 typecmd(int argc, char **argv)
4358 for (i = 1; i < argc; i++) {
4359 #if ENABLE_ASH_CMDCMD
4360 err |= describe_command(argv[i], 1);
4362 err |= describe_command(argv[i]);
4368 #if ENABLE_ASH_CMDCMD
4370 commandcmd(int argc, char **argv)
4378 while ((c = nextopt("pvV")) != '\0')
4380 verify |= VERIFY_VERBOSE;
4382 verify |= VERIFY_BRIEF;
4388 return describe_command(*argptr, verify - VERIFY_BRIEF);
4397 * Routines to expand arguments to commands. We have to deal with
4398 * backquotes, shell variables, and file metacharacters.
4404 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4405 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4406 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4407 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4408 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4411 * Structure specifying which parts of the string should be searched
4412 * for IFS characters.
4416 struct ifsregion *next; /* next region in list */
4417 int begoff; /* offset of start of region */
4418 int endoff; /* offset of end of region */
4419 int nulonly; /* search for nul bytes only */
4422 /* output of current string */
4423 static char *expdest;
4424 /* list of back quote expressions */
4425 static struct nodelist *argbackq;
4426 /* first struct in list of ifs regions */
4427 static struct ifsregion ifsfirst;
4428 /* last struct in list */
4429 static struct ifsregion *ifslastp;
4430 /* holds expanded arg list */
4431 static struct arglist exparg;
4433 static void argstr(char *, int);
4434 static char *exptilde(char *, char *, int);
4435 static void expbackq(union node *, int, int);
4436 static const char *subevalvar(char *, char *, int, int, int, int, int);
4437 static char *evalvar(char *, int);
4438 static void strtodest(const char *, int, int);
4439 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4440 static ssize_t varvalue(char *, int, int);
4441 static void recordregion(int, int, int);
4442 static void removerecordregions(int);
4443 static void ifsbreakup(char *, struct arglist *);
4444 static void ifsfree(void);
4445 static void expandmeta(struct strlist *, int);
4446 static int patmatch(char *, const char *);
4448 static int cvtnum(arith_t);
4449 static size_t esclen(const char *, const char *);
4450 static char *scanleft(char *, char *, char *, char *, int, int);
4451 static char *scanright(char *, char *, char *, char *, int, int);
4452 static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN;
4455 #define pmatch(a, b) !fnmatch((a), (b), 0)
4457 * Prepare a pattern for a expmeta (internal glob(3)) call.
4459 * Returns an stalloced string.
4462 static char * preglob(const char *pattern, int quoted, int flag)
4464 flag |= RMESCAPE_GLOB;
4466 flag |= RMESCAPE_QUOTED;
4468 return _rmescapes((char *)pattern, flag);
4473 esclen(const char *start, const char *p)
4477 while (p > start && *--p == CTLESC) {
4485 * Expand shell variables and backquotes inside a here document.
4488 static void expandhere(union node *arg, int fd)
4491 expandarg(arg, (struct arglist *)NULL, 0);
4492 full_write(fd, stackblock(), expdest - (char *)stackblock());
4497 * Perform variable substitution and command substitution on an argument,
4498 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4499 * perform splitting and file name expansion. When arglist is NULL, perform
4500 * here document expansion.
4503 expandarg(union node *arg, struct arglist *arglist, int flag)
4508 argbackq = arg->narg.backquote;
4509 STARTSTACKSTR(expdest);
4510 ifsfirst.next = NULL;
4512 argstr(arg->narg.text, flag);
4513 p = _STPUTC('\0', expdest);
4515 if (arglist == NULL) {
4516 return; /* here document expanded */
4518 p = grabstackstr(p);
4519 exparg.lastp = &exparg.list;
4523 if (flag & EXP_FULL) {
4524 ifsbreakup(p, &exparg);
4525 *exparg.lastp = NULL;
4526 exparg.lastp = &exparg.list;
4527 expandmeta(exparg.list, flag);
4529 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4531 sp = stalloc(sizeof(*sp));
4534 exparg.lastp = &sp->next;
4538 *exparg.lastp = NULL;
4540 *arglist->lastp = exparg.list;
4541 arglist->lastp = exparg.lastp;
4547 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4548 * characters to allow for further processing. Otherwise treat
4549 * $@ like $* since no splitting will be performed.
4552 argstr(char *p, int flag)
4554 static const char spclchars[] = {
4562 CTLBACKQ | CTLQUOTE,
4563 #if ENABLE_ASH_MATH_SUPPORT
4568 const char *reject = spclchars;
4570 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4571 int breakall = flag & EXP_WORD;
4576 if (!(flag & EXP_VARTILDE)) {
4578 } else if (flag & EXP_VARTILDE2) {
4583 if (flag & EXP_TILDE) {
4589 if (*q == CTLESC && (flag & EXP_QWORD))
4592 p = exptilde(p, q, flag);
4595 startloc = expdest - (char *)stackblock();
4597 length += strcspn(p + length, reject);
4599 if (c && (!(c & 0x80)
4600 #if ENABLE_ASH_MATH_SUPPORT
4604 /* c == '=' || c == ':' || c == CTLENDARI */
4609 expdest = stnputs(p, length, expdest);
4610 newloc = expdest - (char *)stackblock();
4611 if (breakall && !inquotes && newloc > startloc) {
4612 recordregion(startloc, newloc, 0);
4623 if (flag & EXP_VARTILDE2) {
4627 flag |= EXP_VARTILDE2;
4632 * sort of a hack - expand tildes in variable
4633 * assignments (after the first '=' and after ':'s).
4642 case CTLENDVAR: /* ??? */
4645 /* "$@" syntax adherence hack */
4648 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4649 (p[4] == CTLQUOTEMARK || (
4650 p[4] == CTLENDVAR &&
4651 p[5] == CTLQUOTEMARK
4654 p = evalvar(p + 1, flag) + 1;
4657 inquotes = !inquotes;
4670 p = evalvar(p, flag);
4674 case CTLBACKQ|CTLQUOTE:
4675 expbackq(argbackq->n, c, quotes);
4676 argbackq = argbackq->next;
4678 #if ENABLE_ASH_MATH_SUPPORT
4691 exptilde(char *startp, char *p, int flag)
4697 int quotes = flag & (EXP_FULL | EXP_CASE);
4702 while ((c = *++p) != '\0') {
4709 if (flag & EXP_VARTILDE)
4719 if (*name == '\0') {
4720 home = lookupvar(homestr);
4722 pw = getpwnam(name);
4727 if (!home || !*home)
4730 startloc = expdest - (char *)stackblock();
4731 strtodest(home, SQSYNTAX, quotes);
4732 recordregion(startloc, expdest - (char *)stackblock(), 0);
4741 removerecordregions(int endoff)
4743 if (ifslastp == NULL)
4746 if (ifsfirst.endoff > endoff) {
4747 while (ifsfirst.next != NULL) {
4748 struct ifsregion *ifsp;
4750 ifsp = ifsfirst.next->next;
4751 free(ifsfirst.next);
4752 ifsfirst.next = ifsp;
4755 if (ifsfirst.begoff > endoff)
4758 ifslastp = &ifsfirst;
4759 ifsfirst.endoff = endoff;
4764 ifslastp = &ifsfirst;
4765 while (ifslastp->next && ifslastp->next->begoff < endoff)
4766 ifslastp=ifslastp->next;
4767 while (ifslastp->next != NULL) {
4768 struct ifsregion *ifsp;
4770 ifsp = ifslastp->next->next;
4771 free(ifslastp->next);
4772 ifslastp->next = ifsp;
4775 if (ifslastp->endoff > endoff)
4776 ifslastp->endoff = endoff;
4780 #if ENABLE_ASH_MATH_SUPPORT
4782 * Expand arithmetic expression. Backup to start of expression,
4783 * evaluate, place result in (backed up) result, adjust string position.
4796 * This routine is slightly over-complicated for
4797 * efficiency. Next we scan backwards looking for the
4798 * start of arithmetic.
4800 start = stackblock();
4807 while (*p != CTLARI) {
4811 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
4816 esc = esclen(start, p);
4826 removerecordregions(begoff);
4835 len = cvtnum(dash_arith(p + 2));
4838 recordregion(begoff, begoff + len, 0);
4844 * Expand stuff in backwards quotes.
4847 expbackq(union node *cmd, int quoted, int quotes)
4855 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4856 struct stackmark smark;
4859 setstackmark(&smark);
4861 startloc = dest - (char *)stackblock();
4863 evalbackcmd(cmd, (struct backcmd *) &in);
4864 popstackmark(&smark);
4871 memtodest(p, i, syntax, quotes);
4875 i = safe_read(in.fd, buf, sizeof(buf));
4876 TRACE(("expbackq: read returns %d\n", i));
4886 back_exitstatus = waitforjob(in.jp);
4890 /* Eat all trailing newlines */
4892 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4897 recordregion(startloc, dest - (char *)stackblock(), 0);
4898 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4899 (dest - (char *)stackblock()) - startloc,
4900 (dest - (char *)stackblock()) - startloc,
4901 stackblock() + startloc));
4906 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4917 const char *s = loc2;
4923 match = pmatch(str, s);
4927 if (quotes && *loc == CTLESC)
4937 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4944 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
4947 const char *s = loc2;
4952 match = pmatch(str, s);
4959 esc = esclen(startp, loc);
4971 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
4975 int saveherefd = herefd;
4976 struct nodelist *saveargbackq = argbackq;
4978 char *rmesc, *rmescend;
4980 char *(*scan)(char *, char *, char *, char *, int , int);
4983 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4984 STPUTC('\0', expdest);
4985 herefd = saveherefd;
4986 argbackq = saveargbackq;
4987 startp = stackblock() + startloc;
4991 setvar(str, startp, 0);
4992 amount = startp - expdest;
4993 STADJUST(amount, expdest);
4997 varunset(p, str, startp, varflags);
5001 subtype -= VSTRIMRIGHT;
5003 if (subtype < 0 || subtype > 3)
5008 rmescend = stackblock() + strloc;
5010 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5011 if (rmesc != startp) {
5013 startp = stackblock() + startloc;
5017 str = stackblock() + strloc;
5018 preglob(str, varflags & VSQUOTE, 0);
5020 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5021 zero = subtype >> 1;
5022 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5023 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5025 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5028 memmove(startp, loc, str - loc);
5029 loc = startp + (str - loc) - 1;
5032 amount = loc - expdest;
5033 STADJUST(amount, expdest);
5040 * Expand a variable, and return a pointer to the next character in the
5044 evalvar(char *p, int flag)
5057 quotes = flag & (EXP_FULL | EXP_CASE);
5059 subtype = varflags & VSTYPE;
5060 quoted = varflags & VSQUOTE;
5062 easy = (!quoted || (*var == '@' && shellparam.nparam));
5063 startloc = expdest - (char *)stackblock();
5064 p = strchr(p, '=') + 1;
5067 varlen = varvalue(var, varflags, flag);
5068 if (varflags & VSNUL)
5071 if (subtype == VSPLUS) {
5072 varlen = -1 - varlen;
5076 if (subtype == VSMINUS) {
5080 p, flag | EXP_TILDE |
5081 (quoted ? EXP_QWORD : EXP_WORD)
5090 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5092 if (subevalvar(p, var, 0, subtype, startloc, varflags, 0)) {
5095 * Remove any recorded regions beyond
5098 removerecordregions(startloc);
5108 if (varlen < 0 && uflag)
5109 varunset(p, var, 0, 0);
5111 if (subtype == VSLENGTH) {
5112 cvtnum(varlen > 0 ? varlen : 0);
5116 if (subtype == VSNORMAL) {
5120 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5129 case VSTRIMRIGHTMAX:
5138 * Terminate the string and start recording the pattern
5141 STPUTC('\0', expdest);
5142 patloc = expdest - (char *)stackblock();
5143 if (subevalvar(p, NULL, patloc, subtype,
5144 startloc, varflags, quotes) == 0) {
5145 int amount = expdest - (
5146 (char *)stackblock() + patloc - 1
5148 STADJUST(-amount, expdest);
5150 /* Remove any recorded regions beyond start of variable */
5151 removerecordregions(startloc);
5156 if (subtype != VSNORMAL) { /* skip to end of alternative */
5162 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5164 argbackq = argbackq->next;
5165 } else if (c == CTLVAR) {
5166 if ((*p++ & VSTYPE) != VSNORMAL)
5168 } else if (c == CTLENDVAR) {
5179 * Put a string on the stack.
5182 memtodest(const char *p, size_t len, int syntax, int quotes)
5186 q = makestrspace(len * 2, q);
5189 int c = SC2INT(*p++);
5192 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5202 strtodest(const char *p, int syntax, int quotes)
5204 memtodest(p, strlen(p), syntax, quotes);
5209 * Add the value of a specialized variable to the stack string.
5212 varvalue(char *name, int varflags, int flags)
5222 int quoted = varflags & VSQUOTE;
5223 int subtype = varflags & VSTYPE;
5224 int quotes = flags & (EXP_FULL | EXP_CASE);
5226 if (quoted && (flags & EXP_FULL))
5227 sep = 1 << CHAR_BIT;
5229 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5238 num = shellparam.nparam;
5248 p = makestrspace(NOPTS, expdest);
5249 for (i = NOPTS - 1; i >= 0; i--) {
5251 USTPUTC(optletters(i), p);
5262 sep = ifsset() ? SC2INT(ifsval()[0]) : ' ';
5263 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5269 while ((p = *ap++)) {
5272 partlen = strlen(p);
5275 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5276 memtodest(p, partlen, syntax, quotes);
5282 if (subtype == VSPLUS || subtype == VSLENGTH) {
5304 if (num < 0 || num > shellparam.nparam)
5306 p = num ? shellparam.p[num - 1] : arg0;
5309 p = lookupvar(name);
5315 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5316 memtodest(p, len, syntax, quotes);
5320 if (subtype == VSPLUS || subtype == VSLENGTH)
5321 STADJUST(-len, expdest);
5327 * Record the fact that we have to scan this region of the
5328 * string for IFS characters.
5331 recordregion(int start, int end, int nulonly)
5333 struct ifsregion *ifsp;
5335 if (ifslastp == NULL) {
5339 ifsp = ckmalloc(sizeof(*ifsp));
5341 ifslastp->next = ifsp;
5345 ifslastp->begoff = start;
5346 ifslastp->endoff = end;
5347 ifslastp->nulonly = nulonly;
5352 * Break the argument string into pieces based upon IFS and add the
5353 * strings to the argument list. The regions of the string to be
5354 * searched for IFS characters have been stored by recordregion.
5357 ifsbreakup(char *string, struct arglist *arglist)
5359 struct ifsregion *ifsp;
5364 const char *ifs, *realifs;
5369 if (ifslastp != NULL) {
5372 realifs = ifsset() ? ifsval() : defifs;
5375 p = string + ifsp->begoff;
5376 nulonly = ifsp->nulonly;
5377 ifs = nulonly ? nullstr : realifs;
5379 while (p < string + ifsp->endoff) {
5383 if (strchr(ifs, *p)) {
5385 ifsspc = (strchr(defifs, *p) != NULL);
5386 /* Ignore IFS whitespace at start */
5387 if (q == start && ifsspc) {
5393 sp = stalloc(sizeof(*sp));
5395 *arglist->lastp = sp;
5396 arglist->lastp = &sp->next;
5400 if (p >= string + ifsp->endoff) {
5406 if (strchr(ifs, *p) == NULL ) {
5409 } else if (strchr(defifs, *p) == NULL) {
5425 } while ((ifsp = ifsp->next) != NULL);
5434 sp = stalloc(sizeof(*sp));
5436 *arglist->lastp = sp;
5437 arglist->lastp = &sp->next;
5443 struct ifsregion *p;
5448 struct ifsregion *ifsp;
5454 ifsfirst.next = NULL;
5458 static void expmeta(char *, char *);
5459 static struct strlist *expsort(struct strlist *);
5460 static struct strlist *msort(struct strlist *, int);
5462 static char *expdir;
5466 expandmeta(struct strlist *str, int flag)
5468 static const char metachars[] = {
5471 /* TODO - EXP_REDIR */
5474 struct strlist **savelastp;
5480 if (!strpbrk(str->text, metachars))
5482 savelastp = exparg.lastp;
5485 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5487 int i = strlen(str->text);
5488 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5496 if (exparg.lastp == savelastp) {
5501 *exparg.lastp = str;
5502 rmescapes(str->text);
5503 exparg.lastp = &str->next;
5505 *exparg.lastp = NULL;
5506 *savelastp = sp = expsort(*savelastp);
5507 while (sp->next != NULL)
5509 exparg.lastp = &sp->next;
5517 * Add a file name to the list.
5520 addfname(const char *name)
5524 sp = stalloc(sizeof(*sp));
5525 sp->text = sstrdup(name);
5527 exparg.lastp = &sp->next;
5532 * Do metacharacter (i.e. *, ?, [...]) expansion.
5535 expmeta(char *enddir, char *name)
5550 for (p = name; *p; p++) {
5551 if (*p == '*' || *p == '?')
5553 else if (*p == '[') {
5560 if (*q == '/' || *q == '\0')
5567 } else if (*p == '\\')
5569 else if (*p == '/') {
5576 if (metaflag == 0) { /* we've reached the end of the file name */
5577 if (enddir != expdir)
5585 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5596 } while (p < start);
5598 if (enddir == expdir) {
5600 } else if (enddir == expdir + 1 && *expdir == '/') {
5609 if (enddir != expdir)
5611 if (*endname == 0) {
5623 while (! intpending && (dp = readdir(dirp)) != NULL) {
5624 if (dp->d_name[0] == '.' && ! matchdot)
5626 if (pmatch(start, dp->d_name)) {
5628 scopy(dp->d_name, enddir);
5631 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
5634 expmeta(p, endname);
5645 * Sort the results of file name expansion. It calculates the number of
5646 * strings to sort and then calls msort (short for merge sort) to do the
5649 static struct strlist *
5650 expsort(struct strlist *str)
5656 for (sp = str; sp; sp = sp->next)
5658 return msort(str, len);
5662 static struct strlist *
5663 msort(struct strlist *list, int len)
5665 struct strlist *p, *q = NULL;
5666 struct strlist **lpp;
5674 for (n = half; --n >= 0; ) {
5678 q->next = NULL; /* terminate first half of list */
5679 q = msort(list, half); /* sort first half of list */
5680 p = msort(p, len - half); /* sort second half */
5683 #if ENABLE_LOCALE_SUPPORT
5684 if (strcoll(p->text, q->text) < 0)
5686 if (strcmp(p->text, q->text) < 0)
5711 * Returns true if the pattern matches the string.
5713 static int patmatch(char *pattern, const char *string)
5715 return pmatch(preglob(pattern, 0, 0), string);
5720 * Remove any CTLESC characters from a string.
5723 _rmescapes(char *str, int flag)
5726 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5731 p = strpbrk(str, qchars);
5737 if (flag & RMESCAPE_ALLOC) {
5738 size_t len = p - str;
5739 size_t fulllen = len + strlen(p) + 1;
5741 if (flag & RMESCAPE_GROW) {
5742 r = makestrspace(fulllen, expdest);
5743 } else if (flag & RMESCAPE_HEAP) {
5744 r = ckmalloc(fulllen);
5746 r = stalloc(fulllen);
5750 q = memcpy(q, str, len) + len;
5753 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5754 globbing = flag & RMESCAPE_GLOB;
5755 notescaped = globbing;
5757 if (*p == CTLQUOTEMARK) {
5758 inquotes = ~inquotes;
5760 notescaped = globbing;
5764 /* naked back slash */
5770 if (notescaped && inquotes && *p != '/') {
5774 notescaped = globbing;
5779 if (flag & RMESCAPE_GROW) {
5781 STADJUST(q - r + 1, expdest);
5788 * See if a pattern matches in a case statement.
5791 casematch(union node *pattern, char *val)
5793 struct stackmark smark;
5796 setstackmark(&smark);
5797 argbackq = pattern->narg.backquote;
5798 STARTSTACKSTR(expdest);
5800 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5801 STACKSTRNUL(expdest);
5802 result = patmatch(stackblock(), val);
5803 popstackmark(&smark);
5816 expdest = makestrspace(32, expdest);
5817 #if ENABLE_ASH_MATH_SUPPORT_64
5818 len = fmtstr(expdest, 32, "%lld", (long long) num);
5820 len = fmtstr(expdest, 32, "%ld", num);
5822 STADJUST(len, expdest);
5826 static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN;
5828 varunset(const char *end, const char *var, const char *umsg, int varflags)
5834 msg = "parameter not set";
5836 if (*end == CTLENDVAR) {
5837 if (varflags & VSNUL)
5842 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail);
5849 * This implements the input routines used by the parser.
5852 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5854 static void pushfile(void);
5857 * Read a character from the script, returning PEOF on end of file.
5858 * Nul characters in the input are silently discarded.
5862 #define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
5864 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE
5865 #define pgetc_macro() pgetc()
5869 return pgetc_as_macro();
5872 #define pgetc_macro() pgetc_as_macro()
5876 return pgetc_macro();
5882 * Same as pgetc(), but ignores PEOA.
5884 #if ENABLE_ASH_ALIAS
5885 static int pgetc2(void)
5891 } while (c == PEOA);
5895 static int pgetc2(void)
5897 return pgetc_macro();
5902 * Read a line from the script.
5905 static char * pfgets(char *line, int len)
5911 while (--nleft > 0) {
5927 #if ENABLE_FEATURE_EDITING
5928 static line_input_t *line_input_state;
5929 //static SKIP_ASH_EXPAND_PRMT(const) char *cmdedit_prompt;
5930 static const char *cmdedit_prompt;
5931 static void putprompt(const char *s)
5933 if (ENABLE_ASH_EXPAND_PRMT) {
5934 free((char*)cmdedit_prompt);
5935 cmdedit_prompt = xstrdup(s);
5941 static void putprompt(const char *s)
5947 #if ENABLE_FEATURE_EDITING_VI
5948 #define setvimode(on) do { \
5949 if (on) line_input_state->flags |= VI_MODE; \
5950 else line_input_state->flags &= ~VI_MODE; \
5953 #define setvimode(on) viflag = 0 /* forcibly keep the option off */
5957 static int preadfd(void)
5960 char *buf = parsefile->buf;
5964 #if ENABLE_FEATURE_EDITING
5965 if (!iflag || parsefile->fd)
5966 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
5968 #if ENABLE_FEATURE_TAB_COMPLETION
5969 line_input_state->path_lookup = pathval();
5971 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
5973 /* Ctrl+C pressed */
5982 if (nr < 0 && errno == 0) {
5983 /* Ctrl+D presend */
5988 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
5992 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5993 int flags = fcntl(0, F_GETFL, 0);
5994 if (flags >= 0 && flags & O_NONBLOCK) {
5995 flags &=~ O_NONBLOCK;
5996 if (fcntl(0, F_SETFL, flags) >= 0) {
5997 out2str("sh: turning off NDELAY mode\n");
6007 * Refill the input buffer and return the next input character:
6009 * 1) If a string was pushed back on the input, pop it;
6010 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6011 * from a string so we can't refill the buffer, return EOF.
6012 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6013 * 4) Process input up to the next newline, deleting nul characters.
6022 while (parsefile->strpush) {
6023 #if ENABLE_ASH_ALIAS
6024 if (parsenleft == -1 && parsefile->strpush->ap &&
6025 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6030 if (--parsenleft >= 0)
6031 return SC2INT(*parsenextc++);
6033 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6035 flush_stdout_stderr();
6042 parselleft = parsenleft = EOF_NLEFT;
6049 /* delete nul characters */
6057 memmove(q, q + 1, more);
6061 parsenleft = q - parsenextc - 1;
6067 parsenleft = q - parsenextc - 1;
6079 out2str(parsenextc);
6084 return SC2INT(*parsenextc++);
6088 * Undo the last call to pgetc. Only one character may be pushed back.
6089 * PEOF may be pushed back.
6099 * Push a string back onto the input at this current parsefile level.
6100 * We handle aliases this way.
6103 pushstring(char *s, void *ap)
6110 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6111 if (parsefile->strpush) {
6112 sp = ckmalloc(sizeof(struct strpush));
6113 sp->prev = parsefile->strpush;
6114 parsefile->strpush = sp;
6116 sp = parsefile->strpush = &(parsefile->basestrpush);
6117 sp->prevstring = parsenextc;
6118 sp->prevnleft = parsenleft;
6119 #if ENABLE_ASH_ALIAS
6120 sp->ap = (struct alias *)ap;
6122 ((struct alias *)ap)->flag |= ALIASINUSE;
6134 struct strpush *sp = parsefile->strpush;
6137 #if ENABLE_ASH_ALIAS
6139 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6140 checkkwd |= CHKALIAS;
6142 if (sp->string != sp->ap->val) {
6145 sp->ap->flag &= ~ALIASINUSE;
6146 if (sp->ap->flag & ALIASDEAD) {
6147 unalias(sp->ap->name);
6151 parsenextc = sp->prevstring;
6152 parsenleft = sp->prevnleft;
6153 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6154 parsefile->strpush = sp->prev;
6155 if (sp != &(parsefile->basestrpush))
6162 * Set the input to take input from a file. If push is set, push the
6163 * old input onto the stack first.
6166 setinputfile(const char *fname, int flags)
6172 fd = open(fname, O_RDONLY);
6174 if (flags & INPUT_NOFILE_OK)
6176 ash_msg_and_raise_error("Can't open %s", fname);
6179 fd2 = copyfd(fd, 10);
6182 ash_msg_and_raise_error("Out of file descriptors");
6185 setinputfd(fd, flags & INPUT_PUSH_FILE);
6193 * Like setinputfile, but takes an open file descriptor. Call this with
6197 setinputfd(int fd, int push)
6199 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6205 if (parsefile->buf == NULL)
6206 parsefile->buf = ckmalloc(IBUFSIZ);
6207 parselleft = parsenleft = 0;
6213 * Like setinputfile, but takes input from a string.
6216 setinputstring(char *string)
6220 parsenextc = string;
6221 parsenleft = strlen(string);
6222 parsefile->buf = NULL;
6229 * To handle the "." command, a stack of input files is used. Pushfile
6230 * adds a new entry to the stack and popfile restores the previous level.
6235 struct parsefile *pf;
6237 parsefile->nleft = parsenleft;
6238 parsefile->lleft = parselleft;
6239 parsefile->nextc = parsenextc;
6240 parsefile->linno = plinno;
6241 pf = ckmalloc(sizeof(*pf));
6242 pf->prev = parsefile;
6245 pf->basestrpush.prev = NULL;
6253 struct parsefile *pf = parsefile;
6262 parsefile = pf->prev;
6264 parsenleft = parsefile->nleft;
6265 parselleft = parsefile->lleft;
6266 parsenextc = parsefile->nextc;
6267 plinno = parsefile->linno;
6273 * Return to top level.
6278 while (parsefile != &basepf)
6284 * Close the file(s) that the shell is reading commands from. Called
6285 * after a fork is done.
6291 if (parsefile->fd > 0) {
6292 close(parsefile->fd);
6299 /* mode flags for set_curjob */
6300 #define CUR_DELETE 2
6301 #define CUR_RUNNING 1
6302 #define CUR_STOPPED 0
6304 /* mode flags for dowait */
6305 #define DOWAIT_NORMAL 0
6306 #define DOWAIT_BLOCK 1
6309 static struct job *jobtab;
6311 static unsigned njobs;
6313 /* pgrp of shell on invocation */
6314 static int initialpgrp;
6315 static int ttyfd = -1;
6318 static struct job *curjob;
6319 /* number of presumed living untracked jobs */
6322 static void set_curjob(struct job *, unsigned);
6324 static int restartjob(struct job *, int);
6325 static void xtcsetpgrp(int, pid_t);
6326 static char *commandtext(union node *);
6327 static void cmdlist(union node *, int);
6328 static void cmdtxt(union node *);
6329 static void cmdputs(const char *);
6330 static void showpipe(struct job *, FILE *);
6332 static int sprint_status(char *, int, int);
6333 static void freejob(struct job *);
6334 static struct job *getjob(const char *, int);
6335 static struct job *growjobtab(void);
6336 static void forkchild(struct job *, union node *, int);
6337 static void forkparent(struct job *, union node *, int, pid_t);
6338 static int dowait(int, struct job *);
6339 static int getstatus(struct job *);
6342 set_curjob(struct job *jp, unsigned mode)
6345 struct job **jpp, **curp;
6347 /* first remove from list */
6348 jpp = curp = &curjob;
6353 jpp = &jp1->prev_job;
6355 *jpp = jp1->prev_job;
6357 /* Then re-insert in correct position */
6365 /* job being deleted */
6368 /* newly created job or backgrounded job,
6369 put after all stopped jobs. */
6373 if (!jp1 || jp1->state != JOBSTOPPED)
6376 jpp = &jp1->prev_job;
6382 /* newly stopped job - becomes curjob */
6383 jp->prev_job = *jpp;
6391 * Turn job control on and off.
6393 * Note: This code assumes that the third arg to ioctl is a character
6394 * pointer, which is true on Berkeley systems but not System V. Since
6395 * System V doesn't have job control yet, this isn't a problem now.
6397 * Called with interrupts off.
6405 if (on == jobctl || rootshell == 0)
6409 ofd = fd = open(_PATH_TTY, O_RDWR);
6411 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
6412 * That sometimes helps to acquire controlling tty.
6413 * Obviously, a workaround for bugs when someone
6414 * failed to provide a controlling tty to bash! :) */
6416 while (!isatty(fd) && --fd >= 0)
6419 fd = fcntl(fd, F_DUPFD, 10);
6423 fcntl(fd, F_SETFD, FD_CLOEXEC);
6424 do { /* while we are in the background */
6425 pgrp = tcgetpgrp(fd);
6428 ash_msg("can't access tty; job control turned off");
6432 if (pgrp == getpgrp())
6443 xtcsetpgrp(fd, pgrp);
6445 /* turning job control off */
6448 xtcsetpgrp(fd, pgrp);
6462 killcmd(int argc, char **argv)
6472 ash_msg_and_raise_error(
6473 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6474 "kill -l [exitstatus]"
6478 if (**++argv == '-') {
6479 signo = get_signum(*argv + 1);
6483 while ((c = nextopt("ls:")) != '\0')
6493 signo = get_signum(optionarg);
6495 ash_msg_and_raise_error(
6496 "invalid signal number or name: %s",
6507 if (!list && signo < 0)
6510 if ((signo < 0 || !*argv) ^ list) {
6518 for (i = 1; i < NSIG; i++) {
6519 name = get_signame(i);
6521 out1fmt(snlfmt, name);
6525 name = get_signame(signo);
6526 if (!isdigit(*name))
6527 ash_msg_and_raise_error("invalid signal number or exit status: %s", *argptr);
6528 out1fmt(snlfmt, name);
6534 if (**argv == '%') {
6535 jp = getjob(*argv, 0);
6536 pid = -jp->ps[0].pid;
6538 pid = **argv == '-' ?
6539 -number(*argv + 1) : number(*argv);
6541 if (kill(pid, signo) != 0) {
6542 ash_msg("(%d) - %m", pid);
6553 jobno(const struct job *jp)
6555 return jp - jobtab + 1;
6561 fgcmd(int argc, char **argv)
6568 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6573 jp = getjob(*argv, 1);
6574 if (mode == FORK_BG) {
6575 set_curjob(jp, CUR_RUNNING);
6576 fprintf(out, "[%d] ", jobno(jp));
6578 outstr(jp->ps->cmd, out);
6580 retval = restartjob(jp, mode);
6581 } while (*argv && *++argv);
6585 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6589 restartjob(struct job *jp, int mode)
6591 struct procstat *ps;
6597 if (jp->state == JOBDONE)
6599 jp->state = JOBRUNNING;
6601 if (mode == FORK_FG)
6602 xtcsetpgrp(ttyfd, pgid);
6603 killpg(pgid, SIGCONT);
6607 if (WIFSTOPPED(ps->status)) {
6610 } while (ps++, --i);
6612 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6619 sprint_status(char *s, int status, int sigonly)
6625 if (!WIFEXITED(status)) {
6627 if (WIFSTOPPED(status))
6628 st = WSTOPSIG(status);
6631 st = WTERMSIG(status);
6633 if (st == SIGINT || st == SIGPIPE)
6636 if (WIFSTOPPED(status))
6641 col = fmtstr(s, 32, strsignal(st));
6642 if (WCOREDUMP(status)) {
6643 col += fmtstr(s + col, 16, " (core dumped)");
6645 } else if (!sigonly) {
6646 st = WEXITSTATUS(status);
6648 col = fmtstr(s, 16, "Done(%d)", st);
6650 col = fmtstr(s, 16, "Done");
6658 showjob(FILE *out, struct job *jp, int mode)
6660 struct procstat *ps;
6661 struct procstat *psend;
6668 if (mode & SHOW_PGID) {
6669 /* just output process (group) id of pipeline */
6670 fprintf(out, "%d\n", ps->pid);
6674 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6679 else if (curjob && jp == curjob->prev_job)
6682 if (mode & SHOW_PID)
6683 col += fmtstr(s + col, 16, "%d ", ps->pid);
6685 psend = ps + jp->nprocs;
6687 if (jp->state == JOBRUNNING) {
6688 scopy("Running", s + col);
6689 col += strlen("Running");
6691 int status = psend[-1].status;
6693 if (jp->state == JOBSTOPPED)
6694 status = jp->stopstatus;
6696 col += sprint_status(s + col, status, 0);
6702 /* for each process */
6703 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6705 fprintf(out, "%s%*c%s",
6706 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6708 if (!(mode & SHOW_PID)) {
6712 if (++ps == psend) {
6713 outcslow('\n', out);
6720 if (jp->state == JOBDONE) {
6721 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6728 jobscmd(int argc, char **argv)
6734 while ((m = nextopt("lp")))
6744 showjob(out, getjob(*argv,0), mode);
6747 showjobs(out, mode);
6754 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6755 * statuses have changed since the last call to showjobs.
6758 showjobs(FILE *out, int mode)
6762 TRACE(("showjobs(%x) called\n", mode));
6764 /* If not even one one job changed, there is nothing to do */
6765 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6768 for (jp = curjob; jp; jp = jp->prev_job) {
6769 if (!(mode & SHOW_CHANGED) || jp->changed)
6770 showjob(out, jp, mode);
6777 * Mark a job structure as unused.
6780 freejob(struct job *jp)
6782 struct procstat *ps;
6786 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
6787 if (ps->cmd != nullstr)
6790 if (jp->ps != &jp->ps0)
6793 set_curjob(jp, CUR_DELETE);
6799 waitcmd(int argc, char **argv)
6812 /* wait for all jobs */
6817 /* no running procs */
6820 if (jp->state == JOBRUNNING)
6825 dowait(DOWAIT_BLOCK, 0);
6831 if (**argv != '%') {
6832 pid_t pid = number(*argv);
6836 if (job->ps[job->nprocs - 1].pid == pid)
6838 job = job->prev_job;
6844 job = getjob(*argv, 0);
6845 /* loop until process terminated or stopped */
6846 while (job->state == JOBRUNNING)
6847 dowait(DOWAIT_BLOCK, 0);
6849 retval = getstatus(job);
6860 * Convert a job name to a job structure.
6863 getjob(const char *name, int getctl)
6867 const char *err_msg = "No such job: %s";
6871 char *(*match)(const char *, const char *);
6886 if (c == '+' || c == '%') {
6888 err_msg = "No current job";
6890 } else if (c == '-') {
6893 err_msg = "No previous job";
6904 jp = jobtab + num - 1;
6921 if (match(jp->ps[0].cmd, p)) {
6925 err_msg = "%s: ambiguous";
6932 err_msg = "job %s not created under job control";
6933 if (getctl && jp->jobctl == 0)
6938 ash_msg_and_raise_error(err_msg, name);
6943 * Return a new job structure.
6944 * Called with interrupts off.
6948 makejob(union node *node, int nprocs)
6953 for (i = njobs, jp = jobtab; ; jp++) {
6960 if (jp->state != JOBDONE || !jp->waited)
6969 memset(jp, 0, sizeof(*jp));
6974 jp->prev_job = curjob;
6979 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
6981 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6991 struct job *jp, *jq;
6993 len = njobs * sizeof(*jp);
6995 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
6997 offset = (char *)jp - (char *)jq;
6999 /* Relocate pointers */
7002 jq = (struct job *)((char *)jq + l);
7006 #define joff(p) ((struct job *)((char *)(p) + l))
7007 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7008 if (xlikely(joff(jp)->ps == &jq->ps0))
7009 jmove(joff(jp)->ps);
7010 if (joff(jp)->prev_job)
7011 jmove(joff(jp)->prev_job);
7021 jp = (struct job *)((char *)jp + len);
7025 } while (--jq >= jp);
7031 * Fork off a subshell. If we are doing job control, give the subshell its
7032 * own process group. Jp is a job structure that the job is to be added to.
7033 * N is the command that will be evaluated by the child. Both jp and n may
7034 * be NULL. The mode parameter can be one of the following:
7035 * FORK_FG - Fork off a foreground process.
7036 * FORK_BG - Fork off a background process.
7037 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7038 * process group even if job control is on.
7040 * When job control is turned off, background processes have their standard
7041 * input redirected to /dev/null (except for the second and later processes
7044 * Called with interrupts off.
7046 static void forkchild(struct job *jp, union node *n, int mode)
7050 TRACE(("Child shell %d\n", getpid()));
7057 /* do job control only in root shell */
7059 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
7062 if (jp->nprocs == 0)
7065 pgrp = jp->ps[0].pid;
7066 /* This can fail because we are doing it in the parent also */
7067 (void)setpgid(0, pgrp);
7068 if (mode == FORK_FG)
7069 xtcsetpgrp(ttyfd, pgrp);
7074 if (mode == FORK_BG) {
7077 if (jp->nprocs == 0) {
7079 if (open(bb_dev_null, O_RDONLY) != 0)
7080 ash_msg_and_raise_error("Can't open %s", bb_dev_null);
7083 if (!oldlvl && iflag) {
7088 for (jp = curjob; jp; jp = jp->prev_job)
7093 static void forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7095 TRACE(("In parent shell: child = %d\n", pid));
7097 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7102 if (mode != FORK_NOJOB && jp->jobctl) {
7105 if (jp->nprocs == 0)
7108 pgrp = jp->ps[0].pid;
7109 /* This can fail because we are doing it in the child also */
7110 (void)setpgid(pid, pgrp);
7113 if (mode == FORK_BG) {
7114 backgndpid = pid; /* set $! */
7115 set_curjob(jp, CUR_RUNNING);
7118 struct procstat *ps = &jp->ps[jp->nprocs++];
7124 ps->cmd = commandtext(n);
7130 forkshell(struct job *jp, union node *n, int mode)
7134 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7137 TRACE(("Fork failed, errno=%d", errno));
7140 ash_msg_and_raise_error("Cannot fork");
7143 forkchild(jp, n, mode);
7145 forkparent(jp, n, mode, pid);
7151 * Wait for job to finish.
7153 * Under job control we have the problem that while a child process is
7154 * running interrupts generated by the user are sent to the child but not
7155 * to the shell. This means that an infinite loop started by an inter-
7156 * active user may be hard to kill. With job control turned off, an
7157 * interactive user may place an interactive program inside a loop. If
7158 * the interactive program catches interrupts, the user doesn't want
7159 * these interrupts to also abort the loop. The approach we take here
7160 * is to have the shell ignore interrupt signals while waiting for a
7161 * foreground process to terminate, and then send itself an interrupt
7162 * signal if the child process was terminated by an interrupt signal.
7163 * Unfortunately, some programs want to do a bit of cleanup and then
7164 * exit on interrupt; unless these processes terminate themselves by
7165 * sending a signal to themselves (instead of calling exit) they will
7166 * confuse this approach.
7168 * Called with interrupts off.
7171 waitforjob(struct job *jp)
7175 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7176 while (jp->state == JOBRUNNING) {
7177 dowait(DOWAIT_BLOCK, jp);
7182 xtcsetpgrp(ttyfd, rootpid);
7184 * This is truly gross.
7185 * If we're doing job control, then we did a TIOCSPGRP which
7186 * caused us (the shell) to no longer be in the controlling
7187 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7188 * intuit from the subprocess exit status whether a SIGINT
7189 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7194 if (jp->state == JOBDONE)
7202 * Do a wait system call. If job control is compiled in, we accept
7203 * stopped processes. If block is zero, we return a value of zero
7204 * rather than blocking.
7206 * System V doesn't have a non-blocking wait system call. It does
7207 * have a SIGCLD signal that is sent to a process when one of it's
7208 * children dies. The obvious way to use SIGCLD would be to install
7209 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7210 * was received, and have waitproc bump another counter when it got
7211 * the status of a process. Waitproc would then know that a wait
7212 * system call would not block if the two counters were different.
7213 * This approach doesn't work because if a process has children that
7214 * have not been waited for, System V will send it a SIGCLD when it
7215 * installs a signal handler for SIGCLD. What this means is that when
7216 * a child exits, the shell will be sent SIGCLD signals continuously
7217 * until is runs out of stack space, unless it does a wait call before
7218 * restoring the signal handler. The code below takes advantage of
7219 * this (mis)feature by installing a signal handler for SIGCLD and
7220 * then checking to see whether it was called. If there are any
7221 * children to be waited for, it will be.
7223 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7224 * waits at all. In this case, the user will not be informed when
7225 * a background process until the next time she runs a real program
7226 * (as opposed to running a builtin command or just typing return),
7227 * and the jobs command may give out of date information.
7229 static int waitproc(int block, int *status)
7239 return wait3(status, flags, (struct rusage *)NULL);
7244 * Wait for a process to terminate.
7247 dowait(int block, struct job *job)
7252 struct job *thisjob;
7255 TRACE(("dowait(%d) called\n", block));
7256 pid = waitproc(block, &status);
7257 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7262 for (jp = curjob; jp; jp = jp->prev_job) {
7263 struct procstat *sp;
7264 struct procstat *spend;
7265 if (jp->state == JOBDONE)
7268 spend = jp->ps + jp->nprocs;
7271 if (sp->pid == pid) {
7272 TRACE(("Job %d: changing status of proc %d "
7273 "from 0x%x to 0x%x\n",
7274 jobno(jp), pid, sp->status, status));
7275 sp->status = status;
7278 if (sp->status == -1)
7281 if (state == JOBRUNNING)
7283 if (WIFSTOPPED(sp->status)) {
7284 jp->stopstatus = sp->status;
7288 } while (++sp < spend);
7293 if (!WIFSTOPPED(status))
7300 if (state != JOBRUNNING) {
7301 thisjob->changed = 1;
7303 if (thisjob->state != state) {
7304 TRACE(("Job %d: changing state from %d to %d\n",
7305 jobno(thisjob), thisjob->state, state));
7306 thisjob->state = state;
7308 if (state == JOBSTOPPED) {
7309 set_curjob(thisjob, CUR_STOPPED);
7318 if (thisjob && thisjob == job) {
7322 len = sprint_status(s, status, 1);
7334 * return 1 if there are stopped jobs, otherwise 0
7346 if (jp && jp->state == JOBSTOPPED) {
7347 out2str("You have stopped jobs.\n");
7357 * Return a string identifying a command (to be printed by the
7361 static char *cmdnextc;
7364 commandtext(union node *n)
7368 STARTSTACKSTR(cmdnextc);
7370 name = stackblock();
7371 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7372 name, cmdnextc, cmdnextc));
7373 return savestr(name);
7377 cmdtxt(union node *n)
7380 struct nodelist *lp;
7392 lp = n->npipe.cmdlist;
7410 cmdtxt(n->nbinary.ch1);
7426 cmdtxt(n->nif.test);
7429 if (n->nif.elsepart) {
7432 n = n->nif.elsepart;
7448 cmdtxt(n->nbinary.ch1);
7458 cmdputs(n->nfor.var);
7460 cmdlist(n->nfor.args, 1);
7465 cmdputs(n->narg.text);
7469 cmdlist(n->ncmd.args, 1);
7470 cmdlist(n->ncmd.redirect, 0);
7483 cmdputs(n->ncase.expr->narg.text);
7485 for (np = n->ncase.cases; np; np = np->nclist.next) {
7486 cmdtxt(np->nclist.pattern);
7488 cmdtxt(np->nclist.body);
7514 s[0] = n->nfile.fd + '0';
7518 if (n->type == NTOFD || n->type == NFROMFD) {
7519 s[0] = n->ndup.dupfd + '0';
7530 cmdlist(union node *np, int sep)
7532 for (; np; np = np->narg.next) {
7536 if (sep && np->narg.next)
7542 cmdputs(const char *s)
7544 const char *p, *str;
7545 char c, cc[2] = " ";
7549 static const char vstype[VSTYPE + 1][4] = {
7550 "", "}", "-", "+", "?", "=",
7551 "%", "%%", "#", "##"
7553 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7555 while ((c = *p++) != 0) {
7563 if ((subtype & VSTYPE) == VSLENGTH)
7567 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7574 str = "\"}" + !(quoted & 1);
7581 case CTLBACKQ+CTLQUOTE:
7584 #if ENABLE_ASH_MATH_SUPPORT
7599 if ((subtype & VSTYPE) != VSNORMAL)
7601 str = vstype[subtype & VSTYPE];
7602 if (subtype & VSNUL)
7611 /* These can only happen inside quotes */
7624 while ((c = *str++)) {
7629 USTPUTC('"', nextc);
7637 showpipe(struct job *jp, FILE *out)
7639 struct procstat *sp;
7640 struct procstat *spend;
7642 spend = jp->ps + jp->nprocs;
7643 for (sp = jp->ps + 1; sp < spend; sp++)
7644 fprintf(out, " | %s", sp->cmd);
7645 outcslow('\n', out);
7646 flush_stdout_stderr();
7650 xtcsetpgrp(int fd, pid_t pgrp)
7652 if (tcsetpgrp(fd, pgrp))
7653 ash_msg_and_raise_error("Cannot set tty process group (%m)");
7658 getstatus(struct job *job)
7663 status = job->ps[job->nprocs - 1].status;
7664 retval = WEXITSTATUS(status);
7665 if (!WIFEXITED(status)) {
7667 retval = WSTOPSIG(status);
7668 if (!WIFSTOPPED(status))
7671 /* XXX: limits number of signals */
7672 retval = WTERMSIG(status);
7674 if (retval == SIGINT)
7680 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7681 jobno(job), job->nprocs, status, retval));
7689 * Routines to check for mail. (Perhaps make part of main.c?)
7692 #define MAXMBOXES 10
7694 /* times of mailboxes */
7695 static time_t mailtime[MAXMBOXES];
7696 /* Set if MAIL or MAILPATH is changed. */
7697 static int mail_var_path_changed;
7701 * Print appropriate message(s) if mail has arrived.
7702 * If mail_var_path_changed is set,
7703 * then the value of MAIL has mail_var_path_changed,
7704 * so we just update the values.
7713 struct stackmark smark;
7716 setstackmark(&smark);
7717 mpath = mpathset() ? mpathval() : mailval();
7718 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7719 p = padvance(&mpath, nullstr);
7724 for (q = p; *q; q++);
7729 q[-1] = '\0'; /* delete trailing '/' */
7730 if (stat(p, &statb) < 0) {
7734 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7737 pathopt ? pathopt : "you have mail"
7740 *mtp = statb.st_mtime;
7742 mail_var_path_changed = 0;
7743 popstackmark(&smark);
7748 changemail(const char *val)
7750 mail_var_path_changed++;
7753 #endif /* ASH_MAIL */
7756 * Read and execute commands. "Top" is nonzero for the top level command
7757 * loop; it turns on prompting if the shell is interactive.
7763 struct stackmark smark;
7767 TRACE(("cmdloop(%d) called\n", top));
7771 setstackmark(&smark);
7774 showjobs(stderr, SHOW_CHANGED);
7783 n = parsecmd(inter);
7784 /* showtree(n); DEBUG */
7786 if (!top || numeof >= 50)
7788 if (!stoppedjobs()) {
7791 out2str("\nUse \"exit\" to leave shell.\n");
7794 } else if (nflag == 0) {
7795 job_warning = (job_warning == 2) ? 1 : 0;
7799 popstackmark(&smark);
7804 return skip & SKIPEVAL;
7813 * Read a file containing shell functions.
7816 readcmdfile(char *name)
7818 setinputfile(name, INPUT_PUSH_FILE);
7825 * Take commands from a file. To be compatible we should do a path
7826 * search for the file, which is necessary to find sub-commands.
7828 static char * find_dot_file(char *name)
7831 const char *path = pathval();
7834 /* don't try this for absolute or relative paths */
7835 if (strchr(name, '/'))
7838 while ((fullname = padvance(&path, name)) != NULL) {
7839 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7841 * Don't bother freeing here, since it will
7842 * be freed by the caller.
7846 stunalloc(fullname);
7849 /* not found in the PATH */
7850 ash_msg_and_raise_error("%s: not found", name);
7854 static int dotcmd(int argc, char **argv)
7857 volatile struct shparam saveparam;
7860 for (sp = cmdenviron; sp; sp = sp->next)
7861 setvareq(xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
7863 if (argc >= 2) { /* That's what SVR2 does */
7866 fullname = find_dot_file(argv[1]);
7869 saveparam = shellparam;
7870 shellparam.malloc = 0;
7871 shellparam.nparam = argc - 2;
7872 shellparam.p = argv + 2;
7875 setinputfile(fullname, INPUT_PUSH_FILE);
7876 commandname = fullname;
7881 freeparam(&shellparam);
7882 shellparam = saveparam;
7884 status = exitstatus;
7891 exitcmd(int argc, char **argv)
7896 exitstatus = number(argv[1]);
7897 raise_exception(EXEXIT);
7901 #if ENABLE_ASH_BUILTIN_ECHO
7903 echocmd(int argc, char **argv)
7905 return bb_echo(argv);
7909 #if ENABLE_ASH_BUILTIN_TEST
7911 testcmd(int argc, char **argv)
7913 return bb_test(argc, argv);
7920 * Same for malloc, realloc, but returns an error when out of space.
7923 ckrealloc(void * p, size_t nbytes)
7925 p = realloc(p, nbytes);
7927 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7932 ckmalloc(size_t nbytes)
7934 return ckrealloc(NULL, nbytes);
7938 * Make a copy of a string in safe storage.
7941 savestr(const char *s)
7943 char *p = strdup(s);
7945 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7951 * Parse trees for commands are allocated in lifo order, so we use a stack
7952 * to make this more efficient, and also to avoid all sorts of exception
7953 * handling code to handle interrupts in the middle of a parse.
7955 * The size 504 was chosen because the Ultrix malloc handles that size
7959 stalloc(size_t nbytes)
7964 aligned = SHELL_ALIGN(nbytes);
7965 if (aligned > stacknleft) {
7968 struct stack_block *sp;
7970 blocksize = aligned;
7971 if (blocksize < MINSIZE)
7972 blocksize = MINSIZE;
7973 len = sizeof(struct stack_block) - MINSIZE + blocksize;
7974 if (len < blocksize)
7975 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7979 stacknxt = sp->space;
7980 stacknleft = blocksize;
7981 sstrend = stacknxt + blocksize;
7986 stacknxt += aligned;
7987 stacknleft -= aligned;
7996 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
7997 write(2, "stunalloc\n", 10);
8001 stacknleft += stacknxt - (char *)p;
8007 setstackmark(struct stackmark *mark)
8009 mark->stackp = stackp;
8010 mark->stacknxt = stacknxt;
8011 mark->stacknleft = stacknleft;
8012 mark->marknext = markp;
8018 popstackmark(struct stackmark *mark)
8020 struct stack_block *sp;
8023 markp = mark->marknext;
8024 while (stackp != mark->stackp) {
8029 stacknxt = mark->stacknxt;
8030 stacknleft = mark->stacknleft;
8031 sstrend = mark->stacknxt + mark->stacknleft;
8037 * When the parser reads in a string, it wants to stick the string on the
8038 * stack and only adjust the stack pointer when it knows how big the
8039 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8040 * of space on top of the stack and stackblocklen returns the length of
8041 * this block. Growstackblock will grow this space by at least one byte,
8042 * possibly moving it (like realloc). Grabstackblock actually allocates the
8043 * part of the block that has been used.
8046 growstackblock(void)
8050 newlen = stacknleft * 2;
8051 if (newlen < stacknleft)
8052 ash_msg_and_raise_error(bb_msg_memory_exhausted);
8056 if (stacknxt == stackp->space && stackp != &stackbase) {
8057 struct stack_block *oldstackp;
8058 struct stackmark *xmark;
8059 struct stack_block *sp;
8060 struct stack_block *prevstackp;
8066 prevstackp = sp->prev;
8067 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8068 sp = ckrealloc(sp, grosslen);
8069 sp->prev = prevstackp;
8071 stacknxt = sp->space;
8072 stacknleft = newlen;
8073 sstrend = sp->space + newlen;
8076 * Stack marks pointing to the start of the old block
8077 * must be relocated to point to the new block
8080 while (xmark != NULL && xmark->stackp == oldstackp) {
8081 xmark->stackp = stackp;
8082 xmark->stacknxt = stacknxt;
8083 xmark->stacknleft = stacknleft;
8084 xmark = xmark->marknext;
8088 char *oldspace = stacknxt;
8089 int oldlen = stacknleft;
8090 char *p = stalloc(newlen);
8092 /* free the space we just allocated */
8093 stacknxt = memcpy(p, oldspace, oldlen);
8094 stacknleft += newlen;
8098 static void grabstackblock(size_t len)
8100 len = SHELL_ALIGN(len);
8107 * The following routines are somewhat easier to use than the above.
8108 * The user declares a variable of type STACKSTR, which may be declared
8109 * to be a register. The macro STARTSTACKSTR initializes things. Then
8110 * the user uses the macro STPUTC to add characters to the string. In
8111 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8112 * grown as necessary. When the user is done, she can just leave the
8113 * string there and refer to it using stackblock(). Or she can allocate
8114 * the space for it using grabstackstr(). If it is necessary to allow
8115 * someone else to use the stack temporarily and then continue to grow
8116 * the string, the user should use grabstack to allocate the space, and
8117 * then call ungrabstr(p) to return to the previous mode of operation.
8119 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8120 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8121 * is space for at least one character.
8126 size_t len = stackblocksize();
8127 if (herefd >= 0 && len >= 1024) {
8128 full_write(herefd, stackblock(), len);
8129 return stackblock();
8132 return stackblock() + len;
8136 * Called from CHECKSTRSPACE.
8139 makestrspace(size_t newlen, char *p)
8141 size_t len = p - stacknxt;
8142 size_t size = stackblocksize();
8147 size = stackblocksize();
8149 if (nleft >= newlen)
8153 return stackblock() + len;
8157 stnputs(const char *s, size_t n, char *p)
8159 p = makestrspace(n, p);
8160 p = memcpy(p, s, n) + n;
8165 stputs(const char *s, char *p)
8167 return stnputs(s, strlen(s), p);
8175 * number(s) Convert a string of digits to an integer.
8176 * is_number(s) Return true if s is a string of digits.
8180 * prefix -- see if pfx is a prefix of string.
8183 prefix(const char *string, const char *pfx)
8186 if (*pfx++ != *string++)
8189 return (char *) string;
8194 * Convert a string of digits to an integer, printing an error message on
8198 number(const char *s)
8201 ash_msg_and_raise_error(illnum, s);
8207 * Check for a valid number. This should be elsewhere.
8210 is_number(const char *p)
8215 } while (*++p != '\0');
8221 * Produce a possibly single quoted string suitable as input to the shell.
8222 * The return string is allocated on the stack.
8225 single_quote(const char *s)
8235 len = strchrnul(s, '\'') - s;
8237 q = p = makestrspace(len + 3, p);
8240 q = memcpy(q, s, len) + len;
8246 len = strspn(s, "'");
8250 q = p = makestrspace(len + 3, p);
8253 q = memcpy(q, s, len) + len;
8262 return stackblock();
8267 * Like strdup but works with the ash stack.
8270 sstrdup(const char *p)
8272 size_t len = strlen(p) + 1;
8273 return memcpy(stalloc(len), p, len);
8278 calcsize(union node *n)
8282 funcblocksize += nodesize[n->type];
8285 calcsize(n->ncmd.redirect);
8286 calcsize(n->ncmd.args);
8287 calcsize(n->ncmd.assign);
8290 sizenodelist(n->npipe.cmdlist);
8295 calcsize(n->nredir.redirect);
8296 calcsize(n->nredir.n);
8303 calcsize(n->nbinary.ch2);
8304 calcsize(n->nbinary.ch1);
8307 calcsize(n->nif.elsepart);
8308 calcsize(n->nif.ifpart);
8309 calcsize(n->nif.test);
8312 funcstringsize += strlen(n->nfor.var) + 1;
8313 calcsize(n->nfor.body);
8314 calcsize(n->nfor.args);
8317 calcsize(n->ncase.cases);
8318 calcsize(n->ncase.expr);
8321 calcsize(n->nclist.body);
8322 calcsize(n->nclist.pattern);
8323 calcsize(n->nclist.next);
8327 sizenodelist(n->narg.backquote);
8328 funcstringsize += strlen(n->narg.text) + 1;
8329 calcsize(n->narg.next);
8336 calcsize(n->nfile.fname);
8337 calcsize(n->nfile.next);
8341 calcsize(n->ndup.vname);
8342 calcsize(n->ndup.next);
8346 calcsize(n->nhere.doc);
8347 calcsize(n->nhere.next);
8350 calcsize(n->nnot.com);
8357 sizenodelist(struct nodelist *lp)
8360 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8368 copynode(union node *n)
8375 funcblock = (char *) funcblock + nodesize[n->type];
8379 new->ncmd.redirect = copynode(n->ncmd.redirect);
8380 new->ncmd.args = copynode(n->ncmd.args);
8381 new->ncmd.assign = copynode(n->ncmd.assign);
8384 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8385 new->npipe.backgnd = n->npipe.backgnd;
8390 new->nredir.redirect = copynode(n->nredir.redirect);
8391 new->nredir.n = copynode(n->nredir.n);
8398 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8399 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8402 new->nif.elsepart = copynode(n->nif.elsepart);
8403 new->nif.ifpart = copynode(n->nif.ifpart);
8404 new->nif.test = copynode(n->nif.test);
8407 new->nfor.var = nodesavestr(n->nfor.var);
8408 new->nfor.body = copynode(n->nfor.body);
8409 new->nfor.args = copynode(n->nfor.args);
8412 new->ncase.cases = copynode(n->ncase.cases);
8413 new->ncase.expr = copynode(n->ncase.expr);
8416 new->nclist.body = copynode(n->nclist.body);
8417 new->nclist.pattern = copynode(n->nclist.pattern);
8418 new->nclist.next = copynode(n->nclist.next);
8422 new->narg.backquote = copynodelist(n->narg.backquote);
8423 new->narg.text = nodesavestr(n->narg.text);
8424 new->narg.next = copynode(n->narg.next);
8431 new->nfile.fname = copynode(n->nfile.fname);
8432 new->nfile.fd = n->nfile.fd;
8433 new->nfile.next = copynode(n->nfile.next);
8437 new->ndup.vname = copynode(n->ndup.vname);
8438 new->ndup.dupfd = n->ndup.dupfd;
8439 new->ndup.fd = n->ndup.fd;
8440 new->ndup.next = copynode(n->ndup.next);
8444 new->nhere.doc = copynode(n->nhere.doc);
8445 new->nhere.fd = n->nhere.fd;
8446 new->nhere.next = copynode(n->nhere.next);
8449 new->nnot.com = copynode(n->nnot.com);
8452 new->type = n->type;
8457 static struct nodelist *
8458 copynodelist(struct nodelist *lp)
8460 struct nodelist *start;
8461 struct nodelist **lpp;
8466 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8467 (*lpp)->n = copynode(lp->n);
8469 lpp = &(*lpp)->next;
8477 nodesavestr(char *s)
8479 char *rtn = funcstring;
8481 strcpy(funcstring, s);
8482 funcstring += strlen(s) + 1;
8488 * Free a parse tree.
8491 freefunc(struct funcnode *f)
8493 if (f && --f->count < 0)
8498 static void setoption(int, int);
8507 setinteractive(iflag);
8512 static void minus_o(char *name, int val)
8517 for (i = 0; i < NOPTS; i++) {
8518 if (equal(name, optnames(i))) {
8523 ash_msg_and_raise_error("Illegal option -o %s", name);
8525 out1str("Current option settings\n");
8526 for (i = 0; i < NOPTS; i++)
8527 out1fmt("%-16s%s\n", optnames(i),
8528 optlist[i] ? "on" : "off");
8533 * Process shell options. The global variable argptr contains a pointer
8534 * to the argument list; we advance it past the options.
8537 options(int cmdline)
8545 while ((p = *argptr) != NULL) {
8550 if (p[0] == '\0' || LONE_DASH(p)) {
8552 /* "-" means turn off -x and -v */
8555 /* "--" means reset params */
8556 else if (*argptr == NULL)
8559 break; /* "-" or "--" terminates options */
8561 } else if (c == '+') {
8567 while ((c = *p++) != '\0') {
8568 if (c == 'c' && cmdline) {
8569 minusc = p; /* command is after shell args*/
8570 } else if (c == 'o') {
8571 minus_o(*argptr, val);
8574 } else if (cmdline && (c == '-')) { // long options
8575 if (strcmp(p, "login") == 0)
8587 setoption(int flag, int val)
8591 for (i = 0; i < NOPTS; i++) {
8592 if (optletters(i) == flag) {
8597 ash_msg_and_raise_error("Illegal option -%c", flag);
8603 * Set the shell parameters.
8606 setparam(char **argv)
8612 for (nparam = 0; argv[nparam]; nparam++);
8613 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
8615 *ap++ = savestr(*argv++);
8618 freeparam(&shellparam);
8619 shellparam.malloc = 1;
8620 shellparam.nparam = nparam;
8621 shellparam.p = newparam;
8622 #if ENABLE_ASH_GETOPTS
8623 shellparam.optind = 1;
8624 shellparam.optoff = -1;
8630 * Free the list of positional parameters.
8633 freeparam(volatile struct shparam *param)
8637 if (param->malloc) {
8638 for (ap = param->p; *ap; ap++)
8646 * The shift builtin command.
8649 shiftcmd(int argc, char **argv)
8656 n = number(argv[1]);
8657 if (n > shellparam.nparam)
8658 ash_msg_and_raise_error("can't shift that many");
8660 shellparam.nparam -= n;
8661 for (ap1 = shellparam.p; --n >= 0; ap1++) {
8662 if (shellparam.malloc)
8666 while ((*ap2++ = *ap1++) != NULL);
8667 #if ENABLE_ASH_GETOPTS
8668 shellparam.optind = 1;
8669 shellparam.optoff = -1;
8677 * The set command builtin.
8680 setcmd(int argc, char **argv)
8683 return showvars(nullstr, 0, VUNSET);
8687 if (*argptr != NULL) {
8695 #if ENABLE_ASH_GETOPTS
8697 getoptsreset(const char *value)
8699 shellparam.optind = number(value);
8700 shellparam.optoff = -1;
8704 #if ENABLE_LOCALE_SUPPORT
8705 static void change_lc_all(const char *value)
8707 if (value && *value != '\0')
8708 setlocale(LC_ALL, value);
8711 static void change_lc_ctype(const char *value)
8713 if (value && *value != '\0')
8714 setlocale(LC_CTYPE, value);
8719 #if ENABLE_ASH_RANDOM_SUPPORT
8720 /* Roughly copied from bash.. */
8721 static void change_random(const char *value)
8723 if (value == NULL) {
8724 /* "get", generate */
8727 rseed = rseed * 1103515245 + 12345;
8728 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
8729 /* set without recursion */
8730 setvar(vrandom.text, buf, VNOFUNC);
8731 vrandom.flags &= ~VNOFUNC;
8734 rseed = strtoul(value, (char **)NULL, 10);
8740 #if ENABLE_ASH_GETOPTS
8742 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
8751 if (*param_optind < 1)
8753 optnext = optfirst + *param_optind - 1;
8755 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
8758 p = optnext[-1] + *optoff;
8759 if (p == NULL || *p == '\0') {
8760 /* Current word is done, advance */
8762 if (p == NULL || *p != '-' || *++p == '\0') {
8769 if (LONE_DASH(p)) /* check for "--" */
8774 for (q = optstr; *q != c; ) {
8776 if (optstr[0] == ':') {
8779 err |= setvarsafe("OPTARG", s, 0);
8781 fprintf(stderr, "Illegal option -%c\n", c);
8782 (void) unsetvar("OPTARG");
8792 if (*p == '\0' && (p = *optnext) == NULL) {
8793 if (optstr[0] == ':') {
8796 err |= setvarsafe("OPTARG", s, 0);
8799 fprintf(stderr, "No arg for -%c option\n", c);
8800 (void) unsetvar("OPTARG");
8808 err |= setvarsafe("OPTARG", p, 0);
8811 err |= setvarsafe("OPTARG", nullstr, 0);
8813 *optoff = p ? p - *(optnext - 1) : -1;
8814 *param_optind = optnext - optfirst + 1;
8815 fmtstr(s, sizeof(s), "%d", *param_optind);
8816 err |= setvarsafe("OPTIND", s, VNOFUNC);
8819 err |= setvarsafe(optvar, s, 0);
8823 flush_stdout_stderr();
8824 raise_exception(EXERROR);
8831 * The getopts builtin. Shellparam.optnext points to the next argument
8832 * to be processed. Shellparam.optptr points to the next character to
8833 * be processed in the current argument. If shellparam.optnext is NULL,
8834 * then it's the first time getopts has been called.
8837 getoptscmd(int argc, char **argv)
8842 ash_msg_and_raise_error("Usage: getopts optstring var [arg]");
8843 else if (argc == 3) {
8844 optbase = shellparam.p;
8845 if (shellparam.optind > shellparam.nparam + 1) {
8846 shellparam.optind = 1;
8847 shellparam.optoff = -1;
8851 if (shellparam.optind > argc - 2) {
8852 shellparam.optind = 1;
8853 shellparam.optoff = -1;
8857 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
8858 &shellparam.optoff);
8860 #endif /* ASH_GETOPTS */
8863 * XXX - should get rid of. have all builtins use getopt(3). the
8864 * library getopt must have the BSD extension static variable "optreset"
8865 * otherwise it can't be used within the shell safely.
8867 * Standard option processing (a la getopt) for builtin routines. The
8868 * only argument that is passed to nextopt is the option string; the
8869 * other arguments are unnecessary. It return the character, or '\0' on
8873 nextopt(const char *optstring)
8880 if (p == NULL || *p == '\0') {
8882 if (p == NULL || *p != '-' || *++p == '\0')
8885 if (LONE_DASH(p)) /* check for "--" */
8889 for (q = optstring; *q != c; ) {
8891 ash_msg_and_raise_error("Illegal option -%c", c);
8896 if (*p == '\0' && (p = *argptr++) == NULL)
8897 ash_msg_and_raise_error("No arg for -%c option", c);
8910 * Shell command parser.
8913 #define EOFMARKLEN 79
8916 struct heredoc *next; /* next here document in list */
8917 union node *here; /* redirection node */
8918 char *eofmark; /* string indicating end of input */
8919 int striptabs; /* if set, strip leading tabs */
8922 static struct heredoc *heredoclist; /* list of here documents to read */
8924 static union node *list(int);
8925 static union node *andor(void);
8926 static union node *pipeline(void);
8927 static union node *command(void);
8928 static union node *simplecmd(void);
8929 static union node *makename(void);
8930 static void parsefname(void);
8931 static void parseheredoc(void);
8932 static char peektoken(void);
8933 static int readtoken(void);
8934 static int xxreadtoken(void);
8935 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
8936 static int noexpand(char *);
8937 static void setprompt(int);
8939 static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN;
8941 raise_error_syntax(const char *msg)
8943 ash_msg_and_raise_error("Syntax error: %s", msg);
8948 * Called when an unexpected token is read during the parse. The argument
8949 * is the token that is expected, or -1 if more than one type of token can
8950 * occur at this point.
8952 static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN;
8954 raise_error_unexpected_syntax(int token)
8959 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
8961 sprintf(msg + l, " (expecting %s)", tokname(token));
8962 raise_error_syntax(msg);
8967 * Read and parse a command. Returns NEOF on end of file. (NULL is a
8968 * valid parse tree indicating a blank line.)
8971 parsecmd(int interact)
8976 doprompt = interact;
8978 setprompt(doprompt);
8993 union node *n1, *n2, *n3;
8996 checkkwd = CHKNL | CHKKWD | CHKALIAS;
8997 if (nlflag == 2 && peektoken())
9003 if (tok == TBACKGND) {
9004 if (n2->type == NPIPE) {
9005 n2->npipe.backgnd = 1;
9007 if (n2->type != NREDIR) {
9008 n3 = stalloc(sizeof(struct nredir));
9010 n3->nredir.redirect = NULL;
9013 n2->type = NBACKGND;
9019 n3 = stalloc(sizeof(struct nbinary));
9021 n3->nbinary.ch1 = n1;
9022 n3->nbinary.ch2 = n2;
9038 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9046 pungetc(); /* push back EOF on input */
9050 raise_error_unexpected_syntax(-1);
9061 union node *n1, *n2, *n3;
9069 } else if (t == TOR) {
9075 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9077 n3 = stalloc(sizeof(struct nbinary));
9079 n3->nbinary.ch1 = n1;
9080 n3->nbinary.ch2 = n2;
9089 union node *n1, *n2, *pipenode;
9090 struct nodelist *lp, *prev;
9094 TRACE(("pipeline: entered\n"));
9095 if (readtoken() == TNOT) {
9097 checkkwd = CHKKWD | CHKALIAS;
9101 if (readtoken() == TPIPE) {
9102 pipenode = stalloc(sizeof(struct npipe));
9103 pipenode->type = NPIPE;
9104 pipenode->npipe.backgnd = 0;
9105 lp = stalloc(sizeof(struct nodelist));
9106 pipenode->npipe.cmdlist = lp;
9110 lp = stalloc(sizeof(struct nodelist));
9111 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9114 } while (readtoken() == TPIPE);
9120 n2 = stalloc(sizeof(struct nnot));
9132 union node *n1, *n2;
9133 union node *ap, **app;
9134 union node *cp, **cpp;
9135 union node *redir, **rpp;
9142 switch (readtoken()) {
9144 raise_error_unexpected_syntax(-1);
9147 n1 = stalloc(sizeof(struct nif));
9149 n1->nif.test = list(0);
9150 if (readtoken() != TTHEN)
9151 raise_error_unexpected_syntax(TTHEN);
9152 n1->nif.ifpart = list(0);
9154 while (readtoken() == TELIF) {
9155 n2->nif.elsepart = stalloc(sizeof(struct nif));
9156 n2 = n2->nif.elsepart;
9158 n2->nif.test = list(0);
9159 if (readtoken() != TTHEN)
9160 raise_error_unexpected_syntax(TTHEN);
9161 n2->nif.ifpart = list(0);
9163 if (lasttoken == TELSE)
9164 n2->nif.elsepart = list(0);
9166 n2->nif.elsepart = NULL;
9174 n1 = stalloc(sizeof(struct nbinary));
9175 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9176 n1->nbinary.ch1 = list(0);
9177 if ((got=readtoken()) != TDO) {
9178 TRACE(("expecting DO got %s %s\n", tokname(got),
9179 got == TWORD ? wordtext : ""));
9180 raise_error_unexpected_syntax(TDO);
9182 n1->nbinary.ch2 = list(0);
9187 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9188 raise_error_syntax("Bad for loop variable");
9189 n1 = stalloc(sizeof(struct nfor));
9191 n1->nfor.var = wordtext;
9192 checkkwd = CHKKWD | CHKALIAS;
9193 if (readtoken() == TIN) {
9195 while (readtoken() == TWORD) {
9196 n2 = stalloc(sizeof(struct narg));
9198 n2->narg.text = wordtext;
9199 n2->narg.backquote = backquotelist;
9201 app = &n2->narg.next;
9205 if (lasttoken != TNL && lasttoken != TSEMI)
9206 raise_error_unexpected_syntax(-1);
9208 n2 = stalloc(sizeof(struct narg));
9210 n2->narg.text = (char *)dolatstr;
9211 n2->narg.backquote = NULL;
9212 n2->narg.next = NULL;
9215 * Newline or semicolon here is optional (but note
9216 * that the original Bourne shell only allowed NL).
9218 if (lasttoken != TNL && lasttoken != TSEMI)
9221 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9222 if (readtoken() != TDO)
9223 raise_error_unexpected_syntax(TDO);
9224 n1->nfor.body = list(0);
9228 n1 = stalloc(sizeof(struct ncase));
9230 if (readtoken() != TWORD)
9231 raise_error_unexpected_syntax(TWORD);
9232 n1->ncase.expr = n2 = stalloc(sizeof(struct narg));
9234 n2->narg.text = wordtext;
9235 n2->narg.backquote = backquotelist;
9236 n2->narg.next = NULL;
9238 checkkwd = CHKKWD | CHKALIAS;
9239 } while (readtoken() == TNL);
9240 if (lasttoken != TIN)
9241 raise_error_unexpected_syntax(TIN);
9242 cpp = &n1->ncase.cases;
9244 checkkwd = CHKNL | CHKKWD;
9246 while (t != TESAC) {
9247 if (lasttoken == TLP)
9249 *cpp = cp = stalloc(sizeof(struct nclist));
9251 app = &cp->nclist.pattern;
9253 *app = ap = stalloc(sizeof(struct narg));
9255 ap->narg.text = wordtext;
9256 ap->narg.backquote = backquotelist;
9257 if (readtoken() != TPIPE)
9259 app = &ap->narg.next;
9262 ap->narg.next = NULL;
9263 if (lasttoken != TRP)
9264 raise_error_unexpected_syntax(TRP);
9265 cp->nclist.body = list(2);
9267 cpp = &cp->nclist.next;
9269 checkkwd = CHKNL | CHKKWD;
9273 raise_error_unexpected_syntax(TENDCASE);
9280 n1 = stalloc(sizeof(struct nredir));
9281 n1->type = NSUBSHELL;
9282 n1->nredir.n = list(0);
9283 n1->nredir.redirect = NULL;
9296 if (readtoken() != t)
9297 raise_error_unexpected_syntax(t);
9300 /* Now check for redirection which may follow command */
9301 checkkwd = CHKKWD | CHKALIAS;
9303 while (readtoken() == TREDIR) {
9304 *rpp = n2 = redirnode;
9305 rpp = &n2->nfile.next;
9311 if (n1->type != NSUBSHELL) {
9312 n2 = stalloc(sizeof(struct nredir));
9317 n1->nredir.redirect = redir;
9326 union node *args, **app;
9327 union node *n = NULL;
9328 union node *vars, **vpp;
9329 union node **rpp, *redir;
9339 savecheckkwd = CHKALIAS;
9341 checkkwd = savecheckkwd;
9342 switch (readtoken()) {
9344 n = stalloc(sizeof(struct narg));
9346 n->narg.text = wordtext;
9347 n->narg.backquote = backquotelist;
9348 if (savecheckkwd && isassignment(wordtext)) {
9350 vpp = &n->narg.next;
9353 app = &n->narg.next;
9358 *rpp = n = redirnode;
9359 rpp = &n->nfile.next;
9360 parsefname(); /* read name of redirection file */
9363 if (args && app == &args->narg.next
9366 struct builtincmd *bcmd;
9369 /* We have a function */
9370 if (readtoken() != TRP)
9371 raise_error_unexpected_syntax(TRP);
9372 name = n->narg.text;
9374 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
9376 raise_error_syntax("Bad function name");
9379 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9380 n->narg.next = command();
9393 n = stalloc(sizeof(struct ncmd));
9395 n->ncmd.args = args;
9396 n->ncmd.assign = vars;
9397 n->ncmd.redirect = redir;
9406 n = stalloc(sizeof(struct narg));
9408 n->narg.next = NULL;
9409 n->narg.text = wordtext;
9410 n->narg.backquote = backquotelist;
9414 static void fixredir(union node *n, const char *text, int err)
9416 TRACE(("Fix redir %s %d\n", text, err));
9418 n->ndup.vname = NULL;
9420 if (is_digit(text[0]) && text[1] == '\0')
9421 n->ndup.dupfd = digit_val(text[0]);
9422 else if (LONE_DASH(text))
9426 raise_error_syntax("Bad fd number");
9427 n->ndup.vname = makename();
9435 union node *n = redirnode;
9437 if (readtoken() != TWORD)
9438 raise_error_unexpected_syntax(-1);
9439 if (n->type == NHERE) {
9440 struct heredoc *here = heredoc;
9446 TRACE(("Here document %d\n", n->type));
9447 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9448 raise_error_syntax("Illegal eof marker for << redirection");
9449 rmescapes(wordtext);
9450 here->eofmark = wordtext;
9452 if (heredoclist == NULL)
9455 for (p = heredoclist; p->next; p = p->next);
9458 } else if (n->type == NTOFD || n->type == NFROMFD) {
9459 fixredir(n, wordtext, 0);
9461 n->nfile.fname = makename();
9467 * Input any here documents.
9472 struct heredoc *here;
9482 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9483 here->eofmark, here->striptabs);
9484 n = stalloc(sizeof(struct narg));
9485 n->narg.type = NARG;
9486 n->narg.next = NULL;
9487 n->narg.text = wordtext;
9488 n->narg.backquote = backquotelist;
9489 here->here->nhere.doc = n;
9494 static char peektoken(void)
9500 return tokname_array[t][0];
9508 int alreadyseen = tokpushback;
9511 #if ENABLE_ASH_ALIAS
9520 if (checkkwd & CHKNL) {
9527 if (t != TWORD || quoteflag) {
9532 * check for keywords
9534 if (checkkwd & CHKKWD) {
9535 const char *const *pp;
9537 pp = findkwd(wordtext);
9539 lasttoken = t = pp - tokname_array;
9540 TRACE(("keyword %s recognized\n", tokname(t)));
9545 if (checkkwd & CHKALIAS) {
9546 #if ENABLE_ASH_ALIAS
9548 ap = lookupalias(wordtext, 1);
9551 pushstring(ap->val, ap);
9561 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9563 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9570 * Read the next input token.
9571 * If the token is a word, we set backquotelist to the list of cmds in
9572 * backquotes. We set quoteflag to true if any part of the word was
9574 * If the token is TREDIR, then we set redirnode to a structure containing
9576 * In all cases, the variable startlinno is set to the number of the line
9577 * on which the token starts.
9579 * [Change comment: here documents and internal procedures]
9580 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9581 * word parsing code into a separate routine. In this case, readtoken
9582 * doesn't need to have any internal procedures, but parseword does.
9583 * We could also make parseoperator in essence the main routine, and
9584 * have parseword (readtoken1?) handle both words and redirection.]
9586 #define NEW_xxreadtoken
9587 #ifdef NEW_xxreadtoken
9588 /* singles must be first! */
9589 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9591 static const char xxreadtoken_tokens[] = {
9592 TNL, TLP, TRP, /* only single occurrence allowed */
9593 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9594 TEOF, /* corresponds to trailing nul */
9595 TAND, TOR, TENDCASE, /* if double occurrence */
9598 #define xxreadtoken_doubles \
9599 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9600 #define xxreadtoken_singles \
9601 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9603 static int xxreadtoken(void)
9614 startlinno = plinno;
9615 for (;;) { /* until token or start of word found */
9618 if ((c != ' ') && (c != '\t')
9619 #if ENABLE_ASH_ALIAS
9624 while ((c = pgetc()) != '\n' && c != PEOF);
9626 } else if (c == '\\') {
9627 if (pgetc() != '\n') {
9631 startlinno = ++plinno;
9636 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
9641 needprompt = doprompt;
9644 p = strchr(xxreadtoken_chars, c);
9647 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
9650 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
9651 if (pgetc() == *p) { /* double occurrence? */
9652 p += xxreadtoken_doubles + 1;
9658 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
9664 #define RETURN(token) return lasttoken = token
9677 startlinno = plinno;
9678 for (;;) { /* until token or start of word found */
9681 case ' ': case '\t':
9682 #if ENABLE_ASH_ALIAS
9687 while ((c = pgetc()) != '\n' && c != PEOF);
9691 if (pgetc() == '\n') {
9692 startlinno = ++plinno;
9701 needprompt = doprompt;
9729 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
9732 #endif /* NEW_xxreadtoken */
9736 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
9737 * is not NULL, read a here document. In the latter case, eofmark is the
9738 * word which marks the end of the document and striptabs is true if
9739 * leading tabs should be stripped from the document. The argument firstc
9740 * is the first character of the input token or document.
9742 * Because C does not have internal subroutines, I have simulated them
9743 * using goto's to implement the subroutine linkage. The following macros
9744 * will run code that appears at the end of readtoken1.
9747 #define CHECKEND() {goto checkend; checkend_return:;}
9748 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
9749 #define PARSESUB() {goto parsesub; parsesub_return:;}
9750 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
9751 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
9752 #define PARSEARITH() {goto parsearith; parsearith_return:;}
9755 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
9760 char line[EOFMARKLEN + 1];
9761 struct nodelist *bqlist = 0;
9764 int varnest = 0; /* levels of variables expansion */
9765 int arinest = 0; /* levels of arithmetic expansion */
9766 int parenlevel = 0; /* levels of parens in arithmetic */
9767 int dqvarnest = 0; /* levels of variables expansion within double quotes */
9769 int prevsyntax = 0; /* syntax before arithmetic */
9771 /* Avoid longjmp clobbering */
9784 startlinno = plinno;
9786 if (syntax == DQSYNTAX)
9796 loop: { /* for each line, until end of word */
9797 CHECKEND(); /* set c to PEOF if at end of here document */
9798 for (;;) { /* until end of line or end of word */
9799 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
9800 switch (SIT(c, syntax)) {
9801 case CNL: /* '\n' */
9802 if (syntax == BASESYNTAX)
9803 goto endword; /* exit outer loop */
9809 goto loop; /* continue outer loop */
9814 if (eofmark == NULL || dblquote)
9815 USTPUTC(CTLESC, out);
9818 case CBACK: /* backslash */
9821 USTPUTC(CTLESC, out);
9824 } else if (c == '\n') {
9829 c != '\\' && c != '`' &&
9834 USTPUTC(CTLESC, out);
9837 if (SIT(c, SQSYNTAX) == CCTL)
9838 USTPUTC(CTLESC, out);
9846 if (eofmark == NULL) {
9847 USTPUTC(CTLQUOTEMARK, out);
9855 if (eofmark != NULL && arinest == 0
9860 if (dqvarnest == 0) {
9861 syntax = BASESYNTAX;
9868 case CVAR: /* '$' */
9869 PARSESUB(); /* parse substitution */
9871 case CENDVAR: /* '}' */
9874 if (dqvarnest > 0) {
9877 USTPUTC(CTLENDVAR, out);
9882 #if ENABLE_ASH_MATH_SUPPORT
9883 case CLP: /* '(' in arithmetic */
9887 case CRP: /* ')' in arithmetic */
9888 if (parenlevel > 0) {
9892 if (pgetc() == ')') {
9893 if (--arinest == 0) {
9894 USTPUTC(CTLENDARI, out);
9895 syntax = prevsyntax;
9896 if (syntax == DQSYNTAX)
9905 * (don't 2nd guess - no error)
9913 case CBQUOTE: /* '`' */
9917 goto endword; /* exit outer loop */
9922 goto endword; /* exit outer loop */
9923 #if ENABLE_ASH_ALIAS
9933 #if ENABLE_ASH_MATH_SUPPORT
9934 if (syntax == ARISYNTAX)
9935 raise_error_syntax("Missing '))'");
9937 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
9938 raise_error_syntax("Unterminated quoted string");
9940 startlinno = plinno;
9942 raise_error_syntax("Missing '}'");
9945 len = out - (char *)stackblock();
9947 if (eofmark == NULL) {
9948 if ((c == '>' || c == '<')
9951 && (*out == '\0' || is_digit(*out))) {
9953 return lasttoken = TREDIR;
9959 backquotelist = bqlist;
9960 grabstackblock(len);
9964 /* end of readtoken routine */
9968 * Check to see whether we are at the end of the here document. When this
9969 * is called, c is set to the first character of the next input line. If
9970 * we are at the end of the here document, this routine sets the c to PEOF.
9974 #if ENABLE_ASH_ALIAS
9984 if (c == *eofmark) {
9985 if (pfgets(line, sizeof(line)) != NULL) {
9989 for (q = eofmark + 1; *q && *p == *q; p++, q++);
9990 if (*p == '\n' && *q == '\0') {
9993 needprompt = doprompt;
9995 pushstring(line, NULL);
10000 goto checkend_return;
10005 * Parse a redirection operator. The variable "out" points to a string
10006 * specifying the fd to be redirected. The variable "c" contains the
10007 * first character of the redirection operator.
10013 np = stalloc(sizeof(struct nfile));
10018 np->type = NAPPEND;
10020 np->type = NCLOBBER;
10027 } else { /* c == '<' */
10032 if (sizeof(struct nfile) != sizeof(struct nhere)) {
10033 np = stalloc(sizeof(struct nhere));
10037 heredoc = stalloc(sizeof(struct heredoc));
10038 heredoc->here = np;
10041 heredoc->striptabs = 1;
10043 heredoc->striptabs = 0;
10049 np->type = NFROMFD;
10053 np->type = NFROMTO;
10063 np->nfile.fd = digit_val(fd);
10065 goto parseredir_return;
10070 * Parse a substitution. At this point, we have read the dollar sign
10071 * and nothing else.
10078 static const char types[] = "}-+?=";
10082 c <= PEOA_OR_PEOF ||
10083 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10087 } else if (c == '(') { /* $(command) or $((arith)) */
10088 if (pgetc() == '(') {
10089 #if ENABLE_ASH_MATH_SUPPORT
10092 raise_error_syntax("We unsupport $((arith))");
10099 USTPUTC(CTLVAR, out);
10100 typeloc = out - (char *)stackblock();
10101 USTPUTC(VSNORMAL, out);
10102 subtype = VSNORMAL;
10110 subtype = VSLENGTH;
10114 if (c > PEOA_OR_PEOF && is_name(c)) {
10118 } while (c > PEOA_OR_PEOF && is_in_name(c));
10119 } else if (is_digit(c)) {
10123 } while (is_digit(c));
10124 } else if (is_special(c)) {
10128 badsub: raise_error_syntax("Bad substitution");
10132 if (subtype == 0) {
10139 p = strchr(types, c);
10142 subtype = p - types + VSNORMAL;
10148 subtype = c == '#' ? VSTRIMLEFT :
10161 if (dblquote || arinest)
10163 *((char *)stackblock() + typeloc) = subtype | flags;
10164 if (subtype != VSNORMAL) {
10166 if (dblquote || arinest) {
10171 goto parsesub_return;
10176 * Called to parse command substitutions. Newstyle is set if the command
10177 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10178 * list of commands (passed by reference), and savelen is the number of
10179 * characters on the top of the stack which must be preserved.
10182 struct nodelist **nlpp;
10185 char *volatile str;
10186 struct jmploc jmploc;
10187 struct jmploc *volatile savehandler;
10189 int saveprompt = 0;
10191 (void) &saveprompt;
10194 savepbq = parsebackquote;
10195 if (setjmp(jmploc.loc)) {
10198 parsebackquote = 0;
10199 exception_handler = savehandler;
10200 longjmp(exception_handler->loc, 1);
10204 savelen = out - (char *)stackblock();
10206 str = ckmalloc(savelen);
10207 memcpy(str, stackblock(), savelen);
10209 savehandler = exception_handler;
10210 exception_handler = &jmploc;
10213 /* We must read until the closing backquote, giving special
10214 treatment to some slashes, and then push the string and
10215 reread it as input, interpreting it normally. */
10222 STARTSTACKSTR(pout);
10239 * If eating a newline, avoid putting
10240 * the newline into the new character
10241 * stream (via the STPUTC after the
10246 if (pc != '\\' && pc != '`' && pc != '$'
10247 && (!dblquote || pc != '"'))
10248 STPUTC('\\', pout);
10249 if (pc > PEOA_OR_PEOF) {
10255 #if ENABLE_ASH_ALIAS
10258 startlinno = plinno;
10259 raise_error_syntax("EOF in backquote substitution");
10263 needprompt = doprompt;
10272 STPUTC('\0', pout);
10273 psavelen = pout - (char *)stackblock();
10274 if (psavelen > 0) {
10275 pstr = grabstackstr(pout);
10276 setinputstring(pstr);
10281 nlpp = &(*nlpp)->next;
10282 *nlpp = stalloc(sizeof(**nlpp));
10283 (*nlpp)->next = NULL;
10284 parsebackquote = oldstyle;
10287 saveprompt = doprompt;
10294 doprompt = saveprompt;
10296 if (readtoken() != TRP)
10297 raise_error_unexpected_syntax(TRP);
10303 * Start reading from old file again, ignoring any pushed back
10304 * tokens left from the backquote parsing
10309 while (stackblocksize() <= savelen)
10311 STARTSTACKSTR(out);
10313 memcpy(out, str, savelen);
10314 STADJUST(savelen, out);
10320 parsebackquote = savepbq;
10321 exception_handler = savehandler;
10322 if (arinest || dblquote)
10323 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10325 USTPUTC(CTLBACKQ, out);
10327 goto parsebackq_oldreturn;
10328 goto parsebackq_newreturn;
10331 #if ENABLE_ASH_MATH_SUPPORT
10333 * Parse an arithmetic expansion (indicate start of one and set state)
10336 if (++arinest == 1) {
10337 prevsyntax = syntax;
10338 syntax = ARISYNTAX;
10339 USTPUTC(CTLARI, out);
10346 * we collapse embedded arithmetic expansion to
10347 * parenthesis, which should be equivalent
10351 goto parsearith_return;
10355 } /* end of readtoken */
10359 * Returns true if the text contains nothing to expand (no dollar signs
10363 noexpand(char *text)
10369 while ((c = *p++) != '\0') {
10370 if (c == CTLQUOTEMARK)
10374 else if (SIT(c, BASESYNTAX) == CCTL)
10382 * Return of a legal variable name (a letter or underscore followed by zero or
10383 * more letters, underscores, and digits).
10386 endofname(const char *name)
10394 if (!is_in_name(*p))
10402 * called by editline -- any expansions to the prompt
10403 * should be added here.
10405 #if ENABLE_ASH_EXPAND_PRMT
10406 static const char *
10407 expandstr(const char *ps)
10411 /* XXX Fix (char *) cast. */
10412 setinputstring((char *)ps);
10413 readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
10416 n.narg.type = NARG;
10417 n.narg.next = NULL;
10418 n.narg.text = wordtext;
10419 n.narg.backquote = backquotelist;
10421 expandarg(&n, NULL, 0);
10422 return stackblock();
10426 static void setprompt(int whichprompt)
10428 const char *prompt;
10429 #if ENABLE_ASH_EXPAND_PRMT
10430 struct stackmark smark;
10435 switch (whichprompt) {
10445 #if ENABLE_ASH_EXPAND_PRMT
10446 setstackmark(&smark);
10447 stalloc(stackblocksize());
10449 putprompt(expandstr(prompt));
10450 #if ENABLE_ASH_EXPAND_PRMT
10451 popstackmark(&smark);
10456 static const char *const *findkwd(const char *s)
10458 return bsearch(s, tokname_array + KWDOFFSET,
10459 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10460 sizeof(const char *), pstrcmp);
10466 * Code for dealing with input/output redirection.
10469 #define EMPTY -2 /* marks an unused slot in redirtab */
10471 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10473 # define PIPESIZE PIPE_BUF
10477 * Open a file in noclobber mode.
10478 * The code was copied from bash.
10480 static int noclobberopen(const char *fname)
10483 struct stat finfo, finfo2;
10486 * If the file exists and is a regular file, return an error
10489 r = stat(fname, &finfo);
10490 if (r == 0 && S_ISREG(finfo.st_mode)) {
10496 * If the file was not present (r != 0), make sure we open it
10497 * exclusively so that if it is created before we open it, our open
10498 * will fail. Make sure that we do not truncate an existing file.
10499 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10500 * file was not a regular file, we leave O_EXCL off.
10503 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10504 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10506 /* If the open failed, return the file descriptor right away. */
10511 * OK, the open succeeded, but the file may have been changed from a
10512 * non-regular file to a regular file between the stat and the open.
10513 * We are assuming that the O_EXCL open handles the case where FILENAME
10514 * did not exist and is symlinked to an existing file between the stat
10519 * If we can open it and fstat the file descriptor, and neither check
10520 * revealed that it was a regular file, and the file has not been
10521 * replaced, return the file descriptor.
10523 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode)
10524 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10527 /* The file has been replaced. badness. */
10535 * Handle here documents. Normally we fork off a process to write the
10536 * data to a pipe. If the document is short, we can stuff the data in
10537 * the pipe without forking.
10539 static int openhere(union node *redir)
10545 ash_msg_and_raise_error("Pipe call failed");
10546 if (redir->type == NHERE) {
10547 len = strlen(redir->nhere.doc->narg.text);
10548 if (len <= PIPESIZE) {
10549 full_write(pip[1], redir->nhere.doc->narg.text, len);
10553 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10555 signal(SIGINT, SIG_IGN);
10556 signal(SIGQUIT, SIG_IGN);
10557 signal(SIGHUP, SIG_IGN);
10559 signal(SIGTSTP, SIG_IGN);
10561 signal(SIGPIPE, SIG_DFL);
10562 if (redir->type == NHERE)
10563 full_write(pip[1], redir->nhere.doc->narg.text, len);
10565 expandhere(redir->nhere.doc, pip[1]);
10574 openredirect(union node *redir)
10579 switch (redir->nfile.type) {
10581 fname = redir->nfile.expfname;
10582 f = open(fname, O_RDONLY);
10587 fname = redir->nfile.expfname;
10588 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666);
10593 /* Take care of noclobber mode. */
10595 fname = redir->nfile.expfname;
10596 f = noclobberopen(fname);
10603 fname = redir->nfile.expfname;
10604 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10609 fname = redir->nfile.expfname;
10610 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
10618 /* Fall through to eliminate warning. */
10625 f = openhere(redir);
10631 ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "Directory nonexistent"));
10633 ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "No such file"));
10636 static void dupredirect(union node *redir, int f)
10638 int fd = redir->nfile.fd;
10640 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
10641 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
10642 copyfd(redir->ndup.dupfd, fd);
10655 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
10656 * old file descriptors are stashed away so that the redirection can be
10657 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
10658 * standard output, and the standard error if it becomes a duplicate of
10659 * stdout, is saved in memory.
10662 redirect(union node *redir, int flags)
10665 struct redirtab *sv;
10676 if (flags & REDIR_PUSH) {
10677 struct redirtab *q;
10678 q = ckmalloc(sizeof(struct redirtab));
10679 q->next = redirlist;
10681 q->nullredirs = nullredirs - 1;
10682 for (i = 0; i < 10; i++)
10683 q->renamed[i] = EMPTY;
10690 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD)
10691 && n->ndup.dupfd == fd)
10692 continue; /* redirect from/to same file descriptor */
10694 newfd = openredirect(n);
10697 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
10698 i = fcntl(fd, F_DUPFD, 10);
10705 ash_msg_and_raise_error("%d: %m", fd);
10715 dupredirect(n, newfd);
10716 } while ((n = n->nfile.next));
10718 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
10719 preverrout_fd = sv->renamed[2];
10724 * Undo the effects of the last redirection.
10729 struct redirtab *rp;
10732 if (--nullredirs >= 0)
10736 for (i = 0; i < 10; i++) {
10737 if (rp->renamed[i] != EMPTY) {
10740 copyfd(rp->renamed[i], i);
10742 close(rp->renamed[i]);
10745 redirlist = rp->next;
10746 nullredirs = rp->nullredirs;
10752 * Undo all redirections. Called on error or interrupt.
10756 * Discard all saved file descriptors.
10759 clearredir(int drop)
10771 * Copy a file descriptor to be >= to. Returns -1
10772 * if the source file descriptor is closed, EMPTY if there are no unused
10773 * file descriptors left.
10776 copyfd(int from, int to)
10780 newfd = fcntl(from, F_DUPFD, to);
10782 if (errno == EMFILE)
10784 ash_msg_and_raise_error("%d: %m", from);
10791 redirectsafe(union node *redir, int flags)
10794 volatile int saveint;
10795 struct jmploc *volatile savehandler = exception_handler;
10796 struct jmploc jmploc;
10799 err = setjmp(jmploc.loc) * 2;
10801 exception_handler = &jmploc;
10802 redirect(redir, flags);
10804 exception_handler = savehandler;
10805 if (err && exception != EXERROR)
10806 longjmp(exception_handler->loc, 1);
10807 RESTORE_INT(saveint);
10814 static void shtree(union node *, int, char *, FILE*);
10815 static void shcmd(union node *, FILE *);
10816 static void sharg(union node *, FILE *);
10817 static void indent(int, char *, FILE *);
10818 static void trstring(char *);
10822 showtree(union node *n)
10824 trputs("showtree called\n");
10825 shtree(n, 1, NULL, stdout);
10830 shtree(union node *n, int ind, char *pfx, FILE *fp)
10832 struct nodelist *lp;
10838 indent(ind, pfx, fp);
10849 shtree(n->nbinary.ch1, ind, NULL, fp);
10852 shtree(n->nbinary.ch2, ind, NULL, fp);
10860 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
10865 if (n->npipe.backgnd)
10871 fprintf(fp, "<node type %d>", n->type);
10880 shcmd(union node *cmd, FILE *fp)
10888 for (np = cmd->ncmd.args; np; np = np->narg.next) {
10894 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
10897 switch (np->nfile.type) {
10898 case NTO: s = ">"; dftfd = 1; break;
10899 case NCLOBBER: s = ">|"; dftfd = 1; break;
10900 case NAPPEND: s = ">>"; dftfd = 1; break;
10901 case NTOFD: s = ">&"; dftfd = 1; break;
10902 case NFROM: s = "<"; dftfd = 0; break;
10903 case NFROMFD: s = "<&"; dftfd = 0; break;
10904 case NFROMTO: s = "<>"; dftfd = 0; break;
10905 default: s = "*error*"; dftfd = 0; break;
10907 if (np->nfile.fd != dftfd)
10908 fprintf(fp, "%d", np->nfile.fd);
10910 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
10911 fprintf(fp, "%d", np->ndup.dupfd);
10913 sharg(np->nfile.fname, fp);
10921 sharg(union node *arg, FILE *fp)
10924 struct nodelist *bqlist;
10927 if (arg->type != NARG) {
10928 out1fmt("<node type %d>\n", arg->type);
10931 bqlist = arg->narg.backquote;
10932 for (p = arg->narg.text; *p; p++) {
10941 if (subtype == VSLENGTH)
10947 if (subtype & VSNUL)
10950 switch (subtype & VSTYPE) {
10969 case VSTRIMLEFTMAX:
10976 case VSTRIMRIGHTMAX:
10983 out1fmt("<subtype %d>", subtype);
10990 case CTLBACKQ|CTLQUOTE:
10993 shtree(bqlist->n, -1, NULL, fp);
11005 indent(int amount, char *pfx, FILE *fp)
11009 for (i = 0; i < amount; i++) {
11010 if (pfx && i == amount - 1)
11022 static FILE *tracefile;
11030 putc(c, tracefile);
11034 trace(const char *fmt, ...)
11041 (void) vfprintf(tracefile, fmt, va);
11046 tracev(const char *fmt, va_list va)
11050 (void) vfprintf(tracefile, fmt, va);
11055 trputs(const char *s)
11059 fputs(s, tracefile);
11071 putc('"', tracefile);
11072 for (p = s; *p; p++) {
11074 case '\n': c = 'n'; goto backslash;
11075 case '\t': c = 't'; goto backslash;
11076 case '\r': c = 'r'; goto backslash;
11077 case '"': c = '"'; goto backslash;
11078 case '\\': c = '\\'; goto backslash;
11079 case CTLESC: c = 'e'; goto backslash;
11080 case CTLVAR: c = 'v'; goto backslash;
11081 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11082 case CTLBACKQ: c = 'q'; goto backslash;
11083 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11085 putc('\\', tracefile);
11086 putc(c, tracefile);
11089 if (*p >= ' ' && *p <= '~')
11090 putc(*p, tracefile);
11092 putc('\\', tracefile);
11093 putc(*p >> 6 & 03, tracefile);
11094 putc(*p >> 3 & 07, tracefile);
11095 putc(*p & 07, tracefile);
11100 putc('"', tracefile);
11112 putc(' ', tracefile);
11114 putc('\n', tracefile);
11130 /* leave open because libedit might be using it */
11133 scopy("./trace", s);
11135 if (!freopen(s, "a", tracefile)) {
11136 fprintf(stderr, "Can't re-open %s\n", s);
11141 tracefile = fopen(s, "a");
11142 if (tracefile == NULL) {
11143 fprintf(stderr, "Can't open %s\n", s);
11149 flags = fcntl(fileno(tracefile), F_GETFL, 0);
11151 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11153 setlinebuf(tracefile);
11154 fputs("\nTracing started.\n", tracefile);
11162 * Sigmode records the current value of the signal handlers for the various
11163 * modes. A value of zero means that the current handler is not known.
11164 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11167 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11168 #define S_CATCH 2 /* signal is caught */
11169 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11170 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11171 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11175 * The trap builtin.
11178 trapcmd(int argc, char **argv)
11187 for (signo = 0; signo < NSIG; signo++) {
11188 if (trap[signo] != NULL) {
11191 sn = get_signame(signo);
11192 out1fmt("trap -- %s %s\n",
11193 single_quote(trap[signo]), sn);
11203 signo = get_signum(*ap);
11205 ash_msg_and_raise_error("%s: bad trap", *ap);
11208 if (LONE_DASH(action))
11211 action = savestr(action);
11215 trap[signo] = action;
11226 * Clear traps on a fork.
11233 for (tp = trap; tp < &trap[NSIG]; tp++) {
11234 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11238 if (tp != &trap[0])
11239 setsignal(tp - trap);
11247 * Set the signal handler for the specified signal. The routine figures
11248 * out what it should be set to.
11251 setsignal(int signo)
11255 struct sigaction act;
11260 else if (*t != '\0')
11264 if (rootshell && action == S_DFL) {
11267 if (iflag || minusc || sflag == 0)
11290 t = &sigmode[signo - 1];
11294 * current setting unknown
11296 if (sigaction(signo, 0, &act) == -1) {
11298 * Pretend it worked; maybe we should give a warning
11299 * here, but other shells don't. We don't alter
11300 * sigmode, so that we retry every time.
11304 if (act.sa_handler == SIG_IGN) {
11306 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
11308 tsig = S_IGN; /* don't hard ignore these */
11312 tsig = S_RESET; /* force to be set */
11315 if (tsig == S_HARD_IGN || tsig == action)
11319 act.sa_handler = onsig;
11322 act.sa_handler = SIG_IGN;
11325 act.sa_handler = SIG_DFL;
11329 sigfillset(&act.sa_mask);
11330 sigaction(signo, &act, 0);
11338 ignoresig(int signo)
11340 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11341 signal(signo, SIG_IGN);
11343 sigmode[signo - 1] = S_HARD_IGN;
11353 gotsig[signo - 1] = 1;
11354 pendingsigs = signo;
11356 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11365 * Called to execute a trap. Perhaps we should avoid entering new trap
11366 * handlers while we are executing a trap handler.
11377 savestatus = exitstatus;
11381 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
11389 skip = evalstring(p, SKIPEVAL);
11390 exitstatus = savestatus;
11400 * Controls whether the shell is interactive or not.
11403 setinteractive(int on)
11405 static int is_interactive;
11407 if (++on == is_interactive)
11409 is_interactive = on;
11411 setsignal(SIGQUIT);
11412 setsignal(SIGTERM);
11413 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
11414 if (is_interactive > 1) {
11415 /* Looks like they want an interactive shell */
11416 static int do_banner;
11421 "%s Built-in shell (ash)\n"
11422 "Enter 'help' for a list of built-in commands."
11432 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
11433 /*** List the available builtins ***/
11435 static int helpcmd(int argc, char **argv)
11439 out1fmt("\nBuilt-in commands:\n-------------------\n");
11440 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11441 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11442 builtincmd[i].name + 1);
11448 #if ENABLE_FEATURE_SH_STANDALONE_SHELL
11449 for (i = 0; i < NUM_APPLETS; i++) {
11450 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11458 return EXIT_SUCCESS;
11460 #endif /* FEATURE_SH_EXTRA_QUIET */
11464 * Called to exit the shell.
11473 status = exitstatus;
11474 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11475 if (setjmp(loc.loc)) {
11476 if (exception == EXEXIT)
11477 /* dash bug: it just does _exit(exitstatus) here
11478 * but we have to do setjobctl(0) first!
11479 * (bug is still not fixed in dash-0.5.3 - if you run dash
11480 * under Midnight Commander, on exit from dash MC is backgrounded) */
11481 status = exitstatus;
11484 exception_handler = &loc;
11490 flush_stdout_stderr();
11499 static struct var *vartab[VTABSIZE];
11501 static int vpcmp(const void *, const void *);
11502 static struct var **findvar(struct var **, const char *);
11505 * Initialize the variable symbol tables and import the environment
11509 #if ENABLE_ASH_GETOPTS
11511 * Safe version of setvar, returns 1 on success 0 on failure.
11514 setvarsafe(const char *name, const char *val, int flags)
11517 volatile int saveint;
11518 struct jmploc *volatile savehandler = exception_handler;
11519 struct jmploc jmploc;
11522 if (setjmp(jmploc.loc))
11525 exception_handler = &jmploc;
11526 setvar(name, val, flags);
11529 exception_handler = savehandler;
11530 RESTORE_INT(saveint);
11537 * Set the value of a variable. The flags argument is ored with the
11538 * flags of the variable. If val is NULL, the variable is unset.
11541 setvar(const char *name, const char *val, int flags)
11548 q = endofname(name);
11549 p = strchrnul(q, '=');
11550 namelen = p - name;
11551 if (!namelen || p != q)
11552 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
11557 vallen = strlen(val);
11560 nameeq = ckmalloc(namelen + vallen + 2);
11561 p = memcpy(nameeq, name, namelen) + namelen;
11564 p = memcpy(p, val, vallen) + vallen;
11567 setvareq(nameeq, flags | VNOSAVE);
11573 * Same as setvar except that the variable and value are passed in
11574 * the first argument as name=value. Since the first argument will
11575 * be actually stored in the table, it should not be a string that
11577 * Called with interrupts off.
11580 setvareq(char *s, int flags)
11582 struct var *vp, **vpp;
11585 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11586 vp = *findvar(vpp, s);
11588 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
11591 if (flags & VNOSAVE)
11594 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
11597 if (flags & VNOSET)
11600 if (vp->func && (flags & VNOFUNC) == 0)
11601 (*vp->func)(strchrnul(s, '=') + 1);
11603 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11604 free((char*)vp->text);
11606 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
11608 if (flags & VNOSET)
11611 vp = ckmalloc(sizeof(*vp));
11616 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
11624 * Process a linked list of variable assignments.
11627 listsetvar(struct strlist *list_set_var, int flags)
11629 struct strlist *lp = list_set_var;
11635 setvareq(lp->text, flags);
11636 } while ((lp = lp->next));
11642 * Find the value of a variable. Returns NULL if not set.
11645 lookupvar(const char *name)
11649 v = *findvar(hashvar(name), name);
11653 * Dynamic variables are implemented roughly the same way they are
11654 * in bash. Namely, they're "special" so long as they aren't unset.
11655 * As soon as they're unset, they're no longer dynamic, and dynamic
11656 * lookup will no longer happen at that point. -- PFM.
11658 if ((v->flags & VDYNAMIC))
11661 if (!(v->flags & VUNSET))
11662 return strchrnul(v->text, '=') + 1;
11670 * Search the environment of a builtin command.
11673 bltinlookup(const char *name)
11675 struct strlist *sp;
11677 for (sp = cmdenviron; sp; sp = sp->next) {
11678 if (varequal(sp->text, name))
11679 return strchrnul(sp->text, '=') + 1;
11681 return lookupvar(name);
11686 * Generate a list of variables satisfying the given conditions.
11689 listvars(int on, int off, char ***end)
11700 for (vp = *vpp; vp; vp = vp->next)
11701 if ((vp->flags & mask) == on) {
11702 if (ep == stackstrend())
11703 ep = growstackstr();
11704 *ep++ = (char *) vp->text;
11706 } while (++vpp < vartab + VTABSIZE);
11707 if (ep == stackstrend())
11708 ep = growstackstr();
11712 return grabstackstr(ep);
11717 * POSIX requires that 'set' (but not export or readonly) output the
11718 * variables in lexicographic order - by the locale's collating order (sigh).
11719 * Maybe we could keep them in an ordered balanced binary tree
11720 * instead of hashed lists.
11721 * For now just roll 'em through qsort for printing...
11724 showvars(const char *sep_prefix, int on, int off)
11727 char **ep, **epend;
11729 ep = listvars(on, off, &epend);
11730 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11732 sep = *sep_prefix ? spcstr : sep_prefix;
11734 for (; ep < epend; ep++) {
11738 p = strchrnul(*ep, '=');
11741 q = single_quote(++p);
11743 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11751 * The export and readonly commands.
11754 exportcmd(int argc, char **argv)
11760 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
11762 if (nextopt("p") != 'p') {
11767 p = strchr(name, '=');
11771 vp = *findvar(hashvar(name), name);
11777 setvar(name, p, flag);
11778 } while ((name = *++aptr) != NULL);
11782 showvars(argv[0], flag, 0);
11788 * Make a variable a local variable. When a variable is made local, it's
11789 * value and flags are saved in a localvar structure. The saved values
11790 * will be restored when the shell function returns. We handle the name
11791 * "-" as a special case.
11793 static void mklocal(char *name)
11795 struct localvar *lvp;
11800 lvp = ckmalloc(sizeof(struct localvar));
11801 if (LONE_DASH(name)) {
11803 p = ckmalloc(sizeof(optlist));
11804 lvp->text = memcpy(p, optlist, sizeof(optlist));
11809 vpp = hashvar(name);
11810 vp = *findvar(vpp, name);
11811 eq = strchr(name, '=');
11814 setvareq(name, VSTRFIXED);
11816 setvar(name, NULL, VSTRFIXED);
11817 vp = *vpp; /* the new variable */
11818 lvp->flags = VUNSET;
11820 lvp->text = vp->text;
11821 lvp->flags = vp->flags;
11822 vp->flags |= VSTRFIXED|VTEXTFIXED;
11828 lvp->next = localvars;
11835 * The "local" command.
11838 localcmd(int argc, char **argv)
11843 while ((name = *argv++) != NULL) {
11851 * Called after a function returns.
11852 * Interrupts must be off.
11857 struct localvar *lvp;
11860 while ((lvp = localvars) != NULL) {
11861 localvars = lvp->next;
11863 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
11864 if (vp == NULL) { /* $- saved */
11865 memcpy(optlist, lvp->text, sizeof(optlist));
11866 free((char*)lvp->text);
11868 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
11869 unsetvar(vp->text);
11872 (*vp->func)(strchrnul(lvp->text, '=') + 1);
11873 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11874 free((char*)vp->text);
11875 vp->flags = lvp->flags;
11876 vp->text = lvp->text;
11884 * The unset builtin command. We unset the function before we unset the
11885 * variable to allow a function to be unset when there is a readonly variable
11886 * with the same name.
11889 unsetcmd(int argc, char **argv)
11896 while ((i = nextopt("vf")) != '\0') {
11900 for (ap = argptr; *ap; ap++) {
11915 * Unset the specified variable.
11918 unsetvar(const char *s)
11924 vpp = findvar(hashvar(s), s);
11928 int flags = vp->flags;
11931 if (flags & VREADONLY)
11934 vp->flags &= ~VDYNAMIC;
11936 if (flags & VUNSET)
11938 if ((flags & VSTRFIXED) == 0) {
11940 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
11941 free((char*)vp->text);
11947 vp->flags &= ~VEXPORT;
11958 * Find the appropriate entry in the hash table from the name.
11960 static struct var **
11961 hashvar(const char *p)
11963 unsigned int hashval;
11965 hashval = ((unsigned char) *p) << 4;
11966 while (*p && *p != '=')
11967 hashval += (unsigned char) *p++;
11968 return &vartab[hashval % VTABSIZE];
11973 * Compares two strings up to the first = or '\0'. The first
11974 * string must be terminated by '='; the second may be terminated by
11975 * either '=' or '\0'.
11978 varcmp(const char *p, const char *q)
11982 while ((c = *p) == (d = *q)) {
11983 if (!c || c == '=')
11997 vpcmp(const void *a, const void *b)
11999 return varcmp(*(const char **)a, *(const char **)b);
12002 static struct var **
12003 findvar(struct var **vpp, const char *name)
12005 for (; *vpp; vpp = &(*vpp)->next) {
12006 if (varequal((*vpp)->text, name)) {
12014 #include <sys/times.h>
12016 static const unsigned char timescmd_str[] = {
12017 ' ', offsetof(struct tms, tms_utime),
12018 '\n', offsetof(struct tms, tms_stime),
12019 ' ', offsetof(struct tms, tms_cutime),
12020 '\n', offsetof(struct tms, tms_cstime),
12024 static int timescmd(int ac, char **av)
12026 long int clk_tck, s, t;
12027 const unsigned char *p;
12030 clk_tck = sysconf(_SC_CLK_TCK);
12035 t = *(clock_t *)(((char *) &buf) + p[1]);
12037 out1fmt("%ldm%ld.%.3lds%c",
12039 ((t - s * clk_tck) * 1000) / clk_tck,
12041 } while (*(p += 2));
12046 #if ENABLE_ASH_MATH_SUPPORT
12048 dash_arith(const char *s)
12054 result = arith(s, &errcode);
12057 ash_msg_and_raise_error("exponent less than 0");
12058 else if (errcode == -2)
12059 ash_msg_and_raise_error("divide by zero");
12060 else if (errcode == -5)
12061 ash_msg_and_raise_error("expression recursion loop detected");
12063 raise_error_syntax(s);
12072 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12073 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12075 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12078 letcmd(int argc, char **argv)
12085 ash_msg_and_raise_error("expression expected");
12086 for (ap = argv + 1; *ap; ap++) {
12087 i = dash_arith(*ap);
12092 #endif /* ASH_MATH_SUPPORT */
12097 * Miscellaneous builtins.
12102 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12103 typedef enum __rlimit_resource rlim_t;
12108 * The read builtin. The -e option causes backslashes to escape the
12109 * following character.
12111 * This uses unbuffered input, which may be avoidable in some cases.
12114 readcmd(int argc, char **argv)
12126 #if ENABLE_ASH_READ_NCHARS
12130 struct termios tty, old_tty;
12132 #if ENABLE_ASH_READ_TIMEOUT
12136 ts.tv_sec = ts.tv_usec = 0;
12141 #if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT
12142 while ((i = nextopt("p:rt:n:s")) != '\0')
12143 #elif ENABLE_ASH_READ_NCHARS
12144 while ((i = nextopt("p:rn:s")) != '\0')
12145 #elif ENABLE_ASH_READ_TIMEOUT
12146 while ((i = nextopt("p:rt:")) != '\0')
12148 while ((i = nextopt("p:r")) != '\0')
12153 prompt = optionarg;
12155 #if ENABLE_ASH_READ_NCHARS
12157 nchars = strtol(optionarg, &p, 10);
12159 ash_msg_and_raise_error("invalid count");
12160 nch_flag = (nchars > 0);
12166 #if ENABLE_ASH_READ_TIMEOUT
12168 ts.tv_sec = strtol(optionarg, &p, 10);
12174 ts.tv_usec = strtol(p, &p2, 10);
12176 ash_msg_and_raise_error("invalid timeout");
12178 /* normalize to usec */
12180 ash_msg_and_raise_error("invalid timeout");
12181 while (scale++ < 6)
12185 ash_msg_and_raise_error("invalid timeout");
12187 if ( ! ts.tv_sec && ! ts.tv_usec)
12188 ash_msg_and_raise_error("invalid timeout");
12198 if (prompt && isatty(0)) {
12203 ash_msg_and_raise_error("arg count");
12204 ifs = bltinlookup("IFS");
12207 #if ENABLE_ASH_READ_NCHARS
12208 if (nch_flag || silent) {
12209 tcgetattr(0, &tty);
12212 tty.c_lflag &= ~ICANON;
12213 tty.c_cc[VMIN] = nchars;
12216 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
12219 tcsetattr(0, TCSANOW, &tty);
12222 #if ENABLE_ASH_READ_TIMEOUT
12223 if (ts.tv_sec || ts.tv_usec) {
12227 i = select(FD_SETSIZE, &set, NULL, NULL, &ts);
12229 #if ENABLE_ASH_READ_NCHARS
12231 tcsetattr(0, TCSANOW, &old_tty);
12241 #if ENABLE_ASH_READ_NCHARS
12242 while (!nch_flag || nchars--)
12247 if (read(0, &c, 1) != 1) {
12259 if (!rflag && c == '\\') {
12265 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12269 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12271 setvar(*ap, stackblock(), 0);
12280 #if ENABLE_ASH_READ_NCHARS
12281 if (nch_flag || silent)
12282 tcsetattr(0, TCSANOW, &old_tty);
12286 /* Remove trailing blanks */
12287 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12289 setvar(*ap, stackblock(), 0);
12290 while (*++ap != NULL)
12291 setvar(*ap, nullstr, 0);
12296 static int umaskcmd(int argc, char **argv)
12298 static const char permuser[3] = "ugo";
12299 static const char permmode[3] = "rwx";
12300 static const short int permmask[] = {
12301 S_IRUSR, S_IWUSR, S_IXUSR,
12302 S_IRGRP, S_IWGRP, S_IXGRP,
12303 S_IROTH, S_IWOTH, S_IXOTH
12309 int symbolic_mode = 0;
12311 while (nextopt("S") != '\0') {
12322 if (symbolic_mode) {
12326 for (i = 0; i < 3; i++) {
12329 *p++ = permuser[i];
12331 for (j = 0; j < 3; j++) {
12332 if ((mask & permmask[3 * i + j]) == 0) {
12333 *p++ = permmode[j];
12341 out1fmt("%.4o\n", mask);
12344 if (is_digit((unsigned char) *ap)) {
12347 if (*ap >= '8' || *ap < '0')
12348 ash_msg_and_raise_error(illnum, argv[1]);
12349 mask = (mask << 3) + (*ap - '0');
12350 } while (*++ap != '\0');
12353 mask = ~mask & 0777;
12354 if (!bb_parse_mode(ap, &mask)) {
12355 ash_msg_and_raise_error("Illegal mode: %s", ap);
12357 umask(~mask & 0777);
12366 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12367 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12368 * ash by J.T. Conklin.
12376 int factor; /* multiply by to get rlim_{cur,max} values */
12380 static const struct limits limits[] = {
12382 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12384 #ifdef RLIMIT_FSIZE
12385 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12388 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12390 #ifdef RLIMIT_STACK
12391 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12394 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12397 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12399 #ifdef RLIMIT_MEMLOCK
12400 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12402 #ifdef RLIMIT_NPROC
12403 { "process", RLIMIT_NPROC, 1, 'p' },
12405 #ifdef RLIMIT_NOFILE
12406 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
12409 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
12411 #ifdef RLIMIT_LOCKS
12412 { "locks", RLIMIT_LOCKS, 1, 'w' },
12414 { (char *) 0, 0, 0, '\0' }
12417 enum limtype { SOFT = 0x1, HARD = 0x2 };
12419 static void printlim(enum limtype how, const struct rlimit *limit,
12420 const struct limits *l)
12424 val = limit->rlim_max;
12426 val = limit->rlim_cur;
12428 if (val == RLIM_INFINITY)
12429 out1fmt("unlimited\n");
12432 out1fmt("%lld\n", (long long) val);
12437 ulimitcmd(int argc, char **argv)
12441 enum limtype how = SOFT | HARD;
12442 const struct limits *l;
12445 struct rlimit limit;
12448 while ((optc = nextopt("HSa"
12452 #ifdef RLIMIT_FSIZE
12458 #ifdef RLIMIT_STACK
12467 #ifdef RLIMIT_MEMLOCK
12470 #ifdef RLIMIT_NPROC
12473 #ifdef RLIMIT_NOFILE
12479 #ifdef RLIMIT_LOCKS
12497 for (l = limits; l->option != what; l++)
12500 set = *argptr ? 1 : 0;
12504 if (all || argptr[1])
12505 ash_msg_and_raise_error("too many arguments");
12506 if (strncmp(p, "unlimited\n", 9) == 0)
12507 val = RLIM_INFINITY;
12511 while ((c = *p++) >= '0' && c <= '9') {
12512 val = (val * 10) + (long)(c - '0');
12513 if (val < (rlim_t) 0)
12517 ash_msg_and_raise_error("bad number");
12522 for (l = limits; l->name; l++) {
12523 getrlimit(l->cmd, &limit);
12524 out1fmt("%-20s ", l->name);
12525 printlim(how, &limit, l);
12530 getrlimit(l->cmd, &limit);
12533 limit.rlim_max = val;
12535 limit.rlim_cur = val;
12536 if (setrlimit(l->cmd, &limit) < 0)
12537 ash_msg_and_raise_error("error setting limit (%m)");
12539 printlim(how, &limit, l);
12545 #if ENABLE_ASH_MATH_SUPPORT
12547 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12549 Permission is hereby granted, free of charge, to any person obtaining
12550 a copy of this software and associated documentation files (the
12551 "Software"), to deal in the Software without restriction, including
12552 without limitation the rights to use, copy, modify, merge, publish,
12553 distribute, sublicense, and/or sell copies of the Software, and to
12554 permit persons to whom the Software is furnished to do so, subject to
12555 the following conditions:
12557 The above copyright notice and this permission notice shall be
12558 included in all copies or substantial portions of the Software.
12560 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12561 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12562 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12563 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12564 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12565 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12566 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12569 /* This is my infix parser/evaluator. It is optimized for size, intended
12570 * as a replacement for yacc-based parsers. However, it may well be faster
12571 * than a comparable parser written in yacc. The supported operators are
12572 * listed in #defines below. Parens, order of operations, and error handling
12573 * are supported. This code is thread safe. The exact expression format should
12574 * be that which POSIX specifies for shells. */
12576 /* The code uses a simple two-stack algorithm. See
12577 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12578 * for a detailed explanation of the infix-to-postfix algorithm on which
12579 * this is based (this code differs in that it applies operators immediately
12580 * to the stack instead of adding them to a queue to end up with an
12583 /* To use the routine, call it with an expression string and error return
12587 * Aug 24, 2001 Manuel Novoa III
12589 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12591 * 1) In arith_apply():
12592 * a) Cached values of *numptr and &(numptr[-1]).
12593 * b) Removed redundant test for zero denominator.
12596 * a) Eliminated redundant code for processing operator tokens by moving
12597 * to a table-based implementation. Also folded handling of parens
12599 * b) Combined all 3 loops which called arith_apply to reduce generated
12600 * code size at the cost of speed.
12602 * 3) The following expressions were treated as valid by the original code:
12603 * 1() , 0! , 1 ( *3 ) .
12604 * These bugs have been fixed by internally enclosing the expression in
12605 * parens and then checking that all binary ops and right parens are
12606 * preceded by a valid expression (NUM_TOKEN).
12608 * Note: It may be desirable to replace Aaron's test for whitespace with
12609 * ctype's isspace() if it is used by another busybox applet or if additional
12610 * whitespace chars should be considered. Look below the "#include"s for a
12611 * precompiler test.
12615 * Aug 26, 2001 Manuel Novoa III
12617 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12619 * Merge in Aaron's comments previously posted to the busybox list,
12620 * modified slightly to take account of my changes to the code.
12625 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12627 * - allow access to variable,
12628 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12629 * - realize assign syntax (VAR=expr, +=, *= etc)
12630 * - realize exponentiation (** operator)
12631 * - realize comma separated - expr, expr
12632 * - realise ++expr --expr expr++ expr--
12633 * - realise expr ? expr : expr (but, second expr calculate always)
12634 * - allow hexadecimal and octal numbers
12635 * - was restored loses XOR operator
12636 * - remove one goto label, added three ;-)
12637 * - protect $((num num)) as true zero expr (Manuel`s error)
12638 * - always use special isspace(), see comment from bash ;-)
12642 #define arith_isspace(arithval) \
12643 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12646 typedef unsigned char operator;
12648 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12649 * precedence, and 3 high bits are an ID unique across operators of that
12650 * precedence. The ID portion is so that multiple operators can have the
12651 * same precedence, ensuring that the leftmost one is evaluated first.
12652 * Consider * and /. */
12654 #define tok_decl(prec,id) (((id)<<5)|(prec))
12655 #define PREC(op) ((op) & 0x1F)
12657 #define TOK_LPAREN tok_decl(0,0)
12659 #define TOK_COMMA tok_decl(1,0)
12661 #define TOK_ASSIGN tok_decl(2,0)
12662 #define TOK_AND_ASSIGN tok_decl(2,1)
12663 #define TOK_OR_ASSIGN tok_decl(2,2)
12664 #define TOK_XOR_ASSIGN tok_decl(2,3)
12665 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12666 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12667 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12668 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12670 #define TOK_MUL_ASSIGN tok_decl(3,0)
12671 #define TOK_DIV_ASSIGN tok_decl(3,1)
12672 #define TOK_REM_ASSIGN tok_decl(3,2)
12674 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12675 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0)
12677 /* conditional is right associativity too */
12678 #define TOK_CONDITIONAL tok_decl(4,0)
12679 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12681 #define TOK_OR tok_decl(5,0)
12683 #define TOK_AND tok_decl(6,0)
12685 #define TOK_BOR tok_decl(7,0)
12687 #define TOK_BXOR tok_decl(8,0)
12689 #define TOK_BAND tok_decl(9,0)
12691 #define TOK_EQ tok_decl(10,0)
12692 #define TOK_NE tok_decl(10,1)
12694 #define TOK_LT tok_decl(11,0)
12695 #define TOK_GT tok_decl(11,1)
12696 #define TOK_GE tok_decl(11,2)
12697 #define TOK_LE tok_decl(11,3)
12699 #define TOK_LSHIFT tok_decl(12,0)
12700 #define TOK_RSHIFT tok_decl(12,1)
12702 #define TOK_ADD tok_decl(13,0)
12703 #define TOK_SUB tok_decl(13,1)
12705 #define TOK_MUL tok_decl(14,0)
12706 #define TOK_DIV tok_decl(14,1)
12707 #define TOK_REM tok_decl(14,2)
12709 /* exponent is right associativity */
12710 #define TOK_EXPONENT tok_decl(15,1)
12712 /* For now unary operators. */
12713 #define UNARYPREC 16
12714 #define TOK_BNOT tok_decl(UNARYPREC,0)
12715 #define TOK_NOT tok_decl(UNARYPREC,1)
12717 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12718 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12720 #define PREC_PRE (UNARYPREC+2)
12722 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12723 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12725 #define PREC_POST (UNARYPREC+3)
12727 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12728 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12730 #define SPEC_PREC (UNARYPREC+4)
12732 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12733 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12735 #define NUMPTR (*numstackptr)
12737 static int tok_have_assign(operator op)
12739 operator prec = PREC(op);
12741 convert_prec_is_assing(prec);
12742 return (prec == PREC(TOK_ASSIGN) ||
12743 prec == PREC_PRE || prec == PREC_POST);
12746 static int is_right_associativity(operator prec)
12748 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
12749 || prec == PREC(TOK_CONDITIONAL));
12753 typedef struct ARITCH_VAR_NUM {
12755 arith_t contidional_second_val;
12756 char contidional_second_val_initialized;
12757 char *var; /* if NULL then is regular number,
12758 else is variable name */
12762 typedef struct CHK_VAR_RECURSIVE_LOOPED {
12764 struct CHK_VAR_RECURSIVE_LOOPED *next;
12765 } chk_var_recursive_looped_t;
12767 static chk_var_recursive_looped_t *prev_chk_var_recursive;
12770 static int arith_lookup_val(v_n_t *t)
12773 const char * p = lookupvar(t->var);
12778 /* recursive try as expression */
12779 chk_var_recursive_looped_t *cur;
12780 chk_var_recursive_looped_t cur_save;
12782 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
12783 if (strcmp(cur->var, t->var) == 0) {
12784 /* expression recursion loop detected */
12788 /* save current lookuped var name */
12789 cur = prev_chk_var_recursive;
12790 cur_save.var = t->var;
12791 cur_save.next = cur;
12792 prev_chk_var_recursive = &cur_save;
12794 t->val = arith (p, &errcode);
12795 /* restore previous ptr after recursiving */
12796 prev_chk_var_recursive = cur;
12799 /* allow undefined var as 0 */
12805 /* "applying" a token means performing it on the top elements on the integer
12806 * stack. For a unary operator it will only change the top element, but a
12807 * binary operator will pop two arguments and push a result */
12808 static int arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
12811 arith_t numptr_val, rez;
12812 int ret_arith_lookup_val;
12814 /* There is no operator that can work without arguments */
12815 if (NUMPTR == numstack) goto err;
12816 numptr_m1 = NUMPTR - 1;
12818 /* check operand is var with noninteger value */
12819 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12820 if (ret_arith_lookup_val)
12821 return ret_arith_lookup_val;
12823 rez = numptr_m1->val;
12824 if (op == TOK_UMINUS)
12826 else if (op == TOK_NOT)
12828 else if (op == TOK_BNOT)
12830 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
12832 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
12834 else if (op != TOK_UPLUS) {
12835 /* Binary operators */
12837 /* check and binary operators need two arguments */
12838 if (numptr_m1 == numstack) goto err;
12840 /* ... and they pop one */
12843 if (op == TOK_CONDITIONAL) {
12844 if (! numptr_m1->contidional_second_val_initialized) {
12845 /* protect $((expr1 ? expr2)) without ": expr" */
12848 rez = numptr_m1->contidional_second_val;
12849 } else if (numptr_m1->contidional_second_val_initialized) {
12850 /* protect $((expr1 : expr2)) without "expr ? " */
12853 numptr_m1 = NUMPTR - 1;
12854 if (op != TOK_ASSIGN) {
12855 /* check operand is var with noninteger value for not '=' */
12856 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
12857 if (ret_arith_lookup_val)
12858 return ret_arith_lookup_val;
12860 if (op == TOK_CONDITIONAL) {
12861 numptr_m1->contidional_second_val = rez;
12863 rez = numptr_m1->val;
12864 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
12866 else if (op == TOK_OR)
12867 rez = numptr_val || rez;
12868 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
12870 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
12872 else if (op == TOK_AND)
12873 rez = rez && numptr_val;
12874 else if (op == TOK_EQ)
12875 rez = (rez == numptr_val);
12876 else if (op == TOK_NE)
12877 rez = (rez != numptr_val);
12878 else if (op == TOK_GE)
12879 rez = (rez >= numptr_val);
12880 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
12881 rez >>= numptr_val;
12882 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
12883 rez <<= numptr_val;
12884 else if (op == TOK_GT)
12885 rez = (rez > numptr_val);
12886 else if (op == TOK_LT)
12887 rez = (rez < numptr_val);
12888 else if (op == TOK_LE)
12889 rez = (rez <= numptr_val);
12890 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
12892 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
12894 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
12896 else if (op == TOK_ASSIGN || op == TOK_COMMA)
12898 else if (op == TOK_CONDITIONAL_SEP) {
12899 if (numptr_m1 == numstack) {
12900 /* protect $((expr : expr)) without "expr ? " */
12903 numptr_m1->contidional_second_val_initialized = op;
12904 numptr_m1->contidional_second_val = numptr_val;
12906 else if (op == TOK_CONDITIONAL) {
12908 numptr_val : numptr_m1->contidional_second_val;
12910 else if (op == TOK_EXPONENT) {
12911 if (numptr_val < 0)
12912 return -3; /* exponent less than 0 */
12917 while (numptr_val--)
12922 else if (numptr_val==0) /* zero divisor check */
12924 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
12926 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
12929 if (tok_have_assign(op)) {
12932 if (numptr_m1->var == NULL) {
12936 /* save to shell variable */
12937 #if ENABLE_ASH_MATH_SUPPORT_64
12938 snprintf(buf, sizeof(buf), "%lld", arith_t_type rez);
12940 snprintf(buf, sizeof(buf), "%ld", arith_t_type rez);
12942 setvar(numptr_m1->var, buf, 0);
12943 /* after saving, make previous value for v++ or v-- */
12944 if (op == TOK_POST_INC)
12946 else if (op == TOK_POST_DEC)
12949 numptr_m1->val = rez;
12950 /* protect geting var value, is number now */
12951 numptr_m1->var = NULL;
12957 /* longest must first */
12958 static const char op_tokens[] = {
12959 '<','<','=',0, TOK_LSHIFT_ASSIGN,
12960 '>','>','=',0, TOK_RSHIFT_ASSIGN,
12961 '<','<', 0, TOK_LSHIFT,
12962 '>','>', 0, TOK_RSHIFT,
12963 '|','|', 0, TOK_OR,
12964 '&','&', 0, TOK_AND,
12965 '!','=', 0, TOK_NE,
12966 '<','=', 0, TOK_LE,
12967 '>','=', 0, TOK_GE,
12968 '=','=', 0, TOK_EQ,
12969 '|','=', 0, TOK_OR_ASSIGN,
12970 '&','=', 0, TOK_AND_ASSIGN,
12971 '*','=', 0, TOK_MUL_ASSIGN,
12972 '/','=', 0, TOK_DIV_ASSIGN,
12973 '%','=', 0, TOK_REM_ASSIGN,
12974 '+','=', 0, TOK_PLUS_ASSIGN,
12975 '-','=', 0, TOK_MINUS_ASSIGN,
12976 '-','-', 0, TOK_POST_DEC,
12977 '^','=', 0, TOK_XOR_ASSIGN,
12978 '+','+', 0, TOK_POST_INC,
12979 '*','*', 0, TOK_EXPONENT,
12983 '=', 0, TOK_ASSIGN,
12995 '?', 0, TOK_CONDITIONAL,
12996 ':', 0, TOK_CONDITIONAL_SEP,
12997 ')', 0, TOK_RPAREN,
12998 '(', 0, TOK_LPAREN,
13002 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13005 static arith_t arith(const char *expr, int *perrcode)
13007 char arithval; /* Current character under analysis */
13008 operator lasttok, op;
13011 const char *p = endexpression;
13014 size_t datasizes = strlen(expr) + 2;
13016 /* Stack of integers */
13017 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13018 * in any given correct or incorrect expression is left as an exercise to
13020 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13021 *numstackptr = numstack;
13022 /* Stack of operator tokens */
13023 operator *stack = alloca((datasizes) * sizeof(operator)),
13026 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13027 *perrcode = errcode = 0;
13031 if (arithval == 0) {
13032 if (p == endexpression) {
13033 /* Null expression. */
13037 /* This is only reached after all tokens have been extracted from the
13038 * input stream. If there are still tokens on the operator stack, they
13039 * are to be applied in order. At the end, there should be a final
13040 * result on the integer stack */
13042 if (expr != endexpression + 1) {
13043 /* If we haven't done so already, */
13044 /* append a closing right paren */
13045 expr = endexpression;
13046 /* and let the loop process it. */
13049 /* At this point, we're done with the expression. */
13050 if (numstackptr != numstack+1) {
13051 /* ... but if there isn't, it's bad */
13053 return (*perrcode = -1);
13055 if (numstack->var) {
13056 /* expression is $((var)) only, lookup now */
13057 errcode = arith_lookup_val(numstack);
13060 *perrcode = errcode;
13061 return numstack->val;
13064 /* Continue processing the expression. */
13065 if (arith_isspace(arithval)) {
13066 /* Skip whitespace */
13069 p = endofname(expr);
13071 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13073 numstackptr->var = alloca(var_name_size);
13074 safe_strncpy(numstackptr->var, expr, var_name_size);
13077 numstackptr->contidional_second_val_initialized = 0;
13082 if (is_digit(arithval)) {
13083 numstackptr->var = NULL;
13084 #if ENABLE_ASH_MATH_SUPPORT_64
13085 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13087 numstackptr->val = strtol(expr, (char **) &expr, 0);
13091 for (p = op_tokens; ; p++) {
13095 /* strange operator not found */
13098 for (o = expr; *p && *o == *p; p++)
13105 /* skip tail uncompared token */
13108 /* skip zero delim */
13113 /* post grammar: a++ reduce to num */
13114 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13117 /* Plus and minus are binary (not unary) _only_ if the last
13118 * token was as number, or a right paren (which pretends to be
13119 * a number, since it evaluates to one). Think about it.
13120 * It makes sense. */
13121 if (lasttok != TOK_NUM) {
13137 /* We don't want a unary operator to cause recursive descent on the
13138 * stack, because there can be many in a row and it could cause an
13139 * operator to be evaluated before its argument is pushed onto the
13140 * integer stack. */
13141 /* But for binary operators, "apply" everything on the operator
13142 * stack until we find an operator with a lesser priority than the
13143 * one we have just extracted. */
13144 /* Left paren is given the lowest priority so it will never be
13145 * "applied" in this way.
13146 * if associativity is right and priority eq, applied also skip
13149 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13150 /* not left paren or unary */
13151 if (lasttok != TOK_NUM) {
13152 /* binary op must be preceded by a num */
13155 while (stackptr != stack) {
13156 if (op == TOK_RPAREN) {
13157 /* The algorithm employed here is simple: while we don't
13158 * hit an open paren nor the bottom of the stack, pop
13159 * tokens and apply them */
13160 if (stackptr[-1] == TOK_LPAREN) {
13162 /* Any operator directly after a */
13164 /* close paren should consider itself binary */
13168 operator prev_prec = PREC(stackptr[-1]);
13170 convert_prec_is_assing(prec);
13171 convert_prec_is_assing(prev_prec);
13172 if (prev_prec < prec)
13174 /* check right assoc */
13175 if (prev_prec == prec && is_right_associativity(prec))
13178 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13179 if (errcode) goto ret;
13181 if (op == TOK_RPAREN) {
13186 /* Push this operator to the stack and remember it. */
13187 *stackptr++ = lasttok = op;
13192 #endif /* ASH_MATH_SUPPORT */
13195 /* ============ main() and helpers
13197 * Main routine. We initialize things, parse the arguments, execute
13198 * profiles if we're a login shell, and then call cmdloop to execute
13199 * commands. The setjmp call sets up the location to jump to when an
13200 * exception occurs. When an exception occurs the variable "state"
13201 * is used to figure out how far we had gotten.
13204 static void init(void)
13206 /* from input.c: */
13207 basepf.nextc = basepf.buf = basebuf;
13210 signal(SIGCHLD, SIG_DFL);
13217 struct stat st1, st2;
13220 for (envp = environ; envp && *envp; envp++) {
13221 if (strchr(*envp, '=')) {
13222 setvareq(*envp, VEXPORT|VTEXTFIXED);
13226 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
13227 setvar("PPID", ppid, 0);
13229 p = lookupvar("PWD");
13231 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
13232 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
13239 * Process the shell command line arguments.
13242 procargs(int argc, char **argv)
13245 const char *xminusc;
13252 for (i = 0; i < NOPTS; i++)
13258 if (*xargv == NULL) {
13260 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13263 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13267 for (i = 0; i < NOPTS; i++)
13268 if (optlist[i] == 2)
13273 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13278 } else if (!sflag) {
13279 setinputfile(*xargv, 0);
13282 commandname = arg0;
13285 shellparam.p = xargv;
13286 #if ENABLE_ASH_GETOPTS
13287 shellparam.optind = 1;
13288 shellparam.optoff = -1;
13290 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
13292 shellparam.nparam++;
13299 * Read /etc/profile or .profile.
13302 read_profile(const char *name)
13306 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13315 static short profile_buf[16384];
13316 extern int etext();
13319 int ash_main(int argc, char **argv);
13320 int ash_main(int argc, char **argv)
13323 volatile int state;
13324 struct jmploc jmploc;
13325 struct stackmark smark;
13328 dash_errno = __errno_location();
13332 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13335 #if ENABLE_FEATURE_EDITING
13336 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13339 if (setjmp(jmploc.loc)) {
13349 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
13353 outcslow('\n', stderr);
13355 popstackmark(&smark);
13356 FORCE_INT_ON; /* enable interrupts */
13366 exception_handler = &jmploc;
13369 trputs("Shell args: ");
13372 rootpid = getpid();
13374 #if ENABLE_ASH_RANDOM_SUPPORT
13375 rseed = rootpid + time(NULL);
13378 setstackmark(&smark);
13379 procargs(argc, argv);
13380 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13382 const char *hp = lookupvar("HISTFILE");
13385 hp = lookupvar("HOME");
13387 char *defhp = concat_path_file(hp, ".ash_history");
13388 setvar("HISTFILE", defhp, 0);
13394 if (argv[0] && argv[0][0] == '-')
13398 read_profile("/etc/profile");
13401 read_profile(".profile");
13407 getuid() == geteuid() && getgid() == getegid() &&
13411 shinit = lookupvar("ENV");
13412 if (shinit != NULL && *shinit != '\0') {
13413 read_profile(shinit);
13419 evalstring(minusc, 0);
13421 if (sflag || minusc == NULL) {
13422 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
13424 const char *hp = lookupvar("HISTFILE");
13427 line_input_state->hist_file = hp;
13430 state4: /* XXX ??? - why isn't this before the "if" statement */
13438 extern void _mcleanup(void);
13447 const char *applet_name = "debug stuff usage";
13448 int main(int argc, char **argv)
13450 return ash_main(argc, argv);
13456 * Copyright (c) 1989, 1991, 1993, 1994
13457 * The Regents of the University of California. All rights reserved.
13459 * This code is derived from software contributed to Berkeley by
13460 * Kenneth Almquist.
13462 * Redistribution and use in source and binary forms, with or without
13463 * modification, are permitted provided that the following conditions
13465 * 1. Redistributions of source code must retain the above copyright
13466 * notice, this list of conditions and the following disclaimer.
13467 * 2. Redistributions in binary form must reproduce the above copyright
13468 * notice, this list of conditions and the following disclaimer in the
13469 * documentation and/or other materials provided with the distribution.
13470 * 3. Neither the name of the University nor the names of its contributors
13471 * may be used to endorse or promote products derived from this software
13472 * without specific prior written permission.
13474 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13475 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13476 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13477 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13478 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13479 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13480 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13481 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13482 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13483 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF