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)
1357 static const struct builtincmd builtincmd[] = {
1358 { BUILTIN_SPEC_REG ".", dotcmd },
1359 { BUILTIN_SPEC_REG ":", truecmd },
1360 #ifdef CONFIG_ASH_ALIAS
1361 { BUILTIN_REG_ASSG "alias", aliascmd },
1364 { BUILTIN_REGULAR "bg", bgcmd },
1366 { BUILTIN_SPEC_REG "break", breakcmd },
1367 { BUILTIN_REGULAR "cd", cdcmd },
1368 { BUILTIN_NOSPEC "chdir", cdcmd },
1369 #ifdef CONFIG_ASH_CMDCMD
1370 { BUILTIN_REGULAR "command", commandcmd },
1372 { BUILTIN_SPEC_REG "continue", breakcmd },
1373 { BUILTIN_SPEC_REG "eval", evalcmd },
1374 { BUILTIN_SPEC_REG "exec", execcmd },
1375 { BUILTIN_SPEC_REG "exit", exitcmd },
1376 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1377 { BUILTIN_REGULAR "false", falsecmd },
1379 { BUILTIN_REGULAR "fg", fgcmd },
1381 #ifdef CONFIG_ASH_GETOPTS
1382 { BUILTIN_REGULAR "getopts", getoptscmd },
1384 { BUILTIN_NOSPEC "hash", hashcmd },
1385 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1386 { BUILTIN_NOSPEC "help", helpcmd },
1389 { BUILTIN_REGULAR "jobs", jobscmd },
1390 { BUILTIN_REGULAR "kill", killcmd },
1392 #ifdef CONFIG_ASH_MATH_SUPPORT
1393 { BUILTIN_NOSPEC "let", letcmd },
1395 { BUILTIN_ASSIGN "local", localcmd },
1396 { BUILTIN_NOSPEC "pwd", pwdcmd },
1397 { BUILTIN_REGULAR "read", readcmd },
1398 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1399 { BUILTIN_SPEC_REG "return", returncmd },
1400 { BUILTIN_SPEC_REG "set", setcmd },
1401 { BUILTIN_SPEC_REG "shift", shiftcmd },
1402 { BUILTIN_SPEC_REG "times", timescmd },
1403 { BUILTIN_SPEC_REG "trap", trapcmd },
1404 { BUILTIN_REGULAR "true", truecmd },
1405 { BUILTIN_NOSPEC "type", typecmd },
1406 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1407 { BUILTIN_REGULAR "umask", umaskcmd },
1408 #ifdef CONFIG_ASH_ALIAS
1409 { BUILTIN_REGULAR "unalias", unaliascmd },
1411 { BUILTIN_SPEC_REG "unset", unsetcmd },
1412 { BUILTIN_REGULAR "wait", waitcmd },
1415 #define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1423 const struct builtincmd *cmd;
1424 struct funcnode *func;
1429 /* action to find_command() */
1430 #define DO_ERR 0x01 /* prints errors */
1431 #define DO_ABS 0x02 /* checks absolute paths */
1432 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1433 #define DO_ALTPATH 0x08 /* using alternate path */
1434 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1436 static const char *pathopt; /* set by padvance */
1438 static void shellexec(char **, const char *, int)
1439 __attribute__((__noreturn__));
1440 static char *padvance(const char **, const char *);
1441 static void find_command(char *, struct cmdentry *, int, const char *);
1442 static struct builtincmd *find_builtin(const char *);
1443 static void hashcd(void);
1444 static void changepath(const char *);
1445 static void defun(char *, union node *);
1446 static void unsetfunc(const char *);
1448 #ifdef CONFIG_ASH_MATH_SUPPORT_64
1449 typedef int64_t arith_t;
1451 typedef long arith_t;
1454 #ifdef CONFIG_ASH_MATH_SUPPORT
1455 static arith_t dash_arith(const char *);
1456 static arith_t arith(const char *expr, int *perrcode);
1459 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1460 static unsigned long rseed;
1461 static void change_random(const char *);
1462 # ifndef DYNAMIC_VAR
1463 # define DYNAMIC_VAR
1467 /* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1469 static void reset(void);
1471 /* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
1478 #define VEXPORT 0x01 /* variable is exported */
1479 #define VREADONLY 0x02 /* variable cannot be modified */
1480 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1481 #define VTEXTFIXED 0x08 /* text is statically allocated */
1482 #define VSTACK 0x10 /* text is allocated on the stack */
1483 #define VUNSET 0x20 /* the variable is not set */
1484 #define VNOFUNC 0x40 /* don't call the callback function */
1485 #define VNOSET 0x80 /* do not set variable - just readonly test */
1486 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1488 # define VDYNAMIC 0x200 /* dynamic variable */
1494 struct var *next; /* next entry in hash list */
1495 int flags; /* flags are defined above */
1496 const char *text; /* name=value */
1497 void (*func)(const char *); /* function to be called when */
1498 /* the variable gets set/unset */
1502 struct localvar *next; /* next local variable in list */
1503 struct var *vp; /* the variable that was made local */
1504 int flags; /* saved flags */
1505 const char *text; /* saved text */
1509 static struct localvar *localvars;
1515 #ifdef CONFIG_ASH_GETOPTS
1516 static void getoptsreset(const char *);
1519 #ifdef CONFIG_LOCALE_SUPPORT
1521 static void change_lc_all(const char *value);
1522 static void change_lc_ctype(const char *value);
1528 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1530 static const char defifsvar[] = "IFS= \t\n";
1531 #define defifs (defifsvar + 4)
1533 static const char defifs[] = " \t\n";
1537 static struct var varinit[] = {
1539 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1541 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1544 #ifdef CONFIG_ASH_MAIL
1545 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1546 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1549 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1550 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1551 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1552 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1553 #ifdef CONFIG_ASH_GETOPTS
1554 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1556 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1557 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1559 #ifdef CONFIG_LOCALE_SUPPORT
1560 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1561 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
1563 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1564 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
1568 #define vifs varinit[0]
1569 #ifdef CONFIG_ASH_MAIL
1570 #define vmail (&vifs)[1]
1571 #define vmpath (&vmail)[1]
1575 #define vpath (&vmpath)[1]
1576 #define vps1 (&vpath)[1]
1577 #define vps2 (&vps1)[1]
1578 #define vps4 (&vps2)[1]
1579 #define voptind (&vps4)[1]
1580 #ifdef CONFIG_ASH_GETOPTS
1581 #define vrandom (&voptind)[1]
1583 #define vrandom (&vps4)[1]
1585 #define defpath (defpathvar + 5)
1588 * The following macros access the values of the above variables.
1589 * They have to skip over the name. They return the null string
1590 * for unset variables.
1593 #define ifsval() (vifs.text + 4)
1594 #define ifsset() ((vifs.flags & VUNSET) == 0)
1595 #define mailval() (vmail.text + 5)
1596 #define mpathval() (vmpath.text + 9)
1597 #define pathval() (vpath.text + 5)
1598 #define ps1val() (vps1.text + 4)
1599 #define ps2val() (vps2.text + 4)
1600 #define ps4val() (vps4.text + 4)
1601 #define optindval() (voptind.text + 7)
1603 #define mpathset() ((vmpath.flags & VUNSET) == 0)
1605 static void setvar(const char *, const char *, int);
1606 static void setvareq(char *, int);
1607 static void listsetvar(struct strlist *, int);
1608 static char *lookupvar(const char *);
1609 static char *bltinlookup(const char *);
1610 static char **listvars(int, int, char ***);
1611 #define environment() listvars(VEXPORT, VUNSET, 0)
1612 static int showvars(const char *, int, int);
1613 static void poplocalvars(void);
1614 static int unsetvar(const char *);
1615 #ifdef CONFIG_ASH_GETOPTS
1616 static int setvarsafe(const char *, const char *, int);
1618 static int varcmp(const char *, const char *);
1619 static struct var **hashvar(const char *);
1622 static inline int varequal(const char *a, const char *b) {
1623 return !varcmp(a, b);
1627 static int loopnest; /* current loop nesting level */
1630 * The parsefile structure pointed to by the global variable parsefile
1631 * contains information about the current file being read.
1636 struct redirtab *next;
1641 static struct redirtab *redirlist;
1642 static int nullredirs;
1644 extern char **environ;
1646 /* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1649 static void outstr(const char *, FILE *);
1650 static void outcslow(int, FILE *);
1651 static void flushall(void);
1652 static void flusherr(void);
1653 static int out1fmt(const char *, ...)
1654 __attribute__((__format__(__printf__,1,2)));
1655 static int fmtstr(char *, size_t, const char *, ...)
1656 __attribute__((__format__(__printf__,3,4)));
1658 static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1661 static void out1str(const char *p)
1666 static void out2str(const char *p)
1673 * Initialization code.
1677 * This routine initializes the builtin variables.
1688 * PS1 depends on uid
1690 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1691 vps1.text = "PS1=\\w \\$ ";
1694 vps1.text = "PS1=# ";
1697 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1699 vpp = hashvar(vp->text);
1702 } while (++vp < end);
1711 basepf.nextc = basepf.buf = basebuf;
1716 signal(SIGCHLD, SIG_DFL);
1725 for (envp = environ ; *envp ; envp++) {
1726 if (strchr(*envp, '=')) {
1727 setvareq(*envp, VEXPORT|VTEXTFIXED);
1731 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1732 setvar("PPID", ppid, 0);
1737 /* PEOF (the end of file marker) */
1740 * The input line number. Input.c just defines this variable, and saves
1741 * and restores it when files are pushed and popped. The user of this
1742 * package must set its value.
1745 static int pgetc(void);
1746 static int pgetc2(void);
1747 static int preadbuffer(void);
1748 static void pungetc(void);
1749 static void pushstring(char *, void *);
1750 static void popstring(void);
1751 static void setinputfile(const char *, int);
1752 static void setinputfd(int, int);
1753 static void setinputstring(char *);
1754 static void popfile(void);
1755 static void popallfiles(void);
1756 static void closescript(void);
1759 /* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1762 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1765 #define FORK_NOJOB 2
1767 /* mode flags for showjob(s) */
1768 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1769 #define SHOW_PID 0x04 /* include process pid */
1770 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1774 * A job structure contains information about a job. A job is either a
1775 * single process or a set of processes contained in a pipeline. In the
1776 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1781 pid_t pid; /* process id */
1782 int status; /* last process status from wait() */
1783 char *cmd; /* text of command being run */
1787 struct procstat ps0; /* status of process */
1788 struct procstat *ps; /* status or processes when more than one */
1790 int stopstatus; /* status of a stopped job */
1793 nprocs: 16, /* number of processes */
1795 #define JOBRUNNING 0 /* at least one proc running */
1796 #define JOBSTOPPED 1 /* all procs are stopped */
1797 #define JOBDONE 2 /* all procs are completed */
1799 sigint: 1, /* job was killed by SIGINT */
1800 jobctl: 1, /* job running under job control */
1802 waited: 1, /* true if this entry has been waited for */
1803 used: 1, /* true if this entry is in used */
1804 changed: 1; /* true if status has changed */
1805 struct job *prev_job; /* previous job */
1808 static pid_t backgndpid; /* pid of last background process */
1809 static int job_warning; /* user was warned about stopped jobs */
1811 static int jobctl; /* true if doing job control */
1814 static struct job *makejob(union node *, int);
1815 static int forkshell(struct job *, union node *, int);
1816 static int waitforjob(struct job *);
1817 static int stoppedjobs(void);
1820 #define setjobctl(on) /* do nothing */
1822 static void setjobctl(int);
1823 static void showjobs(FILE *, int);
1826 /* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1829 /* pid of main shell */
1831 /* true if we aren't a child of the main shell */
1832 static int rootshell;
1834 static void readcmdfile(char *);
1835 static void cmdloop(int);
1837 /* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1841 struct stack_block *stackp;
1844 struct stackmark *marknext;
1847 /* minimum size of a block */
1848 #define MINSIZE SHELL_ALIGN(504)
1850 struct stack_block {
1851 struct stack_block *prev;
1852 char space[MINSIZE];
1855 static struct stack_block stackbase;
1856 static struct stack_block *stackp = &stackbase;
1857 static struct stackmark *markp;
1858 static char *stacknxt = stackbase.space;
1859 static size_t stacknleft = MINSIZE;
1860 static char *sstrend = stackbase.space + MINSIZE;
1861 static int herefd = -1;
1864 static pointer ckmalloc(size_t);
1865 static pointer ckrealloc(pointer, size_t);
1866 static char *savestr(const char *);
1867 static pointer stalloc(size_t);
1868 static void stunalloc(pointer);
1869 static void setstackmark(struct stackmark *);
1870 static void popstackmark(struct stackmark *);
1871 static void growstackblock(void);
1872 static void *growstackstr(void);
1873 static char *makestrspace(size_t, char *);
1874 static char *stnputs(const char *, size_t, char *);
1875 static char *stputs(const char *, char *);
1878 static inline char *_STPUTC(char c, char *p) {
1885 #define stackblock() ((void *)stacknxt)
1886 #define stackblocksize() stacknleft
1887 #define STARTSTACKSTR(p) ((p) = stackblock())
1888 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1889 #define CHECKSTRSPACE(n, p) \
1893 size_t m = sstrend - q; \
1895 (p) = makestrspace(l, q); \
1898 #define USTPUTC(c, p) (*p++ = (c))
1899 #define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1900 #define STUNPUTC(p) (--p)
1901 #define STTOPC(p) p[-1]
1902 #define STADJUST(amount, p) (p += (amount))
1904 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1905 #define ungrabstackstr(s, p) stunalloc((s))
1906 #define stackstrend() ((void *)sstrend)
1908 #define ckfree(p) free((pointer)(p))
1910 /* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1913 #define DOLATSTRLEN 4
1915 static char *prefix(const char *, const char *);
1916 static int number(const char *);
1917 static int is_number(const char *);
1918 static char *single_quote(const char *);
1919 static char *sstrdup(const char *);
1921 #define equal(s1, s2) (strcmp(s1, s2) == 0)
1922 #define scopy(s1, s2) ((void)strcpy(s2, s1))
1924 /* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1927 int nparam; /* # of positional parameters (without $0) */
1928 unsigned char malloc; /* if parameter list dynamically allocated */
1929 char **p; /* parameter list */
1930 #ifdef CONFIG_ASH_GETOPTS
1931 int optind; /* next parameter to be processed by getopts */
1932 int optoff; /* used by getopts */
1937 #define eflag optlist[0]
1938 #define fflag optlist[1]
1939 #define Iflag optlist[2]
1940 #define iflag optlist[3]
1941 #define mflag optlist[4]
1942 #define nflag optlist[5]
1943 #define sflag optlist[6]
1944 #define xflag optlist[7]
1945 #define vflag optlist[8]
1946 #define Cflag optlist[9]
1947 #define aflag optlist[10]
1948 #define bflag optlist[11]
1949 #define uflag optlist[12]
1950 #define qflag optlist[13]
1953 #define nolog optlist[14]
1954 #define debug optlist[15]
1960 /* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1963 static const char *const optletters_optnames[NOPTS] = {
1984 #define optletters(n) optletters_optnames[(n)][0]
1985 #define optnames(n) (&optletters_optnames[(n)][1])
1988 static char optlist[NOPTS];
1991 static char *arg0; /* value of $0 */
1992 static struct shparam shellparam; /* $@ current positional parameters */
1993 static char **argptr; /* argument list for builtin commands */
1994 static char *optionarg; /* set by nextopt (like getopt) */
1995 static char *optptr; /* used by nextopt */
1997 static char *minusc; /* argument to -c option */
2000 static void procargs(int, char **);
2001 static void optschanged(void);
2002 static void setparam(char **);
2003 static void freeparam(volatile struct shparam *);
2004 static int shiftcmd(int, char **);
2005 static int setcmd(int, char **);
2006 static int nextopt(const char *);
2008 /* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
2010 /* flags passed to redirect */
2011 #define REDIR_PUSH 01 /* save previous values of file descriptors */
2012 #define REDIR_SAVEFD2 03 /* set preverrout */
2015 static void redirect(union node *, int);
2016 static void popredir(int);
2017 static void clearredir(int);
2018 static int copyfd(int, int);
2019 static int redirectsafe(union node *, int);
2021 /* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2025 static void showtree(union node *);
2026 static void trace(const char *, ...);
2027 static void tracev(const char *, va_list);
2028 static void trargs(char **);
2029 static void trputc(int);
2030 static void trputs(const char *);
2031 static void opentrace(void);
2034 /* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2037 /* trap handler commands */
2038 static char *trap[NSIG];
2039 /* current value of signal */
2040 static char sigmode[NSIG - 1];
2041 /* indicates specified signal received */
2042 static char gotsig[NSIG - 1];
2044 static void clear_traps(void);
2045 static void setsignal(int);
2046 static void ignoresig(int);
2047 static void onsig(int);
2048 static void dotrap(void);
2049 static void setinteractive(int);
2050 static void exitshell(void) __attribute__((__noreturn__));
2051 static int decode_signal(const char *, int);
2054 * This routine is called when an error or an interrupt occurs in an
2055 * interactive shell and control is returned to the main command loop.
2070 parselleft = parsenleft = 0; /* clear input buffer */
2074 /* from parser.c: */
2087 #ifdef CONFIG_ASH_ALIAS
2088 static struct alias *atab[ATABSIZE];
2090 static void setalias(const char *, const char *);
2091 static struct alias *freealias(struct alias *);
2092 static struct alias **__lookupalias(const char *);
2095 setalias(const char *name, const char *val)
2097 struct alias *ap, **app;
2099 app = __lookupalias(name);
2103 if (!(ap->flag & ALIASINUSE)) {
2106 ap->val = savestr(val);
2107 ap->flag &= ~ALIASDEAD;
2110 ap = ckmalloc(sizeof (struct alias));
2111 ap->name = savestr(name);
2112 ap->val = savestr(val);
2121 unalias(const char *name)
2125 app = __lookupalias(name);
2129 *app = freealias(*app);
2140 struct alias *ap, **app;
2144 for (i = 0; i < ATABSIZE; i++) {
2146 for (ap = *app; ap; ap = *app) {
2147 *app = freealias(*app);
2156 static struct alias *
2157 lookupalias(const char *name, int check)
2159 struct alias *ap = *__lookupalias(name);
2161 if (check && ap && (ap->flag & ALIASINUSE))
2167 * TODO - sort output
2170 aliascmd(int argc, char **argv)
2179 for (i = 0; i < ATABSIZE; i++)
2180 for (ap = atab[i]; ap; ap = ap->next) {
2185 while ((n = *++argv) != NULL) {
2186 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
2187 if ((ap = *__lookupalias(n)) == NULL) {
2188 fprintf(stderr, "%s: %s not found\n", "alias", n);
2202 unaliascmd(int argc, char **argv)
2206 while ((i = nextopt("a")) != '\0') {
2212 for (i = 0; *argptr; argptr++) {
2213 if (unalias(*argptr)) {
2214 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
2222 static struct alias *
2223 freealias(struct alias *ap) {
2226 if (ap->flag & ALIASINUSE) {
2227 ap->flag |= ALIASDEAD;
2239 printalias(const struct alias *ap) {
2240 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2243 static struct alias **
2244 __lookupalias(const char *name) {
2245 unsigned int hashval;
2252 ch = (unsigned char)*p;
2256 ch = (unsigned char)*++p;
2258 app = &atab[hashval % ATABSIZE];
2260 for (; *app; app = &(*app)->next) {
2261 if (equal(name, (*app)->name)) {
2268 #endif /* CONFIG_ASH_ALIAS */
2271 /* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2274 * The cd and pwd commands.
2277 #define CD_PHYSICAL 1
2280 static int docd(const char *, int);
2281 static int cdopt(void);
2283 static char *curdir = nullstr; /* current working directory */
2284 static char *physdir = nullstr; /* physical working directory */
2293 while ((i = nextopt("LP"))) {
2295 flags ^= CD_PHYSICAL;
2304 cdcmd(int argc, char **argv)
2316 dest = bltinlookup(homestr);
2317 else if (dest[0] == '-' && dest[1] == '\0') {
2318 dest = bltinlookup("OLDPWD");
2319 if ( !dest ) goto out;
2342 if (!(path = bltinlookup("CDPATH"))) {
2350 p = padvance(&path, dest);
2351 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2355 if (!docd(p, flags))
2360 error("can't cd to %s", dest);
2363 if (flags & CD_PRINT)
2364 out1fmt(snlfmt, curdir);
2370 * Update curdir (the name of the current directory) in response to a
2374 static inline const char *
2375 updatepwd(const char *dir)
2382 cdcomppath = sstrdup(dir);
2385 if (curdir == nullstr)
2387 new = stputs(curdir, new);
2389 new = makestrspace(strlen(dir) + 2, new);
2390 lim = stackblock() + 1;
2394 if (new > lim && *lim == '/')
2399 if (dir[1] == '/' && dir[2] != '/') {
2405 p = strtok(cdcomppath, "/");
2409 if (p[1] == '.' && p[2] == '\0') {
2416 } else if (p[1] == '\0')
2420 new = stputs(p, new);
2428 return stackblock();
2432 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2433 * know that the current directory has changed.
2437 docd(const char *dest, int flags)
2439 const char *dir = 0;
2442 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2445 if (!(flags & CD_PHYSICAL)) {
2446 dir = updatepwd(dest);
2461 * Find out what the current directory is. If we already know the current
2462 * directory, this routine returns immediately.
2464 static inline char *
2467 char *dir = getcwd(0, 0);
2468 return dir ? dir : nullstr;
2472 pwdcmd(int argc, char **argv)
2475 const char *dir = curdir;
2479 if (physdir == nullstr)
2483 out1fmt(snlfmt, dir);
2488 setpwd(const char *val, int setold)
2492 oldcur = dir = curdir;
2495 setvar("OLDPWD", oldcur, VEXPORT);
2498 if (physdir != nullstr) {
2499 if (physdir != oldcur)
2503 if (oldcur == val || !val) {
2510 if (oldcur != dir && oldcur != nullstr) {
2515 setvar("PWD", dir, VEXPORT);
2518 /* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2521 * Errors and exceptions.
2525 * Code to handle exceptions in C.
2530 static void exverror(int, const char *, va_list)
2531 __attribute__((__noreturn__));
2534 * Called to raise an exception. Since C doesn't include exceptions, we
2535 * just do a longjmp to the exception handler. The type of exception is
2536 * stored in the global variable "exception".
2543 if (handler == NULL)
2549 longjmp(handler->loc, 1);
2554 * Called from trap.c when a SIGINT is received. (If the user specifies
2555 * that SIGINT is to be trapped or ignored using the trap builtin, then
2556 * this routine is not called.) Suppressint is nonzero when interrupts
2557 * are held using the INTOFF macro. (The test for iflag is just
2558 * defensive programming.)
2568 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2569 if (!(rootshell && iflag)) {
2570 signal(SIGINT, SIG_DFL);
2580 exvwarning(const char *msg, va_list ap)
2593 fprintf(errs, fmt, name, startlinno);
2594 vfprintf(errs, msg, ap);
2595 outcslow('\n', errs);
2599 * Exverror is called to raise the error exception. If the second argument
2600 * is not NULL then error prints an error message using printf style
2601 * formatting. It then raises the error exception.
2604 exverror(int cond, const char *msg, va_list ap)
2608 TRACE(("exverror(%d, \"", cond));
2610 TRACE(("\") pid=%d\n", getpid()));
2612 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2615 exvwarning(msg, ap);
2624 error(const char *msg, ...)
2629 exverror(EXERROR, msg, ap);
2636 exerror(int cond, const char *msg, ...)
2641 exverror(cond, msg, ap);
2647 * error/warning routines for external builtins
2651 sh_warnx(const char *fmt, ...)
2656 exvwarning(fmt, ap);
2662 * Return a string describing an error. The returned string may be a
2663 * pointer to a static buffer that will be overwritten on the next call.
2664 * Action describes the operation that got the error.
2668 errmsg(int e, const char *em)
2670 if(e == ENOENT || e == ENOTDIR) {
2678 /* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2681 * Evaluate a command.
2684 /* flags in argument to evaltree */
2685 #define EV_EXIT 01 /* exit after evaluating tree */
2686 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2687 #define EV_BACKCMD 04 /* command executing within back quotes */
2690 static void evalloop(union node *, int);
2691 static void evalfor(union node *, int);
2692 static void evalcase(union node *, int);
2693 static void evalsubshell(union node *, int);
2694 static void expredir(union node *);
2695 static void evalpipe(union node *, int);
2696 static void evalcommand(union node *, int);
2697 static int evalbltin(const struct builtincmd *, int, char **);
2698 static int evalfun(struct funcnode *, int, char **, int);
2699 static void prehash(union node *);
2700 static int bltincmd(int, char **);
2703 static const struct builtincmd bltin = {
2709 * Called to reset things after an exception.
2717 evalcmd(int argc, char **argv)
2726 STARTSTACKSTR(concat);
2729 concat = stputs(p, concat);
2730 if ((p = *ap++) == NULL)
2732 STPUTC(' ', concat);
2734 STPUTC('\0', concat);
2735 p = grabstackstr(concat);
2744 * Execute a command or commands contained in a string.
2751 struct stackmark smark;
2753 setstackmark(&smark);
2756 while ((n = parsecmd(0)) != NEOF) {
2758 popstackmark(&smark);
2763 popstackmark(&smark);
2769 * Evaluate a parse tree. The value is left in the global variable
2774 evaltree(union node *n, int flags)
2777 void (*evalfn)(union node *, int);
2781 TRACE(("evaltree(NULL) called\n"));
2784 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2785 getpid(), n, n->type, flags));
2789 out1fmt("Node type = %d\n", n->type);
2794 evaltree(n->nnot.com, EV_TESTED);
2795 status = !exitstatus;
2798 expredir(n->nredir.redirect);
2799 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2801 evaltree(n->nredir.n, flags & EV_TESTED);
2802 status = exitstatus;
2807 evalfn = evalcommand;
2809 if (eflag && !(flags & EV_TESTED))
2821 evalfn = evalsubshell;
2833 #error NAND + 1 != NOR
2835 #if NOR + 1 != NSEMI
2836 #error NOR + 1 != NSEMI
2838 isor = n->type - NAND;
2841 (flags | ((isor >> 1) - 1)) & EV_TESTED
2843 if (!exitstatus == isor)
2855 evaltree(n->nif.test, EV_TESTED);
2858 if (exitstatus == 0) {
2861 } else if (n->nif.elsepart) {
2862 n = n->nif.elsepart;
2867 defun(n->narg.text, n->narg.next);
2871 exitstatus = status;
2877 if (flags & EV_EXIT || checkexit & exitstatus)
2882 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2885 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2889 evalloop(union node *n, int flags)
2899 evaltree(n->nbinary.ch1, EV_TESTED);
2901 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2905 if (evalskip == SKIPBREAK && --skipcount <= 0)
2910 if (n->type != NWHILE)
2914 evaltree(n->nbinary.ch2, flags);
2915 status = exitstatus;
2920 exitstatus = status;
2926 evalfor(union node *n, int flags)
2928 struct arglist arglist;
2931 struct stackmark smark;
2933 setstackmark(&smark);
2934 arglist.lastp = &arglist.list;
2935 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2936 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2941 *arglist.lastp = NULL;
2946 for (sp = arglist.list ; sp ; sp = sp->next) {
2947 setvar(n->nfor.var, sp->text, 0);
2948 evaltree(n->nfor.body, flags);
2950 if (evalskip == SKIPCONT && --skipcount <= 0) {
2954 if (evalskip == SKIPBREAK && --skipcount <= 0)
2961 popstackmark(&smark);
2967 evalcase(union node *n, int flags)
2971 struct arglist arglist;
2972 struct stackmark smark;
2974 setstackmark(&smark);
2975 arglist.lastp = &arglist.list;
2976 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2978 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2979 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2980 if (casematch(patp, arglist.list->text)) {
2981 if (evalskip == 0) {
2982 evaltree(cp->nclist.body, flags);
2989 popstackmark(&smark);
2995 * Kick off a subshell to evaluate a tree.
2999 evalsubshell(union node *n, int flags)
3002 int backgnd = (n->type == NBACKGND);
3005 expredir(n->nredir.redirect);
3006 if (!backgnd && flags & EV_EXIT && !trap[0])
3010 if (forkshell(jp, n, backgnd) == 0) {
3014 flags &=~ EV_TESTED;
3016 redirect(n->nredir.redirect, 0);
3017 evaltreenr(n->nredir.n, flags);
3022 status = waitforjob(jp);
3023 exitstatus = status;
3030 * Compute the names of the files in a redirection list.
3034 expredir(union node *n)
3038 for (redir = n ; redir ; redir = redir->nfile.next) {
3040 fn.lastp = &fn.list;
3041 switch (redir->type) {
3047 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3048 redir->nfile.expfname = fn.list->text;
3052 if (redir->ndup.vname) {
3053 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3054 fixredir(redir, fn.list->text, 1);
3064 * Evaluate a pipeline. All the processes in the pipeline are children
3065 * of the process creating the pipeline. (This differs from some versions
3066 * of the shell, which make the last process in a pipeline the parent
3071 evalpipe(union node *n, int flags)
3074 struct nodelist *lp;
3079 TRACE(("evalpipe(0x%lx) called\n", (long)n));
3081 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3085 jp = makejob(n, pipelen);
3087 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3091 if (pipe(pip) < 0) {
3093 error("Pipe call failed");
3096 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3109 evaltreenr(lp->n, flags);
3117 if (n->npipe.backgnd == 0) {
3118 exitstatus = waitforjob(jp);
3119 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
3127 * Execute a command inside back quotes. If it's a builtin command, we
3128 * want to save its output in a block obtained from malloc. Otherwise
3129 * we fork off a subprocess and get the output of the command via a pipe.
3130 * Should be called with interrupts off.
3134 evalbackcmd(union node *n, struct backcmd *result)
3146 saveherefd = herefd;
3154 error("Pipe call failed");
3156 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3165 evaltreenr(n, EV_EXIT);
3169 result->fd = pip[0];
3172 herefd = saveherefd;
3174 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3175 result->fd, result->buf, result->nleft, result->jp));
3178 #ifdef CONFIG_ASH_CMDCMD
3179 static inline char **
3180 parse_command_args(char **argv, const char **path)
3192 if (c == '-' && !*cp) {
3202 /* run 'typecmd' for other options */
3205 } while ((c = *cp++));
3214 * Execute a simple command.
3218 evalcommand(union node *cmd, int flags)
3220 struct stackmark smark;
3222 struct arglist arglist;
3223 struct arglist varlist;
3226 const struct strlist *sp;
3227 struct cmdentry cmdentry;
3236 /* First expand the arguments. */
3237 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3238 setstackmark(&smark);
3239 back_exitstatus = 0;
3241 cmdentry.cmdtype = CMDBUILTIN;
3242 cmdentry.u.cmd = &bltin;
3243 varlist.lastp = &varlist.list;
3244 *varlist.lastp = NULL;
3245 arglist.lastp = &arglist.list;
3246 *arglist.lastp = NULL;
3249 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3250 struct strlist **spp;
3252 spp = arglist.lastp;
3253 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3254 for (sp = *spp; sp; sp = sp->next)
3258 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3259 for (sp = arglist.list ; sp ; sp = sp->next) {
3260 TRACE(("evalcommand arg: %s\n", sp->text));
3261 *nargv++ = sp->text;
3266 if (iflag && funcnest == 0 && argc > 0)
3267 lastarg = nargv[-1];
3270 expredir(cmd->ncmd.redirect);
3271 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
3274 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3275 struct strlist **spp;
3278 spp = varlist.lastp;
3279 expandarg(argp, &varlist, EXP_VARTILDE);
3282 * Modify the command lookup path, if a PATH= assignment
3286 if (varequal(p, path))
3290 /* Print the command if xflag is set. */
3293 const char *p = " %s";
3296 dprintf(preverrout_fd, p, ps4val());
3299 for(n = 0; n < 2; n++) {
3301 dprintf(preverrout_fd, p, sp->text);
3309 bb_full_write(preverrout_fd, "\n", 1);
3315 /* Now locate the command. */
3317 const char *oldpath;
3318 int cmd_flag = DO_ERR;
3323 find_command(argv[0], &cmdentry, cmd_flag, path);
3324 if (cmdentry.cmdtype == CMDUNKNOWN) {
3330 /* implement bltin and command here */
3331 if (cmdentry.cmdtype != CMDBUILTIN)
3334 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3335 if (cmdentry.u.cmd == EXECCMD)
3337 #ifdef CONFIG_ASH_CMDCMD
3338 if (cmdentry.u.cmd == COMMANDCMD) {
3341 nargv = parse_command_args(argv, &path);
3344 argc -= nargv - argv;
3346 cmd_flag |= DO_NOFUNC;
3354 /* We have a redirection error. */
3358 exitstatus = status;
3362 /* Execute the command. */
3363 switch (cmdentry.cmdtype) {
3365 /* Fork off a child process if necessary. */
3366 if (!(flags & EV_EXIT) || trap[0]) {
3368 jp = makejob(cmd, 1);
3369 if (forkshell(jp, cmd, FORK_FG) != 0) {
3370 exitstatus = waitforjob(jp);
3376 listsetvar(varlist.list, VEXPORT|VSTACK);
3377 shellexec(argv, path, cmdentry.u.index);
3381 cmdenviron = varlist.list;
3383 struct strlist *list = cmdenviron;
3385 if (spclbltin > 0 || argc == 0) {
3387 if (cmd_is_exec && argc > 1)
3390 listsetvar(list, i);
3392 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3407 exit_status = j + 128;
3408 exitstatus = exit_status;
3410 if (i == EXINT || spclbltin > 0) {
3412 longjmp(handler->loc, 1);
3419 listsetvar(varlist.list, 0);
3420 if (evalfun(cmdentry.u.func, argc, argv, flags))
3426 popredir(cmd_is_exec);
3428 /* dsl: I think this is intended to be used to support
3429 * '_' in 'vi' command mode during line editing...
3430 * However I implemented that within libedit itself.
3432 setvar("_", lastarg, 0);
3433 popstackmark(&smark);
3437 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3438 char *volatile savecmdname;
3439 struct jmploc *volatile savehandler;
3440 struct jmploc jmploc;
3443 savecmdname = commandname;
3444 if ((i = setjmp(jmploc.loc)))
3446 savehandler = handler;
3448 commandname = argv[0];
3450 optptr = NULL; /* initialize nextopt */
3451 exitstatus = (*cmd->builtin)(argc, argv);
3454 exitstatus |= ferror(stdout);
3455 commandname = savecmdname;
3457 handler = savehandler;
3463 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3465 volatile struct shparam saveparam;
3466 struct localvar *volatile savelocalvars;
3467 struct jmploc *volatile savehandler;
3468 struct jmploc jmploc;
3471 saveparam = shellparam;
3472 savelocalvars = localvars;
3473 if ((e = setjmp(jmploc.loc))) {
3477 savehandler = handler;
3480 shellparam.malloc = 0;
3483 shellparam.nparam = argc - 1;
3484 shellparam.p = argv + 1;
3485 #ifdef CONFIG_ASH_GETOPTS
3486 shellparam.optind = 1;
3487 shellparam.optoff = -1;
3490 evaltree(&func->n, flags & EV_TESTED);
3496 localvars = savelocalvars;
3497 freeparam(&shellparam);
3498 shellparam = saveparam;
3499 handler = savehandler;
3501 if (evalskip == SKIPFUNC) {
3510 goodname(const char *p)
3512 return !*endofname(p);
3516 * Search for a command. This is called before we fork so that the
3517 * location of the command will be available in the parent as well as
3518 * the child. The check for "goodname" is an overly conservative
3519 * check that the name will not be subject to expansion.
3523 prehash(union node *n)
3525 struct cmdentry entry;
3527 if (n->type == NCMD && n->ncmd.args)
3528 if (goodname(n->ncmd.args->narg.text))
3529 find_command(n->ncmd.args->narg.text, &entry, 0,
3536 * Builtin commands. Builtin commands whose functions are closely
3537 * tied to evaluation are implemented here.
3545 bltincmd(int argc, char **argv)
3548 * Preserve exitstatus of a previous possible redirection
3551 return back_exitstatus;
3556 * Handle break and continue commands. Break, continue, and return are
3557 * all handled by setting the evalskip flag. The evaluation routines
3558 * above all check this flag, and if it is set they start skipping
3559 * commands rather than executing them. The variable skipcount is
3560 * the number of loops to break/continue, or the number of function
3561 * levels to return. (The latter is always 1.) It should probably
3562 * be an error to break out of more loops than exist, but it isn't
3563 * in the standard shell so we don't make it one here.
3567 breakcmd(int argc, char **argv)
3569 int n = argc > 1 ? number(argv[1]) : 1;
3572 error(illnum, argv[1]);
3576 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3584 * The return command.
3588 returncmd(int argc, char **argv)
3590 int ret = argc > 1 ? number(argv[1]) : exitstatus;
3593 evalskip = SKIPFUNC;
3598 /* Do what ksh does; skip the rest of the file */
3599 evalskip = SKIPFILE;
3607 falsecmd(int argc, char **argv)
3614 truecmd(int argc, char **argv)
3621 execcmd(int argc, char **argv)
3624 iflag = 0; /* exit on error */
3627 shellexec(argv + 1, pathval(), 0);
3633 /* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3636 * When commands are first encountered, they are entered in a hash table.
3637 * This ensures that a full path search will not have to be done for them
3638 * on each invocation.
3640 * We should investigate converting to a linear search, even though that
3641 * would make the command name "hash" a misnomer.
3644 #define CMDTABLESIZE 31 /* should be prime */
3645 #define ARB 1 /* actual size determined at run time */
3650 struct tblentry *next; /* next entry in hash chain */
3651 union param param; /* definition of builtin function */
3652 short cmdtype; /* index identifying command */
3653 char rehash; /* if set, cd done since entry created */
3654 char cmdname[ARB]; /* name of command */
3658 static struct tblentry *cmdtable[CMDTABLESIZE];
3659 static int builtinloc = -1; /* index in path of %builtin, or -1 */
3662 static void tryexec(char *, char **, char **);
3663 static void clearcmdentry(int);
3664 static struct tblentry *cmdlookup(const char *, int);
3665 static void delete_cmd_entry(void);
3669 * Exec a program. Never returns. If you change this routine, you may
3670 * have to change the find_command routine as well.
3674 shellexec(char **argv, const char *path, int idx)
3681 envp = environment();
3682 if (strchr(argv[0], '/') != NULL
3683 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3684 || find_applet_by_name(argv[0])
3687 tryexec(argv[0], argv, envp);
3691 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3692 if (--idx < 0 && pathopt == NULL) {
3693 tryexec(cmdname, argv, envp);
3694 if (errno != ENOENT && errno != ENOTDIR)
3701 /* Map to POSIX errors */
3713 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3714 argv[0], e, suppressint ));
3715 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3721 tryexec(char *cmd, char **argv, char **envp)
3724 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3725 if(find_applet_by_name(cmd) != NULL) {
3726 /* re-exec ourselves with the new arguments */
3727 execve("/proc/self/exe",argv,envp);
3728 /* If proc isn't mounted, try hardcoded path to busybox binary*/
3729 execve("/bin/busybox",argv,envp);
3730 /* If they called chroot or otherwise made the binary no longer
3731 * executable, fall through */
3738 execve(cmd, argv, envp);
3739 } while (errno == EINTR);
3741 execve(cmd, argv, envp);
3745 } else if (errno == ENOEXEC) {
3749 for (ap = argv; *ap; ap++)
3751 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3753 *ap = cmd = (char *)DEFAULT_SHELL;
3756 while ((*ap++ = *argv++))
3766 * Do a path search. The variable path (passed by reference) should be
3767 * set to the start of the path before the first call; padvance will update
3768 * this value as it proceeds. Successive calls to padvance will return
3769 * the possible path expansions in sequence. If an option (indicated by
3770 * a percent sign) appears in the path entry then the global variable
3771 * pathopt will be set to point to it; otherwise pathopt will be set to
3776 padvance(const char **path, const char *name)
3786 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3787 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3788 while (stackblocksize() < len)
3792 memcpy(q, start, p - start);
3800 while (*p && *p != ':') p++;
3806 return stalloc(len);
3810 /*** Command hashing code ***/
3813 printentry(struct tblentry *cmdp)
3819 idx = cmdp->param.index;
3822 name = padvance(&path, cmdp->cmdname);
3824 } while (--idx >= 0);
3825 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3830 hashcmd(int argc, char **argv)
3832 struct tblentry **pp;
3833 struct tblentry *cmdp;
3835 struct cmdentry entry;
3838 while ((c = nextopt("r")) != '\0') {
3842 if (*argptr == NULL) {
3843 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3844 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3845 if (cmdp->cmdtype == CMDNORMAL)
3852 while ((name = *argptr) != NULL) {
3853 if ((cmdp = cmdlookup(name, 0)) != NULL
3854 && (cmdp->cmdtype == CMDNORMAL
3855 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3857 find_command(name, &entry, DO_ERR, pathval());
3858 if (entry.cmdtype == CMDUNKNOWN)
3867 * Resolve a command name. If you change this routine, you may have to
3868 * change the shellexec routine as well.
3872 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3874 struct tblentry *cmdp;
3881 struct builtincmd *bcmd;
3883 /* If name contains a slash, don't use PATH or hash table */
3884 if (strchr(name, '/') != NULL) {
3885 entry->u.index = -1;
3887 while (stat(name, &statb) < 0) {
3892 entry->cmdtype = CMDUNKNOWN;
3896 entry->cmdtype = CMDNORMAL;
3900 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3901 if (find_applet_by_name(name)) {
3902 entry->cmdtype = CMDNORMAL;
3903 entry->u.index = -1;
3908 updatetbl = (path == pathval());
3911 if (strstr(path, "%builtin") != NULL)
3915 /* If name is in the table, check answer will be ok */
3916 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3919 switch (cmdp->cmdtype) {
3937 } else if (cmdp->rehash == 0)
3938 /* if not invalidated by cd, we're done */
3942 /* If %builtin not in path, check for builtin next */
3943 bcmd = find_builtin(name);
3944 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3945 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3947 goto builtin_success;
3949 /* We have to search path. */
3950 prev = -1; /* where to start */
3951 if (cmdp && cmdp->rehash) { /* doing a rehash */
3952 if (cmdp->cmdtype == CMDBUILTIN)
3955 prev = cmdp->param.index;
3961 while ((fullname = padvance(&path, name)) != NULL) {
3962 stunalloc(fullname);
3965 if (prefix(pathopt, "builtin")) {
3967 goto builtin_success;
3969 } else if (!(act & DO_NOFUNC) &&
3970 prefix(pathopt, "func")) {
3973 /* ignore unimplemented options */
3977 /* if rehash, don't redo absolute path names */
3978 if (fullname[0] == '/' && idx <= prev) {
3981 TRACE(("searchexec \"%s\": no change\n", name));
3984 while (stat(fullname, &statb) < 0) {
3989 if (errno != ENOENT && errno != ENOTDIR)
3993 e = EACCES; /* if we fail, this will be the error */
3994 if (!S_ISREG(statb.st_mode))
3996 if (pathopt) { /* this is a %func directory */
3997 stalloc(strlen(fullname) + 1);
3998 readcmdfile(fullname);
3999 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4000 cmdp->cmdtype != CMDFUNCTION)
4001 error("%s not defined in %s", name, fullname);
4002 stunalloc(fullname);
4005 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4007 entry->cmdtype = CMDNORMAL;
4008 entry->u.index = idx;
4012 cmdp = cmdlookup(name, 1);
4013 cmdp->cmdtype = CMDNORMAL;
4014 cmdp->param.index = idx;
4019 /* We failed. If there was an entry for this command, delete it */
4020 if (cmdp && updatetbl)
4023 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4024 entry->cmdtype = CMDUNKNOWN;
4029 entry->cmdtype = CMDBUILTIN;
4030 entry->u.cmd = bcmd;
4034 cmdp = cmdlookup(name, 1);
4035 cmdp->cmdtype = CMDBUILTIN;
4036 cmdp->param.cmd = bcmd;
4040 entry->cmdtype = cmdp->cmdtype;
4041 entry->u = cmdp->param;
4046 * Wrapper around strcmp for qsort/bsearch/...
4048 static int pstrcmp(const void *a, const void *b)
4050 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4054 * Search the table of builtin commands.
4057 static struct builtincmd *
4058 find_builtin(const char *name)
4060 struct builtincmd *bp;
4063 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4072 * Called when a cd is done. Marks all commands so the next time they
4073 * are executed they will be rehashed.
4079 struct tblentry **pp;
4080 struct tblentry *cmdp;
4082 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4083 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4084 if (cmdp->cmdtype == CMDNORMAL || (
4085 cmdp->cmdtype == CMDBUILTIN &&
4086 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4097 * Fix command hash table when PATH changed.
4098 * Called before PATH is changed. The argument is the new value of PATH;
4099 * pathval() still returns the old value at this point.
4100 * Called with interrupts off.
4104 changepath(const char *newval)
4106 const char *old, *new;
4113 firstchange = 9999; /* assume no change */
4119 if ((*old == '\0' && *new == ':')
4120 || (*old == ':' && *new == '\0'))
4122 old = new; /* ignore subsequent differences */
4126 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4133 if (builtinloc < 0 && idx_bltin >= 0)
4134 builtinloc = idx_bltin; /* zap builtins */
4135 if (builtinloc >= 0 && idx_bltin < 0)
4137 clearcmdentry(firstchange);
4138 builtinloc = idx_bltin;
4143 * Clear out command entries. The argument specifies the first entry in
4144 * PATH which has changed.
4148 clearcmdentry(int firstchange)
4150 struct tblentry **tblp;
4151 struct tblentry **pp;
4152 struct tblentry *cmdp;
4155 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4157 while ((cmdp = *pp) != NULL) {
4158 if ((cmdp->cmdtype == CMDNORMAL &&
4159 cmdp->param.index >= firstchange)
4160 || (cmdp->cmdtype == CMDBUILTIN &&
4161 builtinloc >= firstchange)) {
4175 * Locate a command in the command hash table. If "add" is nonzero,
4176 * add the command to the table if it is not already present. The
4177 * variable "lastcmdentry" is set to point to the address of the link
4178 * pointing to the entry, so that delete_cmd_entry can delete the
4181 * Interrupts must be off if called with add != 0.
4184 static struct tblentry **lastcmdentry;
4187 static struct tblentry *
4188 cmdlookup(const char *name, int add)
4190 unsigned int hashval;
4192 struct tblentry *cmdp;
4193 struct tblentry **pp;
4196 hashval = (unsigned char)*p << 4;
4198 hashval += (unsigned char)*p++;
4200 pp = &cmdtable[hashval % CMDTABLESIZE];
4201 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4202 if (equal(cmdp->cmdname, name))
4206 if (add && cmdp == NULL) {
4207 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4208 + strlen(name) + 1);
4210 cmdp->cmdtype = CMDUNKNOWN;
4211 strcpy(cmdp->cmdname, name);
4218 * Delete the command entry returned on the last lookup.
4222 delete_cmd_entry(void)
4224 struct tblentry *cmdp;
4227 cmdp = *lastcmdentry;
4228 *lastcmdentry = cmdp->next;
4229 if (cmdp->cmdtype == CMDFUNCTION)
4230 freefunc(cmdp->param.func);
4237 * Add a new command entry, replacing any existing command entry for
4238 * the same name - except special builtins.
4242 addcmdentry(char *name, struct cmdentry *entry)
4244 struct tblentry *cmdp;
4246 cmdp = cmdlookup(name, 1);
4247 if (cmdp->cmdtype == CMDFUNCTION) {
4248 freefunc(cmdp->param.func);
4250 cmdp->cmdtype = entry->cmdtype;
4251 cmdp->param = entry->u;
4256 * Make a copy of a parse tree.
4259 static inline struct funcnode *
4260 copyfunc(union node *n)
4265 funcblocksize = offsetof(struct funcnode, n);
4268 blocksize = funcblocksize;
4269 f = ckmalloc(blocksize + funcstringsize);
4270 funcblock = (char *) f + offsetof(struct funcnode, n);
4271 funcstring = (char *) f + blocksize;
4278 * Define a shell function.
4282 defun(char *name, union node *func)
4284 struct cmdentry entry;
4287 entry.cmdtype = CMDFUNCTION;
4288 entry.u.func = copyfunc(func);
4289 addcmdentry(name, &entry);
4295 * Delete a function if it exists.
4299 unsetfunc(const char *name)
4301 struct tblentry *cmdp;
4303 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4304 cmdp->cmdtype == CMDFUNCTION)
4309 * Locate and print what a word is...
4313 #ifdef CONFIG_ASH_CMDCMD
4315 describe_command(char *command, int describe_command_verbose)
4317 #define describe_command_verbose 1
4319 describe_command(char *command)
4322 struct cmdentry entry;
4323 struct tblentry *cmdp;
4324 #ifdef CONFIG_ASH_ALIAS
4325 const struct alias *ap;
4327 const char *path = pathval();
4329 if (describe_command_verbose) {
4333 /* First look at the keywords */
4334 if (findkwd(command)) {
4335 out1str(describe_command_verbose ? " is a shell keyword" : command);
4339 #ifdef CONFIG_ASH_ALIAS
4340 /* Then look at the aliases */
4341 if ((ap = lookupalias(command, 0)) != NULL) {
4342 if (describe_command_verbose) {
4343 out1fmt(" is an alias for %s", ap->val);
4352 /* Then check if it is a tracked alias */
4353 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4354 entry.cmdtype = cmdp->cmdtype;
4355 entry.u = cmdp->param;
4357 /* Finally use brute force */
4358 find_command(command, &entry, DO_ABS, path);
4361 switch (entry.cmdtype) {
4363 int j = entry.u.index;
4369 p = padvance(&path, command);
4373 if (describe_command_verbose) {
4375 (cmdp ? " a tracked alias for" : nullstr), p
4384 if (describe_command_verbose) {
4385 out1str(" is a shell function");
4392 if (describe_command_verbose) {
4393 out1fmt(" is a %sshell builtin",
4394 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4395 "special " : nullstr
4403 if (describe_command_verbose) {
4404 out1str(": not found\n");
4410 outstr("\n", stdout);
4415 typecmd(int argc, char **argv)
4420 for (i = 1; i < argc; i++) {
4421 #ifdef CONFIG_ASH_CMDCMD
4422 err |= describe_command(argv[i], 1);
4424 err |= describe_command(argv[i]);
4430 #ifdef CONFIG_ASH_CMDCMD
4432 commandcmd(int argc, char **argv)
4435 int default_path = 0;
4436 int verify_only = 0;
4437 int verbose_verify_only = 0;
4439 while ((c = nextopt("pvV")) != '\0')
4444 "command: nextopt returned character code 0%o\n", c);
4454 verbose_verify_only = 1;
4458 if (default_path + verify_only + verbose_verify_only > 1 ||
4461 "command [-p] command [arg ...]\n"
4462 "command {-v|-V} command\n");
4466 if (verify_only || verbose_verify_only) {
4467 return describe_command(*argptr, verbose_verify_only);
4474 /* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
4477 * Routines to expand arguments to commands. We have to deal with
4478 * backquotes, shell variables, and file metacharacters.
4484 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4485 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4486 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4487 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4488 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4491 * Structure specifying which parts of the string should be searched
4492 * for IFS characters.
4496 struct ifsregion *next; /* next region in list */
4497 int begoff; /* offset of start of region */
4498 int endoff; /* offset of end of region */
4499 int nulonly; /* search for nul bytes only */
4502 /* output of current string */
4503 static char *expdest;
4504 /* list of back quote expressions */
4505 static struct nodelist *argbackq;
4506 /* first struct in list of ifs regions */
4507 static struct ifsregion ifsfirst;
4508 /* last struct in list */
4509 static struct ifsregion *ifslastp;
4510 /* holds expanded arg list */
4511 static struct arglist exparg;
4513 static void argstr(char *, int);
4514 static char *exptilde(char *, char *, int);
4515 static void expbackq(union node *, int, int);
4516 static const char *subevalvar(char *, char *, int, int, int, int, int);
4517 static char *evalvar(char *, int);
4518 static void strtodest(const char *, int, int);
4519 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4520 static ssize_t varvalue(char *, int, int);
4521 static void recordregion(int, int, int);
4522 static void removerecordregions(int);
4523 static void ifsbreakup(char *, struct arglist *);
4524 static void ifsfree(void);
4525 static void expandmeta(struct strlist *, int);
4526 static int patmatch(char *, const char *);
4528 static int cvtnum(arith_t);
4529 static size_t esclen(const char *, const char *);
4530 static char *scanleft(char *, char *, char *, char *, int, int);
4531 static char *scanright(char *, char *, char *, char *, int, int);
4532 static void varunset(const char *, const char *, const char *, int)
4533 __attribute__((__noreturn__));
4536 #define pmatch(a, b) !fnmatch((a), (b), 0)
4538 * Prepare a pattern for a expmeta (internal glob(3)) call.
4540 * Returns an stalloced string.
4543 static inline char *
4544 preglob(const char *pattern, int quoted, int flag) {
4545 flag |= RMESCAPE_GLOB;
4547 flag |= RMESCAPE_QUOTED;
4549 return _rmescapes((char *)pattern, flag);
4554 esclen(const char *start, const char *p) {
4557 while (p > start && *--p == CTLESC) {
4565 * Expand shell variables and backquotes inside a here document.
4569 expandhere(union node *arg, int fd)
4572 expandarg(arg, (struct arglist *)NULL, 0);
4573 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
4578 * Perform variable substitution and command substitution on an argument,
4579 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4580 * perform splitting and file name expansion. When arglist is NULL, perform
4581 * here document expansion.
4585 expandarg(union node *arg, struct arglist *arglist, int flag)
4590 argbackq = arg->narg.backquote;
4591 STARTSTACKSTR(expdest);
4592 ifsfirst.next = NULL;
4594 argstr(arg->narg.text, flag);
4595 if (arglist == NULL) {
4596 return; /* here document expanded */
4598 STPUTC('\0', expdest);
4599 p = grabstackstr(expdest);
4600 exparg.lastp = &exparg.list;
4604 if (flag & EXP_FULL) {
4605 ifsbreakup(p, &exparg);
4606 *exparg.lastp = NULL;
4607 exparg.lastp = &exparg.list;
4608 expandmeta(exparg.list, flag);
4610 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4612 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4615 exparg.lastp = &sp->next;
4619 *exparg.lastp = NULL;
4621 *arglist->lastp = exparg.list;
4622 arglist->lastp = exparg.lastp;
4628 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4629 * characters to allow for further processing. Otherwise treat
4630 * $@ like $* since no splitting will be performed.
4634 argstr(char *p, int flag)
4636 static const char spclchars[] = {
4644 CTLBACKQ | CTLQUOTE,
4645 #ifdef CONFIG_ASH_MATH_SUPPORT
4650 const char *reject = spclchars;
4652 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4653 int breakall = flag & EXP_WORD;
4658 if (!(flag & EXP_VARTILDE)) {
4660 } else if (flag & EXP_VARTILDE2) {
4665 if (flag & EXP_TILDE) {
4671 if (*q == CTLESC && (flag & EXP_QWORD))
4674 p = exptilde(p, q, flag);
4677 startloc = expdest - (char *)stackblock();
4679 length += strcspn(p + length, reject);
4681 if (c && (!(c & 0x80)
4682 #ifdef CONFIG_ASH_MATH_SUPPORT
4686 /* c == '=' || c == ':' || c == CTLENDARI */
4691 expdest = stnputs(p, length, expdest);
4692 newloc = expdest - (char *)stackblock();
4693 if (breakall && !inquotes && newloc > startloc) {
4694 recordregion(startloc, newloc, 0);
4705 if (flag & EXP_VARTILDE2) {
4709 flag |= EXP_VARTILDE2;
4714 * sort of a hack - expand tildes in variable
4715 * assignments (after the first '=' and after ':'s).
4724 case CTLENDVAR: /* ??? */
4727 /* "$@" syntax adherence hack */
4730 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4731 (p[4] == CTLQUOTEMARK || (
4732 p[4] == CTLENDVAR &&
4733 p[5] == CTLQUOTEMARK
4736 p = evalvar(p + 1, flag) + 1;
4739 inquotes = !inquotes;
4752 p = evalvar(p, flag);
4756 case CTLBACKQ|CTLQUOTE:
4757 expbackq(argbackq->n, c, quotes);
4758 argbackq = argbackq->next;
4760 #ifdef CONFIG_ASH_MATH_SUPPORT
4773 exptilde(char *startp, char *p, int flag)
4779 int quotes = flag & (EXP_FULL | EXP_CASE);
4784 while ((c = *++p) != '\0') {
4791 if (flag & EXP_VARTILDE)
4801 if (*name == '\0') {
4802 if ((home = lookupvar(homestr)) == NULL)
4805 if ((pw = getpwnam(name)) == NULL)
4812 startloc = expdest - (char *)stackblock();
4813 strtodest(home, SQSYNTAX, quotes);
4814 recordregion(startloc, expdest - (char *)stackblock(), 0);
4823 removerecordregions(int endoff)
4825 if (ifslastp == NULL)
4828 if (ifsfirst.endoff > endoff) {
4829 while (ifsfirst.next != NULL) {
4830 struct ifsregion *ifsp;
4832 ifsp = ifsfirst.next->next;
4833 ckfree(ifsfirst.next);
4834 ifsfirst.next = ifsp;
4837 if (ifsfirst.begoff > endoff)
4840 ifslastp = &ifsfirst;
4841 ifsfirst.endoff = endoff;
4846 ifslastp = &ifsfirst;
4847 while (ifslastp->next && ifslastp->next->begoff < endoff)
4848 ifslastp=ifslastp->next;
4849 while (ifslastp->next != NULL) {
4850 struct ifsregion *ifsp;
4852 ifsp = ifslastp->next->next;
4853 ckfree(ifslastp->next);
4854 ifslastp->next = ifsp;
4857 if (ifslastp->endoff > endoff)
4858 ifslastp->endoff = endoff;
4862 #ifdef CONFIG_ASH_MATH_SUPPORT
4864 * Expand arithmetic expression. Backup to start of expression,
4865 * evaluate, place result in (backed up) result, adjust string position.
4878 * This routine is slightly over-complicated for
4879 * efficiency. Next we scan backwards looking for the
4880 * start of arithmetic.
4882 start = stackblock();
4889 while (*p != CTLARI) {
4893 error("missing CTLARI (shouldn't happen)");
4898 esc = esclen(start, p);
4908 removerecordregions(begoff);
4917 len = cvtnum(dash_arith(p + 2));
4920 recordregion(begoff, begoff + len, 0);
4925 * Expand stuff in backwards quotes.
4929 expbackq(union node *cmd, int quoted, int quotes)
4937 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4938 struct stackmark smark;
4941 setstackmark(&smark);
4943 startloc = dest - (char *)stackblock();
4945 evalbackcmd(cmd, (struct backcmd *) &in);
4946 popstackmark(&smark);
4953 memtodest(p, i, syntax, quotes);
4957 i = safe_read(in.fd, buf, sizeof buf);
4958 TRACE(("expbackq: read returns %d\n", i));
4968 back_exitstatus = waitforjob(in.jp);
4972 /* Eat all trailing newlines */
4974 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4979 recordregion(startloc, dest - (char *)stackblock(), 0);
4980 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4981 (dest - (char *)stackblock()) - startloc,
4982 (dest - (char *)stackblock()) - startloc,
4983 stackblock() + startloc));
4988 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4999 const char *s = loc2;
5005 match = pmatch(str, s);
5009 if (quotes && *loc == CTLESC)
5019 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5026 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5029 const char *s = loc2;
5034 match = pmatch(str, s);
5041 esc = esclen(startp, loc);
5053 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5057 int saveherefd = herefd;
5058 struct nodelist *saveargbackq = argbackq;
5060 char *rmesc, *rmescend;
5062 char *(*scan)(char *, char *, char *, char *, int , int);
5065 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5066 STPUTC('\0', expdest);
5067 herefd = saveherefd;
5068 argbackq = saveargbackq;
5069 startp = stackblock() + startloc;
5073 setvar(str, startp, 0);
5074 amount = startp - expdest;
5075 STADJUST(amount, expdest);
5079 varunset(p, str, startp, varflags);
5083 subtype -= VSTRIMRIGHT;
5085 if (subtype < 0 || subtype > 3)
5090 rmescend = stackblock() + strloc;
5092 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5093 if (rmesc != startp) {
5095 startp = stackblock() + startloc;
5099 str = stackblock() + strloc;
5100 preglob(str, varflags & VSQUOTE, 0);
5102 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5103 zero = subtype >> 1;
5104 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5105 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5107 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5110 memmove(startp, loc, str - loc);
5111 loc = startp + (str - loc) - 1;
5114 amount = loc - expdest;
5115 STADJUST(amount, expdest);
5122 * Expand a variable, and return a pointer to the next character in the
5126 evalvar(char *p, int flag)
5139 quotes = flag & (EXP_FULL | EXP_CASE);
5141 subtype = varflags & VSTYPE;
5142 quoted = varflags & VSQUOTE;
5144 easy = (!quoted || (*var == '@' && shellparam.nparam));
5145 startloc = expdest - (char *)stackblock();
5146 p = strchr(p, '=') + 1;
5149 varlen = varvalue(var, varflags, flag);
5150 if (varflags & VSNUL)
5153 if (subtype == VSPLUS) {
5154 varlen = -1 - varlen;
5158 if (subtype == VSMINUS) {
5162 p, flag | EXP_TILDE |
5163 (quoted ? EXP_QWORD : EXP_WORD)
5172 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5174 if (subevalvar(p, var, 0, subtype, startloc,
5178 * Remove any recorded regions beyond
5181 removerecordregions(startloc);
5191 if (varlen < 0 && uflag)
5192 varunset(p, var, 0, 0);
5194 if (subtype == VSLENGTH) {
5195 cvtnum(varlen > 0 ? varlen : 0);
5199 if (subtype == VSNORMAL) {
5203 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5212 case VSTRIMRIGHTMAX:
5221 * Terminate the string and start recording the pattern
5224 STPUTC('\0', expdest);
5225 patloc = expdest - (char *)stackblock();
5226 if (subevalvar(p, NULL, patloc, subtype,
5227 startloc, varflags, quotes) == 0) {
5228 int amount = expdest - (
5229 (char *)stackblock() + patloc - 1
5231 STADJUST(-amount, expdest);
5233 /* Remove any recorded regions beyond start of variable */
5234 removerecordregions(startloc);
5239 if (subtype != VSNORMAL) { /* skip to end of alternative */
5242 if ((c = *p++) == CTLESC)
5244 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5246 argbackq = argbackq->next;
5247 } else if (c == CTLVAR) {
5248 if ((*p++ & VSTYPE) != VSNORMAL)
5250 } else if (c == CTLENDVAR) {
5261 * Put a string on the stack.
5265 memtodest(const char *p, size_t len, int syntax, int quotes) {
5268 q = makestrspace(len * 2, q);
5274 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5284 strtodest(const char *p, int syntax, int quotes)
5286 memtodest(p, strlen(p), syntax, quotes);
5291 * Add the value of a specialized variable to the stack string.
5295 varvalue(char *name, int varflags, int flags)
5305 int quoted = varflags & VSQUOTE;
5306 int subtype = varflags & VSTYPE;
5307 int quotes = flags & (EXP_FULL | EXP_CASE);
5309 if (quoted && (flags & EXP_FULL))
5310 sep = 1 << CHAR_BIT;
5312 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5321 num = shellparam.nparam;
5331 p = makestrspace(NOPTS, expdest);
5332 for (i = NOPTS - 1; i >= 0; i--) {
5334 USTPUTC(optletters(i), p);
5345 sep = ifsset() ? ifsval()[0] : ' ';
5346 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5349 if (!(ap = shellparam.p))
5351 while ((p = *ap++)) {
5354 partlen = strlen(p);
5357 if (len > partlen && sep) {
5361 if (subtype == VSPLUS || subtype == VSLENGTH) {
5371 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5372 memtodest(p, partlen, syntax, quotes);
5386 if (num < 0 || num > shellparam.nparam)
5388 p = num ? shellparam.p[num - 1] : arg0;
5391 p = lookupvar(name);
5397 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5398 memtodest(p, len, syntax, quotes);
5402 if (subtype == VSPLUS || subtype == VSLENGTH)
5403 STADJUST(-len, expdest);
5409 * Record the fact that we have to scan this region of the
5410 * string for IFS characters.
5414 recordregion(int start, int end, int nulonly)
5416 struct ifsregion *ifsp;
5418 if (ifslastp == NULL) {
5422 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5424 ifslastp->next = ifsp;
5428 ifslastp->begoff = start;
5429 ifslastp->endoff = end;
5430 ifslastp->nulonly = nulonly;
5435 * Break the argument string into pieces based upon IFS and add the
5436 * strings to the argument list. The regions of the string to be
5437 * searched for IFS characters have been stored by recordregion.
5440 ifsbreakup(char *string, struct arglist *arglist)
5442 struct ifsregion *ifsp;
5447 const char *ifs, *realifs;
5453 if (ifslastp != NULL) {
5456 realifs = ifsset() ? ifsval() : defifs;
5459 p = string + ifsp->begoff;
5460 nulonly = ifsp->nulonly;
5461 ifs = nulonly ? nullstr : realifs;
5463 while (p < string + ifsp->endoff) {
5467 if (strchr(ifs, *p)) {
5469 ifsspc = (strchr(defifs, *p) != NULL);
5470 /* Ignore IFS whitespace at start */
5471 if (q == start && ifsspc) {
5477 sp = (struct strlist *)stalloc(sizeof *sp);
5479 *arglist->lastp = sp;
5480 arglist->lastp = &sp->next;
5484 if (p >= string + ifsp->endoff) {
5490 if (strchr(ifs, *p) == NULL ) {
5493 } else if (strchr(defifs, *p) == NULL) {
5509 } while ((ifsp = ifsp->next) != NULL);
5518 sp = (struct strlist *)stalloc(sizeof *sp);
5520 *arglist->lastp = sp;
5521 arglist->lastp = &sp->next;
5527 struct ifsregion *p;
5532 struct ifsregion *ifsp;
5538 ifsfirst.next = NULL;
5542 static void expmeta(char *, char *);
5543 static struct strlist *expsort(struct strlist *);
5544 static struct strlist *msort(struct strlist *, int);
5546 static char *expdir;
5550 expandmeta(struct strlist *str, int flag)
5552 static const char metachars[] = {
5555 /* TODO - EXP_REDIR */
5558 struct strlist **savelastp;
5564 if (!strpbrk(str->text, metachars))
5566 savelastp = exparg.lastp;
5569 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5571 int i = strlen(str->text);
5572 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5580 if (exparg.lastp == savelastp) {
5585 *exparg.lastp = str;
5586 rmescapes(str->text);
5587 exparg.lastp = &str->next;
5589 *exparg.lastp = NULL;
5590 *savelastp = sp = expsort(*savelastp);
5591 while (sp->next != NULL)
5593 exparg.lastp = &sp->next;
5600 * Add a file name to the list.
5604 addfname(const char *name)
5608 sp = (struct strlist *)stalloc(sizeof *sp);
5609 sp->text = sstrdup(name);
5611 exparg.lastp = &sp->next;
5616 * Do metacharacter (i.e. *, ?, [...]) expansion.
5620 expmeta(char *enddir, char *name)
5635 for (p = name; *p; p++) {
5636 if (*p == '*' || *p == '?')
5638 else if (*p == '[') {
5645 if (*q == '/' || *q == '\0')
5652 } else if (*p == '\\')
5654 else if (*p == '/') {
5661 if (metaflag == 0) { /* we've reached the end of the file name */
5662 if (enddir != expdir)
5670 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5681 } while (p < start);
5683 if (enddir == expdir) {
5685 } else if (enddir == expdir + 1 && *expdir == '/') {
5691 if ((dirp = opendir(cp)) == NULL)
5693 if (enddir != expdir)
5695 if (*endname == 0) {
5707 while (! intpending && (dp = readdir(dirp)) != NULL) {
5708 if (dp->d_name[0] == '.' && ! matchdot)
5710 if (pmatch(start, dp->d_name)) {
5712 scopy(dp->d_name, enddir);
5715 for (p = enddir, cp = dp->d_name;
5716 (*p++ = *cp++) != '\0';)
5719 expmeta(p, endname);
5729 * Sort the results of file name expansion. It calculates the number of
5730 * strings to sort and then calls msort (short for merge sort) to do the
5734 static struct strlist *
5735 expsort(struct strlist *str)
5741 for (sp = str ; sp ; sp = sp->next)
5743 return msort(str, len);
5747 static struct strlist *
5748 msort(struct strlist *list, int len)
5750 struct strlist *p, *q = NULL;
5751 struct strlist **lpp;
5759 for (n = half ; --n >= 0 ; ) {
5763 q->next = NULL; /* terminate first half of list */
5764 q = msort(list, half); /* sort first half of list */
5765 p = msort(p, len - half); /* sort second half */
5768 #ifdef CONFIG_LOCALE_SUPPORT
5769 if (strcoll(p->text, q->text) < 0)
5771 if (strcmp(p->text, q->text) < 0)
5776 if ((p = *lpp) == NULL) {
5783 if ((q = *lpp) == NULL) {
5794 * Returns true if the pattern matches the string.
5798 patmatch(char *pattern, const char *string)
5800 return pmatch(preglob(pattern, 0, 0), string);
5805 * Remove any CTLESC characters from a string.
5809 _rmescapes(char *str, int flag)
5812 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5817 p = strpbrk(str, qchars);
5823 if (flag & RMESCAPE_ALLOC) {
5824 size_t len = p - str;
5825 size_t fulllen = len + strlen(p) + 1;
5827 if (flag & RMESCAPE_GROW) {
5828 r = makestrspace(fulllen, expdest);
5829 } else if (flag & RMESCAPE_HEAP) {
5830 r = ckmalloc(fulllen);
5832 r = stalloc(fulllen);
5836 q = mempcpy(q, str, len);
5839 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5840 globbing = flag & RMESCAPE_GLOB;
5841 notescaped = globbing;
5843 if (*p == CTLQUOTEMARK) {
5844 inquotes = ~inquotes;
5846 notescaped = globbing;
5850 /* naked back slash */
5856 if (notescaped && inquotes && *p != '/') {
5860 notescaped = globbing;
5865 if (flag & RMESCAPE_GROW) {
5867 STADJUST(q - r + 1, expdest);
5874 * See if a pattern matches in a case statement.
5878 casematch(union node *pattern, char *val)
5880 struct stackmark smark;
5883 setstackmark(&smark);
5884 argbackq = pattern->narg.backquote;
5885 STARTSTACKSTR(expdest);
5887 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5888 STACKSTRNUL(expdest);
5889 result = patmatch(stackblock(), val);
5890 popstackmark(&smark);
5903 expdest = makestrspace(32, expdest);
5904 #ifdef CONFIG_ASH_MATH_SUPPORT_64
5905 len = fmtstr(expdest, 32, "%lld", (long long) num);
5907 len = fmtstr(expdest, 32, "%ld", num);
5909 STADJUST(len, expdest);
5914 varunset(const char *end, const char *var, const char *umsg, int varflags)
5920 msg = "parameter not set";
5922 if (*end == CTLENDVAR) {
5923 if (varflags & VSNUL)
5928 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5932 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5935 * This implements the input routines used by the parser.
5938 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5939 #define IBUFSIZ (BUFSIZ + 1)
5941 static void pushfile(void);
5944 * Read a character from the script, returning PEOF on end of file.
5945 * Nul characters in the input are silently discarded.
5948 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5950 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5951 #define pgetc_macro() pgetc()
5955 return pgetc_as_macro();
5958 #define pgetc_macro() pgetc_as_macro()
5962 return pgetc_macro();
5968 * Same as pgetc(), but ignores PEOA.
5970 #ifdef CONFIG_ASH_ALIAS
5971 static int pgetc2(void)
5977 } while (c == PEOA);
5981 static inline int pgetc2(void)
5983 return pgetc_macro();
5988 * Read a line from the script.
5991 static inline char *
5992 pfgets(char *line, int len)
5998 while (--nleft > 0) {
6015 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6016 static const char *cmdedit_prompt;
6017 static inline void putprompt(const char *s)
6022 static inline void putprompt(const char *s)
6032 char *buf = parsefile->buf;
6036 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6037 if (!iflag || parsefile->fd)
6038 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6040 #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
6041 cmdedit_path_lookup = pathval();
6043 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6045 /* Ctrl+C presend */
6054 if(nr < 0 && errno == 0) {
6055 /* Ctrl+D presend */
6060 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6064 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6065 int flags = fcntl(0, F_GETFL, 0);
6066 if (flags >= 0 && flags & O_NONBLOCK) {
6067 flags &=~ O_NONBLOCK;
6068 if (fcntl(0, F_SETFL, flags) >= 0) {
6069 out2str("sh: turning off NDELAY mode\n");
6079 * Refill the input buffer and return the next input character:
6081 * 1) If a string was pushed back on the input, pop it;
6082 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6083 * from a string so we can't refill the buffer, return EOF.
6084 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6085 * 4) Process input up to the next newline, deleting nul characters.
6095 while (parsefile->strpush) {
6096 #ifdef CONFIG_ASH_ALIAS
6097 if (parsenleft == -1 && parsefile->strpush->ap &&
6098 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6103 if (--parsenleft >= 0)
6104 return (*parsenextc++);
6106 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6111 if (parselleft <= 0) {
6112 if ((parselleft = preadfd()) <= 0) {
6113 parselleft = parsenleft = EOF_NLEFT;
6120 /* delete nul characters */
6121 for (more = 1; more;) {
6128 parsenleft = q - parsenextc;
6129 more = 0; /* Stop processing here */
6136 if (--parselleft <= 0 && more) {
6137 parsenleft = q - parsenextc - 1;
6148 out2str(parsenextc);
6153 return *parsenextc++;
6157 * Undo the last call to pgetc. Only one character may be pushed back.
6158 * PEOF may be pushed back.
6169 * Push a string back onto the input at this current parsefile level.
6170 * We handle aliases this way.
6173 pushstring(char *s, void *ap)
6180 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6181 if (parsefile->strpush) {
6182 sp = ckmalloc(sizeof (struct strpush));
6183 sp->prev = parsefile->strpush;
6184 parsefile->strpush = sp;
6186 sp = parsefile->strpush = &(parsefile->basestrpush);
6187 sp->prevstring = parsenextc;
6188 sp->prevnleft = parsenleft;
6189 #ifdef CONFIG_ASH_ALIAS
6190 sp->ap = (struct alias *)ap;
6192 ((struct alias *)ap)->flag |= ALIASINUSE;
6204 struct strpush *sp = parsefile->strpush;
6207 #ifdef CONFIG_ASH_ALIAS
6209 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6210 checkkwd |= CHKALIAS;
6212 if (sp->string != sp->ap->val) {
6215 sp->ap->flag &= ~ALIASINUSE;
6216 if (sp->ap->flag & ALIASDEAD) {
6217 unalias(sp->ap->name);
6221 parsenextc = sp->prevstring;
6222 parsenleft = sp->prevnleft;
6223 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6224 parsefile->strpush = sp->prev;
6225 if (sp != &(parsefile->basestrpush))
6231 * Set the input to take input from a file. If push is set, push the
6232 * old input onto the stack first.
6236 setinputfile(const char *fname, int push)
6242 if ((fd = open(fname, O_RDONLY)) < 0)
6243 error("Can't open %s", fname);
6245 fd2 = copyfd(fd, 10);
6248 error("Out of file descriptors");
6251 setinputfd(fd, push);
6257 * Like setinputfile, but takes an open file descriptor. Call this with
6262 setinputfd(int fd, int push)
6264 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6270 if (parsefile->buf == NULL)
6271 parsefile->buf = ckmalloc(IBUFSIZ);
6272 parselleft = parsenleft = 0;
6278 * Like setinputfile, but takes input from a string.
6282 setinputstring(char *string)
6286 parsenextc = string;
6287 parsenleft = strlen(string);
6288 parsefile->buf = NULL;
6295 * To handle the "." command, a stack of input files is used. Pushfile
6296 * adds a new entry to the stack and popfile restores the previous level.
6302 struct parsefile *pf;
6304 parsefile->nleft = parsenleft;
6305 parsefile->lleft = parselleft;
6306 parsefile->nextc = parsenextc;
6307 parsefile->linno = plinno;
6308 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6309 pf->prev = parsefile;
6312 pf->basestrpush.prev = NULL;
6320 struct parsefile *pf = parsefile;
6329 parsefile = pf->prev;
6331 parsenleft = parsefile->nleft;
6332 parselleft = parsefile->lleft;
6333 parsenextc = parsefile->nextc;
6334 plinno = parsefile->linno;
6340 * Return to top level.
6346 while (parsefile != &basepf)
6352 * Close the file(s) that the shell is reading commands from. Called
6353 * after a fork is done.
6360 if (parsefile->fd > 0) {
6361 close(parsefile->fd);
6366 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6368 /* mode flags for set_curjob */
6369 #define CUR_DELETE 2
6370 #define CUR_RUNNING 1
6371 #define CUR_STOPPED 0
6373 /* mode flags for dowait */
6374 #define DOWAIT_NORMAL 0
6375 #define DOWAIT_BLOCK 1
6378 static struct job *jobtab;
6380 static unsigned njobs;
6382 /* pgrp of shell on invocation */
6383 static int initialpgrp;
6384 static int ttyfd = -1;
6387 static struct job *curjob;
6388 /* number of presumed living untracked jobs */
6391 static void set_curjob(struct job *, unsigned);
6393 static int restartjob(struct job *, int);
6394 static void xtcsetpgrp(int, pid_t);
6395 static char *commandtext(union node *);
6396 static void cmdlist(union node *, int);
6397 static void cmdtxt(union node *);
6398 static void cmdputs(const char *);
6399 static void showpipe(struct job *, FILE *);
6401 static int sprint_status(char *, int, int);
6402 static void freejob(struct job *);
6403 static struct job *getjob(const char *, int);
6404 static struct job *growjobtab(void);
6405 static void forkchild(struct job *, union node *, int);
6406 static void forkparent(struct job *, union node *, int, pid_t);
6407 static int dowait(int, struct job *);
6408 static int getstatus(struct job *);
6411 set_curjob(struct job *jp, unsigned mode)
6414 struct job **jpp, **curp;
6416 /* first remove from list */
6417 jpp = curp = &curjob;
6422 jpp = &jp1->prev_job;
6424 *jpp = jp1->prev_job;
6426 /* Then re-insert in correct position */
6434 /* job being deleted */
6437 /* newly created job or backgrounded job,
6438 put after all stopped jobs. */
6442 if (!jp1 || jp1->state != JOBSTOPPED)
6445 jpp = &jp1->prev_job;
6451 /* newly stopped job - becomes curjob */
6452 jp->prev_job = *jpp;
6460 * Turn job control on and off.
6462 * Note: This code assumes that the third arg to ioctl is a character
6463 * pointer, which is true on Berkeley systems but not System V. Since
6464 * System V doesn't have job control yet, this isn't a problem now.
6466 * Called with interrupts off.
6475 if (on == jobctl || rootshell == 0)
6479 ofd = fd = open(_PATH_TTY, O_RDWR);
6482 while (!isatty(fd) && --fd >= 0)
6485 fd = fcntl(fd, F_DUPFD, 10);
6489 fcntl(fd, F_SETFD, FD_CLOEXEC);
6490 do { /* while we are in the background */
6491 if ((pgrp = tcgetpgrp(fd)) < 0) {
6493 sh_warnx("can't access tty; job control turned off");
6497 if (pgrp == getpgrp())
6508 xtcsetpgrp(fd, pgrp);
6510 /* turning job control off */
6513 xtcsetpgrp(fd, pgrp);
6527 killcmd(int argc, char **argv)
6538 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6539 "kill -l [exitstatus]"
6543 if (**++argv == '-') {
6544 signo = decode_signal(*argv + 1, 1);
6548 while ((c = nextopt("ls:")) != '\0')
6558 signo = decode_signal(optionarg, 1);
6561 "invalid signal number or name: %s",
6572 if (!list && signo < 0)
6575 if ((signo < 0 || !*argv) ^ list) {
6583 for (i = 1; i < NSIG; i++) {
6584 name = u_signal_names(0, &i, 1);
6586 out1fmt(snlfmt, name);
6590 name = u_signal_names(*argptr, &signo, -1);
6592 out1fmt(snlfmt, name);
6594 error("invalid signal number or exit status: %s", *argptr);
6600 if (**argv == '%') {
6601 jp = getjob(*argv, 0);
6602 pid = -jp->ps[0].pid;
6604 pid = number(*argv);
6605 if (kill(pid, signo) != 0) {
6615 #if defined(JOBS) || defined(DEBUG)
6617 jobno(const struct job *jp)
6619 return jp - jobtab + 1;
6625 fgcmd(int argc, char **argv)
6632 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6637 jp = getjob(*argv, 1);
6638 if (mode == FORK_BG) {
6639 set_curjob(jp, CUR_RUNNING);
6640 fprintf(out, "[%d] ", jobno(jp));
6642 outstr(jp->ps->cmd, out);
6644 retval = restartjob(jp, mode);
6645 } while (*argv && *++argv);
6649 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6653 restartjob(struct job *jp, int mode)
6655 struct procstat *ps;
6661 if (jp->state == JOBDONE)
6663 jp->state = JOBRUNNING;
6665 if (mode == FORK_FG)
6666 xtcsetpgrp(ttyfd, pgid);
6667 killpg(pgid, SIGCONT);
6671 if (WIFSTOPPED(ps->status)) {
6674 } while (ps++, --i);
6676 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6683 sprint_status(char *s, int status, int sigonly)
6689 if (!WIFEXITED(status)) {
6691 if (WIFSTOPPED(status))
6692 st = WSTOPSIG(status);
6695 st = WTERMSIG(status);
6697 if (st == SIGINT || st == SIGPIPE)
6700 if (WIFSTOPPED(status))
6705 col = fmtstr(s, 32, strsignal(st));
6706 if (WCOREDUMP(status)) {
6707 col += fmtstr(s + col, 16, " (core dumped)");
6709 } else if (!sigonly) {
6710 st = WEXITSTATUS(status);
6712 col = fmtstr(s, 16, "Done(%d)", st);
6714 col = fmtstr(s, 16, "Done");
6723 showjob(FILE *out, struct job *jp, int mode)
6725 struct procstat *ps;
6726 struct procstat *psend;
6733 if (mode & SHOW_PGID) {
6734 /* just output process (group) id of pipeline */
6735 fprintf(out, "%d\n", ps->pid);
6739 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6744 else if (curjob && jp == curjob->prev_job)
6747 if (mode & SHOW_PID)
6748 col += fmtstr(s + col, 16, "%d ", ps->pid);
6750 psend = ps + jp->nprocs;
6752 if (jp->state == JOBRUNNING) {
6753 scopy("Running", s + col);
6754 col += strlen("Running");
6756 int status = psend[-1].status;
6758 if (jp->state == JOBSTOPPED)
6759 status = jp->stopstatus;
6761 col += sprint_status(s + col, status, 0);
6767 /* for each process */
6768 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6771 fprintf(out, "%s%*c%s",
6772 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6774 if (!(mode & SHOW_PID)) {
6778 if (++ps == psend) {
6779 outcslow('\n', out);
6786 if (jp->state == JOBDONE) {
6787 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6794 jobscmd(int argc, char **argv)
6800 while ((m = nextopt("lp")))
6810 showjob(out, getjob(*argv,0), mode);
6813 showjobs(out, mode);
6820 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6821 * statuses have changed since the last call to showjobs.
6825 showjobs(FILE *out, int mode)
6829 TRACE(("showjobs(%x) called\n", mode));
6831 /* If not even one one job changed, there is nothing to do */
6832 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6835 for (jp = curjob; jp; jp = jp->prev_job) {
6836 if (!(mode & SHOW_CHANGED) || jp->changed)
6837 showjob(out, jp, mode);
6843 * Mark a job structure as unused.
6847 freejob(struct job *jp)
6849 struct procstat *ps;
6853 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6854 if (ps->cmd != nullstr)
6857 if (jp->ps != &jp->ps0)
6860 set_curjob(jp, CUR_DELETE);
6866 waitcmd(int argc, char **argv)
6879 /* wait for all jobs */
6884 /* no running procs */
6887 if (jp->state == JOBRUNNING)
6892 dowait(DOWAIT_BLOCK, 0);
6898 if (**argv != '%') {
6899 pid_t pid = number(*argv);
6903 if (job->ps[job->nprocs - 1].pid == pid)
6905 job = job->prev_job;
6911 job = getjob(*argv, 0);
6912 /* loop until process terminated or stopped */
6913 while (job->state == JOBRUNNING)
6914 dowait(DOWAIT_BLOCK, 0);
6916 retval = getstatus(job);
6927 * Convert a job name to a job structure.
6931 getjob(const char *name, int getctl)
6935 const char *err_msg = "No such job: %s";
6939 char *(*match)(const char *, const char *);
6954 if (c == '+' || c == '%') {
6956 err_msg = "No current job";
6958 } else if (c == '-') {
6961 err_msg = "No previous job";
6972 jp = jobtab + num - 1;
6989 if (match(jp->ps[0].cmd, p)) {
6993 err_msg = "%s: ambiguous";
7000 err_msg = "job %s not created under job control";
7001 if (getctl && jp->jobctl == 0)
7006 error(err_msg, name);
7011 * Return a new job structure.
7012 * Called with interrupts off.
7016 makejob(union node *node, int nprocs)
7021 for (i = njobs, jp = jobtab ; ; jp++) {
7028 if (jp->state != JOBDONE || !jp->waited)
7037 memset(jp, 0, sizeof(*jp));
7042 jp->prev_job = curjob;
7047 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7049 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7059 struct job *jp, *jq;
7061 len = njobs * sizeof(*jp);
7063 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7065 offset = (char *)jp - (char *)jq;
7067 /* Relocate pointers */
7070 jq = (struct job *)((char *)jq + l);
7074 #define joff(p) ((struct job *)((char *)(p) + l))
7075 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7076 if (xlikely(joff(jp)->ps == &jq->ps0))
7077 jmove(joff(jp)->ps);
7078 if (joff(jp)->prev_job)
7079 jmove(joff(jp)->prev_job);
7089 jp = (struct job *)((char *)jp + len);
7093 } while (--jq >= jp);
7099 * Fork off a subshell. If we are doing job control, give the subshell its
7100 * own process group. Jp is a job structure that the job is to be added to.
7101 * N is the command that will be evaluated by the child. Both jp and n may
7102 * be NULL. The mode parameter can be one of the following:
7103 * FORK_FG - Fork off a foreground process.
7104 * FORK_BG - Fork off a background process.
7105 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7106 * process group even if job control is on.
7108 * When job control is turned off, background processes have their standard
7109 * input redirected to /dev/null (except for the second and later processes
7112 * Called with interrupts off.
7116 forkchild(struct job *jp, union node *n, int mode)
7120 TRACE(("Child shell %d\n", getpid()));
7121 wasroot = rootshell;
7127 /* do job control only in root shell */
7129 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7132 if (jp->nprocs == 0)
7135 pgrp = jp->ps[0].pid;
7136 /* This can fail because we are doing it in the parent also */
7137 (void)setpgid(0, pgrp);
7138 if (mode == FORK_FG)
7139 xtcsetpgrp(ttyfd, pgrp);
7144 if (mode == FORK_BG) {
7147 if (jp->nprocs == 0) {
7149 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7150 error("Can't open %s", _PATH_DEVNULL);
7153 if (wasroot && iflag) {
7158 for (jp = curjob; jp; jp = jp->prev_job)
7164 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7166 TRACE(("In parent shell: child = %d\n", pid));
7168 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7173 if (mode != FORK_NOJOB && jp->jobctl) {
7176 if (jp->nprocs == 0)
7179 pgrp = jp->ps[0].pid;
7180 /* This can fail because we are doing it in the child also */
7181 (void)setpgid(pid, pgrp);
7184 if (mode == FORK_BG) {
7185 backgndpid = pid; /* set $! */
7186 set_curjob(jp, CUR_RUNNING);
7189 struct procstat *ps = &jp->ps[jp->nprocs++];
7195 ps->cmd = commandtext(n);
7201 forkshell(struct job *jp, union node *n, int mode)
7205 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7208 TRACE(("Fork failed, errno=%d", errno));
7211 error("Cannot fork");
7214 forkchild(jp, n, mode);
7216 forkparent(jp, n, mode, pid);
7221 * Wait for job to finish.
7223 * Under job control we have the problem that while a child process is
7224 * running interrupts generated by the user are sent to the child but not
7225 * to the shell. This means that an infinite loop started by an inter-
7226 * active user may be hard to kill. With job control turned off, an
7227 * interactive user may place an interactive program inside a loop. If
7228 * the interactive program catches interrupts, the user doesn't want
7229 * these interrupts to also abort the loop. The approach we take here
7230 * is to have the shell ignore interrupt signals while waiting for a
7231 * foreground process to terminate, and then send itself an interrupt
7232 * signal if the child process was terminated by an interrupt signal.
7233 * Unfortunately, some programs want to do a bit of cleanup and then
7234 * exit on interrupt; unless these processes terminate themselves by
7235 * sending a signal to themselves (instead of calling exit) they will
7236 * confuse this approach.
7238 * Called with interrupts off.
7242 waitforjob(struct job *jp)
7246 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7247 while (jp->state == JOBRUNNING) {
7248 dowait(DOWAIT_BLOCK, jp);
7253 xtcsetpgrp(ttyfd, rootpid);
7255 * This is truly gross.
7256 * If we're doing job control, then we did a TIOCSPGRP which
7257 * caused us (the shell) to no longer be in the controlling
7258 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7259 * intuit from the subprocess exit status whether a SIGINT
7260 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7265 if (jp->state == JOBDONE)
7273 * Do a wait system call. If job control is compiled in, we accept
7274 * stopped processes. If block is zero, we return a value of zero
7275 * rather than blocking.
7277 * System V doesn't have a non-blocking wait system call. It does
7278 * have a SIGCLD signal that is sent to a process when one of it's
7279 * children dies. The obvious way to use SIGCLD would be to install
7280 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7281 * was received, and have waitproc bump another counter when it got
7282 * the status of a process. Waitproc would then know that a wait
7283 * system call would not block if the two counters were different.
7284 * This approach doesn't work because if a process has children that
7285 * have not been waited for, System V will send it a SIGCLD when it
7286 * installs a signal handler for SIGCLD. What this means is that when
7287 * a child exits, the shell will be sent SIGCLD signals continuously
7288 * until is runs out of stack space, unless it does a wait call before
7289 * restoring the signal handler. The code below takes advantage of
7290 * this (mis)feature by installing a signal handler for SIGCLD and
7291 * then checking to see whether it was called. If there are any
7292 * children to be waited for, it will be.
7294 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7295 * waits at all. In this case, the user will not be informed when
7296 * a background process until the next time she runs a real program
7297 * (as opposed to running a builtin command or just typing return),
7298 * and the jobs command may give out of date information.
7302 waitproc(int block, int *status)
7312 return wait3(status, flags, (struct rusage *)NULL);
7316 * Wait for a process to terminate.
7320 dowait(int block, struct job *job)
7325 struct job *thisjob;
7328 TRACE(("dowait(%d) called\n", block));
7329 pid = waitproc(block, &status);
7330 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7335 for (jp = curjob; jp; jp = jp->prev_job) {
7336 struct procstat *sp;
7337 struct procstat *spend;
7338 if (jp->state == JOBDONE)
7341 spend = jp->ps + jp->nprocs;
7344 if (sp->pid == pid) {
7345 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7346 sp->status = status;
7349 if (sp->status == -1)
7352 if (state == JOBRUNNING)
7354 if (WIFSTOPPED(sp->status)) {
7355 jp->stopstatus = sp->status;
7359 } while (++sp < spend);
7364 if (!WIFSTOPPED(status))
7371 if (state != JOBRUNNING) {
7372 thisjob->changed = 1;
7374 if (thisjob->state != state) {
7375 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7376 thisjob->state = state;
7378 if (state == JOBSTOPPED) {
7379 set_curjob(thisjob, CUR_STOPPED);
7388 if (thisjob && thisjob == job) {
7392 len = sprint_status(s, status, 1);
7404 * return 1 if there are stopped jobs, otherwise 0
7417 if (jp && jp->state == JOBSTOPPED) {
7418 out2str("You have stopped jobs.\n");
7428 * Return a string identifying a command (to be printed by the
7433 static char *cmdnextc;
7436 commandtext(union node *n)
7440 STARTSTACKSTR(cmdnextc);
7442 name = stackblock();
7443 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7444 name, cmdnextc, cmdnextc));
7445 return savestr(name);
7449 cmdtxt(union node *n)
7452 struct nodelist *lp;
7464 lp = n->npipe.cmdlist;
7482 cmdtxt(n->nbinary.ch1);
7498 cmdtxt(n->nif.test);
7501 if (n->nif.elsepart) {
7504 n = n->nif.elsepart;
7520 cmdtxt(n->nbinary.ch1);
7530 cmdputs(n->nfor.var);
7532 cmdlist(n->nfor.args, 1);
7537 cmdputs(n->narg.text);
7541 cmdlist(n->ncmd.args, 1);
7542 cmdlist(n->ncmd.redirect, 0);
7555 cmdputs(n->ncase.expr->narg.text);
7557 for (np = n->ncase.cases; np; np = np->nclist.next) {
7558 cmdtxt(np->nclist.pattern);
7560 cmdtxt(np->nclist.body);
7586 s[0] = n->nfile.fd + '0';
7590 if (n->type == NTOFD || n->type == NFROMFD) {
7591 s[0] = n->ndup.dupfd + '0';
7602 cmdlist(union node *np, int sep)
7604 for (; np; np = np->narg.next) {
7608 if (sep && np->narg.next)
7614 cmdputs(const char *s)
7616 const char *p, *str;
7617 char c, cc[2] = " ";
7621 static const char *const vstype[16] = {
7622 nullstr, "}", "-", "+", "?", "=",
7623 "%", "%%", "#", "##", nullstr
7626 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7628 while ((c = *p++) != 0) {
7636 if ((subtype & VSTYPE) == VSLENGTH)
7640 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7658 case CTLBACKQ+CTLQUOTE:
7661 #ifdef CONFIG_ASH_MATH_SUPPORT
7676 str = vstype[subtype & VSTYPE];
7677 if (subtype & VSNUL)
7688 /* These can only happen inside quotes */
7700 while ((c = *str++)) {
7705 USTPUTC('"', nextc);
7713 showpipe(struct job *jp, FILE *out)
7715 struct procstat *sp;
7716 struct procstat *spend;
7718 spend = jp->ps + jp->nprocs;
7719 for (sp = jp->ps + 1; sp < spend; sp++)
7720 fprintf(out, " | %s", sp->cmd);
7721 outcslow('\n', out);
7726 xtcsetpgrp(int fd, pid_t pgrp)
7728 if (tcsetpgrp(fd, pgrp))
7729 error("Cannot set tty process group (%m)");
7734 getstatus(struct job *job) {
7738 status = job->ps[job->nprocs - 1].status;
7739 retval = WEXITSTATUS(status);
7740 if (!WIFEXITED(status)) {
7742 retval = WSTOPSIG(status);
7743 if (!WIFSTOPPED(status))
7746 /* XXX: limits number of signals */
7747 retval = WTERMSIG(status);
7749 if (retval == SIGINT)
7755 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7756 jobno(job), job->nprocs, status, retval));
7760 #ifdef CONFIG_ASH_MAIL
7761 /* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7764 * Routines to check for mail. (Perhaps make part of main.c?)
7767 #define MAXMBOXES 10
7769 /* times of mailboxes */
7770 static time_t mailtime[MAXMBOXES];
7771 /* Set if MAIL or MAILPATH is changed. */
7772 static int mail_var_path_changed;
7777 * Print appropriate message(s) if mail has arrived.
7778 * If mail_var_path_changed is set,
7779 * then the value of MAIL has mail_var_path_changed,
7780 * so we just update the values.
7790 struct stackmark smark;
7793 setstackmark(&smark);
7794 mpath = mpathset() ? mpathval() : mailval();
7795 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7796 p = padvance(&mpath, nullstr);
7801 for (q = p ; *q ; q++);
7806 q[-1] = '\0'; /* delete trailing '/' */
7807 if (stat(p, &statb) < 0) {
7811 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7814 pathopt ? pathopt : "you have mail"
7817 *mtp = statb.st_mtime;
7819 mail_var_path_changed = 0;
7820 popstackmark(&smark);
7825 changemail(const char *val)
7827 mail_var_path_changed++;
7830 #endif /* CONFIG_ASH_MAIL */
7832 /* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7836 static short profile_buf[16384];
7840 static int isloginsh;
7842 static void read_profile(const char *);
7845 * Main routine. We initialize things, parse the arguments, execute
7846 * profiles if we're a login shell, and then call cmdloop to execute
7847 * commands. The setjmp call sets up the location to jump to when an
7848 * exception occurs. When an exception occurs the variable "state"
7849 * is used to figure out how far we had gotten.
7853 ash_main(int argc, char **argv)
7857 struct jmploc jmploc;
7858 struct stackmark smark;
7861 dash_errno = __errno_location();
7865 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7868 if (setjmp(jmploc.loc)) {
7875 switch (exception) {
7885 status = exitstatus;
7888 exitstatus = status;
7890 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7894 outcslow('\n', stderr);
7896 popstackmark(&smark);
7897 FORCEINTON; /* enable interrupts */
7900 else if (state == 2)
7902 else if (state == 3)
7910 trputs("Shell args: "); trargs(argv);
7914 #ifdef CONFIG_ASH_RANDOM_SUPPORT
7915 rseed = rootpid + ((time_t)time((time_t *)0));
7919 setstackmark(&smark);
7920 procargs(argc, argv);
7921 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7923 const char *hp = lookupvar("HISTFILE");
7926 hp = lookupvar("HOME");
7928 char *defhp = concat_path_file(hp, ".ash_history");
7929 setvar("HISTFILE", defhp, 0);
7935 if (argv[0] && argv[0][0] == '-')
7939 read_profile("/etc/profile");
7942 read_profile(".profile");
7948 getuid() == geteuid() && getgid() == getegid() &&
7952 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7953 read_profile(shinit);
7961 if (sflag || minusc == NULL) {
7962 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7964 const char *hp = lookupvar("HISTFILE");
7967 load_history ( hp );
7970 state4: /* XXX ??? - why isn't this before the "if" statement */
7978 extern void _mcleanup(void);
7988 * Read and execute commands. "Top" is nonzero for the top level command
7989 * loop; it turns on prompting if the shell is interactive.
7996 struct stackmark smark;
8000 TRACE(("cmdloop(%d) called\n", top));
8002 setstackmark(&smark);
8007 showjobs(stderr, SHOW_CHANGED);
8012 #ifdef CONFIG_ASH_MAIL
8016 n = parsecmd(inter);
8017 /* showtree(n); DEBUG */
8019 if (!top || numeof >= 50)
8021 if (!stoppedjobs()) {
8024 out2str("\nUse \"exit\" to leave shell.\n");
8027 } else if (n != NULL && nflag == 0) {
8028 job_warning = (job_warning == 2) ? 1 : 0;
8032 popstackmark(&smark);
8042 * Read /etc/profile or .profile. Return on error.
8046 read_profile(const char *name)
8053 if ((fd = open(name, O_RDONLY)) >= 0)
8058 /* -q turns off -x and -v just when executing init files */
8061 xflag = 0, xflag_set = 1;
8063 vflag = 0, vflag_set = 1;
8077 * Read a file containing shell functions.
8081 readcmdfile(char *name)
8086 if ((fd = open(name, O_RDONLY)) >= 0)
8089 error("Can't open %s", name);
8097 * Take commands from a file. To be compatible we should do a path
8098 * search for the file, which is necessary to find sub-commands.
8101 static inline char *
8102 find_dot_file(char *name)
8105 const char *path = pathval();
8108 /* don't try this for absolute or relative paths */
8109 if (strchr(name, '/'))
8112 while ((fullname = padvance(&path, name)) != NULL) {
8113 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8115 * Don't bother freeing here, since it will
8116 * be freed by the caller.
8120 stunalloc(fullname);
8123 /* not found in the PATH */
8124 error(not_found_msg, name);
8128 static int dotcmd(int argc, char **argv)
8131 volatile struct shparam saveparam;
8135 for (sp = cmdenviron; sp; sp = sp->next)
8136 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8138 if (argc >= 2) { /* That's what SVR2 does */
8140 struct stackmark smark;
8142 setstackmark(&smark);
8143 fullname = find_dot_file(argv[1]);
8146 saveparam = shellparam;
8147 shellparam.malloc = 0;
8148 shellparam.nparam = argc - 2;
8149 shellparam.p = argv + 2;
8152 setinputfile(fullname, 1);
8153 commandname = fullname;
8158 freeparam(&shellparam);
8159 shellparam = saveparam;
8162 popstackmark(&smark);
8169 exitcmd(int argc, char **argv)
8174 exitstatus = number(argv[1]);
8179 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8182 * Same for malloc, realloc, but returns an error when out of space.
8186 ckrealloc(pointer p, size_t nbytes)
8188 p = realloc(p, nbytes);
8190 error(bb_msg_memory_exhausted);
8195 ckmalloc(size_t nbytes)
8197 return ckrealloc(NULL, nbytes);
8201 * Make a copy of a string in safe storage.
8205 savestr(const char *s)
8207 char *p = strdup(s);
8209 error(bb_msg_memory_exhausted);
8215 * Parse trees for commands are allocated in lifo order, so we use a stack
8216 * to make this more efficient, and also to avoid all sorts of exception
8217 * handling code to handle interrupts in the middle of a parse.
8219 * The size 504 was chosen because the Ultrix malloc handles that size
8225 stalloc(size_t nbytes)
8230 aligned = SHELL_ALIGN(nbytes);
8231 if (aligned > stacknleft) {
8234 struct stack_block *sp;
8236 blocksize = aligned;
8237 if (blocksize < MINSIZE)
8238 blocksize = MINSIZE;
8239 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8240 if (len < blocksize)
8241 error(bb_msg_memory_exhausted);
8245 stacknxt = sp->space;
8246 stacknleft = blocksize;
8247 sstrend = stacknxt + blocksize;
8252 stacknxt += aligned;
8253 stacknleft -= aligned;
8259 stunalloc(pointer p)
8262 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8263 write(2, "stunalloc\n", 10);
8267 stacknleft += stacknxt - (char *)p;
8273 setstackmark(struct stackmark *mark)
8275 mark->stackp = stackp;
8276 mark->stacknxt = stacknxt;
8277 mark->stacknleft = stacknleft;
8278 mark->marknext = markp;
8284 popstackmark(struct stackmark *mark)
8286 struct stack_block *sp;
8289 markp = mark->marknext;
8290 while (stackp != mark->stackp) {
8295 stacknxt = mark->stacknxt;
8296 stacknleft = mark->stacknleft;
8297 sstrend = mark->stacknxt + mark->stacknleft;
8303 * When the parser reads in a string, it wants to stick the string on the
8304 * stack and only adjust the stack pointer when it knows how big the
8305 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8306 * of space on top of the stack and stackblocklen returns the length of
8307 * this block. Growstackblock will grow this space by at least one byte,
8308 * possibly moving it (like realloc). Grabstackblock actually allocates the
8309 * part of the block that has been used.
8313 growstackblock(void)
8317 newlen = stacknleft * 2;
8318 if (newlen < stacknleft)
8319 error(bb_msg_memory_exhausted);
8323 if (stacknxt == stackp->space && stackp != &stackbase) {
8324 struct stack_block *oldstackp;
8325 struct stackmark *xmark;
8326 struct stack_block *sp;
8327 struct stack_block *prevstackp;
8333 prevstackp = sp->prev;
8334 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8335 sp = ckrealloc((pointer)sp, grosslen);
8336 sp->prev = prevstackp;
8338 stacknxt = sp->space;
8339 stacknleft = newlen;
8340 sstrend = sp->space + newlen;
8343 * Stack marks pointing to the start of the old block
8344 * must be relocated to point to the new block
8347 while (xmark != NULL && xmark->stackp == oldstackp) {
8348 xmark->stackp = stackp;
8349 xmark->stacknxt = stacknxt;
8350 xmark->stacknleft = stacknleft;
8351 xmark = xmark->marknext;
8355 char *oldspace = stacknxt;
8356 int oldlen = stacknleft;
8357 char *p = stalloc(newlen);
8359 /* free the space we just allocated */
8360 stacknxt = memcpy(p, oldspace, oldlen);
8361 stacknleft += newlen;
8366 grabstackblock(size_t len)
8368 len = SHELL_ALIGN(len);
8374 * The following routines are somewhat easier to use than the above.
8375 * The user declares a variable of type STACKSTR, which may be declared
8376 * to be a register. The macro STARTSTACKSTR initializes things. Then
8377 * the user uses the macro STPUTC to add characters to the string. In
8378 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8379 * grown as necessary. When the user is done, she can just leave the
8380 * string there and refer to it using stackblock(). Or she can allocate
8381 * the space for it using grabstackstr(). If it is necessary to allow
8382 * someone else to use the stack temporarily and then continue to grow
8383 * the string, the user should use grabstack to allocate the space, and
8384 * then call ungrabstr(p) to return to the previous mode of operation.
8386 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8387 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8388 * is space for at least one character.
8394 size_t len = stackblocksize();
8395 if (herefd >= 0 && len >= 1024) {
8396 bb_full_write(herefd, stackblock(), len);
8397 return stackblock();
8400 return stackblock() + len;
8404 * Called from CHECKSTRSPACE.
8408 makestrspace(size_t newlen, char *p)
8410 size_t len = p - stacknxt;
8411 size_t size = stackblocksize();
8416 size = stackblocksize();
8418 if (nleft >= newlen)
8422 return stackblock() + len;
8426 stnputs(const char *s, size_t n, char *p)
8428 p = makestrspace(n, p);
8429 p = mempcpy(p, s, n);
8434 stputs(const char *s, char *p)
8436 return stnputs(s, strlen(s), p);
8439 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8444 * number(s) Convert a string of digits to an integer.
8445 * is_number(s) Return true if s is a string of digits.
8449 * prefix -- see if pfx is a prefix of string.
8453 prefix(const char *string, const char *pfx)
8456 if (*pfx++ != *string++)
8459 return (char *) string;
8464 * Convert a string of digits to an integer, printing an error message on
8469 number(const char *s)
8479 * Check for a valid number. This should be elsewhere.
8483 is_number(const char *p)
8488 } while (*++p != '\0');
8494 * Produce a possibly single quoted string suitable as input to the shell.
8495 * The return string is allocated on the stack.
8499 single_quote(const char *s) {
8508 len = strchrnul(s, '\'') - s;
8510 q = p = makestrspace(len + 3, p);
8513 q = mempcpy(q, s, len);
8519 len = strspn(s, "'");
8523 q = p = makestrspace(len + 3, p);
8526 q = mempcpy(q, s, len);
8535 return stackblock();
8539 * Like strdup but works with the ash stack.
8543 sstrdup(const char *p)
8545 size_t len = strlen(p) + 1;
8546 return memcpy(stalloc(len), p, len);
8551 calcsize(union node *n)
8555 funcblocksize += nodesize[n->type];
8558 calcsize(n->ncmd.redirect);
8559 calcsize(n->ncmd.args);
8560 calcsize(n->ncmd.assign);
8563 sizenodelist(n->npipe.cmdlist);
8568 calcsize(n->nredir.redirect);
8569 calcsize(n->nredir.n);
8576 calcsize(n->nbinary.ch2);
8577 calcsize(n->nbinary.ch1);
8580 calcsize(n->nif.elsepart);
8581 calcsize(n->nif.ifpart);
8582 calcsize(n->nif.test);
8585 funcstringsize += strlen(n->nfor.var) + 1;
8586 calcsize(n->nfor.body);
8587 calcsize(n->nfor.args);
8590 calcsize(n->ncase.cases);
8591 calcsize(n->ncase.expr);
8594 calcsize(n->nclist.body);
8595 calcsize(n->nclist.pattern);
8596 calcsize(n->nclist.next);
8600 sizenodelist(n->narg.backquote);
8601 funcstringsize += strlen(n->narg.text) + 1;
8602 calcsize(n->narg.next);
8609 calcsize(n->nfile.fname);
8610 calcsize(n->nfile.next);
8614 calcsize(n->ndup.vname);
8615 calcsize(n->ndup.next);
8619 calcsize(n->nhere.doc);
8620 calcsize(n->nhere.next);
8623 calcsize(n->nnot.com);
8630 sizenodelist(struct nodelist *lp)
8633 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8641 copynode(union node *n)
8648 funcblock = (char *) funcblock + nodesize[n->type];
8651 new->ncmd.redirect = copynode(n->ncmd.redirect);
8652 new->ncmd.args = copynode(n->ncmd.args);
8653 new->ncmd.assign = copynode(n->ncmd.assign);
8656 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8657 new->npipe.backgnd = n->npipe.backgnd;
8662 new->nredir.redirect = copynode(n->nredir.redirect);
8663 new->nredir.n = copynode(n->nredir.n);
8670 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8671 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8674 new->nif.elsepart = copynode(n->nif.elsepart);
8675 new->nif.ifpart = copynode(n->nif.ifpart);
8676 new->nif.test = copynode(n->nif.test);
8679 new->nfor.var = nodesavestr(n->nfor.var);
8680 new->nfor.body = copynode(n->nfor.body);
8681 new->nfor.args = copynode(n->nfor.args);
8684 new->ncase.cases = copynode(n->ncase.cases);
8685 new->ncase.expr = copynode(n->ncase.expr);
8688 new->nclist.body = copynode(n->nclist.body);
8689 new->nclist.pattern = copynode(n->nclist.pattern);
8690 new->nclist.next = copynode(n->nclist.next);
8694 new->narg.backquote = copynodelist(n->narg.backquote);
8695 new->narg.text = nodesavestr(n->narg.text);
8696 new->narg.next = copynode(n->narg.next);
8703 new->nfile.fname = copynode(n->nfile.fname);
8704 new->nfile.fd = n->nfile.fd;
8705 new->nfile.next = copynode(n->nfile.next);
8709 new->ndup.vname = copynode(n->ndup.vname);
8710 new->ndup.dupfd = n->ndup.dupfd;
8711 new->ndup.fd = n->ndup.fd;
8712 new->ndup.next = copynode(n->ndup.next);
8716 new->nhere.doc = copynode(n->nhere.doc);
8717 new->nhere.fd = n->nhere.fd;
8718 new->nhere.next = copynode(n->nhere.next);
8721 new->nnot.com = copynode(n->nnot.com);
8724 new->type = n->type;
8729 static struct nodelist *
8730 copynodelist(struct nodelist *lp)
8732 struct nodelist *start;
8733 struct nodelist **lpp;
8738 funcblock = (char *) funcblock +
8739 SHELL_ALIGN(sizeof(struct nodelist));
8740 (*lpp)->n = copynode(lp->n);
8742 lpp = &(*lpp)->next;
8750 nodesavestr(char *s)
8752 char *rtn = funcstring;
8754 funcstring = stpcpy(funcstring, s) + 1;
8760 * Free a parse tree.
8764 freefunc(struct funcnode *f)
8766 if (f && --f->count < 0)
8771 static void options(int);
8772 static void setoption(int, int);
8776 * Process the shell command line arguments.
8780 procargs(int argc, char **argv)
8783 const char *xminusc;
8790 for (i = 0; i < NOPTS; i++)
8796 if (*xargv == NULL) {
8798 error("-c requires an argument");
8801 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8805 for (i = 0; i < NOPTS; i++)
8806 if (optlist[i] == 2)
8811 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8816 } else if (!sflag) {
8817 setinputfile(*xargv, 0);
8823 shellparam.p = xargv;
8824 #ifdef CONFIG_ASH_GETOPTS
8825 shellparam.optind = 1;
8826 shellparam.optoff = -1;
8828 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8830 shellparam.nparam++;
8843 setinteractive(iflag);
8848 minus_o(char *name, int val)
8853 out1str("Current option settings\n");
8854 for (i = 0; i < NOPTS; i++)
8855 out1fmt("%-16s%s\n", optnames(i),
8856 optlist[i] ? "on" : "off");
8858 for (i = 0; i < NOPTS; i++)
8859 if (equal(name, optnames(i))) {
8863 error("Illegal option -o %s", name);
8868 * Process shell options. The global variable argptr contains a pointer
8869 * to the argument list; we advance it past the options.
8873 options(int cmdline)
8881 while ((p = *argptr) != NULL) {
8883 if ((c = *p++) == '-') {
8885 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8887 /* "-" means turn off -x and -v */
8890 /* "--" means reset params */
8891 else if (*argptr == NULL)
8894 break; /* "-" or "--" terminates options */
8896 } else if (c == '+') {
8902 while ((c = *p++) != '\0') {
8903 if (c == 'c' && cmdline) {
8904 minusc = p; /* command is after shell args*/
8905 } else if (c == 'o') {
8906 minus_o(*argptr, val);
8909 } else if (cmdline && (c == '-')) { // long options
8910 if (strcmp(p, "login") == 0)
8922 setoption(int flag, int val)
8926 for (i = 0; i < NOPTS; i++)
8927 if (optletters(i) == flag) {
8931 error("Illegal option -%c", flag);
8938 * Set the shell parameters.
8942 setparam(char **argv)
8948 for (nparam = 0 ; argv[nparam] ; nparam++);
8949 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8951 *ap++ = savestr(*argv++);
8954 freeparam(&shellparam);
8955 shellparam.malloc = 1;
8956 shellparam.nparam = nparam;
8957 shellparam.p = newparam;
8958 #ifdef CONFIG_ASH_GETOPTS
8959 shellparam.optind = 1;
8960 shellparam.optoff = -1;
8966 * Free the list of positional parameters.
8970 freeparam(volatile struct shparam *param)
8974 if (param->malloc) {
8975 for (ap = param->p ; *ap ; ap++)
8984 * The shift builtin command.
8988 shiftcmd(int argc, char **argv)
8995 n = number(argv[1]);
8996 if (n > shellparam.nparam)
8997 error("can't shift that many");
8999 shellparam.nparam -= n;
9000 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9001 if (shellparam.malloc)
9005 while ((*ap2++ = *ap1++) != NULL);
9006 #ifdef CONFIG_ASH_GETOPTS
9007 shellparam.optind = 1;
9008 shellparam.optoff = -1;
9017 * The set command builtin.
9021 setcmd(int argc, char **argv)
9024 return showvars(nullstr, 0, VUNSET);
9028 if (*argptr != NULL) {
9036 #ifdef CONFIG_ASH_GETOPTS
9041 shellparam.optind = number(value);
9042 shellparam.optoff = -1;
9046 #ifdef CONFIG_LOCALE_SUPPORT
9047 static void change_lc_all(const char *value)
9049 if (value != 0 && *value != 0)
9050 setlocale(LC_ALL, value);
9053 static void change_lc_ctype(const char *value)
9055 if (value != 0 && *value != 0)
9056 setlocale(LC_CTYPE, value);
9061 #ifdef CONFIG_ASH_RANDOM_SUPPORT
9062 /* Roughly copied from bash.. */
9063 static void change_random(const char *value)
9066 /* "get", generate */
9069 rseed = rseed * 1103515245 + 12345;
9070 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9071 /* set without recursion */
9072 setvar(vrandom.text, buf, VNOFUNC);
9073 vrandom.flags &= ~VNOFUNC;
9076 rseed = strtoul(value, (char **)NULL, 10);
9082 #ifdef CONFIG_ASH_GETOPTS
9084 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9093 if(*param_optind < 1)
9095 optnext = optfirst + *param_optind - 1;
9097 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9100 p = optnext[-1] + *optoff;
9101 if (p == NULL || *p == '\0') {
9102 /* Current word is done, advance */
9104 if (p == NULL || *p != '-' || *++p == '\0') {
9111 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9116 for (q = optstr; *q != c; ) {
9118 if (optstr[0] == ':') {
9121 err |= setvarsafe("OPTARG", s, 0);
9123 fprintf(stderr, "Illegal option -%c\n", c);
9124 (void) unsetvar("OPTARG");
9134 if (*p == '\0' && (p = *optnext) == NULL) {
9135 if (optstr[0] == ':') {
9138 err |= setvarsafe("OPTARG", s, 0);
9141 fprintf(stderr, "No arg for -%c option\n", c);
9142 (void) unsetvar("OPTARG");
9150 err |= setvarsafe("OPTARG", p, 0);
9153 err |= setvarsafe("OPTARG", nullstr, 0);
9156 *optoff = p ? p - *(optnext - 1) : -1;
9157 *param_optind = optnext - optfirst + 1;
9158 fmtstr(s, sizeof(s), "%d", *param_optind);
9159 err |= setvarsafe("OPTIND", s, VNOFUNC);
9162 err |= setvarsafe(optvar, s, 0);
9173 * The getopts builtin. Shellparam.optnext points to the next argument
9174 * to be processed. Shellparam.optptr points to the next character to
9175 * be processed in the current argument. If shellparam.optnext is NULL,
9176 * then it's the first time getopts has been called.
9180 getoptscmd(int argc, char **argv)
9185 error("Usage: getopts optstring var [arg]");
9186 else if (argc == 3) {
9187 optbase = shellparam.p;
9188 if (shellparam.optind > shellparam.nparam + 1) {
9189 shellparam.optind = 1;
9190 shellparam.optoff = -1;
9195 if (shellparam.optind > argc - 2) {
9196 shellparam.optind = 1;
9197 shellparam.optoff = -1;
9201 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9202 &shellparam.optoff);
9204 #endif /* CONFIG_ASH_GETOPTS */
9207 * XXX - should get rid of. have all builtins use getopt(3). the
9208 * library getopt must have the BSD extension static variable "optreset"
9209 * otherwise it can't be used within the shell safely.
9211 * Standard option processing (a la getopt) for builtin routines. The
9212 * only argument that is passed to nextopt is the option string; the
9213 * other arguments are unnecessary. It return the character, or '\0' on
9218 nextopt(const char *optstring)
9224 if ((p = optptr) == NULL || *p == '\0') {
9226 if (p == NULL || *p != '-' || *++p == '\0')
9229 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9233 for (q = optstring ; *q != c ; ) {
9235 error("Illegal option -%c", c);
9240 if (*p == '\0' && (p = *argptr++) == NULL)
9241 error("No arg for -%c option", c);
9250 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9253 outstr(const char *p, FILE *file)
9278 outcslow(int c, FILE *dest)
9288 out1fmt(const char *fmt, ...)
9295 r = vprintf(fmt, ap);
9303 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9310 ret = vsnprintf(outbuf, length, fmt, ap);
9318 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9322 * Shell command parser.
9325 #define EOFMARKLEN 79
9329 struct heredoc *next; /* next here document in list */
9330 union node *here; /* redirection node */
9331 char *eofmark; /* string indicating end of input */
9332 int striptabs; /* if set, strip leading tabs */
9337 static struct heredoc *heredoclist; /* list of here documents to read */
9340 static union node *list(int);
9341 static union node *andor(void);
9342 static union node *pipeline(void);
9343 static union node *command(void);
9344 static union node *simplecmd(void);
9345 static union node *makename(void);
9346 static void parsefname(void);
9347 static void parseheredoc(void);
9348 static char peektoken(void);
9349 static int readtoken(void);
9350 static int xxreadtoken(void);
9351 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9352 static int noexpand(char *);
9353 static void synexpect(int) __attribute__((__noreturn__));
9354 static void synerror(const char *) __attribute__((__noreturn__));
9355 static void setprompt(int);
9360 isassignment(const char *p)
9362 const char *q = endofname(p);
9370 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9371 * valid parse tree indicating a blank line.)
9375 parsecmd(int interact)
9380 doprompt = interact;
9382 setprompt(doprompt);
9397 union node *n1, *n2, *n3;
9400 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9401 if (nlflag == 2 && peektoken())
9407 if (tok == TBACKGND) {
9408 if (n2->type == NPIPE) {
9409 n2->npipe.backgnd = 1;
9411 if (n2->type != NREDIR) {
9412 n3 = stalloc(sizeof(struct nredir));
9414 n3->nredir.redirect = NULL;
9417 n2->type = NBACKGND;
9424 n3 = (union node *)stalloc(sizeof (struct nbinary));
9426 n3->nbinary.ch1 = n1;
9427 n3->nbinary.ch2 = n2;
9443 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9451 pungetc(); /* push back EOF on input */
9467 union node *n1, *n2, *n3;
9472 if ((t = readtoken()) == TAND) {
9474 } else if (t == TOR) {
9480 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9482 n3 = (union node *)stalloc(sizeof (struct nbinary));
9484 n3->nbinary.ch1 = n1;
9485 n3->nbinary.ch2 = n2;
9495 union node *n1, *n2, *pipenode;
9496 struct nodelist *lp, *prev;
9500 TRACE(("pipeline: entered\n"));
9501 if (readtoken() == TNOT) {
9503 checkkwd = CHKKWD | CHKALIAS;
9507 if (readtoken() == TPIPE) {
9508 pipenode = (union node *)stalloc(sizeof (struct npipe));
9509 pipenode->type = NPIPE;
9510 pipenode->npipe.backgnd = 0;
9511 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9512 pipenode->npipe.cmdlist = lp;
9516 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9517 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9520 } while (readtoken() == TPIPE);
9526 n2 = (union node *)stalloc(sizeof (struct nnot));
9539 union node *n1, *n2;
9540 union node *ap, **app;
9541 union node *cp, **cpp;
9542 union node *redir, **rpp;
9549 switch (readtoken()) {
9554 n1 = (union node *)stalloc(sizeof (struct nif));
9556 n1->nif.test = list(0);
9557 if (readtoken() != TTHEN)
9559 n1->nif.ifpart = list(0);
9561 while (readtoken() == TELIF) {
9562 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9563 n2 = n2->nif.elsepart;
9565 n2->nif.test = list(0);
9566 if (readtoken() != TTHEN)
9568 n2->nif.ifpart = list(0);
9570 if (lasttoken == TELSE)
9571 n2->nif.elsepart = list(0);
9573 n2->nif.elsepart = NULL;
9581 n1 = (union node *)stalloc(sizeof (struct nbinary));
9582 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9583 n1->nbinary.ch1 = list(0);
9584 if ((got=readtoken()) != TDO) {
9585 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9588 n1->nbinary.ch2 = list(0);
9593 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9594 synerror("Bad for loop variable");
9595 n1 = (union node *)stalloc(sizeof (struct nfor));
9597 n1->nfor.var = wordtext;
9598 checkkwd = CHKKWD | CHKALIAS;
9599 if (readtoken() == TIN) {
9601 while (readtoken() == TWORD) {
9602 n2 = (union node *)stalloc(sizeof (struct narg));
9604 n2->narg.text = wordtext;
9605 n2->narg.backquote = backquotelist;
9607 app = &n2->narg.next;
9611 if (lasttoken != TNL && lasttoken != TSEMI)
9614 n2 = (union node *)stalloc(sizeof (struct narg));
9616 n2->narg.text = (char *)dolatstr;
9617 n2->narg.backquote = NULL;
9618 n2->narg.next = NULL;
9621 * Newline or semicolon here is optional (but note
9622 * that the original Bourne shell only allowed NL).
9624 if (lasttoken != TNL && lasttoken != TSEMI)
9627 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9628 if (readtoken() != TDO)
9630 n1->nfor.body = list(0);
9634 n1 = (union node *)stalloc(sizeof (struct ncase));
9636 if (readtoken() != TWORD)
9638 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9640 n2->narg.text = wordtext;
9641 n2->narg.backquote = backquotelist;
9642 n2->narg.next = NULL;
9644 checkkwd = CHKKWD | CHKALIAS;
9645 } while (readtoken() == TNL);
9646 if (lasttoken != TIN)
9648 cpp = &n1->ncase.cases;
9650 checkkwd = CHKNL | CHKKWD;
9653 if (lasttoken == TLP)
9655 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9657 app = &cp->nclist.pattern;
9659 *app = ap = (union node *)stalloc(sizeof (struct narg));
9661 ap->narg.text = wordtext;
9662 ap->narg.backquote = backquotelist;
9663 if (readtoken() != TPIPE)
9665 app = &ap->narg.next;
9668 ap->narg.next = NULL;
9669 if (lasttoken != TRP)
9671 cp->nclist.body = list(2);
9673 cpp = &cp->nclist.next;
9675 checkkwd = CHKNL | CHKKWD;
9676 if ((t = readtoken()) != TESAC) {
9678 synexpect(TENDCASE);
9686 n1 = (union node *)stalloc(sizeof (struct nredir));
9687 n1->type = NSUBSHELL;
9688 n1->nredir.n = list(0);
9689 n1->nredir.redirect = NULL;
9702 if (readtoken() != t)
9706 /* Now check for redirection which may follow command */
9707 checkkwd = CHKKWD | CHKALIAS;
9709 while (readtoken() == TREDIR) {
9710 *rpp = n2 = redirnode;
9711 rpp = &n2->nfile.next;
9717 if (n1->type != NSUBSHELL) {
9718 n2 = (union node *)stalloc(sizeof (struct nredir));
9723 n1->nredir.redirect = redir;
9732 union node *args, **app;
9733 union node *n = NULL;
9734 union node *vars, **vpp;
9735 union node **rpp, *redir;
9745 savecheckkwd = CHKALIAS;
9747 checkkwd = savecheckkwd;
9748 switch (readtoken()) {
9750 n = (union node *)stalloc(sizeof (struct narg));
9752 n->narg.text = wordtext;
9753 n->narg.backquote = backquotelist;
9754 if (savecheckkwd && isassignment(wordtext)) {
9756 vpp = &n->narg.next;
9759 app = &n->narg.next;
9764 *rpp = n = redirnode;
9765 rpp = &n->nfile.next;
9766 parsefname(); /* read name of redirection file */
9770 args && app == &args->narg.next &&
9773 struct builtincmd *bcmd;
9776 /* We have a function */
9777 if (readtoken() != TRP)
9779 name = n->narg.text;
9781 !goodname(name) || (
9782 (bcmd = find_builtin(name)) &&
9783 IS_BUILTIN_SPECIAL(bcmd)
9786 synerror("Bad function name");
9788 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9789 n->narg.next = command();
9802 n = (union node *)stalloc(sizeof (struct ncmd));
9804 n->ncmd.args = args;
9805 n->ncmd.assign = vars;
9806 n->ncmd.redirect = redir;
9815 n = (union node *)stalloc(sizeof (struct narg));
9817 n->narg.next = NULL;
9818 n->narg.text = wordtext;
9819 n->narg.backquote = backquotelist;
9823 void fixredir(union node *n, const char *text, int err)
9825 TRACE(("Fix redir %s %d\n", text, err));
9827 n->ndup.vname = NULL;
9829 if (is_digit(text[0]) && text[1] == '\0')
9830 n->ndup.dupfd = digit_val(text[0]);
9831 else if (text[0] == '-' && text[1] == '\0')
9836 synerror("Bad fd number");
9838 n->ndup.vname = makename();
9846 union node *n = redirnode;
9848 if (readtoken() != TWORD)
9850 if (n->type == NHERE) {
9851 struct heredoc *here = heredoc;
9857 TRACE(("Here document %d\n", n->type));
9858 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9859 synerror("Illegal eof marker for << redirection");
9860 rmescapes(wordtext);
9861 here->eofmark = wordtext;
9863 if (heredoclist == NULL)
9866 for (p = heredoclist ; p->next ; p = p->next);
9869 } else if (n->type == NTOFD || n->type == NFROMFD) {
9870 fixredir(n, wordtext, 0);
9872 n->nfile.fname = makename();
9878 * Input any here documents.
9884 struct heredoc *here;
9895 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9896 here->eofmark, here->striptabs);
9897 n = (union node *)stalloc(sizeof (struct narg));
9898 n->narg.type = NARG;
9899 n->narg.next = NULL;
9900 n->narg.text = wordtext;
9901 n->narg.backquote = backquotelist;
9902 here->here->nhere.doc = n;
9907 static char peektoken(void)
9913 return tokname_array[t][0];
9921 int alreadyseen = tokpushback;
9924 #ifdef CONFIG_ASH_ALIAS
9933 if (checkkwd & CHKNL) {
9940 if (t != TWORD || quoteflag) {
9945 * check for keywords
9947 if (checkkwd & CHKKWD) {
9948 const char *const *pp;
9950 if ((pp = findkwd(wordtext))) {
9951 lasttoken = t = pp - tokname_array;
9952 TRACE(("keyword %s recognized\n", tokname(t)));
9957 if (checkkwd & CHKALIAS) {
9958 #ifdef CONFIG_ASH_ALIAS
9960 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9962 pushstring(ap->val, ap);
9972 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9974 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9981 * Read the next input token.
9982 * If the token is a word, we set backquotelist to the list of cmds in
9983 * backquotes. We set quoteflag to true if any part of the word was
9985 * If the token is TREDIR, then we set redirnode to a structure containing
9987 * In all cases, the variable startlinno is set to the number of the line
9988 * on which the token starts.
9990 * [Change comment: here documents and internal procedures]
9991 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9992 * word parsing code into a separate routine. In this case, readtoken
9993 * doesn't need to have any internal procedures, but parseword does.
9994 * We could also make parseoperator in essence the main routine, and
9995 * have parseword (readtoken1?) handle both words and redirection.]
9998 #define NEW_xxreadtoken
9999 #ifdef NEW_xxreadtoken
10001 /* singles must be first! */
10002 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10004 static const char xxreadtoken_tokens[] = {
10005 TNL, TLP, TRP, /* only single occurrence allowed */
10006 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10007 TEOF, /* corresponds to trailing nul */
10008 TAND, TOR, TENDCASE, /* if double occurrence */
10011 #define xxreadtoken_doubles \
10012 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10013 #define xxreadtoken_singles \
10014 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10016 static int xxreadtoken()
10028 startlinno = plinno;
10029 for (;;) { /* until token or start of word found */
10032 if ((c != ' ') && (c != '\t')
10033 #ifdef CONFIG_ASH_ALIAS
10038 while ((c = pgetc()) != '\n' && c != PEOF);
10040 } else if (c == '\\') {
10041 if (pgetc() != '\n') {
10045 startlinno = ++plinno;
10050 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10055 needprompt = doprompt;
10058 p = strchr(xxreadtoken_chars, c);
10061 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10064 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10065 if (pgetc() == *p) { /* double occurrence? */
10066 p += xxreadtoken_doubles + 1;
10073 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10081 #define RETURN(token) return lasttoken = token
10096 startlinno = plinno;
10097 for (;;) { /* until token or start of word found */
10100 case ' ': case '\t':
10101 #ifdef CONFIG_ASH_ALIAS
10106 while ((c = pgetc()) != '\n' && c != PEOF);
10110 if (pgetc() == '\n') {
10111 startlinno = ++plinno;
10120 needprompt = doprompt;
10125 if (pgetc() == '&')
10130 if (pgetc() == '|')
10135 if (pgetc() == ';')
10148 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10151 #endif /* NEW_xxreadtoken */
10155 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10156 * is not NULL, read a here document. In the latter case, eofmark is the
10157 * word which marks the end of the document and striptabs is true if
10158 * leading tabs should be stripped from the document. The argument firstc
10159 * is the first character of the input token or document.
10161 * Because C does not have internal subroutines, I have simulated them
10162 * using goto's to implement the subroutine linkage. The following macros
10163 * will run code that appears at the end of readtoken1.
10166 #define CHECKEND() {goto checkend; checkend_return:;}
10167 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10168 #define PARSESUB() {goto parsesub; parsesub_return:;}
10169 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10170 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10171 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10174 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10179 char line[EOFMARKLEN + 1];
10180 struct nodelist *bqlist;
10183 int varnest; /* levels of variables expansion */
10184 int arinest; /* levels of arithmetic expansion */
10185 int parenlevel; /* levels of parens in arithmetic */
10186 int dqvarnest; /* levels of variables expansion within double quotes */
10188 int prevsyntax; /* syntax before arithmetic */
10190 /* Avoid longjmp clobbering */
10196 (void) &parenlevel;
10199 (void) &prevsyntax;
10203 startlinno = plinno;
10205 if (syntax == DQSYNTAX)
10214 STARTSTACKSTR(out);
10215 loop: { /* for each line, until end of word */
10216 CHECKEND(); /* set c to PEOF if at end of here document */
10217 for (;;) { /* until end of line or end of word */
10218 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10219 switch(SIT(c, syntax)) {
10220 case CNL: /* '\n' */
10221 if (syntax == BASESYNTAX)
10222 goto endword; /* exit outer loop */
10228 goto loop; /* continue outer loop */
10233 if (eofmark == NULL || dblquote)
10234 USTPUTC(CTLESC, out);
10237 case CBACK: /* backslash */
10240 USTPUTC(CTLESC, out);
10241 USTPUTC('\\', out);
10243 } else if (c == '\n') {
10249 c != '\\' && c != '`' &&
10255 USTPUTC(CTLESC, out);
10256 USTPUTC('\\', out);
10258 if (SIT(c, SQSYNTAX) == CCTL)
10259 USTPUTC(CTLESC, out);
10267 if (eofmark == NULL) {
10268 USTPUTC(CTLQUOTEMARK, out);
10276 if (eofmark != NULL && arinest == 0 &&
10280 if (dqvarnest == 0) {
10281 syntax = BASESYNTAX;
10288 case CVAR: /* '$' */
10289 PARSESUB(); /* parse substitution */
10291 case CENDVAR: /* '}' */
10294 if (dqvarnest > 0) {
10297 USTPUTC(CTLENDVAR, out);
10302 #ifdef CONFIG_ASH_MATH_SUPPORT
10303 case CLP: /* '(' in arithmetic */
10307 case CRP: /* ')' in arithmetic */
10308 if (parenlevel > 0) {
10312 if (pgetc() == ')') {
10313 if (--arinest == 0) {
10314 USTPUTC(CTLENDARI, out);
10315 syntax = prevsyntax;
10316 if (syntax == DQSYNTAX)
10324 * unbalanced parens
10325 * (don't 2nd guess - no error)
10333 case CBQUOTE: /* '`' */
10337 goto endword; /* exit outer loop */
10342 goto endword; /* exit outer loop */
10343 #ifdef CONFIG_ASH_ALIAS
10353 #ifdef CONFIG_ASH_MATH_SUPPORT
10354 if (syntax == ARISYNTAX)
10355 synerror("Missing '))'");
10357 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10358 synerror("Unterminated quoted string");
10359 if (varnest != 0) {
10360 startlinno = plinno;
10362 synerror("Missing '}'");
10364 USTPUTC('\0', out);
10365 len = out - (char *)stackblock();
10366 out = stackblock();
10367 if (eofmark == NULL) {
10368 if ((c == '>' || c == '<')
10371 && (*out == '\0' || is_digit(*out))) {
10373 return lasttoken = TREDIR;
10378 quoteflag = quotef;
10379 backquotelist = bqlist;
10380 grabstackblock(len);
10382 return lasttoken = TWORD;
10383 /* end of readtoken routine */
10388 * Check to see whether we are at the end of the here document. When this
10389 * is called, c is set to the first character of the next input line. If
10390 * we are at the end of the here document, this routine sets the c to PEOF.
10395 #ifdef CONFIG_ASH_ALIAS
10401 while (c == '\t') {
10405 if (c == *eofmark) {
10406 if (pfgets(line, sizeof line) != NULL) {
10410 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10411 if (*p == '\n' && *q == '\0') {
10414 needprompt = doprompt;
10416 pushstring(line, NULL);
10421 goto checkend_return;
10426 * Parse a redirection operator. The variable "out" points to a string
10427 * specifying the fd to be redirected. The variable "c" contains the
10428 * first character of the redirection operator.
10435 np = (union node *)stalloc(sizeof (struct nfile));
10440 np->type = NAPPEND;
10442 np->type = NCLOBBER;
10449 } else { /* c == '<' */
10451 switch (c = pgetc()) {
10453 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10454 np = (union node *)stalloc(sizeof (struct nhere));
10458 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10459 heredoc->here = np;
10460 if ((c = pgetc()) == '-') {
10461 heredoc->striptabs = 1;
10463 heredoc->striptabs = 0;
10469 np->type = NFROMFD;
10473 np->type = NFROMTO;
10483 np->nfile.fd = digit_val(fd);
10485 goto parseredir_return;
10490 * Parse a substitution. At this point, we have read the dollar sign
10491 * and nothing else.
10499 static const char types[] = "}-+?=";
10503 c <= PEOA_OR_PEOF ||
10504 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10508 } else if (c == '(') { /* $(command) or $((arith)) */
10509 if (pgetc() == '(') {
10510 #ifdef CONFIG_ASH_MATH_SUPPORT
10513 synerror("We unsupport $((arith))");
10520 USTPUTC(CTLVAR, out);
10521 typeloc = out - (char *)stackblock();
10522 USTPUTC(VSNORMAL, out);
10523 subtype = VSNORMAL;
10527 if ((c = pgetc()) == '}')
10530 subtype = VSLENGTH;
10535 if (c > PEOA_OR_PEOF && is_name(c)) {
10539 } while (c > PEOA_OR_PEOF && is_in_name(c));
10540 } else if (is_digit(c)) {
10544 } while (is_digit(c));
10546 else if (is_special(c)) {
10551 badsub: synerror("Bad substitution");
10555 if (subtype == 0) {
10562 p = strchr(types, c);
10565 subtype = p - types + VSNORMAL;
10571 subtype = c == '#' ? VSTRIMLEFT :
10584 if (dblquote || arinest)
10586 *((char *)stackblock() + typeloc) = subtype | flags;
10587 if (subtype != VSNORMAL) {
10589 if (dblquote || arinest) {
10594 goto parsesub_return;
10599 * Called to parse command substitutions. Newstyle is set if the command
10600 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10601 * list of commands (passed by reference), and savelen is the number of
10602 * characters on the top of the stack which must be preserved.
10606 struct nodelist **nlpp;
10609 char *volatile str;
10610 struct jmploc jmploc;
10611 struct jmploc *volatile savehandler;
10615 (void) &saveprompt;
10618 savepbq = parsebackquote;
10619 if (setjmp(jmploc.loc)) {
10622 parsebackquote = 0;
10623 handler = savehandler;
10624 longjmp(handler->loc, 1);
10628 savelen = out - (char *)stackblock();
10630 str = ckmalloc(savelen);
10631 memcpy(str, stackblock(), savelen);
10633 savehandler = handler;
10637 /* We must read until the closing backquote, giving special
10638 treatment to some slashes, and then push the string and
10639 reread it as input, interpreting it normally. */
10646 STARTSTACKSTR(pout);
10652 switch (pc = pgetc()) {
10657 if ((pc = pgetc()) == '\n') {
10662 * If eating a newline, avoid putting
10663 * the newline into the new character
10664 * stream (via the STPUTC after the
10669 if (pc != '\\' && pc != '`' && pc != '$'
10670 && (!dblquote || pc != '"'))
10671 STPUTC('\\', pout);
10672 if (pc > PEOA_OR_PEOF) {
10678 #ifdef CONFIG_ASH_ALIAS
10681 startlinno = plinno;
10682 synerror("EOF in backquote substitution");
10686 needprompt = doprompt;
10695 STPUTC('\0', pout);
10696 psavelen = pout - (char *)stackblock();
10697 if (psavelen > 0) {
10698 pstr = grabstackstr(pout);
10699 setinputstring(pstr);
10704 nlpp = &(*nlpp)->next;
10705 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10706 (*nlpp)->next = NULL;
10707 parsebackquote = oldstyle;
10710 saveprompt = doprompt;
10717 doprompt = saveprompt;
10719 if (readtoken() != TRP)
10726 * Start reading from old file again, ignoring any pushed back
10727 * tokens left from the backquote parsing
10732 while (stackblocksize() <= savelen)
10734 STARTSTACKSTR(out);
10736 memcpy(out, str, savelen);
10737 STADJUST(savelen, out);
10743 parsebackquote = savepbq;
10744 handler = savehandler;
10745 if (arinest || dblquote)
10746 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10748 USTPUTC(CTLBACKQ, out);
10750 goto parsebackq_oldreturn;
10752 goto parsebackq_newreturn;
10755 #ifdef CONFIG_ASH_MATH_SUPPORT
10757 * Parse an arithmetic expansion (indicate start of one and set state)
10761 if (++arinest == 1) {
10762 prevsyntax = syntax;
10763 syntax = ARISYNTAX;
10764 USTPUTC(CTLARI, out);
10771 * we collapse embedded arithmetic expansion to
10772 * parenthesis, which should be equivalent
10776 goto parsearith_return;
10780 } /* end of readtoken */
10785 * Returns true if the text contains nothing to expand (no dollar signs
10790 noexpand(char *text)
10796 while ((c = *p++) != '\0') {
10797 if (c == CTLQUOTEMARK)
10801 else if (SIT(c, BASESYNTAX) == CCTL)
10809 * Return of a legal variable name (a letter or underscore followed by zero or
10810 * more letters, underscores, and digits).
10814 endofname(const char *name)
10822 if (! is_in_name(*p))
10830 * Called when an unexpected token is read during the parse. The argument
10831 * is the token that is expected, or -1 if more than one type of token can
10832 * occur at this point.
10835 static void synexpect(int token)
10840 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10842 sprintf(msg + l, " (expecting %s)", tokname(token));
10848 synerror(const char *msg)
10850 error("Syntax error: %s", msg);
10856 * called by editline -- any expansions to the prompt
10857 * should be added here.
10860 static void setprompt(int whichprompt)
10862 const char *prompt;
10864 switch (whichprompt) {
10878 static const char *const *findkwd(const char *s)
10880 return bsearch(s, tokname_array + KWDOFFSET,
10881 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10882 sizeof(const char *), pstrcmp);
10885 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10888 * Code for dealing with input/output redirection.
10891 #define EMPTY -2 /* marks an unused slot in redirtab */
10893 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10895 # define PIPESIZE PIPE_BUF
10899 * Open a file in noclobber mode.
10900 * The code was copied from bash.
10903 noclobberopen(const char *fname)
10906 struct stat finfo, finfo2;
10909 * If the file exists and is a regular file, return an error
10912 r = stat(fname, &finfo);
10913 if (r == 0 && S_ISREG(finfo.st_mode)) {
10919 * If the file was not present (r != 0), make sure we open it
10920 * exclusively so that if it is created before we open it, our open
10921 * will fail. Make sure that we do not truncate an existing file.
10922 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10923 * file was not a regular file, we leave O_EXCL off.
10926 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10927 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10929 /* If the open failed, return the file descriptor right away. */
10934 * OK, the open succeeded, but the file may have been changed from a
10935 * non-regular file to a regular file between the stat and the open.
10936 * We are assuming that the O_EXCL open handles the case where FILENAME
10937 * did not exist and is symlinked to an existing file between the stat
10942 * If we can open it and fstat the file descriptor, and neither check
10943 * revealed that it was a regular file, and the file has not been
10944 * replaced, return the file descriptor.
10946 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10947 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10950 /* The file has been replaced. badness. */
10957 * Handle here documents. Normally we fork off a process to write the
10958 * data to a pipe. If the document is short, we can stuff the data in
10959 * the pipe without forking.
10963 openhere(union node *redir)
10969 error("Pipe call failed");
10970 if (redir->type == NHERE) {
10971 len = strlen(redir->nhere.doc->narg.text);
10972 if (len <= PIPESIZE) {
10973 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
10977 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10979 signal(SIGINT, SIG_IGN);
10980 signal(SIGQUIT, SIG_IGN);
10981 signal(SIGHUP, SIG_IGN);
10983 signal(SIGTSTP, SIG_IGN);
10985 signal(SIGPIPE, SIG_DFL);
10986 if (redir->type == NHERE)
10987 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
10989 expandhere(redir->nhere.doc, pip[1]);
10998 openredirect(union node *redir)
11003 switch (redir->nfile.type) {
11005 fname = redir->nfile.expfname;
11006 if ((f = open(fname, O_RDONLY)) < 0)
11010 fname = redir->nfile.expfname;
11011 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11015 /* Take care of noclobber mode. */
11017 fname = redir->nfile.expfname;
11018 if ((f = noclobberopen(fname)) < 0)
11024 fname = redir->nfile.expfname;
11025 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11029 fname = redir->nfile.expfname;
11030 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11037 /* Fall through to eliminate warning. */
11044 f = openhere(redir);
11050 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11052 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11056 dupredirect(union node *redir, int f)
11058 int fd = redir->nfile.fd;
11060 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11061 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11062 copyfd(redir->ndup.dupfd, fd);
11075 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11076 * old file descriptors are stashed away so that the redirection can be
11077 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11078 * standard output, and the standard error if it becomes a duplicate of
11079 * stdout, is saved in memory.
11083 redirect(union node *redir, int flags)
11086 struct redirtab *sv;
11097 if (flags & REDIR_PUSH) {
11098 struct redirtab *q;
11099 q = ckmalloc(sizeof (struct redirtab));
11100 q->next = redirlist;
11102 q->nullredirs = nullredirs - 1;
11103 for (i = 0 ; i < 10 ; i++)
11104 q->renamed[i] = EMPTY;
11111 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11112 n->ndup.dupfd == fd)
11113 continue; /* redirect from/to same file descriptor */
11115 newfd = openredirect(n);
11118 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11119 i = fcntl(fd, F_DUPFD, 10);
11126 error("%d: %m", fd);
11136 dupredirect(n, newfd);
11137 } while ((n = n->nfile.next));
11139 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11140 preverrout_fd = sv->renamed[2];
11145 * Undo the effects of the last redirection.
11151 struct redirtab *rp;
11154 if (--nullredirs >= 0)
11158 for (i = 0 ; i < 10 ; i++) {
11159 if (rp->renamed[i] != EMPTY) {
11162 copyfd(rp->renamed[i], i);
11164 close(rp->renamed[i]);
11167 redirlist = rp->next;
11168 nullredirs = rp->nullredirs;
11174 * Undo all redirections. Called on error or interrupt.
11178 * Discard all saved file descriptors.
11182 clearredir(int drop)
11194 * Copy a file descriptor to be >= to. Returns -1
11195 * if the source file descriptor is closed, EMPTY if there are no unused
11196 * file descriptors left.
11200 copyfd(int from, int to)
11204 newfd = fcntl(from, F_DUPFD, to);
11206 if (errno == EMFILE)
11209 error("%d: %m", from);
11216 redirectsafe(union node *redir, int flags)
11219 volatile int saveint;
11220 struct jmploc *volatile savehandler = handler;
11221 struct jmploc jmploc;
11224 if (!(err = setjmp(jmploc.loc) * 2)) {
11226 redirect(redir, flags);
11228 handler = savehandler;
11229 if (err && exception != EXERROR)
11230 longjmp(handler->loc, 1);
11231 RESTOREINT(saveint);
11235 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11238 static void shtree(union node *, int, char *, FILE*);
11239 static void shcmd(union node *, FILE *);
11240 static void sharg(union node *, FILE *);
11241 static void indent(int, char *, FILE *);
11242 static void trstring(char *);
11246 showtree(union node *n)
11248 trputs("showtree called\n");
11249 shtree(n, 1, NULL, stdout);
11254 shtree(union node *n, int ind, char *pfx, FILE *fp)
11256 struct nodelist *lp;
11262 indent(ind, pfx, fp);
11273 shtree(n->nbinary.ch1, ind, NULL, fp);
11276 shtree(n->nbinary.ch2, ind, NULL, fp);
11284 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11289 if (n->npipe.backgnd)
11295 fprintf(fp, "<node type %d>", n->type);
11304 shcmd(union node *cmd, FILE *fp)
11312 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11318 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11321 switch (np->nfile.type) {
11322 case NTO: s = ">"; dftfd = 1; break;
11323 case NCLOBBER: s = ">|"; dftfd = 1; break;
11324 case NAPPEND: s = ">>"; dftfd = 1; break;
11325 case NTOFD: s = ">&"; dftfd = 1; break;
11326 case NFROM: s = "<"; dftfd = 0; break;
11327 case NFROMFD: s = "<&"; dftfd = 0; break;
11328 case NFROMTO: s = "<>"; dftfd = 0; break;
11329 default: s = "*error*"; dftfd = 0; break;
11331 if (np->nfile.fd != dftfd)
11332 fprintf(fp, "%d", np->nfile.fd);
11334 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11335 fprintf(fp, "%d", np->ndup.dupfd);
11337 sharg(np->nfile.fname, fp);
11346 sharg(union node *arg, FILE *fp)
11349 struct nodelist *bqlist;
11352 if (arg->type != NARG) {
11353 out1fmt("<node type %d>\n", arg->type);
11356 bqlist = arg->narg.backquote;
11357 for (p = arg->narg.text ; *p ; p++) {
11366 if (subtype == VSLENGTH)
11372 if (subtype & VSNUL)
11375 switch (subtype & VSTYPE) {
11394 case VSTRIMLEFTMAX:
11401 case VSTRIMRIGHTMAX:
11408 out1fmt("<subtype %d>", subtype);
11415 case CTLBACKQ|CTLQUOTE:
11418 shtree(bqlist->n, -1, NULL, fp);
11430 indent(int amount, char *pfx, FILE *fp)
11434 for (i = 0 ; i < amount ; i++) {
11435 if (pfx && i == amount - 1)
11456 putc(c, tracefile);
11460 trace(const char *fmt, ...)
11467 (void) vfprintf(tracefile, fmt, va);
11472 tracev(const char *fmt, va_list va)
11476 (void) vfprintf(tracefile, fmt, va);
11481 trputs(const char *s)
11485 fputs(s, tracefile);
11497 putc('"', tracefile);
11498 for (p = s ; *p ; p++) {
11500 case '\n': c = 'n'; goto backslash;
11501 case '\t': c = 't'; goto backslash;
11502 case '\r': c = 'r'; goto backslash;
11503 case '"': c = '"'; goto backslash;
11504 case '\\': c = '\\'; goto backslash;
11505 case CTLESC: c = 'e'; goto backslash;
11506 case CTLVAR: c = 'v'; goto backslash;
11507 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11508 case CTLBACKQ: c = 'q'; goto backslash;
11509 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11510 backslash: putc('\\', tracefile);
11511 putc(c, tracefile);
11514 if (*p >= ' ' && *p <= '~')
11515 putc(*p, tracefile);
11517 putc('\\', tracefile);
11518 putc(*p >> 6 & 03, tracefile);
11519 putc(*p >> 3 & 07, tracefile);
11520 putc(*p & 07, tracefile);
11525 putc('"', tracefile);
11537 putc(' ', tracefile);
11539 putc('\n', tracefile);
11555 /* leave open because libedit might be using it */
11558 scopy("./trace", s);
11560 if (!freopen(s, "a", tracefile)) {
11561 fprintf(stderr, "Can't re-open %s\n", s);
11566 if ((tracefile = fopen(s, "a")) == NULL) {
11567 fprintf(stderr, "Can't open %s\n", s);
11573 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11574 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11576 setlinebuf(tracefile);
11577 fputs("\nTracing started.\n", tracefile);
11582 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11585 * Sigmode records the current value of the signal handlers for the various
11586 * modes. A value of zero means that the current handler is not known.
11587 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11590 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11591 #define S_CATCH 2 /* signal is caught */
11592 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11593 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11594 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11599 * The trap builtin.
11603 trapcmd(int argc, char **argv)
11612 for (signo = 0 ; signo < NSIG ; signo++) {
11613 if (trap[signo] != NULL) {
11616 sn = u_signal_names(0, &signo, 0);
11619 out1fmt("trap -- %s %s\n",
11620 single_quote(trap[signo]), sn);
11630 if ((signo = decode_signal(*ap, 0)) < 0)
11631 error("%s: bad trap", *ap);
11634 if (action[0] == '-' && action[1] == '\0')
11637 action = savestr(action);
11640 ckfree(trap[signo]);
11641 trap[signo] = action;
11652 * Clear traps on a fork.
11660 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11661 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11665 if (tp != &trap[0])
11666 setsignal(tp - trap);
11674 * Set the signal handler for the specified signal. The routine figures
11675 * out what it should be set to.
11679 setsignal(int signo)
11683 struct sigaction act;
11685 if ((t = trap[signo]) == NULL)
11687 else if (*t != '\0')
11691 if (rootshell && action == S_DFL) {
11694 if (iflag || minusc || sflag == 0)
11717 t = &sigmode[signo - 1];
11721 * current setting unknown
11723 if (sigaction(signo, 0, &act) == -1) {
11725 * Pretend it worked; maybe we should give a warning
11726 * here, but other shells don't. We don't alter
11727 * sigmode, so that we retry every time.
11731 if (act.sa_handler == SIG_IGN) {
11732 if (mflag && (signo == SIGTSTP ||
11733 signo == SIGTTIN || signo == SIGTTOU)) {
11734 tsig = S_IGN; /* don't hard ignore these */
11738 tsig = S_RESET; /* force to be set */
11741 if (tsig == S_HARD_IGN || tsig == action)
11745 act.sa_handler = onsig;
11748 act.sa_handler = SIG_IGN;
11751 act.sa_handler = SIG_DFL;
11755 sigfillset(&act.sa_mask);
11756 sigaction(signo, &act, 0);
11764 ignoresig(int signo)
11766 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11767 signal(signo, SIG_IGN);
11769 sigmode[signo - 1] = S_HARD_IGN;
11780 gotsig[signo - 1] = 1;
11781 pendingsigs = signo;
11783 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11792 * Called to execute a trap. Perhaps we should avoid entering new trap
11793 * handlers while we are executing a trap handler.
11803 savestatus = exitstatus;
11805 while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
11807 p = trap[p - q + 1];
11811 exitstatus = savestatus;
11817 * Controls whether the shell is interactive or not.
11821 setinteractive(int on)
11823 static int is_interactive;
11825 if (++on == is_interactive)
11827 is_interactive = on;
11829 setsignal(SIGQUIT);
11830 setsignal(SIGTERM);
11831 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11832 if(is_interactive > 1) {
11833 /* Looks like they want an interactive shell */
11834 static int do_banner;
11838 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11839 "Enter 'help' for a list of built-in commands.\n\n");
11847 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11848 /*** List the available builtins ***/
11850 static int helpcmd(int argc, char **argv)
11854 out1fmt("\nBuilt-in commands:\n-------------------\n");
11855 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11856 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11857 builtincmd[i].name + 1);
11863 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11865 extern const struct BB_applet applets[];
11866 extern const size_t NUM_APPLETS;
11868 for (i = 0; i < NUM_APPLETS; i++) {
11870 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11879 return EXIT_SUCCESS;
11881 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11884 * Called to exit the shell.
11895 jmp = setjmp(loc.loc);
11896 status = exitstatus;
11897 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11901 if ((p = trap[0]) != NULL && *p != '\0') {
11907 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11908 if (iflag && rootshell) {
11909 const char *hp = lookupvar("HISTFILE");
11912 save_history ( hp );
11920 static int decode_signal(const char *string, int minsig)
11923 const char *name = u_signal_names(string, &signo, minsig);
11925 return name ? signo : -1;
11928 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11930 static struct var *vartab[VTABSIZE];
11932 static int vpcmp(const void *, const void *);
11933 static struct var **findvar(struct var **, const char *);
11936 * Initialize the variable symbol tables and import the environment
11940 #ifdef CONFIG_ASH_GETOPTS
11942 * Safe version of setvar, returns 1 on success 0 on failure.
11946 setvarsafe(const char *name, const char *val, int flags)
11949 volatile int saveint;
11950 struct jmploc *volatile savehandler = handler;
11951 struct jmploc jmploc;
11954 if (setjmp(jmploc.loc))
11958 setvar(name, val, flags);
11961 handler = savehandler;
11962 RESTOREINT(saveint);
11968 * Set the value of a variable. The flags argument is ored with the
11969 * flags of the variable. If val is NULL, the variable is unset.
11973 setvar(const char *name, const char *val, int flags)
11980 q = endofname(name);
11981 p = strchrnul(q, '=');
11982 namelen = p - name;
11983 if (!namelen || p != q)
11984 error("%.*s: bad variable name", namelen, name);
11989 vallen = strlen(val);
11992 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11996 p = mempcpy(p, val, vallen);
11999 setvareq(nameeq, flags | VNOSAVE);
12005 * Same as setvar except that the variable and value are passed in
12006 * the first argument as name=value. Since the first argument will
12007 * be actually stored in the table, it should not be a string that
12009 * Called with interrupts off.
12013 setvareq(char *s, int flags)
12015 struct var *vp, **vpp;
12018 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12019 vp = *findvar(vpp, s);
12021 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12024 if (flags & VNOSAVE)
12027 error("%.*s: is read only", strchrnul(n, '=') - n, n);
12030 if (flags & VNOSET)
12033 if (vp->func && (flags & VNOFUNC) == 0)
12034 (*vp->func)(strchrnul(s, '=') + 1);
12036 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12039 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12041 if (flags & VNOSET)
12044 vp = ckmalloc(sizeof (*vp));
12049 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12057 * Process a linked list of variable assignments.
12061 listsetvar(struct strlist *list_set_var, int flags)
12063 struct strlist *lp = list_set_var;
12069 setvareq(lp->text, flags);
12070 } while ((lp = lp->next));
12076 * Find the value of a variable. Returns NULL if not set.
12080 lookupvar(const char *name)
12084 if ((v = *findvar(hashvar(name), name))) {
12087 * Dynamic variables are implemented roughly the same way they are
12088 * in bash. Namely, they're "special" so long as they aren't unset.
12089 * As soon as they're unset, they're no longer dynamic, and dynamic
12090 * lookup will no longer happen at that point. -- PFM.
12092 if((v->flags & VDYNAMIC))
12095 if(!(v->flags & VUNSET))
12096 return strchrnul(v->text, '=') + 1;
12104 * Search the environment of a builtin command.
12108 bltinlookup(const char *name)
12110 struct strlist *sp;
12112 for (sp = cmdenviron ; sp ; sp = sp->next) {
12113 if (varequal(sp->text, name))
12114 return strchrnul(sp->text, '=') + 1;
12116 return lookupvar(name);
12121 * Generate a list of variables satisfying the given conditions.
12125 listvars(int on, int off, char ***end)
12136 for (vp = *vpp ; vp ; vp = vp->next)
12137 if ((vp->flags & mask) == on) {
12138 if (ep == stackstrend())
12139 ep = growstackstr();
12140 *ep++ = (char *) vp->text;
12142 } while (++vpp < vartab + VTABSIZE);
12143 if (ep == stackstrend())
12144 ep = growstackstr();
12148 return grabstackstr(ep);
12153 * POSIX requires that 'set' (but not export or readonly) output the
12154 * variables in lexicographic order - by the locale's collating order (sigh).
12155 * Maybe we could keep them in an ordered balanced binary tree
12156 * instead of hashed lists.
12157 * For now just roll 'em through qsort for printing...
12161 showvars(const char *sep_prefix, int on, int off)
12164 char **ep, **epend;
12166 ep = listvars(on, off, &epend);
12167 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12169 sep = *sep_prefix ? spcstr : sep_prefix;
12171 for (; ep < epend; ep++) {
12175 p = strchrnul(*ep, '=');
12178 q = single_quote(++p);
12180 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12189 * The export and readonly commands.
12193 exportcmd(int argc, char **argv)
12199 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12202 notp = nextopt("p") - 'p';
12203 if (notp && ((name = *(aptr = argptr)))) {
12205 if ((p = strchr(name, '=')) != NULL) {
12208 if ((vp = *findvar(hashvar(name), name))) {
12213 setvar(name, p, flag);
12214 } while ((name = *++aptr) != NULL);
12216 showvars(argv[0], flag, 0);
12223 * Make a variable a local variable. When a variable is made local, it's
12224 * value and flags are saved in a localvar structure. The saved values
12225 * will be restored when the shell function returns. We handle the name
12226 * "-" as a special case.
12230 mklocal(char *name)
12232 struct localvar *lvp;
12237 lvp = ckmalloc(sizeof (struct localvar));
12238 if (name[0] == '-' && name[1] == '\0') {
12240 p = ckmalloc(sizeof(optlist));
12241 lvp->text = memcpy(p, optlist, sizeof(optlist));
12246 vpp = hashvar(name);
12247 vp = *findvar(vpp, name);
12248 eq = strchr(name, '=');
12251 setvareq(name, VSTRFIXED);
12253 setvar(name, NULL, VSTRFIXED);
12254 vp = *vpp; /* the new variable */
12255 lvp->flags = VUNSET;
12257 lvp->text = vp->text;
12258 lvp->flags = vp->flags;
12259 vp->flags |= VSTRFIXED|VTEXTFIXED;
12265 lvp->next = localvars;
12271 * The "local" command.
12275 localcmd(int argc, char **argv)
12280 while ((name = *argv++) != NULL) {
12288 * Called after a function returns.
12289 * Interrupts must be off.
12295 struct localvar *lvp;
12298 while ((lvp = localvars) != NULL) {
12299 localvars = lvp->next;
12301 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12302 if (vp == NULL) { /* $- saved */
12303 memcpy(optlist, lvp->text, sizeof(optlist));
12306 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12307 unsetvar(vp->text);
12310 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12311 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12313 vp->flags = lvp->flags;
12314 vp->text = lvp->text;
12322 * The unset builtin command. We unset the function before we unset the
12323 * variable to allow a function to be unset when there is a readonly variable
12324 * with the same name.
12328 unsetcmd(int argc, char **argv)
12335 while ((i = nextopt("vf")) != '\0') {
12339 for (ap = argptr; *ap ; ap++) {
12354 * Unset the specified variable.
12358 unsetvar(const char *s)
12364 vpp = findvar(hashvar(s), s);
12368 int flags = vp->flags;
12371 if (flags & VREADONLY)
12374 vp->flags &= ~VDYNAMIC;
12376 if (flags & VUNSET)
12378 if ((flags & VSTRFIXED) == 0) {
12380 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12387 vp->flags &= ~VEXPORT;
12400 * Find the appropriate entry in the hash table from the name.
12403 static struct var **
12404 hashvar(const char *p)
12406 unsigned int hashval;
12408 hashval = ((unsigned char) *p) << 4;
12409 while (*p && *p != '=')
12410 hashval += (unsigned char) *p++;
12411 return &vartab[hashval % VTABSIZE];
12417 * Compares two strings up to the first = or '\0'. The first
12418 * string must be terminated by '='; the second may be terminated by
12419 * either '=' or '\0'.
12423 varcmp(const char *p, const char *q)
12427 while ((c = *p) == (d = *q)) {
12428 if (!c || c == '=')
12442 vpcmp(const void *a, const void *b)
12444 return varcmp(*(const char **)a, *(const char **)b);
12447 static struct var **
12448 findvar(struct var **vpp, const char *name)
12450 for (; *vpp; vpp = &(*vpp)->next) {
12451 if (varequal((*vpp)->text, name)) {
12457 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12459 #include <sys/times.h>
12461 static const unsigned char timescmd_str[] = {
12462 ' ', offsetof(struct tms, tms_utime),
12463 '\n', offsetof(struct tms, tms_stime),
12464 ' ', offsetof(struct tms, tms_cutime),
12465 '\n', offsetof(struct tms, tms_cstime),
12469 static int timescmd(int ac, char **av)
12471 long int clk_tck, s, t;
12472 const unsigned char *p;
12475 clk_tck = sysconf(_SC_CLK_TCK);
12480 t = *(clock_t *)(((char *) &buf) + p[1]);
12482 out1fmt("%ldm%ld.%.3lds%c",
12484 ((t - s * clk_tck) * 1000) / clk_tck,
12486 } while (*(p += 2));
12491 #ifdef CONFIG_ASH_MATH_SUPPORT
12493 dash_arith(const char *s)
12499 result = arith(s, &errcode);
12502 error("exponent less than 0");
12503 else if (errcode == -2)
12504 error("divide by zero");
12505 else if (errcode == -5)
12506 error("expression recursion loop detected");
12517 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12518 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12520 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12524 letcmd(int argc, char **argv)
12531 error("expression expected");
12532 for (ap = argv + 1; *ap; ap++) {
12533 i = dash_arith(*ap);
12538 #endif /* CONFIG_ASH_MATH_SUPPORT */
12540 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12543 * Miscellaneous builtins.
12549 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12550 typedef enum __rlimit_resource rlim_t;
12556 * The read builtin. The -e option causes backslashes to escape the
12557 * following character.
12559 * This uses unbuffered input, which may be avoidable in some cases.
12563 readcmd(int argc, char **argv)
12572 #if defined(CONFIG_ASH_TIMEOUT)
12575 struct timeval timeout_struct;
12576 struct termios tty, old_tty;
12584 #if defined(CONFIG_ASH_TIMEOUT)
12587 while ((i = nextopt("p:rt:")) != '\0')
12589 while ((i = nextopt("p:r")) != '\0')
12593 prompt = optionarg;
12596 #if defined(CONFIG_ASH_TIMEOUT)
12598 timeout = atoi(optionarg);
12601 if (prompt && isatty(0)) {
12604 if (*(ap = argptr) == NULL)
12605 error("arg count");
12606 if ((ifs = bltinlookup("IFS")) == NULL)
12608 #if defined(CONFIG_ASH_TIMEOUT)
12616 #if defined(CONFIG_ASH_TIMEOUT)
12618 tcgetattr(0, &tty);
12621 /* cfmakeraw(...) disables too much; we just do this instead. */
12622 tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
12623 tcsetattr(0, TCSANOW, &tty);
12628 timeout_struct.tv_sec = timeout;
12629 timeout_struct.tv_usec = 0;
12631 if ((i = select (FD_SETSIZE, &set, NULL, NULL, &timeout_struct)) == 1)
12634 if(c == '\n' || c == 4) /* Handle newlines and EOF */
12635 i = 0; /* Don't read further... */
12637 STPUTC(c, p); /* Keep reading... */
12639 tcsetattr(0, TCSANOW, &old_tty);
12641 /* Echo the character so the user knows it was read...
12642 Yes, this can be done by setting the ECHO flag, but that
12643 echoes ^D and other control characters at this state */
12655 if (read(0, &c, 1) != 1) {
12667 if (!rflag && c == '\\') {
12673 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12677 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12679 setvar(*ap, stackblock(), 0);
12689 /* Remove trailing blanks */
12690 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12692 setvar(*ap, stackblock(), 0);
12693 while (*++ap != NULL)
12694 setvar(*ap, nullstr, 0);
12699 static int umaskcmd(int argc, char **argv)
12701 static const char permuser[3] = "ugo";
12702 static const char permmode[3] = "rwx";
12703 static const short int permmask[] = {
12704 S_IRUSR, S_IWUSR, S_IXUSR,
12705 S_IRGRP, S_IWGRP, S_IXGRP,
12706 S_IROTH, S_IWOTH, S_IXOTH
12712 int symbolic_mode = 0;
12714 while (nextopt("S") != '\0') {
12723 if ((ap = *argptr) == NULL) {
12724 if (symbolic_mode) {
12728 for (i = 0; i < 3; i++) {
12731 *p++ = permuser[i];
12733 for (j = 0; j < 3; j++) {
12734 if ((mask & permmask[3 * i + j]) == 0) {
12735 *p++ = permmode[j];
12743 out1fmt("%.4o\n", mask);
12746 if (is_digit((unsigned char) *ap)) {
12749 if (*ap >= '8' || *ap < '0')
12750 error(illnum, argv[1]);
12751 mask = (mask << 3) + (*ap - '0');
12752 } while (*++ap != '\0');
12755 mask = ~mask & 0777;
12756 if (!bb_parse_mode(ap, &mask)) {
12757 error("Illegal mode: %s", ap);
12759 umask(~mask & 0777);
12768 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12769 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12770 * ash by J.T. Conklin.
12778 int factor; /* multiply by to get rlim_{cur,max} values */
12782 static const struct limits limits[] = {
12784 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12786 #ifdef RLIMIT_FSIZE
12787 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12790 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12792 #ifdef RLIMIT_STACK
12793 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12796 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12799 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12801 #ifdef RLIMIT_MEMLOCK
12802 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12804 #ifdef RLIMIT_NPROC
12805 { "process", RLIMIT_NPROC, 1, 'p' },
12807 #ifdef RLIMIT_NOFILE
12808 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
12811 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
12813 #ifdef RLIMIT_LOCKS
12814 { "locks", RLIMIT_LOCKS, 1, 'w' },
12816 { (char *) 0, 0, 0, '\0' }
12819 enum limtype { SOFT = 0x1, HARD = 0x2 };
12821 static void printlim(enum limtype how, const struct rlimit *limit,
12822 const struct limits *l)
12826 val = limit->rlim_max;
12828 val = limit->rlim_cur;
12830 if (val == RLIM_INFINITY)
12831 out1fmt("unlimited\n");
12834 out1fmt("%lld\n", (long long) val);
12839 ulimitcmd(int argc, char **argv)
12843 enum limtype how = SOFT | HARD;
12844 const struct limits *l;
12847 struct rlimit limit;
12850 while ((optc = nextopt("HSa"
12854 #ifdef RLIMIT_FSIZE
12860 #ifdef RLIMIT_STACK
12869 #ifdef RLIMIT_MEMLOCK
12872 #ifdef RLIMIT_NPROC
12875 #ifdef RLIMIT_NOFILE
12881 #ifdef RLIMIT_LOCKS
12899 for (l = limits; l->option != what; l++)
12902 set = *argptr ? 1 : 0;
12906 if (all || argptr[1])
12907 error("too many arguments");
12908 if (strncmp(p, "unlimited\n", 9) == 0)
12909 val = RLIM_INFINITY;
12913 while ((c = *p++) >= '0' && c <= '9')
12915 val = (val * 10) + (long)(c - '0');
12916 if (val < (rlim_t) 0)
12920 error("bad number");
12925 for (l = limits; l->name; l++) {
12926 getrlimit(l->cmd, &limit);
12927 out1fmt("%-20s ", l->name);
12928 printlim(how, &limit, l);
12933 getrlimit(l->cmd, &limit);
12936 limit.rlim_max = val;
12938 limit.rlim_cur = val;
12939 if (setrlimit(l->cmd, &limit) < 0)
12940 error("error setting limit (%m)");
12942 printlim(how, &limit, l);
12948 #ifdef CONFIG_ASH_MATH_SUPPORT
12950 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12952 Permission is hereby granted, free of charge, to any person obtaining
12953 a copy of this software and associated documentation files (the
12954 "Software"), to deal in the Software without restriction, including
12955 without limitation the rights to use, copy, modify, merge, publish,
12956 distribute, sublicense, and/or sell copies of the Software, and to
12957 permit persons to whom the Software is furnished to do so, subject to
12958 the following conditions:
12960 The above copyright notice and this permission notice shall be
12961 included in all copies or substantial portions of the Software.
12963 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12964 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12965 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12966 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12967 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12968 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12969 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12972 /* This is my infix parser/evaluator. It is optimized for size, intended
12973 * as a replacement for yacc-based parsers. However, it may well be faster
12974 * than a comparable parser written in yacc. The supported operators are
12975 * listed in #defines below. Parens, order of operations, and error handling
12976 * are supported. This code is thread safe. The exact expression format should
12977 * be that which POSIX specifies for shells. */
12979 /* The code uses a simple two-stack algorithm. See
12980 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12981 * for a detailed explanation of the infix-to-postfix algorithm on which
12982 * this is based (this code differs in that it applies operators immediately
12983 * to the stack instead of adding them to a queue to end up with an
12986 /* To use the routine, call it with an expression string and error return
12990 * Aug 24, 2001 Manuel Novoa III
12992 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12994 * 1) In arith_apply():
12995 * a) Cached values of *numptr and &(numptr[-1]).
12996 * b) Removed redundant test for zero denominator.
12999 * a) Eliminated redundant code for processing operator tokens by moving
13000 * to a table-based implementation. Also folded handling of parens
13002 * b) Combined all 3 loops which called arith_apply to reduce generated
13003 * code size at the cost of speed.
13005 * 3) The following expressions were treated as valid by the original code:
13006 * 1() , 0! , 1 ( *3 ) .
13007 * These bugs have been fixed by internally enclosing the expression in
13008 * parens and then checking that all binary ops and right parens are
13009 * preceded by a valid expression (NUM_TOKEN).
13011 * Note: It may be desirable to replace Aaron's test for whitespace with
13012 * ctype's isspace() if it is used by another busybox applet or if additional
13013 * whitespace chars should be considered. Look below the "#include"s for a
13014 * precompiler test.
13018 * Aug 26, 2001 Manuel Novoa III
13020 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13022 * Merge in Aaron's comments previously posted to the busybox list,
13023 * modified slightly to take account of my changes to the code.
13028 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13030 * - allow access to variable,
13031 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13032 * - realize assign syntax (VAR=expr, +=, *= etc)
13033 * - realize exponentiation (** operator)
13034 * - realize comma separated - expr, expr
13035 * - realise ++expr --expr expr++ expr--
13036 * - realise expr ? expr : expr (but, second expr calculate always)
13037 * - allow hexadecimal and octal numbers
13038 * - was restored loses XOR operator
13039 * - remove one goto label, added three ;-)
13040 * - protect $((num num)) as true zero expr (Manuel`s error)
13041 * - always use special isspace(), see comment from bash ;-)
13045 #define arith_isspace(arithval) \
13046 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13049 typedef unsigned char operator;
13051 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
13052 * precedence, and 3 high bits are an ID unique across operators of that
13053 * precedence. The ID portion is so that multiple operators can have the
13054 * same precedence, ensuring that the leftmost one is evaluated first.
13055 * Consider * and /. */
13057 #define tok_decl(prec,id) (((id)<<5)|(prec))
13058 #define PREC(op) ((op) & 0x1F)
13060 #define TOK_LPAREN tok_decl(0,0)
13062 #define TOK_COMMA tok_decl(1,0)
13064 #define TOK_ASSIGN tok_decl(2,0)
13065 #define TOK_AND_ASSIGN tok_decl(2,1)
13066 #define TOK_OR_ASSIGN tok_decl(2,2)
13067 #define TOK_XOR_ASSIGN tok_decl(2,3)
13068 #define TOK_PLUS_ASSIGN tok_decl(2,4)
13069 #define TOK_MINUS_ASSIGN tok_decl(2,5)
13070 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13071 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13073 #define TOK_MUL_ASSIGN tok_decl(3,0)
13074 #define TOK_DIV_ASSIGN tok_decl(3,1)
13075 #define TOK_REM_ASSIGN tok_decl(3,2)
13077 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13078 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13080 /* conditional is right associativity too */
13081 #define TOK_CONDITIONAL tok_decl(4,0)
13082 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
13084 #define TOK_OR tok_decl(5,0)
13086 #define TOK_AND tok_decl(6,0)
13088 #define TOK_BOR tok_decl(7,0)
13090 #define TOK_BXOR tok_decl(8,0)
13092 #define TOK_BAND tok_decl(9,0)
13094 #define TOK_EQ tok_decl(10,0)
13095 #define TOK_NE tok_decl(10,1)
13097 #define TOK_LT tok_decl(11,0)
13098 #define TOK_GT tok_decl(11,1)
13099 #define TOK_GE tok_decl(11,2)
13100 #define TOK_LE tok_decl(11,3)
13102 #define TOK_LSHIFT tok_decl(12,0)
13103 #define TOK_RSHIFT tok_decl(12,1)
13105 #define TOK_ADD tok_decl(13,0)
13106 #define TOK_SUB tok_decl(13,1)
13108 #define TOK_MUL tok_decl(14,0)
13109 #define TOK_DIV tok_decl(14,1)
13110 #define TOK_REM tok_decl(14,2)
13112 /* exponent is right associativity */
13113 #define TOK_EXPONENT tok_decl(15,1)
13115 /* For now unary operators. */
13116 #define UNARYPREC 16
13117 #define TOK_BNOT tok_decl(UNARYPREC,0)
13118 #define TOK_NOT tok_decl(UNARYPREC,1)
13120 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13121 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13123 #define PREC_PRE (UNARYPREC+2)
13125 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13126 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13128 #define PREC_POST (UNARYPREC+3)
13130 #define TOK_POST_INC tok_decl(PREC_POST, 0)
13131 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
13133 #define SPEC_PREC (UNARYPREC+4)
13135 #define TOK_NUM tok_decl(SPEC_PREC, 0)
13136 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13138 #define NUMPTR (*numstackptr)
13140 static inline int tok_have_assign(operator op)
13142 operator prec = PREC(op);
13144 convert_prec_is_assing(prec);
13145 return (prec == PREC(TOK_ASSIGN) ||
13146 prec == PREC_PRE || prec == PREC_POST);
13149 static inline int is_right_associativity(operator prec)
13151 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13152 prec == PREC(TOK_CONDITIONAL));
13156 typedef struct ARITCH_VAR_NUM {
13158 arith_t contidional_second_val;
13159 char contidional_second_val_initialized;
13160 char *var; /* if NULL then is regular number,
13161 else is variable name */
13165 typedef struct CHK_VAR_RECURSIVE_LOOPED {
13167 struct CHK_VAR_RECURSIVE_LOOPED *next;
13168 } chk_var_recursive_looped_t;
13170 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13173 static int arith_lookup_val(v_n_t *t)
13176 const char * p = lookupvar(t->var);
13181 /* recursive try as expression */
13182 chk_var_recursive_looped_t *cur;
13183 chk_var_recursive_looped_t cur_save;
13185 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13186 if(strcmp(cur->var, t->var) == 0) {
13187 /* expression recursion loop detected */
13191 /* save current lookuped var name */
13192 cur = prev_chk_var_recursive;
13193 cur_save.var = t->var;
13194 cur_save.next = cur;
13195 prev_chk_var_recursive = &cur_save;
13197 t->val = arith (p, &errcode);
13198 /* restore previous ptr after recursiving */
13199 prev_chk_var_recursive = cur;
13202 /* allow undefined var as 0 */
13209 /* "applying" a token means performing it on the top elements on the integer
13210 * stack. For a unary operator it will only change the top element, but a
13211 * binary operator will pop two arguments and push a result */
13213 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13216 arith_t numptr_val, rez;
13217 int ret_arith_lookup_val;
13219 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13220 without arguments */
13221 numptr_m1 = NUMPTR - 1;
13223 /* check operand is var with noninteger value */
13224 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13225 if(ret_arith_lookup_val)
13226 return ret_arith_lookup_val;
13228 rez = numptr_m1->val;
13229 if (op == TOK_UMINUS)
13231 else if (op == TOK_NOT)
13233 else if (op == TOK_BNOT)
13235 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13237 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13239 else if (op != TOK_UPLUS) {
13240 /* Binary operators */
13242 /* check and binary operators need two arguments */
13243 if (numptr_m1 == numstack) goto err;
13245 /* ... and they pop one */
13248 if (op == TOK_CONDITIONAL) {
13249 if(! numptr_m1->contidional_second_val_initialized) {
13250 /* protect $((expr1 ? expr2)) without ": expr" */
13253 rez = numptr_m1->contidional_second_val;
13254 } else if(numptr_m1->contidional_second_val_initialized) {
13255 /* protect $((expr1 : expr2)) without "expr ? " */
13258 numptr_m1 = NUMPTR - 1;
13259 if(op != TOK_ASSIGN) {
13260 /* check operand is var with noninteger value for not '=' */
13261 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13262 if(ret_arith_lookup_val)
13263 return ret_arith_lookup_val;
13265 if (op == TOK_CONDITIONAL) {
13266 numptr_m1->contidional_second_val = rez;
13268 rez = numptr_m1->val;
13269 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13271 else if (op == TOK_OR)
13272 rez = numptr_val || rez;
13273 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13275 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13277 else if (op == TOK_AND)
13278 rez = rez && numptr_val;
13279 else if (op == TOK_EQ)
13280 rez = (rez == numptr_val);
13281 else if (op == TOK_NE)
13282 rez = (rez != numptr_val);
13283 else if (op == TOK_GE)
13284 rez = (rez >= numptr_val);
13285 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13286 rez >>= numptr_val;
13287 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13288 rez <<= numptr_val;
13289 else if (op == TOK_GT)
13290 rez = (rez > numptr_val);
13291 else if (op == TOK_LT)
13292 rez = (rez < numptr_val);
13293 else if (op == TOK_LE)
13294 rez = (rez <= numptr_val);
13295 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13297 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13299 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13301 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13303 else if (op == TOK_CONDITIONAL_SEP) {
13304 if (numptr_m1 == numstack) {
13305 /* protect $((expr : expr)) without "expr ? " */
13308 numptr_m1->contidional_second_val_initialized = op;
13309 numptr_m1->contidional_second_val = numptr_val;
13311 else if (op == TOK_CONDITIONAL) {
13313 numptr_val : numptr_m1->contidional_second_val;
13315 else if(op == TOK_EXPONENT) {
13317 return -3; /* exponent less than 0 */
13322 while(numptr_val--)
13327 else if(numptr_val==0) /* zero divisor check */
13329 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13331 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13334 if(tok_have_assign(op)) {
13337 if(numptr_m1->var == NULL) {
13341 /* save to shell variable */
13342 snprintf(buf, sizeof(buf), "%lld", (long long) rez);
13343 setvar(numptr_m1->var, buf, 0);
13344 /* after saving, make previous value for v++ or v-- */
13345 if(op == TOK_POST_INC)
13347 else if(op == TOK_POST_DEC)
13350 numptr_m1->val = rez;
13351 /* protect geting var value, is number now */
13352 numptr_m1->var = NULL;
13357 /* longest must first */
13358 static const char op_tokens[] = {
13359 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13360 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13361 '<','<', 0, TOK_LSHIFT,
13362 '>','>', 0, TOK_RSHIFT,
13363 '|','|', 0, TOK_OR,
13364 '&','&', 0, TOK_AND,
13365 '!','=', 0, TOK_NE,
13366 '<','=', 0, TOK_LE,
13367 '>','=', 0, TOK_GE,
13368 '=','=', 0, TOK_EQ,
13369 '|','=', 0, TOK_OR_ASSIGN,
13370 '&','=', 0, TOK_AND_ASSIGN,
13371 '*','=', 0, TOK_MUL_ASSIGN,
13372 '/','=', 0, TOK_DIV_ASSIGN,
13373 '%','=', 0, TOK_REM_ASSIGN,
13374 '+','=', 0, TOK_PLUS_ASSIGN,
13375 '-','=', 0, TOK_MINUS_ASSIGN,
13376 '-','-', 0, TOK_POST_DEC,
13377 '^','=', 0, TOK_XOR_ASSIGN,
13378 '+','+', 0, TOK_POST_INC,
13379 '*','*', 0, TOK_EXPONENT,
13383 '=', 0, TOK_ASSIGN,
13395 '?', 0, TOK_CONDITIONAL,
13396 ':', 0, TOK_CONDITIONAL_SEP,
13397 ')', 0, TOK_RPAREN,
13398 '(', 0, TOK_LPAREN,
13402 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13405 static arith_t arith (const char *expr, int *perrcode)
13407 register char arithval; /* Current character under analysis */
13408 operator lasttok, op;
13411 const char *p = endexpression;
13414 size_t datasizes = strlen(expr) + 2;
13416 /* Stack of integers */
13417 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13418 * in any given correct or incorrect expression is left as an exercise to
13420 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13421 *numstackptr = numstack;
13422 /* Stack of operator tokens */
13423 operator *stack = alloca((datasizes) * sizeof(operator)),
13426 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13427 *perrcode = errcode = 0;
13430 if ((arithval = *expr) == 0) {
13431 if (p == endexpression) {
13432 /* Null expression. */
13436 /* This is only reached after all tokens have been extracted from the
13437 * input stream. If there are still tokens on the operator stack, they
13438 * are to be applied in order. At the end, there should be a final
13439 * result on the integer stack */
13441 if (expr != endexpression + 1) {
13442 /* If we haven't done so already, */
13443 /* append a closing right paren */
13444 expr = endexpression;
13445 /* and let the loop process it. */
13448 /* At this point, we're done with the expression. */
13449 if (numstackptr != numstack+1) {
13450 /* ... but if there isn't, it's bad */
13452 return (*perrcode = -1);
13454 if(numstack->var) {
13455 /* expression is $((var)) only, lookup now */
13456 errcode = arith_lookup_val(numstack);
13459 *perrcode = errcode;
13460 return numstack->val;
13462 /* Continue processing the expression. */
13463 if (arith_isspace(arithval)) {
13464 /* Skip whitespace */
13467 if((p = endofname(expr)) != expr) {
13468 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13470 numstackptr->var = alloca(var_name_size);
13471 safe_strncpy(numstackptr->var, expr, var_name_size);
13474 numstackptr->contidional_second_val_initialized = 0;
13478 } else if (is_digit(arithval)) {
13479 numstackptr->var = NULL;
13480 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13483 for(p = op_tokens; ; p++) {
13487 /* strange operator not found */
13490 for(o = expr; *p && *o == *p; p++)
13497 /* skip tail uncompared token */
13500 /* skip zero delim */
13505 /* post grammar: a++ reduce to num */
13506 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13509 /* Plus and minus are binary (not unary) _only_ if the last
13510 * token was as number, or a right paren (which pretends to be
13511 * a number, since it evaluates to one). Think about it.
13512 * It makes sense. */
13513 if (lasttok != TOK_NUM) {
13529 /* We don't want a unary operator to cause recursive descent on the
13530 * stack, because there can be many in a row and it could cause an
13531 * operator to be evaluated before its argument is pushed onto the
13532 * integer stack. */
13533 /* But for binary operators, "apply" everything on the operator
13534 * stack until we find an operator with a lesser priority than the
13535 * one we have just extracted. */
13536 /* Left paren is given the lowest priority so it will never be
13537 * "applied" in this way.
13538 * if associativity is right and priority eq, applied also skip
13541 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13542 /* not left paren or unary */
13543 if (lasttok != TOK_NUM) {
13544 /* binary op must be preceded by a num */
13547 while (stackptr != stack) {
13548 if (op == TOK_RPAREN) {
13549 /* The algorithm employed here is simple: while we don't
13550 * hit an open paren nor the bottom of the stack, pop
13551 * tokens and apply them */
13552 if (stackptr[-1] == TOK_LPAREN) {
13554 /* Any operator directly after a */
13556 /* close paren should consider itself binary */
13560 operator prev_prec = PREC(stackptr[-1]);
13562 convert_prec_is_assing(prec);
13563 convert_prec_is_assing(prev_prec);
13564 if (prev_prec < prec)
13566 /* check right assoc */
13567 if(prev_prec == prec && is_right_associativity(prec))
13570 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13571 if(errcode) goto ret;
13573 if (op == TOK_RPAREN) {
13578 /* Push this operator to the stack and remember it. */
13579 *stackptr++ = lasttok = op;
13586 #endif /* CONFIG_ASH_MATH_SUPPORT */
13590 const char *bb_applet_name = "debug stuff usage";
13591 int main(int argc, char **argv)
13593 return ash_main(argc, argv);
13598 * Copyright (c) 1989, 1991, 1993, 1994
13599 * The Regents of the University of California. All rights reserved.
13601 * This code is derived from software contributed to Berkeley by
13602 * Kenneth Almquist.
13604 * Redistribution and use in source and binary forms, with or without
13605 * modification, are permitted provided that the following conditions
13607 * 1. Redistributions of source code must retain the above copyright
13608 * notice, this list of conditions and the following disclaimer.
13609 * 2. Redistributions in binary form must reproduce the above copyright
13610 * notice, this list of conditions and the following disclaimer in the
13611 * documentation and/or other materials provided with the distribution.
13613 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13614 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13616 * 4. Neither the name of the University nor the names of its contributors
13617 * may be used to endorse or promote products derived from this software
13618 * without specific prior written permission.
13620 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13621 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13622 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13623 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13624 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13625 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13626 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13627 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13628 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13629 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF