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
3728 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3736 if(strcmp(name, "busybox")) {
3737 for (ap = argv; *ap; ap++);
3738 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3739 *ap++ = cmd = "/bin/busybox";
3740 while ((*ap++ = *argv++));
3744 cmd = "/bin/busybox";
3752 execve(cmd, argv, envp);
3753 } while (errno == EINTR);
3755 execve(cmd, argv, envp);
3759 } else if (errno == ENOEXEC) {
3763 for (ap = argv; *ap; ap++)
3765 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3767 *ap = cmd = (char *)DEFAULT_SHELL;
3770 while ((*ap++ = *argv++))
3780 * Do a path search. The variable path (passed by reference) should be
3781 * set to the start of the path before the first call; padvance will update
3782 * this value as it proceeds. Successive calls to padvance will return
3783 * the possible path expansions in sequence. If an option (indicated by
3784 * a percent sign) appears in the path entry then the global variable
3785 * pathopt will be set to point to it; otherwise pathopt will be set to
3790 padvance(const char **path, const char *name)
3800 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3801 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3802 while (stackblocksize() < len)
3806 memcpy(q, start, p - start);
3814 while (*p && *p != ':') p++;
3820 return stalloc(len);
3824 /*** Command hashing code ***/
3827 printentry(struct tblentry *cmdp)
3833 idx = cmdp->param.index;
3836 name = padvance(&path, cmdp->cmdname);
3838 } while (--idx >= 0);
3839 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3844 hashcmd(int argc, char **argv)
3846 struct tblentry **pp;
3847 struct tblentry *cmdp;
3849 struct cmdentry entry;
3852 while ((c = nextopt("r")) != '\0') {
3856 if (*argptr == NULL) {
3857 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3858 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3859 if (cmdp->cmdtype == CMDNORMAL)
3866 while ((name = *argptr) != NULL) {
3867 if ((cmdp = cmdlookup(name, 0)) != NULL
3868 && (cmdp->cmdtype == CMDNORMAL
3869 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3871 find_command(name, &entry, DO_ERR, pathval());
3872 if (entry.cmdtype == CMDUNKNOWN)
3881 * Resolve a command name. If you change this routine, you may have to
3882 * change the shellexec routine as well.
3886 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3888 struct tblentry *cmdp;
3895 struct builtincmd *bcmd;
3897 /* If name contains a slash, don't use PATH or hash table */
3898 if (strchr(name, '/') != NULL) {
3899 entry->u.index = -1;
3901 while (stat(name, &statb) < 0) {
3906 entry->cmdtype = CMDUNKNOWN;
3910 entry->cmdtype = CMDNORMAL;
3914 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3915 if (find_applet_by_name(name)) {
3916 entry->cmdtype = CMDNORMAL;
3917 entry->u.index = -1;
3922 updatetbl = (path == pathval());
3925 if (strstr(path, "%builtin") != NULL)
3929 /* If name is in the table, check answer will be ok */
3930 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3933 switch (cmdp->cmdtype) {
3951 } else if (cmdp->rehash == 0)
3952 /* if not invalidated by cd, we're done */
3956 /* If %builtin not in path, check for builtin next */
3957 bcmd = find_builtin(name);
3958 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3959 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3961 goto builtin_success;
3963 /* We have to search path. */
3964 prev = -1; /* where to start */
3965 if (cmdp && cmdp->rehash) { /* doing a rehash */
3966 if (cmdp->cmdtype == CMDBUILTIN)
3969 prev = cmdp->param.index;
3975 while ((fullname = padvance(&path, name)) != NULL) {
3976 stunalloc(fullname);
3979 if (prefix(pathopt, "builtin")) {
3981 goto builtin_success;
3983 } else if (!(act & DO_NOFUNC) &&
3984 prefix(pathopt, "func")) {
3987 /* ignore unimplemented options */
3991 /* if rehash, don't redo absolute path names */
3992 if (fullname[0] == '/' && idx <= prev) {
3995 TRACE(("searchexec \"%s\": no change\n", name));
3998 while (stat(fullname, &statb) < 0) {
4003 if (errno != ENOENT && errno != ENOTDIR)
4007 e = EACCES; /* if we fail, this will be the error */
4008 if (!S_ISREG(statb.st_mode))
4010 if (pathopt) { /* this is a %func directory */
4011 stalloc(strlen(fullname) + 1);
4012 readcmdfile(fullname);
4013 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4014 cmdp->cmdtype != CMDFUNCTION)
4015 error("%s not defined in %s", name, fullname);
4016 stunalloc(fullname);
4019 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4021 entry->cmdtype = CMDNORMAL;
4022 entry->u.index = idx;
4026 cmdp = cmdlookup(name, 1);
4027 cmdp->cmdtype = CMDNORMAL;
4028 cmdp->param.index = idx;
4033 /* We failed. If there was an entry for this command, delete it */
4034 if (cmdp && updatetbl)
4037 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4038 entry->cmdtype = CMDUNKNOWN;
4043 entry->cmdtype = CMDBUILTIN;
4044 entry->u.cmd = bcmd;
4048 cmdp = cmdlookup(name, 1);
4049 cmdp->cmdtype = CMDBUILTIN;
4050 cmdp->param.cmd = bcmd;
4054 entry->cmdtype = cmdp->cmdtype;
4055 entry->u = cmdp->param;
4060 * Wrapper around strcmp for qsort/bsearch/...
4062 static int pstrcmp(const void *a, const void *b)
4064 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4068 * Search the table of builtin commands.
4071 static struct builtincmd *
4072 find_builtin(const char *name)
4074 struct builtincmd *bp;
4077 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4086 * Called when a cd is done. Marks all commands so the next time they
4087 * are executed they will be rehashed.
4093 struct tblentry **pp;
4094 struct tblentry *cmdp;
4096 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4097 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4098 if (cmdp->cmdtype == CMDNORMAL || (
4099 cmdp->cmdtype == CMDBUILTIN &&
4100 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4111 * Fix command hash table when PATH changed.
4112 * Called before PATH is changed. The argument is the new value of PATH;
4113 * pathval() still returns the old value at this point.
4114 * Called with interrupts off.
4118 changepath(const char *newval)
4120 const char *old, *new;
4127 firstchange = 9999; /* assume no change */
4133 if ((*old == '\0' && *new == ':')
4134 || (*old == ':' && *new == '\0'))
4136 old = new; /* ignore subsequent differences */
4140 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4147 if (builtinloc < 0 && idx_bltin >= 0)
4148 builtinloc = idx_bltin; /* zap builtins */
4149 if (builtinloc >= 0 && idx_bltin < 0)
4151 clearcmdentry(firstchange);
4152 builtinloc = idx_bltin;
4157 * Clear out command entries. The argument specifies the first entry in
4158 * PATH which has changed.
4162 clearcmdentry(int firstchange)
4164 struct tblentry **tblp;
4165 struct tblentry **pp;
4166 struct tblentry *cmdp;
4169 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4171 while ((cmdp = *pp) != NULL) {
4172 if ((cmdp->cmdtype == CMDNORMAL &&
4173 cmdp->param.index >= firstchange)
4174 || (cmdp->cmdtype == CMDBUILTIN &&
4175 builtinloc >= firstchange)) {
4189 * Locate a command in the command hash table. If "add" is nonzero,
4190 * add the command to the table if it is not already present. The
4191 * variable "lastcmdentry" is set to point to the address of the link
4192 * pointing to the entry, so that delete_cmd_entry can delete the
4195 * Interrupts must be off if called with add != 0.
4198 static struct tblentry **lastcmdentry;
4201 static struct tblentry *
4202 cmdlookup(const char *name, int add)
4204 unsigned int hashval;
4206 struct tblentry *cmdp;
4207 struct tblentry **pp;
4210 hashval = (unsigned char)*p << 4;
4212 hashval += (unsigned char)*p++;
4214 pp = &cmdtable[hashval % CMDTABLESIZE];
4215 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4216 if (equal(cmdp->cmdname, name))
4220 if (add && cmdp == NULL) {
4221 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4222 + strlen(name) + 1);
4224 cmdp->cmdtype = CMDUNKNOWN;
4225 strcpy(cmdp->cmdname, name);
4232 * Delete the command entry returned on the last lookup.
4236 delete_cmd_entry(void)
4238 struct tblentry *cmdp;
4241 cmdp = *lastcmdentry;
4242 *lastcmdentry = cmdp->next;
4243 if (cmdp->cmdtype == CMDFUNCTION)
4244 freefunc(cmdp->param.func);
4251 * Add a new command entry, replacing any existing command entry for
4252 * the same name - except special builtins.
4256 addcmdentry(char *name, struct cmdentry *entry)
4258 struct tblentry *cmdp;
4260 cmdp = cmdlookup(name, 1);
4261 if (cmdp->cmdtype == CMDFUNCTION) {
4262 freefunc(cmdp->param.func);
4264 cmdp->cmdtype = entry->cmdtype;
4265 cmdp->param = entry->u;
4270 * Make a copy of a parse tree.
4273 static inline struct funcnode *
4274 copyfunc(union node *n)
4279 funcblocksize = offsetof(struct funcnode, n);
4282 blocksize = funcblocksize;
4283 f = ckmalloc(blocksize + funcstringsize);
4284 funcblock = (char *) f + offsetof(struct funcnode, n);
4285 funcstring = (char *) f + blocksize;
4292 * Define a shell function.
4296 defun(char *name, union node *func)
4298 struct cmdentry entry;
4301 entry.cmdtype = CMDFUNCTION;
4302 entry.u.func = copyfunc(func);
4303 addcmdentry(name, &entry);
4309 * Delete a function if it exists.
4313 unsetfunc(const char *name)
4315 struct tblentry *cmdp;
4317 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4318 cmdp->cmdtype == CMDFUNCTION)
4323 * Locate and print what a word is...
4327 #ifdef CONFIG_ASH_CMDCMD
4329 describe_command(char *command, int describe_command_verbose)
4331 #define describe_command_verbose 1
4333 describe_command(char *command)
4336 struct cmdentry entry;
4337 struct tblentry *cmdp;
4338 #ifdef CONFIG_ASH_ALIAS
4339 const struct alias *ap;
4341 const char *path = pathval();
4343 if (describe_command_verbose) {
4347 /* First look at the keywords */
4348 if (findkwd(command)) {
4349 out1str(describe_command_verbose ? " is a shell keyword" : command);
4353 #ifdef CONFIG_ASH_ALIAS
4354 /* Then look at the aliases */
4355 if ((ap = lookupalias(command, 0)) != NULL) {
4356 if (describe_command_verbose) {
4357 out1fmt(" is an alias for %s", ap->val);
4366 /* Then check if it is a tracked alias */
4367 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4368 entry.cmdtype = cmdp->cmdtype;
4369 entry.u = cmdp->param;
4371 /* Finally use brute force */
4372 find_command(command, &entry, DO_ABS, path);
4375 switch (entry.cmdtype) {
4377 int j = entry.u.index;
4383 p = padvance(&path, command);
4387 if (describe_command_verbose) {
4389 (cmdp ? " a tracked alias for" : nullstr), p
4398 if (describe_command_verbose) {
4399 out1str(" is a shell function");
4406 if (describe_command_verbose) {
4407 out1fmt(" is a %sshell builtin",
4408 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4409 "special " : nullstr
4417 if (describe_command_verbose) {
4418 out1str(": not found\n");
4424 outstr("\n", stdout);
4429 typecmd(int argc, char **argv)
4434 for (i = 1; i < argc; i++) {
4435 #ifdef CONFIG_ASH_CMDCMD
4436 err |= describe_command(argv[i], 1);
4438 err |= describe_command(argv[i]);
4444 #ifdef CONFIG_ASH_CMDCMD
4446 commandcmd(int argc, char **argv)
4449 int default_path = 0;
4450 int verify_only = 0;
4451 int verbose_verify_only = 0;
4453 while ((c = nextopt("pvV")) != '\0')
4458 "command: nextopt returned character code 0%o\n", c);
4468 verbose_verify_only = 1;
4472 if (default_path + verify_only + verbose_verify_only > 1 ||
4475 "command [-p] command [arg ...]\n"
4476 "command {-v|-V} command\n");
4480 if (verify_only || verbose_verify_only) {
4481 return describe_command(*argptr, verbose_verify_only);
4488 /* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
4491 * Routines to expand arguments to commands. We have to deal with
4492 * backquotes, shell variables, and file metacharacters.
4498 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4499 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4500 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4501 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4502 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4505 * Structure specifying which parts of the string should be searched
4506 * for IFS characters.
4510 struct ifsregion *next; /* next region in list */
4511 int begoff; /* offset of start of region */
4512 int endoff; /* offset of end of region */
4513 int nulonly; /* search for nul bytes only */
4516 /* output of current string */
4517 static char *expdest;
4518 /* list of back quote expressions */
4519 static struct nodelist *argbackq;
4520 /* first struct in list of ifs regions */
4521 static struct ifsregion ifsfirst;
4522 /* last struct in list */
4523 static struct ifsregion *ifslastp;
4524 /* holds expanded arg list */
4525 static struct arglist exparg;
4527 static void argstr(char *, int);
4528 static char *exptilde(char *, char *, int);
4529 static void expbackq(union node *, int, int);
4530 static const char *subevalvar(char *, char *, int, int, int, int, int);
4531 static char *evalvar(char *, int);
4532 static void strtodest(const char *, int, int);
4533 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4534 static ssize_t varvalue(char *, int, int);
4535 static void recordregion(int, int, int);
4536 static void removerecordregions(int);
4537 static void ifsbreakup(char *, struct arglist *);
4538 static void ifsfree(void);
4539 static void expandmeta(struct strlist *, int);
4540 static int patmatch(char *, const char *);
4542 static int cvtnum(arith_t);
4543 static size_t esclen(const char *, const char *);
4544 static char *scanleft(char *, char *, char *, char *, int, int);
4545 static char *scanright(char *, char *, char *, char *, int, int);
4546 static void varunset(const char *, const char *, const char *, int)
4547 __attribute__((__noreturn__));
4550 #define pmatch(a, b) !fnmatch((a), (b), 0)
4552 * Prepare a pattern for a expmeta (internal glob(3)) call.
4554 * Returns an stalloced string.
4557 static inline char *
4558 preglob(const char *pattern, int quoted, int flag) {
4559 flag |= RMESCAPE_GLOB;
4561 flag |= RMESCAPE_QUOTED;
4563 return _rmescapes((char *)pattern, flag);
4568 esclen(const char *start, const char *p) {
4571 while (p > start && *--p == CTLESC) {
4579 * Expand shell variables and backquotes inside a here document.
4583 expandhere(union node *arg, int fd)
4586 expandarg(arg, (struct arglist *)NULL, 0);
4587 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
4592 * Perform variable substitution and command substitution on an argument,
4593 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4594 * perform splitting and file name expansion. When arglist is NULL, perform
4595 * here document expansion.
4599 expandarg(union node *arg, struct arglist *arglist, int flag)
4604 argbackq = arg->narg.backquote;
4605 STARTSTACKSTR(expdest);
4606 ifsfirst.next = NULL;
4608 argstr(arg->narg.text, flag);
4609 if (arglist == NULL) {
4610 return; /* here document expanded */
4612 STPUTC('\0', expdest);
4613 p = grabstackstr(expdest);
4614 exparg.lastp = &exparg.list;
4618 if (flag & EXP_FULL) {
4619 ifsbreakup(p, &exparg);
4620 *exparg.lastp = NULL;
4621 exparg.lastp = &exparg.list;
4622 expandmeta(exparg.list, flag);
4624 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4626 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4629 exparg.lastp = &sp->next;
4633 *exparg.lastp = NULL;
4635 *arglist->lastp = exparg.list;
4636 arglist->lastp = exparg.lastp;
4642 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4643 * characters to allow for further processing. Otherwise treat
4644 * $@ like $* since no splitting will be performed.
4648 argstr(char *p, int flag)
4650 static const char spclchars[] = {
4658 CTLBACKQ | CTLQUOTE,
4659 #ifdef CONFIG_ASH_MATH_SUPPORT
4664 const char *reject = spclchars;
4666 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4667 int breakall = flag & EXP_WORD;
4672 if (!(flag & EXP_VARTILDE)) {
4674 } else if (flag & EXP_VARTILDE2) {
4679 if (flag & EXP_TILDE) {
4685 if (*q == CTLESC && (flag & EXP_QWORD))
4688 p = exptilde(p, q, flag);
4691 startloc = expdest - (char *)stackblock();
4693 length += strcspn(p + length, reject);
4695 if (c && (!(c & 0x80)
4696 #ifdef CONFIG_ASH_MATH_SUPPORT
4700 /* c == '=' || c == ':' || c == CTLENDARI */
4705 expdest = stnputs(p, length, expdest);
4706 newloc = expdest - (char *)stackblock();
4707 if (breakall && !inquotes && newloc > startloc) {
4708 recordregion(startloc, newloc, 0);
4719 if (flag & EXP_VARTILDE2) {
4723 flag |= EXP_VARTILDE2;
4728 * sort of a hack - expand tildes in variable
4729 * assignments (after the first '=' and after ':'s).
4738 case CTLENDVAR: /* ??? */
4741 /* "$@" syntax adherence hack */
4744 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4745 (p[4] == CTLQUOTEMARK || (
4746 p[4] == CTLENDVAR &&
4747 p[5] == CTLQUOTEMARK
4750 p = evalvar(p + 1, flag) + 1;
4753 inquotes = !inquotes;
4766 p = evalvar(p, flag);
4770 case CTLBACKQ|CTLQUOTE:
4771 expbackq(argbackq->n, c, quotes);
4772 argbackq = argbackq->next;
4774 #ifdef CONFIG_ASH_MATH_SUPPORT
4787 exptilde(char *startp, char *p, int flag)
4793 int quotes = flag & (EXP_FULL | EXP_CASE);
4798 while ((c = *++p) != '\0') {
4805 if (flag & EXP_VARTILDE)
4815 if (*name == '\0') {
4816 if ((home = lookupvar(homestr)) == NULL)
4819 if ((pw = getpwnam(name)) == NULL)
4826 startloc = expdest - (char *)stackblock();
4827 strtodest(home, SQSYNTAX, quotes);
4828 recordregion(startloc, expdest - (char *)stackblock(), 0);
4837 removerecordregions(int endoff)
4839 if (ifslastp == NULL)
4842 if (ifsfirst.endoff > endoff) {
4843 while (ifsfirst.next != NULL) {
4844 struct ifsregion *ifsp;
4846 ifsp = ifsfirst.next->next;
4847 ckfree(ifsfirst.next);
4848 ifsfirst.next = ifsp;
4851 if (ifsfirst.begoff > endoff)
4854 ifslastp = &ifsfirst;
4855 ifsfirst.endoff = endoff;
4860 ifslastp = &ifsfirst;
4861 while (ifslastp->next && ifslastp->next->begoff < endoff)
4862 ifslastp=ifslastp->next;
4863 while (ifslastp->next != NULL) {
4864 struct ifsregion *ifsp;
4866 ifsp = ifslastp->next->next;
4867 ckfree(ifslastp->next);
4868 ifslastp->next = ifsp;
4871 if (ifslastp->endoff > endoff)
4872 ifslastp->endoff = endoff;
4876 #ifdef CONFIG_ASH_MATH_SUPPORT
4878 * Expand arithmetic expression. Backup to start of expression,
4879 * evaluate, place result in (backed up) result, adjust string position.
4892 * This routine is slightly over-complicated for
4893 * efficiency. Next we scan backwards looking for the
4894 * start of arithmetic.
4896 start = stackblock();
4903 while (*p != CTLARI) {
4907 error("missing CTLARI (shouldn't happen)");
4912 esc = esclen(start, p);
4922 removerecordregions(begoff);
4931 len = cvtnum(dash_arith(p + 2));
4934 recordregion(begoff, begoff + len, 0);
4939 * Expand stuff in backwards quotes.
4943 expbackq(union node *cmd, int quoted, int quotes)
4951 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4952 struct stackmark smark;
4955 setstackmark(&smark);
4957 startloc = dest - (char *)stackblock();
4959 evalbackcmd(cmd, (struct backcmd *) &in);
4960 popstackmark(&smark);
4967 memtodest(p, i, syntax, quotes);
4971 i = safe_read(in.fd, buf, sizeof buf);
4972 TRACE(("expbackq: read returns %d\n", i));
4982 back_exitstatus = waitforjob(in.jp);
4986 /* Eat all trailing newlines */
4988 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4993 recordregion(startloc, dest - (char *)stackblock(), 0);
4994 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4995 (dest - (char *)stackblock()) - startloc,
4996 (dest - (char *)stackblock()) - startloc,
4997 stackblock() + startloc));
5002 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5013 const char *s = loc2;
5019 match = pmatch(str, s);
5023 if (quotes && *loc == CTLESC)
5033 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5040 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5043 const char *s = loc2;
5048 match = pmatch(str, s);
5055 esc = esclen(startp, loc);
5067 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5071 int saveherefd = herefd;
5072 struct nodelist *saveargbackq = argbackq;
5074 char *rmesc, *rmescend;
5076 char *(*scan)(char *, char *, char *, char *, int , int);
5079 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5080 STPUTC('\0', expdest);
5081 herefd = saveherefd;
5082 argbackq = saveargbackq;
5083 startp = stackblock() + startloc;
5087 setvar(str, startp, 0);
5088 amount = startp - expdest;
5089 STADJUST(amount, expdest);
5093 varunset(p, str, startp, varflags);
5097 subtype -= VSTRIMRIGHT;
5099 if (subtype < 0 || subtype > 3)
5104 rmescend = stackblock() + strloc;
5106 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5107 if (rmesc != startp) {
5109 startp = stackblock() + startloc;
5113 str = stackblock() + strloc;
5114 preglob(str, varflags & VSQUOTE, 0);
5116 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5117 zero = subtype >> 1;
5118 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5119 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5121 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5124 memmove(startp, loc, str - loc);
5125 loc = startp + (str - loc) - 1;
5128 amount = loc - expdest;
5129 STADJUST(amount, expdest);
5136 * Expand a variable, and return a pointer to the next character in the
5140 evalvar(char *p, int flag)
5153 quotes = flag & (EXP_FULL | EXP_CASE);
5155 subtype = varflags & VSTYPE;
5156 quoted = varflags & VSQUOTE;
5158 easy = (!quoted || (*var == '@' && shellparam.nparam));
5159 startloc = expdest - (char *)stackblock();
5160 p = strchr(p, '=') + 1;
5163 varlen = varvalue(var, varflags, flag);
5164 if (varflags & VSNUL)
5167 if (subtype == VSPLUS) {
5168 varlen = -1 - varlen;
5172 if (subtype == VSMINUS) {
5176 p, flag | EXP_TILDE |
5177 (quoted ? EXP_QWORD : EXP_WORD)
5186 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5188 if (subevalvar(p, var, 0, subtype, startloc,
5192 * Remove any recorded regions beyond
5195 removerecordregions(startloc);
5205 if (varlen < 0 && uflag)
5206 varunset(p, var, 0, 0);
5208 if (subtype == VSLENGTH) {
5209 cvtnum(varlen > 0 ? varlen : 0);
5213 if (subtype == VSNORMAL) {
5217 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5226 case VSTRIMRIGHTMAX:
5235 * Terminate the string and start recording the pattern
5238 STPUTC('\0', expdest);
5239 patloc = expdest - (char *)stackblock();
5240 if (subevalvar(p, NULL, patloc, subtype,
5241 startloc, varflags, quotes) == 0) {
5242 int amount = expdest - (
5243 (char *)stackblock() + patloc - 1
5245 STADJUST(-amount, expdest);
5247 /* Remove any recorded regions beyond start of variable */
5248 removerecordregions(startloc);
5253 if (subtype != VSNORMAL) { /* skip to end of alternative */
5256 if ((c = *p++) == CTLESC)
5258 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5260 argbackq = argbackq->next;
5261 } else if (c == CTLVAR) {
5262 if ((*p++ & VSTYPE) != VSNORMAL)
5264 } else if (c == CTLENDVAR) {
5275 * Put a string on the stack.
5279 memtodest(const char *p, size_t len, int syntax, int quotes) {
5282 q = makestrspace(len * 2, q);
5288 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5298 strtodest(const char *p, int syntax, int quotes)
5300 memtodest(p, strlen(p), syntax, quotes);
5305 * Add the value of a specialized variable to the stack string.
5309 varvalue(char *name, int varflags, int flags)
5319 int quoted = varflags & VSQUOTE;
5320 int subtype = varflags & VSTYPE;
5321 int quotes = flags & (EXP_FULL | EXP_CASE);
5323 if (quoted && (flags & EXP_FULL))
5324 sep = 1 << CHAR_BIT;
5326 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5335 num = shellparam.nparam;
5345 p = makestrspace(NOPTS, expdest);
5346 for (i = NOPTS - 1; i >= 0; i--) {
5348 USTPUTC(optletters(i), p);
5359 sep = ifsset() ? ifsval()[0] : ' ';
5360 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5363 if (!(ap = shellparam.p))
5365 while ((p = *ap++)) {
5368 partlen = strlen(p);
5371 if (len > partlen && sep) {
5375 if (subtype == VSPLUS || subtype == VSLENGTH) {
5385 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5386 memtodest(p, partlen, syntax, quotes);
5400 if (num < 0 || num > shellparam.nparam)
5402 p = num ? shellparam.p[num - 1] : arg0;
5405 p = lookupvar(name);
5411 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5412 memtodest(p, len, syntax, quotes);
5416 if (subtype == VSPLUS || subtype == VSLENGTH)
5417 STADJUST(-len, expdest);
5423 * Record the fact that we have to scan this region of the
5424 * string for IFS characters.
5428 recordregion(int start, int end, int nulonly)
5430 struct ifsregion *ifsp;
5432 if (ifslastp == NULL) {
5436 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5438 ifslastp->next = ifsp;
5442 ifslastp->begoff = start;
5443 ifslastp->endoff = end;
5444 ifslastp->nulonly = nulonly;
5449 * Break the argument string into pieces based upon IFS and add the
5450 * strings to the argument list. The regions of the string to be
5451 * searched for IFS characters have been stored by recordregion.
5454 ifsbreakup(char *string, struct arglist *arglist)
5456 struct ifsregion *ifsp;
5461 const char *ifs, *realifs;
5467 if (ifslastp != NULL) {
5470 realifs = ifsset() ? ifsval() : defifs;
5473 p = string + ifsp->begoff;
5474 nulonly = ifsp->nulonly;
5475 ifs = nulonly ? nullstr : realifs;
5477 while (p < string + ifsp->endoff) {
5481 if (strchr(ifs, *p)) {
5483 ifsspc = (strchr(defifs, *p) != NULL);
5484 /* Ignore IFS whitespace at start */
5485 if (q == start && ifsspc) {
5491 sp = (struct strlist *)stalloc(sizeof *sp);
5493 *arglist->lastp = sp;
5494 arglist->lastp = &sp->next;
5498 if (p >= string + ifsp->endoff) {
5504 if (strchr(ifs, *p) == NULL ) {
5507 } else if (strchr(defifs, *p) == NULL) {
5523 } while ((ifsp = ifsp->next) != NULL);
5532 sp = (struct strlist *)stalloc(sizeof *sp);
5534 *arglist->lastp = sp;
5535 arglist->lastp = &sp->next;
5541 struct ifsregion *p;
5546 struct ifsregion *ifsp;
5552 ifsfirst.next = NULL;
5556 static void expmeta(char *, char *);
5557 static struct strlist *expsort(struct strlist *);
5558 static struct strlist *msort(struct strlist *, int);
5560 static char *expdir;
5564 expandmeta(struct strlist *str, int flag)
5566 static const char metachars[] = {
5569 /* TODO - EXP_REDIR */
5572 struct strlist **savelastp;
5578 if (!strpbrk(str->text, metachars))
5580 savelastp = exparg.lastp;
5583 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5585 int i = strlen(str->text);
5586 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5594 if (exparg.lastp == savelastp) {
5599 *exparg.lastp = str;
5600 rmescapes(str->text);
5601 exparg.lastp = &str->next;
5603 *exparg.lastp = NULL;
5604 *savelastp = sp = expsort(*savelastp);
5605 while (sp->next != NULL)
5607 exparg.lastp = &sp->next;
5614 * Add a file name to the list.
5618 addfname(const char *name)
5622 sp = (struct strlist *)stalloc(sizeof *sp);
5623 sp->text = sstrdup(name);
5625 exparg.lastp = &sp->next;
5630 * Do metacharacter (i.e. *, ?, [...]) expansion.
5634 expmeta(char *enddir, char *name)
5649 for (p = name; *p; p++) {
5650 if (*p == '*' || *p == '?')
5652 else if (*p == '[') {
5659 if (*q == '/' || *q == '\0')
5666 } else if (*p == '\\')
5668 else if (*p == '/') {
5675 if (metaflag == 0) { /* we've reached the end of the file name */
5676 if (enddir != expdir)
5684 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5695 } while (p < start);
5697 if (enddir == expdir) {
5699 } else if (enddir == expdir + 1 && *expdir == '/') {
5705 if ((dirp = opendir(cp)) == NULL)
5707 if (enddir != expdir)
5709 if (*endname == 0) {
5721 while (! intpending && (dp = readdir(dirp)) != NULL) {
5722 if (dp->d_name[0] == '.' && ! matchdot)
5724 if (pmatch(start, dp->d_name)) {
5726 scopy(dp->d_name, enddir);
5729 for (p = enddir, cp = dp->d_name;
5730 (*p++ = *cp++) != '\0';)
5733 expmeta(p, endname);
5743 * Sort the results of file name expansion. It calculates the number of
5744 * strings to sort and then calls msort (short for merge sort) to do the
5748 static struct strlist *
5749 expsort(struct strlist *str)
5755 for (sp = str ; sp ; sp = sp->next)
5757 return msort(str, len);
5761 static struct strlist *
5762 msort(struct strlist *list, int len)
5764 struct strlist *p, *q = NULL;
5765 struct strlist **lpp;
5773 for (n = half ; --n >= 0 ; ) {
5777 q->next = NULL; /* terminate first half of list */
5778 q = msort(list, half); /* sort first half of list */
5779 p = msort(p, len - half); /* sort second half */
5782 #ifdef CONFIG_LOCALE_SUPPORT
5783 if (strcoll(p->text, q->text) < 0)
5785 if (strcmp(p->text, q->text) < 0)
5790 if ((p = *lpp) == NULL) {
5797 if ((q = *lpp) == NULL) {
5808 * Returns true if the pattern matches the string.
5812 patmatch(char *pattern, const char *string)
5814 return pmatch(preglob(pattern, 0, 0), string);
5819 * Remove any CTLESC characters from a string.
5823 _rmescapes(char *str, int flag)
5826 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5831 p = strpbrk(str, qchars);
5837 if (flag & RMESCAPE_ALLOC) {
5838 size_t len = p - str;
5839 size_t fulllen = len + strlen(p) + 1;
5841 if (flag & RMESCAPE_GROW) {
5842 r = makestrspace(fulllen, expdest);
5843 } else if (flag & RMESCAPE_HEAP) {
5844 r = ckmalloc(fulllen);
5846 r = stalloc(fulllen);
5850 q = mempcpy(q, str, len);
5853 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5854 globbing = flag & RMESCAPE_GLOB;
5855 notescaped = globbing;
5857 if (*p == CTLQUOTEMARK) {
5858 inquotes = ~inquotes;
5860 notescaped = globbing;
5864 /* naked back slash */
5870 if (notescaped && inquotes && *p != '/') {
5874 notescaped = globbing;
5879 if (flag & RMESCAPE_GROW) {
5881 STADJUST(q - r + 1, expdest);
5888 * See if a pattern matches in a case statement.
5892 casematch(union node *pattern, char *val)
5894 struct stackmark smark;
5897 setstackmark(&smark);
5898 argbackq = pattern->narg.backquote;
5899 STARTSTACKSTR(expdest);
5901 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5902 STACKSTRNUL(expdest);
5903 result = patmatch(stackblock(), val);
5904 popstackmark(&smark);
5917 expdest = makestrspace(32, expdest);
5918 #ifdef CONFIG_ASH_MATH_SUPPORT_64
5919 len = fmtstr(expdest, 32, "%lld", (long long) num);
5921 len = fmtstr(expdest, 32, "%ld", num);
5923 STADJUST(len, expdest);
5928 varunset(const char *end, const char *var, const char *umsg, int varflags)
5934 msg = "parameter not set";
5936 if (*end == CTLENDVAR) {
5937 if (varflags & VSNUL)
5942 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5946 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5949 * This implements the input routines used by the parser.
5952 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5953 #define IBUFSIZ (BUFSIZ + 1)
5955 static void pushfile(void);
5958 * Read a character from the script, returning PEOF on end of file.
5959 * Nul characters in the input are silently discarded.
5962 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5964 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5965 #define pgetc_macro() pgetc()
5969 return pgetc_as_macro();
5972 #define pgetc_macro() pgetc_as_macro()
5976 return pgetc_macro();
5982 * Same as pgetc(), but ignores PEOA.
5984 #ifdef CONFIG_ASH_ALIAS
5985 static int pgetc2(void)
5991 } while (c == PEOA);
5995 static inline int pgetc2(void)
5997 return pgetc_macro();
6002 * Read a line from the script.
6005 static inline char *
6006 pfgets(char *line, int len)
6012 while (--nleft > 0) {
6029 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6030 static const char *cmdedit_prompt;
6031 static inline void putprompt(const char *s)
6036 static inline void putprompt(const char *s)
6046 char *buf = parsefile->buf;
6050 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6051 if (!iflag || parsefile->fd)
6052 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6054 #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
6055 cmdedit_path_lookup = pathval();
6057 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6059 /* Ctrl+C presend */
6068 if(nr < 0 && errno == 0) {
6069 /* Ctrl+D presend */
6074 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6078 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6079 int flags = fcntl(0, F_GETFL, 0);
6080 if (flags >= 0 && flags & O_NONBLOCK) {
6081 flags &=~ O_NONBLOCK;
6082 if (fcntl(0, F_SETFL, flags) >= 0) {
6083 out2str("sh: turning off NDELAY mode\n");
6093 * Refill the input buffer and return the next input character:
6095 * 1) If a string was pushed back on the input, pop it;
6096 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6097 * from a string so we can't refill the buffer, return EOF.
6098 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6099 * 4) Process input up to the next newline, deleting nul characters.
6109 while (parsefile->strpush) {
6110 #ifdef CONFIG_ASH_ALIAS
6111 if (parsenleft == -1 && parsefile->strpush->ap &&
6112 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6117 if (--parsenleft >= 0)
6118 return (*parsenextc++);
6120 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6125 if (parselleft <= 0) {
6126 if ((parselleft = preadfd()) <= 0) {
6127 parselleft = parsenleft = EOF_NLEFT;
6134 /* delete nul characters */
6135 for (more = 1; more;) {
6142 parsenleft = q - parsenextc;
6143 more = 0; /* Stop processing here */
6150 if (--parselleft <= 0 && more) {
6151 parsenleft = q - parsenextc - 1;
6162 out2str(parsenextc);
6167 return *parsenextc++;
6171 * Undo the last call to pgetc. Only one character may be pushed back.
6172 * PEOF may be pushed back.
6183 * Push a string back onto the input at this current parsefile level.
6184 * We handle aliases this way.
6187 pushstring(char *s, void *ap)
6194 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6195 if (parsefile->strpush) {
6196 sp = ckmalloc(sizeof (struct strpush));
6197 sp->prev = parsefile->strpush;
6198 parsefile->strpush = sp;
6200 sp = parsefile->strpush = &(parsefile->basestrpush);
6201 sp->prevstring = parsenextc;
6202 sp->prevnleft = parsenleft;
6203 #ifdef CONFIG_ASH_ALIAS
6204 sp->ap = (struct alias *)ap;
6206 ((struct alias *)ap)->flag |= ALIASINUSE;
6218 struct strpush *sp = parsefile->strpush;
6221 #ifdef CONFIG_ASH_ALIAS
6223 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6224 checkkwd |= CHKALIAS;
6226 if (sp->string != sp->ap->val) {
6229 sp->ap->flag &= ~ALIASINUSE;
6230 if (sp->ap->flag & ALIASDEAD) {
6231 unalias(sp->ap->name);
6235 parsenextc = sp->prevstring;
6236 parsenleft = sp->prevnleft;
6237 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6238 parsefile->strpush = sp->prev;
6239 if (sp != &(parsefile->basestrpush))
6245 * Set the input to take input from a file. If push is set, push the
6246 * old input onto the stack first.
6250 setinputfile(const char *fname, int push)
6256 if ((fd = open(fname, O_RDONLY)) < 0)
6257 error("Can't open %s", fname);
6259 fd2 = copyfd(fd, 10);
6262 error("Out of file descriptors");
6265 setinputfd(fd, push);
6271 * Like setinputfile, but takes an open file descriptor. Call this with
6276 setinputfd(int fd, int push)
6278 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6284 if (parsefile->buf == NULL)
6285 parsefile->buf = ckmalloc(IBUFSIZ);
6286 parselleft = parsenleft = 0;
6292 * Like setinputfile, but takes input from a string.
6296 setinputstring(char *string)
6300 parsenextc = string;
6301 parsenleft = strlen(string);
6302 parsefile->buf = NULL;
6309 * To handle the "." command, a stack of input files is used. Pushfile
6310 * adds a new entry to the stack and popfile restores the previous level.
6316 struct parsefile *pf;
6318 parsefile->nleft = parsenleft;
6319 parsefile->lleft = parselleft;
6320 parsefile->nextc = parsenextc;
6321 parsefile->linno = plinno;
6322 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6323 pf->prev = parsefile;
6326 pf->basestrpush.prev = NULL;
6334 struct parsefile *pf = parsefile;
6343 parsefile = pf->prev;
6345 parsenleft = parsefile->nleft;
6346 parselleft = parsefile->lleft;
6347 parsenextc = parsefile->nextc;
6348 plinno = parsefile->linno;
6354 * Return to top level.
6360 while (parsefile != &basepf)
6366 * Close the file(s) that the shell is reading commands from. Called
6367 * after a fork is done.
6374 if (parsefile->fd > 0) {
6375 close(parsefile->fd);
6380 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6382 /* mode flags for set_curjob */
6383 #define CUR_DELETE 2
6384 #define CUR_RUNNING 1
6385 #define CUR_STOPPED 0
6387 /* mode flags for dowait */
6388 #define DOWAIT_NORMAL 0
6389 #define DOWAIT_BLOCK 1
6392 static struct job *jobtab;
6394 static unsigned njobs;
6396 /* pgrp of shell on invocation */
6397 static int initialpgrp;
6398 static int ttyfd = -1;
6401 static struct job *curjob;
6402 /* number of presumed living untracked jobs */
6405 static void set_curjob(struct job *, unsigned);
6407 static int restartjob(struct job *, int);
6408 static void xtcsetpgrp(int, pid_t);
6409 static char *commandtext(union node *);
6410 static void cmdlist(union node *, int);
6411 static void cmdtxt(union node *);
6412 static void cmdputs(const char *);
6413 static void showpipe(struct job *, FILE *);
6415 static int sprint_status(char *, int, int);
6416 static void freejob(struct job *);
6417 static struct job *getjob(const char *, int);
6418 static struct job *growjobtab(void);
6419 static void forkchild(struct job *, union node *, int);
6420 static void forkparent(struct job *, union node *, int, pid_t);
6421 static int dowait(int, struct job *);
6422 static int getstatus(struct job *);
6425 set_curjob(struct job *jp, unsigned mode)
6428 struct job **jpp, **curp;
6430 /* first remove from list */
6431 jpp = curp = &curjob;
6436 jpp = &jp1->prev_job;
6438 *jpp = jp1->prev_job;
6440 /* Then re-insert in correct position */
6448 /* job being deleted */
6451 /* newly created job or backgrounded job,
6452 put after all stopped jobs. */
6456 if (!jp1 || jp1->state != JOBSTOPPED)
6459 jpp = &jp1->prev_job;
6465 /* newly stopped job - becomes curjob */
6466 jp->prev_job = *jpp;
6474 * Turn job control on and off.
6476 * Note: This code assumes that the third arg to ioctl is a character
6477 * pointer, which is true on Berkeley systems but not System V. Since
6478 * System V doesn't have job control yet, this isn't a problem now.
6480 * Called with interrupts off.
6489 if (on == jobctl || rootshell == 0)
6493 ofd = fd = open(_PATH_TTY, O_RDWR);
6496 while (!isatty(fd) && --fd >= 0)
6499 fd = fcntl(fd, F_DUPFD, 10);
6503 fcntl(fd, F_SETFD, FD_CLOEXEC);
6504 do { /* while we are in the background */
6505 if ((pgrp = tcgetpgrp(fd)) < 0) {
6507 sh_warnx("can't access tty; job control turned off");
6511 if (pgrp == getpgrp())
6522 xtcsetpgrp(fd, pgrp);
6524 /* turning job control off */
6527 xtcsetpgrp(fd, pgrp);
6541 killcmd(int argc, char **argv)
6552 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6553 "kill -l [exitstatus]"
6557 if (**++argv == '-') {
6558 signo = decode_signal(*argv + 1, 1);
6562 while ((c = nextopt("ls:")) != '\0')
6572 signo = decode_signal(optionarg, 1);
6575 "invalid signal number or name: %s",
6586 if (!list && signo < 0)
6589 if ((signo < 0 || !*argv) ^ list) {
6597 for (i = 1; i < NSIG; i++) {
6598 name = u_signal_names(0, &i, 1);
6600 out1fmt(snlfmt, name);
6604 name = u_signal_names(*argptr, &signo, -1);
6606 out1fmt(snlfmt, name);
6608 error("invalid signal number or exit status: %s", *argptr);
6614 if (**argv == '%') {
6615 jp = getjob(*argv, 0);
6616 pid = -jp->ps[0].pid;
6618 pid = number(*argv);
6619 if (kill(pid, signo) != 0) {
6629 #if defined(JOBS) || defined(DEBUG)
6631 jobno(const struct job *jp)
6633 return jp - jobtab + 1;
6639 fgcmd(int argc, char **argv)
6646 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6651 jp = getjob(*argv, 1);
6652 if (mode == FORK_BG) {
6653 set_curjob(jp, CUR_RUNNING);
6654 fprintf(out, "[%d] ", jobno(jp));
6656 outstr(jp->ps->cmd, out);
6658 retval = restartjob(jp, mode);
6659 } while (*argv && *++argv);
6663 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6667 restartjob(struct job *jp, int mode)
6669 struct procstat *ps;
6675 if (jp->state == JOBDONE)
6677 jp->state = JOBRUNNING;
6679 if (mode == FORK_FG)
6680 xtcsetpgrp(ttyfd, pgid);
6681 killpg(pgid, SIGCONT);
6685 if (WIFSTOPPED(ps->status)) {
6688 } while (ps++, --i);
6690 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6697 sprint_status(char *s, int status, int sigonly)
6703 if (!WIFEXITED(status)) {
6705 if (WIFSTOPPED(status))
6706 st = WSTOPSIG(status);
6709 st = WTERMSIG(status);
6711 if (st == SIGINT || st == SIGPIPE)
6714 if (WIFSTOPPED(status))
6719 col = fmtstr(s, 32, strsignal(st));
6720 if (WCOREDUMP(status)) {
6721 col += fmtstr(s + col, 16, " (core dumped)");
6723 } else if (!sigonly) {
6724 st = WEXITSTATUS(status);
6726 col = fmtstr(s, 16, "Done(%d)", st);
6728 col = fmtstr(s, 16, "Done");
6737 showjob(FILE *out, struct job *jp, int mode)
6739 struct procstat *ps;
6740 struct procstat *psend;
6747 if (mode & SHOW_PGID) {
6748 /* just output process (group) id of pipeline */
6749 fprintf(out, "%d\n", ps->pid);
6753 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6758 else if (curjob && jp == curjob->prev_job)
6761 if (mode & SHOW_PID)
6762 col += fmtstr(s + col, 16, "%d ", ps->pid);
6764 psend = ps + jp->nprocs;
6766 if (jp->state == JOBRUNNING) {
6767 scopy("Running", s + col);
6768 col += strlen("Running");
6770 int status = psend[-1].status;
6772 if (jp->state == JOBSTOPPED)
6773 status = jp->stopstatus;
6775 col += sprint_status(s + col, status, 0);
6781 /* for each process */
6782 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6785 fprintf(out, "%s%*c%s",
6786 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6788 if (!(mode & SHOW_PID)) {
6792 if (++ps == psend) {
6793 outcslow('\n', out);
6800 if (jp->state == JOBDONE) {
6801 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6808 jobscmd(int argc, char **argv)
6814 while ((m = nextopt("lp")))
6824 showjob(out, getjob(*argv,0), mode);
6827 showjobs(out, mode);
6834 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6835 * statuses have changed since the last call to showjobs.
6839 showjobs(FILE *out, int mode)
6843 TRACE(("showjobs(%x) called\n", mode));
6845 /* If not even one one job changed, there is nothing to do */
6846 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6849 for (jp = curjob; jp; jp = jp->prev_job) {
6850 if (!(mode & SHOW_CHANGED) || jp->changed)
6851 showjob(out, jp, mode);
6857 * Mark a job structure as unused.
6861 freejob(struct job *jp)
6863 struct procstat *ps;
6867 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6868 if (ps->cmd != nullstr)
6871 if (jp->ps != &jp->ps0)
6874 set_curjob(jp, CUR_DELETE);
6880 waitcmd(int argc, char **argv)
6893 /* wait for all jobs */
6898 /* no running procs */
6901 if (jp->state == JOBRUNNING)
6906 dowait(DOWAIT_BLOCK, 0);
6912 if (**argv != '%') {
6913 pid_t pid = number(*argv);
6917 if (job->ps[job->nprocs - 1].pid == pid)
6919 job = job->prev_job;
6925 job = getjob(*argv, 0);
6926 /* loop until process terminated or stopped */
6927 while (job->state == JOBRUNNING)
6928 dowait(DOWAIT_BLOCK, 0);
6930 retval = getstatus(job);
6941 * Convert a job name to a job structure.
6945 getjob(const char *name, int getctl)
6949 const char *err_msg = "No such job: %s";
6953 char *(*match)(const char *, const char *);
6968 if (c == '+' || c == '%') {
6970 err_msg = "No current job";
6972 } else if (c == '-') {
6975 err_msg = "No previous job";
6986 jp = jobtab + num - 1;
7003 if (match(jp->ps[0].cmd, p)) {
7007 err_msg = "%s: ambiguous";
7014 err_msg = "job %s not created under job control";
7015 if (getctl && jp->jobctl == 0)
7020 error(err_msg, name);
7025 * Return a new job structure.
7026 * Called with interrupts off.
7030 makejob(union node *node, int nprocs)
7035 for (i = njobs, jp = jobtab ; ; jp++) {
7042 if (jp->state != JOBDONE || !jp->waited)
7051 memset(jp, 0, sizeof(*jp));
7056 jp->prev_job = curjob;
7061 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7063 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7073 struct job *jp, *jq;
7075 len = njobs * sizeof(*jp);
7077 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7079 offset = (char *)jp - (char *)jq;
7081 /* Relocate pointers */
7084 jq = (struct job *)((char *)jq + l);
7088 #define joff(p) ((struct job *)((char *)(p) + l))
7089 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7090 if (xlikely(joff(jp)->ps == &jq->ps0))
7091 jmove(joff(jp)->ps);
7092 if (joff(jp)->prev_job)
7093 jmove(joff(jp)->prev_job);
7103 jp = (struct job *)((char *)jp + len);
7107 } while (--jq >= jp);
7113 * Fork off a subshell. If we are doing job control, give the subshell its
7114 * own process group. Jp is a job structure that the job is to be added to.
7115 * N is the command that will be evaluated by the child. Both jp and n may
7116 * be NULL. The mode parameter can be one of the following:
7117 * FORK_FG - Fork off a foreground process.
7118 * FORK_BG - Fork off a background process.
7119 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7120 * process group even if job control is on.
7122 * When job control is turned off, background processes have their standard
7123 * input redirected to /dev/null (except for the second and later processes
7126 * Called with interrupts off.
7130 forkchild(struct job *jp, union node *n, int mode)
7134 TRACE(("Child shell %d\n", getpid()));
7135 wasroot = rootshell;
7141 /* do job control only in root shell */
7143 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7146 if (jp->nprocs == 0)
7149 pgrp = jp->ps[0].pid;
7150 /* This can fail because we are doing it in the parent also */
7151 (void)setpgid(0, pgrp);
7152 if (mode == FORK_FG)
7153 xtcsetpgrp(ttyfd, pgrp);
7158 if (mode == FORK_BG) {
7161 if (jp->nprocs == 0) {
7163 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7164 error("Can't open %s", _PATH_DEVNULL);
7167 if (wasroot && iflag) {
7172 for (jp = curjob; jp; jp = jp->prev_job)
7178 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7180 TRACE(("In parent shell: child = %d\n", pid));
7182 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7187 if (mode != FORK_NOJOB && jp->jobctl) {
7190 if (jp->nprocs == 0)
7193 pgrp = jp->ps[0].pid;
7194 /* This can fail because we are doing it in the child also */
7195 (void)setpgid(pid, pgrp);
7198 if (mode == FORK_BG) {
7199 backgndpid = pid; /* set $! */
7200 set_curjob(jp, CUR_RUNNING);
7203 struct procstat *ps = &jp->ps[jp->nprocs++];
7209 ps->cmd = commandtext(n);
7215 forkshell(struct job *jp, union node *n, int mode)
7219 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7222 TRACE(("Fork failed, errno=%d", errno));
7225 error("Cannot fork");
7228 forkchild(jp, n, mode);
7230 forkparent(jp, n, mode, pid);
7235 * Wait for job to finish.
7237 * Under job control we have the problem that while a child process is
7238 * running interrupts generated by the user are sent to the child but not
7239 * to the shell. This means that an infinite loop started by an inter-
7240 * active user may be hard to kill. With job control turned off, an
7241 * interactive user may place an interactive program inside a loop. If
7242 * the interactive program catches interrupts, the user doesn't want
7243 * these interrupts to also abort the loop. The approach we take here
7244 * is to have the shell ignore interrupt signals while waiting for a
7245 * foreground process to terminate, and then send itself an interrupt
7246 * signal if the child process was terminated by an interrupt signal.
7247 * Unfortunately, some programs want to do a bit of cleanup and then
7248 * exit on interrupt; unless these processes terminate themselves by
7249 * sending a signal to themselves (instead of calling exit) they will
7250 * confuse this approach.
7252 * Called with interrupts off.
7256 waitforjob(struct job *jp)
7260 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7261 while (jp->state == JOBRUNNING) {
7262 dowait(DOWAIT_BLOCK, jp);
7267 xtcsetpgrp(ttyfd, rootpid);
7269 * This is truly gross.
7270 * If we're doing job control, then we did a TIOCSPGRP which
7271 * caused us (the shell) to no longer be in the controlling
7272 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7273 * intuit from the subprocess exit status whether a SIGINT
7274 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7279 if (jp->state == JOBDONE)
7287 * Do a wait system call. If job control is compiled in, we accept
7288 * stopped processes. If block is zero, we return a value of zero
7289 * rather than blocking.
7291 * System V doesn't have a non-blocking wait system call. It does
7292 * have a SIGCLD signal that is sent to a process when one of it's
7293 * children dies. The obvious way to use SIGCLD would be to install
7294 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7295 * was received, and have waitproc bump another counter when it got
7296 * the status of a process. Waitproc would then know that a wait
7297 * system call would not block if the two counters were different.
7298 * This approach doesn't work because if a process has children that
7299 * have not been waited for, System V will send it a SIGCLD when it
7300 * installs a signal handler for SIGCLD. What this means is that when
7301 * a child exits, the shell will be sent SIGCLD signals continuously
7302 * until is runs out of stack space, unless it does a wait call before
7303 * restoring the signal handler. The code below takes advantage of
7304 * this (mis)feature by installing a signal handler for SIGCLD and
7305 * then checking to see whether it was called. If there are any
7306 * children to be waited for, it will be.
7308 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7309 * waits at all. In this case, the user will not be informed when
7310 * a background process until the next time she runs a real program
7311 * (as opposed to running a builtin command or just typing return),
7312 * and the jobs command may give out of date information.
7316 waitproc(int block, int *status)
7326 return wait3(status, flags, (struct rusage *)NULL);
7330 * Wait for a process to terminate.
7334 dowait(int block, struct job *job)
7339 struct job *thisjob;
7342 TRACE(("dowait(%d) called\n", block));
7343 pid = waitproc(block, &status);
7344 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7349 for (jp = curjob; jp; jp = jp->prev_job) {
7350 struct procstat *sp;
7351 struct procstat *spend;
7352 if (jp->state == JOBDONE)
7355 spend = jp->ps + jp->nprocs;
7358 if (sp->pid == pid) {
7359 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7360 sp->status = status;
7363 if (sp->status == -1)
7366 if (state == JOBRUNNING)
7368 if (WIFSTOPPED(sp->status)) {
7369 jp->stopstatus = sp->status;
7373 } while (++sp < spend);
7378 if (!WIFSTOPPED(status))
7385 if (state != JOBRUNNING) {
7386 thisjob->changed = 1;
7388 if (thisjob->state != state) {
7389 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7390 thisjob->state = state;
7392 if (state == JOBSTOPPED) {
7393 set_curjob(thisjob, CUR_STOPPED);
7402 if (thisjob && thisjob == job) {
7406 len = sprint_status(s, status, 1);
7418 * return 1 if there are stopped jobs, otherwise 0
7431 if (jp && jp->state == JOBSTOPPED) {
7432 out2str("You have stopped jobs.\n");
7442 * Return a string identifying a command (to be printed by the
7447 static char *cmdnextc;
7450 commandtext(union node *n)
7454 STARTSTACKSTR(cmdnextc);
7456 name = stackblock();
7457 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7458 name, cmdnextc, cmdnextc));
7459 return savestr(name);
7463 cmdtxt(union node *n)
7466 struct nodelist *lp;
7478 lp = n->npipe.cmdlist;
7496 cmdtxt(n->nbinary.ch1);
7512 cmdtxt(n->nif.test);
7515 if (n->nif.elsepart) {
7518 n = n->nif.elsepart;
7534 cmdtxt(n->nbinary.ch1);
7544 cmdputs(n->nfor.var);
7546 cmdlist(n->nfor.args, 1);
7551 cmdputs(n->narg.text);
7555 cmdlist(n->ncmd.args, 1);
7556 cmdlist(n->ncmd.redirect, 0);
7569 cmdputs(n->ncase.expr->narg.text);
7571 for (np = n->ncase.cases; np; np = np->nclist.next) {
7572 cmdtxt(np->nclist.pattern);
7574 cmdtxt(np->nclist.body);
7600 s[0] = n->nfile.fd + '0';
7604 if (n->type == NTOFD || n->type == NFROMFD) {
7605 s[0] = n->ndup.dupfd + '0';
7616 cmdlist(union node *np, int sep)
7618 for (; np; np = np->narg.next) {
7622 if (sep && np->narg.next)
7628 cmdputs(const char *s)
7630 const char *p, *str;
7631 char c, cc[2] = " ";
7635 static const char *const vstype[16] = {
7636 nullstr, "}", "-", "+", "?", "=",
7637 "%", "%%", "#", "##", nullstr
7640 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7642 while ((c = *p++) != 0) {
7650 if ((subtype & VSTYPE) == VSLENGTH)
7654 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7672 case CTLBACKQ+CTLQUOTE:
7675 #ifdef CONFIG_ASH_MATH_SUPPORT
7690 str = vstype[subtype & VSTYPE];
7691 if (subtype & VSNUL)
7702 /* These can only happen inside quotes */
7714 while ((c = *str++)) {
7719 USTPUTC('"', nextc);
7727 showpipe(struct job *jp, FILE *out)
7729 struct procstat *sp;
7730 struct procstat *spend;
7732 spend = jp->ps + jp->nprocs;
7733 for (sp = jp->ps + 1; sp < spend; sp++)
7734 fprintf(out, " | %s", sp->cmd);
7735 outcslow('\n', out);
7740 xtcsetpgrp(int fd, pid_t pgrp)
7742 if (tcsetpgrp(fd, pgrp))
7743 error("Cannot set tty process group (%m)");
7748 getstatus(struct job *job) {
7752 status = job->ps[job->nprocs - 1].status;
7753 retval = WEXITSTATUS(status);
7754 if (!WIFEXITED(status)) {
7756 retval = WSTOPSIG(status);
7757 if (!WIFSTOPPED(status))
7760 /* XXX: limits number of signals */
7761 retval = WTERMSIG(status);
7763 if (retval == SIGINT)
7769 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7770 jobno(job), job->nprocs, status, retval));
7774 #ifdef CONFIG_ASH_MAIL
7775 /* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7778 * Routines to check for mail. (Perhaps make part of main.c?)
7781 #define MAXMBOXES 10
7783 /* times of mailboxes */
7784 static time_t mailtime[MAXMBOXES];
7785 /* Set if MAIL or MAILPATH is changed. */
7786 static int mail_var_path_changed;
7791 * Print appropriate message(s) if mail has arrived.
7792 * If mail_var_path_changed is set,
7793 * then the value of MAIL has mail_var_path_changed,
7794 * so we just update the values.
7804 struct stackmark smark;
7807 setstackmark(&smark);
7808 mpath = mpathset() ? mpathval() : mailval();
7809 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7810 p = padvance(&mpath, nullstr);
7815 for (q = p ; *q ; q++);
7820 q[-1] = '\0'; /* delete trailing '/' */
7821 if (stat(p, &statb) < 0) {
7825 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7828 pathopt ? pathopt : "you have mail"
7831 *mtp = statb.st_mtime;
7833 mail_var_path_changed = 0;
7834 popstackmark(&smark);
7839 changemail(const char *val)
7841 mail_var_path_changed++;
7844 #endif /* CONFIG_ASH_MAIL */
7846 /* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7850 static short profile_buf[16384];
7854 static int isloginsh;
7856 static void read_profile(const char *);
7859 * Main routine. We initialize things, parse the arguments, execute
7860 * profiles if we're a login shell, and then call cmdloop to execute
7861 * commands. The setjmp call sets up the location to jump to when an
7862 * exception occurs. When an exception occurs the variable "state"
7863 * is used to figure out how far we had gotten.
7867 ash_main(int argc, char **argv)
7871 struct jmploc jmploc;
7872 struct stackmark smark;
7875 dash_errno = __errno_location();
7879 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7882 if (setjmp(jmploc.loc)) {
7889 switch (exception) {
7899 status = exitstatus;
7902 exitstatus = status;
7904 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7908 outcslow('\n', stderr);
7910 popstackmark(&smark);
7911 FORCEINTON; /* enable interrupts */
7914 else if (state == 2)
7916 else if (state == 3)
7924 trputs("Shell args: "); trargs(argv);
7928 #ifdef CONFIG_ASH_RANDOM_SUPPORT
7929 rseed = rootpid + ((time_t)time((time_t *)0));
7933 setstackmark(&smark);
7934 procargs(argc, argv);
7935 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7937 const char *hp = lookupvar("HISTFILE");
7940 hp = lookupvar("HOME");
7942 char *defhp = concat_path_file(hp, ".ash_history");
7943 setvar("HISTFILE", defhp, 0);
7949 if (argv[0] && argv[0][0] == '-')
7953 read_profile("/etc/profile");
7956 read_profile(".profile");
7962 getuid() == geteuid() && getgid() == getegid() &&
7966 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7967 read_profile(shinit);
7975 if (sflag || minusc == NULL) {
7976 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7978 const char *hp = lookupvar("HISTFILE");
7981 load_history ( hp );
7984 state4: /* XXX ??? - why isn't this before the "if" statement */
7992 extern void _mcleanup(void);
8002 * Read and execute commands. "Top" is nonzero for the top level command
8003 * loop; it turns on prompting if the shell is interactive.
8010 struct stackmark smark;
8014 TRACE(("cmdloop(%d) called\n", top));
8016 setstackmark(&smark);
8021 showjobs(stderr, SHOW_CHANGED);
8026 #ifdef CONFIG_ASH_MAIL
8030 n = parsecmd(inter);
8031 /* showtree(n); DEBUG */
8033 if (!top || numeof >= 50)
8035 if (!stoppedjobs()) {
8038 out2str("\nUse \"exit\" to leave shell.\n");
8041 } else if (n != NULL && nflag == 0) {
8042 job_warning = (job_warning == 2) ? 1 : 0;
8046 popstackmark(&smark);
8056 * Read /etc/profile or .profile. Return on error.
8060 read_profile(const char *name)
8067 if ((fd = open(name, O_RDONLY)) >= 0)
8072 /* -q turns off -x and -v just when executing init files */
8075 xflag = 0, xflag_set = 1;
8077 vflag = 0, vflag_set = 1;
8091 * Read a file containing shell functions.
8095 readcmdfile(char *name)
8100 if ((fd = open(name, O_RDONLY)) >= 0)
8103 error("Can't open %s", name);
8111 * Take commands from a file. To be compatible we should do a path
8112 * search for the file, which is necessary to find sub-commands.
8115 static inline char *
8116 find_dot_file(char *name)
8119 const char *path = pathval();
8122 /* don't try this for absolute or relative paths */
8123 if (strchr(name, '/'))
8126 while ((fullname = padvance(&path, name)) != NULL) {
8127 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8129 * Don't bother freeing here, since it will
8130 * be freed by the caller.
8134 stunalloc(fullname);
8137 /* not found in the PATH */
8138 error(not_found_msg, name);
8142 static int dotcmd(int argc, char **argv)
8145 volatile struct shparam saveparam;
8149 for (sp = cmdenviron; sp; sp = sp->next)
8150 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8152 if (argc >= 2) { /* That's what SVR2 does */
8154 struct stackmark smark;
8156 setstackmark(&smark);
8157 fullname = find_dot_file(argv[1]);
8160 saveparam = shellparam;
8161 shellparam.malloc = 0;
8162 shellparam.nparam = argc - 2;
8163 shellparam.p = argv + 2;
8166 setinputfile(fullname, 1);
8167 commandname = fullname;
8172 freeparam(&shellparam);
8173 shellparam = saveparam;
8176 popstackmark(&smark);
8183 exitcmd(int argc, char **argv)
8188 exitstatus = number(argv[1]);
8193 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8196 * Same for malloc, realloc, but returns an error when out of space.
8200 ckrealloc(pointer p, size_t nbytes)
8202 p = realloc(p, nbytes);
8204 error(bb_msg_memory_exhausted);
8209 ckmalloc(size_t nbytes)
8211 return ckrealloc(NULL, nbytes);
8215 * Make a copy of a string in safe storage.
8219 savestr(const char *s)
8221 char *p = strdup(s);
8223 error(bb_msg_memory_exhausted);
8229 * Parse trees for commands are allocated in lifo order, so we use a stack
8230 * to make this more efficient, and also to avoid all sorts of exception
8231 * handling code to handle interrupts in the middle of a parse.
8233 * The size 504 was chosen because the Ultrix malloc handles that size
8239 stalloc(size_t nbytes)
8244 aligned = SHELL_ALIGN(nbytes);
8245 if (aligned > stacknleft) {
8248 struct stack_block *sp;
8250 blocksize = aligned;
8251 if (blocksize < MINSIZE)
8252 blocksize = MINSIZE;
8253 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8254 if (len < blocksize)
8255 error(bb_msg_memory_exhausted);
8259 stacknxt = sp->space;
8260 stacknleft = blocksize;
8261 sstrend = stacknxt + blocksize;
8266 stacknxt += aligned;
8267 stacknleft -= aligned;
8273 stunalloc(pointer p)
8276 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8277 write(2, "stunalloc\n", 10);
8281 stacknleft += stacknxt - (char *)p;
8287 setstackmark(struct stackmark *mark)
8289 mark->stackp = stackp;
8290 mark->stacknxt = stacknxt;
8291 mark->stacknleft = stacknleft;
8292 mark->marknext = markp;
8298 popstackmark(struct stackmark *mark)
8300 struct stack_block *sp;
8303 markp = mark->marknext;
8304 while (stackp != mark->stackp) {
8309 stacknxt = mark->stacknxt;
8310 stacknleft = mark->stacknleft;
8311 sstrend = mark->stacknxt + mark->stacknleft;
8317 * When the parser reads in a string, it wants to stick the string on the
8318 * stack and only adjust the stack pointer when it knows how big the
8319 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8320 * of space on top of the stack and stackblocklen returns the length of
8321 * this block. Growstackblock will grow this space by at least one byte,
8322 * possibly moving it (like realloc). Grabstackblock actually allocates the
8323 * part of the block that has been used.
8327 growstackblock(void)
8331 newlen = stacknleft * 2;
8332 if (newlen < stacknleft)
8333 error(bb_msg_memory_exhausted);
8337 if (stacknxt == stackp->space && stackp != &stackbase) {
8338 struct stack_block *oldstackp;
8339 struct stackmark *xmark;
8340 struct stack_block *sp;
8341 struct stack_block *prevstackp;
8347 prevstackp = sp->prev;
8348 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8349 sp = ckrealloc((pointer)sp, grosslen);
8350 sp->prev = prevstackp;
8352 stacknxt = sp->space;
8353 stacknleft = newlen;
8354 sstrend = sp->space + newlen;
8357 * Stack marks pointing to the start of the old block
8358 * must be relocated to point to the new block
8361 while (xmark != NULL && xmark->stackp == oldstackp) {
8362 xmark->stackp = stackp;
8363 xmark->stacknxt = stacknxt;
8364 xmark->stacknleft = stacknleft;
8365 xmark = xmark->marknext;
8369 char *oldspace = stacknxt;
8370 int oldlen = stacknleft;
8371 char *p = stalloc(newlen);
8373 /* free the space we just allocated */
8374 stacknxt = memcpy(p, oldspace, oldlen);
8375 stacknleft += newlen;
8380 grabstackblock(size_t len)
8382 len = SHELL_ALIGN(len);
8388 * The following routines are somewhat easier to use than the above.
8389 * The user declares a variable of type STACKSTR, which may be declared
8390 * to be a register. The macro STARTSTACKSTR initializes things. Then
8391 * the user uses the macro STPUTC to add characters to the string. In
8392 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8393 * grown as necessary. When the user is done, she can just leave the
8394 * string there and refer to it using stackblock(). Or she can allocate
8395 * the space for it using grabstackstr(). If it is necessary to allow
8396 * someone else to use the stack temporarily and then continue to grow
8397 * the string, the user should use grabstack to allocate the space, and
8398 * then call ungrabstr(p) to return to the previous mode of operation.
8400 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8401 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8402 * is space for at least one character.
8408 size_t len = stackblocksize();
8409 if (herefd >= 0 && len >= 1024) {
8410 bb_full_write(herefd, stackblock(), len);
8411 return stackblock();
8414 return stackblock() + len;
8418 * Called from CHECKSTRSPACE.
8422 makestrspace(size_t newlen, char *p)
8424 size_t len = p - stacknxt;
8425 size_t size = stackblocksize();
8430 size = stackblocksize();
8432 if (nleft >= newlen)
8436 return stackblock() + len;
8440 stnputs(const char *s, size_t n, char *p)
8442 p = makestrspace(n, p);
8443 p = mempcpy(p, s, n);
8448 stputs(const char *s, char *p)
8450 return stnputs(s, strlen(s), p);
8453 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8458 * number(s) Convert a string of digits to an integer.
8459 * is_number(s) Return true if s is a string of digits.
8463 * prefix -- see if pfx is a prefix of string.
8467 prefix(const char *string, const char *pfx)
8470 if (*pfx++ != *string++)
8473 return (char *) string;
8478 * Convert a string of digits to an integer, printing an error message on
8483 number(const char *s)
8493 * Check for a valid number. This should be elsewhere.
8497 is_number(const char *p)
8502 } while (*++p != '\0');
8508 * Produce a possibly single quoted string suitable as input to the shell.
8509 * The return string is allocated on the stack.
8513 single_quote(const char *s) {
8522 len = strchrnul(s, '\'') - s;
8524 q = p = makestrspace(len + 3, p);
8527 q = mempcpy(q, s, len);
8533 len = strspn(s, "'");
8537 q = p = makestrspace(len + 3, p);
8540 q = mempcpy(q, s, len);
8549 return stackblock();
8553 * Like strdup but works with the ash stack.
8557 sstrdup(const char *p)
8559 size_t len = strlen(p) + 1;
8560 return memcpy(stalloc(len), p, len);
8565 calcsize(union node *n)
8569 funcblocksize += nodesize[n->type];
8572 calcsize(n->ncmd.redirect);
8573 calcsize(n->ncmd.args);
8574 calcsize(n->ncmd.assign);
8577 sizenodelist(n->npipe.cmdlist);
8582 calcsize(n->nredir.redirect);
8583 calcsize(n->nredir.n);
8590 calcsize(n->nbinary.ch2);
8591 calcsize(n->nbinary.ch1);
8594 calcsize(n->nif.elsepart);
8595 calcsize(n->nif.ifpart);
8596 calcsize(n->nif.test);
8599 funcstringsize += strlen(n->nfor.var) + 1;
8600 calcsize(n->nfor.body);
8601 calcsize(n->nfor.args);
8604 calcsize(n->ncase.cases);
8605 calcsize(n->ncase.expr);
8608 calcsize(n->nclist.body);
8609 calcsize(n->nclist.pattern);
8610 calcsize(n->nclist.next);
8614 sizenodelist(n->narg.backquote);
8615 funcstringsize += strlen(n->narg.text) + 1;
8616 calcsize(n->narg.next);
8623 calcsize(n->nfile.fname);
8624 calcsize(n->nfile.next);
8628 calcsize(n->ndup.vname);
8629 calcsize(n->ndup.next);
8633 calcsize(n->nhere.doc);
8634 calcsize(n->nhere.next);
8637 calcsize(n->nnot.com);
8644 sizenodelist(struct nodelist *lp)
8647 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8655 copynode(union node *n)
8662 funcblock = (char *) funcblock + nodesize[n->type];
8665 new->ncmd.redirect = copynode(n->ncmd.redirect);
8666 new->ncmd.args = copynode(n->ncmd.args);
8667 new->ncmd.assign = copynode(n->ncmd.assign);
8670 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8671 new->npipe.backgnd = n->npipe.backgnd;
8676 new->nredir.redirect = copynode(n->nredir.redirect);
8677 new->nredir.n = copynode(n->nredir.n);
8684 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8685 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8688 new->nif.elsepart = copynode(n->nif.elsepart);
8689 new->nif.ifpart = copynode(n->nif.ifpart);
8690 new->nif.test = copynode(n->nif.test);
8693 new->nfor.var = nodesavestr(n->nfor.var);
8694 new->nfor.body = copynode(n->nfor.body);
8695 new->nfor.args = copynode(n->nfor.args);
8698 new->ncase.cases = copynode(n->ncase.cases);
8699 new->ncase.expr = copynode(n->ncase.expr);
8702 new->nclist.body = copynode(n->nclist.body);
8703 new->nclist.pattern = copynode(n->nclist.pattern);
8704 new->nclist.next = copynode(n->nclist.next);
8708 new->narg.backquote = copynodelist(n->narg.backquote);
8709 new->narg.text = nodesavestr(n->narg.text);
8710 new->narg.next = copynode(n->narg.next);
8717 new->nfile.fname = copynode(n->nfile.fname);
8718 new->nfile.fd = n->nfile.fd;
8719 new->nfile.next = copynode(n->nfile.next);
8723 new->ndup.vname = copynode(n->ndup.vname);
8724 new->ndup.dupfd = n->ndup.dupfd;
8725 new->ndup.fd = n->ndup.fd;
8726 new->ndup.next = copynode(n->ndup.next);
8730 new->nhere.doc = copynode(n->nhere.doc);
8731 new->nhere.fd = n->nhere.fd;
8732 new->nhere.next = copynode(n->nhere.next);
8735 new->nnot.com = copynode(n->nnot.com);
8738 new->type = n->type;
8743 static struct nodelist *
8744 copynodelist(struct nodelist *lp)
8746 struct nodelist *start;
8747 struct nodelist **lpp;
8752 funcblock = (char *) funcblock +
8753 SHELL_ALIGN(sizeof(struct nodelist));
8754 (*lpp)->n = copynode(lp->n);
8756 lpp = &(*lpp)->next;
8764 nodesavestr(char *s)
8766 char *rtn = funcstring;
8768 funcstring = stpcpy(funcstring, s) + 1;
8774 * Free a parse tree.
8778 freefunc(struct funcnode *f)
8780 if (f && --f->count < 0)
8785 static void options(int);
8786 static void setoption(int, int);
8790 * Process the shell command line arguments.
8794 procargs(int argc, char **argv)
8797 const char *xminusc;
8804 for (i = 0; i < NOPTS; i++)
8810 if (*xargv == NULL) {
8812 error("-c requires an argument");
8815 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8819 for (i = 0; i < NOPTS; i++)
8820 if (optlist[i] == 2)
8825 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8830 } else if (!sflag) {
8831 setinputfile(*xargv, 0);
8837 shellparam.p = xargv;
8838 #ifdef CONFIG_ASH_GETOPTS
8839 shellparam.optind = 1;
8840 shellparam.optoff = -1;
8842 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8844 shellparam.nparam++;
8857 setinteractive(iflag);
8862 minus_o(char *name, int val)
8867 out1str("Current option settings\n");
8868 for (i = 0; i < NOPTS; i++)
8869 out1fmt("%-16s%s\n", optnames(i),
8870 optlist[i] ? "on" : "off");
8872 for (i = 0; i < NOPTS; i++)
8873 if (equal(name, optnames(i))) {
8877 error("Illegal option -o %s", name);
8882 * Process shell options. The global variable argptr contains a pointer
8883 * to the argument list; we advance it past the options.
8887 options(int cmdline)
8895 while ((p = *argptr) != NULL) {
8897 if ((c = *p++) == '-') {
8899 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8901 /* "-" means turn off -x and -v */
8904 /* "--" means reset params */
8905 else if (*argptr == NULL)
8908 break; /* "-" or "--" terminates options */
8910 } else if (c == '+') {
8916 while ((c = *p++) != '\0') {
8917 if (c == 'c' && cmdline) {
8918 minusc = p; /* command is after shell args*/
8919 } else if (c == 'o') {
8920 minus_o(*argptr, val);
8923 } else if (cmdline && (c == '-')) { // long options
8924 if (strcmp(p, "login") == 0)
8936 setoption(int flag, int val)
8940 for (i = 0; i < NOPTS; i++)
8941 if (optletters(i) == flag) {
8945 error("Illegal option -%c", flag);
8952 * Set the shell parameters.
8956 setparam(char **argv)
8962 for (nparam = 0 ; argv[nparam] ; nparam++);
8963 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8965 *ap++ = savestr(*argv++);
8968 freeparam(&shellparam);
8969 shellparam.malloc = 1;
8970 shellparam.nparam = nparam;
8971 shellparam.p = newparam;
8972 #ifdef CONFIG_ASH_GETOPTS
8973 shellparam.optind = 1;
8974 shellparam.optoff = -1;
8980 * Free the list of positional parameters.
8984 freeparam(volatile struct shparam *param)
8988 if (param->malloc) {
8989 for (ap = param->p ; *ap ; ap++)
8998 * The shift builtin command.
9002 shiftcmd(int argc, char **argv)
9009 n = number(argv[1]);
9010 if (n > shellparam.nparam)
9011 error("can't shift that many");
9013 shellparam.nparam -= n;
9014 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9015 if (shellparam.malloc)
9019 while ((*ap2++ = *ap1++) != NULL);
9020 #ifdef CONFIG_ASH_GETOPTS
9021 shellparam.optind = 1;
9022 shellparam.optoff = -1;
9031 * The set command builtin.
9035 setcmd(int argc, char **argv)
9038 return showvars(nullstr, 0, VUNSET);
9042 if (*argptr != NULL) {
9050 #ifdef CONFIG_ASH_GETOPTS
9055 shellparam.optind = number(value);
9056 shellparam.optoff = -1;
9060 #ifdef CONFIG_LOCALE_SUPPORT
9061 static void change_lc_all(const char *value)
9063 if (value != 0 && *value != 0)
9064 setlocale(LC_ALL, value);
9067 static void change_lc_ctype(const char *value)
9069 if (value != 0 && *value != 0)
9070 setlocale(LC_CTYPE, value);
9075 #ifdef CONFIG_ASH_RANDOM_SUPPORT
9076 /* Roughly copied from bash.. */
9077 static void change_random(const char *value)
9080 /* "get", generate */
9083 rseed = rseed * 1103515245 + 12345;
9084 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9085 /* set without recursion */
9086 setvar(vrandom.text, buf, VNOFUNC);
9087 vrandom.flags &= ~VNOFUNC;
9090 rseed = strtoul(value, (char **)NULL, 10);
9096 #ifdef CONFIG_ASH_GETOPTS
9098 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9107 if(*param_optind < 1)
9109 optnext = optfirst + *param_optind - 1;
9111 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9114 p = optnext[-1] + *optoff;
9115 if (p == NULL || *p == '\0') {
9116 /* Current word is done, advance */
9118 if (p == NULL || *p != '-' || *++p == '\0') {
9125 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9130 for (q = optstr; *q != c; ) {
9132 if (optstr[0] == ':') {
9135 err |= setvarsafe("OPTARG", s, 0);
9137 fprintf(stderr, "Illegal option -%c\n", c);
9138 (void) unsetvar("OPTARG");
9148 if (*p == '\0' && (p = *optnext) == NULL) {
9149 if (optstr[0] == ':') {
9152 err |= setvarsafe("OPTARG", s, 0);
9155 fprintf(stderr, "No arg for -%c option\n", c);
9156 (void) unsetvar("OPTARG");
9164 err |= setvarsafe("OPTARG", p, 0);
9167 err |= setvarsafe("OPTARG", nullstr, 0);
9170 *optoff = p ? p - *(optnext - 1) : -1;
9171 *param_optind = optnext - optfirst + 1;
9172 fmtstr(s, sizeof(s), "%d", *param_optind);
9173 err |= setvarsafe("OPTIND", s, VNOFUNC);
9176 err |= setvarsafe(optvar, s, 0);
9187 * The getopts builtin. Shellparam.optnext points to the next argument
9188 * to be processed. Shellparam.optptr points to the next character to
9189 * be processed in the current argument. If shellparam.optnext is NULL,
9190 * then it's the first time getopts has been called.
9194 getoptscmd(int argc, char **argv)
9199 error("Usage: getopts optstring var [arg]");
9200 else if (argc == 3) {
9201 optbase = shellparam.p;
9202 if (shellparam.optind > shellparam.nparam + 1) {
9203 shellparam.optind = 1;
9204 shellparam.optoff = -1;
9209 if (shellparam.optind > argc - 2) {
9210 shellparam.optind = 1;
9211 shellparam.optoff = -1;
9215 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9216 &shellparam.optoff);
9218 #endif /* CONFIG_ASH_GETOPTS */
9221 * XXX - should get rid of. have all builtins use getopt(3). the
9222 * library getopt must have the BSD extension static variable "optreset"
9223 * otherwise it can't be used within the shell safely.
9225 * Standard option processing (a la getopt) for builtin routines. The
9226 * only argument that is passed to nextopt is the option string; the
9227 * other arguments are unnecessary. It return the character, or '\0' on
9232 nextopt(const char *optstring)
9238 if ((p = optptr) == NULL || *p == '\0') {
9240 if (p == NULL || *p != '-' || *++p == '\0')
9243 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9247 for (q = optstring ; *q != c ; ) {
9249 error("Illegal option -%c", c);
9254 if (*p == '\0' && (p = *argptr++) == NULL)
9255 error("No arg for -%c option", c);
9264 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9267 outstr(const char *p, FILE *file)
9292 outcslow(int c, FILE *dest)
9302 out1fmt(const char *fmt, ...)
9309 r = vprintf(fmt, ap);
9317 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9324 ret = vsnprintf(outbuf, length, fmt, ap);
9332 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9336 * Shell command parser.
9339 #define EOFMARKLEN 79
9343 struct heredoc *next; /* next here document in list */
9344 union node *here; /* redirection node */
9345 char *eofmark; /* string indicating end of input */
9346 int striptabs; /* if set, strip leading tabs */
9351 static struct heredoc *heredoclist; /* list of here documents to read */
9354 static union node *list(int);
9355 static union node *andor(void);
9356 static union node *pipeline(void);
9357 static union node *command(void);
9358 static union node *simplecmd(void);
9359 static union node *makename(void);
9360 static void parsefname(void);
9361 static void parseheredoc(void);
9362 static char peektoken(void);
9363 static int readtoken(void);
9364 static int xxreadtoken(void);
9365 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9366 static int noexpand(char *);
9367 static void synexpect(int) __attribute__((__noreturn__));
9368 static void synerror(const char *) __attribute__((__noreturn__));
9369 static void setprompt(int);
9374 isassignment(const char *p)
9376 const char *q = endofname(p);
9384 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9385 * valid parse tree indicating a blank line.)
9389 parsecmd(int interact)
9394 doprompt = interact;
9396 setprompt(doprompt);
9411 union node *n1, *n2, *n3;
9414 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9415 if (nlflag == 2 && peektoken())
9421 if (tok == TBACKGND) {
9422 if (n2->type == NPIPE) {
9423 n2->npipe.backgnd = 1;
9425 if (n2->type != NREDIR) {
9426 n3 = stalloc(sizeof(struct nredir));
9428 n3->nredir.redirect = NULL;
9431 n2->type = NBACKGND;
9438 n3 = (union node *)stalloc(sizeof (struct nbinary));
9440 n3->nbinary.ch1 = n1;
9441 n3->nbinary.ch2 = n2;
9457 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9465 pungetc(); /* push back EOF on input */
9481 union node *n1, *n2, *n3;
9486 if ((t = readtoken()) == TAND) {
9488 } else if (t == TOR) {
9494 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9496 n3 = (union node *)stalloc(sizeof (struct nbinary));
9498 n3->nbinary.ch1 = n1;
9499 n3->nbinary.ch2 = n2;
9509 union node *n1, *n2, *pipenode;
9510 struct nodelist *lp, *prev;
9514 TRACE(("pipeline: entered\n"));
9515 if (readtoken() == TNOT) {
9517 checkkwd = CHKKWD | CHKALIAS;
9521 if (readtoken() == TPIPE) {
9522 pipenode = (union node *)stalloc(sizeof (struct npipe));
9523 pipenode->type = NPIPE;
9524 pipenode->npipe.backgnd = 0;
9525 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9526 pipenode->npipe.cmdlist = lp;
9530 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9531 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9534 } while (readtoken() == TPIPE);
9540 n2 = (union node *)stalloc(sizeof (struct nnot));
9553 union node *n1, *n2;
9554 union node *ap, **app;
9555 union node *cp, **cpp;
9556 union node *redir, **rpp;
9563 switch (readtoken()) {
9568 n1 = (union node *)stalloc(sizeof (struct nif));
9570 n1->nif.test = list(0);
9571 if (readtoken() != TTHEN)
9573 n1->nif.ifpart = list(0);
9575 while (readtoken() == TELIF) {
9576 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9577 n2 = n2->nif.elsepart;
9579 n2->nif.test = list(0);
9580 if (readtoken() != TTHEN)
9582 n2->nif.ifpart = list(0);
9584 if (lasttoken == TELSE)
9585 n2->nif.elsepart = list(0);
9587 n2->nif.elsepart = NULL;
9595 n1 = (union node *)stalloc(sizeof (struct nbinary));
9596 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9597 n1->nbinary.ch1 = list(0);
9598 if ((got=readtoken()) != TDO) {
9599 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9602 n1->nbinary.ch2 = list(0);
9607 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9608 synerror("Bad for loop variable");
9609 n1 = (union node *)stalloc(sizeof (struct nfor));
9611 n1->nfor.var = wordtext;
9612 checkkwd = CHKKWD | CHKALIAS;
9613 if (readtoken() == TIN) {
9615 while (readtoken() == TWORD) {
9616 n2 = (union node *)stalloc(sizeof (struct narg));
9618 n2->narg.text = wordtext;
9619 n2->narg.backquote = backquotelist;
9621 app = &n2->narg.next;
9625 if (lasttoken != TNL && lasttoken != TSEMI)
9628 n2 = (union node *)stalloc(sizeof (struct narg));
9630 n2->narg.text = (char *)dolatstr;
9631 n2->narg.backquote = NULL;
9632 n2->narg.next = NULL;
9635 * Newline or semicolon here is optional (but note
9636 * that the original Bourne shell only allowed NL).
9638 if (lasttoken != TNL && lasttoken != TSEMI)
9641 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9642 if (readtoken() != TDO)
9644 n1->nfor.body = list(0);
9648 n1 = (union node *)stalloc(sizeof (struct ncase));
9650 if (readtoken() != TWORD)
9652 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9654 n2->narg.text = wordtext;
9655 n2->narg.backquote = backquotelist;
9656 n2->narg.next = NULL;
9658 checkkwd = CHKKWD | CHKALIAS;
9659 } while (readtoken() == TNL);
9660 if (lasttoken != TIN)
9662 cpp = &n1->ncase.cases;
9664 checkkwd = CHKNL | CHKKWD;
9667 if (lasttoken == TLP)
9669 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9671 app = &cp->nclist.pattern;
9673 *app = ap = (union node *)stalloc(sizeof (struct narg));
9675 ap->narg.text = wordtext;
9676 ap->narg.backquote = backquotelist;
9677 if (readtoken() != TPIPE)
9679 app = &ap->narg.next;
9682 ap->narg.next = NULL;
9683 if (lasttoken != TRP)
9685 cp->nclist.body = list(2);
9687 cpp = &cp->nclist.next;
9689 checkkwd = CHKNL | CHKKWD;
9690 if ((t = readtoken()) != TESAC) {
9692 synexpect(TENDCASE);
9700 n1 = (union node *)stalloc(sizeof (struct nredir));
9701 n1->type = NSUBSHELL;
9702 n1->nredir.n = list(0);
9703 n1->nredir.redirect = NULL;
9716 if (readtoken() != t)
9720 /* Now check for redirection which may follow command */
9721 checkkwd = CHKKWD | CHKALIAS;
9723 while (readtoken() == TREDIR) {
9724 *rpp = n2 = redirnode;
9725 rpp = &n2->nfile.next;
9731 if (n1->type != NSUBSHELL) {
9732 n2 = (union node *)stalloc(sizeof (struct nredir));
9737 n1->nredir.redirect = redir;
9746 union node *args, **app;
9747 union node *n = NULL;
9748 union node *vars, **vpp;
9749 union node **rpp, *redir;
9759 savecheckkwd = CHKALIAS;
9761 checkkwd = savecheckkwd;
9762 switch (readtoken()) {
9764 n = (union node *)stalloc(sizeof (struct narg));
9766 n->narg.text = wordtext;
9767 n->narg.backquote = backquotelist;
9768 if (savecheckkwd && isassignment(wordtext)) {
9770 vpp = &n->narg.next;
9773 app = &n->narg.next;
9778 *rpp = n = redirnode;
9779 rpp = &n->nfile.next;
9780 parsefname(); /* read name of redirection file */
9784 args && app == &args->narg.next &&
9787 struct builtincmd *bcmd;
9790 /* We have a function */
9791 if (readtoken() != TRP)
9793 name = n->narg.text;
9795 !goodname(name) || (
9796 (bcmd = find_builtin(name)) &&
9797 IS_BUILTIN_SPECIAL(bcmd)
9800 synerror("Bad function name");
9802 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9803 n->narg.next = command();
9816 n = (union node *)stalloc(sizeof (struct ncmd));
9818 n->ncmd.args = args;
9819 n->ncmd.assign = vars;
9820 n->ncmd.redirect = redir;
9829 n = (union node *)stalloc(sizeof (struct narg));
9831 n->narg.next = NULL;
9832 n->narg.text = wordtext;
9833 n->narg.backquote = backquotelist;
9837 void fixredir(union node *n, const char *text, int err)
9839 TRACE(("Fix redir %s %d\n", text, err));
9841 n->ndup.vname = NULL;
9843 if (is_digit(text[0]) && text[1] == '\0')
9844 n->ndup.dupfd = digit_val(text[0]);
9845 else if (text[0] == '-' && text[1] == '\0')
9850 synerror("Bad fd number");
9852 n->ndup.vname = makename();
9860 union node *n = redirnode;
9862 if (readtoken() != TWORD)
9864 if (n->type == NHERE) {
9865 struct heredoc *here = heredoc;
9871 TRACE(("Here document %d\n", n->type));
9872 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9873 synerror("Illegal eof marker for << redirection");
9874 rmescapes(wordtext);
9875 here->eofmark = wordtext;
9877 if (heredoclist == NULL)
9880 for (p = heredoclist ; p->next ; p = p->next);
9883 } else if (n->type == NTOFD || n->type == NFROMFD) {
9884 fixredir(n, wordtext, 0);
9886 n->nfile.fname = makename();
9892 * Input any here documents.
9898 struct heredoc *here;
9909 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9910 here->eofmark, here->striptabs);
9911 n = (union node *)stalloc(sizeof (struct narg));
9912 n->narg.type = NARG;
9913 n->narg.next = NULL;
9914 n->narg.text = wordtext;
9915 n->narg.backquote = backquotelist;
9916 here->here->nhere.doc = n;
9921 static char peektoken(void)
9927 return tokname_array[t][0];
9935 int alreadyseen = tokpushback;
9938 #ifdef CONFIG_ASH_ALIAS
9947 if (checkkwd & CHKNL) {
9954 if (t != TWORD || quoteflag) {
9959 * check for keywords
9961 if (checkkwd & CHKKWD) {
9962 const char *const *pp;
9964 if ((pp = findkwd(wordtext))) {
9965 lasttoken = t = pp - tokname_array;
9966 TRACE(("keyword %s recognized\n", tokname(t)));
9971 if (checkkwd & CHKALIAS) {
9972 #ifdef CONFIG_ASH_ALIAS
9974 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9976 pushstring(ap->val, ap);
9986 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9988 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9995 * Read the next input token.
9996 * If the token is a word, we set backquotelist to the list of cmds in
9997 * backquotes. We set quoteflag to true if any part of the word was
9999 * If the token is TREDIR, then we set redirnode to a structure containing
10001 * In all cases, the variable startlinno is set to the number of the line
10002 * on which the token starts.
10004 * [Change comment: here documents and internal procedures]
10005 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10006 * word parsing code into a separate routine. In this case, readtoken
10007 * doesn't need to have any internal procedures, but parseword does.
10008 * We could also make parseoperator in essence the main routine, and
10009 * have parseword (readtoken1?) handle both words and redirection.]
10012 #define NEW_xxreadtoken
10013 #ifdef NEW_xxreadtoken
10015 /* singles must be first! */
10016 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10018 static const char xxreadtoken_tokens[] = {
10019 TNL, TLP, TRP, /* only single occurrence allowed */
10020 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10021 TEOF, /* corresponds to trailing nul */
10022 TAND, TOR, TENDCASE, /* if double occurrence */
10025 #define xxreadtoken_doubles \
10026 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10027 #define xxreadtoken_singles \
10028 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10030 static int xxreadtoken()
10042 startlinno = plinno;
10043 for (;;) { /* until token or start of word found */
10046 if ((c != ' ') && (c != '\t')
10047 #ifdef CONFIG_ASH_ALIAS
10052 while ((c = pgetc()) != '\n' && c != PEOF);
10054 } else if (c == '\\') {
10055 if (pgetc() != '\n') {
10059 startlinno = ++plinno;
10064 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10069 needprompt = doprompt;
10072 p = strchr(xxreadtoken_chars, c);
10075 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10078 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10079 if (pgetc() == *p) { /* double occurrence? */
10080 p += xxreadtoken_doubles + 1;
10087 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10095 #define RETURN(token) return lasttoken = token
10110 startlinno = plinno;
10111 for (;;) { /* until token or start of word found */
10114 case ' ': case '\t':
10115 #ifdef CONFIG_ASH_ALIAS
10120 while ((c = pgetc()) != '\n' && c != PEOF);
10124 if (pgetc() == '\n') {
10125 startlinno = ++plinno;
10134 needprompt = doprompt;
10139 if (pgetc() == '&')
10144 if (pgetc() == '|')
10149 if (pgetc() == ';')
10162 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10165 #endif /* NEW_xxreadtoken */
10169 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10170 * is not NULL, read a here document. In the latter case, eofmark is the
10171 * word which marks the end of the document and striptabs is true if
10172 * leading tabs should be stripped from the document. The argument firstc
10173 * is the first character of the input token or document.
10175 * Because C does not have internal subroutines, I have simulated them
10176 * using goto's to implement the subroutine linkage. The following macros
10177 * will run code that appears at the end of readtoken1.
10180 #define CHECKEND() {goto checkend; checkend_return:;}
10181 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10182 #define PARSESUB() {goto parsesub; parsesub_return:;}
10183 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10184 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10185 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10188 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10193 char line[EOFMARKLEN + 1];
10194 struct nodelist *bqlist;
10197 int varnest; /* levels of variables expansion */
10198 int arinest; /* levels of arithmetic expansion */
10199 int parenlevel; /* levels of parens in arithmetic */
10200 int dqvarnest; /* levels of variables expansion within double quotes */
10202 int prevsyntax; /* syntax before arithmetic */
10204 /* Avoid longjmp clobbering */
10210 (void) &parenlevel;
10213 (void) &prevsyntax;
10217 startlinno = plinno;
10219 if (syntax == DQSYNTAX)
10228 STARTSTACKSTR(out);
10229 loop: { /* for each line, until end of word */
10230 CHECKEND(); /* set c to PEOF if at end of here document */
10231 for (;;) { /* until end of line or end of word */
10232 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10233 switch(SIT(c, syntax)) {
10234 case CNL: /* '\n' */
10235 if (syntax == BASESYNTAX)
10236 goto endword; /* exit outer loop */
10242 goto loop; /* continue outer loop */
10247 if (eofmark == NULL || dblquote)
10248 USTPUTC(CTLESC, out);
10251 case CBACK: /* backslash */
10254 USTPUTC(CTLESC, out);
10255 USTPUTC('\\', out);
10257 } else if (c == '\n') {
10263 c != '\\' && c != '`' &&
10269 USTPUTC(CTLESC, out);
10270 USTPUTC('\\', out);
10272 if (SIT(c, SQSYNTAX) == CCTL)
10273 USTPUTC(CTLESC, out);
10281 if (eofmark == NULL) {
10282 USTPUTC(CTLQUOTEMARK, out);
10290 if (eofmark != NULL && arinest == 0 &&
10294 if (dqvarnest == 0) {
10295 syntax = BASESYNTAX;
10302 case CVAR: /* '$' */
10303 PARSESUB(); /* parse substitution */
10305 case CENDVAR: /* '}' */
10308 if (dqvarnest > 0) {
10311 USTPUTC(CTLENDVAR, out);
10316 #ifdef CONFIG_ASH_MATH_SUPPORT
10317 case CLP: /* '(' in arithmetic */
10321 case CRP: /* ')' in arithmetic */
10322 if (parenlevel > 0) {
10326 if (pgetc() == ')') {
10327 if (--arinest == 0) {
10328 USTPUTC(CTLENDARI, out);
10329 syntax = prevsyntax;
10330 if (syntax == DQSYNTAX)
10338 * unbalanced parens
10339 * (don't 2nd guess - no error)
10347 case CBQUOTE: /* '`' */
10351 goto endword; /* exit outer loop */
10356 goto endword; /* exit outer loop */
10357 #ifdef CONFIG_ASH_ALIAS
10367 #ifdef CONFIG_ASH_MATH_SUPPORT
10368 if (syntax == ARISYNTAX)
10369 synerror("Missing '))'");
10371 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10372 synerror("Unterminated quoted string");
10373 if (varnest != 0) {
10374 startlinno = plinno;
10376 synerror("Missing '}'");
10378 USTPUTC('\0', out);
10379 len = out - (char *)stackblock();
10380 out = stackblock();
10381 if (eofmark == NULL) {
10382 if ((c == '>' || c == '<')
10385 && (*out == '\0' || is_digit(*out))) {
10387 return lasttoken = TREDIR;
10392 quoteflag = quotef;
10393 backquotelist = bqlist;
10394 grabstackblock(len);
10396 return lasttoken = TWORD;
10397 /* end of readtoken routine */
10402 * Check to see whether we are at the end of the here document. When this
10403 * is called, c is set to the first character of the next input line. If
10404 * we are at the end of the here document, this routine sets the c to PEOF.
10409 #ifdef CONFIG_ASH_ALIAS
10415 while (c == '\t') {
10419 if (c == *eofmark) {
10420 if (pfgets(line, sizeof line) != NULL) {
10424 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10425 if (*p == '\n' && *q == '\0') {
10428 needprompt = doprompt;
10430 pushstring(line, NULL);
10435 goto checkend_return;
10440 * Parse a redirection operator. The variable "out" points to a string
10441 * specifying the fd to be redirected. The variable "c" contains the
10442 * first character of the redirection operator.
10449 np = (union node *)stalloc(sizeof (struct nfile));
10454 np->type = NAPPEND;
10456 np->type = NCLOBBER;
10463 } else { /* c == '<' */
10465 switch (c = pgetc()) {
10467 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10468 np = (union node *)stalloc(sizeof (struct nhere));
10472 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10473 heredoc->here = np;
10474 if ((c = pgetc()) == '-') {
10475 heredoc->striptabs = 1;
10477 heredoc->striptabs = 0;
10483 np->type = NFROMFD;
10487 np->type = NFROMTO;
10497 np->nfile.fd = digit_val(fd);
10499 goto parseredir_return;
10504 * Parse a substitution. At this point, we have read the dollar sign
10505 * and nothing else.
10513 static const char types[] = "}-+?=";
10517 c <= PEOA_OR_PEOF ||
10518 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10522 } else if (c == '(') { /* $(command) or $((arith)) */
10523 if (pgetc() == '(') {
10524 #ifdef CONFIG_ASH_MATH_SUPPORT
10527 synerror("We unsupport $((arith))");
10534 USTPUTC(CTLVAR, out);
10535 typeloc = out - (char *)stackblock();
10536 USTPUTC(VSNORMAL, out);
10537 subtype = VSNORMAL;
10541 if ((c = pgetc()) == '}')
10544 subtype = VSLENGTH;
10549 if (c > PEOA_OR_PEOF && is_name(c)) {
10553 } while (c > PEOA_OR_PEOF && is_in_name(c));
10554 } else if (is_digit(c)) {
10558 } while (is_digit(c));
10560 else if (is_special(c)) {
10565 badsub: synerror("Bad substitution");
10569 if (subtype == 0) {
10576 p = strchr(types, c);
10579 subtype = p - types + VSNORMAL;
10585 subtype = c == '#' ? VSTRIMLEFT :
10598 if (dblquote || arinest)
10600 *((char *)stackblock() + typeloc) = subtype | flags;
10601 if (subtype != VSNORMAL) {
10603 if (dblquote || arinest) {
10608 goto parsesub_return;
10613 * Called to parse command substitutions. Newstyle is set if the command
10614 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10615 * list of commands (passed by reference), and savelen is the number of
10616 * characters on the top of the stack which must be preserved.
10620 struct nodelist **nlpp;
10623 char *volatile str;
10624 struct jmploc jmploc;
10625 struct jmploc *volatile savehandler;
10629 (void) &saveprompt;
10632 savepbq = parsebackquote;
10633 if (setjmp(jmploc.loc)) {
10636 parsebackquote = 0;
10637 handler = savehandler;
10638 longjmp(handler->loc, 1);
10642 savelen = out - (char *)stackblock();
10644 str = ckmalloc(savelen);
10645 memcpy(str, stackblock(), savelen);
10647 savehandler = handler;
10651 /* We must read until the closing backquote, giving special
10652 treatment to some slashes, and then push the string and
10653 reread it as input, interpreting it normally. */
10660 STARTSTACKSTR(pout);
10666 switch (pc = pgetc()) {
10671 if ((pc = pgetc()) == '\n') {
10676 * If eating a newline, avoid putting
10677 * the newline into the new character
10678 * stream (via the STPUTC after the
10683 if (pc != '\\' && pc != '`' && pc != '$'
10684 && (!dblquote || pc != '"'))
10685 STPUTC('\\', pout);
10686 if (pc > PEOA_OR_PEOF) {
10692 #ifdef CONFIG_ASH_ALIAS
10695 startlinno = plinno;
10696 synerror("EOF in backquote substitution");
10700 needprompt = doprompt;
10709 STPUTC('\0', pout);
10710 psavelen = pout - (char *)stackblock();
10711 if (psavelen > 0) {
10712 pstr = grabstackstr(pout);
10713 setinputstring(pstr);
10718 nlpp = &(*nlpp)->next;
10719 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10720 (*nlpp)->next = NULL;
10721 parsebackquote = oldstyle;
10724 saveprompt = doprompt;
10731 doprompt = saveprompt;
10733 if (readtoken() != TRP)
10740 * Start reading from old file again, ignoring any pushed back
10741 * tokens left from the backquote parsing
10746 while (stackblocksize() <= savelen)
10748 STARTSTACKSTR(out);
10750 memcpy(out, str, savelen);
10751 STADJUST(savelen, out);
10757 parsebackquote = savepbq;
10758 handler = savehandler;
10759 if (arinest || dblquote)
10760 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10762 USTPUTC(CTLBACKQ, out);
10764 goto parsebackq_oldreturn;
10766 goto parsebackq_newreturn;
10769 #ifdef CONFIG_ASH_MATH_SUPPORT
10771 * Parse an arithmetic expansion (indicate start of one and set state)
10775 if (++arinest == 1) {
10776 prevsyntax = syntax;
10777 syntax = ARISYNTAX;
10778 USTPUTC(CTLARI, out);
10785 * we collapse embedded arithmetic expansion to
10786 * parenthesis, which should be equivalent
10790 goto parsearith_return;
10794 } /* end of readtoken */
10799 * Returns true if the text contains nothing to expand (no dollar signs
10804 noexpand(char *text)
10810 while ((c = *p++) != '\0') {
10811 if (c == CTLQUOTEMARK)
10815 else if (SIT(c, BASESYNTAX) == CCTL)
10823 * Return of a legal variable name (a letter or underscore followed by zero or
10824 * more letters, underscores, and digits).
10828 endofname(const char *name)
10836 if (! is_in_name(*p))
10844 * Called when an unexpected token is read during the parse. The argument
10845 * is the token that is expected, or -1 if more than one type of token can
10846 * occur at this point.
10849 static void synexpect(int token)
10854 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10856 sprintf(msg + l, " (expecting %s)", tokname(token));
10862 synerror(const char *msg)
10864 error("Syntax error: %s", msg);
10870 * called by editline -- any expansions to the prompt
10871 * should be added here.
10874 static void setprompt(int whichprompt)
10876 const char *prompt;
10878 switch (whichprompt) {
10892 static const char *const *findkwd(const char *s)
10894 return bsearch(s, tokname_array + KWDOFFSET,
10895 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10896 sizeof(const char *), pstrcmp);
10899 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10902 * Code for dealing with input/output redirection.
10905 #define EMPTY -2 /* marks an unused slot in redirtab */
10907 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10909 # define PIPESIZE PIPE_BUF
10913 * Open a file in noclobber mode.
10914 * The code was copied from bash.
10917 noclobberopen(const char *fname)
10920 struct stat finfo, finfo2;
10923 * If the file exists and is a regular file, return an error
10926 r = stat(fname, &finfo);
10927 if (r == 0 && S_ISREG(finfo.st_mode)) {
10933 * If the file was not present (r != 0), make sure we open it
10934 * exclusively so that if it is created before we open it, our open
10935 * will fail. Make sure that we do not truncate an existing file.
10936 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10937 * file was not a regular file, we leave O_EXCL off.
10940 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10941 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10943 /* If the open failed, return the file descriptor right away. */
10948 * OK, the open succeeded, but the file may have been changed from a
10949 * non-regular file to a regular file between the stat and the open.
10950 * We are assuming that the O_EXCL open handles the case where FILENAME
10951 * did not exist and is symlinked to an existing file between the stat
10956 * If we can open it and fstat the file descriptor, and neither check
10957 * revealed that it was a regular file, and the file has not been
10958 * replaced, return the file descriptor.
10960 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10961 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10964 /* The file has been replaced. badness. */
10971 * Handle here documents. Normally we fork off a process to write the
10972 * data to a pipe. If the document is short, we can stuff the data in
10973 * the pipe without forking.
10977 openhere(union node *redir)
10983 error("Pipe call failed");
10984 if (redir->type == NHERE) {
10985 len = strlen(redir->nhere.doc->narg.text);
10986 if (len <= PIPESIZE) {
10987 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
10991 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10993 signal(SIGINT, SIG_IGN);
10994 signal(SIGQUIT, SIG_IGN);
10995 signal(SIGHUP, SIG_IGN);
10997 signal(SIGTSTP, SIG_IGN);
10999 signal(SIGPIPE, SIG_DFL);
11000 if (redir->type == NHERE)
11001 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
11003 expandhere(redir->nhere.doc, pip[1]);
11012 openredirect(union node *redir)
11017 switch (redir->nfile.type) {
11019 fname = redir->nfile.expfname;
11020 if ((f = open(fname, O_RDONLY)) < 0)
11024 fname = redir->nfile.expfname;
11025 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11029 /* Take care of noclobber mode. */
11031 fname = redir->nfile.expfname;
11032 if ((f = noclobberopen(fname)) < 0)
11038 fname = redir->nfile.expfname;
11039 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11043 fname = redir->nfile.expfname;
11044 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11051 /* Fall through to eliminate warning. */
11058 f = openhere(redir);
11064 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11066 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11070 dupredirect(union node *redir, int f)
11072 int fd = redir->nfile.fd;
11074 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11075 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11076 copyfd(redir->ndup.dupfd, fd);
11089 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11090 * old file descriptors are stashed away so that the redirection can be
11091 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11092 * standard output, and the standard error if it becomes a duplicate of
11093 * stdout, is saved in memory.
11097 redirect(union node *redir, int flags)
11100 struct redirtab *sv;
11111 if (flags & REDIR_PUSH) {
11112 struct redirtab *q;
11113 q = ckmalloc(sizeof (struct redirtab));
11114 q->next = redirlist;
11116 q->nullredirs = nullredirs - 1;
11117 for (i = 0 ; i < 10 ; i++)
11118 q->renamed[i] = EMPTY;
11125 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11126 n->ndup.dupfd == fd)
11127 continue; /* redirect from/to same file descriptor */
11129 newfd = openredirect(n);
11132 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11133 i = fcntl(fd, F_DUPFD, 10);
11140 error("%d: %m", fd);
11150 dupredirect(n, newfd);
11151 } while ((n = n->nfile.next));
11153 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11154 preverrout_fd = sv->renamed[2];
11159 * Undo the effects of the last redirection.
11165 struct redirtab *rp;
11168 if (--nullredirs >= 0)
11172 for (i = 0 ; i < 10 ; i++) {
11173 if (rp->renamed[i] != EMPTY) {
11176 copyfd(rp->renamed[i], i);
11178 close(rp->renamed[i]);
11181 redirlist = rp->next;
11182 nullredirs = rp->nullredirs;
11188 * Undo all redirections. Called on error or interrupt.
11192 * Discard all saved file descriptors.
11196 clearredir(int drop)
11208 * Copy a file descriptor to be >= to. Returns -1
11209 * if the source file descriptor is closed, EMPTY if there are no unused
11210 * file descriptors left.
11214 copyfd(int from, int to)
11218 newfd = fcntl(from, F_DUPFD, to);
11220 if (errno == EMFILE)
11223 error("%d: %m", from);
11230 redirectsafe(union node *redir, int flags)
11233 volatile int saveint;
11234 struct jmploc *volatile savehandler = handler;
11235 struct jmploc jmploc;
11238 if (!(err = setjmp(jmploc.loc) * 2)) {
11240 redirect(redir, flags);
11242 handler = savehandler;
11243 if (err && exception != EXERROR)
11244 longjmp(handler->loc, 1);
11245 RESTOREINT(saveint);
11249 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11252 static void shtree(union node *, int, char *, FILE*);
11253 static void shcmd(union node *, FILE *);
11254 static void sharg(union node *, FILE *);
11255 static void indent(int, char *, FILE *);
11256 static void trstring(char *);
11260 showtree(union node *n)
11262 trputs("showtree called\n");
11263 shtree(n, 1, NULL, stdout);
11268 shtree(union node *n, int ind, char *pfx, FILE *fp)
11270 struct nodelist *lp;
11276 indent(ind, pfx, fp);
11287 shtree(n->nbinary.ch1, ind, NULL, fp);
11290 shtree(n->nbinary.ch2, ind, NULL, fp);
11298 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11303 if (n->npipe.backgnd)
11309 fprintf(fp, "<node type %d>", n->type);
11318 shcmd(union node *cmd, FILE *fp)
11326 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11332 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11335 switch (np->nfile.type) {
11336 case NTO: s = ">"; dftfd = 1; break;
11337 case NCLOBBER: s = ">|"; dftfd = 1; break;
11338 case NAPPEND: s = ">>"; dftfd = 1; break;
11339 case NTOFD: s = ">&"; dftfd = 1; break;
11340 case NFROM: s = "<"; dftfd = 0; break;
11341 case NFROMFD: s = "<&"; dftfd = 0; break;
11342 case NFROMTO: s = "<>"; dftfd = 0; break;
11343 default: s = "*error*"; dftfd = 0; break;
11345 if (np->nfile.fd != dftfd)
11346 fprintf(fp, "%d", np->nfile.fd);
11348 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11349 fprintf(fp, "%d", np->ndup.dupfd);
11351 sharg(np->nfile.fname, fp);
11360 sharg(union node *arg, FILE *fp)
11363 struct nodelist *bqlist;
11366 if (arg->type != NARG) {
11367 out1fmt("<node type %d>\n", arg->type);
11370 bqlist = arg->narg.backquote;
11371 for (p = arg->narg.text ; *p ; p++) {
11380 if (subtype == VSLENGTH)
11386 if (subtype & VSNUL)
11389 switch (subtype & VSTYPE) {
11408 case VSTRIMLEFTMAX:
11415 case VSTRIMRIGHTMAX:
11422 out1fmt("<subtype %d>", subtype);
11429 case CTLBACKQ|CTLQUOTE:
11432 shtree(bqlist->n, -1, NULL, fp);
11444 indent(int amount, char *pfx, FILE *fp)
11448 for (i = 0 ; i < amount ; i++) {
11449 if (pfx && i == amount - 1)
11470 putc(c, tracefile);
11474 trace(const char *fmt, ...)
11481 (void) vfprintf(tracefile, fmt, va);
11486 tracev(const char *fmt, va_list va)
11490 (void) vfprintf(tracefile, fmt, va);
11495 trputs(const char *s)
11499 fputs(s, tracefile);
11511 putc('"', tracefile);
11512 for (p = s ; *p ; p++) {
11514 case '\n': c = 'n'; goto backslash;
11515 case '\t': c = 't'; goto backslash;
11516 case '\r': c = 'r'; goto backslash;
11517 case '"': c = '"'; goto backslash;
11518 case '\\': c = '\\'; goto backslash;
11519 case CTLESC: c = 'e'; goto backslash;
11520 case CTLVAR: c = 'v'; goto backslash;
11521 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11522 case CTLBACKQ: c = 'q'; goto backslash;
11523 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11524 backslash: putc('\\', tracefile);
11525 putc(c, tracefile);
11528 if (*p >= ' ' && *p <= '~')
11529 putc(*p, tracefile);
11531 putc('\\', tracefile);
11532 putc(*p >> 6 & 03, tracefile);
11533 putc(*p >> 3 & 07, tracefile);
11534 putc(*p & 07, tracefile);
11539 putc('"', tracefile);
11551 putc(' ', tracefile);
11553 putc('\n', tracefile);
11569 /* leave open because libedit might be using it */
11572 scopy("./trace", s);
11574 if (!freopen(s, "a", tracefile)) {
11575 fprintf(stderr, "Can't re-open %s\n", s);
11580 if ((tracefile = fopen(s, "a")) == NULL) {
11581 fprintf(stderr, "Can't open %s\n", s);
11587 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11588 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11590 setlinebuf(tracefile);
11591 fputs("\nTracing started.\n", tracefile);
11596 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11599 * Sigmode records the current value of the signal handlers for the various
11600 * modes. A value of zero means that the current handler is not known.
11601 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11604 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11605 #define S_CATCH 2 /* signal is caught */
11606 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11607 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11608 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11613 * The trap builtin.
11617 trapcmd(int argc, char **argv)
11626 for (signo = 0 ; signo < NSIG ; signo++) {
11627 if (trap[signo] != NULL) {
11630 sn = u_signal_names(0, &signo, 0);
11633 out1fmt("trap -- %s %s\n",
11634 single_quote(trap[signo]), sn);
11644 if ((signo = decode_signal(*ap, 0)) < 0)
11645 error("%s: bad trap", *ap);
11648 if (action[0] == '-' && action[1] == '\0')
11651 action = savestr(action);
11654 ckfree(trap[signo]);
11655 trap[signo] = action;
11666 * Clear traps on a fork.
11674 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11675 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11679 if (tp != &trap[0])
11680 setsignal(tp - trap);
11688 * Set the signal handler for the specified signal. The routine figures
11689 * out what it should be set to.
11693 setsignal(int signo)
11697 struct sigaction act;
11699 if ((t = trap[signo]) == NULL)
11701 else if (*t != '\0')
11705 if (rootshell && action == S_DFL) {
11708 if (iflag || minusc || sflag == 0)
11731 t = &sigmode[signo - 1];
11735 * current setting unknown
11737 if (sigaction(signo, 0, &act) == -1) {
11739 * Pretend it worked; maybe we should give a warning
11740 * here, but other shells don't. We don't alter
11741 * sigmode, so that we retry every time.
11745 if (act.sa_handler == SIG_IGN) {
11746 if (mflag && (signo == SIGTSTP ||
11747 signo == SIGTTIN || signo == SIGTTOU)) {
11748 tsig = S_IGN; /* don't hard ignore these */
11752 tsig = S_RESET; /* force to be set */
11755 if (tsig == S_HARD_IGN || tsig == action)
11759 act.sa_handler = onsig;
11762 act.sa_handler = SIG_IGN;
11765 act.sa_handler = SIG_DFL;
11769 sigfillset(&act.sa_mask);
11770 sigaction(signo, &act, 0);
11778 ignoresig(int signo)
11780 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11781 signal(signo, SIG_IGN);
11783 sigmode[signo - 1] = S_HARD_IGN;
11794 gotsig[signo - 1] = 1;
11795 pendingsigs = signo;
11797 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11806 * Called to execute a trap. Perhaps we should avoid entering new trap
11807 * handlers while we are executing a trap handler.
11817 savestatus = exitstatus;
11819 while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
11821 p = trap[p - q + 1];
11825 exitstatus = savestatus;
11831 * Controls whether the shell is interactive or not.
11835 setinteractive(int on)
11837 static int is_interactive;
11839 if (++on == is_interactive)
11841 is_interactive = on;
11843 setsignal(SIGQUIT);
11844 setsignal(SIGTERM);
11845 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11846 if(is_interactive > 1) {
11847 /* Looks like they want an interactive shell */
11848 static int do_banner;
11852 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11853 "Enter 'help' for a list of built-in commands.\n\n");
11861 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11862 /*** List the available builtins ***/
11864 static int helpcmd(int argc, char **argv)
11868 out1fmt("\nBuilt-in commands:\n-------------------\n");
11869 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11870 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11871 builtincmd[i].name + 1);
11877 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11879 extern const struct BB_applet applets[];
11880 extern const size_t NUM_APPLETS;
11882 for (i = 0; i < NUM_APPLETS; i++) {
11884 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11893 return EXIT_SUCCESS;
11895 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11898 * Called to exit the shell.
11909 jmp = setjmp(loc.loc);
11910 status = exitstatus;
11911 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11915 if ((p = trap[0]) != NULL && *p != '\0') {
11921 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11922 if (iflag && rootshell) {
11923 const char *hp = lookupvar("HISTFILE");
11926 save_history ( hp );
11934 static int decode_signal(const char *string, int minsig)
11937 const char *name = u_signal_names(string, &signo, minsig);
11939 return name ? signo : -1;
11942 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11944 static struct var *vartab[VTABSIZE];
11946 static int vpcmp(const void *, const void *);
11947 static struct var **findvar(struct var **, const char *);
11950 * Initialize the variable symbol tables and import the environment
11954 #ifdef CONFIG_ASH_GETOPTS
11956 * Safe version of setvar, returns 1 on success 0 on failure.
11960 setvarsafe(const char *name, const char *val, int flags)
11963 volatile int saveint;
11964 struct jmploc *volatile savehandler = handler;
11965 struct jmploc jmploc;
11968 if (setjmp(jmploc.loc))
11972 setvar(name, val, flags);
11975 handler = savehandler;
11976 RESTOREINT(saveint);
11982 * Set the value of a variable. The flags argument is ored with the
11983 * flags of the variable. If val is NULL, the variable is unset.
11987 setvar(const char *name, const char *val, int flags)
11994 q = endofname(name);
11995 p = strchrnul(q, '=');
11996 namelen = p - name;
11997 if (!namelen || p != q)
11998 error("%.*s: bad variable name", namelen, name);
12003 vallen = strlen(val);
12006 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
12010 p = mempcpy(p, val, vallen);
12013 setvareq(nameeq, flags | VNOSAVE);
12019 * Same as setvar except that the variable and value are passed in
12020 * the first argument as name=value. Since the first argument will
12021 * be actually stored in the table, it should not be a string that
12023 * Called with interrupts off.
12027 setvareq(char *s, int flags)
12029 struct var *vp, **vpp;
12032 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12033 vp = *findvar(vpp, s);
12035 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12038 if (flags & VNOSAVE)
12041 error("%.*s: is read only", strchrnul(n, '=') - n, n);
12044 if (flags & VNOSET)
12047 if (vp->func && (flags & VNOFUNC) == 0)
12048 (*vp->func)(strchrnul(s, '=') + 1);
12050 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12053 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12055 if (flags & VNOSET)
12058 vp = ckmalloc(sizeof (*vp));
12063 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12071 * Process a linked list of variable assignments.
12075 listsetvar(struct strlist *list_set_var, int flags)
12077 struct strlist *lp = list_set_var;
12083 setvareq(lp->text, flags);
12084 } while ((lp = lp->next));
12090 * Find the value of a variable. Returns NULL if not set.
12094 lookupvar(const char *name)
12098 if ((v = *findvar(hashvar(name), name))) {
12101 * Dynamic variables are implemented roughly the same way they are
12102 * in bash. Namely, they're "special" so long as they aren't unset.
12103 * As soon as they're unset, they're no longer dynamic, and dynamic
12104 * lookup will no longer happen at that point. -- PFM.
12106 if((v->flags & VDYNAMIC))
12109 if(!(v->flags & VUNSET))
12110 return strchrnul(v->text, '=') + 1;
12118 * Search the environment of a builtin command.
12122 bltinlookup(const char *name)
12124 struct strlist *sp;
12126 for (sp = cmdenviron ; sp ; sp = sp->next) {
12127 if (varequal(sp->text, name))
12128 return strchrnul(sp->text, '=') + 1;
12130 return lookupvar(name);
12135 * Generate a list of variables satisfying the given conditions.
12139 listvars(int on, int off, char ***end)
12150 for (vp = *vpp ; vp ; vp = vp->next)
12151 if ((vp->flags & mask) == on) {
12152 if (ep == stackstrend())
12153 ep = growstackstr();
12154 *ep++ = (char *) vp->text;
12156 } while (++vpp < vartab + VTABSIZE);
12157 if (ep == stackstrend())
12158 ep = growstackstr();
12162 return grabstackstr(ep);
12167 * POSIX requires that 'set' (but not export or readonly) output the
12168 * variables in lexicographic order - by the locale's collating order (sigh).
12169 * Maybe we could keep them in an ordered balanced binary tree
12170 * instead of hashed lists.
12171 * For now just roll 'em through qsort for printing...
12175 showvars(const char *sep_prefix, int on, int off)
12178 char **ep, **epend;
12180 ep = listvars(on, off, &epend);
12181 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12183 sep = *sep_prefix ? spcstr : sep_prefix;
12185 for (; ep < epend; ep++) {
12189 p = strchrnul(*ep, '=');
12192 q = single_quote(++p);
12194 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12203 * The export and readonly commands.
12207 exportcmd(int argc, char **argv)
12213 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12216 notp = nextopt("p") - 'p';
12217 if (notp && ((name = *(aptr = argptr)))) {
12219 if ((p = strchr(name, '=')) != NULL) {
12222 if ((vp = *findvar(hashvar(name), name))) {
12227 setvar(name, p, flag);
12228 } while ((name = *++aptr) != NULL);
12230 showvars(argv[0], flag, 0);
12237 * Make a variable a local variable. When a variable is made local, it's
12238 * value and flags are saved in a localvar structure. The saved values
12239 * will be restored when the shell function returns. We handle the name
12240 * "-" as a special case.
12244 mklocal(char *name)
12246 struct localvar *lvp;
12251 lvp = ckmalloc(sizeof (struct localvar));
12252 if (name[0] == '-' && name[1] == '\0') {
12254 p = ckmalloc(sizeof(optlist));
12255 lvp->text = memcpy(p, optlist, sizeof(optlist));
12260 vpp = hashvar(name);
12261 vp = *findvar(vpp, name);
12262 eq = strchr(name, '=');
12265 setvareq(name, VSTRFIXED);
12267 setvar(name, NULL, VSTRFIXED);
12268 vp = *vpp; /* the new variable */
12269 lvp->flags = VUNSET;
12271 lvp->text = vp->text;
12272 lvp->flags = vp->flags;
12273 vp->flags |= VSTRFIXED|VTEXTFIXED;
12279 lvp->next = localvars;
12285 * The "local" command.
12289 localcmd(int argc, char **argv)
12294 while ((name = *argv++) != NULL) {
12302 * Called after a function returns.
12303 * Interrupts must be off.
12309 struct localvar *lvp;
12312 while ((lvp = localvars) != NULL) {
12313 localvars = lvp->next;
12315 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12316 if (vp == NULL) { /* $- saved */
12317 memcpy(optlist, lvp->text, sizeof(optlist));
12320 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12321 unsetvar(vp->text);
12324 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12325 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12327 vp->flags = lvp->flags;
12328 vp->text = lvp->text;
12336 * The unset builtin command. We unset the function before we unset the
12337 * variable to allow a function to be unset when there is a readonly variable
12338 * with the same name.
12342 unsetcmd(int argc, char **argv)
12349 while ((i = nextopt("vf")) != '\0') {
12353 for (ap = argptr; *ap ; ap++) {
12368 * Unset the specified variable.
12372 unsetvar(const char *s)
12378 vpp = findvar(hashvar(s), s);
12382 int flags = vp->flags;
12385 if (flags & VREADONLY)
12388 vp->flags &= ~VDYNAMIC;
12390 if (flags & VUNSET)
12392 if ((flags & VSTRFIXED) == 0) {
12394 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12401 vp->flags &= ~VEXPORT;
12414 * Find the appropriate entry in the hash table from the name.
12417 static struct var **
12418 hashvar(const char *p)
12420 unsigned int hashval;
12422 hashval = ((unsigned char) *p) << 4;
12423 while (*p && *p != '=')
12424 hashval += (unsigned char) *p++;
12425 return &vartab[hashval % VTABSIZE];
12431 * Compares two strings up to the first = or '\0'. The first
12432 * string must be terminated by '='; the second may be terminated by
12433 * either '=' or '\0'.
12437 varcmp(const char *p, const char *q)
12441 while ((c = *p) == (d = *q)) {
12442 if (!c || c == '=')
12456 vpcmp(const void *a, const void *b)
12458 return varcmp(*(const char **)a, *(const char **)b);
12461 static struct var **
12462 findvar(struct var **vpp, const char *name)
12464 for (; *vpp; vpp = &(*vpp)->next) {
12465 if (varequal((*vpp)->text, name)) {
12471 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12473 #include <sys/times.h>
12475 static const unsigned char timescmd_str[] = {
12476 ' ', offsetof(struct tms, tms_utime),
12477 '\n', offsetof(struct tms, tms_stime),
12478 ' ', offsetof(struct tms, tms_cutime),
12479 '\n', offsetof(struct tms, tms_cstime),
12483 static int timescmd(int ac, char **av)
12485 long int clk_tck, s, t;
12486 const unsigned char *p;
12489 clk_tck = sysconf(_SC_CLK_TCK);
12494 t = *(clock_t *)(((char *) &buf) + p[1]);
12496 out1fmt("%ldm%ld.%.3lds%c",
12498 ((t - s * clk_tck) * 1000) / clk_tck,
12500 } while (*(p += 2));
12505 #ifdef CONFIG_ASH_MATH_SUPPORT
12507 dash_arith(const char *s)
12513 result = arith(s, &errcode);
12516 error("exponent less than 0");
12517 else if (errcode == -2)
12518 error("divide by zero");
12519 else if (errcode == -5)
12520 error("expression recursion loop detected");
12531 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12532 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12534 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12538 letcmd(int argc, char **argv)
12545 error("expression expected");
12546 for (ap = argv + 1; *ap; ap++) {
12547 i = dash_arith(*ap);
12552 #endif /* CONFIG_ASH_MATH_SUPPORT */
12554 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12557 * Miscellaneous builtins.
12563 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12564 typedef enum __rlimit_resource rlim_t;
12570 * The read builtin. The -e option causes backslashes to escape the
12571 * following character.
12573 * This uses unbuffered input, which may be avoidable in some cases.
12577 readcmd(int argc, char **argv)
12586 #if defined(CONFIG_ASH_TIMEOUT)
12589 struct timeval timeout_struct;
12590 struct termios tty, old_tty;
12598 #if defined(CONFIG_ASH_TIMEOUT)
12601 while ((i = nextopt("p:rt:")) != '\0')
12603 while ((i = nextopt("p:r")) != '\0')
12607 prompt = optionarg;
12610 #if defined(CONFIG_ASH_TIMEOUT)
12612 timeout = atoi(optionarg);
12615 if (prompt && isatty(0)) {
12618 if (*(ap = argptr) == NULL)
12619 error("arg count");
12620 if ((ifs = bltinlookup("IFS")) == NULL)
12622 #if defined(CONFIG_ASH_TIMEOUT)
12630 #if defined(CONFIG_ASH_TIMEOUT)
12632 tcgetattr(0, &tty);
12635 /* cfmakeraw(...) disables too much; we just do this instead. */
12636 tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
12637 tcsetattr(0, TCSANOW, &tty);
12642 timeout_struct.tv_sec = timeout;
12643 timeout_struct.tv_usec = 0;
12645 if ((i = select (FD_SETSIZE, &set, NULL, NULL, &timeout_struct)) == 1)
12648 if(c == '\n' || c == 4) /* Handle newlines and EOF */
12649 i = 0; /* Don't read further... */
12651 STPUTC(c, p); /* Keep reading... */
12653 tcsetattr(0, TCSANOW, &old_tty);
12655 /* Echo the character so the user knows it was read...
12656 Yes, this can be done by setting the ECHO flag, but that
12657 echoes ^D and other control characters at this state */
12669 if (read(0, &c, 1) != 1) {
12681 if (!rflag && c == '\\') {
12687 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12691 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12693 setvar(*ap, stackblock(), 0);
12703 /* Remove trailing blanks */
12704 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12706 setvar(*ap, stackblock(), 0);
12707 while (*++ap != NULL)
12708 setvar(*ap, nullstr, 0);
12713 static int umaskcmd(int argc, char **argv)
12715 static const char permuser[3] = "ugo";
12716 static const char permmode[3] = "rwx";
12717 static const short int permmask[] = {
12718 S_IRUSR, S_IWUSR, S_IXUSR,
12719 S_IRGRP, S_IWGRP, S_IXGRP,
12720 S_IROTH, S_IWOTH, S_IXOTH
12726 int symbolic_mode = 0;
12728 while (nextopt("S") != '\0') {
12737 if ((ap = *argptr) == NULL) {
12738 if (symbolic_mode) {
12742 for (i = 0; i < 3; i++) {
12745 *p++ = permuser[i];
12747 for (j = 0; j < 3; j++) {
12748 if ((mask & permmask[3 * i + j]) == 0) {
12749 *p++ = permmode[j];
12757 out1fmt("%.4o\n", mask);
12760 if (is_digit((unsigned char) *ap)) {
12763 if (*ap >= '8' || *ap < '0')
12764 error(illnum, argv[1]);
12765 mask = (mask << 3) + (*ap - '0');
12766 } while (*++ap != '\0');
12769 mask = ~mask & 0777;
12770 if (!bb_parse_mode(ap, &mask)) {
12771 error("Illegal mode: %s", ap);
12773 umask(~mask & 0777);
12782 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12783 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12784 * ash by J.T. Conklin.
12792 int factor; /* multiply by to get rlim_{cur,max} values */
12796 static const struct limits limits[] = {
12798 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12800 #ifdef RLIMIT_FSIZE
12801 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12804 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12806 #ifdef RLIMIT_STACK
12807 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12810 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12813 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12815 #ifdef RLIMIT_MEMLOCK
12816 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12818 #ifdef RLIMIT_NPROC
12819 { "process", RLIMIT_NPROC, 1, 'p' },
12821 #ifdef RLIMIT_NOFILE
12822 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
12825 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
12827 #ifdef RLIMIT_LOCKS
12828 { "locks", RLIMIT_LOCKS, 1, 'w' },
12830 { (char *) 0, 0, 0, '\0' }
12833 enum limtype { SOFT = 0x1, HARD = 0x2 };
12835 static void printlim(enum limtype how, const struct rlimit *limit,
12836 const struct limits *l)
12840 val = limit->rlim_max;
12842 val = limit->rlim_cur;
12844 if (val == RLIM_INFINITY)
12845 out1fmt("unlimited\n");
12848 out1fmt("%lld\n", (long long) val);
12853 ulimitcmd(int argc, char **argv)
12857 enum limtype how = SOFT | HARD;
12858 const struct limits *l;
12861 struct rlimit limit;
12864 while ((optc = nextopt("HSa"
12868 #ifdef RLIMIT_FSIZE
12874 #ifdef RLIMIT_STACK
12883 #ifdef RLIMIT_MEMLOCK
12886 #ifdef RLIMIT_NPROC
12889 #ifdef RLIMIT_NOFILE
12895 #ifdef RLIMIT_LOCKS
12913 for (l = limits; l->option != what; l++)
12916 set = *argptr ? 1 : 0;
12920 if (all || argptr[1])
12921 error("too many arguments");
12922 if (strncmp(p, "unlimited\n", 9) == 0)
12923 val = RLIM_INFINITY;
12927 while ((c = *p++) >= '0' && c <= '9')
12929 val = (val * 10) + (long)(c - '0');
12930 if (val < (rlim_t) 0)
12934 error("bad number");
12939 for (l = limits; l->name; l++) {
12940 getrlimit(l->cmd, &limit);
12941 out1fmt("%-20s ", l->name);
12942 printlim(how, &limit, l);
12947 getrlimit(l->cmd, &limit);
12950 limit.rlim_max = val;
12952 limit.rlim_cur = val;
12953 if (setrlimit(l->cmd, &limit) < 0)
12954 error("error setting limit (%m)");
12956 printlim(how, &limit, l);
12962 #ifdef CONFIG_ASH_MATH_SUPPORT
12964 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12966 Permission is hereby granted, free of charge, to any person obtaining
12967 a copy of this software and associated documentation files (the
12968 "Software"), to deal in the Software without restriction, including
12969 without limitation the rights to use, copy, modify, merge, publish,
12970 distribute, sublicense, and/or sell copies of the Software, and to
12971 permit persons to whom the Software is furnished to do so, subject to
12972 the following conditions:
12974 The above copyright notice and this permission notice shall be
12975 included in all copies or substantial portions of the Software.
12977 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12978 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12979 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12980 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12981 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12982 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12983 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12986 /* This is my infix parser/evaluator. It is optimized for size, intended
12987 * as a replacement for yacc-based parsers. However, it may well be faster
12988 * than a comparable parser written in yacc. The supported operators are
12989 * listed in #defines below. Parens, order of operations, and error handling
12990 * are supported. This code is thread safe. The exact expression format should
12991 * be that which POSIX specifies for shells. */
12993 /* The code uses a simple two-stack algorithm. See
12994 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12995 * for a detailed explanation of the infix-to-postfix algorithm on which
12996 * this is based (this code differs in that it applies operators immediately
12997 * to the stack instead of adding them to a queue to end up with an
13000 /* To use the routine, call it with an expression string and error return
13004 * Aug 24, 2001 Manuel Novoa III
13006 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13008 * 1) In arith_apply():
13009 * a) Cached values of *numptr and &(numptr[-1]).
13010 * b) Removed redundant test for zero denominator.
13013 * a) Eliminated redundant code for processing operator tokens by moving
13014 * to a table-based implementation. Also folded handling of parens
13016 * b) Combined all 3 loops which called arith_apply to reduce generated
13017 * code size at the cost of speed.
13019 * 3) The following expressions were treated as valid by the original code:
13020 * 1() , 0! , 1 ( *3 ) .
13021 * These bugs have been fixed by internally enclosing the expression in
13022 * parens and then checking that all binary ops and right parens are
13023 * preceded by a valid expression (NUM_TOKEN).
13025 * Note: It may be desirable to replace Aaron's test for whitespace with
13026 * ctype's isspace() if it is used by another busybox applet or if additional
13027 * whitespace chars should be considered. Look below the "#include"s for a
13028 * precompiler test.
13032 * Aug 26, 2001 Manuel Novoa III
13034 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13036 * Merge in Aaron's comments previously posted to the busybox list,
13037 * modified slightly to take account of my changes to the code.
13042 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13044 * - allow access to variable,
13045 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13046 * - realize assign syntax (VAR=expr, +=, *= etc)
13047 * - realize exponentiation (** operator)
13048 * - realize comma separated - expr, expr
13049 * - realise ++expr --expr expr++ expr--
13050 * - realise expr ? expr : expr (but, second expr calculate always)
13051 * - allow hexadecimal and octal numbers
13052 * - was restored loses XOR operator
13053 * - remove one goto label, added three ;-)
13054 * - protect $((num num)) as true zero expr (Manuel`s error)
13055 * - always use special isspace(), see comment from bash ;-)
13059 #define arith_isspace(arithval) \
13060 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13063 typedef unsigned char operator;
13065 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
13066 * precedence, and 3 high bits are an ID unique across operators of that
13067 * precedence. The ID portion is so that multiple operators can have the
13068 * same precedence, ensuring that the leftmost one is evaluated first.
13069 * Consider * and /. */
13071 #define tok_decl(prec,id) (((id)<<5)|(prec))
13072 #define PREC(op) ((op) & 0x1F)
13074 #define TOK_LPAREN tok_decl(0,0)
13076 #define TOK_COMMA tok_decl(1,0)
13078 #define TOK_ASSIGN tok_decl(2,0)
13079 #define TOK_AND_ASSIGN tok_decl(2,1)
13080 #define TOK_OR_ASSIGN tok_decl(2,2)
13081 #define TOK_XOR_ASSIGN tok_decl(2,3)
13082 #define TOK_PLUS_ASSIGN tok_decl(2,4)
13083 #define TOK_MINUS_ASSIGN tok_decl(2,5)
13084 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13085 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13087 #define TOK_MUL_ASSIGN tok_decl(3,0)
13088 #define TOK_DIV_ASSIGN tok_decl(3,1)
13089 #define TOK_REM_ASSIGN tok_decl(3,2)
13091 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13092 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13094 /* conditional is right associativity too */
13095 #define TOK_CONDITIONAL tok_decl(4,0)
13096 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
13098 #define TOK_OR tok_decl(5,0)
13100 #define TOK_AND tok_decl(6,0)
13102 #define TOK_BOR tok_decl(7,0)
13104 #define TOK_BXOR tok_decl(8,0)
13106 #define TOK_BAND tok_decl(9,0)
13108 #define TOK_EQ tok_decl(10,0)
13109 #define TOK_NE tok_decl(10,1)
13111 #define TOK_LT tok_decl(11,0)
13112 #define TOK_GT tok_decl(11,1)
13113 #define TOK_GE tok_decl(11,2)
13114 #define TOK_LE tok_decl(11,3)
13116 #define TOK_LSHIFT tok_decl(12,0)
13117 #define TOK_RSHIFT tok_decl(12,1)
13119 #define TOK_ADD tok_decl(13,0)
13120 #define TOK_SUB tok_decl(13,1)
13122 #define TOK_MUL tok_decl(14,0)
13123 #define TOK_DIV tok_decl(14,1)
13124 #define TOK_REM tok_decl(14,2)
13126 /* exponent is right associativity */
13127 #define TOK_EXPONENT tok_decl(15,1)
13129 /* For now unary operators. */
13130 #define UNARYPREC 16
13131 #define TOK_BNOT tok_decl(UNARYPREC,0)
13132 #define TOK_NOT tok_decl(UNARYPREC,1)
13134 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13135 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13137 #define PREC_PRE (UNARYPREC+2)
13139 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13140 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13142 #define PREC_POST (UNARYPREC+3)
13144 #define TOK_POST_INC tok_decl(PREC_POST, 0)
13145 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
13147 #define SPEC_PREC (UNARYPREC+4)
13149 #define TOK_NUM tok_decl(SPEC_PREC, 0)
13150 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13152 #define NUMPTR (*numstackptr)
13154 static inline int tok_have_assign(operator op)
13156 operator prec = PREC(op);
13158 convert_prec_is_assing(prec);
13159 return (prec == PREC(TOK_ASSIGN) ||
13160 prec == PREC_PRE || prec == PREC_POST);
13163 static inline int is_right_associativity(operator prec)
13165 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13166 prec == PREC(TOK_CONDITIONAL));
13170 typedef struct ARITCH_VAR_NUM {
13172 arith_t contidional_second_val;
13173 char contidional_second_val_initialized;
13174 char *var; /* if NULL then is regular number,
13175 else is variable name */
13179 typedef struct CHK_VAR_RECURSIVE_LOOPED {
13181 struct CHK_VAR_RECURSIVE_LOOPED *next;
13182 } chk_var_recursive_looped_t;
13184 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13187 static int arith_lookup_val(v_n_t *t)
13190 const char * p = lookupvar(t->var);
13195 /* recursive try as expression */
13196 chk_var_recursive_looped_t *cur;
13197 chk_var_recursive_looped_t cur_save;
13199 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13200 if(strcmp(cur->var, t->var) == 0) {
13201 /* expression recursion loop detected */
13205 /* save current lookuped var name */
13206 cur = prev_chk_var_recursive;
13207 cur_save.var = t->var;
13208 cur_save.next = cur;
13209 prev_chk_var_recursive = &cur_save;
13211 t->val = arith (p, &errcode);
13212 /* restore previous ptr after recursiving */
13213 prev_chk_var_recursive = cur;
13216 /* allow undefined var as 0 */
13223 /* "applying" a token means performing it on the top elements on the integer
13224 * stack. For a unary operator it will only change the top element, but a
13225 * binary operator will pop two arguments and push a result */
13227 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13230 arith_t numptr_val, rez;
13231 int ret_arith_lookup_val;
13233 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13234 without arguments */
13235 numptr_m1 = NUMPTR - 1;
13237 /* check operand is var with noninteger value */
13238 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13239 if(ret_arith_lookup_val)
13240 return ret_arith_lookup_val;
13242 rez = numptr_m1->val;
13243 if (op == TOK_UMINUS)
13245 else if (op == TOK_NOT)
13247 else if (op == TOK_BNOT)
13249 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13251 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13253 else if (op != TOK_UPLUS) {
13254 /* Binary operators */
13256 /* check and binary operators need two arguments */
13257 if (numptr_m1 == numstack) goto err;
13259 /* ... and they pop one */
13262 if (op == TOK_CONDITIONAL) {
13263 if(! numptr_m1->contidional_second_val_initialized) {
13264 /* protect $((expr1 ? expr2)) without ": expr" */
13267 rez = numptr_m1->contidional_second_val;
13268 } else if(numptr_m1->contidional_second_val_initialized) {
13269 /* protect $((expr1 : expr2)) without "expr ? " */
13272 numptr_m1 = NUMPTR - 1;
13273 if(op != TOK_ASSIGN) {
13274 /* check operand is var with noninteger value for not '=' */
13275 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13276 if(ret_arith_lookup_val)
13277 return ret_arith_lookup_val;
13279 if (op == TOK_CONDITIONAL) {
13280 numptr_m1->contidional_second_val = rez;
13282 rez = numptr_m1->val;
13283 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13285 else if (op == TOK_OR)
13286 rez = numptr_val || rez;
13287 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13289 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13291 else if (op == TOK_AND)
13292 rez = rez && numptr_val;
13293 else if (op == TOK_EQ)
13294 rez = (rez == numptr_val);
13295 else if (op == TOK_NE)
13296 rez = (rez != numptr_val);
13297 else if (op == TOK_GE)
13298 rez = (rez >= numptr_val);
13299 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13300 rez >>= numptr_val;
13301 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13302 rez <<= numptr_val;
13303 else if (op == TOK_GT)
13304 rez = (rez > numptr_val);
13305 else if (op == TOK_LT)
13306 rez = (rez < numptr_val);
13307 else if (op == TOK_LE)
13308 rez = (rez <= numptr_val);
13309 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13311 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13313 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13315 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13317 else if (op == TOK_CONDITIONAL_SEP) {
13318 if (numptr_m1 == numstack) {
13319 /* protect $((expr : expr)) without "expr ? " */
13322 numptr_m1->contidional_second_val_initialized = op;
13323 numptr_m1->contidional_second_val = numptr_val;
13325 else if (op == TOK_CONDITIONAL) {
13327 numptr_val : numptr_m1->contidional_second_val;
13329 else if(op == TOK_EXPONENT) {
13331 return -3; /* exponent less than 0 */
13336 while(numptr_val--)
13341 else if(numptr_val==0) /* zero divisor check */
13343 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13345 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13348 if(tok_have_assign(op)) {
13351 if(numptr_m1->var == NULL) {
13355 /* save to shell variable */
13356 snprintf(buf, sizeof(buf), "%lld", (long long) rez);
13357 setvar(numptr_m1->var, buf, 0);
13358 /* after saving, make previous value for v++ or v-- */
13359 if(op == TOK_POST_INC)
13361 else if(op == TOK_POST_DEC)
13364 numptr_m1->val = rez;
13365 /* protect geting var value, is number now */
13366 numptr_m1->var = NULL;
13371 /* longest must first */
13372 static const char op_tokens[] = {
13373 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13374 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13375 '<','<', 0, TOK_LSHIFT,
13376 '>','>', 0, TOK_RSHIFT,
13377 '|','|', 0, TOK_OR,
13378 '&','&', 0, TOK_AND,
13379 '!','=', 0, TOK_NE,
13380 '<','=', 0, TOK_LE,
13381 '>','=', 0, TOK_GE,
13382 '=','=', 0, TOK_EQ,
13383 '|','=', 0, TOK_OR_ASSIGN,
13384 '&','=', 0, TOK_AND_ASSIGN,
13385 '*','=', 0, TOK_MUL_ASSIGN,
13386 '/','=', 0, TOK_DIV_ASSIGN,
13387 '%','=', 0, TOK_REM_ASSIGN,
13388 '+','=', 0, TOK_PLUS_ASSIGN,
13389 '-','=', 0, TOK_MINUS_ASSIGN,
13390 '-','-', 0, TOK_POST_DEC,
13391 '^','=', 0, TOK_XOR_ASSIGN,
13392 '+','+', 0, TOK_POST_INC,
13393 '*','*', 0, TOK_EXPONENT,
13397 '=', 0, TOK_ASSIGN,
13409 '?', 0, TOK_CONDITIONAL,
13410 ':', 0, TOK_CONDITIONAL_SEP,
13411 ')', 0, TOK_RPAREN,
13412 '(', 0, TOK_LPAREN,
13416 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13419 static arith_t arith (const char *expr, int *perrcode)
13421 register char arithval; /* Current character under analysis */
13422 operator lasttok, op;
13425 const char *p = endexpression;
13428 size_t datasizes = strlen(expr) + 2;
13430 /* Stack of integers */
13431 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13432 * in any given correct or incorrect expression is left as an exercise to
13434 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13435 *numstackptr = numstack;
13436 /* Stack of operator tokens */
13437 operator *stack = alloca((datasizes) * sizeof(operator)),
13440 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13441 *perrcode = errcode = 0;
13444 if ((arithval = *expr) == 0) {
13445 if (p == endexpression) {
13446 /* Null expression. */
13450 /* This is only reached after all tokens have been extracted from the
13451 * input stream. If there are still tokens on the operator stack, they
13452 * are to be applied in order. At the end, there should be a final
13453 * result on the integer stack */
13455 if (expr != endexpression + 1) {
13456 /* If we haven't done so already, */
13457 /* append a closing right paren */
13458 expr = endexpression;
13459 /* and let the loop process it. */
13462 /* At this point, we're done with the expression. */
13463 if (numstackptr != numstack+1) {
13464 /* ... but if there isn't, it's bad */
13466 return (*perrcode = -1);
13468 if(numstack->var) {
13469 /* expression is $((var)) only, lookup now */
13470 errcode = arith_lookup_val(numstack);
13473 *perrcode = errcode;
13474 return numstack->val;
13476 /* Continue processing the expression. */
13477 if (arith_isspace(arithval)) {
13478 /* Skip whitespace */
13481 if((p = endofname(expr)) != expr) {
13482 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13484 numstackptr->var = alloca(var_name_size);
13485 safe_strncpy(numstackptr->var, expr, var_name_size);
13488 numstackptr->contidional_second_val_initialized = 0;
13492 } else if (is_digit(arithval)) {
13493 numstackptr->var = NULL;
13494 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13497 for(p = op_tokens; ; p++) {
13501 /* strange operator not found */
13504 for(o = expr; *p && *o == *p; p++)
13511 /* skip tail uncompared token */
13514 /* skip zero delim */
13519 /* post grammar: a++ reduce to num */
13520 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13523 /* Plus and minus are binary (not unary) _only_ if the last
13524 * token was as number, or a right paren (which pretends to be
13525 * a number, since it evaluates to one). Think about it.
13526 * It makes sense. */
13527 if (lasttok != TOK_NUM) {
13543 /* We don't want a unary operator to cause recursive descent on the
13544 * stack, because there can be many in a row and it could cause an
13545 * operator to be evaluated before its argument is pushed onto the
13546 * integer stack. */
13547 /* But for binary operators, "apply" everything on the operator
13548 * stack until we find an operator with a lesser priority than the
13549 * one we have just extracted. */
13550 /* Left paren is given the lowest priority so it will never be
13551 * "applied" in this way.
13552 * if associativity is right and priority eq, applied also skip
13555 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13556 /* not left paren or unary */
13557 if (lasttok != TOK_NUM) {
13558 /* binary op must be preceded by a num */
13561 while (stackptr != stack) {
13562 if (op == TOK_RPAREN) {
13563 /* The algorithm employed here is simple: while we don't
13564 * hit an open paren nor the bottom of the stack, pop
13565 * tokens and apply them */
13566 if (stackptr[-1] == TOK_LPAREN) {
13568 /* Any operator directly after a */
13570 /* close paren should consider itself binary */
13574 operator prev_prec = PREC(stackptr[-1]);
13576 convert_prec_is_assing(prec);
13577 convert_prec_is_assing(prev_prec);
13578 if (prev_prec < prec)
13580 /* check right assoc */
13581 if(prev_prec == prec && is_right_associativity(prec))
13584 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13585 if(errcode) goto ret;
13587 if (op == TOK_RPAREN) {
13592 /* Push this operator to the stack and remember it. */
13593 *stackptr++ = lasttok = op;
13600 #endif /* CONFIG_ASH_MATH_SUPPORT */
13604 const char *bb_applet_name = "debug stuff usage";
13605 int main(int argc, char **argv)
13607 return ash_main(argc, argv);
13612 * Copyright (c) 1989, 1991, 1993, 1994
13613 * The Regents of the University of California. All rights reserved.
13615 * This code is derived from software contributed to Berkeley by
13616 * Kenneth Almquist.
13618 * Redistribution and use in source and binary forms, with or without
13619 * modification, are permitted provided that the following conditions
13621 * 1. Redistributions of source code must retain the above copyright
13622 * notice, this list of conditions and the following disclaimer.
13623 * 2. Redistributions in binary form must reproduce the above copyright
13624 * notice, this list of conditions and the following disclaimer in the
13625 * documentation and/or other materials provided with the distribution.
13627 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13628 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13630 * 4. Neither the name of the University nor the names of its contributors
13631 * may be used to endorse or promote products derived from this software
13632 * without specific prior written permission.
13634 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13635 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13636 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13637 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13638 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13639 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13640 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13641 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13642 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13643 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF