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 static int execcmd(int, char **);
1253 static int exitcmd(int, char **);
1254 static int exportcmd(int, char **);
1255 static int falsecmd(int, char **);
1257 static int fgcmd(int, char **);
1259 #ifdef CONFIG_ASH_GETOPTS
1260 static int getoptscmd(int, char **);
1262 static int hashcmd(int, char **);
1263 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1264 static int helpcmd(int argc, char **argv);
1267 static int jobscmd(int, char **);
1269 #ifdef CONFIG_ASH_MATH_SUPPORT
1270 static int letcmd(int, char **);
1272 static int localcmd(int, char **);
1273 static int pwdcmd(int, char **);
1274 static int readcmd(int, char **);
1275 static int returncmd(int, char **);
1276 static int setcmd(int, char **);
1277 static int shiftcmd(int, char **);
1278 static int timescmd(int, char **);
1279 static int trapcmd(int, char **);
1280 static int truecmd(int, char **);
1281 static int typecmd(int, char **);
1282 static int umaskcmd(int, char **);
1283 static int unsetcmd(int, char **);
1284 static int waitcmd(int, char **);
1285 static int ulimitcmd(int, char **);
1287 static int killcmd(int, char **);
1290 /* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1292 #ifdef CONFIG_ASH_MAIL
1293 static void chkmail(void);
1294 static void changemail(const char *);
1297 /* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1299 /* values of cmdtype */
1300 #define CMDUNKNOWN -1 /* no entry in table for command */
1301 #define CMDNORMAL 0 /* command is an executable program */
1302 #define CMDFUNCTION 1 /* command is a shell function */
1303 #define CMDBUILTIN 2 /* command is a shell builtin */
1307 int (*builtin)(int, char **);
1308 /* unsigned flags; */
1311 #ifdef CONFIG_ASH_CMDCMD
1313 # ifdef CONFIG_ASH_ALIAS
1314 # define COMMANDCMD (builtincmd + 7)
1315 # define EXECCMD (builtincmd + 10)
1317 # define COMMANDCMD (builtincmd + 6)
1318 # define EXECCMD (builtincmd + 9)
1321 # ifdef CONFIG_ASH_ALIAS
1322 # define COMMANDCMD (builtincmd + 6)
1323 # define EXECCMD (builtincmd + 9)
1325 # define COMMANDCMD (builtincmd + 5)
1326 # define EXECCMD (builtincmd + 8)
1329 #else /* ! CONFIG_ASH_CMDCMD */
1331 # ifdef CONFIG_ASH_ALIAS
1332 # define EXECCMD (builtincmd + 9)
1334 # define EXECCMD (builtincmd + 8)
1337 # ifdef CONFIG_ASH_ALIAS
1338 # define EXECCMD (builtincmd + 8)
1340 # define EXECCMD (builtincmd + 7)
1343 #endif /* CONFIG_ASH_CMDCMD */
1345 #define BUILTIN_NOSPEC "0"
1346 #define BUILTIN_SPECIAL "1"
1347 #define BUILTIN_REGULAR "2"
1348 #define BUILTIN_SPEC_REG "3"
1349 #define BUILTIN_ASSIGN "4"
1350 #define BUILTIN_SPEC_ASSG "5"
1351 #define BUILTIN_REG_ASSG "6"
1352 #define BUILTIN_SPEC_REG_ASSG "7"
1354 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1355 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1356 #define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1358 static const struct builtincmd builtincmd[] = {
1359 { BUILTIN_SPEC_REG ".", dotcmd },
1360 { BUILTIN_SPEC_REG ":", truecmd },
1361 #ifdef CONFIG_ASH_ALIAS
1362 { BUILTIN_REG_ASSG "alias", aliascmd },
1365 { BUILTIN_REGULAR "bg", bgcmd },
1367 { BUILTIN_SPEC_REG "break", breakcmd },
1368 { BUILTIN_REGULAR "cd", cdcmd },
1369 { BUILTIN_NOSPEC "chdir", cdcmd },
1370 #ifdef CONFIG_ASH_CMDCMD
1371 { BUILTIN_REGULAR "command", commandcmd },
1373 { BUILTIN_SPEC_REG "continue", breakcmd },
1374 { BUILTIN_SPEC_REG "eval", evalcmd },
1375 { BUILTIN_SPEC_REG "exec", execcmd },
1376 { BUILTIN_SPEC_REG "exit", exitcmd },
1377 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1378 { BUILTIN_REGULAR "false", falsecmd },
1380 { BUILTIN_REGULAR "fg", fgcmd },
1382 #ifdef CONFIG_ASH_GETOPTS
1383 { BUILTIN_REGULAR "getopts", getoptscmd },
1385 { BUILTIN_NOSPEC "hash", hashcmd },
1386 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1387 { BUILTIN_NOSPEC "help", helpcmd },
1390 { BUILTIN_REGULAR "jobs", jobscmd },
1391 { BUILTIN_REGULAR "kill", killcmd },
1393 #ifdef CONFIG_ASH_MATH_SUPPORT
1394 { BUILTIN_NOSPEC "let", letcmd },
1396 { BUILTIN_ASSIGN "local", localcmd },
1397 { BUILTIN_NOSPEC "pwd", pwdcmd },
1398 { BUILTIN_REGULAR "read", readcmd },
1399 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1400 { BUILTIN_SPEC_REG "return", returncmd },
1401 { BUILTIN_SPEC_REG "set", setcmd },
1402 { BUILTIN_SPEC_REG "shift", shiftcmd },
1403 { BUILTIN_SPEC_REG "times", timescmd },
1404 { BUILTIN_SPEC_REG "trap", trapcmd },
1405 { BUILTIN_REGULAR "true", truecmd },
1406 { BUILTIN_NOSPEC "type", typecmd },
1407 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1408 { BUILTIN_REGULAR "umask", umaskcmd },
1409 #ifdef CONFIG_ASH_ALIAS
1410 { BUILTIN_REGULAR "unalias", unaliascmd },
1412 { BUILTIN_SPEC_REG "unset", unsetcmd },
1413 { BUILTIN_REGULAR "wait", waitcmd },
1416 #define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1424 const struct builtincmd *cmd;
1425 struct funcnode *func;
1430 /* action to find_command() */
1431 #define DO_ERR 0x01 /* prints errors */
1432 #define DO_ABS 0x02 /* checks absolute paths */
1433 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1434 #define DO_ALTPATH 0x08 /* using alternate path */
1435 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1437 static const char *pathopt; /* set by padvance */
1439 static void shellexec(char **, const char *, int)
1440 __attribute__((__noreturn__));
1441 static char *padvance(const char **, const char *);
1442 static void find_command(char *, struct cmdentry *, int, const char *);
1443 static struct builtincmd *find_builtin(const char *);
1444 static void hashcd(void);
1445 static void changepath(const char *);
1446 static void defun(char *, union node *);
1447 static void unsetfunc(const char *);
1449 #ifdef CONFIG_ASH_MATH_SUPPORT_64
1450 typedef int64_t arith_t;
1452 typedef long arith_t;
1455 #ifdef CONFIG_ASH_MATH_SUPPORT
1456 static arith_t dash_arith(const char *);
1457 static arith_t arith(const char *expr, int *perrcode);
1460 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1461 static unsigned long rseed;
1462 static void change_random(const char *);
1463 # ifndef DYNAMIC_VAR
1464 # define DYNAMIC_VAR
1468 /* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1470 static void reset(void);
1472 /* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
1479 #define VEXPORT 0x01 /* variable is exported */
1480 #define VREADONLY 0x02 /* variable cannot be modified */
1481 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1482 #define VTEXTFIXED 0x08 /* text is statically allocated */
1483 #define VSTACK 0x10 /* text is allocated on the stack */
1484 #define VUNSET 0x20 /* the variable is not set */
1485 #define VNOFUNC 0x40 /* don't call the callback function */
1486 #define VNOSET 0x80 /* do not set variable - just readonly test */
1487 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1489 # define VDYNAMIC 0x200 /* dynamic variable */
1495 struct var *next; /* next entry in hash list */
1496 int flags; /* flags are defined above */
1497 const char *text; /* name=value */
1498 void (*func)(const char *); /* function to be called when */
1499 /* the variable gets set/unset */
1503 struct localvar *next; /* next local variable in list */
1504 struct var *vp; /* the variable that was made local */
1505 int flags; /* saved flags */
1506 const char *text; /* saved text */
1510 static struct localvar *localvars;
1516 #ifdef CONFIG_ASH_GETOPTS
1517 static void getoptsreset(const char *);
1520 #ifdef CONFIG_LOCALE_SUPPORT
1522 static void change_lc_all(const char *value);
1523 static void change_lc_ctype(const char *value);
1529 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1531 static const char defifsvar[] = "IFS= \t\n";
1532 #define defifs (defifsvar + 4)
1534 static const char defifs[] = " \t\n";
1538 static struct var varinit[] = {
1540 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1542 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1545 #ifdef CONFIG_ASH_MAIL
1546 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1547 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1550 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1551 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1552 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1553 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1554 #ifdef CONFIG_ASH_GETOPTS
1555 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1557 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1558 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1560 #ifdef CONFIG_LOCALE_SUPPORT
1561 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1562 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
1564 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1565 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
1569 #define vifs varinit[0]
1570 #ifdef CONFIG_ASH_MAIL
1571 #define vmail (&vifs)[1]
1572 #define vmpath (&vmail)[1]
1576 #define vpath (&vmpath)[1]
1577 #define vps1 (&vpath)[1]
1578 #define vps2 (&vps1)[1]
1579 #define vps4 (&vps2)[1]
1580 #define voptind (&vps4)[1]
1581 #ifdef CONFIG_ASH_GETOPTS
1582 #define vrandom (&voptind)[1]
1584 #define vrandom (&vps4)[1]
1586 #define defpath (defpathvar + 5)
1589 * The following macros access the values of the above variables.
1590 * They have to skip over the name. They return the null string
1591 * for unset variables.
1594 #define ifsval() (vifs.text + 4)
1595 #define ifsset() ((vifs.flags & VUNSET) == 0)
1596 #define mailval() (vmail.text + 5)
1597 #define mpathval() (vmpath.text + 9)
1598 #define pathval() (vpath.text + 5)
1599 #define ps1val() (vps1.text + 4)
1600 #define ps2val() (vps2.text + 4)
1601 #define ps4val() (vps4.text + 4)
1602 #define optindval() (voptind.text + 7)
1604 #define mpathset() ((vmpath.flags & VUNSET) == 0)
1606 static void setvar(const char *, const char *, int);
1607 static void setvareq(char *, int);
1608 static void listsetvar(struct strlist *, int);
1609 static char *lookupvar(const char *);
1610 static char *bltinlookup(const char *);
1611 static char **listvars(int, int, char ***);
1612 #define environment() listvars(VEXPORT, VUNSET, 0)
1613 static int showvars(const char *, int, int);
1614 static void poplocalvars(void);
1615 static int unsetvar(const char *);
1616 #ifdef CONFIG_ASH_GETOPTS
1617 static int setvarsafe(const char *, const char *, int);
1619 static int varcmp(const char *, const char *);
1620 static struct var **hashvar(const char *);
1623 static inline int varequal(const char *a, const char *b) {
1624 return !varcmp(a, b);
1628 static int loopnest; /* current loop nesting level */
1631 * The parsefile structure pointed to by the global variable parsefile
1632 * contains information about the current file being read.
1637 struct redirtab *next;
1642 static struct redirtab *redirlist;
1643 static int nullredirs;
1645 extern char **environ;
1647 /* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1650 static void outstr(const char *, FILE *);
1651 static void outcslow(int, FILE *);
1652 static void flushall(void);
1653 static void flusherr(void);
1654 static int out1fmt(const char *, ...)
1655 __attribute__((__format__(__printf__,1,2)));
1656 static int fmtstr(char *, size_t, const char *, ...)
1657 __attribute__((__format__(__printf__,3,4)));
1659 static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1662 static void out1str(const char *p)
1667 static void out2str(const char *p)
1674 * Initialization code.
1678 * This routine initializes the builtin variables.
1689 * PS1 depends on uid
1691 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1692 vps1.text = "PS1=\\w \\$ ";
1695 vps1.text = "PS1=# ";
1698 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1700 vpp = hashvar(vp->text);
1703 } while (++vp < end);
1712 basepf.nextc = basepf.buf = basebuf;
1717 signal(SIGCHLD, SIG_DFL);
1726 for (envp = environ ; *envp ; envp++) {
1727 if (strchr(*envp, '=')) {
1728 setvareq(*envp, VEXPORT|VTEXTFIXED);
1732 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1733 setvar("PPID", ppid, 0);
1738 /* PEOF (the end of file marker) */
1741 * The input line number. Input.c just defines this variable, and saves
1742 * and restores it when files are pushed and popped. The user of this
1743 * package must set its value.
1746 static int pgetc(void);
1747 static int pgetc2(void);
1748 static int preadbuffer(void);
1749 static void pungetc(void);
1750 static void pushstring(char *, void *);
1751 static void popstring(void);
1752 static void setinputfile(const char *, int);
1753 static void setinputfd(int, int);
1754 static void setinputstring(char *);
1755 static void popfile(void);
1756 static void popallfiles(void);
1757 static void closescript(void);
1760 /* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1763 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1766 #define FORK_NOJOB 2
1768 /* mode flags for showjob(s) */
1769 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1770 #define SHOW_PID 0x04 /* include process pid */
1771 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1775 * A job structure contains information about a job. A job is either a
1776 * single process or a set of processes contained in a pipeline. In the
1777 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1782 pid_t pid; /* process id */
1783 int status; /* last process status from wait() */
1784 char *cmd; /* text of command being run */
1788 struct procstat ps0; /* status of process */
1789 struct procstat *ps; /* status or processes when more than one */
1791 int stopstatus; /* status of a stopped job */
1794 nprocs: 16, /* number of processes */
1796 #define JOBRUNNING 0 /* at least one proc running */
1797 #define JOBSTOPPED 1 /* all procs are stopped */
1798 #define JOBDONE 2 /* all procs are completed */
1800 sigint: 1, /* job was killed by SIGINT */
1801 jobctl: 1, /* job running under job control */
1803 waited: 1, /* true if this entry has been waited for */
1804 used: 1, /* true if this entry is in used */
1805 changed: 1; /* true if status has changed */
1806 struct job *prev_job; /* previous job */
1809 static pid_t backgndpid; /* pid of last background process */
1810 static int job_warning; /* user was warned about stopped jobs */
1812 static int jobctl; /* true if doing job control */
1815 static struct job *makejob(union node *, int);
1816 static int forkshell(struct job *, union node *, int);
1817 static int waitforjob(struct job *);
1818 static int stoppedjobs(void);
1821 #define setjobctl(on) /* do nothing */
1823 static void setjobctl(int);
1824 static void showjobs(FILE *, int);
1827 /* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1830 /* pid of main shell */
1832 /* true if we aren't a child of the main shell */
1833 static int rootshell;
1835 static void readcmdfile(char *);
1836 static void cmdloop(int);
1838 /* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1842 struct stack_block *stackp;
1845 struct stackmark *marknext;
1848 /* minimum size of a block */
1849 #define MINSIZE SHELL_ALIGN(504)
1851 struct stack_block {
1852 struct stack_block *prev;
1853 char space[MINSIZE];
1856 static struct stack_block stackbase;
1857 static struct stack_block *stackp = &stackbase;
1858 static struct stackmark *markp;
1859 static char *stacknxt = stackbase.space;
1860 static size_t stacknleft = MINSIZE;
1861 static char *sstrend = stackbase.space + MINSIZE;
1862 static int herefd = -1;
1865 static pointer ckmalloc(size_t);
1866 static pointer ckrealloc(pointer, size_t);
1867 static char *savestr(const char *);
1868 static pointer stalloc(size_t);
1869 static void stunalloc(pointer);
1870 static void setstackmark(struct stackmark *);
1871 static void popstackmark(struct stackmark *);
1872 static void growstackblock(void);
1873 static void *growstackstr(void);
1874 static char *makestrspace(size_t, char *);
1875 static char *stnputs(const char *, size_t, char *);
1876 static char *stputs(const char *, char *);
1879 static inline char *_STPUTC(char c, char *p) {
1886 #define stackblock() ((void *)stacknxt)
1887 #define stackblocksize() stacknleft
1888 #define STARTSTACKSTR(p) ((p) = stackblock())
1889 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1890 #define CHECKSTRSPACE(n, p) \
1894 size_t m = sstrend - q; \
1896 (p) = makestrspace(l, q); \
1899 #define USTPUTC(c, p) (*p++ = (c))
1900 #define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1901 #define STUNPUTC(p) (--p)
1902 #define STTOPC(p) p[-1]
1903 #define STADJUST(amount, p) (p += (amount))
1905 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1906 #define ungrabstackstr(s, p) stunalloc((s))
1907 #define stackstrend() ((void *)sstrend)
1909 #define ckfree(p) free((pointer)(p))
1911 /* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1914 #define DOLATSTRLEN 4
1916 static char *prefix(const char *, const char *);
1917 static int number(const char *);
1918 static int is_number(const char *);
1919 static char *single_quote(const char *);
1920 static char *sstrdup(const char *);
1922 #define equal(s1, s2) (strcmp(s1, s2) == 0)
1923 #define scopy(s1, s2) ((void)strcpy(s2, s1))
1925 /* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1928 int nparam; /* # of positional parameters (without $0) */
1929 unsigned char malloc; /* if parameter list dynamically allocated */
1930 char **p; /* parameter list */
1931 #ifdef CONFIG_ASH_GETOPTS
1932 int optind; /* next parameter to be processed by getopts */
1933 int optoff; /* used by getopts */
1938 #define eflag optlist[0]
1939 #define fflag optlist[1]
1940 #define Iflag optlist[2]
1941 #define iflag optlist[3]
1942 #define mflag optlist[4]
1943 #define nflag optlist[5]
1944 #define sflag optlist[6]
1945 #define xflag optlist[7]
1946 #define vflag optlist[8]
1947 #define Cflag optlist[9]
1948 #define aflag optlist[10]
1949 #define bflag optlist[11]
1950 #define uflag optlist[12]
1951 #define qflag optlist[13]
1954 #define nolog optlist[14]
1955 #define debug optlist[15]
1961 /* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1964 static const char *const optletters_optnames[NOPTS] = {
1985 #define optletters(n) optletters_optnames[(n)][0]
1986 #define optnames(n) (&optletters_optnames[(n)][1])
1989 static char optlist[NOPTS];
1992 static char *arg0; /* value of $0 */
1993 static struct shparam shellparam; /* $@ current positional parameters */
1994 static char **argptr; /* argument list for builtin commands */
1995 static char *optionarg; /* set by nextopt (like getopt) */
1996 static char *optptr; /* used by nextopt */
1998 static char *minusc; /* argument to -c option */
2001 static void procargs(int, char **);
2002 static void optschanged(void);
2003 static void setparam(char **);
2004 static void freeparam(volatile struct shparam *);
2005 static int shiftcmd(int, char **);
2006 static int setcmd(int, char **);
2007 static int nextopt(const char *);
2009 /* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
2011 /* flags passed to redirect */
2012 #define REDIR_PUSH 01 /* save previous values of file descriptors */
2013 #define REDIR_SAVEFD2 03 /* set preverrout */
2016 static void redirect(union node *, int);
2017 static void popredir(int);
2018 static void clearredir(int);
2019 static int copyfd(int, int);
2020 static int redirectsafe(union node *, int);
2022 /* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2026 static void showtree(union node *);
2027 static void trace(const char *, ...);
2028 static void tracev(const char *, va_list);
2029 static void trargs(char **);
2030 static void trputc(int);
2031 static void trputs(const char *);
2032 static void opentrace(void);
2035 /* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2038 /* trap handler commands */
2039 static char *trap[NSIG];
2040 /* current value of signal */
2041 static char sigmode[NSIG - 1];
2042 /* indicates specified signal received */
2043 static char gotsig[NSIG - 1];
2045 static void clear_traps(void);
2046 static void setsignal(int);
2047 static void ignoresig(int);
2048 static void onsig(int);
2049 static void dotrap(void);
2050 static void setinteractive(int);
2051 static void exitshell(void) __attribute__((__noreturn__));
2052 static int decode_signal(const char *, int);
2055 * This routine is called when an error or an interrupt occurs in an
2056 * interactive shell and control is returned to the main command loop.
2071 parselleft = parsenleft = 0; /* clear input buffer */
2075 /* from parser.c: */
2088 #ifdef CONFIG_ASH_ALIAS
2089 static struct alias *atab[ATABSIZE];
2091 static void setalias(const char *, const char *);
2092 static struct alias *freealias(struct alias *);
2093 static struct alias **__lookupalias(const char *);
2096 setalias(const char *name, const char *val)
2098 struct alias *ap, **app;
2100 app = __lookupalias(name);
2104 if (!(ap->flag & ALIASINUSE)) {
2107 ap->val = savestr(val);
2108 ap->flag &= ~ALIASDEAD;
2111 ap = ckmalloc(sizeof (struct alias));
2112 ap->name = savestr(name);
2113 ap->val = savestr(val);
2122 unalias(const char *name)
2126 app = __lookupalias(name);
2130 *app = freealias(*app);
2141 struct alias *ap, **app;
2145 for (i = 0; i < ATABSIZE; i++) {
2147 for (ap = *app; ap; ap = *app) {
2148 *app = freealias(*app);
2157 static struct alias *
2158 lookupalias(const char *name, int check)
2160 struct alias *ap = *__lookupalias(name);
2162 if (check && ap && (ap->flag & ALIASINUSE))
2168 * TODO - sort output
2171 aliascmd(int argc, char **argv)
2180 for (i = 0; i < ATABSIZE; i++)
2181 for (ap = atab[i]; ap; ap = ap->next) {
2186 while ((n = *++argv) != NULL) {
2187 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
2188 if ((ap = *__lookupalias(n)) == NULL) {
2189 fprintf(stderr, "%s: %s not found\n", "alias", n);
2203 unaliascmd(int argc, char **argv)
2207 while ((i = nextopt("a")) != '\0') {
2213 for (i = 0; *argptr; argptr++) {
2214 if (unalias(*argptr)) {
2215 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
2223 static struct alias *
2224 freealias(struct alias *ap) {
2227 if (ap->flag & ALIASINUSE) {
2228 ap->flag |= ALIASDEAD;
2240 printalias(const struct alias *ap) {
2241 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2244 static struct alias **
2245 __lookupalias(const char *name) {
2246 unsigned int hashval;
2253 ch = (unsigned char)*p;
2257 ch = (unsigned char)*++p;
2259 app = &atab[hashval % ATABSIZE];
2261 for (; *app; app = &(*app)->next) {
2262 if (equal(name, (*app)->name)) {
2269 #endif /* CONFIG_ASH_ALIAS */
2272 /* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2275 * The cd and pwd commands.
2278 #define CD_PHYSICAL 1
2281 static int docd(const char *, int);
2282 static int cdopt(void);
2284 static char *curdir = nullstr; /* current working directory */
2285 static char *physdir = nullstr; /* physical working directory */
2294 while ((i = nextopt("LP"))) {
2296 flags ^= CD_PHYSICAL;
2305 cdcmd(int argc, char **argv)
2317 dest = bltinlookup(homestr);
2318 else if (dest[0] == '-' && dest[1] == '\0') {
2319 dest = bltinlookup("OLDPWD");
2320 if ( !dest ) goto out;
2343 if (!(path = bltinlookup("CDPATH"))) {
2351 p = padvance(&path, dest);
2352 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2356 if (!docd(p, flags))
2361 error("can't cd to %s", dest);
2364 if (flags & CD_PRINT)
2365 out1fmt(snlfmt, curdir);
2371 * Update curdir (the name of the current directory) in response to a
2375 static inline const char *
2376 updatepwd(const char *dir)
2383 cdcomppath = sstrdup(dir);
2386 if (curdir == nullstr)
2388 new = stputs(curdir, new);
2390 new = makestrspace(strlen(dir) + 2, new);
2391 lim = stackblock() + 1;
2395 if (new > lim && *lim == '/')
2400 if (dir[1] == '/' && dir[2] != '/') {
2406 p = strtok(cdcomppath, "/");
2410 if (p[1] == '.' && p[2] == '\0') {
2417 } else if (p[1] == '\0')
2421 new = stputs(p, new);
2429 return stackblock();
2433 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2434 * know that the current directory has changed.
2438 docd(const char *dest, int flags)
2440 const char *dir = 0;
2443 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2446 if (!(flags & CD_PHYSICAL)) {
2447 dir = updatepwd(dest);
2462 * Find out what the current directory is. If we already know the current
2463 * directory, this routine returns immediately.
2465 static inline char *
2468 char *dir = getcwd(0, 0);
2469 return dir ? dir : nullstr;
2473 pwdcmd(int argc, char **argv)
2476 const char *dir = curdir;
2480 if (physdir == nullstr)
2484 out1fmt(snlfmt, dir);
2489 setpwd(const char *val, int setold)
2493 oldcur = dir = curdir;
2496 setvar("OLDPWD", oldcur, VEXPORT);
2499 if (physdir != nullstr) {
2500 if (physdir != oldcur)
2504 if (oldcur == val || !val) {
2511 if (oldcur != dir && oldcur != nullstr) {
2516 setvar("PWD", dir, VEXPORT);
2519 /* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2522 * Errors and exceptions.
2526 * Code to handle exceptions in C.
2531 static void exverror(int, const char *, va_list)
2532 __attribute__((__noreturn__));
2535 * Called to raise an exception. Since C doesn't include exceptions, we
2536 * just do a longjmp to the exception handler. The type of exception is
2537 * stored in the global variable "exception".
2544 if (handler == NULL)
2550 longjmp(handler->loc, 1);
2555 * Called from trap.c when a SIGINT is received. (If the user specifies
2556 * that SIGINT is to be trapped or ignored using the trap builtin, then
2557 * this routine is not called.) Suppressint is nonzero when interrupts
2558 * are held using the INTOFF macro. (The test for iflag is just
2559 * defensive programming.)
2569 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2570 if (!(rootshell && iflag)) {
2571 signal(SIGINT, SIG_DFL);
2581 exvwarning(const char *msg, va_list ap)
2594 fprintf(errs, fmt, name, startlinno);
2595 vfprintf(errs, msg, ap);
2596 outcslow('\n', errs);
2600 * Exverror is called to raise the error exception. If the second argument
2601 * is not NULL then error prints an error message using printf style
2602 * formatting. It then raises the error exception.
2605 exverror(int cond, const char *msg, va_list ap)
2609 TRACE(("exverror(%d, \"", cond));
2611 TRACE(("\") pid=%d\n", getpid()));
2613 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2616 exvwarning(msg, ap);
2625 error(const char *msg, ...)
2630 exverror(EXERROR, msg, ap);
2637 exerror(int cond, const char *msg, ...)
2642 exverror(cond, msg, ap);
2648 * error/warning routines for external builtins
2652 sh_warnx(const char *fmt, ...)
2657 exvwarning(fmt, ap);
2663 * Return a string describing an error. The returned string may be a
2664 * pointer to a static buffer that will be overwritten on the next call.
2665 * Action describes the operation that got the error.
2669 errmsg(int e, const char *em)
2671 if(e == ENOENT || e == ENOTDIR) {
2679 /* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2682 * Evaluate a command.
2685 /* flags in argument to evaltree */
2686 #define EV_EXIT 01 /* exit after evaluating tree */
2687 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2688 #define EV_BACKCMD 04 /* command executing within back quotes */
2691 static void evalloop(union node *, int);
2692 static void evalfor(union node *, int);
2693 static void evalcase(union node *, int);
2694 static void evalsubshell(union node *, int);
2695 static void expredir(union node *);
2696 static void evalpipe(union node *, int);
2697 static void evalcommand(union node *, int);
2698 static int evalbltin(const struct builtincmd *, int, char **);
2699 static int evalfun(struct funcnode *, int, char **, int);
2700 static void prehash(union node *);
2701 static int bltincmd(int, char **);
2704 static const struct builtincmd bltin = {
2710 * Called to reset things after an exception.
2718 evalcmd(int argc, char **argv)
2727 STARTSTACKSTR(concat);
2730 concat = stputs(p, concat);
2731 if ((p = *ap++) == NULL)
2733 STPUTC(' ', concat);
2735 STPUTC('\0', concat);
2736 p = grabstackstr(concat);
2745 * Execute a command or commands contained in a string.
2752 struct stackmark smark;
2754 setstackmark(&smark);
2757 while ((n = parsecmd(0)) != NEOF) {
2759 popstackmark(&smark);
2764 popstackmark(&smark);
2770 * Evaluate a parse tree. The value is left in the global variable
2775 evaltree(union node *n, int flags)
2778 void (*evalfn)(union node *, int);
2782 TRACE(("evaltree(NULL) called\n"));
2785 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2786 getpid(), n, n->type, flags));
2790 out1fmt("Node type = %d\n", n->type);
2795 evaltree(n->nnot.com, EV_TESTED);
2796 status = !exitstatus;
2799 expredir(n->nredir.redirect);
2800 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2802 evaltree(n->nredir.n, flags & EV_TESTED);
2803 status = exitstatus;
2808 evalfn = evalcommand;
2810 if (eflag && !(flags & EV_TESTED))
2822 evalfn = evalsubshell;
2834 #error NAND + 1 != NOR
2836 #if NOR + 1 != NSEMI
2837 #error NOR + 1 != NSEMI
2839 isor = n->type - NAND;
2842 (flags | ((isor >> 1) - 1)) & EV_TESTED
2844 if (!exitstatus == isor)
2856 evaltree(n->nif.test, EV_TESTED);
2859 if (exitstatus == 0) {
2862 } else if (n->nif.elsepart) {
2863 n = n->nif.elsepart;
2868 defun(n->narg.text, n->narg.next);
2872 exitstatus = status;
2878 if (flags & EV_EXIT || checkexit & exitstatus)
2883 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2886 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2890 evalloop(union node *n, int flags)
2900 evaltree(n->nbinary.ch1, EV_TESTED);
2902 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2906 if (evalskip == SKIPBREAK && --skipcount <= 0)
2911 if (n->type != NWHILE)
2915 evaltree(n->nbinary.ch2, flags);
2916 status = exitstatus;
2921 exitstatus = status;
2927 evalfor(union node *n, int flags)
2929 struct arglist arglist;
2932 struct stackmark smark;
2934 setstackmark(&smark);
2935 arglist.lastp = &arglist.list;
2936 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2937 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2942 *arglist.lastp = NULL;
2947 for (sp = arglist.list ; sp ; sp = sp->next) {
2948 setvar(n->nfor.var, sp->text, 0);
2949 evaltree(n->nfor.body, flags);
2951 if (evalskip == SKIPCONT && --skipcount <= 0) {
2955 if (evalskip == SKIPBREAK && --skipcount <= 0)
2962 popstackmark(&smark);
2968 evalcase(union node *n, int flags)
2972 struct arglist arglist;
2973 struct stackmark smark;
2975 setstackmark(&smark);
2976 arglist.lastp = &arglist.list;
2977 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2979 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2980 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2981 if (casematch(patp, arglist.list->text)) {
2982 if (evalskip == 0) {
2983 evaltree(cp->nclist.body, flags);
2990 popstackmark(&smark);
2996 * Kick off a subshell to evaluate a tree.
3000 evalsubshell(union node *n, int flags)
3003 int backgnd = (n->type == NBACKGND);
3006 expredir(n->nredir.redirect);
3007 if (!backgnd && flags & EV_EXIT && !trap[0])
3011 if (forkshell(jp, n, backgnd) == 0) {
3015 flags &=~ EV_TESTED;
3017 redirect(n->nredir.redirect, 0);
3018 evaltreenr(n->nredir.n, flags);
3023 status = waitforjob(jp);
3024 exitstatus = status;
3031 * Compute the names of the files in a redirection list.
3035 expredir(union node *n)
3039 for (redir = n ; redir ; redir = redir->nfile.next) {
3041 fn.lastp = &fn.list;
3042 switch (redir->type) {
3048 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3049 redir->nfile.expfname = fn.list->text;
3053 if (redir->ndup.vname) {
3054 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3055 fixredir(redir, fn.list->text, 1);
3065 * Evaluate a pipeline. All the processes in the pipeline are children
3066 * of the process creating the pipeline. (This differs from some versions
3067 * of the shell, which make the last process in a pipeline the parent
3072 evalpipe(union node *n, int flags)
3075 struct nodelist *lp;
3080 TRACE(("evalpipe(0x%lx) called\n", (long)n));
3082 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3086 jp = makejob(n, pipelen);
3088 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3092 if (pipe(pip) < 0) {
3094 error("Pipe call failed");
3097 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3110 evaltreenr(lp->n, flags);
3118 if (n->npipe.backgnd == 0) {
3119 exitstatus = waitforjob(jp);
3120 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
3128 * Execute a command inside back quotes. If it's a builtin command, we
3129 * want to save its output in a block obtained from malloc. Otherwise
3130 * we fork off a subprocess and get the output of the command via a pipe.
3131 * Should be called with interrupts off.
3135 evalbackcmd(union node *n, struct backcmd *result)
3147 saveherefd = herefd;
3155 error("Pipe call failed");
3157 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3166 evaltreenr(n, EV_EXIT);
3170 result->fd = pip[0];
3173 herefd = saveherefd;
3175 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3176 result->fd, result->buf, result->nleft, result->jp));
3179 #ifdef CONFIG_ASH_CMDCMD
3180 static inline char **
3181 parse_command_args(char **argv, const char **path)
3193 if (c == '-' && !*cp) {
3203 /* run 'typecmd' for other options */
3206 } while ((c = *cp++));
3213 isassignment(const char *p)
3215 const char *q = endofname(p);
3222 * Execute a simple command.
3226 evalcommand(union node *cmd, int flags)
3228 struct stackmark smark;
3230 struct arglist arglist;
3231 struct arglist varlist;
3234 const struct strlist *sp;
3235 struct cmdentry cmdentry;
3243 struct builtincmd *bcmd;
3244 int pseudovarflag = 0;
3246 /* First expand the arguments. */
3247 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3248 setstackmark(&smark);
3249 back_exitstatus = 0;
3251 cmdentry.cmdtype = CMDBUILTIN;
3252 cmdentry.u.cmd = &bltin;
3253 varlist.lastp = &varlist.list;
3254 *varlist.lastp = NULL;
3255 arglist.lastp = &arglist.list;
3256 *arglist.lastp = NULL;
3261 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3262 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3265 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3266 struct strlist **spp;
3268 spp = arglist.lastp;
3269 if (pseudovarflag && isassignment(argp->narg.text))
3270 expandarg(argp, &arglist, EXP_VARTILDE);
3272 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3274 for (sp = *spp; sp; sp = sp->next)
3278 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3279 for (sp = arglist.list ; sp ; sp = sp->next) {
3280 TRACE(("evalcommand arg: %s\n", sp->text));
3281 *nargv++ = sp->text;
3286 if (iflag && funcnest == 0 && argc > 0)
3287 lastarg = nargv[-1];
3290 expredir(cmd->ncmd.redirect);
3291 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
3294 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3295 struct strlist **spp;
3298 spp = varlist.lastp;
3299 expandarg(argp, &varlist, EXP_VARTILDE);
3302 * Modify the command lookup path, if a PATH= assignment
3306 if (varequal(p, path))
3310 /* Print the command if xflag is set. */
3313 const char *p = " %s";
3316 dprintf(preverrout_fd, p, ps4val());
3319 for(n = 0; n < 2; n++) {
3321 dprintf(preverrout_fd, p, sp->text);
3329 bb_full_write(preverrout_fd, "\n", 1);
3335 /* Now locate the command. */
3337 const char *oldpath;
3338 int cmd_flag = DO_ERR;
3343 find_command(argv[0], &cmdentry, cmd_flag, path);
3344 if (cmdentry.cmdtype == CMDUNKNOWN) {
3350 /* implement bltin and command here */
3351 if (cmdentry.cmdtype != CMDBUILTIN)
3354 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3355 if (cmdentry.u.cmd == EXECCMD)
3357 #ifdef CONFIG_ASH_CMDCMD
3358 if (cmdentry.u.cmd == COMMANDCMD) {
3361 nargv = parse_command_args(argv, &path);
3364 argc -= nargv - argv;
3366 cmd_flag |= DO_NOFUNC;
3374 /* We have a redirection error. */
3378 exitstatus = status;
3382 /* Execute the command. */
3383 switch (cmdentry.cmdtype) {
3385 /* Fork off a child process if necessary. */
3386 if (!(flags & EV_EXIT) || trap[0]) {
3388 jp = makejob(cmd, 1);
3389 if (forkshell(jp, cmd, FORK_FG) != 0) {
3390 exitstatus = waitforjob(jp);
3396 listsetvar(varlist.list, VEXPORT|VSTACK);
3397 shellexec(argv, path, cmdentry.u.index);
3401 cmdenviron = varlist.list;
3403 struct strlist *list = cmdenviron;
3405 if (spclbltin > 0 || argc == 0) {
3407 if (cmd_is_exec && argc > 1)
3410 listsetvar(list, i);
3412 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3427 exit_status = j + 128;
3428 exitstatus = exit_status;
3430 if (i == EXINT || spclbltin > 0) {
3432 longjmp(handler->loc, 1);
3439 listsetvar(varlist.list, 0);
3440 if (evalfun(cmdentry.u.func, argc, argv, flags))
3446 popredir(cmd_is_exec);
3448 /* dsl: I think this is intended to be used to support
3449 * '_' in 'vi' command mode during line editing...
3450 * However I implemented that within libedit itself.
3452 setvar("_", lastarg, 0);
3453 popstackmark(&smark);
3457 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3458 char *volatile savecmdname;
3459 struct jmploc *volatile savehandler;
3460 struct jmploc jmploc;
3463 savecmdname = commandname;
3464 if ((i = setjmp(jmploc.loc)))
3466 savehandler = handler;
3468 commandname = argv[0];
3470 optptr = NULL; /* initialize nextopt */
3471 exitstatus = (*cmd->builtin)(argc, argv);
3474 exitstatus |= ferror(stdout);
3475 commandname = savecmdname;
3477 handler = savehandler;
3483 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3485 volatile struct shparam saveparam;
3486 struct localvar *volatile savelocalvars;
3487 struct jmploc *volatile savehandler;
3488 struct jmploc jmploc;
3491 saveparam = shellparam;
3492 savelocalvars = localvars;
3493 if ((e = setjmp(jmploc.loc))) {
3497 savehandler = handler;
3500 shellparam.malloc = 0;
3503 shellparam.nparam = argc - 1;
3504 shellparam.p = argv + 1;
3505 #ifdef CONFIG_ASH_GETOPTS
3506 shellparam.optind = 1;
3507 shellparam.optoff = -1;
3510 evaltree(&func->n, flags & EV_TESTED);
3516 localvars = savelocalvars;
3517 freeparam(&shellparam);
3518 shellparam = saveparam;
3519 handler = savehandler;
3521 if (evalskip == SKIPFUNC) {
3530 goodname(const char *p)
3532 return !*endofname(p);
3536 * Search for a command. This is called before we fork so that the
3537 * location of the command will be available in the parent as well as
3538 * the child. The check for "goodname" is an overly conservative
3539 * check that the name will not be subject to expansion.
3543 prehash(union node *n)
3545 struct cmdentry entry;
3547 if (n->type == NCMD && n->ncmd.args)
3548 if (goodname(n->ncmd.args->narg.text))
3549 find_command(n->ncmd.args->narg.text, &entry, 0,
3556 * Builtin commands. Builtin commands whose functions are closely
3557 * tied to evaluation are implemented here.
3565 bltincmd(int argc, char **argv)
3568 * Preserve exitstatus of a previous possible redirection
3571 return back_exitstatus;
3576 * Handle break and continue commands. Break, continue, and return are
3577 * all handled by setting the evalskip flag. The evaluation routines
3578 * above all check this flag, and if it is set they start skipping
3579 * commands rather than executing them. The variable skipcount is
3580 * the number of loops to break/continue, or the number of function
3581 * levels to return. (The latter is always 1.) It should probably
3582 * be an error to break out of more loops than exist, but it isn't
3583 * in the standard shell so we don't make it one here.
3587 breakcmd(int argc, char **argv)
3589 int n = argc > 1 ? number(argv[1]) : 1;
3592 error(illnum, argv[1]);
3596 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3604 * The return command.
3608 returncmd(int argc, char **argv)
3610 int ret = argc > 1 ? number(argv[1]) : exitstatus;
3613 evalskip = SKIPFUNC;
3618 /* Do what ksh does; skip the rest of the file */
3619 evalskip = SKIPFILE;
3627 falsecmd(int argc, char **argv)
3634 truecmd(int argc, char **argv)
3641 execcmd(int argc, char **argv)
3644 iflag = 0; /* exit on error */
3647 shellexec(argv + 1, pathval(), 0);
3653 /* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3656 * When commands are first encountered, they are entered in a hash table.
3657 * This ensures that a full path search will not have to be done for them
3658 * on each invocation.
3660 * We should investigate converting to a linear search, even though that
3661 * would make the command name "hash" a misnomer.
3664 #define CMDTABLESIZE 31 /* should be prime */
3665 #define ARB 1 /* actual size determined at run time */
3670 struct tblentry *next; /* next entry in hash chain */
3671 union param param; /* definition of builtin function */
3672 short cmdtype; /* index identifying command */
3673 char rehash; /* if set, cd done since entry created */
3674 char cmdname[ARB]; /* name of command */
3678 static struct tblentry *cmdtable[CMDTABLESIZE];
3679 static int builtinloc = -1; /* index in path of %builtin, or -1 */
3682 static void tryexec(char *, char **, char **);
3683 static void clearcmdentry(int);
3684 static struct tblentry *cmdlookup(const char *, int);
3685 static void delete_cmd_entry(void);
3689 * Exec a program. Never returns. If you change this routine, you may
3690 * have to change the find_command routine as well.
3694 shellexec(char **argv, const char *path, int idx)
3701 envp = environment();
3702 if (strchr(argv[0], '/') != NULL
3703 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3704 || find_applet_by_name(argv[0])
3707 tryexec(argv[0], argv, envp);
3711 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3712 if (--idx < 0 && pathopt == NULL) {
3713 tryexec(cmdname, argv, envp);
3714 if (errno != ENOENT && errno != ENOTDIR)
3721 /* Map to POSIX errors */
3733 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3734 argv[0], e, suppressint ));
3735 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3741 tryexec(char *cmd, char **argv, char **envp)
3744 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3745 if(find_applet_by_name(cmd) != NULL) {
3746 /* re-exec ourselves with the new arguments */
3747 execve("/proc/self/exe",argv,envp);
3748 /* If proc isn't mounted, try hardcoded path to busybox binary*/
3749 execve("/bin/busybox",argv,envp);
3750 /* If they called chroot or otherwise made the binary no longer
3751 * executable, fall through */
3758 execve(cmd, argv, envp);
3759 } while (errno == EINTR);
3761 execve(cmd, argv, envp);
3765 } else if (errno == ENOEXEC) {
3769 for (ap = argv; *ap; ap++)
3771 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3773 *ap = cmd = (char *)DEFAULT_SHELL;
3776 while ((*ap++ = *argv++))
3786 * Do a path search. The variable path (passed by reference) should be
3787 * set to the start of the path before the first call; padvance will update
3788 * this value as it proceeds. Successive calls to padvance will return
3789 * the possible path expansions in sequence. If an option (indicated by
3790 * a percent sign) appears in the path entry then the global variable
3791 * pathopt will be set to point to it; otherwise pathopt will be set to
3796 padvance(const char **path, const char *name)
3806 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3807 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3808 while (stackblocksize() < len)
3812 memcpy(q, start, p - start);
3820 while (*p && *p != ':') p++;
3826 return stalloc(len);
3830 /*** Command hashing code ***/
3833 printentry(struct tblentry *cmdp)
3839 idx = cmdp->param.index;
3842 name = padvance(&path, cmdp->cmdname);
3844 } while (--idx >= 0);
3845 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3850 hashcmd(int argc, char **argv)
3852 struct tblentry **pp;
3853 struct tblentry *cmdp;
3855 struct cmdentry entry;
3858 while ((c = nextopt("r")) != '\0') {
3862 if (*argptr == NULL) {
3863 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3864 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3865 if (cmdp->cmdtype == CMDNORMAL)
3872 while ((name = *argptr) != NULL) {
3873 if ((cmdp = cmdlookup(name, 0)) != NULL
3874 && (cmdp->cmdtype == CMDNORMAL
3875 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3877 find_command(name, &entry, DO_ERR, pathval());
3878 if (entry.cmdtype == CMDUNKNOWN)
3887 * Resolve a command name. If you change this routine, you may have to
3888 * change the shellexec routine as well.
3892 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3894 struct tblentry *cmdp;
3901 struct builtincmd *bcmd;
3903 /* If name contains a slash, don't use PATH or hash table */
3904 if (strchr(name, '/') != NULL) {
3905 entry->u.index = -1;
3907 while (stat(name, &statb) < 0) {
3912 entry->cmdtype = CMDUNKNOWN;
3916 entry->cmdtype = CMDNORMAL;
3920 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3921 if (find_applet_by_name(name)) {
3922 entry->cmdtype = CMDNORMAL;
3923 entry->u.index = -1;
3928 updatetbl = (path == pathval());
3931 if (strstr(path, "%builtin") != NULL)
3935 /* If name is in the table, check answer will be ok */
3936 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3939 switch (cmdp->cmdtype) {
3957 } else if (cmdp->rehash == 0)
3958 /* if not invalidated by cd, we're done */
3962 /* If %builtin not in path, check for builtin next */
3963 bcmd = find_builtin(name);
3964 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3965 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3967 goto builtin_success;
3969 /* We have to search path. */
3970 prev = -1; /* where to start */
3971 if (cmdp && cmdp->rehash) { /* doing a rehash */
3972 if (cmdp->cmdtype == CMDBUILTIN)
3975 prev = cmdp->param.index;
3981 while ((fullname = padvance(&path, name)) != NULL) {
3982 stunalloc(fullname);
3985 if (prefix(pathopt, "builtin")) {
3987 goto builtin_success;
3989 } else if (!(act & DO_NOFUNC) &&
3990 prefix(pathopt, "func")) {
3993 /* ignore unimplemented options */
3997 /* if rehash, don't redo absolute path names */
3998 if (fullname[0] == '/' && idx <= prev) {
4001 TRACE(("searchexec \"%s\": no change\n", name));
4004 while (stat(fullname, &statb) < 0) {
4009 if (errno != ENOENT && errno != ENOTDIR)
4013 e = EACCES; /* if we fail, this will be the error */
4014 if (!S_ISREG(statb.st_mode))
4016 if (pathopt) { /* this is a %func directory */
4017 stalloc(strlen(fullname) + 1);
4018 readcmdfile(fullname);
4019 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4020 cmdp->cmdtype != CMDFUNCTION)
4021 error("%s not defined in %s", name, fullname);
4022 stunalloc(fullname);
4025 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4027 entry->cmdtype = CMDNORMAL;
4028 entry->u.index = idx;
4032 cmdp = cmdlookup(name, 1);
4033 cmdp->cmdtype = CMDNORMAL;
4034 cmdp->param.index = idx;
4039 /* We failed. If there was an entry for this command, delete it */
4040 if (cmdp && updatetbl)
4043 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4044 entry->cmdtype = CMDUNKNOWN;
4049 entry->cmdtype = CMDBUILTIN;
4050 entry->u.cmd = bcmd;
4054 cmdp = cmdlookup(name, 1);
4055 cmdp->cmdtype = CMDBUILTIN;
4056 cmdp->param.cmd = bcmd;
4060 entry->cmdtype = cmdp->cmdtype;
4061 entry->u = cmdp->param;
4066 * Wrapper around strcmp for qsort/bsearch/...
4068 static int pstrcmp(const void *a, const void *b)
4070 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4074 * Search the table of builtin commands.
4077 static struct builtincmd *
4078 find_builtin(const char *name)
4080 struct builtincmd *bp;
4083 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4092 * Called when a cd is done. Marks all commands so the next time they
4093 * are executed they will be rehashed.
4099 struct tblentry **pp;
4100 struct tblentry *cmdp;
4102 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4103 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4104 if (cmdp->cmdtype == CMDNORMAL || (
4105 cmdp->cmdtype == CMDBUILTIN &&
4106 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4117 * Fix command hash table when PATH changed.
4118 * Called before PATH is changed. The argument is the new value of PATH;
4119 * pathval() still returns the old value at this point.
4120 * Called with interrupts off.
4124 changepath(const char *newval)
4126 const char *old, *new;
4133 firstchange = 9999; /* assume no change */
4139 if ((*old == '\0' && *new == ':')
4140 || (*old == ':' && *new == '\0'))
4142 old = new; /* ignore subsequent differences */
4146 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4153 if (builtinloc < 0 && idx_bltin >= 0)
4154 builtinloc = idx_bltin; /* zap builtins */
4155 if (builtinloc >= 0 && idx_bltin < 0)
4157 clearcmdentry(firstchange);
4158 builtinloc = idx_bltin;
4163 * Clear out command entries. The argument specifies the first entry in
4164 * PATH which has changed.
4168 clearcmdentry(int firstchange)
4170 struct tblentry **tblp;
4171 struct tblentry **pp;
4172 struct tblentry *cmdp;
4175 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4177 while ((cmdp = *pp) != NULL) {
4178 if ((cmdp->cmdtype == CMDNORMAL &&
4179 cmdp->param.index >= firstchange)
4180 || (cmdp->cmdtype == CMDBUILTIN &&
4181 builtinloc >= firstchange)) {
4195 * Locate a command in the command hash table. If "add" is nonzero,
4196 * add the command to the table if it is not already present. The
4197 * variable "lastcmdentry" is set to point to the address of the link
4198 * pointing to the entry, so that delete_cmd_entry can delete the
4201 * Interrupts must be off if called with add != 0.
4204 static struct tblentry **lastcmdentry;
4207 static struct tblentry *
4208 cmdlookup(const char *name, int add)
4210 unsigned int hashval;
4212 struct tblentry *cmdp;
4213 struct tblentry **pp;
4216 hashval = (unsigned char)*p << 4;
4218 hashval += (unsigned char)*p++;
4220 pp = &cmdtable[hashval % CMDTABLESIZE];
4221 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4222 if (equal(cmdp->cmdname, name))
4226 if (add && cmdp == NULL) {
4227 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4228 + strlen(name) + 1);
4230 cmdp->cmdtype = CMDUNKNOWN;
4231 strcpy(cmdp->cmdname, name);
4238 * Delete the command entry returned on the last lookup.
4242 delete_cmd_entry(void)
4244 struct tblentry *cmdp;
4247 cmdp = *lastcmdentry;
4248 *lastcmdentry = cmdp->next;
4249 if (cmdp->cmdtype == CMDFUNCTION)
4250 freefunc(cmdp->param.func);
4257 * Add a new command entry, replacing any existing command entry for
4258 * the same name - except special builtins.
4262 addcmdentry(char *name, struct cmdentry *entry)
4264 struct tblentry *cmdp;
4266 cmdp = cmdlookup(name, 1);
4267 if (cmdp->cmdtype == CMDFUNCTION) {
4268 freefunc(cmdp->param.func);
4270 cmdp->cmdtype = entry->cmdtype;
4271 cmdp->param = entry->u;
4276 * Make a copy of a parse tree.
4279 static inline struct funcnode *
4280 copyfunc(union node *n)
4285 funcblocksize = offsetof(struct funcnode, n);
4288 blocksize = funcblocksize;
4289 f = ckmalloc(blocksize + funcstringsize);
4290 funcblock = (char *) f + offsetof(struct funcnode, n);
4291 funcstring = (char *) f + blocksize;
4298 * Define a shell function.
4302 defun(char *name, union node *func)
4304 struct cmdentry entry;
4307 entry.cmdtype = CMDFUNCTION;
4308 entry.u.func = copyfunc(func);
4309 addcmdentry(name, &entry);
4315 * Delete a function if it exists.
4319 unsetfunc(const char *name)
4321 struct tblentry *cmdp;
4323 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4324 cmdp->cmdtype == CMDFUNCTION)
4329 * Locate and print what a word is...
4333 #ifdef CONFIG_ASH_CMDCMD
4335 describe_command(char *command, int describe_command_verbose)
4337 #define describe_command_verbose 1
4339 describe_command(char *command)
4342 struct cmdentry entry;
4343 struct tblentry *cmdp;
4344 #ifdef CONFIG_ASH_ALIAS
4345 const struct alias *ap;
4347 const char *path = pathval();
4349 if (describe_command_verbose) {
4353 /* First look at the keywords */
4354 if (findkwd(command)) {
4355 out1str(describe_command_verbose ? " is a shell keyword" : command);
4359 #ifdef CONFIG_ASH_ALIAS
4360 /* Then look at the aliases */
4361 if ((ap = lookupalias(command, 0)) != NULL) {
4362 if (describe_command_verbose) {
4363 out1fmt(" is an alias for %s", ap->val);
4372 /* Then check if it is a tracked alias */
4373 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4374 entry.cmdtype = cmdp->cmdtype;
4375 entry.u = cmdp->param;
4377 /* Finally use brute force */
4378 find_command(command, &entry, DO_ABS, path);
4381 switch (entry.cmdtype) {
4383 int j = entry.u.index;
4389 p = padvance(&path, command);
4393 if (describe_command_verbose) {
4395 (cmdp ? " a tracked alias for" : nullstr), p
4404 if (describe_command_verbose) {
4405 out1str(" is a shell function");
4412 if (describe_command_verbose) {
4413 out1fmt(" is a %sshell builtin",
4414 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4415 "special " : nullstr
4423 if (describe_command_verbose) {
4424 out1str(": not found\n");
4430 outstr("\n", stdout);
4435 typecmd(int argc, char **argv)
4440 for (i = 1; i < argc; i++) {
4441 #ifdef CONFIG_ASH_CMDCMD
4442 err |= describe_command(argv[i], 1);
4444 err |= describe_command(argv[i]);
4450 #ifdef CONFIG_ASH_CMDCMD
4452 commandcmd(int argc, char **argv)
4455 int default_path = 0;
4456 int verify_only = 0;
4457 int verbose_verify_only = 0;
4459 while ((c = nextopt("pvV")) != '\0')
4464 "command: nextopt returned character code 0%o\n", c);
4474 verbose_verify_only = 1;
4478 if (default_path + verify_only + verbose_verify_only > 1 ||
4481 "command [-p] command [arg ...]\n"
4482 "command {-v|-V} command\n");
4486 if (verify_only || verbose_verify_only) {
4487 return describe_command(*argptr, verbose_verify_only);
4494 /* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
4497 * Routines to expand arguments to commands. We have to deal with
4498 * backquotes, shell variables, and file metacharacters.
4504 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4505 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4506 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4507 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4508 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4511 * Structure specifying which parts of the string should be searched
4512 * for IFS characters.
4516 struct ifsregion *next; /* next region in list */
4517 int begoff; /* offset of start of region */
4518 int endoff; /* offset of end of region */
4519 int nulonly; /* search for nul bytes only */
4522 /* output of current string */
4523 static char *expdest;
4524 /* list of back quote expressions */
4525 static struct nodelist *argbackq;
4526 /* first struct in list of ifs regions */
4527 static struct ifsregion ifsfirst;
4528 /* last struct in list */
4529 static struct ifsregion *ifslastp;
4530 /* holds expanded arg list */
4531 static struct arglist exparg;
4533 static void argstr(char *, int);
4534 static char *exptilde(char *, char *, int);
4535 static void expbackq(union node *, int, int);
4536 static const char *subevalvar(char *, char *, int, int, int, int, int);
4537 static char *evalvar(char *, int);
4538 static void strtodest(const char *, int, int);
4539 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4540 static ssize_t varvalue(char *, int, int);
4541 static void recordregion(int, int, int);
4542 static void removerecordregions(int);
4543 static void ifsbreakup(char *, struct arglist *);
4544 static void ifsfree(void);
4545 static void expandmeta(struct strlist *, int);
4546 static int patmatch(char *, const char *);
4548 static int cvtnum(arith_t);
4549 static size_t esclen(const char *, const char *);
4550 static char *scanleft(char *, char *, char *, char *, int, int);
4551 static char *scanright(char *, char *, char *, char *, int, int);
4552 static void varunset(const char *, const char *, const char *, int)
4553 __attribute__((__noreturn__));
4556 #define pmatch(a, b) !fnmatch((a), (b), 0)
4558 * Prepare a pattern for a expmeta (internal glob(3)) call.
4560 * Returns an stalloced string.
4563 static inline char *
4564 preglob(const char *pattern, int quoted, int flag) {
4565 flag |= RMESCAPE_GLOB;
4567 flag |= RMESCAPE_QUOTED;
4569 return _rmescapes((char *)pattern, flag);
4574 esclen(const char *start, const char *p) {
4577 while (p > start && *--p == CTLESC) {
4585 * Expand shell variables and backquotes inside a here document.
4589 expandhere(union node *arg, int fd)
4592 expandarg(arg, (struct arglist *)NULL, 0);
4593 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
4598 * Perform variable substitution and command substitution on an argument,
4599 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4600 * perform splitting and file name expansion. When arglist is NULL, perform
4601 * here document expansion.
4605 expandarg(union node *arg, struct arglist *arglist, int flag)
4610 argbackq = arg->narg.backquote;
4611 STARTSTACKSTR(expdest);
4612 ifsfirst.next = NULL;
4614 argstr(arg->narg.text, flag);
4615 if (arglist == NULL) {
4616 return; /* here document expanded */
4618 STPUTC('\0', expdest);
4619 p = grabstackstr(expdest);
4620 exparg.lastp = &exparg.list;
4624 if (flag & EXP_FULL) {
4625 ifsbreakup(p, &exparg);
4626 *exparg.lastp = NULL;
4627 exparg.lastp = &exparg.list;
4628 expandmeta(exparg.list, flag);
4630 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4632 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4635 exparg.lastp = &sp->next;
4639 *exparg.lastp = NULL;
4641 *arglist->lastp = exparg.list;
4642 arglist->lastp = exparg.lastp;
4648 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4649 * characters to allow for further processing. Otherwise treat
4650 * $@ like $* since no splitting will be performed.
4654 argstr(char *p, int flag)
4656 static const char spclchars[] = {
4664 CTLBACKQ | CTLQUOTE,
4665 #ifdef CONFIG_ASH_MATH_SUPPORT
4670 const char *reject = spclchars;
4672 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4673 int breakall = flag & EXP_WORD;
4678 if (!(flag & EXP_VARTILDE)) {
4680 } else if (flag & EXP_VARTILDE2) {
4685 if (flag & EXP_TILDE) {
4691 if (*q == CTLESC && (flag & EXP_QWORD))
4694 p = exptilde(p, q, flag);
4697 startloc = expdest - (char *)stackblock();
4699 length += strcspn(p + length, reject);
4701 if (c && (!(c & 0x80)
4702 #ifdef CONFIG_ASH_MATH_SUPPORT
4706 /* c == '=' || c == ':' || c == CTLENDARI */
4711 expdest = stnputs(p, length, expdest);
4712 newloc = expdest - (char *)stackblock();
4713 if (breakall && !inquotes && newloc > startloc) {
4714 recordregion(startloc, newloc, 0);
4725 if (flag & EXP_VARTILDE2) {
4729 flag |= EXP_VARTILDE2;
4734 * sort of a hack - expand tildes in variable
4735 * assignments (after the first '=' and after ':'s).
4744 case CTLENDVAR: /* ??? */
4747 /* "$@" syntax adherence hack */
4750 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4751 (p[4] == CTLQUOTEMARK || (
4752 p[4] == CTLENDVAR &&
4753 p[5] == CTLQUOTEMARK
4756 p = evalvar(p + 1, flag) + 1;
4759 inquotes = !inquotes;
4772 p = evalvar(p, flag);
4776 case CTLBACKQ|CTLQUOTE:
4777 expbackq(argbackq->n, c, quotes);
4778 argbackq = argbackq->next;
4780 #ifdef CONFIG_ASH_MATH_SUPPORT
4793 exptilde(char *startp, char *p, int flag)
4799 int quotes = flag & (EXP_FULL | EXP_CASE);
4804 while ((c = *++p) != '\0') {
4811 if (flag & EXP_VARTILDE)
4821 if (*name == '\0') {
4822 if ((home = lookupvar(homestr)) == NULL)
4825 if ((pw = getpwnam(name)) == NULL)
4832 startloc = expdest - (char *)stackblock();
4833 strtodest(home, SQSYNTAX, quotes);
4834 recordregion(startloc, expdest - (char *)stackblock(), 0);
4843 removerecordregions(int endoff)
4845 if (ifslastp == NULL)
4848 if (ifsfirst.endoff > endoff) {
4849 while (ifsfirst.next != NULL) {
4850 struct ifsregion *ifsp;
4852 ifsp = ifsfirst.next->next;
4853 ckfree(ifsfirst.next);
4854 ifsfirst.next = ifsp;
4857 if (ifsfirst.begoff > endoff)
4860 ifslastp = &ifsfirst;
4861 ifsfirst.endoff = endoff;
4866 ifslastp = &ifsfirst;
4867 while (ifslastp->next && ifslastp->next->begoff < endoff)
4868 ifslastp=ifslastp->next;
4869 while (ifslastp->next != NULL) {
4870 struct ifsregion *ifsp;
4872 ifsp = ifslastp->next->next;
4873 ckfree(ifslastp->next);
4874 ifslastp->next = ifsp;
4877 if (ifslastp->endoff > endoff)
4878 ifslastp->endoff = endoff;
4882 #ifdef CONFIG_ASH_MATH_SUPPORT
4884 * Expand arithmetic expression. Backup to start of expression,
4885 * evaluate, place result in (backed up) result, adjust string position.
4898 * This routine is slightly over-complicated for
4899 * efficiency. Next we scan backwards looking for the
4900 * start of arithmetic.
4902 start = stackblock();
4909 while (*p != CTLARI) {
4913 error("missing CTLARI (shouldn't happen)");
4918 esc = esclen(start, p);
4928 removerecordregions(begoff);
4937 len = cvtnum(dash_arith(p + 2));
4940 recordregion(begoff, begoff + len, 0);
4945 * Expand stuff in backwards quotes.
4949 expbackq(union node *cmd, int quoted, int quotes)
4957 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4958 struct stackmark smark;
4961 setstackmark(&smark);
4963 startloc = dest - (char *)stackblock();
4965 evalbackcmd(cmd, (struct backcmd *) &in);
4966 popstackmark(&smark);
4973 memtodest(p, i, syntax, quotes);
4977 i = safe_read(in.fd, buf, sizeof buf);
4978 TRACE(("expbackq: read returns %d\n", i));
4988 back_exitstatus = waitforjob(in.jp);
4992 /* Eat all trailing newlines */
4994 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4999 recordregion(startloc, dest - (char *)stackblock(), 0);
5000 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5001 (dest - (char *)stackblock()) - startloc,
5002 (dest - (char *)stackblock()) - startloc,
5003 stackblock() + startloc));
5008 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5019 const char *s = loc2;
5025 match = pmatch(str, s);
5029 if (quotes && *loc == CTLESC)
5039 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5046 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5049 const char *s = loc2;
5054 match = pmatch(str, s);
5061 esc = esclen(startp, loc);
5073 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5077 int saveherefd = herefd;
5078 struct nodelist *saveargbackq = argbackq;
5080 char *rmesc, *rmescend;
5082 char *(*scan)(char *, char *, char *, char *, int , int);
5085 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5086 STPUTC('\0', expdest);
5087 herefd = saveherefd;
5088 argbackq = saveargbackq;
5089 startp = stackblock() + startloc;
5093 setvar(str, startp, 0);
5094 amount = startp - expdest;
5095 STADJUST(amount, expdest);
5099 varunset(p, str, startp, varflags);
5103 subtype -= VSTRIMRIGHT;
5105 if (subtype < 0 || subtype > 3)
5110 rmescend = stackblock() + strloc;
5112 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5113 if (rmesc != startp) {
5115 startp = stackblock() + startloc;
5119 str = stackblock() + strloc;
5120 preglob(str, varflags & VSQUOTE, 0);
5122 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5123 zero = subtype >> 1;
5124 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5125 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5127 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5130 memmove(startp, loc, str - loc);
5131 loc = startp + (str - loc) - 1;
5134 amount = loc - expdest;
5135 STADJUST(amount, expdest);
5142 * Expand a variable, and return a pointer to the next character in the
5146 evalvar(char *p, int flag)
5159 quotes = flag & (EXP_FULL | EXP_CASE);
5161 subtype = varflags & VSTYPE;
5162 quoted = varflags & VSQUOTE;
5164 easy = (!quoted || (*var == '@' && shellparam.nparam));
5165 startloc = expdest - (char *)stackblock();
5166 p = strchr(p, '=') + 1;
5169 varlen = varvalue(var, varflags, flag);
5170 if (varflags & VSNUL)
5173 if (subtype == VSPLUS) {
5174 varlen = -1 - varlen;
5178 if (subtype == VSMINUS) {
5182 p, flag | EXP_TILDE |
5183 (quoted ? EXP_QWORD : EXP_WORD)
5192 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5194 if (subevalvar(p, var, 0, subtype, startloc,
5198 * Remove any recorded regions beyond
5201 removerecordregions(startloc);
5211 if (varlen < 0 && uflag)
5212 varunset(p, var, 0, 0);
5214 if (subtype == VSLENGTH) {
5215 cvtnum(varlen > 0 ? varlen : 0);
5219 if (subtype == VSNORMAL) {
5223 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5232 case VSTRIMRIGHTMAX:
5241 * Terminate the string and start recording the pattern
5244 STPUTC('\0', expdest);
5245 patloc = expdest - (char *)stackblock();
5246 if (subevalvar(p, NULL, patloc, subtype,
5247 startloc, varflags, quotes) == 0) {
5248 int amount = expdest - (
5249 (char *)stackblock() + patloc - 1
5251 STADJUST(-amount, expdest);
5253 /* Remove any recorded regions beyond start of variable */
5254 removerecordregions(startloc);
5259 if (subtype != VSNORMAL) { /* skip to end of alternative */
5262 if ((c = *p++) == CTLESC)
5264 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5266 argbackq = argbackq->next;
5267 } else if (c == CTLVAR) {
5268 if ((*p++ & VSTYPE) != VSNORMAL)
5270 } else if (c == CTLENDVAR) {
5281 * Put a string on the stack.
5285 memtodest(const char *p, size_t len, int syntax, int quotes) {
5288 q = makestrspace(len * 2, q);
5294 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5304 strtodest(const char *p, int syntax, int quotes)
5306 memtodest(p, strlen(p), syntax, quotes);
5311 * Add the value of a specialized variable to the stack string.
5315 varvalue(char *name, int varflags, int flags)
5325 int quoted = varflags & VSQUOTE;
5326 int subtype = varflags & VSTYPE;
5327 int quotes = flags & (EXP_FULL | EXP_CASE);
5329 if (quoted && (flags & EXP_FULL))
5330 sep = 1 << CHAR_BIT;
5332 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5341 num = shellparam.nparam;
5351 p = makestrspace(NOPTS, expdest);
5352 for (i = NOPTS - 1; i >= 0; i--) {
5354 USTPUTC(optletters(i), p);
5365 sep = ifsset() ? ifsval()[0] : ' ';
5366 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5369 if (!(ap = shellparam.p))
5371 while ((p = *ap++)) {
5374 partlen = strlen(p);
5377 if (len > partlen && sep) {
5381 if (subtype == VSPLUS || subtype == VSLENGTH) {
5391 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5392 memtodest(p, partlen, syntax, quotes);
5406 if (num < 0 || num > shellparam.nparam)
5408 p = num ? shellparam.p[num - 1] : arg0;
5411 p = lookupvar(name);
5417 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5418 memtodest(p, len, syntax, quotes);
5422 if (subtype == VSPLUS || subtype == VSLENGTH)
5423 STADJUST(-len, expdest);
5429 * Record the fact that we have to scan this region of the
5430 * string for IFS characters.
5434 recordregion(int start, int end, int nulonly)
5436 struct ifsregion *ifsp;
5438 if (ifslastp == NULL) {
5442 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5444 ifslastp->next = ifsp;
5448 ifslastp->begoff = start;
5449 ifslastp->endoff = end;
5450 ifslastp->nulonly = nulonly;
5455 * Break the argument string into pieces based upon IFS and add the
5456 * strings to the argument list. The regions of the string to be
5457 * searched for IFS characters have been stored by recordregion.
5460 ifsbreakup(char *string, struct arglist *arglist)
5462 struct ifsregion *ifsp;
5467 const char *ifs, *realifs;
5473 if (ifslastp != NULL) {
5476 realifs = ifsset() ? ifsval() : defifs;
5479 p = string + ifsp->begoff;
5480 nulonly = ifsp->nulonly;
5481 ifs = nulonly ? nullstr : realifs;
5483 while (p < string + ifsp->endoff) {
5487 if (strchr(ifs, *p)) {
5489 ifsspc = (strchr(defifs, *p) != NULL);
5490 /* Ignore IFS whitespace at start */
5491 if (q == start && ifsspc) {
5497 sp = (struct strlist *)stalloc(sizeof *sp);
5499 *arglist->lastp = sp;
5500 arglist->lastp = &sp->next;
5504 if (p >= string + ifsp->endoff) {
5510 if (strchr(ifs, *p) == NULL ) {
5513 } else if (strchr(defifs, *p) == NULL) {
5529 } while ((ifsp = ifsp->next) != NULL);
5538 sp = (struct strlist *)stalloc(sizeof *sp);
5540 *arglist->lastp = sp;
5541 arglist->lastp = &sp->next;
5547 struct ifsregion *p;
5552 struct ifsregion *ifsp;
5558 ifsfirst.next = NULL;
5562 static void expmeta(char *, char *);
5563 static struct strlist *expsort(struct strlist *);
5564 static struct strlist *msort(struct strlist *, int);
5566 static char *expdir;
5570 expandmeta(struct strlist *str, int flag)
5572 static const char metachars[] = {
5575 /* TODO - EXP_REDIR */
5578 struct strlist **savelastp;
5584 if (!strpbrk(str->text, metachars))
5586 savelastp = exparg.lastp;
5589 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5591 int i = strlen(str->text);
5592 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5600 if (exparg.lastp == savelastp) {
5605 *exparg.lastp = str;
5606 rmescapes(str->text);
5607 exparg.lastp = &str->next;
5609 *exparg.lastp = NULL;
5610 *savelastp = sp = expsort(*savelastp);
5611 while (sp->next != NULL)
5613 exparg.lastp = &sp->next;
5620 * Add a file name to the list.
5624 addfname(const char *name)
5628 sp = (struct strlist *)stalloc(sizeof *sp);
5629 sp->text = sstrdup(name);
5631 exparg.lastp = &sp->next;
5636 * Do metacharacter (i.e. *, ?, [...]) expansion.
5640 expmeta(char *enddir, char *name)
5655 for (p = name; *p; p++) {
5656 if (*p == '*' || *p == '?')
5658 else if (*p == '[') {
5665 if (*q == '/' || *q == '\0')
5672 } else if (*p == '\\')
5674 else if (*p == '/') {
5681 if (metaflag == 0) { /* we've reached the end of the file name */
5682 if (enddir != expdir)
5690 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5701 } while (p < start);
5703 if (enddir == expdir) {
5705 } else if (enddir == expdir + 1 && *expdir == '/') {
5711 if ((dirp = opendir(cp)) == NULL)
5713 if (enddir != expdir)
5715 if (*endname == 0) {
5727 while (! intpending && (dp = readdir(dirp)) != NULL) {
5728 if (dp->d_name[0] == '.' && ! matchdot)
5730 if (pmatch(start, dp->d_name)) {
5732 scopy(dp->d_name, enddir);
5735 for (p = enddir, cp = dp->d_name;
5736 (*p++ = *cp++) != '\0';)
5739 expmeta(p, endname);
5749 * Sort the results of file name expansion. It calculates the number of
5750 * strings to sort and then calls msort (short for merge sort) to do the
5754 static struct strlist *
5755 expsort(struct strlist *str)
5761 for (sp = str ; sp ; sp = sp->next)
5763 return msort(str, len);
5767 static struct strlist *
5768 msort(struct strlist *list, int len)
5770 struct strlist *p, *q = NULL;
5771 struct strlist **lpp;
5779 for (n = half ; --n >= 0 ; ) {
5783 q->next = NULL; /* terminate first half of list */
5784 q = msort(list, half); /* sort first half of list */
5785 p = msort(p, len - half); /* sort second half */
5788 #ifdef CONFIG_LOCALE_SUPPORT
5789 if (strcoll(p->text, q->text) < 0)
5791 if (strcmp(p->text, q->text) < 0)
5796 if ((p = *lpp) == NULL) {
5803 if ((q = *lpp) == NULL) {
5814 * Returns true if the pattern matches the string.
5818 patmatch(char *pattern, const char *string)
5820 return pmatch(preglob(pattern, 0, 0), string);
5825 * Remove any CTLESC characters from a string.
5829 _rmescapes(char *str, int flag)
5832 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5837 p = strpbrk(str, qchars);
5843 if (flag & RMESCAPE_ALLOC) {
5844 size_t len = p - str;
5845 size_t fulllen = len + strlen(p) + 1;
5847 if (flag & RMESCAPE_GROW) {
5848 r = makestrspace(fulllen, expdest);
5849 } else if (flag & RMESCAPE_HEAP) {
5850 r = ckmalloc(fulllen);
5852 r = stalloc(fulllen);
5856 q = mempcpy(q, str, len);
5859 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5860 globbing = flag & RMESCAPE_GLOB;
5861 notescaped = globbing;
5863 if (*p == CTLQUOTEMARK) {
5864 inquotes = ~inquotes;
5866 notescaped = globbing;
5870 /* naked back slash */
5876 if (notescaped && inquotes && *p != '/') {
5880 notescaped = globbing;
5885 if (flag & RMESCAPE_GROW) {
5887 STADJUST(q - r + 1, expdest);
5894 * See if a pattern matches in a case statement.
5898 casematch(union node *pattern, char *val)
5900 struct stackmark smark;
5903 setstackmark(&smark);
5904 argbackq = pattern->narg.backquote;
5905 STARTSTACKSTR(expdest);
5907 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5908 STACKSTRNUL(expdest);
5909 result = patmatch(stackblock(), val);
5910 popstackmark(&smark);
5923 expdest = makestrspace(32, expdest);
5924 #ifdef CONFIG_ASH_MATH_SUPPORT_64
5925 len = fmtstr(expdest, 32, "%lld", (long long) num);
5927 len = fmtstr(expdest, 32, "%ld", num);
5929 STADJUST(len, expdest);
5934 varunset(const char *end, const char *var, const char *umsg, int varflags)
5940 msg = "parameter not set";
5942 if (*end == CTLENDVAR) {
5943 if (varflags & VSNUL)
5948 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5952 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5955 * This implements the input routines used by the parser.
5958 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5959 #define IBUFSIZ (BUFSIZ + 1)
5961 static void pushfile(void);
5964 * Read a character from the script, returning PEOF on end of file.
5965 * Nul characters in the input are silently discarded.
5968 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5970 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5971 #define pgetc_macro() pgetc()
5975 return pgetc_as_macro();
5978 #define pgetc_macro() pgetc_as_macro()
5982 return pgetc_macro();
5988 * Same as pgetc(), but ignores PEOA.
5990 #ifdef CONFIG_ASH_ALIAS
5991 static int pgetc2(void)
5997 } while (c == PEOA);
6001 static inline int pgetc2(void)
6003 return pgetc_macro();
6008 * Read a line from the script.
6011 static inline char *
6012 pfgets(char *line, int len)
6018 while (--nleft > 0) {
6035 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6036 static const char *cmdedit_prompt;
6037 static inline void putprompt(const char *s)
6042 static inline void putprompt(const char *s)
6052 char *buf = parsefile->buf;
6056 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6057 if (!iflag || parsefile->fd)
6058 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6060 #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
6061 cmdedit_path_lookup = pathval();
6063 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6065 /* Ctrl+C presend */
6074 if(nr < 0 && errno == 0) {
6075 /* Ctrl+D presend */
6080 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6084 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6085 int flags = fcntl(0, F_GETFL, 0);
6086 if (flags >= 0 && flags & O_NONBLOCK) {
6087 flags &=~ O_NONBLOCK;
6088 if (fcntl(0, F_SETFL, flags) >= 0) {
6089 out2str("sh: turning off NDELAY mode\n");
6099 * Refill the input buffer and return the next input character:
6101 * 1) If a string was pushed back on the input, pop it;
6102 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6103 * from a string so we can't refill the buffer, return EOF.
6104 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6105 * 4) Process input up to the next newline, deleting nul characters.
6115 while (parsefile->strpush) {
6116 #ifdef CONFIG_ASH_ALIAS
6117 if (parsenleft == -1 && parsefile->strpush->ap &&
6118 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6123 if (--parsenleft >= 0)
6124 return (*parsenextc++);
6126 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6131 if (parselleft <= 0) {
6132 if ((parselleft = preadfd()) <= 0) {
6133 parselleft = parsenleft = EOF_NLEFT;
6140 /* delete nul characters */
6141 for (more = 1; more;) {
6148 parsenleft = q - parsenextc;
6149 more = 0; /* Stop processing here */
6156 if (--parselleft <= 0 && more) {
6157 parsenleft = q - parsenextc - 1;
6168 out2str(parsenextc);
6173 return *parsenextc++;
6177 * Undo the last call to pgetc. Only one character may be pushed back.
6178 * PEOF may be pushed back.
6189 * Push a string back onto the input at this current parsefile level.
6190 * We handle aliases this way.
6193 pushstring(char *s, void *ap)
6200 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6201 if (parsefile->strpush) {
6202 sp = ckmalloc(sizeof (struct strpush));
6203 sp->prev = parsefile->strpush;
6204 parsefile->strpush = sp;
6206 sp = parsefile->strpush = &(parsefile->basestrpush);
6207 sp->prevstring = parsenextc;
6208 sp->prevnleft = parsenleft;
6209 #ifdef CONFIG_ASH_ALIAS
6210 sp->ap = (struct alias *)ap;
6212 ((struct alias *)ap)->flag |= ALIASINUSE;
6224 struct strpush *sp = parsefile->strpush;
6227 #ifdef CONFIG_ASH_ALIAS
6229 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6230 checkkwd |= CHKALIAS;
6232 if (sp->string != sp->ap->val) {
6235 sp->ap->flag &= ~ALIASINUSE;
6236 if (sp->ap->flag & ALIASDEAD) {
6237 unalias(sp->ap->name);
6241 parsenextc = sp->prevstring;
6242 parsenleft = sp->prevnleft;
6243 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6244 parsefile->strpush = sp->prev;
6245 if (sp != &(parsefile->basestrpush))
6251 * Set the input to take input from a file. If push is set, push the
6252 * old input onto the stack first.
6256 setinputfile(const char *fname, int push)
6262 if ((fd = open(fname, O_RDONLY)) < 0)
6263 error("Can't open %s", fname);
6265 fd2 = copyfd(fd, 10);
6268 error("Out of file descriptors");
6271 setinputfd(fd, push);
6277 * Like setinputfile, but takes an open file descriptor. Call this with
6282 setinputfd(int fd, int push)
6284 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6290 if (parsefile->buf == NULL)
6291 parsefile->buf = ckmalloc(IBUFSIZ);
6292 parselleft = parsenleft = 0;
6298 * Like setinputfile, but takes input from a string.
6302 setinputstring(char *string)
6306 parsenextc = string;
6307 parsenleft = strlen(string);
6308 parsefile->buf = NULL;
6315 * To handle the "." command, a stack of input files is used. Pushfile
6316 * adds a new entry to the stack and popfile restores the previous level.
6322 struct parsefile *pf;
6324 parsefile->nleft = parsenleft;
6325 parsefile->lleft = parselleft;
6326 parsefile->nextc = parsenextc;
6327 parsefile->linno = plinno;
6328 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6329 pf->prev = parsefile;
6332 pf->basestrpush.prev = NULL;
6340 struct parsefile *pf = parsefile;
6349 parsefile = pf->prev;
6351 parsenleft = parsefile->nleft;
6352 parselleft = parsefile->lleft;
6353 parsenextc = parsefile->nextc;
6354 plinno = parsefile->linno;
6360 * Return to top level.
6366 while (parsefile != &basepf)
6372 * Close the file(s) that the shell is reading commands from. Called
6373 * after a fork is done.
6380 if (parsefile->fd > 0) {
6381 close(parsefile->fd);
6386 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6388 /* mode flags for set_curjob */
6389 #define CUR_DELETE 2
6390 #define CUR_RUNNING 1
6391 #define CUR_STOPPED 0
6393 /* mode flags for dowait */
6394 #define DOWAIT_NORMAL 0
6395 #define DOWAIT_BLOCK 1
6398 static struct job *jobtab;
6400 static unsigned njobs;
6402 /* pgrp of shell on invocation */
6403 static int initialpgrp;
6404 static int ttyfd = -1;
6407 static struct job *curjob;
6408 /* number of presumed living untracked jobs */
6411 static void set_curjob(struct job *, unsigned);
6413 static int restartjob(struct job *, int);
6414 static void xtcsetpgrp(int, pid_t);
6415 static char *commandtext(union node *);
6416 static void cmdlist(union node *, int);
6417 static void cmdtxt(union node *);
6418 static void cmdputs(const char *);
6419 static void showpipe(struct job *, FILE *);
6421 static int sprint_status(char *, int, int);
6422 static void freejob(struct job *);
6423 static struct job *getjob(const char *, int);
6424 static struct job *growjobtab(void);
6425 static void forkchild(struct job *, union node *, int);
6426 static void forkparent(struct job *, union node *, int, pid_t);
6427 static int dowait(int, struct job *);
6428 static int getstatus(struct job *);
6431 set_curjob(struct job *jp, unsigned mode)
6434 struct job **jpp, **curp;
6436 /* first remove from list */
6437 jpp = curp = &curjob;
6442 jpp = &jp1->prev_job;
6444 *jpp = jp1->prev_job;
6446 /* Then re-insert in correct position */
6454 /* job being deleted */
6457 /* newly created job or backgrounded job,
6458 put after all stopped jobs. */
6462 if (!jp1 || jp1->state != JOBSTOPPED)
6465 jpp = &jp1->prev_job;
6471 /* newly stopped job - becomes curjob */
6472 jp->prev_job = *jpp;
6480 * Turn job control on and off.
6482 * Note: This code assumes that the third arg to ioctl is a character
6483 * pointer, which is true on Berkeley systems but not System V. Since
6484 * System V doesn't have job control yet, this isn't a problem now.
6486 * Called with interrupts off.
6495 if (on == jobctl || rootshell == 0)
6499 ofd = fd = open(_PATH_TTY, O_RDWR);
6502 while (!isatty(fd) && --fd >= 0)
6505 fd = fcntl(fd, F_DUPFD, 10);
6509 fcntl(fd, F_SETFD, FD_CLOEXEC);
6510 do { /* while we are in the background */
6511 if ((pgrp = tcgetpgrp(fd)) < 0) {
6513 sh_warnx("can't access tty; job control turned off");
6517 if (pgrp == getpgrp())
6528 xtcsetpgrp(fd, pgrp);
6530 /* turning job control off */
6533 xtcsetpgrp(fd, pgrp);
6547 killcmd(int argc, char **argv)
6558 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6559 "kill -l [exitstatus]"
6563 if (**++argv == '-') {
6564 signo = decode_signal(*argv + 1, 1);
6568 while ((c = nextopt("ls:")) != '\0')
6578 signo = decode_signal(optionarg, 1);
6581 "invalid signal number or name: %s",
6592 if (!list && signo < 0)
6595 if ((signo < 0 || !*argv) ^ list) {
6603 for (i = 1; i < NSIG; i++) {
6604 name = u_signal_names(0, &i, 1);
6606 out1fmt(snlfmt, name);
6610 name = u_signal_names(*argptr, &signo, -1);
6612 out1fmt(snlfmt, name);
6614 error("invalid signal number or exit status: %s", *argptr);
6620 if (**argv == '%') {
6621 jp = getjob(*argv, 0);
6622 pid = -jp->ps[0].pid;
6624 pid = number(*argv);
6625 if (kill(pid, signo) != 0) {
6635 #if defined(JOBS) || defined(DEBUG)
6637 jobno(const struct job *jp)
6639 return jp - jobtab + 1;
6645 fgcmd(int argc, char **argv)
6652 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6657 jp = getjob(*argv, 1);
6658 if (mode == FORK_BG) {
6659 set_curjob(jp, CUR_RUNNING);
6660 fprintf(out, "[%d] ", jobno(jp));
6662 outstr(jp->ps->cmd, out);
6664 retval = restartjob(jp, mode);
6665 } while (*argv && *++argv);
6669 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6673 restartjob(struct job *jp, int mode)
6675 struct procstat *ps;
6681 if (jp->state == JOBDONE)
6683 jp->state = JOBRUNNING;
6685 if (mode == FORK_FG)
6686 xtcsetpgrp(ttyfd, pgid);
6687 killpg(pgid, SIGCONT);
6691 if (WIFSTOPPED(ps->status)) {
6694 } while (ps++, --i);
6696 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6703 sprint_status(char *s, int status, int sigonly)
6709 if (!WIFEXITED(status)) {
6711 if (WIFSTOPPED(status))
6712 st = WSTOPSIG(status);
6715 st = WTERMSIG(status);
6717 if (st == SIGINT || st == SIGPIPE)
6720 if (WIFSTOPPED(status))
6725 col = fmtstr(s, 32, strsignal(st));
6726 if (WCOREDUMP(status)) {
6727 col += fmtstr(s + col, 16, " (core dumped)");
6729 } else if (!sigonly) {
6730 st = WEXITSTATUS(status);
6732 col = fmtstr(s, 16, "Done(%d)", st);
6734 col = fmtstr(s, 16, "Done");
6743 showjob(FILE *out, struct job *jp, int mode)
6745 struct procstat *ps;
6746 struct procstat *psend;
6753 if (mode & SHOW_PGID) {
6754 /* just output process (group) id of pipeline */
6755 fprintf(out, "%d\n", ps->pid);
6759 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6764 else if (curjob && jp == curjob->prev_job)
6767 if (mode & SHOW_PID)
6768 col += fmtstr(s + col, 16, "%d ", ps->pid);
6770 psend = ps + jp->nprocs;
6772 if (jp->state == JOBRUNNING) {
6773 scopy("Running", s + col);
6774 col += strlen("Running");
6776 int status = psend[-1].status;
6778 if (jp->state == JOBSTOPPED)
6779 status = jp->stopstatus;
6781 col += sprint_status(s + col, status, 0);
6787 /* for each process */
6788 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6791 fprintf(out, "%s%*c%s",
6792 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6794 if (!(mode & SHOW_PID)) {
6798 if (++ps == psend) {
6799 outcslow('\n', out);
6806 if (jp->state == JOBDONE) {
6807 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6814 jobscmd(int argc, char **argv)
6820 while ((m = nextopt("lp")))
6830 showjob(out, getjob(*argv,0), mode);
6833 showjobs(out, mode);
6840 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6841 * statuses have changed since the last call to showjobs.
6845 showjobs(FILE *out, int mode)
6849 TRACE(("showjobs(%x) called\n", mode));
6851 /* If not even one one job changed, there is nothing to do */
6852 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6855 for (jp = curjob; jp; jp = jp->prev_job) {
6856 if (!(mode & SHOW_CHANGED) || jp->changed)
6857 showjob(out, jp, mode);
6863 * Mark a job structure as unused.
6867 freejob(struct job *jp)
6869 struct procstat *ps;
6873 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6874 if (ps->cmd != nullstr)
6877 if (jp->ps != &jp->ps0)
6880 set_curjob(jp, CUR_DELETE);
6886 waitcmd(int argc, char **argv)
6899 /* wait for all jobs */
6904 /* no running procs */
6907 if (jp->state == JOBRUNNING)
6912 dowait(DOWAIT_BLOCK, 0);
6918 if (**argv != '%') {
6919 pid_t pid = number(*argv);
6923 if (job->ps[job->nprocs - 1].pid == pid)
6925 job = job->prev_job;
6931 job = getjob(*argv, 0);
6932 /* loop until process terminated or stopped */
6933 while (job->state == JOBRUNNING)
6934 dowait(DOWAIT_BLOCK, 0);
6936 retval = getstatus(job);
6947 * Convert a job name to a job structure.
6951 getjob(const char *name, int getctl)
6955 const char *err_msg = "No such job: %s";
6959 char *(*match)(const char *, const char *);
6974 if (c == '+' || c == '%') {
6976 err_msg = "No current job";
6978 } else if (c == '-') {
6981 err_msg = "No previous job";
6992 jp = jobtab + num - 1;
7009 if (match(jp->ps[0].cmd, p)) {
7013 err_msg = "%s: ambiguous";
7020 err_msg = "job %s not created under job control";
7021 if (getctl && jp->jobctl == 0)
7026 error(err_msg, name);
7031 * Return a new job structure.
7032 * Called with interrupts off.
7036 makejob(union node *node, int nprocs)
7041 for (i = njobs, jp = jobtab ; ; jp++) {
7048 if (jp->state != JOBDONE || !jp->waited)
7057 memset(jp, 0, sizeof(*jp));
7062 jp->prev_job = curjob;
7067 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7069 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7079 struct job *jp, *jq;
7081 len = njobs * sizeof(*jp);
7083 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7085 offset = (char *)jp - (char *)jq;
7087 /* Relocate pointers */
7090 jq = (struct job *)((char *)jq + l);
7094 #define joff(p) ((struct job *)((char *)(p) + l))
7095 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7096 if (xlikely(joff(jp)->ps == &jq->ps0))
7097 jmove(joff(jp)->ps);
7098 if (joff(jp)->prev_job)
7099 jmove(joff(jp)->prev_job);
7109 jp = (struct job *)((char *)jp + len);
7113 } while (--jq >= jp);
7119 * Fork off a subshell. If we are doing job control, give the subshell its
7120 * own process group. Jp is a job structure that the job is to be added to.
7121 * N is the command that will be evaluated by the child. Both jp and n may
7122 * be NULL. The mode parameter can be one of the following:
7123 * FORK_FG - Fork off a foreground process.
7124 * FORK_BG - Fork off a background process.
7125 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7126 * process group even if job control is on.
7128 * When job control is turned off, background processes have their standard
7129 * input redirected to /dev/null (except for the second and later processes
7132 * Called with interrupts off.
7136 forkchild(struct job *jp, union node *n, int mode)
7140 TRACE(("Child shell %d\n", getpid()));
7141 wasroot = rootshell;
7147 /* do job control only in root shell */
7149 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7152 if (jp->nprocs == 0)
7155 pgrp = jp->ps[0].pid;
7156 /* This can fail because we are doing it in the parent also */
7157 (void)setpgid(0, pgrp);
7158 if (mode == FORK_FG)
7159 xtcsetpgrp(ttyfd, pgrp);
7164 if (mode == FORK_BG) {
7167 if (jp->nprocs == 0) {
7169 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7170 error("Can't open %s", _PATH_DEVNULL);
7173 if (wasroot && iflag) {
7178 for (jp = curjob; jp; jp = jp->prev_job)
7184 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7186 TRACE(("In parent shell: child = %d\n", pid));
7188 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7193 if (mode != FORK_NOJOB && jp->jobctl) {
7196 if (jp->nprocs == 0)
7199 pgrp = jp->ps[0].pid;
7200 /* This can fail because we are doing it in the child also */
7201 (void)setpgid(pid, pgrp);
7204 if (mode == FORK_BG) {
7205 backgndpid = pid; /* set $! */
7206 set_curjob(jp, CUR_RUNNING);
7209 struct procstat *ps = &jp->ps[jp->nprocs++];
7215 ps->cmd = commandtext(n);
7221 forkshell(struct job *jp, union node *n, int mode)
7225 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7228 TRACE(("Fork failed, errno=%d", errno));
7231 error("Cannot fork");
7234 forkchild(jp, n, mode);
7236 forkparent(jp, n, mode, pid);
7241 * Wait for job to finish.
7243 * Under job control we have the problem that while a child process is
7244 * running interrupts generated by the user are sent to the child but not
7245 * to the shell. This means that an infinite loop started by an inter-
7246 * active user may be hard to kill. With job control turned off, an
7247 * interactive user may place an interactive program inside a loop. If
7248 * the interactive program catches interrupts, the user doesn't want
7249 * these interrupts to also abort the loop. The approach we take here
7250 * is to have the shell ignore interrupt signals while waiting for a
7251 * foreground process to terminate, and then send itself an interrupt
7252 * signal if the child process was terminated by an interrupt signal.
7253 * Unfortunately, some programs want to do a bit of cleanup and then
7254 * exit on interrupt; unless these processes terminate themselves by
7255 * sending a signal to themselves (instead of calling exit) they will
7256 * confuse this approach.
7258 * Called with interrupts off.
7262 waitforjob(struct job *jp)
7266 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7267 while (jp->state == JOBRUNNING) {
7268 dowait(DOWAIT_BLOCK, jp);
7273 xtcsetpgrp(ttyfd, rootpid);
7275 * This is truly gross.
7276 * If we're doing job control, then we did a TIOCSPGRP which
7277 * caused us (the shell) to no longer be in the controlling
7278 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7279 * intuit from the subprocess exit status whether a SIGINT
7280 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7285 if (jp->state == JOBDONE)
7293 * Do a wait system call. If job control is compiled in, we accept
7294 * stopped processes. If block is zero, we return a value of zero
7295 * rather than blocking.
7297 * System V doesn't have a non-blocking wait system call. It does
7298 * have a SIGCLD signal that is sent to a process when one of it's
7299 * children dies. The obvious way to use SIGCLD would be to install
7300 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7301 * was received, and have waitproc bump another counter when it got
7302 * the status of a process. Waitproc would then know that a wait
7303 * system call would not block if the two counters were different.
7304 * This approach doesn't work because if a process has children that
7305 * have not been waited for, System V will send it a SIGCLD when it
7306 * installs a signal handler for SIGCLD. What this means is that when
7307 * a child exits, the shell will be sent SIGCLD signals continuously
7308 * until is runs out of stack space, unless it does a wait call before
7309 * restoring the signal handler. The code below takes advantage of
7310 * this (mis)feature by installing a signal handler for SIGCLD and
7311 * then checking to see whether it was called. If there are any
7312 * children to be waited for, it will be.
7314 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7315 * waits at all. In this case, the user will not be informed when
7316 * a background process until the next time she runs a real program
7317 * (as opposed to running a builtin command or just typing return),
7318 * and the jobs command may give out of date information.
7322 waitproc(int block, int *status)
7332 return wait3(status, flags, (struct rusage *)NULL);
7336 * Wait for a process to terminate.
7340 dowait(int block, struct job *job)
7345 struct job *thisjob;
7348 TRACE(("dowait(%d) called\n", block));
7349 pid = waitproc(block, &status);
7350 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7355 for (jp = curjob; jp; jp = jp->prev_job) {
7356 struct procstat *sp;
7357 struct procstat *spend;
7358 if (jp->state == JOBDONE)
7361 spend = jp->ps + jp->nprocs;
7364 if (sp->pid == pid) {
7365 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7366 sp->status = status;
7369 if (sp->status == -1)
7372 if (state == JOBRUNNING)
7374 if (WIFSTOPPED(sp->status)) {
7375 jp->stopstatus = sp->status;
7379 } while (++sp < spend);
7384 if (!WIFSTOPPED(status))
7391 if (state != JOBRUNNING) {
7392 thisjob->changed = 1;
7394 if (thisjob->state != state) {
7395 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7396 thisjob->state = state;
7398 if (state == JOBSTOPPED) {
7399 set_curjob(thisjob, CUR_STOPPED);
7408 if (thisjob && thisjob == job) {
7412 len = sprint_status(s, status, 1);
7424 * return 1 if there are stopped jobs, otherwise 0
7437 if (jp && jp->state == JOBSTOPPED) {
7438 out2str("You have stopped jobs.\n");
7448 * Return a string identifying a command (to be printed by the
7453 static char *cmdnextc;
7456 commandtext(union node *n)
7460 STARTSTACKSTR(cmdnextc);
7462 name = stackblock();
7463 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7464 name, cmdnextc, cmdnextc));
7465 return savestr(name);
7469 cmdtxt(union node *n)
7472 struct nodelist *lp;
7484 lp = n->npipe.cmdlist;
7502 cmdtxt(n->nbinary.ch1);
7518 cmdtxt(n->nif.test);
7521 if (n->nif.elsepart) {
7524 n = n->nif.elsepart;
7540 cmdtxt(n->nbinary.ch1);
7550 cmdputs(n->nfor.var);
7552 cmdlist(n->nfor.args, 1);
7557 cmdputs(n->narg.text);
7561 cmdlist(n->ncmd.args, 1);
7562 cmdlist(n->ncmd.redirect, 0);
7575 cmdputs(n->ncase.expr->narg.text);
7577 for (np = n->ncase.cases; np; np = np->nclist.next) {
7578 cmdtxt(np->nclist.pattern);
7580 cmdtxt(np->nclist.body);
7606 s[0] = n->nfile.fd + '0';
7610 if (n->type == NTOFD || n->type == NFROMFD) {
7611 s[0] = n->ndup.dupfd + '0';
7622 cmdlist(union node *np, int sep)
7624 for (; np; np = np->narg.next) {
7628 if (sep && np->narg.next)
7634 cmdputs(const char *s)
7636 const char *p, *str;
7637 char c, cc[2] = " ";
7641 static const char *const vstype[16] = {
7642 nullstr, "}", "-", "+", "?", "=",
7643 "%", "%%", "#", "##", nullstr
7646 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7648 while ((c = *p++) != 0) {
7656 if ((subtype & VSTYPE) == VSLENGTH)
7660 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7678 case CTLBACKQ+CTLQUOTE:
7681 #ifdef CONFIG_ASH_MATH_SUPPORT
7696 str = vstype[subtype & VSTYPE];
7697 if (subtype & VSNUL)
7708 /* These can only happen inside quotes */
7720 while ((c = *str++)) {
7725 USTPUTC('"', nextc);
7733 showpipe(struct job *jp, FILE *out)
7735 struct procstat *sp;
7736 struct procstat *spend;
7738 spend = jp->ps + jp->nprocs;
7739 for (sp = jp->ps + 1; sp < spend; sp++)
7740 fprintf(out, " | %s", sp->cmd);
7741 outcslow('\n', out);
7746 xtcsetpgrp(int fd, pid_t pgrp)
7748 if (tcsetpgrp(fd, pgrp))
7749 error("Cannot set tty process group (%m)");
7754 getstatus(struct job *job) {
7758 status = job->ps[job->nprocs - 1].status;
7759 retval = WEXITSTATUS(status);
7760 if (!WIFEXITED(status)) {
7762 retval = WSTOPSIG(status);
7763 if (!WIFSTOPPED(status))
7766 /* XXX: limits number of signals */
7767 retval = WTERMSIG(status);
7769 if (retval == SIGINT)
7775 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7776 jobno(job), job->nprocs, status, retval));
7780 #ifdef CONFIG_ASH_MAIL
7781 /* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7784 * Routines to check for mail. (Perhaps make part of main.c?)
7787 #define MAXMBOXES 10
7789 /* times of mailboxes */
7790 static time_t mailtime[MAXMBOXES];
7791 /* Set if MAIL or MAILPATH is changed. */
7792 static int mail_var_path_changed;
7797 * Print appropriate message(s) if mail has arrived.
7798 * If mail_var_path_changed is set,
7799 * then the value of MAIL has mail_var_path_changed,
7800 * so we just update the values.
7810 struct stackmark smark;
7813 setstackmark(&smark);
7814 mpath = mpathset() ? mpathval() : mailval();
7815 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7816 p = padvance(&mpath, nullstr);
7821 for (q = p ; *q ; q++);
7826 q[-1] = '\0'; /* delete trailing '/' */
7827 if (stat(p, &statb) < 0) {
7831 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7834 pathopt ? pathopt : "you have mail"
7837 *mtp = statb.st_mtime;
7839 mail_var_path_changed = 0;
7840 popstackmark(&smark);
7845 changemail(const char *val)
7847 mail_var_path_changed++;
7850 #endif /* CONFIG_ASH_MAIL */
7852 /* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7856 static short profile_buf[16384];
7860 static int isloginsh;
7862 static void read_profile(const char *);
7865 * Main routine. We initialize things, parse the arguments, execute
7866 * profiles if we're a login shell, and then call cmdloop to execute
7867 * commands. The setjmp call sets up the location to jump to when an
7868 * exception occurs. When an exception occurs the variable "state"
7869 * is used to figure out how far we had gotten.
7873 ash_main(int argc, char **argv)
7877 struct jmploc jmploc;
7878 struct stackmark smark;
7881 dash_errno = __errno_location();
7885 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7888 if (setjmp(jmploc.loc)) {
7895 switch (exception) {
7905 status = exitstatus;
7908 exitstatus = status;
7910 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7914 outcslow('\n', stderr);
7916 popstackmark(&smark);
7917 FORCEINTON; /* enable interrupts */
7920 else if (state == 2)
7922 else if (state == 3)
7930 trputs("Shell args: "); trargs(argv);
7934 #ifdef CONFIG_ASH_RANDOM_SUPPORT
7935 rseed = rootpid + ((time_t)time((time_t *)0));
7939 setstackmark(&smark);
7940 procargs(argc, argv);
7941 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7943 const char *hp = lookupvar("HISTFILE");
7946 hp = lookupvar("HOME");
7948 char *defhp = concat_path_file(hp, ".ash_history");
7949 setvar("HISTFILE", defhp, 0);
7955 if (argv[0] && argv[0][0] == '-')
7959 read_profile("/etc/profile");
7962 read_profile(".profile");
7968 getuid() == geteuid() && getgid() == getegid() &&
7972 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7973 read_profile(shinit);
7981 if (sflag || minusc == NULL) {
7982 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7984 const char *hp = lookupvar("HISTFILE");
7987 load_history ( hp );
7990 state4: /* XXX ??? - why isn't this before the "if" statement */
7998 extern void _mcleanup(void);
8008 * Read and execute commands. "Top" is nonzero for the top level command
8009 * loop; it turns on prompting if the shell is interactive.
8016 struct stackmark smark;
8020 TRACE(("cmdloop(%d) called\n", top));
8022 setstackmark(&smark);
8027 showjobs(stderr, SHOW_CHANGED);
8032 #ifdef CONFIG_ASH_MAIL
8036 n = parsecmd(inter);
8037 /* showtree(n); DEBUG */
8039 if (!top || numeof >= 50)
8041 if (!stoppedjobs()) {
8044 out2str("\nUse \"exit\" to leave shell.\n");
8047 } else if (n != NULL && nflag == 0) {
8048 job_warning = (job_warning == 2) ? 1 : 0;
8052 popstackmark(&smark);
8062 * Read /etc/profile or .profile. Return on error.
8066 read_profile(const char *name)
8073 if ((fd = open(name, O_RDONLY)) >= 0)
8078 /* -q turns off -x and -v just when executing init files */
8081 xflag = 0, xflag_set = 1;
8083 vflag = 0, vflag_set = 1;
8097 * Read a file containing shell functions.
8101 readcmdfile(char *name)
8106 if ((fd = open(name, O_RDONLY)) >= 0)
8109 error("Can't open %s", name);
8117 * Take commands from a file. To be compatible we should do a path
8118 * search for the file, which is necessary to find sub-commands.
8121 static inline char *
8122 find_dot_file(char *name)
8125 const char *path = pathval();
8128 /* don't try this for absolute or relative paths */
8129 if (strchr(name, '/'))
8132 while ((fullname = padvance(&path, name)) != NULL) {
8133 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8135 * Don't bother freeing here, since it will
8136 * be freed by the caller.
8140 stunalloc(fullname);
8143 /* not found in the PATH */
8144 error(not_found_msg, name);
8148 static int dotcmd(int argc, char **argv)
8151 volatile struct shparam saveparam;
8155 for (sp = cmdenviron; sp; sp = sp->next)
8156 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8158 if (argc >= 2) { /* That's what SVR2 does */
8160 struct stackmark smark;
8162 setstackmark(&smark);
8163 fullname = find_dot_file(argv[1]);
8166 saveparam = shellparam;
8167 shellparam.malloc = 0;
8168 shellparam.nparam = argc - 2;
8169 shellparam.p = argv + 2;
8172 setinputfile(fullname, 1);
8173 commandname = fullname;
8178 freeparam(&shellparam);
8179 shellparam = saveparam;
8182 popstackmark(&smark);
8189 exitcmd(int argc, char **argv)
8194 exitstatus = number(argv[1]);
8199 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8202 * Same for malloc, realloc, but returns an error when out of space.
8206 ckrealloc(pointer p, size_t nbytes)
8208 p = realloc(p, nbytes);
8210 error(bb_msg_memory_exhausted);
8215 ckmalloc(size_t nbytes)
8217 return ckrealloc(NULL, nbytes);
8221 * Make a copy of a string in safe storage.
8225 savestr(const char *s)
8227 char *p = strdup(s);
8229 error(bb_msg_memory_exhausted);
8235 * Parse trees for commands are allocated in lifo order, so we use a stack
8236 * to make this more efficient, and also to avoid all sorts of exception
8237 * handling code to handle interrupts in the middle of a parse.
8239 * The size 504 was chosen because the Ultrix malloc handles that size
8245 stalloc(size_t nbytes)
8250 aligned = SHELL_ALIGN(nbytes);
8251 if (aligned > stacknleft) {
8254 struct stack_block *sp;
8256 blocksize = aligned;
8257 if (blocksize < MINSIZE)
8258 blocksize = MINSIZE;
8259 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8260 if (len < blocksize)
8261 error(bb_msg_memory_exhausted);
8265 stacknxt = sp->space;
8266 stacknleft = blocksize;
8267 sstrend = stacknxt + blocksize;
8272 stacknxt += aligned;
8273 stacknleft -= aligned;
8279 stunalloc(pointer p)
8282 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8283 write(2, "stunalloc\n", 10);
8287 stacknleft += stacknxt - (char *)p;
8293 setstackmark(struct stackmark *mark)
8295 mark->stackp = stackp;
8296 mark->stacknxt = stacknxt;
8297 mark->stacknleft = stacknleft;
8298 mark->marknext = markp;
8304 popstackmark(struct stackmark *mark)
8306 struct stack_block *sp;
8309 markp = mark->marknext;
8310 while (stackp != mark->stackp) {
8315 stacknxt = mark->stacknxt;
8316 stacknleft = mark->stacknleft;
8317 sstrend = mark->stacknxt + mark->stacknleft;
8323 * When the parser reads in a string, it wants to stick the string on the
8324 * stack and only adjust the stack pointer when it knows how big the
8325 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8326 * of space on top of the stack and stackblocklen returns the length of
8327 * this block. Growstackblock will grow this space by at least one byte,
8328 * possibly moving it (like realloc). Grabstackblock actually allocates the
8329 * part of the block that has been used.
8333 growstackblock(void)
8337 newlen = stacknleft * 2;
8338 if (newlen < stacknleft)
8339 error(bb_msg_memory_exhausted);
8343 if (stacknxt == stackp->space && stackp != &stackbase) {
8344 struct stack_block *oldstackp;
8345 struct stackmark *xmark;
8346 struct stack_block *sp;
8347 struct stack_block *prevstackp;
8353 prevstackp = sp->prev;
8354 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8355 sp = ckrealloc((pointer)sp, grosslen);
8356 sp->prev = prevstackp;
8358 stacknxt = sp->space;
8359 stacknleft = newlen;
8360 sstrend = sp->space + newlen;
8363 * Stack marks pointing to the start of the old block
8364 * must be relocated to point to the new block
8367 while (xmark != NULL && xmark->stackp == oldstackp) {
8368 xmark->stackp = stackp;
8369 xmark->stacknxt = stacknxt;
8370 xmark->stacknleft = stacknleft;
8371 xmark = xmark->marknext;
8375 char *oldspace = stacknxt;
8376 int oldlen = stacknleft;
8377 char *p = stalloc(newlen);
8379 /* free the space we just allocated */
8380 stacknxt = memcpy(p, oldspace, oldlen);
8381 stacknleft += newlen;
8386 grabstackblock(size_t len)
8388 len = SHELL_ALIGN(len);
8394 * The following routines are somewhat easier to use than the above.
8395 * The user declares a variable of type STACKSTR, which may be declared
8396 * to be a register. The macro STARTSTACKSTR initializes things. Then
8397 * the user uses the macro STPUTC to add characters to the string. In
8398 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8399 * grown as necessary. When the user is done, she can just leave the
8400 * string there and refer to it using stackblock(). Or she can allocate
8401 * the space for it using grabstackstr(). If it is necessary to allow
8402 * someone else to use the stack temporarily and then continue to grow
8403 * the string, the user should use grabstack to allocate the space, and
8404 * then call ungrabstr(p) to return to the previous mode of operation.
8406 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8407 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8408 * is space for at least one character.
8414 size_t len = stackblocksize();
8415 if (herefd >= 0 && len >= 1024) {
8416 bb_full_write(herefd, stackblock(), len);
8417 return stackblock();
8420 return stackblock() + len;
8424 * Called from CHECKSTRSPACE.
8428 makestrspace(size_t newlen, char *p)
8430 size_t len = p - stacknxt;
8431 size_t size = stackblocksize();
8436 size = stackblocksize();
8438 if (nleft >= newlen)
8442 return stackblock() + len;
8446 stnputs(const char *s, size_t n, char *p)
8448 p = makestrspace(n, p);
8449 p = mempcpy(p, s, n);
8454 stputs(const char *s, char *p)
8456 return stnputs(s, strlen(s), p);
8459 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8464 * number(s) Convert a string of digits to an integer.
8465 * is_number(s) Return true if s is a string of digits.
8469 * prefix -- see if pfx is a prefix of string.
8473 prefix(const char *string, const char *pfx)
8476 if (*pfx++ != *string++)
8479 return (char *) string;
8484 * Convert a string of digits to an integer, printing an error message on
8489 number(const char *s)
8499 * Check for a valid number. This should be elsewhere.
8503 is_number(const char *p)
8508 } while (*++p != '\0');
8514 * Produce a possibly single quoted string suitable as input to the shell.
8515 * The return string is allocated on the stack.
8519 single_quote(const char *s) {
8528 len = strchrnul(s, '\'') - s;
8530 q = p = makestrspace(len + 3, p);
8533 q = mempcpy(q, s, len);
8539 len = strspn(s, "'");
8543 q = p = makestrspace(len + 3, p);
8546 q = mempcpy(q, s, len);
8555 return stackblock();
8559 * Like strdup but works with the ash stack.
8563 sstrdup(const char *p)
8565 size_t len = strlen(p) + 1;
8566 return memcpy(stalloc(len), p, len);
8571 calcsize(union node *n)
8575 funcblocksize += nodesize[n->type];
8578 calcsize(n->ncmd.redirect);
8579 calcsize(n->ncmd.args);
8580 calcsize(n->ncmd.assign);
8583 sizenodelist(n->npipe.cmdlist);
8588 calcsize(n->nredir.redirect);
8589 calcsize(n->nredir.n);
8596 calcsize(n->nbinary.ch2);
8597 calcsize(n->nbinary.ch1);
8600 calcsize(n->nif.elsepart);
8601 calcsize(n->nif.ifpart);
8602 calcsize(n->nif.test);
8605 funcstringsize += strlen(n->nfor.var) + 1;
8606 calcsize(n->nfor.body);
8607 calcsize(n->nfor.args);
8610 calcsize(n->ncase.cases);
8611 calcsize(n->ncase.expr);
8614 calcsize(n->nclist.body);
8615 calcsize(n->nclist.pattern);
8616 calcsize(n->nclist.next);
8620 sizenodelist(n->narg.backquote);
8621 funcstringsize += strlen(n->narg.text) + 1;
8622 calcsize(n->narg.next);
8629 calcsize(n->nfile.fname);
8630 calcsize(n->nfile.next);
8634 calcsize(n->ndup.vname);
8635 calcsize(n->ndup.next);
8639 calcsize(n->nhere.doc);
8640 calcsize(n->nhere.next);
8643 calcsize(n->nnot.com);
8650 sizenodelist(struct nodelist *lp)
8653 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8661 copynode(union node *n)
8668 funcblock = (char *) funcblock + nodesize[n->type];
8671 new->ncmd.redirect = copynode(n->ncmd.redirect);
8672 new->ncmd.args = copynode(n->ncmd.args);
8673 new->ncmd.assign = copynode(n->ncmd.assign);
8676 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8677 new->npipe.backgnd = n->npipe.backgnd;
8682 new->nredir.redirect = copynode(n->nredir.redirect);
8683 new->nredir.n = copynode(n->nredir.n);
8690 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8691 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8694 new->nif.elsepart = copynode(n->nif.elsepart);
8695 new->nif.ifpart = copynode(n->nif.ifpart);
8696 new->nif.test = copynode(n->nif.test);
8699 new->nfor.var = nodesavestr(n->nfor.var);
8700 new->nfor.body = copynode(n->nfor.body);
8701 new->nfor.args = copynode(n->nfor.args);
8704 new->ncase.cases = copynode(n->ncase.cases);
8705 new->ncase.expr = copynode(n->ncase.expr);
8708 new->nclist.body = copynode(n->nclist.body);
8709 new->nclist.pattern = copynode(n->nclist.pattern);
8710 new->nclist.next = copynode(n->nclist.next);
8714 new->narg.backquote = copynodelist(n->narg.backquote);
8715 new->narg.text = nodesavestr(n->narg.text);
8716 new->narg.next = copynode(n->narg.next);
8723 new->nfile.fname = copynode(n->nfile.fname);
8724 new->nfile.fd = n->nfile.fd;
8725 new->nfile.next = copynode(n->nfile.next);
8729 new->ndup.vname = copynode(n->ndup.vname);
8730 new->ndup.dupfd = n->ndup.dupfd;
8731 new->ndup.fd = n->ndup.fd;
8732 new->ndup.next = copynode(n->ndup.next);
8736 new->nhere.doc = copynode(n->nhere.doc);
8737 new->nhere.fd = n->nhere.fd;
8738 new->nhere.next = copynode(n->nhere.next);
8741 new->nnot.com = copynode(n->nnot.com);
8744 new->type = n->type;
8749 static struct nodelist *
8750 copynodelist(struct nodelist *lp)
8752 struct nodelist *start;
8753 struct nodelist **lpp;
8758 funcblock = (char *) funcblock +
8759 SHELL_ALIGN(sizeof(struct nodelist));
8760 (*lpp)->n = copynode(lp->n);
8762 lpp = &(*lpp)->next;
8770 nodesavestr(char *s)
8772 char *rtn = funcstring;
8774 funcstring = stpcpy(funcstring, s) + 1;
8780 * Free a parse tree.
8784 freefunc(struct funcnode *f)
8786 if (f && --f->count < 0)
8791 static void options(int);
8792 static void setoption(int, int);
8796 * Process the shell command line arguments.
8800 procargs(int argc, char **argv)
8803 const char *xminusc;
8810 for (i = 0; i < NOPTS; i++)
8816 if (*xargv == NULL) {
8818 error("-c requires an argument");
8821 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8825 for (i = 0; i < NOPTS; i++)
8826 if (optlist[i] == 2)
8831 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8836 } else if (!sflag) {
8837 setinputfile(*xargv, 0);
8843 shellparam.p = xargv;
8844 #ifdef CONFIG_ASH_GETOPTS
8845 shellparam.optind = 1;
8846 shellparam.optoff = -1;
8848 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8850 shellparam.nparam++;
8863 setinteractive(iflag);
8868 minus_o(char *name, int val)
8873 out1str("Current option settings\n");
8874 for (i = 0; i < NOPTS; i++)
8875 out1fmt("%-16s%s\n", optnames(i),
8876 optlist[i] ? "on" : "off");
8878 for (i = 0; i < NOPTS; i++)
8879 if (equal(name, optnames(i))) {
8883 error("Illegal option -o %s", name);
8888 * Process shell options. The global variable argptr contains a pointer
8889 * to the argument list; we advance it past the options.
8893 options(int cmdline)
8901 while ((p = *argptr) != NULL) {
8903 if ((c = *p++) == '-') {
8905 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8907 /* "-" means turn off -x and -v */
8910 /* "--" means reset params */
8911 else if (*argptr == NULL)
8914 break; /* "-" or "--" terminates options */
8916 } else if (c == '+') {
8922 while ((c = *p++) != '\0') {
8923 if (c == 'c' && cmdline) {
8924 minusc = p; /* command is after shell args*/
8925 } else if (c == 'o') {
8926 minus_o(*argptr, val);
8929 } else if (cmdline && (c == '-')) { // long options
8930 if (strcmp(p, "login") == 0)
8942 setoption(int flag, int val)
8946 for (i = 0; i < NOPTS; i++)
8947 if (optletters(i) == flag) {
8951 error("Illegal option -%c", flag);
8958 * Set the shell parameters.
8962 setparam(char **argv)
8968 for (nparam = 0 ; argv[nparam] ; nparam++);
8969 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8971 *ap++ = savestr(*argv++);
8974 freeparam(&shellparam);
8975 shellparam.malloc = 1;
8976 shellparam.nparam = nparam;
8977 shellparam.p = newparam;
8978 #ifdef CONFIG_ASH_GETOPTS
8979 shellparam.optind = 1;
8980 shellparam.optoff = -1;
8986 * Free the list of positional parameters.
8990 freeparam(volatile struct shparam *param)
8994 if (param->malloc) {
8995 for (ap = param->p ; *ap ; ap++)
9004 * The shift builtin command.
9008 shiftcmd(int argc, char **argv)
9015 n = number(argv[1]);
9016 if (n > shellparam.nparam)
9017 error("can't shift that many");
9019 shellparam.nparam -= n;
9020 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9021 if (shellparam.malloc)
9025 while ((*ap2++ = *ap1++) != NULL);
9026 #ifdef CONFIG_ASH_GETOPTS
9027 shellparam.optind = 1;
9028 shellparam.optoff = -1;
9037 * The set command builtin.
9041 setcmd(int argc, char **argv)
9044 return showvars(nullstr, 0, VUNSET);
9048 if (*argptr != NULL) {
9056 #ifdef CONFIG_ASH_GETOPTS
9061 shellparam.optind = number(value);
9062 shellparam.optoff = -1;
9066 #ifdef CONFIG_LOCALE_SUPPORT
9067 static void change_lc_all(const char *value)
9069 if (value != 0 && *value != 0)
9070 setlocale(LC_ALL, value);
9073 static void change_lc_ctype(const char *value)
9075 if (value != 0 && *value != 0)
9076 setlocale(LC_CTYPE, value);
9081 #ifdef CONFIG_ASH_RANDOM_SUPPORT
9082 /* Roughly copied from bash.. */
9083 static void change_random(const char *value)
9086 /* "get", generate */
9089 rseed = rseed * 1103515245 + 12345;
9090 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9091 /* set without recursion */
9092 setvar(vrandom.text, buf, VNOFUNC);
9093 vrandom.flags &= ~VNOFUNC;
9096 rseed = strtoul(value, (char **)NULL, 10);
9102 #ifdef CONFIG_ASH_GETOPTS
9104 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9113 if(*param_optind < 1)
9115 optnext = optfirst + *param_optind - 1;
9117 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9120 p = optnext[-1] + *optoff;
9121 if (p == NULL || *p == '\0') {
9122 /* Current word is done, advance */
9124 if (p == NULL || *p != '-' || *++p == '\0') {
9131 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9136 for (q = optstr; *q != c; ) {
9138 if (optstr[0] == ':') {
9141 err |= setvarsafe("OPTARG", s, 0);
9143 fprintf(stderr, "Illegal option -%c\n", c);
9144 (void) unsetvar("OPTARG");
9154 if (*p == '\0' && (p = *optnext) == NULL) {
9155 if (optstr[0] == ':') {
9158 err |= setvarsafe("OPTARG", s, 0);
9161 fprintf(stderr, "No arg for -%c option\n", c);
9162 (void) unsetvar("OPTARG");
9170 err |= setvarsafe("OPTARG", p, 0);
9173 err |= setvarsafe("OPTARG", nullstr, 0);
9176 *optoff = p ? p - *(optnext - 1) : -1;
9177 *param_optind = optnext - optfirst + 1;
9178 fmtstr(s, sizeof(s), "%d", *param_optind);
9179 err |= setvarsafe("OPTIND", s, VNOFUNC);
9182 err |= setvarsafe(optvar, s, 0);
9193 * The getopts builtin. Shellparam.optnext points to the next argument
9194 * to be processed. Shellparam.optptr points to the next character to
9195 * be processed in the current argument. If shellparam.optnext is NULL,
9196 * then it's the first time getopts has been called.
9200 getoptscmd(int argc, char **argv)
9205 error("Usage: getopts optstring var [arg]");
9206 else if (argc == 3) {
9207 optbase = shellparam.p;
9208 if (shellparam.optind > shellparam.nparam + 1) {
9209 shellparam.optind = 1;
9210 shellparam.optoff = -1;
9215 if (shellparam.optind > argc - 2) {
9216 shellparam.optind = 1;
9217 shellparam.optoff = -1;
9221 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9222 &shellparam.optoff);
9224 #endif /* CONFIG_ASH_GETOPTS */
9227 * XXX - should get rid of. have all builtins use getopt(3). the
9228 * library getopt must have the BSD extension static variable "optreset"
9229 * otherwise it can't be used within the shell safely.
9231 * Standard option processing (a la getopt) for builtin routines. The
9232 * only argument that is passed to nextopt is the option string; the
9233 * other arguments are unnecessary. It return the character, or '\0' on
9238 nextopt(const char *optstring)
9244 if ((p = optptr) == NULL || *p == '\0') {
9246 if (p == NULL || *p != '-' || *++p == '\0')
9249 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9253 for (q = optstring ; *q != c ; ) {
9255 error("Illegal option -%c", c);
9260 if (*p == '\0' && (p = *argptr++) == NULL)
9261 error("No arg for -%c option", c);
9270 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9273 outstr(const char *p, FILE *file)
9298 outcslow(int c, FILE *dest)
9308 out1fmt(const char *fmt, ...)
9315 r = vprintf(fmt, ap);
9323 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9330 ret = vsnprintf(outbuf, length, fmt, ap);
9338 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9342 * Shell command parser.
9345 #define EOFMARKLEN 79
9349 struct heredoc *next; /* next here document in list */
9350 union node *here; /* redirection node */
9351 char *eofmark; /* string indicating end of input */
9352 int striptabs; /* if set, strip leading tabs */
9357 static struct heredoc *heredoclist; /* list of here documents to read */
9360 static union node *list(int);
9361 static union node *andor(void);
9362 static union node *pipeline(void);
9363 static union node *command(void);
9364 static union node *simplecmd(void);
9365 static union node *makename(void);
9366 static void parsefname(void);
9367 static void parseheredoc(void);
9368 static char peektoken(void);
9369 static int readtoken(void);
9370 static int xxreadtoken(void);
9371 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9372 static int noexpand(char *);
9373 static void synexpect(int) __attribute__((__noreturn__));
9374 static void synerror(const char *) __attribute__((__noreturn__));
9375 static void setprompt(int);
9381 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9382 * valid parse tree indicating a blank line.)
9386 parsecmd(int interact)
9391 doprompt = interact;
9393 setprompt(doprompt);
9408 union node *n1, *n2, *n3;
9411 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9412 if (nlflag == 2 && peektoken())
9418 if (tok == TBACKGND) {
9419 if (n2->type == NPIPE) {
9420 n2->npipe.backgnd = 1;
9422 if (n2->type != NREDIR) {
9423 n3 = stalloc(sizeof(struct nredir));
9425 n3->nredir.redirect = NULL;
9428 n2->type = NBACKGND;
9435 n3 = (union node *)stalloc(sizeof (struct nbinary));
9437 n3->nbinary.ch1 = n1;
9438 n3->nbinary.ch2 = n2;
9454 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9462 pungetc(); /* push back EOF on input */
9478 union node *n1, *n2, *n3;
9483 if ((t = readtoken()) == TAND) {
9485 } else if (t == TOR) {
9491 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9493 n3 = (union node *)stalloc(sizeof (struct nbinary));
9495 n3->nbinary.ch1 = n1;
9496 n3->nbinary.ch2 = n2;
9506 union node *n1, *n2, *pipenode;
9507 struct nodelist *lp, *prev;
9511 TRACE(("pipeline: entered\n"));
9512 if (readtoken() == TNOT) {
9514 checkkwd = CHKKWD | CHKALIAS;
9518 if (readtoken() == TPIPE) {
9519 pipenode = (union node *)stalloc(sizeof (struct npipe));
9520 pipenode->type = NPIPE;
9521 pipenode->npipe.backgnd = 0;
9522 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9523 pipenode->npipe.cmdlist = lp;
9527 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9528 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9531 } while (readtoken() == TPIPE);
9537 n2 = (union node *)stalloc(sizeof (struct nnot));
9550 union node *n1, *n2;
9551 union node *ap, **app;
9552 union node *cp, **cpp;
9553 union node *redir, **rpp;
9560 switch (readtoken()) {
9565 n1 = (union node *)stalloc(sizeof (struct nif));
9567 n1->nif.test = list(0);
9568 if (readtoken() != TTHEN)
9570 n1->nif.ifpart = list(0);
9572 while (readtoken() == TELIF) {
9573 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9574 n2 = n2->nif.elsepart;
9576 n2->nif.test = list(0);
9577 if (readtoken() != TTHEN)
9579 n2->nif.ifpart = list(0);
9581 if (lasttoken == TELSE)
9582 n2->nif.elsepart = list(0);
9584 n2->nif.elsepart = NULL;
9592 n1 = (union node *)stalloc(sizeof (struct nbinary));
9593 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9594 n1->nbinary.ch1 = list(0);
9595 if ((got=readtoken()) != TDO) {
9596 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9599 n1->nbinary.ch2 = list(0);
9604 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9605 synerror("Bad for loop variable");
9606 n1 = (union node *)stalloc(sizeof (struct nfor));
9608 n1->nfor.var = wordtext;
9609 checkkwd = CHKKWD | CHKALIAS;
9610 if (readtoken() == TIN) {
9612 while (readtoken() == TWORD) {
9613 n2 = (union node *)stalloc(sizeof (struct narg));
9615 n2->narg.text = wordtext;
9616 n2->narg.backquote = backquotelist;
9618 app = &n2->narg.next;
9622 if (lasttoken != TNL && lasttoken != TSEMI)
9625 n2 = (union node *)stalloc(sizeof (struct narg));
9627 n2->narg.text = (char *)dolatstr;
9628 n2->narg.backquote = NULL;
9629 n2->narg.next = NULL;
9632 * Newline or semicolon here is optional (but note
9633 * that the original Bourne shell only allowed NL).
9635 if (lasttoken != TNL && lasttoken != TSEMI)
9638 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9639 if (readtoken() != TDO)
9641 n1->nfor.body = list(0);
9645 n1 = (union node *)stalloc(sizeof (struct ncase));
9647 if (readtoken() != TWORD)
9649 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9651 n2->narg.text = wordtext;
9652 n2->narg.backquote = backquotelist;
9653 n2->narg.next = NULL;
9655 checkkwd = CHKKWD | CHKALIAS;
9656 } while (readtoken() == TNL);
9657 if (lasttoken != TIN)
9659 cpp = &n1->ncase.cases;
9661 checkkwd = CHKNL | CHKKWD;
9664 if (lasttoken == TLP)
9666 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9668 app = &cp->nclist.pattern;
9670 *app = ap = (union node *)stalloc(sizeof (struct narg));
9672 ap->narg.text = wordtext;
9673 ap->narg.backquote = backquotelist;
9674 if (readtoken() != TPIPE)
9676 app = &ap->narg.next;
9679 ap->narg.next = NULL;
9680 if (lasttoken != TRP)
9682 cp->nclist.body = list(2);
9684 cpp = &cp->nclist.next;
9686 checkkwd = CHKNL | CHKKWD;
9687 if ((t = readtoken()) != TESAC) {
9689 synexpect(TENDCASE);
9697 n1 = (union node *)stalloc(sizeof (struct nredir));
9698 n1->type = NSUBSHELL;
9699 n1->nredir.n = list(0);
9700 n1->nredir.redirect = NULL;
9713 if (readtoken() != t)
9717 /* Now check for redirection which may follow command */
9718 checkkwd = CHKKWD | CHKALIAS;
9720 while (readtoken() == TREDIR) {
9721 *rpp = n2 = redirnode;
9722 rpp = &n2->nfile.next;
9728 if (n1->type != NSUBSHELL) {
9729 n2 = (union node *)stalloc(sizeof (struct nredir));
9734 n1->nredir.redirect = redir;
9743 union node *args, **app;
9744 union node *n = NULL;
9745 union node *vars, **vpp;
9746 union node **rpp, *redir;
9756 savecheckkwd = CHKALIAS;
9758 checkkwd = savecheckkwd;
9759 switch (readtoken()) {
9761 n = (union node *)stalloc(sizeof (struct narg));
9763 n->narg.text = wordtext;
9764 n->narg.backquote = backquotelist;
9765 if (savecheckkwd && isassignment(wordtext)) {
9767 vpp = &n->narg.next;
9770 app = &n->narg.next;
9775 *rpp = n = redirnode;
9776 rpp = &n->nfile.next;
9777 parsefname(); /* read name of redirection file */
9781 args && app == &args->narg.next &&
9784 struct builtincmd *bcmd;
9787 /* We have a function */
9788 if (readtoken() != TRP)
9790 name = n->narg.text;
9792 !goodname(name) || (
9793 (bcmd = find_builtin(name)) &&
9794 IS_BUILTIN_SPECIAL(bcmd)
9797 synerror("Bad function name");
9799 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9800 n->narg.next = command();
9813 n = (union node *)stalloc(sizeof (struct ncmd));
9815 n->ncmd.args = args;
9816 n->ncmd.assign = vars;
9817 n->ncmd.redirect = redir;
9826 n = (union node *)stalloc(sizeof (struct narg));
9828 n->narg.next = NULL;
9829 n->narg.text = wordtext;
9830 n->narg.backquote = backquotelist;
9834 void fixredir(union node *n, const char *text, int err)
9836 TRACE(("Fix redir %s %d\n", text, err));
9838 n->ndup.vname = NULL;
9840 if (is_digit(text[0]) && text[1] == '\0')
9841 n->ndup.dupfd = digit_val(text[0]);
9842 else if (text[0] == '-' && text[1] == '\0')
9847 synerror("Bad fd number");
9849 n->ndup.vname = makename();
9857 union node *n = redirnode;
9859 if (readtoken() != TWORD)
9861 if (n->type == NHERE) {
9862 struct heredoc *here = heredoc;
9868 TRACE(("Here document %d\n", n->type));
9869 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9870 synerror("Illegal eof marker for << redirection");
9871 rmescapes(wordtext);
9872 here->eofmark = wordtext;
9874 if (heredoclist == NULL)
9877 for (p = heredoclist ; p->next ; p = p->next);
9880 } else if (n->type == NTOFD || n->type == NFROMFD) {
9881 fixredir(n, wordtext, 0);
9883 n->nfile.fname = makename();
9889 * Input any here documents.
9895 struct heredoc *here;
9906 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9907 here->eofmark, here->striptabs);
9908 n = (union node *)stalloc(sizeof (struct narg));
9909 n->narg.type = NARG;
9910 n->narg.next = NULL;
9911 n->narg.text = wordtext;
9912 n->narg.backquote = backquotelist;
9913 here->here->nhere.doc = n;
9918 static char peektoken(void)
9924 return tokname_array[t][0];
9932 int alreadyseen = tokpushback;
9935 #ifdef CONFIG_ASH_ALIAS
9944 if (checkkwd & CHKNL) {
9951 if (t != TWORD || quoteflag) {
9956 * check for keywords
9958 if (checkkwd & CHKKWD) {
9959 const char *const *pp;
9961 if ((pp = findkwd(wordtext))) {
9962 lasttoken = t = pp - tokname_array;
9963 TRACE(("keyword %s recognized\n", tokname(t)));
9968 if (checkkwd & CHKALIAS) {
9969 #ifdef CONFIG_ASH_ALIAS
9971 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9973 pushstring(ap->val, ap);
9983 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9985 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9992 * Read the next input token.
9993 * If the token is a word, we set backquotelist to the list of cmds in
9994 * backquotes. We set quoteflag to true if any part of the word was
9996 * If the token is TREDIR, then we set redirnode to a structure containing
9998 * In all cases, the variable startlinno is set to the number of the line
9999 * on which the token starts.
10001 * [Change comment: here documents and internal procedures]
10002 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10003 * word parsing code into a separate routine. In this case, readtoken
10004 * doesn't need to have any internal procedures, but parseword does.
10005 * We could also make parseoperator in essence the main routine, and
10006 * have parseword (readtoken1?) handle both words and redirection.]
10009 #define NEW_xxreadtoken
10010 #ifdef NEW_xxreadtoken
10012 /* singles must be first! */
10013 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10015 static const char xxreadtoken_tokens[] = {
10016 TNL, TLP, TRP, /* only single occurrence allowed */
10017 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10018 TEOF, /* corresponds to trailing nul */
10019 TAND, TOR, TENDCASE, /* if double occurrence */
10022 #define xxreadtoken_doubles \
10023 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10024 #define xxreadtoken_singles \
10025 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10027 static int xxreadtoken()
10039 startlinno = plinno;
10040 for (;;) { /* until token or start of word found */
10043 if ((c != ' ') && (c != '\t')
10044 #ifdef CONFIG_ASH_ALIAS
10049 while ((c = pgetc()) != '\n' && c != PEOF);
10051 } else if (c == '\\') {
10052 if (pgetc() != '\n') {
10056 startlinno = ++plinno;
10061 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10066 needprompt = doprompt;
10069 p = strchr(xxreadtoken_chars, c);
10072 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10075 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10076 if (pgetc() == *p) { /* double occurrence? */
10077 p += xxreadtoken_doubles + 1;
10084 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10092 #define RETURN(token) return lasttoken = token
10107 startlinno = plinno;
10108 for (;;) { /* until token or start of word found */
10111 case ' ': case '\t':
10112 #ifdef CONFIG_ASH_ALIAS
10117 while ((c = pgetc()) != '\n' && c != PEOF);
10121 if (pgetc() == '\n') {
10122 startlinno = ++plinno;
10131 needprompt = doprompt;
10136 if (pgetc() == '&')
10141 if (pgetc() == '|')
10146 if (pgetc() == ';')
10159 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10162 #endif /* NEW_xxreadtoken */
10166 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10167 * is not NULL, read a here document. In the latter case, eofmark is the
10168 * word which marks the end of the document and striptabs is true if
10169 * leading tabs should be stripped from the document. The argument firstc
10170 * is the first character of the input token or document.
10172 * Because C does not have internal subroutines, I have simulated them
10173 * using goto's to implement the subroutine linkage. The following macros
10174 * will run code that appears at the end of readtoken1.
10177 #define CHECKEND() {goto checkend; checkend_return:;}
10178 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10179 #define PARSESUB() {goto parsesub; parsesub_return:;}
10180 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10181 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10182 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10185 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10190 char line[EOFMARKLEN + 1];
10191 struct nodelist *bqlist;
10194 int varnest; /* levels of variables expansion */
10195 int arinest; /* levels of arithmetic expansion */
10196 int parenlevel; /* levels of parens in arithmetic */
10197 int dqvarnest; /* levels of variables expansion within double quotes */
10199 int prevsyntax; /* syntax before arithmetic */
10201 /* Avoid longjmp clobbering */
10207 (void) &parenlevel;
10210 (void) &prevsyntax;
10214 startlinno = plinno;
10216 if (syntax == DQSYNTAX)
10225 STARTSTACKSTR(out);
10226 loop: { /* for each line, until end of word */
10227 CHECKEND(); /* set c to PEOF if at end of here document */
10228 for (;;) { /* until end of line or end of word */
10229 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10230 switch(SIT(c, syntax)) {
10231 case CNL: /* '\n' */
10232 if (syntax == BASESYNTAX)
10233 goto endword; /* exit outer loop */
10239 goto loop; /* continue outer loop */
10244 if (eofmark == NULL || dblquote)
10245 USTPUTC(CTLESC, out);
10248 case CBACK: /* backslash */
10251 USTPUTC(CTLESC, out);
10252 USTPUTC('\\', out);
10254 } else if (c == '\n') {
10260 c != '\\' && c != '`' &&
10266 USTPUTC(CTLESC, out);
10267 USTPUTC('\\', out);
10269 if (SIT(c, SQSYNTAX) == CCTL)
10270 USTPUTC(CTLESC, out);
10278 if (eofmark == NULL) {
10279 USTPUTC(CTLQUOTEMARK, out);
10287 if (eofmark != NULL && arinest == 0 &&
10291 if (dqvarnest == 0) {
10292 syntax = BASESYNTAX;
10299 case CVAR: /* '$' */
10300 PARSESUB(); /* parse substitution */
10302 case CENDVAR: /* '}' */
10305 if (dqvarnest > 0) {
10308 USTPUTC(CTLENDVAR, out);
10313 #ifdef CONFIG_ASH_MATH_SUPPORT
10314 case CLP: /* '(' in arithmetic */
10318 case CRP: /* ')' in arithmetic */
10319 if (parenlevel > 0) {
10323 if (pgetc() == ')') {
10324 if (--arinest == 0) {
10325 USTPUTC(CTLENDARI, out);
10326 syntax = prevsyntax;
10327 if (syntax == DQSYNTAX)
10335 * unbalanced parens
10336 * (don't 2nd guess - no error)
10344 case CBQUOTE: /* '`' */
10348 goto endword; /* exit outer loop */
10353 goto endword; /* exit outer loop */
10354 #ifdef CONFIG_ASH_ALIAS
10364 #ifdef CONFIG_ASH_MATH_SUPPORT
10365 if (syntax == ARISYNTAX)
10366 synerror("Missing '))'");
10368 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10369 synerror("Unterminated quoted string");
10370 if (varnest != 0) {
10371 startlinno = plinno;
10373 synerror("Missing '}'");
10375 USTPUTC('\0', out);
10376 len = out - (char *)stackblock();
10377 out = stackblock();
10378 if (eofmark == NULL) {
10379 if ((c == '>' || c == '<')
10382 && (*out == '\0' || is_digit(*out))) {
10384 return lasttoken = TREDIR;
10389 quoteflag = quotef;
10390 backquotelist = bqlist;
10391 grabstackblock(len);
10393 return lasttoken = TWORD;
10394 /* end of readtoken routine */
10399 * Check to see whether we are at the end of the here document. When this
10400 * is called, c is set to the first character of the next input line. If
10401 * we are at the end of the here document, this routine sets the c to PEOF.
10406 #ifdef CONFIG_ASH_ALIAS
10412 while (c == '\t') {
10416 if (c == *eofmark) {
10417 if (pfgets(line, sizeof line) != NULL) {
10421 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10422 if (*p == '\n' && *q == '\0') {
10425 needprompt = doprompt;
10427 pushstring(line, NULL);
10432 goto checkend_return;
10437 * Parse a redirection operator. The variable "out" points to a string
10438 * specifying the fd to be redirected. The variable "c" contains the
10439 * first character of the redirection operator.
10446 np = (union node *)stalloc(sizeof (struct nfile));
10451 np->type = NAPPEND;
10453 np->type = NCLOBBER;
10460 } else { /* c == '<' */
10462 switch (c = pgetc()) {
10464 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10465 np = (union node *)stalloc(sizeof (struct nhere));
10469 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10470 heredoc->here = np;
10471 if ((c = pgetc()) == '-') {
10472 heredoc->striptabs = 1;
10474 heredoc->striptabs = 0;
10480 np->type = NFROMFD;
10484 np->type = NFROMTO;
10494 np->nfile.fd = digit_val(fd);
10496 goto parseredir_return;
10501 * Parse a substitution. At this point, we have read the dollar sign
10502 * and nothing else.
10510 static const char types[] = "}-+?=";
10514 c <= PEOA_OR_PEOF ||
10515 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10519 } else if (c == '(') { /* $(command) or $((arith)) */
10520 if (pgetc() == '(') {
10521 #ifdef CONFIG_ASH_MATH_SUPPORT
10524 synerror("We unsupport $((arith))");
10531 USTPUTC(CTLVAR, out);
10532 typeloc = out - (char *)stackblock();
10533 USTPUTC(VSNORMAL, out);
10534 subtype = VSNORMAL;
10538 if ((c = pgetc()) == '}')
10541 subtype = VSLENGTH;
10546 if (c > PEOA_OR_PEOF && is_name(c)) {
10550 } while (c > PEOA_OR_PEOF && is_in_name(c));
10551 } else if (is_digit(c)) {
10555 } while (is_digit(c));
10557 else if (is_special(c)) {
10562 badsub: synerror("Bad substitution");
10566 if (subtype == 0) {
10573 p = strchr(types, c);
10576 subtype = p - types + VSNORMAL;
10582 subtype = c == '#' ? VSTRIMLEFT :
10595 if (dblquote || arinest)
10597 *((char *)stackblock() + typeloc) = subtype | flags;
10598 if (subtype != VSNORMAL) {
10600 if (dblquote || arinest) {
10605 goto parsesub_return;
10610 * Called to parse command substitutions. Newstyle is set if the command
10611 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10612 * list of commands (passed by reference), and savelen is the number of
10613 * characters on the top of the stack which must be preserved.
10617 struct nodelist **nlpp;
10620 char *volatile str;
10621 struct jmploc jmploc;
10622 struct jmploc *volatile savehandler;
10626 (void) &saveprompt;
10629 savepbq = parsebackquote;
10630 if (setjmp(jmploc.loc)) {
10633 parsebackquote = 0;
10634 handler = savehandler;
10635 longjmp(handler->loc, 1);
10639 savelen = out - (char *)stackblock();
10641 str = ckmalloc(savelen);
10642 memcpy(str, stackblock(), savelen);
10644 savehandler = handler;
10648 /* We must read until the closing backquote, giving special
10649 treatment to some slashes, and then push the string and
10650 reread it as input, interpreting it normally. */
10657 STARTSTACKSTR(pout);
10663 switch (pc = pgetc()) {
10668 if ((pc = pgetc()) == '\n') {
10673 * If eating a newline, avoid putting
10674 * the newline into the new character
10675 * stream (via the STPUTC after the
10680 if (pc != '\\' && pc != '`' && pc != '$'
10681 && (!dblquote || pc != '"'))
10682 STPUTC('\\', pout);
10683 if (pc > PEOA_OR_PEOF) {
10689 #ifdef CONFIG_ASH_ALIAS
10692 startlinno = plinno;
10693 synerror("EOF in backquote substitution");
10697 needprompt = doprompt;
10706 STPUTC('\0', pout);
10707 psavelen = pout - (char *)stackblock();
10708 if (psavelen > 0) {
10709 pstr = grabstackstr(pout);
10710 setinputstring(pstr);
10715 nlpp = &(*nlpp)->next;
10716 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10717 (*nlpp)->next = NULL;
10718 parsebackquote = oldstyle;
10721 saveprompt = doprompt;
10728 doprompt = saveprompt;
10730 if (readtoken() != TRP)
10737 * Start reading from old file again, ignoring any pushed back
10738 * tokens left from the backquote parsing
10743 while (stackblocksize() <= savelen)
10745 STARTSTACKSTR(out);
10747 memcpy(out, str, savelen);
10748 STADJUST(savelen, out);
10754 parsebackquote = savepbq;
10755 handler = savehandler;
10756 if (arinest || dblquote)
10757 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10759 USTPUTC(CTLBACKQ, out);
10761 goto parsebackq_oldreturn;
10763 goto parsebackq_newreturn;
10766 #ifdef CONFIG_ASH_MATH_SUPPORT
10768 * Parse an arithmetic expansion (indicate start of one and set state)
10772 if (++arinest == 1) {
10773 prevsyntax = syntax;
10774 syntax = ARISYNTAX;
10775 USTPUTC(CTLARI, out);
10782 * we collapse embedded arithmetic expansion to
10783 * parenthesis, which should be equivalent
10787 goto parsearith_return;
10791 } /* end of readtoken */
10796 * Returns true if the text contains nothing to expand (no dollar signs
10801 noexpand(char *text)
10807 while ((c = *p++) != '\0') {
10808 if (c == CTLQUOTEMARK)
10812 else if (SIT(c, BASESYNTAX) == CCTL)
10820 * Return of a legal variable name (a letter or underscore followed by zero or
10821 * more letters, underscores, and digits).
10825 endofname(const char *name)
10833 if (! is_in_name(*p))
10841 * Called when an unexpected token is read during the parse. The argument
10842 * is the token that is expected, or -1 if more than one type of token can
10843 * occur at this point.
10846 static void synexpect(int token)
10851 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10853 sprintf(msg + l, " (expecting %s)", tokname(token));
10859 synerror(const char *msg)
10861 error("Syntax error: %s", msg);
10867 * called by editline -- any expansions to the prompt
10868 * should be added here.
10871 static void setprompt(int whichprompt)
10873 const char *prompt;
10875 switch (whichprompt) {
10889 static const char *const *findkwd(const char *s)
10891 return bsearch(s, tokname_array + KWDOFFSET,
10892 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10893 sizeof(const char *), pstrcmp);
10896 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10899 * Code for dealing with input/output redirection.
10902 #define EMPTY -2 /* marks an unused slot in redirtab */
10904 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10906 # define PIPESIZE PIPE_BUF
10910 * Open a file in noclobber mode.
10911 * The code was copied from bash.
10914 noclobberopen(const char *fname)
10917 struct stat finfo, finfo2;
10920 * If the file exists and is a regular file, return an error
10923 r = stat(fname, &finfo);
10924 if (r == 0 && S_ISREG(finfo.st_mode)) {
10930 * If the file was not present (r != 0), make sure we open it
10931 * exclusively so that if it is created before we open it, our open
10932 * will fail. Make sure that we do not truncate an existing file.
10933 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10934 * file was not a regular file, we leave O_EXCL off.
10937 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10938 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10940 /* If the open failed, return the file descriptor right away. */
10945 * OK, the open succeeded, but the file may have been changed from a
10946 * non-regular file to a regular file between the stat and the open.
10947 * We are assuming that the O_EXCL open handles the case where FILENAME
10948 * did not exist and is symlinked to an existing file between the stat
10953 * If we can open it and fstat the file descriptor, and neither check
10954 * revealed that it was a regular file, and the file has not been
10955 * replaced, return the file descriptor.
10957 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10958 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10961 /* The file has been replaced. badness. */
10968 * Handle here documents. Normally we fork off a process to write the
10969 * data to a pipe. If the document is short, we can stuff the data in
10970 * the pipe without forking.
10974 openhere(union node *redir)
10980 error("Pipe call failed");
10981 if (redir->type == NHERE) {
10982 len = strlen(redir->nhere.doc->narg.text);
10983 if (len <= PIPESIZE) {
10984 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
10988 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10990 signal(SIGINT, SIG_IGN);
10991 signal(SIGQUIT, SIG_IGN);
10992 signal(SIGHUP, SIG_IGN);
10994 signal(SIGTSTP, SIG_IGN);
10996 signal(SIGPIPE, SIG_DFL);
10997 if (redir->type == NHERE)
10998 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
11000 expandhere(redir->nhere.doc, pip[1]);
11009 openredirect(union node *redir)
11014 switch (redir->nfile.type) {
11016 fname = redir->nfile.expfname;
11017 if ((f = open(fname, O_RDONLY)) < 0)
11021 fname = redir->nfile.expfname;
11022 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11026 /* Take care of noclobber mode. */
11028 fname = redir->nfile.expfname;
11029 if ((f = noclobberopen(fname)) < 0)
11035 fname = redir->nfile.expfname;
11036 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11040 fname = redir->nfile.expfname;
11041 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11048 /* Fall through to eliminate warning. */
11055 f = openhere(redir);
11061 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11063 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11067 dupredirect(union node *redir, int f)
11069 int fd = redir->nfile.fd;
11071 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11072 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11073 copyfd(redir->ndup.dupfd, fd);
11086 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11087 * old file descriptors are stashed away so that the redirection can be
11088 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11089 * standard output, and the standard error if it becomes a duplicate of
11090 * stdout, is saved in memory.
11094 redirect(union node *redir, int flags)
11097 struct redirtab *sv;
11108 if (flags & REDIR_PUSH) {
11109 struct redirtab *q;
11110 q = ckmalloc(sizeof (struct redirtab));
11111 q->next = redirlist;
11113 q->nullredirs = nullredirs - 1;
11114 for (i = 0 ; i < 10 ; i++)
11115 q->renamed[i] = EMPTY;
11122 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11123 n->ndup.dupfd == fd)
11124 continue; /* redirect from/to same file descriptor */
11126 newfd = openredirect(n);
11129 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11130 i = fcntl(fd, F_DUPFD, 10);
11137 error("%d: %m", fd);
11147 dupredirect(n, newfd);
11148 } while ((n = n->nfile.next));
11150 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11151 preverrout_fd = sv->renamed[2];
11156 * Undo the effects of the last redirection.
11162 struct redirtab *rp;
11165 if (--nullredirs >= 0)
11169 for (i = 0 ; i < 10 ; i++) {
11170 if (rp->renamed[i] != EMPTY) {
11173 copyfd(rp->renamed[i], i);
11175 close(rp->renamed[i]);
11178 redirlist = rp->next;
11179 nullredirs = rp->nullredirs;
11185 * Undo all redirections. Called on error or interrupt.
11189 * Discard all saved file descriptors.
11193 clearredir(int drop)
11205 * Copy a file descriptor to be >= to. Returns -1
11206 * if the source file descriptor is closed, EMPTY if there are no unused
11207 * file descriptors left.
11211 copyfd(int from, int to)
11215 newfd = fcntl(from, F_DUPFD, to);
11217 if (errno == EMFILE)
11220 error("%d: %m", from);
11227 redirectsafe(union node *redir, int flags)
11230 volatile int saveint;
11231 struct jmploc *volatile savehandler = handler;
11232 struct jmploc jmploc;
11235 if (!(err = setjmp(jmploc.loc) * 2)) {
11237 redirect(redir, flags);
11239 handler = savehandler;
11240 if (err && exception != EXERROR)
11241 longjmp(handler->loc, 1);
11242 RESTOREINT(saveint);
11246 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11249 static void shtree(union node *, int, char *, FILE*);
11250 static void shcmd(union node *, FILE *);
11251 static void sharg(union node *, FILE *);
11252 static void indent(int, char *, FILE *);
11253 static void trstring(char *);
11257 showtree(union node *n)
11259 trputs("showtree called\n");
11260 shtree(n, 1, NULL, stdout);
11265 shtree(union node *n, int ind, char *pfx, FILE *fp)
11267 struct nodelist *lp;
11273 indent(ind, pfx, fp);
11284 shtree(n->nbinary.ch1, ind, NULL, fp);
11287 shtree(n->nbinary.ch2, ind, NULL, fp);
11295 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11300 if (n->npipe.backgnd)
11306 fprintf(fp, "<node type %d>", n->type);
11315 shcmd(union node *cmd, FILE *fp)
11323 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11329 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11332 switch (np->nfile.type) {
11333 case NTO: s = ">"; dftfd = 1; break;
11334 case NCLOBBER: s = ">|"; dftfd = 1; break;
11335 case NAPPEND: s = ">>"; dftfd = 1; break;
11336 case NTOFD: s = ">&"; dftfd = 1; break;
11337 case NFROM: s = "<"; dftfd = 0; break;
11338 case NFROMFD: s = "<&"; dftfd = 0; break;
11339 case NFROMTO: s = "<>"; dftfd = 0; break;
11340 default: s = "*error*"; dftfd = 0; break;
11342 if (np->nfile.fd != dftfd)
11343 fprintf(fp, "%d", np->nfile.fd);
11345 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11346 fprintf(fp, "%d", np->ndup.dupfd);
11348 sharg(np->nfile.fname, fp);
11357 sharg(union node *arg, FILE *fp)
11360 struct nodelist *bqlist;
11363 if (arg->type != NARG) {
11364 out1fmt("<node type %d>\n", arg->type);
11367 bqlist = arg->narg.backquote;
11368 for (p = arg->narg.text ; *p ; p++) {
11377 if (subtype == VSLENGTH)
11383 if (subtype & VSNUL)
11386 switch (subtype & VSTYPE) {
11405 case VSTRIMLEFTMAX:
11412 case VSTRIMRIGHTMAX:
11419 out1fmt("<subtype %d>", subtype);
11426 case CTLBACKQ|CTLQUOTE:
11429 shtree(bqlist->n, -1, NULL, fp);
11441 indent(int amount, char *pfx, FILE *fp)
11445 for (i = 0 ; i < amount ; i++) {
11446 if (pfx && i == amount - 1)
11467 putc(c, tracefile);
11471 trace(const char *fmt, ...)
11478 (void) vfprintf(tracefile, fmt, va);
11483 tracev(const char *fmt, va_list va)
11487 (void) vfprintf(tracefile, fmt, va);
11492 trputs(const char *s)
11496 fputs(s, tracefile);
11508 putc('"', tracefile);
11509 for (p = s ; *p ; p++) {
11511 case '\n': c = 'n'; goto backslash;
11512 case '\t': c = 't'; goto backslash;
11513 case '\r': c = 'r'; goto backslash;
11514 case '"': c = '"'; goto backslash;
11515 case '\\': c = '\\'; goto backslash;
11516 case CTLESC: c = 'e'; goto backslash;
11517 case CTLVAR: c = 'v'; goto backslash;
11518 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11519 case CTLBACKQ: c = 'q'; goto backslash;
11520 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11521 backslash: putc('\\', tracefile);
11522 putc(c, tracefile);
11525 if (*p >= ' ' && *p <= '~')
11526 putc(*p, tracefile);
11528 putc('\\', tracefile);
11529 putc(*p >> 6 & 03, tracefile);
11530 putc(*p >> 3 & 07, tracefile);
11531 putc(*p & 07, tracefile);
11536 putc('"', tracefile);
11548 putc(' ', tracefile);
11550 putc('\n', tracefile);
11566 /* leave open because libedit might be using it */
11569 scopy("./trace", s);
11571 if (!freopen(s, "a", tracefile)) {
11572 fprintf(stderr, "Can't re-open %s\n", s);
11577 if ((tracefile = fopen(s, "a")) == NULL) {
11578 fprintf(stderr, "Can't open %s\n", s);
11584 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11585 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11587 setlinebuf(tracefile);
11588 fputs("\nTracing started.\n", tracefile);
11593 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11596 * Sigmode records the current value of the signal handlers for the various
11597 * modes. A value of zero means that the current handler is not known.
11598 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11601 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11602 #define S_CATCH 2 /* signal is caught */
11603 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11604 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11605 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11610 * The trap builtin.
11614 trapcmd(int argc, char **argv)
11623 for (signo = 0 ; signo < NSIG ; signo++) {
11624 if (trap[signo] != NULL) {
11627 sn = u_signal_names(0, &signo, 0);
11630 out1fmt("trap -- %s %s\n",
11631 single_quote(trap[signo]), sn);
11641 if ((signo = decode_signal(*ap, 0)) < 0)
11642 error("%s: bad trap", *ap);
11645 if (action[0] == '-' && action[1] == '\0')
11648 action = savestr(action);
11651 ckfree(trap[signo]);
11652 trap[signo] = action;
11663 * Clear traps on a fork.
11671 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11672 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11676 if (tp != &trap[0])
11677 setsignal(tp - trap);
11685 * Set the signal handler for the specified signal. The routine figures
11686 * out what it should be set to.
11690 setsignal(int signo)
11694 struct sigaction act;
11696 if ((t = trap[signo]) == NULL)
11698 else if (*t != '\0')
11702 if (rootshell && action == S_DFL) {
11705 if (iflag || minusc || sflag == 0)
11728 t = &sigmode[signo - 1];
11732 * current setting unknown
11734 if (sigaction(signo, 0, &act) == -1) {
11736 * Pretend it worked; maybe we should give a warning
11737 * here, but other shells don't. We don't alter
11738 * sigmode, so that we retry every time.
11742 if (act.sa_handler == SIG_IGN) {
11743 if (mflag && (signo == SIGTSTP ||
11744 signo == SIGTTIN || signo == SIGTTOU)) {
11745 tsig = S_IGN; /* don't hard ignore these */
11749 tsig = S_RESET; /* force to be set */
11752 if (tsig == S_HARD_IGN || tsig == action)
11756 act.sa_handler = onsig;
11759 act.sa_handler = SIG_IGN;
11762 act.sa_handler = SIG_DFL;
11766 sigfillset(&act.sa_mask);
11767 sigaction(signo, &act, 0);
11775 ignoresig(int signo)
11777 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11778 signal(signo, SIG_IGN);
11780 sigmode[signo - 1] = S_HARD_IGN;
11791 gotsig[signo - 1] = 1;
11792 pendingsigs = signo;
11794 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11803 * Called to execute a trap. Perhaps we should avoid entering new trap
11804 * handlers while we are executing a trap handler.
11814 savestatus = exitstatus;
11816 while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
11818 p = trap[p - q + 1];
11822 exitstatus = savestatus;
11828 * Controls whether the shell is interactive or not.
11832 setinteractive(int on)
11834 static int is_interactive;
11836 if (++on == is_interactive)
11838 is_interactive = on;
11840 setsignal(SIGQUIT);
11841 setsignal(SIGTERM);
11842 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11843 if(is_interactive > 1) {
11844 /* Looks like they want an interactive shell */
11845 static int do_banner;
11849 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11850 "Enter 'help' for a list of built-in commands.\n\n");
11858 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11859 /*** List the available builtins ***/
11861 static int helpcmd(int argc, char **argv)
11865 out1fmt("\nBuilt-in commands:\n-------------------\n");
11866 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11867 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11868 builtincmd[i].name + 1);
11874 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11876 extern const struct BB_applet applets[];
11877 extern const size_t NUM_APPLETS;
11879 for (i = 0; i < NUM_APPLETS; i++) {
11881 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11890 return EXIT_SUCCESS;
11892 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11895 * Called to exit the shell.
11906 jmp = setjmp(loc.loc);
11907 status = exitstatus;
11908 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11912 if ((p = trap[0]) != NULL && *p != '\0') {
11918 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11919 if (iflag && rootshell) {
11920 const char *hp = lookupvar("HISTFILE");
11923 save_history ( hp );
11931 static int decode_signal(const char *string, int minsig)
11934 const char *name = u_signal_names(string, &signo, minsig);
11936 return name ? signo : -1;
11939 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11941 static struct var *vartab[VTABSIZE];
11943 static int vpcmp(const void *, const void *);
11944 static struct var **findvar(struct var **, const char *);
11947 * Initialize the variable symbol tables and import the environment
11951 #ifdef CONFIG_ASH_GETOPTS
11953 * Safe version of setvar, returns 1 on success 0 on failure.
11957 setvarsafe(const char *name, const char *val, int flags)
11960 volatile int saveint;
11961 struct jmploc *volatile savehandler = handler;
11962 struct jmploc jmploc;
11965 if (setjmp(jmploc.loc))
11969 setvar(name, val, flags);
11972 handler = savehandler;
11973 RESTOREINT(saveint);
11979 * Set the value of a variable. The flags argument is ored with the
11980 * flags of the variable. If val is NULL, the variable is unset.
11984 setvar(const char *name, const char *val, int flags)
11991 q = endofname(name);
11992 p = strchrnul(q, '=');
11993 namelen = p - name;
11994 if (!namelen || p != q)
11995 error("%.*s: bad variable name", namelen, name);
12000 vallen = strlen(val);
12003 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
12007 p = mempcpy(p, val, vallen);
12010 setvareq(nameeq, flags | VNOSAVE);
12016 * Same as setvar except that the variable and value are passed in
12017 * the first argument as name=value. Since the first argument will
12018 * be actually stored in the table, it should not be a string that
12020 * Called with interrupts off.
12024 setvareq(char *s, int flags)
12026 struct var *vp, **vpp;
12029 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12030 vp = *findvar(vpp, s);
12032 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12035 if (flags & VNOSAVE)
12038 error("%.*s: is read only", strchrnul(n, '=') - n, n);
12041 if (flags & VNOSET)
12044 if (vp->func && (flags & VNOFUNC) == 0)
12045 (*vp->func)(strchrnul(s, '=') + 1);
12047 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12050 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12052 if (flags & VNOSET)
12055 vp = ckmalloc(sizeof (*vp));
12060 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12068 * Process a linked list of variable assignments.
12072 listsetvar(struct strlist *list_set_var, int flags)
12074 struct strlist *lp = list_set_var;
12080 setvareq(lp->text, flags);
12081 } while ((lp = lp->next));
12087 * Find the value of a variable. Returns NULL if not set.
12091 lookupvar(const char *name)
12095 if ((v = *findvar(hashvar(name), name))) {
12098 * Dynamic variables are implemented roughly the same way they are
12099 * in bash. Namely, they're "special" so long as they aren't unset.
12100 * As soon as they're unset, they're no longer dynamic, and dynamic
12101 * lookup will no longer happen at that point. -- PFM.
12103 if((v->flags & VDYNAMIC))
12106 if(!(v->flags & VUNSET))
12107 return strchrnul(v->text, '=') + 1;
12115 * Search the environment of a builtin command.
12119 bltinlookup(const char *name)
12121 struct strlist *sp;
12123 for (sp = cmdenviron ; sp ; sp = sp->next) {
12124 if (varequal(sp->text, name))
12125 return strchrnul(sp->text, '=') + 1;
12127 return lookupvar(name);
12132 * Generate a list of variables satisfying the given conditions.
12136 listvars(int on, int off, char ***end)
12147 for (vp = *vpp ; vp ; vp = vp->next)
12148 if ((vp->flags & mask) == on) {
12149 if (ep == stackstrend())
12150 ep = growstackstr();
12151 *ep++ = (char *) vp->text;
12153 } while (++vpp < vartab + VTABSIZE);
12154 if (ep == stackstrend())
12155 ep = growstackstr();
12159 return grabstackstr(ep);
12164 * POSIX requires that 'set' (but not export or readonly) output the
12165 * variables in lexicographic order - by the locale's collating order (sigh).
12166 * Maybe we could keep them in an ordered balanced binary tree
12167 * instead of hashed lists.
12168 * For now just roll 'em through qsort for printing...
12172 showvars(const char *sep_prefix, int on, int off)
12175 char **ep, **epend;
12177 ep = listvars(on, off, &epend);
12178 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12180 sep = *sep_prefix ? spcstr : sep_prefix;
12182 for (; ep < epend; ep++) {
12186 p = strchrnul(*ep, '=');
12189 q = single_quote(++p);
12191 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12200 * The export and readonly commands.
12204 exportcmd(int argc, char **argv)
12210 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12213 notp = nextopt("p") - 'p';
12214 if (notp && ((name = *(aptr = argptr)))) {
12216 if ((p = strchr(name, '=')) != NULL) {
12219 if ((vp = *findvar(hashvar(name), name))) {
12224 setvar(name, p, flag);
12225 } while ((name = *++aptr) != NULL);
12227 showvars(argv[0], flag, 0);
12234 * Make a variable a local variable. When a variable is made local, it's
12235 * value and flags are saved in a localvar structure. The saved values
12236 * will be restored when the shell function returns. We handle the name
12237 * "-" as a special case.
12241 mklocal(char *name)
12243 struct localvar *lvp;
12248 lvp = ckmalloc(sizeof (struct localvar));
12249 if (name[0] == '-' && name[1] == '\0') {
12251 p = ckmalloc(sizeof(optlist));
12252 lvp->text = memcpy(p, optlist, sizeof(optlist));
12257 vpp = hashvar(name);
12258 vp = *findvar(vpp, name);
12259 eq = strchr(name, '=');
12262 setvareq(name, VSTRFIXED);
12264 setvar(name, NULL, VSTRFIXED);
12265 vp = *vpp; /* the new variable */
12266 lvp->flags = VUNSET;
12268 lvp->text = vp->text;
12269 lvp->flags = vp->flags;
12270 vp->flags |= VSTRFIXED|VTEXTFIXED;
12276 lvp->next = localvars;
12282 * The "local" command.
12286 localcmd(int argc, char **argv)
12291 while ((name = *argv++) != NULL) {
12299 * Called after a function returns.
12300 * Interrupts must be off.
12306 struct localvar *lvp;
12309 while ((lvp = localvars) != NULL) {
12310 localvars = lvp->next;
12312 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12313 if (vp == NULL) { /* $- saved */
12314 memcpy(optlist, lvp->text, sizeof(optlist));
12317 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12318 unsetvar(vp->text);
12321 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12322 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12324 vp->flags = lvp->flags;
12325 vp->text = lvp->text;
12333 * The unset builtin command. We unset the function before we unset the
12334 * variable to allow a function to be unset when there is a readonly variable
12335 * with the same name.
12339 unsetcmd(int argc, char **argv)
12346 while ((i = nextopt("vf")) != '\0') {
12350 for (ap = argptr; *ap ; ap++) {
12365 * Unset the specified variable.
12369 unsetvar(const char *s)
12375 vpp = findvar(hashvar(s), s);
12379 int flags = vp->flags;
12382 if (flags & VREADONLY)
12385 vp->flags &= ~VDYNAMIC;
12387 if (flags & VUNSET)
12389 if ((flags & VSTRFIXED) == 0) {
12391 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12398 vp->flags &= ~VEXPORT;
12411 * Find the appropriate entry in the hash table from the name.
12414 static struct var **
12415 hashvar(const char *p)
12417 unsigned int hashval;
12419 hashval = ((unsigned char) *p) << 4;
12420 while (*p && *p != '=')
12421 hashval += (unsigned char) *p++;
12422 return &vartab[hashval % VTABSIZE];
12428 * Compares two strings up to the first = or '\0'. The first
12429 * string must be terminated by '='; the second may be terminated by
12430 * either '=' or '\0'.
12434 varcmp(const char *p, const char *q)
12438 while ((c = *p) == (d = *q)) {
12439 if (!c || c == '=')
12453 vpcmp(const void *a, const void *b)
12455 return varcmp(*(const char **)a, *(const char **)b);
12458 static struct var **
12459 findvar(struct var **vpp, const char *name)
12461 for (; *vpp; vpp = &(*vpp)->next) {
12462 if (varequal((*vpp)->text, name)) {
12468 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12470 #include <sys/times.h>
12472 static const unsigned char timescmd_str[] = {
12473 ' ', offsetof(struct tms, tms_utime),
12474 '\n', offsetof(struct tms, tms_stime),
12475 ' ', offsetof(struct tms, tms_cutime),
12476 '\n', offsetof(struct tms, tms_cstime),
12480 static int timescmd(int ac, char **av)
12482 long int clk_tck, s, t;
12483 const unsigned char *p;
12486 clk_tck = sysconf(_SC_CLK_TCK);
12491 t = *(clock_t *)(((char *) &buf) + p[1]);
12493 out1fmt("%ldm%ld.%.3lds%c",
12495 ((t - s * clk_tck) * 1000) / clk_tck,
12497 } while (*(p += 2));
12502 #ifdef CONFIG_ASH_MATH_SUPPORT
12504 dash_arith(const char *s)
12510 result = arith(s, &errcode);
12513 error("exponent less than 0");
12514 else if (errcode == -2)
12515 error("divide by zero");
12516 else if (errcode == -5)
12517 error("expression recursion loop detected");
12528 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12529 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12531 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12535 letcmd(int argc, char **argv)
12542 error("expression expected");
12543 for (ap = argv + 1; *ap; ap++) {
12544 i = dash_arith(*ap);
12549 #endif /* CONFIG_ASH_MATH_SUPPORT */
12551 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12554 * Miscellaneous builtins.
12560 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12561 typedef enum __rlimit_resource rlim_t;
12567 * The read builtin. The -e option causes backslashes to escape the
12568 * following character.
12570 * This uses unbuffered input, which may be avoidable in some cases.
12574 readcmd(int argc, char **argv)
12583 #if defined(CONFIG_ASH_TIMEOUT)
12586 struct timeval timeout_struct;
12587 struct termios tty, old_tty;
12595 #if defined(CONFIG_ASH_TIMEOUT)
12598 while ((i = nextopt("p:rt:")) != '\0')
12600 while ((i = nextopt("p:r")) != '\0')
12604 prompt = optionarg;
12607 #if defined(CONFIG_ASH_TIMEOUT)
12609 timeout = atoi(optionarg);
12612 if (prompt && isatty(0)) {
12615 if (*(ap = argptr) == NULL)
12616 error("arg count");
12617 if ((ifs = bltinlookup("IFS")) == NULL)
12619 #if defined(CONFIG_ASH_TIMEOUT)
12627 #if defined(CONFIG_ASH_TIMEOUT)
12629 tcgetattr(0, &tty);
12632 /* cfmakeraw(...) disables too much; we just do this instead. */
12633 tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
12634 tcsetattr(0, TCSANOW, &tty);
12639 timeout_struct.tv_sec = timeout;
12640 timeout_struct.tv_usec = 0;
12642 if ((i = select (FD_SETSIZE, &set, NULL, NULL, &timeout_struct)) == 1)
12645 if(c == '\n' || c == 4) /* Handle newlines and EOF */
12646 i = 0; /* Don't read further... */
12648 STPUTC(c, p); /* Keep reading... */
12650 tcsetattr(0, TCSANOW, &old_tty);
12652 /* Echo the character so the user knows it was read...
12653 Yes, this can be done by setting the ECHO flag, but that
12654 echoes ^D and other control characters at this state */
12666 if (read(0, &c, 1) != 1) {
12678 if (!rflag && c == '\\') {
12684 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12688 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12690 setvar(*ap, stackblock(), 0);
12700 /* Remove trailing blanks */
12701 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12703 setvar(*ap, stackblock(), 0);
12704 while (*++ap != NULL)
12705 setvar(*ap, nullstr, 0);
12710 static int umaskcmd(int argc, char **argv)
12712 static const char permuser[3] = "ugo";
12713 static const char permmode[3] = "rwx";
12714 static const short int permmask[] = {
12715 S_IRUSR, S_IWUSR, S_IXUSR,
12716 S_IRGRP, S_IWGRP, S_IXGRP,
12717 S_IROTH, S_IWOTH, S_IXOTH
12723 int symbolic_mode = 0;
12725 while (nextopt("S") != '\0') {
12734 if ((ap = *argptr) == NULL) {
12735 if (symbolic_mode) {
12739 for (i = 0; i < 3; i++) {
12742 *p++ = permuser[i];
12744 for (j = 0; j < 3; j++) {
12745 if ((mask & permmask[3 * i + j]) == 0) {
12746 *p++ = permmode[j];
12754 out1fmt("%.4o\n", mask);
12757 if (is_digit((unsigned char) *ap)) {
12760 if (*ap >= '8' || *ap < '0')
12761 error(illnum, argv[1]);
12762 mask = (mask << 3) + (*ap - '0');
12763 } while (*++ap != '\0');
12766 mask = ~mask & 0777;
12767 if (!bb_parse_mode(ap, &mask)) {
12768 error("Illegal mode: %s", ap);
12770 umask(~mask & 0777);
12779 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12780 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12781 * ash by J.T. Conklin.
12789 int factor; /* multiply by to get rlim_{cur,max} values */
12793 static const struct limits limits[] = {
12795 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12797 #ifdef RLIMIT_FSIZE
12798 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12801 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12803 #ifdef RLIMIT_STACK
12804 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12807 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12810 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12812 #ifdef RLIMIT_MEMLOCK
12813 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12815 #ifdef RLIMIT_NPROC
12816 { "process", RLIMIT_NPROC, 1, 'p' },
12818 #ifdef RLIMIT_NOFILE
12819 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
12822 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
12824 #ifdef RLIMIT_LOCKS
12825 { "locks", RLIMIT_LOCKS, 1, 'w' },
12827 { (char *) 0, 0, 0, '\0' }
12830 enum limtype { SOFT = 0x1, HARD = 0x2 };
12832 static void printlim(enum limtype how, const struct rlimit *limit,
12833 const struct limits *l)
12837 val = limit->rlim_max;
12839 val = limit->rlim_cur;
12841 if (val == RLIM_INFINITY)
12842 out1fmt("unlimited\n");
12845 out1fmt("%lld\n", (long long) val);
12850 ulimitcmd(int argc, char **argv)
12854 enum limtype how = SOFT | HARD;
12855 const struct limits *l;
12858 struct rlimit limit;
12861 while ((optc = nextopt("HSa"
12865 #ifdef RLIMIT_FSIZE
12871 #ifdef RLIMIT_STACK
12880 #ifdef RLIMIT_MEMLOCK
12883 #ifdef RLIMIT_NPROC
12886 #ifdef RLIMIT_NOFILE
12892 #ifdef RLIMIT_LOCKS
12910 for (l = limits; l->option != what; l++)
12913 set = *argptr ? 1 : 0;
12917 if (all || argptr[1])
12918 error("too many arguments");
12919 if (strncmp(p, "unlimited\n", 9) == 0)
12920 val = RLIM_INFINITY;
12924 while ((c = *p++) >= '0' && c <= '9')
12926 val = (val * 10) + (long)(c - '0');
12927 if (val < (rlim_t) 0)
12931 error("bad number");
12936 for (l = limits; l->name; l++) {
12937 getrlimit(l->cmd, &limit);
12938 out1fmt("%-20s ", l->name);
12939 printlim(how, &limit, l);
12944 getrlimit(l->cmd, &limit);
12947 limit.rlim_max = val;
12949 limit.rlim_cur = val;
12950 if (setrlimit(l->cmd, &limit) < 0)
12951 error("error setting limit (%m)");
12953 printlim(how, &limit, l);
12959 #ifdef CONFIG_ASH_MATH_SUPPORT
12961 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12963 Permission is hereby granted, free of charge, to any person obtaining
12964 a copy of this software and associated documentation files (the
12965 "Software"), to deal in the Software without restriction, including
12966 without limitation the rights to use, copy, modify, merge, publish,
12967 distribute, sublicense, and/or sell copies of the Software, and to
12968 permit persons to whom the Software is furnished to do so, subject to
12969 the following conditions:
12971 The above copyright notice and this permission notice shall be
12972 included in all copies or substantial portions of the Software.
12974 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12975 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12976 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12977 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12978 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12979 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12980 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12983 /* This is my infix parser/evaluator. It is optimized for size, intended
12984 * as a replacement for yacc-based parsers. However, it may well be faster
12985 * than a comparable parser written in yacc. The supported operators are
12986 * listed in #defines below. Parens, order of operations, and error handling
12987 * are supported. This code is thread safe. The exact expression format should
12988 * be that which POSIX specifies for shells. */
12990 /* The code uses a simple two-stack algorithm. See
12991 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12992 * for a detailed explanation of the infix-to-postfix algorithm on which
12993 * this is based (this code differs in that it applies operators immediately
12994 * to the stack instead of adding them to a queue to end up with an
12997 /* To use the routine, call it with an expression string and error return
13001 * Aug 24, 2001 Manuel Novoa III
13003 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13005 * 1) In arith_apply():
13006 * a) Cached values of *numptr and &(numptr[-1]).
13007 * b) Removed redundant test for zero denominator.
13010 * a) Eliminated redundant code for processing operator tokens by moving
13011 * to a table-based implementation. Also folded handling of parens
13013 * b) Combined all 3 loops which called arith_apply to reduce generated
13014 * code size at the cost of speed.
13016 * 3) The following expressions were treated as valid by the original code:
13017 * 1() , 0! , 1 ( *3 ) .
13018 * These bugs have been fixed by internally enclosing the expression in
13019 * parens and then checking that all binary ops and right parens are
13020 * preceded by a valid expression (NUM_TOKEN).
13022 * Note: It may be desirable to replace Aaron's test for whitespace with
13023 * ctype's isspace() if it is used by another busybox applet or if additional
13024 * whitespace chars should be considered. Look below the "#include"s for a
13025 * precompiler test.
13029 * Aug 26, 2001 Manuel Novoa III
13031 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13033 * Merge in Aaron's comments previously posted to the busybox list,
13034 * modified slightly to take account of my changes to the code.
13039 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13041 * - allow access to variable,
13042 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13043 * - realize assign syntax (VAR=expr, +=, *= etc)
13044 * - realize exponentiation (** operator)
13045 * - realize comma separated - expr, expr
13046 * - realise ++expr --expr expr++ expr--
13047 * - realise expr ? expr : expr (but, second expr calculate always)
13048 * - allow hexadecimal and octal numbers
13049 * - was restored loses XOR operator
13050 * - remove one goto label, added three ;-)
13051 * - protect $((num num)) as true zero expr (Manuel`s error)
13052 * - always use special isspace(), see comment from bash ;-)
13056 #define arith_isspace(arithval) \
13057 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13060 typedef unsigned char operator;
13062 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
13063 * precedence, and 3 high bits are an ID unique across operators of that
13064 * precedence. The ID portion is so that multiple operators can have the
13065 * same precedence, ensuring that the leftmost one is evaluated first.
13066 * Consider * and /. */
13068 #define tok_decl(prec,id) (((id)<<5)|(prec))
13069 #define PREC(op) ((op) & 0x1F)
13071 #define TOK_LPAREN tok_decl(0,0)
13073 #define TOK_COMMA tok_decl(1,0)
13075 #define TOK_ASSIGN tok_decl(2,0)
13076 #define TOK_AND_ASSIGN tok_decl(2,1)
13077 #define TOK_OR_ASSIGN tok_decl(2,2)
13078 #define TOK_XOR_ASSIGN tok_decl(2,3)
13079 #define TOK_PLUS_ASSIGN tok_decl(2,4)
13080 #define TOK_MINUS_ASSIGN tok_decl(2,5)
13081 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13082 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13084 #define TOK_MUL_ASSIGN tok_decl(3,0)
13085 #define TOK_DIV_ASSIGN tok_decl(3,1)
13086 #define TOK_REM_ASSIGN tok_decl(3,2)
13088 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13089 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13091 /* conditional is right associativity too */
13092 #define TOK_CONDITIONAL tok_decl(4,0)
13093 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
13095 #define TOK_OR tok_decl(5,0)
13097 #define TOK_AND tok_decl(6,0)
13099 #define TOK_BOR tok_decl(7,0)
13101 #define TOK_BXOR tok_decl(8,0)
13103 #define TOK_BAND tok_decl(9,0)
13105 #define TOK_EQ tok_decl(10,0)
13106 #define TOK_NE tok_decl(10,1)
13108 #define TOK_LT tok_decl(11,0)
13109 #define TOK_GT tok_decl(11,1)
13110 #define TOK_GE tok_decl(11,2)
13111 #define TOK_LE tok_decl(11,3)
13113 #define TOK_LSHIFT tok_decl(12,0)
13114 #define TOK_RSHIFT tok_decl(12,1)
13116 #define TOK_ADD tok_decl(13,0)
13117 #define TOK_SUB tok_decl(13,1)
13119 #define TOK_MUL tok_decl(14,0)
13120 #define TOK_DIV tok_decl(14,1)
13121 #define TOK_REM tok_decl(14,2)
13123 /* exponent is right associativity */
13124 #define TOK_EXPONENT tok_decl(15,1)
13126 /* For now unary operators. */
13127 #define UNARYPREC 16
13128 #define TOK_BNOT tok_decl(UNARYPREC,0)
13129 #define TOK_NOT tok_decl(UNARYPREC,1)
13131 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13132 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13134 #define PREC_PRE (UNARYPREC+2)
13136 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13137 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13139 #define PREC_POST (UNARYPREC+3)
13141 #define TOK_POST_INC tok_decl(PREC_POST, 0)
13142 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
13144 #define SPEC_PREC (UNARYPREC+4)
13146 #define TOK_NUM tok_decl(SPEC_PREC, 0)
13147 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13149 #define NUMPTR (*numstackptr)
13151 static inline int tok_have_assign(operator op)
13153 operator prec = PREC(op);
13155 convert_prec_is_assing(prec);
13156 return (prec == PREC(TOK_ASSIGN) ||
13157 prec == PREC_PRE || prec == PREC_POST);
13160 static inline int is_right_associativity(operator prec)
13162 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13163 prec == PREC(TOK_CONDITIONAL));
13167 typedef struct ARITCH_VAR_NUM {
13169 arith_t contidional_second_val;
13170 char contidional_second_val_initialized;
13171 char *var; /* if NULL then is regular number,
13172 else is variable name */
13176 typedef struct CHK_VAR_RECURSIVE_LOOPED {
13178 struct CHK_VAR_RECURSIVE_LOOPED *next;
13179 } chk_var_recursive_looped_t;
13181 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13184 static int arith_lookup_val(v_n_t *t)
13187 const char * p = lookupvar(t->var);
13192 /* recursive try as expression */
13193 chk_var_recursive_looped_t *cur;
13194 chk_var_recursive_looped_t cur_save;
13196 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13197 if(strcmp(cur->var, t->var) == 0) {
13198 /* expression recursion loop detected */
13202 /* save current lookuped var name */
13203 cur = prev_chk_var_recursive;
13204 cur_save.var = t->var;
13205 cur_save.next = cur;
13206 prev_chk_var_recursive = &cur_save;
13208 t->val = arith (p, &errcode);
13209 /* restore previous ptr after recursiving */
13210 prev_chk_var_recursive = cur;
13213 /* allow undefined var as 0 */
13220 /* "applying" a token means performing it on the top elements on the integer
13221 * stack. For a unary operator it will only change the top element, but a
13222 * binary operator will pop two arguments and push a result */
13224 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13227 arith_t numptr_val, rez;
13228 int ret_arith_lookup_val;
13230 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13231 without arguments */
13232 numptr_m1 = NUMPTR - 1;
13234 /* check operand is var with noninteger value */
13235 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13236 if(ret_arith_lookup_val)
13237 return ret_arith_lookup_val;
13239 rez = numptr_m1->val;
13240 if (op == TOK_UMINUS)
13242 else if (op == TOK_NOT)
13244 else if (op == TOK_BNOT)
13246 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13248 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13250 else if (op != TOK_UPLUS) {
13251 /* Binary operators */
13253 /* check and binary operators need two arguments */
13254 if (numptr_m1 == numstack) goto err;
13256 /* ... and they pop one */
13259 if (op == TOK_CONDITIONAL) {
13260 if(! numptr_m1->contidional_second_val_initialized) {
13261 /* protect $((expr1 ? expr2)) without ": expr" */
13264 rez = numptr_m1->contidional_second_val;
13265 } else if(numptr_m1->contidional_second_val_initialized) {
13266 /* protect $((expr1 : expr2)) without "expr ? " */
13269 numptr_m1 = NUMPTR - 1;
13270 if(op != TOK_ASSIGN) {
13271 /* check operand is var with noninteger value for not '=' */
13272 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13273 if(ret_arith_lookup_val)
13274 return ret_arith_lookup_val;
13276 if (op == TOK_CONDITIONAL) {
13277 numptr_m1->contidional_second_val = rez;
13279 rez = numptr_m1->val;
13280 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13282 else if (op == TOK_OR)
13283 rez = numptr_val || rez;
13284 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13286 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13288 else if (op == TOK_AND)
13289 rez = rez && numptr_val;
13290 else if (op == TOK_EQ)
13291 rez = (rez == numptr_val);
13292 else if (op == TOK_NE)
13293 rez = (rez != numptr_val);
13294 else if (op == TOK_GE)
13295 rez = (rez >= numptr_val);
13296 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13297 rez >>= numptr_val;
13298 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13299 rez <<= numptr_val;
13300 else if (op == TOK_GT)
13301 rez = (rez > numptr_val);
13302 else if (op == TOK_LT)
13303 rez = (rez < numptr_val);
13304 else if (op == TOK_LE)
13305 rez = (rez <= numptr_val);
13306 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13308 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13310 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13312 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13314 else if (op == TOK_CONDITIONAL_SEP) {
13315 if (numptr_m1 == numstack) {
13316 /* protect $((expr : expr)) without "expr ? " */
13319 numptr_m1->contidional_second_val_initialized = op;
13320 numptr_m1->contidional_second_val = numptr_val;
13322 else if (op == TOK_CONDITIONAL) {
13324 numptr_val : numptr_m1->contidional_second_val;
13326 else if(op == TOK_EXPONENT) {
13328 return -3; /* exponent less than 0 */
13333 while(numptr_val--)
13338 else if(numptr_val==0) /* zero divisor check */
13340 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13342 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13345 if(tok_have_assign(op)) {
13348 if(numptr_m1->var == NULL) {
13352 /* save to shell variable */
13353 snprintf(buf, sizeof(buf), "%lld", (long long) rez);
13354 setvar(numptr_m1->var, buf, 0);
13355 /* after saving, make previous value for v++ or v-- */
13356 if(op == TOK_POST_INC)
13358 else if(op == TOK_POST_DEC)
13361 numptr_m1->val = rez;
13362 /* protect geting var value, is number now */
13363 numptr_m1->var = NULL;
13368 /* longest must first */
13369 static const char op_tokens[] = {
13370 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13371 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13372 '<','<', 0, TOK_LSHIFT,
13373 '>','>', 0, TOK_RSHIFT,
13374 '|','|', 0, TOK_OR,
13375 '&','&', 0, TOK_AND,
13376 '!','=', 0, TOK_NE,
13377 '<','=', 0, TOK_LE,
13378 '>','=', 0, TOK_GE,
13379 '=','=', 0, TOK_EQ,
13380 '|','=', 0, TOK_OR_ASSIGN,
13381 '&','=', 0, TOK_AND_ASSIGN,
13382 '*','=', 0, TOK_MUL_ASSIGN,
13383 '/','=', 0, TOK_DIV_ASSIGN,
13384 '%','=', 0, TOK_REM_ASSIGN,
13385 '+','=', 0, TOK_PLUS_ASSIGN,
13386 '-','=', 0, TOK_MINUS_ASSIGN,
13387 '-','-', 0, TOK_POST_DEC,
13388 '^','=', 0, TOK_XOR_ASSIGN,
13389 '+','+', 0, TOK_POST_INC,
13390 '*','*', 0, TOK_EXPONENT,
13394 '=', 0, TOK_ASSIGN,
13406 '?', 0, TOK_CONDITIONAL,
13407 ':', 0, TOK_CONDITIONAL_SEP,
13408 ')', 0, TOK_RPAREN,
13409 '(', 0, TOK_LPAREN,
13413 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13416 static arith_t arith (const char *expr, int *perrcode)
13418 register char arithval; /* Current character under analysis */
13419 operator lasttok, op;
13422 const char *p = endexpression;
13425 size_t datasizes = strlen(expr) + 2;
13427 /* Stack of integers */
13428 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13429 * in any given correct or incorrect expression is left as an exercise to
13431 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13432 *numstackptr = numstack;
13433 /* Stack of operator tokens */
13434 operator *stack = alloca((datasizes) * sizeof(operator)),
13437 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13438 *perrcode = errcode = 0;
13441 if ((arithval = *expr) == 0) {
13442 if (p == endexpression) {
13443 /* Null expression. */
13447 /* This is only reached after all tokens have been extracted from the
13448 * input stream. If there are still tokens on the operator stack, they
13449 * are to be applied in order. At the end, there should be a final
13450 * result on the integer stack */
13452 if (expr != endexpression + 1) {
13453 /* If we haven't done so already, */
13454 /* append a closing right paren */
13455 expr = endexpression;
13456 /* and let the loop process it. */
13459 /* At this point, we're done with the expression. */
13460 if (numstackptr != numstack+1) {
13461 /* ... but if there isn't, it's bad */
13463 return (*perrcode = -1);
13465 if(numstack->var) {
13466 /* expression is $((var)) only, lookup now */
13467 errcode = arith_lookup_val(numstack);
13470 *perrcode = errcode;
13471 return numstack->val;
13473 /* Continue processing the expression. */
13474 if (arith_isspace(arithval)) {
13475 /* Skip whitespace */
13478 if((p = endofname(expr)) != expr) {
13479 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13481 numstackptr->var = alloca(var_name_size);
13482 safe_strncpy(numstackptr->var, expr, var_name_size);
13485 numstackptr->contidional_second_val_initialized = 0;
13489 } else if (is_digit(arithval)) {
13490 numstackptr->var = NULL;
13491 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13494 for(p = op_tokens; ; p++) {
13498 /* strange operator not found */
13501 for(o = expr; *p && *o == *p; p++)
13508 /* skip tail uncompared token */
13511 /* skip zero delim */
13516 /* post grammar: a++ reduce to num */
13517 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13520 /* Plus and minus are binary (not unary) _only_ if the last
13521 * token was as number, or a right paren (which pretends to be
13522 * a number, since it evaluates to one). Think about it.
13523 * It makes sense. */
13524 if (lasttok != TOK_NUM) {
13540 /* We don't want a unary operator to cause recursive descent on the
13541 * stack, because there can be many in a row and it could cause an
13542 * operator to be evaluated before its argument is pushed onto the
13543 * integer stack. */
13544 /* But for binary operators, "apply" everything on the operator
13545 * stack until we find an operator with a lesser priority than the
13546 * one we have just extracted. */
13547 /* Left paren is given the lowest priority so it will never be
13548 * "applied" in this way.
13549 * if associativity is right and priority eq, applied also skip
13552 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13553 /* not left paren or unary */
13554 if (lasttok != TOK_NUM) {
13555 /* binary op must be preceded by a num */
13558 while (stackptr != stack) {
13559 if (op == TOK_RPAREN) {
13560 /* The algorithm employed here is simple: while we don't
13561 * hit an open paren nor the bottom of the stack, pop
13562 * tokens and apply them */
13563 if (stackptr[-1] == TOK_LPAREN) {
13565 /* Any operator directly after a */
13567 /* close paren should consider itself binary */
13571 operator prev_prec = PREC(stackptr[-1]);
13573 convert_prec_is_assing(prec);
13574 convert_prec_is_assing(prev_prec);
13575 if (prev_prec < prec)
13577 /* check right assoc */
13578 if(prev_prec == prec && is_right_associativity(prec))
13581 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13582 if(errcode) goto ret;
13584 if (op == TOK_RPAREN) {
13589 /* Push this operator to the stack and remember it. */
13590 *stackptr++ = lasttok = op;
13597 #endif /* CONFIG_ASH_MATH_SUPPORT */
13601 const char *bb_applet_name = "debug stuff usage";
13602 int main(int argc, char **argv)
13604 return ash_main(argc, argv);
13609 * Copyright (c) 1989, 1991, 1993, 1994
13610 * The Regents of the University of California. All rights reserved.
13612 * This code is derived from software contributed to Berkeley by
13613 * Kenneth Almquist.
13615 * Redistribution and use in source and binary forms, with or without
13616 * modification, are permitted provided that the following conditions
13618 * 1. Redistributions of source code must retain the above copyright
13619 * notice, this list of conditions and the following disclaimer.
13620 * 2. Redistributions in binary form must reproduce the above copyright
13621 * notice, this list of conditions and the following disclaimer in the
13622 * documentation and/or other materials provided with the distribution.
13624 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13625 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13627 * 4. Neither the name of the University nor the names of its contributors
13628 * may be used to endorse or promote products derived from this software
13629 * without specific prior written permission.
13631 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13632 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13633 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13634 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13635 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13636 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13637 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13638 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13639 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13640 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF