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-2003 Herbert Xu <herbert@debian.org>
9 * was re-ported from NetBSD and debianized.
12 * This code is derived from software contributed to Berkeley by
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 * Original BSD copyright notice is retained at the end of this file.
33 * rewrite arith.y to micro stack based cryptic algorithm by
34 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
36 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
39 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2004 to be
40 * used in busybox and size optimizations,
41 * rewrote arith (see notes to this), added locale support,
42 * rewrote dynamic variables.
48 * The follow should be set to reflect the type of system you have:
49 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
50 * define SYSV if you are running under System V.
51 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
52 * define DEBUG=2 to compile in and turn on debugging.
54 * When debugging is on, debugging info will be written to ./trace and
55 * a quit signal will generate a core dump.
68 #include <sys/types.h>
69 #include <sys/cdefs.h>
70 #include <sys/ioctl.h>
71 #include <sys/param.h>
72 #include <sys/resource.h>
102 #ifdef CONFIG_ASH_JOB_CONTROL
116 static int *dash_errno;
118 #define errno (*dash_errno)
121 #if defined(__uClinux__)
122 #error "Do not even bother, ash will not run on uClinux"
126 #define _DIAGASSERT(assert_expr) assert(assert_expr)
128 #define _DIAGASSERT(assert_expr)
132 #ifdef CONFIG_ASH_ALIAS
133 /* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */
145 static struct alias *lookupalias(const char *, int);
146 static int aliascmd(int, char **);
147 static int unaliascmd(int, char **);
148 static void rmaliases(void);
149 static int unalias(const char *);
150 static void printalias(const struct alias *);
153 /* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */
156 static void setpwd(const char *, int);
158 /* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */
162 * Types of operations (passed to the errmsg routine).
166 static const char not_found_msg[] = "%s: not found";
169 #define E_OPEN "No such file" /* opening a file */
170 #define E_CREAT "Directory nonexistent" /* creating a file */
171 #define E_EXEC not_found_msg+4 /* executing a program */
174 * We enclose jmp_buf in a structure so that we can declare pointers to
175 * jump locations. The global variable handler contains the location to
176 * jump to when an exception occurs, and the global variable exception
177 * contains a code identifying the exception. To implement nested
178 * exception handlers, the user should save the value of handler on entry
179 * to an inner scope, set handler to point to a jmploc structure for the
180 * inner scope, and restore handler on exit from the scope.
187 static struct jmploc *handler;
188 static int exception;
189 static volatile int suppressint;
190 static volatile sig_atomic_t intpending;
192 static int exerrno; /* Last exec error, error for EXEXEC */
195 #define EXINT 0 /* SIGINT received */
196 #define EXERROR 1 /* a generic error */
197 #define EXSHELLPROC 2 /* execute a shell procedure */
198 #define EXEXEC 3 /* command execution failed */
199 #define EXEXIT 4 /* exit the shell */
200 #define EXSIG 5 /* trapped signal in wait(1) */
203 /* do we generate EXSIG events */
205 /* last pending signal */
206 static volatile sig_atomic_t pendingsigs;
209 * These macros allow the user to suspend the handling of interrupt signals
210 * over a period of time. This is similar to SIGHOLD to or sigblock, but
211 * much more efficient and portable. (But hacking the kernel is so much
212 * more fun than worrying about efficiency and portability. :-))
215 #define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
222 #define SAVEINT(v) ((v) = suppressint)
223 #define RESTOREINT(v) \
226 if ((suppressint = (v)) == 0 && intpending) onint(); \
237 /* EXSIG is turned off by evalbltin(). */
240 static void exraise(int) __attribute__((__noreturn__));
241 static void onint(void) __attribute__((__noreturn__));
243 static void error(const char *, ...) __attribute__((__noreturn__));
244 static void exerror(int, const char *, ...) __attribute__((__noreturn__));
246 static void sh_warnx(const char *, ...);
248 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
251 if (--suppressint == 0 && intpending) {
255 #define INTON inton()
256 static void forceinton(void)
262 #define FORCEINTON forceinton()
267 if (--suppressint == 0 && intpending) onint(); \
274 if (intpending) onint(); \
277 #endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
280 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
281 * so we use _setjmp instead.
284 #if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
285 #define setjmp(jmploc) _setjmp(jmploc)
286 #define longjmp(jmploc, val) _longjmp(jmploc, val)
289 /* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
292 struct strlist *next;
298 struct strlist *list;
299 struct strlist **lastp;
305 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
306 #define EXP_TILDE 0x2 /* do normal tilde expansion */
307 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
308 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
309 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
310 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
311 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
312 #define EXP_WORD 0x80 /* expand word in parameter expansion */
313 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
317 static void expandarg(union node *, struct arglist *, int);
318 #define rmescapes(p) _rmescapes((p), 0)
319 static char *_rmescapes(char *, int);
320 static int casematch(union node *, char *);
322 #ifdef CONFIG_ASH_MATH_SUPPORT
323 static void expari(int);
326 /* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */
328 static char *commandname; /* currently executing command */
329 static struct strlist *cmdenviron; /* environment for builtin command */
330 static int exitstatus; /* exit status of last command */
331 static int back_exitstatus; /* exit status of backquoted command */
334 struct backcmd { /* result of evalbackcmd */
335 int fd; /* file descriptor to read from */
336 char *buf; /* buffer */
337 int nleft; /* number of chars in buffer */
338 struct job *jp; /* job structure for command */
342 * This file was generated by the mknodes program.
378 union node *redirect;
385 struct nodelist *cmdlist;
392 union node *redirect;
407 union node *elsepart;
438 struct nodelist *backquote;
478 struct nredir nredir;
479 struct nbinary nbinary;
483 struct nclist nclist;
493 struct nodelist *next;
504 static void freefunc(struct funcnode *);
505 /* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */
507 /* control characters in argument strings */
508 #define CTL_FIRST '\201' /* first 'special' character */
509 #define CTLESC '\201' /* escape next character */
510 #define CTLVAR '\202' /* variable defn */
511 #define CTLENDVAR '\203'
512 #define CTLBACKQ '\204'
513 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
514 /* CTLBACKQ | CTLQUOTE == '\205' */
515 #define CTLARI '\206' /* arithmetic expression */
516 #define CTLENDARI '\207'
517 #define CTLQUOTEMARK '\210'
518 #define CTL_LAST '\210' /* last 'special' character */
520 /* variable substitution byte (follows CTLVAR) */
521 #define VSTYPE 0x0f /* type of variable substitution */
522 #define VSNUL 0x10 /* colon--treat the empty string as unset */
523 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
525 /* values of VSTYPE field */
526 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
527 #define VSMINUS 0x2 /* ${var-text} */
528 #define VSPLUS 0x3 /* ${var+text} */
529 #define VSQUESTION 0x4 /* ${var?message} */
530 #define VSASSIGN 0x5 /* ${var=text} */
531 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
532 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
533 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
534 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
535 #define VSLENGTH 0xa /* ${#var} */
537 /* values of checkkwd variable */
542 #define IBUFSIZ (BUFSIZ + 1)
545 * NEOF is returned by parsecmd when it encounters an end of file. It
546 * must be distinct from NULL, so we use the address of a variable that
547 * happens to be handy.
549 static int plinno = 1; /* input line number */
551 /* number of characters left in input buffer */
552 static int parsenleft; /* copy of parsefile->nleft */
553 static int parselleft; /* copy of parsefile->lleft */
555 /* next character in input buffer */
556 static char *parsenextc; /* copy of parsefile->nextc */
559 struct strpush *prev; /* preceding string on stack */
562 #ifdef CONFIG_ASH_ALIAS
563 struct alias *ap; /* if push was associated with an alias */
565 char *string; /* remember the string since it may change */
569 struct parsefile *prev; /* preceding file on stack */
570 int linno; /* current line */
571 int fd; /* file descriptor (or -1 if string) */
572 int nleft; /* number of chars left in this line */
573 int lleft; /* number of chars left in this buffer */
574 char *nextc; /* next char in buffer */
575 char *buf; /* input buffer */
576 struct strpush *strpush; /* for pushing strings at this level */
577 struct strpush basestrpush; /* so pushing one is fast */
580 static struct parsefile basepf; /* top level input file */
581 static char basebuf[IBUFSIZ]; /* buffer for top level input file */
582 static struct parsefile *parsefile = &basepf; /* current input file */
585 static int tokpushback; /* last token pushed back */
586 #define NEOF ((union node *)&tokpushback)
587 static int parsebackquote; /* nonzero if we are inside backquotes */
588 static int doprompt; /* if set, prompt the user */
589 static int needprompt; /* true if interactive and at start of line */
590 static int lasttoken; /* last token read */
591 static char *wordtext; /* text of last word returned by readtoken */
593 static struct nodelist *backquotelist;
594 static union node *redirnode;
595 static struct heredoc *heredoc;
596 static int quoteflag; /* set if (part of) last token was quoted */
597 static int startlinno; /* line # where last token started */
599 static union node *parsecmd(int);
600 static void fixredir(union node *, const char *, int);
601 static const char *const *findkwd(const char *);
602 static char *endofname(const char *);
604 /* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
606 typedef void *pointer;
608 static char nullstr[1]; /* zero length string */
609 static const char spcstr[] = " ";
610 static const char snlfmt[] = "%s\n";
611 static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
612 static const char illnum[] = "Illegal number: %s";
613 static const char homestr[] = "HOME";
616 #define TRACE(param) trace param
617 #define TRACEV(param) tracev param
620 #define TRACEV(param)
623 #if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
624 #define __builtin_expect(x, expected_value) (x)
627 #define xlikely(x) __builtin_expect((x),1)
642 #define TENDBQUOTE 12
660 /* first char is indicating which tokens mark the end of a list */
661 static const char *const tokname_array[] = {
676 /* the following are keywords */
695 static const char *tokname(int tok)
701 sprintf(buf + (tok >= TSEMI), "%s%c",
702 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
706 /* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */
709 * Most machines require the value returned from malloc to be aligned
710 * in some way. The following macro will get this right on many machines.
713 #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
715 * It appears that grabstackstr() will barf with such alignments
716 * because stalloc() will return a string allocated in a new stackblock.
718 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
721 * This file was generated by the mksyntax program.
726 #define CWORD 0 /* character is nothing special */
727 #define CNL 1 /* newline character */
728 #define CBACK 2 /* a backslash character */
729 #define CSQUOTE 3 /* single quote */
730 #define CDQUOTE 4 /* double quote */
731 #define CENDQUOTE 5 /* a terminating quote */
732 #define CBQUOTE 6 /* backwards single quote */
733 #define CVAR 7 /* a dollar sign */
734 #define CENDVAR 8 /* a '}' character */
735 #define CLP 9 /* a left paren in arithmetic */
736 #define CRP 10 /* a right paren in arithmetic */
737 #define CENDFILE 11 /* end of file */
738 #define CCTL 12 /* like CWORD, except it must be escaped */
739 #define CSPCL 13 /* these terminate a word */
740 #define CIGN 14 /* character should be ignored */
742 #ifdef CONFIG_ASH_ALIAS
746 #define PEOA_OR_PEOF PEOA
750 #define PEOA_OR_PEOF PEOF
753 #define is_digit(c) ((unsigned)((c) - '0') <= 9)
754 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
755 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
758 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
759 * (assuming ascii char codes, as the original implementation did)
761 #define is_special(c) \
762 ( (((unsigned int)c) - 33 < 32) \
763 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
765 #define digit_val(c) ((c) - '0')
768 * This file was generated by the mksyntax program.
771 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
772 #define USE_SIT_FUNCTION
775 /* number syntax index */
776 #define BASESYNTAX 0 /* not in quotes */
777 #define DQSYNTAX 1 /* in double quotes */
778 #define SQSYNTAX 2 /* in single quotes */
779 #define ARISYNTAX 3 /* in arithmetic */
781 #ifdef CONFIG_ASH_MATH_SUPPORT
782 static const char S_I_T[][4] = {
783 #ifdef CONFIG_ASH_ALIAS
784 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
786 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
787 {CNL, CNL, CNL, CNL}, /* 2, \n */
788 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
789 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
790 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
791 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
792 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
793 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
794 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
795 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
796 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
797 #ifndef USE_SIT_FUNCTION
798 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
799 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
800 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
804 static const char S_I_T[][3] = {
805 #ifdef CONFIG_ASH_ALIAS
806 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
808 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
809 {CNL, CNL, CNL}, /* 2, \n */
810 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
811 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
812 {CVAR, CVAR, CWORD}, /* 5, $ */
813 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
814 {CSPCL, CWORD, CWORD}, /* 7, ( */
815 {CSPCL, CWORD, CWORD}, /* 8, ) */
816 {CBACK, CBACK, CCTL}, /* 9, \ */
817 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
818 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
819 #ifndef USE_SIT_FUNCTION
820 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
821 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
822 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
825 #endif /* CONFIG_ASH_MATH_SUPPORT */
827 #ifdef USE_SIT_FUNCTION
829 #define U_C(c) ((unsigned char)(c))
831 static int SIT(int c, int syntax)
833 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
834 #ifdef CONFIG_ASH_ALIAS
835 static const char syntax_index_table[] = {
836 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
837 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
838 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
842 static const char syntax_index_table[] = {
843 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
844 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
845 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
852 if (c == PEOF) /* 2^8+2 */
854 #ifdef CONFIG_ASH_ALIAS
855 if (c == PEOA) /* 2^8+1 */
859 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
862 s = strchr(spec_symbls, c);
863 if (s == 0 || *s == 0)
865 indx = syntax_index_table[(s - spec_symbls)];
867 return S_I_T[indx][syntax];
870 #else /* USE_SIT_FUNCTION */
872 #define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
874 #ifdef CONFIG_ASH_ALIAS
875 #define CSPCL_CIGN_CIGN_CIGN 0
876 #define CSPCL_CWORD_CWORD_CWORD 1
877 #define CNL_CNL_CNL_CNL 2
878 #define CWORD_CCTL_CCTL_CWORD 3
879 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
880 #define CVAR_CVAR_CWORD_CVAR 5
881 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
882 #define CSPCL_CWORD_CWORD_CLP 7
883 #define CSPCL_CWORD_CWORD_CRP 8
884 #define CBACK_CBACK_CCTL_CBACK 9
885 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
886 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
887 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
888 #define CWORD_CWORD_CWORD_CWORD 13
889 #define CCTL_CCTL_CCTL_CCTL 14
891 #define CSPCL_CWORD_CWORD_CWORD 0
892 #define CNL_CNL_CNL_CNL 1
893 #define CWORD_CCTL_CCTL_CWORD 2
894 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
895 #define CVAR_CVAR_CWORD_CVAR 4
896 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
897 #define CSPCL_CWORD_CWORD_CLP 6
898 #define CSPCL_CWORD_CWORD_CRP 7
899 #define CBACK_CBACK_CCTL_CBACK 8
900 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
901 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
902 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
903 #define CWORD_CWORD_CWORD_CWORD 12
904 #define CCTL_CCTL_CCTL_CCTL 13
907 static const char syntax_index_table[258] = {
908 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
909 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
910 #ifdef CONFIG_ASH_ALIAS
911 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
913 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
914 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
915 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
916 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
917 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
918 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
919 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
920 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
921 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
922 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
923 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
924 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
925 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
926 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
927 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
928 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
929 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
930 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
931 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
932 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
933 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
934 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
935 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
936 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
937 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
938 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
939 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
940 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
941 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
942 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
943 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
944 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
945 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
946 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
947 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
948 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
949 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
950 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
951 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
952 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
953 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
954 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
955 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
956 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
957 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
958 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
959 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
960 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
961 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
962 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
963 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
964 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
965 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
966 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
967 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
968 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
969 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
970 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
971 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
972 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
973 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
974 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
975 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
976 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
977 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
978 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
979 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
980 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
981 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
982 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
983 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
984 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
985 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
986 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
987 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
988 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
989 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
990 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
991 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
992 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
993 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
994 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
995 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
996 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
997 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
998 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
999 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
1024 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
1025 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1047 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1048 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1049 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1050 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1051 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1052 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1053 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1054 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1055 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1056 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1057 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1058 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1059 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1060 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1061 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1062 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1063 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1064 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1065 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1066 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1067 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1068 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1069 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1070 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1071 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1072 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1073 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1074 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
1075 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
1076 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1077 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1078 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1079 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
1080 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
1081 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1082 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1083 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1084 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1086 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1087 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1088 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1089 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1100 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1101 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1102 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1103 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1104 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1105 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1106 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1107 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1108 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1109 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1110 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1133 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1134 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1135 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1138 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1139 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1140 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1141 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1142 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1143 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1144 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1145 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1146 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1147 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1148 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1149 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1150 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1151 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1152 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1153 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1154 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1155 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1156 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1157 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1158 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1159 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1160 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1161 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1162 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1163 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1164 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1165 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1166 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1167 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1168 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
1171 #endif /* USE_SIT_FUNCTION */
1173 /* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */
1178 static int funcblocksize; /* size of structures in function */
1179 static int funcstringsize; /* size of strings in node */
1180 static pointer funcblock; /* block to allocate function from */
1181 static char *funcstring; /* block to allocate strings from */
1183 static const short nodesize[26] = {
1184 SHELL_ALIGN(sizeof (struct ncmd)),
1185 SHELL_ALIGN(sizeof (struct npipe)),
1186 SHELL_ALIGN(sizeof (struct nredir)),
1187 SHELL_ALIGN(sizeof (struct nredir)),
1188 SHELL_ALIGN(sizeof (struct nredir)),
1189 SHELL_ALIGN(sizeof (struct nbinary)),
1190 SHELL_ALIGN(sizeof (struct nbinary)),
1191 SHELL_ALIGN(sizeof (struct nbinary)),
1192 SHELL_ALIGN(sizeof (struct nif)),
1193 SHELL_ALIGN(sizeof (struct nbinary)),
1194 SHELL_ALIGN(sizeof (struct nbinary)),
1195 SHELL_ALIGN(sizeof (struct nfor)),
1196 SHELL_ALIGN(sizeof (struct ncase)),
1197 SHELL_ALIGN(sizeof (struct nclist)),
1198 SHELL_ALIGN(sizeof (struct narg)),
1199 SHELL_ALIGN(sizeof (struct narg)),
1200 SHELL_ALIGN(sizeof (struct nfile)),
1201 SHELL_ALIGN(sizeof (struct nfile)),
1202 SHELL_ALIGN(sizeof (struct nfile)),
1203 SHELL_ALIGN(sizeof (struct nfile)),
1204 SHELL_ALIGN(sizeof (struct nfile)),
1205 SHELL_ALIGN(sizeof (struct ndup)),
1206 SHELL_ALIGN(sizeof (struct ndup)),
1207 SHELL_ALIGN(sizeof (struct nhere)),
1208 SHELL_ALIGN(sizeof (struct nhere)),
1209 SHELL_ALIGN(sizeof (struct nnot)),
1213 static void calcsize(union node *);
1214 static void sizenodelist(struct nodelist *);
1215 static union node *copynode(union node *);
1216 static struct nodelist *copynodelist(struct nodelist *);
1217 static char *nodesavestr(char *);
1221 static void evalstring(char *);
1222 union node; /* BLETCH for ansi C */
1223 static void evaltree(union node *, int);
1224 static void evalbackcmd(union node *, struct backcmd *);
1226 /* in_function returns nonzero if we are currently evaluating a function */
1227 #define in_function() funcnest
1228 static int evalskip; /* set if we are skipping commands */
1229 static int skipcount; /* number of levels to skip */
1230 static int funcnest; /* depth of function calls */
1232 /* reasons for skipping commands (see comment on breakcmd routine) */
1239 * This file was generated by the mkbuiltins program.
1243 static int bgcmd(int, char **);
1245 static int breakcmd(int, char **);
1246 static int cdcmd(int, char **);
1247 #ifdef CONFIG_ASH_CMDCMD
1248 static int commandcmd(int, char **);
1250 static int dotcmd(int, char **);
1251 static int evalcmd(int, char **);
1252 #ifdef CONFIG_ASH_BUILTIN_ECHO
1253 static int echocmd(int, char **);
1255 static int execcmd(int, char **);
1256 static int exitcmd(int, char **);
1257 static int exportcmd(int, char **);
1258 static int falsecmd(int, char **);
1260 static int fgcmd(int, char **);
1262 #ifdef CONFIG_ASH_GETOPTS
1263 static int getoptscmd(int, char **);
1265 static int hashcmd(int, char **);
1266 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1267 static int helpcmd(int argc, char **argv);
1270 static int jobscmd(int, char **);
1272 #ifdef CONFIG_ASH_MATH_SUPPORT
1273 static int letcmd(int, char **);
1275 static int localcmd(int, char **);
1276 static int pwdcmd(int, char **);
1277 static int readcmd(int, char **);
1278 static int returncmd(int, char **);
1279 static int setcmd(int, char **);
1280 static int shiftcmd(int, char **);
1281 static int timescmd(int, char **);
1282 static int trapcmd(int, char **);
1283 static int truecmd(int, char **);
1284 static int typecmd(int, char **);
1285 static int umaskcmd(int, char **);
1286 static int unsetcmd(int, char **);
1287 static int waitcmd(int, char **);
1288 static int ulimitcmd(int, char **);
1290 static int killcmd(int, char **);
1293 /* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1295 #ifdef CONFIG_ASH_MAIL
1296 static void chkmail(void);
1297 static void changemail(const char *);
1300 /* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1302 /* values of cmdtype */
1303 #define CMDUNKNOWN -1 /* no entry in table for command */
1304 #define CMDNORMAL 0 /* command is an executable program */
1305 #define CMDFUNCTION 1 /* command is a shell function */
1306 #define CMDBUILTIN 2 /* command is a shell builtin */
1310 int (*builtin)(int, char **);
1311 /* unsigned flags; */
1315 #define COMMANDCMD (builtincmd + 5 + \
1316 ENABLE_ASH_ALIAS + ENABLE_ASH_JOB_CONTROL)
1317 #define EXECCMD (builtincmd + 7 + \
1318 ENABLE_ASH_CMDCMD + ENABLE_ASH_ALIAS + \
1319 ENABLE_ASH_BUILTIN_ECHO + ENABLE_ASH_JOB_CONTROL)
1321 #define BUILTIN_NOSPEC "0"
1322 #define BUILTIN_SPECIAL "1"
1323 #define BUILTIN_REGULAR "2"
1324 #define BUILTIN_SPEC_REG "3"
1325 #define BUILTIN_ASSIGN "4"
1326 #define BUILTIN_SPEC_ASSG "5"
1327 #define BUILTIN_REG_ASSG "6"
1328 #define BUILTIN_SPEC_REG_ASSG "7"
1330 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1331 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1332 #define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1334 static const struct builtincmd builtincmd[] = {
1335 { BUILTIN_SPEC_REG ".", dotcmd },
1336 { BUILTIN_SPEC_REG ":", truecmd },
1337 #ifdef CONFIG_ASH_ALIAS
1338 { BUILTIN_REG_ASSG "alias", aliascmd },
1341 { BUILTIN_REGULAR "bg", bgcmd },
1343 { BUILTIN_SPEC_REG "break", breakcmd },
1344 { BUILTIN_REGULAR "cd", cdcmd },
1345 { BUILTIN_NOSPEC "chdir", cdcmd },
1346 #ifdef CONFIG_ASH_CMDCMD
1347 { BUILTIN_REGULAR "command", commandcmd },
1349 { BUILTIN_SPEC_REG "continue", breakcmd },
1350 #ifdef CONFIG_ASH_BUILTIN_ECHO
1351 { BUILTIN_REGULAR "echo", echocmd },
1353 { BUILTIN_SPEC_REG "eval", evalcmd },
1354 { BUILTIN_SPEC_REG "exec", execcmd },
1355 { BUILTIN_SPEC_REG "exit", exitcmd },
1356 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1357 { BUILTIN_REGULAR "false", falsecmd },
1359 { BUILTIN_REGULAR "fg", fgcmd },
1361 #ifdef CONFIG_ASH_GETOPTS
1362 { BUILTIN_REGULAR "getopts", getoptscmd },
1364 { BUILTIN_NOSPEC "hash", hashcmd },
1365 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1366 { BUILTIN_NOSPEC "help", helpcmd },
1369 { BUILTIN_REGULAR "jobs", jobscmd },
1370 { BUILTIN_REGULAR "kill", killcmd },
1372 #ifdef CONFIG_ASH_MATH_SUPPORT
1373 { BUILTIN_NOSPEC "let", letcmd },
1375 { BUILTIN_ASSIGN "local", localcmd },
1376 { BUILTIN_NOSPEC "pwd", pwdcmd },
1377 { BUILTIN_REGULAR "read", readcmd },
1378 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1379 { BUILTIN_SPEC_REG "return", returncmd },
1380 { BUILTIN_SPEC_REG "set", setcmd },
1381 { BUILTIN_SPEC_REG "shift", shiftcmd },
1382 { BUILTIN_SPEC_REG "times", timescmd },
1383 { BUILTIN_SPEC_REG "trap", trapcmd },
1384 { BUILTIN_REGULAR "true", truecmd },
1385 { BUILTIN_NOSPEC "type", typecmd },
1386 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1387 { BUILTIN_REGULAR "umask", umaskcmd },
1388 #ifdef CONFIG_ASH_ALIAS
1389 { BUILTIN_REGULAR "unalias", unaliascmd },
1391 { BUILTIN_SPEC_REG "unset", unsetcmd },
1392 { BUILTIN_REGULAR "wait", waitcmd },
1395 #define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1403 const struct builtincmd *cmd;
1404 struct funcnode *func;
1409 /* action to find_command() */
1410 #define DO_ERR 0x01 /* prints errors */
1411 #define DO_ABS 0x02 /* checks absolute paths */
1412 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1413 #define DO_ALTPATH 0x08 /* using alternate path */
1414 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1416 static const char *pathopt; /* set by padvance */
1418 static void shellexec(char **, const char *, int)
1419 __attribute__((__noreturn__));
1420 static char *padvance(const char **, const char *);
1421 static void find_command(char *, struct cmdentry *, int, const char *);
1422 static struct builtincmd *find_builtin(const char *);
1423 static void hashcd(void);
1424 static void changepath(const char *);
1425 static void defun(char *, union node *);
1426 static void unsetfunc(const char *);
1428 #ifdef CONFIG_ASH_MATH_SUPPORT_64
1429 typedef int64_t arith_t;
1431 typedef long arith_t;
1434 #ifdef CONFIG_ASH_MATH_SUPPORT
1435 static arith_t dash_arith(const char *);
1436 static arith_t arith(const char *expr, int *perrcode);
1439 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1440 static unsigned long rseed;
1441 static void change_random(const char *);
1442 # ifndef DYNAMIC_VAR
1443 # define DYNAMIC_VAR
1447 /* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1449 static void reset(void);
1451 /* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
1458 #define VEXPORT 0x01 /* variable is exported */
1459 #define VREADONLY 0x02 /* variable cannot be modified */
1460 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1461 #define VTEXTFIXED 0x08 /* text is statically allocated */
1462 #define VSTACK 0x10 /* text is allocated on the stack */
1463 #define VUNSET 0x20 /* the variable is not set */
1464 #define VNOFUNC 0x40 /* don't call the callback function */
1465 #define VNOSET 0x80 /* do not set variable - just readonly test */
1466 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1468 # define VDYNAMIC 0x200 /* dynamic variable */
1474 struct var *next; /* next entry in hash list */
1475 int flags; /* flags are defined above */
1476 const char *text; /* name=value */
1477 void (*func)(const char *); /* function to be called when */
1478 /* the variable gets set/unset */
1482 struct localvar *next; /* next local variable in list */
1483 struct var *vp; /* the variable that was made local */
1484 int flags; /* saved flags */
1485 const char *text; /* saved text */
1489 static struct localvar *localvars;
1495 #ifdef CONFIG_ASH_GETOPTS
1496 static void getoptsreset(const char *);
1499 #ifdef CONFIG_LOCALE_SUPPORT
1501 static void change_lc_all(const char *value);
1502 static void change_lc_ctype(const char *value);
1508 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1510 static const char defifsvar[] = "IFS= \t\n";
1511 #define defifs (defifsvar + 4)
1513 static const char defifs[] = " \t\n";
1517 static struct var varinit[] = {
1519 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1521 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1524 #ifdef CONFIG_ASH_MAIL
1525 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1526 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1529 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1530 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1531 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1532 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1533 #ifdef CONFIG_ASH_GETOPTS
1534 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1536 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1537 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1539 #ifdef CONFIG_LOCALE_SUPPORT
1540 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1541 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
1543 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1544 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
1548 #define vifs varinit[0]
1549 #ifdef CONFIG_ASH_MAIL
1550 #define vmail (&vifs)[1]
1551 #define vmpath (&vmail)[1]
1555 #define vpath (&vmpath)[1]
1556 #define vps1 (&vpath)[1]
1557 #define vps2 (&vps1)[1]
1558 #define vps4 (&vps2)[1]
1559 #define voptind (&vps4)[1]
1560 #ifdef CONFIG_ASH_GETOPTS
1561 #define vrandom (&voptind)[1]
1563 #define vrandom (&vps4)[1]
1565 #define defpath (defpathvar + 5)
1568 * The following macros access the values of the above variables.
1569 * They have to skip over the name. They return the null string
1570 * for unset variables.
1573 #define ifsval() (vifs.text + 4)
1574 #define ifsset() ((vifs.flags & VUNSET) == 0)
1575 #define mailval() (vmail.text + 5)
1576 #define mpathval() (vmpath.text + 9)
1577 #define pathval() (vpath.text + 5)
1578 #define ps1val() (vps1.text + 4)
1579 #define ps2val() (vps2.text + 4)
1580 #define ps4val() (vps4.text + 4)
1581 #define optindval() (voptind.text + 7)
1583 #define mpathset() ((vmpath.flags & VUNSET) == 0)
1585 static void setvar(const char *, const char *, int);
1586 static void setvareq(char *, int);
1587 static void listsetvar(struct strlist *, int);
1588 static char *lookupvar(const char *);
1589 static char *bltinlookup(const char *);
1590 static char **listvars(int, int, char ***);
1591 #define environment() listvars(VEXPORT, VUNSET, 0)
1592 static int showvars(const char *, int, int);
1593 static void poplocalvars(void);
1594 static int unsetvar(const char *);
1595 #ifdef CONFIG_ASH_GETOPTS
1596 static int setvarsafe(const char *, const char *, int);
1598 static int varcmp(const char *, const char *);
1599 static struct var **hashvar(const char *);
1602 static inline int varequal(const char *a, const char *b) {
1603 return !varcmp(a, b);
1607 static int loopnest; /* current loop nesting level */
1610 * The parsefile structure pointed to by the global variable parsefile
1611 * contains information about the current file being read.
1616 struct redirtab *next;
1621 static struct redirtab *redirlist;
1622 static int nullredirs;
1624 extern char **environ;
1626 /* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1629 static void outstr(const char *, FILE *);
1630 static void outcslow(int, FILE *);
1631 static void flushall(void);
1632 static void flusherr(void);
1633 static int out1fmt(const char *, ...)
1634 __attribute__((__format__(__printf__,1,2)));
1635 static int fmtstr(char *, size_t, const char *, ...)
1636 __attribute__((__format__(__printf__,3,4)));
1638 static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1641 static void out1str(const char *p)
1646 static void out2str(const char *p)
1653 * Initialization code.
1657 * This routine initializes the builtin variables.
1668 * PS1 depends on uid
1670 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1671 vps1.text = "PS1=\\w \\$ ";
1674 vps1.text = "PS1=# ";
1677 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1679 vpp = hashvar(vp->text);
1682 } while (++vp < end);
1691 basepf.nextc = basepf.buf = basebuf;
1696 signal(SIGCHLD, SIG_DFL);
1705 for (envp = environ ; *envp ; envp++) {
1706 if (strchr(*envp, '=')) {
1707 setvareq(*envp, VEXPORT|VTEXTFIXED);
1711 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1712 setvar("PPID", ppid, 0);
1717 /* PEOF (the end of file marker) */
1720 * The input line number. Input.c just defines this variable, and saves
1721 * and restores it when files are pushed and popped. The user of this
1722 * package must set its value.
1725 static int pgetc(void);
1726 static int pgetc2(void);
1727 static int preadbuffer(void);
1728 static void pungetc(void);
1729 static void pushstring(char *, void *);
1730 static void popstring(void);
1731 static void setinputfile(const char *, int);
1732 static void setinputfd(int, int);
1733 static void setinputstring(char *);
1734 static void popfile(void);
1735 static void popallfiles(void);
1736 static void closescript(void);
1739 /* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1742 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1745 #define FORK_NOJOB 2
1747 /* mode flags for showjob(s) */
1748 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1749 #define SHOW_PID 0x04 /* include process pid */
1750 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1754 * A job structure contains information about a job. A job is either a
1755 * single process or a set of processes contained in a pipeline. In the
1756 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1761 pid_t pid; /* process id */
1762 int status; /* last process status from wait() */
1763 char *cmd; /* text of command being run */
1767 struct procstat ps0; /* status of process */
1768 struct procstat *ps; /* status or processes when more than one */
1770 int stopstatus; /* status of a stopped job */
1773 nprocs: 16, /* number of processes */
1775 #define JOBRUNNING 0 /* at least one proc running */
1776 #define JOBSTOPPED 1 /* all procs are stopped */
1777 #define JOBDONE 2 /* all procs are completed */
1779 sigint: 1, /* job was killed by SIGINT */
1780 jobctl: 1, /* job running under job control */
1782 waited: 1, /* true if this entry has been waited for */
1783 used: 1, /* true if this entry is in used */
1784 changed: 1; /* true if status has changed */
1785 struct job *prev_job; /* previous job */
1788 static pid_t backgndpid; /* pid of last background process */
1789 static int job_warning; /* user was warned about stopped jobs */
1791 static int jobctl; /* true if doing job control */
1794 static struct job *makejob(union node *, int);
1795 static int forkshell(struct job *, union node *, int);
1796 static int waitforjob(struct job *);
1797 static int stoppedjobs(void);
1800 #define setjobctl(on) /* do nothing */
1802 static void setjobctl(int);
1803 static void showjobs(FILE *, int);
1806 /* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1809 /* pid of main shell */
1811 /* true if we aren't a child of the main shell */
1812 static int rootshell;
1814 static void readcmdfile(char *);
1815 static void cmdloop(int);
1817 /* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1821 struct stack_block *stackp;
1824 struct stackmark *marknext;
1827 /* minimum size of a block */
1828 #define MINSIZE SHELL_ALIGN(504)
1830 struct stack_block {
1831 struct stack_block *prev;
1832 char space[MINSIZE];
1835 static struct stack_block stackbase;
1836 static struct stack_block *stackp = &stackbase;
1837 static struct stackmark *markp;
1838 static char *stacknxt = stackbase.space;
1839 static size_t stacknleft = MINSIZE;
1840 static char *sstrend = stackbase.space + MINSIZE;
1841 static int herefd = -1;
1844 static pointer ckmalloc(size_t);
1845 static pointer ckrealloc(pointer, size_t);
1846 static char *savestr(const char *);
1847 static pointer stalloc(size_t);
1848 static void stunalloc(pointer);
1849 static void setstackmark(struct stackmark *);
1850 static void popstackmark(struct stackmark *);
1851 static void growstackblock(void);
1852 static void *growstackstr(void);
1853 static char *makestrspace(size_t, char *);
1854 static char *stnputs(const char *, size_t, char *);
1855 static char *stputs(const char *, char *);
1858 static inline char *_STPUTC(char c, char *p) {
1865 #define stackblock() ((void *)stacknxt)
1866 #define stackblocksize() stacknleft
1867 #define STARTSTACKSTR(p) ((p) = stackblock())
1868 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1869 #define CHECKSTRSPACE(n, p) \
1873 size_t m = sstrend - q; \
1875 (p) = makestrspace(l, q); \
1878 #define USTPUTC(c, p) (*p++ = (c))
1879 #define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1880 #define STUNPUTC(p) (--p)
1881 #define STTOPC(p) p[-1]
1882 #define STADJUST(amount, p) (p += (amount))
1884 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1885 #define ungrabstackstr(s, p) stunalloc((s))
1886 #define stackstrend() ((void *)sstrend)
1888 #define ckfree(p) free((pointer)(p))
1890 /* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1893 #define DOLATSTRLEN 4
1895 static char *prefix(const char *, const char *);
1896 static int number(const char *);
1897 static int is_number(const char *);
1898 static char *single_quote(const char *);
1899 static char *sstrdup(const char *);
1901 #define equal(s1, s2) (strcmp(s1, s2) == 0)
1902 #define scopy(s1, s2) ((void)strcpy(s2, s1))
1904 /* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1907 int nparam; /* # of positional parameters (without $0) */
1908 unsigned char malloc; /* if parameter list dynamically allocated */
1909 char **p; /* parameter list */
1910 #ifdef CONFIG_ASH_GETOPTS
1911 int optind; /* next parameter to be processed by getopts */
1912 int optoff; /* used by getopts */
1917 #define eflag optlist[0]
1918 #define fflag optlist[1]
1919 #define Iflag optlist[2]
1920 #define iflag optlist[3]
1921 #define mflag optlist[4]
1922 #define nflag optlist[5]
1923 #define sflag optlist[6]
1924 #define xflag optlist[7]
1925 #define vflag optlist[8]
1926 #define Cflag optlist[9]
1927 #define aflag optlist[10]
1928 #define bflag optlist[11]
1929 #define uflag optlist[12]
1930 #define qflag optlist[13]
1931 #define viflag optlist[14]
1934 #define nolog optlist[15]
1935 #define debug optlist[16]
1938 #ifndef CONFIG_FEATURE_COMMAND_EDITING_VI
1939 #define setvimode(on) viflag = 0 /* forcibly keep the option off */
1942 /* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1945 static const char *const optletters_optnames[] = {
1967 #define optletters(n) optletters_optnames[(n)][0]
1968 #define optnames(n) (&optletters_optnames[(n)][1])
1970 #define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
1972 static char optlist[NOPTS];
1975 static char *arg0; /* value of $0 */
1976 static struct shparam shellparam; /* $@ current positional parameters */
1977 static char **argptr; /* argument list for builtin commands */
1978 static char *optionarg; /* set by nextopt (like getopt) */
1979 static char *optptr; /* used by nextopt */
1981 static char *minusc; /* argument to -c option */
1984 static void procargs(int, char **);
1985 static void optschanged(void);
1986 static void setparam(char **);
1987 static void freeparam(volatile struct shparam *);
1988 static int shiftcmd(int, char **);
1989 static int setcmd(int, char **);
1990 static int nextopt(const char *);
1992 /* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
1994 /* flags passed to redirect */
1995 #define REDIR_PUSH 01 /* save previous values of file descriptors */
1996 #define REDIR_SAVEFD2 03 /* set preverrout */
1999 static void redirect(union node *, int);
2000 static void popredir(int);
2001 static void clearredir(int);
2002 static int copyfd(int, int);
2003 static int redirectsafe(union node *, int);
2005 /* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2009 static void showtree(union node *);
2010 static void trace(const char *, ...);
2011 static void tracev(const char *, va_list);
2012 static void trargs(char **);
2013 static void trputc(int);
2014 static void trputs(const char *);
2015 static void opentrace(void);
2018 /* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2021 /* trap handler commands */
2022 static char *trap[NSIG];
2023 /* current value of signal */
2024 static char sigmode[NSIG - 1];
2025 /* indicates specified signal received */
2026 static char gotsig[NSIG - 1];
2028 static void clear_traps(void);
2029 static void setsignal(int);
2030 static void ignoresig(int);
2031 static void onsig(int);
2032 static void dotrap(void);
2033 static void setinteractive(int);
2034 static void exitshell(void) __attribute__((__noreturn__));
2035 static int decode_signal(const char *, int);
2038 * This routine is called when an error or an interrupt occurs in an
2039 * interactive shell and control is returned to the main command loop.
2054 parselleft = parsenleft = 0; /* clear input buffer */
2058 /* from parser.c: */
2071 #ifdef CONFIG_ASH_ALIAS
2072 static struct alias *atab[ATABSIZE];
2074 static void setalias(const char *, const char *);
2075 static struct alias *freealias(struct alias *);
2076 static struct alias **__lookupalias(const char *);
2079 setalias(const char *name, const char *val)
2081 struct alias *ap, **app;
2083 app = __lookupalias(name);
2087 if (!(ap->flag & ALIASINUSE)) {
2090 ap->val = savestr(val);
2091 ap->flag &= ~ALIASDEAD;
2094 ap = ckmalloc(sizeof (struct alias));
2095 ap->name = savestr(name);
2096 ap->val = savestr(val);
2105 unalias(const char *name)
2109 app = __lookupalias(name);
2113 *app = freealias(*app);
2124 struct alias *ap, **app;
2128 for (i = 0; i < ATABSIZE; i++) {
2130 for (ap = *app; ap; ap = *app) {
2131 *app = freealias(*app);
2140 static struct alias *
2141 lookupalias(const char *name, int check)
2143 struct alias *ap = *__lookupalias(name);
2145 if (check && ap && (ap->flag & ALIASINUSE))
2151 * TODO - sort output
2154 aliascmd(int argc, char **argv)
2163 for (i = 0; i < ATABSIZE; i++)
2164 for (ap = atab[i]; ap; ap = ap->next) {
2169 while ((n = *++argv) != NULL) {
2170 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
2171 if ((ap = *__lookupalias(n)) == NULL) {
2172 fprintf(stderr, "%s: %s not found\n", "alias", n);
2186 unaliascmd(int argc, char **argv)
2190 while ((i = nextopt("a")) != '\0') {
2196 for (i = 0; *argptr; argptr++) {
2197 if (unalias(*argptr)) {
2198 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
2206 static struct alias *
2207 freealias(struct alias *ap) {
2210 if (ap->flag & ALIASINUSE) {
2211 ap->flag |= ALIASDEAD;
2223 printalias(const struct alias *ap) {
2224 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2227 static struct alias **
2228 __lookupalias(const char *name) {
2229 unsigned int hashval;
2236 ch = (unsigned char)*p;
2240 ch = (unsigned char)*++p;
2242 app = &atab[hashval % ATABSIZE];
2244 for (; *app; app = &(*app)->next) {
2245 if (equal(name, (*app)->name)) {
2252 #endif /* CONFIG_ASH_ALIAS */
2255 /* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2258 * The cd and pwd commands.
2261 #define CD_PHYSICAL 1
2264 static int docd(const char *, int);
2265 static int cdopt(void);
2267 static char *curdir = nullstr; /* current working directory */
2268 static char *physdir = nullstr; /* physical working directory */
2277 while ((i = nextopt("LP"))) {
2279 flags ^= CD_PHYSICAL;
2288 cdcmd(int argc, char **argv)
2300 dest = bltinlookup(homestr);
2301 else if (dest[0] == '-' && dest[1] == '\0') {
2302 dest = bltinlookup("OLDPWD");
2303 if ( !dest ) goto out;
2326 if (!(path = bltinlookup("CDPATH"))) {
2334 p = padvance(&path, dest);
2335 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2339 if (!docd(p, flags))
2344 error("can't cd to %s", dest);
2347 if (flags & CD_PRINT)
2348 out1fmt(snlfmt, curdir);
2354 * Update curdir (the name of the current directory) in response to a
2358 static inline const char *
2359 updatepwd(const char *dir)
2366 cdcomppath = sstrdup(dir);
2369 if (curdir == nullstr)
2371 new = stputs(curdir, new);
2373 new = makestrspace(strlen(dir) + 2, new);
2374 lim = stackblock() + 1;
2378 if (new > lim && *lim == '/')
2383 if (dir[1] == '/' && dir[2] != '/') {
2389 p = strtok(cdcomppath, "/");
2393 if (p[1] == '.' && p[2] == '\0') {
2400 } else if (p[1] == '\0')
2404 new = stputs(p, new);
2412 return stackblock();
2416 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2417 * know that the current directory has changed.
2421 docd(const char *dest, int flags)
2423 const char *dir = 0;
2426 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2429 if (!(flags & CD_PHYSICAL)) {
2430 dir = updatepwd(dest);
2445 * Find out what the current directory is. If we already know the current
2446 * directory, this routine returns immediately.
2448 static inline char *
2451 char *dir = getcwd(0, 0);
2452 return dir ? dir : nullstr;
2456 pwdcmd(int argc, char **argv)
2459 const char *dir = curdir;
2463 if (physdir == nullstr)
2467 out1fmt(snlfmt, dir);
2472 setpwd(const char *val, int setold)
2476 oldcur = dir = curdir;
2479 setvar("OLDPWD", oldcur, VEXPORT);
2482 if (physdir != nullstr) {
2483 if (physdir != oldcur)
2487 if (oldcur == val || !val) {
2494 if (oldcur != dir && oldcur != nullstr) {
2499 setvar("PWD", dir, VEXPORT);
2502 /* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2505 * Errors and exceptions.
2509 * Code to handle exceptions in C.
2514 static void exverror(int, const char *, va_list)
2515 __attribute__((__noreturn__));
2518 * Called to raise an exception. Since C doesn't include exceptions, we
2519 * just do a longjmp to the exception handler. The type of exception is
2520 * stored in the global variable "exception".
2527 if (handler == NULL)
2533 longjmp(handler->loc, 1);
2538 * Called from trap.c when a SIGINT is received. (If the user specifies
2539 * that SIGINT is to be trapped or ignored using the trap builtin, then
2540 * this routine is not called.) Suppressint is nonzero when interrupts
2541 * are held using the INTOFF macro. (The test for iflag is just
2542 * defensive programming.)
2552 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2553 if (!(rootshell && iflag)) {
2554 signal(SIGINT, SIG_DFL);
2564 exvwarning(const char *msg, va_list ap)
2577 fprintf(errs, fmt, name, startlinno);
2578 vfprintf(errs, msg, ap);
2579 outcslow('\n', errs);
2583 * Exverror is called to raise the error exception. If the second argument
2584 * is not NULL then error prints an error message using printf style
2585 * formatting. It then raises the error exception.
2588 exverror(int cond, const char *msg, va_list ap)
2592 TRACE(("exverror(%d, \"", cond));
2594 TRACE(("\") pid=%d\n", getpid()));
2596 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2599 exvwarning(msg, ap);
2608 error(const char *msg, ...)
2613 exverror(EXERROR, msg, ap);
2620 exerror(int cond, const char *msg, ...)
2625 exverror(cond, msg, ap);
2631 * error/warning routines for external builtins
2635 sh_warnx(const char *fmt, ...)
2640 exvwarning(fmt, ap);
2646 * Return a string describing an error. The returned string may be a
2647 * pointer to a static buffer that will be overwritten on the next call.
2648 * Action describes the operation that got the error.
2652 errmsg(int e, const char *em)
2654 if(e == ENOENT || e == ENOTDIR) {
2662 /* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2665 * Evaluate a command.
2668 /* flags in argument to evaltree */
2669 #define EV_EXIT 01 /* exit after evaluating tree */
2670 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2671 #define EV_BACKCMD 04 /* command executing within back quotes */
2674 static void evalloop(union node *, int);
2675 static void evalfor(union node *, int);
2676 static void evalcase(union node *, int);
2677 static void evalsubshell(union node *, int);
2678 static void expredir(union node *);
2679 static void evalpipe(union node *, int);
2680 static void evalcommand(union node *, int);
2681 static int evalbltin(const struct builtincmd *, int, char **);
2682 static int evalfun(struct funcnode *, int, char **, int);
2683 static void prehash(union node *);
2684 static int bltincmd(int, char **);
2687 static const struct builtincmd bltin = {
2693 * Called to reset things after an exception.
2701 evalcmd(int argc, char **argv)
2710 STARTSTACKSTR(concat);
2713 concat = stputs(p, concat);
2714 if ((p = *ap++) == NULL)
2716 STPUTC(' ', concat);
2718 STPUTC('\0', concat);
2719 p = grabstackstr(concat);
2728 * Execute a command or commands contained in a string.
2735 struct stackmark smark;
2737 setstackmark(&smark);
2740 while ((n = parsecmd(0)) != NEOF) {
2742 popstackmark(&smark);
2747 popstackmark(&smark);
2753 * Evaluate a parse tree. The value is left in the global variable
2758 evaltree(union node *n, int flags)
2761 void (*evalfn)(union node *, int);
2765 TRACE(("evaltree(NULL) called\n"));
2768 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2769 getpid(), n, n->type, flags));
2773 out1fmt("Node type = %d\n", n->type);
2778 evaltree(n->nnot.com, EV_TESTED);
2779 status = !exitstatus;
2782 expredir(n->nredir.redirect);
2783 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2785 evaltree(n->nredir.n, flags & EV_TESTED);
2786 status = exitstatus;
2791 evalfn = evalcommand;
2793 if (eflag && !(flags & EV_TESTED))
2805 evalfn = evalsubshell;
2817 #error NAND + 1 != NOR
2819 #if NOR + 1 != NSEMI
2820 #error NOR + 1 != NSEMI
2822 isor = n->type - NAND;
2825 (flags | ((isor >> 1) - 1)) & EV_TESTED
2827 if (!exitstatus == isor)
2839 evaltree(n->nif.test, EV_TESTED);
2842 if (exitstatus == 0) {
2845 } else if (n->nif.elsepart) {
2846 n = n->nif.elsepart;
2851 defun(n->narg.text, n->narg.next);
2855 exitstatus = status;
2861 if (flags & EV_EXIT || checkexit & exitstatus)
2866 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2869 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2873 evalloop(union node *n, int flags)
2883 evaltree(n->nbinary.ch1, EV_TESTED);
2885 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2889 if (evalskip == SKIPBREAK && --skipcount <= 0)
2894 if (n->type != NWHILE)
2898 evaltree(n->nbinary.ch2, flags);
2899 status = exitstatus;
2904 exitstatus = status;
2910 evalfor(union node *n, int flags)
2912 struct arglist arglist;
2915 struct stackmark smark;
2917 setstackmark(&smark);
2918 arglist.lastp = &arglist.list;
2919 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2920 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2925 *arglist.lastp = NULL;
2930 for (sp = arglist.list ; sp ; sp = sp->next) {
2931 setvar(n->nfor.var, sp->text, 0);
2932 evaltree(n->nfor.body, flags);
2934 if (evalskip == SKIPCONT && --skipcount <= 0) {
2938 if (evalskip == SKIPBREAK && --skipcount <= 0)
2945 popstackmark(&smark);
2951 evalcase(union node *n, int flags)
2955 struct arglist arglist;
2956 struct stackmark smark;
2958 setstackmark(&smark);
2959 arglist.lastp = &arglist.list;
2960 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2962 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2963 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2964 if (casematch(patp, arglist.list->text)) {
2965 if (evalskip == 0) {
2966 evaltree(cp->nclist.body, flags);
2973 popstackmark(&smark);
2979 * Kick off a subshell to evaluate a tree.
2983 evalsubshell(union node *n, int flags)
2986 int backgnd = (n->type == NBACKGND);
2989 expredir(n->nredir.redirect);
2990 if (!backgnd && flags & EV_EXIT && !trap[0])
2994 if (forkshell(jp, n, backgnd) == 0) {
2998 flags &=~ EV_TESTED;
3000 redirect(n->nredir.redirect, 0);
3001 evaltreenr(n->nredir.n, flags);
3006 status = waitforjob(jp);
3007 exitstatus = status;
3014 * Compute the names of the files in a redirection list.
3018 expredir(union node *n)
3022 for (redir = n ; redir ; redir = redir->nfile.next) {
3024 fn.lastp = &fn.list;
3025 switch (redir->type) {
3031 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3032 redir->nfile.expfname = fn.list->text;
3036 if (redir->ndup.vname) {
3037 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3038 fixredir(redir, fn.list->text, 1);
3048 * Evaluate a pipeline. All the processes in the pipeline are children
3049 * of the process creating the pipeline. (This differs from some versions
3050 * of the shell, which make the last process in a pipeline the parent
3055 evalpipe(union node *n, int flags)
3058 struct nodelist *lp;
3063 TRACE(("evalpipe(0x%lx) called\n", (long)n));
3065 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3069 jp = makejob(n, pipelen);
3071 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3075 if (pipe(pip) < 0) {
3077 error("Pipe call failed");
3080 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3093 evaltreenr(lp->n, flags);
3101 if (n->npipe.backgnd == 0) {
3102 exitstatus = waitforjob(jp);
3103 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
3111 * Execute a command inside back quotes. If it's a builtin command, we
3112 * want to save its output in a block obtained from malloc. Otherwise
3113 * we fork off a subprocess and get the output of the command via a pipe.
3114 * Should be called with interrupts off.
3118 evalbackcmd(union node *n, struct backcmd *result)
3130 saveherefd = herefd;
3138 error("Pipe call failed");
3140 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3149 evaltreenr(n, EV_EXIT);
3153 result->fd = pip[0];
3156 herefd = saveherefd;
3158 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3159 result->fd, result->buf, result->nleft, result->jp));
3162 #ifdef CONFIG_ASH_CMDCMD
3163 static inline char **
3164 parse_command_args(char **argv, const char **path)
3176 if (c == '-' && !*cp) {
3186 /* run 'typecmd' for other options */
3189 } while ((c = *cp++));
3196 isassignment(const char *p)
3198 const char *q = endofname(p);
3205 * Execute a simple command.
3209 evalcommand(union node *cmd, int flags)
3211 struct stackmark smark;
3213 struct arglist arglist;
3214 struct arglist varlist;
3217 const struct strlist *sp;
3218 struct cmdentry cmdentry;
3226 struct builtincmd *bcmd;
3227 int pseudovarflag = 0;
3229 /* First expand the arguments. */
3230 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3231 setstackmark(&smark);
3232 back_exitstatus = 0;
3234 cmdentry.cmdtype = CMDBUILTIN;
3235 cmdentry.u.cmd = &bltin;
3236 varlist.lastp = &varlist.list;
3237 *varlist.lastp = NULL;
3238 arglist.lastp = &arglist.list;
3239 *arglist.lastp = NULL;
3244 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3245 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3248 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3249 struct strlist **spp;
3251 spp = arglist.lastp;
3252 if (pseudovarflag && isassignment(argp->narg.text))
3253 expandarg(argp, &arglist, EXP_VARTILDE);
3255 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3257 for (sp = *spp; sp; sp = sp->next)
3261 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3262 for (sp = arglist.list ; sp ; sp = sp->next) {
3263 TRACE(("evalcommand arg: %s\n", sp->text));
3264 *nargv++ = sp->text;
3269 if (iflag && funcnest == 0 && argc > 0)
3270 lastarg = nargv[-1];
3273 expredir(cmd->ncmd.redirect);
3274 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
3277 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3278 struct strlist **spp;
3281 spp = varlist.lastp;
3282 expandarg(argp, &varlist, EXP_VARTILDE);
3285 * Modify the command lookup path, if a PATH= assignment
3289 if (varequal(p, path))
3293 /* Print the command if xflag is set. */
3296 const char *p = " %s";
3299 dprintf(preverrout_fd, p, ps4val());
3302 for(n = 0; n < 2; n++) {
3304 dprintf(preverrout_fd, p, sp->text);
3312 bb_full_write(preverrout_fd, "\n", 1);
3318 /* Now locate the command. */
3320 const char *oldpath;
3321 int cmd_flag = DO_ERR;
3326 find_command(argv[0], &cmdentry, cmd_flag, path);
3327 if (cmdentry.cmdtype == CMDUNKNOWN) {
3333 /* implement bltin and command here */
3334 if (cmdentry.cmdtype != CMDBUILTIN)
3337 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3338 if (cmdentry.u.cmd == EXECCMD)
3340 #ifdef CONFIG_ASH_CMDCMD
3341 if (cmdentry.u.cmd == COMMANDCMD) {
3344 nargv = parse_command_args(argv, &path);
3347 argc -= nargv - argv;
3349 cmd_flag |= DO_NOFUNC;
3357 /* We have a redirection error. */
3361 exitstatus = status;
3365 /* Execute the command. */
3366 switch (cmdentry.cmdtype) {
3368 /* Fork off a child process if necessary. */
3369 if (!(flags & EV_EXIT) || trap[0]) {
3371 jp = makejob(cmd, 1);
3372 if (forkshell(jp, cmd, FORK_FG) != 0) {
3373 exitstatus = waitforjob(jp);
3379 listsetvar(varlist.list, VEXPORT|VSTACK);
3380 shellexec(argv, path, cmdentry.u.index);
3384 cmdenviron = varlist.list;
3386 struct strlist *list = cmdenviron;
3388 if (spclbltin > 0 || argc == 0) {
3390 if (cmd_is_exec && argc > 1)
3393 listsetvar(list, i);
3395 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3410 exit_status = j + 128;
3411 exitstatus = exit_status;
3413 if (i == EXINT || spclbltin > 0) {
3415 longjmp(handler->loc, 1);
3422 listsetvar(varlist.list, 0);
3423 if (evalfun(cmdentry.u.func, argc, argv, flags))
3429 popredir(cmd_is_exec);
3431 /* dsl: I think this is intended to be used to support
3432 * '_' in 'vi' command mode during line editing...
3433 * However I implemented that within libedit itself.
3435 setvar("_", lastarg, 0);
3436 popstackmark(&smark);
3440 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3441 char *volatile savecmdname;
3442 struct jmploc *volatile savehandler;
3443 struct jmploc jmploc;
3446 savecmdname = commandname;
3447 if ((i = setjmp(jmploc.loc)))
3449 savehandler = handler;
3451 commandname = argv[0];
3453 optptr = NULL; /* initialize nextopt */
3454 exitstatus = (*cmd->builtin)(argc, argv);
3457 exitstatus |= ferror(stdout);
3458 commandname = savecmdname;
3460 handler = savehandler;
3466 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3468 volatile struct shparam saveparam;
3469 struct localvar *volatile savelocalvars;
3470 struct jmploc *volatile savehandler;
3471 struct jmploc jmploc;
3474 saveparam = shellparam;
3475 savelocalvars = localvars;
3476 if ((e = setjmp(jmploc.loc))) {
3480 savehandler = handler;
3483 shellparam.malloc = 0;
3486 shellparam.nparam = argc - 1;
3487 shellparam.p = argv + 1;
3488 #ifdef CONFIG_ASH_GETOPTS
3489 shellparam.optind = 1;
3490 shellparam.optoff = -1;
3493 evaltree(&func->n, flags & EV_TESTED);
3499 localvars = savelocalvars;
3500 freeparam(&shellparam);
3501 shellparam = saveparam;
3502 handler = savehandler;
3504 if (evalskip == SKIPFUNC) {
3513 goodname(const char *p)
3515 return !*endofname(p);
3519 * Search for a command. This is called before we fork so that the
3520 * location of the command will be available in the parent as well as
3521 * the child. The check for "goodname" is an overly conservative
3522 * check that the name will not be subject to expansion.
3526 prehash(union node *n)
3528 struct cmdentry entry;
3530 if (n->type == NCMD && n->ncmd.args)
3531 if (goodname(n->ncmd.args->narg.text))
3532 find_command(n->ncmd.args->narg.text, &entry, 0,
3539 * Builtin commands. Builtin commands whose functions are closely
3540 * tied to evaluation are implemented here.
3548 bltincmd(int argc, char **argv)
3551 * Preserve exitstatus of a previous possible redirection
3554 return back_exitstatus;
3559 * Handle break and continue commands. Break, continue, and return are
3560 * all handled by setting the evalskip flag. The evaluation routines
3561 * above all check this flag, and if it is set they start skipping
3562 * commands rather than executing them. The variable skipcount is
3563 * the number of loops to break/continue, or the number of function
3564 * levels to return. (The latter is always 1.) It should probably
3565 * be an error to break out of more loops than exist, but it isn't
3566 * in the standard shell so we don't make it one here.
3570 breakcmd(int argc, char **argv)
3572 int n = argc > 1 ? number(argv[1]) : 1;
3575 error(illnum, argv[1]);
3579 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3587 * The return command.
3591 returncmd(int argc, char **argv)
3593 int ret = argc > 1 ? number(argv[1]) : exitstatus;
3596 evalskip = SKIPFUNC;
3601 /* Do what ksh does; skip the rest of the file */
3602 evalskip = SKIPFILE;
3610 falsecmd(int argc, char **argv)
3617 truecmd(int argc, char **argv)
3624 execcmd(int argc, char **argv)
3627 iflag = 0; /* exit on error */
3630 shellexec(argv + 1, pathval(), 0);
3636 /* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3639 * When commands are first encountered, they are entered in a hash table.
3640 * This ensures that a full path search will not have to be done for them
3641 * on each invocation.
3643 * We should investigate converting to a linear search, even though that
3644 * would make the command name "hash" a misnomer.
3647 #define CMDTABLESIZE 31 /* should be prime */
3648 #define ARB 1 /* actual size determined at run time */
3653 struct tblentry *next; /* next entry in hash chain */
3654 union param param; /* definition of builtin function */
3655 short cmdtype; /* index identifying command */
3656 char rehash; /* if set, cd done since entry created */
3657 char cmdname[ARB]; /* name of command */
3661 static struct tblentry *cmdtable[CMDTABLESIZE];
3662 static int builtinloc = -1; /* index in path of %builtin, or -1 */
3665 static void tryexec(char *, char **, char **);
3666 static void clearcmdentry(int);
3667 static struct tblentry *cmdlookup(const char *, int);
3668 static void delete_cmd_entry(void);
3672 * Exec a program. Never returns. If you change this routine, you may
3673 * have to change the find_command routine as well.
3677 shellexec(char **argv, const char *path, int idx)
3684 envp = environment();
3685 if (strchr(argv[0], '/') != NULL
3686 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3687 || find_applet_by_name(argv[0])
3690 tryexec(argv[0], argv, envp);
3694 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3695 if (--idx < 0 && pathopt == NULL) {
3696 tryexec(cmdname, argv, envp);
3697 if (errno != ENOENT && errno != ENOTDIR)
3704 /* Map to POSIX errors */
3716 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3717 argv[0], e, suppressint ));
3718 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3724 tryexec(char *cmd, char **argv, char **envp)
3727 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3728 if(find_applet_by_name(cmd) != NULL) {
3729 /* re-exec ourselves with the new arguments */
3730 execve("/proc/self/exe",argv,envp);
3731 /* If proc isn't mounted, try hardcoded path to busybox binary*/
3732 execve("/bin/busybox",argv,envp);
3733 /* If they called chroot or otherwise made the binary no longer
3734 * executable, fall through */
3741 execve(cmd, argv, envp);
3742 } while (errno == EINTR);
3744 execve(cmd, argv, envp);
3748 } else if (errno == ENOEXEC) {
3752 for (ap = argv; *ap; ap++)
3754 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3756 *ap = cmd = (char *)DEFAULT_SHELL;
3759 while ((*ap++ = *argv++))
3769 * Do a path search. The variable path (passed by reference) should be
3770 * set to the start of the path before the first call; padvance will update
3771 * this value as it proceeds. Successive calls to padvance will return
3772 * the possible path expansions in sequence. If an option (indicated by
3773 * a percent sign) appears in the path entry then the global variable
3774 * pathopt will be set to point to it; otherwise pathopt will be set to
3779 padvance(const char **path, const char *name)
3789 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3790 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3791 while (stackblocksize() < len)
3795 memcpy(q, start, p - start);
3803 while (*p && *p != ':') p++;
3809 return stalloc(len);
3813 /*** Command hashing code ***/
3816 printentry(struct tblentry *cmdp)
3822 idx = cmdp->param.index;
3825 name = padvance(&path, cmdp->cmdname);
3827 } while (--idx >= 0);
3828 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3833 hashcmd(int argc, char **argv)
3835 struct tblentry **pp;
3836 struct tblentry *cmdp;
3838 struct cmdentry entry;
3841 while ((c = nextopt("r")) != '\0') {
3845 if (*argptr == NULL) {
3846 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3847 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3848 if (cmdp->cmdtype == CMDNORMAL)
3855 while ((name = *argptr) != NULL) {
3856 if ((cmdp = cmdlookup(name, 0)) != NULL
3857 && (cmdp->cmdtype == CMDNORMAL
3858 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3860 find_command(name, &entry, DO_ERR, pathval());
3861 if (entry.cmdtype == CMDUNKNOWN)
3870 * Resolve a command name. If you change this routine, you may have to
3871 * change the shellexec routine as well.
3875 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3877 struct tblentry *cmdp;
3884 struct builtincmd *bcmd;
3886 /* If name contains a slash, don't use PATH or hash table */
3887 if (strchr(name, '/') != NULL) {
3888 entry->u.index = -1;
3890 while (stat(name, &statb) < 0) {
3895 entry->cmdtype = CMDUNKNOWN;
3899 entry->cmdtype = CMDNORMAL;
3903 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3904 if (find_applet_by_name(name)) {
3905 entry->cmdtype = CMDNORMAL;
3906 entry->u.index = -1;
3911 updatetbl = (path == pathval());
3914 if (strstr(path, "%builtin") != NULL)
3918 /* If name is in the table, check answer will be ok */
3919 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3922 switch (cmdp->cmdtype) {
3940 } else if (cmdp->rehash == 0)
3941 /* if not invalidated by cd, we're done */
3945 /* If %builtin not in path, check for builtin next */
3946 bcmd = find_builtin(name);
3947 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3948 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3950 goto builtin_success;
3952 /* We have to search path. */
3953 prev = -1; /* where to start */
3954 if (cmdp && cmdp->rehash) { /* doing a rehash */
3955 if (cmdp->cmdtype == CMDBUILTIN)
3958 prev = cmdp->param.index;
3964 while ((fullname = padvance(&path, name)) != NULL) {
3965 stunalloc(fullname);
3968 if (prefix(pathopt, "builtin")) {
3970 goto builtin_success;
3972 } else if (!(act & DO_NOFUNC) &&
3973 prefix(pathopt, "func")) {
3976 /* ignore unimplemented options */
3980 /* if rehash, don't redo absolute path names */
3981 if (fullname[0] == '/' && idx <= prev) {
3984 TRACE(("searchexec \"%s\": no change\n", name));
3987 while (stat(fullname, &statb) < 0) {
3992 if (errno != ENOENT && errno != ENOTDIR)
3996 e = EACCES; /* if we fail, this will be the error */
3997 if (!S_ISREG(statb.st_mode))
3999 if (pathopt) { /* this is a %func directory */
4000 stalloc(strlen(fullname) + 1);
4001 readcmdfile(fullname);
4002 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4003 cmdp->cmdtype != CMDFUNCTION)
4004 error("%s not defined in %s", name, fullname);
4005 stunalloc(fullname);
4008 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4010 entry->cmdtype = CMDNORMAL;
4011 entry->u.index = idx;
4015 cmdp = cmdlookup(name, 1);
4016 cmdp->cmdtype = CMDNORMAL;
4017 cmdp->param.index = idx;
4022 /* We failed. If there was an entry for this command, delete it */
4023 if (cmdp && updatetbl)
4026 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4027 entry->cmdtype = CMDUNKNOWN;
4032 entry->cmdtype = CMDBUILTIN;
4033 entry->u.cmd = bcmd;
4037 cmdp = cmdlookup(name, 1);
4038 cmdp->cmdtype = CMDBUILTIN;
4039 cmdp->param.cmd = bcmd;
4043 entry->cmdtype = cmdp->cmdtype;
4044 entry->u = cmdp->param;
4049 * Wrapper around strcmp for qsort/bsearch/...
4051 static int pstrcmp(const void *a, const void *b)
4053 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4057 * Search the table of builtin commands.
4060 static struct builtincmd *
4061 find_builtin(const char *name)
4063 struct builtincmd *bp;
4066 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4075 * Called when a cd is done. Marks all commands so the next time they
4076 * are executed they will be rehashed.
4082 struct tblentry **pp;
4083 struct tblentry *cmdp;
4085 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4086 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4087 if (cmdp->cmdtype == CMDNORMAL || (
4088 cmdp->cmdtype == CMDBUILTIN &&
4089 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4100 * Fix command hash table when PATH changed.
4101 * Called before PATH is changed. The argument is the new value of PATH;
4102 * pathval() still returns the old value at this point.
4103 * Called with interrupts off.
4107 changepath(const char *newval)
4109 const char *old, *new;
4116 firstchange = 9999; /* assume no change */
4122 if ((*old == '\0' && *new == ':')
4123 || (*old == ':' && *new == '\0'))
4125 old = new; /* ignore subsequent differences */
4129 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4136 if (builtinloc < 0 && idx_bltin >= 0)
4137 builtinloc = idx_bltin; /* zap builtins */
4138 if (builtinloc >= 0 && idx_bltin < 0)
4140 clearcmdentry(firstchange);
4141 builtinloc = idx_bltin;
4146 * Clear out command entries. The argument specifies the first entry in
4147 * PATH which has changed.
4151 clearcmdentry(int firstchange)
4153 struct tblentry **tblp;
4154 struct tblentry **pp;
4155 struct tblentry *cmdp;
4158 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4160 while ((cmdp = *pp) != NULL) {
4161 if ((cmdp->cmdtype == CMDNORMAL &&
4162 cmdp->param.index >= firstchange)
4163 || (cmdp->cmdtype == CMDBUILTIN &&
4164 builtinloc >= firstchange)) {
4178 * Locate a command in the command hash table. If "add" is nonzero,
4179 * add the command to the table if it is not already present. The
4180 * variable "lastcmdentry" is set to point to the address of the link
4181 * pointing to the entry, so that delete_cmd_entry can delete the
4184 * Interrupts must be off if called with add != 0.
4187 static struct tblentry **lastcmdentry;
4190 static struct tblentry *
4191 cmdlookup(const char *name, int add)
4193 unsigned int hashval;
4195 struct tblentry *cmdp;
4196 struct tblentry **pp;
4199 hashval = (unsigned char)*p << 4;
4201 hashval += (unsigned char)*p++;
4203 pp = &cmdtable[hashval % CMDTABLESIZE];
4204 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4205 if (equal(cmdp->cmdname, name))
4209 if (add && cmdp == NULL) {
4210 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4211 + strlen(name) + 1);
4213 cmdp->cmdtype = CMDUNKNOWN;
4214 strcpy(cmdp->cmdname, name);
4221 * Delete the command entry returned on the last lookup.
4225 delete_cmd_entry(void)
4227 struct tblentry *cmdp;
4230 cmdp = *lastcmdentry;
4231 *lastcmdentry = cmdp->next;
4232 if (cmdp->cmdtype == CMDFUNCTION)
4233 freefunc(cmdp->param.func);
4240 * Add a new command entry, replacing any existing command entry for
4241 * the same name - except special builtins.
4245 addcmdentry(char *name, struct cmdentry *entry)
4247 struct tblentry *cmdp;
4249 cmdp = cmdlookup(name, 1);
4250 if (cmdp->cmdtype == CMDFUNCTION) {
4251 freefunc(cmdp->param.func);
4253 cmdp->cmdtype = entry->cmdtype;
4254 cmdp->param = entry->u;
4259 * Make a copy of a parse tree.
4262 static inline struct funcnode *
4263 copyfunc(union node *n)
4268 funcblocksize = offsetof(struct funcnode, n);
4271 blocksize = funcblocksize;
4272 f = ckmalloc(blocksize + funcstringsize);
4273 funcblock = (char *) f + offsetof(struct funcnode, n);
4274 funcstring = (char *) f + blocksize;
4281 * Define a shell function.
4285 defun(char *name, union node *func)
4287 struct cmdentry entry;
4290 entry.cmdtype = CMDFUNCTION;
4291 entry.u.func = copyfunc(func);
4292 addcmdentry(name, &entry);
4298 * Delete a function if it exists.
4302 unsetfunc(const char *name)
4304 struct tblentry *cmdp;
4306 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4307 cmdp->cmdtype == CMDFUNCTION)
4312 * Locate and print what a word is...
4316 #ifdef CONFIG_ASH_CMDCMD
4318 describe_command(char *command, int describe_command_verbose)
4320 #define describe_command_verbose 1
4322 describe_command(char *command)
4325 struct cmdentry entry;
4326 struct tblentry *cmdp;
4327 #ifdef CONFIG_ASH_ALIAS
4328 const struct alias *ap;
4330 const char *path = pathval();
4332 if (describe_command_verbose) {
4336 /* First look at the keywords */
4337 if (findkwd(command)) {
4338 out1str(describe_command_verbose ? " is a shell keyword" : command);
4342 #ifdef CONFIG_ASH_ALIAS
4343 /* Then look at the aliases */
4344 if ((ap = lookupalias(command, 0)) != NULL) {
4345 if (describe_command_verbose) {
4346 out1fmt(" is an alias for %s", ap->val);
4355 /* Then check if it is a tracked alias */
4356 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4357 entry.cmdtype = cmdp->cmdtype;
4358 entry.u = cmdp->param;
4360 /* Finally use brute force */
4361 find_command(command, &entry, DO_ABS, path);
4364 switch (entry.cmdtype) {
4366 int j = entry.u.index;
4372 p = padvance(&path, command);
4376 if (describe_command_verbose) {
4378 (cmdp ? " a tracked alias for" : nullstr), p
4387 if (describe_command_verbose) {
4388 out1str(" is a shell function");
4395 if (describe_command_verbose) {
4396 out1fmt(" is a %sshell builtin",
4397 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4398 "special " : nullstr
4406 if (describe_command_verbose) {
4407 out1str(": not found\n");
4413 outstr("\n", stdout);
4418 typecmd(int argc, char **argv)
4423 for (i = 1; i < argc; i++) {
4424 #ifdef CONFIG_ASH_CMDCMD
4425 err |= describe_command(argv[i], 1);
4427 err |= describe_command(argv[i]);
4433 #ifdef CONFIG_ASH_CMDCMD
4435 commandcmd(int argc, char **argv)
4438 int default_path = 0;
4439 int verify_only = 0;
4440 int verbose_verify_only = 0;
4442 while ((c = nextopt("pvV")) != '\0')
4447 "command: nextopt returned character code 0%o\n", c);
4457 verbose_verify_only = 1;
4461 if (default_path + verify_only + verbose_verify_only > 1 ||
4464 "command [-p] command [arg ...]\n"
4465 "command {-v|-V} command\n");
4469 if (verify_only || verbose_verify_only) {
4470 return describe_command(*argptr, verbose_verify_only);
4477 /* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
4480 * Routines to expand arguments to commands. We have to deal with
4481 * backquotes, shell variables, and file metacharacters.
4487 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4488 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4489 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4490 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4491 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4494 * Structure specifying which parts of the string should be searched
4495 * for IFS characters.
4499 struct ifsregion *next; /* next region in list */
4500 int begoff; /* offset of start of region */
4501 int endoff; /* offset of end of region */
4502 int nulonly; /* search for nul bytes only */
4505 /* output of current string */
4506 static char *expdest;
4507 /* list of back quote expressions */
4508 static struct nodelist *argbackq;
4509 /* first struct in list of ifs regions */
4510 static struct ifsregion ifsfirst;
4511 /* last struct in list */
4512 static struct ifsregion *ifslastp;
4513 /* holds expanded arg list */
4514 static struct arglist exparg;
4516 static void argstr(char *, int);
4517 static char *exptilde(char *, char *, int);
4518 static void expbackq(union node *, int, int);
4519 static const char *subevalvar(char *, char *, int, int, int, int, int);
4520 static char *evalvar(char *, int);
4521 static void strtodest(const char *, int, int);
4522 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4523 static ssize_t varvalue(char *, int, int);
4524 static void recordregion(int, int, int);
4525 static void removerecordregions(int);
4526 static void ifsbreakup(char *, struct arglist *);
4527 static void ifsfree(void);
4528 static void expandmeta(struct strlist *, int);
4529 static int patmatch(char *, const char *);
4531 static int cvtnum(arith_t);
4532 static size_t esclen(const char *, const char *);
4533 static char *scanleft(char *, char *, char *, char *, int, int);
4534 static char *scanright(char *, char *, char *, char *, int, int);
4535 static void varunset(const char *, const char *, const char *, int)
4536 __attribute__((__noreturn__));
4539 #define pmatch(a, b) !fnmatch((a), (b), 0)
4541 * Prepare a pattern for a expmeta (internal glob(3)) call.
4543 * Returns an stalloced string.
4546 static inline char *
4547 preglob(const char *pattern, int quoted, int flag) {
4548 flag |= RMESCAPE_GLOB;
4550 flag |= RMESCAPE_QUOTED;
4552 return _rmescapes((char *)pattern, flag);
4557 esclen(const char *start, const char *p) {
4560 while (p > start && *--p == CTLESC) {
4568 * Expand shell variables and backquotes inside a here document.
4572 expandhere(union node *arg, int fd)
4575 expandarg(arg, (struct arglist *)NULL, 0);
4576 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
4581 * Perform variable substitution and command substitution on an argument,
4582 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4583 * perform splitting and file name expansion. When arglist is NULL, perform
4584 * here document expansion.
4588 expandarg(union node *arg, struct arglist *arglist, int flag)
4593 argbackq = arg->narg.backquote;
4594 STARTSTACKSTR(expdest);
4595 ifsfirst.next = NULL;
4597 argstr(arg->narg.text, flag);
4598 if (arglist == NULL) {
4599 return; /* here document expanded */
4601 STPUTC('\0', expdest);
4602 p = grabstackstr(expdest);
4603 exparg.lastp = &exparg.list;
4607 if (flag & EXP_FULL) {
4608 ifsbreakup(p, &exparg);
4609 *exparg.lastp = NULL;
4610 exparg.lastp = &exparg.list;
4611 expandmeta(exparg.list, flag);
4613 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4615 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4618 exparg.lastp = &sp->next;
4622 *exparg.lastp = NULL;
4624 *arglist->lastp = exparg.list;
4625 arglist->lastp = exparg.lastp;
4631 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4632 * characters to allow for further processing. Otherwise treat
4633 * $@ like $* since no splitting will be performed.
4637 argstr(char *p, int flag)
4639 static const char spclchars[] = {
4647 CTLBACKQ | CTLQUOTE,
4648 #ifdef CONFIG_ASH_MATH_SUPPORT
4653 const char *reject = spclchars;
4655 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4656 int breakall = flag & EXP_WORD;
4661 if (!(flag & EXP_VARTILDE)) {
4663 } else if (flag & EXP_VARTILDE2) {
4668 if (flag & EXP_TILDE) {
4674 if (*q == CTLESC && (flag & EXP_QWORD))
4677 p = exptilde(p, q, flag);
4680 startloc = expdest - (char *)stackblock();
4682 length += strcspn(p + length, reject);
4684 if (c && (!(c & 0x80)
4685 #ifdef CONFIG_ASH_MATH_SUPPORT
4689 /* c == '=' || c == ':' || c == CTLENDARI */
4694 expdest = stnputs(p, length, expdest);
4695 newloc = expdest - (char *)stackblock();
4696 if (breakall && !inquotes && newloc > startloc) {
4697 recordregion(startloc, newloc, 0);
4708 if (flag & EXP_VARTILDE2) {
4712 flag |= EXP_VARTILDE2;
4717 * sort of a hack - expand tildes in variable
4718 * assignments (after the first '=' and after ':'s).
4727 case CTLENDVAR: /* ??? */
4730 /* "$@" syntax adherence hack */
4733 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4734 (p[4] == CTLQUOTEMARK || (
4735 p[4] == CTLENDVAR &&
4736 p[5] == CTLQUOTEMARK
4739 p = evalvar(p + 1, flag) + 1;
4742 inquotes = !inquotes;
4755 p = evalvar(p, flag);
4759 case CTLBACKQ|CTLQUOTE:
4760 expbackq(argbackq->n, c, quotes);
4761 argbackq = argbackq->next;
4763 #ifdef CONFIG_ASH_MATH_SUPPORT
4776 exptilde(char *startp, char *p, int flag)
4782 int quotes = flag & (EXP_FULL | EXP_CASE);
4787 while ((c = *++p) != '\0') {
4794 if (flag & EXP_VARTILDE)
4804 if (*name == '\0') {
4805 if ((home = lookupvar(homestr)) == NULL)
4808 if ((pw = getpwnam(name)) == NULL)
4815 startloc = expdest - (char *)stackblock();
4816 strtodest(home, SQSYNTAX, quotes);
4817 recordregion(startloc, expdest - (char *)stackblock(), 0);
4826 removerecordregions(int endoff)
4828 if (ifslastp == NULL)
4831 if (ifsfirst.endoff > endoff) {
4832 while (ifsfirst.next != NULL) {
4833 struct ifsregion *ifsp;
4835 ifsp = ifsfirst.next->next;
4836 ckfree(ifsfirst.next);
4837 ifsfirst.next = ifsp;
4840 if (ifsfirst.begoff > endoff)
4843 ifslastp = &ifsfirst;
4844 ifsfirst.endoff = endoff;
4849 ifslastp = &ifsfirst;
4850 while (ifslastp->next && ifslastp->next->begoff < endoff)
4851 ifslastp=ifslastp->next;
4852 while (ifslastp->next != NULL) {
4853 struct ifsregion *ifsp;
4855 ifsp = ifslastp->next->next;
4856 ckfree(ifslastp->next);
4857 ifslastp->next = ifsp;
4860 if (ifslastp->endoff > endoff)
4861 ifslastp->endoff = endoff;
4865 #ifdef CONFIG_ASH_MATH_SUPPORT
4867 * Expand arithmetic expression. Backup to start of expression,
4868 * evaluate, place result in (backed up) result, adjust string position.
4881 * This routine is slightly over-complicated for
4882 * efficiency. Next we scan backwards looking for the
4883 * start of arithmetic.
4885 start = stackblock();
4892 while (*p != CTLARI) {
4896 error("missing CTLARI (shouldn't happen)");
4901 esc = esclen(start, p);
4911 removerecordregions(begoff);
4920 len = cvtnum(dash_arith(p + 2));
4923 recordregion(begoff, begoff + len, 0);
4928 * Expand stuff in backwards quotes.
4932 expbackq(union node *cmd, int quoted, int quotes)
4940 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4941 struct stackmark smark;
4944 setstackmark(&smark);
4946 startloc = dest - (char *)stackblock();
4948 evalbackcmd(cmd, (struct backcmd *) &in);
4949 popstackmark(&smark);
4956 memtodest(p, i, syntax, quotes);
4960 i = safe_read(in.fd, buf, sizeof buf);
4961 TRACE(("expbackq: read returns %d\n", i));
4971 back_exitstatus = waitforjob(in.jp);
4975 /* Eat all trailing newlines */
4977 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4982 recordregion(startloc, dest - (char *)stackblock(), 0);
4983 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4984 (dest - (char *)stackblock()) - startloc,
4985 (dest - (char *)stackblock()) - startloc,
4986 stackblock() + startloc));
4991 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5002 const char *s = loc2;
5008 match = pmatch(str, s);
5012 if (quotes && *loc == CTLESC)
5022 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5029 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5032 const char *s = loc2;
5037 match = pmatch(str, s);
5044 esc = esclen(startp, loc);
5056 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5060 int saveherefd = herefd;
5061 struct nodelist *saveargbackq = argbackq;
5063 char *rmesc, *rmescend;
5065 char *(*scan)(char *, char *, char *, char *, int , int);
5068 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5069 STPUTC('\0', expdest);
5070 herefd = saveherefd;
5071 argbackq = saveargbackq;
5072 startp = stackblock() + startloc;
5076 setvar(str, startp, 0);
5077 amount = startp - expdest;
5078 STADJUST(amount, expdest);
5082 varunset(p, str, startp, varflags);
5086 subtype -= VSTRIMRIGHT;
5088 if (subtype < 0 || subtype > 3)
5093 rmescend = stackblock() + strloc;
5095 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5096 if (rmesc != startp) {
5098 startp = stackblock() + startloc;
5102 str = stackblock() + strloc;
5103 preglob(str, varflags & VSQUOTE, 0);
5105 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5106 zero = subtype >> 1;
5107 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5108 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5110 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5113 memmove(startp, loc, str - loc);
5114 loc = startp + (str - loc) - 1;
5117 amount = loc - expdest;
5118 STADJUST(amount, expdest);
5125 * Expand a variable, and return a pointer to the next character in the
5129 evalvar(char *p, int flag)
5142 quotes = flag & (EXP_FULL | EXP_CASE);
5144 subtype = varflags & VSTYPE;
5145 quoted = varflags & VSQUOTE;
5147 easy = (!quoted || (*var == '@' && shellparam.nparam));
5148 startloc = expdest - (char *)stackblock();
5149 p = strchr(p, '=') + 1;
5152 varlen = varvalue(var, varflags, flag);
5153 if (varflags & VSNUL)
5156 if (subtype == VSPLUS) {
5157 varlen = -1 - varlen;
5161 if (subtype == VSMINUS) {
5165 p, flag | EXP_TILDE |
5166 (quoted ? EXP_QWORD : EXP_WORD)
5175 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5177 if (subevalvar(p, var, 0, subtype, startloc,
5181 * Remove any recorded regions beyond
5184 removerecordregions(startloc);
5194 if (varlen < 0 && uflag)
5195 varunset(p, var, 0, 0);
5197 if (subtype == VSLENGTH) {
5198 cvtnum(varlen > 0 ? varlen : 0);
5202 if (subtype == VSNORMAL) {
5206 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5215 case VSTRIMRIGHTMAX:
5224 * Terminate the string and start recording the pattern
5227 STPUTC('\0', expdest);
5228 patloc = expdest - (char *)stackblock();
5229 if (subevalvar(p, NULL, patloc, subtype,
5230 startloc, varflags, quotes) == 0) {
5231 int amount = expdest - (
5232 (char *)stackblock() + patloc - 1
5234 STADJUST(-amount, expdest);
5236 /* Remove any recorded regions beyond start of variable */
5237 removerecordregions(startloc);
5242 if (subtype != VSNORMAL) { /* skip to end of alternative */
5245 if ((c = *p++) == CTLESC)
5247 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5249 argbackq = argbackq->next;
5250 } else if (c == CTLVAR) {
5251 if ((*p++ & VSTYPE) != VSNORMAL)
5253 } else if (c == CTLENDVAR) {
5264 * Put a string on the stack.
5268 memtodest(const char *p, size_t len, int syntax, int quotes) {
5271 q = makestrspace(len * 2, q);
5277 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5287 strtodest(const char *p, int syntax, int quotes)
5289 memtodest(p, strlen(p), syntax, quotes);
5294 * Add the value of a specialized variable to the stack string.
5298 varvalue(char *name, int varflags, int flags)
5308 int quoted = varflags & VSQUOTE;
5309 int subtype = varflags & VSTYPE;
5310 int quotes = flags & (EXP_FULL | EXP_CASE);
5312 if (quoted && (flags & EXP_FULL))
5313 sep = 1 << CHAR_BIT;
5315 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5324 num = shellparam.nparam;
5334 p = makestrspace(NOPTS, expdest);
5335 for (i = NOPTS - 1; i >= 0; i--) {
5337 USTPUTC(optletters(i), p);
5348 sep = ifsset() ? ifsval()[0] : ' ';
5349 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5352 if (!(ap = shellparam.p))
5354 while ((p = *ap++)) {
5357 partlen = strlen(p);
5360 if (len > partlen && sep) {
5364 if (subtype == VSPLUS || subtype == VSLENGTH) {
5374 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5375 memtodest(p, partlen, syntax, quotes);
5389 if (num < 0 || num > shellparam.nparam)
5391 p = num ? shellparam.p[num - 1] : arg0;
5394 p = lookupvar(name);
5400 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5401 memtodest(p, len, syntax, quotes);
5405 if (subtype == VSPLUS || subtype == VSLENGTH)
5406 STADJUST(-len, expdest);
5412 * Record the fact that we have to scan this region of the
5413 * string for IFS characters.
5417 recordregion(int start, int end, int nulonly)
5419 struct ifsregion *ifsp;
5421 if (ifslastp == NULL) {
5425 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5427 ifslastp->next = ifsp;
5431 ifslastp->begoff = start;
5432 ifslastp->endoff = end;
5433 ifslastp->nulonly = nulonly;
5438 * Break the argument string into pieces based upon IFS and add the
5439 * strings to the argument list. The regions of the string to be
5440 * searched for IFS characters have been stored by recordregion.
5443 ifsbreakup(char *string, struct arglist *arglist)
5445 struct ifsregion *ifsp;
5450 const char *ifs, *realifs;
5456 if (ifslastp != NULL) {
5459 realifs = ifsset() ? ifsval() : defifs;
5462 p = string + ifsp->begoff;
5463 nulonly = ifsp->nulonly;
5464 ifs = nulonly ? nullstr : realifs;
5466 while (p < string + ifsp->endoff) {
5470 if (strchr(ifs, *p)) {
5472 ifsspc = (strchr(defifs, *p) != NULL);
5473 /* Ignore IFS whitespace at start */
5474 if (q == start && ifsspc) {
5480 sp = (struct strlist *)stalloc(sizeof *sp);
5482 *arglist->lastp = sp;
5483 arglist->lastp = &sp->next;
5487 if (p >= string + ifsp->endoff) {
5493 if (strchr(ifs, *p) == NULL ) {
5496 } else if (strchr(defifs, *p) == NULL) {
5512 } while ((ifsp = ifsp->next) != NULL);
5521 sp = (struct strlist *)stalloc(sizeof *sp);
5523 *arglist->lastp = sp;
5524 arglist->lastp = &sp->next;
5530 struct ifsregion *p;
5535 struct ifsregion *ifsp;
5541 ifsfirst.next = NULL;
5545 static void expmeta(char *, char *);
5546 static struct strlist *expsort(struct strlist *);
5547 static struct strlist *msort(struct strlist *, int);
5549 static char *expdir;
5553 expandmeta(struct strlist *str, int flag)
5555 static const char metachars[] = {
5558 /* TODO - EXP_REDIR */
5561 struct strlist **savelastp;
5567 if (!strpbrk(str->text, metachars))
5569 savelastp = exparg.lastp;
5572 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5574 int i = strlen(str->text);
5575 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5583 if (exparg.lastp == savelastp) {
5588 *exparg.lastp = str;
5589 rmescapes(str->text);
5590 exparg.lastp = &str->next;
5592 *exparg.lastp = NULL;
5593 *savelastp = sp = expsort(*savelastp);
5594 while (sp->next != NULL)
5596 exparg.lastp = &sp->next;
5603 * Add a file name to the list.
5607 addfname(const char *name)
5611 sp = (struct strlist *)stalloc(sizeof *sp);
5612 sp->text = sstrdup(name);
5614 exparg.lastp = &sp->next;
5619 * Do metacharacter (i.e. *, ?, [...]) expansion.
5623 expmeta(char *enddir, char *name)
5638 for (p = name; *p; p++) {
5639 if (*p == '*' || *p == '?')
5641 else if (*p == '[') {
5648 if (*q == '/' || *q == '\0')
5655 } else if (*p == '\\')
5657 else if (*p == '/') {
5664 if (metaflag == 0) { /* we've reached the end of the file name */
5665 if (enddir != expdir)
5673 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5684 } while (p < start);
5686 if (enddir == expdir) {
5688 } else if (enddir == expdir + 1 && *expdir == '/') {
5694 if ((dirp = opendir(cp)) == NULL)
5696 if (enddir != expdir)
5698 if (*endname == 0) {
5710 while (! intpending && (dp = readdir(dirp)) != NULL) {
5711 if (dp->d_name[0] == '.' && ! matchdot)
5713 if (pmatch(start, dp->d_name)) {
5715 scopy(dp->d_name, enddir);
5718 for (p = enddir, cp = dp->d_name;
5719 (*p++ = *cp++) != '\0';)
5722 expmeta(p, endname);
5732 * Sort the results of file name expansion. It calculates the number of
5733 * strings to sort and then calls msort (short for merge sort) to do the
5737 static struct strlist *
5738 expsort(struct strlist *str)
5744 for (sp = str ; sp ; sp = sp->next)
5746 return msort(str, len);
5750 static struct strlist *
5751 msort(struct strlist *list, int len)
5753 struct strlist *p, *q = NULL;
5754 struct strlist **lpp;
5762 for (n = half ; --n >= 0 ; ) {
5766 q->next = NULL; /* terminate first half of list */
5767 q = msort(list, half); /* sort first half of list */
5768 p = msort(p, len - half); /* sort second half */
5771 #ifdef CONFIG_LOCALE_SUPPORT
5772 if (strcoll(p->text, q->text) < 0)
5774 if (strcmp(p->text, q->text) < 0)
5779 if ((p = *lpp) == NULL) {
5786 if ((q = *lpp) == NULL) {
5797 * Returns true if the pattern matches the string.
5801 patmatch(char *pattern, const char *string)
5803 return pmatch(preglob(pattern, 0, 0), string);
5808 * Remove any CTLESC characters from a string.
5812 _rmescapes(char *str, int flag)
5815 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5820 p = strpbrk(str, qchars);
5826 if (flag & RMESCAPE_ALLOC) {
5827 size_t len = p - str;
5828 size_t fulllen = len + strlen(p) + 1;
5830 if (flag & RMESCAPE_GROW) {
5831 r = makestrspace(fulllen, expdest);
5832 } else if (flag & RMESCAPE_HEAP) {
5833 r = ckmalloc(fulllen);
5835 r = stalloc(fulllen);
5839 q = mempcpy(q, str, len);
5842 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5843 globbing = flag & RMESCAPE_GLOB;
5844 notescaped = globbing;
5846 if (*p == CTLQUOTEMARK) {
5847 inquotes = ~inquotes;
5849 notescaped = globbing;
5853 /* naked back slash */
5859 if (notescaped && inquotes && *p != '/') {
5863 notescaped = globbing;
5868 if (flag & RMESCAPE_GROW) {
5870 STADJUST(q - r + 1, expdest);
5877 * See if a pattern matches in a case statement.
5881 casematch(union node *pattern, char *val)
5883 struct stackmark smark;
5886 setstackmark(&smark);
5887 argbackq = pattern->narg.backquote;
5888 STARTSTACKSTR(expdest);
5890 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5891 STACKSTRNUL(expdest);
5892 result = patmatch(stackblock(), val);
5893 popstackmark(&smark);
5906 expdest = makestrspace(32, expdest);
5907 #ifdef CONFIG_ASH_MATH_SUPPORT_64
5908 len = fmtstr(expdest, 32, "%lld", (long long) num);
5910 len = fmtstr(expdest, 32, "%ld", num);
5912 STADJUST(len, expdest);
5917 varunset(const char *end, const char *var, const char *umsg, int varflags)
5923 msg = "parameter not set";
5925 if (*end == CTLENDVAR) {
5926 if (varflags & VSNUL)
5931 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5935 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5938 * This implements the input routines used by the parser.
5941 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5942 #define IBUFSIZ (BUFSIZ + 1)
5944 static void pushfile(void);
5947 * Read a character from the script, returning PEOF on end of file.
5948 * Nul characters in the input are silently discarded.
5951 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5953 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5954 #define pgetc_macro() pgetc()
5958 return pgetc_as_macro();
5961 #define pgetc_macro() pgetc_as_macro()
5965 return pgetc_macro();
5971 * Same as pgetc(), but ignores PEOA.
5973 #ifdef CONFIG_ASH_ALIAS
5974 static int pgetc2(void)
5980 } while (c == PEOA);
5984 static inline int pgetc2(void)
5986 return pgetc_macro();
5991 * Read a line from the script.
5994 static inline char *
5995 pfgets(char *line, int len)
6001 while (--nleft > 0) {
6018 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6019 static const char *cmdedit_prompt;
6020 static inline void putprompt(const char *s)
6025 static inline void putprompt(const char *s)
6035 char *buf = parsefile->buf;
6039 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6040 if (!iflag || parsefile->fd)
6041 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6043 #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
6044 cmdedit_path_lookup = pathval();
6046 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6048 /* Ctrl+C presend */
6057 if(nr < 0 && errno == 0) {
6058 /* Ctrl+D presend */
6063 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6067 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6068 int flags = fcntl(0, F_GETFL, 0);
6069 if (flags >= 0 && flags & O_NONBLOCK) {
6070 flags &=~ O_NONBLOCK;
6071 if (fcntl(0, F_SETFL, flags) >= 0) {
6072 out2str("sh: turning off NDELAY mode\n");
6082 * Refill the input buffer and return the next input character:
6084 * 1) If a string was pushed back on the input, pop it;
6085 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6086 * from a string so we can't refill the buffer, return EOF.
6087 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6088 * 4) Process input up to the next newline, deleting nul characters.
6098 while (parsefile->strpush) {
6099 #ifdef CONFIG_ASH_ALIAS
6100 if (parsenleft == -1 && parsefile->strpush->ap &&
6101 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6106 if (--parsenleft >= 0)
6107 return (*parsenextc++);
6109 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6114 if (parselleft <= 0) {
6115 if ((parselleft = preadfd()) <= 0) {
6116 parselleft = parsenleft = EOF_NLEFT;
6123 /* delete nul characters */
6124 for (more = 1; more;) {
6131 parsenleft = q - parsenextc;
6132 more = 0; /* Stop processing here */
6139 if (--parselleft <= 0 && more) {
6140 parsenleft = q - parsenextc - 1;
6151 out2str(parsenextc);
6156 return *parsenextc++;
6160 * Undo the last call to pgetc. Only one character may be pushed back.
6161 * PEOF may be pushed back.
6172 * Push a string back onto the input at this current parsefile level.
6173 * We handle aliases this way.
6176 pushstring(char *s, void *ap)
6183 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6184 if (parsefile->strpush) {
6185 sp = ckmalloc(sizeof (struct strpush));
6186 sp->prev = parsefile->strpush;
6187 parsefile->strpush = sp;
6189 sp = parsefile->strpush = &(parsefile->basestrpush);
6190 sp->prevstring = parsenextc;
6191 sp->prevnleft = parsenleft;
6192 #ifdef CONFIG_ASH_ALIAS
6193 sp->ap = (struct alias *)ap;
6195 ((struct alias *)ap)->flag |= ALIASINUSE;
6207 struct strpush *sp = parsefile->strpush;
6210 #ifdef CONFIG_ASH_ALIAS
6212 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6213 checkkwd |= CHKALIAS;
6215 if (sp->string != sp->ap->val) {
6218 sp->ap->flag &= ~ALIASINUSE;
6219 if (sp->ap->flag & ALIASDEAD) {
6220 unalias(sp->ap->name);
6224 parsenextc = sp->prevstring;
6225 parsenleft = sp->prevnleft;
6226 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6227 parsefile->strpush = sp->prev;
6228 if (sp != &(parsefile->basestrpush))
6234 * Set the input to take input from a file. If push is set, push the
6235 * old input onto the stack first.
6239 setinputfile(const char *fname, int push)
6245 if ((fd = open(fname, O_RDONLY)) < 0)
6246 error("Can't open %s", fname);
6248 fd2 = copyfd(fd, 10);
6251 error("Out of file descriptors");
6254 setinputfd(fd, push);
6260 * Like setinputfile, but takes an open file descriptor. Call this with
6265 setinputfd(int fd, int push)
6267 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6273 if (parsefile->buf == NULL)
6274 parsefile->buf = ckmalloc(IBUFSIZ);
6275 parselleft = parsenleft = 0;
6281 * Like setinputfile, but takes input from a string.
6285 setinputstring(char *string)
6289 parsenextc = string;
6290 parsenleft = strlen(string);
6291 parsefile->buf = NULL;
6298 * To handle the "." command, a stack of input files is used. Pushfile
6299 * adds a new entry to the stack and popfile restores the previous level.
6305 struct parsefile *pf;
6307 parsefile->nleft = parsenleft;
6308 parsefile->lleft = parselleft;
6309 parsefile->nextc = parsenextc;
6310 parsefile->linno = plinno;
6311 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6312 pf->prev = parsefile;
6315 pf->basestrpush.prev = NULL;
6323 struct parsefile *pf = parsefile;
6332 parsefile = pf->prev;
6334 parsenleft = parsefile->nleft;
6335 parselleft = parsefile->lleft;
6336 parsenextc = parsefile->nextc;
6337 plinno = parsefile->linno;
6343 * Return to top level.
6349 while (parsefile != &basepf)
6355 * Close the file(s) that the shell is reading commands from. Called
6356 * after a fork is done.
6363 if (parsefile->fd > 0) {
6364 close(parsefile->fd);
6369 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6371 /* mode flags for set_curjob */
6372 #define CUR_DELETE 2
6373 #define CUR_RUNNING 1
6374 #define CUR_STOPPED 0
6376 /* mode flags for dowait */
6377 #define DOWAIT_NORMAL 0
6378 #define DOWAIT_BLOCK 1
6381 static struct job *jobtab;
6383 static unsigned njobs;
6385 /* pgrp of shell on invocation */
6386 static int initialpgrp;
6387 static int ttyfd = -1;
6390 static struct job *curjob;
6391 /* number of presumed living untracked jobs */
6394 static void set_curjob(struct job *, unsigned);
6396 static int restartjob(struct job *, int);
6397 static void xtcsetpgrp(int, pid_t);
6398 static char *commandtext(union node *);
6399 static void cmdlist(union node *, int);
6400 static void cmdtxt(union node *);
6401 static void cmdputs(const char *);
6402 static void showpipe(struct job *, FILE *);
6404 static int sprint_status(char *, int, int);
6405 static void freejob(struct job *);
6406 static struct job *getjob(const char *, int);
6407 static struct job *growjobtab(void);
6408 static void forkchild(struct job *, union node *, int);
6409 static void forkparent(struct job *, union node *, int, pid_t);
6410 static int dowait(int, struct job *);
6411 static int getstatus(struct job *);
6414 set_curjob(struct job *jp, unsigned mode)
6417 struct job **jpp, **curp;
6419 /* first remove from list */
6420 jpp = curp = &curjob;
6425 jpp = &jp1->prev_job;
6427 *jpp = jp1->prev_job;
6429 /* Then re-insert in correct position */
6437 /* job being deleted */
6440 /* newly created job or backgrounded job,
6441 put after all stopped jobs. */
6445 if (!jp1 || jp1->state != JOBSTOPPED)
6448 jpp = &jp1->prev_job;
6454 /* newly stopped job - becomes curjob */
6455 jp->prev_job = *jpp;
6463 * Turn job control on and off.
6465 * Note: This code assumes that the third arg to ioctl is a character
6466 * pointer, which is true on Berkeley systems but not System V. Since
6467 * System V doesn't have job control yet, this isn't a problem now.
6469 * Called with interrupts off.
6478 if (on == jobctl || rootshell == 0)
6482 ofd = fd = open(_PATH_TTY, O_RDWR);
6485 while (!isatty(fd) && --fd >= 0)
6488 fd = fcntl(fd, F_DUPFD, 10);
6492 fcntl(fd, F_SETFD, FD_CLOEXEC);
6493 do { /* while we are in the background */
6494 if ((pgrp = tcgetpgrp(fd)) < 0) {
6496 sh_warnx("can't access tty; job control turned off");
6500 if (pgrp == getpgrp())
6511 xtcsetpgrp(fd, pgrp);
6513 /* turning job control off */
6516 xtcsetpgrp(fd, pgrp);
6530 killcmd(int argc, char **argv)
6541 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6542 "kill -l [exitstatus]"
6546 if (**++argv == '-') {
6547 signo = decode_signal(*argv + 1, 1);
6551 while ((c = nextopt("ls:")) != '\0')
6561 signo = decode_signal(optionarg, 1);
6564 "invalid signal number or name: %s",
6575 if (!list && signo < 0)
6578 if ((signo < 0 || !*argv) ^ list) {
6586 for (i = 1; i < NSIG; i++) {
6587 name = u_signal_names(0, &i, 1);
6589 out1fmt(snlfmt, name);
6593 name = u_signal_names(*argptr, &signo, -1);
6595 out1fmt(snlfmt, name);
6597 error("invalid signal number or exit status: %s", *argptr);
6603 if (**argv == '%') {
6604 jp = getjob(*argv, 0);
6605 pid = -jp->ps[0].pid;
6607 pid = number(*argv);
6608 if (kill(pid, signo) != 0) {
6618 #if defined(JOBS) || defined(DEBUG)
6620 jobno(const struct job *jp)
6622 return jp - jobtab + 1;
6628 fgcmd(int argc, char **argv)
6635 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6640 jp = getjob(*argv, 1);
6641 if (mode == FORK_BG) {
6642 set_curjob(jp, CUR_RUNNING);
6643 fprintf(out, "[%d] ", jobno(jp));
6645 outstr(jp->ps->cmd, out);
6647 retval = restartjob(jp, mode);
6648 } while (*argv && *++argv);
6652 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6656 restartjob(struct job *jp, int mode)
6658 struct procstat *ps;
6664 if (jp->state == JOBDONE)
6666 jp->state = JOBRUNNING;
6668 if (mode == FORK_FG)
6669 xtcsetpgrp(ttyfd, pgid);
6670 killpg(pgid, SIGCONT);
6674 if (WIFSTOPPED(ps->status)) {
6677 } while (ps++, --i);
6679 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6686 sprint_status(char *s, int status, int sigonly)
6692 if (!WIFEXITED(status)) {
6694 if (WIFSTOPPED(status))
6695 st = WSTOPSIG(status);
6698 st = WTERMSIG(status);
6700 if (st == SIGINT || st == SIGPIPE)
6703 if (WIFSTOPPED(status))
6708 col = fmtstr(s, 32, strsignal(st));
6709 if (WCOREDUMP(status)) {
6710 col += fmtstr(s + col, 16, " (core dumped)");
6712 } else if (!sigonly) {
6713 st = WEXITSTATUS(status);
6715 col = fmtstr(s, 16, "Done(%d)", st);
6717 col = fmtstr(s, 16, "Done");
6726 showjob(FILE *out, struct job *jp, int mode)
6728 struct procstat *ps;
6729 struct procstat *psend;
6736 if (mode & SHOW_PGID) {
6737 /* just output process (group) id of pipeline */
6738 fprintf(out, "%d\n", ps->pid);
6742 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6747 else if (curjob && jp == curjob->prev_job)
6750 if (mode & SHOW_PID)
6751 col += fmtstr(s + col, 16, "%d ", ps->pid);
6753 psend = ps + jp->nprocs;
6755 if (jp->state == JOBRUNNING) {
6756 scopy("Running", s + col);
6757 col += strlen("Running");
6759 int status = psend[-1].status;
6761 if (jp->state == JOBSTOPPED)
6762 status = jp->stopstatus;
6764 col += sprint_status(s + col, status, 0);
6770 /* for each process */
6771 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6774 fprintf(out, "%s%*c%s",
6775 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6777 if (!(mode & SHOW_PID)) {
6781 if (++ps == psend) {
6782 outcslow('\n', out);
6789 if (jp->state == JOBDONE) {
6790 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6797 jobscmd(int argc, char **argv)
6803 while ((m = nextopt("lp")))
6813 showjob(out, getjob(*argv,0), mode);
6816 showjobs(out, mode);
6823 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6824 * statuses have changed since the last call to showjobs.
6828 showjobs(FILE *out, int mode)
6832 TRACE(("showjobs(%x) called\n", mode));
6834 /* If not even one one job changed, there is nothing to do */
6835 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6838 for (jp = curjob; jp; jp = jp->prev_job) {
6839 if (!(mode & SHOW_CHANGED) || jp->changed)
6840 showjob(out, jp, mode);
6846 * Mark a job structure as unused.
6850 freejob(struct job *jp)
6852 struct procstat *ps;
6856 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6857 if (ps->cmd != nullstr)
6860 if (jp->ps != &jp->ps0)
6863 set_curjob(jp, CUR_DELETE);
6869 waitcmd(int argc, char **argv)
6882 /* wait for all jobs */
6887 /* no running procs */
6890 if (jp->state == JOBRUNNING)
6895 dowait(DOWAIT_BLOCK, 0);
6901 if (**argv != '%') {
6902 pid_t pid = number(*argv);
6906 if (job->ps[job->nprocs - 1].pid == pid)
6908 job = job->prev_job;
6914 job = getjob(*argv, 0);
6915 /* loop until process terminated or stopped */
6916 while (job->state == JOBRUNNING)
6917 dowait(DOWAIT_BLOCK, 0);
6919 retval = getstatus(job);
6930 * Convert a job name to a job structure.
6934 getjob(const char *name, int getctl)
6938 const char *err_msg = "No such job: %s";
6942 char *(*match)(const char *, const char *);
6957 if (c == '+' || c == '%') {
6959 err_msg = "No current job";
6961 } else if (c == '-') {
6964 err_msg = "No previous job";
6975 jp = jobtab + num - 1;
6992 if (match(jp->ps[0].cmd, p)) {
6996 err_msg = "%s: ambiguous";
7003 err_msg = "job %s not created under job control";
7004 if (getctl && jp->jobctl == 0)
7009 error(err_msg, name);
7014 * Return a new job structure.
7015 * Called with interrupts off.
7019 makejob(union node *node, int nprocs)
7024 for (i = njobs, jp = jobtab ; ; jp++) {
7031 if (jp->state != JOBDONE || !jp->waited)
7040 memset(jp, 0, sizeof(*jp));
7045 jp->prev_job = curjob;
7050 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7052 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7062 struct job *jp, *jq;
7064 len = njobs * sizeof(*jp);
7066 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7068 offset = (char *)jp - (char *)jq;
7070 /* Relocate pointers */
7073 jq = (struct job *)((char *)jq + l);
7077 #define joff(p) ((struct job *)((char *)(p) + l))
7078 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7079 if (xlikely(joff(jp)->ps == &jq->ps0))
7080 jmove(joff(jp)->ps);
7081 if (joff(jp)->prev_job)
7082 jmove(joff(jp)->prev_job);
7092 jp = (struct job *)((char *)jp + len);
7096 } while (--jq >= jp);
7102 * Fork off a subshell. If we are doing job control, give the subshell its
7103 * own process group. Jp is a job structure that the job is to be added to.
7104 * N is the command that will be evaluated by the child. Both jp and n may
7105 * be NULL. The mode parameter can be one of the following:
7106 * FORK_FG - Fork off a foreground process.
7107 * FORK_BG - Fork off a background process.
7108 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7109 * process group even if job control is on.
7111 * When job control is turned off, background processes have their standard
7112 * input redirected to /dev/null (except for the second and later processes
7115 * Called with interrupts off.
7119 forkchild(struct job *jp, union node *n, int mode)
7123 TRACE(("Child shell %d\n", getpid()));
7124 wasroot = rootshell;
7130 /* do job control only in root shell */
7132 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7135 if (jp->nprocs == 0)
7138 pgrp = jp->ps[0].pid;
7139 /* This can fail because we are doing it in the parent also */
7140 (void)setpgid(0, pgrp);
7141 if (mode == FORK_FG)
7142 xtcsetpgrp(ttyfd, pgrp);
7147 if (mode == FORK_BG) {
7150 if (jp->nprocs == 0) {
7152 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7153 error("Can't open %s", _PATH_DEVNULL);
7156 if (wasroot && iflag) {
7161 for (jp = curjob; jp; jp = jp->prev_job)
7167 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7169 TRACE(("In parent shell: child = %d\n", pid));
7171 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7176 if (mode != FORK_NOJOB && jp->jobctl) {
7179 if (jp->nprocs == 0)
7182 pgrp = jp->ps[0].pid;
7183 /* This can fail because we are doing it in the child also */
7184 (void)setpgid(pid, pgrp);
7187 if (mode == FORK_BG) {
7188 backgndpid = pid; /* set $! */
7189 set_curjob(jp, CUR_RUNNING);
7192 struct procstat *ps = &jp->ps[jp->nprocs++];
7198 ps->cmd = commandtext(n);
7204 forkshell(struct job *jp, union node *n, int mode)
7208 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7211 TRACE(("Fork failed, errno=%d", errno));
7214 error("Cannot fork");
7217 forkchild(jp, n, mode);
7219 forkparent(jp, n, mode, pid);
7224 * Wait for job to finish.
7226 * Under job control we have the problem that while a child process is
7227 * running interrupts generated by the user are sent to the child but not
7228 * to the shell. This means that an infinite loop started by an inter-
7229 * active user may be hard to kill. With job control turned off, an
7230 * interactive user may place an interactive program inside a loop. If
7231 * the interactive program catches interrupts, the user doesn't want
7232 * these interrupts to also abort the loop. The approach we take here
7233 * is to have the shell ignore interrupt signals while waiting for a
7234 * foreground process to terminate, and then send itself an interrupt
7235 * signal if the child process was terminated by an interrupt signal.
7236 * Unfortunately, some programs want to do a bit of cleanup and then
7237 * exit on interrupt; unless these processes terminate themselves by
7238 * sending a signal to themselves (instead of calling exit) they will
7239 * confuse this approach.
7241 * Called with interrupts off.
7245 waitforjob(struct job *jp)
7249 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7250 while (jp->state == JOBRUNNING) {
7251 dowait(DOWAIT_BLOCK, jp);
7256 xtcsetpgrp(ttyfd, rootpid);
7258 * This is truly gross.
7259 * If we're doing job control, then we did a TIOCSPGRP which
7260 * caused us (the shell) to no longer be in the controlling
7261 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7262 * intuit from the subprocess exit status whether a SIGINT
7263 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7268 if (jp->state == JOBDONE)
7276 * Do a wait system call. If job control is compiled in, we accept
7277 * stopped processes. If block is zero, we return a value of zero
7278 * rather than blocking.
7280 * System V doesn't have a non-blocking wait system call. It does
7281 * have a SIGCLD signal that is sent to a process when one of it's
7282 * children dies. The obvious way to use SIGCLD would be to install
7283 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7284 * was received, and have waitproc bump another counter when it got
7285 * the status of a process. Waitproc would then know that a wait
7286 * system call would not block if the two counters were different.
7287 * This approach doesn't work because if a process has children that
7288 * have not been waited for, System V will send it a SIGCLD when it
7289 * installs a signal handler for SIGCLD. What this means is that when
7290 * a child exits, the shell will be sent SIGCLD signals continuously
7291 * until is runs out of stack space, unless it does a wait call before
7292 * restoring the signal handler. The code below takes advantage of
7293 * this (mis)feature by installing a signal handler for SIGCLD and
7294 * then checking to see whether it was called. If there are any
7295 * children to be waited for, it will be.
7297 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7298 * waits at all. In this case, the user will not be informed when
7299 * a background process until the next time she runs a real program
7300 * (as opposed to running a builtin command or just typing return),
7301 * and the jobs command may give out of date information.
7305 waitproc(int block, int *status)
7315 return wait3(status, flags, (struct rusage *)NULL);
7319 * Wait for a process to terminate.
7323 dowait(int block, struct job *job)
7328 struct job *thisjob;
7331 TRACE(("dowait(%d) called\n", block));
7332 pid = waitproc(block, &status);
7333 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7338 for (jp = curjob; jp; jp = jp->prev_job) {
7339 struct procstat *sp;
7340 struct procstat *spend;
7341 if (jp->state == JOBDONE)
7344 spend = jp->ps + jp->nprocs;
7347 if (sp->pid == pid) {
7348 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7349 sp->status = status;
7352 if (sp->status == -1)
7355 if (state == JOBRUNNING)
7357 if (WIFSTOPPED(sp->status)) {
7358 jp->stopstatus = sp->status;
7362 } while (++sp < spend);
7367 if (!WIFSTOPPED(status))
7374 if (state != JOBRUNNING) {
7375 thisjob->changed = 1;
7377 if (thisjob->state != state) {
7378 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7379 thisjob->state = state;
7381 if (state == JOBSTOPPED) {
7382 set_curjob(thisjob, CUR_STOPPED);
7391 if (thisjob && thisjob == job) {
7395 len = sprint_status(s, status, 1);
7407 * return 1 if there are stopped jobs, otherwise 0
7420 if (jp && jp->state == JOBSTOPPED) {
7421 out2str("You have stopped jobs.\n");
7431 * Return a string identifying a command (to be printed by the
7436 static char *cmdnextc;
7439 commandtext(union node *n)
7443 STARTSTACKSTR(cmdnextc);
7445 name = stackblock();
7446 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7447 name, cmdnextc, cmdnextc));
7448 return savestr(name);
7452 cmdtxt(union node *n)
7455 struct nodelist *lp;
7467 lp = n->npipe.cmdlist;
7485 cmdtxt(n->nbinary.ch1);
7501 cmdtxt(n->nif.test);
7504 if (n->nif.elsepart) {
7507 n = n->nif.elsepart;
7523 cmdtxt(n->nbinary.ch1);
7533 cmdputs(n->nfor.var);
7535 cmdlist(n->nfor.args, 1);
7540 cmdputs(n->narg.text);
7544 cmdlist(n->ncmd.args, 1);
7545 cmdlist(n->ncmd.redirect, 0);
7558 cmdputs(n->ncase.expr->narg.text);
7560 for (np = n->ncase.cases; np; np = np->nclist.next) {
7561 cmdtxt(np->nclist.pattern);
7563 cmdtxt(np->nclist.body);
7589 s[0] = n->nfile.fd + '0';
7593 if (n->type == NTOFD || n->type == NFROMFD) {
7594 s[0] = n->ndup.dupfd + '0';
7605 cmdlist(union node *np, int sep)
7607 for (; np; np = np->narg.next) {
7611 if (sep && np->narg.next)
7617 cmdputs(const char *s)
7619 const char *p, *str;
7620 char c, cc[2] = " ";
7624 static const char *const vstype[16] = {
7625 nullstr, "}", "-", "+", "?", "=",
7626 "%", "%%", "#", "##", nullstr
7629 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7631 while ((c = *p++) != 0) {
7639 if ((subtype & VSTYPE) == VSLENGTH)
7643 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7661 case CTLBACKQ+CTLQUOTE:
7664 #ifdef CONFIG_ASH_MATH_SUPPORT
7679 str = vstype[subtype & VSTYPE];
7680 if (subtype & VSNUL)
7691 /* These can only happen inside quotes */
7703 while ((c = *str++)) {
7708 USTPUTC('"', nextc);
7716 showpipe(struct job *jp, FILE *out)
7718 struct procstat *sp;
7719 struct procstat *spend;
7721 spend = jp->ps + jp->nprocs;
7722 for (sp = jp->ps + 1; sp < spend; sp++)
7723 fprintf(out, " | %s", sp->cmd);
7724 outcslow('\n', out);
7729 xtcsetpgrp(int fd, pid_t pgrp)
7731 if (tcsetpgrp(fd, pgrp))
7732 error("Cannot set tty process group (%m)");
7737 getstatus(struct job *job) {
7741 status = job->ps[job->nprocs - 1].status;
7742 retval = WEXITSTATUS(status);
7743 if (!WIFEXITED(status)) {
7745 retval = WSTOPSIG(status);
7746 if (!WIFSTOPPED(status))
7749 /* XXX: limits number of signals */
7750 retval = WTERMSIG(status);
7752 if (retval == SIGINT)
7758 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7759 jobno(job), job->nprocs, status, retval));
7763 #ifdef CONFIG_ASH_MAIL
7764 /* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7767 * Routines to check for mail. (Perhaps make part of main.c?)
7770 #define MAXMBOXES 10
7772 /* times of mailboxes */
7773 static time_t mailtime[MAXMBOXES];
7774 /* Set if MAIL or MAILPATH is changed. */
7775 static int mail_var_path_changed;
7780 * Print appropriate message(s) if mail has arrived.
7781 * If mail_var_path_changed is set,
7782 * then the value of MAIL has mail_var_path_changed,
7783 * so we just update the values.
7793 struct stackmark smark;
7796 setstackmark(&smark);
7797 mpath = mpathset() ? mpathval() : mailval();
7798 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7799 p = padvance(&mpath, nullstr);
7804 for (q = p ; *q ; q++);
7809 q[-1] = '\0'; /* delete trailing '/' */
7810 if (stat(p, &statb) < 0) {
7814 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7817 pathopt ? pathopt : "you have mail"
7820 *mtp = statb.st_mtime;
7822 mail_var_path_changed = 0;
7823 popstackmark(&smark);
7828 changemail(const char *val)
7830 mail_var_path_changed++;
7833 #endif /* CONFIG_ASH_MAIL */
7835 /* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7839 static short profile_buf[16384];
7843 static int isloginsh;
7845 static void read_profile(const char *);
7848 * Main routine. We initialize things, parse the arguments, execute
7849 * profiles if we're a login shell, and then call cmdloop to execute
7850 * commands. The setjmp call sets up the location to jump to when an
7851 * exception occurs. When an exception occurs the variable "state"
7852 * is used to figure out how far we had gotten.
7856 ash_main(int argc, char **argv)
7860 struct jmploc jmploc;
7861 struct stackmark smark;
7864 dash_errno = __errno_location();
7868 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7871 if (setjmp(jmploc.loc)) {
7878 switch (exception) {
7888 status = exitstatus;
7891 exitstatus = status;
7893 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7897 outcslow('\n', stderr);
7899 popstackmark(&smark);
7900 FORCEINTON; /* enable interrupts */
7903 else if (state == 2)
7905 else if (state == 3)
7913 trputs("Shell args: "); trargs(argv);
7917 #ifdef CONFIG_ASH_RANDOM_SUPPORT
7918 rseed = rootpid + ((time_t)time((time_t *)0));
7922 setstackmark(&smark);
7923 procargs(argc, argv);
7924 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7926 const char *hp = lookupvar("HISTFILE");
7929 hp = lookupvar("HOME");
7931 char *defhp = concat_path_file(hp, ".ash_history");
7932 setvar("HISTFILE", defhp, 0);
7938 if (argv[0] && argv[0][0] == '-')
7942 read_profile("/etc/profile");
7945 read_profile(".profile");
7951 getuid() == geteuid() && getgid() == getegid() &&
7955 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7956 read_profile(shinit);
7964 if (sflag || minusc == NULL) {
7965 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7967 const char *hp = lookupvar("HISTFILE");
7970 load_history ( hp );
7973 state4: /* XXX ??? - why isn't this before the "if" statement */
7981 extern void _mcleanup(void);
7991 * Read and execute commands. "Top" is nonzero for the top level command
7992 * loop; it turns on prompting if the shell is interactive.
7999 struct stackmark smark;
8003 TRACE(("cmdloop(%d) called\n", top));
8005 setstackmark(&smark);
8010 showjobs(stderr, SHOW_CHANGED);
8015 #ifdef CONFIG_ASH_MAIL
8019 n = parsecmd(inter);
8020 /* showtree(n); DEBUG */
8022 if (!top || numeof >= 50)
8024 if (!stoppedjobs()) {
8027 out2str("\nUse \"exit\" to leave shell.\n");
8030 } else if (n != NULL && nflag == 0) {
8031 job_warning = (job_warning == 2) ? 1 : 0;
8035 popstackmark(&smark);
8045 * Read /etc/profile or .profile. Return on error.
8049 read_profile(const char *name)
8056 if ((fd = open(name, O_RDONLY)) >= 0)
8061 /* -q turns off -x and -v just when executing init files */
8064 xflag = 0, xflag_set = 1;
8066 vflag = 0, vflag_set = 1;
8080 * Read a file containing shell functions.
8084 readcmdfile(char *name)
8089 if ((fd = open(name, O_RDONLY)) >= 0)
8092 error("Can't open %s", name);
8100 * Take commands from a file. To be compatible we should do a path
8101 * search for the file, which is necessary to find sub-commands.
8104 static inline char *
8105 find_dot_file(char *name)
8108 const char *path = pathval();
8111 /* don't try this for absolute or relative paths */
8112 if (strchr(name, '/'))
8115 while ((fullname = padvance(&path, name)) != NULL) {
8116 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8118 * Don't bother freeing here, since it will
8119 * be freed by the caller.
8123 stunalloc(fullname);
8126 /* not found in the PATH */
8127 error(not_found_msg, name);
8131 static int dotcmd(int argc, char **argv)
8134 volatile struct shparam saveparam;
8138 for (sp = cmdenviron; sp; sp = sp->next)
8139 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8141 if (argc >= 2) { /* That's what SVR2 does */
8143 struct stackmark smark;
8145 setstackmark(&smark);
8146 fullname = find_dot_file(argv[1]);
8149 saveparam = shellparam;
8150 shellparam.malloc = 0;
8151 shellparam.nparam = argc - 2;
8152 shellparam.p = argv + 2;
8155 setinputfile(fullname, 1);
8156 commandname = fullname;
8161 freeparam(&shellparam);
8162 shellparam = saveparam;
8165 popstackmark(&smark);
8172 exitcmd(int argc, char **argv)
8177 exitstatus = number(argv[1]);
8182 #ifdef CONFIG_ASH_BUILTIN_ECHO
8184 echocmd(int argc, char **argv)
8186 return bb_echo(argc, argv);
8189 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8192 * Same for malloc, realloc, but returns an error when out of space.
8196 ckrealloc(pointer p, size_t nbytes)
8198 p = realloc(p, nbytes);
8200 error(bb_msg_memory_exhausted);
8205 ckmalloc(size_t nbytes)
8207 return ckrealloc(NULL, nbytes);
8211 * Make a copy of a string in safe storage.
8215 savestr(const char *s)
8217 char *p = strdup(s);
8219 error(bb_msg_memory_exhausted);
8225 * Parse trees for commands are allocated in lifo order, so we use a stack
8226 * to make this more efficient, and also to avoid all sorts of exception
8227 * handling code to handle interrupts in the middle of a parse.
8229 * The size 504 was chosen because the Ultrix malloc handles that size
8235 stalloc(size_t nbytes)
8240 aligned = SHELL_ALIGN(nbytes);
8241 if (aligned > stacknleft) {
8244 struct stack_block *sp;
8246 blocksize = aligned;
8247 if (blocksize < MINSIZE)
8248 blocksize = MINSIZE;
8249 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8250 if (len < blocksize)
8251 error(bb_msg_memory_exhausted);
8255 stacknxt = sp->space;
8256 stacknleft = blocksize;
8257 sstrend = stacknxt + blocksize;
8262 stacknxt += aligned;
8263 stacknleft -= aligned;
8269 stunalloc(pointer p)
8272 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8273 write(2, "stunalloc\n", 10);
8277 stacknleft += stacknxt - (char *)p;
8283 setstackmark(struct stackmark *mark)
8285 mark->stackp = stackp;
8286 mark->stacknxt = stacknxt;
8287 mark->stacknleft = stacknleft;
8288 mark->marknext = markp;
8294 popstackmark(struct stackmark *mark)
8296 struct stack_block *sp;
8299 markp = mark->marknext;
8300 while (stackp != mark->stackp) {
8305 stacknxt = mark->stacknxt;
8306 stacknleft = mark->stacknleft;
8307 sstrend = mark->stacknxt + mark->stacknleft;
8313 * When the parser reads in a string, it wants to stick the string on the
8314 * stack and only adjust the stack pointer when it knows how big the
8315 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8316 * of space on top of the stack and stackblocklen returns the length of
8317 * this block. Growstackblock will grow this space by at least one byte,
8318 * possibly moving it (like realloc). Grabstackblock actually allocates the
8319 * part of the block that has been used.
8323 growstackblock(void)
8327 newlen = stacknleft * 2;
8328 if (newlen < stacknleft)
8329 error(bb_msg_memory_exhausted);
8333 if (stacknxt == stackp->space && stackp != &stackbase) {
8334 struct stack_block *oldstackp;
8335 struct stackmark *xmark;
8336 struct stack_block *sp;
8337 struct stack_block *prevstackp;
8343 prevstackp = sp->prev;
8344 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8345 sp = ckrealloc((pointer)sp, grosslen);
8346 sp->prev = prevstackp;
8348 stacknxt = sp->space;
8349 stacknleft = newlen;
8350 sstrend = sp->space + newlen;
8353 * Stack marks pointing to the start of the old block
8354 * must be relocated to point to the new block
8357 while (xmark != NULL && xmark->stackp == oldstackp) {
8358 xmark->stackp = stackp;
8359 xmark->stacknxt = stacknxt;
8360 xmark->stacknleft = stacknleft;
8361 xmark = xmark->marknext;
8365 char *oldspace = stacknxt;
8366 int oldlen = stacknleft;
8367 char *p = stalloc(newlen);
8369 /* free the space we just allocated */
8370 stacknxt = memcpy(p, oldspace, oldlen);
8371 stacknleft += newlen;
8376 grabstackblock(size_t len)
8378 len = SHELL_ALIGN(len);
8384 * The following routines are somewhat easier to use than the above.
8385 * The user declares a variable of type STACKSTR, which may be declared
8386 * to be a register. The macro STARTSTACKSTR initializes things. Then
8387 * the user uses the macro STPUTC to add characters to the string. In
8388 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8389 * grown as necessary. When the user is done, she can just leave the
8390 * string there and refer to it using stackblock(). Or she can allocate
8391 * the space for it using grabstackstr(). If it is necessary to allow
8392 * someone else to use the stack temporarily and then continue to grow
8393 * the string, the user should use grabstack to allocate the space, and
8394 * then call ungrabstr(p) to return to the previous mode of operation.
8396 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8397 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8398 * is space for at least one character.
8404 size_t len = stackblocksize();
8405 if (herefd >= 0 && len >= 1024) {
8406 bb_full_write(herefd, stackblock(), len);
8407 return stackblock();
8410 return stackblock() + len;
8414 * Called from CHECKSTRSPACE.
8418 makestrspace(size_t newlen, char *p)
8420 size_t len = p - stacknxt;
8421 size_t size = stackblocksize();
8426 size = stackblocksize();
8428 if (nleft >= newlen)
8432 return stackblock() + len;
8436 stnputs(const char *s, size_t n, char *p)
8438 p = makestrspace(n, p);
8439 p = mempcpy(p, s, n);
8444 stputs(const char *s, char *p)
8446 return stnputs(s, strlen(s), p);
8449 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8454 * number(s) Convert a string of digits to an integer.
8455 * is_number(s) Return true if s is a string of digits.
8459 * prefix -- see if pfx is a prefix of string.
8463 prefix(const char *string, const char *pfx)
8466 if (*pfx++ != *string++)
8469 return (char *) string;
8474 * Convert a string of digits to an integer, printing an error message on
8479 number(const char *s)
8489 * Check for a valid number. This should be elsewhere.
8493 is_number(const char *p)
8498 } while (*++p != '\0');
8504 * Produce a possibly single quoted string suitable as input to the shell.
8505 * The return string is allocated on the stack.
8509 single_quote(const char *s) {
8518 len = strchrnul(s, '\'') - s;
8520 q = p = makestrspace(len + 3, p);
8523 q = mempcpy(q, s, len);
8529 len = strspn(s, "'");
8533 q = p = makestrspace(len + 3, p);
8536 q = mempcpy(q, s, len);
8545 return stackblock();
8549 * Like strdup but works with the ash stack.
8553 sstrdup(const char *p)
8555 size_t len = strlen(p) + 1;
8556 return memcpy(stalloc(len), p, len);
8561 calcsize(union node *n)
8565 funcblocksize += nodesize[n->type];
8568 calcsize(n->ncmd.redirect);
8569 calcsize(n->ncmd.args);
8570 calcsize(n->ncmd.assign);
8573 sizenodelist(n->npipe.cmdlist);
8578 calcsize(n->nredir.redirect);
8579 calcsize(n->nredir.n);
8586 calcsize(n->nbinary.ch2);
8587 calcsize(n->nbinary.ch1);
8590 calcsize(n->nif.elsepart);
8591 calcsize(n->nif.ifpart);
8592 calcsize(n->nif.test);
8595 funcstringsize += strlen(n->nfor.var) + 1;
8596 calcsize(n->nfor.body);
8597 calcsize(n->nfor.args);
8600 calcsize(n->ncase.cases);
8601 calcsize(n->ncase.expr);
8604 calcsize(n->nclist.body);
8605 calcsize(n->nclist.pattern);
8606 calcsize(n->nclist.next);
8610 sizenodelist(n->narg.backquote);
8611 funcstringsize += strlen(n->narg.text) + 1;
8612 calcsize(n->narg.next);
8619 calcsize(n->nfile.fname);
8620 calcsize(n->nfile.next);
8624 calcsize(n->ndup.vname);
8625 calcsize(n->ndup.next);
8629 calcsize(n->nhere.doc);
8630 calcsize(n->nhere.next);
8633 calcsize(n->nnot.com);
8640 sizenodelist(struct nodelist *lp)
8643 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8651 copynode(union node *n)
8658 funcblock = (char *) funcblock + nodesize[n->type];
8661 new->ncmd.redirect = copynode(n->ncmd.redirect);
8662 new->ncmd.args = copynode(n->ncmd.args);
8663 new->ncmd.assign = copynode(n->ncmd.assign);
8666 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8667 new->npipe.backgnd = n->npipe.backgnd;
8672 new->nredir.redirect = copynode(n->nredir.redirect);
8673 new->nredir.n = copynode(n->nredir.n);
8680 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8681 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8684 new->nif.elsepart = copynode(n->nif.elsepart);
8685 new->nif.ifpart = copynode(n->nif.ifpart);
8686 new->nif.test = copynode(n->nif.test);
8689 new->nfor.var = nodesavestr(n->nfor.var);
8690 new->nfor.body = copynode(n->nfor.body);
8691 new->nfor.args = copynode(n->nfor.args);
8694 new->ncase.cases = copynode(n->ncase.cases);
8695 new->ncase.expr = copynode(n->ncase.expr);
8698 new->nclist.body = copynode(n->nclist.body);
8699 new->nclist.pattern = copynode(n->nclist.pattern);
8700 new->nclist.next = copynode(n->nclist.next);
8704 new->narg.backquote = copynodelist(n->narg.backquote);
8705 new->narg.text = nodesavestr(n->narg.text);
8706 new->narg.next = copynode(n->narg.next);
8713 new->nfile.fname = copynode(n->nfile.fname);
8714 new->nfile.fd = n->nfile.fd;
8715 new->nfile.next = copynode(n->nfile.next);
8719 new->ndup.vname = copynode(n->ndup.vname);
8720 new->ndup.dupfd = n->ndup.dupfd;
8721 new->ndup.fd = n->ndup.fd;
8722 new->ndup.next = copynode(n->ndup.next);
8726 new->nhere.doc = copynode(n->nhere.doc);
8727 new->nhere.fd = n->nhere.fd;
8728 new->nhere.next = copynode(n->nhere.next);
8731 new->nnot.com = copynode(n->nnot.com);
8734 new->type = n->type;
8739 static struct nodelist *
8740 copynodelist(struct nodelist *lp)
8742 struct nodelist *start;
8743 struct nodelist **lpp;
8748 funcblock = (char *) funcblock +
8749 SHELL_ALIGN(sizeof(struct nodelist));
8750 (*lpp)->n = copynode(lp->n);
8752 lpp = &(*lpp)->next;
8760 nodesavestr(char *s)
8762 char *rtn = funcstring;
8764 funcstring = stpcpy(funcstring, s) + 1;
8770 * Free a parse tree.
8774 freefunc(struct funcnode *f)
8776 if (f && --f->count < 0)
8781 static void options(int);
8782 static void setoption(int, int);
8786 * Process the shell command line arguments.
8790 procargs(int argc, char **argv)
8793 const char *xminusc;
8800 for (i = 0; i < NOPTS; i++)
8806 if (*xargv == NULL) {
8808 error("-c requires an argument");
8811 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8815 for (i = 0; i < NOPTS; i++)
8816 if (optlist[i] == 2)
8821 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8826 } else if (!sflag) {
8827 setinputfile(*xargv, 0);
8833 shellparam.p = xargv;
8834 #ifdef CONFIG_ASH_GETOPTS
8835 shellparam.optind = 1;
8836 shellparam.optoff = -1;
8838 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8840 shellparam.nparam++;
8853 setinteractive(iflag);
8859 minus_o(char *name, int val)
8864 out1str("Current option settings\n");
8865 for (i = 0; i < NOPTS; i++)
8866 out1fmt("%-16s%s\n", optnames(i),
8867 optlist[i] ? "on" : "off");
8869 for (i = 0; i < NOPTS; i++)
8870 if (equal(name, optnames(i))) {
8874 error("Illegal option -o %s", name);
8879 * Process shell options. The global variable argptr contains a pointer
8880 * to the argument list; we advance it past the options.
8884 options(int cmdline)
8892 while ((p = *argptr) != NULL) {
8894 if ((c = *p++) == '-') {
8896 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8898 /* "-" means turn off -x and -v */
8901 /* "--" means reset params */
8902 else if (*argptr == NULL)
8905 break; /* "-" or "--" terminates options */
8907 } else if (c == '+') {
8913 while ((c = *p++) != '\0') {
8914 if (c == 'c' && cmdline) {
8915 minusc = p; /* command is after shell args*/
8916 } else if (c == 'o') {
8917 minus_o(*argptr, val);
8920 } else if (cmdline && (c == '-')) { // long options
8921 if (strcmp(p, "login") == 0)
8933 setoption(int flag, int val)
8937 for (i = 0; i < NOPTS; i++)
8938 if (optletters(i) == flag) {
8942 error("Illegal option -%c", flag);
8949 * Set the shell parameters.
8953 setparam(char **argv)
8959 for (nparam = 0 ; argv[nparam] ; nparam++);
8960 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8962 *ap++ = savestr(*argv++);
8965 freeparam(&shellparam);
8966 shellparam.malloc = 1;
8967 shellparam.nparam = nparam;
8968 shellparam.p = newparam;
8969 #ifdef CONFIG_ASH_GETOPTS
8970 shellparam.optind = 1;
8971 shellparam.optoff = -1;
8977 * Free the list of positional parameters.
8981 freeparam(volatile struct shparam *param)
8985 if (param->malloc) {
8986 for (ap = param->p ; *ap ; ap++)
8995 * The shift builtin command.
8999 shiftcmd(int argc, char **argv)
9006 n = number(argv[1]);
9007 if (n > shellparam.nparam)
9008 error("can't shift that many");
9010 shellparam.nparam -= n;
9011 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9012 if (shellparam.malloc)
9016 while ((*ap2++ = *ap1++) != NULL);
9017 #ifdef CONFIG_ASH_GETOPTS
9018 shellparam.optind = 1;
9019 shellparam.optoff = -1;
9028 * The set command builtin.
9032 setcmd(int argc, char **argv)
9035 return showvars(nullstr, 0, VUNSET);
9039 if (*argptr != NULL) {
9047 #ifdef CONFIG_ASH_GETOPTS
9052 shellparam.optind = number(value);
9053 shellparam.optoff = -1;
9057 #ifdef CONFIG_LOCALE_SUPPORT
9058 static void change_lc_all(const char *value)
9060 if (value != 0 && *value != 0)
9061 setlocale(LC_ALL, value);
9064 static void change_lc_ctype(const char *value)
9066 if (value != 0 && *value != 0)
9067 setlocale(LC_CTYPE, value);
9072 #ifdef CONFIG_ASH_RANDOM_SUPPORT
9073 /* Roughly copied from bash.. */
9074 static void change_random(const char *value)
9077 /* "get", generate */
9080 rseed = rseed * 1103515245 + 12345;
9081 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9082 /* set without recursion */
9083 setvar(vrandom.text, buf, VNOFUNC);
9084 vrandom.flags &= ~VNOFUNC;
9087 rseed = strtoul(value, (char **)NULL, 10);
9093 #ifdef CONFIG_ASH_GETOPTS
9095 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9104 if(*param_optind < 1)
9106 optnext = optfirst + *param_optind - 1;
9108 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9111 p = optnext[-1] + *optoff;
9112 if (p == NULL || *p == '\0') {
9113 /* Current word is done, advance */
9115 if (p == NULL || *p != '-' || *++p == '\0') {
9122 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9127 for (q = optstr; *q != c; ) {
9129 if (optstr[0] == ':') {
9132 err |= setvarsafe("OPTARG", s, 0);
9134 fprintf(stderr, "Illegal option -%c\n", c);
9135 (void) unsetvar("OPTARG");
9145 if (*p == '\0' && (p = *optnext) == NULL) {
9146 if (optstr[0] == ':') {
9149 err |= setvarsafe("OPTARG", s, 0);
9152 fprintf(stderr, "No arg for -%c option\n", c);
9153 (void) unsetvar("OPTARG");
9161 err |= setvarsafe("OPTARG", p, 0);
9164 err |= setvarsafe("OPTARG", nullstr, 0);
9167 *optoff = p ? p - *(optnext - 1) : -1;
9168 *param_optind = optnext - optfirst + 1;
9169 fmtstr(s, sizeof(s), "%d", *param_optind);
9170 err |= setvarsafe("OPTIND", s, VNOFUNC);
9173 err |= setvarsafe(optvar, s, 0);
9184 * The getopts builtin. Shellparam.optnext points to the next argument
9185 * to be processed. Shellparam.optptr points to the next character to
9186 * be processed in the current argument. If shellparam.optnext is NULL,
9187 * then it's the first time getopts has been called.
9191 getoptscmd(int argc, char **argv)
9196 error("Usage: getopts optstring var [arg]");
9197 else if (argc == 3) {
9198 optbase = shellparam.p;
9199 if (shellparam.optind > shellparam.nparam + 1) {
9200 shellparam.optind = 1;
9201 shellparam.optoff = -1;
9206 if (shellparam.optind > argc - 2) {
9207 shellparam.optind = 1;
9208 shellparam.optoff = -1;
9212 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9213 &shellparam.optoff);
9215 #endif /* CONFIG_ASH_GETOPTS */
9218 * XXX - should get rid of. have all builtins use getopt(3). the
9219 * library getopt must have the BSD extension static variable "optreset"
9220 * otherwise it can't be used within the shell safely.
9222 * Standard option processing (a la getopt) for builtin routines. The
9223 * only argument that is passed to nextopt is the option string; the
9224 * other arguments are unnecessary. It return the character, or '\0' on
9229 nextopt(const char *optstring)
9235 if ((p = optptr) == NULL || *p == '\0') {
9237 if (p == NULL || *p != '-' || *++p == '\0')
9240 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9244 for (q = optstring ; *q != c ; ) {
9246 error("Illegal option -%c", c);
9251 if (*p == '\0' && (p = *argptr++) == NULL)
9252 error("No arg for -%c option", c);
9261 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9264 outstr(const char *p, FILE *file)
9289 outcslow(int c, FILE *dest)
9299 out1fmt(const char *fmt, ...)
9306 r = vprintf(fmt, ap);
9314 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9321 ret = vsnprintf(outbuf, length, fmt, ap);
9329 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9333 * Shell command parser.
9336 #define EOFMARKLEN 79
9340 struct heredoc *next; /* next here document in list */
9341 union node *here; /* redirection node */
9342 char *eofmark; /* string indicating end of input */
9343 int striptabs; /* if set, strip leading tabs */
9348 static struct heredoc *heredoclist; /* list of here documents to read */
9351 static union node *list(int);
9352 static union node *andor(void);
9353 static union node *pipeline(void);
9354 static union node *command(void);
9355 static union node *simplecmd(void);
9356 static union node *makename(void);
9357 static void parsefname(void);
9358 static void parseheredoc(void);
9359 static char peektoken(void);
9360 static int readtoken(void);
9361 static int xxreadtoken(void);
9362 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9363 static int noexpand(char *);
9364 static void synexpect(int) __attribute__((__noreturn__));
9365 static void synerror(const char *) __attribute__((__noreturn__));
9366 static void setprompt(int);
9372 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9373 * valid parse tree indicating a blank line.)
9377 parsecmd(int interact)
9382 doprompt = interact;
9384 setprompt(doprompt);
9399 union node *n1, *n2, *n3;
9402 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9403 if (nlflag == 2 && peektoken())
9409 if (tok == TBACKGND) {
9410 if (n2->type == NPIPE) {
9411 n2->npipe.backgnd = 1;
9413 if (n2->type != NREDIR) {
9414 n3 = stalloc(sizeof(struct nredir));
9416 n3->nredir.redirect = NULL;
9419 n2->type = NBACKGND;
9426 n3 = (union node *)stalloc(sizeof (struct nbinary));
9428 n3->nbinary.ch1 = n1;
9429 n3->nbinary.ch2 = n2;
9445 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9453 pungetc(); /* push back EOF on input */
9469 union node *n1, *n2, *n3;
9474 if ((t = readtoken()) == TAND) {
9476 } else if (t == TOR) {
9482 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9484 n3 = (union node *)stalloc(sizeof (struct nbinary));
9486 n3->nbinary.ch1 = n1;
9487 n3->nbinary.ch2 = n2;
9497 union node *n1, *n2, *pipenode;
9498 struct nodelist *lp, *prev;
9502 TRACE(("pipeline: entered\n"));
9503 if (readtoken() == TNOT) {
9505 checkkwd = CHKKWD | CHKALIAS;
9509 if (readtoken() == TPIPE) {
9510 pipenode = (union node *)stalloc(sizeof (struct npipe));
9511 pipenode->type = NPIPE;
9512 pipenode->npipe.backgnd = 0;
9513 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9514 pipenode->npipe.cmdlist = lp;
9518 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9519 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9522 } while (readtoken() == TPIPE);
9528 n2 = (union node *)stalloc(sizeof (struct nnot));
9541 union node *n1, *n2;
9542 union node *ap, **app;
9543 union node *cp, **cpp;
9544 union node *redir, **rpp;
9551 switch (readtoken()) {
9556 n1 = (union node *)stalloc(sizeof (struct nif));
9558 n1->nif.test = list(0);
9559 if (readtoken() != TTHEN)
9561 n1->nif.ifpart = list(0);
9563 while (readtoken() == TELIF) {
9564 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9565 n2 = n2->nif.elsepart;
9567 n2->nif.test = list(0);
9568 if (readtoken() != TTHEN)
9570 n2->nif.ifpart = list(0);
9572 if (lasttoken == TELSE)
9573 n2->nif.elsepart = list(0);
9575 n2->nif.elsepart = NULL;
9583 n1 = (union node *)stalloc(sizeof (struct nbinary));
9584 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9585 n1->nbinary.ch1 = list(0);
9586 if ((got=readtoken()) != TDO) {
9587 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9590 n1->nbinary.ch2 = list(0);
9595 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9596 synerror("Bad for loop variable");
9597 n1 = (union node *)stalloc(sizeof (struct nfor));
9599 n1->nfor.var = wordtext;
9600 checkkwd = CHKKWD | CHKALIAS;
9601 if (readtoken() == TIN) {
9603 while (readtoken() == TWORD) {
9604 n2 = (union node *)stalloc(sizeof (struct narg));
9606 n2->narg.text = wordtext;
9607 n2->narg.backquote = backquotelist;
9609 app = &n2->narg.next;
9613 if (lasttoken != TNL && lasttoken != TSEMI)
9616 n2 = (union node *)stalloc(sizeof (struct narg));
9618 n2->narg.text = (char *)dolatstr;
9619 n2->narg.backquote = NULL;
9620 n2->narg.next = NULL;
9623 * Newline or semicolon here is optional (but note
9624 * that the original Bourne shell only allowed NL).
9626 if (lasttoken != TNL && lasttoken != TSEMI)
9629 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9630 if (readtoken() != TDO)
9632 n1->nfor.body = list(0);
9636 n1 = (union node *)stalloc(sizeof (struct ncase));
9638 if (readtoken() != TWORD)
9640 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9642 n2->narg.text = wordtext;
9643 n2->narg.backquote = backquotelist;
9644 n2->narg.next = NULL;
9646 checkkwd = CHKKWD | CHKALIAS;
9647 } while (readtoken() == TNL);
9648 if (lasttoken != TIN)
9650 cpp = &n1->ncase.cases;
9652 checkkwd = CHKNL | CHKKWD;
9655 if (lasttoken == TLP)
9657 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9659 app = &cp->nclist.pattern;
9661 *app = ap = (union node *)stalloc(sizeof (struct narg));
9663 ap->narg.text = wordtext;
9664 ap->narg.backquote = backquotelist;
9665 if (readtoken() != TPIPE)
9667 app = &ap->narg.next;
9670 ap->narg.next = NULL;
9671 if (lasttoken != TRP)
9673 cp->nclist.body = list(2);
9675 cpp = &cp->nclist.next;
9677 checkkwd = CHKNL | CHKKWD;
9678 if ((t = readtoken()) != TESAC) {
9680 synexpect(TENDCASE);
9688 n1 = (union node *)stalloc(sizeof (struct nredir));
9689 n1->type = NSUBSHELL;
9690 n1->nredir.n = list(0);
9691 n1->nredir.redirect = NULL;
9704 if (readtoken() != t)
9708 /* Now check for redirection which may follow command */
9709 checkkwd = CHKKWD | CHKALIAS;
9711 while (readtoken() == TREDIR) {
9712 *rpp = n2 = redirnode;
9713 rpp = &n2->nfile.next;
9719 if (n1->type != NSUBSHELL) {
9720 n2 = (union node *)stalloc(sizeof (struct nredir));
9725 n1->nredir.redirect = redir;
9734 union node *args, **app;
9735 union node *n = NULL;
9736 union node *vars, **vpp;
9737 union node **rpp, *redir;
9747 savecheckkwd = CHKALIAS;
9749 checkkwd = savecheckkwd;
9750 switch (readtoken()) {
9752 n = (union node *)stalloc(sizeof (struct narg));
9754 n->narg.text = wordtext;
9755 n->narg.backquote = backquotelist;
9756 if (savecheckkwd && isassignment(wordtext)) {
9758 vpp = &n->narg.next;
9761 app = &n->narg.next;
9766 *rpp = n = redirnode;
9767 rpp = &n->nfile.next;
9768 parsefname(); /* read name of redirection file */
9772 args && app == &args->narg.next &&
9775 struct builtincmd *bcmd;
9778 /* We have a function */
9779 if (readtoken() != TRP)
9781 name = n->narg.text;
9783 !goodname(name) || (
9784 (bcmd = find_builtin(name)) &&
9785 IS_BUILTIN_SPECIAL(bcmd)
9788 synerror("Bad function name");
9790 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9791 n->narg.next = command();
9804 n = (union node *)stalloc(sizeof (struct ncmd));
9806 n->ncmd.args = args;
9807 n->ncmd.assign = vars;
9808 n->ncmd.redirect = redir;
9817 n = (union node *)stalloc(sizeof (struct narg));
9819 n->narg.next = NULL;
9820 n->narg.text = wordtext;
9821 n->narg.backquote = backquotelist;
9825 void fixredir(union node *n, const char *text, int err)
9827 TRACE(("Fix redir %s %d\n", text, err));
9829 n->ndup.vname = NULL;
9831 if (is_digit(text[0]) && text[1] == '\0')
9832 n->ndup.dupfd = digit_val(text[0]);
9833 else if (text[0] == '-' && text[1] == '\0')
9838 synerror("Bad fd number");
9840 n->ndup.vname = makename();
9848 union node *n = redirnode;
9850 if (readtoken() != TWORD)
9852 if (n->type == NHERE) {
9853 struct heredoc *here = heredoc;
9859 TRACE(("Here document %d\n", n->type));
9860 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9861 synerror("Illegal eof marker for << redirection");
9862 rmescapes(wordtext);
9863 here->eofmark = wordtext;
9865 if (heredoclist == NULL)
9868 for (p = heredoclist ; p->next ; p = p->next);
9871 } else if (n->type == NTOFD || n->type == NFROMFD) {
9872 fixredir(n, wordtext, 0);
9874 n->nfile.fname = makename();
9880 * Input any here documents.
9886 struct heredoc *here;
9897 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9898 here->eofmark, here->striptabs);
9899 n = (union node *)stalloc(sizeof (struct narg));
9900 n->narg.type = NARG;
9901 n->narg.next = NULL;
9902 n->narg.text = wordtext;
9903 n->narg.backquote = backquotelist;
9904 here->here->nhere.doc = n;
9909 static char peektoken(void)
9915 return tokname_array[t][0];
9923 int alreadyseen = tokpushback;
9926 #ifdef CONFIG_ASH_ALIAS
9935 if (checkkwd & CHKNL) {
9942 if (t != TWORD || quoteflag) {
9947 * check for keywords
9949 if (checkkwd & CHKKWD) {
9950 const char *const *pp;
9952 if ((pp = findkwd(wordtext))) {
9953 lasttoken = t = pp - tokname_array;
9954 TRACE(("keyword %s recognized\n", tokname(t)));
9959 if (checkkwd & CHKALIAS) {
9960 #ifdef CONFIG_ASH_ALIAS
9962 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9964 pushstring(ap->val, ap);
9974 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9976 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9983 * Read the next input token.
9984 * If the token is a word, we set backquotelist to the list of cmds in
9985 * backquotes. We set quoteflag to true if any part of the word was
9987 * If the token is TREDIR, then we set redirnode to a structure containing
9989 * In all cases, the variable startlinno is set to the number of the line
9990 * on which the token starts.
9992 * [Change comment: here documents and internal procedures]
9993 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9994 * word parsing code into a separate routine. In this case, readtoken
9995 * doesn't need to have any internal procedures, but parseword does.
9996 * We could also make parseoperator in essence the main routine, and
9997 * have parseword (readtoken1?) handle both words and redirection.]
10000 #define NEW_xxreadtoken
10001 #ifdef NEW_xxreadtoken
10003 /* singles must be first! */
10004 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10006 static const char xxreadtoken_tokens[] = {
10007 TNL, TLP, TRP, /* only single occurrence allowed */
10008 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10009 TEOF, /* corresponds to trailing nul */
10010 TAND, TOR, TENDCASE, /* if double occurrence */
10013 #define xxreadtoken_doubles \
10014 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10015 #define xxreadtoken_singles \
10016 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10018 static int xxreadtoken()
10030 startlinno = plinno;
10031 for (;;) { /* until token or start of word found */
10034 if ((c != ' ') && (c != '\t')
10035 #ifdef CONFIG_ASH_ALIAS
10040 while ((c = pgetc()) != '\n' && c != PEOF);
10042 } else if (c == '\\') {
10043 if (pgetc() != '\n') {
10047 startlinno = ++plinno;
10052 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10057 needprompt = doprompt;
10060 p = strchr(xxreadtoken_chars, c);
10063 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10066 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10067 if (pgetc() == *p) { /* double occurrence? */
10068 p += xxreadtoken_doubles + 1;
10075 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10083 #define RETURN(token) return lasttoken = token
10098 startlinno = plinno;
10099 for (;;) { /* until token or start of word found */
10102 case ' ': case '\t':
10103 #ifdef CONFIG_ASH_ALIAS
10108 while ((c = pgetc()) != '\n' && c != PEOF);
10112 if (pgetc() == '\n') {
10113 startlinno = ++plinno;
10122 needprompt = doprompt;
10127 if (pgetc() == '&')
10132 if (pgetc() == '|')
10137 if (pgetc() == ';')
10150 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10153 #endif /* NEW_xxreadtoken */
10157 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10158 * is not NULL, read a here document. In the latter case, eofmark is the
10159 * word which marks the end of the document and striptabs is true if
10160 * leading tabs should be stripped from the document. The argument firstc
10161 * is the first character of the input token or document.
10163 * Because C does not have internal subroutines, I have simulated them
10164 * using goto's to implement the subroutine linkage. The following macros
10165 * will run code that appears at the end of readtoken1.
10168 #define CHECKEND() {goto checkend; checkend_return:;}
10169 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10170 #define PARSESUB() {goto parsesub; parsesub_return:;}
10171 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10172 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10173 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10176 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10181 char line[EOFMARKLEN + 1];
10182 struct nodelist *bqlist;
10185 int varnest; /* levels of variables expansion */
10186 int arinest; /* levels of arithmetic expansion */
10187 int parenlevel; /* levels of parens in arithmetic */
10188 int dqvarnest; /* levels of variables expansion within double quotes */
10190 int prevsyntax; /* syntax before arithmetic */
10192 /* Avoid longjmp clobbering */
10198 (void) &parenlevel;
10201 (void) &prevsyntax;
10205 startlinno = plinno;
10207 if (syntax == DQSYNTAX)
10216 STARTSTACKSTR(out);
10217 loop: { /* for each line, until end of word */
10218 CHECKEND(); /* set c to PEOF if at end of here document */
10219 for (;;) { /* until end of line or end of word */
10220 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10221 switch(SIT(c, syntax)) {
10222 case CNL: /* '\n' */
10223 if (syntax == BASESYNTAX)
10224 goto endword; /* exit outer loop */
10230 goto loop; /* continue outer loop */
10235 if (eofmark == NULL || dblquote)
10236 USTPUTC(CTLESC, out);
10239 case CBACK: /* backslash */
10242 USTPUTC(CTLESC, out);
10243 USTPUTC('\\', out);
10245 } else if (c == '\n') {
10251 c != '\\' && c != '`' &&
10257 USTPUTC(CTLESC, out);
10258 USTPUTC('\\', out);
10260 if (SIT(c, SQSYNTAX) == CCTL)
10261 USTPUTC(CTLESC, out);
10269 if (eofmark == NULL) {
10270 USTPUTC(CTLQUOTEMARK, out);
10278 if (eofmark != NULL && arinest == 0 &&
10282 if (dqvarnest == 0) {
10283 syntax = BASESYNTAX;
10290 case CVAR: /* '$' */
10291 PARSESUB(); /* parse substitution */
10293 case CENDVAR: /* '}' */
10296 if (dqvarnest > 0) {
10299 USTPUTC(CTLENDVAR, out);
10304 #ifdef CONFIG_ASH_MATH_SUPPORT
10305 case CLP: /* '(' in arithmetic */
10309 case CRP: /* ')' in arithmetic */
10310 if (parenlevel > 0) {
10314 if (pgetc() == ')') {
10315 if (--arinest == 0) {
10316 USTPUTC(CTLENDARI, out);
10317 syntax = prevsyntax;
10318 if (syntax == DQSYNTAX)
10326 * unbalanced parens
10327 * (don't 2nd guess - no error)
10335 case CBQUOTE: /* '`' */
10339 goto endword; /* exit outer loop */
10344 goto endword; /* exit outer loop */
10345 #ifdef CONFIG_ASH_ALIAS
10355 #ifdef CONFIG_ASH_MATH_SUPPORT
10356 if (syntax == ARISYNTAX)
10357 synerror("Missing '))'");
10359 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10360 synerror("Unterminated quoted string");
10361 if (varnest != 0) {
10362 startlinno = plinno;
10364 synerror("Missing '}'");
10366 USTPUTC('\0', out);
10367 len = out - (char *)stackblock();
10368 out = stackblock();
10369 if (eofmark == NULL) {
10370 if ((c == '>' || c == '<')
10373 && (*out == '\0' || is_digit(*out))) {
10375 return lasttoken = TREDIR;
10380 quoteflag = quotef;
10381 backquotelist = bqlist;
10382 grabstackblock(len);
10384 return lasttoken = TWORD;
10385 /* end of readtoken routine */
10390 * Check to see whether we are at the end of the here document. When this
10391 * is called, c is set to the first character of the next input line. If
10392 * we are at the end of the here document, this routine sets the c to PEOF.
10397 #ifdef CONFIG_ASH_ALIAS
10403 while (c == '\t') {
10407 if (c == *eofmark) {
10408 if (pfgets(line, sizeof line) != NULL) {
10412 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10413 if (*p == '\n' && *q == '\0') {
10416 needprompt = doprompt;
10418 pushstring(line, NULL);
10423 goto checkend_return;
10428 * Parse a redirection operator. The variable "out" points to a string
10429 * specifying the fd to be redirected. The variable "c" contains the
10430 * first character of the redirection operator.
10437 np = (union node *)stalloc(sizeof (struct nfile));
10442 np->type = NAPPEND;
10444 np->type = NCLOBBER;
10451 } else { /* c == '<' */
10453 switch (c = pgetc()) {
10455 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10456 np = (union node *)stalloc(sizeof (struct nhere));
10460 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10461 heredoc->here = np;
10462 if ((c = pgetc()) == '-') {
10463 heredoc->striptabs = 1;
10465 heredoc->striptabs = 0;
10471 np->type = NFROMFD;
10475 np->type = NFROMTO;
10485 np->nfile.fd = digit_val(fd);
10487 goto parseredir_return;
10492 * Parse a substitution. At this point, we have read the dollar sign
10493 * and nothing else.
10501 static const char types[] = "}-+?=";
10505 c <= PEOA_OR_PEOF ||
10506 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10510 } else if (c == '(') { /* $(command) or $((arith)) */
10511 if (pgetc() == '(') {
10512 #ifdef CONFIG_ASH_MATH_SUPPORT
10515 synerror("We unsupport $((arith))");
10522 USTPUTC(CTLVAR, out);
10523 typeloc = out - (char *)stackblock();
10524 USTPUTC(VSNORMAL, out);
10525 subtype = VSNORMAL;
10529 if ((c = pgetc()) == '}')
10532 subtype = VSLENGTH;
10537 if (c > PEOA_OR_PEOF && is_name(c)) {
10541 } while (c > PEOA_OR_PEOF && is_in_name(c));
10542 } else if (is_digit(c)) {
10546 } while (is_digit(c));
10548 else if (is_special(c)) {
10553 badsub: synerror("Bad substitution");
10557 if (subtype == 0) {
10564 p = strchr(types, c);
10567 subtype = p - types + VSNORMAL;
10573 subtype = c == '#' ? VSTRIMLEFT :
10586 if (dblquote || arinest)
10588 *((char *)stackblock() + typeloc) = subtype | flags;
10589 if (subtype != VSNORMAL) {
10591 if (dblquote || arinest) {
10596 goto parsesub_return;
10601 * Called to parse command substitutions. Newstyle is set if the command
10602 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10603 * list of commands (passed by reference), and savelen is the number of
10604 * characters on the top of the stack which must be preserved.
10608 struct nodelist **nlpp;
10611 char *volatile str;
10612 struct jmploc jmploc;
10613 struct jmploc *volatile savehandler;
10617 (void) &saveprompt;
10620 savepbq = parsebackquote;
10621 if (setjmp(jmploc.loc)) {
10624 parsebackquote = 0;
10625 handler = savehandler;
10626 longjmp(handler->loc, 1);
10630 savelen = out - (char *)stackblock();
10632 str = ckmalloc(savelen);
10633 memcpy(str, stackblock(), savelen);
10635 savehandler = handler;
10639 /* We must read until the closing backquote, giving special
10640 treatment to some slashes, and then push the string and
10641 reread it as input, interpreting it normally. */
10648 STARTSTACKSTR(pout);
10654 switch (pc = pgetc()) {
10659 if ((pc = pgetc()) == '\n') {
10664 * If eating a newline, avoid putting
10665 * the newline into the new character
10666 * stream (via the STPUTC after the
10671 if (pc != '\\' && pc != '`' && pc != '$'
10672 && (!dblquote || pc != '"'))
10673 STPUTC('\\', pout);
10674 if (pc > PEOA_OR_PEOF) {
10680 #ifdef CONFIG_ASH_ALIAS
10683 startlinno = plinno;
10684 synerror("EOF in backquote substitution");
10688 needprompt = doprompt;
10697 STPUTC('\0', pout);
10698 psavelen = pout - (char *)stackblock();
10699 if (psavelen > 0) {
10700 pstr = grabstackstr(pout);
10701 setinputstring(pstr);
10706 nlpp = &(*nlpp)->next;
10707 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10708 (*nlpp)->next = NULL;
10709 parsebackquote = oldstyle;
10712 saveprompt = doprompt;
10719 doprompt = saveprompt;
10721 if (readtoken() != TRP)
10728 * Start reading from old file again, ignoring any pushed back
10729 * tokens left from the backquote parsing
10734 while (stackblocksize() <= savelen)
10736 STARTSTACKSTR(out);
10738 memcpy(out, str, savelen);
10739 STADJUST(savelen, out);
10745 parsebackquote = savepbq;
10746 handler = savehandler;
10747 if (arinest || dblquote)
10748 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10750 USTPUTC(CTLBACKQ, out);
10752 goto parsebackq_oldreturn;
10754 goto parsebackq_newreturn;
10757 #ifdef CONFIG_ASH_MATH_SUPPORT
10759 * Parse an arithmetic expansion (indicate start of one and set state)
10763 if (++arinest == 1) {
10764 prevsyntax = syntax;
10765 syntax = ARISYNTAX;
10766 USTPUTC(CTLARI, out);
10773 * we collapse embedded arithmetic expansion to
10774 * parenthesis, which should be equivalent
10778 goto parsearith_return;
10782 } /* end of readtoken */
10787 * Returns true if the text contains nothing to expand (no dollar signs
10792 noexpand(char *text)
10798 while ((c = *p++) != '\0') {
10799 if (c == CTLQUOTEMARK)
10803 else if (SIT(c, BASESYNTAX) == CCTL)
10811 * Return of a legal variable name (a letter or underscore followed by zero or
10812 * more letters, underscores, and digits).
10816 endofname(const char *name)
10824 if (! is_in_name(*p))
10832 * Called when an unexpected token is read during the parse. The argument
10833 * is the token that is expected, or -1 if more than one type of token can
10834 * occur at this point.
10837 static void synexpect(int token)
10842 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10844 sprintf(msg + l, " (expecting %s)", tokname(token));
10850 synerror(const char *msg)
10852 error("Syntax error: %s", msg);
10858 * called by editline -- any expansions to the prompt
10859 * should be added here.
10862 static void setprompt(int whichprompt)
10864 const char *prompt;
10866 switch (whichprompt) {
10880 static const char *const *findkwd(const char *s)
10882 return bsearch(s, tokname_array + KWDOFFSET,
10883 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10884 sizeof(const char *), pstrcmp);
10887 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10890 * Code for dealing with input/output redirection.
10893 #define EMPTY -2 /* marks an unused slot in redirtab */
10895 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10897 # define PIPESIZE PIPE_BUF
10901 * Open a file in noclobber mode.
10902 * The code was copied from bash.
10905 noclobberopen(const char *fname)
10908 struct stat finfo, finfo2;
10911 * If the file exists and is a regular file, return an error
10914 r = stat(fname, &finfo);
10915 if (r == 0 && S_ISREG(finfo.st_mode)) {
10921 * If the file was not present (r != 0), make sure we open it
10922 * exclusively so that if it is created before we open it, our open
10923 * will fail. Make sure that we do not truncate an existing file.
10924 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10925 * file was not a regular file, we leave O_EXCL off.
10928 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10929 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10931 /* If the open failed, return the file descriptor right away. */
10936 * OK, the open succeeded, but the file may have been changed from a
10937 * non-regular file to a regular file between the stat and the open.
10938 * We are assuming that the O_EXCL open handles the case where FILENAME
10939 * did not exist and is symlinked to an existing file between the stat
10944 * If we can open it and fstat the file descriptor, and neither check
10945 * revealed that it was a regular file, and the file has not been
10946 * replaced, return the file descriptor.
10948 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10949 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10952 /* The file has been replaced. badness. */
10959 * Handle here documents. Normally we fork off a process to write the
10960 * data to a pipe. If the document is short, we can stuff the data in
10961 * the pipe without forking.
10965 openhere(union node *redir)
10971 error("Pipe call failed");
10972 if (redir->type == NHERE) {
10973 len = strlen(redir->nhere.doc->narg.text);
10974 if (len <= PIPESIZE) {
10975 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
10979 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10981 signal(SIGINT, SIG_IGN);
10982 signal(SIGQUIT, SIG_IGN);
10983 signal(SIGHUP, SIG_IGN);
10985 signal(SIGTSTP, SIG_IGN);
10987 signal(SIGPIPE, SIG_DFL);
10988 if (redir->type == NHERE)
10989 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
10991 expandhere(redir->nhere.doc, pip[1]);
11000 openredirect(union node *redir)
11005 switch (redir->nfile.type) {
11007 fname = redir->nfile.expfname;
11008 if ((f = open(fname, O_RDONLY)) < 0)
11012 fname = redir->nfile.expfname;
11013 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11017 /* Take care of noclobber mode. */
11019 fname = redir->nfile.expfname;
11020 if ((f = noclobberopen(fname)) < 0)
11026 fname = redir->nfile.expfname;
11027 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11031 fname = redir->nfile.expfname;
11032 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11039 /* Fall through to eliminate warning. */
11046 f = openhere(redir);
11052 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11054 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11058 dupredirect(union node *redir, int f)
11060 int fd = redir->nfile.fd;
11062 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11063 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11064 copyfd(redir->ndup.dupfd, fd);
11077 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11078 * old file descriptors are stashed away so that the redirection can be
11079 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11080 * standard output, and the standard error if it becomes a duplicate of
11081 * stdout, is saved in memory.
11085 redirect(union node *redir, int flags)
11088 struct redirtab *sv;
11099 if (flags & REDIR_PUSH) {
11100 struct redirtab *q;
11101 q = ckmalloc(sizeof (struct redirtab));
11102 q->next = redirlist;
11104 q->nullredirs = nullredirs - 1;
11105 for (i = 0 ; i < 10 ; i++)
11106 q->renamed[i] = EMPTY;
11113 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11114 n->ndup.dupfd == fd)
11115 continue; /* redirect from/to same file descriptor */
11117 newfd = openredirect(n);
11120 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11121 i = fcntl(fd, F_DUPFD, 10);
11128 error("%d: %m", fd);
11138 dupredirect(n, newfd);
11139 } while ((n = n->nfile.next));
11141 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11142 preverrout_fd = sv->renamed[2];
11147 * Undo the effects of the last redirection.
11153 struct redirtab *rp;
11156 if (--nullredirs >= 0)
11160 for (i = 0 ; i < 10 ; i++) {
11161 if (rp->renamed[i] != EMPTY) {
11164 copyfd(rp->renamed[i], i);
11166 close(rp->renamed[i]);
11169 redirlist = rp->next;
11170 nullredirs = rp->nullredirs;
11176 * Undo all redirections. Called on error or interrupt.
11180 * Discard all saved file descriptors.
11184 clearredir(int drop)
11196 * Copy a file descriptor to be >= to. Returns -1
11197 * if the source file descriptor is closed, EMPTY if there are no unused
11198 * file descriptors left.
11202 copyfd(int from, int to)
11206 newfd = fcntl(from, F_DUPFD, to);
11208 if (errno == EMFILE)
11211 error("%d: %m", from);
11218 redirectsafe(union node *redir, int flags)
11221 volatile int saveint;
11222 struct jmploc *volatile savehandler = handler;
11223 struct jmploc jmploc;
11226 if (!(err = setjmp(jmploc.loc) * 2)) {
11228 redirect(redir, flags);
11230 handler = savehandler;
11231 if (err && exception != EXERROR)
11232 longjmp(handler->loc, 1);
11233 RESTOREINT(saveint);
11237 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11240 static void shtree(union node *, int, char *, FILE*);
11241 static void shcmd(union node *, FILE *);
11242 static void sharg(union node *, FILE *);
11243 static void indent(int, char *, FILE *);
11244 static void trstring(char *);
11248 showtree(union node *n)
11250 trputs("showtree called\n");
11251 shtree(n, 1, NULL, stdout);
11256 shtree(union node *n, int ind, char *pfx, FILE *fp)
11258 struct nodelist *lp;
11264 indent(ind, pfx, fp);
11275 shtree(n->nbinary.ch1, ind, NULL, fp);
11278 shtree(n->nbinary.ch2, ind, NULL, fp);
11286 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11291 if (n->npipe.backgnd)
11297 fprintf(fp, "<node type %d>", n->type);
11306 shcmd(union node *cmd, FILE *fp)
11314 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11320 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11323 switch (np->nfile.type) {
11324 case NTO: s = ">"; dftfd = 1; break;
11325 case NCLOBBER: s = ">|"; dftfd = 1; break;
11326 case NAPPEND: s = ">>"; dftfd = 1; break;
11327 case NTOFD: s = ">&"; dftfd = 1; break;
11328 case NFROM: s = "<"; dftfd = 0; break;
11329 case NFROMFD: s = "<&"; dftfd = 0; break;
11330 case NFROMTO: s = "<>"; dftfd = 0; break;
11331 default: s = "*error*"; dftfd = 0; break;
11333 if (np->nfile.fd != dftfd)
11334 fprintf(fp, "%d", np->nfile.fd);
11336 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11337 fprintf(fp, "%d", np->ndup.dupfd);
11339 sharg(np->nfile.fname, fp);
11348 sharg(union node *arg, FILE *fp)
11351 struct nodelist *bqlist;
11354 if (arg->type != NARG) {
11355 out1fmt("<node type %d>\n", arg->type);
11358 bqlist = arg->narg.backquote;
11359 for (p = arg->narg.text ; *p ; p++) {
11368 if (subtype == VSLENGTH)
11374 if (subtype & VSNUL)
11377 switch (subtype & VSTYPE) {
11396 case VSTRIMLEFTMAX:
11403 case VSTRIMRIGHTMAX:
11410 out1fmt("<subtype %d>", subtype);
11417 case CTLBACKQ|CTLQUOTE:
11420 shtree(bqlist->n, -1, NULL, fp);
11432 indent(int amount, char *pfx, FILE *fp)
11436 for (i = 0 ; i < amount ; i++) {
11437 if (pfx && i == amount - 1)
11458 putc(c, tracefile);
11462 trace(const char *fmt, ...)
11469 (void) vfprintf(tracefile, fmt, va);
11474 tracev(const char *fmt, va_list va)
11478 (void) vfprintf(tracefile, fmt, va);
11483 trputs(const char *s)
11487 fputs(s, tracefile);
11499 putc('"', tracefile);
11500 for (p = s ; *p ; p++) {
11502 case '\n': c = 'n'; goto backslash;
11503 case '\t': c = 't'; goto backslash;
11504 case '\r': c = 'r'; goto backslash;
11505 case '"': c = '"'; goto backslash;
11506 case '\\': c = '\\'; goto backslash;
11507 case CTLESC: c = 'e'; goto backslash;
11508 case CTLVAR: c = 'v'; goto backslash;
11509 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11510 case CTLBACKQ: c = 'q'; goto backslash;
11511 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11512 backslash: putc('\\', tracefile);
11513 putc(c, tracefile);
11516 if (*p >= ' ' && *p <= '~')
11517 putc(*p, tracefile);
11519 putc('\\', tracefile);
11520 putc(*p >> 6 & 03, tracefile);
11521 putc(*p >> 3 & 07, tracefile);
11522 putc(*p & 07, tracefile);
11527 putc('"', tracefile);
11539 putc(' ', tracefile);
11541 putc('\n', tracefile);
11557 /* leave open because libedit might be using it */
11560 scopy("./trace", s);
11562 if (!freopen(s, "a", tracefile)) {
11563 fprintf(stderr, "Can't re-open %s\n", s);
11568 if ((tracefile = fopen(s, "a")) == NULL) {
11569 fprintf(stderr, "Can't open %s\n", s);
11575 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11576 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11578 setlinebuf(tracefile);
11579 fputs("\nTracing started.\n", tracefile);
11584 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11587 * Sigmode records the current value of the signal handlers for the various
11588 * modes. A value of zero means that the current handler is not known.
11589 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11592 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11593 #define S_CATCH 2 /* signal is caught */
11594 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11595 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11596 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11601 * The trap builtin.
11605 trapcmd(int argc, char **argv)
11614 for (signo = 0 ; signo < NSIG ; signo++) {
11615 if (trap[signo] != NULL) {
11618 sn = u_signal_names(0, &signo, 0);
11621 out1fmt("trap -- %s %s\n",
11622 single_quote(trap[signo]), sn);
11632 if ((signo = decode_signal(*ap, 0)) < 0)
11633 error("%s: bad trap", *ap);
11636 if (action[0] == '-' && action[1] == '\0')
11639 action = savestr(action);
11642 ckfree(trap[signo]);
11643 trap[signo] = action;
11654 * Clear traps on a fork.
11662 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11663 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11667 if (tp != &trap[0])
11668 setsignal(tp - trap);
11676 * Set the signal handler for the specified signal. The routine figures
11677 * out what it should be set to.
11681 setsignal(int signo)
11685 struct sigaction act;
11687 if ((t = trap[signo]) == NULL)
11689 else if (*t != '\0')
11693 if (rootshell && action == S_DFL) {
11696 if (iflag || minusc || sflag == 0)
11719 t = &sigmode[signo - 1];
11723 * current setting unknown
11725 if (sigaction(signo, 0, &act) == -1) {
11727 * Pretend it worked; maybe we should give a warning
11728 * here, but other shells don't. We don't alter
11729 * sigmode, so that we retry every time.
11733 if (act.sa_handler == SIG_IGN) {
11734 if (mflag && (signo == SIGTSTP ||
11735 signo == SIGTTIN || signo == SIGTTOU)) {
11736 tsig = S_IGN; /* don't hard ignore these */
11740 tsig = S_RESET; /* force to be set */
11743 if (tsig == S_HARD_IGN || tsig == action)
11747 act.sa_handler = onsig;
11750 act.sa_handler = SIG_IGN;
11753 act.sa_handler = SIG_DFL;
11757 sigfillset(&act.sa_mask);
11758 sigaction(signo, &act, 0);
11766 ignoresig(int signo)
11768 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11769 signal(signo, SIG_IGN);
11771 sigmode[signo - 1] = S_HARD_IGN;
11782 gotsig[signo - 1] = 1;
11783 pendingsigs = signo;
11785 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11794 * Called to execute a trap. Perhaps we should avoid entering new trap
11795 * handlers while we are executing a trap handler.
11805 savestatus = exitstatus;
11807 while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
11809 p = trap[p - q + 1];
11813 exitstatus = savestatus;
11819 * Controls whether the shell is interactive or not.
11823 setinteractive(int on)
11825 static int is_interactive;
11827 if (++on == is_interactive)
11829 is_interactive = on;
11831 setsignal(SIGQUIT);
11832 setsignal(SIGTERM);
11833 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11834 if(is_interactive > 1) {
11835 /* Looks like they want an interactive shell */
11836 static int do_banner;
11840 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11841 "Enter 'help' for a list of built-in commands.\n\n");
11849 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11850 /*** List the available builtins ***/
11852 static int helpcmd(int argc, char **argv)
11856 out1fmt("\nBuilt-in commands:\n-------------------\n");
11857 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11858 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11859 builtincmd[i].name + 1);
11865 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11867 extern const struct BB_applet applets[];
11868 extern const size_t NUM_APPLETS;
11870 for (i = 0; i < NUM_APPLETS; i++) {
11872 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11881 return EXIT_SUCCESS;
11883 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11886 * Called to exit the shell.
11897 jmp = setjmp(loc.loc);
11898 status = exitstatus;
11899 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11903 if ((p = trap[0]) != NULL && *p != '\0') {
11909 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11910 if (iflag && rootshell) {
11911 const char *hp = lookupvar("HISTFILE");
11914 save_history ( hp );
11922 static int decode_signal(const char *string, int minsig)
11925 const char *name = u_signal_names(string, &signo, minsig);
11927 return name ? signo : -1;
11930 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11932 static struct var *vartab[VTABSIZE];
11934 static int vpcmp(const void *, const void *);
11935 static struct var **findvar(struct var **, const char *);
11938 * Initialize the variable symbol tables and import the environment
11942 #ifdef CONFIG_ASH_GETOPTS
11944 * Safe version of setvar, returns 1 on success 0 on failure.
11948 setvarsafe(const char *name, const char *val, int flags)
11951 volatile int saveint;
11952 struct jmploc *volatile savehandler = handler;
11953 struct jmploc jmploc;
11956 if (setjmp(jmploc.loc))
11960 setvar(name, val, flags);
11963 handler = savehandler;
11964 RESTOREINT(saveint);
11970 * Set the value of a variable. The flags argument is ored with the
11971 * flags of the variable. If val is NULL, the variable is unset.
11975 setvar(const char *name, const char *val, int flags)
11982 q = endofname(name);
11983 p = strchrnul(q, '=');
11984 namelen = p - name;
11985 if (!namelen || p != q)
11986 error("%.*s: bad variable name", namelen, name);
11991 vallen = strlen(val);
11994 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11998 p = mempcpy(p, val, vallen);
12001 setvareq(nameeq, flags | VNOSAVE);
12007 * Same as setvar except that the variable and value are passed in
12008 * the first argument as name=value. Since the first argument will
12009 * be actually stored in the table, it should not be a string that
12011 * Called with interrupts off.
12015 setvareq(char *s, int flags)
12017 struct var *vp, **vpp;
12020 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12021 vp = *findvar(vpp, s);
12023 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12026 if (flags & VNOSAVE)
12029 error("%.*s: is read only", strchrnul(n, '=') - n, n);
12032 if (flags & VNOSET)
12035 if (vp->func && (flags & VNOFUNC) == 0)
12036 (*vp->func)(strchrnul(s, '=') + 1);
12038 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12041 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12043 if (flags & VNOSET)
12046 vp = ckmalloc(sizeof (*vp));
12051 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12059 * Process a linked list of variable assignments.
12063 listsetvar(struct strlist *list_set_var, int flags)
12065 struct strlist *lp = list_set_var;
12071 setvareq(lp->text, flags);
12072 } while ((lp = lp->next));
12078 * Find the value of a variable. Returns NULL if not set.
12082 lookupvar(const char *name)
12086 if ((v = *findvar(hashvar(name), name))) {
12089 * Dynamic variables are implemented roughly the same way they are
12090 * in bash. Namely, they're "special" so long as they aren't unset.
12091 * As soon as they're unset, they're no longer dynamic, and dynamic
12092 * lookup will no longer happen at that point. -- PFM.
12094 if((v->flags & VDYNAMIC))
12097 if(!(v->flags & VUNSET))
12098 return strchrnul(v->text, '=') + 1;
12106 * Search the environment of a builtin command.
12110 bltinlookup(const char *name)
12112 struct strlist *sp;
12114 for (sp = cmdenviron ; sp ; sp = sp->next) {
12115 if (varequal(sp->text, name))
12116 return strchrnul(sp->text, '=') + 1;
12118 return lookupvar(name);
12123 * Generate a list of variables satisfying the given conditions.
12127 listvars(int on, int off, char ***end)
12138 for (vp = *vpp ; vp ; vp = vp->next)
12139 if ((vp->flags & mask) == on) {
12140 if (ep == stackstrend())
12141 ep = growstackstr();
12142 *ep++ = (char *) vp->text;
12144 } while (++vpp < vartab + VTABSIZE);
12145 if (ep == stackstrend())
12146 ep = growstackstr();
12150 return grabstackstr(ep);
12155 * POSIX requires that 'set' (but not export or readonly) output the
12156 * variables in lexicographic order - by the locale's collating order (sigh).
12157 * Maybe we could keep them in an ordered balanced binary tree
12158 * instead of hashed lists.
12159 * For now just roll 'em through qsort for printing...
12163 showvars(const char *sep_prefix, int on, int off)
12166 char **ep, **epend;
12168 ep = listvars(on, off, &epend);
12169 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12171 sep = *sep_prefix ? spcstr : sep_prefix;
12173 for (; ep < epend; ep++) {
12177 p = strchrnul(*ep, '=');
12180 q = single_quote(++p);
12182 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12191 * The export and readonly commands.
12195 exportcmd(int argc, char **argv)
12201 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12204 notp = nextopt("p") - 'p';
12205 if (notp && ((name = *(aptr = argptr)))) {
12207 if ((p = strchr(name, '=')) != NULL) {
12210 if ((vp = *findvar(hashvar(name), name))) {
12215 setvar(name, p, flag);
12216 } while ((name = *++aptr) != NULL);
12218 showvars(argv[0], flag, 0);
12225 * Make a variable a local variable. When a variable is made local, it's
12226 * value and flags are saved in a localvar structure. The saved values
12227 * will be restored when the shell function returns. We handle the name
12228 * "-" as a special case.
12232 mklocal(char *name)
12234 struct localvar *lvp;
12239 lvp = ckmalloc(sizeof (struct localvar));
12240 if (name[0] == '-' && name[1] == '\0') {
12242 p = ckmalloc(sizeof(optlist));
12243 lvp->text = memcpy(p, optlist, sizeof(optlist));
12248 vpp = hashvar(name);
12249 vp = *findvar(vpp, name);
12250 eq = strchr(name, '=');
12253 setvareq(name, VSTRFIXED);
12255 setvar(name, NULL, VSTRFIXED);
12256 vp = *vpp; /* the new variable */
12257 lvp->flags = VUNSET;
12259 lvp->text = vp->text;
12260 lvp->flags = vp->flags;
12261 vp->flags |= VSTRFIXED|VTEXTFIXED;
12267 lvp->next = localvars;
12273 * The "local" command.
12277 localcmd(int argc, char **argv)
12282 while ((name = *argv++) != NULL) {
12290 * Called after a function returns.
12291 * Interrupts must be off.
12297 struct localvar *lvp;
12300 while ((lvp = localvars) != NULL) {
12301 localvars = lvp->next;
12303 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12304 if (vp == NULL) { /* $- saved */
12305 memcpy(optlist, lvp->text, sizeof(optlist));
12308 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12309 unsetvar(vp->text);
12312 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12313 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12315 vp->flags = lvp->flags;
12316 vp->text = lvp->text;
12324 * The unset builtin command. We unset the function before we unset the
12325 * variable to allow a function to be unset when there is a readonly variable
12326 * with the same name.
12330 unsetcmd(int argc, char **argv)
12337 while ((i = nextopt("vf")) != '\0') {
12341 for (ap = argptr; *ap ; ap++) {
12356 * Unset the specified variable.
12360 unsetvar(const char *s)
12366 vpp = findvar(hashvar(s), s);
12370 int flags = vp->flags;
12373 if (flags & VREADONLY)
12376 vp->flags &= ~VDYNAMIC;
12378 if (flags & VUNSET)
12380 if ((flags & VSTRFIXED) == 0) {
12382 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12389 vp->flags &= ~VEXPORT;
12402 * Find the appropriate entry in the hash table from the name.
12405 static struct var **
12406 hashvar(const char *p)
12408 unsigned int hashval;
12410 hashval = ((unsigned char) *p) << 4;
12411 while (*p && *p != '=')
12412 hashval += (unsigned char) *p++;
12413 return &vartab[hashval % VTABSIZE];
12419 * Compares two strings up to the first = or '\0'. The first
12420 * string must be terminated by '='; the second may be terminated by
12421 * either '=' or '\0'.
12425 varcmp(const char *p, const char *q)
12429 while ((c = *p) == (d = *q)) {
12430 if (!c || c == '=')
12444 vpcmp(const void *a, const void *b)
12446 return varcmp(*(const char **)a, *(const char **)b);
12449 static struct var **
12450 findvar(struct var **vpp, const char *name)
12452 for (; *vpp; vpp = &(*vpp)->next) {
12453 if (varequal((*vpp)->text, name)) {
12459 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12461 #include <sys/times.h>
12463 static const unsigned char timescmd_str[] = {
12464 ' ', offsetof(struct tms, tms_utime),
12465 '\n', offsetof(struct tms, tms_stime),
12466 ' ', offsetof(struct tms, tms_cutime),
12467 '\n', offsetof(struct tms, tms_cstime),
12471 static int timescmd(int ac, char **av)
12473 long int clk_tck, s, t;
12474 const unsigned char *p;
12477 clk_tck = sysconf(_SC_CLK_TCK);
12482 t = *(clock_t *)(((char *) &buf) + p[1]);
12484 out1fmt("%ldm%ld.%.3lds%c",
12486 ((t - s * clk_tck) * 1000) / clk_tck,
12488 } while (*(p += 2));
12493 #ifdef CONFIG_ASH_MATH_SUPPORT
12495 dash_arith(const char *s)
12501 result = arith(s, &errcode);
12504 error("exponent less than 0");
12505 else if (errcode == -2)
12506 error("divide by zero");
12507 else if (errcode == -5)
12508 error("expression recursion loop detected");
12519 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12520 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12522 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12526 letcmd(int argc, char **argv)
12533 error("expression expected");
12534 for (ap = argv + 1; *ap; ap++) {
12535 i = dash_arith(*ap);
12540 #endif /* CONFIG_ASH_MATH_SUPPORT */
12542 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12545 * Miscellaneous builtins.
12551 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12552 typedef enum __rlimit_resource rlim_t;
12558 * The read builtin. The -e option causes backslashes to escape the
12559 * following character.
12561 * This uses unbuffered input, which may be avoidable in some cases.
12565 readcmd(int argc, char **argv)
12574 #if defined(CONFIG_ASH_TIMEOUT)
12577 struct timeval timeout_struct;
12578 struct termios tty, old_tty;
12586 #if defined(CONFIG_ASH_TIMEOUT)
12589 while ((i = nextopt("p:rt:")) != '\0')
12591 while ((i = nextopt("p:r")) != '\0')
12595 prompt = optionarg;
12598 #if defined(CONFIG_ASH_TIMEOUT)
12600 timeout = atoi(optionarg);
12603 if (prompt && isatty(0)) {
12606 if (*(ap = argptr) == NULL)
12607 error("arg count");
12608 if ((ifs = bltinlookup("IFS")) == NULL)
12610 #if defined(CONFIG_ASH_TIMEOUT)
12618 #if defined(CONFIG_ASH_TIMEOUT)
12620 tcgetattr(0, &tty);
12623 /* cfmakeraw(...) disables too much; we just do this instead. */
12624 tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
12625 tcsetattr(0, TCSANOW, &tty);
12630 timeout_struct.tv_sec = timeout;
12631 timeout_struct.tv_usec = 0;
12633 if ((i = select (FD_SETSIZE, &set, NULL, NULL, &timeout_struct)) == 1)
12636 if(c == '\n' || c == 4) /* Handle newlines and EOF */
12637 i = 0; /* Don't read further... */
12639 STPUTC(c, p); /* Keep reading... */
12641 tcsetattr(0, TCSANOW, &old_tty);
12643 /* Echo the character so the user knows it was read...
12644 Yes, this can be done by setting the ECHO flag, but that
12645 echoes ^D and other control characters at this state */
12657 if (read(0, &c, 1) != 1) {
12669 if (!rflag && c == '\\') {
12675 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12679 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12681 setvar(*ap, stackblock(), 0);
12691 /* Remove trailing blanks */
12692 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12694 setvar(*ap, stackblock(), 0);
12695 while (*++ap != NULL)
12696 setvar(*ap, nullstr, 0);
12701 static int umaskcmd(int argc, char **argv)
12703 static const char permuser[3] = "ugo";
12704 static const char permmode[3] = "rwx";
12705 static const short int permmask[] = {
12706 S_IRUSR, S_IWUSR, S_IXUSR,
12707 S_IRGRP, S_IWGRP, S_IXGRP,
12708 S_IROTH, S_IWOTH, S_IXOTH
12714 int symbolic_mode = 0;
12716 while (nextopt("S") != '\0') {
12725 if ((ap = *argptr) == NULL) {
12726 if (symbolic_mode) {
12730 for (i = 0; i < 3; i++) {
12733 *p++ = permuser[i];
12735 for (j = 0; j < 3; j++) {
12736 if ((mask & permmask[3 * i + j]) == 0) {
12737 *p++ = permmode[j];
12745 out1fmt("%.4o\n", mask);
12748 if (is_digit((unsigned char) *ap)) {
12751 if (*ap >= '8' || *ap < '0')
12752 error(illnum, argv[1]);
12753 mask = (mask << 3) + (*ap - '0');
12754 } while (*++ap != '\0');
12757 mask = ~mask & 0777;
12758 if (!bb_parse_mode(ap, &mask)) {
12759 error("Illegal mode: %s", ap);
12761 umask(~mask & 0777);
12770 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12771 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12772 * ash by J.T. Conklin.
12780 int factor; /* multiply by to get rlim_{cur,max} values */
12784 static const struct limits limits[] = {
12786 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12788 #ifdef RLIMIT_FSIZE
12789 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12792 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12794 #ifdef RLIMIT_STACK
12795 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12798 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12801 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12803 #ifdef RLIMIT_MEMLOCK
12804 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12806 #ifdef RLIMIT_NPROC
12807 { "process", RLIMIT_NPROC, 1, 'p' },
12809 #ifdef RLIMIT_NOFILE
12810 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
12813 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
12815 #ifdef RLIMIT_LOCKS
12816 { "locks", RLIMIT_LOCKS, 1, 'w' },
12818 { (char *) 0, 0, 0, '\0' }
12821 enum limtype { SOFT = 0x1, HARD = 0x2 };
12823 static void printlim(enum limtype how, const struct rlimit *limit,
12824 const struct limits *l)
12828 val = limit->rlim_max;
12830 val = limit->rlim_cur;
12832 if (val == RLIM_INFINITY)
12833 out1fmt("unlimited\n");
12836 out1fmt("%lld\n", (long long) val);
12841 ulimitcmd(int argc, char **argv)
12845 enum limtype how = SOFT | HARD;
12846 const struct limits *l;
12849 struct rlimit limit;
12852 while ((optc = nextopt("HSa"
12856 #ifdef RLIMIT_FSIZE
12862 #ifdef RLIMIT_STACK
12871 #ifdef RLIMIT_MEMLOCK
12874 #ifdef RLIMIT_NPROC
12877 #ifdef RLIMIT_NOFILE
12883 #ifdef RLIMIT_LOCKS
12901 for (l = limits; l->option != what; l++)
12904 set = *argptr ? 1 : 0;
12908 if (all || argptr[1])
12909 error("too many arguments");
12910 if (strncmp(p, "unlimited\n", 9) == 0)
12911 val = RLIM_INFINITY;
12915 while ((c = *p++) >= '0' && c <= '9')
12917 val = (val * 10) + (long)(c - '0');
12918 if (val < (rlim_t) 0)
12922 error("bad number");
12927 for (l = limits; l->name; l++) {
12928 getrlimit(l->cmd, &limit);
12929 out1fmt("%-20s ", l->name);
12930 printlim(how, &limit, l);
12935 getrlimit(l->cmd, &limit);
12938 limit.rlim_max = val;
12940 limit.rlim_cur = val;
12941 if (setrlimit(l->cmd, &limit) < 0)
12942 error("error setting limit (%m)");
12944 printlim(how, &limit, l);
12950 #ifdef CONFIG_ASH_MATH_SUPPORT
12952 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12954 Permission is hereby granted, free of charge, to any person obtaining
12955 a copy of this software and associated documentation files (the
12956 "Software"), to deal in the Software without restriction, including
12957 without limitation the rights to use, copy, modify, merge, publish,
12958 distribute, sublicense, and/or sell copies of the Software, and to
12959 permit persons to whom the Software is furnished to do so, subject to
12960 the following conditions:
12962 The above copyright notice and this permission notice shall be
12963 included in all copies or substantial portions of the Software.
12965 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12966 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12967 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12968 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12969 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12970 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12971 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12974 /* This is my infix parser/evaluator. It is optimized for size, intended
12975 * as a replacement for yacc-based parsers. However, it may well be faster
12976 * than a comparable parser written in yacc. The supported operators are
12977 * listed in #defines below. Parens, order of operations, and error handling
12978 * are supported. This code is thread safe. The exact expression format should
12979 * be that which POSIX specifies for shells. */
12981 /* The code uses a simple two-stack algorithm. See
12982 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12983 * for a detailed explanation of the infix-to-postfix algorithm on which
12984 * this is based (this code differs in that it applies operators immediately
12985 * to the stack instead of adding them to a queue to end up with an
12988 /* To use the routine, call it with an expression string and error return
12992 * Aug 24, 2001 Manuel Novoa III
12994 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12996 * 1) In arith_apply():
12997 * a) Cached values of *numptr and &(numptr[-1]).
12998 * b) Removed redundant test for zero denominator.
13001 * a) Eliminated redundant code for processing operator tokens by moving
13002 * to a table-based implementation. Also folded handling of parens
13004 * b) Combined all 3 loops which called arith_apply to reduce generated
13005 * code size at the cost of speed.
13007 * 3) The following expressions were treated as valid by the original code:
13008 * 1() , 0! , 1 ( *3 ) .
13009 * These bugs have been fixed by internally enclosing the expression in
13010 * parens and then checking that all binary ops and right parens are
13011 * preceded by a valid expression (NUM_TOKEN).
13013 * Note: It may be desirable to replace Aaron's test for whitespace with
13014 * ctype's isspace() if it is used by another busybox applet or if additional
13015 * whitespace chars should be considered. Look below the "#include"s for a
13016 * precompiler test.
13020 * Aug 26, 2001 Manuel Novoa III
13022 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13024 * Merge in Aaron's comments previously posted to the busybox list,
13025 * modified slightly to take account of my changes to the code.
13030 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13032 * - allow access to variable,
13033 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13034 * - realize assign syntax (VAR=expr, +=, *= etc)
13035 * - realize exponentiation (** operator)
13036 * - realize comma separated - expr, expr
13037 * - realise ++expr --expr expr++ expr--
13038 * - realise expr ? expr : expr (but, second expr calculate always)
13039 * - allow hexadecimal and octal numbers
13040 * - was restored loses XOR operator
13041 * - remove one goto label, added three ;-)
13042 * - protect $((num num)) as true zero expr (Manuel`s error)
13043 * - always use special isspace(), see comment from bash ;-)
13047 #define arith_isspace(arithval) \
13048 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13051 typedef unsigned char operator;
13053 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
13054 * precedence, and 3 high bits are an ID unique across operators of that
13055 * precedence. The ID portion is so that multiple operators can have the
13056 * same precedence, ensuring that the leftmost one is evaluated first.
13057 * Consider * and /. */
13059 #define tok_decl(prec,id) (((id)<<5)|(prec))
13060 #define PREC(op) ((op) & 0x1F)
13062 #define TOK_LPAREN tok_decl(0,0)
13064 #define TOK_COMMA tok_decl(1,0)
13066 #define TOK_ASSIGN tok_decl(2,0)
13067 #define TOK_AND_ASSIGN tok_decl(2,1)
13068 #define TOK_OR_ASSIGN tok_decl(2,2)
13069 #define TOK_XOR_ASSIGN tok_decl(2,3)
13070 #define TOK_PLUS_ASSIGN tok_decl(2,4)
13071 #define TOK_MINUS_ASSIGN tok_decl(2,5)
13072 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13073 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13075 #define TOK_MUL_ASSIGN tok_decl(3,0)
13076 #define TOK_DIV_ASSIGN tok_decl(3,1)
13077 #define TOK_REM_ASSIGN tok_decl(3,2)
13079 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13080 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13082 /* conditional is right associativity too */
13083 #define TOK_CONDITIONAL tok_decl(4,0)
13084 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
13086 #define TOK_OR tok_decl(5,0)
13088 #define TOK_AND tok_decl(6,0)
13090 #define TOK_BOR tok_decl(7,0)
13092 #define TOK_BXOR tok_decl(8,0)
13094 #define TOK_BAND tok_decl(9,0)
13096 #define TOK_EQ tok_decl(10,0)
13097 #define TOK_NE tok_decl(10,1)
13099 #define TOK_LT tok_decl(11,0)
13100 #define TOK_GT tok_decl(11,1)
13101 #define TOK_GE tok_decl(11,2)
13102 #define TOK_LE tok_decl(11,3)
13104 #define TOK_LSHIFT tok_decl(12,0)
13105 #define TOK_RSHIFT tok_decl(12,1)
13107 #define TOK_ADD tok_decl(13,0)
13108 #define TOK_SUB tok_decl(13,1)
13110 #define TOK_MUL tok_decl(14,0)
13111 #define TOK_DIV tok_decl(14,1)
13112 #define TOK_REM tok_decl(14,2)
13114 /* exponent is right associativity */
13115 #define TOK_EXPONENT tok_decl(15,1)
13117 /* For now unary operators. */
13118 #define UNARYPREC 16
13119 #define TOK_BNOT tok_decl(UNARYPREC,0)
13120 #define TOK_NOT tok_decl(UNARYPREC,1)
13122 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13123 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13125 #define PREC_PRE (UNARYPREC+2)
13127 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13128 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13130 #define PREC_POST (UNARYPREC+3)
13132 #define TOK_POST_INC tok_decl(PREC_POST, 0)
13133 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
13135 #define SPEC_PREC (UNARYPREC+4)
13137 #define TOK_NUM tok_decl(SPEC_PREC, 0)
13138 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13140 #define NUMPTR (*numstackptr)
13142 static inline int tok_have_assign(operator op)
13144 operator prec = PREC(op);
13146 convert_prec_is_assing(prec);
13147 return (prec == PREC(TOK_ASSIGN) ||
13148 prec == PREC_PRE || prec == PREC_POST);
13151 static inline int is_right_associativity(operator prec)
13153 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13154 prec == PREC(TOK_CONDITIONAL));
13158 typedef struct ARITCH_VAR_NUM {
13160 arith_t contidional_second_val;
13161 char contidional_second_val_initialized;
13162 char *var; /* if NULL then is regular number,
13163 else is variable name */
13167 typedef struct CHK_VAR_RECURSIVE_LOOPED {
13169 struct CHK_VAR_RECURSIVE_LOOPED *next;
13170 } chk_var_recursive_looped_t;
13172 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13175 static int arith_lookup_val(v_n_t *t)
13178 const char * p = lookupvar(t->var);
13183 /* recursive try as expression */
13184 chk_var_recursive_looped_t *cur;
13185 chk_var_recursive_looped_t cur_save;
13187 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13188 if(strcmp(cur->var, t->var) == 0) {
13189 /* expression recursion loop detected */
13193 /* save current lookuped var name */
13194 cur = prev_chk_var_recursive;
13195 cur_save.var = t->var;
13196 cur_save.next = cur;
13197 prev_chk_var_recursive = &cur_save;
13199 t->val = arith (p, &errcode);
13200 /* restore previous ptr after recursiving */
13201 prev_chk_var_recursive = cur;
13204 /* allow undefined var as 0 */
13211 /* "applying" a token means performing it on the top elements on the integer
13212 * stack. For a unary operator it will only change the top element, but a
13213 * binary operator will pop two arguments and push a result */
13215 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13218 arith_t numptr_val, rez;
13219 int ret_arith_lookup_val;
13221 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13222 without arguments */
13223 numptr_m1 = NUMPTR - 1;
13225 /* check operand is var with noninteger value */
13226 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13227 if(ret_arith_lookup_val)
13228 return ret_arith_lookup_val;
13230 rez = numptr_m1->val;
13231 if (op == TOK_UMINUS)
13233 else if (op == TOK_NOT)
13235 else if (op == TOK_BNOT)
13237 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13239 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13241 else if (op != TOK_UPLUS) {
13242 /* Binary operators */
13244 /* check and binary operators need two arguments */
13245 if (numptr_m1 == numstack) goto err;
13247 /* ... and they pop one */
13250 if (op == TOK_CONDITIONAL) {
13251 if(! numptr_m1->contidional_second_val_initialized) {
13252 /* protect $((expr1 ? expr2)) without ": expr" */
13255 rez = numptr_m1->contidional_second_val;
13256 } else if(numptr_m1->contidional_second_val_initialized) {
13257 /* protect $((expr1 : expr2)) without "expr ? " */
13260 numptr_m1 = NUMPTR - 1;
13261 if(op != TOK_ASSIGN) {
13262 /* check operand is var with noninteger value for not '=' */
13263 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13264 if(ret_arith_lookup_val)
13265 return ret_arith_lookup_val;
13267 if (op == TOK_CONDITIONAL) {
13268 numptr_m1->contidional_second_val = rez;
13270 rez = numptr_m1->val;
13271 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13273 else if (op == TOK_OR)
13274 rez = numptr_val || rez;
13275 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13277 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13279 else if (op == TOK_AND)
13280 rez = rez && numptr_val;
13281 else if (op == TOK_EQ)
13282 rez = (rez == numptr_val);
13283 else if (op == TOK_NE)
13284 rez = (rez != numptr_val);
13285 else if (op == TOK_GE)
13286 rez = (rez >= numptr_val);
13287 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13288 rez >>= numptr_val;
13289 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13290 rez <<= numptr_val;
13291 else if (op == TOK_GT)
13292 rez = (rez > numptr_val);
13293 else if (op == TOK_LT)
13294 rez = (rez < numptr_val);
13295 else if (op == TOK_LE)
13296 rez = (rez <= numptr_val);
13297 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13299 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13301 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13303 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13305 else if (op == TOK_CONDITIONAL_SEP) {
13306 if (numptr_m1 == numstack) {
13307 /* protect $((expr : expr)) without "expr ? " */
13310 numptr_m1->contidional_second_val_initialized = op;
13311 numptr_m1->contidional_second_val = numptr_val;
13313 else if (op == TOK_CONDITIONAL) {
13315 numptr_val : numptr_m1->contidional_second_val;
13317 else if(op == TOK_EXPONENT) {
13319 return -3; /* exponent less than 0 */
13324 while(numptr_val--)
13329 else if(numptr_val==0) /* zero divisor check */
13331 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13333 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13336 if(tok_have_assign(op)) {
13339 if(numptr_m1->var == NULL) {
13343 /* save to shell variable */
13344 snprintf(buf, sizeof(buf), "%lld", (long long) rez);
13345 setvar(numptr_m1->var, buf, 0);
13346 /* after saving, make previous value for v++ or v-- */
13347 if(op == TOK_POST_INC)
13349 else if(op == TOK_POST_DEC)
13352 numptr_m1->val = rez;
13353 /* protect geting var value, is number now */
13354 numptr_m1->var = NULL;
13359 /* longest must first */
13360 static const char op_tokens[] = {
13361 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13362 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13363 '<','<', 0, TOK_LSHIFT,
13364 '>','>', 0, TOK_RSHIFT,
13365 '|','|', 0, TOK_OR,
13366 '&','&', 0, TOK_AND,
13367 '!','=', 0, TOK_NE,
13368 '<','=', 0, TOK_LE,
13369 '>','=', 0, TOK_GE,
13370 '=','=', 0, TOK_EQ,
13371 '|','=', 0, TOK_OR_ASSIGN,
13372 '&','=', 0, TOK_AND_ASSIGN,
13373 '*','=', 0, TOK_MUL_ASSIGN,
13374 '/','=', 0, TOK_DIV_ASSIGN,
13375 '%','=', 0, TOK_REM_ASSIGN,
13376 '+','=', 0, TOK_PLUS_ASSIGN,
13377 '-','=', 0, TOK_MINUS_ASSIGN,
13378 '-','-', 0, TOK_POST_DEC,
13379 '^','=', 0, TOK_XOR_ASSIGN,
13380 '+','+', 0, TOK_POST_INC,
13381 '*','*', 0, TOK_EXPONENT,
13385 '=', 0, TOK_ASSIGN,
13397 '?', 0, TOK_CONDITIONAL,
13398 ':', 0, TOK_CONDITIONAL_SEP,
13399 ')', 0, TOK_RPAREN,
13400 '(', 0, TOK_LPAREN,
13404 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13407 static arith_t arith (const char *expr, int *perrcode)
13409 register char arithval; /* Current character under analysis */
13410 operator lasttok, op;
13413 const char *p = endexpression;
13416 size_t datasizes = strlen(expr) + 2;
13418 /* Stack of integers */
13419 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13420 * in any given correct or incorrect expression is left as an exercise to
13422 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13423 *numstackptr = numstack;
13424 /* Stack of operator tokens */
13425 operator *stack = alloca((datasizes) * sizeof(operator)),
13428 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13429 *perrcode = errcode = 0;
13432 if ((arithval = *expr) == 0) {
13433 if (p == endexpression) {
13434 /* Null expression. */
13438 /* This is only reached after all tokens have been extracted from the
13439 * input stream. If there are still tokens on the operator stack, they
13440 * are to be applied in order. At the end, there should be a final
13441 * result on the integer stack */
13443 if (expr != endexpression + 1) {
13444 /* If we haven't done so already, */
13445 /* append a closing right paren */
13446 expr = endexpression;
13447 /* and let the loop process it. */
13450 /* At this point, we're done with the expression. */
13451 if (numstackptr != numstack+1) {
13452 /* ... but if there isn't, it's bad */
13454 return (*perrcode = -1);
13456 if(numstack->var) {
13457 /* expression is $((var)) only, lookup now */
13458 errcode = arith_lookup_val(numstack);
13461 *perrcode = errcode;
13462 return numstack->val;
13464 /* Continue processing the expression. */
13465 if (arith_isspace(arithval)) {
13466 /* Skip whitespace */
13469 if((p = endofname(expr)) != expr) {
13470 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13472 numstackptr->var = alloca(var_name_size);
13473 safe_strncpy(numstackptr->var, expr, var_name_size);
13476 numstackptr->contidional_second_val_initialized = 0;
13480 } else if (is_digit(arithval)) {
13481 numstackptr->var = NULL;
13482 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13485 for(p = op_tokens; ; p++) {
13489 /* strange operator not found */
13492 for(o = expr; *p && *o == *p; p++)
13499 /* skip tail uncompared token */
13502 /* skip zero delim */
13507 /* post grammar: a++ reduce to num */
13508 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13511 /* Plus and minus are binary (not unary) _only_ if the last
13512 * token was as number, or a right paren (which pretends to be
13513 * a number, since it evaluates to one). Think about it.
13514 * It makes sense. */
13515 if (lasttok != TOK_NUM) {
13531 /* We don't want a unary operator to cause recursive descent on the
13532 * stack, because there can be many in a row and it could cause an
13533 * operator to be evaluated before its argument is pushed onto the
13534 * integer stack. */
13535 /* But for binary operators, "apply" everything on the operator
13536 * stack until we find an operator with a lesser priority than the
13537 * one we have just extracted. */
13538 /* Left paren is given the lowest priority so it will never be
13539 * "applied" in this way.
13540 * if associativity is right and priority eq, applied also skip
13543 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13544 /* not left paren or unary */
13545 if (lasttok != TOK_NUM) {
13546 /* binary op must be preceded by a num */
13549 while (stackptr != stack) {
13550 if (op == TOK_RPAREN) {
13551 /* The algorithm employed here is simple: while we don't
13552 * hit an open paren nor the bottom of the stack, pop
13553 * tokens and apply them */
13554 if (stackptr[-1] == TOK_LPAREN) {
13556 /* Any operator directly after a */
13558 /* close paren should consider itself binary */
13562 operator prev_prec = PREC(stackptr[-1]);
13564 convert_prec_is_assing(prec);
13565 convert_prec_is_assing(prev_prec);
13566 if (prev_prec < prec)
13568 /* check right assoc */
13569 if(prev_prec == prec && is_right_associativity(prec))
13572 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13573 if(errcode) goto ret;
13575 if (op == TOK_RPAREN) {
13580 /* Push this operator to the stack and remember it. */
13581 *stackptr++ = lasttok = op;
13588 #endif /* CONFIG_ASH_MATH_SUPPORT */
13592 const char *bb_applet_name = "debug stuff usage";
13593 int main(int argc, char **argv)
13595 return ash_main(argc, argv);
13600 * Copyright (c) 1989, 1991, 1993, 1994
13601 * The Regents of the University of California. All rights reserved.
13603 * This code is derived from software contributed to Berkeley by
13604 * Kenneth Almquist.
13606 * Redistribution and use in source and binary forms, with or without
13607 * modification, are permitted provided that the following conditions
13609 * 1. Redistributions of source code must retain the above copyright
13610 * notice, this list of conditions and the following disclaimer.
13611 * 2. Redistributions in binary form must reproduce the above copyright
13612 * notice, this list of conditions and the following disclaimer in the
13613 * documentation and/or other materials provided with the distribution.
13615 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13616 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13618 * 4. Neither the name of the University nor the names of its contributors
13619 * may be used to endorse or promote products derived from this software
13620 * without specific prior written permission.
13622 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13623 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13624 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13625 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13626 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13627 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13628 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13629 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13630 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13631 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF