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 barrier() ({ __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 likely(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
1449 #ifdef CONFIG_ASH_MATH_SUPPORT_64
1450 typedef int64_t arith_t;
1452 typedef long arith_t;
1454 static arith_t dash_arith(const char *);
1455 static arith_t arith(const char *expr, int *perrcode);
1458 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1459 static unsigned long rseed;
1460 static void change_random(const char *);
1461 # ifndef DYNAMIC_VAR
1462 # define DYNAMIC_VAR
1466 /* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1468 static void reset(void);
1470 /* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
1477 #define VEXPORT 0x01 /* variable is exported */
1478 #define VREADONLY 0x02 /* variable cannot be modified */
1479 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1480 #define VTEXTFIXED 0x08 /* text is statically allocated */
1481 #define VSTACK 0x10 /* text is allocated on the stack */
1482 #define VUNSET 0x20 /* the variable is not set */
1483 #define VNOFUNC 0x40 /* don't call the callback function */
1484 #define VNOSET 0x80 /* do not set variable - just readonly test */
1485 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1487 # define VDYNAMIC 0x200 /* dynamic variable */
1493 struct var *next; /* next entry in hash list */
1494 int flags; /* flags are defined above */
1495 const char *text; /* name=value */
1496 void (*func)(const char *); /* function to be called when */
1497 /* the variable gets set/unset */
1501 struct localvar *next; /* next local variable in list */
1502 struct var *vp; /* the variable that was made local */
1503 int flags; /* saved flags */
1504 const char *text; /* saved text */
1508 static struct localvar *localvars;
1514 #ifdef CONFIG_ASH_GETOPTS
1515 static void getoptsreset(const char *);
1518 #ifdef CONFIG_LOCALE_SUPPORT
1520 static void change_lc_all(const char *value);
1521 static void change_lc_ctype(const char *value);
1527 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1529 static const char defifsvar[] = "IFS= \t\n";
1530 #define defifs (defifsvar + 4)
1532 static const char defifs[] = " \t\n";
1536 static struct var varinit[] = {
1538 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1540 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1543 #ifdef CONFIG_ASH_MAIL
1544 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1545 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1548 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1549 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1550 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1551 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1552 #ifdef CONFIG_ASH_GETOPTS
1553 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1555 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1556 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1558 #ifdef CONFIG_LOCALE_SUPPORT
1559 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1560 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
1562 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1563 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
1567 #define vifs varinit[0]
1568 #ifdef CONFIG_ASH_MAIL
1569 #define vmail (&vifs)[1]
1570 #define vmpath (&vmail)[1]
1574 #define vpath (&vmpath)[1]
1575 #define vps1 (&vpath)[1]
1576 #define vps2 (&vps1)[1]
1577 #define vps4 (&vps2)[1]
1578 #define voptind (&vps4)[1]
1579 #ifdef CONFIG_ASH_GETOPTS
1580 #define vrandom (&voptind)[1]
1582 #define vrandom (&vps4)[1]
1584 #define defpath (defpathvar + 5)
1587 * The following macros access the values of the above variables.
1588 * They have to skip over the name. They return the null string
1589 * for unset variables.
1592 #define ifsval() (vifs.text + 4)
1593 #define ifsset() ((vifs.flags & VUNSET) == 0)
1594 #define mailval() (vmail.text + 5)
1595 #define mpathval() (vmpath.text + 9)
1596 #define pathval() (vpath.text + 5)
1597 #define ps1val() (vps1.text + 4)
1598 #define ps2val() (vps2.text + 4)
1599 #define ps4val() (vps4.text + 4)
1600 #define optindval() (voptind.text + 7)
1602 #define mpathset() ((vmpath.flags & VUNSET) == 0)
1604 static void setvar(const char *, const char *, int);
1605 static void setvareq(char *, int);
1606 static void listsetvar(struct strlist *, int);
1607 static char *lookupvar(const char *);
1608 static char *bltinlookup(const char *);
1609 static char **listvars(int, int, char ***);
1610 #define environment() listvars(VEXPORT, VUNSET, 0)
1611 static int showvars(const char *, int, int);
1612 static void poplocalvars(void);
1613 static int unsetvar(const char *);
1614 #ifdef CONFIG_ASH_GETOPTS
1615 static int setvarsafe(const char *, const char *, int);
1617 static int varcmp(const char *, const char *);
1618 static struct var **hashvar(const char *);
1621 static inline int varequal(const char *a, const char *b) {
1622 return !varcmp(a, b);
1626 static int loopnest; /* current loop nesting level */
1629 * The parsefile structure pointed to by the global variable parsefile
1630 * contains information about the current file being read.
1635 struct redirtab *next;
1640 static struct redirtab *redirlist;
1641 static int nullredirs;
1643 extern char **environ;
1645 /* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1648 static void outstr(const char *, FILE *);
1649 static void outcslow(int, FILE *);
1650 static void flushall(void);
1651 static void flusherr(void);
1652 static int out1fmt(const char *, ...)
1653 __attribute__((__format__(__printf__,1,2)));
1654 static int fmtstr(char *, size_t, const char *, ...)
1655 __attribute__((__format__(__printf__,3,4)));
1657 static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1660 static void out1str(const char *p)
1665 static void out2str(const char *p)
1672 * Initialization code.
1676 * This routine initializes the builtin variables.
1687 * PS1 depends on uid
1689 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1690 vps1.text = "PS1=\\w \\$ ";
1693 vps1.text = "PS1=# ";
1696 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1698 vpp = hashvar(vp->text);
1701 } while (++vp < end);
1710 basepf.nextc = basepf.buf = basebuf;
1715 signal(SIGCHLD, SIG_DFL);
1724 for (envp = environ ; *envp ; envp++) {
1725 if (strchr(*envp, '=')) {
1726 setvareq(*envp, VEXPORT|VTEXTFIXED);
1730 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1731 setvar("PPID", ppid, 0);
1736 /* PEOF (the end of file marker) */
1739 * The input line number. Input.c just defines this variable, and saves
1740 * and restores it when files are pushed and popped. The user of this
1741 * package must set its value.
1744 static int pgetc(void);
1745 static int pgetc2(void);
1746 static int preadbuffer(void);
1747 static void pungetc(void);
1748 static void pushstring(char *, void *);
1749 static void popstring(void);
1750 static void setinputfile(const char *, int);
1751 static void setinputfd(int, int);
1752 static void setinputstring(char *);
1753 static void popfile(void);
1754 static void popallfiles(void);
1755 static void closescript(void);
1758 /* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1761 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1764 #define FORK_NOJOB 2
1766 /* mode flags for showjob(s) */
1767 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1768 #define SHOW_PID 0x04 /* include process pid */
1769 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1773 * A job structure contains information about a job. A job is either a
1774 * single process or a set of processes contained in a pipeline. In the
1775 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1780 pid_t pid; /* process id */
1781 int status; /* last process status from wait() */
1782 char *cmd; /* text of command being run */
1786 struct procstat ps0; /* status of process */
1787 struct procstat *ps; /* status or processes when more than one */
1789 int stopstatus; /* status of a stopped job */
1792 nprocs: 16, /* number of processes */
1794 #define JOBRUNNING 0 /* at least one proc running */
1795 #define JOBSTOPPED 1 /* all procs are stopped */
1796 #define JOBDONE 2 /* all procs are completed */
1798 sigint: 1, /* job was killed by SIGINT */
1799 jobctl: 1, /* job running under job control */
1801 waited: 1, /* true if this entry has been waited for */
1802 used: 1, /* true if this entry is in used */
1803 changed: 1; /* true if status has changed */
1804 struct job *prev_job; /* previous job */
1807 static pid_t backgndpid; /* pid of last background process */
1808 static int job_warning; /* user was warned about stopped jobs */
1810 static int jobctl; /* true if doing job control */
1813 static struct job *makejob(union node *, int);
1814 static int forkshell(struct job *, union node *, int);
1815 static int waitforjob(struct job *);
1816 static int stoppedjobs(void);
1819 #define setjobctl(on) /* do nothing */
1821 static void setjobctl(int);
1822 static void showjobs(FILE *, int);
1825 /* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1828 /* pid of main shell */
1830 /* true if we aren't a child of the main shell */
1831 static int rootshell;
1833 static void readcmdfile(char *);
1834 static void cmdloop(int);
1836 /* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1840 struct stack_block *stackp;
1843 struct stackmark *marknext;
1846 /* minimum size of a block */
1847 #define MINSIZE SHELL_ALIGN(504)
1849 struct stack_block {
1850 struct stack_block *prev;
1851 char space[MINSIZE];
1854 static struct stack_block stackbase;
1855 static struct stack_block *stackp = &stackbase;
1856 static struct stackmark *markp;
1857 static char *stacknxt = stackbase.space;
1858 static size_t stacknleft = MINSIZE;
1859 static char *sstrend = stackbase.space + MINSIZE;
1860 static int herefd = -1;
1863 static pointer ckmalloc(size_t);
1864 static pointer ckrealloc(pointer, size_t);
1865 static char *savestr(const char *);
1866 static pointer stalloc(size_t);
1867 static void stunalloc(pointer);
1868 static void setstackmark(struct stackmark *);
1869 static void popstackmark(struct stackmark *);
1870 static void growstackblock(void);
1871 static void *growstackstr(void);
1872 static char *makestrspace(size_t, char *);
1873 static char *stnputs(const char *, size_t, char *);
1874 static char *stputs(const char *, char *);
1877 static inline char *_STPUTC(char c, char *p) {
1884 #define stackblock() ((void *)stacknxt)
1885 #define stackblocksize() stacknleft
1886 #define STARTSTACKSTR(p) ((p) = stackblock())
1887 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1888 #define CHECKSTRSPACE(n, p) \
1892 size_t m = sstrend - q; \
1894 (p) = makestrspace(l, q); \
1897 #define USTPUTC(c, p) (*p++ = (c))
1898 #define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1899 #define STUNPUTC(p) (--p)
1900 #define STTOPC(p) p[-1]
1901 #define STADJUST(amount, p) (p += (amount))
1903 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1904 #define ungrabstackstr(s, p) stunalloc((s))
1905 #define stackstrend() ((void *)sstrend)
1907 #define ckfree(p) free((pointer)(p))
1909 /* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1912 #define DOLATSTRLEN 4
1914 static char *prefix(const char *, const char *);
1915 static int number(const char *);
1916 static int is_number(const char *);
1917 static char *single_quote(const char *);
1918 static char *sstrdup(const char *);
1920 #define equal(s1, s2) (strcmp(s1, s2) == 0)
1921 #define scopy(s1, s2) ((void)strcpy(s2, s1))
1923 /* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1926 int nparam; /* # of positional parameters (without $0) */
1927 unsigned char malloc; /* if parameter list dynamically allocated */
1928 char **p; /* parameter list */
1929 #ifdef CONFIG_ASH_GETOPTS
1930 int optind; /* next parameter to be processed by getopts */
1931 int optoff; /* used by getopts */
1936 #define eflag optlist[0]
1937 #define fflag optlist[1]
1938 #define Iflag optlist[2]
1939 #define iflag optlist[3]
1940 #define mflag optlist[4]
1941 #define nflag optlist[5]
1942 #define sflag optlist[6]
1943 #define xflag optlist[7]
1944 #define vflag optlist[8]
1945 #define Cflag optlist[9]
1946 #define aflag optlist[10]
1947 #define bflag optlist[11]
1948 #define uflag optlist[12]
1949 #define qflag optlist[13]
1952 #define nolog optlist[14]
1953 #define debug optlist[15]
1959 /* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1962 static const char *const optletters_optnames[NOPTS] = {
1983 #define optletters(n) optletters_optnames[(n)][0]
1984 #define optnames(n) (&optletters_optnames[(n)][1])
1987 static char optlist[NOPTS];
1990 static char *arg0; /* value of $0 */
1991 static struct shparam shellparam; /* $@ current positional parameters */
1992 static char **argptr; /* argument list for builtin commands */
1993 static char *optionarg; /* set by nextopt (like getopt) */
1994 static char *optptr; /* used by nextopt */
1996 static char *minusc; /* argument to -c option */
1999 static void procargs(int, char **);
2000 static void optschanged(void);
2001 static void setparam(char **);
2002 static void freeparam(volatile struct shparam *);
2003 static int shiftcmd(int, char **);
2004 static int setcmd(int, char **);
2005 static int nextopt(const char *);
2007 /* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
2009 /* flags passed to redirect */
2010 #define REDIR_PUSH 01 /* save previous values of file descriptors */
2011 #define REDIR_SAVEFD2 03 /* set preverrout */
2014 static void redirect(union node *, int);
2015 static void popredir(int);
2016 static void clearredir(int);
2017 static int copyfd(int, int);
2018 static int redirectsafe(union node *, int);
2020 /* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2024 static void showtree(union node *);
2025 static void trace(const char *, ...);
2026 static void tracev(const char *, va_list);
2027 static void trargs(char **);
2028 static void trputc(int);
2029 static void trputs(const char *);
2030 static void opentrace(void);
2033 /* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2036 /* trap handler commands */
2037 static char *trap[NSIG];
2038 /* current value of signal */
2039 static char sigmode[NSIG - 1];
2040 /* indicates specified signal received */
2041 static char gotsig[NSIG - 1];
2043 static void clear_traps(void);
2044 static void setsignal(int);
2045 static void ignoresig(int);
2046 static void onsig(int);
2047 static void dotrap(void);
2048 static void setinteractive(int);
2049 static void exitshell(void) __attribute__((__noreturn__));
2050 static int decode_signal(const char *, int);
2053 * This routine is called when an error or an interrupt occurs in an
2054 * interactive shell and control is returned to the main command loop.
2069 parselleft = parsenleft = 0; /* clear input buffer */
2073 /* from parser.c: */
2086 #ifdef CONFIG_ASH_ALIAS
2087 static struct alias *atab[ATABSIZE];
2089 static void setalias(const char *, const char *);
2090 static struct alias *freealias(struct alias *);
2091 static struct alias **__lookupalias(const char *);
2094 setalias(const char *name, const char *val)
2096 struct alias *ap, **app;
2098 app = __lookupalias(name);
2102 if (!(ap->flag & ALIASINUSE)) {
2105 ap->val = savestr(val);
2106 ap->flag &= ~ALIASDEAD;
2109 ap = ckmalloc(sizeof (struct alias));
2110 ap->name = savestr(name);
2111 ap->val = savestr(val);
2120 unalias(const char *name)
2124 app = __lookupalias(name);
2128 *app = freealias(*app);
2139 struct alias *ap, **app;
2143 for (i = 0; i < ATABSIZE; i++) {
2145 for (ap = *app; ap; ap = *app) {
2146 *app = freealias(*app);
2155 static struct alias *
2156 lookupalias(const char *name, int check)
2158 struct alias *ap = *__lookupalias(name);
2160 if (check && ap && (ap->flag & ALIASINUSE))
2166 * TODO - sort output
2169 aliascmd(int argc, char **argv)
2178 for (i = 0; i < ATABSIZE; i++)
2179 for (ap = atab[i]; ap; ap = ap->next) {
2184 while ((n = *++argv) != NULL) {
2185 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
2186 if ((ap = *__lookupalias(n)) == NULL) {
2187 fprintf(stderr, "%s: %s not found\n", "alias", n);
2201 unaliascmd(int argc, char **argv)
2205 while ((i = nextopt("a")) != '\0') {
2211 for (i = 0; *argptr; argptr++) {
2212 if (unalias(*argptr)) {
2213 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
2221 static struct alias *
2222 freealias(struct alias *ap) {
2225 if (ap->flag & ALIASINUSE) {
2226 ap->flag |= ALIASDEAD;
2238 printalias(const struct alias *ap) {
2239 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2242 static struct alias **
2243 __lookupalias(const char *name) {
2244 unsigned int hashval;
2251 ch = (unsigned char)*p;
2255 ch = (unsigned char)*++p;
2257 app = &atab[hashval % ATABSIZE];
2259 for (; *app; app = &(*app)->next) {
2260 if (equal(name, (*app)->name)) {
2267 #endif /* CONFIG_ASH_ALIAS */
2270 /* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2273 * The cd and pwd commands.
2276 #define CD_PHYSICAL 1
2279 static int docd(const char *, int);
2280 static int cdopt(void);
2282 static char *curdir = nullstr; /* current working directory */
2283 static char *physdir = nullstr; /* physical working directory */
2292 while ((i = nextopt("LP"))) {
2294 flags ^= CD_PHYSICAL;
2303 cdcmd(int argc, char **argv)
2315 dest = bltinlookup(homestr);
2316 else if (dest[0] == '-' && dest[1] == '\0') {
2317 dest = bltinlookup("OLDPWD");
2340 if (!(path = bltinlookup("CDPATH"))) {
2348 p = padvance(&path, dest);
2349 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2353 if (!docd(p, flags))
2358 error("can't cd to %s", dest);
2361 if (flags & CD_PRINT)
2362 out1fmt(snlfmt, curdir);
2368 * Update curdir (the name of the current directory) in response to a
2372 static inline const char *
2373 updatepwd(const char *dir)
2380 cdcomppath = sstrdup(dir);
2383 if (curdir == nullstr)
2385 new = stputs(curdir, new);
2387 new = makestrspace(strlen(dir) + 2, new);
2388 lim = stackblock() + 1;
2392 if (new > lim && *lim == '/')
2397 if (dir[1] == '/' && dir[2] != '/') {
2403 p = strtok(cdcomppath, "/");
2407 if (p[1] == '.' && p[2] == '\0') {
2414 } else if (p[1] == '\0')
2418 new = stputs(p, new);
2426 return stackblock();
2430 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2431 * know that the current directory has changed.
2435 docd(const char *dest, int flags)
2437 const char *dir = 0;
2440 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2443 if (!(flags & CD_PHYSICAL)) {
2444 dir = updatepwd(dest);
2459 * Find out what the current directory is. If we already know the current
2460 * directory, this routine returns immediately.
2462 static inline char *
2465 char *dir = getcwd(0, 0);
2466 return dir ? dir : nullstr;
2470 pwdcmd(int argc, char **argv)
2473 const char *dir = curdir;
2477 if (physdir == nullstr)
2481 out1fmt(snlfmt, dir);
2486 setpwd(const char *val, int setold)
2490 oldcur = dir = curdir;
2493 setvar("OLDPWD", oldcur, VEXPORT);
2496 if (physdir != nullstr) {
2497 if (physdir != oldcur)
2501 if (oldcur == val || !val) {
2508 if (oldcur != dir && oldcur != nullstr) {
2513 setvar("PWD", dir, VEXPORT);
2516 /* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2519 * Errors and exceptions.
2523 * Code to handle exceptions in C.
2528 static void exverror(int, const char *, va_list)
2529 __attribute__((__noreturn__));
2532 * Called to raise an exception. Since C doesn't include exceptions, we
2533 * just do a longjmp to the exception handler. The type of exception is
2534 * stored in the global variable "exception".
2541 if (handler == NULL)
2547 longjmp(handler->loc, 1);
2552 * Called from trap.c when a SIGINT is received. (If the user specifies
2553 * that SIGINT is to be trapped or ignored using the trap builtin, then
2554 * this routine is not called.) Suppressint is nonzero when interrupts
2555 * are held using the INTOFF macro. (The test for iflag is just
2556 * defensive programming.)
2566 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2567 if (!(rootshell && iflag)) {
2568 signal(SIGINT, SIG_DFL);
2578 exvwarning(const char *msg, va_list ap)
2591 fprintf(errs, fmt, name, startlinno);
2592 vfprintf(errs, msg, ap);
2593 outcslow('\n', errs);
2597 * Exverror is called to raise the error exception. If the second argument
2598 * is not NULL then error prints an error message using printf style
2599 * formatting. It then raises the error exception.
2602 exverror(int cond, const char *msg, va_list ap)
2606 TRACE(("exverror(%d, \"", cond));
2608 TRACE(("\") pid=%d\n", getpid()));
2610 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2613 exvwarning(msg, ap);
2622 error(const char *msg, ...)
2627 exverror(EXERROR, msg, ap);
2634 exerror(int cond, const char *msg, ...)
2639 exverror(cond, msg, ap);
2645 * error/warning routines for external builtins
2649 sh_warnx(const char *fmt, ...)
2654 exvwarning(fmt, ap);
2660 * Return a string describing an error. The returned string may be a
2661 * pointer to a static buffer that will be overwritten on the next call.
2662 * Action describes the operation that got the error.
2666 errmsg(int e, const char *em)
2668 if(e == ENOENT || e == ENOTDIR) {
2676 /* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2679 * Evaluate a command.
2682 /* flags in argument to evaltree */
2683 #define EV_EXIT 01 /* exit after evaluating tree */
2684 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2685 #define EV_BACKCMD 04 /* command executing within back quotes */
2688 static void evalloop(union node *, int);
2689 static void evalfor(union node *, int);
2690 static void evalcase(union node *, int);
2691 static void evalsubshell(union node *, int);
2692 static void expredir(union node *);
2693 static void evalpipe(union node *, int);
2694 static void evalcommand(union node *, int);
2695 static int evalbltin(const struct builtincmd *, int, char **);
2696 static int evalfun(struct funcnode *, int, char **, int);
2697 static void prehash(union node *);
2698 static int bltincmd(int, char **);
2701 static const struct builtincmd bltin = {
2707 * Called to reset things after an exception.
2715 evalcmd(int argc, char **argv)
2724 STARTSTACKSTR(concat);
2727 concat = stputs(p, concat);
2728 if ((p = *ap++) == NULL)
2730 STPUTC(' ', concat);
2732 STPUTC('\0', concat);
2733 p = grabstackstr(concat);
2742 * Execute a command or commands contained in a string.
2749 struct stackmark smark;
2751 setstackmark(&smark);
2754 while ((n = parsecmd(0)) != NEOF) {
2756 popstackmark(&smark);
2761 popstackmark(&smark);
2767 * Evaluate a parse tree. The value is left in the global variable
2772 evaltree(union node *n, int flags)
2775 void (*evalfn)(union node *, int);
2779 TRACE(("evaltree(NULL) called\n"));
2782 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2783 getpid(), n, n->type, flags));
2787 out1fmt("Node type = %d\n", n->type);
2792 evaltree(n->nnot.com, EV_TESTED);
2793 status = !exitstatus;
2796 expredir(n->nredir.redirect);
2797 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2799 evaltree(n->nredir.n, flags & EV_TESTED);
2800 status = exitstatus;
2805 evalfn = evalcommand;
2807 if (eflag && !(flags & EV_TESTED))
2819 evalfn = evalsubshell;
2831 #error NAND + 1 != NOR
2833 #if NOR + 1 != NSEMI
2834 #error NOR + 1 != NSEMI
2836 isor = n->type - NAND;
2839 (flags | ((isor >> 1) - 1)) & EV_TESTED
2841 if (!exitstatus == isor)
2853 evaltree(n->nif.test, EV_TESTED);
2856 if (exitstatus == 0) {
2859 } else if (n->nif.elsepart) {
2860 n = n->nif.elsepart;
2865 defun(n->narg.text, n->narg.next);
2869 exitstatus = status;
2875 if (flags & EV_EXIT || checkexit & exitstatus)
2880 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2883 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2887 evalloop(union node *n, int flags)
2897 evaltree(n->nbinary.ch1, EV_TESTED);
2899 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2903 if (evalskip == SKIPBREAK && --skipcount <= 0)
2908 if (n->type != NWHILE)
2912 evaltree(n->nbinary.ch2, flags);
2913 status = exitstatus;
2918 exitstatus = status;
2924 evalfor(union node *n, int flags)
2926 struct arglist arglist;
2929 struct stackmark smark;
2931 setstackmark(&smark);
2932 arglist.lastp = &arglist.list;
2933 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2934 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2939 *arglist.lastp = NULL;
2944 for (sp = arglist.list ; sp ; sp = sp->next) {
2945 setvar(n->nfor.var, sp->text, 0);
2946 evaltree(n->nfor.body, flags);
2948 if (evalskip == SKIPCONT && --skipcount <= 0) {
2952 if (evalskip == SKIPBREAK && --skipcount <= 0)
2959 popstackmark(&smark);
2965 evalcase(union node *n, int flags)
2969 struct arglist arglist;
2970 struct stackmark smark;
2972 setstackmark(&smark);
2973 arglist.lastp = &arglist.list;
2974 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2976 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2977 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2978 if (casematch(patp, arglist.list->text)) {
2979 if (evalskip == 0) {
2980 evaltree(cp->nclist.body, flags);
2987 popstackmark(&smark);
2993 * Kick off a subshell to evaluate a tree.
2997 evalsubshell(union node *n, int flags)
3000 int backgnd = (n->type == NBACKGND);
3003 expredir(n->nredir.redirect);
3004 if (!backgnd && flags & EV_EXIT && !trap[0])
3008 if (forkshell(jp, n, backgnd) == 0) {
3012 flags &=~ EV_TESTED;
3014 redirect(n->nredir.redirect, 0);
3015 evaltreenr(n->nredir.n, flags);
3020 status = waitforjob(jp);
3021 exitstatus = status;
3028 * Compute the names of the files in a redirection list.
3032 expredir(union node *n)
3036 for (redir = n ; redir ; redir = redir->nfile.next) {
3038 fn.lastp = &fn.list;
3039 switch (redir->type) {
3045 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3046 redir->nfile.expfname = fn.list->text;
3050 if (redir->ndup.vname) {
3051 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3052 fixredir(redir, fn.list->text, 1);
3062 * Evaluate a pipeline. All the processes in the pipeline are children
3063 * of the process creating the pipeline. (This differs from some versions
3064 * of the shell, which make the last process in a pipeline the parent
3069 evalpipe(union node *n, int flags)
3072 struct nodelist *lp;
3077 TRACE(("evalpipe(0x%lx) called\n", (long)n));
3079 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3083 jp = makejob(n, pipelen);
3085 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3089 if (pipe(pip) < 0) {
3091 error("Pipe call failed");
3094 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3107 evaltreenr(lp->n, flags);
3115 if (n->npipe.backgnd == 0) {
3116 exitstatus = waitforjob(jp);
3117 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
3125 * Execute a command inside back quotes. If it's a builtin command, we
3126 * want to save its output in a block obtained from malloc. Otherwise
3127 * we fork off a subprocess and get the output of the command via a pipe.
3128 * Should be called with interrupts off.
3132 evalbackcmd(union node *n, struct backcmd *result)
3144 saveherefd = herefd;
3152 error("Pipe call failed");
3154 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3163 evaltreenr(n, EV_EXIT);
3167 result->fd = pip[0];
3170 herefd = saveherefd;
3172 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3173 result->fd, result->buf, result->nleft, result->jp));
3176 #ifdef CONFIG_ASH_CMDCMD
3177 static inline char **
3178 parse_command_args(char **argv, const char **path)
3190 if (c == '-' && !*cp) {
3200 /* run 'typecmd' for other options */
3203 } while ((c = *cp++));
3212 * Execute a simple command.
3216 evalcommand(union node *cmd, int flags)
3218 struct stackmark smark;
3220 struct arglist arglist;
3221 struct arglist varlist;
3224 const struct strlist *sp;
3225 struct cmdentry cmdentry;
3234 /* First expand the arguments. */
3235 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3236 setstackmark(&smark);
3237 back_exitstatus = 0;
3239 cmdentry.cmdtype = CMDBUILTIN;
3240 cmdentry.u.cmd = &bltin;
3241 varlist.lastp = &varlist.list;
3242 *varlist.lastp = NULL;
3243 arglist.lastp = &arglist.list;
3244 *arglist.lastp = NULL;
3247 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3248 struct strlist **spp;
3250 spp = arglist.lastp;
3251 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3252 for (sp = *spp; sp; sp = sp->next)
3256 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3257 for (sp = arglist.list ; sp ; sp = sp->next) {
3258 TRACE(("evalcommand arg: %s\n", sp->text));
3259 *nargv++ = sp->text;
3264 if (iflag && funcnest == 0 && argc > 0)
3265 lastarg = nargv[-1];
3268 expredir(cmd->ncmd.redirect);
3269 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
3272 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3273 struct strlist **spp;
3276 spp = varlist.lastp;
3277 expandarg(argp, &varlist, EXP_VARTILDE);
3280 * Modify the command lookup path, if a PATH= assignment
3284 if (varequal(p, path))
3288 /* Print the command if xflag is set. */
3291 const char *p = " %s";
3294 dprintf(preverrout_fd, p, ps4val());
3297 for(n = 0; n < 2; n++) {
3299 dprintf(preverrout_fd, p, sp->text);
3307 bb_full_write(preverrout_fd, "\n", 1);
3313 /* Now locate the command. */
3315 const char *oldpath;
3316 int cmd_flag = DO_ERR;
3321 find_command(argv[0], &cmdentry, cmd_flag, path);
3322 if (cmdentry.cmdtype == CMDUNKNOWN) {
3328 /* implement bltin and command here */
3329 if (cmdentry.cmdtype != CMDBUILTIN)
3332 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3333 if (cmdentry.u.cmd == EXECCMD)
3335 #ifdef CONFIG_ASH_CMDCMD
3336 if (cmdentry.u.cmd == COMMANDCMD) {
3339 nargv = parse_command_args(argv, &path);
3342 argc -= nargv - argv;
3344 cmd_flag |= DO_NOFUNC;
3352 /* We have a redirection error. */
3356 exitstatus = status;
3360 /* Execute the command. */
3361 switch (cmdentry.cmdtype) {
3363 /* Fork off a child process if necessary. */
3364 if (!(flags & EV_EXIT) || trap[0]) {
3366 jp = makejob(cmd, 1);
3367 if (forkshell(jp, cmd, FORK_FG) != 0) {
3368 exitstatus = waitforjob(jp);
3374 listsetvar(varlist.list, VEXPORT|VSTACK);
3375 shellexec(argv, path, cmdentry.u.index);
3379 cmdenviron = varlist.list;
3381 struct strlist *list = cmdenviron;
3383 if (spclbltin > 0 || argc == 0) {
3385 if (cmd_is_exec && argc > 1)
3388 listsetvar(list, i);
3390 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3405 exit_status = j + 128;
3406 exitstatus = exit_status;
3408 if (i == EXINT || spclbltin > 0) {
3410 longjmp(handler->loc, 1);
3417 listsetvar(varlist.list, 0);
3418 if (evalfun(cmdentry.u.func, argc, argv, flags))
3424 popredir(cmd_is_exec);
3426 /* dsl: I think this is intended to be used to support
3427 * '_' in 'vi' command mode during line editing...
3428 * However I implemented that within libedit itself.
3430 setvar("_", lastarg, 0);
3431 popstackmark(&smark);
3435 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3436 char *volatile savecmdname;
3437 struct jmploc *volatile savehandler;
3438 struct jmploc jmploc;
3441 savecmdname = commandname;
3442 if ((i = setjmp(jmploc.loc)))
3444 savehandler = handler;
3446 commandname = argv[0];
3448 optptr = NULL; /* initialize nextopt */
3449 exitstatus = (*cmd->builtin)(argc, argv);
3452 exitstatus |= ferror(stdout);
3453 commandname = savecmdname;
3455 handler = savehandler;
3461 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3463 volatile struct shparam saveparam;
3464 struct localvar *volatile savelocalvars;
3465 struct jmploc *volatile savehandler;
3466 struct jmploc jmploc;
3469 saveparam = shellparam;
3470 savelocalvars = localvars;
3471 if ((e = setjmp(jmploc.loc))) {
3475 savehandler = handler;
3478 shellparam.malloc = 0;
3481 shellparam.nparam = argc - 1;
3482 shellparam.p = argv + 1;
3483 #ifdef CONFIG_ASH_GETOPTS
3484 shellparam.optind = 1;
3485 shellparam.optoff = -1;
3488 evaltree(&func->n, flags & EV_TESTED);
3494 localvars = savelocalvars;
3495 freeparam(&shellparam);
3496 shellparam = saveparam;
3497 handler = savehandler;
3499 if (evalskip == SKIPFUNC) {
3508 goodname(const char *p)
3510 return !*endofname(p);
3514 * Search for a command. This is called before we fork so that the
3515 * location of the command will be available in the parent as well as
3516 * the child. The check for "goodname" is an overly conservative
3517 * check that the name will not be subject to expansion.
3521 prehash(union node *n)
3523 struct cmdentry entry;
3525 if (n->type == NCMD && n->ncmd.args)
3526 if (goodname(n->ncmd.args->narg.text))
3527 find_command(n->ncmd.args->narg.text, &entry, 0,
3534 * Builtin commands. Builtin commands whose functions are closely
3535 * tied to evaluation are implemented here.
3543 bltincmd(int argc, char **argv)
3546 * Preserve exitstatus of a previous possible redirection
3549 return back_exitstatus;
3554 * Handle break and continue commands. Break, continue, and return are
3555 * all handled by setting the evalskip flag. The evaluation routines
3556 * above all check this flag, and if it is set they start skipping
3557 * commands rather than executing them. The variable skipcount is
3558 * the number of loops to break/continue, or the number of function
3559 * levels to return. (The latter is always 1.) It should probably
3560 * be an error to break out of more loops than exist, but it isn't
3561 * in the standard shell so we don't make it one here.
3565 breakcmd(int argc, char **argv)
3567 int n = argc > 1 ? number(argv[1]) : 1;
3570 error(illnum, argv[1]);
3574 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3582 * The return command.
3586 returncmd(int argc, char **argv)
3588 int ret = argc > 1 ? number(argv[1]) : exitstatus;
3591 evalskip = SKIPFUNC;
3596 /* Do what ksh does; skip the rest of the file */
3597 evalskip = SKIPFILE;
3605 falsecmd(int argc, char **argv)
3612 truecmd(int argc, char **argv)
3619 execcmd(int argc, char **argv)
3622 iflag = 0; /* exit on error */
3625 shellexec(argv + 1, pathval(), 0);
3631 /* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3634 * When commands are first encountered, they are entered in a hash table.
3635 * This ensures that a full path search will not have to be done for them
3636 * on each invocation.
3638 * We should investigate converting to a linear search, even though that
3639 * would make the command name "hash" a misnomer.
3642 #define CMDTABLESIZE 31 /* should be prime */
3643 #define ARB 1 /* actual size determined at run time */
3648 struct tblentry *next; /* next entry in hash chain */
3649 union param param; /* definition of builtin function */
3650 short cmdtype; /* index identifying command */
3651 char rehash; /* if set, cd done since entry created */
3652 char cmdname[ARB]; /* name of command */
3656 static struct tblentry *cmdtable[CMDTABLESIZE];
3657 static int builtinloc = -1; /* index in path of %builtin, or -1 */
3660 static void tryexec(char *, char **, char **);
3661 static void clearcmdentry(int);
3662 static struct tblentry *cmdlookup(const char *, int);
3663 static void delete_cmd_entry(void);
3667 * Exec a program. Never returns. If you change this routine, you may
3668 * have to change the find_command routine as well.
3672 shellexec(char **argv, const char *path, int idx)
3679 envp = environment();
3680 if (strchr(argv[0], '/') != NULL
3681 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3682 || find_applet_by_name(argv[0])
3685 tryexec(argv[0], argv, envp);
3689 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3690 if (--idx < 0 && pathopt == NULL) {
3691 tryexec(cmdname, argv, envp);
3692 if (errno != ENOENT && errno != ENOTDIR)
3699 /* Map to POSIX errors */
3711 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3712 argv[0], e, suppressint ));
3713 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3719 tryexec(char *cmd, char **argv, char **envp)
3722 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3726 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3734 if(strcmp(name, "busybox")) {
3735 for (ap = argv; *ap; ap++);
3736 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3737 *ap++ = cmd = "/bin/busybox";
3738 while ((*ap++ = *argv++));
3742 cmd = "/bin/busybox";
3750 execve(cmd, argv, envp);
3751 } while (errno == EINTR);
3753 execve(cmd, argv, envp);
3757 } else if (errno == ENOEXEC) {
3761 for (ap = argv; *ap; ap++)
3763 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3765 *ap = cmd = (char *)DEFAULT_SHELL;
3768 while ((*ap++ = *argv++))
3778 * Do a path search. The variable path (passed by reference) should be
3779 * set to the start of the path before the first call; padvance will update
3780 * this value as it proceeds. Successive calls to padvance will return
3781 * the possible path expansions in sequence. If an option (indicated by
3782 * a percent sign) appears in the path entry then the global variable
3783 * pathopt will be set to point to it; otherwise pathopt will be set to
3788 padvance(const char **path, const char *name)
3798 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3799 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3800 while (stackblocksize() < len)
3804 memcpy(q, start, p - start);
3812 while (*p && *p != ':') p++;
3818 return stalloc(len);
3822 /*** Command hashing code ***/
3825 printentry(struct tblentry *cmdp)
3831 idx = cmdp->param.index;
3834 name = padvance(&path, cmdp->cmdname);
3836 } while (--idx >= 0);
3837 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3842 hashcmd(int argc, char **argv)
3844 struct tblentry **pp;
3845 struct tblentry *cmdp;
3847 struct cmdentry entry;
3850 while ((c = nextopt("r")) != '\0') {
3854 if (*argptr == NULL) {
3855 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3856 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3857 if (cmdp->cmdtype == CMDNORMAL)
3864 while ((name = *argptr) != NULL) {
3865 if ((cmdp = cmdlookup(name, 0)) != NULL
3866 && (cmdp->cmdtype == CMDNORMAL
3867 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3869 find_command(name, &entry, DO_ERR, pathval());
3870 if (entry.cmdtype == CMDUNKNOWN)
3879 * Resolve a command name. If you change this routine, you may have to
3880 * change the shellexec routine as well.
3884 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3886 struct tblentry *cmdp;
3893 struct builtincmd *bcmd;
3895 /* If name contains a slash, don't use PATH or hash table */
3896 if (strchr(name, '/') != NULL) {
3897 entry->u.index = -1;
3899 while (stat(name, &statb) < 0) {
3904 entry->cmdtype = CMDUNKNOWN;
3908 entry->cmdtype = CMDNORMAL;
3912 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3913 if (find_applet_by_name(name)) {
3914 entry->cmdtype = CMDNORMAL;
3915 entry->u.index = -1;
3920 updatetbl = (path == pathval());
3923 if (strstr(path, "%builtin") != NULL)
3927 /* If name is in the table, check answer will be ok */
3928 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3931 switch (cmdp->cmdtype) {
3949 } else if (cmdp->rehash == 0)
3950 /* if not invalidated by cd, we're done */
3954 /* If %builtin not in path, check for builtin next */
3955 bcmd = find_builtin(name);
3956 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3957 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3959 goto builtin_success;
3961 /* We have to search path. */
3962 prev = -1; /* where to start */
3963 if (cmdp && cmdp->rehash) { /* doing a rehash */
3964 if (cmdp->cmdtype == CMDBUILTIN)
3967 prev = cmdp->param.index;
3973 while ((fullname = padvance(&path, name)) != NULL) {
3974 stunalloc(fullname);
3977 if (prefix(pathopt, "builtin")) {
3979 goto builtin_success;
3981 } else if (!(act & DO_NOFUNC) &&
3982 prefix(pathopt, "func")) {
3985 /* ignore unimplemented options */
3989 /* if rehash, don't redo absolute path names */
3990 if (fullname[0] == '/' && idx <= prev) {
3993 TRACE(("searchexec \"%s\": no change\n", name));
3996 while (stat(fullname, &statb) < 0) {
4001 if (errno != ENOENT && errno != ENOTDIR)
4005 e = EACCES; /* if we fail, this will be the error */
4006 if (!S_ISREG(statb.st_mode))
4008 if (pathopt) { /* this is a %func directory */
4009 stalloc(strlen(fullname) + 1);
4010 readcmdfile(fullname);
4011 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4012 cmdp->cmdtype != CMDFUNCTION)
4013 error("%s not defined in %s", name, fullname);
4014 stunalloc(fullname);
4017 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4019 entry->cmdtype = CMDNORMAL;
4020 entry->u.index = idx;
4024 cmdp = cmdlookup(name, 1);
4025 cmdp->cmdtype = CMDNORMAL;
4026 cmdp->param.index = idx;
4031 /* We failed. If there was an entry for this command, delete it */
4032 if (cmdp && updatetbl)
4035 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4036 entry->cmdtype = CMDUNKNOWN;
4041 entry->cmdtype = CMDBUILTIN;
4042 entry->u.cmd = bcmd;
4046 cmdp = cmdlookup(name, 1);
4047 cmdp->cmdtype = CMDBUILTIN;
4048 cmdp->param.cmd = bcmd;
4052 entry->cmdtype = cmdp->cmdtype;
4053 entry->u = cmdp->param;
4058 * Wrapper around strcmp for qsort/bsearch/...
4060 static int pstrcmp(const void *a, const void *b)
4062 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4066 * Search the table of builtin commands.
4069 static struct builtincmd *
4070 find_builtin(const char *name)
4072 struct builtincmd *bp;
4075 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4084 * Called when a cd is done. Marks all commands so the next time they
4085 * are executed they will be rehashed.
4091 struct tblentry **pp;
4092 struct tblentry *cmdp;
4094 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4095 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4096 if (cmdp->cmdtype == CMDNORMAL || (
4097 cmdp->cmdtype == CMDBUILTIN &&
4098 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4109 * Fix command hash table when PATH changed.
4110 * Called before PATH is changed. The argument is the new value of PATH;
4111 * pathval() still returns the old value at this point.
4112 * Called with interrupts off.
4116 changepath(const char *newval)
4118 const char *old, *new;
4125 firstchange = 9999; /* assume no change */
4131 if ((*old == '\0' && *new == ':')
4132 || (*old == ':' && *new == '\0'))
4134 old = new; /* ignore subsequent differences */
4138 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4145 if (builtinloc < 0 && idx_bltin >= 0)
4146 builtinloc = idx_bltin; /* zap builtins */
4147 if (builtinloc >= 0 && idx_bltin < 0)
4149 clearcmdentry(firstchange);
4150 builtinloc = idx_bltin;
4155 * Clear out command entries. The argument specifies the first entry in
4156 * PATH which has changed.
4160 clearcmdentry(int firstchange)
4162 struct tblentry **tblp;
4163 struct tblentry **pp;
4164 struct tblentry *cmdp;
4167 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4169 while ((cmdp = *pp) != NULL) {
4170 if ((cmdp->cmdtype == CMDNORMAL &&
4171 cmdp->param.index >= firstchange)
4172 || (cmdp->cmdtype == CMDBUILTIN &&
4173 builtinloc >= firstchange)) {
4187 * Locate a command in the command hash table. If "add" is nonzero,
4188 * add the command to the table if it is not already present. The
4189 * variable "lastcmdentry" is set to point to the address of the link
4190 * pointing to the entry, so that delete_cmd_entry can delete the
4193 * Interrupts must be off if called with add != 0.
4196 static struct tblentry **lastcmdentry;
4199 static struct tblentry *
4200 cmdlookup(const char *name, int add)
4202 unsigned int hashval;
4204 struct tblentry *cmdp;
4205 struct tblentry **pp;
4208 hashval = (unsigned char)*p << 4;
4210 hashval += (unsigned char)*p++;
4212 pp = &cmdtable[hashval % CMDTABLESIZE];
4213 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4214 if (equal(cmdp->cmdname, name))
4218 if (add && cmdp == NULL) {
4219 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4220 + strlen(name) + 1);
4222 cmdp->cmdtype = CMDUNKNOWN;
4223 strcpy(cmdp->cmdname, name);
4230 * Delete the command entry returned on the last lookup.
4234 delete_cmd_entry(void)
4236 struct tblentry *cmdp;
4239 cmdp = *lastcmdentry;
4240 *lastcmdentry = cmdp->next;
4241 if (cmdp->cmdtype == CMDFUNCTION)
4242 freefunc(cmdp->param.func);
4249 * Add a new command entry, replacing any existing command entry for
4250 * the same name - except special builtins.
4254 addcmdentry(char *name, struct cmdentry *entry)
4256 struct tblentry *cmdp;
4258 cmdp = cmdlookup(name, 1);
4259 if (cmdp->cmdtype == CMDFUNCTION) {
4260 freefunc(cmdp->param.func);
4262 cmdp->cmdtype = entry->cmdtype;
4263 cmdp->param = entry->u;
4268 * Make a copy of a parse tree.
4271 static inline struct funcnode *
4272 copyfunc(union node *n)
4277 funcblocksize = offsetof(struct funcnode, n);
4280 blocksize = funcblocksize;
4281 f = ckmalloc(blocksize + funcstringsize);
4282 funcblock = (char *) f + offsetof(struct funcnode, n);
4283 funcstring = (char *) f + blocksize;
4290 * Define a shell function.
4294 defun(char *name, union node *func)
4296 struct cmdentry entry;
4299 entry.cmdtype = CMDFUNCTION;
4300 entry.u.func = copyfunc(func);
4301 addcmdentry(name, &entry);
4307 * Delete a function if it exists.
4311 unsetfunc(const char *name)
4313 struct tblentry *cmdp;
4315 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4316 cmdp->cmdtype == CMDFUNCTION)
4321 * Locate and print what a word is...
4325 #ifdef CONFIG_ASH_CMDCMD
4327 describe_command(char *command, int describe_command_verbose)
4329 #define describe_command_verbose 1
4331 describe_command(char *command)
4334 struct cmdentry entry;
4335 struct tblentry *cmdp;
4336 #ifdef CONFIG_ASH_ALIAS
4337 const struct alias *ap;
4339 const char *path = pathval();
4341 if (describe_command_verbose) {
4345 /* First look at the keywords */
4346 if (findkwd(command)) {
4347 out1str(describe_command_verbose ? " is a shell keyword" : command);
4351 #ifdef CONFIG_ASH_ALIAS
4352 /* Then look at the aliases */
4353 if ((ap = lookupalias(command, 0)) != NULL) {
4354 if (describe_command_verbose) {
4355 out1fmt(" is an alias for %s", ap->val);
4364 /* Then check if it is a tracked alias */
4365 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4366 entry.cmdtype = cmdp->cmdtype;
4367 entry.u = cmdp->param;
4369 /* Finally use brute force */
4370 find_command(command, &entry, DO_ABS, path);
4373 switch (entry.cmdtype) {
4375 int j = entry.u.index;
4381 p = padvance(&path, command);
4385 if (describe_command_verbose) {
4387 (cmdp ? " a tracked alias for" : nullstr), p
4396 if (describe_command_verbose) {
4397 out1str(" is a shell function");
4404 if (describe_command_verbose) {
4405 out1fmt(" is a %sshell builtin",
4406 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4407 "special " : nullstr
4415 if (describe_command_verbose) {
4416 out1str(": not found\n");
4422 outstr("\n", stdout);
4427 typecmd(int argc, char **argv)
4432 for (i = 1; i < argc; i++) {
4433 #ifdef CONFIG_ASH_CMDCMD
4434 err |= describe_command(argv[i], 1);
4436 err |= describe_command(argv[i]);
4442 #ifdef CONFIG_ASH_CMDCMD
4444 commandcmd(int argc, char **argv)
4447 int default_path = 0;
4448 int verify_only = 0;
4449 int verbose_verify_only = 0;
4451 while ((c = nextopt("pvV")) != '\0')
4456 "command: nextopt returned character code 0%o\n", c);
4466 verbose_verify_only = 1;
4470 if (default_path + verify_only + verbose_verify_only > 1 ||
4473 "command [-p] command [arg ...]\n"
4474 "command {-v|-V} command\n");
4478 if (verify_only || verbose_verify_only) {
4479 return describe_command(*argptr, verbose_verify_only);
4486 /* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
4489 * Routines to expand arguments to commands. We have to deal with
4490 * backquotes, shell variables, and file metacharacters.
4496 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4497 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4498 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4499 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4500 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4503 * Structure specifying which parts of the string should be searched
4504 * for IFS characters.
4508 struct ifsregion *next; /* next region in list */
4509 int begoff; /* offset of start of region */
4510 int endoff; /* offset of end of region */
4511 int nulonly; /* search for nul bytes only */
4514 /* output of current string */
4515 static char *expdest;
4516 /* list of back quote expressions */
4517 static struct nodelist *argbackq;
4518 /* first struct in list of ifs regions */
4519 static struct ifsregion ifsfirst;
4520 /* last struct in list */
4521 static struct ifsregion *ifslastp;
4522 /* holds expanded arg list */
4523 static struct arglist exparg;
4525 static void argstr(char *, int);
4526 static char *exptilde(char *, char *, int);
4527 static void expbackq(union node *, int, int);
4528 static const char *subevalvar(char *, char *, int, int, int, int, int);
4529 static char *evalvar(char *, int);
4530 static void strtodest(const char *, int, int);
4531 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4532 static ssize_t varvalue(char *, int, int);
4533 static void recordregion(int, int, int);
4534 static void removerecordregions(int);
4535 static void ifsbreakup(char *, struct arglist *);
4536 static void ifsfree(void);
4537 static void expandmeta(struct strlist *, int);
4538 static int patmatch(char *, const char *);
4540 static int cvtnum(arith_t);
4541 static size_t esclen(const char *, const char *);
4542 static char *scanleft(char *, char *, char *, char *, int, int);
4543 static char *scanright(char *, char *, char *, char *, int, int);
4544 static void varunset(const char *, const char *, const char *, int)
4545 __attribute__((__noreturn__));
4548 #define pmatch(a, b) !fnmatch((a), (b), 0)
4550 * Prepare a pattern for a expmeta (internal glob(3)) call.
4552 * Returns an stalloced string.
4555 static inline char *
4556 preglob(const char *pattern, int quoted, int flag) {
4557 flag |= RMESCAPE_GLOB;
4559 flag |= RMESCAPE_QUOTED;
4561 return _rmescapes((char *)pattern, flag);
4566 esclen(const char *start, const char *p) {
4569 while (p > start && *--p == CTLESC) {
4577 * Expand shell variables and backquotes inside a here document.
4581 expandhere(union node *arg, int fd)
4584 expandarg(arg, (struct arglist *)NULL, 0);
4585 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
4590 * Perform variable substitution and command substitution on an argument,
4591 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4592 * perform splitting and file name expansion. When arglist is NULL, perform
4593 * here document expansion.
4597 expandarg(union node *arg, struct arglist *arglist, int flag)
4602 argbackq = arg->narg.backquote;
4603 STARTSTACKSTR(expdest);
4604 ifsfirst.next = NULL;
4606 argstr(arg->narg.text, flag);
4607 if (arglist == NULL) {
4608 return; /* here document expanded */
4610 STPUTC('\0', expdest);
4611 p = grabstackstr(expdest);
4612 exparg.lastp = &exparg.list;
4616 if (flag & EXP_FULL) {
4617 ifsbreakup(p, &exparg);
4618 *exparg.lastp = NULL;
4619 exparg.lastp = &exparg.list;
4620 expandmeta(exparg.list, flag);
4622 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4624 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4627 exparg.lastp = &sp->next;
4631 *exparg.lastp = NULL;
4633 *arglist->lastp = exparg.list;
4634 arglist->lastp = exparg.lastp;
4640 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4641 * characters to allow for further processing. Otherwise treat
4642 * $@ like $* since no splitting will be performed.
4646 argstr(char *p, int flag)
4648 static const char spclchars[] = {
4656 CTLBACKQ | CTLQUOTE,
4657 #ifdef CONFIG_ASH_MATH_SUPPORT
4662 const char *reject = spclchars;
4664 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4665 int breakall = flag & EXP_WORD;
4670 if (!(flag & EXP_VARTILDE)) {
4672 } else if (flag & EXP_VARTILDE2) {
4677 if (flag & EXP_TILDE) {
4683 if (*q == CTLESC && (flag & EXP_QWORD))
4686 p = exptilde(p, q, flag);
4689 startloc = expdest - (char *)stackblock();
4691 length += strcspn(p + length, reject);
4693 if (c && (!(c & 0x80)
4694 #ifdef CONFIG_ASH_MATH_SUPPORT
4698 /* c == '=' || c == ':' || c == CTLENDARI */
4703 expdest = stnputs(p, length, expdest);
4704 newloc = expdest - (char *)stackblock();
4705 if (breakall && !inquotes && newloc > startloc) {
4706 recordregion(startloc, newloc, 0);
4717 if (flag & EXP_VARTILDE2) {
4721 flag |= EXP_VARTILDE2;
4726 * sort of a hack - expand tildes in variable
4727 * assignments (after the first '=' and after ':'s).
4736 case CTLENDVAR: /* ??? */
4739 /* "$@" syntax adherence hack */
4742 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4743 (p[4] == CTLQUOTEMARK || (
4744 p[4] == CTLENDVAR &&
4745 p[5] == CTLQUOTEMARK
4748 p = evalvar(p + 1, flag) + 1;
4751 inquotes = !inquotes;
4764 p = evalvar(p, flag);
4768 case CTLBACKQ|CTLQUOTE:
4769 expbackq(argbackq->n, c, quotes);
4770 argbackq = argbackq->next;
4772 #ifdef CONFIG_ASH_MATH_SUPPORT
4785 exptilde(char *startp, char *p, int flag)
4791 int quotes = flag & (EXP_FULL | EXP_CASE);
4796 while ((c = *++p) != '\0') {
4803 if (flag & EXP_VARTILDE)
4813 if (*name == '\0') {
4814 if ((home = lookupvar(homestr)) == NULL)
4817 if ((pw = getpwnam(name)) == NULL)
4824 startloc = expdest - (char *)stackblock();
4825 strtodest(home, SQSYNTAX, quotes);
4826 recordregion(startloc, expdest - (char *)stackblock(), 0);
4835 removerecordregions(int endoff)
4837 if (ifslastp == NULL)
4840 if (ifsfirst.endoff > endoff) {
4841 while (ifsfirst.next != NULL) {
4842 struct ifsregion *ifsp;
4844 ifsp = ifsfirst.next->next;
4845 ckfree(ifsfirst.next);
4846 ifsfirst.next = ifsp;
4849 if (ifsfirst.begoff > endoff)
4852 ifslastp = &ifsfirst;
4853 ifsfirst.endoff = endoff;
4858 ifslastp = &ifsfirst;
4859 while (ifslastp->next && ifslastp->next->begoff < endoff)
4860 ifslastp=ifslastp->next;
4861 while (ifslastp->next != NULL) {
4862 struct ifsregion *ifsp;
4864 ifsp = ifslastp->next->next;
4865 ckfree(ifslastp->next);
4866 ifslastp->next = ifsp;
4869 if (ifslastp->endoff > endoff)
4870 ifslastp->endoff = endoff;
4874 #ifdef CONFIG_ASH_MATH_SUPPORT
4876 * Expand arithmetic expression. Backup to start of expression,
4877 * evaluate, place result in (backed up) result, adjust string position.
4890 * This routine is slightly over-complicated for
4891 * efficiency. Next we scan backwards looking for the
4892 * start of arithmetic.
4894 start = stackblock();
4901 while (*p != CTLARI) {
4905 error("missing CTLARI (shouldn't happen)");
4910 esc = esclen(start, p);
4920 removerecordregions(begoff);
4929 len = cvtnum(dash_arith(p + 2));
4932 recordregion(begoff, begoff + len, 0);
4937 * Expand stuff in backwards quotes.
4941 expbackq(union node *cmd, int quoted, int quotes)
4949 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4950 struct stackmark smark;
4953 setstackmark(&smark);
4955 startloc = dest - (char *)stackblock();
4957 evalbackcmd(cmd, (struct backcmd *) &in);
4958 popstackmark(&smark);
4965 memtodest(p, i, syntax, quotes);
4969 i = safe_read(in.fd, buf, sizeof buf);
4970 TRACE(("expbackq: read returns %d\n", i));
4980 back_exitstatus = waitforjob(in.jp);
4984 /* Eat all trailing newlines */
4986 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4991 recordregion(startloc, dest - (char *)stackblock(), 0);
4992 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4993 (dest - (char *)stackblock()) - startloc,
4994 (dest - (char *)stackblock()) - startloc,
4995 stackblock() + startloc));
5000 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5011 const char *s = loc2;
5017 match = pmatch(str, s);
5021 if (quotes && *loc == CTLESC)
5031 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5038 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5041 const char *s = loc2;
5046 match = pmatch(str, s);
5053 esc = esclen(startp, loc);
5065 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5069 int saveherefd = herefd;
5070 struct nodelist *saveargbackq = argbackq;
5072 char *rmesc, *rmescend;
5074 char *(*scan)(char *, char *, char *, char *, int , int);
5077 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5078 STPUTC('\0', expdest);
5079 herefd = saveherefd;
5080 argbackq = saveargbackq;
5081 startp = stackblock() + startloc;
5085 setvar(str, startp, 0);
5086 amount = startp - expdest;
5087 STADJUST(amount, expdest);
5091 varunset(p, str, startp, varflags);
5095 subtype -= VSTRIMRIGHT;
5097 if (subtype < 0 || subtype > 3)
5102 rmescend = stackblock() + strloc;
5104 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5105 if (rmesc != startp) {
5107 startp = stackblock() + startloc;
5111 str = stackblock() + strloc;
5112 preglob(str, varflags & VSQUOTE, 0);
5114 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5115 zero = subtype >> 1;
5116 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5117 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5119 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5122 memmove(startp, loc, str - loc);
5123 loc = startp + (str - loc) - 1;
5126 amount = loc - expdest;
5127 STADJUST(amount, expdest);
5134 * Expand a variable, and return a pointer to the next character in the
5138 evalvar(char *p, int flag)
5151 quotes = flag & (EXP_FULL | EXP_CASE);
5153 subtype = varflags & VSTYPE;
5154 quoted = varflags & VSQUOTE;
5156 easy = (!quoted || (*var == '@' && shellparam.nparam));
5157 startloc = expdest - (char *)stackblock();
5158 p = strchr(p, '=') + 1;
5161 varlen = varvalue(var, varflags, flag);
5162 if (varflags & VSNUL)
5165 if (subtype == VSPLUS) {
5166 varlen = -1 - varlen;
5170 if (subtype == VSMINUS) {
5174 p, flag | EXP_TILDE |
5175 (quoted ? EXP_QWORD : EXP_WORD)
5184 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5186 if (subevalvar(p, var, 0, subtype, startloc,
5190 * Remove any recorded regions beyond
5193 removerecordregions(startloc);
5203 if (varlen < 0 && uflag)
5204 varunset(p, var, 0, 0);
5206 if (subtype == VSLENGTH) {
5207 cvtnum(varlen > 0 ? varlen : 0);
5211 if (subtype == VSNORMAL) {
5215 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5224 case VSTRIMRIGHTMAX:
5233 * Terminate the string and start recording the pattern
5236 STPUTC('\0', expdest);
5237 patloc = expdest - (char *)stackblock();
5238 if (subevalvar(p, NULL, patloc, subtype,
5239 startloc, varflags, quotes) == 0) {
5240 int amount = expdest - (
5241 (char *)stackblock() + patloc - 1
5243 STADJUST(-amount, expdest);
5245 /* Remove any recorded regions beyond start of variable */
5246 removerecordregions(startloc);
5251 if (subtype != VSNORMAL) { /* skip to end of alternative */
5254 if ((c = *p++) == CTLESC)
5256 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5258 argbackq = argbackq->next;
5259 } else if (c == CTLVAR) {
5260 if ((*p++ & VSTYPE) != VSNORMAL)
5262 } else if (c == CTLENDVAR) {
5273 * Put a string on the stack.
5277 memtodest(const char *p, size_t len, int syntax, int quotes) {
5280 q = makestrspace(len * 2, q);
5286 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5296 strtodest(const char *p, int syntax, int quotes)
5298 memtodest(p, strlen(p), syntax, quotes);
5303 * Add the value of a specialized variable to the stack string.
5307 varvalue(char *name, int varflags, int flags)
5317 int quoted = varflags & VSQUOTE;
5318 int subtype = varflags & VSTYPE;
5319 int quotes = flags & (EXP_FULL | EXP_CASE);
5321 if (quoted && (flags & EXP_FULL))
5322 sep = 1 << CHAR_BIT;
5324 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5333 num = shellparam.nparam;
5343 p = makestrspace(NOPTS, expdest);
5344 for (i = NOPTS - 1; i >= 0; i--) {
5346 USTPUTC(optletters(i), p);
5357 sep = ifsset() ? ifsval()[0] : ' ';
5358 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5361 if (!(ap = shellparam.p))
5363 while ((p = *ap++)) {
5366 partlen = strlen(p);
5369 if (len > partlen && sep) {
5373 if (subtype == VSPLUS || subtype == VSLENGTH) {
5383 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5384 memtodest(p, partlen, syntax, quotes);
5398 if (num < 0 || num > shellparam.nparam)
5400 p = num ? shellparam.p[num - 1] : arg0;
5403 p = lookupvar(name);
5409 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5410 memtodest(p, len, syntax, quotes);
5414 if (subtype == VSPLUS || subtype == VSLENGTH)
5415 STADJUST(-len, expdest);
5421 * Record the fact that we have to scan this region of the
5422 * string for IFS characters.
5426 recordregion(int start, int end, int nulonly)
5428 struct ifsregion *ifsp;
5430 if (ifslastp == NULL) {
5434 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5436 ifslastp->next = ifsp;
5440 ifslastp->begoff = start;
5441 ifslastp->endoff = end;
5442 ifslastp->nulonly = nulonly;
5447 * Break the argument string into pieces based upon IFS and add the
5448 * strings to the argument list. The regions of the string to be
5449 * searched for IFS characters have been stored by recordregion.
5452 ifsbreakup(char *string, struct arglist *arglist)
5454 struct ifsregion *ifsp;
5459 const char *ifs, *realifs;
5465 if (ifslastp != NULL) {
5468 realifs = ifsset() ? ifsval() : defifs;
5471 p = string + ifsp->begoff;
5472 nulonly = ifsp->nulonly;
5473 ifs = nulonly ? nullstr : realifs;
5475 while (p < string + ifsp->endoff) {
5479 if (strchr(ifs, *p)) {
5481 ifsspc = (strchr(defifs, *p) != NULL);
5482 /* Ignore IFS whitespace at start */
5483 if (q == start && ifsspc) {
5489 sp = (struct strlist *)stalloc(sizeof *sp);
5491 *arglist->lastp = sp;
5492 arglist->lastp = &sp->next;
5496 if (p >= string + ifsp->endoff) {
5502 if (strchr(ifs, *p) == NULL ) {
5505 } else if (strchr(defifs, *p) == NULL) {
5521 } while ((ifsp = ifsp->next) != NULL);
5530 sp = (struct strlist *)stalloc(sizeof *sp);
5532 *arglist->lastp = sp;
5533 arglist->lastp = &sp->next;
5539 struct ifsregion *p;
5544 struct ifsregion *ifsp;
5550 ifsfirst.next = NULL;
5554 static void expmeta(char *, char *);
5555 static struct strlist *expsort(struct strlist *);
5556 static struct strlist *msort(struct strlist *, int);
5558 static char *expdir;
5562 expandmeta(struct strlist *str, int flag)
5564 static const char metachars[] = {
5567 /* TODO - EXP_REDIR */
5570 struct strlist **savelastp;
5576 if (!strpbrk(str->text, metachars))
5578 savelastp = exparg.lastp;
5581 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5583 int i = strlen(str->text);
5584 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5592 if (exparg.lastp == savelastp) {
5597 *exparg.lastp = str;
5598 rmescapes(str->text);
5599 exparg.lastp = &str->next;
5601 *exparg.lastp = NULL;
5602 *savelastp = sp = expsort(*savelastp);
5603 while (sp->next != NULL)
5605 exparg.lastp = &sp->next;
5612 * Add a file name to the list.
5616 addfname(const char *name)
5620 sp = (struct strlist *)stalloc(sizeof *sp);
5621 sp->text = sstrdup(name);
5623 exparg.lastp = &sp->next;
5628 * Do metacharacter (i.e. *, ?, [...]) expansion.
5632 expmeta(char *enddir, char *name)
5647 for (p = name; *p; p++) {
5648 if (*p == '*' || *p == '?')
5650 else if (*p == '[') {
5657 if (*q == '/' || *q == '\0')
5664 } else if (*p == '\\')
5666 else if (*p == '/') {
5673 if (metaflag == 0) { /* we've reached the end of the file name */
5674 if (enddir != expdir)
5682 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5693 } while (p < start);
5695 if (enddir == expdir) {
5697 } else if (enddir == expdir + 1 && *expdir == '/') {
5703 if ((dirp = opendir(cp)) == NULL)
5705 if (enddir != expdir)
5707 if (*endname == 0) {
5719 while (! intpending && (dp = readdir(dirp)) != NULL) {
5720 if (dp->d_name[0] == '.' && ! matchdot)
5722 if (pmatch(start, dp->d_name)) {
5724 scopy(dp->d_name, enddir);
5727 for (p = enddir, cp = dp->d_name;
5728 (*p++ = *cp++) != '\0';)
5731 expmeta(p, endname);
5741 * Sort the results of file name expansion. It calculates the number of
5742 * strings to sort and then calls msort (short for merge sort) to do the
5746 static struct strlist *
5747 expsort(struct strlist *str)
5753 for (sp = str ; sp ; sp = sp->next)
5755 return msort(str, len);
5759 static struct strlist *
5760 msort(struct strlist *list, int len)
5762 struct strlist *p, *q = NULL;
5763 struct strlist **lpp;
5771 for (n = half ; --n >= 0 ; ) {
5775 q->next = NULL; /* terminate first half of list */
5776 q = msort(list, half); /* sort first half of list */
5777 p = msort(p, len - half); /* sort second half */
5780 #ifdef CONFIG_LOCALE_SUPPORT
5781 if (strcoll(p->text, q->text) < 0)
5783 if (strcmp(p->text, q->text) < 0)
5788 if ((p = *lpp) == NULL) {
5795 if ((q = *lpp) == NULL) {
5806 * Returns true if the pattern matches the string.
5810 patmatch(char *pattern, const char *string)
5812 return pmatch(preglob(pattern, 0, 0), string);
5817 * Remove any CTLESC characters from a string.
5821 _rmescapes(char *str, int flag)
5824 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5829 p = strpbrk(str, qchars);
5835 if (flag & RMESCAPE_ALLOC) {
5836 size_t len = p - str;
5837 size_t fulllen = len + strlen(p) + 1;
5839 if (flag & RMESCAPE_GROW) {
5840 r = makestrspace(fulllen, expdest);
5841 } else if (flag & RMESCAPE_HEAP) {
5842 r = ckmalloc(fulllen);
5844 r = stalloc(fulllen);
5848 q = mempcpy(q, str, len);
5851 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5852 globbing = flag & RMESCAPE_GLOB;
5853 notescaped = globbing;
5855 if (*p == CTLQUOTEMARK) {
5856 inquotes = ~inquotes;
5858 notescaped = globbing;
5862 /* naked back slash */
5868 if (notescaped && inquotes && *p != '/') {
5872 notescaped = globbing;
5877 if (flag & RMESCAPE_GROW) {
5879 STADJUST(q - r + 1, expdest);
5886 * See if a pattern matches in a case statement.
5890 casematch(union node *pattern, char *val)
5892 struct stackmark smark;
5895 setstackmark(&smark);
5896 argbackq = pattern->narg.backquote;
5897 STARTSTACKSTR(expdest);
5899 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5900 STACKSTRNUL(expdest);
5901 result = patmatch(stackblock(), val);
5902 popstackmark(&smark);
5915 expdest = makestrspace(32, expdest);
5916 #ifdef CONFIG_ASH_MATH_SUPPORT_64
5917 len = fmtstr(expdest, 32, "%lld", (long long) num);
5919 len = fmtstr(expdest, 32, "%ld", num);
5921 STADJUST(len, expdest);
5926 varunset(const char *end, const char *var, const char *umsg, int varflags)
5932 msg = "parameter not set";
5934 if (*end == CTLENDVAR) {
5935 if (varflags & VSNUL)
5940 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5944 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5947 * This implements the input routines used by the parser.
5950 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5951 #define IBUFSIZ (BUFSIZ + 1)
5953 static void pushfile(void);
5956 * Read a line from the script.
5959 static inline char *
5960 pfgets(char *line, int len)
5966 while (--nleft > 0) {
5983 * Read a character from the script, returning PEOF on end of file.
5984 * Nul characters in the input are silently discarded.
5987 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5989 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5990 #define pgetc_macro() pgetc()
5994 return pgetc_as_macro();
5997 #define pgetc_macro() pgetc_as_macro()
6001 return pgetc_macro();
6007 * Same as pgetc(), but ignores PEOA.
6009 #ifdef CONFIG_ASH_ALIAS
6010 static int pgetc2(void)
6016 } while (c == PEOA);
6020 static inline int pgetc2(void)
6022 return pgetc_macro();
6027 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6028 static const char *cmdedit_prompt;
6029 static inline void putprompt(const char *s)
6034 static inline void putprompt(const char *s)
6044 char *buf = parsefile->buf;
6048 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6049 if (!iflag || parsefile->fd)
6050 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6052 cmdedit_path_lookup = pathval();
6053 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6055 /* Ctrl+C presend */
6065 /* Ctrl+D presend */
6070 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6074 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6075 int flags = fcntl(0, F_GETFL, 0);
6076 if (flags >= 0 && flags & O_NONBLOCK) {
6077 flags &=~ O_NONBLOCK;
6078 if (fcntl(0, F_SETFL, flags) >= 0) {
6079 out2str("sh: turning off NDELAY mode\n");
6089 * Refill the input buffer and return the next input character:
6091 * 1) If a string was pushed back on the input, pop it;
6092 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6093 * from a string so we can't refill the buffer, return EOF.
6094 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6095 * 4) Process input up to the next newline, deleting nul characters.
6105 while (parsefile->strpush) {
6106 #ifdef CONFIG_ASH_ALIAS
6107 if (parsenleft == -1 && parsefile->strpush->ap &&
6108 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6113 if (--parsenleft >= 0)
6114 return (*parsenextc++);
6116 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6121 if (parselleft <= 0) {
6122 if ((parselleft = preadfd()) <= 0) {
6123 parselleft = parsenleft = EOF_NLEFT;
6130 /* delete nul characters */
6131 for (more = 1; more;) {
6138 parsenleft = q - parsenextc;
6139 more = 0; /* Stop processing here */
6146 if (--parselleft <= 0 && more) {
6147 parsenleft = q - parsenextc - 1;
6158 out2str(parsenextc);
6163 return *parsenextc++;
6167 * Undo the last call to pgetc. Only one character may be pushed back.
6168 * PEOF may be pushed back.
6179 * Push a string back onto the input at this current parsefile level.
6180 * We handle aliases this way.
6183 pushstring(char *s, void *ap)
6190 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6191 if (parsefile->strpush) {
6192 sp = ckmalloc(sizeof (struct strpush));
6193 sp->prev = parsefile->strpush;
6194 parsefile->strpush = sp;
6196 sp = parsefile->strpush = &(parsefile->basestrpush);
6197 sp->prevstring = parsenextc;
6198 sp->prevnleft = parsenleft;
6199 #ifdef CONFIG_ASH_ALIAS
6200 sp->ap = (struct alias *)ap;
6202 ((struct alias *)ap)->flag |= ALIASINUSE;
6214 struct strpush *sp = parsefile->strpush;
6217 #ifdef CONFIG_ASH_ALIAS
6219 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6220 checkkwd |= CHKALIAS;
6222 if (sp->string != sp->ap->val) {
6225 sp->ap->flag &= ~ALIASINUSE;
6226 if (sp->ap->flag & ALIASDEAD) {
6227 unalias(sp->ap->name);
6231 parsenextc = sp->prevstring;
6232 parsenleft = sp->prevnleft;
6233 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6234 parsefile->strpush = sp->prev;
6235 if (sp != &(parsefile->basestrpush))
6241 * Set the input to take input from a file. If push is set, push the
6242 * old input onto the stack first.
6246 setinputfile(const char *fname, int push)
6252 if ((fd = open(fname, O_RDONLY)) < 0)
6253 error("Can't open %s", fname);
6255 fd2 = copyfd(fd, 10);
6258 error("Out of file descriptors");
6261 setinputfd(fd, push);
6267 * Like setinputfile, but takes an open file descriptor. Call this with
6272 setinputfd(int fd, int push)
6274 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6280 if (parsefile->buf == NULL)
6281 parsefile->buf = ckmalloc(IBUFSIZ);
6282 parselleft = parsenleft = 0;
6288 * Like setinputfile, but takes input from a string.
6292 setinputstring(char *string)
6296 parsenextc = string;
6297 parsenleft = strlen(string);
6298 parsefile->buf = NULL;
6305 * To handle the "." command, a stack of input files is used. Pushfile
6306 * adds a new entry to the stack and popfile restores the previous level.
6312 struct parsefile *pf;
6314 parsefile->nleft = parsenleft;
6315 parsefile->lleft = parselleft;
6316 parsefile->nextc = parsenextc;
6317 parsefile->linno = plinno;
6318 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6319 pf->prev = parsefile;
6322 pf->basestrpush.prev = NULL;
6330 struct parsefile *pf = parsefile;
6339 parsefile = pf->prev;
6341 parsenleft = parsefile->nleft;
6342 parselleft = parsefile->lleft;
6343 parsenextc = parsefile->nextc;
6344 plinno = parsefile->linno;
6350 * Return to top level.
6356 while (parsefile != &basepf)
6362 * Close the file(s) that the shell is reading commands from. Called
6363 * after a fork is done.
6370 if (parsefile->fd > 0) {
6371 close(parsefile->fd);
6376 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6378 /* mode flags for set_curjob */
6379 #define CUR_DELETE 2
6380 #define CUR_RUNNING 1
6381 #define CUR_STOPPED 0
6383 /* mode flags for dowait */
6384 #define DOWAIT_NORMAL 0
6385 #define DOWAIT_BLOCK 1
6388 static struct job *jobtab;
6390 static unsigned njobs;
6392 /* pgrp of shell on invocation */
6393 static int initialpgrp;
6394 static int ttyfd = -1;
6397 static struct job *curjob;
6398 /* number of presumed living untracked jobs */
6401 static void set_curjob(struct job *, unsigned);
6403 static int restartjob(struct job *, int);
6404 static void xtcsetpgrp(int, pid_t);
6405 static char *commandtext(union node *);
6406 static void cmdlist(union node *, int);
6407 static void cmdtxt(union node *);
6408 static void cmdputs(const char *);
6409 static void showpipe(struct job *, FILE *);
6411 static int sprint_status(char *, int, int);
6412 static void freejob(struct job *);
6413 static struct job *getjob(const char *, int);
6414 static struct job *growjobtab(void);
6415 static void forkchild(struct job *, union node *, int);
6416 static void forkparent(struct job *, union node *, int, pid_t);
6417 static int dowait(int, struct job *);
6418 static int getstatus(struct job *);
6421 set_curjob(struct job *jp, unsigned mode)
6424 struct job **jpp, **curp;
6426 /* first remove from list */
6427 jpp = curp = &curjob;
6432 jpp = &jp1->prev_job;
6434 *jpp = jp1->prev_job;
6436 /* Then re-insert in correct position */
6444 /* job being deleted */
6447 /* newly created job or backgrounded job,
6448 put after all stopped jobs. */
6452 if (!jp1 || jp1->state != JOBSTOPPED)
6455 jpp = &jp1->prev_job;
6461 /* newly stopped job - becomes curjob */
6462 jp->prev_job = *jpp;
6470 * Turn job control on and off.
6472 * Note: This code assumes that the third arg to ioctl is a character
6473 * pointer, which is true on Berkeley systems but not System V. Since
6474 * System V doesn't have job control yet, this isn't a problem now.
6476 * Called with interrupts off.
6485 if (on == jobctl || rootshell == 0)
6489 ofd = fd = open(_PATH_TTY, O_RDWR);
6492 while (!isatty(fd) && --fd >= 0)
6495 fd = fcntl(fd, F_DUPFD, 10);
6499 fcntl(fd, F_SETFD, FD_CLOEXEC);
6500 do { /* while we are in the background */
6501 if ((pgrp = tcgetpgrp(fd)) < 0) {
6503 sh_warnx("can't access tty; job control turned off");
6507 if (pgrp == getpgrp())
6518 xtcsetpgrp(fd, pgrp);
6520 /* turning job control off */
6523 xtcsetpgrp(fd, pgrp);
6537 killcmd(int argc, char **argv)
6548 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6549 "kill -l [exitstatus]"
6553 if (**++argv == '-') {
6554 signo = decode_signal(*argv + 1, 1);
6558 while ((c = nextopt("ls:")) != '\0')
6568 signo = decode_signal(optionarg, 1);
6571 "invalid signal number or name: %s",
6582 if (!list && signo < 0)
6585 if ((signo < 0 || !*argv) ^ list) {
6593 for (i = 1; i < NSIG; i++) {
6594 name = u_signal_names(0, &i, 1);
6596 out1fmt(snlfmt, name);
6600 name = u_signal_names(*argptr, &signo, -1);
6602 out1fmt(snlfmt, name);
6604 error("invalid signal number or exit status: %s", *argptr);
6610 if (**argv == '%') {
6611 jp = getjob(*argv, 0);
6612 pid = -jp->ps[0].pid;
6614 pid = number(*argv);
6615 if (kill(pid, signo) != 0) {
6625 #if defined(JOBS) || defined(DEBUG)
6627 jobno(const struct job *jp)
6629 return jp - jobtab + 1;
6635 fgcmd(int argc, char **argv)
6642 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6647 jp = getjob(*argv, 1);
6648 if (mode == FORK_BG) {
6649 set_curjob(jp, CUR_RUNNING);
6650 fprintf(out, "[%d] ", jobno(jp));
6652 outstr(jp->ps->cmd, out);
6654 retval = restartjob(jp, mode);
6655 } while (*argv && *++argv);
6659 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6663 restartjob(struct job *jp, int mode)
6665 struct procstat *ps;
6671 if (jp->state == JOBDONE)
6673 jp->state = JOBRUNNING;
6675 if (mode == FORK_FG)
6676 xtcsetpgrp(ttyfd, pgid);
6677 killpg(pgid, SIGCONT);
6681 if (WIFSTOPPED(ps->status)) {
6684 } while (ps++, --i);
6686 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6693 sprint_status(char *s, int status, int sigonly)
6699 if (!WIFEXITED(status)) {
6701 if (WIFSTOPPED(status))
6702 st = WSTOPSIG(status);
6705 st = WTERMSIG(status);
6707 if (st == SIGINT || st == SIGPIPE)
6710 if (WIFSTOPPED(status))
6715 col = fmtstr(s, 32, strsignal(st));
6716 if (WCOREDUMP(status)) {
6717 col += fmtstr(s + col, 16, " (core dumped)");
6719 } else if (!sigonly) {
6720 st = WEXITSTATUS(status);
6722 col = fmtstr(s, 16, "Done(%d)", st);
6724 col = fmtstr(s, 16, "Done");
6733 showjob(FILE *out, struct job *jp, int mode)
6735 struct procstat *ps;
6736 struct procstat *psend;
6743 if (mode & SHOW_PGID) {
6744 /* just output process (group) id of pipeline */
6745 fprintf(out, "%d\n", ps->pid);
6749 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6754 else if (curjob && jp == curjob->prev_job)
6757 if (mode & SHOW_PID)
6758 col += fmtstr(s + col, 16, "%d ", ps->pid);
6760 psend = ps + jp->nprocs;
6762 if (jp->state == JOBRUNNING) {
6763 scopy("Running", s + col);
6764 col += strlen("Running");
6766 int status = psend[-1].status;
6768 if (jp->state == JOBSTOPPED)
6769 status = jp->stopstatus;
6771 col += sprint_status(s + col, status, 0);
6777 /* for each process */
6778 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6781 fprintf(out, "%s%*c%s",
6782 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6784 if (!(mode & SHOW_PID)) {
6788 if (++ps == psend) {
6789 outcslow('\n', out);
6796 if (jp->state == JOBDONE) {
6797 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6804 jobscmd(int argc, char **argv)
6810 while ((m = nextopt("lp")))
6820 showjob(out, getjob(*argv,0), mode);
6823 showjobs(out, mode);
6830 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6831 * statuses have changed since the last call to showjobs.
6835 showjobs(FILE *out, int mode)
6839 TRACE(("showjobs(%x) called\n", mode));
6841 /* If not even one one job changed, there is nothing to do */
6842 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6845 for (jp = curjob; jp; jp = jp->prev_job) {
6846 if (!(mode & SHOW_CHANGED) || jp->changed)
6847 showjob(out, jp, mode);
6853 * Mark a job structure as unused.
6857 freejob(struct job *jp)
6859 struct procstat *ps;
6863 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6864 if (ps->cmd != nullstr)
6867 if (jp->ps != &jp->ps0)
6870 set_curjob(jp, CUR_DELETE);
6876 waitcmd(int argc, char **argv)
6889 /* wait for all jobs */
6894 /* no running procs */
6897 if (jp->state == JOBRUNNING)
6902 dowait(DOWAIT_BLOCK, 0);
6908 if (**argv != '%') {
6909 pid_t pid = number(*argv);
6913 if (job->ps[job->nprocs - 1].pid == pid)
6915 job = job->prev_job;
6921 job = getjob(*argv, 0);
6922 /* loop until process terminated or stopped */
6923 while (job->state == JOBRUNNING)
6924 dowait(DOWAIT_BLOCK, 0);
6926 retval = getstatus(job);
6937 * Convert a job name to a job structure.
6941 getjob(const char *name, int getctl)
6945 const char *err_msg = "No such job: %s";
6949 char *(*match)(const char *, const char *);
6964 if (c == '+' || c == '%') {
6966 err_msg = "No current job";
6968 } else if (c == '-') {
6971 err_msg = "No previous job";
6982 jp = jobtab + num - 1;
6999 if (match(jp->ps[0].cmd, p)) {
7003 err_msg = "%s: ambiguous";
7010 err_msg = "job %s not created under job control";
7011 if (getctl && jp->jobctl == 0)
7016 error(err_msg, name);
7021 * Return a new job structure.
7022 * Called with interrupts off.
7026 makejob(union node *node, int nprocs)
7031 for (i = njobs, jp = jobtab ; ; jp++) {
7038 if (jp->state != JOBDONE || !jp->waited)
7047 memset(jp, 0, sizeof(*jp));
7052 jp->prev_job = curjob;
7057 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7059 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7069 struct job *jp, *jq;
7071 len = njobs * sizeof(*jp);
7073 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7075 offset = (char *)jp - (char *)jq;
7077 /* Relocate pointers */
7080 jq = (struct job *)((char *)jq + l);
7084 #define joff(p) ((struct job *)((char *)(p) + l))
7085 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7086 if (likely(joff(jp)->ps == &jq->ps0))
7087 jmove(joff(jp)->ps);
7088 if (joff(jp)->prev_job)
7089 jmove(joff(jp)->prev_job);
7099 jp = (struct job *)((char *)jp + len);
7103 } while (--jq >= jp);
7109 * Fork off a subshell. If we are doing job control, give the subshell its
7110 * own process group. Jp is a job structure that the job is to be added to.
7111 * N is the command that will be evaluated by the child. Both jp and n may
7112 * be NULL. The mode parameter can be one of the following:
7113 * FORK_FG - Fork off a foreground process.
7114 * FORK_BG - Fork off a background process.
7115 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7116 * process group even if job control is on.
7118 * When job control is turned off, background processes have their standard
7119 * input redirected to /dev/null (except for the second and later processes
7122 * Called with interrupts off.
7126 forkchild(struct job *jp, union node *n, int mode)
7130 TRACE(("Child shell %d\n", getpid()));
7131 wasroot = rootshell;
7137 /* do job control only in root shell */
7139 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7142 if (jp->nprocs == 0)
7145 pgrp = jp->ps[0].pid;
7146 /* This can fail because we are doing it in the parent also */
7147 (void)setpgid(0, pgrp);
7148 if (mode == FORK_FG)
7149 xtcsetpgrp(ttyfd, pgrp);
7154 if (mode == FORK_BG) {
7157 if (jp->nprocs == 0) {
7159 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7160 error("Can't open %s", _PATH_DEVNULL);
7163 if (wasroot && iflag) {
7168 for (jp = curjob; jp; jp = jp->prev_job)
7174 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7176 TRACE(("In parent shell: child = %d\n", pid));
7178 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7183 if (mode != FORK_NOJOB && jp->jobctl) {
7186 if (jp->nprocs == 0)
7189 pgrp = jp->ps[0].pid;
7190 /* This can fail because we are doing it in the child also */
7191 (void)setpgid(pid, pgrp);
7194 if (mode == FORK_BG) {
7195 backgndpid = pid; /* set $! */
7196 set_curjob(jp, CUR_RUNNING);
7199 struct procstat *ps = &jp->ps[jp->nprocs++];
7205 ps->cmd = commandtext(n);
7211 forkshell(struct job *jp, union node *n, int mode)
7215 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7218 TRACE(("Fork failed, errno=%d", errno));
7221 error("Cannot fork");
7224 forkchild(jp, n, mode);
7226 forkparent(jp, n, mode, pid);
7231 * Wait for job to finish.
7233 * Under job control we have the problem that while a child process is
7234 * running interrupts generated by the user are sent to the child but not
7235 * to the shell. This means that an infinite loop started by an inter-
7236 * active user may be hard to kill. With job control turned off, an
7237 * interactive user may place an interactive program inside a loop. If
7238 * the interactive program catches interrupts, the user doesn't want
7239 * these interrupts to also abort the loop. The approach we take here
7240 * is to have the shell ignore interrupt signals while waiting for a
7241 * foreground process to terminate, and then send itself an interrupt
7242 * signal if the child process was terminated by an interrupt signal.
7243 * Unfortunately, some programs want to do a bit of cleanup and then
7244 * exit on interrupt; unless these processes terminate themselves by
7245 * sending a signal to themselves (instead of calling exit) they will
7246 * confuse this approach.
7248 * Called with interrupts off.
7252 waitforjob(struct job *jp)
7256 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7257 while (jp->state == JOBRUNNING) {
7258 dowait(DOWAIT_BLOCK, jp);
7263 xtcsetpgrp(ttyfd, rootpid);
7265 * This is truly gross.
7266 * If we're doing job control, then we did a TIOCSPGRP which
7267 * caused us (the shell) to no longer be in the controlling
7268 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7269 * intuit from the subprocess exit status whether a SIGINT
7270 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7275 if (jp->state == JOBDONE)
7283 * Do a wait system call. If job control is compiled in, we accept
7284 * stopped processes. If block is zero, we return a value of zero
7285 * rather than blocking.
7287 * System V doesn't have a non-blocking wait system call. It does
7288 * have a SIGCLD signal that is sent to a process when one of it's
7289 * children dies. The obvious way to use SIGCLD would be to install
7290 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7291 * was received, and have waitproc bump another counter when it got
7292 * the status of a process. Waitproc would then know that a wait
7293 * system call would not block if the two counters were different.
7294 * This approach doesn't work because if a process has children that
7295 * have not been waited for, System V will send it a SIGCLD when it
7296 * installs a signal handler for SIGCLD. What this means is that when
7297 * a child exits, the shell will be sent SIGCLD signals continuously
7298 * until is runs out of stack space, unless it does a wait call before
7299 * restoring the signal handler. The code below takes advantage of
7300 * this (mis)feature by installing a signal handler for SIGCLD and
7301 * then checking to see whether it was called. If there are any
7302 * children to be waited for, it will be.
7304 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7305 * waits at all. In this case, the user will not be informed when
7306 * a background process until the next time she runs a real program
7307 * (as opposed to running a builtin command or just typing return),
7308 * and the jobs command may give out of date information.
7312 waitproc(int block, int *status)
7322 return wait3(status, flags, (struct rusage *)NULL);
7326 * Wait for a process to terminate.
7330 dowait(int block, struct job *job)
7335 struct job *thisjob;
7338 TRACE(("dowait(%d) called\n", block));
7339 pid = waitproc(block, &status);
7340 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7345 for (jp = curjob; jp; jp = jp->prev_job) {
7346 struct procstat *sp;
7347 struct procstat *spend;
7348 if (jp->state == JOBDONE)
7351 spend = jp->ps + jp->nprocs;
7354 if (sp->pid == pid) {
7355 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7356 sp->status = status;
7359 if (sp->status == -1)
7362 if (state == JOBRUNNING)
7364 if (WIFSTOPPED(sp->status)) {
7365 jp->stopstatus = sp->status;
7369 } while (++sp < spend);
7374 if (!WIFSTOPPED(status))
7381 if (state != JOBRUNNING) {
7382 thisjob->changed = 1;
7384 if (thisjob->state != state) {
7385 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7386 thisjob->state = state;
7388 if (state == JOBSTOPPED) {
7389 set_curjob(thisjob, CUR_STOPPED);
7398 if (thisjob && thisjob == job) {
7402 len = sprint_status(s, status, 1);
7414 * return 1 if there are stopped jobs, otherwise 0
7427 if (jp && jp->state == JOBSTOPPED) {
7428 out2str("You have stopped jobs.\n");
7438 * Return a string identifying a command (to be printed by the
7443 static char *cmdnextc;
7446 commandtext(union node *n)
7450 STARTSTACKSTR(cmdnextc);
7452 name = stackblock();
7453 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7454 name, cmdnextc, cmdnextc));
7455 return savestr(name);
7459 cmdtxt(union node *n)
7462 struct nodelist *lp;
7474 lp = n->npipe.cmdlist;
7492 cmdtxt(n->nbinary.ch1);
7508 cmdtxt(n->nif.test);
7511 if (n->nif.elsepart) {
7514 n = n->nif.elsepart;
7530 cmdtxt(n->nbinary.ch1);
7540 cmdputs(n->nfor.var);
7542 cmdlist(n->nfor.args, 1);
7547 cmdputs(n->narg.text);
7551 cmdlist(n->ncmd.args, 1);
7552 cmdlist(n->ncmd.redirect, 0);
7565 cmdputs(n->ncase.expr->narg.text);
7567 for (np = n->ncase.cases; np; np = np->nclist.next) {
7568 cmdtxt(np->nclist.pattern);
7570 cmdtxt(np->nclist.body);
7596 s[0] = n->nfile.fd + '0';
7600 if (n->type == NTOFD || n->type == NFROMFD) {
7601 s[0] = n->ndup.dupfd + '0';
7612 cmdlist(union node *np, int sep)
7614 for (; np; np = np->narg.next) {
7618 if (sep && np->narg.next)
7624 cmdputs(const char *s)
7626 const char *p, *str;
7627 char c, cc[2] = " ";
7631 static const char *const vstype[16] = {
7632 nullstr, "}", "-", "+", "?", "=",
7633 "%", "%%", "#", "##", nullstr
7636 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7638 while ((c = *p++) != 0) {
7646 if ((subtype & VSTYPE) == VSLENGTH)
7650 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7668 case CTLBACKQ+CTLQUOTE:
7671 #ifdef CONFIG_ASH_MATH_SUPPORT
7686 str = vstype[subtype & VSTYPE];
7687 if (subtype & VSNUL)
7698 /* These can only happen inside quotes */
7710 while ((c = *str++)) {
7715 USTPUTC('"', nextc);
7723 showpipe(struct job *jp, FILE *out)
7725 struct procstat *sp;
7726 struct procstat *spend;
7728 spend = jp->ps + jp->nprocs;
7729 for (sp = jp->ps + 1; sp < spend; sp++)
7730 fprintf(out, " | %s", sp->cmd);
7731 outcslow('\n', out);
7736 xtcsetpgrp(int fd, pid_t pgrp)
7738 if (tcsetpgrp(fd, pgrp))
7739 error("Cannot set tty process group (%m)");
7744 getstatus(struct job *job) {
7748 status = job->ps[job->nprocs - 1].status;
7749 retval = WEXITSTATUS(status);
7750 if (!WIFEXITED(status)) {
7752 retval = WSTOPSIG(status);
7753 if (!WIFSTOPPED(status))
7756 /* XXX: limits number of signals */
7757 retval = WTERMSIG(status);
7759 if (retval == SIGINT)
7765 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7766 jobno(job), job->nprocs, status, retval));
7770 #ifdef CONFIG_ASH_MAIL
7771 /* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7774 * Routines to check for mail. (Perhaps make part of main.c?)
7777 #define MAXMBOXES 10
7779 /* times of mailboxes */
7780 static time_t mailtime[MAXMBOXES];
7781 /* Set if MAIL or MAILPATH is changed. */
7782 static int mail_var_path_changed;
7787 * Print appropriate message(s) if mail has arrived.
7788 * If mail_var_path_changed is set,
7789 * then the value of MAIL has mail_var_path_changed,
7790 * so we just update the values.
7800 struct stackmark smark;
7803 setstackmark(&smark);
7804 mpath = mpathset() ? mpathval() : mailval();
7805 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7806 p = padvance(&mpath, nullstr);
7811 for (q = p ; *q ; q++);
7816 q[-1] = '\0'; /* delete trailing '/' */
7817 if (stat(p, &statb) < 0) {
7821 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7824 pathopt ? pathopt : "you have mail"
7827 *mtp = statb.st_mtime;
7829 mail_var_path_changed = 0;
7830 popstackmark(&smark);
7835 changemail(const char *val)
7837 mail_var_path_changed++;
7840 #endif /* CONFIG_ASH_MAIL */
7842 /* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7846 static short profile_buf[16384];
7850 static int isloginsh;
7852 static void read_profile(const char *);
7855 * Main routine. We initialize things, parse the arguments, execute
7856 * profiles if we're a login shell, and then call cmdloop to execute
7857 * commands. The setjmp call sets up the location to jump to when an
7858 * exception occurs. When an exception occurs the variable "state"
7859 * is used to figure out how far we had gotten.
7863 ash_main(int argc, char **argv)
7867 struct jmploc jmploc;
7868 struct stackmark smark;
7871 dash_errno = __errno_location();
7875 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7878 if (setjmp(jmploc.loc)) {
7885 switch (exception) {
7895 status = exitstatus;
7898 exitstatus = status;
7900 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7904 outcslow('\n', stderr);
7906 popstackmark(&smark);
7907 FORCEINTON; /* enable interrupts */
7910 else if (state == 2)
7912 else if (state == 3)
7920 trputs("Shell args: "); trargs(argv);
7924 #ifdef CONFIG_ASH_RANDOM_SUPPORT
7925 rseed = rootpid + ((time_t)time((time_t *)0));
7929 setstackmark(&smark);
7930 procargs(argc, argv);
7931 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7933 const char *hp = lookupvar("HISTFILE");
7936 hp = lookupvar("HOME");
7938 char *defhp = concat_path_file(hp, ".ash_history");
7939 setvar("HISTFILE", defhp, 0);
7945 if (argv[0] && argv[0][0] == '-')
7949 read_profile("/etc/profile");
7952 read_profile(".profile");
7958 getuid() == geteuid() && getgid() == getegid() &&
7962 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7963 read_profile(shinit);
7971 if (sflag || minusc == NULL) {
7972 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7974 const char *hp = lookupvar("HISTFILE");
7977 load_history ( hp );
7980 state4: /* XXX ??? - why isn't this before the "if" statement */
7988 extern void _mcleanup(void);
7998 * Read and execute commands. "Top" is nonzero for the top level command
7999 * loop; it turns on prompting if the shell is interactive.
8006 struct stackmark smark;
8010 TRACE(("cmdloop(%d) called\n", top));
8012 setstackmark(&smark);
8017 showjobs(stderr, SHOW_CHANGED);
8022 #ifdef CONFIG_ASH_MAIL
8026 n = parsecmd(inter);
8027 /* showtree(n); DEBUG */
8029 if (!top || numeof >= 50)
8031 if (!stoppedjobs()) {
8034 out2str("\nUse \"exit\" to leave shell.\n");
8037 } else if (n != NULL && nflag == 0) {
8038 job_warning = (job_warning == 2) ? 1 : 0;
8042 popstackmark(&smark);
8052 * Read /etc/profile or .profile. Return on error.
8056 read_profile(const char *name)
8063 if ((fd = open(name, O_RDONLY)) >= 0)
8068 /* -q turns off -x and -v just when executing init files */
8071 xflag = 0, xflag_set = 1;
8073 vflag = 0, vflag_set = 1;
8087 * Read a file containing shell functions.
8091 readcmdfile(char *name)
8096 if ((fd = open(name, O_RDONLY)) >= 0)
8099 error("Can't open %s", name);
8107 * Take commands from a file. To be compatible we should do a path
8108 * search for the file, which is necessary to find sub-commands.
8111 static inline char *
8112 find_dot_file(char *name)
8115 const char *path = pathval();
8118 /* don't try this for absolute or relative paths */
8119 if (strchr(name, '/'))
8122 while ((fullname = padvance(&path, name)) != NULL) {
8123 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8125 * Don't bother freeing here, since it will
8126 * be freed by the caller.
8130 stunalloc(fullname);
8133 /* not found in the PATH */
8134 error(not_found_msg, name);
8138 static int dotcmd(int argc, char **argv)
8141 volatile struct shparam saveparam;
8145 for (sp = cmdenviron; sp; sp = sp->next)
8146 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8148 if (argc >= 2) { /* That's what SVR2 does */
8150 struct stackmark smark;
8152 setstackmark(&smark);
8153 fullname = find_dot_file(argv[1]);
8156 saveparam = shellparam;
8157 shellparam.malloc = 0;
8158 shellparam.nparam = argc - 2;
8159 shellparam.p = argv + 2;
8162 setinputfile(fullname, 1);
8163 commandname = fullname;
8168 freeparam(&shellparam);
8169 shellparam = saveparam;
8172 popstackmark(&smark);
8179 exitcmd(int argc, char **argv)
8184 exitstatus = number(argv[1]);
8189 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8192 * Same for malloc, realloc, but returns an error when out of space.
8196 ckrealloc(pointer p, size_t nbytes)
8198 p = realloc(p, nbytes);
8200 error(bb_msg_memory_exhausted);
8205 ckmalloc(size_t nbytes)
8207 return ckrealloc(NULL, nbytes);
8211 * Make a copy of a string in safe storage.
8215 savestr(const char *s)
8217 char *p = strdup(s);
8219 error(bb_msg_memory_exhausted);
8225 * Parse trees for commands are allocated in lifo order, so we use a stack
8226 * to make this more efficient, and also to avoid all sorts of exception
8227 * handling code to handle interrupts in the middle of a parse.
8229 * The size 504 was chosen because the Ultrix malloc handles that size
8235 stalloc(size_t nbytes)
8240 aligned = SHELL_ALIGN(nbytes);
8241 if (aligned > stacknleft) {
8244 struct stack_block *sp;
8246 blocksize = aligned;
8247 if (blocksize < MINSIZE)
8248 blocksize = MINSIZE;
8249 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8250 if (len < blocksize)
8251 error(bb_msg_memory_exhausted);
8255 stacknxt = sp->space;
8256 stacknleft = blocksize;
8257 sstrend = stacknxt + blocksize;
8262 stacknxt += aligned;
8263 stacknleft -= aligned;
8269 stunalloc(pointer p)
8272 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8273 write(2, "stunalloc\n", 10);
8277 stacknleft += stacknxt - (char *)p;
8283 setstackmark(struct stackmark *mark)
8285 mark->stackp = stackp;
8286 mark->stacknxt = stacknxt;
8287 mark->stacknleft = stacknleft;
8288 mark->marknext = markp;
8294 popstackmark(struct stackmark *mark)
8296 struct stack_block *sp;
8299 markp = mark->marknext;
8300 while (stackp != mark->stackp) {
8305 stacknxt = mark->stacknxt;
8306 stacknleft = mark->stacknleft;
8307 sstrend = mark->stacknxt + mark->stacknleft;
8313 * When the parser reads in a string, it wants to stick the string on the
8314 * stack and only adjust the stack pointer when it knows how big the
8315 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8316 * of space on top of the stack and stackblocklen returns the length of
8317 * this block. Growstackblock will grow this space by at least one byte,
8318 * possibly moving it (like realloc). Grabstackblock actually allocates the
8319 * part of the block that has been used.
8323 growstackblock(void)
8327 newlen = stacknleft * 2;
8328 if (newlen < stacknleft)
8329 error(bb_msg_memory_exhausted);
8333 if (stacknxt == stackp->space && stackp != &stackbase) {
8334 struct stack_block *oldstackp;
8335 struct stackmark *xmark;
8336 struct stack_block *sp;
8337 struct stack_block *prevstackp;
8343 prevstackp = sp->prev;
8344 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8345 sp = ckrealloc((pointer)sp, grosslen);
8346 sp->prev = prevstackp;
8348 stacknxt = sp->space;
8349 stacknleft = newlen;
8350 sstrend = sp->space + newlen;
8353 * Stack marks pointing to the start of the old block
8354 * must be relocated to point to the new block
8357 while (xmark != NULL && xmark->stackp == oldstackp) {
8358 xmark->stackp = stackp;
8359 xmark->stacknxt = stacknxt;
8360 xmark->stacknleft = stacknleft;
8361 xmark = xmark->marknext;
8365 char *oldspace = stacknxt;
8366 int oldlen = stacknleft;
8367 char *p = stalloc(newlen);
8369 /* free the space we just allocated */
8370 stacknxt = memcpy(p, oldspace, oldlen);
8371 stacknleft += newlen;
8376 grabstackblock(size_t len)
8378 len = SHELL_ALIGN(len);
8384 * The following routines are somewhat easier to use than the above.
8385 * The user declares a variable of type STACKSTR, which may be declared
8386 * to be a register. The macro STARTSTACKSTR initializes things. Then
8387 * the user uses the macro STPUTC to add characters to the string. In
8388 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8389 * grown as necessary. When the user is done, she can just leave the
8390 * string there and refer to it using stackblock(). Or she can allocate
8391 * the space for it using grabstackstr(). If it is necessary to allow
8392 * someone else to use the stack temporarily and then continue to grow
8393 * the string, the user should use grabstack to allocate the space, and
8394 * then call ungrabstr(p) to return to the previous mode of operation.
8396 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8397 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8398 * is space for at least one character.
8404 size_t len = stackblocksize();
8405 if (herefd >= 0 && len >= 1024) {
8406 bb_full_write(herefd, stackblock(), len);
8407 return stackblock();
8410 return stackblock() + len;
8414 * Called from CHECKSTRSPACE.
8418 makestrspace(size_t newlen, char *p)
8420 size_t len = p - stacknxt;
8421 size_t size = stackblocksize();
8426 size = stackblocksize();
8428 if (nleft >= newlen)
8432 return stackblock() + len;
8436 stnputs(const char *s, size_t n, char *p)
8438 p = makestrspace(n, p);
8439 p = mempcpy(p, s, n);
8444 stputs(const char *s, char *p)
8446 return stnputs(s, strlen(s), p);
8449 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8454 * number(s) Convert a string of digits to an integer.
8455 * is_number(s) Return true if s is a string of digits.
8459 * prefix -- see if pfx is a prefix of string.
8463 prefix(const char *string, const char *pfx)
8466 if (*pfx++ != *string++)
8469 return (char *) string;
8474 * Convert a string of digits to an integer, printing an error message on
8479 number(const char *s)
8489 * Check for a valid number. This should be elsewhere.
8493 is_number(const char *p)
8498 } while (*++p != '\0');
8504 * Produce a possibly single quoted string suitable as input to the shell.
8505 * The return string is allocated on the stack.
8509 single_quote(const char *s) {
8518 len = strchrnul(s, '\'') - s;
8520 q = p = makestrspace(len + 3, p);
8523 q = mempcpy(q, s, len);
8529 len = strspn(s, "'");
8533 q = p = makestrspace(len + 3, p);
8536 q = mempcpy(q, s, len);
8545 return stackblock();
8549 * Like strdup but works with the ash stack.
8553 sstrdup(const char *p)
8555 size_t len = strlen(p) + 1;
8556 return memcpy(stalloc(len), p, len);
8561 calcsize(union node *n)
8565 funcblocksize += nodesize[n->type];
8568 calcsize(n->ncmd.redirect);
8569 calcsize(n->ncmd.args);
8570 calcsize(n->ncmd.assign);
8573 sizenodelist(n->npipe.cmdlist);
8578 calcsize(n->nredir.redirect);
8579 calcsize(n->nredir.n);
8586 calcsize(n->nbinary.ch2);
8587 calcsize(n->nbinary.ch1);
8590 calcsize(n->nif.elsepart);
8591 calcsize(n->nif.ifpart);
8592 calcsize(n->nif.test);
8595 funcstringsize += strlen(n->nfor.var) + 1;
8596 calcsize(n->nfor.body);
8597 calcsize(n->nfor.args);
8600 calcsize(n->ncase.cases);
8601 calcsize(n->ncase.expr);
8604 calcsize(n->nclist.body);
8605 calcsize(n->nclist.pattern);
8606 calcsize(n->nclist.next);
8610 sizenodelist(n->narg.backquote);
8611 funcstringsize += strlen(n->narg.text) + 1;
8612 calcsize(n->narg.next);
8619 calcsize(n->nfile.fname);
8620 calcsize(n->nfile.next);
8624 calcsize(n->ndup.vname);
8625 calcsize(n->ndup.next);
8629 calcsize(n->nhere.doc);
8630 calcsize(n->nhere.next);
8633 calcsize(n->nnot.com);
8640 sizenodelist(struct nodelist *lp)
8643 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8651 copynode(union node *n)
8658 funcblock = (char *) funcblock + nodesize[n->type];
8661 new->ncmd.redirect = copynode(n->ncmd.redirect);
8662 new->ncmd.args = copynode(n->ncmd.args);
8663 new->ncmd.assign = copynode(n->ncmd.assign);
8666 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8667 new->npipe.backgnd = n->npipe.backgnd;
8672 new->nredir.redirect = copynode(n->nredir.redirect);
8673 new->nredir.n = copynode(n->nredir.n);
8680 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8681 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8684 new->nif.elsepart = copynode(n->nif.elsepart);
8685 new->nif.ifpart = copynode(n->nif.ifpart);
8686 new->nif.test = copynode(n->nif.test);
8689 new->nfor.var = nodesavestr(n->nfor.var);
8690 new->nfor.body = copynode(n->nfor.body);
8691 new->nfor.args = copynode(n->nfor.args);
8694 new->ncase.cases = copynode(n->ncase.cases);
8695 new->ncase.expr = copynode(n->ncase.expr);
8698 new->nclist.body = copynode(n->nclist.body);
8699 new->nclist.pattern = copynode(n->nclist.pattern);
8700 new->nclist.next = copynode(n->nclist.next);
8704 new->narg.backquote = copynodelist(n->narg.backquote);
8705 new->narg.text = nodesavestr(n->narg.text);
8706 new->narg.next = copynode(n->narg.next);
8713 new->nfile.fname = copynode(n->nfile.fname);
8714 new->nfile.fd = n->nfile.fd;
8715 new->nfile.next = copynode(n->nfile.next);
8719 new->ndup.vname = copynode(n->ndup.vname);
8720 new->ndup.dupfd = n->ndup.dupfd;
8721 new->ndup.fd = n->ndup.fd;
8722 new->ndup.next = copynode(n->ndup.next);
8726 new->nhere.doc = copynode(n->nhere.doc);
8727 new->nhere.fd = n->nhere.fd;
8728 new->nhere.next = copynode(n->nhere.next);
8731 new->nnot.com = copynode(n->nnot.com);
8734 new->type = n->type;
8739 static struct nodelist *
8740 copynodelist(struct nodelist *lp)
8742 struct nodelist *start;
8743 struct nodelist **lpp;
8748 funcblock = (char *) funcblock +
8749 SHELL_ALIGN(sizeof(struct nodelist));
8750 (*lpp)->n = copynode(lp->n);
8752 lpp = &(*lpp)->next;
8760 nodesavestr(char *s)
8762 char *rtn = funcstring;
8764 funcstring = stpcpy(funcstring, s) + 1;
8770 * Free a parse tree.
8774 freefunc(struct funcnode *f)
8776 if (f && --f->count < 0)
8781 static void options(int);
8782 static void setoption(int, int);
8786 * Process the shell command line arguments.
8790 procargs(int argc, char **argv)
8793 const char *xminusc;
8800 for (i = 0; i < NOPTS; i++)
8806 if (*xargv == NULL) {
8808 error("-c requires an argument");
8811 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8815 for (i = 0; i < NOPTS; i++)
8816 if (optlist[i] == 2)
8821 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8826 } else if (!sflag) {
8827 setinputfile(*xargv, 0);
8833 shellparam.p = xargv;
8834 #ifdef CONFIG_ASH_GETOPTS
8835 shellparam.optind = 1;
8836 shellparam.optoff = -1;
8838 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8840 shellparam.nparam++;
8853 setinteractive(iflag);
8858 minus_o(char *name, int val)
8863 out1str("Current option settings\n");
8864 for (i = 0; i < NOPTS; i++)
8865 out1fmt("%-16s%s\n", optnames(i),
8866 optlist[i] ? "on" : "off");
8868 for (i = 0; i < NOPTS; i++)
8869 if (equal(name, optnames(i))) {
8873 error("Illegal option -o %s", name);
8878 * Process shell options. The global variable argptr contains a pointer
8879 * to the argument list; we advance it past the options.
8883 options(int cmdline)
8891 while ((p = *argptr) != NULL) {
8893 if ((c = *p++) == '-') {
8895 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8897 /* "-" means turn off -x and -v */
8900 /* "--" means reset params */
8901 else if (*argptr == NULL)
8904 break; /* "-" or "--" terminates options */
8906 } else if (c == '+') {
8912 while ((c = *p++) != '\0') {
8913 if (c == 'c' && cmdline) {
8914 minusc = p; /* command is after shell args*/
8915 } else if (c == 'o') {
8916 minus_o(*argptr, val);
8919 } else if (cmdline && (c == '-')) { // long options
8920 if (strcmp(p, "login") == 0)
8932 setoption(int flag, int val)
8936 for (i = 0; i < NOPTS; i++)
8937 if (optletters(i) == flag) {
8941 error("Illegal option -%c", flag);
8948 * Set the shell parameters.
8952 setparam(char **argv)
8958 for (nparam = 0 ; argv[nparam] ; nparam++);
8959 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8961 *ap++ = savestr(*argv++);
8964 freeparam(&shellparam);
8965 shellparam.malloc = 1;
8966 shellparam.nparam = nparam;
8967 shellparam.p = newparam;
8968 #ifdef CONFIG_ASH_GETOPTS
8969 shellparam.optind = 1;
8970 shellparam.optoff = -1;
8976 * Free the list of positional parameters.
8980 freeparam(volatile struct shparam *param)
8984 if (param->malloc) {
8985 for (ap = param->p ; *ap ; ap++)
8994 * The shift builtin command.
8998 shiftcmd(int argc, char **argv)
9005 n = number(argv[1]);
9006 if (n > shellparam.nparam)
9007 error("can't shift that many");
9009 shellparam.nparam -= n;
9010 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9011 if (shellparam.malloc)
9015 while ((*ap2++ = *ap1++) != NULL);
9016 #ifdef CONFIG_ASH_GETOPTS
9017 shellparam.optind = 1;
9018 shellparam.optoff = -1;
9027 * The set command builtin.
9031 setcmd(int argc, char **argv)
9034 return showvars(nullstr, 0, VUNSET);
9038 if (*argptr != NULL) {
9046 #ifdef CONFIG_ASH_GETOPTS
9051 shellparam.optind = number(value);
9052 shellparam.optoff = -1;
9056 #ifdef CONFIG_LOCALE_SUPPORT
9057 static void change_lc_all(const char *value)
9059 if (value != 0 && *value != 0)
9060 setlocale(LC_ALL, value);
9063 static void change_lc_ctype(const char *value)
9065 if (value != 0 && *value != 0)
9066 setlocale(LC_CTYPE, value);
9071 #ifdef CONFIG_ASH_RANDOM_SUPPORT
9072 /* Roughly copied from bash.. */
9073 static void change_random(const char *value)
9076 /* "get", generate */
9079 rseed = rseed * 1103515245 + 12345;
9080 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9081 /* set without recursion */
9082 setvar(vrandom.text, buf, VNOFUNC);
9083 vrandom.flags &= ~VNOFUNC;
9086 rseed = strtoul(value, (char **)NULL, 10);
9092 #ifdef CONFIG_ASH_GETOPTS
9094 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9103 if(*param_optind < 1)
9105 optnext = optfirst + *param_optind - 1;
9107 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9110 p = optnext[-1] + *optoff;
9111 if (p == NULL || *p == '\0') {
9112 /* Current word is done, advance */
9114 if (p == NULL || *p != '-' || *++p == '\0') {
9121 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9126 for (q = optstr; *q != c; ) {
9128 if (optstr[0] == ':') {
9131 err |= setvarsafe("OPTARG", s, 0);
9133 fprintf(stderr, "Illegal option -%c\n", c);
9134 (void) unsetvar("OPTARG");
9144 if (*p == '\0' && (p = *optnext) == NULL) {
9145 if (optstr[0] == ':') {
9148 err |= setvarsafe("OPTARG", s, 0);
9151 fprintf(stderr, "No arg for -%c option\n", c);
9152 (void) unsetvar("OPTARG");
9160 err |= setvarsafe("OPTARG", p, 0);
9163 err |= setvarsafe("OPTARG", nullstr, 0);
9166 *optoff = p ? p - *(optnext - 1) : -1;
9167 *param_optind = optnext - optfirst + 1;
9168 fmtstr(s, sizeof(s), "%d", *param_optind);
9169 err |= setvarsafe("OPTIND", s, VNOFUNC);
9172 err |= setvarsafe(optvar, s, 0);
9183 * The getopts builtin. Shellparam.optnext points to the next argument
9184 * to be processed. Shellparam.optptr points to the next character to
9185 * be processed in the current argument. If shellparam.optnext is NULL,
9186 * then it's the first time getopts has been called.
9190 getoptscmd(int argc, char **argv)
9195 error("Usage: getopts optstring var [arg]");
9196 else if (argc == 3) {
9197 optbase = shellparam.p;
9198 if (shellparam.optind > shellparam.nparam + 1) {
9199 shellparam.optind = 1;
9200 shellparam.optoff = -1;
9205 if (shellparam.optind > argc - 2) {
9206 shellparam.optind = 1;
9207 shellparam.optoff = -1;
9211 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9212 &shellparam.optoff);
9214 #endif /* CONFIG_ASH_GETOPTS */
9217 * XXX - should get rid of. have all builtins use getopt(3). the
9218 * library getopt must have the BSD extension static variable "optreset"
9219 * otherwise it can't be used within the shell safely.
9221 * Standard option processing (a la getopt) for builtin routines. The
9222 * only argument that is passed to nextopt is the option string; the
9223 * other arguments are unnecessary. It return the character, or '\0' on
9228 nextopt(const char *optstring)
9234 if ((p = optptr) == NULL || *p == '\0') {
9236 if (p == NULL || *p != '-' || *++p == '\0')
9239 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9243 for (q = optstring ; *q != c ; ) {
9245 error("Illegal option -%c", c);
9250 if (*p == '\0' && (p = *argptr++) == NULL)
9251 error("No arg for -%c option", c);
9260 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9263 outstr(const char *p, FILE *file)
9288 outcslow(int c, FILE *dest)
9298 out1fmt(const char *fmt, ...)
9305 r = vprintf(fmt, ap);
9313 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9320 ret = vsnprintf(outbuf, length, fmt, ap);
9328 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9332 * Shell command parser.
9335 #define EOFMARKLEN 79
9339 struct heredoc *next; /* next here document in list */
9340 union node *here; /* redirection node */
9341 char *eofmark; /* string indicating end of input */
9342 int striptabs; /* if set, strip leading tabs */
9347 static struct heredoc *heredoclist; /* list of here documents to read */
9350 static union node *list(int);
9351 static union node *andor(void);
9352 static union node *pipeline(void);
9353 static union node *command(void);
9354 static union node *simplecmd(void);
9355 static union node *makename(void);
9356 static void parsefname(void);
9357 static void parseheredoc(void);
9358 static char peektoken(void);
9359 static int readtoken(void);
9360 static int xxreadtoken(void);
9361 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9362 static int noexpand(char *);
9363 static void synexpect(int) __attribute__((__noreturn__));
9364 static void synerror(const char *) __attribute__((__noreturn__));
9365 static void setprompt(int);
9370 isassignment(const char *p)
9372 const char *q = endofname(p);
9380 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9381 * valid parse tree indicating a blank line.)
9385 parsecmd(int interact)
9390 doprompt = interact;
9392 setprompt(doprompt);
9407 union node *n1, *n2, *n3;
9410 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9411 if (nlflag == 2 && peektoken())
9417 if (tok == TBACKGND) {
9418 if (n2->type == NPIPE) {
9419 n2->npipe.backgnd = 1;
9421 if (n2->type != NREDIR) {
9422 n3 = stalloc(sizeof(struct nredir));
9424 n3->nredir.redirect = NULL;
9427 n2->type = NBACKGND;
9434 n3 = (union node *)stalloc(sizeof (struct nbinary));
9436 n3->nbinary.ch1 = n1;
9437 n3->nbinary.ch2 = n2;
9453 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9461 pungetc(); /* push back EOF on input */
9477 union node *n1, *n2, *n3;
9482 if ((t = readtoken()) == TAND) {
9484 } else if (t == TOR) {
9490 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9492 n3 = (union node *)stalloc(sizeof (struct nbinary));
9494 n3->nbinary.ch1 = n1;
9495 n3->nbinary.ch2 = n2;
9505 union node *n1, *n2, *pipenode;
9506 struct nodelist *lp, *prev;
9510 TRACE(("pipeline: entered\n"));
9511 if (readtoken() == TNOT) {
9513 checkkwd = CHKKWD | CHKALIAS;
9517 if (readtoken() == TPIPE) {
9518 pipenode = (union node *)stalloc(sizeof (struct npipe));
9519 pipenode->type = NPIPE;
9520 pipenode->npipe.backgnd = 0;
9521 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9522 pipenode->npipe.cmdlist = lp;
9526 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9527 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9530 } while (readtoken() == TPIPE);
9536 n2 = (union node *)stalloc(sizeof (struct nnot));
9549 union node *n1, *n2;
9550 union node *ap, **app;
9551 union node *cp, **cpp;
9552 union node *redir, **rpp;
9559 switch (readtoken()) {
9564 n1 = (union node *)stalloc(sizeof (struct nif));
9566 n1->nif.test = list(0);
9567 if (readtoken() != TTHEN)
9569 n1->nif.ifpart = list(0);
9571 while (readtoken() == TELIF) {
9572 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9573 n2 = n2->nif.elsepart;
9575 n2->nif.test = list(0);
9576 if (readtoken() != TTHEN)
9578 n2->nif.ifpart = list(0);
9580 if (lasttoken == TELSE)
9581 n2->nif.elsepart = list(0);
9583 n2->nif.elsepart = NULL;
9591 n1 = (union node *)stalloc(sizeof (struct nbinary));
9592 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9593 n1->nbinary.ch1 = list(0);
9594 if ((got=readtoken()) != TDO) {
9595 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9598 n1->nbinary.ch2 = list(0);
9603 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9604 synerror("Bad for loop variable");
9605 n1 = (union node *)stalloc(sizeof (struct nfor));
9607 n1->nfor.var = wordtext;
9608 checkkwd = CHKKWD | CHKALIAS;
9609 if (readtoken() == TIN) {
9611 while (readtoken() == TWORD) {
9612 n2 = (union node *)stalloc(sizeof (struct narg));
9614 n2->narg.text = wordtext;
9615 n2->narg.backquote = backquotelist;
9617 app = &n2->narg.next;
9621 if (lasttoken != TNL && lasttoken != TSEMI)
9624 n2 = (union node *)stalloc(sizeof (struct narg));
9626 n2->narg.text = (char *)dolatstr;
9627 n2->narg.backquote = NULL;
9628 n2->narg.next = NULL;
9631 * Newline or semicolon here is optional (but note
9632 * that the original Bourne shell only allowed NL).
9634 if (lasttoken != TNL && lasttoken != TSEMI)
9637 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9638 if (readtoken() != TDO)
9640 n1->nfor.body = list(0);
9644 n1 = (union node *)stalloc(sizeof (struct ncase));
9646 if (readtoken() != TWORD)
9648 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9650 n2->narg.text = wordtext;
9651 n2->narg.backquote = backquotelist;
9652 n2->narg.next = NULL;
9654 checkkwd = CHKKWD | CHKALIAS;
9655 } while (readtoken() == TNL);
9656 if (lasttoken != TIN)
9658 cpp = &n1->ncase.cases;
9660 checkkwd = CHKNL | CHKKWD;
9663 if (lasttoken == TLP)
9665 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9667 app = &cp->nclist.pattern;
9669 *app = ap = (union node *)stalloc(sizeof (struct narg));
9671 ap->narg.text = wordtext;
9672 ap->narg.backquote = backquotelist;
9673 if (readtoken() != TPIPE)
9675 app = &ap->narg.next;
9678 ap->narg.next = NULL;
9679 if (lasttoken != TRP)
9681 cp->nclist.body = list(2);
9683 cpp = &cp->nclist.next;
9685 checkkwd = CHKNL | CHKKWD;
9686 if ((t = readtoken()) != TESAC) {
9688 synexpect(TENDCASE);
9696 n1 = (union node *)stalloc(sizeof (struct nredir));
9697 n1->type = NSUBSHELL;
9698 n1->nredir.n = list(0);
9699 n1->nredir.redirect = NULL;
9712 if (readtoken() != t)
9716 /* Now check for redirection which may follow command */
9717 checkkwd = CHKKWD | CHKALIAS;
9719 while (readtoken() == TREDIR) {
9720 *rpp = n2 = redirnode;
9721 rpp = &n2->nfile.next;
9727 if (n1->type != NSUBSHELL) {
9728 n2 = (union node *)stalloc(sizeof (struct nredir));
9733 n1->nredir.redirect = redir;
9742 union node *args, **app;
9743 union node *n = NULL;
9744 union node *vars, **vpp;
9745 union node **rpp, *redir;
9755 savecheckkwd = CHKALIAS;
9757 checkkwd = savecheckkwd;
9758 switch (readtoken()) {
9760 n = (union node *)stalloc(sizeof (struct narg));
9762 n->narg.text = wordtext;
9763 n->narg.backquote = backquotelist;
9764 if (savecheckkwd && isassignment(wordtext)) {
9766 vpp = &n->narg.next;
9769 app = &n->narg.next;
9774 *rpp = n = redirnode;
9775 rpp = &n->nfile.next;
9776 parsefname(); /* read name of redirection file */
9780 args && app == &args->narg.next &&
9783 struct builtincmd *bcmd;
9786 /* We have a function */
9787 if (readtoken() != TRP)
9789 name = n->narg.text;
9791 !goodname(name) || (
9792 (bcmd = find_builtin(name)) &&
9793 IS_BUILTIN_SPECIAL(bcmd)
9796 synerror("Bad function name");
9798 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9799 n->narg.next = command();
9812 n = (union node *)stalloc(sizeof (struct ncmd));
9814 n->ncmd.args = args;
9815 n->ncmd.assign = vars;
9816 n->ncmd.redirect = redir;
9825 n = (union node *)stalloc(sizeof (struct narg));
9827 n->narg.next = NULL;
9828 n->narg.text = wordtext;
9829 n->narg.backquote = backquotelist;
9833 void fixredir(union node *n, const char *text, int err)
9835 TRACE(("Fix redir %s %d\n", text, err));
9837 n->ndup.vname = NULL;
9839 if (is_digit(text[0]) && text[1] == '\0')
9840 n->ndup.dupfd = digit_val(text[0]);
9841 else if (text[0] == '-' && text[1] == '\0')
9846 synerror("Bad fd number");
9848 n->ndup.vname = makename();
9856 union node *n = redirnode;
9858 if (readtoken() != TWORD)
9860 if (n->type == NHERE) {
9861 struct heredoc *here = heredoc;
9867 TRACE(("Here document %d\n", n->type));
9868 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9869 synerror("Illegal eof marker for << redirection");
9870 rmescapes(wordtext);
9871 here->eofmark = wordtext;
9873 if (heredoclist == NULL)
9876 for (p = heredoclist ; p->next ; p = p->next);
9879 } else if (n->type == NTOFD || n->type == NFROMFD) {
9880 fixredir(n, wordtext, 0);
9882 n->nfile.fname = makename();
9888 * Input any here documents.
9894 struct heredoc *here;
9905 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9906 here->eofmark, here->striptabs);
9907 n = (union node *)stalloc(sizeof (struct narg));
9908 n->narg.type = NARG;
9909 n->narg.next = NULL;
9910 n->narg.text = wordtext;
9911 n->narg.backquote = backquotelist;
9912 here->here->nhere.doc = n;
9917 static char peektoken(void)
9923 return tokname_array[t][0];
9931 int alreadyseen = tokpushback;
9934 #ifdef CONFIG_ASH_ALIAS
9943 if (checkkwd & CHKNL) {
9950 if (t != TWORD || quoteflag) {
9955 * check for keywords
9957 if (checkkwd & CHKKWD) {
9958 const char *const *pp;
9960 if ((pp = findkwd(wordtext))) {
9961 lasttoken = t = pp - tokname_array;
9962 TRACE(("keyword %s recognized\n", tokname(t)));
9967 if (checkkwd & CHKALIAS) {
9968 #ifdef CONFIG_ASH_ALIAS
9970 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9972 pushstring(ap->val, ap);
9982 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9984 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9991 * Read the next input token.
9992 * If the token is a word, we set backquotelist to the list of cmds in
9993 * backquotes. We set quoteflag to true if any part of the word was
9995 * If the token is TREDIR, then we set redirnode to a structure containing
9997 * In all cases, the variable startlinno is set to the number of the line
9998 * on which the token starts.
10000 * [Change comment: here documents and internal procedures]
10001 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10002 * word parsing code into a separate routine. In this case, readtoken
10003 * doesn't need to have any internal procedures, but parseword does.
10004 * We could also make parseoperator in essence the main routine, and
10005 * have parseword (readtoken1?) handle both words and redirection.]
10008 #define NEW_xxreadtoken
10009 #ifdef NEW_xxreadtoken
10011 /* singles must be first! */
10012 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10014 static const char xxreadtoken_tokens[] = {
10015 TNL, TLP, TRP, /* only single occurrence allowed */
10016 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10017 TEOF, /* corresponds to trailing nul */
10018 TAND, TOR, TENDCASE, /* if double occurrence */
10021 #define xxreadtoken_doubles \
10022 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10023 #define xxreadtoken_singles \
10024 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10026 static int xxreadtoken()
10038 startlinno = plinno;
10039 for (;;) { /* until token or start of word found */
10042 if ((c != ' ') && (c != '\t')
10043 #ifdef CONFIG_ASH_ALIAS
10048 while ((c = pgetc()) != '\n' && c != PEOF);
10050 } else if (c == '\\') {
10051 if (pgetc() != '\n') {
10055 startlinno = ++plinno;
10060 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10065 needprompt = doprompt;
10068 p = strchr(xxreadtoken_chars, c);
10071 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10074 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10075 if (pgetc() == *p) { /* double occurrence? */
10076 p += xxreadtoken_doubles + 1;
10083 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10091 #define RETURN(token) return lasttoken = token
10106 startlinno = plinno;
10107 for (;;) { /* until token or start of word found */
10110 case ' ': case '\t':
10111 #ifdef CONFIG_ASH_ALIAS
10116 while ((c = pgetc()) != '\n' && c != PEOF);
10120 if (pgetc() == '\n') {
10121 startlinno = ++plinno;
10130 needprompt = doprompt;
10135 if (pgetc() == '&')
10140 if (pgetc() == '|')
10145 if (pgetc() == ';')
10158 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10161 #endif /* NEW_xxreadtoken */
10165 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10166 * is not NULL, read a here document. In the latter case, eofmark is the
10167 * word which marks the end of the document and striptabs is true if
10168 * leading tabs should be stripped from the document. The argument firstc
10169 * is the first character of the input token or document.
10171 * Because C does not have internal subroutines, I have simulated them
10172 * using goto's to implement the subroutine linkage. The following macros
10173 * will run code that appears at the end of readtoken1.
10176 #define CHECKEND() {goto checkend; checkend_return:;}
10177 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10178 #define PARSESUB() {goto parsesub; parsesub_return:;}
10179 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10180 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10181 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10184 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10189 char line[EOFMARKLEN + 1];
10190 struct nodelist *bqlist;
10193 int varnest; /* levels of variables expansion */
10194 int arinest; /* levels of arithmetic expansion */
10195 int parenlevel; /* levels of parens in arithmetic */
10196 int dqvarnest; /* levels of variables expansion within double quotes */
10198 int prevsyntax; /* syntax before arithmetic */
10200 /* Avoid longjmp clobbering */
10206 (void) &parenlevel;
10209 (void) &prevsyntax;
10213 startlinno = plinno;
10215 if (syntax == DQSYNTAX)
10224 STARTSTACKSTR(out);
10225 loop: { /* for each line, until end of word */
10226 CHECKEND(); /* set c to PEOF if at end of here document */
10227 for (;;) { /* until end of line or end of word */
10228 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10229 switch(SIT(c, syntax)) {
10230 case CNL: /* '\n' */
10231 if (syntax == BASESYNTAX)
10232 goto endword; /* exit outer loop */
10238 goto loop; /* continue outer loop */
10243 if (eofmark == NULL || dblquote)
10244 USTPUTC(CTLESC, out);
10247 case CBACK: /* backslash */
10250 USTPUTC(CTLESC, out);
10251 USTPUTC('\\', out);
10253 } else if (c == '\n') {
10259 c != '\\' && c != '`' &&
10265 USTPUTC(CTLESC, out);
10266 USTPUTC('\\', out);
10268 if (SIT(c, SQSYNTAX) == CCTL)
10269 USTPUTC(CTLESC, out);
10277 if (eofmark == NULL) {
10278 USTPUTC(CTLQUOTEMARK, out);
10286 if (eofmark != NULL && arinest == 0 &&
10290 if (dqvarnest == 0) {
10291 syntax = BASESYNTAX;
10298 case CVAR: /* '$' */
10299 PARSESUB(); /* parse substitution */
10301 case CENDVAR: /* '}' */
10304 if (dqvarnest > 0) {
10307 USTPUTC(CTLENDVAR, out);
10312 #ifdef CONFIG_ASH_MATH_SUPPORT
10313 case CLP: /* '(' in arithmetic */
10317 case CRP: /* ')' in arithmetic */
10318 if (parenlevel > 0) {
10322 if (pgetc() == ')') {
10323 if (--arinest == 0) {
10324 USTPUTC(CTLENDARI, out);
10325 syntax = prevsyntax;
10326 if (syntax == DQSYNTAX)
10334 * unbalanced parens
10335 * (don't 2nd guess - no error)
10343 case CBQUOTE: /* '`' */
10347 goto endword; /* exit outer loop */
10352 goto endword; /* exit outer loop */
10353 #ifdef CONFIG_ASH_ALIAS
10363 #ifdef CONFIG_ASH_MATH_SUPPORT
10364 if (syntax == ARISYNTAX)
10365 synerror("Missing '))'");
10367 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10368 synerror("Unterminated quoted string");
10369 if (varnest != 0) {
10370 startlinno = plinno;
10372 synerror("Missing '}'");
10374 USTPUTC('\0', out);
10375 len = out - (char *)stackblock();
10376 out = stackblock();
10377 if (eofmark == NULL) {
10378 if ((c == '>' || c == '<')
10381 && (*out == '\0' || is_digit(*out))) {
10383 return lasttoken = TREDIR;
10388 quoteflag = quotef;
10389 backquotelist = bqlist;
10390 grabstackblock(len);
10392 return lasttoken = TWORD;
10393 /* end of readtoken routine */
10398 * Check to see whether we are at the end of the here document. When this
10399 * is called, c is set to the first character of the next input line. If
10400 * we are at the end of the here document, this routine sets the c to PEOF.
10405 #ifdef CONFIG_ASH_ALIAS
10411 while (c == '\t') {
10415 if (c == *eofmark) {
10416 if (pfgets(line, sizeof line) != NULL) {
10420 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10421 if (*p == '\n' && *q == '\0') {
10424 needprompt = doprompt;
10426 pushstring(line, NULL);
10431 goto checkend_return;
10436 * Parse a redirection operator. The variable "out" points to a string
10437 * specifying the fd to be redirected. The variable "c" contains the
10438 * first character of the redirection operator.
10445 np = (union node *)stalloc(sizeof (struct nfile));
10450 np->type = NAPPEND;
10452 np->type = NCLOBBER;
10459 } else { /* c == '<' */
10461 switch (c = pgetc()) {
10463 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10464 np = (union node *)stalloc(sizeof (struct nhere));
10468 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10469 heredoc->here = np;
10470 if ((c = pgetc()) == '-') {
10471 heredoc->striptabs = 1;
10473 heredoc->striptabs = 0;
10479 np->type = NFROMFD;
10483 np->type = NFROMTO;
10493 np->nfile.fd = digit_val(fd);
10495 goto parseredir_return;
10500 * Parse a substitution. At this point, we have read the dollar sign
10501 * and nothing else.
10509 static const char types[] = "}-+?=";
10513 c <= PEOA_OR_PEOF ||
10514 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10518 } else if (c == '(') { /* $(command) or $((arith)) */
10519 if (pgetc() == '(') {
10520 #ifdef CONFIG_ASH_MATH_SUPPORT
10523 synerror("We unsupport $((arith))");
10530 USTPUTC(CTLVAR, out);
10531 typeloc = out - (char *)stackblock();
10532 USTPUTC(VSNORMAL, out);
10533 subtype = VSNORMAL;
10537 if ((c = pgetc()) == '}')
10540 subtype = VSLENGTH;
10545 if (c > PEOA_OR_PEOF && is_name(c)) {
10549 } while (c > PEOA_OR_PEOF && is_in_name(c));
10550 } else if (is_digit(c)) {
10554 } while (is_digit(c));
10556 else if (is_special(c)) {
10561 badsub: synerror("Bad substitution");
10565 if (subtype == 0) {
10572 p = strchr(types, c);
10575 subtype = p - types + VSNORMAL;
10581 subtype = c == '#' ? VSTRIMLEFT :
10594 if (dblquote || arinest)
10596 *((char *)stackblock() + typeloc) = subtype | flags;
10597 if (subtype != VSNORMAL) {
10599 if (dblquote || arinest) {
10604 goto parsesub_return;
10609 * Called to parse command substitutions. Newstyle is set if the command
10610 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10611 * list of commands (passed by reference), and savelen is the number of
10612 * characters on the top of the stack which must be preserved.
10616 struct nodelist **nlpp;
10619 char *volatile str;
10620 struct jmploc jmploc;
10621 struct jmploc *volatile savehandler;
10625 (void) &saveprompt;
10628 savepbq = parsebackquote;
10629 if (setjmp(jmploc.loc)) {
10632 parsebackquote = 0;
10633 handler = savehandler;
10634 longjmp(handler->loc, 1);
10638 savelen = out - (char *)stackblock();
10640 str = ckmalloc(savelen);
10641 memcpy(str, stackblock(), savelen);
10643 savehandler = handler;
10647 /* We must read until the closing backquote, giving special
10648 treatment to some slashes, and then push the string and
10649 reread it as input, interpreting it normally. */
10656 STARTSTACKSTR(pout);
10662 switch (pc = pgetc()) {
10667 if ((pc = pgetc()) == '\n') {
10672 * If eating a newline, avoid putting
10673 * the newline into the new character
10674 * stream (via the STPUTC after the
10679 if (pc != '\\' && pc != '`' && pc != '$'
10680 && (!dblquote || pc != '"'))
10681 STPUTC('\\', pout);
10682 if (pc > PEOA_OR_PEOF) {
10688 #ifdef CONFIG_ASH_ALIAS
10691 startlinno = plinno;
10692 synerror("EOF in backquote substitution");
10696 needprompt = doprompt;
10705 STPUTC('\0', pout);
10706 psavelen = pout - (char *)stackblock();
10707 if (psavelen > 0) {
10708 pstr = grabstackstr(pout);
10709 setinputstring(pstr);
10714 nlpp = &(*nlpp)->next;
10715 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10716 (*nlpp)->next = NULL;
10717 parsebackquote = oldstyle;
10720 saveprompt = doprompt;
10727 doprompt = saveprompt;
10729 if (readtoken() != TRP)
10736 * Start reading from old file again, ignoring any pushed back
10737 * tokens left from the backquote parsing
10742 while (stackblocksize() <= savelen)
10744 STARTSTACKSTR(out);
10746 memcpy(out, str, savelen);
10747 STADJUST(savelen, out);
10753 parsebackquote = savepbq;
10754 handler = savehandler;
10755 if (arinest || dblquote)
10756 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10758 USTPUTC(CTLBACKQ, out);
10760 goto parsebackq_oldreturn;
10762 goto parsebackq_newreturn;
10765 #ifdef CONFIG_ASH_MATH_SUPPORT
10767 * Parse an arithmetic expansion (indicate start of one and set state)
10771 if (++arinest == 1) {
10772 prevsyntax = syntax;
10773 syntax = ARISYNTAX;
10774 USTPUTC(CTLARI, out);
10781 * we collapse embedded arithmetic expansion to
10782 * parenthesis, which should be equivalent
10786 goto parsearith_return;
10790 } /* end of readtoken */
10795 * Returns true if the text contains nothing to expand (no dollar signs
10800 noexpand(char *text)
10806 while ((c = *p++) != '\0') {
10807 if (c == CTLQUOTEMARK)
10811 else if (SIT(c, BASESYNTAX) == CCTL)
10819 * Return of a legal variable name (a letter or underscore followed by zero or
10820 * more letters, underscores, and digits).
10824 endofname(const char *name)
10832 if (! is_in_name(*p))
10840 * Called when an unexpected token is read during the parse. The argument
10841 * is the token that is expected, or -1 if more than one type of token can
10842 * occur at this point.
10845 static void synexpect(int token)
10850 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10852 sprintf(msg + l, " (expecting %s)", tokname(token));
10858 synerror(const char *msg)
10860 error("Syntax error: %s", msg);
10866 * called by editline -- any expansions to the prompt
10867 * should be added here.
10870 static void setprompt(int whichprompt)
10872 const char *prompt;
10874 switch (whichprompt) {
10888 static const char *const *findkwd(const char *s)
10890 return bsearch(s, tokname_array + KWDOFFSET,
10891 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10892 sizeof(const char *), pstrcmp);
10895 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10898 * Code for dealing with input/output redirection.
10901 #define EMPTY -2 /* marks an unused slot in redirtab */
10903 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10905 # define PIPESIZE PIPE_BUF
10909 * Open a file in noclobber mode.
10910 * The code was copied from bash.
10913 noclobberopen(const char *fname)
10916 struct stat finfo, finfo2;
10919 * If the file exists and is a regular file, return an error
10922 r = stat(fname, &finfo);
10923 if (r == 0 && S_ISREG(finfo.st_mode)) {
10929 * If the file was not present (r != 0), make sure we open it
10930 * exclusively so that if it is created before we open it, our open
10931 * will fail. Make sure that we do not truncate an existing file.
10932 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10933 * file was not a regular file, we leave O_EXCL off.
10936 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10937 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10939 /* If the open failed, return the file descriptor right away. */
10944 * OK, the open succeeded, but the file may have been changed from a
10945 * non-regular file to a regular file between the stat and the open.
10946 * We are assuming that the O_EXCL open handles the case where FILENAME
10947 * did not exist and is symlinked to an existing file between the stat
10952 * If we can open it and fstat the file descriptor, and neither check
10953 * revealed that it was a regular file, and the file has not been
10954 * replaced, return the file descriptor.
10956 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10957 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10960 /* The file has been replaced. badness. */
10967 * Handle here documents. Normally we fork off a process to write the
10968 * data to a pipe. If the document is short, we can stuff the data in
10969 * the pipe without forking.
10973 openhere(union node *redir)
10979 error("Pipe call failed");
10980 if (redir->type == NHERE) {
10981 len = strlen(redir->nhere.doc->narg.text);
10982 if (len <= PIPESIZE) {
10983 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
10987 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10989 signal(SIGINT, SIG_IGN);
10990 signal(SIGQUIT, SIG_IGN);
10991 signal(SIGHUP, SIG_IGN);
10993 signal(SIGTSTP, SIG_IGN);
10995 signal(SIGPIPE, SIG_DFL);
10996 if (redir->type == NHERE)
10997 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
10999 expandhere(redir->nhere.doc, pip[1]);
11008 openredirect(union node *redir)
11013 switch (redir->nfile.type) {
11015 fname = redir->nfile.expfname;
11016 if ((f = open(fname, O_RDONLY)) < 0)
11020 fname = redir->nfile.expfname;
11021 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11025 /* Take care of noclobber mode. */
11027 fname = redir->nfile.expfname;
11028 if ((f = noclobberopen(fname)) < 0)
11034 fname = redir->nfile.expfname;
11035 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11039 fname = redir->nfile.expfname;
11040 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11047 /* Fall through to eliminate warning. */
11054 f = openhere(redir);
11060 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11062 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11066 dupredirect(union node *redir, int f)
11068 int fd = redir->nfile.fd;
11070 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11071 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11072 copyfd(redir->ndup.dupfd, fd);
11085 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11086 * old file descriptors are stashed away so that the redirection can be
11087 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11088 * standard output, and the standard error if it becomes a duplicate of
11089 * stdout, is saved in memory.
11093 redirect(union node *redir, int flags)
11096 struct redirtab *sv;
11107 if (flags & REDIR_PUSH) {
11108 struct redirtab *q;
11109 q = ckmalloc(sizeof (struct redirtab));
11110 q->next = redirlist;
11112 q->nullredirs = nullredirs - 1;
11113 for (i = 0 ; i < 10 ; i++)
11114 q->renamed[i] = EMPTY;
11121 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11122 n->ndup.dupfd == fd)
11123 continue; /* redirect from/to same file descriptor */
11125 newfd = openredirect(n);
11128 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11129 i = fcntl(fd, F_DUPFD, 10);
11136 error("%d: %m", fd);
11146 dupredirect(n, newfd);
11147 } while ((n = n->nfile.next));
11149 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11150 preverrout_fd = sv->renamed[2];
11155 * Undo the effects of the last redirection.
11161 struct redirtab *rp;
11164 if (--nullredirs >= 0)
11168 for (i = 0 ; i < 10 ; i++) {
11169 if (rp->renamed[i] != EMPTY) {
11172 copyfd(rp->renamed[i], i);
11174 close(rp->renamed[i]);
11177 redirlist = rp->next;
11178 nullredirs = rp->nullredirs;
11184 * Undo all redirections. Called on error or interrupt.
11188 * Discard all saved file descriptors.
11192 clearredir(int drop)
11204 * Copy a file descriptor to be >= to. Returns -1
11205 * if the source file descriptor is closed, EMPTY if there are no unused
11206 * file descriptors left.
11210 copyfd(int from, int to)
11214 newfd = fcntl(from, F_DUPFD, to);
11216 if (errno == EMFILE)
11219 error("%d: %m", from);
11226 redirectsafe(union node *redir, int flags)
11229 volatile int saveint;
11230 struct jmploc *volatile savehandler = handler;
11231 struct jmploc jmploc;
11234 if (!(err = setjmp(jmploc.loc) * 2)) {
11236 redirect(redir, flags);
11238 handler = savehandler;
11239 if (err && exception != EXERROR)
11240 longjmp(handler->loc, 1);
11241 RESTOREINT(saveint);
11245 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11248 static void shtree(union node *, int, char *, FILE*);
11249 static void shcmd(union node *, FILE *);
11250 static void sharg(union node *, FILE *);
11251 static void indent(int, char *, FILE *);
11252 static void trstring(char *);
11256 showtree(union node *n)
11258 trputs("showtree called\n");
11259 shtree(n, 1, NULL, stdout);
11264 shtree(union node *n, int ind, char *pfx, FILE *fp)
11266 struct nodelist *lp;
11272 indent(ind, pfx, fp);
11283 shtree(n->nbinary.ch1, ind, NULL, fp);
11286 shtree(n->nbinary.ch2, ind, NULL, fp);
11294 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11299 if (n->npipe.backgnd)
11305 fprintf(fp, "<node type %d>", n->type);
11314 shcmd(union node *cmd, FILE *fp)
11322 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11328 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11331 switch (np->nfile.type) {
11332 case NTO: s = ">"; dftfd = 1; break;
11333 case NCLOBBER: s = ">|"; dftfd = 1; break;
11334 case NAPPEND: s = ">>"; dftfd = 1; break;
11335 case NTOFD: s = ">&"; dftfd = 1; break;
11336 case NFROM: s = "<"; dftfd = 0; break;
11337 case NFROMFD: s = "<&"; dftfd = 0; break;
11338 case NFROMTO: s = "<>"; dftfd = 0; break;
11339 default: s = "*error*"; dftfd = 0; break;
11341 if (np->nfile.fd != dftfd)
11342 fprintf(fp, "%d", np->nfile.fd);
11344 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11345 fprintf(fp, "%d", np->ndup.dupfd);
11347 sharg(np->nfile.fname, fp);
11356 sharg(union node *arg, FILE *fp)
11359 struct nodelist *bqlist;
11362 if (arg->type != NARG) {
11363 out1fmt("<node type %d>\n", arg->type);
11366 bqlist = arg->narg.backquote;
11367 for (p = arg->narg.text ; *p ; p++) {
11376 if (subtype == VSLENGTH)
11382 if (subtype & VSNUL)
11385 switch (subtype & VSTYPE) {
11404 case VSTRIMLEFTMAX:
11411 case VSTRIMRIGHTMAX:
11418 out1fmt("<subtype %d>", subtype);
11425 case CTLBACKQ|CTLQUOTE:
11428 shtree(bqlist->n, -1, NULL, fp);
11440 indent(int amount, char *pfx, FILE *fp)
11444 for (i = 0 ; i < amount ; i++) {
11445 if (pfx && i == amount - 1)
11466 putc(c, tracefile);
11470 trace(const char *fmt, ...)
11477 (void) vfprintf(tracefile, fmt, va);
11482 tracev(const char *fmt, va_list va)
11486 (void) vfprintf(tracefile, fmt, va);
11491 trputs(const char *s)
11495 fputs(s, tracefile);
11507 putc('"', tracefile);
11508 for (p = s ; *p ; p++) {
11510 case '\n': c = 'n'; goto backslash;
11511 case '\t': c = 't'; goto backslash;
11512 case '\r': c = 'r'; goto backslash;
11513 case '"': c = '"'; goto backslash;
11514 case '\\': c = '\\'; goto backslash;
11515 case CTLESC: c = 'e'; goto backslash;
11516 case CTLVAR: c = 'v'; goto backslash;
11517 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11518 case CTLBACKQ: c = 'q'; goto backslash;
11519 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11520 backslash: putc('\\', tracefile);
11521 putc(c, tracefile);
11524 if (*p >= ' ' && *p <= '~')
11525 putc(*p, tracefile);
11527 putc('\\', tracefile);
11528 putc(*p >> 6 & 03, tracefile);
11529 putc(*p >> 3 & 07, tracefile);
11530 putc(*p & 07, tracefile);
11535 putc('"', tracefile);
11547 putc(' ', tracefile);
11549 putc('\n', tracefile);
11565 /* leave open because libedit might be using it */
11568 scopy("./trace", s);
11570 if (!freopen(s, "a", tracefile)) {
11571 fprintf(stderr, "Can't re-open %s\n", s);
11576 if ((tracefile = fopen(s, "a")) == NULL) {
11577 fprintf(stderr, "Can't open %s\n", s);
11583 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11584 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11586 setlinebuf(tracefile);
11587 fputs("\nTracing started.\n", tracefile);
11592 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11595 * Sigmode records the current value of the signal handlers for the various
11596 * modes. A value of zero means that the current handler is not known.
11597 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11600 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11601 #define S_CATCH 2 /* signal is caught */
11602 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11603 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11604 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11609 * The trap builtin.
11613 trapcmd(int argc, char **argv)
11622 for (signo = 0 ; signo < NSIG ; signo++) {
11623 if (trap[signo] != NULL) {
11626 sn = u_signal_names(0, &signo, 0);
11629 out1fmt("trap -- %s %s\n",
11630 single_quote(trap[signo]), sn);
11640 if ((signo = decode_signal(*ap, 0)) < 0)
11641 error("%s: bad trap", *ap);
11644 if (action[0] == '-' && action[1] == '\0')
11647 action = savestr(action);
11650 ckfree(trap[signo]);
11651 trap[signo] = action;
11662 * Clear traps on a fork.
11670 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11671 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11675 if (tp != &trap[0])
11676 setsignal(tp - trap);
11684 * Set the signal handler for the specified signal. The routine figures
11685 * out what it should be set to.
11689 setsignal(int signo)
11693 struct sigaction act;
11695 if ((t = trap[signo]) == NULL)
11697 else if (*t != '\0')
11701 if (rootshell && action == S_DFL) {
11704 if (iflag || minusc || sflag == 0)
11727 t = &sigmode[signo - 1];
11731 * current setting unknown
11733 if (sigaction(signo, 0, &act) == -1) {
11735 * Pretend it worked; maybe we should give a warning
11736 * here, but other shells don't. We don't alter
11737 * sigmode, so that we retry every time.
11741 if (act.sa_handler == SIG_IGN) {
11742 if (mflag && (signo == SIGTSTP ||
11743 signo == SIGTTIN || signo == SIGTTOU)) {
11744 tsig = S_IGN; /* don't hard ignore these */
11748 tsig = S_RESET; /* force to be set */
11751 if (tsig == S_HARD_IGN || tsig == action)
11755 act.sa_handler = onsig;
11758 act.sa_handler = SIG_IGN;
11761 act.sa_handler = SIG_DFL;
11765 sigfillset(&act.sa_mask);
11766 sigaction(signo, &act, 0);
11774 ignoresig(int signo)
11776 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11777 signal(signo, SIG_IGN);
11779 sigmode[signo - 1] = S_HARD_IGN;
11790 gotsig[signo - 1] = 1;
11791 pendingsigs = signo;
11793 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11802 * Called to execute a trap. Perhaps we should avoid entering new trap
11803 * handlers while we are executing a trap handler.
11813 savestatus = exitstatus;
11815 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11817 p = trap[p - q + 1];
11821 exitstatus = savestatus;
11827 * Controls whether the shell is interactive or not.
11831 setinteractive(int on)
11833 static int is_interactive;
11835 if (++on == is_interactive)
11837 is_interactive = on;
11839 setsignal(SIGQUIT);
11840 setsignal(SIGTERM);
11841 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11842 if(is_interactive > 1) {
11843 /* Looks like they want an interactive shell */
11844 static int do_banner;
11848 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11849 "Enter 'help' for a list of built-in commands.\n\n");
11857 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11858 /*** List the available builtins ***/
11860 static int helpcmd(int argc, char **argv)
11864 out1fmt("\nBuilt-in commands:\n-------------------\n");
11865 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11866 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11867 builtincmd[i].name + 1);
11873 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11875 extern const struct BB_applet applets[];
11876 extern const size_t NUM_APPLETS;
11878 for (i = 0; i < NUM_APPLETS; i++) {
11880 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11889 return EXIT_SUCCESS;
11891 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11894 * Called to exit the shell.
11905 jmp = setjmp(loc.loc);
11906 status = exitstatus;
11907 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11911 if ((p = trap[0]) != NULL && *p != '\0') {
11916 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11917 if (iflag && rootshell) {
11918 const char *hp = lookupvar("HISTFILE");
11921 save_history ( hp );
11929 static int decode_signal(const char *string, int minsig)
11932 const char *name = u_signal_names(string, &signo, minsig);
11934 return name ? signo : -1;
11937 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11939 static struct var *vartab[VTABSIZE];
11941 static int vpcmp(const void *, const void *);
11942 static struct var **findvar(struct var **, const char *);
11945 * Initialize the variable symbol tables and import the environment
11949 #ifdef CONFIG_ASH_GETOPTS
11951 * Safe version of setvar, returns 1 on success 0 on failure.
11955 setvarsafe(const char *name, const char *val, int flags)
11958 volatile int saveint;
11959 struct jmploc *volatile savehandler = handler;
11960 struct jmploc jmploc;
11963 if (setjmp(jmploc.loc))
11967 setvar(name, val, flags);
11970 handler = savehandler;
11971 RESTOREINT(saveint);
11977 * Set the value of a variable. The flags argument is ored with the
11978 * flags of the variable. If val is NULL, the variable is unset.
11982 setvar(const char *name, const char *val, int flags)
11989 q = endofname(name);
11990 p = strchrnul(q, '=');
11991 namelen = p - name;
11992 if (!namelen || p != q)
11993 error("%.*s: bad variable name", namelen, name);
11998 vallen = strlen(val);
12001 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
12005 p = mempcpy(p, val, vallen);
12008 setvareq(nameeq, flags | VNOSAVE);
12014 * Same as setvar except that the variable and value are passed in
12015 * the first argument as name=value. Since the first argument will
12016 * be actually stored in the table, it should not be a string that
12018 * Called with interrupts off.
12022 setvareq(char *s, int flags)
12024 struct var *vp, **vpp;
12027 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12028 vp = *findvar(vpp, s);
12030 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12033 if (flags & VNOSAVE)
12036 error("%.*s: is read only", strchrnul(n, '=') - n, n);
12039 if (flags & VNOSET)
12042 if (vp->func && (flags & VNOFUNC) == 0)
12043 (*vp->func)(strchrnul(s, '=') + 1);
12045 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12048 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12050 if (flags & VNOSET)
12053 vp = ckmalloc(sizeof (*vp));
12058 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12066 * Process a linked list of variable assignments.
12070 listsetvar(struct strlist *list_set_var, int flags)
12072 struct strlist *lp = list_set_var;
12078 setvareq(lp->text, flags);
12079 } while ((lp = lp->next));
12085 * Find the value of a variable. Returns NULL if not set.
12089 lookupvar(const char *name)
12093 if ((v = *findvar(hashvar(name), name))) {
12096 * Dynamic variables are implemented roughly the same way they are
12097 * in bash. Namely, they're "special" so long as they aren't unset.
12098 * As soon as they're unset, they're no longer dynamic, and dynamic
12099 * lookup will no longer happen at that point. -- PFM.
12101 if((v->flags & VDYNAMIC))
12104 if(!(v->flags & VUNSET))
12105 return strchrnul(v->text, '=') + 1;
12113 * Search the environment of a builtin command.
12117 bltinlookup(const char *name)
12119 struct strlist *sp;
12121 for (sp = cmdenviron ; sp ; sp = sp->next) {
12122 if (varequal(sp->text, name))
12123 return strchrnul(sp->text, '=') + 1;
12125 return lookupvar(name);
12130 * Generate a list of variables satisfying the given conditions.
12134 listvars(int on, int off, char ***end)
12145 for (vp = *vpp ; vp ; vp = vp->next)
12146 if ((vp->flags & mask) == on) {
12147 if (ep == stackstrend())
12148 ep = growstackstr();
12149 *ep++ = (char *) vp->text;
12151 } while (++vpp < vartab + VTABSIZE);
12152 if (ep == stackstrend())
12153 ep = growstackstr();
12157 return grabstackstr(ep);
12162 * POSIX requires that 'set' (but not export or readonly) output the
12163 * variables in lexicographic order - by the locale's collating order (sigh).
12164 * Maybe we could keep them in an ordered balanced binary tree
12165 * instead of hashed lists.
12166 * For now just roll 'em through qsort for printing...
12170 showvars(const char *sep_prefix, int on, int off)
12173 char **ep, **epend;
12175 ep = listvars(on, off, &epend);
12176 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12178 sep = *sep_prefix ? spcstr : sep_prefix;
12180 for (; ep < epend; ep++) {
12184 p = strchrnul(*ep, '=');
12187 q = single_quote(++p);
12189 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12198 * The export and readonly commands.
12202 exportcmd(int argc, char **argv)
12208 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12211 notp = nextopt("p") - 'p';
12212 if (notp && ((name = *(aptr = argptr)))) {
12214 if ((p = strchr(name, '=')) != NULL) {
12217 if ((vp = *findvar(hashvar(name), name))) {
12222 setvar(name, p, flag);
12223 } while ((name = *++aptr) != NULL);
12225 showvars(argv[0], flag, 0);
12232 * Make a variable a local variable. When a variable is made local, it's
12233 * value and flags are saved in a localvar structure. The saved values
12234 * will be restored when the shell function returns. We handle the name
12235 * "-" as a special case.
12239 mklocal(char *name)
12241 struct localvar *lvp;
12246 lvp = ckmalloc(sizeof (struct localvar));
12247 if (name[0] == '-' && name[1] == '\0') {
12249 p = ckmalloc(sizeof(optlist));
12250 lvp->text = memcpy(p, optlist, sizeof(optlist));
12255 vpp = hashvar(name);
12256 vp = *findvar(vpp, name);
12257 eq = strchr(name, '=');
12260 setvareq(name, VSTRFIXED);
12262 setvar(name, NULL, VSTRFIXED);
12263 vp = *vpp; /* the new variable */
12264 lvp->flags = VUNSET;
12266 lvp->text = vp->text;
12267 lvp->flags = vp->flags;
12268 vp->flags |= VSTRFIXED|VTEXTFIXED;
12274 lvp->next = localvars;
12280 * The "local" command.
12284 localcmd(int argc, char **argv)
12289 while ((name = *argv++) != NULL) {
12297 * Called after a function returns.
12298 * Interrupts must be off.
12304 struct localvar *lvp;
12307 while ((lvp = localvars) != NULL) {
12308 localvars = lvp->next;
12310 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12311 if (vp == NULL) { /* $- saved */
12312 memcpy(optlist, lvp->text, sizeof(optlist));
12315 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12316 unsetvar(vp->text);
12319 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12320 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12322 vp->flags = lvp->flags;
12323 vp->text = lvp->text;
12331 * The unset builtin command. We unset the function before we unset the
12332 * variable to allow a function to be unset when there is a readonly variable
12333 * with the same name.
12337 unsetcmd(int argc, char **argv)
12344 while ((i = nextopt("vf")) != '\0') {
12348 for (ap = argptr; *ap ; ap++) {
12363 * Unset the specified variable.
12367 unsetvar(const char *s)
12373 vpp = findvar(hashvar(s), s);
12377 int flags = vp->flags;
12380 if (flags & VREADONLY)
12383 vp->flags &= ~VDYNAMIC;
12385 if (flags & VUNSET)
12387 if ((flags & VSTRFIXED) == 0) {
12389 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12396 vp->flags &= ~VEXPORT;
12409 * Find the appropriate entry in the hash table from the name.
12412 static struct var **
12413 hashvar(const char *p)
12415 unsigned int hashval;
12417 hashval = ((unsigned char) *p) << 4;
12418 while (*p && *p != '=')
12419 hashval += (unsigned char) *p++;
12420 return &vartab[hashval % VTABSIZE];
12426 * Compares two strings up to the first = or '\0'. The first
12427 * string must be terminated by '='; the second may be terminated by
12428 * either '=' or '\0'.
12432 varcmp(const char *p, const char *q)
12436 while ((c = *p) == (d = *q)) {
12437 if (!c || c == '=')
12451 vpcmp(const void *a, const void *b)
12453 return varcmp(*(const char **)a, *(const char **)b);
12456 static struct var **
12457 findvar(struct var **vpp, const char *name)
12459 for (; *vpp; vpp = &(*vpp)->next) {
12460 if (varequal((*vpp)->text, name)) {
12466 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12468 #include <sys/times.h>
12470 static const unsigned char timescmd_str[] = {
12471 ' ', offsetof(struct tms, tms_utime),
12472 '\n', offsetof(struct tms, tms_stime),
12473 ' ', offsetof(struct tms, tms_cutime),
12474 '\n', offsetof(struct tms, tms_cstime),
12478 static int timescmd(int ac, char **av)
12480 long int clk_tck, s, t;
12481 const unsigned char *p;
12484 clk_tck = sysconf(_SC_CLK_TCK);
12489 t = *(clock_t *)(((char *) &buf) + p[1]);
12491 out1fmt("%ldm%ld.%.3lds%c",
12493 ((t - s * clk_tck) * 1000) / clk_tck,
12495 } while (*(p += 2));
12500 #ifdef CONFIG_ASH_MATH_SUPPORT
12502 dash_arith(const char *s)
12508 result = arith(s, &errcode);
12511 error("exponent less than 0");
12512 else if (errcode == -2)
12513 error("divide by zero");
12514 else if (errcode == -5)
12515 error("expression recursion loop detected");
12526 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12527 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12529 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12533 letcmd(int argc, char **argv)
12540 error("expression expected");
12541 for (ap = argv + 1; *ap; ap++) {
12542 i = dash_arith(*ap);
12547 #endif /* CONFIG_ASH_MATH_SUPPORT */
12549 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12552 * Miscellaneous builtins.
12558 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12559 typedef enum __rlimit_resource rlim_t;
12565 * The read builtin. The -e option causes backslashes to escape the
12566 * following character.
12568 * This uses unbuffered input, which may be avoidable in some cases.
12572 readcmd(int argc, char **argv)
12587 while ((i = nextopt("p:r")) != '\0') {
12589 prompt = optionarg;
12593 if (prompt && isatty(0)) {
12596 if (*(ap = argptr) == NULL)
12597 error("arg count");
12598 if ((ifs = bltinlookup("IFS")) == NULL)
12605 if (read(0, &c, 1) != 1) {
12617 if (!rflag && c == '\\') {
12623 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12627 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12629 setvar(*ap, stackblock(), 0);
12639 /* Remove trailing blanks */
12640 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12642 setvar(*ap, stackblock(), 0);
12643 while (*++ap != NULL)
12644 setvar(*ap, nullstr, 0);
12649 static int umaskcmd(int argc, char **argv)
12651 static const char permuser[3] = "ugo";
12652 static const char permmode[3] = "rwx";
12653 static const short int permmask[] = {
12654 S_IRUSR, S_IWUSR, S_IXUSR,
12655 S_IRGRP, S_IWGRP, S_IXGRP,
12656 S_IROTH, S_IWOTH, S_IXOTH
12662 int symbolic_mode = 0;
12664 while (nextopt("S") != '\0') {
12673 if ((ap = *argptr) == NULL) {
12674 if (symbolic_mode) {
12678 for (i = 0; i < 3; i++) {
12681 *p++ = permuser[i];
12683 for (j = 0; j < 3; j++) {
12684 if ((mask & permmask[3 * i + j]) == 0) {
12685 *p++ = permmode[j];
12693 out1fmt("%.4o\n", mask);
12696 if (is_digit((unsigned char) *ap)) {
12699 if (*ap >= '8' || *ap < '0')
12700 error(illnum, argv[1]);
12701 mask = (mask << 3) + (*ap - '0');
12702 } while (*++ap != '\0');
12705 mask = ~mask & 0777;
12706 if (!bb_parse_mode(ap, &mask)) {
12707 error("Illegal mode: %s", ap);
12709 umask(~mask & 0777);
12718 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12719 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12720 * ash by J.T. Conklin.
12728 int factor; /* multiply by to get rlim_{cur,max} values */
12732 static const struct limits limits[] = {
12734 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12736 #ifdef RLIMIT_FSIZE
12737 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12740 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12742 #ifdef RLIMIT_STACK
12743 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12746 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12749 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12751 #ifdef RLIMIT_MEMLOCK
12752 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12754 #ifdef RLIMIT_NPROC
12755 { "process", RLIMIT_NPROC, 1, 'p' },
12757 #ifdef RLIMIT_NOFILE
12758 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
12761 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
12763 #ifdef RLIMIT_LOCKS
12764 { "locks", RLIMIT_LOCKS, 1, 'w' },
12766 { (char *) 0, 0, 0, '\0' }
12769 enum limtype { SOFT = 0x1, HARD = 0x2 };
12771 static void printlim(enum limtype how, const struct rlimit *limit,
12772 const struct limits *l)
12776 val = limit->rlim_max;
12778 val = limit->rlim_cur;
12780 if (val == RLIM_INFINITY)
12781 out1fmt("unlimited\n");
12784 out1fmt("%lld\n", (long long) val);
12789 ulimitcmd(int argc, char **argv)
12793 enum limtype how = SOFT | HARD;
12794 const struct limits *l;
12797 struct rlimit limit;
12800 while ((optc = nextopt("HSa"
12804 #ifdef RLIMIT_FSIZE
12810 #ifdef RLIMIT_STACK
12819 #ifdef RLIMIT_MEMLOCK
12822 #ifdef RLIMIT_NPROC
12825 #ifdef RLIMIT_NOFILE
12831 #ifdef RLIMIT_LOCKS
12849 for (l = limits; l->option != what; l++)
12852 set = *argptr ? 1 : 0;
12856 if (all || argptr[1])
12857 error("too many arguments");
12858 if (strncmp(p, "unlimited\n", 9) == 0)
12859 val = RLIM_INFINITY;
12863 while ((c = *p++) >= '0' && c <= '9')
12865 val = (val * 10) + (long)(c - '0');
12866 if (val < (rlim_t) 0)
12870 error("bad number");
12875 for (l = limits; l->name; l++) {
12876 getrlimit(l->cmd, &limit);
12877 out1fmt("%-20s ", l->name);
12878 printlim(how, &limit, l);
12883 getrlimit(l->cmd, &limit);
12886 limit.rlim_max = val;
12888 limit.rlim_cur = val;
12889 if (setrlimit(l->cmd, &limit) < 0)
12890 error("error setting limit (%m)");
12892 printlim(how, &limit, l);
12898 #ifdef CONFIG_ASH_MATH_SUPPORT
12900 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12902 Permission is hereby granted, free of charge, to any person obtaining
12903 a copy of this software and associated documentation files (the
12904 "Software"), to deal in the Software without restriction, including
12905 without limitation the rights to use, copy, modify, merge, publish,
12906 distribute, sublicense, and/or sell copies of the Software, and to
12907 permit persons to whom the Software is furnished to do so, subject to
12908 the following conditions:
12910 The above copyright notice and this permission notice shall be
12911 included in all copies or substantial portions of the Software.
12913 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12914 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12915 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12916 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12917 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12918 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12919 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12922 /* This is my infix parser/evaluator. It is optimized for size, intended
12923 * as a replacement for yacc-based parsers. However, it may well be faster
12924 * than a comparable parser written in yacc. The supported operators are
12925 * listed in #defines below. Parens, order of operations, and error handling
12926 * are supported. This code is thread safe. The exact expression format should
12927 * be that which POSIX specifies for shells. */
12929 /* The code uses a simple two-stack algorithm. See
12930 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12931 * for a detailed explanation of the infix-to-postfix algorithm on which
12932 * this is based (this code differs in that it applies operators immediately
12933 * to the stack instead of adding them to a queue to end up with an
12936 /* To use the routine, call it with an expression string and error return
12940 * Aug 24, 2001 Manuel Novoa III
12942 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12944 * 1) In arith_apply():
12945 * a) Cached values of *numptr and &(numptr[-1]).
12946 * b) Removed redundant test for zero denominator.
12949 * a) Eliminated redundant code for processing operator tokens by moving
12950 * to a table-based implementation. Also folded handling of parens
12952 * b) Combined all 3 loops which called arith_apply to reduce generated
12953 * code size at the cost of speed.
12955 * 3) The following expressions were treated as valid by the original code:
12956 * 1() , 0! , 1 ( *3 ) .
12957 * These bugs have been fixed by internally enclosing the expression in
12958 * parens and then checking that all binary ops and right parens are
12959 * preceded by a valid expression (NUM_TOKEN).
12961 * Note: It may be desirable to replace Aaron's test for whitespace with
12962 * ctype's isspace() if it is used by another busybox applet or if additional
12963 * whitespace chars should be considered. Look below the "#include"s for a
12964 * precompiler test.
12968 * Aug 26, 2001 Manuel Novoa III
12970 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12972 * Merge in Aaron's comments previously posted to the busybox list,
12973 * modified slightly to take account of my changes to the code.
12978 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12980 * - allow access to variable,
12981 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12982 * - realize assign syntax (VAR=expr, +=, *= etc)
12983 * - realize exponentiation (** operator)
12984 * - realize comma separated - expr, expr
12985 * - realise ++expr --expr expr++ expr--
12986 * - realise expr ? expr : expr (but, second expr calculate always)
12987 * - allow hexadecimal and octal numbers
12988 * - was restored loses XOR operator
12989 * - remove one goto label, added three ;-)
12990 * - protect $((num num)) as true zero expr (Manuel`s error)
12991 * - always use special isspace(), see comment from bash ;-)
12995 #define arith_isspace(arithval) \
12996 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12999 typedef unsigned char operator;
13001 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
13002 * precedence, and 3 high bits are an ID unique across operators of that
13003 * precedence. The ID portion is so that multiple operators can have the
13004 * same precedence, ensuring that the leftmost one is evaluated first.
13005 * Consider * and /. */
13007 #define tok_decl(prec,id) (((id)<<5)|(prec))
13008 #define PREC(op) ((op) & 0x1F)
13010 #define TOK_LPAREN tok_decl(0,0)
13012 #define TOK_COMMA tok_decl(1,0)
13014 #define TOK_ASSIGN tok_decl(2,0)
13015 #define TOK_AND_ASSIGN tok_decl(2,1)
13016 #define TOK_OR_ASSIGN tok_decl(2,2)
13017 #define TOK_XOR_ASSIGN tok_decl(2,3)
13018 #define TOK_PLUS_ASSIGN tok_decl(2,4)
13019 #define TOK_MINUS_ASSIGN tok_decl(2,5)
13020 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13021 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13023 #define TOK_MUL_ASSIGN tok_decl(3,0)
13024 #define TOK_DIV_ASSIGN tok_decl(3,1)
13025 #define TOK_REM_ASSIGN tok_decl(3,2)
13027 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13028 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13030 /* conditional is right associativity too */
13031 #define TOK_CONDITIONAL tok_decl(4,0)
13032 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
13034 #define TOK_OR tok_decl(5,0)
13036 #define TOK_AND tok_decl(6,0)
13038 #define TOK_BOR tok_decl(7,0)
13040 #define TOK_BXOR tok_decl(8,0)
13042 #define TOK_BAND tok_decl(9,0)
13044 #define TOK_EQ tok_decl(10,0)
13045 #define TOK_NE tok_decl(10,1)
13047 #define TOK_LT tok_decl(11,0)
13048 #define TOK_GT tok_decl(11,1)
13049 #define TOK_GE tok_decl(11,2)
13050 #define TOK_LE tok_decl(11,3)
13052 #define TOK_LSHIFT tok_decl(12,0)
13053 #define TOK_RSHIFT tok_decl(12,1)
13055 #define TOK_ADD tok_decl(13,0)
13056 #define TOK_SUB tok_decl(13,1)
13058 #define TOK_MUL tok_decl(14,0)
13059 #define TOK_DIV tok_decl(14,1)
13060 #define TOK_REM tok_decl(14,2)
13062 /* exponent is right associativity */
13063 #define TOK_EXPONENT tok_decl(15,1)
13065 /* For now unary operators. */
13066 #define UNARYPREC 16
13067 #define TOK_BNOT tok_decl(UNARYPREC,0)
13068 #define TOK_NOT tok_decl(UNARYPREC,1)
13070 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13071 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13073 #define PREC_PRE (UNARYPREC+2)
13075 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13076 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13078 #define PREC_POST (UNARYPREC+3)
13080 #define TOK_POST_INC tok_decl(PREC_POST, 0)
13081 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
13083 #define SPEC_PREC (UNARYPREC+4)
13085 #define TOK_NUM tok_decl(SPEC_PREC, 0)
13086 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13088 #define NUMPTR (*numstackptr)
13090 static inline int tok_have_assign(operator op)
13092 operator prec = PREC(op);
13094 convert_prec_is_assing(prec);
13095 return (prec == PREC(TOK_ASSIGN) ||
13096 prec == PREC_PRE || prec == PREC_POST);
13099 static inline int is_right_associativity(operator prec)
13101 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13102 prec == PREC(TOK_CONDITIONAL));
13106 typedef struct ARITCH_VAR_NUM {
13108 arith_t contidional_second_val;
13109 char contidional_second_val_initialized;
13110 char *var; /* if NULL then is regular number,
13111 else is variable name */
13115 typedef struct CHK_VAR_RECURSIVE_LOOPED {
13117 struct CHK_VAR_RECURSIVE_LOOPED *next;
13118 } chk_var_recursive_looped_t;
13120 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13123 static int arith_lookup_val(v_n_t *t)
13126 const char * p = lookupvar(t->var);
13131 /* recursive try as expression */
13132 chk_var_recursive_looped_t *cur;
13133 chk_var_recursive_looped_t cur_save;
13135 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13136 if(strcmp(cur->var, t->var) == 0) {
13137 /* expression recursion loop detected */
13141 /* save current lookuped var name */
13142 cur = prev_chk_var_recursive;
13143 cur_save.var = t->var;
13144 cur_save.next = cur;
13145 prev_chk_var_recursive = &cur_save;
13147 t->val = arith (p, &errcode);
13148 /* restore previous ptr after recursiving */
13149 prev_chk_var_recursive = cur;
13152 /* allow undefined var as 0 */
13159 /* "applying" a token means performing it on the top elements on the integer
13160 * stack. For a unary operator it will only change the top element, but a
13161 * binary operator will pop two arguments and push a result */
13163 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13166 arith_t numptr_val, rez
13167 int ret_arith_lookup_val;
13169 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13170 without arguments */
13171 numptr_m1 = NUMPTR - 1;
13173 /* check operand is var with noninteger value */
13174 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13175 if(ret_arith_lookup_val)
13176 return ret_arith_lookup_val;
13178 rez = numptr_m1->val;
13179 if (op == TOK_UMINUS)
13181 else if (op == TOK_NOT)
13183 else if (op == TOK_BNOT)
13185 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13187 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13189 else if (op != TOK_UPLUS) {
13190 /* Binary operators */
13192 /* check and binary operators need two arguments */
13193 if (numptr_m1 == numstack) goto err;
13195 /* ... and they pop one */
13198 if (op == TOK_CONDITIONAL) {
13199 if(! numptr_m1->contidional_second_val_initialized) {
13200 /* protect $((expr1 ? expr2)) without ": expr" */
13203 rez = numptr_m1->contidional_second_val;
13204 } else if(numptr_m1->contidional_second_val_initialized) {
13205 /* protect $((expr1 : expr2)) without "expr ? " */
13208 numptr_m1 = NUMPTR - 1;
13209 if(op != TOK_ASSIGN) {
13210 /* check operand is var with noninteger value for not '=' */
13211 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13212 if(ret_arith_lookup_val)
13213 return ret_arith_lookup_val;
13215 if (op == TOK_CONDITIONAL) {
13216 numptr_m1->contidional_second_val = rez;
13218 rez = numptr_m1->val;
13219 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13221 else if (op == TOK_OR)
13222 rez = numptr_val || rez;
13223 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13225 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13227 else if (op == TOK_AND)
13228 rez = rez && numptr_val;
13229 else if (op == TOK_EQ)
13230 rez = (rez == numptr_val);
13231 else if (op == TOK_NE)
13232 rez = (rez != numptr_val);
13233 else if (op == TOK_GE)
13234 rez = (rez >= numptr_val);
13235 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13236 rez >>= numptr_val;
13237 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13238 rez <<= numptr_val;
13239 else if (op == TOK_GT)
13240 rez = (rez > numptr_val);
13241 else if (op == TOK_LT)
13242 rez = (rez < numptr_val);
13243 else if (op == TOK_LE)
13244 rez = (rez <= numptr_val);
13245 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13247 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13249 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13251 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13253 else if (op == TOK_CONDITIONAL_SEP) {
13254 if (numptr_m1 == numstack) {
13255 /* protect $((expr : expr)) without "expr ? " */
13258 numptr_m1->contidional_second_val_initialized = op;
13259 numptr_m1->contidional_second_val = numptr_val;
13261 else if (op == TOK_CONDITIONAL) {
13263 numptr_val : numptr_m1->contidional_second_val;
13265 else if(op == TOK_EXPONENT) {
13267 return -3; /* exponent less than 0 */
13272 while(numptr_val--)
13277 else if(numptr_val==0) /* zero divisor check */
13279 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13281 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13284 if(tok_have_assign(op)) {
13287 if(numptr_m1->var == NULL) {
13291 /* save to shell variable */
13292 sprintf(buf, "%lld", (long long) rez);
13293 setvar(numptr_m1->var, buf, 0);
13294 /* after saving, make previous value for v++ or v-- */
13295 if(op == TOK_POST_INC)
13297 else if(op == TOK_POST_DEC)
13300 numptr_m1->val = rez;
13301 /* protect geting var value, is number now */
13302 numptr_m1->var = NULL;
13307 /* longest must first */
13308 static const char op_tokens[] = {
13309 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13310 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13311 '<','<', 0, TOK_LSHIFT,
13312 '>','>', 0, TOK_RSHIFT,
13313 '|','|', 0, TOK_OR,
13314 '&','&', 0, TOK_AND,
13315 '!','=', 0, TOK_NE,
13316 '<','=', 0, TOK_LE,
13317 '>','=', 0, TOK_GE,
13318 '=','=', 0, TOK_EQ,
13319 '|','=', 0, TOK_OR_ASSIGN,
13320 '&','=', 0, TOK_AND_ASSIGN,
13321 '*','=', 0, TOK_MUL_ASSIGN,
13322 '/','=', 0, TOK_DIV_ASSIGN,
13323 '%','=', 0, TOK_REM_ASSIGN,
13324 '+','=', 0, TOK_PLUS_ASSIGN,
13325 '-','=', 0, TOK_MINUS_ASSIGN,
13326 '-','-', 0, TOK_POST_DEC,
13327 '^','=', 0, TOK_XOR_ASSIGN,
13328 '+','+', 0, TOK_POST_INC,
13329 '*','*', 0, TOK_EXPONENT,
13333 '=', 0, TOK_ASSIGN,
13345 '?', 0, TOK_CONDITIONAL,
13346 ':', 0, TOK_CONDITIONAL_SEP,
13347 ')', 0, TOK_RPAREN,
13348 '(', 0, TOK_LPAREN,
13352 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13355 static arith_t arith (const char *expr, int *perrcode)
13357 register char arithval; /* Current character under analysis */
13358 operator lasttok, op;
13361 const char *p = endexpression;
13364 size_t datasizes = strlen(expr) + 2;
13366 /* Stack of integers */
13367 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13368 * in any given correct or incorrect expression is left as an exercise to
13370 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13371 *numstackptr = numstack;
13372 /* Stack of operator tokens */
13373 operator *stack = alloca((datasizes) * sizeof(operator)),
13376 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13377 *perrcode = errcode = 0;
13380 if ((arithval = *expr) == 0) {
13381 if (p == endexpression) {
13382 /* Null expression. */
13386 /* This is only reached after all tokens have been extracted from the
13387 * input stream. If there are still tokens on the operator stack, they
13388 * are to be applied in order. At the end, there should be a final
13389 * result on the integer stack */
13391 if (expr != endexpression + 1) {
13392 /* If we haven't done so already, */
13393 /* append a closing right paren */
13394 expr = endexpression;
13395 /* and let the loop process it. */
13398 /* At this point, we're done with the expression. */
13399 if (numstackptr != numstack+1) {
13400 /* ... but if there isn't, it's bad */
13402 return (*perrcode = -1);
13404 if(numstack->var) {
13405 /* expression is $((var)) only, lookup now */
13406 errcode = arith_lookup_val(numstack);
13409 *perrcode = errcode;
13410 return numstack->val;
13412 /* Continue processing the expression. */
13413 if (arith_isspace(arithval)) {
13414 /* Skip whitespace */
13417 if((p = endofname(expr)) != expr) {
13418 int var_name_size = (p-expr) + 1; /* trailing zero */
13420 numstackptr->var = alloca(var_name_size);
13421 safe_strncpy(numstackptr->var, expr, var_name_size);
13424 numstackptr->contidional_second_val_initialized = 0;
13428 } else if (is_digit(arithval)) {
13429 numstackptr->var = NULL;
13430 numstackptr->val = strtol(expr, (char **) &expr, 0);
13433 for(p = op_tokens; ; p++) {
13437 /* strange operator not found */
13440 for(o = expr; *p && *o == *p; p++)
13447 /* skip tail uncompared token */
13450 /* skip zero delim */
13455 /* post grammar: a++ reduce to num */
13456 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13459 /* Plus and minus are binary (not unary) _only_ if the last
13460 * token was as number, or a right paren (which pretends to be
13461 * a number, since it evaluates to one). Think about it.
13462 * It makes sense. */
13463 if (lasttok != TOK_NUM) {
13479 /* We don't want a unary operator to cause recursive descent on the
13480 * stack, because there can be many in a row and it could cause an
13481 * operator to be evaluated before its argument is pushed onto the
13482 * integer stack. */
13483 /* But for binary operators, "apply" everything on the operator
13484 * stack until we find an operator with a lesser priority than the
13485 * one we have just extracted. */
13486 /* Left paren is given the lowest priority so it will never be
13487 * "applied" in this way.
13488 * if associativity is right and priority eq, applied also skip
13491 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13492 /* not left paren or unary */
13493 if (lasttok != TOK_NUM) {
13494 /* binary op must be preceded by a num */
13497 while (stackptr != stack) {
13498 if (op == TOK_RPAREN) {
13499 /* The algorithm employed here is simple: while we don't
13500 * hit an open paren nor the bottom of the stack, pop
13501 * tokens and apply them */
13502 if (stackptr[-1] == TOK_LPAREN) {
13504 /* Any operator directly after a */
13506 /* close paren should consider itself binary */
13510 operator prev_prec = PREC(stackptr[-1]);
13512 convert_prec_is_assing(prec);
13513 convert_prec_is_assing(prev_prec);
13514 if (prev_prec < prec)
13516 /* check right assoc */
13517 if(prev_prec == prec && is_right_associativity(prec))
13520 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13521 if(errcode) goto ret;
13523 if (op == TOK_RPAREN) {
13528 /* Push this operator to the stack and remember it. */
13529 *stackptr++ = lasttok = op;
13536 #endif /* CONFIG_ASH_MATH_SUPPORT */
13540 const char *bb_applet_name = "debug stuff usage";
13541 int main(int argc, char **argv)
13543 return ash_main(argc, argv);
13548 * Copyright (c) 1989, 1991, 1993, 1994
13549 * The Regents of the University of California. All rights reserved.
13551 * This code is derived from software contributed to Berkeley by
13552 * Kenneth Almquist.
13554 * Redistribution and use in source and binary forms, with or without
13555 * modification, are permitted provided that the following conditions
13557 * 1. Redistributions of source code must retain the above copyright
13558 * notice, this list of conditions and the following disclaimer.
13559 * 2. Redistributions in binary form must reproduce the above copyright
13560 * notice, this list of conditions and the following disclaimer in the
13561 * documentation and/or other materials provided with the distribution.
13563 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13564 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13566 * 4. Neither the name of the University nor the names of its contributors
13567 * may be used to endorse or promote products derived from this software
13568 * without specific prior written permission.
13570 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13571 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13572 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13573 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13574 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13575 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13576 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13577 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13578 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13579 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF